summaryrefslogtreecommitdiffstats
path: root/Tools
diff options
context:
space:
mode:
authorBen Murdoch <benm@google.com>2011-05-05 14:36:32 +0100
committerBen Murdoch <benm@google.com>2011-05-10 15:38:30 +0100
commitf05b935882198ccf7d81675736e3aeb089c5113a (patch)
tree4ea0ca838d9ef1b15cf17ddb3928efb427c7e5a1 /Tools
parent60fbdcc62bced8db2cb1fd233cc4d1e4ea17db1b (diff)
downloadexternal_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.zip
external_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.tar.gz
external_webkit-f05b935882198ccf7d81675736e3aeb089c5113a.tar.bz2
Merge WebKit at r74534: Initial merge by git.
Change-Id: I6ccd1154fa1b19c2ec2a66878eb675738735f1eb
Diffstat (limited to 'Tools')
-rwxr-xr-xTools/BuildSlaveSupport/build-launcher-app120
-rwxr-xr-xTools/BuildSlaveSupport/build-launcher-dmg118
-rw-r--r--Tools/BuildSlaveSupport/build.webkit.org-config/Makefile19
-rw-r--r--Tools/BuildSlaveSupport/build.webkit.org-config/README2
-rw-r--r--Tools/BuildSlaveSupport/build.webkit.org-config/buildbot.tac21
-rw-r--r--Tools/BuildSlaveSupport/build.webkit.org-config/config.json258
-rw-r--r--Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg567
-rw-r--r--Tools/BuildSlaveSupport/build.webkit.org-config/public_html/buildbot.css382
-rw-r--r--Tools/BuildSlaveSupport/build.webkit.org-config/public_html/default.css524
-rw-r--r--Tools/BuildSlaveSupport/build.webkit.org-config/public_html/robots.txt13
-rwxr-xr-xTools/BuildSlaveSupport/build.webkit.org-config/templates/root.html24
-rw-r--r--Tools/BuildSlaveSupport/built-product-archive148
-rw-r--r--Tools/BuildSlaveSupport/gtk/README52
-rwxr-xr-xTools/BuildSlaveSupport/gtk/buildbot/log/run38
-rwxr-xr-xTools/BuildSlaveSupport/gtk/buildbot/run77
-rwxr-xr-xTools/BuildSlaveSupport/gtk/crashmon/crashmon73
-rwxr-xr-xTools/BuildSlaveSupport/gtk/crashmon/log/run38
-rwxr-xr-xTools/BuildSlaveSupport/gtk/crashmon/run74
-rw-r--r--Tools/BuildSlaveSupport/gtk/daemontools-buildbot.conf87
-rwxr-xr-xTools/BuildSlaveSupport/gtk/pulseaudio/run24
-rwxr-xr-xTools/BuildSlaveSupport/gtk/xvfb/log/run37
-rwxr-xr-xTools/BuildSlaveSupport/gtk/xvfb/run41
-rwxr-xr-xTools/BuildSlaveSupport/run-performance-tests80
-rw-r--r--Tools/BuildSlaveSupport/test-result-archive118
-rwxr-xr-xTools/BuildSlaveSupport/win/kill-old-processes38
-rw-r--r--Tools/CLWrapper/CLWrapper.cpp52
-rw-r--r--Tools/CLWrapper/CLWrapper.sln20
-rw-r--r--Tools/CLWrapper/CLWrapper.vcproj199
-rw-r--r--Tools/CMakeListsEfl.txt59
-rw-r--r--Tools/CMakeListsWinCE.txt24
-rw-r--r--Tools/CSSTestSuiteHarness/harness/harness.css308
-rw-r--r--Tools/CSSTestSuiteHarness/harness/harness.html262
-rw-r--r--Tools/CSSTestSuiteHarness/harness/harness.js1902
-rw-r--r--Tools/ChangeLog26465
-rw-r--r--Tools/ChangeLog-2009-06-1625221
-rw-r--r--Tools/ChangeLog-2010-05-2435303
-rw-r--r--Tools/CodeCoverage/README22
-rw-r--r--Tools/CodeCoverage/amber.pngbin0 -> 127 bytes
-rw-r--r--Tools/CodeCoverage/cov.py201
-rw-r--r--Tools/CodeCoverage/emerald.pngbin0 -> 127 bytes
-rw-r--r--Tools/CodeCoverage/gcov.css116
-rw-r--r--Tools/CodeCoverage/glass.pngbin0 -> 127 bytes
-rwxr-xr-xTools/CodeCoverage/regenerate-coverage-display382
-rw-r--r--Tools/CodeCoverage/ruby.pngbin0 -> 127 bytes
-rwxr-xr-xTools/CodeCoverage/run-generate-coverage-data240
-rw-r--r--Tools/CodeCoverage/snow.pngbin0 -> 127 bytes
-rw-r--r--Tools/CygwinDownloader/cygwin-downloader.py157
-rw-r--r--Tools/CygwinDownloader/cygwin-downloader.zipbin0 -> 2989085 bytes
-rwxr-xr-xTools/CygwinDownloader/make-zip.sh30
-rw-r--r--Tools/CygwinDownloader/setup.py4
-rw-r--r--Tools/DumpRenderTree/AccessibilityController.cpp122
-rw-r--r--Tools/DumpRenderTree/AccessibilityController.h72
-rw-r--r--Tools/DumpRenderTree/AccessibilityTextMarker.cpp134
-rw-r--r--Tools/DumpRenderTree/AccessibilityTextMarker.h105
-rw-r--r--Tools/DumpRenderTree/AccessibilityUIElement.cpp983
-rw-r--r--Tools/DumpRenderTree/AccessibilityUIElement.h224
-rw-r--r--Tools/DumpRenderTree/DumpRenderTree.gypi72
-rw-r--r--Tools/DumpRenderTree/DumpRenderTree.h64
-rw-r--r--Tools/DumpRenderTree/DumpRenderTree.sln83
-rw-r--r--Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj1071
-rw-r--r--Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.h39
-rw-r--r--Tools/DumpRenderTree/DumpRenderTreeFileDraggingSource.m38
-rw-r--r--Tools/DumpRenderTree/DumpRenderTreePrefix.h38
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/ASCIICType.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/CurrentTime.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
-rwxr-xr-xTools/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/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/StringExtras.h1
-rw-r--r--Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadSafeShared.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.cpp2144
-rw-r--r--Tools/DumpRenderTree/LayoutTestController.h370
-rw-r--r--Tools/DumpRenderTree/Makefile2
-rw-r--r--Tools/DumpRenderTree/PixelDumpSupport.cpp90
-rw-r--r--Tools/DumpRenderTree/PixelDumpSupport.h55
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp1245
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h97
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginObjectMac.mm102
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp145
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h222
-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/GetUserAgentWithNullNPPFromNPPNew.cpp56
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp72
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp89
-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/win/DrawsGradient.cpp118
-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.cpp90
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp114
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/mac/Info.plist60
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp762
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.def6
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.rc101
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj508
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginCommon.vsprops19
-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/TestNetscapePlugin_debug.def6
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp71
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h50
-rw-r--r--Tools/DumpRenderTree/TestNetscapePlugIn/win/resource.h14
-rw-r--r--Tools/DumpRenderTree/WorkQueue.cpp104
-rw-r--r--Tools/DumpRenderTree/WorkQueue.h53
-rw-r--r--Tools/DumpRenderTree/WorkQueueItem.h141
-rw-r--r--Tools/DumpRenderTree/android/get_layout_tests_dir_contents.php110
-rw-r--r--Tools/DumpRenderTree/android/view_source.php53
-rw-r--r--Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp93
-rw-r--r--Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h81
-rw-r--r--Tools/DumpRenderTree/cf/WebArchiveDumpSupport.cpp229
-rw-r--r--Tools/DumpRenderTree/cf/WebArchiveDumpSupport.h41
-rw-r--r--Tools/DumpRenderTree/cg/ImageDiffCG.cpp250
-rw-r--r--Tools/DumpRenderTree/cg/PixelDumpSupportCG.cpp113
-rw-r--r--Tools/DumpRenderTree/cg/PixelDumpSupportCG.h84
-rw-r--r--Tools/DumpRenderTree/chromium/AccessibilityController.cpp124
-rw-r--r--Tools/DumpRenderTree/chromium/AccessibilityController.h84
-rw-r--r--Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp585
-rw-r--r--Tools/DumpRenderTree/chromium/AccessibilityUIElement.h142
-rw-r--r--Tools/DumpRenderTree/chromium/CppBoundClass.cpp350
-rw-r--r--Tools/DumpRenderTree/chromium/CppBoundClass.h241
-rw-r--r--Tools/DumpRenderTree/chromium/CppVariant.cpp310
-rw-r--r--Tools/DumpRenderTree/chromium/CppVariant.h133
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp161
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h105
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.cpp36
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.h65
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp124
-rw-r--r--Tools/DumpRenderTree/chromium/DRTDevToolsClient.h90
-rw-r--r--Tools/DumpRenderTree/chromium/DumpRenderTree.cpp214
-rw-r--r--Tools/DumpRenderTree/chromium/EventSender.cpp1008
-rw-r--r--Tools/DumpRenderTree/chromium/EventSender.h163
-rw-r--r--Tools/DumpRenderTree/chromium/ImageDiff.cpp408
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestController.cpp1590
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestController.h551
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestHelper.mm118
-rw-r--r--Tools/DumpRenderTree/chromium/LayoutTestHelperWin.cpp84
-rw-r--r--Tools/DumpRenderTree/chromium/MockSpellCheck.cpp156
-rw-r--r--Tools/DumpRenderTree/chromium/MockSpellCheck.h83
-rw-r--r--Tools/DumpRenderTree/chromium/NotificationPresenter.cpp148
-rw-r--r--Tools/DumpRenderTree/chromium/NotificationPresenter.h77
-rw-r--r--Tools/DumpRenderTree/chromium/PlainTextController.cpp79
-rw-r--r--Tools/DumpRenderTree/chromium/PlainTextController.h52
-rw-r--r--Tools/DumpRenderTree/chromium/Task.cpp75
-rw-r--r--Tools/DumpRenderTree/chromium/Task.h88
-rw-r--r--Tools/DumpRenderTree/chromium/TestEventPrinter.cpp168
-rw-r--r--Tools/DumpRenderTree/chromium/TestEventPrinter.h43
-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/TestNetscapePlugIn/Info.plist60
-rw-r--r--Tools/DumpRenderTree/chromium/TestShell.cpp621
-rw-r--r--Tools/DumpRenderTree/chromium/TestShell.h221
-rw-r--r--Tools/DumpRenderTree/chromium/TestShellGtk.cpp211
-rw-r--r--Tools/DumpRenderTree/chromium/TestShellMac.mm145
-rw-r--r--Tools/DumpRenderTree/chromium/TestShellWin.cpp244
-rw-r--r--Tools/DumpRenderTree/chromium/TestWebWorker.h93
-rw-r--r--Tools/DumpRenderTree/chromium/TextInputController.cpp262
-rw-r--r--Tools/DumpRenderTree/chromium/TextInputController.h74
-rw-r--r--Tools/DumpRenderTree/chromium/WebPreferences.cpp166
-rw-r--r--Tools/DumpRenderTree/chromium/WebPreferences.h88
-rwxr-xr-xTools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp523
-rw-r--r--Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h203
-rwxr-xr-xTools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp758
-rw-r--r--Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h97
-rw-r--r--Tools/DumpRenderTree/chromium/WebViewHost.cpp1519
-rw-r--r--Tools/DumpRenderTree/chromium/WebViewHost.h332
-rw-r--r--Tools/DumpRenderTree/chromium/config.h56
-rw-r--r--Tools/DumpRenderTree/chromium/fonts.conf155
-rw-r--r--Tools/DumpRenderTree/config.h80
-rw-r--r--Tools/DumpRenderTree/fonts/ColorBits-A.pngbin0 -> 585 bytes
-rw-r--r--Tools/DumpRenderTree/fonts/ColorBits.ttfbin0 -> 1028 bytes
-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/AccessibilityControllerGtk.cpp90
-rw-r--r--Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp739
-rw-r--r--Tools/DumpRenderTree/gtk/DumpRenderTree.cpp1112
-rw-r--r--Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h45
-rw-r--r--Tools/DumpRenderTree/gtk/EditingCallbacks.cpp206
-rw-r--r--Tools/DumpRenderTree/gtk/EditingCallbacks.h35
-rw-r--r--Tools/DumpRenderTree/gtk/EventSender.cpp764
-rw-r--r--Tools/DumpRenderTree/gtk/EventSender.h42
-rw-r--r--Tools/DumpRenderTree/gtk/GCControllerGtk.cpp50
-rw-r--r--Tools/DumpRenderTree/gtk/ImageDiff.cpp239
-rw-r--r--Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp842
-rw-r--r--Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp59
-rw-r--r--Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp96
-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.conf405
-rw-r--r--Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm81
-rw-r--r--Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm81
-rw-r--r--Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm1341
-rw-r--r--Tools/DumpRenderTree/mac/AppleScriptController.h39
-rw-r--r--Tools/DumpRenderTree/mac/AppleScriptController.m127
-rw-r--r--Tools/DumpRenderTree/mac/CheckedMalloc.cpp72
-rw-r--r--Tools/DumpRenderTree/mac/CheckedMalloc.h31
-rw-r--r--Tools/DumpRenderTree/mac/Configurations/Base.xcconfig69
-rw-r--r--Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig40
-rw-r--r--Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig27
-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.mm1188
-rw-r--r--Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h53
-rw-r--r--Tools/DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm146
-rw-r--r--Tools/DumpRenderTree/mac/DumpRenderTreeMac.h68
-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.mm868
-rw-r--r--Tools/DumpRenderTree/mac/FrameLoadDelegate.h42
-rw-r--r--Tools/DumpRenderTree/mac/FrameLoadDelegate.mm400
-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.mm1005
-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.m285
-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/Makefile74
-rw-r--r--Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm279
-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.mm245
-rw-r--r--Tools/DumpRenderTree/mac/TextInputController.h42
-rw-r--r--Tools/DumpRenderTree/mac/TextInputController.m431
-rw-r--r--Tools/DumpRenderTree/mac/UIDelegate.h41
-rw-r--r--Tools/DumpRenderTree/mac/UIDelegate.mm263
-rw-r--r--Tools/DumpRenderTree/mac/WebArchiveDumpSupportMac.mm76
-rw-r--r--Tools/DumpRenderTree/mac/WorkQueueItemMac.mm91
-rw-r--r--Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp138
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTree.pro53
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp1151
-rw-r--r--Tools/DumpRenderTree/qt/DumpRenderTreeQt.h232
-rw-r--r--Tools/DumpRenderTree/qt/EventSenderQt.cpp653
-rw-r--r--Tools/DumpRenderTree/qt/EventSenderQt.h112
-rw-r--r--Tools/DumpRenderTree/qt/GCControllerQt.cpp54
-rw-r--r--Tools/DumpRenderTree/qt/GCControllerQt.h50
-rw-r--r--Tools/DumpRenderTree/qt/ImageDiff.cpp149
-rw-r--r--Tools/DumpRenderTree/qt/ImageDiff.pro16
-rw-r--r--Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp834
-rw-r--r--Tools/DumpRenderTree/qt/LayoutTestControllerQt.h289
-rw-r--r--Tools/DumpRenderTree/qt/PlainTextControllerQt.cpp44
-rw-r--r--Tools/DumpRenderTree/qt/PlainTextControllerQt.h47
-rw-r--r--Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro46
-rw-r--r--Tools/DumpRenderTree/qt/TextInputControllerQt.cpp158
-rw-r--r--Tools/DumpRenderTree/qt/TextInputControllerQt.h57
-rw-r--r--Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp106
-rw-r--r--Tools/DumpRenderTree/qt/WorkQueueItemQt.h159
-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.cpp173
-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/unix/TestNetscapePlugin/TestNetscapePlugin.cpp434
-rw-r--r--Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp295
-rw-r--r--Tools/DumpRenderTree/win/AccessibilityUIElementWin.cpp681
-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.cpp1392
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTree.vcproj720
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeApple.vsprops15
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeCFLite.vsprops11
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeCairo.vsprops12
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeCommon.vsprops20
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreePostBuild.cmd40
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreePreBuild.cmd18
-rw-r--r--Tools/DumpRenderTree/win/DumpRenderTreeWin.h69
-rw-r--r--Tools/DumpRenderTree/win/EditingDelegate.cpp424
-rw-r--r--Tools/DumpRenderTree/win/EditingDelegate.h176
-rw-r--r--Tools/DumpRenderTree/win/EventSender.cpp691
-rw-r--r--Tools/DumpRenderTree/win/EventSender.h43
-rw-r--r--Tools/DumpRenderTree/win/FrameLoadDelegate.cpp420
-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.vcproj395
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffCommon.vsprops17
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffPostBuild.cmd1
-rw-r--r--Tools/DumpRenderTree/win/ImageDiffPreBuild.cmd6
-rw-r--r--Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp1432
-rw-r--r--Tools/DumpRenderTree/win/MD5.cpp78
-rw-r--r--Tools/DumpRenderTree/win/MD5.h45
-rw-r--r--Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp85
-rw-r--r--Tools/DumpRenderTree/win/PolicyDelegate.cpp187
-rw-r--r--Tools/DumpRenderTree/win/PolicyDelegate.h82
-rw-r--r--Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp379
-rw-r--r--Tools/DumpRenderTree/win/ResourceLoadDelegate.h119
-rwxr-xr-xTools/DumpRenderTree/win/UIDelegate.cpp662
-rwxr-xr-xTools/DumpRenderTree/win/UIDelegate.h415
-rw-r--r--Tools/DumpRenderTree/win/WorkQueueItemWin.cpp158
-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.cpp546
-rw-r--r--Tools/DumpRenderTree/wx/WorkQueueItemWx.cpp57
-rw-r--r--Tools/EWSTools/boot.sh30
-rwxr-xr-xTools/EWSTools/create-webkit-git42
-rw-r--r--Tools/EWSTools/screen-config4
-rwxr-xr-xTools/EWSTools/start-queue.sh55
-rw-r--r--Tools/EWSTools/ubuntu-ews-packages61
-rw-r--r--Tools/EWebLauncher/main.c903
-rw-r--r--Tools/FindSafari/FindSafari.cpp169
-rw-r--r--Tools/FindSafari/FindSafari.rc70
-rw-r--r--Tools/FindSafari/FindSafari.vcproj420
-rw-r--r--Tools/FindSafari/FindSafariCommon.vsprops13
-rw-r--r--Tools/FindSafari/Safari.exe.manifest129
-rw-r--r--Tools/FindSafari/resource.h16
-rw-r--r--Tools/GNUmakefile.am192
-rw-r--r--Tools/GtkLauncher/main.c255
-rw-r--r--Tools/GtkLauncher/simple.svg15
-rw-r--r--Tools/GtkLauncher/text.html9
-rw-r--r--Tools/MIDLWrapper/MIDLWrapper.cpp86
-rw-r--r--Tools/MIDLWrapper/MIDLWrapper.sln20
-rw-r--r--Tools/MIDLWrapper/MIDLWrapper.vcproj199
-rw-r--r--Tools/Makefile17
-rw-r--r--Tools/MiniBrowser/Configurations/Base.xcconfig66
-rw-r--r--Tools/MiniBrowser/Configurations/DebugRelease.xcconfig40
-rw-r--r--Tools/MiniBrowser/Configurations/MiniBrowser.xcconfig26
-rw-r--r--Tools/MiniBrowser/Configurations/MiniBrowserCFLite.vsprops11
-rw-r--r--Tools/MiniBrowser/Configurations/MiniBrowserCommon.vsprops12
-rw-r--r--Tools/MiniBrowser/Configurations/MiniBrowserCoreFoundation.vsprops11
-rw-r--r--Tools/MiniBrowser/Configurations/WebBundle.xcconfig26
-rw-r--r--Tools/MiniBrowser/DerivedSources.pro32
-rw-r--r--Tools/MiniBrowser/MBToolbarItem.h28
-rw-r--r--Tools/MiniBrowser/MBToolbarItem.m35
-rw-r--r--Tools/MiniBrowser/Makefile21
-rw-r--r--Tools/MiniBrowser/MiniBrowser.qrc5
-rw-r--r--Tools/MiniBrowser/MiniBrowser.vcproj508
-rw-r--r--Tools/MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj421
-rw-r--r--Tools/MiniBrowser/MiniBrowserPostBuild.cmd33
-rw-r--r--Tools/MiniBrowser/MiniBrowserPreBuild.cmd5
-rw-r--r--Tools/MiniBrowser/mac/AppDelegate.h44
-rw-r--r--Tools/MiniBrowser/mac/AppDelegate.m266
-rw-r--r--Tools/MiniBrowser/mac/BrowserStatisticsWindow.xib974
-rw-r--r--Tools/MiniBrowser/mac/BrowserStatisticsWindowController.h20
-rw-r--r--Tools/MiniBrowser/mac/BrowserStatisticsWindowController.m47
-rw-r--r--Tools/MiniBrowser/mac/BrowserWindow.xib1558
-rw-r--r--Tools/MiniBrowser/mac/BrowserWindowController.h67
-rw-r--r--Tools/MiniBrowser/mac/BrowserWindowController.m740
-rw-r--r--Tools/MiniBrowser/mac/Info.plist32
-rw-r--r--Tools/MiniBrowser/mac/MainMenu.xib3623
-rw-r--r--Tools/MiniBrowser/mac/MiniBrowser_Prefix.pch38
-rw-r--r--Tools/MiniBrowser/mac/WebBundle/Info.plist22
-rw-r--r--Tools/MiniBrowser/mac/WebBundle/WebBundleMain.m104
-rw-r--r--Tools/MiniBrowser/mac/main.m31
-rwxr-xr-xTools/MiniBrowser/mac/make-launchable.sh27
-rw-r--r--Tools/MiniBrowser/qt/BrowserView.cpp71
-rw-r--r--Tools/MiniBrowser/qt/BrowserView.h54
-rw-r--r--Tools/MiniBrowser/qt/BrowserWindow.cpp181
-rw-r--r--Tools/MiniBrowser/qt/BrowserWindow.h66
-rw-r--r--Tools/MiniBrowser/qt/MiniBrowser.pro58
-rw-r--r--Tools/MiniBrowser/qt/main.cpp65
-rw-r--r--Tools/MiniBrowser/win/BrowserView.cpp145
-rw-r--r--Tools/MiniBrowser/win/BrowserView.h49
-rw-r--r--Tools/MiniBrowser/win/BrowserWindow.cpp261
-rw-r--r--Tools/MiniBrowser/win/BrowserWindow.h70
-rw-r--r--Tools/MiniBrowser/win/MiniBrowser.cpp84
-rw-r--r--Tools/MiniBrowser/win/MiniBrowser.h55
-rw-r--r--Tools/MiniBrowser/win/MiniBrowser.rc79
-rw-r--r--Tools/MiniBrowser/win/main.cpp62
-rw-r--r--Tools/MiniBrowser/win/resource.h23
-rw-r--r--Tools/MiniBrowser/win/stdafx.cpp33
-rw-r--r--Tools/MiniBrowser/win/stdafx.h33
-rw-r--r--Tools/QtTestBrowser/QtTestBrowser.pro61
-rw-r--r--Tools/QtTestBrowser/QtTestBrowser.qrc5
-rw-r--r--Tools/QtTestBrowser/fpstimer.cpp80
-rw-r--r--Tools/QtTestBrowser/fpstimer.h54
-rw-r--r--Tools/QtTestBrowser/launcherwindow.cpp872
-rw-r--r--Tools/QtTestBrowser/launcherwindow.h209
-rw-r--r--Tools/QtTestBrowser/locationedit.cpp80
-rw-r--r--Tools/QtTestBrowser/locationedit.h54
-rw-r--r--Tools/QtTestBrowser/main.cpp258
-rw-r--r--Tools/QtTestBrowser/mainwindow.cpp197
-rw-r--r--Tools/QtTestBrowser/mainwindow.h72
-rw-r--r--Tools/QtTestBrowser/urlloader.cpp130
-rw-r--r--Tools/QtTestBrowser/urlloader.h71
-rw-r--r--Tools/QtTestBrowser/useragentlist.txt10
-rw-r--r--Tools/QtTestBrowser/utils.cpp88
-rw-r--r--Tools/QtTestBrowser/utils.h52
-rw-r--r--Tools/QtTestBrowser/webinspector.h56
-rw-r--r--Tools/QtTestBrowser/webpage.cpp224
-rw-r--r--Tools/QtTestBrowser/webpage.h105
-rw-r--r--Tools/QtTestBrowser/webview.cpp273
-rw-r--r--Tools/QtTestBrowser/webview.h129
-rw-r--r--Tools/QueueStatusServer/__init__.py29
-rw-r--r--Tools/QueueStatusServer/app.yaml15
-rw-r--r--Tools/QueueStatusServer/cron.yaml4
-rw-r--r--Tools/QueueStatusServer/filters/__init__.py1
-rw-r--r--Tools/QueueStatusServer/filters/webkit_extras.py59
-rw-r--r--Tools/QueueStatusServer/handlers/__init__.py3
-rw-r--r--Tools/QueueStatusServer/handlers/dashboard.py64
-rw-r--r--Tools/QueueStatusServer/handlers/gc.py44
-rw-r--r--Tools/QueueStatusServer/handlers/nextpatch.py59
-rw-r--r--Tools/QueueStatusServer/handlers/patch.py53
-rw-r--r--Tools/QueueStatusServer/handlers/patchstatus.py40
-rw-r--r--Tools/QueueStatusServer/handlers/queuestatus.py72
-rw-r--r--Tools/QueueStatusServer/handlers/queuestatus_unittest.py62
-rw-r--r--Tools/QueueStatusServer/handlers/recentstatus.py94
-rw-r--r--Tools/QueueStatusServer/handlers/releasepatch.py62
-rw-r--r--Tools/QueueStatusServer/handlers/showresults.py41
-rw-r--r--Tools/QueueStatusServer/handlers/statusbubble.py59
-rw-r--r--Tools/QueueStatusServer/handlers/statusbubble_unittest.py62
-rw-r--r--Tools/QueueStatusServer/handlers/submittoews.py64
-rw-r--r--Tools/QueueStatusServer/handlers/svnrevision.py40
-rw-r--r--Tools/QueueStatusServer/handlers/updatebase.py41
-rw-r--r--Tools/QueueStatusServer/handlers/updatestatus.py66
-rw-r--r--Tools/QueueStatusServer/handlers/updatesvnrevision.py53
-rw-r--r--Tools/QueueStatusServer/handlers/updateworkitems.py66
-rw-r--r--Tools/QueueStatusServer/index.yaml41
-rw-r--r--Tools/QueueStatusServer/main.py79
-rw-r--r--Tools/QueueStatusServer/model/__init__.py3
-rw-r--r--Tools/QueueStatusServer/model/activeworkitems.py89
-rw-r--r--Tools/QueueStatusServer/model/activeworkitems_unitest.py52
-rw-r--r--Tools/QueueStatusServer/model/attachment.py133
-rw-r--r--Tools/QueueStatusServer/model/queuepropertymixin.py39
-rw-r--r--Tools/QueueStatusServer/model/queuepropertymixin_unittest.py52
-rw-r--r--Tools/QueueStatusServer/model/queues.py113
-rw-r--r--Tools/QueueStatusServer/model/queues_unittest.py80
-rw-r--r--Tools/QueueStatusServer/model/queuestatus.py44
-rw-r--r--Tools/QueueStatusServer/model/svnrevision.py35
-rw-r--r--Tools/QueueStatusServer/model/workitems.py69
-rw-r--r--Tools/QueueStatusServer/model/workitems_unittest.py45
-rw-r--r--Tools/QueueStatusServer/stylesheets/dashboard.css103
-rw-r--r--Tools/QueueStatusServer/stylesheets/main.css26
-rw-r--r--Tools/QueueStatusServer/templates/dashboard.html44
-rw-r--r--Tools/QueueStatusServer/templates/includes/singlequeuestatus.html9
-rw-r--r--Tools/QueueStatusServer/templates/patch.html21
-rw-r--r--Tools/QueueStatusServer/templates/queuestatus.html62
-rw-r--r--Tools/QueueStatusServer/templates/recentstatus.html54
-rw-r--r--Tools/QueueStatusServer/templates/releasepatch.html3
-rw-r--r--Tools/QueueStatusServer/templates/statusbubble.html77
-rw-r--r--Tools/QueueStatusServer/templates/submittoews.html3
-rw-r--r--Tools/QueueStatusServer/templates/updatestatus.html21
-rw-r--r--Tools/QueueStatusServer/templates/updatesvnrevision.html8
-rw-r--r--Tools/QueueStatusServer/templates/updateworkitems.html8
-rw-r--r--Tools/Scripts/SpacingHeuristics.pm101
-rw-r--r--Tools/Scripts/VCSUtils.pm1768
-rwxr-xr-xTools/Scripts/add-include135
-rwxr-xr-xTools/Scripts/bisect-builds432
-rwxr-xr-xTools/Scripts/build-api-tests70
-rwxr-xr-xTools/Scripts/build-dumprendertree80
-rwxr-xr-xTools/Scripts/build-jsc76
-rwxr-xr-xTools/Scripts/build-webkit589
-rwxr-xr-xTools/Scripts/build-webkittestrunner73
-rwxr-xr-xTools/Scripts/check-Xcode-source-file-types168
-rwxr-xr-xTools/Scripts/check-dom-results141
-rwxr-xr-xTools/Scripts/check-for-exit-time-destructors151
-rwxr-xr-xTools/Scripts/check-for-global-initializers161
-rwxr-xr-xTools/Scripts/check-for-inappropriate-files-in-framework68
-rwxr-xr-xTools/Scripts/check-for-weak-vtables-and-externals120
-rwxr-xr-xTools/Scripts/check-for-webkit-framework-include-consistency111
-rwxr-xr-xTools/Scripts/check-webkit-style134
-rwxr-xr-xTools/Scripts/clean-header-guards53
-rwxr-xr-xTools/Scripts/commit-log-editor325
-rwxr-xr-xTools/Scripts/compare-timing-files88
-rwxr-xr-xTools/Scripts/create-exports5
-rwxr-xr-xTools/Scripts/debug-minibrowser38
-rwxr-xr-xTools/Scripts/debug-safari38
-rwxr-xr-xTools/Scripts/debug-test-runner35
-rwxr-xr-xTools/Scripts/deduplicate-tests84
-rwxr-xr-xTools/Scripts/detect-mismatched-virtual-const167
-rwxr-xr-xTools/Scripts/do-file-rename117
-rwxr-xr-xTools/Scripts/do-webcore-rename247
-rwxr-xr-xTools/Scripts/ensure-valid-python152
-rwxr-xr-xTools/Scripts/execAppWithEnv38
-rwxr-xr-xTools/Scripts/extract-localizable-strings390
-rwxr-xr-xTools/Scripts/find-extra-includes102
-rwxr-xr-xTools/Scripts/find-included-framework-headers30
-rwxr-xr-xTools/Scripts/gdb-safari53
-rwxr-xr-xTools/Scripts/generate-coverage-data71
-rwxr-xr-xTools/Scripts/generate-qt-inspector-resource53
-rwxr-xr-xTools/Scripts/make-script-test-wrappers141
-rwxr-xr-xTools/Scripts/new-run-webkit-httpd97
-rwxr-xr-xTools/Scripts/new-run-webkit-tests41
-rw-r--r--Tools/Scripts/new-run-webkit-websocketserver108
-rwxr-xr-xTools/Scripts/num-cpus6
-rwxr-xr-xTools/Scripts/old-run-webkit-tests2481
-rwxr-xr-xTools/Scripts/parallelcl224
-rwxr-xr-xTools/Scripts/parse-malloc-history174
-rwxr-xr-xTools/Scripts/pdevenv45
-rwxr-xr-xTools/Scripts/prepare-ChangeLog1723
-rwxr-xr-xTools/Scripts/print-msvc-project-dependencies143
-rwxr-xr-xTools/Scripts/print-vse-failure-logs113
-rwxr-xr-xTools/Scripts/rebaseline-chromium-webkit-tests44
-rwxr-xr-xTools/Scripts/report-include-statistics114
-rwxr-xr-xTools/Scripts/resolve-ChangeLogs488
-rwxr-xr-xTools/Scripts/roll-over-ChangeLogs47
-rwxr-xr-xTools/Scripts/run-api-tests246
-rwxr-xr-xTools/Scripts/run-bindings-tests137
-rwxr-xr-xTools/Scripts/run-chromium-webkit-unit-tests51
-rw-r--r--Tools/Scripts/run-gtk-tests35
-rwxr-xr-xTools/Scripts/run-iexploder-tests143
-rwxr-xr-xTools/Scripts/run-javascriptcore-tests191
-rwxr-xr-xTools/Scripts/run-jsc59
-rwxr-xr-xTools/Scripts/run-launcher84
-rwxr-xr-xTools/Scripts/run-leaks221
-rwxr-xr-xTools/Scripts/run-mangleme-tests176
-rwxr-xr-xTools/Scripts/run-minibrowser38
-rwxr-xr-xTools/Scripts/run-pageloadtest92
-rw-r--r--Tools/Scripts/run-qtwebkit-tests358
-rwxr-xr-xTools/Scripts/run-safari41
-rwxr-xr-xTools/Scripts/run-sunspider129
-rwxr-xr-xTools/Scripts/run-test-runner35
-rwxr-xr-xTools/Scripts/run-test-webkit-api38
-rwxr-xr-xTools/Scripts/run-webkit-app50
-rwxr-xr-xTools/Scripts/run-webkit-httpd96
-rwxr-xr-xTools/Scripts/run-webkit-nightly.cmd10
-rwxr-xr-xTools/Scripts/run-webkit-tests84
-rwxr-xr-xTools/Scripts/run-webkit-websocketserver88
-rwxr-xr-xTools/Scripts/set-webkit-configuration79
-rwxr-xr-xTools/Scripts/sort-Xcode-project-file172
-rwxr-xr-xTools/Scripts/split-file-by-class159
-rwxr-xr-xTools/Scripts/sunspider-compare-results133
-rwxr-xr-xTools/Scripts/svn-apply454
-rwxr-xr-xTools/Scripts/svn-create-patch431
-rwxr-xr-xTools/Scripts/svn-unapply280
-rwxr-xr-xTools/Scripts/test-webkit-scripts85
-rwxr-xr-xTools/Scripts/test-webkitperl59
-rwxr-xr-xTools/Scripts/test-webkitpy266
-rwxr-xr-xTools/Scripts/update-iexploder-cssproperties129
-rwxr-xr-xTools/Scripts/update-javascriptcore-test-results73
-rwxr-xr-xTools/Scripts/update-sources-list.py93
-rwxr-xr-xTools/Scripts/update-webgl-conformance-tests36
-rwxr-xr-xTools/Scripts/update-webkit133
-rwxr-xr-xTools/Scripts/update-webkit-auxiliary-libs134
-rwxr-xr-xTools/Scripts/update-webkit-chromium68
-rwxr-xr-xTools/Scripts/update-webkit-localizable-strings46
-rwxr-xr-xTools/Scripts/update-webkit-support-libs148
-rwxr-xr-xTools/Scripts/validate-committer-lists260
-rwxr-xr-xTools/Scripts/webkit-build-directory69
-rwxr-xr-xTools/Scripts/webkit-patch70
-rw-r--r--Tools/Scripts/webkit-tools-completion.sh95
-rw-r--r--Tools/Scripts/webkitdirs.pm1872
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/fixChangeLogPatch.pl533
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/generatePatchCommand.pl87
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/mergeChangeLogs.pl336
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl1208
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl121
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/parseGitDiffHeader.pl494
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/parsePatch.pl94
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl397
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffHeader.pl220
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnProperty.pl743
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl233
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/prepareParsedPatch.pl136
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/removeEOL.pl56
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/runPatchCommand.pl92
-rw-r--r--Tools/Scripts/webkitperl/VCSUtils_unittest/setChangeLogDateAndReviewer.pl128
-rw-r--r--Tools/Scripts/webkitperl/features.pm105
-rw-r--r--Tools/Scripts/webkitperl/httpd.pm321
-rw-r--r--Tools/Scripts/webkitpy/__init__.py13
-rw-r--r--Tools/Scripts/webkitpy/common/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/common/array_stream.py66
-rw-r--r--Tools/Scripts/webkitpy/common/array_stream_unittest.py78
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/__init__.py3
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/api.py164
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/api_unittest.py196
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/changelog.py191
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py230
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/commitinfo.py93
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/commitinfo_unittest.py61
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/diff_parser.py181
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/diff_parser_unittest.py146
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/scm.py941
-rw-r--r--Tools/Scripts/webkitpy/common/checkout/scm_unittest.py1320
-rw-r--r--Tools/Scripts/webkitpy/common/config/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/common/config/build.py136
-rw-r--r--Tools/Scripts/webkitpy/common/config/build_unittest.py64
-rw-r--r--Tools/Scripts/webkitpy/common/config/committers.py335
-rw-r--r--Tools/Scripts/webkitpy/common/config/committers_unittest.py72
-rw-r--r--Tools/Scripts/webkitpy/common/config/committervalidator.py114
-rw-r--r--Tools/Scripts/webkitpy/common/config/committervalidator_unittest.py43
-rw-r--r--Tools/Scripts/webkitpy/common/config/irc.py31
-rw-r--r--Tools/Scripts/webkitpy/common/config/ports.py249
-rw-r--r--Tools/Scripts/webkitpy/common/config/ports_unittest.py76
-rw-r--r--Tools/Scripts/webkitpy/common/config/urls.py38
-rw-r--r--Tools/Scripts/webkitpy/common/memoized.py55
-rw-r--r--Tools/Scripts/webkitpy/common/memoized_unittest.py65
-rw-r--r--Tools/Scripts/webkitpy/common/net/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/common/net/bugzilla/__init__.py8
-rw-r--r--Tools/Scripts/webkitpy/common/net/bugzilla/attachment.py114
-rw-r--r--Tools/Scripts/webkitpy/common/net/bugzilla/bug.py111
-rw-r--r--Tools/Scripts/webkitpy/common/net/bugzilla/bug_unittest.py40
-rw-r--r--Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py761
-rw-r--r--Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py392
-rw-r--r--Tools/Scripts/webkitpy/common/net/buildbot/__init__.py5
-rw-r--r--Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py463
-rw-r--r--Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py413
-rw-r--r--Tools/Scripts/webkitpy/common/net/credentials.py155
-rw-r--r--Tools/Scripts/webkitpy/common/net/credentials_unittest.py176
-rw-r--r--Tools/Scripts/webkitpy/common/net/failuremap.py85
-rw-r--r--Tools/Scripts/webkitpy/common/net/failuremap_unittest.py76
-rw-r--r--Tools/Scripts/webkitpy/common/net/irc/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/common/net/irc/ircbot.py91
-rw-r--r--Tools/Scripts/webkitpy/common/net/irc/ircproxy.py62
-rw-r--r--Tools/Scripts/webkitpy/common/net/irc/ircproxy_unittest.py43
-rw-r--r--Tools/Scripts/webkitpy/common/net/layouttestresults.py92
-rw-r--r--Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py77
-rw-r--r--Tools/Scripts/webkitpy/common/net/networktransaction.py72
-rw-r--r--Tools/Scripts/webkitpy/common/net/networktransaction_unittest.py93
-rw-r--r--Tools/Scripts/webkitpy/common/net/regressionwindow.py52
-rw-r--r--Tools/Scripts/webkitpy/common/net/statusserver.py160
-rw-r--r--Tools/Scripts/webkitpy/common/net/statusserver_unittest.py43
-rw-r--r--Tools/Scripts/webkitpy/common/newstringio.py40
-rw-r--r--Tools/Scripts/webkitpy/common/newstringio_unittest.py46
-rw-r--r--Tools/Scripts/webkitpy/common/prettypatch.py67
-rw-r--r--Tools/Scripts/webkitpy/common/prettypatch_unittest.py70
-rw-r--r--Tools/Scripts/webkitpy/common/system/__init__.py1
-rwxr-xr-xTools/Scripts/webkitpy/common/system/autoinstall.py517
-rw-r--r--Tools/Scripts/webkitpy/common/system/deprecated_logging.py91
-rw-r--r--Tools/Scripts/webkitpy/common/system/deprecated_logging_unittest.py60
-rw-r--r--Tools/Scripts/webkitpy/common/system/executive.py399
-rw-r--r--Tools/Scripts/webkitpy/common/system/executive_mock.py59
-rw-r--r--Tools/Scripts/webkitpy/common/system/executive_unittest.py151
-rw-r--r--Tools/Scripts/webkitpy/common/system/file_lock.py83
-rw-r--r--Tools/Scripts/webkitpy/common/system/file_lock_unittest.py61
-rw-r--r--Tools/Scripts/webkitpy/common/system/filesystem.py154
-rw-r--r--Tools/Scripts/webkitpy/common/system/filesystem_mock.py109
-rw-r--r--Tools/Scripts/webkitpy/common/system/filesystem_unittest.py172
-rw-r--r--Tools/Scripts/webkitpy/common/system/fileutils.py33
-rw-r--r--Tools/Scripts/webkitpy/common/system/logtesting.py258
-rw-r--r--Tools/Scripts/webkitpy/common/system/logutils.py207
-rw-r--r--Tools/Scripts/webkitpy/common/system/logutils_unittest.py142
-rw-r--r--Tools/Scripts/webkitpy/common/system/ospath.py83
-rw-r--r--Tools/Scripts/webkitpy/common/system/ospath_unittest.py62
-rw-r--r--Tools/Scripts/webkitpy/common/system/outputcapture.py86
-rw-r--r--Tools/Scripts/webkitpy/common/system/path.py138
-rw-r--r--Tools/Scripts/webkitpy/common/system/path_unittest.py105
-rw-r--r--Tools/Scripts/webkitpy/common/system/platforminfo.py43
-rw-r--r--Tools/Scripts/webkitpy/common/system/user.py143
-rw-r--r--Tools/Scripts/webkitpy/common/system/user_unittest.py109
-rw-r--r--Tools/Scripts/webkitpy/common/thread/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/common/thread/messagepump.py59
-rw-r--r--Tools/Scripts/webkitpy/common/thread/messagepump_unittest.py83
-rw-r--r--Tools/Scripts/webkitpy/common/thread/threadedmessagequeue.py54
-rw-r--r--Tools/Scripts/webkitpy/common/thread/threadedmessagequeue_unittest.py53
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/deduplicate_tests.py231
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py210
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py569
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py212
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py598
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py220
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py197
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py183
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/metered_stream.py146
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/metered_stream_unittest.py115
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py553
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py608
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/result_summary.py89
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py868
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py350
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py282
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py84
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_input.py47
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_output.py56
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_results.py61
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_results_unittest.py52
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_results_uploader.py107
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py1218
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py102
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/__init__.py32
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/apache_http_server.py230
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/base.py862
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py315
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium.py546
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py152
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py73
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py190
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py182
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py40
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py193
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py173
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py74
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/config.py169
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/config_mock.py50
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/config_standalone.py70
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/config_unittest.py202
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/dryrun.py132
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/factory.py113
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/factory_unittest.py188
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py122
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py103
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/gtk.py116
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/http_lock.py133
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/http_lock_unittest.py111
-rwxr-xr-xTools/Scripts/webkitpy/layout_tests/port/http_server.py233
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/http_server_base.py83
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/httpd2.pem41
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/lighttpd.conf90
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/mac.py152
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py81
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py97
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/qt.py119
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/server_process.py225
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/test.py343
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/test_files.py128
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py75
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/webkit.py497
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py68
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/websocket_server.py257
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/port/win.py75
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py966
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py157
-rwxr-xr-xTools/Scripts/webkitpy/layout_tests/run_webkit_tests.py434
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py545
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/test_types/__init__.py0
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py146
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py223
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py47
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py93
-rwxr-xr-xTools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests.py160
-rw-r--r--Tools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests_unittest.py102
-rw-r--r--Tools/Scripts/webkitpy/python24/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/python24/versioning.py133
-rw-r--r--Tools/Scripts/webkitpy/python24/versioning_unittest.py134
-rw-r--r--Tools/Scripts/webkitpy/style/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/style/checker.py749
-rwxr-xr-xTools/Scripts/webkitpy/style/checker_unittest.py832
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/common.py74
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/common_unittest.py124
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/cpp.py3171
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py3998
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/python.py56
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/python_unittest.py62
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/python_unittest_input.py2
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/test_expectations.py120
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py173
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/text.py51
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/text_unittest.py94
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/xml.py45
-rw-r--r--Tools/Scripts/webkitpy/style/checkers/xml_unittest.py72
-rw-r--r--Tools/Scripts/webkitpy/style/error_handlers.py159
-rw-r--r--Tools/Scripts/webkitpy/style/error_handlers_unittest.py187
-rw-r--r--Tools/Scripts/webkitpy/style/filereader.py162
-rw-r--r--Tools/Scripts/webkitpy/style/filereader_unittest.py166
-rw-r--r--Tools/Scripts/webkitpy/style/filter.py278
-rw-r--r--Tools/Scripts/webkitpy/style/filter_unittest.py256
-rw-r--r--Tools/Scripts/webkitpy/style/main.py130
-rw-r--r--Tools/Scripts/webkitpy/style/main_unittest.py124
-rw-r--r--Tools/Scripts/webkitpy/style/optparser.py457
-rw-r--r--Tools/Scripts/webkitpy/style/optparser_unittest.py258
-rw-r--r--Tools/Scripts/webkitpy/style/patchreader.py66
-rw-r--r--Tools/Scripts/webkitpy/style/patchreader_unittest.py92
-rw-r--r--Tools/Scripts/webkitpy/style_references.py74
-rw-r--r--Tools/Scripts/webkitpy/test/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/test/cat.py42
-rw-r--r--Tools/Scripts/webkitpy/test/cat_unittest.py52
-rw-r--r--Tools/Scripts/webkitpy/test/echo.py52
-rw-r--r--Tools/Scripts/webkitpy/test/echo_unittest.py64
-rw-r--r--Tools/Scripts/webkitpy/test/main.py140
-rw-r--r--Tools/Scripts/webkitpy/test/skip.py52
-rw-r--r--Tools/Scripts/webkitpy/test/skip_unittest.py77
-rw-r--r--Tools/Scripts/webkitpy/thirdparty/BeautifulSoup.py2000
-rw-r--r--Tools/Scripts/webkitpy/thirdparty/__init__.py98
-rw-r--r--Tools/Scripts/webkitpy/thirdparty/mock.py309
-rw-r--r--Tools/Scripts/webkitpy/thirdparty/simplejson/LICENSE.txt19
-rw-r--r--Tools/Scripts/webkitpy/thirdparty/simplejson/README.txt11
-rw-r--r--Tools/Scripts/webkitpy/thirdparty/simplejson/__init__.py287
-rw-r--r--Tools/Scripts/webkitpy/thirdparty/simplejson/_speedups.c215
-rw-r--r--Tools/Scripts/webkitpy/thirdparty/simplejson/decoder.py273
-rw-r--r--Tools/Scripts/webkitpy/thirdparty/simplejson/encoder.py371
-rw-r--r--Tools/Scripts/webkitpy/thirdparty/simplejson/jsonfilter.py40
-rw-r--r--Tools/Scripts/webkitpy/thirdparty/simplejson/scanner.py63
-rw-r--r--Tools/Scripts/webkitpy/tool/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/__init__.py1
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py220
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py316
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/feeders.py90
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/feeders_unittest.py70
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/flakytestreporter.py181
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py145
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/irc_command.py109
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/irc_command_unittest.py38
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/queueengine.py165
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/queueengine_unittest.py209
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/sheriff.py91
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/sheriff_unittest.py90
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/sheriffircbot.py83
-rw-r--r--Tools/Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py95
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/__init__.py14
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/abstractsequencedcommand.py51
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/bugfortest.py48
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/bugsearch.py42
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/commandtest.py48
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html180
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js144
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css309
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js543
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js186
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/util.js104
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/download.py405
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/download_unittest.py206
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py182
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py132
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/openbugs.py63
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/openbugs_unittest.py50
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/prettydiff.py38
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/queries.py389
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/queries_unittest.py90
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/queues.py406
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/queues_unittest.py380
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/queuestest.py95
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/rebaseline.py112
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py38
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/rebaselineserver.py457
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/rebaselineserver_unittest.py304
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/sheriffbot.py106
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/sheriffbot_unittest.py57
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/stepsequence.py83
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/upload.py483
-rw-r--r--Tools/Scripts/webkitpy/tool/commands/upload_unittest.py122
-rwxr-xr-xTools/Scripts/webkitpy/tool/comments.py42
-rw-r--r--Tools/Scripts/webkitpy/tool/grammar.py54
-rw-r--r--Tools/Scripts/webkitpy/tool/grammar_unittest.py41
-rwxr-xr-xTools/Scripts/webkitpy/tool/main.py141
-rw-r--r--Tools/Scripts/webkitpy/tool/mocktool.py735
-rw-r--r--Tools/Scripts/webkitpy/tool/mocktool_unittest.py59
-rw-r--r--Tools/Scripts/webkitpy/tool/multicommandtool.py314
-rw-r--r--Tools/Scripts/webkitpy/tool/multicommandtool_unittest.py177
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/__init__.py59
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/abstractstep.py79
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/applypatch.py43
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/applypatchwithlocalcommit.py43
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/build.py54
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/checkstyle.py66
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/cleanworkingdirectory.py54
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/cleanworkingdirectory_unittest.py49
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/cleanworkingdirectorywithlocalcommits.py34
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/closebug.py51
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/closebugforlanddiff.py58
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/closebugforlanddiff_unittest.py40
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/closepatch.py36
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/commit.py81
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/confirmdiff.py77
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/createbug.py52
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/editchangelog.py38
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/ensurebuildersaregreen.py48
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/ensurelocalcommitifneeded.py43
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/metastep.py54
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/obsoletepatches.py51
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/options.py59
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/postdiff.py50
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/postdiffforcommit.py39
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/postdiffforrevert.py49
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/preparechangelog.py77
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/preparechangelog_unittest.py54
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py44
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/promptforbugortitle.py45
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/reopenbugafterrollout.py44
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/revertrevision.py35
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/runtests.py81
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/steps_unittest.py92
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/suggestreviewers.py51
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py45
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/update.py45
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittest.py48
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py72
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/validatereviewer.py71
-rw-r--r--Tools/Scripts/webkitpy/tool/steps/validatereviewer_unittest.py57
-rwxr-xr-xTools/Scripts/wkstyle89
-rw-r--r--Tools/TestResultServer/app.yaml19
-rw-r--r--Tools/TestResultServer/handlers/__init__.py1
-rw-r--r--Tools/TestResultServer/handlers/dashboardhandler.py123
-rw-r--r--Tools/TestResultServer/handlers/menu.py63
-rw-r--r--Tools/TestResultServer/handlers/testfilehandler.py230
-rw-r--r--Tools/TestResultServer/index.yaml65
-rw-r--r--Tools/TestResultServer/main.py58
-rw-r--r--Tools/TestResultServer/model/__init__.py1
-rw-r--r--Tools/TestResultServer/model/dashboardfile.py119
-rwxr-xr-xTools/TestResultServer/model/datastorefile.py150
-rwxr-xr-xTools/TestResultServer/model/jsonresults.py466
-rwxr-xr-xTools/TestResultServer/model/jsonresults_unittest.py322
-rw-r--r--Tools/TestResultServer/model/testfile.py127
-rw-r--r--Tools/TestResultServer/stylesheets/dashboardfile.css30
-rw-r--r--Tools/TestResultServer/stylesheets/form.css26
-rw-r--r--Tools/TestResultServer/stylesheets/menu.css28
-rw-r--r--Tools/TestResultServer/stylesheets/testfile.css30
-rw-r--r--Tools/TestResultServer/templates/dashboardfilelist.html38
-rw-r--r--Tools/TestResultServer/templates/menu.html27
-rw-r--r--Tools/TestResultServer/templates/showfilelist.html58
-rw-r--r--Tools/TestResultServer/templates/uploadform.html33
-rw-r--r--Tools/TestWebKitAPI/Configurations/Base.xcconfig72
-rw-r--r--Tools/TestWebKitAPI/Configurations/DebugRelease.xcconfig42
-rw-r--r--Tools/TestWebKitAPI/Configurations/InjectedBundle.xcconfig24
-rw-r--r--Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig26
-rw-r--r--Tools/TestWebKitAPI/Configurations/TestWebKitAPICFLite.vsprops11
-rw-r--r--Tools/TestWebKitAPI/Configurations/TestWebKitAPICommon.vsprops17
-rw-r--r--Tools/TestWebKitAPI/Configurations/TestWebKitAPICoreFoundation.vsprops11
-rw-r--r--Tools/TestWebKitAPI/InjectedBundle-Info.plist22
-rw-r--r--Tools/TestWebKitAPI/InjectedBundleController.cpp126
-rw-r--r--Tools/TestWebKitAPI/InjectedBundleController.h65
-rw-r--r--Tools/TestWebKitAPI/InjectedBundleMain.cpp37
-rw-r--r--Tools/TestWebKitAPI/InjectedBundleTest.h71
-rw-r--r--Tools/TestWebKitAPI/Makefile21
-rw-r--r--Tools/TestWebKitAPI/PlatformUtilities.cpp67
-rw-r--r--Tools/TestWebKitAPI/PlatformUtilities.h59
-rw-r--r--Tools/TestWebKitAPI/PlatformWebView.h85
-rw-r--r--Tools/TestWebKitAPI/Test.h86
-rw-r--r--Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj501
-rw-r--r--Tools/TestWebKitAPI/TestWebKitAPIPrefix.h41
-rw-r--r--Tools/TestWebKitAPI/Tests/WTF/VectorBasic.cpp40
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp66
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp58
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/EvaluateJavaScript.cpp60
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp68
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/Find.cpp81
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.cpp78
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.cpp78
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic.cpp79
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic_Bundle.cpp49
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp144
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp85
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/PreventEmptyUserAgent.cpp60
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp132
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp100
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp52
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/WKStringJSString.cpp52
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/file-with-anchor.html19
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/find.html5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/icon.pngbin0 -> 36541 bytes
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/simple.html5
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/spacebar-scrolling.html26
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/win/AltKeyGeneratesWMSysCommand.cpp86
-rw-r--r--Tools/TestWebKitAPI/Tests/WebKit2/win/WMCloseCallsUIClientClose.cpp57
-rw-r--r--Tools/TestWebKitAPI/TestsController.cpp82
-rw-r--r--Tools/TestWebKitAPI/TestsController.h61
-rw-r--r--Tools/TestWebKitAPI/mac/PlatformUtilitiesMac.mm66
-rw-r--r--Tools/TestWebKitAPI/mac/PlatformWebViewMac.mm97
-rw-r--r--Tools/TestWebKitAPI/mac/main.mm45
-rw-r--r--Tools/TestWebKitAPI/win/PlatformUtilitiesWin.cpp85
-rw-r--r--Tools/TestWebKitAPI/win/PlatformWebViewWin.cpp118
-rw-r--r--Tools/TestWebKitAPI/win/TestWebKitAPI.sln54
-rw-r--r--Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj535
-rw-r--r--Tools/TestWebKitAPI/win/TestWebKitAPIGenerated.vcproj82
-rw-r--r--Tools/TestWebKitAPI/win/TestWebKitAPIGeneratedCommon.vsprops13
-rw-r--r--Tools/TestWebKitAPI/win/TestWebKitAPIPostBuild.cmd1
-rw-r--r--Tools/TestWebKitAPI/win/TestWebKitAPIPreBuild.cmd6
-rw-r--r--Tools/TestWebKitAPI/win/WindowMessageObserver.h41
-rwxr-xr-xTools/TestWebKitAPI/win/copy-resources.cmd25
-rw-r--r--Tools/TestWebKitAPI/win/main.cpp39
-rw-r--r--Tools/WebKitAPITest/HostWindow.cpp83
-rw-r--r--Tools/WebKitAPITest/HostWindow.h51
-rw-r--r--Tools/WebKitAPITest/Test.h59
-rw-r--r--Tools/WebKitAPITest/TestsController.cpp147
-rw-r--r--Tools/WebKitAPITest/TestsController.h65
-rw-r--r--Tools/WebKitAPITest/WebKitAPITest.vcproj418
-rw-r--r--Tools/WebKitAPITest/WebKitAPITestCommon.vsprops21
-rw-r--r--Tools/WebKitAPITest/WebKitAPITestPostBuild.cmd1
-rw-r--r--Tools/WebKitAPITest/WebKitAPITestPreBuild.cmd6
-rw-r--r--Tools/WebKitAPITest/main.cpp35
-rw-r--r--Tools/WebKitAPITest/tests/WebViewDestruction.cpp230
-rw-r--r--Tools/WebKitLauncher/Configurations/Base.xcconfig39
-rw-r--r--Tools/WebKitLauncher/Configurations/WebKitLauncher.xcconfig27
-rw-r--r--Tools/WebKitLauncher/Configurations/WebKitNightlyEnabler.xcconfig29
-rw-r--r--Tools/WebKitLauncher/Info.plist493
-rw-r--r--Tools/WebKitLauncher/VERSION1
-rw-r--r--Tools/WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj448
-rw-r--r--Tools/WebKitLauncher/WebKitLauncherURLProtocol.h33
-rw-r--r--Tools/WebKitLauncher/WebKitLauncherURLProtocol.m123
-rw-r--r--Tools/WebKitLauncher/WebKitNightlyEnabler.h31
-rw-r--r--Tools/WebKitLauncher/WebKitNightlyEnabler.m236
-rw-r--r--Tools/WebKitLauncher/WebKitNightlyEnablerSparkle.h30
-rw-r--r--Tools/WebKitLauncher/WebKitNightlyEnablerSparkle.m156
-rw-r--r--Tools/WebKitLauncher/main.m248
-rw-r--r--Tools/WebKitLauncher/nightly.webkit.org.public.pem20
-rw-r--r--Tools/WebKitLauncher/start.html33
-rw-r--r--Tools/WebKitLauncher/webkit.icnsbin0 -> 319035 bytes
-rw-r--r--Tools/WebKitLauncherWin/Resource.h19
-rw-r--r--Tools/WebKitLauncherWin/WebKitLauncherWin.cpp95
-rw-r--r--Tools/WebKitLauncherWin/WebKitLauncherWin.rc70
-rw-r--r--Tools/WebKitLauncherWin/WebKitLauncherWin.vcproj426
-rw-r--r--Tools/WebKitLauncherWin/WebKitLauncherWinCommon.vsprops12
-rw-r--r--Tools/WebKitLauncherWin/webkit.icobin0 -> 82726 bytes
-rw-r--r--Tools/WebKitTestRunner/Configurations/Base.xcconfig72
-rw-r--r--Tools/WebKitTestRunner/Configurations/DebugRelease.xcconfig42
-rw-r--r--Tools/WebKitTestRunner/Configurations/InjectedBundle.xcconfig24
-rw-r--r--Tools/WebKitTestRunner/Configurations/InjectedBundleCFLite.vsprops12
-rw-r--r--Tools/WebKitTestRunner/Configurations/InjectedBundleCommon.vsprops12
-rw-r--r--Tools/WebKitTestRunner/Configurations/InjectedBundleCoreFoundation.vsprops12
-rw-r--r--Tools/WebKitTestRunner/Configurations/WebKitTestRunner.xcconfig26
-rw-r--r--Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCFLite.vsprops11
-rw-r--r--Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCommon.vsprops20
-rw-r--r--Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCoreFoundation.vsprops11
-rw-r--r--Tools/WebKitTestRunner/DerivedSources.make51
-rw-r--r--Tools/WebKitTestRunner/DerivedSources.pro57
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle-Info.plist22
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/ActivateFonts.h35
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm530
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl43
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/GCController.idl34
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h47
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp79
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h57
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl81
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp136
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h63
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/GCController.cpp74
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/GCController.h54
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp188
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h104
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp37
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp901
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h130
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp307
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h152
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/mac/ActivateFonts.mm75
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/mac/LayoutTestControllerMac.mm59
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp83
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro77
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/qt/LayoutTestControllerQt.cpp74
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/win/ActivateFonts.cpp107
-rw-r--r--Tools/WebKitTestRunner/InjectedBundle/win/LayoutTestControllerWin.cpp61
-rw-r--r--Tools/WebKitTestRunner/Makefile21
-rw-r--r--Tools/WebKitTestRunner/PlatformWebView.h73
-rw-r--r--Tools/WebKitTestRunner/StringFunctions.h97
-rw-r--r--Tools/WebKitTestRunner/TestController.cpp408
-rw-r--r--Tools/WebKitTestRunner/TestController.h114
-rw-r--r--Tools/WebKitTestRunner/TestInvocation.cpp202
-rw-r--r--Tools/WebKitTestRunner/TestInvocation.h57
-rw-r--r--Tools/WebKitTestRunner/WebKitTestRunner.pro5
-rw-r--r--Tools/WebKitTestRunner/WebKitTestRunner.sln91
-rw-r--r--Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj582
-rw-r--r--Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h37
-rw-r--r--Tools/WebKitTestRunner/fonts/AHEM____.TTFbin0 -> 12480 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/ColorBits-A.pngbin0 -> 585 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/ColorBits.ttfbin0 -> 1028 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/WebKit Layout Tests 2.ttfbin0 -> 28812 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/WebKit Layout Tests.ttfbin0 -> 28780 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/WebKitWeightWatcher100.ttfbin0 -> 28512 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/WebKitWeightWatcher200.ttfbin0 -> 28512 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/WebKitWeightWatcher300.ttfbin0 -> 28492 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/WebKitWeightWatcher400.ttfbin0 -> 28440 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/WebKitWeightWatcher500.ttfbin0 -> 28424 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/WebKitWeightWatcher600.ttfbin0 -> 28460 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/WebKitWeightWatcher700.ttfbin0 -> 28384 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/WebKitWeightWatcher800.ttfbin0 -> 28492 bytes
-rw-r--r--Tools/WebKitTestRunner/fonts/WebKitWeightWatcher900.ttfbin0 -> 28492 bytes
-rw-r--r--Tools/WebKitTestRunner/mac/PlatformWebViewMac.mm83
-rw-r--r--Tools/WebKitTestRunner/mac/TestControllerMac.mm63
-rw-r--r--Tools/WebKitTestRunner/mac/main.mm37
-rw-r--r--Tools/WebKitTestRunner/qt/PlatformWebViewQt.cpp100
-rw-r--r--Tools/WebKitTestRunner/qt/TestControllerQt.cpp133
-rw-r--r--Tools/WebKitTestRunner/qt/WebKitTestRunner.pro71
-rw-r--r--Tools/WebKitTestRunner/qt/main.cpp69
-rw-r--r--Tools/WebKitTestRunner/win/InjectedBundle.vcproj492
-rwxr-xr-xTools/WebKitTestRunner/win/InjectedBundleGenerated.vcproj87
-rw-r--r--Tools/WebKitTestRunner/win/InjectedBundleGeneratedCommon.vsprops15
-rw-r--r--Tools/WebKitTestRunner/win/InjectedBundlePostBuild.cmd1
-rw-r--r--Tools/WebKitTestRunner/win/InjectedBundlePreBuild.cmd6
-rw-r--r--Tools/WebKitTestRunner/win/PlatformWebViewWin.cpp98
-rw-r--r--Tools/WebKitTestRunner/win/TestControllerWin.cpp155
-rw-r--r--Tools/WebKitTestRunner/win/WebKitTestRunner.vcproj432
-rw-r--r--Tools/WebKitTestRunner/win/WebKitTestRunnerPostBuild.cmd38
-rw-r--r--Tools/WebKitTestRunner/win/WebKitTestRunnerPreBuild.cmd6
-rw-r--r--Tools/WebKitTestRunner/win/build-generated-files.sh42
-rw-r--r--Tools/WebKitTestRunner/win/main.cpp35
-rw-r--r--Tools/WinCELauncher/main.cpp132
-rw-r--r--Tools/WinLauncher/PrintWebUIDelegate.cpp194
-rw-r--r--Tools/WinLauncher/PrintWebUIDelegate.h109
-rw-r--r--Tools/WinLauncher/WinLauncher.cpp500
-rw-r--r--Tools/WinLauncher/WinLauncher.h119
-rw-r--r--Tools/WinLauncher/WinLauncher.icobin0 -> 23558 bytes
-rw-r--r--Tools/WinLauncher/WinLauncher.rc137
-rw-r--r--Tools/WinLauncher/WinLauncher.vcproj498
-rw-r--r--Tools/WinLauncher/WinLauncherCommon.vsprops16
-rw-r--r--Tools/WinLauncher/WinLauncherPostBuild.cmd1
-rw-r--r--Tools/WinLauncher/WinLauncherPreBuild.cmd6
-rw-r--r--Tools/WinLauncher/resource.h28
-rw-r--r--Tools/WinLauncher/small.icobin0 -> 23558 bytes
-rw-r--r--Tools/WinLauncher/stdafx.cpp33
-rw-r--r--Tools/WinLauncher/stdafx.h69
-rw-r--r--Tools/android/flex-2.5.4a/COPYING38
-rw-r--r--Tools/android/flex-2.5.4a/FlexLexer.h186
-rw-r--r--Tools/android/flex-2.5.4a/INSTALL117
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Amiga/README.amiga72
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Amiga/SMakefile195
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Amiga/config.h25
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Amiga/libmain.ch8
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Amiga/libyywrap.ch8
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Amiga/parse.ych8
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Atari/Atari.patches911
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Borland.old/Borland-2.4419
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Borland.old/Turbo-C179
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Borland/Makefile163
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Borland/NOTES66
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Borland/config.h29
-rw-r--r--Tools/android/flex-2.5.4a/MISC/EBCDIC48
-rw-r--r--Tools/android/flex-2.5.4a/MISC/MSDOS/MSC70.make115
-rw-r--r--Tools/android/flex-2.5.4a/MISC/MSDOS/configur.bat6
-rw-r--r--Tools/android/flex-2.5.4a/MISC/MSDOS/djgpp.sed12
-rw-r--r--Tools/android/flex-2.5.4a/MISC/MVS/MVS.mail56
-rw-r--r--Tools/android/flex-2.5.4a/MISC/MVS/MVS.todo23
-rw-r--r--Tools/android/flex-2.5.4a/MISC/MVS/MVS.uudecode341
-rw-r--r--Tools/android/flex-2.5.4a/MISC/MVS/README44
-rw-r--r--Tools/android/flex-2.5.4a/MISC/MVS/diffs854
-rw-r--r--Tools/android/flex-2.5.4a/MISC/MVS/fixit.l138
-rw-r--r--Tools/android/flex-2.5.4a/MISC/MVS/initscan-mvs.c2672
-rw-r--r--Tools/android/flex-2.5.4a/MISC/MVS/unfixit.l141
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Macintosh/THINK_C_notes100
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Macintosh/alloca.c195
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Macintosh/alloca.h10
-rw-r--r--Tools/android/flex-2.5.4a/MISC/Macintosh/xmalloc.c69
-rw-r--r--Tools/android/flex-2.5.4a/MISC/NT/Makefile103
-rw-r--r--Tools/android/flex-2.5.4a/MISC/NT/config.h32
-rw-r--r--Tools/android/flex-2.5.4a/MISC/NeXT34
-rw-r--r--Tools/android/flex-2.5.4a/MISC/OS2/Makefile.os272
-rw-r--r--Tools/android/flex-2.5.4a/MISC/OS2/config.h28
-rw-r--r--Tools/android/flex-2.5.4a/MISC/README76
-rw-r--r--Tools/android/flex-2.5.4a/MISC/VMS/README.VMS83
-rw-r--r--Tools/android/flex-2.5.4a/MISC/VMS/build.com155
-rw-r--r--Tools/android/flex-2.5.4a/MISC/VMS/descrip.mms311
-rw-r--r--Tools/android/flex-2.5.4a/MISC/VMS/mkskel.tpu45
-rw-r--r--Tools/android/flex-2.5.4a/MISC/VMS/vms-code.c152
-rw-r--r--Tools/android/flex-2.5.4a/MISC/VMS/vms-conf.h32
-rw-r--r--Tools/android/flex-2.5.4a/MISC/alloca.c484
-rw-r--r--Tools/android/flex-2.5.4a/MISC/debflex.awk119
-rw-r--r--Tools/android/flex-2.5.4a/MISC/fastwc/README56
-rw-r--r--Tools/android/flex-2.5.4a/MISC/fastwc/mywc.c26
-rw-r--r--Tools/android/flex-2.5.4a/MISC/fastwc/wc1.l18
-rw-r--r--Tools/android/flex-2.5.4a/MISC/fastwc/wc2.l20
-rw-r--r--Tools/android/flex-2.5.4a/MISC/fastwc/wc3.l24
-rw-r--r--Tools/android/flex-2.5.4a/MISC/fastwc/wc4.l27
-rw-r--r--Tools/android/flex-2.5.4a/MISC/fastwc/wc5.l24
-rw-r--r--Tools/android/flex-2.5.4a/MISC/flex.man3696
-rw-r--r--Tools/android/flex-2.5.4a/MISC/parse.c1452
-rw-r--r--Tools/android/flex-2.5.4a/MISC/parse.h24
-rw-r--r--Tools/android/flex-2.5.4a/MISC/testxxLexer.l58
-rw-r--r--Tools/android/flex-2.5.4a/MISC/texinfo/flex.info2951
-rw-r--r--Tools/android/flex-2.5.4a/MISC/texinfo/flex.texi3448
-rw-r--r--Tools/android/flex-2.5.4a/Makefile.in262
-rw-r--r--Tools/android/flex-2.5.4a/NEWS1233
-rw-r--r--Tools/android/flex-2.5.4a/README60
-rw-r--r--Tools/android/flex-2.5.4a/ccl.c149
-rw-r--r--Tools/android/flex-2.5.4a/conf.in25
-rwxr-xr-xTools/android/flex-2.5.4a/configure1632
-rw-r--r--Tools/android/flex-2.5.4a/configure.in24
-rw-r--r--Tools/android/flex-2.5.4a/dfa.c1095
-rw-r--r--Tools/android/flex-2.5.4a/ecs.c225
-rw-r--r--Tools/android/flex-2.5.4a/flex.14060
-rw-r--r--Tools/android/flex-2.5.4a/flex.skl1541
-rw-r--r--Tools/android/flex-2.5.4a/flexdef.h1048
-rw-r--r--Tools/android/flex-2.5.4a/gen.c1625
-rw-r--r--Tools/android/flex-2.5.4a/initscan.c3697
-rwxr-xr-xTools/android/flex-2.5.4a/install.sh119
-rw-r--r--Tools/android/flex-2.5.4a/libmain.c15
-rw-r--r--Tools/android/flex-2.5.4a/libyywrap.c8
-rw-r--r--Tools/android/flex-2.5.4a/main.c1177
-rw-r--r--Tools/android/flex-2.5.4a/misc.c886
-rwxr-xr-xTools/android/flex-2.5.4a/mkinstalldirs35
-rwxr-xr-xTools/android/flex-2.5.4a/mkskel.sh16
-rw-r--r--Tools/android/flex-2.5.4a/nfa.c709
-rw-r--r--Tools/android/flex-2.5.4a/parse.y913
-rw-r--r--Tools/android/flex-2.5.4a/scan.l710
-rw-r--r--Tools/android/flex-2.5.4a/skel.c1548
-rw-r--r--Tools/android/flex-2.5.4a/sym.c262
-rw-r--r--Tools/android/flex-2.5.4a/tblcmp.c887
-rw-r--r--Tools/android/flex-2.5.4a/version.h1
-rw-r--r--Tools/android/flex-2.5.4a/yylex.c216
-rw-r--r--Tools/android/webkitmerge/Android.mk24
-rw-r--r--Tools/android/webkitmerge/webkitmerge.cpp1834
-rw-r--r--Tools/android/webkitmerge/webkitmerge.xcodeproj/project.pbxproj206
-rw-r--r--Tools/gdb/webcore.py32
-rw-r--r--Tools/gdb/webkit.py304
-rw-r--r--Tools/iExploder/htdocs/config.rb6
-rw-r--r--Tools/iExploder/htdocs/cssproperties.in426
-rw-r--r--Tools/iExploder/htdocs/cssvalues.in339
-rw-r--r--Tools/iExploder/htdocs/htmlattrs.in373
-rw-r--r--Tools/iExploder/htdocs/htmltags.in155
-rw-r--r--Tools/iExploder/htdocs/htmlvalues.in35
-rwxr-xr-xTools/iExploder/htdocs/iexploder.cgi45
-rw-r--r--Tools/iExploder/htdocs/iexploder.rb337
-rw-r--r--Tools/iExploder/htdocs/index.html34
-rwxr-xr-xTools/iExploder/htdocs/webserver.rb75
-rw-r--r--Tools/iExploder/iexploder-1.3.2/CHANGELOG.txt328
-rw-r--r--Tools/iExploder/iexploder-1.3.2/LICENSE.txt20
-rw-r--r--Tools/iExploder/iexploder-1.3.2/README.txt149
-rw-r--r--Tools/iExploder/iexploder-1.3.2/htdocs/config.rb6
-rw-r--r--Tools/iExploder/iexploder-1.3.2/htdocs/cssproperties.in426
-rw-r--r--Tools/iExploder/iexploder-1.3.2/htdocs/cssvalues.in339
-rw-r--r--Tools/iExploder/iexploder-1.3.2/htdocs/htmlattrs.in373
-rw-r--r--Tools/iExploder/iexploder-1.3.2/htdocs/htmltags.in155
-rw-r--r--Tools/iExploder/iexploder-1.3.2/htdocs/htmlvalues.in35
-rwxr-xr-xTools/iExploder/iexploder-1.3.2/htdocs/iexploder.cgi45
-rw-r--r--Tools/iExploder/iexploder-1.3.2/htdocs/iexploder.rb337
-rw-r--r--Tools/iExploder/iexploder-1.3.2/htdocs/index.html34
-rwxr-xr-xTools/iExploder/iexploder-1.3.2/htdocs/webserver.rb75
-rwxr-xr-xTools/iExploder/iexploder-1.3.2/tools/lasthit.rb53
-rwxr-xr-xTools/iExploder/iexploder-1.3.2/tools/osx_last_crash.rb48
-rwxr-xr-xTools/iExploder/iexploder-1.3.2/tools/showtest.rb43
-rw-r--r--Tools/iExploder/iexploder-1.7.2/ChangeLog.txt890
-rw-r--r--Tools/iExploder/iexploder-1.7.2/LICENSE.txt202
-rw-r--r--Tools/iExploder/iexploder-1.7.2/README.txt174
-rwxr-xr-xTools/iExploder/iexploder-1.7.2/src/browser_harness.rb389
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/config.yaml54
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-atrules/mozilla6
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-atrules/webkit14
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-properties/dillo98
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-properties/gtkhtml16
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-properties/internet_explorer629
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-properties/mozilla275
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-properties/webkit256
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-pseudo/mozilla60
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-pseudo/webkit101
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-values/dillo93
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-values/gtkhtml18
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-values/mozilla558
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-values/other20
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/css-values/webkit478
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/headers/dillo9
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/headers/gtkhtml0
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/headers/mozilla70
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/headers/webkit30
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-attrs/dillo51
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-attrs/gtkhtml64
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-attrs/internet_explorer618
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-attrs/mozilla694
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-attrs/other36
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-attrs/webkit284
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-tags/dillo73
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-tags/gtkhtml46
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-tags/mozilla119
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-tags/other8
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-tags/webkit133
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-values/dillo30
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-values/gtkhtml9
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-values/mozilla44
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-values/other16
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/html-values/webkit88
-rwxr-xr-xTools/iExploder/iexploder-1.7.2/src/iexploder.cgi48
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/iexploder.rb792
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/index.html105
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/media/blank.oggbin0 -> 3976 bytes
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/media/blank.sndbin0 -> 16044 bytes
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/media/blank.wavbin0 -> 80956 bytes
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/media/bug.bmpbin0 -> 65658 bytes
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/media/bug.gifbin0 -> 6371 bytes
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/media/bug.icobin0 -> 67646 bytes
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/media/bug.jngbin0 -> 9357 bytes
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/media/bug.jpgbin0 -> 6371 bytes
-rwxr-xr-xTools/iExploder/iexploder-1.7.2/src/media/bug.pngbin0 -> 18668 bytes
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/media/bug.svg16389
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/media/bug.tiffbin0 -> 20654 bytes
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/media/bug.xbm174
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/media/bug.xpm390
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/mime-types/dillo14
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/mime-types/mozilla122
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/mime-types/webkit157
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/protocols/dillo4
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/protocols/gtkhtml3
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/protocols/mozilla30
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/protocols/webkit16
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/scanner.rb154
-rw-r--r--Tools/iExploder/iexploder-1.7.2/src/version.rb1
-rwxr-xr-xTools/iExploder/iexploder-1.7.2/src/webserver.rb161
-rw-r--r--Tools/iExploder/iexploder-1.7.2/testcases/testcase-Linux_x86_64_rv2.0b6pre_Gecko-20100904_Firefox-4.0b6pre-TEST-8375-1_59.html47
-rw-r--r--Tools/iExploder/iexploder-1.7.2/testcases/testcase-Opera-9.80_Linux_x86_64_en_Presto-2.6.30_Version-10.61-16704-3_108,3.html6
-rw-r--r--Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Intel_Mac_OS_X_10_6_4_en-US_AppleWebKit-534.8_Chrome-7.0.529.0-TEST-611-3_36,9.html8
-rw-r--r--Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Intel_Mac_OS_X_10_6_4_en-US_AppleWebKit-534.8_hrome-7.0.529.0-TEST-55313622206-3_6,0.html11
-rw-r--r--Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.6_Chrome-7.0.503.1-TEST-120813-8_72,56,24,8,0.html6
-rw-r--r--Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.6_Chrome-7.0.503.1-TEST-121240-3_81,3.html11
-rw-r--r--Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-4800-5_80,65,15.html13
-rw-r--r--Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-TEST-23583190347-3_15,12.html14
-rwxr-xr-xTools/iExploder/iexploder-1.7.2/tools/lasthit.rb74
-rwxr-xr-xTools/iExploder/iexploder-1.7.2/tools/osx_last_crash.rb63
-rwxr-xr-xTools/iExploder/iexploder-1.7.2/tools/release_src.sh28
-rwxr-xr-xTools/iExploder/iexploder-1.7.2/tools/update_html_tags_from_sources.sh125
-rwxr-xr-xTools/iExploder/tools/lasthit.rb53
-rwxr-xr-xTools/iExploder/tools/osx_last_crash.rb48
-rwxr-xr-xTools/iExploder/tools/showtest.rb43
-rw-r--r--Tools/mangleme/LICENSE504
-rw-r--r--Tools/mangleme/Makefile16
-rw-r--r--Tools/mangleme/README20
-rw-r--r--Tools/mangleme/mangle.cgi.c122
-rw-r--r--Tools/mangleme/remangle.cgi.c125
-rw-r--r--Tools/mangleme/tags.h76
-rw-r--r--Tools/record-memory-win/main.cpp213
-rw-r--r--Tools/record-memory-win/record-memory-win-common.vsprops11
-rw-r--r--Tools/record-memory-win/record-memory-win.vcproj414
-rwxr-xr-xTools/vcbin/cl.exebin0 -> 6656 bytes
-rwxr-xr-xTools/vcbin/midl.exebin0 -> 7168 bytes
-rw-r--r--Tools/wx/browser/browser.cpp70
-rw-r--r--Tools/wx/browser/wscript55
-rw-r--r--Tools/wx/build/build_utils.py188
-rw-r--r--Tools/wx/build/settings.py407
-rw-r--r--Tools/wx/build/waf_extensions.py83
-rw-r--r--Tools/wx/build/wxpresets.py120
-rwxr-xr-xTools/wx/install-unix-extras200
-rw-r--r--Tools/wx/packaging/build-debian-installer.py36
-rw-r--r--Tools/wx/packaging/build-mac-installer.py158
-rw-r--r--Tools/wx/packaging/build-win-installer.py98
-rw-r--r--Tools/wx/packaging/debian/changelog1
-rw-r--r--Tools/wx/packaging/debian/compat1
-rw-r--r--Tools/wx/packaging/debian/control29
-rw-r--r--Tools/wx/packaging/debian/copyright18
-rw-r--r--Tools/wx/packaging/debian/python-webkitwx.install1
-rw-r--r--Tools/wx/packaging/debian/rules75
-rw-r--r--Tools/wx/packaging/wxWebKitInstaller.iss.in79
1360 files changed, 352056 insertions, 0 deletions
diff --git a/Tools/BuildSlaveSupport/build-launcher-app b/Tools/BuildSlaveSupport/build-launcher-app
new file mode 100755
index 0000000..117b008
--- /dev/null
+++ b/Tools/BuildSlaveSupport/build-launcher-app
@@ -0,0 +1,120 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+# Copyright (C) 2006 Mark Rowe <opendarwin.org@bdash.net.nz>. 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.
+
+# Creates the launcher WebKit.app with bundled frameworks.
+
+use strict;
+
+use FindBin;
+use lib "$FindBin::Bin/../Scripts";
+use webkitdirs;
+
+my @xcodeBuildArguments = XcodeOptions();
+my $nightlyLauncherTemplatePath = "$FindBin::Bin/../WebKitLauncher";
+my $nightlyLauncherStagingPath = productDir() . "/WebKit.app";
+
+sub buildNightlyLauncher
+{
+ chdir($nightlyLauncherTemplatePath);
+ system("xcodebuild", "clean", "-alltargets", @xcodeBuildArguments, @ARGV) == 0 or die "Failed cleaning WebKitLauncher project";
+ system("xcodebuild", @xcodeBuildArguments, @ARGV) == 0 or die "Failed building WebKitLauncher project";
+ chdirWebKit();
+}
+
+sub currentRevision
+{
+ my $sourceDir = sourceDir();
+ if (isSVNDirectory($sourceDir)) {
+ return currentSVNRevision();
+ } elsif (isGitDirectory($sourceDir)) {
+ my $gitLog = `cd $sourceDir && LC_ALL=C git log --grep='git-svn-id: ' -n 1 | grep git-svn-id:`;
+ (my $revision) = ($gitLog =~ m/ +git-svn-id: .+@(\d+) /g);
+ return $revision;
+ }
+}
+
+sub currentBranch
+{
+ my $sourceDir = sourceDir();
+ my ($url, $branch);
+ if (isSVNDirectory($sourceDir)) {
+ my $svnInfo = `LC_ALL=C svn info $sourceDir | grep URL:`;
+ ($url) = ($svnInfo =~ m/URL: (.+)/g);
+ } elsif (isGitDirectory($sourceDir)) {
+ my $gitLog = `cd $sourceDir && LC_ALL=C git log --grep='git-svn-id: ' -n 1 | grep git-svn-id:`;
+ ($url) = ($gitLog =~ m/ +git-svn-id: (.+)@\d+ /g);
+ }
+ ($branch) = ($url =~ m/\/webkit\/(trunk|branches\/[^\/]+)/);
+ die "Unable to determine current SVN branch in $sourceDir" unless (defined $branch);
+ $branch =~ s/^branches\///;
+ return $branch;
+}
+
+sub copyNightlyLauncher
+{
+ my $revision = currentRevision();
+ my $branch = currentBranch();
+
+ my $infoPlist = "$nightlyLauncherStagingPath/Contents/Info.plist";
+ my $versionFile = "$nightlyLauncherStagingPath/Contents/Resources/VERSION";
+ my $branchFile = "$nightlyLauncherStagingPath/Contents/Resources/BRANCH";
+ my $data;
+ open(IN, $infoPlist) or die "Couldn't open Info.plist in built application for reading";
+ {
+ undef $/;
+ $data = <IN>;
+ }
+ close(IN);
+ open(OUT, ">$infoPlist") or die "Couldn't open Info.plist in built application for writing";
+ $data =~ s/VERSION/$revision/g;
+ print OUT $data;
+ close(OUT);
+
+ open(OUT, ">$versionFile") or die "Couldn't open VERSION in built application for writing";
+ print OUT "$revision\n";
+ close(OUT);
+
+ open(OUT, ">$branchFile") or die "Couldn't open BRANCH in built application for writing";
+ print OUT "$branch\n";
+ close(OUT);
+
+ my @frameworks = ("JavaScriptCore", "JavaScriptGlue", "WebCore", "WebKit");
+ for my $framework (@frameworks) {
+ system("ditto", productDir() . "/$framework.framework", "$nightlyLauncherStagingPath/Contents/Resources/$framework.framework") == 0 or die "Failed copying $framework.framework into $nightlyLauncherStagingPath";
+ }
+}
+
+my $b = currentBranch();
+my $r = currentRevision();
+print "Branch: ", $b, "\n";
+print "Revision: ", $r, "\n";
+
+chdirWebKit();
+buildNightlyLauncher();
+copyNightlyLauncher();
diff --git a/Tools/BuildSlaveSupport/build-launcher-dmg b/Tools/BuildSlaveSupport/build-launcher-dmg
new file mode 100755
index 0000000..4dce7fb
--- /dev/null
+++ b/Tools/BuildSlaveSupport/build-launcher-dmg
@@ -0,0 +1,118 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
+# Copyright (C) 2006 Mark Rowe <opendarwin.org@bdash.net.nz>. 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.
+
+# Script used by build slaves to create a disk-image containing WebKit.app.
+
+use strict;
+
+use File::Basename;
+use Getopt::Long;
+use FindBin;
+use lib "$FindBin::Bin/../Scripts";
+use webkitdirs;
+
+my $nightlyLauncherStagingPath = productDir() . "/WebKit.app";
+my $droseraStagingPath = productDir() . "/DroseraLauncher.app";
+my $nightlyLauncherDiskImagePath;
+
+my $nightlyRemoteHost = 'webkit-nightlies@live.nightly.webkit.org';
+my $nightlyRemotePath = "/home/webkit-nightlies";
+my $nightlyRemoteLatestPath = "$nightlyRemotePath/update-latest.sh";
+
+sub buildDiskImage
+{
+ my $revision = currentSVNRevision();
+ my $productDir = productDir();
+ $nightlyLauncherDiskImagePath = productDir() . "/WebKit-SVN-r$revision.dmg";
+
+ print "Removing previous temp source directory (if any)...\n";
+ `rm -rf /tmp/WebKitNightly`;
+ die "Removing previous temp source directory failed" if $?;
+
+ print "Making a new temp source directory...\n";
+ `mkdir /tmp/WebKitNightly`;
+ die "Making a new temp source directory failed" if $?;
+
+ print "Copying WebKit.app to temp source directory...\n";
+ `cp -R \"$nightlyLauncherStagingPath\" /tmp/WebKitNightly/WebKit.app`;
+ die "Copying WebKit.app to temp source directory failed" if $?;
+
+ print "Copying Drosera.app to temp source directory...\n";
+ `cp -R \"$droseraStagingPath\" /tmp/WebKitNightly/Drosera.app`;
+ die "Copying Drosera.app to temp source directory failed" if $?;
+
+ print "Creating disk image...\n";
+ `hdiutil create \"$nightlyLauncherDiskImagePath\" -ov -srcfolder /tmp/WebKitNightly -fs HFS+ -volname \"WebKit\"`;
+ die "Creating disk image failed" if $?;
+
+ print "Removing temp source directory...\n";
+ `rm -rf /tmp/WebKitNightly`;
+ die "Removing temp source directory failed" if $?;
+
+ print "Compressing disk image...\n";
+ system("mv", "-f", $nightlyLauncherDiskImagePath, "$nightlyLauncherDiskImagePath.uncompressed.dmg") == 0 or die "Renaming disk image failed";
+ system("hdiutil", "convert", "-quiet", "$nightlyLauncherDiskImagePath.uncompressed.dmg", "-format", "UDBZ", "-imagekey", "zlib-level=9", "-o", "$nightlyLauncherDiskImagePath");
+ die "Compressing disk image failed" if $?;
+
+ unlink "$nightlyLauncherDiskImagePath.uncompressed.dmg";
+}
+
+sub uploadNightlyDiskImage
+{
+ my $buildTag = shift(@_);
+ my $nightlyRemoteDiskImagePath = "$nightlyRemotePath/builds/$buildTag/mac/" . basename($nightlyLauncherDiskImagePath);
+ my $revision = currentSVNRevision();
+ system("rsync", "-vP", $nightlyLauncherDiskImagePath, "$nightlyRemoteHost:$nightlyRemoteDiskImagePath") == 0 or die "Failed uploading disk image";
+ system("ssh", $nightlyRemoteHost, $nightlyRemoteLatestPath, $buildTag, "mac", $nightlyRemoteDiskImagePath, $revision) == 0 or die "Failed linking disk image to latest";
+}
+
+sub uploadBuildSlaveDiskImage
+{
+ my $remoteDiskImagePath = shift(@_) . basename($nightlyLauncherDiskImagePath);
+ system("rsync", "-vP", $nightlyLauncherDiskImagePath, $remoteDiskImagePath) == 0 or die "Failed uploading disk image";
+}
+
+
+my $uploadTo;
+my $nightlyBuild = 0;
+my $buildTag = 'trunk';
+GetOptions('upload-to-host=s' => \$uploadTo,
+ 'upload-as-nightly!' => \$nightlyBuild,
+ 'tag=s' => \$buildTag);
+
+chdirWebKit();
+buildDiskImage($buildTag);
+
+if ($nightlyBuild) {
+ uploadNightlyDiskImage($buildTag);
+} elsif ($uploadTo) {
+ uploadBuildSlaveDiskImage($uploadTo);
+} else {
+ print "Disk image left at $nightlyLauncherDiskImagePath\n";
+}
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/Makefile b/Tools/BuildSlaveSupport/build.webkit.org-config/Makefile
new file mode 100644
index 0000000..bd5e749
--- /dev/null
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/Makefile
@@ -0,0 +1,19 @@
+# -*- makefile -*-
+
+# This is a simple makefile which lives in a buildmaster/buildslave
+# directory (next to the buildbot.tac file). It allows you to start/stop the
+# master or slave by doing 'make start' or 'make stop'.
+
+# The 'reconfig' target will tell a buildmaster to reload its config file.
+
+start:
+ /opt/local/bin/twistd2.5 --no_save -y buildbot.tac
+
+stop:
+ kill `cat twistd.pid`
+
+reconfig:
+ kill -HUP `cat twistd.pid`
+
+log:
+ tail -f twistd.log
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/README b/Tools/BuildSlaveSupport/build.webkit.org-config/README
new file mode 100644
index 0000000..3ba8a22
--- /dev/null
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/README
@@ -0,0 +1,2 @@
+Note: This directory is *not* automatically synchronized with Subversion via a post-commit hook.
+Any changes made to code within this directory will need to be manually pushed to build.webkit.org.
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/buildbot.tac b/Tools/BuildSlaveSupport/build.webkit.org-config/buildbot.tac
new file mode 100644
index 0000000..1a53acf
--- /dev/null
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/buildbot.tac
@@ -0,0 +1,21 @@
+
+from twisted.application import service
+from buildbot.master import BuildMaster
+
+basedir = r'/buildbot/webkit'
+configfile = r'master.cfg'
+rotateLength = 1000000
+maxRotatedFiles = None
+
+application = service.Application('buildmaster')
+try:
+ from twisted.python.logfile import LogFile
+ from twisted.python.log import ILogObserver, FileLogObserver
+ logfile = LogFile.fromFullPath("twistd.log", rotateLength=rotateLength,
+ maxRotatedFiles=maxRotatedFiles)
+ application.setComponent(ILogObserver, FileLogObserver(logfile).emit)
+except ImportError:
+ # probably not yet twisted 8.2.0 and beyond, can't set log yet
+ pass
+BuildMaster(basedir, configfile).setServiceParent(application)
+
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/config.json b/Tools/BuildSlaveSupport/build.webkit.org-config/config.json
new file mode 100644
index 0000000..19d7535
--- /dev/null
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/config.json
@@ -0,0 +1,258 @@
+{
+ "slaves": [ { "name": "test-slave", "platform": "*" },
+
+ { "name": "apple-xserve-1", "platform": "mac-leopard" },
+ { "name": "apple-xserve-2", "platform": "mac-leopard" },
+ { "name": "apple-xserve-3", "platform": "mac-leopard" },
+
+ { "name": "apple-xserve-4", "platform": "mac-snowleopard" },
+ { "name": "apple-xserve-5", "platform": "mac-snowleopard" },
+ { "name": "apple-xserve-6", "platform": "mac-snowleopard" },
+ { "name": "apple-xserve-7", "platform": "mac-snowleopard" },
+
+ { "name": "apple-pixel-1", "platform": "mac-leopard" },
+
+ { "name": "apple-macpro-1", "platform": "mac-snowleopard" },
+ { "name": "apple-macpro-2", "platform": "mac-snowleopard" },
+ { "name": "apple-macpro-3", "platform": "mac-snowleopard" },
+ { "name": "apple-macpro-4", "platform": "mac-leopard" },
+ { "name": "apple-macpro-5", "platform": "mac-leopard" },
+ { "name": "apple-macpro-6", "platform": "mac-leopard" },
+
+ { "name": "apple-windows-1", "platform": "win"},
+ { "name": "apple-windows-2", "platform": "win"},
+ { "name": "apple-windows-3", "platform": "win"},
+ { "name": "apple-windows-4", "platform": "win"},
+ { "name": "apple-windows-5", "platform": "win"},
+ { "name": "apple-windows-6", "platform": "win"},
+ { "name": "apple-windows-7", "platform": "win"},
+ { "name": "apple-windows-8", "platform": "win"},
+ { "name": "apple-windows-9", "platform": "win"},
+ { "name": "apple-windows-10", "platform": "win"},
+ { "name": "apple-windows-11", "platform": "win"},
+ { "name": "apple-windows-12", "platform": "win"},
+ { "name": "apple-windows-13", "platform": "win"},
+ { "name": "apple-windows-14", "platform": "win"},
+ { "name": "apple-windows-15", "platform": "win"},
+
+ { "name": "gtk-linux-slave-1", "platform": "gtk"},
+ { "name": "gtk-linux-slave-2", "platform": "gtk"},
+ { "name": "gtk-linux-slave-3", "platform": "gtk"},
+ { "name": "gtk-linux-slave-4", "platform": "gtk"},
+
+ { "name": "szeged-linux-1", "platform": "qt"},
+ { "name": "szeged-linux-2", "platform": "qt"},
+ { "name": "szeged-linux-3", "platform": "qt"},
+ { "name": "szeged-linux-4", "platform": "qt"},
+
+ { "name": "szeged-windows-1", "platform": "qt"},
+ { "name": "szeged-windows-2", "platform": "qt"},
+
+ { "name": "google-windows-1", "platform": "chromium-win" },
+ { "name": "google-mac-1", "platform": "chromium-mac" },
+ { "name": "google-linux-1", "platform": "chromium-linux" },
+ { "name": "google-windows-2", "platform": "chromium-win" },
+ { "name": "google-mac-2", "platform": "chromium-mac" },
+ { "name": "google-linux-2", "platform": "chromium-linux" },
+ { "name": "google-new-tests", "platform": "mac-leopard" },
+
+ { "name": "wincairo-1", "platform": "wincairo" },
+
+ { "name": "efl-linux-slave-1", "platform": "efl" }
+ ],
+
+ "builders": [ { "name": "Leopard Intel Release (Build)", "type": "Build", "builddir": "leopard-intel-release",
+ "platform": "mac-leopard", "configuration": "release", "architectures": ["i386"],
+ "triggers": ["leopard-intel-release-tests"],
+ "slavenames": ["apple-xserve-1", "apple-xserve-2", "test-slave"]
+ },
+ { "name": "Leopard Intel Release (Tests)", "type": "Test", "builddir": "leopard-intel-release-tests",
+ "platform": "mac-leopard", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["apple-macpro-4", "apple-pixel-1", "test-slave"]
+ },
+
+ { "name": "Leopard Intel Debug (Build)", "type": "Build", "builddir": "leopard-intel-debug",
+ "platform": "mac-leopard", "configuration": "debug", "architectures": ["i386"],
+ "triggers": ["leopard-intel-debug-tests"],
+ "slavenames": ["apple-xserve-1", "apple-xserve-2", "test-slave"]
+ },
+ { "name": "Leopard Intel Debug (Tests)", "type": "Test", "builddir": "leopard-intel-debug-tests",
+ "platform": "mac-leopard", "configuration": "debug", "architectures": ["i386"],
+ "slavenames": ["apple-xserve-3", "test-slave", "apple-macpro-5", "apple-macpro-6"]
+ },
+ { "name": "SnowLeopard Intel Release (Build)", "type": "Build", "builddir": "snowleopard-intel-release",
+ "platform": "mac-snowleopard", "configuration": "release", "architectures": ["x86_64"],
+ "triggers": ["snowleopard-intel-release-tests", "snowleopard-intel-release-tests-wk2"],
+ "slavenames": ["apple-xserve-4", "test-slave"]
+ },
+ { "name": "SnowLeopard Intel Release (Tests)", "type": "Test", "builddir": "snowleopard-intel-release-tests",
+ "platform": "mac-snowleopard", "configuration": "release", "architectures": ["x86_64"],
+ "slavenames": ["apple-xserve-5", "apple-xserve-6", "test-slave"]
+ },
+ { "name": "SnowLeopard Intel Leaks", "type": "BuildAndTestLeaks", "builddir": "snowleopard-intel-leaks",
+ "platform": "mac-snowleopard", "configuration": "debug", "architectures": ["x86_64"],
+ "slavenames": ["apple-macpro-1", "apple-macpro-3", "test-slave"]
+ },
+ { "name": "SnowLeopard Intel Release (WebKit2 Tests)", "type": "TestWebKit2", "builddir": "snowleopard-intel-release-tests-wk2",
+ "platform": "mac-snowleopard", "configuration": "release", "architectures": ["x86_64"],
+ "slavenames": ["apple-xserve-7", "test-slave"]
+ },
+ {
+ "name": "Windows Release (Build)", "type": "Build", "builddir": "win-release",
+ "platform": "win", "configuration": "release", "architectures": ["i386"],
+ "triggers": ["win-release-tests", "win-release-tests-wk2"],
+ "slavenames": ["apple-windows-2", "test-slave"]
+ },
+ {
+ "name": "Windows 7 Release (Tests)", "type": "Test", "builddir": "win-release-tests",
+ "platform": "win", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["apple-windows-5", "apple-windows-6", "apple-windows-11", "apple-windows-12", "test-slave"]
+ },
+ {
+ "name": "Windows Debug (Build)", "type": "Build", "builddir": "win-debug",
+ "platform": "win", "configuration": "debug", "architectures": ["i386"],
+ "triggers": ["win-debug-tests"],
+ "slavenames": ["apple-windows-1", "test-slave"]
+ },
+ {
+ "name": "Windows XP Debug (Tests)", "type": "Test", "builddir": "win-debug-tests",
+ "platform": "win", "configuration": "debug", "architectures": ["i386"],
+ "slavenames": ["apple-windows-3", "apple-windows-4", "apple-windows-13", "apple-windows-14", "apple-windows-15", "test-slave"]
+ },
+ { "name": "Windows 7 Release (WebKit2 Tests)", "type": "TestWebKit2", "builddir": "win-release-tests-wk2",
+ "platform": "win", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["apple-windows-7", "apple-windows-8", "apple-windows-9", "apple-windows-10", "test-slave"]
+ },
+ {
+ "name": "GTK Linux 32-bit Release", "type": "BuildAndTest", "builddir": "gtk-linux-32-release",
+ "platform": "gtk", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["gtk-linux-slave-1"]
+ },
+ {
+ "name": "GTK Linux 32-bit Debug", "type": "BuildAndTest", "builddir": "gtk-linux-32-debug",
+ "platform": "gtk", "configuration": "debug", "architectures": ["i386"],
+ "slavenames": ["gtk-linux-slave-2"]
+ },
+ {
+ "name": "GTK Linux 64-bit Debug", "type": "BuildAndTest", "builddir": "gtk-linux-64-debug",
+ "platform": "gtk", "configuration": "debug", "architectures": ["x86_64"],
+ "slavenames": ["gtk-linux-slave-3"]
+ },
+ {
+ "name": "GTK Linux 64-bit Release", "type": "BuildAndTest", "builddir": "gtk-linux-64-release",
+ "platform": "gtk", "configuration": "release", "architectures": ["x86_64"],
+ "slavenames": ["gtk-linux-slave-4"]
+ },
+ {
+ "name": "Qt Linux Release", "type": "BuildAndTest", "builddir": "qt-linux-release",
+ "platform": "qt", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["szeged-linux-1"]
+ },
+ {
+ "name": "Qt Linux Release minimal", "type": "Build", "builddir": "qt-linux-release-minimal",
+ "platform": "qt", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["szeged-linux-2"]
+ },
+ {
+ "name": "Qt Linux ARMv5 Release", "type": "Build", "builddir": "qt-linux-armv5-release",
+ "platform": "qt", "configuration": "release", "architectures": ["armv5"],
+ "slavenames": ["szeged-linux-3"]
+ },
+ {
+ "name": "Qt Linux ARMv7 Release", "type": "Build", "builddir": "qt-linux-armv7-release",
+ "platform": "qt", "configuration": "release", "architectures": ["armv7"],
+ "slavenames": ["szeged-linux-4"]
+ },
+ {
+ "name": "Qt Windows 32-bit Release", "type": "Build", "builddir": "qt-windows-32bit-release",
+ "platform": "qt", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["szeged-windows-1"]
+ },
+ {
+ "name": "Qt Windows 32-bit Debug", "type": "Build", "builddir": "qt-windows-32bit-debug",
+ "platform": "qt", "configuration": "debug", "architectures": ["i386"],
+ "slavenames": ["szeged-windows-2"]
+ },
+ {
+ "name": "Chromium Win Release", "type": "Build", "builddir": "chromium-win-release",
+ "platform": "chromium-win", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["google-windows-1"]
+ },
+ {
+ "name": "Chromium Mac Release", "type": "Build", "builddir": "chromium-mac-release",
+ "platform": "chromium-mac", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["google-mac-1"]
+ },
+ {
+ "name": "Chromium Linux Release", "type": "Build", "builddir": "chromium-linux-release",
+ "platform": "chromium-linux", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["google-linux-1"]
+ },
+ {
+ "name": "Chromium Win Release (Tests)", "type": "NewBuildAndTest", "builddir": "chromium-win-release-tests",
+ "platform": "chromium-win", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["google-windows-2"]
+ },
+ {
+ "name": "Chromium Mac Release (Tests)", "type": "NewBuildAndTest", "builddir": "chromium-mac-release-tests",
+ "platform": "chromium-mac", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["google-mac-2"]
+ },
+ {
+ "name": "Chromium Linux Release (Tests)", "type": "NewBuildAndTest", "builddir": "chromium-linux-release-tests",
+ "platform": "chromium-linux", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["google-linux-2"]
+ },
+ {
+ "name": "New run-webkit-tests", "type": "NewBuildAndTest", "builddir": "google-new-tests",
+ "platform": "mac-leopard", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["google-new-tests"]
+ },
+ {
+ "name": "WinCairo Debug (Build)", "type": "Build", "builddir": "win-cairo-debug",
+ "platform": "wincairo", "configuration": "debug", "architectures": ["i386"],
+ "slavenames": ["wincairo-1"]
+ },
+ {
+ "name": "EFL Linux Release (Build)", "type": "Build", "builddir": "efl-linux-release",
+ "platform": "efl", "configuration": "release", "architectures": ["i386"],
+ "slavenames": ["efl-linux-slave-1"]
+ }
+ ],
+
+ "schedulers": [ { "type": "AnyBranchScheduler", "name": "trunk", "change_filter": "trunk_filter", "treeStableTimer": 45.0,
+ "builderNames": ["Leopard Intel Release (Build)", "Leopard Intel Debug (Build)",
+ "SnowLeopard Intel Release (Build)", "SnowLeopard Intel Leaks",
+ "GTK Linux 32-bit Release", "GTK Linux 32-bit Debug", "GTK Linux 64-bit Debug", "GTK Linux 64-bit Release",
+ "Qt Linux Release", "Qt Linux Release minimal", "Qt Linux ARMv5 Release", "Qt Linux ARMv7 Release",
+ "Qt Windows 32-bit Release", "Qt Windows 32-bit Debug",
+ "Chromium Win Release", "Chromium Mac Release", "Chromium Linux Release",
+ "Chromium Win Release (Tests)", "Chromium Mac Release (Tests)", "Chromium Linux Release (Tests)",
+ "WinCairo Debug (Build)", "EFL Linux Release (Build)"]
+ },
+ { "type": "PlatformSpecificScheduler", "platform": "win", "branch": "trunk", "treeStableTimer": 45.0,
+ "builderNames": ["Windows Release (Build)", "Windows Debug (Build)"]
+ },
+ { "type": "Triggerable", "name": "leopard-intel-release-tests",
+ "builderNames": ["Leopard Intel Release (Tests)"]
+ },
+ { "type": "Triggerable", "name": "leopard-intel-debug-tests",
+ "builderNames": ["Leopard Intel Debug (Tests)"]
+ },
+ { "type": "Triggerable", "name": "snowleopard-intel-release-tests",
+ "builderNames": ["SnowLeopard Intel Release (Tests)"]
+ },
+ { "type": "Triggerable", "name": "snowleopard-intel-release-tests-wk2",
+ "builderNames": ["SnowLeopard Intel Release (WebKit2 Tests)"]
+ },
+ { "type": "Triggerable", "name": "win-release-tests",
+ "builderNames": ["Windows 7 Release (Tests)"]
+ },
+ { "type": "Triggerable", "name": "win-debug-tests",
+ "builderNames": ["Windows XP Debug (Tests)"]
+ },
+ { "type": "Triggerable", "name": "win-release-tests-wk2",
+ "builderNames": ["Windows 7 Release (WebKit2 Tests)"]
+ }
+ ]
+}
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg b/Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg
new file mode 100644
index 0000000..df9dcb0
--- /dev/null
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/master.cfg
@@ -0,0 +1,567 @@
+# -*- python -*-
+# ex: set syntax=python:
+
+c = BuildmasterConfig = {}
+
+from buildbot.buildslave import BuildSlave
+from buildbot.changes.pb import PBChangeSource
+from buildbot.scheduler import AnyBranchScheduler, Triggerable
+from buildbot.schedulers.filter import ChangeFilter
+from buildbot.status import html
+from buildbot.status.web.authz import Authz
+from buildbot.process import buildstep, factory, properties
+from buildbot.steps import master, shell, source, transfer, trigger
+from buildbot.status.builder import SUCCESS, FAILURE, WARNINGS, SKIPPED
+
+from twisted.internet import defer
+
+import re
+import simplejson
+
+from webkitpy.common.config import build as wkbuild
+from webkitpy.common.net.buildbot import BuildBot as wkbuildbot
+
+WithProperties = properties.WithProperties
+
+class ConfigureBuild(buildstep.BuildStep):
+ name = "configure build"
+ description = ["configuring build"]
+ descriptionDone = ["configured build"]
+ def __init__(self, platform, configuration, architecture, buildOnly, *args, **kwargs):
+ buildstep.BuildStep.__init__(self, *args, **kwargs)
+ self.platform = platform.split('-', 1)[0]
+ self.fullPlatform = platform
+ self.configuration = configuration
+ self.architecture = architecture
+ self.buildOnly = buildOnly
+ self.addFactoryArguments(platform=platform, configuration=configuration, architecture=architecture, buildOnly=buildOnly)
+
+ def start(self):
+ self.setProperty("platform", self.platform)
+ self.setProperty("fullPlatform", self.fullPlatform)
+ self.setProperty("configuration", self.configuration)
+ self.setProperty("architecture", self.architecture)
+ self.setProperty("buildOnly", self.buildOnly)
+ self.finished(SUCCESS)
+ return defer.succeed(None)
+
+
+class CheckOutSource(source.SVN):
+ baseURL = "http://svn.webkit.org/repository/webkit/"
+ mode = "update"
+ def __init__(self, *args, **kwargs):
+ source.SVN.__init__(self, baseURL=self.baseURL, defaultBranch="trunk", mode=self.mode, *args, **kwargs)
+
+
+class InstallWin32Dependencies(shell.Compile):
+ description = ["installing dependencies"]
+ descriptionDone = ["installed dependencies"]
+ command = ["perl", "./Tools/Scripts/update-webkit-auxiliary-libs"]
+
+class KillOldProcesses(shell.Compile):
+ name = "kill old processes"
+ description = ["killing old processes"]
+ descriptionDone = ["killed old processes"]
+ command = ["python", "./Tools/BuildSlaveSupport/win/kill-old-processes"]
+
+class InstallChromiumDependencies(shell.ShellCommand):
+ name = "gclient"
+ description = ["updating chromium dependencies"]
+ descriptionDone = ["updated chromium dependencies"]
+ command = ["perl", "./Tools/Scripts/update-webkit-chromium", "--force"]
+ haltOnFailure = True
+
+class CleanupChromiumLinuxCrashLogs(shell.ShellCommand):
+ name = "cleanup crash logs"
+ description = ["removing crash logs"]
+ descriptionDone = ["removed crash logs"]
+ command = ["sh", "-c", "rm -rf /tmp/.org.chromium.*"]
+ haltOnFailure = False
+
+
+def appendCustomBuildFlags(step, platform):
+ if platform in ('gtk', 'wx', 'qt', 'chromium', 'wincairo', 'efl'):
+ step.setCommand(step.command + ['--' + platform])
+
+
+class CompileWebKit(shell.Compile):
+ command = ["perl", "./Tools/Scripts/build-webkit", WithProperties("--%(configuration)s")]
+ env = {'MFLAGS':''}
+ name = "compile-webkit"
+ description = ["compiling"]
+ descriptionDone = ["compiled"]
+ warningPattern = ".*arning: .*"
+
+ def start(self):
+ platform = self.getProperty('platform')
+ buildOnly = self.getProperty('buildOnly')
+ if platform == 'mac' and buildOnly:
+ self.setCommand(self.command + ['DEBUG_INFORMATION_FORMAT=dwarf-with-dsym'])
+
+ appendCustomBuildFlags(self, platform)
+ return shell.Compile.start(self)
+
+
+class ArchiveBuiltProduct(shell.ShellCommand):
+ command = ["python", "./Tools/BuildSlaveSupport/built-product-archive",
+ WithProperties("--platform=%(platform)s"), WithProperties("--%(configuration)s"), "archive"]
+ name = "archive-built-product"
+ description = ["archiving built product"]
+ descriptionDone = ["archived built product"]
+ haltOnFailure = True
+
+
+class ExtractBuiltProduct(shell.ShellCommand):
+ command = ["python", "./Tools/BuildSlaveSupport/built-product-archive",
+ WithProperties("--platform=%(platform)s"), WithProperties("--%(configuration)s"), "extract"]
+ name = "extract-built-product"
+ description = ["extracting built product"]
+ descriptionDone = ["extracted built product"]
+ haltOnFailure = True
+
+
+class UploadBuiltProduct(transfer.FileUpload):
+ slavesrc = WithProperties("WebKitBuild/%(configuration)s.zip")
+ masterdest = WithProperties("archives/%(fullPlatform)s-%(architecture)s-%(configuration)s/%(got_revision)s.zip")
+ haltOnFailure = True
+
+ def __init__(self):
+ transfer.FileUpload.__init__(self, self.slavesrc, self.masterdest)
+
+
+class DownloadBuiltProduct(transfer.FileDownload):
+ slavedest = WithProperties("WebKitBuild/%(configuration)s.zip")
+ mastersrc = WithProperties("archives/%(fullPlatform)s-%(architecture)s-%(configuration)s/%(got_revision)s.zip")
+ haltOnFailure = True
+ flunkOnFailure = True
+
+ def __init__(self):
+ transfer.FileDownload.__init__(self, self.mastersrc, self.slavedest)
+
+
+class RunJavaScriptCoreTests(shell.Test):
+ name = "jscore-test"
+ description = ["jscore-tests running"]
+ descriptionDone = ["jscore-tests"]
+ command = ["perl", "./Tools/Scripts/run-javascriptcore-tests", WithProperties("--%(configuration)s")]
+ logfiles = {'results': 'JavaScriptCore/tests/mozilla/actual.html'}
+
+ def __init__(self, skipBuild=False, *args, **kwargs):
+ self.skipBuild = skipBuild
+ shell.Test.__init__(self, *args, **kwargs)
+ self.addFactoryArguments(skipBuild=skipBuild)
+
+ def start(self):
+ appendCustomBuildFlags(self, self.getProperty('platform'))
+ if self.skipBuild:
+ self.setCommand(self.command + ['--skip-build'])
+ return shell.Test.start(self)
+
+ def commandComplete(self, cmd):
+ shell.Test.commandComplete(self, cmd)
+
+ logText = cmd.logs['stdio'].getText()
+ statusLines = [line for line in logText.splitlines() if line.find('regression') >= 0 and line.find(' found.') >= 0]
+ if statusLines and statusLines[0].split()[0] != '0':
+ self.regressionLine = statusLines[0]
+ else:
+ self.regressionLine = None
+
+ def evaluateCommand(self, cmd):
+ if self.regressionLine:
+ return FAILURE
+
+ if cmd.rc != 0:
+ return FAILURE
+
+ return SUCCESS
+
+ def getText(self, cmd, results):
+ return self.getText2(cmd, results)
+
+ def getText2(self, cmd, results):
+ if results != SUCCESS and self.regressionLine:
+ return [self.name, self.regressionLine]
+
+ return [self.name]
+
+
+class RunWebKitTests(shell.Test):
+ name = "layout-test"
+ description = ["layout-tests running"]
+ descriptionDone = ["layout-tests"]
+ command = ["perl", "./Tools/Scripts/run-webkit-tests", "--no-launch-safari", "--no-new-test-results",
+ "--no-sample-on-timeout", "--results-directory", "layout-test-results", "--use-remote-links-to-tests",
+ WithProperties("--%(configuration)s"), "--exit-after-n-crashes-or-timeouts", "20"]
+
+ def __init__(self, skipBuild=False, *args, **kwargs):
+ self.skipBuild = skipBuild
+ shell.Test.__init__(self, *args, **kwargs)
+ self.addFactoryArguments(skipBuild=skipBuild)
+
+ def start(self):
+ appendCustomBuildFlags(self, self.getProperty('platform'))
+ if self.skipBuild:
+ self.setCommand(self.command + ['--root=WebKitBuild/bin'])
+ return shell.Test.start(self)
+
+ def commandComplete(self, cmd):
+ shell.Test.commandComplete(self, cmd)
+
+ logText = cmd.logs['stdio'].getText()
+ incorrectLayoutLines = []
+ for line in logText.splitlines():
+ if line.find('had incorrect layout') >= 0 or line.find('were new') >= 0 or line.find('was new') >= 0:
+ incorrectLayoutLines.append(line)
+ elif line.find('test case') >= 0 and (line.find(' crashed') >= 0 or line.find(' timed out') >= 0):
+ incorrectLayoutLines.append(line)
+ elif line.startswith("WARNING:") and line.find(' leak') >= 0:
+ incorrectLayoutLines.append(line.replace('WARNING: ', ''))
+ elif line.find('Exiting early') >= 0:
+ incorrectLayoutLines.append(line)
+
+ # FIXME: Detect and summarize leaks of RefCounted objects
+
+ self.incorrectLayoutLines = incorrectLayoutLines
+
+ def evaluateCommand(self, cmd):
+ if self.incorrectLayoutLines:
+ if len(self.incorrectLayoutLines) == 1:
+ line = self.incorrectLayoutLines[0]
+ if line.find('were new') >= 0 or line.find('was new') >= 0 or line.find(' leak') >= 0:
+ return WARNINGS
+
+ return FAILURE
+
+ if cmd.rc != 0:
+ return FAILURE
+
+ return SUCCESS
+
+ def getText(self, cmd, results):
+ return self.getText2(cmd, results)
+
+ def getText2(self, cmd, results):
+ if results != SUCCESS and self.incorrectLayoutLines:
+ return self.incorrectLayoutLines
+
+ return [self.name]
+
+
+class NewRunWebKitTests(RunWebKitTests):
+ command = ["python", "./Tools/Scripts/new-run-webkit-tests", "--noshow-results",
+ "--verbose", "--results-directory", "layout-test-results",
+ "--builder-name", WithProperties("%(buildername)s"),
+ "--build-number", WithProperties("%(buildnumber)s"),
+ "--master-name", "webkit.org",
+ "--test-results-server", "test-results.appspot.com",
+ WithProperties("--%(configuration)s")]
+
+
+class RunPythonTests(shell.Test):
+ name = "webkitpy-test"
+ description = ["python-tests running"]
+ descriptionDone = ["python-tests"]
+ command = ["python", "./Tools/Scripts/test-webkitpy"]
+
+
+class RunPerlTests(shell.Test):
+ name = "webkitperl-test"
+ description = ["perl-tests running"]
+ descriptionDone = ["perl-tests"]
+ command = ["perl", "./Tools/Scripts/test-webkitperl"]
+
+
+class RunGtkAPITests(shell.Test):
+ name = "API tests"
+ description = ["API tests running"]
+ descriptionDone = ["API tests"]
+ command = ["perl", "./Tools/Scripts/run-gtk-tests", WithProperties("--%(configuration)s")]
+
+ def commandComplete(self, cmd):
+ shell.Test.commandComplete(self, cmd)
+
+ logText = cmd.logs['stdio'].getText()
+ incorrectLines = []
+ for line in logText.splitlines():
+ if line.startswith('ERROR'):
+ incorrectLines.append(line)
+
+ self.incorrectLines = incorrectLines
+
+ def evaluateCommand(self, cmd):
+ if self.incorrectLines:
+ return FAILURE
+
+ if cmd.rc != 0:
+ return FAILURE
+
+ return SUCCESS
+
+ def getText(self, cmd, results):
+ return self.getText2(cmd, results)
+
+ def getText2(self, cmd, results):
+ if results != SUCCESS and self.incorrectLines:
+ return ["%d API tests failed" % len(self.incorrectLines)]
+
+ return [self.name]
+
+class RunQtAPITests(shell.Test):
+ name = "API tests"
+ description = ["API tests running"]
+ descriptionDone = ["API tests"]
+ command = ["python", "./Tools/Scripts/run-qtwebkit-tests",
+ "--output-file=qt-unit-tests.html", "--do-not-open-results",
+ WithProperties("WebKitBuild/%(configuration_pretty)s/WebKit/qt/tests/")]
+
+ def start(self):
+ self.setProperty("configuration_pretty", self.getProperty("configuration").title())
+ return shell.Test.start(self)
+
+ def commandComplete(self, cmd):
+ shell.Test.commandComplete(self, cmd)
+
+ logText = cmd.logs['stdio'].getText()
+ foundItems = re.findall("TOTALS: (?P<passed>\d+) passed, (?P<failed>\d+) failed, (?P<skipped>\d+) skipped", logText)
+
+ self.incorrectTests = 0
+ self.statusLine = []
+
+ if foundItems:
+ self.incorrectTests = int(foundItems[0][1])
+ if self.incorrectTests > 0:
+ self.statusLine = [
+ "%s passed, %s failed, %s skipped" % (foundItems[0][0], foundItems[0][1], foundItems[0][2])
+ ]
+
+ def evaluateCommand(self, cmd):
+ if self.incorrectTests:
+ return WARNINGS
+
+ if cmd.rc != 0:
+ return FAILURE
+
+ return SUCCESS
+
+ def getText(self, cmd, results):
+ return self.getText2(cmd, results)
+
+ def getText2(self, cmd, results):
+ if results != SUCCESS and self.incorrectTests:
+ return self.statusLine
+
+ return [self.name]
+
+class RunWebKitLeakTests(RunWebKitTests):
+ def start(self):
+ self.setCommand(self.command + ["--leaks"])
+ return RunWebKitTests.start(self)
+
+
+class RunWebKit2Tests(RunWebKitTests):
+ def start(self):
+ self.setCommand(self.command + ["--webkit-test-runner"])
+ return RunWebKitTests.start(self)
+
+
+class RunChromiumWebKitUnitTests(shell.Test):
+ name = "webkit-unit-tests"
+ description = ["webkit-unit-tests running"]
+ descriptionDone = ["webkit-unit-tests"]
+ command = ["perl", "./Tools/Scripts/run-chromium-webkit-unit-tests",
+ WithProperties("--%(configuration)s")]
+
+
+class ArchiveTestResults(shell.ShellCommand):
+ command = ["python", "./Tools/BuildSlaveSupport/test-result-archive",
+ WithProperties("--platform=%(platform)s"), WithProperties("--%(configuration)s"), "archive"]
+ name = "archive-test-results"
+ description = ["archiving test results"]
+ descriptionDone = ["archived test results"]
+ haltOnFailure = True
+
+
+class UploadTestResults(transfer.FileUpload):
+ slavesrc = "layout-test-results.zip"
+ masterdest = WithProperties("public_html/results/%(buildername)s/r%(got_revision)s (%(buildnumber)s).zip")
+
+ def __init__(self):
+ transfer.FileUpload.__init__(self, self.slavesrc, self.masterdest)
+
+
+class ExtractTestResults(master.MasterShellCommand):
+ zipFile = WithProperties("public_html/results/%(buildername)s/r%(got_revision)s (%(buildnumber)s).zip")
+ resultDirectory = WithProperties("public_html/results/%(buildername)s/r%(got_revision)s (%(buildnumber)s)")
+
+ def __init__(self):
+ master.MasterShellCommand.__init__(self, "")
+
+ def start(self):
+ self.command = ["ditto", "-k", "-x", "-V", self.build.getProperties().render(self.zipFile), self.build.getProperties().render(self.resultDirectory)]
+ return master.MasterShellCommand.start(self)
+
+ def finished(self, result):
+ url = self.build.getProperties().render(self.resultDirectory).replace("public_html/", "/")
+ self.addURL("view results", url)
+ result = master.MasterShellCommand.finished(self, result)
+ self.step_status.setText(["uploaded results"])
+ return result
+
+
+class Factory(factory.BuildFactory):
+ def __init__(self, platform, configuration, architectures, buildOnly):
+ factory.BuildFactory.__init__(self)
+ self.addStep(ConfigureBuild, platform=platform, configuration=configuration, architecture=" ".join(architectures), buildOnly=buildOnly)
+ self.addStep(CheckOutSource)
+ if platform == "win":
+ self.addStep(KillOldProcesses)
+ self.addStep(InstallWin32Dependencies)
+ if platform.startswith("chromium"):
+ self.addStep(InstallChromiumDependencies)
+
+class BuildFactory(Factory):
+ def __init__(self, platform, configuration, architectures, triggers=None):
+ Factory.__init__(self, platform, configuration, architectures, True)
+ self.addStep(CompileWebKit)
+ if triggers:
+ self.addStep(ArchiveBuiltProduct)
+ self.addStep(UploadBuiltProduct)
+ self.addStep(trigger.Trigger, schedulerNames=triggers)
+
+class TestFactory(Factory):
+ TestClass = RunWebKitTests
+ def __init__(self, platform, configuration, architectures):
+ Factory.__init__(self, platform, configuration, architectures, False)
+ self.addStep(DownloadBuiltProduct)
+ self.addStep(ExtractBuiltProduct)
+ self.addStep(RunJavaScriptCoreTests, skipBuild=True)
+ self.addStep(self.TestClass, skipBuild=(platform == 'win'))
+ # Tiger's Python 2.3 is too old. WebKit Python requires 2.5+.
+ # Sadly we have no way to detect the version on the slave from here.
+ if platform != "mac-tiger":
+ self.addStep(RunPythonTests)
+ self.addStep(RunPerlTests)
+ self.addStep(ArchiveTestResults)
+ self.addStep(UploadTestResults)
+ self.addStep(ExtractTestResults)
+
+class BuildAndTestFactory(Factory):
+ TestClass = RunWebKitTests
+ def __init__(self, platform, configuration, architectures):
+ Factory.__init__(self, platform, configuration, architectures, False)
+ if platform == "chromium-linux":
+ self.addStep(CleanupChromiumLinuxCrashLogs)
+ self.addStep(CompileWebKit)
+ if not platform.startswith("chromium"):
+ self.addStep(RunJavaScriptCoreTests)
+ if platform.startswith("chromium"):
+ self.addStep(RunChromiumWebKitUnitTests)
+ self.addStep(self.TestClass)
+ # Tiger's Python 2.3 is too old. WebKit Python requires 2.5+.
+ # Sadly we have no way to detect the version on the slave from here.
+ if platform != "mac-tiger":
+ self.addStep(RunPythonTests)
+ self.addStep(RunPerlTests)
+ self.addStep(ArchiveTestResults)
+ self.addStep(UploadTestResults)
+ self.addStep(ExtractTestResults)
+ if platform == "gtk":
+ self.addStep(RunGtkAPITests)
+ if platform == "qt":
+ self.addStep(RunQtAPITests)
+
+class BuildAndTestLeaksFactory(BuildAndTestFactory):
+ TestClass = RunWebKitLeakTests
+
+class NewBuildAndTestFactory(BuildAndTestFactory):
+ TestClass = NewRunWebKitTests
+
+class TestWebKit2Factory(TestFactory):
+ TestClass = RunWebKit2Tests
+
+class PlatformSpecificScheduler(AnyBranchScheduler):
+ def __init__(self, platform, branch, **kwargs):
+ self.platform = platform
+ filter = ChangeFilter(branch=[branch, None], filter_fn=self.filter)
+ AnyBranchScheduler.__init__(self, name=platform, change_filter=filter, **kwargs)
+
+ def filter(self, change):
+ return wkbuild.should_build(self.platform, change.files)
+
+trunk_filter = ChangeFilter(branch=["trunk", None])
+
+def loadBuilderConfig(c):
+ # FIXME: These file handles are leaked.
+ passwords = simplejson.load(open('passwords.json'))
+ config = simplejson.load(open('config.json'))
+
+ # use webkitpy's buildbot module to test for core builders
+ wkbb = wkbuildbot()
+
+ c['slaves'] = [BuildSlave(slave['name'], passwords[slave['name']], max_builds=1) for slave in config['slaves']]
+
+ c['schedulers'] = []
+ for scheduler in config['schedulers']:
+ if "change_filter" in scheduler:
+ scheduler["change_filter"] = globals()[scheduler["change_filter"]]
+ kls = globals()[scheduler.pop('type')]
+ c['schedulers'].append(kls(**scheduler))
+
+ c['builders'] = []
+ for builder in config['builders']:
+ for slaveName in builder['slavenames']:
+ for slave in config['slaves']:
+ if slave['name'] != slaveName or slave['platform'] == '*':
+ continue
+
+ if slave['platform'] != builder['platform']:
+ raise Exception, "Builder %r is for platform %r but has slave %r for platform %r!" % (builder['name'], builder['platform'], slave['name'], slave['platform'])
+
+ break
+
+ factory = globals()["%sFactory" % builder.pop('type')]
+ factoryArgs = []
+ for key in "platform", "configuration", "architectures", "triggers":
+ value = builder.pop(key, None)
+ if value:
+ factoryArgs.append(value)
+
+ builder["factory"] = factory(*factoryArgs)
+
+ builder["category"] = "noncore"
+ if wkbb._is_core_builder(builder['name']):
+ builder["category"] = "core"
+
+ c['builders'].append(builder)
+
+loadBuilderConfig(c)
+
+c['change_source'] = PBChangeSource()
+
+# permissions for WebStatus
+authz = Authz(
+ forceBuild=True,
+ forceAllBuilds=True,
+ pingBuilder=True,
+ gracefulShutdown=False,
+ stopBuild=True,
+ stopAllBuilds=True,
+ cancelPendingBuild=True,
+ stopChange=True,
+ cleanShutdown=False)
+
+c['status'] = []
+c['status'].append(html.WebStatus(http_port=8710,
+ revlink="http://trac.webkit.org/changeset/%s",
+ authz=authz))
+
+c['slavePortnum'] = 17000
+c['projectName'] = "WebKit"
+c['projectURL'] = "http://webkit.org"
+c['buildbotURL'] = "http://build.webkit.org/"
+
+c['buildHorizon'] = 1000
+c['logHorizon'] = 500
+c['eventHorizon'] = 200
+c['buildCacheSize'] = 60
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/buildbot.css b/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/buildbot.css
new file mode 100644
index 0000000..a71c81f
--- /dev/null
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/buildbot.css
@@ -0,0 +1,382 @@
+body {
+ margin-bottom:50px;
+}
+
+body, td {
+ font-family: Verdana, Cursor;
+ font-size: 10px;
+ font-weight: bold;
+}
+
+a:link,a:visited,a:active {
+ color: #444;
+}
+
+a:hover {
+ color: #000000;
+}
+
+table {
+ border-spacing: 1px 1px;
+}
+
+table td {
+ padding: 3px 0px 3px 0px;
+ text-align: center;
+}
+
+.Project {
+ width: 100px;
+}
+
+.LastBuild, .Activity {
+ padding: 0 0 0 4px;
+}
+
+.LastBuild, .Activity, .Builder, .BuildStep {
+ width: 155px;
+ max-width: 155px;
+}
+
+td.Time {
+ color: #000;
+ border-bottom: 1px solid #aaa;
+ background-color: #eee;
+}
+
+td.Activity, td.Change, td.Builder {
+ color: #333333;
+ background-color: #CCCCCC;
+}
+
+td.Change {
+ border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+}
+td.Event {
+ color: #777;
+ background-color: #ddd;
+ border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+}
+
+td.Activity {
+ border-top-left-radius: 10px;
+ -webkit-border-top-left-radius: 10px;
+ -moz-border-radius-topleft: 10px;
+ min-height: 20px;
+ padding: 2px 0 2px 0;
+}
+
+td.idle, td.waiting, td.offline, td.building {
+ border-top-left-radius: 0px;
+ -webkit-border-top-left-radius: 0px;
+ -moz-border-radius-topleft: 0px;
+}
+
+.LastBuild {
+ border-top-left-radius: 5px;
+ -webkit-border-top-left-radius: 5px;
+ -moz-border-radius-topleft: 5px;
+ border-top-right-radius: 5px;
+ -webkit-border-top-right-radius: 5px;
+ -moz-border-radius-topright: 5px;
+}
+
+/* Console view styles */
+
+td.DevRev {
+ padding: 4px 8px 4px 8px;
+ color: #333333;
+ border-top-left-radius: 5px;
+ -webkit-border-top-left-radius: 5px;
+ -moz-border-radius-topleft: 5px;
+ background-color: #eee;
+ width: 1%;
+}
+
+td.DevRevCollapse {
+ border-bottom-left-radius: 5px;
+ -webkit-border-bottom-left-radius: 5px;
+ -moz-border-radius-bottomleft: 5px;
+}
+
+td.DevName {
+ padding: 4px 8px 4px 8px;
+ color: #333333;
+ background-color: #eee;
+ width: 1%;
+ text-align: left;
+}
+
+td.DevStatus {
+ padding: 4px 4px 4px 4px;
+ color: #333333;
+ background-color: #eee;
+}
+
+td.DevSlave {
+ padding: 4px 4px 4px 4px;
+ color: #333333;
+ background-color: #eee;
+}
+
+td.first {
+ border-top-left-radius: 5px;
+ -webkit-border-top-left-radius: 5px;
+ -moz-border-radius-topleft: 5px;
+}
+
+td.last {
+ border-top-right-radius: 5px;
+ -webkit-border-top-right-radius: 5px;
+ -moz-border-radius-topright: 5px;
+}
+
+td.DevStatusCategory {
+ border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-width:1px;
+ border-style:solid;
+}
+
+td.DevStatusCollapse {
+ border-bottom-right-radius: 5px;
+ -webkit-border-bottom-right-radius: 5px;
+ -moz-border-radius-bottomright: 5px;
+}
+
+td.DevDetails {
+ font-weight: normal;
+ padding: 8px 8px 8px 8px;
+ color: #333333;
+ background-color: #eee;
+ text-align: left;
+}
+
+td.DevComment {
+ font-weight: normal;
+ padding: 8px 8px 8px 8px;
+ color: #333333;
+ border-bottom-right-radius: 5px;
+ -webkit-border-bottom-right-radius: 5px;
+ -moz-border-radius-bottomright: 5px;
+ border-bottom-left-radius: 5px;
+ -webkit-border-bottom-left-radius: 5px;
+ -moz-border-radius-bottomleft: 5px;
+ background-color: #eee;
+ text-align: left;
+}
+
+td.Alt {
+ background-color: #CCCCCC;
+}
+
+.legend {
+ border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ width: 100px;
+ max-width: 100px;
+ text-align:center;
+ padding: 2px 2px 2px 2px;
+ height:14px;
+ white-space:nowrap;
+}
+
+.DevStatusBox {
+ text-align:center;
+ height:20px;
+ padding:0 2px;
+ line-height:0;
+ white-space:nowrap;
+}
+
+.DevStatusBox a {
+ opacity: 0.85;
+ border-width:1px;
+ border-style:solid;
+ border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ display:block;
+ width:90%;
+ height:20px;
+ line-height:20px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.DevSlaveBox {
+ text-align:center;
+ height:10px;
+ padding:0 2px;
+ line-height:0;
+ white-space:nowrap;
+}
+
+.DevSlaveBox a {
+ opacity: 0.85;
+ border-width:1px;
+ border-style:solid;
+ border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ display:block;
+ width:90%;
+ height:10px;
+ line-height:20px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+a.noround {
+ border-radius: 0px;
+ -webkit-border-radius: 0px;
+ -moz-border-radius: 0px;
+ position: relative;
+ margin-top: -8px;
+ margin-bottom: -8px;
+ height: 36px;
+ border-top-width: 0;
+ border-bottom-width: 0;
+}
+
+a.begin {
+ border-top-width:1px;
+ position: relative;
+ margin-top: 0px;
+ margin-bottom: -7px;
+ height: 27px;
+ border-top-left-radius: 4px;
+ -webkit-border-top-left-radius: 4px;
+ -moz-border-radius-topleft: 4px;
+ border-top-right-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+}
+
+a.end {
+ border-bottom-width:1px;
+ position: relative;
+ margin-top: -7px;
+ margin-bottom: 0px;
+ height: 27px;
+ border-bottom-left-radius: 4px;
+ -webkit-border-bottom-left-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+ border-bottom-right-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -moz-border-radius-bottomright: 4px;
+}
+
+.center_align {
+ text-align: center;
+}
+
+.right_align {
+ text-align: right;
+}
+
+.left_align {
+ text-align: left;
+}
+
+div.BuildWaterfall {
+ border-radius: 7px;
+ -webkit-border-radius: 7px;
+ -moz-border-radius: 7px;
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ background-color: #FFFFFF;
+ padding: 4px 4px 4px 4px;
+ float: left;
+ display: none;
+ border-width: 1px;
+ border-style: solid;
+}
+
+/* LastBuild, BuildStep states */
+.success {
+ color: #FFFFFF;
+ background-color: #8fdf5f;
+ border-color: #4F8530;
+}
+
+.failure {
+ color: #FFFFFF;
+ background-color: #e98080;
+ border-color: #A77272;
+}
+
+.warnings {
+ color: #FFFFFF;
+ background-color: #ffc343;
+ border-color: #C29D46;
+}
+
+.exception, td.offline {
+ color: #FFFFFF;
+ background-color: #e0b0ff;
+ border-color: #ACA0B3;
+}
+
+.start,.running, td.building {
+ color: #666666;
+ background-color: #fffc6c;
+ border-color: #C5C56D;
+}
+
+.start {
+ border-bottom-left-radius: 10px;
+ -webkit-border-bottom-left-radius: 10px;
+ -moz-border-radius-bottomleft: 10px;
+ border-bottom-right-radius: 10px;
+ -webkit-border-bottom-right-radius: 10px;
+ -moz-border-radius-bottomright: 10px;
+}
+
+.notstarted {
+ border-width:1px;
+ border-style:solid;
+ border-color:#aaa;
+}
+
+td.Project a:hover, td.start a:hover {
+ color: #000;
+}
+
+/* grid styles */
+
+table.Grid {
+ border-collapse: collapse;
+}
+
+table.Grid tr td {
+ padding: 0.2em;
+ margin: 0px;
+ text-align: center;
+}
+
+table.Grid tr td.title {
+ font-size: 90%;
+ border-right: 1px gray solid;
+ border-bottom: 1px gray solid;
+}
+
+table.Grid tr td.sourcestamp {
+ font-size: 90%;
+}
+
+table.Grid tr td.builder {
+ text-align: right;
+ font-size: 90%;
+}
+
+table.Grid tr td.build {
+ border: 1px gray solid;
+}
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/default.css b/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/default.css
new file mode 100644
index 0000000..4223807
--- /dev/null
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/default.css
@@ -0,0 +1,524 @@
+div.header { display: none; }
+body > hr { display: none; }
+div.content h1 { display: none; }
+
+body.interface {
+ background: url(bg_gradient.jpg) repeat-x;
+ font-family: Verdana, Cursor;
+ font-size: 10px;
+ font-weight: bold;
+ background-color: #fff;
+ color: #333;
+}
+
+a:link,a:visited,a:active {
+ color: #444;
+}
+
+table {
+ border-spacing: 1px 1px;
+}
+
+table td {
+ padding: 3px 2px 3px 2px;
+}
+
+.Project {
+ min-width: 6em;
+}
+
+.LastBuild,.Activity {
+ padding: 0 0 0 4px;
+}
+
+/* Chromium Specific styles */
+div.BuildResultInfo {
+ color: #444;
+}
+
+div.Announcement {
+ margin-bottom: 1em;
+}
+
+div.Announcement>a:hover {
+ color: black;
+}
+
+div.Announcement>div.Notice {
+ background-color: #afdaff;
+ padding: 0.5em;
+ font-size: 16px;
+ text-align: center;
+}
+
+div.Announcement>div.Open {
+ border: 3px solid #8fdf5f;
+ padding: 0.5em;
+ font-size: 16px;
+ text-align: center;
+}
+
+div.Announcement>div.Closed {
+ border: 5px solid #e98080;
+ padding: 0.5em;
+ font-size: 24px;
+ font-weight: bold;
+ text-align: center;
+}
+
+td.Time {
+ color: #000;
+ border-bottom: 1px solid #aaa;
+ background-color: #eee;
+}
+
+td.Activity,td.Change,td.Builder {
+ color: #333333;
+ background-color: #CCCCCC;
+}
+
+td.Change {
+ border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+}
+
+td.Event {
+ color: #777;
+ background-color: #ddd;
+ border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+}
+
+td.Activity {
+ border-top-left-radius: 10px;
+ -webkit-border-top-left-radius: 10px;
+ -moz-border-radius-topleft: 10px;
+ min-height: 20px;
+ padding: 2px 0 2px 0;
+}
+
+td.idle,td.waiting,td.offline,td.building {
+ border-top-left-radius: 0px;
+ -webkit-border-top-left-radius: 0px;
+ -moz-border-radius-topleft: 0px;
+}
+
+.LastBuild {
+ border-top-left-radius: 5px;
+ -webkit-border-top-left-radius: 5px;
+ -moz-border-radius-topleft: 5px;
+ border-top-right-radius: 5px;
+ -webkit-border-top-right-radius: 5px;
+ -moz-border-radius-topright: 5px;
+}
+
+/* Console view styles */
+td.DevRev {
+ padding: 4px 8px 4px 8px;
+ color: #333333;
+ border-top-left-radius: 5px;
+ -webkit-border-top-left-radius: 5px;
+ -moz-border-radius-topleft: 5px;
+ background-color: #eee;
+ width: 1%;
+}
+
+td.DevRevCollapse {
+ border-bottom-left-radius: 5px;
+ -webkit-border-bottom-left-radius: 5px;
+ -moz-border-radius-bottomleft: 5px;
+}
+
+td.DevName {
+ padding: 4px 8px 4px 8px;
+ color: #333333;
+ background-color: #eee;
+ width: 1%;
+ text-align: left;
+}
+
+td.DevStatus {
+ padding: 4px 4px 4px 4px;
+ color: #333333;
+ background-color: #eee;
+}
+
+td.DevSlave {
+ padding: 4px 4px 4px 4px;
+ color: #333333;
+ background-color: #eee;
+}
+
+td.first {
+ border-top-left-radius: 5px;
+ -webkit-border-top-left-radius: 5px;
+ -moz-border-radius-topleft: 5px;
+}
+
+td.last {
+ border-top-right-radius: 5px;
+ -webkit-border-top-right-radius: 5px;
+ -moz-border-radius-topright: 5px;
+}
+
+td.DevStatusCategory {
+ border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-width: 1px;
+ border-style: solid;
+}
+
+td.DevStatusCollapse {
+ border-bottom-right-radius: 5px;
+ -webkit-border-bottom-right-radius: 5px;
+ -moz-border-radius-bottomright: 5px;
+}
+
+td.DevDetails {
+ font-weight: normal;
+ padding: 8px 8px 8px 8px;
+ color: #333333;
+ background-color: #eee;
+ text-align: left;
+}
+
+td.DevComment {
+ font-weight: normal;
+ padding: 8px 8px 8px 8px;
+ color: #333333;
+ border-bottom-right-radius: 5px;
+ -webkit-border-bottom-right-radius: 5px;
+ -moz-border-radius-bottomright: 5px;
+ border-bottom-left-radius: 5px;
+ -webkit-border-bottom-left-radius: 5px;
+ -moz-border-radius-bottomleft: 5px;
+ background-color: #eee;
+ text-align: left;
+}
+
+td.Alt {
+ background-color: #ddd;
+}
+
+.legend {
+ border-radius: 5px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ width: 100px;
+ max-width: 100px;
+ text-align: center;
+ padding: 2px 2px 2px 2px;
+ height: 14px;
+ white-space: nowrap;
+}
+
+.DevStatusBox {
+ text-align: center;
+ height: 20px;
+ padding: 0 2px;
+ line-height: 0;
+ white-space: nowrap;
+}
+
+.DevStatusBox a {
+ opacity: 0.85;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ display: block;
+ width: 90%;
+ height: 20px;
+ line-height: 20px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.DevSlaveBox {
+ text-align: center;
+ height: 10px;
+ padding: 0 2px;
+ line-height: 0;
+ white-space: nowrap;
+}
+
+.DevSlaveBox a {
+ opacity: 0.85;
+ border-width: 1px;
+ border-style: solid;
+ border-radius: 4px;
+ -webkit-border-radius: 4px;
+ -moz-border-radius: 4px;
+ display: block;
+ width: 90%;
+ height: 10px;
+ line-height: 20px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+a.noround {
+ border-radius: 0px;
+ -webkit-border-radius: 0px;
+ -moz-border-radius: 0px;
+ position: relative;
+ margin-top: -8px;
+ margin-bottom: -8px;
+ height: 36px;
+ border-top-width: 0;
+ border-bottom-width: 0;
+}
+
+a.begin {
+ border-top-width: 1px;
+ position: relative;
+ margin-top: 0px;
+ margin-bottom: -7px;
+ height: 27px;
+ border-top-left-radius: 4px;
+ -webkit-border-top-left-radius: 4px;
+ -moz-border-radius-topleft: 4px;
+ border-top-right-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ -moz-border-radius-topright: 4px;
+}
+
+a.end {
+ border-bottom-width: 1px;
+ position: relative;
+ margin-top: -7px;
+ margin-bottom: 0px;
+ height: 27px;
+ border-bottom-left-radius: 4px;
+ -webkit-border-bottom-left-radius: 4px;
+ -moz-border-radius-bottomleft: 4px;
+ border-bottom-right-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -moz-border-radius-bottomright: 4px;
+}
+
+.center_align {
+ text-align: center;
+}
+
+.right_align {
+ text-align: right;
+}
+
+.left_align {
+ text-align: left;
+}
+
+div.BuildWaterfall {
+ border-radius: 7px;
+ -webkit-border-radius: 7px;
+ -moz-border-radius: 7px;
+ position: absolute;
+ left: 0px;
+ top: 0px;
+ background-color: #FFFFFF;
+ padding: 4px 4px 4px 4px;
+ float: left;
+ display: none;
+ border-width: 1px;
+ border-style: solid;
+}
+
+/* LastBuild, BuildStep states */
+.success {
+ color: #FFFFFF;
+ background-color: #8FDF5F;
+ border-color: #4F8530;
+}
+
+.failure {
+ color: #FFFFFF;
+ background-color: #E98080;
+ border-color: #A77272;
+}
+
+.warnings {
+ color: #FFFFFF;
+ background-color: #FFC343;
+ border-color: #C29D46;
+}
+
+.exception {
+ color: #FFFFFF;
+ background-color: #E0B0FF;
+ border-color: #ACA0B3;
+}
+
+.start,.running,td.building {
+ color: #666666;
+ background-color: #FFFC6C;
+ border-color: #C5C56D;
+}
+
+.offline,td.offline {
+ color: #FFFFFF;
+ background-color: #E0B0FF;
+ border-color: #dddddd;
+}
+
+
+.start {
+ border-bottom-left-radius: 10px;
+ -webkit-border-bottom-left-radius: 10px;
+ -moz-border-radius-bottomleft: 10px;
+ border-bottom-right-radius: 10px;
+ -webkit-border-bottom-right-radius: 10px;
+ -moz-border-radius-bottomright: 10px;
+}
+
+.notstarted {
+ border-width: 1px;
+ border-style: solid;
+ border-color: #aaa;
+ background-color: #fff;
+}
+
+.closed {
+ background-color: #ff0000;
+}
+
+.closed .large {
+ font-size: 1.5em;
+ font-weight: bolder;
+}
+
+td.Project a:hover,td.start a:hover {
+ color: #000;
+}
+
+.mini-box {
+ text-align: center;
+ height: 20px;
+ padding: 0 2px;
+ line-height: 0;
+ white-space: nowrap;
+}
+
+.mini-box a {
+ border-radius: 0;
+ -webkit-border-radius: 0;
+ -moz-border-radius: 0;
+ display: block;
+ width: 100%;
+ height: 20px;
+ line-height: 20px;
+ margin-top: -30px;
+}
+
+.mini-closed {
+ -box-sizing: border-box;
+ -webkit-box-sizing: border-box;
+ border: 4px solid red;
+}
+
+/* grid styles */
+table.Grid {
+ border-collapse: collapse;
+}
+
+table.Grid tr td {
+ padding: 0.2em;
+ margin: 0px;
+ text-align: center;
+}
+
+table.Grid tr td.title {
+ font-size: 90%;
+ border-right: 1px gray solid;
+ border-bottom: 1px gray solid;
+}
+
+table.Grid tr td.sourcestamp {
+ font-size: 90%;
+}
+
+table.Grid tr td.builder {
+ text-align: right;
+ font-size: 90%;
+}
+
+table.Grid tr td.build {
+ border: 1px gray solid;
+}
+
+/* column container */
+div.column {
+ margin: 0 2em 2em 0;
+ float: left;
+}
+
+/* info tables */
+table.info {
+ border-spacing: 1px;
+}
+
+table.info td {
+ padding: 0.1em 1em 0.1em 1em;
+ text-align: center;
+}
+
+table.info th {
+ padding: 0.2em 1.5em 0.2em 1.5em;
+ text-align: center;
+}
+
+table.info td.left {
+ text-align: left
+}
+
+.alt {
+ background-color: #d6d6d6;
+}
+
+li {
+ padding: 0.1em 1em 0.1em 1em;
+}
+
+.result {
+ padding: 0.3em 1em 0.3em 1em;
+}
+
+/* log view */
+.log * {
+ vlink: #800080;
+ font-family: "Courier New", courier, monotype;
+}
+
+span.stdout {
+ color: black;
+}
+
+span.stderr {
+ color: red;
+}
+
+span.header {
+ color: blue;
+}
+
+/* revision & email */
+.revision .full {
+ display: none;
+}
+
+.user .email {
+ display: none;
+}
+
+/* change comments (use regular colors here) */
+pre.comments>a:link,pre.comments>a:visited {
+ color: blue;
+}
+
+pre.comments>a:active {
+ color: purple;
+}
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/robots.txt b/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/robots.txt
new file mode 100644
index 0000000..579297c
--- /dev/null
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/public_html/robots.txt
@@ -0,0 +1,13 @@
+User-agent: *
+Disallow: /waterfall
+Disallow: /builders
+Disallow: /changes
+Disallow: /buildslaves
+Disallow: /schedulers
+Disallow: /one_line_per_build
+Disallow: /one_box_per_builder
+Disallow: /xmlrpc
+Disallow: /grid
+Disallow: /tgrid
+Disallow: /console
+Disallow: /results
diff --git a/Tools/BuildSlaveSupport/build.webkit.org-config/templates/root.html b/Tools/BuildSlaveSupport/build.webkit.org-config/templates/root.html
new file mode 100755
index 0000000..c6d2343
--- /dev/null
+++ b/Tools/BuildSlaveSupport/build.webkit.org-config/templates/root.html
@@ -0,0 +1,24 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-15">
+<title>Welcome to the Buildbot</title>
+</head>
+
+<body>
+<h1>Welcome to the Buildbot!</h1>
+
+<ul>
+ <li><a href="console?category=core">Core Console</a></li>
+ <li><a href="waterfall?category=core">Core Waterfall</a></li>
+ <li><a href="console">Console</a></li>
+ <li><a href="waterfall">Waterfall Display</a> will give you a time-oriented summary of recent buildbot activity.</li>
+ <li><a href="one_box_per_builder">Latest Build</a> for each builder is here.</li>
+ <li><a href="one_line_per_build">Recent Builds</a> are summarized here, one per line.</li>
+ <li><a href="buildslaves">Buildslave</a> information</li>
+ <li><a href="http://webkit-commit-queue.appspot.com/">Commit Queue Status</a> information.</li>
+ <li><a href="changes">ChangeSource</a> information.</li>
+ <li><a href="results">Test Results</a></li>
+</ul>
+</body> </html>
+
diff --git a/Tools/BuildSlaveSupport/built-product-archive b/Tools/BuildSlaveSupport/built-product-archive
new file mode 100644
index 0000000..b27cf77
--- /dev/null
+++ b/Tools/BuildSlaveSupport/built-product-archive
@@ -0,0 +1,148 @@
+#!/usr/bin/python
+
+# 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 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 optparse, os, shutil, subprocess, sys
+
+buildDirectory = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "WebKitBuild"))
+
+def main():
+ parser = optparse.OptionParser("usage: %prog [options] [action]")
+ parser.add_option("--platform", dest="platform")
+ parser.add_option("--debug", action="store_const", const="debug", dest="configuration")
+ parser.add_option("--release", action="store_const", const="release", dest="configuration")
+
+ options, (action, ) = parser.parse_args()
+ if not options.platform:
+ parser.error("Platform is required")
+ if not options.configuration:
+ parser.error("Configuration is required")
+ if action not in ('archive', 'extract'):
+ parser.error("Action is required")
+
+ if action == 'archive':
+ archiveBuiltProduct(options.configuration, options.platform)
+ else:
+ extractBuiltProduct(options.configuration, options.platform)
+
+
+def archiveBuiltProduct(configuration, platform):
+ assert platform in ('mac', 'win','qt')
+
+ archiveFile = os.path.join(buildDirectory, configuration + ".zip")
+
+ try:
+ os.unlink(archiveFile)
+ except OSError, e:
+ if e.errno != 2:
+ raise
+
+ if platform == 'mac':
+ configurationBuildDirectory = os.path.join(buildDirectory, configuration.title())
+ return subprocess.call(["ditto", "-c", "-k", "--keepParent", "--sequesterRsrc", configurationBuildDirectory, archiveFile])
+ elif platform == 'win':
+ binDirectory = os.path.join(buildDirectory, "bin")
+ thinDirectory = os.path.join(buildDirectory, "thin")
+ thinBinDirectory = os.path.join(thinDirectory, "bin")
+
+ if os.path.isdir(thinDirectory):
+ shutil.rmtree(thinDirectory)
+ os.mkdir(thinDirectory)
+
+ if subprocess.call(["cp", "-R", binDirectory, thinBinDirectory]):
+ return 1
+
+ if subprocess.call("rm -f %s" % os.path.join(thinBinDirectory, "*.ilk"), shell=True):
+ return 1
+
+ if subprocess.call(["zip", "-r", archiveFile, "bin"], cwd=thinDirectory):
+ return 1
+
+ shutil.rmtree(thinDirectory)
+
+ elif platform == 'qt':
+ configurationBuildDirectory = os.path.join(buildDirectory, configuration.title())
+ thinDirectory = os.path.join(configurationBuildDirectory, "thin")
+
+ if os.path.isdir(thinDirectory):
+ shutil.rmtree(thinDirectory)
+ os.mkdir(thinDirectory)
+
+ for dirname in ["bin", "lib", "JavaScriptCore"]:
+ fromDir = os.path.join(configurationBuildDirectory, dirname)
+ toDir = os.path.join(thinDirectory, dirname)
+ if subprocess.call(["cp", "-R", fromDir, toDir]):
+ return 1
+
+ for root, dirs, files in os.walk(thinDirectory, topdown=False):
+ for name in files:
+ if name.endswith(".o"):
+ os.remove(os.path.join(root, name))
+
+ if subprocess.call(["zip", "-y", "-r", archiveFile, "."], cwd=thinDirectory):
+ return 1
+
+def extractBuiltProduct(configuration, platform):
+ assert platform in ('mac', 'win','qt')
+
+ archiveFile = os.path.join(buildDirectory, configuration + ".zip")
+
+ if platform == 'mac':
+ configurationBuildDirectory = os.path.join(buildDirectory, configuration.title())
+
+ if os.path.isdir(configurationBuildDirectory):
+ shutil.rmtree(configurationBuildDirectory)
+
+ if subprocess.call(["ditto", "-x", "-k", archiveFile, buildDirectory]):
+ return 1
+ os.unlink(archiveFile)
+
+ elif platform == 'win':
+ binDirectory = os.path.join(buildDirectory, "bin")
+ if os.path.isdir(binDirectory):
+ shutil.rmtree(binDirectory)
+
+ os.mkdir(binDirectory)
+
+ safariPath = subprocess.Popen('cygpath -w "$PROGRAMFILES"/Safari',
+ shell=True, stdout=subprocess.PIPE).communicate()[0].strip()
+
+ if subprocess.call('cp -R "%s"/*.dll "%s"/*.resources %s' % (safariPath, safariPath, binDirectory), shell=True):
+ return 1
+
+ if subprocess.call(["unzip", "-o", archiveFile], cwd=buildDirectory):
+ return 1
+
+ elif platform == 'qt':
+ configurationBuildDirectory = os.path.join(buildDirectory, configuration.title())
+
+ if os.path.isdir(configurationBuildDirectory):
+ shutil.rmtree(configurationBuildDirectory)
+
+ if subprocess.call(["unzip", "-o", archiveFile, "-d", configurationBuildDirectory], cwd=buildDirectory):
+ return 1
+ os.unlink(archiveFile)
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/Tools/BuildSlaveSupport/gtk/README b/Tools/BuildSlaveSupport/gtk/README
new file mode 100644
index 0000000..9e58ae2
--- /dev/null
+++ b/Tools/BuildSlaveSupport/gtk/README
@@ -0,0 +1,52 @@
+==============================================
+ Running a GTK+ build slave under daemontools
+==============================================
+
+This directory contains several scripts which can be used to run a WebKitGTK+
+build slave under daemontools [1]. This is convenient because daemontools
+will automatically restart services when they die, and that means less human
+intervention is needed.
+
+
+Dependencies
+============
+
+In order to use the provided service control files, you will need the
+following:
+
+* The GNU Bash shell (the scripts contain some bash-isms)
+
+* The daemontools package (or one of its drop-in replacements, like runit
+ or freedt; but only daemontools has been tested so far).
+
+* The crash dump monitor also uses "inotifywait" (part of inotify-tools [2])
+
+In short, in a Debian-based system you can ensure you have the needed bits
+with the following command:
+
+ apt-get install inotify-tools daemontools-run
+
+
+Setup
+=====
+
+1. Follow the instructions at http://trac.webkit.org/wiki/BuildBot
+
+2. Install the dependencies outlined above.
+
+3. Copy "daemontools-buildbot.conf" to "/etc/daemontools-buildbot.conf"
+
+4. Edit the configuration file to suit your needs, the comments should
+ be self-explanatory.
+
+5. Drop the "buildbot", "pulseaudio" and "xvfb" directories (plus
+ "crashmon", if desired) to the service control directory of
+ daemontools; for Debian-based setups that would be "/etc/service"
+
+
+References
+==========
+
+[1] http://cr.yp.to/daemontools.html
+[2] http://wiki.github.com/rvoicilas/inotify-tools/
+
diff --git a/Tools/BuildSlaveSupport/gtk/buildbot/log/run b/Tools/BuildSlaveSupport/gtk/buildbot/log/run
new file mode 100755
index 0000000..cc2c87e
--- /dev/null
+++ b/Tools/BuildSlaveSupport/gtk/buildbot/log/run
@@ -0,0 +1,38 @@
+#! /bin/bash
+#
+# Copyright (C) 2010 Igalia S.L. All rights reserved.
+#
+# 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.
+
+: ${BUILDBOT_CONFIG:=/etc/daemontools-buildbot.conf}
+
+# Read configuration file
+[ -r "${BUILDBOT_CONFIG}" ] && . "${BUILDBOT_CONFIG}"
+
+: ${buildbot_user:=${HOME}}
+: ${buildbot_log_path:=/var/log/buildbot}
+
+# Expand all "env_*" environment variables
+for varname in ${!env_*} ; do
+ eval "export ${varname#env_}=\${${varname}}"
+done
+
+mkdir -p "${buildbot_log_path}"
+chown "${buildbot_user}" "${buildbot_log_path}"
+
+exec /usr/bin/setuidgid "${buildbot_user}" \
+ /usr/bin/multilog t "${buildbot_log_path}"
+
diff --git a/Tools/BuildSlaveSupport/gtk/buildbot/run b/Tools/BuildSlaveSupport/gtk/buildbot/run
new file mode 100755
index 0000000..b26fe58
--- /dev/null
+++ b/Tools/BuildSlaveSupport/gtk/buildbot/run
@@ -0,0 +1,77 @@
+#! /bin/bash
+#
+# Copyright (C) 2010 Igalia S.L. All rights reserved.
+#
+# 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.
+
+exec 2>&1
+
+: ${BUILDBOT_CONFIG:=/etc/daemontools-buildbot.conf}
+
+# Read configuration file
+[ -r "${BUILDBOT_CONFIG}" ] && . "${BUILDBOT_CONFIG}"
+
+# Expand all "env_*" environment variables
+for varname in ${!env_*} ; do
+ eval "export ${varname#env_}=\${${varname}}"
+done
+
+
+if ! [ "${buildbot_path}" ] ; then
+ echo "No \${buildbot_path} defined! (will sleep for 5 minutes)"
+ sleep 300
+ exit 111
+fi
+
+
+if ! [ "${WEBKIT_TESTFONTS}" ] ; then
+ echo "No \${WEBKIT_TESTFONTS} environment variable! (will sleep for 5 minutes)"
+ sleep 300
+ exit 111
+fi
+
+
+if [ "${coredump_output:=''}" ] ; then
+ # Ensure that the output directory exists.
+ if [[ ! -d ${crashmon_output} ]] ; then
+ mkdir -p "${crashmon_output}"
+ fi
+
+ ulimit -c "${crashmon_max_size:=unlimited}"
+fi
+
+
+if [ "${ccache_path}" ] ; then
+ export PATH="${ccache_path}:${PATH}"
+fi
+
+: ${buildbot_user:=${USER}}
+
+cd "${buildbot_path}"
+exec /usr/bin/env - \
+ TERM=dumb \
+ TZ=PST8PDT \
+ PATH="${PATH}" \
+ SHELL=/bin/bash \
+ LANG=en_US.UTF-8 \
+ USER="${buildbot_user}" \
+ LOGNAME="${buildbot_user}" \
+ HOME="/home/${buildbot_user}" \
+ DISPLAY="${xvfb_display:-':10'}" \
+ MAIL="/var/mail/${buildbot_user}" \
+ /usr/bin/setuidgid "${buildbot_user}" \
+ /usr/bin/twistd -noy buildbot.tac
+
diff --git a/Tools/BuildSlaveSupport/gtk/crashmon/crashmon b/Tools/BuildSlaveSupport/gtk/crashmon/crashmon
new file mode 100755
index 0000000..41705a2
--- /dev/null
+++ b/Tools/BuildSlaveSupport/gtk/crashmon/crashmon
@@ -0,0 +1,73 @@
+#! /bin/bash
+#
+# Copyright (C) 2010 Carlos Lopez <clopez@igalia.com>, Igalia S.L.
+#
+# 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.
+
+set -e
+
+[ "${coredir}" ] || {
+ echo "Env var '\${coredir}' not defined!" >&2
+ exit 111
+}
+[ "${programpath}" ] || {
+ echo "Env var '\${programpath}' not defined" >&2
+ exit 111
+}
+[ "${arch}" ] || {
+ echo "Env var '\${arch}' not defined" >&2
+ exit 111
+}
+[ "${mailto}" ] || {
+ echo "Env var '\${mailto}' not defined" >&2
+ exit 111
+}
+
+
+inotifywait -q -m --format '%f' --exclude '.trace.html$' -e close_write "${coredir}" | \
+while read -r coredump
+do
+ if grep -qE '^core-when_[[:digit:]]{10\,12}-_-who_[[:print:]]+-_-why_' <<< "${coredump}"
+ then
+ # Get revision number from Subversion sources
+ rev=$(cd "${crashmon_src_path}" && svn info | sed -e '/^Revision:/s/Revision: //p' -e d)
+
+ # Get the who from the coredump name
+ programfile=$(echo "${coredump}" \
+ | awk -F'-_-who_' '{ print $2 }'\
+ | awk -F'-_-why_' '{ print $1 }')
+
+ # Sometimes programfile gets cut when it is a long name:
+ # Search using wildcards
+ fullprogrampath=$(find "${programpath}" -executable -name "${programfile}"\* | head -n1)
+
+ ( printf "<html><head><title>StackTrace for ${programfile} from svn"
+ printf " rev ${rev}</title></head>\n<body>Core dump file: "
+ printf "<a href=\"cores/${coredump}\">${coredump}</a><br/>\n"
+ printf "<pre>Executable crashed: ${fullprogrampath}</pre>\n"
+ printf "<br/><hr><b>Stack Trace:</b><hr><br/>\n<pre>"
+
+ gdb -ex "thread apply all bt" --batch "${fullprogrampath}" "${coredump}" 2>&1 \
+ | sed -e 's/\&/\&amp/g;s/</\&lt;/g;s/>/\&gt;/g;s/\"/\&quot;/g' -e "s/'/\&\#039;/g"
+
+ printf "</pre></body></html>\n"
+ ) > "/var/www/svn_${rev}.${coredump}.trace.html"
+
+ # Make sure the web server can read it
+ chmod 644 "${coredump}"
+ fi
+done
+
diff --git a/Tools/BuildSlaveSupport/gtk/crashmon/log/run b/Tools/BuildSlaveSupport/gtk/crashmon/log/run
new file mode 100755
index 0000000..4dcd71f
--- /dev/null
+++ b/Tools/BuildSlaveSupport/gtk/crashmon/log/run
@@ -0,0 +1,38 @@
+#! /bin/bash
+#
+# Copyright (C) 2010 Igalia S.L. All rights reserved.
+#
+# 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.
+
+: ${BUILDBOT_CONFIG:=/etc/daemontools-buildbot.conf}
+
+# Read configuration file
+[ -r "${BUILDBOT_CONFIG}" ] && . "${BUILDBOT_CONFIG}"
+
+: ${buildbot_user:=${HOME}}
+: ${crashmon_log_path:=/var/log/crashmon}
+
+# Expand all "env_*" environment variables
+for varname in ${!env_*} ; do
+ eval "export ${varname#env_}=\${${varname}}"
+done
+
+mkdir -p "${crashmon_log_path}"
+chown "${buildbot_user}" "${crashmon_log_path}"
+
+exec /usr/bin/setuidgid "${buildbot_user}" \
+ /usr/bin/multilog t "${crashmon_log_path}"
+
diff --git a/Tools/BuildSlaveSupport/gtk/crashmon/run b/Tools/BuildSlaveSupport/gtk/crashmon/run
new file mode 100755
index 0000000..38be3fe
--- /dev/null
+++ b/Tools/BuildSlaveSupport/gtk/crashmon/run
@@ -0,0 +1,74 @@
+#! /bin/bash
+#
+# Copyright (C) 2010 Igalia S.L. All rights reserved.
+#
+# 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.
+
+exec 2>&1
+
+: ${BUILDBOT_CONFIG:=/etc/daemontools-buildbot.conf}
+
+# Read configuration file
+[ -r "${BUILDBOT_CONFIG}" ] && . "${BUILDBOT_CONFIG}"
+
+: ${buildbot_user:=${USER:-${LOGNAME}}}
+: ${crashmon_output:=''}
+
+# Expand all "env_*" environment variables
+for varname in ${!env_*} ; do
+ eval "export ${varname#env_}=\${${varname}}"
+done
+
+
+if [ ! -d "${crashmon_output}" ]
+then
+ if ! [ "${crashmon_output}" ]
+ then
+ echo "Dump directory '${crashmon_output}' does not exist (sleeping)"
+ fi
+ sleep $(( 60 * 60 * 4 ))
+ exit 111
+fi
+
+
+if ! [ "${buildbot_bits}" ]
+then
+ # Guess bits (32/64) from uname -m
+ machine=$(uname -m)
+ case ${machine} in
+ x86_64 | amd64 | ia64 | ppc64)
+ buildbot_bits="64" ;;
+ *)
+ buildbot_bits="32" ;;
+ esac
+fi
+
+: ${crashmon_bin_path:="${buildbot_path}/gtk-linux-${buildbot_bits}-debug/build/WebKitBuild/Debug/Programs"}
+
+
+cd "${crashmon_output}"
+exec /usr/bin/env - \
+ PATH="${PATH}" \
+ SHELL="/bin/bash" \
+ USER="${buildbot_user}" \
+ arch="${buildbot_bits}" \
+ LOGNAME="${buildbot_user}" \
+ coredir="${crashmon_output}" \
+ HOME="/home/${buildbot_user}" \
+ mailto="${crashmon_mailto:-''}" \
+ programpath="${crashmon_bin_path}" \
+ /usr/bin/setuidgid "${buildbot_user}" "$(pwd)/crashmon"
+
diff --git a/Tools/BuildSlaveSupport/gtk/daemontools-buildbot.conf b/Tools/BuildSlaveSupport/gtk/daemontools-buildbot.conf
new file mode 100644
index 0000000..59c1c0b
--- /dev/null
+++ b/Tools/BuildSlaveSupport/gtk/daemontools-buildbot.conf
@@ -0,0 +1,87 @@
+# Copyright (C) 2010 Igalia S.L. All rights reserved.
+#
+# 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.
+
+
+# Path to the Buildbot slave directory
+#
+buildbot_path="/home/slave/webkitgtk"
+
+# User account used to run Buildbot.
+#
+buildbot_user="slave"
+
+# Path to a directory where to log Buildbot output
+#
+buildbot_log_path="/var/log/buildbot"
+
+
+# Display number under which Xvfb will run
+#
+xvfb_display=":10"
+
+# Graphical mode which Xvfb will report to applications
+#
+xvfb_mode="1024x768x24"
+
+# Path to a directory where to log Xvfb error output
+#
+xvfb_log_path="/var/log/xvfb"
+
+
+# Output directory for core dumps. Set this to an empty string to
+# disable recording them.
+#
+crashmon_output="/var/www/webkitgtk-coredumps"
+
+# Maximum size of core dumps. With the default "unlimited" setting
+# it is recommended to have ~20GB for cores in 64-bit machines.
+# For 32-bit bots, less space is needed.
+#
+crashmon_max_size="unlimited"
+
+# Path to a directory where to log crashmon output
+#
+crashmon_log_path="/var/log/crashmon"
+
+# A list of e-mail addresses where to send notifications of core dumps.
+# Leave empty to disable mail notifications.
+#
+# WARNING: E-mail addresses will be flooded with messages!
+#
+crashmon_mailto=""
+
+# Base directory where to find sources and built binaries of which
+# crash dumps are to be catched. Usually you will not need to change this.
+#
+crashmon_src_path="${buildbot_path}/gtk-linux-${buildbot_bits}-debug/build"
+crashmon_bin_path="${crashmon_src_path}/WebKitBuild/Debug/Programs"
+
+
+# If you want to use ccache, set a path to where synlinks with tool
+# names pointing to ccache are installed. In Debian systems this
+# would be /usr/lib/ccache. Set to empty to disable.
+#
+ccache_path="/usr/lib/ccache"
+
+
+# Environment variables. Prefix them with "env_".
+#
+env_CFLAGS="-pipe"
+env_CXXFLAGS="-pipe"
+env_WebKitMakeArguments="-j3"
+env_WEBKIT_TESTFONTS="/home/${buildbot_user}/testfonts"
+
diff --git a/Tools/BuildSlaveSupport/gtk/pulseaudio/run b/Tools/BuildSlaveSupport/gtk/pulseaudio/run
new file mode 100755
index 0000000..37ba0de
--- /dev/null
+++ b/Tools/BuildSlaveSupport/gtk/pulseaudio/run
@@ -0,0 +1,24 @@
+#! /bin/bash
+#
+# Copyright (C) 2010 Igalia S.L. All rights reserved.
+#
+# 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.
+
+exec 2>&1
+exec /usr/bin/pulseaudio --system \
+ --disallow-exit --disallow-module-loading \
+ --log-target=syslog
+
diff --git a/Tools/BuildSlaveSupport/gtk/xvfb/log/run b/Tools/BuildSlaveSupport/gtk/xvfb/log/run
new file mode 100755
index 0000000..1c83922
--- /dev/null
+++ b/Tools/BuildSlaveSupport/gtk/xvfb/log/run
@@ -0,0 +1,37 @@
+#! /bin/bash
+#
+# Copyright (C) 2010 Igalia S.L. All rights reserved.
+#
+# 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.
+
+: ${BUILDBOT_CONFIG:=/etc/daemontools-buildbot.conf}
+
+# Read configuration file
+[ -r "${BUILDBOT_CONFIG}" ] && . "${BUILDBOT_CONFIG}"
+
+: ${buildbot_user:=${HOME}}
+: ${xvfb_log_path:=/var/log/xvfb}
+
+# Expand all "env_*" environment variables
+for varname in ${!env_*} ; do
+ eval "export ${varname#env_}=\${${varname}}"
+done
+
+mkdir -p "${xvfb_log_path}"
+chown "${buildbot_user}" "${xvfb_log_path}"
+
+exec /usr/bin/setuidgid "${buildbot_user}" \
+ /usr/bin/multilog t "${xvfb_log_path}"
diff --git a/Tools/BuildSlaveSupport/gtk/xvfb/run b/Tools/BuildSlaveSupport/gtk/xvfb/run
new file mode 100755
index 0000000..89cd301
--- /dev/null
+++ b/Tools/BuildSlaveSupport/gtk/xvfb/run
@@ -0,0 +1,41 @@
+#! /bin/bash
+#
+# Copyright (C) 2010 Igalia S.L. All rights reserved.
+#
+# 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.
+
+exec 2>&1
+
+: ${BUILDBOT_CONFIG:=/etc/daemontools-buildbot.conf}
+
+# Read configuration file
+[ -r "${BUILDBOT_CONFIG}" ] && . "${BUILDBOT_CONFIG}"
+
+: ${xvfb_display:=':10'}
+: ${xvfb_mode:='1024x768x24'}
+
+# Expand all "env_*" environment variables
+for varname in ${!env_*} ; do
+ eval "export ${varname#env_}=\${${varname}}"
+done
+
+mkdir -p "xvfb${xvfb_display}"
+exec /usr/bin/Xvfb "${xvfb_display}" \
+ -fbdir "xvfb${xvfb_display}" \
+ -screen 0 "${xvfb_mode}" \
+ -nolisten inet6 \
+ -nolisten inet
+
diff --git a/Tools/BuildSlaveSupport/run-performance-tests b/Tools/BuildSlaveSupport/run-performance-tests
new file mode 100755
index 0000000..5d6ea44
--- /dev/null
+++ b/Tools/BuildSlaveSupport/run-performance-tests
@@ -0,0 +1,80 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Script used by WebKit build slave to kick off performance tests.
+
+use strict;
+
+use FindBin;
+use lib "$FindBin::Bin/../Scripts";
+use webkitdirs;
+
+use Getopt::Long;
+use IO::Socket;
+my $shouldPrebuild = 1;
+
+my $perfMaster = "webkit-build-1.local";
+my $perfSlave = "webkit-build-2.local";
+my $slaveUser = "buildbot";
+my $reportPort = 54481; # Something that looks sorta like SAFARI
+my $slaveDirectory = "/ToTest";
+
+my $buildDirectory = determineConfigurationProductDir();
+
+my $userAndHost = $slaveUser . "@" . $perfSlave;
+my $resultsUploadDestination;
+
+GetOptions('upload-results=s' => \$resultsUploadDestination);
+
+print "Copying built frameworks to PLT slave...\n";
+my @frameworks = ("$buildDirectory/JavaScriptCore.framework", "$buildDirectory/WebCore.framework", "$buildDirectory/WebKit.framework");
+die "Failed to copy to slave\n" unless (system("rsync", "-avz", @frameworks, "$userAndHost:$slaveDirectory") == 0);
+
+print "Opening reponse port for PLT slave...\n";
+my $sock = new IO::Socket::INET(LocalHost => $perfMaster,
+ LocalPort => $reportPort,
+ Proto => 'tcp',
+ Listen => 1,
+ Reuse => 1);
+die "Could not create socket for port $reportPort: $!\n" unless $sock;
+
+print "Starting performance tests on PLT slave...\n";
+die "Failed to start slave!\n" unless (system("ssh", $userAndHost, "autovicki", $slaveDirectory, "--safari", "$slaveDirectory/Safari.app", "--count", 5, "--clean-exit", "--webkit-revision", currentSVNRevision(), "--show-results", "send-completed-results.command") == 0);
+
+print "Waiting for PLT slave to respond...\n";
+my $new_sock = $sock->accept();
+while(<$new_sock>) {
+ print $_;
+}
+close($sock);
+
+if ($resultsUploadDestination) {
+ print "Uploading results to $resultsUploadDestination\n";
+ die "Failed to upload xml results file." unless (system("scp", "$userAndHost:/Results/PerformanceReportSummary.xml", $resultsUploadDestination) == 0);
+ die "Failed to upload svg results file." unless (system("scp", "$userAndHost:/Results/PerformanceGraph.svg", $resultsUploadDestination) == 0);
+}
diff --git a/Tools/BuildSlaveSupport/test-result-archive b/Tools/BuildSlaveSupport/test-result-archive
new file mode 100644
index 0000000..af66bf0
--- /dev/null
+++ b/Tools/BuildSlaveSupport/test-result-archive
@@ -0,0 +1,118 @@
+#!/usr/bin/python
+
+# 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 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 optparse, os, shutil, subprocess, sys, zipfile
+
+sourceRootDirectory = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", ".."))
+archiveFile = os.path.join(sourceRootDirectory, "layout-test-results.zip")
+
+def main():
+ parser = optparse.OptionParser("usage: %prog [options] [action]")
+ parser.add_option("--platform", dest="platform")
+ parser.add_option("--debug", action="store_const", const="debug", dest="configuration")
+ parser.add_option("--release", action="store_const", const="release", dest="configuration")
+
+ options, (action, ) = parser.parse_args()
+ if not options.platform:
+ parser.error("Platform is required")
+ if not options.configuration:
+ parser.error("Configuration is required")
+ if action not in ('archive'):
+ parser.error("Action is required")
+
+ layoutTestResultsDir = os.path.abspath(os.path.join(sourceRootDirectory, "layout-test-results"))
+ if options.platform == 'chromium':
+ # See results_directory() in webkitpy/layout_tests/port/chromium.py.
+ layoutTestResultsDir = os.path.abspath(os.path.join(sourceRootDirectory,
+ "WebKit", "chromium", "webkit", options.configuration.capitalize(),
+ "layout-test-results"))
+
+ return archiveTestResults(options.configuration, options.platform, layoutTestResultsDir)
+
+def archiveTestResults(configuration, platform, layoutTestResultsDir):
+ assert platform in ('mac', 'win', 'gtk', 'qt', 'chromium')
+
+ try:
+ os.unlink(archiveFile)
+ except OSError, e:
+ if e.errno != 2:
+ raise
+
+ try:
+ # Ensure that layoutTestResultsDir exists since we cannot archive a directory that does not exist
+ os.makedirs(layoutTestResultsDir)
+ except OSError, e:
+ if e.errno != 17:
+ raise
+
+ open(os.path.join(layoutTestResultsDir, '.placeholder'), 'w').close()
+
+ if platform == 'mac':
+ if subprocess.call(["ditto", "-c", "-k", "--sequesterRsrc", layoutTestResultsDir, archiveFile]):
+ return 1
+ elif platform in ('win', 'gtk', 'qt'):
+ if subprocess.call(["zip", "-r", archiveFile, "."], cwd=layoutTestResultsDir):
+ return 1
+ elif platform == 'chromium':
+ cwd = os.getcwd()
+ os.chdir(layoutTestResultsDir)
+ zipFilesRecursively(archiveFile, ["."])
+ os.chdir(cwd)
+
+ try:
+ shutil.rmtree(layoutTestResultsDir)
+ except OSError, e:
+
+ # Python in Cygwin throws a mysterious exception with errno of 90
+ # when removing the layout test result directory after successfully
+ # deleting its contents, claiming "Directory not empty".
+ # We can safely ignore this since it was the directory contents that
+ # we are most interested in deleting.
+ if e.errno != 90:
+ raise
+
+def zipFilesRecursively(archiveFile, files):
+ """Make a zip archive.
+
+ Args:
+ archiveFile: The resultant zip archive file name.
+ files: A list of files to be archived. If a list item is a directory,
+ files in the directory are archived recursively."""
+ zipper = zipfile.ZipFile(archiveFile, 'w', zipfile.ZIP_DEFLATED)
+ for file in files:
+ if os.path.isdir(file):
+ for dirPath, dirNames, fileNames in os.walk(file):
+ for fileName in fileNames:
+ relativePath = os.path.join(dirPath, fileName)
+ print "Adding", relativePath
+ zipper.write(relativePath)
+ else:
+ print "Adding", file
+ zipper.write(file)
+ zipper.close()
+ print "Created zip archive: ", archiveFile
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/Tools/BuildSlaveSupport/win/kill-old-processes b/Tools/BuildSlaveSupport/win/kill-old-processes
new file mode 100755
index 0000000..6760e08
--- /dev/null
+++ b/Tools/BuildSlaveSupport/win/kill-old-processes
@@ -0,0 +1,38 @@
+#!/usr/bin/python
+
+# 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 os, sys
+
+def main():
+ tasksToKill = ["DumpRenderTree.exe", "DumpRenderTree_debug.exe", "testapi.exe", "testapi_debug.exe",
+ "svn.exe", "httpd.exe", "cl.exe", "link.exe", "midl.exe", "devenv.exe", "perl.exe",
+ "imagediff.exe", "imagediff_debug.exe", "jsc.exe", "jsc_debug.exe", "WebKit2WebProcess.exe",
+ "WebKit2WebProcess_debug.exe", "WebKitTestRunner.exe", "WebKitTestRunner_debug.exe"]
+
+ for task in tasksToKill:
+ os.system("taskkill /f /im " + task)
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/Tools/CLWrapper/CLWrapper.cpp b/Tools/CLWrapper/CLWrapper.cpp
new file mode 100644
index 0000000..7d41f2b
--- /dev/null
+++ b/Tools/CLWrapper/CLWrapper.cpp
@@ -0,0 +1,52 @@
+// CLWrapper.cpp : Calls the perl script parallelcl to perform parallel compilation
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#include <process.h>
+#include <stdio.h>
+#include <string>
+#include <windows.h>
+
+using namespace std;
+
+int wmain(int argc, wchar_t* argv[])
+{
+ const int numArgs = 3;
+
+#ifndef NDEBUG
+ fwprintf(stderr, L"######### im in ur IDE, compiling ur c0des ########\n");
+#endif
+
+ wstring** args = new wstring*[numArgs];
+
+ args[0] = new wstring(L"sh");
+ args[1] = new wstring(L"-c");
+
+ args[2] = new wstring(L"\"parallelcl");
+ for (int i = 1; i < argc; ++i) {
+ args[2]->append(L" '");
+ args[2]->append(argv[i]);
+ if (i < argc - 1)
+ args[2]->append(L"' ");
+ else
+ args[2]->append(L"'");
+ }
+ args[2]->append(L"\"");
+
+ for (unsigned i = 0; i < args[2]->length(); i++) {
+ if (args[2]->at(i) == '\\')
+ args[2]->at(i) = '/';
+ }
+
+ wchar_t** newArgv = new wchar_t*[numArgs + 1];
+ for (int i = 0; i < numArgs; i++)
+ newArgv[i] = (wchar_t*)args[i]->c_str();
+
+ newArgv[numArgs] = 0;
+
+#ifndef NDEBUG
+ fwprintf(stderr, L"exec(\"%s\", \"%s\", \"%s\", \"%s\")\n", L"sh", newArgv[0], newArgv[1], newArgv[2]);
+#endif
+
+ return _wspawnvp(_P_WAIT, L"sh", newArgv);
+}
+
diff --git a/Tools/CLWrapper/CLWrapper.sln b/Tools/CLWrapper/CLWrapper.sln
new file mode 100644
index 0000000..7501ea6
--- /dev/null
+++ b/Tools/CLWrapper/CLWrapper.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "CLWrapper", "CLWrapper.vcproj", "{230BF635-9BD8-434A-8857-0B096EBC7233}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {230BF635-9BD8-434A-8857-0B096EBC7233}.Debug|Win32.ActiveCfg = Debug|Win32
+ {230BF635-9BD8-434A-8857-0B096EBC7233}.Debug|Win32.Build.0 = Debug|Win32
+ {230BF635-9BD8-434A-8857-0B096EBC7233}.Release|Win32.ActiveCfg = Release|Win32
+ {230BF635-9BD8-434A-8857-0B096EBC7233}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Tools/CLWrapper/CLWrapper.vcproj b/Tools/CLWrapper/CLWrapper.vcproj
new file mode 100644
index 0000000..844d72a
--- /dev/null
+++ b/Tools/CLWrapper/CLWrapper.vcproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="CLWrapper"
+ ProjectGUID="{230BF635-9BD8-434A-8857-0B096EBC7233}"
+ RootNamespace="CLWrapper"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\vcbin"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)\cl.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <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"
+ OutputDirectory="..\vcbin"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)\cl.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <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="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\CLWrapper.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/CMakeListsEfl.txt b/Tools/CMakeListsEfl.txt
new file mode 100644
index 0000000..24ef85c
--- /dev/null
+++ b/Tools/CMakeListsEfl.txt
@@ -0,0 +1,59 @@
+SET(EWebLauncher_SOURCES
+ ${TOOLS_DIR}/EWebLauncher/main.c
+)
+
+SET(EWebLauncher_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(EWebLauncher_INCLUDE_DIRECTORIES
+ "${WEBKIT_DIR}/efl/ewk"
+ ${Cairo_INCLUDE_DIRS}
+ ${EDJE_INCLUDE_DIRS}
+ ${EFLDEPS_INCLUDE_DIRS}
+ ${EVAS_INCLUDE_DIRS}
+)
+
+SET(EWebLauncher_LINK_FLAGS
+ ${ECORE_X_LDFLAGS}
+ ${EDJE_LDFLAGS}
+ ${EFLDEPS_LDFLAGS}
+ ${EVAS_LDFLAGS}
+)
+
+IF (ENABLE_GLIB_SUPPORT)
+ LIST(APPEND EWebLauncher_LIBRARIES
+ ${Gdk_LIBRARIES}
+ ${Glib_LIBRARIES}
+ ${Gthread_LIBRARIES}
+ )
+ENDIF ()
+
+IF (WTF_USE_SOUP)
+ LIST(APPEND EWebLauncher_LIBRARIES ${LIBSOUP24_LIBRARIES})
+ LIST(APPEND EWebLauncher_LINK_FLAGS ${LIBSOUP24_LDFLAGS})
+ENDIF ()
+
+IF (WTF_USE_CURL)
+ LIST(APPEND EWebLauncher_LIBRARIES ${CURL_LIBRARIES})
+ LIST(APPEND EWebLauncher_LINK_FLAGS ${CURL_LDFLAGS})
+ENDIF ()
+
+# Override data directory. We always want to get a fresh theme.
+REMOVE_DEFINITIONS(-DDATA_DIR=\"${DATA_DIR}\")
+ADD_DEFINITIONS(-DDATA_DIR=\"${BUILD_DATA_DIR}\")
+
+INCLUDE_DIRECTORIES(${EWebLauncher_INCLUDE_DIRECTORIES})
+ADD_EXECUTABLE(Programs/EWebLauncher ${EWebLauncher_SOURCES})
+TARGET_LINK_LIBRARIES(Programs/EWebLauncher ${EWebLauncher_LIBRARIES})
+ADD_TARGET_PROPERTIES(Programs/EWebLauncher LINK_FLAGS "${EWebLauncher_LINK_FLAGS}")
diff --git a/Tools/CMakeListsWinCE.txt b/Tools/CMakeListsWinCE.txt
new file mode 100644
index 0000000..6050499
--- /dev/null
+++ b/Tools/CMakeListsWinCE.txt
@@ -0,0 +1,24 @@
+SET(WinCELauncher_INCLUDE_DIRECTORIES
+ "${WEBKIT_DIR}/wince"
+ "${WEBCORE_DIR}"
+ "${WEBCORE_DIR}/platform"
+ "${WEBCORE_DIR}/platform/graphics"
+ "${WEBCORE_DIR}/platform/network"
+ "${WEBCORE_DIR}/platform/text"
+ "${JAVASCRIPTCORE_DIR}"
+ "${JAVASCRIPTCORE_DIR}/wtf"
+ "${DERIVED_SOURCES_DIR}"
+ "${CMAKE_BINARY_DIR}"
+)
+
+SET(WinCELauncher_SOURCES
+ ${WEBKITTOOLS_DIR}/WinCELauncher/main.cpp
+)
+
+SET(WinCELauncher_LIBRARIES
+ ${WebKit_LIBRARY_NAME}
+)
+
+INCLUDE_DIRECTORIES(${WinCELauncher_INCLUDE_DIRECTORIES})
+ADD_EXECUTABLE(WinCELauncher ${WinCELauncher_SOURCES})
+TARGET_LINK_LIBRARIES(WinCELauncher ${WinCELauncher_LIBRARIES})
diff --git a/Tools/CSSTestSuiteHarness/harness/harness.css b/Tools/CSSTestSuiteHarness/harness/harness.css
new file mode 100644
index 0000000..3f4c97d
--- /dev/null
+++ b/Tools/CSSTestSuiteHarness/harness/harness.css
@@ -0,0 +1,308 @@
+/*
+ * 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.
+ */
+
+body {
+ font-family: Helvetica, sans-serif;
+ background-color: #DDD;
+}
+
+.controls {
+ border: 1px solid black;
+ width: 300px;
+ height: 660px;
+ float: left;
+ font-size: smaller;
+ padding: 4px;
+}
+
+.controls div {
+ margin: 4px;
+}
+
+.controls select {
+ width: 100%;
+}
+
+.details > div {
+ margin: 4px 0;
+}
+
+.test-type {
+ float: left;
+}
+
+.name > button {
+ margin-top: 20px;
+ float: right;
+}
+
+.actions {
+ margin-left: 320px;
+ border: 1px solid black;
+ font-size: smaller;
+ height: 30px;
+ padding: 4px;
+ margin-bottom: 8px;
+}
+
+.actions button {
+ font-size: 13px;
+ width: 5em;
+}
+
+.note {
+ display: inline-block;
+ font-size: 10px;
+ margin-left: 5px;
+ color: gray;
+}
+.action-buttons {
+ float: right;
+}
+
+#test-content {
+ margin-left: 320px;
+ height: 612px;
+ border: 1px solid black;
+ padding: 4px;
+ background-color: white;
+}
+
+.info > div {
+ margin: 6px 0;
+}
+
+.info .title {
+ font-size: larger;
+ font-weight: bold;
+}
+
+.info .url {
+ font-family: monospace;
+}
+
+.info .assertion, .info .flags {
+ font-size: smaller;
+}
+
+#warning {
+ padding-left: 1em;
+ color: red;
+ display: none;
+}
+
+#print-button {
+ float: right;
+ display: none;
+}
+
+#test-content.print {
+}
+
+#test-content.print #print-button {
+ display: inline;
+}
+
+#test-content.warn #warning {
+ display: inline;
+}
+
+#test-content iframe {
+ border: 1px solid gray;
+ margin: 2px;
+}
+
+#test-content h2 {
+ font-size: 11pt;
+ margin: 2px 0 2px 0;
+ color: darkgray;
+}
+
+#test-list > option.untested {
+}
+
+#test-list > option.pass {
+ color: rgba(0, 128, 0, 0.6);
+}
+
+#test-list > option.fail {
+ color: rgba(255, 0, 0, 0.6);
+}
+
+#test-list > option.skipped {
+ color: rgba(255, 128, 0, 0.6);
+}
+
+#test-content.with-ref {
+}
+
+.frame-wrapper {
+
+}
+
+.frame-wrapper iframe {
+ width: 98%;
+ height: 460px;
+}
+
+.frame-wrapper {
+ height: 500px;
+ width: 99%;
+ display: inline-block;
+}
+
+.with-ref > .frame-wrapper {
+ width: 49%;
+}
+
+#ref-wrapper {
+ height: 500px;
+ width: 49%;
+ display: none;
+}
+
+.with-ref > #ref-wrapper {
+ display: inline-block;
+}
+
+.results {
+ border: 1px solid black;
+ padding: 4px;
+ margin-top: 6px;
+}
+
+#output {
+ border: 1px solid black;
+ font-size: smaller;
+ height: 220px;
+ margin: 4px;
+ padding: 4px;
+ overflow-y: auto;
+ background-color: white;
+}
+
+#output > p {
+ margin: 0;
+}
+#output .pass {
+ color: green;
+}
+
+#output .fail {
+ color: red;
+}
+
+#output .skipped {
+ color: orange;
+}
+
+#output .invalid {
+ background: red;
+}
+
+.output-options {
+ float: right;
+ border: 1px solid black;
+ width: 200px;
+ height: 220px;
+ margin: 4px;
+ padding: 4px;
+ font-size: smaller;
+}
+
+.output-options select {
+ width: 90%;
+}
+
+.summary {
+ font-size: smaller;
+ margin: 4px;
+}
+
+.summary .label {
+ display: inline-block;
+ min-width: 5em;
+ margin: 0;
+}
+
+.summary span {
+ display: inline-block;
+ min-width: 3em;
+ text-align: right;
+ margin: 0;
+}
+
+.summary td {
+ text-align: right;
+ padding: 4px;
+}
+
+.custom button {
+ display: block;
+ margin: 12px 0;
+}
+
+/* Overlay */
+
+#overlay {
+ position: fixed;
+ top: 0;
+ left: 0;
+ bottom: 0;
+ right: 0;
+ background-color: rgba(0, 0, 0, 0.6);
+ display: none;
+}
+
+#overlay.visible {
+ display: block;
+}
+
+.overlay-contents {
+ position: relative;
+ background-color: white;
+ margin: 50px auto;
+ width: 1000px;
+ padding: 20px;
+}
+
+.overlay-contents textarea {
+ width: 90em;
+ height: 50em;
+}
+.overlay-contents .buttons {
+ text-align: right;
+}
+
+.overlay-contents .note {
+ float: left;
+}
+
+.overlay-contents .buttons button {
+ font-size: 13px;
+ width: 6em;
+ margin: 12px 8px;
+}
+
diff --git a/Tools/CSSTestSuiteHarness/harness/harness.html b/Tools/CSSTestSuiteHarness/harness/harness.html
new file mode 100644
index 0000000..3877f49
--- /dev/null
+++ b/Tools/CSSTestSuiteHarness/harness/harness.html
@@ -0,0 +1,262 @@
+<!--
+/*
+ * 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.
+ */
+-->
+
+<!DOCTYPE html>
+<html>
+ <head>
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
+ <title>CSS 2.1 Test Harness</title>
+ <link rel="stylesheet" href="harness.css" type="text/css" media="screen" charset="utf-8">
+
+ <script src="http://code.jquery.com/jquery-1.4.2.min.js" type="text/javascript" charset="utf-8"></script>
+ <script src="harness.js" type="text/javascript" charset="utf-8"></script>
+
+ <script type="text/javascript" charset="utf-8">
+ var gTestSuite;
+ function setupTests()
+ {
+ gTestSuite = new TestSuite();
+ }
+
+ window.addEventListener('load', setupTests, false);
+
+ function skipTest()
+ {
+ gTestSuite.skipTest(document.getElementById('skip-reason').value);
+ }
+
+ function invalidTest()
+ {
+ gTestSuite.invalidTest();
+ }
+
+ function failTest()
+ {
+ gTestSuite.failTest();
+ }
+
+ function passTest()
+ {
+ gTestSuite.passTest();
+ }
+
+ function goToNextUntested()
+ {
+ gTestSuite.goToNextIncompleteTest();
+ }
+
+ function goToTest()
+ {
+ var testName = prompt('Go to test:', '');
+
+ // This accepts any of the following:
+ // at-charset-010
+ // at-charset-010.xht
+ // xhtml1/at-charset-010
+ // xhtml1/at-charset-010.xht
+ // and will choose the format if specified.
+ if (!gTestSuite.goToTestByName(testName))
+ alert('Failed to find test ' + testName);
+ }
+
+ function formatChanged()
+ {
+ var newFormat;
+ if (document.harness.format.html4.checked)
+ newFormat = 'html4';
+ else
+ newFormat = 'xhtml1';
+ gTestSuite.formatChanged(newFormat);
+ }
+
+ function testSelected()
+ {
+ var list = document.getElementById('test-list')
+ if (list.selectedIndex >= 0)
+ gTestSuite.goToTestIndex(list.selectedIndex);
+ else
+ gTestSuite.clearTest();
+ }
+
+ function resultsPopupChanged(popup)
+ {
+ gTestSuite.resultsPopupChanged(popup.selectedIndex);
+ }
+
+ function doExport()
+ {
+ gTestSuite.exportResults(document.getElementById('results-popup').selectedIndex);
+ }
+
+ function printTestIframe()
+ {
+ var testFrame = document.getElementById('test-frame');
+ testFrame.contentWindow.print();
+ }
+
+ var gOverlayConfirmCallback;
+ function showOverlay(overlayConfirmCallback)
+ {
+ document.getElementById('overlay-data').value = '';
+ gOverlayConfirmCallback = overlayConfirmCallback;
+ $('#overlay').addClass('visible');
+ }
+
+ function overlayCancel()
+ {
+ $('#overlay').removeClass('visible');
+ }
+
+ function overlayConfirm()
+ {
+ var data = document.getElementById('overlay-data').value;
+ gOverlayConfirmCallback(data);
+ $('#overlay').removeClass('visible');
+ }
+
+ function doImport()
+ {
+ document.getElementById('overlay-action').innerText = 'Enter results to import (in the same format as the exported results):';
+ showOverlay(function(data) {
+ gTestSuite.importResults(data);
+ });
+ }
+
+ function doClear()
+ {
+ document.getElementById('overlay-action').innerText = 'Enter list of tests for which to clear results (so they can be re-tested):';
+ showOverlay(function(data) {
+ gTestSuite.clearResults(data);
+ });
+ }
+ </script>
+
+</head>
+<body>
+
+ <div class="controls">
+ <form name="harness" onsubmit="return false;">
+ <select id="chapters">
+ <option>Test category</option>
+ </select>
+ <div class="progress">
+ <div><span id="test-index">1</span> of <span id="chapter-test-count">200</span> unique tests</div>
+ </div>
+ <div class="details">
+ <div class="name">
+ <div class="test-type">
+ <input type="radio" name="format" id="html4" onchange="formatChanged()" checked><label for="html4">HTML4</label><br>
+ <input type="radio" name="format" id="xhtml1" onchange="formatChanged()"><label for="xhtml1">XHTML1</label>
+ </div>
+ <button onclick="goToNextUntested()" accesskey="n"><strong>N</strong>ext Untested</button>
+ <button onclick="goToTest()" accesskey="g">Go to Test...</button>
+ </div>
+ </div>
+
+ <div>
+ <select id="test-list" size="40" onchange="testSelected()"></select>
+ </div>
+ </form>
+ </div>
+
+ <div class="actions">
+ <span>Skip reason:</span> <input type="text" id="skip-reason" size="50">
+ <button onclick="skipTest()" accesskey="s"><strong>S</strong>kip</button>
+ <div class="note">Use <i>Control-Option-letter</i> to<br> trigger buttons via the keyboard.</div>
+ <div class="action-buttons">
+ <button onclick="invalidTest()" accesskey="i">Invalid</button>
+ <button onclick="failTest()" accesskey="f"><strong>F</strong>ail</button>
+ <button onclick="passTest()" accesskey="p"><strong>P</strong>ass</button>
+ </div>
+ </div>
+ <div id="test-content">
+ <div class="info">
+ <div class="title">Title: <span id="test-title"></span></div>
+ <div class="url">URL: <span id="test-url"></span></div>
+ <div class="assertion">Assertion: <span id="test-assertion"></span></div>
+ <div class="flags">Flags: <span id="test-flags"></span>
+ <span id="warning">This test must be run over HTTP.</span>
+ <button id="print-button" onclick="printTestIframe()">Print Preview</button>
+ </div>
+ </div>
+
+ <div id="test-wrapper" class="frame-wrapper">
+ <h2>Test</h2>
+ <iframe id="test-frame"></iframe>
+ </div>
+ <div id="ref-wrapper" class="frame-wrapper">
+ <h2>Reference</h2>
+ <iframe id="ref-frame"></iframe>
+ </div>
+ </div>
+
+ <div class="results">
+
+ <div class="output-options">
+ <p>Show results for:</p>
+ <select id="results-popup" onchange="resultsPopupChanged(this)">
+ </select>
+ <div>
+ <button id="export-button" onclick="doExport()">Export...</button>
+ </div>
+
+ <div class="custom">
+ <button id="import-button" onclick="doImport()">Import...</button>
+ <button id="import-button" onclick="doClear()">Clear Results...</button>
+ </div>
+ </div>
+
+ <div id="output"></div>
+ <div class="summary">
+ <table>
+ <tr>
+ <th></th><th>Passed</th><th>Failed</th><th>Skipped</th><th>Invalid</th><th>Tested</th><th>Total</th><th>% done</th>
+ </tr>
+ <tr>
+ <td class="label">HTML4:</td><td id="h-passed"></td><td id="h-failed"></td><td id="h-skipped"></td><td id="h-invalid"></td><td id="h-tested"></td><td id="h-total"></td><td id="h-percent"></td>
+ </tr>
+ <tr>
+ <td class="label">XHTML1:</td><td id="x-passed"></td><td id="x-failed"></td><td id="x-skipped"></td><td id="x-invalid"></td><td id="x-tested"></td><td id="x-total"></td><td id="x-percent"></td>
+ </tr>
+ </table>
+ </div>
+ </div>
+
+ <div id="overlay">
+
+ <div class="overlay-contents">
+ <p id="overlay-action"></p>
+ <textarea id="overlay-data"></textarea>
+ <p class="note">Pasting many lines of text here can be very slow in Safari 5. You can quit Safari and use a <a href="http://nightly.webkit.org/" title="WebKit Nightly Builds">WebKit nightly build</a> for importing or clearing.</p>
+ <div class="buttons">
+ <button onclick="overlayCancel()">Cancel</button><button onclick="overlayConfirm()">OK</button>
+ </div>
+ </div>
+
+ </div>
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/CSSTestSuiteHarness/harness/harness.js b/Tools/CSSTestSuiteHarness/harness/harness.js
new file mode 100644
index 0000000..ed7cb7d
--- /dev/null
+++ b/Tools/CSSTestSuiteHarness/harness/harness.js
@@ -0,0 +1,1902 @@
+/*
+ * 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.
+ */
+
+// requires jQuery
+
+const kTestSuiteVersion = '20101001';
+const kTestSuiteHome = '../' + kTestSuiteVersion + '/';
+const kTestInfoDataFile = 'testinfo.data';
+
+const kChapterData = [
+ {
+ 'file' : 'about.html',
+ 'title' : 'About the CSS 2.1 Specification',
+ },
+ {
+ 'file' : 'intro.html',
+ 'title' : 'Introduction to CSS 2.1',
+ },
+ {
+ 'file' : 'conform.html',
+ 'title' : 'Conformance: Requirements and Recommendations',
+ },
+ {
+ 'file' : "syndata.html",
+ 'title' : 'Syntax and basic data types',
+ },
+ {
+ 'file' : 'selector.html' ,
+ 'title' : 'Selectors',
+ },
+ {
+ 'file' : 'cascade.html',
+ 'title' : 'Assigning property values, Cascading, and Inheritance',
+ },
+ {
+ 'file' : 'media.html',
+ 'title' : 'Media types',
+ },
+ {
+ 'file' : 'box.html' ,
+ 'title' : 'Box model',
+ },
+ {
+ 'file' : 'visuren.html',
+ 'title' : 'Visual formatting model',
+ },
+ {
+ 'file' :'visudet.html',
+ 'title' : 'Visual formatting model details',
+ },
+ {
+ 'file' : 'visufx.html',
+ 'title' : 'Visual effects',
+ },
+ {
+ 'file' : 'generate.html',
+ 'title' : 'Generated content, automatic numbering, and lists',
+ },
+ {
+ 'file' : 'page.html',
+ 'title' : 'Paged media',
+ },
+ {
+ 'file' : 'colors.html',
+ 'title' : 'Colors and Backgrounds',
+ },
+ {
+ 'file' : 'fonts.html',
+ 'title' : 'Fonts',
+ },
+ {
+ 'file' : 'text.html',
+ 'title' : 'Text',
+ },
+ {
+ 'file' : 'tables.html',
+ 'title' : 'Tables',
+ },
+ {
+ 'file' : 'ui.html',
+ 'title' : 'User interface',
+ },
+ {
+ 'file' : 'aural.html',
+ 'title' : 'Appendix A. Aural style sheets',
+ },
+ {
+ 'file' : 'refs.html',
+ 'title' : 'Appendix B. Bibliography',
+ },
+ {
+ 'file' : 'changes.html',
+ 'title' : 'Appendix C. Changes',
+ },
+ {
+ 'file' : 'sample.html',
+ 'title' : 'Appendix D. Default style sheet for HTML 4',
+ },
+ {
+ 'file' : 'zindex.html',
+ 'title' : 'Appendix E. Elaborate description of Stacking Contexts',
+ },
+ {
+ 'file' : 'propidx.html',
+ 'title' : 'Appendix F. Full property table',
+ },
+ {
+ 'file' : 'grammar.html',
+ 'title' : 'Appendix G. Grammar of CSS',
+ },
+ {
+ 'file' : 'other.html',
+ 'title' : 'Other',
+ },
+];
+
+
+const kHTML4Data = {
+ 'path' : 'html4',
+ 'suffix' : '.htm'
+};
+
+const kXHTML1Data = {
+ 'path' : 'xhtml1',
+ 'suffix' : '.xht'
+};
+
+// Results popup
+const kResultsSelector = [
+ {
+ 'name': 'All Tests',
+ 'handler' : function(self) { self.showResultsForAllTests(); },
+ 'exporter' : function(self) { self.exportResultsForAllTests(); }
+ },
+ {
+ 'name': 'Completed Tests',
+ 'handler' : function(self) { self.showResultsForCompletedTests(); },
+ 'exporter' : function(self) { self.exportResultsForCompletedTests(); }
+ },
+ {
+ 'name': 'Passing Tests',
+ 'handler' : function(self) { self.showResultsForTestsWithStatus('pass'); },
+ 'exporter' : function(self) { self.exportResultsForTestsWithStatus('pass'); }
+ },
+ {
+ 'name': 'Failing Tests',
+ 'handler' : function(self) { self.showResultsForTestsWithStatus('fail'); },
+ 'exporter' : function(self) { self.exportResultsForTestsWithStatus('fail'); }
+ },
+ {
+ 'name': 'Skipped Tests',
+ 'handler' : function(self) { self.showResultsForTestsWithStatus('skipped'); },
+ 'exporter' : function(self) { self.exportResultsForTestsWithStatus('skipped'); }
+ },
+ {
+ 'name': 'Invalid Tests',
+ 'handler' : function(self) { self.showResultsForTestsWithStatus('invalid'); },
+ 'exporter' : function(self) { self.exportResultsForTestsWithStatus('invalid'); }
+ },
+ {
+ 'name': 'Tests where HTML4 and XHTML1 results differ',
+ 'handler' : function(self) { self.showResultsForTestsWithMismatchedResults(); },
+ 'exporter' : function(self) { self.exportResultsForTestsWithMismatchedResults(); }
+ },
+ {
+ 'name': 'Tests Not Run',
+ 'handler' : function(self) { self.showResultsForTestsNotRun(); },
+ 'exporter' : function(self) { self.exportResultsForTestsNotRun(); }
+ }
+];
+
+function Test(testInfoLine)
+{
+ var fields = testInfoLine.split('\t');
+
+ this.id = fields[0];
+ this.reference = fields[1];
+ this.title = fields[2];
+ this.flags = fields[3];
+ this.links = fields[4];
+ this.assertion = fields[5];
+
+ this.paged = false;
+ this.testHTML = true;
+ this.testXHTML = true;
+
+ if (this.flags) {
+ this.paged = this.flags.indexOf('paged') != -1;
+
+ if (this.flags.indexOf('nonHTML') != -1)
+ this.testHTML = false;
+
+ if (this.flags.indexOf('HTMLonly') != -1)
+ this.testXHTML = false;
+ }
+
+ this.completedHTML = false; // true if this test has a result (pass, fail or skip)
+ this.completedXHTML = false; // true if this test has a result (pass, fail or skip)
+
+ this.statusHTML = '';
+ this.statusXHTML = '';
+
+ if (!this.links)
+ this.links = "other.html"
+}
+
+Test.prototype.runForFormat = function(format)
+{
+ if (format == 'html4')
+ return this.testHTML;
+
+ if (format == 'xhtml1')
+ return this.testXHTML;
+
+ return true;
+}
+
+Test.prototype.completedForFormat = function(format)
+{
+ if (format == 'html4')
+ return this.completedHTML;
+
+ if (format == 'xhtml1')
+ return this.completedXHTML;
+
+ return true;
+}
+
+Test.prototype.statusForFormat = function(format)
+{
+ if (format == 'html4')
+ return this.statusHTML;
+
+ if (format == 'xhtml1')
+ return this.statusXHTML;
+
+ return true;
+}
+
+function ChapterSection(link)
+{
+ var result= link.match(/^([.\w]+)(#.+)?$/);
+ if (result != null) {
+ this.file = result[1];
+ this.anchor = result[2];
+ }
+
+ this.testCountHTML = 0;
+ this.testCountXHTML = 0;
+
+ this.tests = [];
+}
+
+ChapterSection.prototype.countTests = function()
+{
+ this.testCountHTML = 0;
+ this.testCountXHTML = 0;
+
+ for (var i = 0; i < this.tests.length; ++i) {
+ var currTest = this.tests[i];
+
+ if (currTest.testHTML)
+ ++this.testCountHTML;
+
+ if (currTest.testXHTML)
+ ++this.testCountXHTML;
+ }
+}
+
+function Chapter(chapterInfo)
+{
+ this.file = chapterInfo.file;
+ this.title = chapterInfo.title;
+ this.testCountHTML = 0;
+ this.testCountXHTML = 0;
+ this.sections = []; // array of ChapterSection
+}
+
+Chapter.prototype.description = function(format)
+{
+
+
+ return this.title + ' (' + this.testCount(format) + ' tests, ' + this.untestedCount(format) + ' untested)';
+}
+
+Chapter.prototype.countTests = function()
+{
+ this.testCountHTML = 0;
+ this.testCountXHTML = 0;
+
+ for (var i = 0; i < this.sections.length; ++i) {
+ var currSection = this.sections[i];
+
+ currSection.countTests();
+
+ this.testCountHTML += currSection.testCountHTML;
+ this.testCountXHTML += currSection.testCountXHTML;
+ }
+}
+
+Chapter.prototype.testCount = function(format)
+{
+ if (format == 'html4')
+ return this.testCountHTML;
+
+ if (format == 'xhtml1')
+ return this.testCountXHTML;
+
+ return 0;
+}
+
+Chapter.prototype.untestedCount = function(format)
+{
+ var completedProperty = format == 'html4' ? 'completedHTML' : 'completedXHTML';
+
+ var count = 0;
+ for (var i = 0; i < this.sections.length; ++i) {
+ var currSection = this.sections[i];
+ for (var j = 0; j < currSection.tests.length; ++j) {
+ count += currSection.tests[j].completedForFormat(format) ? 0 : 1;
+ }
+ }
+ return count;
+
+}
+
+// Utils
+String.prototype.trim = function() { return this.replace(/^\s+|\s+$/g, ''); }
+
+function TestSuite()
+{
+ this.chapterSections = {}; // map of links to ChapterSections
+ this.tests = {}; // map of test id to test info
+
+ this.chapters = {}; // map of file name to chapter
+ this.currentChapter = null;
+
+ this.currentChapterTests = []; // array of tests for the current chapter.
+ this.currChapterTestIndex = -1; // index of test in the current chapter
+
+ this.format = '';
+ this.formatChanged('html4');
+
+ this.testInfoLoaded = false;
+
+ this.populatingDatabase = false;
+
+ var testInfoPath = kTestSuiteHome + kTestInfoDataFile;
+ this.loadTestInfo(testInfoPath);
+}
+
+TestSuite.prototype.loadTestInfo = function(testInfoPath)
+{
+ var _self = this;
+ this.asyncLoad(testInfoPath, 'data', function(data, status) {
+ _self.testInfoDataLoaded(data, status);
+ });
+}
+
+TestSuite.prototype.testInfoDataLoaded = function(data, status)
+{
+ if (status != 'success') {
+ alert("Failed to load testinfo.data. Database of tests will not be initialized.");
+ return;
+ }
+
+ this.parseTests(data);
+ this.buildChapters();
+
+ this.testInfoLoaded = true;
+
+ this.fillChapterPopup();
+
+ this.initializeControls();
+
+ this.openDatabase();
+}
+
+TestSuite.prototype.parseTests = function(data)
+{
+ var lines = data.split('\n');
+
+ // First line is column labels
+ for (var i = 1; i < lines.length; ++i) {
+ var test = new Test(lines[i]);
+ if (test.id.length > 0)
+ this.tests[test.id] = test;
+ }
+}
+
+TestSuite.prototype.buildChapters = function()
+{
+ for (var testID in this.tests) {
+ var currTest = this.tests[testID];
+
+ // FIXME: tests with more than one link will be presented to the user
+ // twice. Be smarter about avoiding this.
+ var testLinks = currTest.links.split(',');
+ for (var i = 0; i < testLinks.length; ++i) {
+ var link = testLinks[i];
+ var section = this.chapterSections[link];
+ if (!section) {
+ section = new ChapterSection(link);
+ this.chapterSections[link] = section;
+ }
+
+ section.tests.push(currTest);
+ }
+ }
+
+ for (var i = 0; i < kChapterData.length; ++i) {
+ var chapter = new Chapter(kChapterData[i]);
+ chapter.index = i;
+ this.chapters[chapter.file] = chapter;
+ }
+
+ for (var sectionName in this.chapterSections) {
+ var section = this.chapterSections[sectionName];
+
+ var file = section.file;
+ var chapter = this.chapters[file];
+ if (!chapter)
+ window.console.log('failed to find chapter ' + file + ' in chapter data.');
+ chapter.sections.push(section);
+ }
+
+ for (var chapterName in this.chapters) {
+ var currChapter = this.chapters[chapterName];
+ currChapter.sections.sort();
+ currChapter.countTests();
+ }
+}
+
+TestSuite.prototype.indexOfChapter = function(chapter)
+{
+ for (var i = 0; i < kChapterData.length; ++i) {
+ if (kChapterData[i].file == chapter.file)
+ return i;
+ }
+
+ window.console.log('indexOfChapter for ' + chapter.file + ' failed');
+ return -1;
+}
+
+TestSuite.prototype.chapterAtIndex = function(index)
+{
+ if (index < 0 || index >= kChapterData.length)
+ return null;
+
+ return this.chapters[kChapterData[index].file];
+}
+
+TestSuite.prototype.fillChapterPopup = function()
+{
+ var select = document.getElementById('chapters')
+ select.innerHTML = ''; // Remove all children.
+
+ for (var i = 0; i < kChapterData.length; ++i) {
+ var chapterData = kChapterData[i];
+ var chapter = this.chapters[chapterData.file];
+
+ var option = document.createElement('option');
+ option.innerText = chapter.description(this.format);
+ option._chapter = chapter;
+
+ select.appendChild(option);
+ }
+}
+
+TestSuite.prototype.updateChapterPopup = function()
+{
+ var select = document.getElementById('chapters')
+ var currOption = select.firstChild;
+
+ for (var i = 0; i < kChapterData.length; ++i) {
+ var chapterData = kChapterData[i];
+ var chapter = this.chapters[chapterData.file];
+ if (!chapter)
+ continue;
+ currOption.innerText = chapter.description(this.format);
+ currOption = currOption.nextSibling;
+ }
+}
+
+TestSuite.prototype.buildTestListForChapter = function(chapter)
+{
+ this.currentChapterTests = this.testListForChapter(chapter);
+}
+
+TestSuite.prototype.testListForChapter = function(chapter)
+{
+ var testList = [];
+
+ for (var i in chapter.sections) {
+ var currSection = chapter.sections[i];
+
+ for (var j = 0; j < currSection.tests.length; ++j) {
+ var currTest = currSection.tests[j];
+ if (currTest.runForFormat(this.format))
+ testList.push(currTest);
+ }
+ }
+
+ // FIXME: test may occur more than once.
+ testList.sort(function(a, b) {
+ return a.id.localeCompare(b.id);
+ });
+
+ return testList;
+}
+
+TestSuite.prototype.initializeControls = function()
+{
+ var chaptersPopup = document.getElementById('chapters');
+
+ var _self = this;
+ chaptersPopup.addEventListener('change', function() {
+ _self.chapterPopupChanged();
+ }, false);
+
+ this.chapterPopupChanged();
+
+ // Results popup
+ var resultsPopup = document.getElementById('results-popup');
+ resultsPopup.innerHTML = '';
+
+ for (var i = 0; i < kResultsSelector.length; ++i) {
+ var option = document.createElement('option');
+ option.innerText = kResultsSelector[i].name;
+
+ resultsPopup.appendChild(option);
+ }
+}
+
+TestSuite.prototype.chapterPopupChanged = function()
+{
+ var chaptersPopup = document.getElementById('chapters');
+ var selectedChapter = chaptersPopup.options[chaptersPopup.selectedIndex]._chapter;
+
+ this.setSelectedChapter(selectedChapter);
+}
+
+TestSuite.prototype.fillTestList = function()
+{
+ var statusProperty = this.format == 'html4' ? 'statusHTML' : 'statusXHTML';
+
+ var testList = document.getElementById('test-list');
+ testList.innerHTML = '';
+
+ for (var i = 0; i < this.currentChapterTests.length; ++i) {
+ var currTest = this.currentChapterTests[i];
+
+ var option = document.createElement('option');
+ option.innerText = currTest.id;
+ option.className = currTest[statusProperty];
+ option._test = currTest;
+ testList.appendChild(option);
+ }
+}
+
+TestSuite.prototype.updateTestList = function()
+{
+ var statusProperty = this.format == 'html4' ? 'statusHTML' : 'statusXHTML';
+ var testList = document.getElementById('test-list');
+
+ var options = testList.getElementsByTagName('option');
+ for (var i = 0; i < options.length; ++i) {
+ var currOption = options[i];
+ currOption.className = currOption._test[statusProperty];
+ }
+}
+
+TestSuite.prototype.setSelectedChapter = function(chapter)
+{
+ this.currentChapter = chapter;
+ this.buildTestListForChapter(this.currentChapter);
+ this.currChapterTestIndex = -1;
+
+ this.fillTestList();
+ this.goToTestIndex(0);
+
+ var chaptersPopup = document.getElementById('chapters');
+ chaptersPopup.selectedIndex = this.indexOfChapter(chapter);
+}
+
+/* ------------------------------------------------------- */
+
+TestSuite.prototype.passTest = function()
+{
+ this.recordResult(this.currentTestName(), 'pass');
+ this.nextTest();
+}
+
+TestSuite.prototype.failTest = function()
+{
+ this.recordResult(this.currentTestName(), 'fail');
+ this.nextTest();
+}
+
+TestSuite.prototype.invalidTest = function()
+{
+ this.recordResult(this.currentTestName(), 'invalid');
+ this.nextTest();
+}
+
+TestSuite.prototype.skipTest = function(reason)
+{
+ this.recordResult(this.currentTestName(), 'skipped', reason);
+ this.nextTest();
+}
+
+TestSuite.prototype.nextTest = function()
+{
+ if (this.currChapterTestIndex < this.currentChapterTests.length - 1)
+ this.goToTestIndex(this.currChapterTestIndex + 1);
+ else {
+ var currChapterIndex = this.indexOfChapter(this.currentChapter);
+ this.goToChapterIndex(currChapterIndex + 1);
+ }
+}
+
+TestSuite.prototype.previousTest = function()
+{
+ if (this.currChapterTestIndex > 0)
+ this.goToTestIndex(this.currChapterTestIndex - 1);
+ else {
+ var currChapterIndex = this.indexOfChapter(this.currentChapter);
+ if (currChapterIndex > 0)
+ this.goToChapterIndex(currChapterIndex - 1);
+ }
+}
+
+TestSuite.prototype.goToNextIncompleteTest = function()
+{
+ var completedProperty = this.format == 'html4' ? 'completedHTML' : 'completedXHTML';
+
+ // Look to the end of this chapter.
+ for (var i = this.currChapterTestIndex + 1; i < this.currentChapterTests.length; ++i) {
+ if (!this.currentChapterTests[i][completedProperty]) {
+ this.goToTestIndex(i);
+ return;
+ }
+ }
+
+ // Start looking through later chapter
+ var currChapterIndex = this.indexOfChapter(this.currentChapter);
+ for (var c = currChapterIndex + 1; c < kChapterData.length; ++c) {
+ var chapterData = this.chapterAtIndex(c);
+
+ var testIndex = this.firstIncompleteTestIndex(chapterData);
+ if (testIndex != -1) {
+ this.goToChapterIndex(c);
+ this.goToTestIndex(testIndex);
+ break;
+ }
+ }
+}
+
+TestSuite.prototype.firstIncompleteTestIndex = function(chapter)
+{
+ var completedProperty = this.format == 'html4' ? 'completedHTML' : 'completedXHTML';
+
+ var chapterTests = this.testListForChapter(chapter);
+ for (var i = 0; i < chapterTests.length; ++i) {
+ if (!chapterTests[i][completedProperty])
+ return i;
+ }
+
+ return -1;
+}
+
+/* ------------------------------------------------------- */
+
+TestSuite.prototype.goToTestByName = function(testName)
+{
+ var match = testName.match(/^(?:(html4|xhtml1)\/)?([\w-_]+)(\.xht|\.htm)?/);
+ if (!match)
+ return false;
+
+ var prefix = match[1];
+ var testId = match[2];
+ var extension = match[3];
+
+ var format = this.format;
+ if (prefix)
+ format = prefix;
+ else if (extension) {
+ if (extension == kXHTML1Data.suffix)
+ format = kXHTML1Data.path;
+ else if (extension == kHTML4Data.suffix)
+ format = kHTML4Data.path;
+ }
+
+ this.switchToFormat(format);
+
+ var test = this.tests[testId];
+ if (!test)
+ return false;
+
+ // Find the first chapter.
+ var links = test.links.split(',');
+ if (links.length == 0) {
+ window.console.log('test ' + test.id + 'had no links.');
+ return false;
+ }
+
+ var firstLink = links[0];
+ var result = firstLink.match(/^([.\w]+)(#.+)?$/);
+ if (result)
+ firstLink = result[1];
+
+ // Find the chapter and index of the test.
+ for (var i = 0; i < kChapterData.length; ++i) {
+ var chapterData = kChapterData[i];
+ if (chapterData.file == firstLink) {
+
+ this.goToChapterIndex(i);
+
+ for (var j = 0; j < this.currentChapterTests.length; ++j) {
+ var currTest = this.currentChapterTests[j];
+ if (currTest.id == testId) {
+ this.goToTestIndex(j);
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+TestSuite.prototype.goToTestIndex = function(index)
+{
+ if (index >= 0 && index < this.currentChapterTests.length) {
+ this.currChapterTestIndex = index;
+ this.loadCurrentTest();
+ }
+}
+
+TestSuite.prototype.goToChapterIndex = function(chapterIndex)
+{
+ if (chapterIndex >= 0 && chapterIndex < kChapterData.length) {
+ var chapterFile = kChapterData[chapterIndex].file;
+ this.setSelectedChapter(this.chapters[chapterFile]);
+ }
+}
+
+TestSuite.prototype.currentTestName = function()
+{
+ if (this.currChapterTestIndex < 0 || this.currChapterTestIndex >= this.currentChapterTests.length)
+ return undefined;
+
+ return this.currentChapterTests[this.currChapterTestIndex].id;
+}
+
+TestSuite.prototype.loadCurrentTest = function()
+{
+ var theTest = this.currentChapterTests[this.currChapterTestIndex];
+ if (!theTest) {
+ this.configureForManualTest();
+ this.clearTest();
+ return;
+ }
+
+ if (theTest.reference) {
+ this.configureForRefTest();
+ this.loadRef(theTest);
+ } else {
+ this.configureForManualTest();
+ }
+
+ this.loadTest(theTest);
+
+ this.updateProgressLabel();
+
+ document.getElementById('test-list').selectedIndex = this.currChapterTestIndex;
+}
+
+TestSuite.prototype.updateProgressLabel = function()
+{
+ document.getElementById('test-index').innerText = this.currChapterTestIndex + 1;
+ document.getElementById('chapter-test-count').innerText = this.currentChapterTests.length;
+}
+
+TestSuite.prototype.configureForRefTest = function()
+{
+ $('#test-content').addClass('with-ref');
+}
+
+TestSuite.prototype.configureForManualTest = function()
+{
+ $('#test-content').removeClass('with-ref');
+}
+
+TestSuite.prototype.loadTest = function(test)
+{
+ var iframe = document.getElementById('test-frame');
+ iframe.src = 'about:blank';
+
+ var url = this.urlForTest(test.id);
+ window.setTimeout(function() {
+ iframe.src = url;
+ }, 0);
+
+ document.getElementById('test-title').innerText = test.title;
+ document.getElementById('test-url').innerText = this.pathForTest(test.id);
+ document.getElementById('test-assertion').innerText = test.assertion;
+ document.getElementById('test-flags').innerText = test.flags;
+
+ this.processFlags(test);
+}
+
+TestSuite.prototype.processFlags = function(test)
+{
+ if (test.paged)
+ $('#test-content').addClass('print');
+ else
+ $('#test-content').removeClass('print');
+
+ var showWarning = false;
+ var warning = '';
+ if (test.flags.indexOf('font') != -1)
+ warning = 'Requires a specific font to be installed.';
+
+ if (test.flags.indexOf('http') != -1) {
+ if (warning != '')
+ warning += ' ';
+ warning += 'Must be tested over HTTP, with custom HTTP headers.';
+ }
+
+ if (test.paged) {
+ if (warning != '')
+ warning += ' ';
+ warning += 'Test via the browser\'s Print Preview.';
+ }
+
+ document.getElementById('warning').innerText = warning;
+
+ if (warning.length > 0)
+ $('#test-content').addClass('warn');
+ else
+ $('#test-content').removeClass('warn');
+
+}
+
+TestSuite.prototype.clearTest = function()
+{
+ var iframe = document.getElementById('test-frame');
+ iframe.src = 'about:blank';
+
+ document.getElementById('test-title').innerText = '';
+ document.getElementById('test-url').innerText = '';
+ document.getElementById('test-assertion').innerText = '';
+ document.getElementById('test-flags').innerText = '';
+
+ $('#test-content').removeClass('print');
+ $('#test-content').removeClass('warn');
+ document.getElementById('warning').innerText = '';
+}
+
+TestSuite.prototype.loadRef = function(test)
+{
+ // Suites 20101001 and earlier used .xht refs, even for HTML tests, so strip off
+ // the extension and use the same format as the test.
+ var ref = test.reference.replace(/(\.xht)?$/, '');
+
+ var iframe = document.getElementById('ref-frame');
+ iframe.src = this.urlForTest(ref);
+}
+
+TestSuite.prototype.pathForTest = function(testName)
+{
+ var prefix = this.formatInfo.path;
+ var suffix = this.formatInfo.suffix;
+
+ return prefix + '/' + testName + suffix;
+}
+
+TestSuite.prototype.urlForTest = function(testName)
+{
+ return kTestSuiteHome + this.pathForTest(testName);
+}
+
+/* ------------------------------------------------------- */
+
+TestSuite.prototype.recordResult = function(testName, resolution, comment)
+{
+ if (!testName)
+ return;
+
+ this.beginAppendingOutput();
+ this.appendResultToOutput(this.formatInfo, testName, resolution, comment);
+ this.endAppendingOutput();
+
+ if (comment == undefined)
+ comment = '';
+
+ this.storeTestResult(testName, this.format, resolution, comment, navigator.userAgent);
+
+ var htmlStatus = null;
+ var xhtmlStatus = null;
+ if (this.format == 'html4')
+ htmlStatus = resolution;
+ if (this.format == 'xhtml1')
+ xhtmlStatus = resolution;
+
+ this.markTestCompleted(testName, htmlStatus, xhtmlStatus);
+ this.updateTestList();
+
+ this.updateSummaryData();
+ this.updateChapterPopup();
+}
+
+TestSuite.prototype.beginAppendingOutput = function()
+{
+}
+
+TestSuite.prototype.endAppendingOutput = function()
+{
+ var output = document.getElementById('output');
+ output.scrollTop = output.scrollHeight;
+}
+
+TestSuite.prototype.appendResultToOutput = function(formatData, testName, resolution, comment)
+{
+ var output = document.getElementById('output');
+
+ var result = formatData.path + '/' + testName + formatData.suffix + '\t' + resolution;
+ if (comment)
+ result += '\t(' + comment + ')';
+
+ var line = document.createElement('p');
+ line.className = resolution;
+ line.appendChild(document.createTextNode(result));
+ output.appendChild(line);
+}
+
+TestSuite.prototype.clearOutput = function()
+{
+ document.getElementById('output').innerHTML = '';
+}
+
+/* ------------------------------------------------------- */
+
+TestSuite.prototype.switchToFormat = function(formatString)
+{
+ if (formatString == 'html4')
+ document.harness.format.html4.checked = true;
+ else
+ document.harness.format.xhtml1.checked = true;
+
+ this.formatChanged(formatString);
+}
+
+TestSuite.prototype.formatChanged = function(formatString)
+{
+ if (this.format == formatString)
+ return;
+
+ this.format = formatString;
+
+ if (formatString == 'html4')
+ this.formatInfo = kHTML4Data;
+ else
+ this.formatInfo = kXHTML1Data;
+
+ // try to keep the current test selected
+ var selectedTestName;
+ if (this.currChapterTestIndex >= 0 && this.currChapterTestIndex < this.currentChapterTests.length)
+ selectedTestName = this.currentChapterTests[this.currChapterTestIndex].id;
+
+ if (this.currentChapter) {
+ this.buildTestListForChapter(this.currentChapter);
+ this.fillTestList();
+ this.goToTestByName(selectedTestName);
+ }
+
+ this.updateChapterPopup();
+ this.updateTestList();
+ this.updateProgressLabel();
+}
+
+/* ------------------------------------------------------- */
+
+TestSuite.prototype.asyncLoad = function(url, type, handler)
+{
+ $.get(url, handler, type);
+}
+
+/* ------------------------------------------------------- */
+
+TestSuite.prototype.exportResults = function(resultTypeIndex)
+{
+ var resultInfo = kResultsSelector[resultTypeIndex];
+ if (!resultInfo)
+ return;
+
+ resultInfo.exporter(this);
+}
+
+TestSuite.prototype.exportHeader = function()
+{
+ var result = '# Safari 5.0.2' + ' ' + navigator.platform + '\n';
+ result += '# ' + navigator.userAgent + '\n';
+ result += '# http://test.csswg.org/suites/css2.1/' + kTestSuiteVersion + '/\n';
+ result += 'testname\tresult\n';
+
+ return result;
+}
+
+TestSuite.prototype.createExportLine = function(formatData, testName, resolution, comment)
+{
+ var result = formatData.path + '/' + testName + '\t' + resolution;
+ if (comment)
+ result += '\t(' + comment + ')';
+ return result;
+}
+
+TestSuite.prototype.exportQueryComplete = function(data)
+{
+ window.open("data:text/plain," + escape(data))
+}
+
+TestSuite.prototype.resultsPopupChanged = function(index)
+{
+ var resultInfo = kResultsSelector[index];
+ if (!resultInfo)
+ return;
+
+ this.clearOutput();
+ resultInfo.handler(this);
+
+ var enableExport = resultInfo.exporter != undefined;
+ document.getElementById('export-button').disabled = !enableExport;
+}
+
+/* ------------------------- Import ------------------------------- */
+/*
+ Import format is the same as the export format, namely:
+
+ testname<tab>result
+
+ with optional trailing <tab>comment.
+
+html4/absolute-non-replaced-height-002<tab>pass
+xhtml1/absolute-non-replaced-height-002<tab>?
+
+ Lines starting with # are ignored.
+ The "testname<tab>result" line is ignored.
+*/
+TestSuite.prototype.importResults = function(data)
+{
+ var testsToImport = [];
+
+ var lines = data.split('\n');
+ for (var i = 0; i < lines.length; ++i) {
+ var currLine = lines[i];
+ if (currLine.length == 0 || currLine.charAt(0) == '#')
+ continue;
+
+ var match = currLine.match(/^(html4|xhtml1)\/([\w-_]+)\t([\w?]+)\t?(.+)?$/);
+ if (match) {
+ var test = { 'id' : match[2] };
+ test.format = match[1];
+ test.result = match[3];
+ test.comment = match[4];
+
+ if (test.result != '?')
+ testsToImport.push(test);
+ } else {
+ window.console.log('failed to match line \'' + currLine + '\'');
+ }
+ }
+
+ this.importTestResults(testsToImport);
+
+ this.resetTestStatus();
+ this.updateSummaryData();
+}
+
+
+
+/* --------------------- Clear Results --------------------------- */
+/*
+ Clear results format is either same as the export format, or
+ a list of bare test IDs (e.g. absolute-non-replaced-height-001)
+ in which case both HTML4 and XHTML1 results are cleared.
+*/
+TestSuite.prototype.clearResults = function(data)
+{
+ var testsToClear = [];
+
+ var lines = data.split('\n');
+ for (var i = 0; i < lines.length; ++i) {
+ var currLine = lines[i];
+ if (currLine.length == 0 || currLine.charAt(0) == '#')
+ continue;
+
+ // Look for format/test with possible extension
+ var result = currLine.match(/^((html4|xhtml1)?)\/?([\w-_]+)/);
+ if (result) {
+ var testId = result[3];
+ var format = result[1];
+
+ var clearHTML = format.length == 0 || format == 'html4';
+ var clearXHTML = format.length == 0 || format == 'xhtml1';
+
+ var result = { 'id' : testId };
+ result.clearHTML = clearHTML;
+ result.clearXHTML = clearXHTML;
+
+ testsToClear.push(result);
+ } else {
+ window.console.log('failed to match line ' + currLine);
+ }
+ }
+
+ this.clearTestResults(testsToClear);
+
+ this.resetTestStatus();
+ this.updateSummaryData();
+}
+
+/* -------------------------------------------------------- */
+
+TestSuite.prototype.exportResultsCompletion = function(exportTests)
+{
+ // Lame workaround for ORDER BY not working
+ exportTests.sort(function(a, b) {
+ return a.test.localeCompare(b.test);
+ });
+
+ var exportLines = [];
+ for (var i = 0; i < exportTests.length; ++i) {
+ var currTest = exportTests[i];
+ if (currTest.html4 != '')
+ exportLines.push(currTest.html4);
+ if (currTest.xhtml1 != '')
+ exportLines.push(currTest.xhtml1);
+ }
+
+ var exportString = this.exportHeader() + exportLines.join('\n');
+ this.exportQueryComplete(exportString);
+}
+
+/* -------------------------------------------------------- */
+
+TestSuite.prototype.showResultsForCompletedTests = function()
+{
+ this.beginAppendingOutput();
+
+ var _self = this;
+ this.queryDatabaseForCompletedTests(
+ function(item) {
+ if (item.hstatus)
+ _self.appendResultToOutput(kHTML4Data, item.test, item.hstatus, item.hcomment);
+
+ if (item.xstatus)
+ _self.appendResultToOutput(kXHTML1Data, item.test, item.xstatus, item.xcomment);
+ },
+ function() {
+ _self.endAppendingOutput();
+ }
+ );
+}
+
+TestSuite.prototype.exportResultsForCompletedTests = function()
+{
+ var exportTests = []; // each test will have html and xhtml items on it
+
+ var _self = this;
+ this.queryDatabaseForCompletedTests(
+ function(item) {
+ var htmlLine = '';
+ if (item.hstatus)
+ htmlLine= _self.createExportLine(kHTML4Data, item.test, item.hstatus, item.hcomment);
+
+ var xhtmlLine = '';
+ if (item.xstatus)
+ xhtmlLine = _self.createExportLine(kXHTML1Data, item.test, item.xstatus, item.xcomment);
+
+ exportTests.push({
+ 'test' : item.test,
+ 'html4' : htmlLine,
+ 'xhtml1' : xhtmlLine });
+ },
+ function() {
+ _self.exportResultsCompletion(exportTests);
+ }
+ );
+}
+
+
+/* -------------------------------------------------------- */
+
+TestSuite.prototype.showResultsForAllTests = function()
+{
+ this.beginAppendingOutput();
+
+ var _self = this;
+ this.queryDatabaseForAllTests('test',
+ function(item) {
+ _self.appendResultToOutput(kHTML4Data, item.test, item.hstatus, item.hcomment);
+ _self.appendResultToOutput(kXHTML1Data, item.test, item.xstatus, item.xcomment);
+ },
+ function() {
+ _self.endAppendingOutput();
+ });
+}
+
+TestSuite.prototype.exportResultsForAllTests = function()
+{
+ var exportTests = [];
+
+ var _self = this;
+ this.queryDatabaseForAllTests('test',
+ function(item) {
+ var htmlLine= _self.createExportLine(kHTML4Data, item.test, item.hstatus ? item.hstatus : '?', item.hcomment);
+ var xhtmlLine = _self.createExportLine(kXHTML1Data, item.test, item.xstatus ? item.xstatus : '?', item.xcomment);
+ exportTests.push({
+ 'test' : item.test,
+ 'html4' : htmlLine,
+ 'xhtml1' : xhtmlLine });
+ },
+ function() {
+ _self.exportResultsCompletion(exportTests);
+ }
+ );
+}
+
+/* -------------------------------------------------------- */
+
+TestSuite.prototype.showResultsForTestsNotRun = function()
+{
+ this.beginAppendingOutput();
+
+ var _self = this;
+ this.queryDatabaseForTestsNotRun(
+ function(item) {
+ if (!item.hstatus)
+ _self.appendResultToOutput(kHTML4Data, item.test, '?', item.hcomment);
+ if (!item.xstatus)
+ _self.appendResultToOutput(kXHTML1Data, item.test, '?', item.xcomment);
+ },
+ function() {
+ _self.endAppendingOutput();
+ }
+ );
+}
+
+TestSuite.prototype.exportResultsForTestsNotRun = function()
+{
+ var exportTests = [];
+
+ var _self = this;
+ this.queryDatabaseForTestsNotRun(
+ function(item) {
+ var htmlLine = '';
+ if (!item.hstatus)
+ htmlLine= _self.createExportLine(kHTML4Data, item.test, '?', item.hcomment);
+
+ var xhtmlLine = '';
+ if (!item.xstatus)
+ xhtmlLine = _self.createExportLine(kXHTML1Data, item.test, '?', item.xcomment);
+
+ exportTests.push({
+ 'test' : item.test,
+ 'html4' : htmlLine,
+ 'xhtml1' : xhtmlLine });
+ },
+ function() {
+ _self.exportResultsCompletion(exportTests);
+ }
+ );
+}
+
+/* -------------------------------------------------------- */
+
+TestSuite.prototype.showResultsForTestsWithStatus = function(status)
+{
+ this.beginAppendingOutput();
+
+ var _self = this;
+ this.queryDatabaseForTestsWithStatus(status,
+ function(item) {
+ if (item.hstatus == status)
+ _self.appendResultToOutput(kHTML4Data, item.test, item.hstatus, item.hcomment);
+ if (item.xstatus == status)
+ _self.appendResultToOutput(kXHTML1Data, item.test, item.xstatus, item.xcomment);
+ },
+ function() {
+ _self.endAppendingOutput();
+ }
+ );
+}
+
+TestSuite.prototype.exportResultsForTestsWithStatus = function(status)
+{
+ var exportTests = [];
+
+ var _self = this;
+ this.queryDatabaseForTestsWithStatus(status,
+ function(item) {
+ var htmlLine = '';
+ if (item.hstatus == status)
+ htmlLine= _self.createExportLine(kHTML4Data, item.test, item.hstatus, item.hcomment);
+
+ var xhtmlLine = '';
+ if (item.xstatus == status)
+ xhtmlLine = _self.createExportLine(kXHTML1Data, item.test, item.xstatus, item.xcomment);
+
+ exportTests.push({
+ 'test' : item.test,
+ 'html4' : htmlLine,
+ 'xhtml1' : xhtmlLine });
+ },
+ function() {
+ _self.exportResultsCompletion(exportTests);
+ }
+ );
+}
+
+/* -------------------------------------------------------- */
+
+TestSuite.prototype.showResultsForTestsWithMismatchedResults = function()
+{
+ this.beginAppendingOutput();
+
+ var _self = this;
+ this.queryDatabaseForTestsWithMixedStatus(
+ function(item) {
+ _self.appendResultToOutput(kHTML4Data, item.test, item.hstatus, item.hcomment);
+ _self.appendResultToOutput(kXHTML1Data, item.test, item.xstatus, item.xcomment);
+ },
+ function() {
+ _self.endAppendingOutput();
+ }
+ );
+}
+
+TestSuite.prototype.exportResultsForTestsWithMismatchedResults = function()
+{
+ var exportTests = [];
+
+ var _self = this;
+ this.queryDatabaseForTestsWithMixedStatus(
+ function(item) {
+ var htmlLine= _self.createExportLine(kHTML4Data, item.test, item.hstatus ? item.hstatus : '?', item.hcomment);
+ var xhtmlLine = _self.createExportLine(kXHTML1Data, item.test, item.xstatus ? item.xstatus : '?', item.xcomment);
+ exportTests.push({
+ 'test' : item.test,
+ 'html4' : htmlLine,
+ 'xhtml1' : xhtmlLine });
+ },
+ function() {
+ _self.exportResultsCompletion(exportTests);
+ }
+ );
+}
+
+/* -------------------------------------------------------- */
+
+TestSuite.prototype.markTestCompleted = function(testID, htmlStatus, xhtmlStatus)
+{
+ var test = this.tests[testID];
+ if (!test) {
+ window.console.log('markTestCompleted failed to find test ' + testID);
+ return;
+ }
+
+ if (htmlStatus) {
+ test.completedHTML = true;
+ test.statusHTML = htmlStatus;
+ }
+ if (xhtmlStatus) {
+ test.completedXHTML = true;
+ test.statusXHTML = xhtmlStatus;
+ }
+}
+
+TestSuite.prototype.testCompletionStateChanged = function()
+{
+ this.updateTestList();
+ this.updateChapterPopup();
+}
+
+TestSuite.prototype.loadTestStatus = function()
+{
+ var _self = this;
+ this.queryDatabaseForCompletedTests(
+ function(item) {
+ _self.markTestCompleted(item.test, item.hstatus, item.xstatus);
+ },
+ function() {
+ _self.testCompletionStateChanged();
+ }
+ );
+
+ this.updateChapterPopup();
+}
+
+TestSuite.prototype.resetTestStatus = function()
+{
+ for (var testID in this.tests) {
+ var currTest = this.tests[testID];
+ currTest.completedHTML = false;
+ currTest.completedXHTML = false;
+ }
+ this.loadTestStatus();
+}
+
+/* -------------------------------------------------------- */
+
+TestSuite.prototype.updateSummaryData = function()
+{
+ this.queryDatabaseForSummary(
+ function(results) {
+
+ var hTotal, xTotal;
+ var hDone, xDone;
+
+ for (var i = 0; i < results.length; ++i) {
+ var result = results[i];
+
+ switch (result.name) {
+ case 'h-total': hTotal = result.count; break;
+ case 'x-total': xTotal = result.count; break;
+ case 'h-tested': hDone = result.count; break;
+ case 'x-tested': xDone = result.count; break;
+ }
+
+ document.getElementById(result.name).innerText = result.count;
+ }
+
+ // We should get these all together.
+ if (hTotal) {
+ document.getElementById('h-percent').innerText = Math.round(100.0 * hDone / hTotal);
+ document.getElementById('x-percent').innerText = Math.round(100.0 * xDone / xTotal);
+ }
+ }
+ );
+}
+
+/* ------------------------------------------------------- */
+// Database stuff
+
+function errorHandler(transaction, error)
+{
+ alert('Database error: ' + error.message);
+ window.console.log('Database error: ' + error.message);
+}
+
+TestSuite.prototype.openDatabase = function()
+{
+ if (!'openDatabase' in window) {
+ alert('Your browser does not support client-side SQL databases, so results will not be stored.');
+ return;
+ }
+
+ var _self = this;
+ this.db = window.openDatabase('css21testsuite', '', 'CSS 2.1 test suite results', 10 * 1024 * 1024);
+
+ // Migration handling. We assume migration will happen whenever the suite version changes,
+ // so that we can check for new or obsoleted tests.
+ function creation(tx) {
+ _self.databaseCreated(tx);
+ }
+
+ function migration1_0To1_1(tx) {
+ window.console.log('updating 1.0 to 1.1');
+ // We'll use the 'seen' column to cross-check with testinfo.data.
+ tx.executeSql('ALTER TABLE tests ADD COLUMN seen BOOLEAN DEFAULT \"FALSE\"', null, function() {
+ _self.syncDatabaseWithTestInfoData();
+ }, errorHandler);
+ }
+
+ if (this.db.version == '') {
+ _self.db.changeVersion('', '1.0', creation, null, function() {
+ _self.db.changeVersion('1.0', '1.1', migration1_0To1_1, null, function() {
+ _self.databaseReady();
+ }, errorHandler);
+ }, errorHandler);
+
+ return;
+ }
+
+ if (this.db.version == '1.0') {
+ _self.db.changeVersion('1.0', '1.1', migration1_0To1_1, null, function() {
+ window.console.log('ready')
+ _self.databaseReady();
+ }, errorHandler);
+ return;
+ }
+
+ this.databaseReady();
+}
+
+TestSuite.prototype.databaseCreated = function(tx)
+{
+ window.console.log('databaseCreated');
+ this.populatingDatabase = true;
+
+ // hstatus: HTML4 result
+ // xstatus: XHTML1 result
+ var _self = this;
+ tx.executeSql('CREATE TABLE tests (test PRIMARY KEY UNIQUE, ref, title, flags, links, assertion, hstatus, hcomment, xstatus, xcomment)', null,
+ function(tx, results) {
+ _self.populateDatabaseFromTestInfoData();
+ }, errorHandler);
+}
+
+TestSuite.prototype.databaseReady = function()
+{
+ this.updateSummaryData();
+ this.loadTestStatus();
+}
+
+TestSuite.prototype.storeTestResult = function(test, format, result, comment, useragent)
+{
+ if (!this.db)
+ return;
+
+ this.db.transaction(function (tx) {
+ if (format == 'html4')
+ tx.executeSql('UPDATE tests SET hstatus=?, hcomment=? WHERE test=?\n', [result, comment, test], null, errorHandler);
+ else if (format == 'xhtml1')
+ tx.executeSql('UPDATE tests SET xstatus=?, xcomment=? WHERE test=?\n', [result, comment, test], null, errorHandler);
+ });
+}
+
+TestSuite.prototype.importTestResults = function(results)
+{
+ if (!this.db)
+ return;
+
+ this.db.transaction(function (tx) {
+
+ for (var i = 0; i < results.length; ++i) {
+ var currResult = results[i];
+
+ var query;
+ if (currResult.format == 'html4')
+ query = 'UPDATE tests SET hstatus=?, hcomment=? WHERE test=?\n';
+ else if (currResult.format == 'xhtml1')
+ query = 'UPDATE tests SET xstatus=?, xcomment=? WHERE test=?\n';
+
+ tx.executeSql(query, [currResult.result, currResult.comment, currResult.id], null, errorHandler);
+ }
+ });
+}
+
+TestSuite.prototype.clearTestResults = function(results)
+{
+ if (!this.db)
+ return;
+
+ this.db.transaction(function (tx) {
+
+ for (var i = 0; i < results.length; ++i) {
+ var currResult = results[i];
+
+ if (currResult.clearHTML)
+ tx.executeSql('UPDATE tests SET hstatus=NULL, hcomment=NULL WHERE test=?\n', [currResult.id], null, errorHandler);
+
+ if (currResult.clearXHTML)
+ tx.executeSql('UPDATE tests SET xstatus=NULL, xcomment=NULL WHERE test=?\n', [currResult.id], null, errorHandler);
+
+ }
+ });
+}
+
+TestSuite.prototype.populateDatabaseFromTestInfoData = function()
+{
+ if (!this.testInfoLoaded) {
+ window.console.log('Tring to populate database before testinfo.data has been loaded');
+ return;
+ }
+
+ window.console.log('populateDatabaseFromTestInfoData')
+ var _self = this;
+ this.db.transaction(function (tx) {
+ for (var testID in _self.tests) {
+ var test = _self.tests[testID];
+ // Version 1.0, so no 'seen' column.
+ tx.executeSql('INSERT INTO tests (test, ref, title, flags, links, assertion) VALUES (?, ?, ?, ?, ?, ?)',
+ [test.id, test.reference, test.title, test.flags, test.links, test.assertion], null, errorHandler);
+ }
+ _self.populatingDatabase = false;
+ });
+
+}
+
+TestSuite.prototype.insertTest = function(tx, test)
+{
+ tx.executeSql('INSERT INTO tests (test, ref, title, flags, links, assertion, seen) VALUES (?, ?, ?, ?, ?, ?, ?)',
+ [test.id, test.reference, test.title, test.flags, test.links, test.assertion, 'TRUE'], null, errorHandler);
+}
+
+// Deal with removed/renamed tests in a new version of the suite.
+// self.tests is canonical; the database may contain stale entries.
+TestSuite.prototype.syncDatabaseWithTestInfoData = function()
+{
+ if (!this.testInfoLoaded) {
+ window.console.log('Trying to sync database before testinfo.data has been loaded');
+ return;
+ }
+
+ // Make an object with all tests that we'll use to track new tests.
+ var testsToInsert = {};
+ for (var testId in this.tests) {
+ var currTest = this.tests[testId];
+ testsToInsert[currTest.id] = currTest;
+ }
+
+ var _self = this;
+ this.db.transaction(function (tx) {
+ // Find tests that are not in the database yet.
+ // (Wasn't able to get INSERT ... IF NOT working.)
+ tx.executeSql('SELECT * FROM tests', [], function(tx, results) {
+ var len = results.rows.length;
+ for (var i = 0; i < len; ++i) {
+ var item = results.rows.item(i);
+ delete testsToInsert[item.test];
+ }
+ }, errorHandler);
+ });
+
+ this.db.transaction(function (tx) {
+ for (var testId in testsToInsert) {
+ var currTest = testsToInsert[testId];
+ window.console.log(currTest.id + ' is new; inserting');
+ _self.insertTest(tx, currTest);
+ }
+ });
+
+ this.db.transaction(function (tx) {
+ for (var testID in _self.tests)
+ tx.executeSql('UPDATE tests SET seen=\"TRUE\" WHERE test=?\n', [testID], null, errorHandler);
+
+ tx.executeSql('SELECT * FROM tests WHERE seen=\"FALSE\"', [], function(tx, results) {
+ var len = results.rows.length;
+ for (var i = 0; i < len; ++i) {
+ var item = results.rows.item(i);
+ window.console.log('Test ' + item.test + ' was in the database but is no longer in the suite; deleting.');
+ }
+ }, errorHandler);
+
+ // Delete rows for disappeared tests.
+ tx.executeSql('DELETE FROM tests WHERE seen=\"FALSE\"', [], function(tx, results) {
+ _self.populatingDatabase = false;
+ _self.databaseReady();
+ }, errorHandler);
+ });
+}
+
+TestSuite.prototype.queryDatabaseForAllTests = function(sortKey, perRowHandler, completionHandler)
+{
+ if (this.populatingDatabase)
+ return;
+
+ var _self = this;
+ this.db.transaction(function (tx) {
+ if (_self.populatingDatabase)
+ return;
+ var query;
+ var args = [];
+ if (sortKey != '') {
+ query = 'SELECT * FROM tests ORDER BY ? ASC'; // ORDER BY doesn't seem to work
+ args.push(sortKey);
+ }
+ else
+ query = 'SELECT * FROM tests';
+
+ tx.executeSql(query, args, function(tx, results) {
+
+ var len = results.rows.length;
+ for (var i = 0; i < len; ++i)
+ perRowHandler(results.rows.item(i));
+
+ completionHandler();
+ }, errorHandler);
+ });
+}
+
+TestSuite.prototype.queryDatabaseForTestsWithStatus = function(status, perRowHandler, completionHandler)
+{
+ if (this.populatingDatabase)
+ return;
+
+ var _self = this;
+ this.db.transaction(function (tx) {
+ if (_self.populatingDatabase)
+ return;
+ tx.executeSql('SELECT * FROM tests WHERE hstatus=? OR xstatus=?', [status, status], function(tx, results) {
+
+ var len = results.rows.length;
+ for (var i = 0; i < len; ++i)
+ perRowHandler(results.rows.item(i));
+
+ completionHandler();
+ }, errorHandler);
+ });
+}
+
+TestSuite.prototype.queryDatabaseForTestsWithMixedStatus = function(perRowHandler, completionHandler)
+{
+ if (this.populatingDatabase)
+ return;
+
+ var _self = this;
+ this.db.transaction(function (tx) {
+ if (_self.populatingDatabase)
+ return;
+ tx.executeSql('SELECT * FROM tests WHERE hstatus IS NOT NULL AND xstatus IS NOT NULL AND hstatus <> xstatus', [], function(tx, results) {
+
+ var len = results.rows.length;
+ for (var i = 0; i < len; ++i)
+ perRowHandler(results.rows.item(i));
+
+ completionHandler();
+ }, errorHandler);
+ });
+}
+
+TestSuite.prototype.queryDatabaseForCompletedTests = function(perRowHandler, completionHandler)
+{
+ if (this.populatingDatabase)
+ return;
+
+ var _self = this;
+ this.db.transaction(function (tx) {
+
+ if (_self.populatingDatabase)
+ return;
+
+ tx.executeSql('SELECT * FROM tests WHERE hstatus IS NOT NULL OR xstatus IS NOT NULL', [], function(tx, results) {
+ var len = results.rows.length;
+ for (var i = 0; i < len; ++i)
+ perRowHandler(results.rows.item(i));
+
+ completionHandler();
+ }, errorHandler);
+ });
+}
+
+TestSuite.prototype.queryDatabaseForTestsNotRun = function(perRowHandler, completionHandler)
+{
+ if (this.populatingDatabase)
+ return;
+
+ var _self = this;
+ this.db.transaction(function (tx) {
+ if (_self.populatingDatabase)
+ return;
+
+ tx.executeSql('SELECT * FROM tests WHERE hstatus IS NULL OR xstatus IS NULL', [], function(tx, results) {
+
+ var len = results.rows.length;
+ for (var i = 0; i < len; ++i)
+ perRowHandler(results.rows.item(i));
+
+ completionHandler();
+ }, errorHandler);
+ });
+}
+
+/*
+
+ completionHandler gets called an array of results,
+ which may be some or all of:
+
+ data = [
+ { 'name' : ,
+ 'count' :
+ },
+ ]
+
+ where name is one of:
+
+ 'h-total'
+ 'h-tested'
+ 'h-passed'
+ 'h-failed'
+ 'h-skipped'
+
+ 'x-total'
+ 'x-tested'
+ 'x-passed'
+ 'x-failed'
+ 'x-skipped'
+
+ */
+
+
+TestSuite.prototype.countTestsWithColumnValue = function(tx, completionHandler, column, value, label)
+{
+ var allRowsCount = 'COUNT(*)';
+
+ tx.executeSql('SELECT COUNT(*) FROM tests WHERE ' + column + '=?', [value], function(tx, results) {
+ var data = [];
+ if (results.rows.length > 0)
+ data.push({ 'name' : label, 'count' : results.rows.item(0)[allRowsCount] })
+ completionHandler(data);
+ }, errorHandler);
+}
+
+TestSuite.prototype.countTestsWithFlag = function(tx, completionHandler, flag)
+{
+ var allRowsCount = 'COUNT(*)';
+
+ tx.executeSql('SELECT COUNT(*) FROM tests WHERE flags LIKE \"%' + flag + '%\"', [], function(tx, results) {
+ var rowCount = 0;
+ if (results.rows.length > 0)
+ rowCount = results.rows.item(0)[allRowsCount];
+ completionHandler(rowCount);
+ }, errorHandler);
+}
+
+TestSuite.prototype.queryDatabaseForSummary = function(completionHandler)
+{
+ if (!this.db || this.populatingDatabase)
+ return;
+
+ var _self = this;
+
+ var htmlOnlyTestCount = 0;
+ var xHtmlOnlyTestCount = 0;
+
+ this.db.transaction(function (tx) {
+ if (_self.populatingDatabase)
+ return;
+
+ var allRowsCount = 'COUNT(*)';
+
+ _self.countTestsWithFlag(tx, function(count) {
+ htmlOnlyTestCount = count;
+ }, 'htmlOnly');
+
+ _self.countTestsWithFlag(tx, function(count) {
+ xHtmlOnlyTestCount = count;
+ }, 'nonHTML');
+ });
+
+ this.db.transaction(function (tx) {
+ if (_self.populatingDatabase)
+ return;
+
+ var allRowsCount = 'COUNT(*)';
+ var html4RowsCount = 'COUNT(hstatus)';
+ var xhtml1RowsCount = 'COUNT(xstatus)';
+
+ tx.executeSql('SELECT COUNT(*), COUNT(hstatus), COUNT(xstatus) FROM tests', [], function(tx, results) {
+
+ var data = [];
+ if (results.rows.length > 0) {
+ var rowItem = results.rows.item(0);
+ data.push({ 'name' : 'h-total' , 'count' : rowItem[allRowsCount] - xHtmlOnlyTestCount })
+ data.push({ 'name' : 'x-total' , 'count' : rowItem[allRowsCount] - htmlOnlyTestCount })
+ data.push({ 'name' : 'h-tested', 'count' : rowItem[html4RowsCount] })
+ data.push({ 'name' : 'x-tested', 'count' : rowItem[xhtml1RowsCount] })
+ }
+ completionHandler(data);
+
+ }, errorHandler);
+
+
+ _self.countTestsWithColumnValue(tx, completionHandler, 'hstatus', 'pass', 'h-passed');
+ _self.countTestsWithColumnValue(tx, completionHandler, 'xstatus', 'pass', 'x-passed');
+
+ _self.countTestsWithColumnValue(tx, completionHandler, 'hstatus', 'fail', 'h-failed');
+ _self.countTestsWithColumnValue(tx, completionHandler, 'xstatus', 'fail', 'x-failed');
+
+ _self.countTestsWithColumnValue(tx, completionHandler, 'hstatus', 'skipped', 'h-skipped');
+ _self.countTestsWithColumnValue(tx, completionHandler, 'xstatus', 'skipped', 'x-skipped');
+
+ _self.countTestsWithColumnValue(tx, completionHandler, 'hstatus', 'invalid', 'h-invalid');
+ _self.countTestsWithColumnValue(tx, completionHandler, 'xstatus', 'invalid', 'x-invalid');
+ });
+}
+
diff --git a/Tools/ChangeLog b/Tools/ChangeLog
new file mode 100644
index 0000000..65aaa70
--- /dev/null
+++ b/Tools/ChangeLog
@@ -0,0 +1,26465 @@
+2010-12-22 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ This change splits out the TestRunner class into its own file.
+ When we fork the code for message passing, we will create a new
+ TestRunner, and this change will allow that to be more modular.
+
+ While we're at it, split out TestInput and ResultSummary into
+ their own files, to reduce the size of run_webkit_tests to
+ something more managable.
+
+ https://bugs.webkit.org/show_bug.cgi?id=51092
+
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/result_summary.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_runner.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_input.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+ 2010-12-22 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ nrwt multiprocessing - start over, prepare to fork the code
+
+ This code cleans up the signatures and implementation of the
+ TestRunner class so we can easily fork it to run either the
+ stable implementation or the new, unstable message-passing
+ implementation. The two variants will have different
+ implementations of the run_tests() method. We will switch
+ between the two based on the setting for the '--worker-model'
+ switch. We rename the two currently valid values to 'old-inline'
+ and 'old-threads'.
+
+ https://bugs.webkit.org/show_bug.cgi?id=51081
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-12-22 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ [Chromium] Update chromium archive test result url in rebaseline script.
+
+ https://bugs.webkit.org/show_bug.cgi?id=51503
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-12-22 Lucas Forschler <lforschler@apple.com>
+
+ Reviewed by Alice Liu.
+
+ <rdar://problem/8633222> record-memory-win needs to record memory used by the webprocess.
+ Verified on Chrome, Safari, and IE.
+ With this change, we will record memory from a parent browser window and all child processes.
+
+ * record-memory-win/main.cpp:
+ (ProcessArgs):
+ (PrintUsage):
+ (getMemoryInfo):
+ (printProcessInfo):
+ (evalProcesses):
+ (UseImage):
+ (QueryContinuously):
+ (ElapsedTime):
+
+2010-12-22 Lucas Forschler <lforschler@apple.com>
+
+ Unreviewed rollout r74489, because it was missing changelog.
+
+ * record-memory-win/main.cpp:
+
+2010-12-22 Ryosuke Niwa <rniwa@webkit.org>
+
+ Adding myself as a reviewer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-12-22 Andrew Scherkus <scherkus@chromium.org>
+
+ Unreviewed. Adding myself to committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-12-22 Ariya Hidayat <ariya@sencha.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ TestNetscapePlugIn should use #if defined
+ https://bugs.webkit.org/show_bug.cgi?id=51471
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NP_Initialize):
+ (NPP_New):
+
+2010-12-22 Ilya Tikhonovsky <loislo@chromium.org>
+
+ Reviewed by Yury Semikhatsky.
+
+ Web Inspector: [chromium] DRT inspector layout tests are flaky in debug.
+
+ DevTools window should be closed explicitly because it has custom deinitialization code.
+
+ https://bugs.webkit.org/show_bug.cgi?id=50722
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::closeRemainingWindows):
+
+2010-12-22 David Levin <levin@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ check-webkit-style shouldn't complaint about underscores in variables in objective C files.
+ https://bugs.webkit.org/show_bug.cgi?id=51452
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ (_FileState.__init__): Added the information to determine if a file is C or Objective C.
+ Using the file extension if possible but falling back to the file contents if we have a header file.
+ (_FileState.is_objective_c): Determine if we have an Objective C by examining the file contents if needed.
+ (_FileState.is_c_or_objective_c):
+ (check_using_std): Changed to using _FileState to determine the file type.
+ (check_max_min_macros): Ditto.
+ (check_for_null): Ditto.
+ (check_style): Changed the parameters to various calls since they now need _FileState
+ to determine the file type.
+ (check_language): Added the file_state parameter so it could be passed
+ to check_identifier_name_in_declaration.
+ (check_identifier_name_in_declaration): Don't warn about underscores in variables if
+ this is an Objective C file.
+ (_process_lines): Added information for the _FileState constructor (and moved the
+ call to a place that had the information).
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+ (CppFunctionsTest.test_is_c_or_objective_c): Changed the tests to use FileState and exercise
+ its functionality.
+ (WebKitStyleTest.test_names): Add tests for underscores in Objective C files.
+
+2010-12-21 Andy Estes <aestes@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Do not build non-Intel architectures for WebKit2-related projects.
+ https://bugs.webkit.org/show_bug.cgi?id=51440
+
+ * MiniBrowser/Configurations/Base.xcconfig: Only build for i386 and x86_64.
+ * TestWebKitAPI/Configurations/Base.xcconfig: Ditto.
+ * WebKitTestRunner/Configurations/Base.xcconfig: Ditto.
+
+2010-12-21 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ [Chromium] Rename WebThemeEngine/ControlDRT to WebThemeEngine/ControlDRTWin
+ https://bugs.webkit.org/show_bug.cgi?id=51406
+
+ Rename WebThemeControlDRT to WebThemeControlDRTWin and WebThemeEngineDRT
+ to WebThemeEngineDRTWin and update references everywhere.
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+ * DumpRenderTree/chromium/TestShellWin.cpp:
+ * DumpRenderTree/chromium/WebThemeControlDRTWin.cpp: Renamed from Tools/DumpRenderTree/chromium/WebThemeControlDRT.cpp.
+ * DumpRenderTree/chromium/WebThemeControlDRTWin.h: Renamed from Tools/DumpRenderTree/chromium/WebThemeControlDRT.h.
+ * DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp: Renamed from Tools/DumpRenderTree/chromium/WebThemeEngineDRT.cpp.
+ * DumpRenderTree/chromium/WebThemeEngineDRTWin.h: Renamed from Tools/DumpRenderTree/chromium/WebThemeEngineDRT.h.
+
+2010-12-21 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by John Sullivan.
+
+ Clicking missing plug-in text does not show a sheet
+ https://bugs.webkit.org/show_bug.cgi?id=51403
+
+ Update for changes to the WebPageUIClient.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ (WTR::TestController::initialize):
+
+2010-12-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue will report constant failures as flaky if other tests flake
+ https://bugs.webkit.org/show_bug.cgi?id=51272
+
+ This patch just removes functionality and adds testing.
+ Previously we attempted to report flaky tests when we had
+ two different tests fail in a row. However, since we stop
+ running the tests at the first failure, our code was wrong in
+ trying to determine flakiness from the incomplete runs.
+
+ Originally I posted an alternate patch:
+ https://bug-51272-attachments.webkit.org/attachment.cgi?id=77078
+ which fixed our flaky logic in this case, however it was decided
+ that that patch would be too difficult to maintain, so now
+ I'm just removing the broken logic.
+
+ This will dramatically cut-down on our flaky-test false positives
+ at the (small) cost of the queues being unable to report
+ any flakiness if the tree is very flaky. (With at least one test
+ flaking on every run, we'll never report failures anymore.) I think
+ this is a tradeoff worth making.
+
+ * Scripts/webkitpy/tool/bot/commitqueuetask.py:
+ * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py:
+
+2010-12-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue wrongly rejects patches when it can't update itself
+ https://bugs.webkit.org/show_bug.cgi?id=46636
+
+ * Scripts/webkitpy/tool/bot/commitqueuetask.py:
+ * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-12-20 Adam Barth <abarth@webkit.org>
+
+ Move web sites to Websites directory
+ https://bugs.webkit.org/show_bug.cgi?id=51323
+
+ Update references to BugsSite to point to the new location.
+
+ This patch was never officially reviewed (because it was too large to
+ upload to bugs.webkit.org), but it was discussed on webkit-dev and Mark
+ Rowe gave me the green light.
+
+ * Scripts/old-run-webkit-tests:
+ * Scripts/webkitpy/common/config/build.py:
+ * Scripts/webkitpy/common/config/build_unittest.py:
+ * Scripts/webkitpy/common/prettypatch.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/style/main.py:
+
+2010-12-20 Adrienne Walker <enne@google.com>
+
+ Unreviewed. Adding myself to the list of committers.
+
+ * webkitpy/common/config/committers.py:
+
+2010-12-20 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ <rdar://problem/8757601> Don't install header files in to the Resources directory.
+
+ * Scripts/check-for-inappropriate-files-in-framework: Don't allow .h files in the
+ Resources directory.
+
+2010-12-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue should include bot id when attaching failure diffs
+ https://bugs.webkit.org/show_bug.cgi?id=51280
+
+ This is a tiny change to include the bot id in the name of the attachment.
+ Most of this diff is just changing the unit test expectations
+ now that I hid the comment printing when the comment is None.
+
+ * Scripts/webkitpy/tool/bot/flakytestreporter.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-12-20 Jeff Miller <jeffm@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Tools/vcbin/midl.exe needs to be rebuilt
+ https://bugs.webkit.org/show_bug.cgi?id=51347
+
+ * vcbin/midl.exe: Rebuilt.
+
+2010-12-20 David Levin <levin@chromium.org>
+
+ Reviewed by Ariya Hidayat.
+
+ .gitignore and webkit-tools-completion.sh have references to WebKitTools that should be Tools.
+ https://bugs.webkit.org/show_bug.cgi?id=51343
+
+ Follow up from the WebKitTools -> Tools rename.
+
+ * Scripts/webkit-tools-completion.sh:
+
+2010-12-20 Cosmin Truta <ctruta@chromium.org>
+
+ Reviewed by James Robinson.
+
+ new-run-webkit-tests ignores trailing EOL differences in text tests
+ https://bugs.webkit.org/show_bug.cgi?id=36983
+
+ Changed the handling of new-line characters within new-run-webkit-tests
+ to match old-run-webkit-tests. Differences in leading and trailing empty
+ lines in text expectation files are no longer ignored.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ Added unit tests. Removed old duplicate unit test entries.
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-12-20 David Levin <levin@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ check-webkit-style should detect function declarations (and trivial functions).
+ https://bugs.webkit.org/show_bug.cgi?id=51303
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ (_FunctionState.begin): Add is_declaration and changed the line count
+ start to begin at -1 (which will keep the results consistent, since
+ the starting line number passed in is one less in this change).
+ (detect_functions): changed function detection to now catch trivial
+ functions and declarations.
+ (check_pass_ptr_usage): Don't check for Pass*Ptr on the first line
+ of the function as this may look at return values (when processing
+ a declaration).
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+ (FunctionDetectionTest.perform_function_detection): Basic mechanics
+ of testing the function detection.
+ (FunctionDetectionTest.test_basic_function_detection): Test a simple
+ function.
+ (FunctionDetectionTest.test_function_declaration_detection): Test a
+ declaration.
+ (FunctionDetectionTest.test_non_functions): A test case for a case
+ that caused the code to fail due to the { being in quotes.
+ (PassPtrTest.test_pass_ref_ptr_return_value): Added some more test
+ cases to help catch false alarms for return values.
+ (PassPtrTest.test_pass_ref_ptr_member_variable): Ensure that
+ we don't get false alarms for member variables either.
+
+2010-12-20 Ryuan Choi <ryuan.choi@samsung.com>
+
+ Reviewed by Antonio Gomes.
+
+ [CMAKE] Rename WEBKITTOOLS_DIR to TOOLS_DIR
+ https://bugs.webkit.org/show_bug.cgi?id=51319
+
+ * CMakeListsEfl.txt:
+
+2010-12-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Sam Weinig.
+
+ Move WebKitExamplePlugins to Examples
+ https://bugs.webkit.org/show_bug.cgi?id=51291
+
+ * Scripts/webkitpy/common/config/build.py:
+
+2010-12-17 Csaba Osztrogonác <ossy@webkit.org>
+
+ Unreviewed Qt buildfix after r74301.
+
+ Rename WebKitTools to Tools
+ https://bugs.webkit.org/show_bug.cgi?id=49861
+
+ * MiniBrowser/DerivedSources.pro:
+ * MiniBrowser/qt/MiniBrowser.pro:
+
+2010-12-17 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ Rename WebKitTools to Tools
+ https://bugs.webkit.org/show_bug.cgi?id=49861
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+ * CodeCoverage/README:
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::initializeFonts):
+ * EWSTools/start-commit-queue.sh:
+ * EWSTools/start-queue.sh:
+ * GNUmakefile.am:
+ * MIDLWrapper/MIDLWrapper.cpp:
+ (wmain):
+ * MiniBrowser/qt/MiniBrowser.pro:
+ * Scripts/build-api-tests:
+ * Scripts/build-dumprendertree:
+ * Scripts/build-webkit:
+ * Scripts/build-webkittestrunner:
+ * Scripts/generate-coverage-data:
+ * Scripts/old-run-webkit-tests:
+ * Scripts/run-api-tests:
+ * Scripts/run-iexploder-tests:
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/run-mangleme-tests:
+ * Scripts/run-sunspider:
+ * Scripts/run-webkit-websocketserver:
+ * Scripts/sunspider-compare-results:
+ * Scripts/test-webkitperl:
+ * Scripts/test-webkitpy:
+ * Scripts/update-iexploder-cssproperties:
+ * Scripts/update-webkit:
+ * Scripts/update-webkit-localizable-strings:
+ * Scripts/webkitdirs.pm:
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ * Scripts/webkitpy/common/config/committervalidator.py:
+ * Scripts/webkitpy/common/config/committervalidator_unittest.py:
+ * Scripts/webkitpy/common/config/ports.py:
+ * Scripts/webkitpy/common/config/ports_unittest.py:
+ * Scripts/webkitpy/common/system/logutils_unittest.py:
+ * Scripts/webkitpy/common/system/ospath_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/config.py:
+ * Scripts/webkitpy/layout_tests/port/config_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/http_server.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/style/checker.py:
+ * Scripts/webkitpy/style/checker_unittest.py:
+ * Scripts/webkitpy/tool/bot/feeders_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ * WebKitTestRunner/DerivedSources.pro:
+ * WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp:
+ (WTR::activateFonts):
+ * WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro:
+ * wx/build/build_utils.py:
+
+2010-12-16 Antonio Gomes <agomes@rim.com>
+
+ Reviewed by Martin Robinson.
+
+ Settings::editingBehaviorType() incorrectly returns mac for the gtk build when running tests
+ https://bugs.webkit.org/show_bug.cgi?id=51163
+
+ Since GTK+'s default editing behavior was changed to UNIX in r70975 (see webkitwebsettings.cpp),
+ GTK+'s DRT should also reset to UNIX after each test execution.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2010-12-17 David Levin <levin@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ check-webkit-style should understand WTF #include guards
+ https://bugs.webkit.org/show_bug.cgi?id=44911
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ (get_header_guard_cpp_variable): modify to suggest the WTF style
+ of header guard when appropriate.
+ (check_for_header_guard): handle multiple return values from
+ get_header_guard_cpp_variable
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+ (CppStyleTest.test_build_header_guard): Added tests for the WTF
+ header style.
+
+2010-12-16 David Levin <levin@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ test-webkitpy: unittest for the xml.py checker displays a decprecation warning.
+ https://bugs.webkit.org/show_bug.cgi?id=51210
+
+ The error only shows up when using python 2.6 or later.
+
+ * Scripts/webkitpy/style/checkers/xml.py: Replace the usage of
+ the decprecated field error,message with something equivalent.
+
+2010-12-16 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Add --exit-after-n-failures/crashes to NRWT
+ https://bugs.webkit.org/show_bug.cgi?id=51160
+
+ Abort test run (in a similar way to how control-C is handled) when
+ --exit-after-n-failures/crashes-or-timeouts are passed and we've reached
+ that number of unexpected failures/crashes/timeouts.
+
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-12-16 David Levin <levin@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ check-webkit-style unit tests has some duplicate boilerplate code.
+ https://bugs.webkit.org/show_bug.cgi?id=49519
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ (update_include_state): Replaced the "io" parameter with the global
+ configuration _unit_test_config. This allowed not calling into
+ functions at a low level and also not plumbing through the injection
+ information through many levels of code.
+ (check_for_include_what_you_use): Ditto.
+ (process_file_data): Added the ability to set up the unit test config
+ to allow for injection.
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+ (ErrorCollector.__init__): Added support for having a filter for errors.
+ (ErrorCollector.__call__): Ditto.
+ (CppStyleTestBase.process_file_data): Added the ability to set unit_test_config.
+ (CppStyleTestBase.perform_lint): Consolidated logic for the perform functions.
+ (CppStyleTestBase.perform_single_line_lint): Replace specific calls to
+ functions in the cpp.py with generic processing and a filter that
+ indicates what errors should be kept.
+ (CppStyleTestBase.perform_multi_line_lint): Ditto.
+ (CppStyleTestBase.perform_language_rules_check): Ditto.
+ (CppStyleTestBase.perform_function_lengths_check): Ditto.
+ (CppStyleTestBase.perform_pass_ptr_check): Ditto.
+ (CppStyleTestBase.perform_include_what_you_use): Ditto.
+ (CppStyleTest.test_multi_line_comments): Added another
+ error message which applies to the test case.
+ (CppStyleTest.test_spacing_for_binary_ops): Fixed test
+ to not have config.h, since it is processed as a header file.
+ (CppStyleTest.test_static_or_global_stlstrings): Fixed variable name
+ style and indentation in checked code.
+ (OrderOfIncludesTest.test_check_preprocessor_in_include_section):
+ Fixed line number.
+ (NoNonVirtualDestructorsTest.test_multi_line_declaration_with_error):
+ Ditto.
+
+2010-12-15 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r74136.
+ http://trac.webkit.org/changeset/74136
+ https://bugs.webkit.org/show_bug.cgi?id=51135
+
+ r74136 breaks chromium canary bots because some tests are not
+ rebaselined correctly to resolve EOL differences (Requested by
+ jianli on #webkit).
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-12-15 Adam Roben <aroben@apple.com>
+
+ Teach check-webkit-style to check .vcproj and .vsprops files for XML
+ syntax errors
+
+ Fixes <http://webkit.org/b/51103> check-webkit-style should check for
+ XML syntax errors in .vcproj/.vsprops files
+
+ Reviewed by Dave Levin.
+
+ * Scripts/webkitpy/style/checker.py: Added lists of file extensions
+ that should be treated as XML and that should be allowed to contain
+ carriage returns. (These lists happen to be identical currently.)
+ (FileType): Added a new XML type.
+ (CheckerDispatcher.should_check_and_strip_carriage_returns): Added.
+ Just does a simple file extension check.
+ (CheckerDispatcher._file_type): Added a case for XML files.
+ (CheckerDispatcher._create_checker): Ditto. We use XMLChecker for XML
+ files (surprise!).
+ (StyleProcessor.process): Ask the dispatcher whether we should pass the
+ lines through the carriage checker.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ (CheckerDispatcherCarriageReturnTest.test_should_check_and_strip_carriage_returns):
+ Added. Checks a few file names to see if carriage returns are allowed
+ or not.
+ (CheckerDispatcherDispatchTest.assert_checker_xml): Added. Similar to
+ other assert_checker_* functions.
+ (CheckerDispatcherDispatchTest.test_xml_paths): Added. Similar to other
+ test_*_paths functions.
+ (CheckerDispatcherDispatchTest.test_xml_paths): Added. Similar to other
+ test_*_paths functions.
+ (CheckerDispatcherDispatchTest.test_none_paths): Removed the vcproj
+ file from this test case, as vcproj files now have a type.
+ (StyleProcessor_CodeCoverageTest.MockDispatcher.should_check_and_strip_carriage_returns):
+ Added. Similar to the other should_* functions.
+ (StyleProcessor_CodeCoverageTest.test_process__carriage_returns_not_stripped):
+ Added. Checks that carriage returns aren't checked for or stripped for
+ allowed files.
+
+ * Scripts/webkitpy/style/checkers/xml.py: Added.
+ (XMLChecker.__init__): Simple init method.
+ (XMLChecker.check): Pass each line through the expat parser, and record
+ a style error for any errors thrown by the parser.
+
+ * Scripts/webkitpy/style/checkers/xml_unittest.py: Added.
+ (XMLCheckerTest.assert_no_error): Checks that the given XML does not
+ produce a style error.
+ (XMLCheckerTest.assert_error): Checks that the given XML produces an
+ error of the given category on the given line.
+ (XMLCheckerTest.mock_handle_style_error): Does nothing. Used for
+ checking that the XMLChecker constructor works properly.
+ (XMLCheckerTest.test_conflict_marker): Tests that conflict markers
+ cause a style error (see, e.g., r73887).
+ (XMLCheckerTest.test_extra_closing_tag): Tests that extra closing tags
+ cause a style error (see, e.g., r73773).
+ (XMLCheckerTest.test_init): Tests that the XMLChecker constructor works
+ properly.
+ (XMLCheckerTest.test_missing_closing_tag): Tests that missing closing
+ tags cause a style error (see, e.g., r72795).
+ (XMLCheckerTest.test_no_error): Tests that valid XML does not cause a
+ style error.
+
+2010-12-15 Lucas Forschler <lforschler@apple.com>
+
+ Reviewed by Stephanie Lewis.
+
+ https://bugs.webkit.org/show_bug.cgi?id=51117
+ Add a new leopard test bot
+ really really commit to trunk this time.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2010-12-15 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ WebKit2: Can't add files to an <input type=file>
+ https://bugs.webkit.org/show_bug.cgi?id=51087
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (runOpenPanel):
+ (-[BrowserWindowController awakeFromNib]):
+ Add simple implementation of runOpenPanel callback.
+
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::create):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ (WTR::TestController::initialize):
+ Stub out runOpenPanel callback.
+
+2010-12-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue should upload failure diffs when tests flake
+ https://bugs.webkit.org/show_bug.cgi?id=51051
+
+ To make this testable I needed to pipe FileSystem down onto tool.
+ We've wanted it there for a long time anyway.
+
+ This patch is kinda a big hack. But we don't have a nice
+ way to read results.html files. I think this will need further
+ revision before this code actually feels clean.
+
+ As part of testing this change, I had to make MockBugzilla.create_bug
+ actually return an id (like it should) which required updating
+ a few other unit test results (for the better).
+
+ The results_matching_keys change in layouttestresults/rebasline
+ was an alternate path which I decided not to use in the end, but
+ I left the change as it seemed an improvement.
+
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla.py:
+ * Scripts/webkitpy/common/net/layouttestresults.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/rebaseline.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-12-15 Cosmin Truta <ctruta@chromium.org>
+
+ Reviewed by James Robinson.
+
+ new-run-webkit-tests ignores trailing EOL differences in text tests
+ https://bugs.webkit.org/show_bug.cgi?id=36983
+
+ Changed the handling of new-line characters within new-run-webkit-tests
+ to match old-run-webkit-tests. Differences in leading and trailing empty
+ lines in text expectation files are no longer ignored.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ Added unit tests. Removed old duplicate unit test entries.
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-12-15 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ make status-bubble white-space:nowrap so we can measure it's width without wrapping
+ https://bugs.webkit.org/show_bug.cgi?id=51149
+
+ * QueueStatusServer/templates/statusbubble.html:
+
+2010-12-15 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ have the statusbubble postMessage it's metrics so that embedders can properly size the iframe
+ https://bugs.webkit.org/show_bug.cgi?id=51125
+
+ * QueueStatusServer/templates/statusbubble.html:
+
+2010-12-15 Darin Adler <darin@apple.com>
+
+ * Scripts/webkitpy/common/net/buildbot: Added property svn:ignore.
+
+2010-12-15 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r74117.
+ http://trac.webkit.org/changeset/74117
+ https://bugs.webkit.org/show_bug.cgi?id=51113
+
+ This broke the GTK1 build. (Requested by mrobinson on
+ #webkit).
+
+ * Scripts/webkitdirs.pm:
+
+2010-12-15 Amruth Raj <amruthraj@motorola.com> and Ravi Kasibhatla <ravi.kasibhatla@motorola.com>
+
+ Reviewed by Martin Robinson.
+
+ Change generate-forwarding-headers.pl for GTK port usage
+ (https://bugs.webkit.org/show_bug.cgi?id=37369)
+
+ * Scripts/webkitdirs.pm: Added changes to build webkit2 for GTK port using build-webkit script.
+
+2010-12-14 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Jian Li.
+
+ [DRT/Chromium] Remove another unnecessary error message
+ https://bugs.webkit.org/show_bug.cgi?id=51083
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::didInvalidateRect):
+
+2010-12-14 Lucas Forschler <lforschler@apple.com>
+
+ Reviewed by Stephanie Lewis.
+
+ Add a new Leopard Debug Test WK2 Bot
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2010-12-14 Ojan Vafai <ojan@chromium.org>
+
+ Fix python unittests after http://trac.webkit.org/changeset/74070.
+
+ * Scripts/webkitpy/style/checkers/test_expectations_unittest.py:
+
+2010-12-14 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Jian Li.
+
+ [DRT/Chromium] Remove a unnecessary error message
+ https://bugs.webkit.org/show_bug.cgi?id=51069
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::paintInvalidatedRegion):
+
+2010-12-14 Benjamin Kalman <kalman@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Using BUG/BUGWK in test_expectations is error prone, should use BUGCR/BUGWK
+ https://bugs.webkit.org/show_bug.cgi?id=48926
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ Add presubmit check that BUG isn't used, either BUGCR/BUGWK/BUGV8_.
+
+2010-12-14 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] [Symbian] Do not use pkg-config on Symbian as it is not supported
+ https://bugs.webkit.org/show_bug.cgi?id=50231
+
+ Guard CONFIG+=link_pkgconfig with !symbian.
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro:
+ * WebKitTestRunner/qt/WebKitTestRunner.pro:
+
+2010-12-14 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by Ojan Vafai.
+
+ [new-run-webkit-tests] expectations parsing is slow
+ https://bugs.webkit.org/show_bug.cgi?id=50635
+
+ Avoid expensive iteration of all the tests when checking if a test
+ file is to be skipped or not.
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+
+2010-12-14 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [Gtk] Implement STATE_FOCUSED, STATE_FOCUSABLE, and corresponding events for text objects
+ https://bugs.webkit.org/show_bug.cgi?id=27048
+
+ Add support in DRT for checking whether an accessibility UI
+ element is focusable and/or focused. Implemented for GTK.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getIsFocusedCallback): New.
+ (getIsFocusableCallback): New.
+ (AccessibilityUIElement::getJSClass): Add the new available
+ callbacks for isFocused and isFocusable.
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::isFocused): New, implemented by checking
+ whether the related AtkState value is in the object's state set.
+ (AccessibilityUIElement::isFocusable): Ditto.
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::isFocused): New, dummy implementation.
+ (AccessibilityUIElement::isFocusable): Ditto.
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::isFocused): Ditto.
+ (AccessibilityUIElement::isFocusable): Ditto.
+
+2010-12-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Ojan Vafai.
+
+ webkit-patch should warn users when they're using a 32-bit git on a 64-bit system
+ https://bugs.webkit.org/show_bug.cgi?id=50715
+
+ This patch makes webkit-patch print the following:
+
+ Warning: This machine is 64-bit, but the git binary (/usr/local/git/bin/git) does not support 64-bit.
+ Install a 64-bit git for better performance, see:
+ https://lists.webkit.org/pipermail/webkit-dev/2010-December/015249.html
+
+ I wrote this mostly because I have approximately 8 machines that I use
+ and making sure each one is using a good Git install seemed folly.
+ webkit-patch makes a lot of git calls, so using a fast git can shave
+ several seconds in every invocation. See the webkit-dev thread for more info.
+
+ This message will print twice during 'webkit-patch upload',
+ once from webkit-patch and once from check-webkit-style.
+
+ Unfortunately there is no good way to test this due to how machine-dependent
+ the code is. I considered writing a test for the log message, but it seemed not worth it.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+
+2010-12-13 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ FlakyTestReporter doesn't understand bots running from multiple email addresses
+ https://bugs.webkit.org/show_bug.cgi?id=50960
+
+ This explains at least one of the dupes of:
+ https://bugs.webkit.org/show_bug.cgi?id=50863
+ that we saw filed by the commit-queue this morning.
+ I think the other one was explained by my previous fix to result counting code.
+
+ Since this is really hard to test with a unit test, instead I
+ create a new (possibly useful in the future) command
+ which given a layout test path will return you
+ the one bug which our tools would assume it the flaky test bug.
+ If some other script wants to use bug-for-test we'll
+ need to extend it with some options like --create-if-missing or similar.
+
+ * Scripts/webkitpy/common/net/bugzilla/bug.py:
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter.py:
+ * Scripts/webkitpy/tool/commands/__init__.py:
+ * Scripts/webkitpy/tool/commands/bugfortest.py: Added.
+
+2010-12-13 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by James Robinson.
+
+ Add option to build-webkit to not build WebKit2
+ https://bugs.webkit.org/show_bug.cgi?id=50988
+
+ Add support for a --no-webkit2 option to build-webkit. It seems to save
+ ~1 minute from clean builds and ~10 seconds from no-op builds.
+
+ * Scripts/build-webkit:
+
+2010-12-13 Lucas Forschler <lforschler@apple.com>
+
+ Reviewed by Dave Kilzer.
+
+ Update iexploder from 1.3.2 to 1.7.2
+ Move 1.3.2 into its own subdir
+ Add 1.7.2 into its own subdir
+ update scripts to point to new 1.3.2 location (avoid breaking existing scripts)
+
+ * Scripts/run-iexploder-tests:
+ * Scripts/update-iexploder-cssproperties:
+ * iExploder/CHANGELOG.txt: Removed.
+ * iExploder/LICENSE.txt: Removed.
+ * iExploder/README.txt: Removed.
+ * iExploder/htdocs: Removed.
+ * iExploder/iexploder-1.3.2: Added.
+ * iExploder/iexploder-1.3.2/CHANGELOG.txt: Copied from iExploder/CHANGELOG.txt.
+ * iExploder/iexploder-1.3.2/LICENSE.txt: Copied from iExploder/LICENSE.txt.
+ * iExploder/iexploder-1.3.2/README.txt: Copied from iExploder/README.txt.
+ * iExploder/iexploder-1.3.2/htdocs: Added.
+ * iExploder/iexploder-1.3.2/htdocs/config.rb: Copied from iExploder/htdocs/config.rb.
+ * iExploder/iexploder-1.3.2/htdocs/cssproperties.in: Copied from iExploder/htdocs/cssproperties.in.
+ * iExploder/iexploder-1.3.2/htdocs/cssvalues.in: Copied from iExploder/htdocs/cssvalues.in.
+ * iExploder/iexploder-1.3.2/htdocs/htmlattrs.in: Copied from iExploder/htdocs/htmlattrs.in.
+ * iExploder/iexploder-1.3.2/htdocs/htmltags.in: Copied from iExploder/htdocs/htmltags.in.
+ * iExploder/iexploder-1.3.2/htdocs/htmlvalues.in: Copied from iExploder/htdocs/htmlvalues.in.
+ * iExploder/iexploder-1.3.2/htdocs/iexploder.cgi: Copied from iExploder/htdocs/iexploder.cgi.
+ * iExploder/iexploder-1.3.2/htdocs/iexploder.rb: Copied from iExploder/htdocs/iexploder.rb.
+ * iExploder/iexploder-1.3.2/htdocs/index.html: Copied from iExploder/htdocs/index.html.
+ * iExploder/iexploder-1.3.2/htdocs/webserver.rb: Copied from iExploder/htdocs/webserver.rb.
+ * iExploder/iexploder-1.3.2/tools: Added.
+ * iExploder/iexploder-1.3.2/tools/lasthit.rb: Copied from iExploder/tools/lasthit.rb.
+ * iExploder/iexploder-1.3.2/tools/osx_last_crash.rb: Copied from iExploder/tools/osx_last_crash.rb.
+ * iExploder/iexploder-1.3.2/tools/showtest.rb: Copied from iExploder/tools/showtest.rb.
+ * iExploder/iexploder-1.7.2: Added.
+ * iExploder/iexploder-1.7.2/ChangeLog.txt: Added.
+ * iExploder/iexploder-1.7.2/LICENSE.txt: Added.
+ * iExploder/iexploder-1.7.2/README.txt: Added.
+ * iExploder/iexploder-1.7.2/output: Added.
+ * iExploder/iexploder-1.7.2/src: Added.
+ * iExploder/iexploder-1.7.2/src/browser_harness.rb: Added.
+ * iExploder/iexploder-1.7.2/src/config.yaml: Added.
+ * iExploder/iexploder-1.7.2/src/css-atrules: Added.
+ * iExploder/iexploder-1.7.2/src/css-atrules/mozilla: Added.
+ * iExploder/iexploder-1.7.2/src/css-atrules/webkit: Added.
+ * iExploder/iexploder-1.7.2/src/css-properties: Added.
+ * iExploder/iexploder-1.7.2/src/css-properties/dillo: Added.
+ * iExploder/iexploder-1.7.2/src/css-properties/gtkhtml: Added.
+ * iExploder/iexploder-1.7.2/src/css-properties/internet_explorer6: Added.
+ * iExploder/iexploder-1.7.2/src/css-properties/mozilla: Added.
+ * iExploder/iexploder-1.7.2/src/css-properties/webkit: Added.
+ * iExploder/iexploder-1.7.2/src/css-pseudo: Added.
+ * iExploder/iexploder-1.7.2/src/css-pseudo/mozilla: Added.
+ * iExploder/iexploder-1.7.2/src/css-pseudo/webkit: Added.
+ * iExploder/iexploder-1.7.2/src/css-values: Added.
+ * iExploder/iexploder-1.7.2/src/css-values/dillo: Added.
+ * iExploder/iexploder-1.7.2/src/css-values/gtkhtml: Added.
+ * iExploder/iexploder-1.7.2/src/css-values/mozilla: Added.
+ * iExploder/iexploder-1.7.2/src/css-values/other: Added.
+ * iExploder/iexploder-1.7.2/src/css-values/webkit: Added.
+ * iExploder/iexploder-1.7.2/src/headers: Added.
+ * iExploder/iexploder-1.7.2/src/headers/dillo: Added.
+ * iExploder/iexploder-1.7.2/src/headers/gtkhtml: Added.
+ * iExploder/iexploder-1.7.2/src/headers/mozilla: Added.
+ * iExploder/iexploder-1.7.2/src/headers/webkit: Added.
+ * iExploder/iexploder-1.7.2/src/html-attrs: Added.
+ * iExploder/iexploder-1.7.2/src/html-attrs/dillo: Added.
+ * iExploder/iexploder-1.7.2/src/html-attrs/gtkhtml: Added.
+ * iExploder/iexploder-1.7.2/src/html-attrs/internet_explorer6: Added.
+ * iExploder/iexploder-1.7.2/src/html-attrs/mozilla: Added.
+ * iExploder/iexploder-1.7.2/src/html-attrs/other: Added.
+ * iExploder/iexploder-1.7.2/src/html-attrs/webkit: Added.
+ * iExploder/iexploder-1.7.2/src/html-tags: Added.
+ * iExploder/iexploder-1.7.2/src/html-tags/dillo: Added.
+ * iExploder/iexploder-1.7.2/src/html-tags/gtkhtml: Added.
+ * iExploder/iexploder-1.7.2/src/html-tags/mozilla: Added.
+ * iExploder/iexploder-1.7.2/src/html-tags/other: Added.
+ * iExploder/iexploder-1.7.2/src/html-tags/webkit: Added.
+ * iExploder/iexploder-1.7.2/src/html-values: Added.
+ * iExploder/iexploder-1.7.2/src/html-values/dillo: Added.
+ * iExploder/iexploder-1.7.2/src/html-values/gtkhtml: Added.
+ * iExploder/iexploder-1.7.2/src/html-values/mozilla: Added.
+ * iExploder/iexploder-1.7.2/src/html-values/other: Added.
+ * iExploder/iexploder-1.7.2/src/html-values/webkit: Added.
+ * iExploder/iexploder-1.7.2/src/iexploder.cgi: Added.
+ * iExploder/iexploder-1.7.2/src/iexploder.rb: Added.
+ * iExploder/iexploder-1.7.2/src/index.html: Added.
+ * iExploder/iexploder-1.7.2/src/media: Added.
+ * iExploder/iexploder-1.7.2/src/media/blank.ogg: Added.
+ * iExploder/iexploder-1.7.2/src/media/blank.snd: Added.
+ * iExploder/iexploder-1.7.2/src/media/blank.wav: Added.
+ * iExploder/iexploder-1.7.2/src/media/bug.bmp: Added.
+ * iExploder/iexploder-1.7.2/src/media/bug.gif: Added.
+ * iExploder/iexploder-1.7.2/src/media/bug.ico: Added.
+ * iExploder/iexploder-1.7.2/src/media/bug.jng: Added.
+ * iExploder/iexploder-1.7.2/src/media/bug.jpg: Added.
+ * iExploder/iexploder-1.7.2/src/media/bug.png: Added.
+ * iExploder/iexploder-1.7.2/src/media/bug.svg: Added.
+ * iExploder/iexploder-1.7.2/src/media/bug.tiff: Added.
+ * iExploder/iexploder-1.7.2/src/media/bug.xbm: Added.
+ * iExploder/iexploder-1.7.2/src/media/bug.xpm: Added.
+ * iExploder/iexploder-1.7.2/src/mime-types: Added.
+ * iExploder/iexploder-1.7.2/src/mime-types/dillo: Added.
+ * iExploder/iexploder-1.7.2/src/mime-types/mozilla: Added.
+ * iExploder/iexploder-1.7.2/src/mime-types/webkit: Added.
+ * iExploder/iexploder-1.7.2/src/protocols: Added.
+ * iExploder/iexploder-1.7.2/src/protocols/dillo: Added.
+ * iExploder/iexploder-1.7.2/src/protocols/gtkhtml: Added.
+ * iExploder/iexploder-1.7.2/src/protocols/mozilla: Added.
+ * iExploder/iexploder-1.7.2/src/protocols/webkit: Added.
+ * iExploder/iexploder-1.7.2/src/scanner.rb: Added.
+ * iExploder/iexploder-1.7.2/src/version.rb: Added.
+ * iExploder/iexploder-1.7.2/src/webserver.rb: Added.
+ * iExploder/iexploder-1.7.2/testcases: Added.
+ * iExploder/iexploder-1.7.2/testcases/testcase-Linux_x86_64_rv2.0b6pre_Gecko-20100904_Firefox-4.0b6pre-TEST-8375-1_59.html: Added.
+ * iExploder/iexploder-1.7.2/testcases/testcase-Opera-9.80_Linux_x86_64_en_Presto-2.6.30_Version-10.61-16704-3_108,3.html: Added.
+ * iExploder/iexploder-1.7.2/testcases/testcase-U_Intel_Mac_OS_X_10_6_4_en-US_AppleWebKit-534.8_Chrome-7.0.529.0-TEST-611-3_36,9.html: Added.
+ * iExploder/iexploder-1.7.2/testcases/testcase-U_Intel_Mac_OS_X_10_6_4_en-US_AppleWebKit-534.8_hrome-7.0.529.0-TEST-55313622206-3_6,0.html: Added.
+ * iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.6_Chrome-7.0.503.1-TEST-120813-8_72,56,24,8,0.html: Added.
+ * iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.6_Chrome-7.0.503.1-TEST-121240-3_81,3.html: Added.
+ * iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-4800-5_80,65,15.html: Added.
+ * iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-TEST-23583190347-3_15,12.html: Added.
+ * iExploder/iexploder-1.7.2/tools: Added.
+ * iExploder/iexploder-1.7.2/tools/lasthit.rb: Added.
+ * iExploder/iexploder-1.7.2/tools/osx_last_crash.rb: Added.
+ * iExploder/iexploder-1.7.2/tools/release_src.sh: Added.
+ * iExploder/iexploder-1.7.2/tools/update_html_tags_from_sources.sh: Added.
+ * iExploder/tools: Removed.
+
+2010-12-13 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Remove associated page concept from WKView constructor
+ https://bugs.webkit.org/show_bug.cgi?id=50983
+
+ Step 1: Remove associate page constructors from WKView and make
+ all views use the shared namespace for the context.
+
+ * TestWebKitAPI/PlatformWebView.h:
+ * TestWebKitAPI/mac/PlatformWebViewMac.mm:
+ * TestWebKitAPI/win/PlatformWebViewWin.cpp:
+ * WebKitTestRunner/PlatformWebView.h:
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ * WebKitTestRunner/mac/PlatformWebViewMac.mm:
+ * WebKitTestRunner/qt/PlatformWebViewQt.cpp:
+ * WebKitTestRunner/win/PlatformWebViewWin.cpp:
+
+2010-12-13 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Change the WebKit2 public API so there is no explicit WKPageNamespace object
+ https://bugs.webkit.org/show_bug.cgi?id=50898
+
+ * MiniBrowser/mac/AppDelegate.h:
+ * MiniBrowser/mac/AppDelegate.m:
+ * MiniBrowser/mac/BrowserWindowController.h:
+ * MiniBrowser/mac/BrowserWindowController.m:
+ * MiniBrowser/win/BrowserView.cpp:
+ Convert MiniBrowser to not use PageNamespaces.
+
+ * TestWebKitAPI/PlatformWebView.h:
+ * TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp:
+ * TestWebKitAPI/Tests/WebKit2/EvaluateJavaScript.cpp:
+ * TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp:
+ * TestWebKitAPI/Tests/WebKit2/Find.cpp:
+ * TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.cpp:
+ * TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.cpp:
+ * TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic.cpp:
+ * TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp:
+ * TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp:
+ * TestWebKitAPI/Tests/WebKit2/PreventEmptyUserAgent.cpp:
+ * TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp:
+ * TestWebKitAPI/Tests/WebKit2/win/AltKeyGeneratesWMSysCommand.cpp:
+ * TestWebKitAPI/Tests/WebKit2/win/WMCloseCallsUIClientClose.cpp:
+ * TestWebKitAPI/mac/PlatformWebViewMac.mm:
+ * TestWebKitAPI/win/PlatformWebViewWin.cpp:
+ Convert TestWebKitAPI to not use PageNamespaces.
+
+ * WebKitTestRunner/PlatformWebView.h:
+ * WebKitTestRunner/TestController.cpp:
+ * WebKitTestRunner/TestController.h:
+ * WebKitTestRunner/mac/PlatformWebViewMac.mm:
+ * WebKitTestRunner/qt/PlatformWebViewQt.cpp:
+ * WebKitTestRunner/win/PlatformWebViewWin.cpp:
+ Convert WebKitTestRunner to not use PageNamespaces.
+
+2010-12-13 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch rollout should be able to do multi-revision rollouts
+ https://bugs.webkit.org/show_bug.cgi?id=33336
+
+ Make it possible to pass more than one revision to webkit-patch.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ * Scripts/webkitpy/common/checkout/changelog_unittest.py:
+ * Scripts/webkitpy/tool/commands/abstractsequencedcommand.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/preparechangelogforrevert.py:
+ * Scripts/webkitpy/tool/steps/revertrevision.py:
+
+2010-12-13 Eric Seidel <eric@webkit.org>
+
+ Unreviewed.
+
+ Teach webkit-patch how to search bugzilla
+ https://bugs.webkit.org/show_bug.cgi?id=50500
+
+ webkit-patch bug-search fails when there is only one result.
+ Turns out we needed a bit more logic in our result count parsing code.
+
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py:
+
+2010-12-13 Antti Koivisto <antti@apple.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Add setSerializeHTTPLoads function to allow testing resource load order on OS X.
+ https://bugs.webkit.org/show_bug.cgi?id=50758
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setSerializeHTTPLoadsCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setSerializeHTTPLoads):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setSerializeHTTPLoads):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setSerializeHTTPLoads):
+
+2010-12-13 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Remove "use-drt" option from test step command line, since the option was removed in r73748.
+ https://bugs.webkit.org/show_bug.cgi?id=50936
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: Removed the option.
+
+2010-12-13 Patrick Gansterer <paroga@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ Add revlink to BuildBot status
+ https://bugs.webkit.org/show_bug.cgi?id=50914
+
+ This adds a hyperlink to trac changeset on the revision numbers.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2010-12-13 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [Qt][WK2] Fix build if WebKitTools are not available
+ https://bugs.webkit.org/show_bug.cgi?id=50242
+
+ * MiniBrowser/qt/MiniBrowser.pro: Correct the comment.
+ * Scripts/webkitdirs.pm: Added WebKitTools/MiniBrowser to $subdirs.
+ * MiniBrowser/DerivedSources.pro: Added.
+
+2010-12-13 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ EWS Queues should remove orpahned pyc files before starting
+ https://bugs.webkit.org/show_bug.cgi?id=50904
+
+ A previous check added a platform.py which caused
+ EWS bots on some platforms to hit an import exception.
+ The platform.py file was removed in a subsequent commit, but
+ the EWS bots in question stayed stuck. This change will
+ fix those bots once restarted (and prevent this in the future).
+
+ I also went ahead and unified start-queue and start-commit-queue
+ since they were nearly identical. I also added bot_id support
+ to both force all EWSes to have bot ids as well as get rid of the one
+ remaining reason why I had my own copies of these scripts.
+ Hopefully this will be enough to get all the other bot admins
+ (ahem, Adam, ahem) to move to using these checked in copies as well.
+
+ * EWSTools/start-commit-queue.sh: Removed.
+ * EWSTools/start-queue.sh:
+
+2010-10-28 MORITA Hajime <morrita@google.com>
+
+ Reviewed by Ojan Vafai.
+
+ spellcheck does not check pasted text
+ https://bugs.webkit.org/show_bug.cgi?id=40092
+
+ Added LayoutTestController::setAsynchronousSpellCheckingEnabled()
+ to control the setting.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setAsynchronousSpellCheckingEnabledCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::setAsynchronousSpellCheckingEnabled):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setAsynchronousSpellCheckingEnabled):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setAsynchronousSpellCheckingEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setAsynchronousSpellCheckingEnabled):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setAsynchronousSpellCheckingEnabled):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setAsynchronousSpellCheckingEnabled):
+
+2010-12-12 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Fix failing API test. It turns out that a pop-state event
+ is sent before every fragment navigation, so we have to test
+ for it in addition in PageLoadDidChangeLocationWithinPageForFrame.
+
+ * TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp:
+ (TestWebKitAPI::didSameDocumentNavigationForFrame):
+
+2010-12-12 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Eric Seidel.
+
+ [GTK] Add new-run-webkit-tests support to gtk
+ https://bugs.webkit.org/show_bug.cgi?id=50681
+
+ Adding the basic support to run the new-run-webkit-tests.
+
+ * Scripts/webkitpy/layout_tests/port/gtk.py:
+
+2010-10-11 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Mock DeviceOrientation client for DRT
+ https://bugs.webkit.org/show_bug.cgi?id=47490
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::~DumpRenderTree):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setMockDeviceOrientation):
+
+2010-12-11 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] launcher: disable the Mozilla-style fullscreen API
+ https://bugs.webkit.org/show_bug.cgi?id=50874
+
+ Disabling the fullscreen API until its implementation for GTK is
+ mature enough. The webview setting for it is already FALSE by
+ default.
+
+ * GtkLauncher/main.c:
+ (createWindow):
+
+2010-12-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue flaky test messages show cryptic version information for mac os x
+ https://bugs.webkit.org/show_bug.cgi?id=50864
+
+ Turns out platform.platform() returns kernel version information
+ which isn't helpful, and just plain confusing on Mac
+ (OS X 10.6.5 uses Darwin Kernel 10.5.0).
+
+ So I've updated PlatformInfo.display_name() to special case
+ mac. I also found a bad use of sys.platform in the process
+ and fixed that. (sys.platform always returns 'darwin' on mac).
+
+ * Scripts/webkitpy/common/system/platforminfo.py:
+ * Scripts/webkitpy/common/system/user.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-12-10 Eric Seidel <eric@webkit.org>
+
+ Unreviewed.
+
+ Exception seen while reporting flaky test with commit-queue.
+ Just a missing include.
+
+ * Scripts/webkitpy/tool/bot/flakytestreporter.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py:
+
+2010-12-10 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [Chromium] Remove old JSONResultsGenerator script that existed for backward-compatibility
+ https://bugs.webkit.org/show_bug.cgi?id=50796
+
+ Also updating the test code to use JSONResultsGeneratorBase and
+ to improve test coverage for incremental cases.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py:
+
+2010-12-10 Joseph Pecoraro <joepeck@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ prepare-ChangeLog --help doesn't mention --bug shorthand -b
+ https://bugs.webkit.org/show_bug.cgi?id=50835
+
+ * Scripts/prepare-ChangeLog: be more explicit about -b and match file style.
+
+2010-12-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Bugs created by the commit-queue should all block on a master bug
+ https://bugs.webkit.org/show_bug.cgi?id=50857
+
+ This makes all bugs created by the commit-queue block on:
+ https://bugs.webkit.org/show_bug.cgi?id=50856
+
+ In the process of testing this, I found that the existing
+ create_bug code was wrong. I also found that existing
+ unit tests for create-rollout used invalid values
+ for options.blocks. I fixed both issues and tested.
+
+ * Scripts/webkitpy/tool/bot/flakytestreporter.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py:
+ * Scripts/webkitpy/tool/commands/commandtest.py:
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/options.py:
+
+2010-12-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Teach webkitpy how to follow duplicate chains when posting comments on flake bugs
+ https://bugs.webkit.org/show_bug.cgi?id=50853
+
+ I also discovered when doing this that the code was posting
+ the comment on the wrong bug, but that's fixed here too.
+
+ * Scripts/webkitpy/common/net/bugzilla/bug.py:
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-12-10 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by John Sullivan.
+
+ Make WKContextGetStatistics gather global statistics
+ https://bugs.webkit.org/show_bug.cgi?id=50850
+
+ Remove the code that gets the statistics and fills in the per context
+ statistics information for now.
+
+ * MiniBrowser/mac/BrowserStatisticsWindowController.m:
+ (-[BrowserStatisticsWindowController refreshStatistics:]):
+
+2010-12-10 Eric Seidel <eric@webkit.org>
+
+ Unreviewed.
+
+ commit-queue should report port/platform information when commenting on flaky test bugs
+ https://bugs.webkit.org/show_bug.cgi?id=50839
+
+ Renamed platform.py to platforminfo.py. This broke import platform in executive.py
+ which was only used by new run webkit tests (and clearly not unit tested).
+
+ * Scripts/webkitpy/common/system/platforminfo.py: Renamed from WebKitTools/Scripts/webkitpy/common/system/platform.py.
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-12-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Tony Chang.
+
+ commit-queue should report port/platform information when commenting on flaky test bugs
+ https://bugs.webkit.org/show_bug.cgi?id=50839
+
+ This was a suggestion from Tony Chang this morning.
+ I added a platform.py class so I could easily mock the platform call,
+ but that may not be the final solution for this mocking.
+ We'll try it and see.
+
+ * Scripts/webkitpy/common/system/platform.py: Added.
+ * Scripts/webkitpy/tool/bot/flakytestreporter.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-12-10 Krithigassree Sambamurthy <krithigassree.sambamurthy@nokia.com>
+
+ Reviewed by Joseph Pecoraro.
+
+ Bug 43455 - [Qt]: Implement Application Cache Quotas
+ https://bugs.webkit.org/show_bug.cgi?id=43455
+
+ Introduce functions to allow new appcache layout test origin-quota.html
+ to work correctly under Qt.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::dumpApplicationCacheQuota):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+
+ Introduce functions to allow new appcache layout test origin-quota.html
+ to be successful under qt. Changes required because LayoutTestControllerQt
+ does not inherit from LayoutController.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::clearAllApplicationCaches):
+ (LayoutTestController::setApplicationCacheOriginQuota):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::shouldDumpApplicationCacheDelegateCallbacks):
+ (LayoutTestController::dumpApplicationCacheDelegateCallbacks):
+
+2010-12-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Move buildbot.py into its own module so we can split it out into one-file-per-class
+ https://bugs.webkit.org/show_bug.cgi?id=50806
+
+ We're adding more buildbot logic these days, so it makes sense
+ to give buildbot its own module.
+
+ * Scripts/webkitpy/common/net/buildbot/__init__.py: Added.
+ * Scripts/webkitpy/common/net/buildbot/buildbot.py: Renamed from WebKitTools/Scripts/webkitpy/common/net/buildbot.py.
+ * Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py: Renamed from WebKitTools/Scripts/webkitpy/common/net/buildbot_unittest.py.
+ * Scripts/webkitpy/common/net/failuremap.py:
+ * Scripts/webkitpy/common/net/regressionwindow.py:
+ * Scripts/webkitpy/tool/commands/rebaseline.py:
+
+2010-12-10 Tony Chang <tony@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Use FileSystem::remove when cleaning up http lock files
+ https://bugs.webkit.org/show_bug.cgi?id=50830
+
+ * Scripts/webkitpy/layout_tests/port/http_lock.py:
+
+2010-12-10 Joone Hur <joone@kldp.org>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] DRT needs layoutTestController.setCacheModel
+ https://bugs.webkit.org/show_bug.cgi?id=50705
+
+ webkit_set_cache_mode() is called to set the cache model.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setCacheModel): Set the cache model.
+
+2010-12-10 Tony Chang <tony@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ [chromium] remove --use-drt and add --use-test-shell
+ https://bugs.webkit.org/show_bug.cgi?id=50701
+
+ * Scripts/webkitpy/common/config/ports.py:
+ * Scripts/webkitpy/common/config/ports_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/style/checkers/test_expectations.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+
+2010-12-10 John Knottenbelt <jknotten@chromium.org>
+
+ Reviewed by Steve Block.
+
+ [Chromium] Implement mocks for client-based geolocation
+ https://bugs.webkit.org/show_bug.cgi?id=46895
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setGeolocationPermission):
+ (LayoutTestController::setMockGeolocationPosition):
+ (LayoutTestController::setMockGeolocationError):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::geolocationClient):
+ (WebViewHost::geolocationClientMock):
+ (WebViewHost::reset):
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-12-10 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Add hasSpellingMarker support to the DRT
+ https://bugs.webkit.org/show_bug.cgi?id=50739
+
+ Implemented the hasSpellingMarker to support spelling tests.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::hasSpellingMarker):
+
+2010-12-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Ojan Vafai.
+
+ webkit-patch: not possible to use build-and-test with local commits
+ https://bugs.webkit.org/show_bug.cgi?id=33378
+
+ Make --no-clean not even check if we have local commits.
+ It's unclear to me why the code was originally written this way.
+ I was unable to dig up a reason from svn history.
+
+ * Scripts/webkitpy/tool/steps/cleanworkingdirectory.py:
+ * Scripts/webkitpy/tool/steps/cleanworkingdirectory_unittest.py: Copied from WebKitTools/Scripts/webkitpy/tool/steps/cleanworkingdirectory.py.
+
+2010-12-10 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] AX: implement isEnabled in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=50814
+
+ Implement AccessibilityUIElement::isEnabled() for GTK.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (checkElementState): New function to refactor common code.
+ (AccessibilityUIElement::isEnabled): Implement this by checking
+ the current state of the AtkObject.
+ (AccessibilityUIElement::isSelected): Use the new
+ checkElementState function.
+
+2010-12-10 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt][WK2] Add the QWKContext API class to wrap the WebContext.
+ https://bugs.webkit.org/show_bug.cgi?id=50750
+
+ * MiniBrowser/qt/BrowserView.cpp:
+ (BrowserView::BrowserView):
+ * MiniBrowser/qt/BrowserView.h:
+ * WebKitTestRunner/qt/PlatformWebViewQt.cpp:
+ (WTR::WebView::WebView):
+
+2010-12-10 Joone Hur <joone@kldp.org>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Unskipping some test cases in userscripts dependent on addUserStyleSheet
+ https://bugs.webkit.org/show_bug.cgi?id=50808
+
+ Unskipping the following test cases:
+ userscripts/mixed-case-stylesheet.html
+ userscripts/simple-stylesheet.html
+ userscripts/user-style-all-frames.html
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::addUserStyleSheet):
+
+2010-12-10 Joone Hur <joone@kldp.org>
+
+ Reviewed by Eric Seidel.
+
+ [GTK] Add DRT support for pageProperty, isPageBoxVisible, pageSizeAndMarginsInPixels, and addUserStyleSheet
+ https://bugs.webkit.org/show_bug.cgi?id=50783
+
+ This patch allows to unskip the following test cases:
+ printing/page-rule-selection.html
+ printing/page-format-data.html
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::pageProperty): Added.
+ (LayoutTestController::isPageBoxVisible): Ditto.
+ (LayoutTestController::pageSizeAndMarginsInPixels): Ditto.
+ (LayoutTestController::addUserStyleSheet): Ditto.
+
+2010-12-10 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Make QtTestBrowser spawn QNAM in a secondary thread.
+
+ A menu allows to switch QNAM back to the same thread.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::initializeView):
+ (LauncherWindow::createChrome):
+ (LauncherWindow::toggleThreadedQnam):
+ * QtTestBrowser/launcherwindow.h:
+ (WindowOptions::WindowOptions):
+ * QtTestBrowser/webpage.cpp:
+ (WebPage::WebPage):
+ (WebPage::setQnamThreaded):
+ * QtTestBrowser/webpage.h:
+ (QnamThread::QnamThread):
+ (QnamThread::~QnamThread):
+ (QnamThread::networkAccessManager):
+ (QnamThread::run):
+
+2010-12-10 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [Gtk] style="font-family: courier" makes text disappear
+ https://bugs.webkit.org/show_bug.cgi?id=47452
+
+ Add a test that verifies that fonts without valid charmaps are
+ never selected.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (initializeFonts): Initialize DRT with our font (derived from Ahem)
+ that has no valid charmap.
+ * DumpRenderTree/gtk/fonts/FontWithNoValidEncoding.fon: Added.
+ * DumpRenderTree/gtk/fonts/fonts.conf: Updated settings to override users'
+ settings which may disable selection of bitmap fonts.
+
+2010-12-10 Eric Seidel <eric@webkit.org>
+
+ Unreviewed.
+
+ The commit-queue should file bugs about flaky tests it encounters
+ https://bugs.webkit.org/show_bug.cgi?id=50803
+
+ create_bug_for_flaky_test was insufficiently tested, thus buggy.
+ Now it's tested.
+
+ * Scripts/webkitpy/tool/bot/flakytestreporter.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py:
+
+2010-12-10 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Somehow this last-minute edit didn't quite get committed.
+
+ The commit-queue should file bugs about flaky tests it encounters
+ https://bugs.webkit.org/show_bug.cgi?id=50803
+
+ * Scripts/webkitpy/tool/bot/flakytestreporter.py:
+
+2010-12-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ The commit-queue should file bugs about flaky tests it encounters
+ https://bugs.webkit.org/show_bug.cgi?id=50803
+
+ This change got a bit big. I also added a new config.urls file
+ because I needed to share the view_source_url code with committervalidator.py.
+
+ This adds a new class FlakyTestReporter which holds all the logic about
+ reporting flaky tests to bugzilla.
+
+ Right now this code knows how to look up bugs for flaky tests.
+ If it can't find a bug filed from the commit-queue, it will open a new
+ one, ccing the relevant people and adding information about the failure.
+
+ It is not yet smart enough to chase down duplicate chains, or to include
+ the actual failure diff. But those can be added in later iterations.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ * Scripts/webkitpy/common/checkout/commitinfo.py:
+ * Scripts/webkitpy/common/config/committervalidator.py:
+ * Scripts/webkitpy/common/config/urls.py: Copied from WebKitTools/Scripts/webkitpy/tool/comments.py.
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla.py:
+ * Scripts/webkitpy/tool/bot/flakytestreporter.py: Added.
+ * Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py: Copied from WebKitTools/Scripts/webkitpy/tool/comments.py.
+ * Scripts/webkitpy/tool/bot/irc_command.py:
+ * Scripts/webkitpy/tool/bot/sheriff.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/comments.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/commit.py:
+
+2010-12-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Teach webkit-patch how to search bugzilla
+ https://bugs.webkit.org/show_bug.cgi?id=50500
+
+ This is a step towards teaching webkitpy how to file
+ new bugs for flaky tests and update them when new flakes occur.
+
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py:
+ * Scripts/webkitpy/tool/commands/__init__.py:
+ * Scripts/webkitpy/tool/commands/bugsearch.py: Added.
+
+2010-12-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Ojan Vafai.
+
+ commit-queue errors out due to local commits
+ https://bugs.webkit.org/show_bug.cgi?id=50766
+
+ We seem to be tripping over having local commits in the working copy a
+ lot recently. I don't quite fully understand what the issue is, but
+ this patch attempts to solve the problem by adding an explicit clean
+ step before processing a patch. Previously, we did the cleaning as
+ part of the apply-attachment step, so this might not actually fix the
+ problem.
+
+ * Scripts/webkitpy/tool/bot/commitqueuetask.py:
+ * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-12-09 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Make new-run-webkit-tests --lint-test-files log slightly better
+ messages and return -1 if lint fails. Remove the
+ 'suppress_errors' keyword param to the TestExpectationsFile
+ class, and clean up logging and exception raising for error
+ handling. Also add more unit tests and clean up the unit test code a bit.
+
+ https://bugs.webkit.org/show_bug.cgi?id=50205
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/style/checkers/test_expectations.py:
+ * Scripts/webkitpy/style/checkers/test_expectations_unittest.py:
+
+2010-12-09 Tony Chang <tony@chromium.org>
+
+ Unreviewed, fix for windows code. We were catching the wrong
+ exception in Windows.
+
+ * Scripts/webkitpy/common/system/filesystem.py:
+
+2010-12-09 Antonio Gomes <agomes@rim.com>
+
+ Reviewed by Martin Robinson.
+
+ [Gtk] Populate DumpRenderTreeSupportGtk (part IV)
+ https://bugs.webkit.org/show_bug.cgi?id=48429
+
+ Adjust call sites of webkit_thread_count to use the DumpRenderTreeSupportGtk version now.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::workerThreadCount):
+
+2010-12-06 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Support the Mozilla-style Fullscreen Javascript API
+ https://bugs.webkit.org/show_bug.cgi?id=50572
+
+ Enable the Javascript Fullscreen support in the GtkLauncher. Also
+ make DRT update the Chrome when the WebView settings have been
+ reset to consistent values.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * GtkLauncher/main.c:
+ (create_window):
+ * Scripts/build-webkit:
+
+2010-12-09 Koan-Sin Tan <koansin.tan@gmail.com>
+
+ Reviewed by Tor Arne Vestbø
+
+ [Qt] run-launcher doesn't start the browser on Mac OS X 10.6
+ https://bugs.webkit.org/show_bug.cgi?id=50742
+
+ check not only QtWebKit.framework/QtWebKit but also libQtWebKit.dylib
+
+ * Scripts/webkitdirs.pm:
+
+2010-12-09 Joone Hur <joone@kldp.org>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Support for viewport meta tag
+ https://bugs.webkit.org/show_bug.cgi?id=45443
+
+ Add support for testing the viewport properties for WebKitGtk.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (dumpConfigurationForViewportCallback): Added this JS callback to set the size of the visible viewport.
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::dumpConfigurationForViewport): Added this function to test the viewport properties.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::dumpConfigurationForViewport): Ditto.
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::dumpConfigurationForViewport): Ditto.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::dumpConfigurationForViewport): Ditto.
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::dumpConfigurationForViewport): Ditto.
+
+2010-12-08 William Siegrist <wsiegrist@apple.com>
+
+ Reviewed by Eric Seidel.
+
+ Migrate buildbot.py from xmlrpc to json.
+ https://bugs.webkit.org/show_bug.cgi?id=50647
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+
+2010-12-08 Tony Chang <tony@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ make starting the websocket server more reliable on windows
+ https://bugs.webkit.org/show_bug.cgi?id=50712
+
+ * Scripts/webkitpy/common/system/filesystem.py:
+ (remove): Substitute method for os.remove to retry on error on Windows
+ * Scripts/webkitpy/common/system/filesystem_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/http_server_base.py: Use FileSystem.remove
+
+2010-12-08 Jessie Berlin <jberlin@apple.com>
+
+ Reviewed by Adam Roben.
+
+ WebKit2: Implement WebChromeClient::exceededDatabaseQuota
+ https://bugs.webkit.org/show_bug.cgi?id=50656
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]):
+ Indicate that exceededDatabaseQuota is not implemented.
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::create):
+ Ditto.
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ Ditto.
+ (WTR::TestController::initialize):
+ Ditto.
+
+2010-12-08 Antonio Gomes <agomes@rim.com>
+
+ Reviewed by Martin Robinson.
+
+ [Gtk] Populate DumpRenderTreeSupportGtk (part III)
+ https://bugs.webkit.org/show_bug.cgi?id=48429
+
+ Moved the following methods from webkitprivate.h to DumpRenderTreeSupportGtk.cpp|h:
+ * webkit_gc_collect_javascript_objects;
+ * webkit_gc_collect_javascript_objects_on_alternate_thread;
+ * webkit_gc_count_javascript_objects;
+ * webkit_web_frame_layout.
+
+ These were all only used by GTK+ DRT.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (dispatchEvent):
+ * DumpRenderTree/gtk/GCControllerGtk.cpp:
+ (GCController::collect):
+ (GCController::collectOnAlternateThread):
+ (GCController::getJSObjectCount):
+
+2010-12-07 Tony Chang <tony@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ [chromium] force NRWT to use DRT
+ https://bugs.webkit.org/show_bug.cgi?id=50359
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-12-06 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Generalize didChangeLocationWithinPageForFrame for all same document navigations
+ https://bugs.webkit.org/show_bug.cgi?id=50584
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (didSameDocumentNavigationForFrame):
+ (-[BrowserWindowController awakeFromNib]):
+ (-[BrowserWindowController didSameDocumentNavigationForFrame:]):
+ * TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp:
+ (TestWebKitAPI::didSameDocumentNavigationForFrame):
+ (TestWebKitAPI::TEST):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::didSameDocumentNavigationForFrame):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize):
+
+2010-12-06 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Make TestResultsServer return 404 for non-existing results files.
+ https://bugs.webkit.org/show_bug.cgi?id=50581
+
+ * TestResultServer/handlers/testfilehandler.py:
+
+2010-12-06 Tony Chang <tony@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ [chromium] fix an assert hit in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=50575
+
+ This class uses WTF's RefPtr, but expects chrome's base::RefPtr
+ semantics.
+
+ Otherwise, we hit ASSERTION FAILED: !m_adoptionIsRequired
+ (third_party/WebKit/JavaScriptCore/wtf/RefCounted.h:37 void
+ WTF::RefCountedBase::ref()).
+
+ * DumpRenderTree/chromium/TestWebWorker.h:
+ (TestWebWorker::TestWebWorker):
+
+2010-12-02 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ make webkit-patch command work when the git branch is not synced to the remote svn branch
+ https://bugs.webkit.org/show_bug.cgi?id=50424
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+
+2010-12-06 Patrick Gansterer <paroga@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [WINCE] Add build system
+ https://bugs.webkit.org/show_bug.cgi?id=50522
+
+ * CMakeListsWinCE.txt: Added.
+
+2010-12-03 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Allow the Chromium port to have Leopard-specific baselines
+ https://bugs.webkit.org/show_bug.cgi?id=50506
+
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+
+2010-12-03 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] fix 2 bugs with inspector tests in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=50492
+
+ Tasks can outlive the tasklist (even when canceled) so this was
+ causing a crash when ~WebTask() ran. Avoid this by unregistering
+ when a task is canceled.
+
+ Also fix an assert when closing devtool windows by copying some
+ logic from test_shell.
+
+ * DumpRenderTree/chromium/Task.cpp:
+ (WebTask::~WebTask):
+ (TaskList::revokeAll):
+ * DumpRenderTree/chromium/Task.h: Canceling a task now removes it from
+ the tasklist (since the task can outlive the tasklist).
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::devToolsWebView):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::~WebViewHost): Don't load about:blank when closing
+ a window if the window has devtools loaded. This avoids an
+ ASSERT and matches test_shell.
+
+2010-12-06 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Fix GtkLauncher.c style, use webkit style
+ https://bugs.webkit.org/show_bug.cgi?id=50542
+
+ * GtkLauncher/main.c:
+ (activateUriEntryCb):
+ (updateTitle):
+ (linkHoverCb):
+ (notifyTitleCb):
+ (notifyLoadStatusCb):
+ (notifyProgressCb):
+ (destroyCb):
+ (goBackCb):
+ (goForwardCb):
+ (create_webViewCb):
+ (webViewReadyCb):
+ (closeWebViewCb):
+ (createBrowser):
+ (createStatusbar):
+ (createToolbar):
+ (createWindow):
+ (main):
+
+2010-12-04 Antonio Gomes <agomes@rim.com>
+
+ Reviewed by Martin Robinson.
+
+ [Gtk] Populate DumpRenderTreeSupportGtk (Part II)
+ https://bugs.webkit.org/show_bug.cgi?id=48429
+
+ Moved more private method declared with WEBKIT_API to
+ DumpRenderTreeSupportGtk, since they were only being used by DRT.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::addOriginAccessWhitelistEntry):
+ (LayoutTestController::execCommand):
+ (LayoutTestController::isCommandEnabled):
+
+2010-12-04 Antonio Gomes <agomes@rim.com>
+
+ Reviewed by Andreas Kling.
+
+ Removed extern webkit_web_view_set_group_name from gtk/DumpRenderTree.cpp
+
+ Method was removed by http://trac.webkit.org/changeset/71604
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+
+2010-12-05 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Fix compilation warnings reported by clang
+ https://bugs.webkit.org/show_bug.cgi?id=50252
+
+ * GtkLauncher/main.c:
+ (create_window): The create_statusbar function does not have
+ parameters.
+
+2010-12-05 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Zero-sized font does not yet work
+
+ Fix fast/text/font-size-zero.html
+
+ Copy other ports by setting minimumFontSize to 0 for DRT runs.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49759
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+
+2010-12-04 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Jon Honeycutt.
+
+ WebKit2: Need client functions to notify app when the url changes due to a fragment navigation
+ https://bugs.webkit.org/show_bug.cgi?id=50511
+
+ Update tools for new didChangeLocationWithinPageForFrame client function (and changed bundle
+ signature) and added a test for the functionality (PageLoadDidChangeLocationWithinPageForFrame.cpp)
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (didChangeLocationWithinPageForFrame):
+ (-[BrowserWindowController awakeFromNib]):
+ (-[BrowserWindowController didChangeLocationWithinPageForFrame:]):
+ * TestWebKitAPI/PlatformUtilities.cpp:
+ (TestWebKitAPI::Util::toWK):
+ * TestWebKitAPI/PlatformUtilities.h:
+ (TestWebKitAPI::Util::adoptWK):
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp: Added.
+ (TestWebKitAPI::nullJavaScriptCallback):
+ (TestWebKitAPI::didFinishLoadForFrame):
+ (TestWebKitAPI::didChangeLocationWithinPageForFrame):
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/file-with-anchor.html: Added.
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj:
+ * TestWebKitAPI/win/copy-resources.cmd:
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::didChangeLocationWithinPageForFrame):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize):
+
+2010-11-08 Antonio Gomes <agomes@rim.com>
+
+ Reviewed by Martin Robinson.
+
+ [Gtk] Populate DumpRenderTreeSupportGtk
+ https://bugs.webkit.org/show_bug.cgi?id=48429
+
+ Made the previous calls to webkit_web_frame* functions defined as private
+ APIs in webkitprivate.h go through DRTSupportGtk.
+
+ * DumpRenderTree/gtk/AccessibilityControllerGtk.cpp:
+ (AccessibilityController::focusedElement):
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dumpFramesAsText):
+ (resetDefaultsToConsistentValues):
+ (dump):
+ (webViewDocumentLoadFinished):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::counterValueForElementById):
+ (LayoutTestController::pageNumberForElementById):
+ (LayoutTestController::numberOfPages):
+ (LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+ (LayoutTestController::numberOfActiveAnimations):
+ (LayoutTestController::suspendAnimations):
+ (LayoutTestController::resumeAnimations):
+ (LayoutTestController::markerTextForListItem):
+
+2010-12-03 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: use pretty text diff output
+ https://bugs.webkit.org/show_bug.cgi?id=50484
+
+ Serve *-pretty-diff.html for text diff output.
+
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js:
+ * Scripts/webkitpy/tool/commands/rebaselineserver.py:
+
+2010-12-03 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r73302.
+ http://trac.webkit.org/changeset/73302
+ https://bugs.webkit.org/show_bug.cgi?id=50499
+
+ Causes crashes in debug LayoutTests (Requested by xan_ on
+ #webkit).
+
+ * DumpRenderTree/chromium/AccessibilityUIElement.cpp:
+ (AccessibilityUIElement::AccessibilityUIElement):
+ (AccessibilityUIElement::parentElementCallback):
+ * DumpRenderTree/chromium/AccessibilityUIElement.h:
+ * DumpRenderTree/chromium/CppBoundClass.cpp:
+ * DumpRenderTree/chromium/CppBoundClass.h:
+
+2010-12-03 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Enable <a ping> for Mac/Windows/WebKit2 builds
+ <rdar://problem/8504473>
+ https://bugs.webkit.org/show_bug.cgi?id=50488
+
+ * TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp:
+ (TestWebKitAPI::TEST): Test that the default value of
+ WKPreferencesGetHyperlinkAuditingEnabled is true.
+
+2010-12-03 Chris Guillory <chris.guillory@google.com>
+
+ Reviewed by Chris Fleizach.
+
+ Include the FrameView widget of a RenderWidget in the accessibility tree.
+ https://bugs.webkit.org/show_bug.cgi?id=49106
+
+ * DumpRenderTree/chromium/AccessibilityUIElement.cpp:
+ (AccessibilityUIElement::AccessibilityUIElement):
+ (AccessibilityUIElement::parentElementCallback):
+ (AccessibilityUIElement::isEqualCallback):
+ * DumpRenderTree/chromium/AccessibilityUIElement.h:
+ * DumpRenderTree/chromium/CppBoundClass.cpp:
+ (CppBoundClass::getFromCppVariant):
+ * DumpRenderTree/chromium/CppBoundClass.h:
+
+2010-12-03 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: organize tests by state, add dry run mode
+ https://bugs.webkit.org/show_bug.cgi?id=50473
+
+ Group tests in the menu by state, so that it's easier to see after
+ processing the queue which failed.
+
+ Add support for the --dry-run flag so that it's easier to test changes
+ such as this (stubs out filesystem and SCM operations).
+
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js:
+ * Scripts/webkitpy/tool/commands/rebaselineserver.py:
+
+2010-12-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Anders Carlsson.
+
+ Groundwork for <rdar://problem/7660733> and https://bugs.webkit.org/show_bug.cgi?id=50191
+ WebKit2 Authentication Support
+
+ Keep these builds working:
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]):
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize):
+
+2010-12-02 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: move existing baselines
+ https://bugs.webkit.org/show_bug.cgi?id=50421
+
+ Implement moving of existing baselines: move all files that are about
+ to be overwriten by update baselines.
+
+ Also fix a typo in the UI JS.
+
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js:
+ * Scripts/webkitpy/tool/commands/rebaselineserver.py:
+ * Scripts/webkitpy/tool/commands/rebaselineserver_unittest.py:
+
+2010-12-03 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r73211.
+ http://trac.webkit.org/changeset/73211
+ https://bugs.webkit.org/show_bug.cgi?id=50450
+
+ Broke Chromium's "Webkit Win (dbg)(2)" bot. (Requested by
+ yutak on #webkit).
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+
+2010-12-03 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r73222.
+ http://trac.webkit.org/changeset/73222
+ https://bugs.webkit.org/show_bug.cgi?id=50449
+
+ r73211 seemed to break Chromium's "Webkit Win (dbg)(2)" bot.
+ (Requested by yutak on #webkit).
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker.py:
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-12-03 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r73228.
+ http://trac.webkit.org/changeset/73228
+ https://bugs.webkit.org/show_bug.cgi?id=50448
+
+ r73211 seemed to break Chromium's "Webkit Win (dbg)(2)" bot.
+ (Requested by yutak on #webkit).
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-12-03 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r73231.
+ http://trac.webkit.org/changeset/73231
+ https://bugs.webkit.org/show_bug.cgi?id=50443
+
+ r73211 seemed to broke Chromium's "Webkit Win (dbg)(2)" bot.
+ (Requested by yutak on #webkit).
+
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker.py:
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-12-03 David Levin <levin@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ check-webkit-style: false positive reported for #if macro
+ https://bugs.webkit.org/show_bug.cgi?id=48242
+
+ * Scripts/webkitpy/style/checkers/cpp.py: Adjusted check to avoid
+ all preprocessor commands.
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py: Added test.
+
+2010-12-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Update the EWSTools scripts to use modern-style git repos
+ https://bugs.webkit.org/show_bug.cgi?id=50402
+
+ * EWSTools/create-webkit-git:
+ * EWSTools/start-commit-queue.sh:
+ * EWSTools/start-queue.sh:
+
+2010-12-02 Simon Fraser <simon.fraser@apple.com>
+
+ Fix Chromium Linux plugin tests by not logging
+ unconditionally from the event handling code.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (handleEventX11):
+
+2010-12-02 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ nrwt multiprocessing - move logic back into run_webkit_tests
+
+ This change moves a bunch of logic that I had put into
+ message_broker back into run_webkit_tests, in a slightly
+ different format. WorkerMessageBroker needed to become less aware of
+ the logic the TestRunner class uses, and more generic.
+ Eventually the MessageBroker will only do generic messaging and
+ thread/process-pooling, and (almost) all of the
+ run-webkit-tests-specific logic will be moved to
+ run_webkit_tests.py and dump_render_tree_thread.py.
+
+ The biggest changes are that the Broker can now start a single
+ worker, but the responsibility for starting all of them is pushed
+ back to the TestRunner (Manager), and the logic for checking if
+ the threads are done or wedged is moved back to TestRunner. We
+ also remove WorkerMessageBroker.cleanup (not needed) and
+ cancel_workers (they have to be cancelled individually).
+
+ The message_broker is now encapsulated inside
+ TestRunner._run_tests(); it only needs to exist while actually
+ running the tests.
+
+ Also, delete a bunch of tests in message_broker_unittest that no
+ longer make much sense.
+
+ This patch depends on bug 50372.
+
+ https://bugs.webkit.org/show_bug.cgi?id=50374
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker.py:
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-12-02 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Refactor test_types's compare_output() method so that it takes a
+ TestInput object.
+
+ compare_output() will need additional information included in a TestInput
+ object to support reftests. This change is a pre-requirement of that.
+
+ https://bugs.webkit.org/show_bug.cgi?id=50362
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-12-02 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Anders Carlsson.
+
+ Add the ability to run script on 'new' and 'paint' in the test plugin
+ https://bugs.webkit.org/show_bug.cgi?id=50425
+
+ Add "onnew" and "onpaintevent" attributes to the test plugin,
+ so that tests can run JS at these times.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+ (NPP_Destroy):
+ (handleEventCarbon):
+ (handleEventCocoa):
+ (NPP_HandleEvent):
+
+2010-12-02 Sam Weinig <sam@webkit.org>
+
+ Fix Qt build.
+
+ * WebKitTestRunner/qt/PlatformWebViewQt.cpp:
+ (WTR::PlatformWebView::PlatformWebView):
+
+2010-12-02 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ WebKit2 Preferences should be held off the PageGroup, not the Context
+ https://bugs.webkit.org/show_bug.cgi?id=50414
+
+ Update for API changes.
+
+ * WebKitTestRunner/PlatformWebView.h:
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ (WTR::TestController::initialize):
+ (WTR::TestController::resetStateToConsistentValues):
+ * WebKitTestRunner/TestController.h:
+ * WebKitTestRunner/mac/PlatformWebViewMac.mm:
+ (WTR::PlatformWebView::PlatformWebView):
+ * WebKitTestRunner/win/PlatformWebViewWin.cpp:
+ (WTR::PlatformWebView::PlatformWebView):
+
+2010-12-02 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: minor cleanup for multiprocessing work
+
+ This change:
+ * moves worker naming into TestShellThread, eliminating a
+ parameter to the constructor and putting the responsibility in
+ the correct place.
+ * eliminates the _WorkerState() class in message_broker, because
+ it turns out that state really needs to be in run_webkit_tests
+ * renames the Broker classes to be module-private.
+ * fixes a bunch of minor commenting and whitespace issues to
+ make subsequent patches a bit clearer.
+ * Adds a Port hook for default_worker_model() so that we can
+ accomodate the potential for different worker models on
+ different ports.
+ * merge in the fix from 50420 for the brokenness introduced in
+ bug 50367.
+
+ This patch depends on bug 50367.
+
+ https://bugs.webkit.org/show_bug.cgi?id=50372
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker.py:
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-12-02 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ This change is a bunch of cleanup / refactoring of the file
+ below. It moves a bunch of free functions to methods on the
+ TestShellThread class, and restructures other methods to be
+ closer to the structure we'll need for the multiprocessing
+ rewrite.
+
+ It also makes the logic of --run-singly a *lot* easier to follow
+ by nestling all of the separate-thread logic into a single
+ routine.
+
+ There should be no semantic changes in this patch, just cleanup.
+
+ https://bugs.webkit.org/show_bug.cgi?id=50367
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+
+2010-12-02 Tony Chang <tony@chromium.org>
+
+ Unreviewed, rolling out r73164.
+ http://trac.webkit.org/changeset/73164
+ https://bugs.webkit.org/show_bug.cgi?id=50359
+
+ broke debugger tests on win
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-11-30 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: add updating of baselines
+ https://bugs.webkit.org/show_bug.cgi?id=50305
+
+ Implements updating of baselines, where we copy -actual.* files over
+ the current -expected.* files. To do this, we need a
+ _get_actual_result_files method to get test results files and a
+ _rebaseline_test method to actually do the file copy and SCM operation.
+ _rebaseline_test logs output into a buffer, this is useful for both
+ showing result in the UI and for unit tests.
+
+ To make passing around of the various test environment properties
+ (results directory, filesystem, SCM, etc) easier, add a TestConfig
+ class for them.
+
+ Moving of existing baselines is not implemented yet, this patch is big
+ enough as it is.
+
+ * Scripts/webkitpy/common/system/filesystem.py:
+ * Scripts/webkitpy/common/system/filesystem_mock.py:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js:
+ * Scripts/webkitpy/tool/commands/rebaselineserver.py:
+ * Scripts/webkitpy/tool/commands/rebaselineserver_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-12-02 Brent Fulgham <bfulgham@webkit.org>
+
+ Unreviewed build fix after vcproj updates.
+
+ * DumpRenderTree/win/DumpRenderTreeCairo.vsprops: Make sure
+ that WIN_CAIRO is defined for this build.
+ * DumpRenderTree/win/DumpRenderTreePreBuild.cmd: Update file
+ to reflect new 'Debug_Cairo_CFLite' and 'Release_Cairo_CFLite'
+ (these were previously 'Debug_Cairo' and 'Release_Cairo'
+
+2010-12-02 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ WebKit2 needs API to turn on popup blocking
+ https://bugs.webkit.org/show_bug.cgi?id=50407
+
+ * TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp:
+ (TestWebKitAPI::TEST):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::resetStateToConsistentValues):
+
+2010-12-01 Tony Chang <tony@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ [chromium] force NRWT to use DRT
+ https://bugs.webkit.org/show_bug.cgi?id=50359
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-12-02 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] DumpRenderTree has two copies of JavaScriptCore
+ https://bugs.webkit.org/show_bug.cgi?id=49877
+
+ * GNUmakefile.am: Remove the second copy of JavaScriptCore from the
+ LDADD list for DumpRenderTree.
+
+2010-12-02 Sergio Villar Senin <svillar@igalia.com>
+
+ Unreviewed: Added myself to list of Committers.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-12-01 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ build-webkit --chromium always updates DEPS and re-generates project files
+ https://bugs.webkit.org/show_bug.cgi?id=50340
+
+ Make build-webkit --chromium invoke update-webkit-chromium only when
+ --update-chromium is passed in, so that we don't add 20 seconds to all
+ builds.
+
+ Making all invocations update was added with r61883, with the goal of
+ making EWS bots always update. The bots will switch to using this flag
+ (as will all other webkit-patch build steps) so nothing should change
+ for them.
+
+ * Scripts/webkitdirs.pm:
+ * Scripts/webkitpy/common/config/ports.py:
+ * Scripts/webkitpy/common/config/ports_unittest.py:
+
+2010-12-01 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: add a --dry-run / -n flag
+ https://bugs.webkit.org/show_bug.cgi?id=50045
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-12-01 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ WinCairo build should not use link-time code generation (LTCG)
+ https://bugs.webkit.org/show_bug.cgi?id=50353
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * FindSafari/FindSafari.vcproj:
+ * MiniBrowser/MiniBrowser.vcproj:
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj:
+ * WebKitAPITest/WebKitAPITest.vcproj:
+ * WebKitLauncherWin/WebKitLauncherWin.vcproj:
+ * WebKitTestRunner/win/InjectedBundle.vcproj:
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj:
+ * WinLauncher/WinLauncher.vcproj:
+ * record-memory-win/record-memory-win.vcproj:
+
+2010-12-01 Martin Robinson <mrobinson@igalia.com>
+
+ Touch GetUserAgentWithNullNPPFromNPPNew.cpp in an effort to force
+ a rebuild of TestNetscapePlugin.la on GTK+. It seems that simply
+ adding the file to the sources list was not enough to force the rebuild.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp:
+ Remove an empty line at the end of this file to force a rebuild.
+
+2010-12-01 Sam Weinig <sam@webkit.org>
+
+ Fix windows build.
+
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::create):
+
+2010-12-01 Martin Robinson <mrobinson@igalia.com>
+
+ Add missing file to the TestNetscapePlugin sources list after r73057.
+
+ * GNUmakefile.am: Add missing file.
+
+2010-12-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add PageGrouping to WebKit2 API
+ https://bugs.webkit.org/show_bug.cgi?id=50332
+
+ - Update testing harnesses to deal with new PageGroup API.
+
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (WKBundleInitialize):
+ * TestWebKitAPI/InjectedBundleController.cpp:
+ (TestWebKitAPI::InjectedBundleController::initialize):
+ (TestWebKitAPI::InjectedBundleController::didInitializePageGroup):
+ (TestWebKitAPI::InjectedBundleController::initializeTestNamed):
+ * TestWebKitAPI/InjectedBundleController.h:
+ * TestWebKitAPI/InjectedBundleTest.h:
+ (TestWebKitAPI::InjectedBundleTest::initialize):
+ (TestWebKitAPI::InjectedBundleTest::didInitializePageGroup):
+ * TestWebKitAPI/PlatformUtilities.cpp:
+ (TestWebKitAPI::Util::createContextForInjectedBundleTest):
+ * TestWebKitAPI/PlatformUtilities.h:
+ * TestWebKitAPI/PlatformWebView.h:
+ * TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp:
+ (TestWebKitAPI::DocumentStartUserScriptAlertCrashTest::initialize):
+ * TestWebKitAPI/mac/PlatformWebViewMac.mm:
+ (TestWebKitAPI::PlatformWebView::PlatformWebView):
+ * TestWebKitAPI/win/PlatformWebViewWin.cpp:
+ (TestWebKitAPI::PlatformWebView::PlatformWebView):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::didInitializePageGroup):
+ (WTR::InjectedBundle::initialize):
+ (WTR::InjectedBundle::beginTesting):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h:
+ (WTR::InjectedBundle::pageGroup):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::addUserScript):
+ (WTR::LayoutTestController::addUserStyleSheet):
+ (WTR::LayoutTestController::setXSSAuditorEnabled):
+ * WebKitTestRunner/TestController.cpp:
+ * WebKitTestRunner/win/PlatformWebViewWin.cpp:
+ (WTR::PlatformWebView::PlatformWebView):
+
+2010-12-01 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ vcproj changes can't be applied cleanly by the Windows EWS bot
+ https://bugs.webkit.org/show_bug.cgi?id=50328
+
+ * CLWrapper/CLWrapper.sln: Modified property svn:eol-style.
+ * CLWrapper/CLWrapper.vcproj: Modified property svn:eol-style.
+ * DumpRenderTree/DumpRenderTree.sln: Modified property svn:eol-style.
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginCommon.vsprops: Added property svn:eol-style.
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Modified property svn:eol-style.
+ * DumpRenderTree/win/DumpRenderTreeApple.vsprops: Added property svn:eol-style.
+ * DumpRenderTree/win/DumpRenderTreeCFLite.vsprops: Added property svn:eol-style.
+ * DumpRenderTree/win/DumpRenderTreeCairo.vsprops: Added property svn:eol-style.
+ * DumpRenderTree/win/DumpRenderTreeCommon.vsprops: Added property svn:eol-style.
+ * DumpRenderTree/win/ImageDiff.vcproj: Modified property svn:eol-style.
+ * DumpRenderTree/win/ImageDiffCommon.vsprops: Added property svn:eol-style.
+ * FindSafari/FindSafari.vcproj: Modified property svn:eol-style.
+ * FindSafari/FindSafariCommon.vsprops: Added property svn:eol-style.
+ * MIDLWrapper/MIDLWrapper.sln: Modified property svn:eol-style.
+ * MIDLWrapper/MIDLWrapper.vcproj: Modified property svn:eol-style.
+ * MiniBrowser/Configurations/MiniBrowserCFLite.vsprops: Added property svn:eol-style.
+ * MiniBrowser/Configurations/MiniBrowserCommon.vsprops: Added property svn:eol-style.
+ * MiniBrowser/Configurations/MiniBrowserCoreFoundation.vsprops: Added property svn:eol-style.
+ * MiniBrowser/MiniBrowser.vcproj: Added property svn:eol-style.
+ * TestWebKitAPI/Configurations/TestWebKitAPICFLite.vsprops: Added property svn:eol-style.
+ * TestWebKitAPI/Configurations/TestWebKitAPICommon.vsprops: Added property svn:eol-style.
+ * TestWebKitAPI/Configurations/TestWebKitAPICoreFoundation.vsprops: Added property svn:eol-style.
+ * TestWebKitAPI/win/TestWebKitAPI.sln: Added property svn:eol-style.
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj: Added property svn:eol-style.
+ * TestWebKitAPI/win/TestWebKitAPIGenerated.vcproj: Added property svn:eol-style.
+ * TestWebKitAPI/win/TestWebKitAPIGeneratedCommon.vsprops: Added property svn:eol-style.
+ * WebKitAPITest/WebKitAPITest.vcproj: Added property svn:eol-style.
+ * WebKitAPITest/WebKitAPITestCommon.vsprops: Added property svn:eol-style.
+ * WebKitLauncherWin/WebKitLauncherWin.vcproj: Modified property svn:eol-style.
+ * WebKitLauncherWin/WebKitLauncherWinCommon.vsprops: Added property svn:eol-style.
+ * WebKitTestRunner/Configurations/InjectedBundleCFLite.vsprops: Added property svn:eol-style.
+ * WebKitTestRunner/Configurations/InjectedBundleCommon.vsprops: Added property svn:eol-style.
+ * WebKitTestRunner/Configurations/InjectedBundleCoreFoundation.vsprops: Added property svn:eol-style.
+ * WebKitTestRunner/Configurations/WebKitTestRunnerCFLite.vsprops: Added property svn:eol-style.
+ * WebKitTestRunner/Configurations/WebKitTestRunnerCommon.vsprops: Added property svn:eol-style.
+ * WebKitTestRunner/Configurations/WebKitTestRunnerCoreFoundation.vsprops: Added property svn:eol-style.
+ * WebKitTestRunner/WebKitTestRunner.sln: Added property svn:eol-style.
+ * WebKitTestRunner/win/InjectedBundle.vcproj: Added property svn:eol-style.
+ * WebKitTestRunner/win/InjectedBundleGenerated.vcproj: Added property svn:eol-style.
+ * WebKitTestRunner/win/InjectedBundleGeneratedCommon.vsprops: Added property svn:eol-style.
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj: Added property svn:eol-style.
+ * WinLauncher/WinLauncher.vcproj: Modified property svn:eol-style.
+ * WinLauncher/WinLauncherCommon.vsprops: Added property svn:eol-style.
+ * record-memory-win/record-memory-win-common.vsprops: Added property svn:eol-style.
+ * record-memory-win/record-memory-win.vcproj: Modified property svn:eol-style.
+
+2010-12-01 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Return a correct user agent if NPN_UserAgent is called with a null NPP from NPP_New.
+ https://bugs.webkit.org/show_bug.cgi?id=50336
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ Add new test.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp:
+ (PluginTest::NPP_New):
+ Add default implementation/
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.h:
+ * DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp: Added.
+ (GetUserAgentWithNullNPPFromNPPNew::GetUserAgentWithNullNPPFromNPPNew):
+ (GetUserAgentWithNullNPPFromNPPNew::NPP_New):
+ Get the user agent.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+ Call PluginTest::NPP_New.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+ Add new files.
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance):
+ Call PluginTest::NPP_New.
+
+2010-12-01 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fixes after recent trunk changes.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::findString):
+ * wx/build/settings.py:
+
+2010-12-01 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Darin Adler.
+
+ WebKitTestRunner needs layoutTestController.findString
+ https://bugs.webkit.org/show_bug.cgi?id=50238
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: Added findString().
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::findString): Updated signature for autogenerated bindings.
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h: Ditto.
+
+2010-12-01 Steve Falkenburg <sfalken@apple.com>
+
+ Try using svn:eol-style native on a vcproj file.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj: Modified property svn:eol-style.
+
+2010-12-01 Patrick Gansterer <paroga@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ [WINCE] Add WinCELauncher
+ https://bugs.webkit.org/show_bug.cgi?id=50217
+
+ * WinCELauncher/main.cpp: Added.
+
+2010-11-30 Benjamin Poulain <benjamin.poulain@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Implement layoutTestController.findString
+ https://bugs.webkit.org/show_bug.cgi?id=50236
+
+ Add the missing function to the LayoutTestController.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::findString):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-11-30 Tony Chang <tony@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ [chromium] fix get-int-identifier-special-values.html using TestNetscapePlugIn
+ https://bugs.webkit.org/show_bug.cgi?id=49036
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp: Use IsNumber instead of IsInt32
+ for CppVariants.
+ (LayoutTestController::cppVariantToBool):
+ (LayoutTestController::cppVariantToInt32):
+ (LayoutTestController::setDatabaseQuota):
+ (LayoutTestController::evaluateInWebInspector):
+ (LayoutTestController::setMockGeolocationError):
+
+2010-11-30 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Tony Chang.
+
+ update-webkit should call git fetch before git svn rebase
+ https://bugs.webkit.org/show_bug.cgi?id=50273
+
+ After discussion on webkit-dev, we've decided to move the "default"
+ git setup to pulling updates from git.webkit.org in preference
+ to rebuilding the local svn index using git svn fetch every time.
+
+ This change should have no effect on people using the "old" git setup
+ and should dramatically increase the speed of updates for those using
+ the "new" git setup along with update-webkit. I'm about to move the
+ EWS and other queues over to this setup once this lands.
+
+ * Scripts/update-webkit:
+
+2010-11-30 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ GTK: AX: implement press in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=36146
+
+ Implement AccessibilityUIElement::press() for GTK.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::press): Implemented.
+
+2010-11-29 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ config.webkit_base_dir returns a path with a trailing slash
+ https://bugs.webkit.org/show_bug.cgi?id=50197
+
+ config.webkit_base_dir() should return a path without a trailing slash,
+ like all the other methods that return paths.
+
+ Undoes MockFileSytem changes by r72640, since they're no longer
+ necessary for GetBaselinesTest to pass.
+
+ * Scripts/webkitpy/common/system/filesystem_mock.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/config.py:
+ * Scripts/webkitpy/layout_tests/port/config_unittest.py:
+
+2010-11-30 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: baseline display tweaks
+ https://bugs.webkit.org/show_bug.cgi?id=50207
+
+ Determine which baselines were used when running the tests and highlight
+ them in the UI. Sort platform names alphabetically.
+
+ Also makes the server URL be launched in the user's browser
+ automatically.
+
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/util.js:
+ * Scripts/webkitpy/tool/commands/rebaselineserver.py:
+ * Scripts/webkitpy/tool/commands/rebaselineserver_unittest.py:
+
+2010-11-30 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Anders Carlsson.
+
+ <rdar://problem/8710645> WebKitTestRunner needs layoutTestController.findString
+ https://bugs.webkit.org/show_bug.cgi?id=50238
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::findString): Added.
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+
+2010-11-30 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ All projects on Windows should use cmd files for build events
+ https://bugs.webkit.org/show_bug.cgi?id=50213
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginCommon.vsprops:
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPostBuild.cmd: Added.
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPreBuild.cmd: Added.
+ * DumpRenderTree/win/DumpRenderTreeCommon.vsprops:
+ * DumpRenderTree/win/DumpRenderTreePostBuild.cmd: Added.
+ * DumpRenderTree/win/DumpRenderTreePreBuild.cmd: Added.
+ * DumpRenderTree/win/ImageDiffCommon.vsprops:
+ * DumpRenderTree/win/ImageDiffPostBuild.cmd: Added.
+ * DumpRenderTree/win/ImageDiffPreBuild.cmd: Added.
+ * MiniBrowser/Configurations/MiniBrowserCFLite.vsprops:
+ * MiniBrowser/Configurations/MiniBrowserCommon.vsprops:
+ * MiniBrowser/Configurations/MiniBrowserCoreFoundation.vsprops:
+ * MiniBrowser/MiniBrowserPostBuild.cmd: Added.
+ * MiniBrowser/MiniBrowserPreBuild.cmd: Added.
+ * TestWebKitAPI/Configurations/TestWebKitAPICommon.vsprops:
+ * TestWebKitAPI/win/TestWebKitAPIPostBuild.cmd: Added.
+ * TestWebKitAPI/win/TestWebKitAPIPreBuild.cmd: Added.
+ * WebKitAPITest/WebKitAPITestCommon.vsprops:
+ * WebKitAPITest/WebKitAPITestPostBuild.cmd: Added.
+ * WebKitAPITest/WebKitAPITestPreBuild.cmd: Added.
+ * WebKitTestRunner/Configurations/InjectedBundleCommon.vsprops:
+ * WebKitTestRunner/Configurations/WebKitTestRunnerCommon.vsprops:
+ * WebKitTestRunner/win/InjectedBundlePostBuild.cmd: Added.
+ * WebKitTestRunner/win/InjectedBundlePreBuild.cmd: Added.
+ * WebKitTestRunner/win/WebKitTestRunnerPostBuild.cmd: Added.
+ * WebKitTestRunner/win/WebKitTestRunnerPreBuild.cmd: Added.
+ * WinLauncher/WinLauncherCommon.vsprops:
+ * WinLauncher/WinLauncherPostBuild.cmd: Added.
+ * WinLauncher/WinLauncherPreBuild.cmd: Added.
+
+2010-11-29 Dan Bernstein <mitz@apple.com>
+
+ GTK DumpRenderTree build fix after r72887.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::findString):
+
+2010-11-29 Dan Bernstein <mitz@apple.com>
+
+ Windows DumpRenderTree build fix after r72887.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::findString): Added empty implementation.
+
+2010-11-29 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Darin Adler.
+
+ DumpRenderTree changes for testing the text search API.
+ https://bugs.webkit.org/show_bug.cgi?id=50038
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (findStringCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::findString):
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController find:]):
+
+2010-11-29 Johnny Ding <jnd@chromium.org>
+
+ Unreviewed: Add myself to the list of Committers.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-11-29 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ <rdar://problem/8694997> DumpRenderTree fails to build.
+
+ * DumpRenderTree/mac/PerlSupport/Makefile: Skip generating wrappers.
+
+2010-11-29 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ <rdar://problem/8694997> DumpRenderTree fails to build.
+
+ * DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportPregenerated.pm: Renamed from WebKitTools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportTiger.pm.
+ * DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapPregenerated.c: Renamed from WebKitTools/DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapTiger.c.
+ * DumpRenderTree/mac/PerlSupport/Makefile:
+
+2010-11-29 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Null-check needed in DRT's AccessibilityUIElement::allAtributes()
+ https://bugs.webkit.org/show_bug.cgi?id=50154
+
+ Added missing checks to allAttributes().
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::allAttributes): Added missing checks.
+
+2010-11-29 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Allow pre-generation for package builds for WebKit2
+ https://bugs.webkit.org/show_bug.cgi?id=50139
+
+ Use a build variable for the generated directory path and set the
+ value based on CONFIG just like for WebKit1.
+
+ For non-package builds use a relative base path for the
+ genrated directory just like for WebKit1.
+
+ * WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro:
+ * WebKitTestRunner/qt/WebKitTestRunner.pro:
+
+2010-11-28 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Move some build logic from Qt to platform independent code
+ https://bugs.webkit.org/show_bug.cgi?id=50134
+
+ Create target directories inside generate-forwarding-headers.pl.
+
+ * Scripts/generate-forwarding-headers.pl:
+
+2010-11-24 Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Windowless plugins gets broken key input
+ https://bugs.webkit.org/show_bug.cgi?id=49927
+
+ Convert the XEvent::keycode to ASCII before printing it. Not
+ doing this was causing false positive in
+ plugins/keyboard-events.html.
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (keycode_to_char):
+ (webkit_test_plugin_handle_event):
+
+2010-11-24 Jan Erik Hanssen <jhanssen@sencha.com>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] Html autofocus not working with QGraphicsWebView
+ https://bugs.webkit.org/show_bug.cgi?id=43169
+
+ Tell the scene to set the webview item as the currently
+ focused item. This makes the input field with autofocus get
+ focus as it should.
+
+ * QtTestBrowser/webview.cpp:
+ (WebViewGraphicsBased::WebViewGraphicsBased):
+
+2010-11-24 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ nrwt - clean up create_driver interface and print out the
+ command line used for DumpRenderTree/TestShell.
+
+ This patch adds a driver_cmd_line() call to the Port class in
+ order to retrive the command line to print it out (as part of
+ --print config).
+
+ In addition, this patch cleans up the Port.create_driver()
+ signature and the Driver constructor interface to take a worker
+ number and no longer require the image_path argument (Chromium's
+ drivers now synthesize the image_path from the worker number
+ internally).
+
+ https://bugs.webkit.org/show_bug.cgi?id=49934
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+ * Scripts/webkitpy/layout_tests/port/port_testcase.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-11-24 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [chromium] improve memory usage for test results server and store fewer runs
+ https://bugs.webkit.org/show_bug.cgi?id=50035
+
+ Store fewer runs and don't pass full files around when we only need bools.
+ Greatly improves error rates on test-results.appspot.com.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * TestResultServer/handlers/testfilehandler.py:
+ * TestResultServer/model/dashboardfile.py:
+ * TestResultServer/model/jsonresults.py:
+
+2010-11-24 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ This patch implements the first part of the manager side of the
+ Broker objects - it handles creating threads, waiting for them
+ to complete, and running a single-threaded loop as well.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49779
+
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker.py:
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-11-24 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by David Levin.
+
+ DRT should not generate pixel output for text/plain tests
+ https://bugs.webkit.org/show_bug.cgi?id=50002
+
+ Modify Mac, Windows and GTK DRT implementations to disable pixel output
+ when encountering a text/plain response (the Chromium one already does
+ this, and none of the other ports special-case text/plain output in
+ the first place).
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dump):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dump):
+
+2010-11-24 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Unreviewed.
+
+ Add my other email address to committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-11-24 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Reviewed by Csaba Osztrogonác.
+
+ Make build-webkit --minimal build with ENABLE_INSPECTOR=0
+ https://bugs.webkit.org/show_bug.cgi?id=49975
+
+ * Scripts/build-webkit: Add ENABLE_INSPECTOR define to features,
+ to enable the script to define it 0 in case of a minimal build.
+
+2010-11-24 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] The WebKitWebView should expose a set of signals encapsulating the behavior of the EditorClient
+ https://bugs.webkit.org/show_bug.cgi?id=49143
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (createWebView): Call the new connectEditingCallbacks function.
+ * DumpRenderTree/gtk/EditingCallbacks.cpp: Added.
+ (dumpNodePath):
+ (dumpRange):
+ (insertActionString):
+ (selectionAffinityString):
+ (shouldBeginEditing):
+ (shouldEndEditing):
+ (shouldInsertNode):
+ (shouldInsertText):
+ (shouldDeleteRange):
+ (shouldShowDeleteInterfaceForElement):
+ (shouldChangeSelectedRange):
+ (shouldApplyStyle):
+ (editingBegan):
+ (userChangedContents):
+ (editingEnded):
+ (selectionChanged):
+ (connectEditingCallbacks):
+ * DumpRenderTree/gtk/EditingCallbacks.h: Added.
+ * GNUmakefile.am: Added EditingCallbacks.{h,cpp} to the source list.
+
+2010-11-24 Yi Shen <yi.4.shen@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Make QtTestBrowser remember the selected user agent
+ https://bugs.webkit.org/show_bug.cgi?id=50021
+
+ Set user agent for a new page by using the old page's
+
+ * QtTestBrowser/mainwindow.cpp:
+ (MainWindow::setPage):
+
+2010-11-24 Patrick Gansterer <paroga@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ Remove Bakefile build system files
+ https://bugs.webkit.org/show_bug.cgi?id=49983
+
+ r53757 only removed the content, but not the files.
+ This patch removes that empty files.
+
+ * DumpRenderTree/wx/DumpRenderTree.bkl: Removed.
+ * wx/browser/browser.bkl: Removed.
+ * wx/build-wxwebkit: Removed.
+
+2010-11-23 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ This patch cleans up the logic used to shard tests into groups a
+ bit and adds the --worker-model flag to NRWT. The flag is only
+ used at the moment to control whether to run single-threaded or
+ not, but eventually will also allow toggling between threads and
+ processes.
+
+ Also add a minor cleanup with _test_is_slow(), which just
+ eliminates some repetition and gives slightly better encapsulation.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49773
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-11-23 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: list current baselines and platforms
+ https://bugs.webkit.org/show_bug.cgi?id=49991
+
+ List existing baselines (with Trac links) for tests.
+
+ Add dropdowns for choosing with platform baselines to target (and what
+ to do with existing ones).
+
+ Also fix MockFileSystem.join to behave more like os.path.join (unit
+ test was ending up with two consecutive slashes in a layout test
+ path).
+
+ * Scripts/webkitpy/common/system/filesystem_mock.py:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/util.js:
+ * Scripts/webkitpy/tool/commands/rebaselineserver.py:
+ * Scripts/webkitpy/tool/commands/rebaselineserver_unittest.py: Added.
+
+2010-11-23 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ remove timeout argument to urlopen
+ https://bugs.webkit.org/show_bug.cgi?id=49995
+
+ Apparently the version of python we have on the bots doesn't accept a timeout argument.
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_results_uploader.py:
+
+2010-11-23 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r72628.
+ http://trac.webkit.org/changeset/72628
+ https://bugs.webkit.org/show_bug.cgi?id=49994
+
+ This patch is causing layout-test failtures on GTK Linux
+ 64-bit Debug (Requested by ctguil on #webkit).
+
+ * DumpRenderTree/chromium/AccessibilityUIElement.cpp:
+ (AccessibilityUIElement::AccessibilityUIElement):
+ (AccessibilityUIElement::parentElementCallback):
+ * DumpRenderTree/chromium/AccessibilityUIElement.h:
+ * DumpRenderTree/chromium/CppBoundClass.cpp:
+ * DumpRenderTree/chromium/CppBoundClass.h:
+
+2010-11-22 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ speculative fix for upload errors: stop using mechanize to upload to test-results.appspot.com
+ https://bugs.webkit.org/show_bug.cgi?id=49944
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_results_uploader.py:
+
+2010-11-23 Chris Guillory <chris.guillory@google.com>
+
+ Reviewed by Dimitri Glazkov.
+
+ Include the FrameView widget of a RenderWidget in the accessibility tree.
+ https://bugs.webkit.org/show_bug.cgi?id=49106
+
+ * DumpRenderTree/chromium/AccessibilityUIElement.cpp:
+ (AccessibilityUIElement::AccessibilityUIElement):
+ (AccessibilityUIElement::parentElementCallback):
+ (AccessibilityUIElement::isEqualCallback):
+ * DumpRenderTree/chromium/AccessibilityUIElement.h:
+ * DumpRenderTree/chromium/CppBoundClass.cpp:
+ (CppBoundClass::getFromCppVariant):
+ * DumpRenderTree/chromium/CppBoundClass.h:
+
+2010-11-23 Alex Grilo <abgrilo@profusion.mobi>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [EFL] Add tiled backing store to EWebLauncher
+ https://bugs.webkit.org/show_bug.cgi?id=45777
+
+ Allow EWebLauncher to choose between single and tiled backing store
+
+ * EWebLauncher/main.c:
+ (on_key_down):
+ (browserCreate):
+ (main):
+
+2010-11-23 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [Qt] Review the setUserPermission & friends API
+ https://bugs.webkit.org/show_bug.cgi?id=46810
+
+ Renamed requestPermissionFromUser to featurePermissionRequested
+ and cancelRequestsForPermission to featurePermissionRequestCanceled.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ * QtTestBrowser/webpage.cpp:
+ (WebPage::WebPage):
+ (WebPage::featurePermissionRequestCanceled):
+ * QtTestBrowser/webpage.h:
+
+2010-11-23 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [Qt] Review the setUserPermission & friends API
+ https://bugs.webkit.org/show_bug.cgi?id=46810
+
+ Rename setUserPermission to setFeaturePermission
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::requestPermission):
+ (WebCore::WebPage::permissionSet):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::grantDesktopNotificationPermission):
+ * QtTestBrowser/webpage.cpp:
+ (WebPage::requestPermission):
+
+2010-11-23 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [Qt] Review the setUserPermission & friends API
+ https://bugs.webkit.org/show_bug.cgi?id=46810
+
+ Rename PermissionDomain to Feature, NotificationsPermissionDomain to Notifications
+ and GeolocationPermissionDomain to Geolocation.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::requestPermission):
+ (WebCore::WebPage::cancelPermission):
+ (WebCore::WebPage::permissionSet):
+ (WebCore::DumpRenderTree::geolocationPermissionSet):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::grantDesktopNotificationPermission):
+ * QtTestBrowser/webpage.cpp:
+ (WebPage::WebPage):
+ (WebPage::requestPermission):
+ (WebPage::cancelRequestsForPermission):
+ * QtTestBrowser/webpage.h:
+
+2010-11-23 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [Qt] Review the setUserPermission & friends API
+ https://bugs.webkit.org/show_bug.cgi?id=46810
+
+ Add a ByUser suffix to PermissionGranted/Denied. In the future
+ we can add PermissionGrantedByDefault.
+
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::requestPermission):
+ (WebCore::WebPage::permissionSet):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::grantDesktopNotificationPermission):
+ * QtTestBrowser/webpage.cpp:
+ (WebPage::requestPermission):
+
+2010-11-18 Satish Sampath <satish@chromium.org>
+
+ Reviewed by Jeremy Orlow.
+
+ For speech input event, send an event object containing all the recognition results and metadata.
+ https://bugs.webkit.org/show_bug.cgi?id=49736
+
+ Updated DRT by renaming the mock result method on all platforms to the new signature.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (addMockSpeechInputResultCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::addMockSpeechInputResult):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::addMockSpeechInputResult):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::addMockSpeechInputResult):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::addMockSpeechInputResult):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::addMockSpeechInputResult):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::addMockSpeechInputResult):
+
+2010-11-22 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Fix some spacing issues with log messages with
+ new-run-webkit-tests --verbose.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49936
+
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+
+2010-11-22 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ update scm to work with different remote branches
+ https://bugs.webkit.org/show_bug.cgi?id=49949
+
+ This works if there are multiple svn tracking branches
+ and/or if the tracking branch is refs/remots/origin/master
+ instead of refs/remotes/trunk which is the direction we're trying
+ to head since that makes fetches faster.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+
+2010-11-22 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Ignore reference files which will be used by reftests when collecting
+ test cases.
+ https://bugs.webkit.org/show_bug.cgi?id=49835
+
+ * Scripts/webkitpy/layout_tests/port/test_files.py:
+ * Scripts/webkitpy/layout_tests/port/test_files_unittest.py:
+
+2010-11-22 Adam Roben <aroben@apple.com>
+
+ Use paths relative to $WebKitVSPropsRedirectionDir to access shared .vsprops files
+
+ Apple's Windows build allows placing header files and import libraries for WebKit's
+ dependencies (CoreGraphics, CFNetwork, SQLite, etc.) outside the source tree via the
+ $WebKitLibrariesDir environment variable. This is both required for production builds and
+ convenient for Apple-internal developer builds. Apple's production builds also require that
+ WebKit's shared .vsprops files be accessed relative to $WebKitLibrariesDir. In production
+ builds, the files are copied into that directory tree by the
+ WebKitLibraries/win/tools/WinTools.make file. In Apple-internal developer builds, the
+ copying is done by
+ JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.make.
+
+ This .vsprops copying is problematic in one very important case: when a developer updates
+ their source tree and then tries to build. Visual Studio only reads .vsprops files when a
+ project is first loaded. So, when Visual Studio is first opened after the .vsprops files are
+ updated, it reads in the old files that were already residing in $WebKitLibrariesDir. When a
+ build is started, JavaScriptCoreGenerated.make copies the new .vsprops files into
+ $WebKitLibrariesDir, but Visual Studio will not pick up the changes. The rest of the build
+ will proceed with out-of-date .vsprops files, which will likely result in a build failure.
+
+ To fix this, we now use normal relative paths to access the .vsprops files in the source
+ tree rather than in $WebKitLibrariesDir, but prefix those paths with a new environment
+ variable, $WebKitVSPropsRedirectionDir. In developer builds, this environment variable is
+ unset, so the normal relative paths are used to read the .vsprops files out of the source
+ tree directly. In production builds, this environment variable is set to a fake directory
+ that will cause the .vsprops files in $WebKitLibrariesDir to be found when the relative path
+ is resolved.
+
+ For example, JavaScriptCore.vcproj uses this path for FeatureDefines.vsprops:
+
+ $(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops
+
+ In developer builds, where $WebKitVSPropsRedirectionDir is unset, this will point to the
+ files in WebKitLibraries\win\tools\vsprops in the source tree. In production builds,
+ JavaScriptCore.make sets $WebKitVSPropsRedirectionDir to
+ "$(SRCROOT)\AppleInternal\tools\vsprops\OpenSource\1\2\3\", so the full path for
+ FeatureDefines.vsprops becomes:
+
+ $(SRCROOT)\AppleInternal\tools\vsprops\OpenSource\1\2\3\..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops
+
+ which resolves to:
+
+ $(SRCROOT)\AppleInternal\tools\vsprops\OpenSource\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops
+
+ (We rely on the fact that Windows doesn't care whether the directories "1", "2", and "3"
+ actually exist since they are matched by an equal number of ".." path components.)
+
+ Note that Visual Studio still won't pick up changes made to .vsprops files while Visual
+ Studio is open, but that problem hasn't seemed to cause developers many headaches so far.
+
+ Fixes <http://webkit.org/b/49181> Windows build fails mysteriously when .vsprops files are
+ updated
+
+ Reviewed by Dave Hyatt.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * FindSafari/FindSafari.vcproj:
+ * MiniBrowser/MiniBrowser.vcproj:
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj:
+ * TestWebKitAPI/win/TestWebKitAPIGenerated.vcproj:
+ * WebKitAPITest/WebKitAPITest.vcproj:
+ * WebKitLauncherWin/WebKitLauncherWin.vcproj:
+ * WebKitTestRunner/win/InjectedBundle.vcproj:
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj:
+ * WinLauncher/WinLauncher.vcproj:
+ * record-memory-win/record-memory-win.vcproj:
+ Changed to use paths relative to $WebKitVSPropsRedirectionDir to access shared .vsprops
+ files.
+
+2010-11-22 Adam Roben <aroben@apple.com>
+
+ Make it possible to run tests on Windows without Visual Studio or VC++
+ Express installed
+
+ webkitdir.pm::setupCygwinEnv dies when Visual Studio and VC++ Express
+ are not installed. But this function doesn't need to be called when we
+ already have a build available and are just trying to run the tests.
+
+ Fixes <http://webkit.org/b/49932> New Windows 7 bot can't run tests
+ because Visual Studio/VC++ Express aren't installed
+
+ Reviewed by Dave Hyatt.
+
+ * Scripts/webkitdirs.pm:
+ (determineConfigurationForVisualStudio): Don't call setupCygwinEnv, as
+ it is not needed by this function. Also added a FIXME.
+
+ (usingVisualStudioExpress): Call setupCygwinEnv directly rather than
+ relying on determineConfigurationForVisualStudio doing it.
+
+2010-11-19 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Simplify Driver.run_test() so that it takes only one parameter, TestInput.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49812
+
+ * Scripts/webkitpy/layout_tests/driver_test.py:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-11-22 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [NRWT] Retry a few times in reading a png image to avoid a race condition.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49924
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-11-22 João Paulo Rechi Vita <jprvita@profusion.mobi>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Fix EWebLauncher zoom discretization
+ https://bugs.webkit.org/show_bug.cgi?id=49810
+
+ * EWebLauncher/main.c:
+ (nearest_zoom_level_get):
+ (zoom_level_set):
+ (on_load_finished):
+ (on_key_down):
+
+2010-11-21 Sam Weinig <sam@webkit.org>
+
+ Rubber-stamped by Dan Bernstein.
+
+ Fix ~300 WebKit2 tests by enabling developer extras preference.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::resetStateToConsistentValues):
+
+2010-11-21 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ Textareas should be resizable by default
+ https://bugs.webkit.org/show_bug.cgi?id=49892
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp: Added.
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj:
+ Add preferences test.
+
+2010-11-19 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: checksum-only differences and prefetching
+ https://bugs.webkit.org/show_bug.cgi?id=49841
+
+ Add support for image test results where the only difference is in the
+ checksum.
+
+ Add prefetching of the image results from the next test.
+
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js:
+
+2010-11-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ nrwt multiprocessing - add 'worker number' concept, move stuff to worker thread
+
+ Add the 'worker number' and 'worker name' concepts to the
+ TestShellThread objects, and move test_types and test_args from
+ the TestRunner to the TestShellThread.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49768
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-11-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Do some minor cleanup and bug fixing.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49777
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-11-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ nrwt - config.build_directory() is busted
+
+ Fixes a typo that was causing us to usually return the top level
+ directory WebKitBuild instead of WebKitBuild/{Debug,Release}. The
+ bug was hidden by test stubs that were too simplistic :(.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49815
+
+ * Scripts/webkitpy/common/system/executive_mock.py:
+ * Scripts/webkitpy/layout_tests/port/config.py:
+ * Scripts/webkitpy/layout_tests/port/config_unittest.py:
+
+2010-11-19 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Add Debug_Cairo_CFLite and Release_Cairo_CFLite configurations for all vcproj files
+ https://bugs.webkit.org/show_bug.cgi?id=49819
+
+ * DumpRenderTree/DumpRenderTree.sln:
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * FindSafari/FindSafari.vcproj:
+ * MiniBrowser/MiniBrowser.vcproj:
+ * TestWebKitAPI/win/TestWebKitAPI.sln:
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj:
+ * TestWebKitAPI/win/TestWebKitAPIGenerated.vcproj:
+ * WebKitAPITest/WebKitAPITest.vcproj:
+ * WebKitLauncherWin/WebKitLauncherWin.vcproj:
+ * WebKitTestRunner/win/InjectedBundle.vcproj:
+ * WebKitTestRunner/win/InjectedBundleGenerated.vcproj:
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj:
+ * WinLauncher/WinLauncher.vcproj:
+ * record-memory-win/record-memory-win.vcproj:
+
+2010-11-19 Adam Roben <aroben@apple.com>
+
+ Add some more Windows slaves
+
+ This is probably more than we will be using in the immediate future,
+ but having some extra slave names makes experimenting with different
+ configurations easier.
+
+ Reviewed by Jon Honeycutt.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json: Added 5 more
+ Windows slaves and distributed them among the three different Test
+ builders.
+
+2010-11-19 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ [Chromium] REGRESSION: Record actual test results in the JSON result summary for non-layout tests
+ https://bugs.webkit.org/show_bug.cgi?id=49702
+
+ Re-landing r72357 with a test fix.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py:
+
+2010-11-19 Avi Drissman <avi@google.com>
+
+ Reviewed by Antonio Gomes.
+
+ Complete support for Unix editing mode
+ https://bugs.webkit.org/show_bug.cgi?id=49757
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setEditingBehaviorCallback):
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setEditingBehavior):
+
+2010-11-19 Adam Roben <aroben@apple.com>
+
+ Fix run-javascriptcore-tests when there's a space in the path to
+ testapi
+
+ Reviewed by Sam Weinig.
+
+ * Scripts/run-javascriptcore-tests: Use an indirect object when calling
+ system() to force it to interpret spaces in the path correctly.
+
+2010-11-19 Adam Roben <aroben@apple.com>
+
+ Update scripts for .exe name changes after r72327
+
+ As of r72327, the "_debug" suffix is only used in Debug_All builds.
+
+ Reviewed by Sam Weinig.
+
+ * Scripts/run-javascriptcore-tests:
+ (testapiPath):
+
+ * Scripts/sunspider-compare-results:
+ (pathToBuiltJSC):
+
+ * Scripts/webkitdirs.pm:
+ (jscPath):
+ (safariPath):
+
+2010-11-19 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Normalize Cairo/CFLite project/solution configuration names
+ https://bugs.webkit.org/show_bug.cgi?id=49818
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * MiniBrowser/MiniBrowser.vcproj:
+ * TestWebKitAPI/win/TestWebKitAPI.sln:
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj:
+ * WebKitAPITest/WebKitAPITest.vcproj:
+ * WebKitTestRunner/win/InjectedBundle.vcproj:
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj:
+ * WinLauncher/WinLauncher.vcproj:
+ * Scripts/webkitdirs.pm: Updated cairo build configs.
+
+2010-11-18 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Windows vcproj configuration names should be normalized across projects
+ https://bugs.webkit.org/show_bug.cgi?id=49776
+
+ * DumpRenderTree/DumpRenderTree.sln:
+ * FindSafari/FindSafari.vcproj:
+ * TestWebKitAPI/win/TestWebKitAPI.sln:
+ * TestWebKitAPI/win/TestWebKitAPIGenerated.vcproj:
+ * TestWebKitAPI/win/TestWebKitAPIGeneratedCommon.vsprops: Added.
+ * WebKitAPITest/WebKitAPITest.vcproj:
+ * WebKitAPITest/WebKitAPITestCommon.vsprops:
+ * WebKitLauncherWin/WebKitLauncherWin.vcproj:
+ * WebKitTestRunner/WebKitTestRunner.sln:
+ * WebKitTestRunner/win/InjectedBundleGenerated.vcproj:
+ * WebKitTestRunner/win/InjectedBundleGeneratedCommon.vsprops: Added.
+ * record-memory-win/record-memory-win.vcproj:
+
+2010-11-18 Gavin Barraclough <barraclough@apple.com>
+
+ Build fix - as per DRT-mac, always enabled developer extras,
+ in win/qt/gtk DRT.
+
+ This is necessary to enable rich exception messages to be generated
+ following https://bugs.webkit.org/show_bug.cgi?id=49708.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (shouldEnableDeveloperExtras):
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::shouldEnableDeveloperExtras):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (shouldEnableDeveloperExtras):
+
+2010-11-18 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r72357.
+ http://trac.webkit.org/changeset/72357
+ https://bugs.webkit.org/show_bug.cgi?id=49784
+
+ It broke test-webkitpy tests since the patch didn't have the
+ corresponding test update (Requested by kinuko on #webkit).
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+
+2010-11-18 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: add rebaseline queue
+ https://bugs.webkit.org/show_bug.cgi?id=49763
+
+ Add a UI queue (a multi-item <select>) where tests to be baselined
+ can be enqueued (also supports basic removal). A queue is used instead
+ of immediately doing rebaselines since SCM operations can take a while.
+ It's better to go through lots of tests quickly to mark them as
+ needing rebaselining and then batch the SCM operations.
+
+ Also adds a simple log where results can be displayed.
+
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js: Added.
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/util.js:
+ * Scripts/webkitpy/tool/commands/rebaselineserver.py:
+
+2010-11-18 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Bug 49708 - Stop recompiling functions to regenerate exception info.
+
+ Instead only hold info as necessary – keep divot info is the inspector
+ is enabled, line number info is debugging or profiling, and handler
+ info for functions with try/catch.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (shouldEnableDeveloperExtras):
+ - always enable the developer tools from DRT, to ensure we
+ produce rich error messages on JavaScript exceptions.
+
+2010-11-18 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ [Chromium] REGRESSION: Record actual test results in the JSON result summary for non-layout tests
+ https://bugs.webkit.org/show_bug.cgi?id=49702
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+
+2010-11-18 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: create first part of 'message_broker' class for multiprocessing fixes
+
+ Create the first version of the 'message_broker' package. This
+ class will encapsulate all of the threading/multiprocessing and
+ message-sending details for the communication between the
+ 'manager' object and the 'worker' objects. For the moment, it
+ just holds some routines and tests for logging thread stacks.
+
+ There should be no functional changes in this patch, just moving stuff
+ around.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49707
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread_unittest.py: Removed.
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-11-18 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Remove leftover Windows Debug_Internal configurations
+ https://bugs.webkit.org/show_bug.cgi?id=49758
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * MiniBrowser/MiniBrowser.vcproj:
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj:
+ * WebKitAPITest/WebKitAPITest.vcproj:
+ * WebKitTestRunner/win/InjectedBundle.vcproj:
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj:
+ * WinLauncher/WinLauncher.vcproj:
+
+2010-11-18 Adam Roben <aroben@apple.com>
+
+ Add three new Windows XP build slaves
+
+ Reviewed by Steve Falkenburg.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json: Added three
+ new slaves, and added them to the Windows XP Debug (Tests) builder.
+
+2010-11-18 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Adam Roben.
+
+ update-webkit-support-libs should fall back to existing
+ WebKitSupportLibrary version if there is no internet connectivity
+ https://bugs.webkit.org/show_bug.cgi?id=49503
+
+ Fall back to existing support libraries (if present) when there is
+ no internet connection.
+
+ Currently, update-webkit-support-libs dies with an "out-of-date"
+ error when there is no internet connection because it cannot
+ retrieve versioning information from developer.apple.com. Because
+ update-webkit-support-libs fails, build-webkit fails. Instead,
+ if there is no internet connection and the support libraries are
+ present then we should warn the user and exit() with success so
+ that build-webkit can work without an internet connection.
+
+ * Scripts/update-webkit-support-libs:
+
+2010-11-18 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Debug_Internal Windows configuration is unnecessary, should be removed
+ https://bugs.webkit.org/show_bug.cgi?id=49753
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ * MiniBrowser/win/stdafx.h:
+ * TestWebKitAPI/win/PlatformUtilitiesWin.cpp:
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+
+2010-11-18 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Clean up vcproj errors
+ https://bugs.webkit.org/show_bug.cgi?id=49741
+
+ * MiniBrowser/MiniBrowser.vcproj:
+ * WebKitAPITest/WebKitAPITest.vcproj:
+ * WebKitTestRunner/win/InjectedBundle.vcproj:
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj:
+
+2010-11-18 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ [NRWT] Fix a break of '--new-baseline' feature in pixel_test
+ which is caused by r72249.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49751
+
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+
+2010-11-18 Adam Roben <aroben@apple.com>
+
+ Implement layoutTestController.waitForPolicyDelegate on Windows
+
+ Fixes <http://webkit.org/b/25038> <rdar://problem/6790213>.
+
+ Reviewed by Simon Fraser.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::waitForPolicyDelegate): Implemented by porting
+ code from LayoutTestControllerMac.mm.
+
+2010-11-18 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ [NRWT] Fix a break of '--new-baseline' feature which is caused by r72249.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49740
+
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-11-18 Tony Chang <tony@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ run platform/chromium/plugins/refcount-leaks.html on all platforms
+ https://bugs.webkit.org/show_bug.cgi?id=49485
+
+ Add PluginObject.testObjectCount which returns the number of allocated
+ TestObjects. Add PluginObject.testCreateTestObject which allocates
+ and returns a TestObject.
+
+ Add TestObject.refCount which returns the number of refs on the
+ TestObject.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (pluginGetProperty):
+ (pluginInvoke):
+ * DumpRenderTree/TestNetscapePlugIn/TestObject.cpp:
+ (getTestObjectCount):
+ (testAllocate):
+ (testDeallocate):
+ (testGetProperty):
+ (testScriptObjectInvoke): Release a ref to a plugin object that was
+ previously leaked.
+ * DumpRenderTree/TestNetscapePlugIn/TestObject.h:
+
+2010-11-17 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ WebKitTools projects (WebKitTestRunner, record-memory-win) should use vsprops for common build settings
+ https://bugs.webkit.org/show_bug.cgi?id=49711
+
+ * WebKitTestRunner/Configurations/WebKitTestRunnerCFLite.vsprops: Added.
+ * WebKitTestRunner/Configurations/WebKitTestRunnerCommon.vsprops: Added.
+ * WebKitTestRunner/Configurations/WebKitTestRunnerCoreFoundation.vsprops: Added.
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj:
+ * record-memory-win/record-memory-win-common.vsprops: Added.
+ * record-memory-win/record-memory-win.vcproj:
+
+2010-11-18 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [Qt][WK2] Only add user agent strings to the list which aren't listed yet.
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::updateUserAgentList):
+
+2010-11-17 Adam Roben <aroben@apple.com>
+
+ Don't trigger Windows builds when chromium-win test results change
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/webkitpy/common/config/build.py:
+ (_should_file_trigger_build): Changed the regular expression used to
+ search for directory names to only consider full directory names,
+ rather than matching directory names where the string we care about is
+ a suffix of the name.
+
+ * Scripts/webkitpy/common/config/build_unittest.py:
+ (ShouldBuildTest): Added a test.
+
+2010-11-17 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Remove a uri member from TestInput class.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49691
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-11-17 Adam Roben <aroben@apple.com>
+
+ Move FindSafari's settings into a vsprops file
+
+ Fixes <http://webkit.org/b/49699> FindSafari should use a vsprops file
+
+ Reviewed by Steve Falkenburg.
+
+ * FindSafari/FindSafari.vcproj:
+ * FindSafari/FindSafariCommon.vsprops: Added.
+
+2010-11-17 Adam Roben <aroben@apple.com>
+
+ Use a minimum font size of 0 in DRT on Windows
+
+ This is the Windows equivalent of r72164.
+
+ Rubber-stamped by Dave Hyatt.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2010-11-17 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Andreas Kling.
+
+ webkit-patch pretty-diff shouldn't need to be run from a checkout root in git
+ https://bugs.webkit.org/show_bug.cgi?id=49639
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+
+2010-11-17 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: add loupe for image diffs
+ https://bugs.webkit.org/show_bug.cgi?id=49692
+
+ Add a loupe (magnifiying glass) for inspecting image diffs. Shows an
+ enlarged area of the expected, actual and diff images side by side.
+
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js: Added.
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js:
+ * Scripts/webkitpy/tool/commands/rebaselineserver.py:
+
+2010-11-17 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ WebKitLauncherWin should use vsprops for shared build settings
+ https://bugs.webkit.org/show_bug.cgi?id=49696
+
+ * WebKitLauncherWin/WebKitLauncherWin.vcproj:
+ * WebKitLauncherWin/WebKitLauncherWinCommon.vsprops: Added.
+
+2010-11-17 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ WinLauncher should use vsprops for shared build settings
+ https://bugs.webkit.org/show_bug.cgi?id=49695
+
+ * WinLauncher/WinLauncher.cpp:
+ (_tWinMain):
+ (PrintView):
+ (WndProc):
+ (MyEditProc):
+ * WinLauncher/WinLauncher.vcproj:
+ * WinLauncher/WinLauncherCommon.vsprops: Added.
+
+2010-11-17 Steve Falkenburg <sfalken@apple.com>
+
+ Delete unused file unintentionally added in last change.
+
+ * DumpRenderTree/win/DumpRenderTreeCURL.vsprops: Removed.
+
+2010-11-17 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ DumpRenderTree on Windows should use a vsprops file for shared project settings
+ https://bugs.webkit.org/show_bug.cgi?id=49690
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginCommon.vsprops: Added.
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/DumpRenderTreeApple.vsprops: Added.
+ * DumpRenderTree/win/DumpRenderTreeCFLite.vsprops: Added.
+ * DumpRenderTree/win/DumpRenderTreeCURL.vsprops: Added.
+ * DumpRenderTree/win/DumpRenderTreeCairo.vsprops: Added.
+ * DumpRenderTree/win/DumpRenderTreeCommon.vsprops: Added.
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * DumpRenderTree/win/ImageDiffCommon.vsprops: Added.
+
+2010-11-17 Hayato Ito <hayato@chromium.org>
+
+ Refactor TestTypeBase.compare_output().
+
+ Introduce a TestOutput class and update compare_output() of each test
+ types so that they can take both actual and expected TestOutput objects.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49431
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_output.py: Added.
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-11-17 Adam Roben <aroben@apple.com>
+
+ Make each Windows Test builder use the same OS for all its slaves
+
+ Currently each WebKit1 Windows Test builder has one Windows XP slave
+ and one Windows 7 slave. Having different OSes in a single builder
+ meant that the builders would alternate between red and green when
+ there were OS-specific failures.
+
+ Fixes <http://webkit.org/b/49688> Windows Test builders alternate
+ between red and green because of multiple OS versions
+
+ Reviewed by Mark Rowe.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json: Renamed
+ "Windows Release (Tests)" to "Windows 7 Release (Tests)", "Windows
+ Debug (Tests)" to "Windows XP Debug (Tests)", and "Windows Release
+ (WebKit2 Tests)" to "Windows 7 Release (WebKit2 Tests)". Updated the
+ builders for the two WebKit1 builders so that they would all use the
+ appropriate OS.
+
+2010-11-17 James Robinson <jamesr@chromium.org>
+
+ Reviewed by Dan Bernstein.
+
+ [chromium] Set minimum font size to 0 for DRT
+ https://bugs.webkit.org/show_bug.cgi?id=49677
+
+ Followup for http://trac.webkit.org/changeset/72141.
+
+ Test: http/tests/misc/acid3.html
+
+ * DumpRenderTree/chromium/WebPreferences.cpp:
+ (WebPreferences::reset):
+
+2010-11-17 Andras Becsi <abecsi@webkit.org>
+
+ Unreviewed build fix.
+
+ [Qt] Add missing file I forgot in r72220.
+
+ * MiniBrowser/MiniBrowser.qrc: Added.
+
+2010-11-17 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt][WK2] Make it possible to set custom user agent strings in MiniBrowser.
+ https://bugs.webkit.org/show_bug.cgi?id=49627
+
+ Add a user agent dialog and a resource file for useragentlist.txt to MiniBrowser.
+
+ * MiniBrowser/MiniBrowser.qrc: Added.
+ Add it here to prevent qmake from detecting it
+ since it needs to be copied to the build directory.
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::updateUserAgentList):
+ (BrowserWindow::showUserAgentDialog):
+ * MiniBrowser/qt/BrowserWindow.h:
+ * MiniBrowser/qt/MiniBrowser.pro:
+
+2010-11-17 Adam Roben <aroben@apple.com>
+
+ Make changes to the Mac WebKit2 Skipped file trigger Windows builds
+
+ We use that file on Windows!
+
+ Fixes <http://webkit.org/b/49643> Changes to
+ LayoutTests/platform/mac-wk2 should trigger a Windows build, but don't
+
+ Reviewed by Steve Falkenburg.
+
+ * Scripts/webkitpy/common/config/build.py:
+ (_should_file_trigger_build): Added the mac-wk2 directory and make it
+ trigger builds on SnowLeopard and Windows.
+
+ * Scripts/webkitpy/common/config/build_unittest.py:
+ (ShouldBuildTest.test_should_build): Added a test.
+
+2010-11-17 Satish Sampath <satish@chromium.org>
+
+ Reviewed by Jeremy Orlow.
+
+ Clear the speech input mock explicitly before each test.
+ https://bugs.webkit.org/show_bug.cgi?id=49660
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::speechInputController):
+ (WebViewHost::reset): Invoke speech input mock's clearResults method.
+ * DumpRenderTree/chromium/WebViewHost.h:
+ (WebViewHost::speechInputControllerMock): Moved mock from LayoutTestController.
+
+2010-11-17 Alexander Pavlov <apavlov@chromium.org>
+
+ Unreviewed, specify IRC nickname in committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-11-17 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Tony Chang.
+
+ [NRWT] Make http locking similar to perl implementation
+ https://bugs.webkit.org/show_bug.cgi?id=49187
+
+ * Scripts/webkitpy/common/system/file_lock.py: Added.
+ * Scripts/webkitpy/common/system/file_lock_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/port/http_lock.py:
+
+2010-11-17 MORITA Hajime <morrita@google.com>
+
+ Reviewed by Kent Tamura.
+
+ [Chromium][DRT] EventSender.contextClick() should aware spellchecking
+ https://bugs.webkit.org/show_bug.cgi?id=49366
+
+ - EvenSender: Checked WebContextMenuData.misspelledWord and added extra context menu entries
+ according to the spellchecker suggestion
+ - MockSpellCheck: add fillSuggestionList to provide fake suggestions.
+
+ test_expectations.txt will be changed after this change is ported to test_shell.
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (makeMenuItemStringsFor):
+ (EventSender::contextClick):
+ * DumpRenderTree/chromium/MockSpellCheck.cpp:
+ (MockSpellCheck::fillSuggestionList):
+ (MockSpellCheck::initializeIfNeeded):
+ * DumpRenderTree/chromium/MockSpellCheck.h:
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::mockSpellCheck):
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-11-16 Dave Hyatt <hyatt@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Make sure the pref for minimum font size is just explicitly set to 0 every time,
+ since the bots have 1 stuck in their plist otherwise.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+
+2010-11-16 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: compute diffs client-side
+ https://bugs.webkit.org/show_bug.cgi?id=49640
+
+ The image diff output from the DRT is pretty bad on some ports (at
+ least the Mac one), so it's better to compute diffs on the client by
+ using <canvas>.
+
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js:
+
+2010-11-16 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: display test results
+ https://bugs.webkit.org/show_bug.cgi?id=49626
+
+ Adds basic result display to the rebaseline server. On the Python side
+ this involves:
+ - Parsing the unexpected_results.json into a dictionary.
+ - Serving it as JSON under /results.json.
+ (the JSON -> dict -> JSON transform isn't strictly necessary right now,
+ but I'll need to have access to the parsed results on the Python side
+ for follow-up changes).
+
+ On the web UI side this adds:
+ - Markup for display image and text results (expected, actual, diff),
+ and JS for populating it.
+ - Markup for breaking down test results by failure type and directory,
+ and JS for populating it.
+
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/util.js: Added.
+ * Scripts/webkitpy/tool/commands/rebaselineserver.py:
+
+2010-11-16 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ See Chromium issue http://codereview.chromium.org/5133001/ - we
+ are modifying the build bots to pass in the builder name with
+ the "GPU" string appended instead of appending it in the code.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49636
+
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+
+2010-11-16 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Disable LTCG for Windows Release builds. Add new Release_LTCG configuration.
+ https://bugs.webkit.org/show_bug.cgi?id=49632
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * MiniBrowser/MiniBrowser.vcproj:
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj:
+ * WebKitLauncherWin/WebKitLauncherWin.vcproj:
+ * WebKitTestRunner/win/InjectedBundle.vcproj:
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj:
+ * WinLauncher/WinLauncher.vcproj:
+ * record-memory-win/record-memory-win.vcproj:
+
+2010-11-16 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: rename TestInfo to TestInput, move image hash to work thread
+
+ Rename the TestInfo class to TestInput to be clearer about its
+ function, and move the checksum-reading code into dump_render_tree_thread
+ to avoid cross-thread access.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49573
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-11-16 Dave Hyatt <hyatt@apple.com>
+
+ Fix bustage. Remove the minimum font size pref setting in DumpRenderTree.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+
+2010-11-16 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ <rdar://problem/8624267> Leak creating offscreen webview running fast/dom tests
+
+ Use shared DeviceOrientationProviderMock. The old allocation method created a new WebDeviceOrientationProviderMock
+ for every WebView, and the WebKit API doesn't support that ownership model.
+
+ I also fixed a leak in setMockDeviceOrientation by adding a missing release.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (createWebViewAndOffscreenWindow):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMockDeviceOrientation):
+
+2010-11-16 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: log the process id in --verbose mode
+
+ As part of the switch to multi-process mode, we should log the
+ process id when running w/ --verbose.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49571
+
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+
+2010-11-16 Adam Roben <aroben@apple.com>
+
+ Only trigger Windows builds when files that we actually use on Windows
+ are changed
+
+ A new Scheduler subclass, PlatformSpecificScheduler, has been added.
+ It uses the new webkitpy.common.config.build module to determine
+ whether a particular change should trigger a build on a particular
+ platform. The Windows builders have been switched to use a
+ PlatformSpecificScheduler.
+
+ The logic to determine whether or not a particular change should
+ trigger a build on a given platform has only been implemented/tested
+ for Windows. I tried to make it easy to add more platforms in the
+ future, but I don't have enough familiarity with all platforms to be
+ able to implement it for them.
+
+ Fixes <http://webkit.org/b/49407> Windows builders kick off builds for
+ lots irrelevant changes (e.g., rebaselining Chromium test results)
+
+ Reviewed by Eric Seidel.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json: Use a
+ PlatformSpecificScheduler for the Windows builders.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+ (PlatformSpecificScheduler.__init__): Added. Stores our platform, sets
+ up a ChangeFilter that filters to our branch and will call through to
+ our filter method, and calls up to our base class.
+ (PlatformSpecificScheduler.filter): Calls through to
+ build.should_build to find out whether we should trigger a build for
+ this change.
+
+ * Scripts/webkitpy/common/net/build.py: Added.
+ (_should_file_trigger_build): Uses a set of directories and regexp
+ patterns to determine whether the given file should trigger a build on
+ the given platform. As mentioned earlier, this has only been
+ implemented for Windows, though I did try to make some guesses about
+ other platforms.
+ (should_build): Returns true if any of the files should trigger a
+ build on the given platform.
+
+ * Scripts/webkitpy/common/net/build_unittest.py: Added.
+ (ShouldBuildTest.test_should_build): Does some basic testing to make
+ sure we're triggering builds for the right files. It only tests
+ Windows for now, though I tried to make some guesses about other
+ platforms.
+
+2010-11-16 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Remove synchronous QWebPage::checkPermissions signal
+ https://bugs.webkit.org/show_bug.cgi?id=46810
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::grantDesktopNotificationPermission): When granting
+ permission, grant it directly on the QWebPage/Frame, that will remember it.
+ * QtTestBrowser/webpage.cpp:
+ (WebPage::WebPage):
+ * QtTestBrowser/webpage.h:
+
+
+2010-11-16 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [Qt] Add isPrinting and setPrinting methods to DRT's LayoutTestController.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::isPrinting):
+ (LayoutTestController::setPrinting):
+
+2010-11-16 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt][WK2] Add a way to turn on tiled backing store in MiniBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=49587
+
+ * MiniBrowser/qt/BrowserView.cpp:
+ (BrowserView::BrowserView): Added BackingStoreType
+ argument to ctor. Propagating it to the QGraphicsWKView.
+ * MiniBrowser/qt/BrowserView.h:
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::newWindow): Create the new BrowserWindow
+ with the same BackingStoreType that this instance has.
+ * MiniBrowser/qt/BrowserWindow.h: Added BackingStoreType member.
+ * MiniBrowser/qt/main.cpp:
+ (main): Use tiled backing store if got -tiled command line argument.
+ Avoid redundant copy of command line args.
+
+2010-11-16 John Knottenbelt <jknotten@chromium.org>
+
+ Reviewed by Jeremy Orlow.
+
+ Move DeviceOrientationClientMock from LayoutTestController to WebViewHost.
+ https://bugs.webkit.org/show_bug.cgi?id=48506
+
+ This ensures that there is one mock per page WebView / WebViewHost. This is a
+ design constraint of the DeviceOrientationClientMock because the m_controller
+ field can only store a pointer to a single instance of the corresponding
+ DeviceOrientationController.
+
+ Test: fast/dom/DeviceOrientation/no-page-cache.html
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setMockDeviceOrientation):
+ (LayoutTestController::deviceOrientationClientMock):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::deviceOrientationClientMock):
+ (WebViewHost::deviceOrientationClient):
+ (WebViewHost::reset):
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-11-15 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt][WK2] Avoid polling in WebKitTestRunner.
+ https://bugs.webkit.org/show_bug.cgi?id=49542
+
+ Make the WK2 testing session about 10-15% faster and decrease random flakiness
+ resulting from timing skew by removing the millisecond polling from TestControllerQt.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::didFinishLoadForFrame):
+ * WebKitTestRunner/TestController.h:
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::didReceiveMessageFromInjectedBundle):
+ * WebKitTestRunner/mac/TestControllerMac.mm:
+ (WTR::TestController::notifyDone): Add method stub.
+ * WebKitTestRunner/qt/TestControllerQt.cpp:
+ (WTR::TestControllerRunLoop::instance):
+ (WTR::TestControllerRunLoop::start):
+ (WTR::TestControllerRunLoop::stop):
+ (WTR::TestControllerRunLoop::TestControllerRunLoop):
+ (WTR::TestControllerRunLoop::timerEvent):
+ (WTR::TestController::notifyDone):
+ (WTR::TestController::platformRunUntil):
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::notifyDone): Add method stub.
+
+2010-11-15 Darin Adler <darin@apple.com>
+
+ * Scripts/webkitpy/common/net/bugzilla: Added property svn:ignore.
+
+2010-11-15 Benjamin Poulain <benjamin.poulain@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] [WK2] Add Ctrl+L shortcut to Qt Minibrowser
+ https://bugs.webkit.org/show_bug.cgi?id=49544
+
+ Add the shortcut to BrowserWindow.
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::openLocation):
+ * MiniBrowser/qt/BrowserWindow.h:
+
+2010-11-14 David Levin <levin@chromium.org>
+
+ Reviewed by Daniel Bates.
+
+ check-webkit-style should detect PassRefPtr usage in functions.
+ https://bugs.webkit.org/show_bug.cgi?id=49513
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ (check_for_function_lengths): Revert a comment change that I
+ accidentally made in r71986.
+ (check_pass_ptr_usage): Added the code to do the check.
+ (process_line): Added the call to check_pass_ptr_usage.
+ (CppChecker): Added the new error category.
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+ (CppStyleTestBase::perform_pass_ptr_check): Runs the new check for
+ testing purposes.
+ (PassPtrTest::*): The class/functions to unit test the new
+ functionality.
+
+2010-11-14 David Levin <levin@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ check-webkit-style function detection and the line count style checks should be separate.
+ https://bugs.webkit.org/show_bug.cgi?id=49512
+
+ * Scripts/webkitpy/style/checkers/cpp.py: Do the separation.
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py: Adjust the test to
+ call the detection function and fix line counts in two places now that
+ the code really only counts the lines in the body of the function.
+
+2010-11-14 Andreas Kling <kling@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ http/tests/plugins tests print "Unhandled variable" to stderr under Qt
+ https://bugs.webkit.org/show_bug.cgi?id=33438
+
+ Stifle "Unhandled variable" warning to match what the other
+ TestNetscapePlugin does (NPP_GetValue in TestNetscapePlugIn/main.cpp
+ simply returns NPERR_GENERIC_ERROR for unhandled variables.)
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_get_value):
+
+2010-11-13 David Levin <levin@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ check-webkit-style function detection crashes on functions in templates.
+ https://bugs.webkit.org/show_bug.cgi?id=49504
+
+ For example "template <bool shouldClose(const Element*)>".
+
+ * Scripts/webkitpy/style/checkers/cpp.py: If not function is detected, bail out.
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py: Modified the complex
+ function detection test to expose this issue.
+
+2010-11-12 David Levin <levin@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ check-webkit-style function detection doesn't detect indented functions declaractions.
+ https://bugs.webkit.org/show_bug.cgi?id=49446
+
+ Indented function declarations occur inside class definitions, so
+ they are a pretty common (and worth detecting).
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ Changed regex to allow indentation.
+ Changed the function start detection to only happen when not in a
+ function.
+ Changed function end detection to work based on matching braces
+ instead of finding a close brace at the beginning of the line.
+ Fixed close_expression to do what it says when it doesn't find
+ the close.
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py: Indented function test.
+
+2010-11-12 Daniel Bates <dbates@rim.com>
+
+ Rubber-stamped by Nikolas Zimmermann.
+
+ Make do-file-rename rename files in the directory WebKit2.
+
+ This also makes the list of searched directories in do-file-rename
+ consistent with the list of searched directories in the script do-webcore-rename.
+
+ * Scripts/do-file-rename:
+
+2010-11-12 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by James Robinson.
+
+ Attempt yet again to land the fix for bug 49360 (respecting
+ set-webkit-configuration). We need to handle the cases where
+ trying to run webkit-build-directory to find out where the
+ default configuration might be fails (that shows up on some
+ Chromium bots that apparently don't have perl installed).
+
+ https://bugs.webkit.org/show_bug.cgi?id=49360
+
+ * Scripts/webkitpy/layout_tests/port/config.py:
+ * Scripts/webkitpy/layout_tests/port/config_standalone.py: Added.
+ * Scripts/webkitpy/layout_tests/port/config_unittest.py:
+
+2010-11-12 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch land logs commit message twice
+ https://bugs.webkit.org/show_bug.cgi?id=49482
+
+ Don't log the comment that's used by bugzilla.close_bug_as_fixed, since
+ that's just the commit message, which we now output following the
+ actual commit.
+
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla.py:
+
+2010-11-12 Tony Chang <tony@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ run platform/chromium/plugins/script-object-invoke.html on all platforms
+ https://bugs.webkit.org/show_bug.cgi?id=49280
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (testScriptObjectInvoke):
+ (pluginInvoke):
+
+2010-11-12 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch land-cowboy (and other commands) should display the committed SVN revision after landing a patch
+ https://bugs.webkit.org/show_bug.cgi?id=49471
+
+ Right now there's no indication of a successful commit.
+
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/steps/commit.py:
+
+2010-11-12 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Include detailed test modifiers in results.json and enable incremental uploading for non-layout tests
+ https://bugs.webkit.org/show_bug.cgi?id=49354
+
+ Also moved/integrated the upload method from run_webkit_tests.py to json_results_generator.py.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-11-12 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] Load a blank page when closing DRT WebViewHosts
+ https://bugs.webkit.org/show_bug.cgi?id=49417
+
+ In test_shell, when we close a window, we first load about:blank
+ and run GC to fire the destruction logic of the page. In test_shell,
+ this happens in ~TestShell. In DRT, we manage virtual windows as
+ WebViewHosts, so we need to replicate this logic in ~WebViewHost.
+
+ Managing focus is a bit trickier, since normally you would get window
+ events to reset the focus to the right window. We do it manually
+ instead.
+
+ This fixes 2 plugin tests on DRT.
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::~TestShell): Move window close logic to ~WebViewHost.
+ (TestShell::closeWindow): Move widget close() to WVH destructor and
+ manage focus manually.
+ (TestShell::closeRemainingWindows): Comment typo.
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::closeWidget):
+ (invokeCloseWidget):
+ (WebViewHost::closeWidgetSoon): Close the window asynchronously (matches
+ test_shell).
+ (WebViewHost::~WebViewHost):
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-11-12 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ cpp.py needs some tidying.
+ https://bugs.webkit.org/show_bug.cgi?id=49443
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ Fix parameter ordering for iteratively_replace_matches_with_char
+ to mirror other similar functions (and improved comments, etc.)
+ Also, use a python-ism (for/else) to get rid of a variable that
+ was there to determine if something had been found in the loop.
+
+2010-11-12 Robert Kroeger <rjkroege@chromium.org>
+
+ Reviewed by James Robinson.
+
+ [Chromium/DRT] Make EventSendingController send complete touch events.
+ https://bugs.webkit.org/show_bug.cgi?id=49285
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::addTouchPoint):
+ (EventSender::updateTouchPoint):
+ (EventSender::sendCurrentTouchEvent):
+
+2010-11-12 Mihai Parparita <mihaip@chromium.org>
+
+ Unreviewed rollout of r71858.
+
+ Rollout out r71858 since it breaks new-run-webkit-httpd as used by the
+ NaCl tests.
+
+ * Scripts/webkitpy/layout_tests/port/config.py:
+ * Scripts/webkitpy/layout_tests/port/config_standalone.py: Removed.
+ * Scripts/webkitpy/layout_tests/port/config_unittest.py:
+
+2010-11-12 Benjamin Poulain <benjamin.poulain@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] TestController::runUntil doesn't honor the timeout parameter
+ https://bugs.webkit.org/show_bug.cgi?id=48941
+
+ Implement the missing timeout of WebKitTestRunner for Qt.
+
+ A QElapsedTimer has been added to RunUntilConditionLoop in order
+ to measure how long the loop has been running. When the timer
+ is bigger or equal than the timeout, the loop ends even if the
+ condition is not met.
+
+ * WebKitTestRunner/qt/TestControllerQt.cpp:
+ (WTR::RunUntilConditionLoop::start):
+ (WTR::RunUntilConditionLoop::run):
+ (WTR::RunUntilConditionLoop::timerEvent):
+ (WTR::TestController::platformRunUntil):
+
+2010-11-11 David Levin <levin@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ check-webkit-style function detection doesn't handle templates with spaces.
+ https://bugs.webkit.org/show_bug.cgi?id=49427
+
+ * Scripts/webkitpy/style/checkers/cpp.py: Stripped out templates when
+ finding the function name.
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py: Made the test have a
+ template with a space.
+
+2010-11-11 Ademar de Souza Reis Jr <ademar.reis@openbossa.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Enable check-webkit-style on Qt files
+ https://bugs.webkit.org/show_bug.cgi?id=48322
+
+ Adding exception for _q_... private slots and
+ ..._data() methods in tests
+
+ * Scripts/webkitpy/style/checker.py: enable Qt dirs, add exceptions
+ * Scripts/webkitpy/style/checker_unittest.py: improve unittests
+
+2010-11-11 David Levin <levin@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ check-webkit-style function detection doesn't work for templates and destructors.
+ https://bugs.webkit.org/show_bug.cgi?id=49425
+
+ * Scripts/webkitpy/style/checkers/cpp.py: Changed regex for templates and destructors.
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py: Made the test hit this issue.
+
+2010-11-11 Joone Hur <joone@kldp.org>
+
+ Reviewed by Antonio Gomes.
+
+ [GTK][DRT] Implement LayoutTestController::nodesFromRect
+ https://bugs.webkit.org/show_bug.cgi?id=46598
+
+ Support nodesFromRect in DRT
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::nodesFromRect):
+
+2010-11-11 MORITA Hajime <morrita@google.com>
+
+ Reviewed by Kent Tamura.
+
+ editing/selection/context-menu-on-text.html fails on chromium
+ https://bugs.webkit.org/show_bug.cgi?id=45898
+
+ Enhance Chromium's EventSender::contextClick() to return
+ array of menu strings. The implementation incomplete because
+ Although actual context menu is implemented by the browser,
+ it reflects editability of underlying context thus makes
+ context-menu-on-text.html passed.
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (makeMenuItemStringsFor): Added.
+ (EventSender::contextClick): Now returns array of menu strings.
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::showContextMenu): Now storing given WebContextMenuData object.
+ (WebViewHost::clearContextMenuData): Added.
+ (WebViewHost::lastContextMenuData): Added.
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-11-11 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ fix build breakage caused by fix for bug 49380 (r71858).
+
+ config_standalone needs to ensure that the packages it needs are
+ in sys.path.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49419
+
+ * Scripts/webkitpy/layout_tests/port/config_standalone.py:
+
+2010-11-11 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Roben.
+
+ Fix NRWT to respect set-webkit-configuration again :(
+
+ This change fixes a typo in config.py that was causing the wrong
+ value to be read initially and us never actually looking into
+ the filesystem to get the default configuration.
+
+ * Scripts/webkitpy/layout_tests/port/config.py:
+ * Scripts/webkitpy/layout_tests/port/config_standalone.py:
+ * Scripts/webkitpy/layout_tests/port/config_unittest.py:
+
+2010-11-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Split out Bug, Attachment and CommitterValidator from bugzilla.py
+ https://bugs.webkit.org/show_bug.cgi?id=49403
+
+ CommitterValidator really had nothing to do with bugzilla.py.
+ I've put it next to committers.py for now since its rather tied to that file.
+
+ * Scripts/webkitpy/common/config/committervalidator.py: Added.
+ * Scripts/webkitpy/common/config/committervalidator_unittest.py: Added.
+ * Scripts/webkitpy/common/net/bugzilla/__init__.py:
+ * Scripts/webkitpy/common/net/bugzilla/attachment.py: Added.
+ * Scripts/webkitpy/common/net/bugzilla/bug.py: Added.
+ * Scripts/webkitpy/common/net/bugzilla/bug_unittest.py: Added.
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py:
+ * Scripts/webkitpy/tool/bot/feeders.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-11-11 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ fix missing 'pid' argument for http lockfile checking on win32
+ https://bugs.webkit.org/show_bug.cgi?id=49363
+
+ * Scripts/webkitpy/common/system/executive.py:
+
+2010-11-11 Eric Seidel <eric@webkit.org>
+
+ Rubber-stamped by Adam Barth.
+
+ Move bugzilla.py into its own module in preparation for splitting one-file-per-class
+ https://bugs.webkit.org/show_bug.cgi?id=49402
+
+ * Scripts/webkitpy/common/net/bugzilla/__init__.py: Added.
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla.py: Renamed from WebKitTools/Scripts/webkitpy/common/net/bugzilla.py.
+ * Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py: Renamed from WebKitTools/Scripts/webkitpy/common/net/bugzilla_unittest.py.
+
+2010-11-10 Chris Guillory <chris.guillory@google.com>
+
+ Reviewed by Chris Fleizach.
+
+ Use IAccessibleComparable to compare accessibility objects.
+ https://bugs.webkit.org/show_bug.cgi?id=49118
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (AccessibilityUIElement::isEqual):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (comparableObject):
+ (AccessibilityUIElement::isEqual):
+
+2010-11-10 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by David Hyatt.
+
+ HTML5 Ruby support should be mandatory feature
+ https://bugs.webkit.org/show_bug.cgi?id=49272
+
+ Remove Ruby as optional feature.
+
+ * Scripts/build-webkit:
+
+2010-11-10 Adam Roben <aroben@apple.com>
+
+ Print VC++ Express build logs in the same order that the projects are
+ built
+
+ Fixes <http://webkit.org/b/49326> print-vse-failure-logs prints logs
+ in an unhelpful order
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/print-vse-failure-logs:
+ (PrintVisualStudioExpressLogs._build_order): Added. Uses
+ print-msvc-project-dependencies to figure out the order in which
+ projects are built.
+ (PrintVisualStudioExpressLogs._sort_buildlogs): Added. Sorts the logs
+ based on their build order and project name.
+ (PrintVisualStudioExpressLogs._obj_directory): Moved code to find the
+ scripts directory from here...
+ (PrintVisualStudioExpressLogs._scripts_directory): ...to here.
+ (PrintVisualStudioExpressLogs.main): Sort the logs before printing
+ them.
+
+2010-11-10 Adam Roben <aroben@apple.com>
+
+ Only print the interesting text from VC++ Express build logs
+
+ Fixes <http://webkit.org/b/49325> It's hard to find the interesting
+ output from print-vse-failure-logs
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/print-vse-failure-logs: Removed unnecessary os.path import,
+ added newly-required imports. Removed a comment that was essentially a
+ FIXME, and is now fixed.
+ (PrintVisualStudioExpressLogs._relevant_text): Added. Uses
+ BeautifulSoup to extract the relevant text from the build log.
+ (PrintVisualStudioExpressLogs.main): Only print the relevant text.
+
+2010-11-09 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [Chromium] http/tests/security/XFrameOptions fail with Chromium DRT
+ https://bugs.webkit.org/show_bug.cgi?id=49286
+
+ The tests in http/tests/security/XFrameOptions started to fail after
+ r71297, since it changed the WebViewHost::assignIdentifierToRequest
+ logic to always assign identifiers to requests, even if we're not going
+ to be dumping resource load callbacks at that point. These tests
+ only call LayoutTestController.dumpResourceLoadCallbacks after the
+ request is started, thus their expectations have "<unknown>" as the
+ identifier. Change WebViewHost to the previous behavior, which also
+ match the other ports'.
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::assignIdentifierToRequest):
+ (WebViewHost::removeIdentifierForRequest):
+
+2010-11-08 Tony Chang <tony@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ run platform/chromium/plugins/return-npobject.html on all platforms
+ https://bugs.webkit.org/show_bug.cgi?id=49103
+
+ This tests that we can get an NPObject returned through a method on
+ an NPAPI Object.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (testCallbackReturn):
+ (pluginInvoke):
+
+2010-11-09 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r71672.
+ http://trac.webkit.org/changeset/71672
+ https://bugs.webkit.org/show_bug.cgi?id=49276
+
+ It doesn't work on Chromium Windows bot (Requested by Ossy on
+ #webkit).
+
+ * Scripts/webkitpy/common/system/file_lock.py: Removed.
+ * Scripts/webkitpy/common/system/file_lock_unittest.py: Removed.
+ * Scripts/webkitpy/layout_tests/port/http_lock.py:
+
+2010-11-09 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Tony Chang.
+
+ [NRWT] Make http locking similar to perl implementation
+ https://bugs.webkit.org/show_bug.cgi?id=49187
+
+ * Scripts/webkitpy/common/system/file_lock.py: Added.
+ * Scripts/webkitpy/common/system/file_lock_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/port/http_lock.py:
+
+2010-11-09 James Kozianski <koz@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Clean up imports for webkit-patch.
+ https://bugs.webkit.org/show_bug.cgi?id=49083
+
+ Move some imports from commands into main.py where they are used.
+ Move command imports into the __init__ of the commands module.
+
+ * Scripts/webkitpy/tool/commands/__init__.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/main.py:
+
+2010-11-09 Yi Shen <yi.4.shen@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt][QtTestBrowser] Don't erase incorrect url in the Url Bar
+ https://bugs.webkit.org/show_bug.cgi?id=49047
+
+ * QtTestBrowser/mainwindow.cpp:
+ (MainWindow::setAddressUrl):
+
+2010-11-09 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ Improve old-run-webkit-tests --verbose to show DumpTool opening/closing
+ https://bugs.webkit.org/show_bug.cgi?id=49252
+
+ * Scripts/old-run-webkit-tests:
+
+2010-11-09 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Output of old-run-webkit-tests is buggy in verbose mode
+ https://bugs.webkit.org/show_bug.cgi?id=49249
+
+ * Scripts/old-run-webkit-tests: Redundant outputs removed.
+
+2010-11-08 Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Link with target name set does not work
+ https://bugs.webkit.org/show_bug.cgi?id=48865
+
+ When a new page is created with a name (target=myFrame), the new
+ mainFrame could not be found because they where not stored in the
+ same PageGroup. As PageGroup are not exposed externally so the
+ simpliest solution is to use a global page group name. This also fixes
+ issue with visited link coloration across pages. After this change the
+ private function webkit_web_view_set_group_name() was no longer used
+ so it was removed completly.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (createWebView):
+
+2010-11-08 John Knottenbelt <jknotten@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ WebViewHost::reset() uses placement new.
+ https://bugs.webkit.org/show_bug.cgi?id=49069
+
+ WebViewHost is using placement destruction / new to simulate a fresh
+ WebViewHost object at the same address. This is because the WebView remains
+ open across tests and maintains a pointer to the WebViewHost.
+ This change resets member variables explictly instead of the placement new dance.
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::WebViewHost):
+ (WebViewHost::reset):
+
+2010-11-08 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix the webkit_base_dir logic in webkitpy/layout_tests/port/config.py.
+ It turns out that NRWT can't use the code in scm.find_checkout_root()
+ because the Chromium bots don't do full checkouts of the WebKit
+ tree; they only check out subdirectories like WebKitTools/Scripts.
+ Until we can figure out a better approach for this, I've
+ restored the base_dir-detecting code from NRWT, which works in
+ any directory tree, scm or no.
+
+ This also restores the files modified in r71475 and r71474.
+
+ https://bugs.webkit.org/show_bug.cgi?id=49151
+
+ * WebKitTools/Scripts/webkitpy/layout_tests/port/config.py
+ * WebKitTools/Scripts/webkitpy/layout_tests/port/config_unittest.py
+
+2010-11-08 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch failure-reason explodes if a build is missing
+ https://bugs.webkit.org/show_bug.cgi?id=49195
+
+ This is likely a recent regression. Adding a unit test for this case.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+
+2010-11-08 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Ignore the system scrollbar setting.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues): Set the scrollbar default.
+
+2010-11-05 Adam Roben <aroben@apple.com>
+
+ Make webkitpy.common.system.executive_unittest pass when running under
+ Win32 Python
+
+ Fixes <http://webkit.org/b/49033>.
+
+ Reviewed by Dave Levin and Eric Seidel.
+
+ * Scripts/webkitpy/common/system/executive.py:
+ (Executive._run_command_with_teed_output): Pass the arguments through
+ encode_argument_if_needed rather than using Cygwin-specific code here.
+ (Executive.run_and_throw_if_fail): Use child_process_encoding to decode
+ the output.
+ (Executive.run_command): Use encode_argument_if_needed to encode the
+ arguments and child_process_encoding to decode the output.
+ (Executive._child_process_encoding): Returns the encoding that should be
+ used when communicating with child processes. On Windows we use mbcs,
+ which maps to the current code page. On all other platforms we use
+ UTF-8.
+ (Executive._should_encode_child_process_arguments): Returns True if
+ arguments to child processes need to be encoded. This is currently
+ only needed on Cygwin and Win32 Python 2.x.
+ (Executive._encode_argument_if_needed): Encode the argument using
+ child_process_encoding if we need to encode arguments to child
+ processes on this platform.
+
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ (never_ending_command): Added. Returns arguments to run a command that
+ will not quit until we kill it. On Windows we use wmic, on other
+ platforms we use yes.
+ (ExecutiveTest.test_run_command_with_unicode): Changed to expect the
+ mbcs encoding to be used and for output from the child processes to
+ have been roundtripped through encode/decode on Win32 Python. When
+ UTF-8 is the encoding the roundtripping is undetectable, but with mbcs
+ it's possible that some characters will not be able to be converted
+ and will be replaced by question marks; the round-tripping allows us
+ to expect this result.
+
+ (ExecutiveTest.test_kill_process):
+ (ExecutiveTest.test_kill_all):
+ Use never_ending_command instead of invoking "yes" directly. Expect an
+ exit code of 1 when using Win32 Python, as that's what seems to happen.
+
+2010-11-08 Adam Roben <aroben@apple.com>
+
+ Roll out r71532
+
+ It broke the build for Cygwin 1.7 installs. Cygwin 1.7's default
+ .bashrc unsets %TEMP%, which broke copy-tools.cmd.
+
+ * Scripts/webkitdirs.pm:
+
+2010-11-08 Tony Chang <tony@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ run platform/chromium/plugins/nested-plugin-objects.html on all platforms
+ https://bugs.webkit.org/show_bug.cgi?id=49094
+
+ This tests that objects created by plugins are proplery cleaned up.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (testPassTestObject):
+ (pluginInvoke):
+ * DumpRenderTree/TestNetscapePlugIn/TestObject.cpp:
+ (testAllocate):
+ (testDeallocate):
+ (testGetProperty):
+ (testConstruct):
+
+2010-11-08 Adam Roben <aroben@apple.com>
+
+ Mark Windows builds triggered from Perl as being non-interactive
+
+ This affects whether some of our scripts will show alerts vs. printing
+ to the build log.
+
+ Fixes <http://webkit.org/b/49181> Windows build fail mysteriously when
+ .vsprops files are updated
+
+ Reviewed by Steve Falkenburg.
+
+ * Scripts/webkitdirs.pm:
+ (buildVisualStudioProject): Set WEBKIT_NONINTERACTIVE_BUILD to 1.
+
+2010-11-08 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Ojan Vafai.
+
+ Make http locking default in NRWT.
+ https://bugs.webkit.org/show_bug.cgi?id=48053
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-11-08 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [NRWT] If the http lock fails we shouldn't do any locking
+ https://bugs.webkit.org/show_bug.cgi?id=49164
+
+ If something goes wrong with the locking, the test should keep going.
+
+ * Scripts/webkitpy/layout_tests/port/http_lock.py:
+
+2010-11-08 Adam Roben <aroben@apple.com>
+
+ Switch back to using kCGImageAlphaPremultipliedFirst when generating
+ pixel dumps on Windows
+
+ I changed this behavior in r71418 thinking that it was required for
+ getting plugins to show up in pixel dumps. But it doesn't seem to be
+ necessary, and was making it impossible to compare new Windows pixel
+ dumps with existing Windows or Mac pixel dumps (because ImageDiff won't
+ compare an image with alpha to an image without alpha).
+
+ Fixes <http://webkit.org/b/49172> REGRESION (r71418): Can't compare
+ new Windows pixel results to existing Windows or Mac results
+
+ Reviewed by Antti Koivisto.
+
+ * DumpRenderTree/win/PixelDumpSupportWin.cpp:
+ (createBitmapContextFromWebView): Replaced kCGImageAlphaNoneSkipFirst
+ with kCGImageAlphaPremultipliedFirst.
+
+2010-11-08 Csaba Osztrogonac <ossy@webkit.org>
+
+ Unreviewed, rolling out r71466.
+ http://trac.webkit.org/changeset/71466
+ https://bugs.webkit.org/show_bug.cgi?id=48865
+
+ It broke layout tests on GTK bots.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (createWebView):
+
+2010-11-08 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Csaba Osztrogonác.
+
+ Enable running of Qt API tests on BuildBot
+ https://bugs.webkit.org/show_bug.cgi?id=49004
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2010-11-08 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add clean-review-queue command to remove closed bugs from the webkit.org/pending-review
+ https://bugs.webkit.org/show_bug.cgi?id=49160
+
+ Bugzilla doesn't automatically remove r? when a bug gets closed.
+ This script takes care of that for webkit.org.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+
+2010-11-07 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed, rolling out r71474.
+ http://trac.webkit.org/changeset/71474
+ https://bugs.webkit.org/show_bug.cgi?id=48280
+
+ breaks chromium webkit tests
+ https://bugs.webkit.org/show_bug.cgi?id=49151
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/config.py:
+ * Scripts/webkitpy/layout_tests/port/config_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-11-07 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed, rolling out r71475.
+ http://trac.webkit.org/changeset/71475
+
+ breaks chromium webkit tests
+ https://bugs.webkit.org/show_bug.cgi?id=49151
+
+ * Scripts/webkitpy/common/newstringio.py: Removed.
+ * Scripts/webkitpy/common/newstringio_unittest.py: Removed.
+ * Scripts/webkitpy/common/system/executive_mock.py: Removed.
+ * Scripts/webkitpy/common/system/filesystem_mock.py: Removed.
+ * Scripts/webkitpy/layout_tests/port/config_mock.py: Removed.
+
+2010-11-06 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Add files inexplicably not committed in r71474 as part of the
+ fix for bug 48280.
+
+ * Scripts/webkitpy/common/newstringio.py: Added.
+ * Scripts/webkitpy/common/newstringio_unittest.py: Added.
+ * Scripts/webkitpy/common/system/executive_mock.py: Added.
+ * Scripts/webkitpy/common/system/filesystem_mock.py: Added.
+ * Scripts/webkitpy/layout_tests/port/config_mock.py: Added.
+
+2010-11-06 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Siedel.
+
+ new-run-webkit-tests: update port/base and port/webkit to use the
+ new FileSystem and Config abstractions, pulling more logic out of
+ the base Port classes into separate, mockable objects.
+
+ Also create a MockFileSystem object, a MockConfig object, move
+ MockExecutive into common/system to be next to executive, and
+ update the config object to use a FileSystem.
+
+ https://bugs.webkit.org/show_bug.cgi?id=48280
+
+ * Scripts/webkitpy/common/newstringio.py: Added.
+ * Scripts/webkitpy/common/newstringio_unittest.py: Added.
+ * Scripts/webkitpy/common/system/executive_mock.py: Added.
+ * Scripts/webkitpy/common/system/filesystem_mock.py: Added.
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/config.py:
+ * Scripts/webkitpy/layout_tests/port/config_mock.py:
+ * Scripts/webkitpy/layout_tests/port/config_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-11-06 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build breakage.
+
+ Apparently I uploaded the wrong version of the file to fix 49122
+ and neither Eric or I noticed - it was missing a dirname() call.
+ Fixing ...
+
+ https://bugs.webkit.org/show_bug.cgi?id=49122
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+
+2010-11-06 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ webkitpy/tool/* unittests change cwd and don't clean up properly
+
+ https://bugs.webkit.org/show_bug.cgi?id=49122
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+
+2010-11-05 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ suspendAnimations/resumeAnimations not present in WebKit2
+ https://bugs.webkit.org/show_bug.cgi?id=49109
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::suspendAnimations):
+ (WTR::LayoutTestController::resumeAnimations):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+
+2010-11-05 Tony Chang <tony@chromium.org>
+
+ Reviewed by David Levin.
+
+ cleanup style in TestNetscapePlugIn/PluginObject.cpp
+ https://bugs.webkit.org/show_bug.cgi?id=49044
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (getPluginClass):
+ (pluginGetProperty):
+ (pluginSetProperty):
+ (variantToIdentifier):
+ (testCallback):
+ (getURL):
+ (getURLNotify):
+ (testInvokeDefault):
+ (testGetProperty):
+ (testDocumentOpen):
+ (testWindowOpen):
+ (pluginInvoke):
+ (handleCallback):
+ (notifyStream):
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.h:
+
+2010-11-05 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ Add QueueStatusServer/__init__.py so others can run the QueueStatusServer tests
+ https://bugs.webkit.org/show_bug.cgi?id=49032
+
+ I wrote this file as part of bug 47847, but I forgot to commit it.
+ No one else noticed it missing because test-webkitpy knows how
+ to recover in the case where it can't import QueueStatusServer
+ (which generally occurs due to not having installed the AppEngine SDK).
+
+ * QueueStatusServer/__init__.py: Added.
+ * QueueStatusServer/model/workitems_unittest.py:
+ - Remove a test which fails. This was probably landed (by me)
+ from my other machine, which since this __init__.py was missing
+ I never noticed the failure and landed this invalid test.
+ Sadly we can't really test remove_work_item as it depends
+ on .key() working. .key() will throw unless the object
+ has already been saved it seems.
+ This may be a mis-design in our remove_work_item implementation,
+ but for now, just removing the test.
+
+2010-11-04 Adam Roben <aroben@apple.com>
+
+ Teach check-webkit-style about TestNetscapePlugIn
+
+ Fixes <http://webkit.org/b/49030> check-webkit-style is ignorant of
+ TestNetscapePlugIn's coding conventions
+
+ Reviewed by John Sullivan.
+
+ * Scripts/webkitpy/style/checker.py: Lump TestNetscapePlugIn in with
+ WebKitAPITest and TestWebKitAPI in having different include order and
+ naming conventions than WebCore. Added some comments about why the
+ exceptions exist.
+
+2010-11-04 Adam Roben <aroben@apple.com>
+
+ Add a test that shows that windowed plugins are able to paint
+
+ Somehow we never had a test for this before.
+
+ Fixes <http://webkit.org/b/49029> Should add a test that shows
+ windowed plugins can paint
+
+ Reviewed by Jon Honeycutt.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp: Added.
+ (DrawsGradient::DrawsGradient):
+ (DrawsGradient::wndProc): We handle the WM_PAINT and WM_PRINTCLIENT messages.
+
+ (DrawsGradient::onPaint):
+ (DrawsGradient::onPrintClient):
+ These both just call through to paint.
+
+ (DrawsGradient::paint): Fills our client area with some gradients.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj: Link
+ against Msimg32.lib for ::GradientFill and added DrawsGradient.
+
+ * DumpRenderTree/win/PixelDumpSupportWin.cpp:
+ (createBitmapContextFromWebView): Use WM_PRINT instead of
+ WM_PRINTCLIENT so that ::DefWindowProc will send
+ WM_PRINT/WM_PRINTCLIENT messages to the WebView's child windows.
+ Replaced kCGImageAlphaPremultipledFirst with kCGImageAlphaNoneSkipFirst
+ because GDI doesn't support alpha and kCGImageBitmapOrder32Little with
+ kCGImageBitmapOrder32Host because, who knows, maybe someday Windows
+ will run on a big-endian platform.
+
+2010-11-04 Adam Roben <aroben@apple.com>
+
+ Extract much of NPNInvalidateRectInvalidatesWindow's code into a
+ WindowedPluginTest base class
+
+ The base class takes care of subclassing the plugin's window so that a
+ custom WNDPROC is called. This will make it easier to write tests that
+ need to handle window messages.
+
+ Fixes <http://webkit.org/b/49028> It's hard to write a PluginTest with
+ a custom WNDPROC
+
+ Reviewed by Jon Honeycutt.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp:
+ (NPNInvalidateRectInvalidatesWindow::NPNInvalidateRectInvalidatesWindow):
+ (NPNInvalidateRectInvalidatesWindow::NPP_SetWindow):
+ (NPNInvalidateRectInvalidatesWindow::wndProc):
+ (NPNInvalidateRectInvalidatesWindow::testInvalidateRect):
+ Moved code from here to WindowedPluginTest. Changed to use window()
+ instead of m_window.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ Added WindowedPluginTest and added TestNetscapePlugIn/win to the
+ include path. Also reordered the include path to make a little more
+ sense and simplified the entry that added TestNetscapePlugIn itself to
+ the include path.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp: Added.
+ (WindowedPluginTest::WindowedPluginTest):
+ (WindowedPluginTest::NPP_SetWindow):
+ (WindowedPluginTest::staticWndProc):
+ * DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h: Added.
+ (WindowedPluginTest::window):
+ Code came from NPNInvalidateRectInvalidatesWindow.
+
+2010-11-04 Adam Roben <aroben@apple.com>
+
+ Add a plugin test to show that windowed plugins are clipped correctly
+
+ Fixes <http://webkit.org/b/49024> <rdar://problem/8487847> Windowed
+ plugins aren't clipped in WebKit2 on Windows
+
+ Reviewed by Jon Honeycutt.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp: Added.
+ (WindowRegionIsSetToClipRect::WindowRegionIsSetToClipRect): Initialize members.
+ (WindowRegionIsSetToClipRect::NPP_SetWindow): Check that our window
+ region matches the clip rect we know we should have based on
+ window-region-is-set-to-clip-rect.html, and check that our window class
+ doesn't have the CS_PARENTDC style.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ Added WindowRegionIsSetToClipRect.
+
+2010-11-05 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Avoid font hinting in the DRT
+ https://bugs.webkit.org/show_bug.cgi?id=48548
+
+ Change the settings to avoid font hinting, it was causing
+ different results depending on the distribution.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (initializeGtkFontSettings):
+ * DumpRenderTree/gtk/fonts/fonts.conf:
+
+2010-11-05 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ build-webkit spams system.log by repeatedly checking for PBXProductDirectory in com.apple.Xcode
+ https://bugs.webkit.org/show_bug.cgi?id=49051
+
+ This is a speculative fix. The unit tests cover these methods, however
+ I don't know if this will fully stop the system.log spam.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-11-05 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add basic support for showing bot id on /queue-status/ pages
+ https://bugs.webkit.org/show_bug.cgi?id=49037
+
+ This support is really simple. Eventually we'll want to
+ show the bot id in the lock table too, but we don't have
+ that information stored in the server yet.
+
+ * QueueStatusServer/handlers/queuestatus.py:
+ * QueueStatusServer/handlers/queuestatus_unittest.py: Added.
+ * QueueStatusServer/templates/includes/singlequeuestatus.html:
+
+2010-11-04 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Create a filesystem wrapper that we can use to enforce
+ particular conventions and use for mocking and dependency
+ injection down the line.
+
+ https://bugs.webkit.org/show_bug.cgi?id=48144
+
+ * Scripts/webkitpy/common/system/filesystem.py: Added.
+ * Scripts/webkitpy/common/system/filesystem_unittest.py: Added.
+
+2010-11-04 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ run_webkit_tests_unittest fails under Python 2.5
+ https://bugs.webkit.org/show_bug.cgi?id=49043
+
+ Switch from itertools.chain.from_iterable (which was added in 2.6)
+ to using itertools.chain directly.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-11-04 Mihai Parparita <mihaip@chromium.org>
+
+ Unreviewed fix to webkit-patch rebaseline-server so that it runs under
+ Python 2.5 (it needs an import to use the with statement).
+
+ * Scripts/webkitpy/tool/commands/rebaselineserver.py:
+
+2010-11-04 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests: split out webkit-specific configuration stuff into a new module
+
+ The current NRWT code has webkit-specific configuration code (like
+ _script_path, default configuration, etc.) mixed in with
+ layout-test-specific stuff in port/base. The configuration code
+ should be split out into a separate module for easier mocking,
+ testing, and isolation.
+
+ https://bugs.webkit.org/show_bug.cgi?id=48264
+
+ * Scripts/webkitpy/layout_tests/port/config.py: Added.
+ * Scripts/webkitpy/layout_tests/port/config_unittest.py: Added.
+
+2010-11-04 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Rebaseline server: initial framework
+ https://bugs.webkit.org/show_bug.cgi?id=48892
+
+ Adds the basic framework for the rebaseline server (details at
+ http://webkit.org/b/47761). Includes the rebaseline-server webkit-patch
+ command, which starts an HTTP server that can serve static files or
+ invoke handler methods on a class.
+
+ * Scripts/webkitpy/tool/commands/__init__.py:
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html: Added.
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css: Added.
+ * Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js: Added.
+ * Scripts/webkitpy/tool/commands/rebaselineserver.py: Added.
+
+2010-11-04 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by James Robinson.
+
+ new-run-webkit-tests wasn't using DRT by default for
+ --platform chromium-gpu
+
+ The default value was set to False instead of None, which meant
+ that the platform specific logic wasn't firing to change the
+ value to True (b/c we were afraid we'd be overriding the user
+ preference).
+
+ https://bugs.webkit.org/show_bug.cgi?id=49038
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-11-04 Tony Chang <tony@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ make platform/chromium/plugins/multiple-plugins.html pass on all platforms
+ https://bugs.webkit.org/show_bug.cgi?id=49026
+
+ Have the testObject.bar property return the string "bar". This lets
+ us run and pass platform/chromium/plugins/multiple-plugins.html on all
+ platforms.
+
+ * DumpRenderTree/TestNetscapePlugIn/TestObject.cpp:
+ (testGetProperty):
+
+2010-11-04 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ NRWT doesn't have good test coverage for --run-chunk, --batch-size, --run-part, etc.
+ https://bugs.webkit.org/show_bug.cgi?id=48878
+
+ Add get_tests_run so that it's easy to see which tests get run (and with
+ what batching) for a given flag combination. Flesh out the various
+ test cases that have FIXMEs.
+
+ Also fixes an off-by-one error (batch sizes were one larger than
+ expected) and makes --run-part also have wraparound behavior, like
+ --run-chunk.
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-11-04 Erik Arvidsson <arv@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Support box-sizing without the vendor prefix
+ https://bugs.webkit.org/show_bug.cgi?id=36713
+
+ Based on patch by Peter Beverloo <peter@lvp-media.com>
+
+ * iExploder/htdocs/cssproperties.in: Change -webkit-box-sizing to box-sizing.
+
+2010-11-04 Csaba Osztrogonác <ossy@webkit.org>
+
+ Unreviewed rollout r71340, because it broke Chromium Windows bot.
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-11-04 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Ojan Vafai.
+
+ Make http locking default in NRWT.
+ https://bugs.webkit.org/show_bug.cgi?id=48053
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-11-04 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Eric Seidel.
+
+ [NRWT] Clear invalid http locks on Windows platform as well
+ https://bugs.webkit.org/show_bug.cgi?id=48515
+
+ * Scripts/webkitpy/common/system/executive.py:
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/http_lock.py:
+
+2010-11-02 Adam Roben <aroben@apple.com>
+
+ Reduce our dependence on coreutils when running Python tests
+
+ This patch introduces versions of the standard echo and cat utilities
+ implemented in Python. They are probably missing features of their
+ coreutils equivalents, but they can do what's necessary for our Python
+ tests. This is useful on Windows, where these utilities typically
+ aren't available.
+
+ Fixes <http://webkit.org/b/48883> executive_unittest relies on echo
+ and cat utilities from coreutils, which are not present on Windows
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/webkitpy/common/system/executive_unittest.py: Changed to use
+ our Python-based echo and cat.
+
+ * Scripts/webkitpy/common/system/fileutils.py: Added.
+ (make_stdout_binary): On Windows, puts sys.stdout into binary mode so
+ that \n won't be translated into \r\n. I couldn't think of a good way
+ to test this directly without touching the filesystem, but it is tested
+ indirectly by echo_unittest.
+
+ * Scripts/webkitpy/test/cat.py: Added.
+ (command_arguments): Returns a list for invoking cat with the given arguments.
+ (main): Acts like a simplified version of the coreutils cat utility.
+
+ * Scripts/webkitpy/test/cat_unittest.py: Added.
+ (CatTest.assert_cat): Runs cat with the given input and ensures the
+ output matches the input.
+ (CatTest.test_basic): Performs a simple test of cat.
+ (CatTest.test_no_newline): Tests what happens when the input string
+ doesn't have a trailing newline.
+ (CatTest.test_unicode): Tests passing a unicode string to cat.
+ (CatTest.test_as_command): Tests running cat as a separate command.
+
+ * Scripts/webkitpy/test/echo.py: Added.
+ (command_arguments): Returns a list for invoking echo with the given arguments.
+ (main): Acts like a simplified version of the coreutils echo utility.
+
+ * Scripts/webkitpy/test/echo_unittest.py: Added.
+ (EchoTest.test_basic): Performs a simple test of echo.
+ (EchoTest.test_no_newline): Tests passing -n to echo to suppress the
+ trailing newline.
+ (EchoTest.test_unicode): Tests passing unicode and non-unicode strings
+ to echo.
+ (EchoTest.test_argument_order): Tests what happens when -n is not the
+ first argument.
+ (EchoTest.test_empty_arguments): Tests what happens when you pass [] to
+ echo.main.
+ (EchoTest.test_no_arguments): Tests what happens when you call
+ echo.main with no arguments.
+ (EchoTest.test_as_command): Tests running echo as a separate command.
+
+2010-11-04 Renata Hodovan <reni@inf.u-szeged.hu>
+
+ Unreviewed: Add myself to the list of Committers.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-11-04 Andreas Kling <kling@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Hook into QWebPage::scrollRequested for resizes-to-contents mode
+
+ In RTC mode the QGraphicsWebView item is the size of the contents,
+ scrolling works a bit differently (we need to react to scrollRequested.)
+
+ Normally QGraphicsView will replay the last mouse event when scrolling,
+ so to prevent WebKit from getting confused by this we temporarily make
+ the QGraphicsView non-interactive.
+
+ * QtTestBrowser/webview.cpp:
+ (WebViewGraphicsBased::setPage):
+ (WebViewGraphicsBased::scrollRequested):
+ * QtTestBrowser/webview.h:
+
+2010-11-04 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ Use OS(MAC_OS_X) rather than PLATFORM(MAC) in TestControllerQt
+
+ PLATFORM(MAC) is not defined for the Qt port, as it refers to
+ the Mac-port, not the Mac OS X operating system.
+
+ * WebKitTestRunner/qt/TestControllerQt.cpp:
+ (WTR::isExistingLibrary):
+
+2010-11-04 Leonid Ebril <leonid.ebril@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Adding iphone user agent string the user agent list for QtTestBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=48869
+
+ * QtTestBrowser/useragentlist.txt:
+
+2010-11-03 Adam Roben <aroben@apple.com>
+
+ Always use uppercase drive names in strings returned by abspath_to_uri
+
+ Some versions of cygpath use lowercase drive letters while others use
+ uppercase, which makes it hard to test the output of code that uses
+ cygpath.
+
+ Fixes <http://webkit.org/b/48914> webkitpy.common.system.path_unittest
+ fails with Cygwin 1.5
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/webkitpy/common/system/path.py:
+ (cygpath): Updated the docstring to indicate that only absolute paths
+ should be passed for now (though relative paths will work fine).
+ (_Cygpath.convert): Upper-case the first letter of the converted Windows path.
+
+2010-11-03 George Guo <George.Guo@Nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] QtTestBrowser : set mmp rule pageddata in Symbian
+ https://bugs.webkit.org/show_bug.cgi?id=48767
+
+ Paging is needd on Symbian devices to support benchmarks tests like
+ dromaeo.com and Celtic Kane that need a lot of memory to run
+
+ * QtTestBrowser/QtTestBrowser.pro:
+
+2010-11-03 Jenn Braithwaite <jennb@chromium.org>
+
+ Reviewed by Dmitry Titov.
+
+ Chromium: Update resource tracking when moving a frame between documents
+ https://bugs.webkit.org/show_bug.cgi?id=48363
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::assignIdentifierToRequest):
+ Always put resource id in map so we can make assumptions about its
+ presence.
+ (WebViewHost::removeIdentifierForRequest):
+ Added.
+ (WebViewHost::didFinishResourceLoad):
+ (WebViewHost::didFailResourceLoad):
+ Check existence of resource id before removing from map.
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-11-03 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ [Chromium] update buildbot names in chromium rebaseline tool.
+
+ https://bugs.webkit.org/show_bug.cgi?id=48881
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-11-03 Darin Adler <darin@apple.com>
+
+ Updated Xcode projects by opening them with Xcode 3.2.4.
+ Updated svn:ignore for Xcode projects.
+
+ * MiniBrowser/MiniBrowser.xcodeproj: Added property svn:ignore.
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj: Added property svn:ignore.
+ * WebKitLauncher/WebKitLauncher.xcodeproj: Modified property svn:ignore.
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj: Updated with Xcode 3.2.4.
+
+2010-11-03 Adam Roben <aroben@apple.com>
+
+ Stop waiting for messages from the web process after a timeout elapses
+
+ TestController::runUntil now takes a timeout parameter that specifies
+ how long to wait for the condition to become true. WebKitTestRunner
+ takes a --timeout flag that specifies how long the timeout should be.
+ run-webkit-tests passes this flag to WebKitTestRunner so its timeout
+ will be similar to run-webkit-tests.
+
+ Fixes <http://webkit.org/b/43047> <rdar://problem/8365833>
+ WebKitTestRunner waits forever if the web process crashes
+
+ Reviewed by Darin Adler and Anders Carlsson.
+
+ * Scripts/old-run-webkit-tests:
+ (top level): Moved the GuardMalloc timeout adjustment here from
+ readFromDumpToolWithTimer.
+ (openDumpTool): Make WTR use a timeout similar to but slightly shorter
+ than the one that was specified on the command line.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::TestController): Initialize our timeout values.
+ (WTR::TestController::initialize): Parse the --timeout flag and use it
+ to modify our timeout values.
+ (WTR::TestController::resetStateToConsistentValues): Changed to use a
+ short timeout while waiting for the web process to reset and to return
+ a boolean indicating whether we were able to reset the web process.
+ Uses a 5-second timeout while waiting for the process to be reset.
+ (WTR::TestController::runTest): Changed to return a boolean indicating
+ whether we were able to reset the web process (and thus run the test).
+ (WTR::TestController::runUntil): Call through to platformRunUntil.
+
+ (WTR::TestController::runTestingServerLoop):
+ (WTR::TestController::run):
+ Changed to bail if any test can't be run. This will cause the process
+ to exit. (Unfortunately this will make run-webkit-tests think we
+ crashed; see <http://webkit.org/b/48943>.)
+
+ * WebKitTestRunner/TestController.h: Added platformRunUntil,
+ m_longTimeout, and m_shortTimeout.
+
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::invoke): Use a short timeout when waiting for the
+ initial response and a long timeout when waiting for the test to
+ complete. Check whether runUntil timed out and print an error message
+ if so.
+
+ * WebKitTestRunner/mac/TestControllerMac.mm:
+ (WTR::TestController::platformRunUntil): Renamed from runUntil. Pass
+ [NSDate distantPast] to -[NSRunLoop runMode:beforeDate:] so that we
+ won't block waiting for the run loop. Only loop until the timeout
+ elapses.
+
+ * WebKitTestRunner/qt/TestControllerQt.cpp:
+ (WTR::TestController::platformRunUntil): Renamed from runUntil. Added a
+ FIXME about honoring the timeout.
+
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::platformRunUntil): Renamed from runUntil. Use
+ ::MsgWaitForMultipleObjectsEx to implement the timeout. Changed to use
+ ::PeekMessageW so that we don't block waiting for messages to become
+ available.
+
+2010-11-03 Adam Roben <aroben@apple.com>
+
+ Add a plugin test that evaluates JS after removing the plugin element
+ from the document
+
+ This test replaces platform/win/plugins/plugin-delayed-destroy.html.
+ That test was made to prevent a crash very similar to this one, but
+ unfortunately tested only the mechanism that prevented the crash and
+ not whether the crash itself was prevented. Since WebKit2 uses a
+ different mechanism to prevent the crash, the test was failing even
+ though WebKit2 was not vulnerable to the crash. This new test crashes
+ if there is no mechanism in place to prevent it and passes in both
+ WebKit1 and WebKit2.
+
+ Fixes <http://webkit.org/b/46711> <rdar://problem/8485903>
+ platform/win/plugins/plugin-delayed-destroy.html fails in WebKit2
+
+ Reviewed by Anders Carlsson.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+ * GNUmakefile.am:
+ Added new file.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (pluginDeallocate): Make sure we delete the PluginTest object. This
+ prevents a leak and also allows us to test the crash.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp:
+ (PluginTest::executeScript): Made this into a non-static member
+ function.
+
+ (PluginTest::waitUntilDone):
+ (PluginTest::notifyDone):
+ Updated for changes to executeScript.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.h: Added executeScript.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp: Added.
+ (EvaluateJSAfterRemovingPluginElement::EvaluateJSAfterRemovingPluginElement):
+ Initialize ourselves and tell the test harness to wait.
+ (EvaluateJSAfterRemovingPluginElement::NPP_DestroyStream): Remove our
+ plugin element from the document, then execute some JavaScript. If
+ WebKit does not have appropriate mechanisms in place, we'll be
+ destroyed inside the first call to executeScript and crash on the
+ second call.
+
+2010-11-02 Stephen White <senorblanco@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [chromium] Fix LayoutTestController UMRs.
+ https://bugs.webkit.org/show_bug.cgi?id=48872
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+
+2010-11-03 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ REGRESSION: rebaseline-chromium-webkit-tests uses non-zero tolerance for
+ image dup detection
+ https://bugs.webkit.org/show_bug.cgi?id=48744
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ - Make a function for option parsing for ease of test
+ - Set 0 to options.tolerance
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py:
+ - Add a test for this change
+
+2010-11-02 Gyuyoung Kim <gyuyoung.kim@samsung.com>
+
+ Unreviewed: Add myself to the list of Committers.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-11-02 Anders Carlsson <andersca@apple.com>
+
+ Fix build.
+
+ * TestWebKitAPI/PlatformUtilities.cpp:
+ (TestWebKitAPI::Util::createContextForInjectedBundleTest):
+
+2010-11-02 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add a way to send startup messages on the context which can be posted when a process launches
+ <rdar://problem/8617928>
+ https://bugs.webkit.org/show_bug.cgi?id=48838
+
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (WKBundleInitialize):
+ * TestWebKitAPI/InjectedBundleController.cpp:
+ (TestWebKitAPI::InjectedBundleController::initialize):
+ (TestWebKitAPI::InjectedBundleController::didReceiveMessage):
+ * TestWebKitAPI/InjectedBundleController.h:
+ * TestWebKitAPI/InjectedBundleMain.cpp:
+ (WKBundleInitialize):
+ * TestWebKitAPI/PlatformUtilities.cpp:
+ (TestWebKitAPI::Util::createContextForInjectedBundleTest):
+ * WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp:
+ (WKBundleInitialize):
+ Update implementations of WKBundleInitialize to take an initial userData
+ argument. Change TestWebKitAPI to use the new initial userData to initialize
+ each test's bundle.
+
+2010-11-02 Benjamin Kalman <kalman@google.com>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests doesn't strip "LayoutTests/" from prefix, unlike old-run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=48794
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py: Strip the "LayoutTests/" prefix from test argument paths.
+
+2010-11-02 Adam Roben <aroben@apple.com>
+
+ Skip webkitpy.layout_tests.run_webkit_tests_unittest.MainTest on Cygwin
+ Python 2.5.x
+
+ It is known to hang on that version of Python. See
+ <http://webkit.org/b/48614>.
+
+ Reviewed by Adam Barth.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: Use
+ skip_if to skip MainTest on Cygwin Python 2.5.x.
+
+ * Scripts/webkitpy/test/skip.py: Added.
+ (skip_if): If the passed-in condition is false, find all the test_*
+ methods of the given class and replace them with a function that just
+ logs that we're skipping these tests. This is loosely based on the
+ unittest.skip_if decorator added in Python 3.1.
+ (_skipped_method): Returns a function that just logs that the tests are
+ being skipped. This is used in place of the actual test_* functions.
+
+ * Scripts/webkitpy/test/skip_unittest.py: Added.
+ (SkipTest.setUp): Create a logger for ourselves and give it a handler
+ that logs to a private stream.
+ (SkipTest.tearDown): Reset the logger.
+ (SkipTest.create_fixture_class): Returns a class that we use to test
+ skip_if. It has a single test_* method, test_foo, that just calls
+ through to a callback.
+ (SkipTest.foo_callback): Record that test_foo was called.
+ (SkipTest.test_skip_if_false): Pass skip_if a False condition and test
+ that test_foo does get called.
+ (SkipTest.test_skip_if_true): Pass skip_if a True condition and test
+ that test_foo does not get called and the appropriate message gets
+ logged.
+
+2010-11-02 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch should tell check-webkit-style which files were changed so
+ check-webkit-style doesn't have to stat the whole working copy again
+ https://bugs.webkit.org/show_bug.cgi?id=48792
+
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/checkstyle.py:
+
+2010-11-02 Robert Kroeger <rjkroege@chromium.org>
+
+ Reviewed by James Robinson.
+
+ [Chromium/DRT] Make EventSendingController honour leapForward for touch events.
+ https://bugs.webkit.org/show_bug.cgi?id=48777
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::sendCurrentTouchEvent):
+
+2010-11-02 Adam Roben <aroben@apple.com>
+
+ Only track resource identifiers in DRT when dumpResourceLoadCallbacks
+ is on
+
+ This reverts Windows to our pre-r71097 behavior. That patch made us
+ track all resource identifiers, including the main resource, so the
+ main resource's URL started appearing in test output instead of
+ "<unknown>". Arguably having the main resource's URL is better, but all
+ other platforms print "<unknown>" and we want to match.
+
+ Fixes <http://webkit.org/b/48837> <rdar://problem/8620351> REGRESSION
+ (r71097): Many http tests failing on Windows
+
+ Reviewed by Anders Carlsson.
+
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::identifierForInitialRequest): Don't add the
+ identifier to the URL map if we're not supposed to dump resource load
+ callbacks.
+ (ResourceLoadDelegate::removeIdentifierForRequest): Always remove the
+ identifier from the URL map even if we're already "done". There's no
+ point in keeping out-of-date identifiers around.
+
+2010-11-01 Jenn Braithwaite <jennb@chromium.org>
+
+ Reviewed by Adam Roben.
+
+ Windows: Update resource tracking when moving a frame between documents
+ https://bugs.webkit.org/show_bug.cgi?id=48364
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (createWebViewAndOffscreenWindow):
+ (main):
+ Give each WebView its own ResourceLoadDelegate instance in order to
+ make assertions about resource ids on a particular WebView.
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::identifierForInitialRequest):
+ Always add id to the map.
+ (ResourceLoadDelegate::removeIdentifierForRequest):
+ Added.
+ (ResourceLoadDelegate::willSendRequest):
+ (ResourceLoadDelegate::didReceiveAuthenticationChallenge):
+ (ResourceLoadDelegate::didReceiveResponse):
+ (ResourceLoadDelegate::didFinishLoadingFromDataSource):
+ (ResourceLoadDelegate::didFailLoadingWithError):
+ (ResourceLoadDelegate::descriptionSuitableForTestResult):
+ Replace static descriptionSuitableForTestResult with static member function to access identifier map.
+ * DumpRenderTree/win/ResourceLoadDelegate.h:
+ (ResourceLoadDelegate::urlMap):
+ Moved within class so that each WebView has its own id map.
+
+2010-11-01 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ remove debug code from run_webkit_tests.py
+ https://bugs.webkit.org/show_bug.cgi?id=48800
+
+ Remove temporary debug code and make --master-name required
+ if --test-results-server is set now that all clients set
+ --master-name.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-11-01 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ add plugin event logging for linux
+ https://bugs.webkit.org/show_bug.cgi?id=48779
+
+ This is taken from Chromium's fork of the layout test plugin:
+ http://git.chromium.org/gitweb/?p=chromium.git/.git;a=blob;f=webkit/tools/npapi_layout_test_plugin/main.cpp;h=3ebdada2f049b3624756438cff852364f86a2ede;hb=HEAD#l348
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (handleEventX11):
+ (NPP_HandleEvent):
+
+2010-11-01 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by James Robinson.
+
+ new-run-webkit-tests: use DRT, child-processes=1 for GPU tests by default
+ https://bugs.webkit.org/show_bug.cgi?id=48790
+
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py:
+
+2010-11-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Teach check-webkit-style how to accept a list of files to diff on the
+ command line
+ https://bugs.webkit.org/show_bug.cgi?id=48784
+
+ In a future patch, webkit-patch will use this option to improve
+ performance. I'm landing this in two pieces to avoid causing a version
+ skew problem for the style-bot.
+
+ * Scripts/check-webkit-style:
+ * Scripts/webkitpy/style/optparser.py:
+ * Scripts/webkitpy/style/optparser_unittest.py:
+ * Scripts/webkitpy/style_references.py:
+
+2010-11-01 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by John Sullivan.
+
+ Tear down the related WebProcessProxy when a WebContext is deallocated
+ https://bugs.webkit.org/show_bug.cgi?id=48769
+
+ * TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp:
+ (TestWebKitAPI::didFailProvisionalLoadWithErrorForFrame):
+ We don't support empty URLs anymore, update test to expect a null URL instead.
+
+2010-11-01 Søren Gjesse <sgjesse@chromium.org>
+
+ Reviewed by Andreas Kling.
+
+ Fix warning when compiling the chromium port of DumpRenderShell
+ with clang.
+ https://bugs.webkit.org/show_bug.cgi?id=48414
+
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::javaScriptFlagsForLoad):
+
+2010-11-01 Adam Roben <aroben@apple.com>
+
+ Fix typo from r71022
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2010-11-01 Adam Roben <aroben@apple.com>
+
+ Trigger the Windows Release WebKit2 tests when a Release build
+ finishes, not when a Debug build finishes
+
+ Fixes <http://webkit.org/b/48754> Windows Release WebKit2 tests are
+ triggered at the wrong time
+
+ Reviewed by Sam Weinig.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json: Fixed
+ triggerable name and trigger.
+
+2010-11-01 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Unreviewed. Adding my IRC nickname to the list of committers.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-10-31 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] [Gtk] Plug-ins having upper case in mime type are failing to load
+
+ Qt and Gtk are case-sensitive when storing the declared mime-type
+ of plugins. Since plugin mime-types are lowercased prior to searching
+ for them in the plugin database, ensure they are loaded with the
+ mime-type in lower case too.
+
+ Change the test netscape plugin to declare its mimetype in sentence
+ case so that the correct behaviour is enforced.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36815
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (NP_GetMIMEDescription):
+
+2010-10-31 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] Support nodesFromRect in DRT
+
+ https://bugs.webkit.org/show_bug.cgi?id=48716
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::nodesFromRect):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-10-30 Andreas Kling <kling@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] QtTestBrowser: Switching view type moves the embedded inspector
+ https://bugs.webkit.org/show_bug.cgi?id=48705
+
+ Reinsert the embedded inspector into the splitter after changing
+ between QWebView/QGraphicsWebView.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::init):
+ (LauncherWindow::initializeView):
+ * QtTestBrowser/webinspector.h:
+ (WebInspector::WebInspector):
+
+2010-10-28 Antonio Gomes <agomes@rim.com>
+
+ Reviewed by Ojan Vafai.
+
+ Needs a "LinuxEditingBehavior", perhaps with a better name
+ https://bugs.webkit.org/show_bug.cgi?id=36627
+
+ Adding support to Mac's, GTK+'s, Windows' and Chromium's LayoutTestController class to test the newly introduced Unix editing behavior.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setEditingBehavior):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setEditingBehavior):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setEditingBehavior):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setEditingBehavior):
+
+2010-10-29 Andreas Kling <kling@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] QtTestBrowser: Add keyboard shortcut to toggle full screen (F11)
+ https://bugs.webkit.org/show_bug.cgi?id=48695
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::createChrome):
+
+2010-10-29 Andreas Kling <kling@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] QtTestBrowser: Fix uninitialized read in FpsTimer
+ https://bugs.webkit.org/show_bug.cgi?id=48675
+
+ FpsTimer::m_timer was never initialized and passed to QObject::killTimer()
+ on startup with in -graphicsbased mode.
+
+ * QtTestBrowser/fpstimer.cpp:
+ (FpsTimer::FpsTimer):
+ (FpsTimer::numFrames):
+ (FpsTimer::stop):
+ (FpsTimer::timerEvent):
+ * QtTestBrowser/fpstimer.h:
+
+2010-10-29 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: change TestResults to be serializable
+
+ In preparation for changing new-run-webkit-tests from
+ multithreaded to multiprocess, we need to make sure the data
+ going between the threads is easily serialized over a socket.
+
+ This change adds serialization/pickling for the TestResults and
+ TestFailure objects (using cPickle).
+
+ The TestFailure objects included a "has_wdiff" flag for Text
+ results, but the flag wasn't being used, so I've removed it,
+ simplifying the state to basically a set of enum objects with
+ associated methods.
+
+ https://bugs.webkit.org/show_bug.cgi?id=48616
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_failures.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_results.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/test_results_unittest.py:Added.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-10-29 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: need to provide separate dashboard results for GPU tests
+ https://bugs.webkit.org/show_bug.cgi?id=48687
+
+ Modify the steps to upload the JSON files to the dashboards so
+ that the GPU tests don't conflict with the regular tests on a
+ port. We do this by modifying the --builder-name parameter to
+ append " - GPU", which should cause the app to treat the results
+ as a completely new builder. This is a little non-obvious, but
+ keeps us from having to restructure the app.
+
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-29 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [chromium] add debug logging to help diagnose flakiness dashboard issues
+ https://bugs.webkit.org/show_bug.cgi?id=48657
+
+ The appengine app thinks it's getting empty files uploaded. Add some logging
+ to see if new-run-webkit-tests agrees.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-29 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ [Chromium/DRT] Add master-name flag to new-run-webkit-tests.
+ https://bugs.webkit.org/show_bug.cgi?id=48649
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: Added flag.
+
+2010-10-29 Nicolas Dufresne <nicolas.dufresne@collabora.co.uk>
+
+ Reviewed by Martin Robinson.
+
+ Enable popup window in GtkLauncher
+ https://bugs.webkit.org/show_bug.cgi?id=48335
+
+ The GtkLauncher application does not support opening new window when
+ a link with "target=_blank" is clicked or similar call to
+ window.open(). Instead, GtkLauncher does nothing which breaks
+ navigation of some websites.
+
+ * GtkLauncher/main.c:
+ (activate_uri_entry_cb):
+ (update_title):
+ (link_hover_cb):
+ (notify_title_cb):
+ (notify_load_status_cb):
+ (notify_progress_cb):
+ (destroy_cb):
+ (go_back_cb):
+ (go_forward_cb):
+ (create_web_view_cb):
+ (web_view_ready_cb):
+ (close_web_view_cb):
+ (create_browser):
+ (create_statusbar):
+ (create_toolbar):
+ (create_window):
+ (main):
+
+2010-10-29 Adam Roben <aroben@apple.com>
+
+ Teach check-webkit-style about WebKit2's idiosyncracies
+
+ Fixes <http://webkit.org/b/48638> Style bot complains about a number
+ of WebKit2 conventions
+
+ Reviewed by Anders Carlsson.
+
+ * Scripts/webkitpy/style/checker.py: Excluded some rules for various
+ WebKit2-related files. Also updated the excluded rules for
+ WebKitAPITest to match the current code.
+
+2010-10-29 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Adam Roben and David Kilzer.
+
+ Fix and cleanup of build systems
+ https://bugs.webkit.org/show_bug.cgi?id=48342
+
+ * Scripts/build-webkit:
+ - Remove unnecessary ENABLE_SANDBOX option.
+ - Add ENABLE_FULLSCREEN_API option.
+
+2010-10-28 Adam Roben <aroben@apple.com>
+
+ Switch the Windows WebKit2 bot to the Release configuration
+
+ We only have one machine testing WebKit2 on Windows right now, and
+ Debug is just too slow for it to keep up.
+
+ Fixes (hopefully!) <http://webkit.org/b/48615> Windows WebKit2 bot is
+ always way behind
+
+ Reviewed by Jon Honeycutt.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2010-10-29 Leandro Gracia Gil <leandrogracia@google.com>
+
+ Reviewed by Jeremy Orlow.
+
+ Added a second parameter to setMockSpeechInputResult for
+ the language used in speech input.
+ https://bugs.webkit.org/show_bug.cgi?id=47089
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setMockSpeechInputResultCallback):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ (LayoutTestController::pageSizeAndMarginsInPixels):
+
+2010-10-28 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [chromium] add a result-small.json file for the test dashboard
+ https://bugs.webkit.org/show_bug.cgi?id=48547
+
+ Output both a results.json file and a results-small.json file.
+ The dashboard will load results-small.json by default so it loads faster.
+
+ * TestResultServer/model/jsonresults.py:
+ * TestResultServer/model/jsonresults_unittest.py:
+ Added a bunch of sys.path hackery. Unforunately, this uses hardcoded
+ paths. That obviously needs to be fixed, but at least this way it
+ clearly documents what paths are necessary.
+
+2010-10-28 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch upload calls changed_files more often than it should
+ https://bugs.webkit.org/show_bug.cgi?id=48567
+
+ Passing changed_files around everywhere isn't a very elegant solution
+ but it's the one we have for the moment. I think keeping an explicit
+ cache on Checkout (or making StepState() a real class) is a better
+ long-term option.
+
+ Previously bug_id_for_this_commit was calling changed_files and the
+ result was never getting cached on the state. Now we're explicitly
+ caching the result on the state and passing that to the bug_id_for_this_commit call.
+
+ I looked into building unit tests for this. Doing so would require
+ using a real Checkout object with a MockSCM and overriding the appropriate
+ calls on SCM to count how often we're stating the file system.
+ That's a useful set of tests to build for a separate change.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-10-28 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make suggest-reviewers slightly faster
+ https://bugs.webkit.org/show_bug.cgi?id=48562
+
+ Add @memoized to one more common call.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+
+2010-10-28 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch suggest-reviewers -g 260550a6e30b7bf34f16bdb4a5396cf26264fc1c is still very slow
+ https://bugs.webkit.org/show_bug.cgi?id=48536
+
+ This patch makes it about 40 seconds faster, but it still
+ takes 1:40. This will require more refinement.
+
+ The suggested reviewers list appears to be the same.
+
+ I think the next step may be to have it stop the search after
+ 5 reviewers are found. We never want to suggest 30 people.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ - Using --remove-empty to theoretically stop lookups past
+ when a file is removed. I'm not entirely clear that the option
+ does what it says it does. Example:
+ git log --pretty=format:%H -5 --remove-empty -- /Projects/WebKit/WebCore/platform/wx/SearchPopupMenuWx.h
+ returns only one commit
+ vs.
+ git log --pretty=format:%H -5 -- /Projects/WebKit/WebCore/platform/wx/SearchPopupMenuWx.h
+ which returns 5. I was not aware that wx files were ever removed from the repository?
+
+2010-10-28 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by David Levin.
+
+ [Chromium] Support FileSystem in chromium DRT
+ https://bugs.webkit.org/show_bug.cgi?id=47643
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::openFileSystem): Added.
+ * DumpRenderTree/chromium/WebViewHost.h:
+ (WebViewHost::openFileSystem): Added.
+
+2010-10-28 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ WKURLRefs should be allowed to be null
+ <rdar://problem/8575621>
+ https://bugs.webkit.org/show_bug.cgi?id=48535
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp:
+ (TestWebKitAPI::didStartProvisionalLoadForFrame):
+ (TestWebKitAPI::didCommitLoadForFrame):
+ (TestWebKitAPI::didFinishLoadForFrame):
+ Test that URLs are null pointers when unset.
+
+2010-10-28 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ AX: multi select group option does not handle setting of AXSelectedChildren correctly
+ https://bugs.webkit.org/show_bug.cgi?id=48464
+
+ Add support for querying information about selected children to DRT, including:
+ selectedChildAtIndex
+ selectedChildrenCount
+ setSelectedChild
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (selectedChildAtIndexCallback):
+ (setSelectedChildCallback):
+ (selectedChildrenCountCallback):
+ (AccessibilityUIElement::setSelectedChild):
+ (AccessibilityUIElement::selectedChildrenCount):
+ (AccessibilityUIElement::selectedChildAtIndex):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::selectedChildAtIndex):
+ (AccessibilityUIElement::selectedChildrenCount):
+ (AccessibilityUIElement::setSelectedChild):
+
+2010-10-27 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add WebKit2 API for window feature getter/setters
+ <rdar://problem/8590373>
+ https://bugs.webkit.org/show_bug.cgi?id=48496
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]):
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::create):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ (WTR::TestController::initialize):
+
+2010-10-28 Søren Gjesse <sgjesse@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Added support for the DumpRenderTree flags --multiple-loads and --js-flags to the Python test runner.
+ https://bugs.webkit.org/show_bug.cgi?id=48236
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-28 Sergio Villar Senin <svillar@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] WebKitWebFrame's load-status is not properly notified to the tests
+ https://bugs.webkit.org/show_bug.cgi?id=48048
+
+ DRT now listens to WebKitWebFrame load-status signals for each
+ created frame instead of the load-status signal of the
+ WebKitWebView that only notifies about changes in the main frame.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewLoadFinished):
+ (webFrameLoadStatusNotified):
+ (frameCreatedCallback):
+ (createWebView):
+ (main):
+
+2010-10-28 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] fix textInputController.{selectedRange,markedRange}
+ https://bugs.webkit.org/show_bug.cgi?id=48487
+
+ * DumpRenderTree/chromium/TextInputController.cpp:
+ (TextInputController::markedRange): Return arrays of ints, rather than a string
+ (TextInputController::selectedRange): Ditto.
+
+2010-10-27 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [chromium] add a master-name flag to new-run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=48488
+
+ The test results server now allows adding a master name to
+ the uploaded files. This lets us distinguish bots that have
+ the same name, but are on different masters.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-28 Adam Roben <aroben@apple.com>
+
+ Don't append a newline to the test output if the frame has no document
+ element in WebKitTestRunner
+
+ Fixes <http://webkit.org/b/48526> Extra trailing newline when running
+ plugins/document-open.html in WebKitTestRunner
+
+ Reviewed by Anders Carlsson.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::toJS): Added. Turns a UTF-8 C string into a JSStringRef.
+ (WTR::hasDocumentElement): Added. Uses the JSC API to figure out
+ whether the frame has a document element.
+ (WTR::dumpFrameText): Match DRT by bailing (rather than appending an
+ empty string and a newline) if the frame has no document element.
+
+2010-10-28 Adam Roben <aroben@apple.com>
+
+ Skip npn-invalidate-rect-invalidates-window.html on headless XP
+ machines
+
+ TestNetscapePlugIn never receives a WM_PAINT message on headless XP
+ machines, so this test times out. Fixing the test is covered by
+ <http://webkit.org/b/48333>.
+
+ * Scripts/old-run-webkit-tests: Skip
+ npn-invalidate-rect-invalidates-window.html on Windows if accelerated
+ compositing support is disabled, which likely means we're on a headless
+ XP machine.
+
+2010-10-28 Kimmo Kinnunen <kimmok@iki.fi>
+
+ Adding myself as a committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-10-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch suggest-reviewers -g 260550a6e30b7bf34f16bdb4a5396cf26264fc1c is very slow
+ https://bugs.webkit.org/show_bug.cgi?id=48500
+
+ This doesn't fix the problem, but it makes things slightly better.
+ Each git svn find-rev call takes about .25 seconds on my desktop.
+ This patch uses a new memoized class to avoid those calls when possible.
+
+ The real slowness is still git log on some files, like:
+ git log --pretty=format:%H -5 -- /Projects/WebKit/WebCore/platform/wx/SearchPopupMenuWx.h
+ I'm not yet sure how to make the pathological git logs better.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/memoized.py: Added.
+ * Scripts/webkitpy/common/memoized_unittest.py: Added.
+
+2010-10-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Ojan Vafai.
+
+ EWS bots should not use --quiet when running build-webkit
+ https://bugs.webkit.org/show_bug.cgi?id=48482
+
+ --quiet is only correct when the sub-process does the error reporting.
+ In the case of _can_build() the parent process is reporting the error.
+ We'd like the full build log at queues.webkit.org so someone can look
+ at the log and understand why the EWS is failing to build trunk.
+
+ * Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-10-27 Brian Weinstein <bweinstein@apple.com>
+
+ More Windows build fixage. Rename a variable that was named string.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::hasPrefix):
+
+2010-10-27 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [chromium] Make the test results server store which master the bot is on
+ https://bugs.webkit.org/show_bug.cgi?id=48478
+
+ The chromium bots recently changed so that there are multiple slaves with
+ the same name on different masters. Up till now, the test results server
+ assumed slave names were unique. Adds a master field to the file in order
+ to distinguish.
+
+ Also, for files that currently lack a master or testtype, set them appropriately.
+
+ * TestResultServer/handlers/testfilehandler.py:
+ * TestResultServer/index.yaml:
+ * TestResultServer/model/jsonresults.py:
+ * TestResultServer/model/testfile.py:
+ * TestResultServer/templates/showfilelist.html:
+ * TestResultServer/templates/uploadform.html:
+
+2010-10-26 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ WebKitTestRunner needs to support layoutTestController.dumpBackForwardList
+ https://bugs.webkit.org/show_bug.cgi?id=42322
+ rdar://problem/8193631
+
+ WebKitTestRunner needs to support layoutTestController.clearBackForwardList
+ https://bugs.webkit.org/show_bug.cgi?id=42333
+ rdar://problem/8193643
+
+ * WebKitTestRunner/Configurations/InjectedBundle.xcconfig:
+ Renamed the product to WebKitTestRunnerInjectedBundle to avoid
+ name conflicts in the build directory.
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ Added dumpBackForwardList and clearBackForwardList.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::InjectedBundle): Removed initialization of m_mainPage.
+ (WTR::InjectedBundle::didCreatePage): Removed unneeded underscore.
+ (WTR::InjectedBundle::willDestroyPage): Ditto.
+ (WTR::InjectedBundle::didReceiveMessage): Ditto.
+ (WTR::InjectedBundle::initialize): Ditto.
+ (WTR::InjectedBundle::didCreatePage): Changed code to use m_pages
+ instead of m_mainPage and m_otherPages.
+ (WTR::InjectedBundle::willDestroyPage): Ditto.
+ (WTR::InjectedBundle::page): Ditto.
+ (WTR::InjectedBundle::beginTesting): Ditto.
+ (WTR::InjectedBundle::done): Ditto.
+ (WTR::InjectedBundle::closeOtherPages): Ditto.
+ (WTR::InjectedBundle::dumpBackForwardListsForAllPages): Added.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h: Changed
+ page function to longer be inline, and pageCount function
+ to use m_pages. Added dumpBackForwardListsForAllPages, and
+ removed some underscores. Replaced m_mainPage and m_otherPageas
+ with m_pages.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::adoptWK): Added.
+ (WTR::hasPrefix): Added.
+ (WTR::InjectedBundlePage::reset): Added code to set up
+ m_previousTestBackForwardListItem.
+ (WTR::InjectedBundlePage::dump): Added code to call
+ dumpBackForwardListsForAllPages.
+ (WTR::compareByTargetName): Added.
+ (WTR::dumpBackForwardListItem): Added.
+ (WTR::InjectedBundlePage::dumpBackForwardList): Added.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h: Added
+ dumpBackForwardList and m_previousTestBackForwardListItem.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::LayoutTestController): Initialize
+ m_shouldDumpBackForwardListsForAllWindows to false.
+ (WTR::LayoutTestController::clearBackForwardList): Added.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ Added dumpBackForwardList, clearBackForwardList,
+ shouldDumpBackForwardListsForAllWindows, and
+ m_shouldDumpBackForwardListsForAllWindows.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize): Set up
+ didReceiveSynchronousMessageFromInjectedBundle.
+ (WTR::TestController::didReceiveSynchronousMessageFromInjectedBundle):
+ Added.
+ * WebKitTestRunner/TestController.h: Ditto.
+
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::didReceiveSynchronousMessageFromInjectedBundle):
+ Added.
+ * WebKitTestRunner/TestInvocation.h: Ditto.
+
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+ Renamed bundle to WebKitTestRunnerInjectedBundle (see above).
+ * WebKitTestRunner/mac/TestControllerMac.mm:
+ (WTR::TestController::initializeInjectedBundlePath): Ditto.
+
+2010-10-27 Chris Rogers <crogers@google.com>
+
+ Reviewed by Chris Marrin.
+
+ Add ENABLE_WEB_AUDIO feature enable flag (initially disabled) to build-webkit
+ https://bugs.webkit.org/show_bug.cgi?id=48279
+
+ * Scripts/build-webkit:
+
+2010-10-27 Eric Seidel <eric@webkit.org>
+
+ Unreviewed.
+
+ build-webkit should collect Visual Studio Express logs and display them
+ https://bugs.webkit.org/show_bug.cgi?id=39199
+
+ It turns out my previous patch wasn't actually working on the win-ews
+ machine. So I've fixed my mistakes from before.
+
+ * Scripts/build-webkit:
+ - Windows VSE builds change the CWD while building. Why? Who knows.
+ * Scripts/print-vse-failure-logs:
+ - windows VSE builds don't use Debug/Release as I expected, so I've
+ moved off of --configuration to --top-level and added the /obj
+ optimization while I was there.
+
+2010-10-27 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Unreviewed, rolling out r70674.
+ http://trac.webkit.org/changeset/70674
+ https://bugs.webkit.org/show_bug.cgi?id=48053
+
+ Broke Chromium Windows build.
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-25 Tony Chang <tony@chromium.org>
+
+ Reviewed by Anders Carlsson.
+
+ compile TestNetscapePlugIn on chromium linux
+ https://bugs.webkit.org/show_bug.cgi?id=48274
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NP_Initialize): On Linux, plugin funcs are set in initialize.
+ (NPP_New): Mark the plugin as windowless.
+ (NPP_GetValue): Handle mime type values.
+ (NP_GetMIMEDescription):
+ (NP_GetValue):
+ * DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h: define TRUE and FALSE, which are in webkit's npapi.h.
+ * DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h: Pull in npapi.h to get TRUE/FALSE (matches webkit's npfunctions.h)
+
+2010-10-27 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Remove contentSizeChanged callbacks as it is no longer
+ part of the public UIClient.
+
+ Make WKPageContentsSizeChangedCallback be a private API
+ https://bugs.webkit.org/show_bug.cgi?id=48409
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]):
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::create):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ (WTR::TestController::initialize):
+
+2010-10-27 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Ojan Vafai.
+
+ Make http locking default in NRWT.
+ https://bugs.webkit.org/show_bug.cgi?id=48053
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-27 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Tony Chang.
+
+ [NRWT] Fix http lock on Windows platform
+ https://bugs.webkit.org/show_bug.cgi?id=48321
+
+ * Scripts/webkitpy/layout_tests/port/http_lock.py:
+
+2010-10-27 Satish Sampath <satish@chromium.org>
+
+ Unreviewed, rolling out r70665.
+ http://trac.webkit.org/changeset/70665
+ https://bugs.webkit.org/show_bug.cgi?id=47089
+
+ Need to address Alexey's review comments.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setMockSpeechInputResultCallback):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+
+2010-10-27 Leandro Gracia Gil <leandrogracia@google.com>
+
+ Reviewed by Jeremy Orlow.
+
+ Added a second parameter to setMockSpeechInputResult for
+ the language used in speech input.
+ https://bugs.webkit.org/show_bug.cgi?id=47089
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setMockSpeechInputResultCallback):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ (LayoutTestController::pageSizeAndMarginsInPixels):
+
+2010-10-27 Adam Roben <aroben@apple.com>
+
+ Reset TestNetscapePlugIn's NPP_GetValue pointer when
+ NullNPPGetValuePointer finishes running
+
+ Fixes <http://webkit.org/b/48435> REGRESSION (r70655): Many plugins
+ tests are failing on Qt
+
+ Reviewed by Anders Carlsson.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp:
+ (PluginTest::NPP_Destroy):
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.h:
+ Added a do-nothing NPP_Destroy implementation.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp:
+ (NullNPPGetValuePointer::NullNPPGetValuePointer): Save the original
+ NPP_GetValue pointer in m_originalNPPGetValuePointer so we can restore
+ it later.
+ (NullNPPGetValuePointer::NPP_Destroy): Added. Restores the original
+ NPP_GetValue pointer so it can be used in other tests.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_Destroy):
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_destroy_instance):
+ Call through to the PluginTest when NPP_Destroy is called.
+
+2010-10-26 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Adam Roben.
+
+ WebKit2 shouldn't try to send an empty user agent
+ https://bugs.webkit.org/show_bug.cgi?id=48397
+
+ Add a test that when we set our custom user agent to an empty string, we don't send
+ an empty user agent.
+
+ * TestWebKitAPI/Tests/WebKit2/PreventEmptyUserAgent.cpp: Added.
+ (TestWebKitAPI::didRunJavaScript): Make sure that the result of navigator.userAgent isn't empty.
+ (TestWebKitAPI::TEST): Set our custom user agent to the empty string, and run navigator.userAgent.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Add the new file.
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj: Ditto.
+
+2010-10-27 Adam Roben <aroben@apple.com>
+
+ Check in file I forgot in r70653
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (NP_Initialize): Save the NPPluginFuncs struct the browser passed to us
+ so we can be naughty and modify it later.
+
+2010-10-27 Adam Roben <aroben@apple.com>
+
+ Test that WebKit doesn't crash if the plugin passes 0 for its
+ NPP_GetValue pointer
+
+ Test for <http://webkit.org/b/48433> Crash in
+ NetscapePlugin::shouldLoadSrcURL when using Shockwave Director 10.3 in
+ WebKit2 on Windows
+
+ Reviewed by Eric Carlson.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+ * GNUmakefile.am:
+ Added NullNPPGetValuePointer.cpp.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.h:
+ Set up a place to store the NPPluginFuncs struct the browser passed to us.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp: Added.
+ (NullNPPGetValuePointer::NullNPPGetValuePointer): Null out the
+ NPP_GetValue pointer we passed to the browser to simulate a plugin that
+ doesn't implement NPP_GetValue.
+ (NullNPPGetValuePointer::NPP_GetValue): Print an error message. If this
+ function is called, it means that WebKit has changed in a way that
+ makes this test invalid.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NP_GetEntryPoints): Save the NPPluginFuncs struct the browser passed
+ to us so we can be naughty and modify it later.
+
+2010-10-27 Ademar de Souza Reis Jr <ademar.reis@openbossa.org>
+
+ Reviewed by Andreas Kling.
+
+ Remove references to ancient QGVLauncher and QtLauncher
+ https://bugs.webkit.org/show_bug.cgi?id=48430
+
+ QtTestBrowser substitutes both and has checks enabled.
+
+ * Scripts/webkitpy/style/checker.py: remove references
+ * Scripts/webkitpy/style/checker_unittest.py: ditto
+
+2010-10-27 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Ojan Vafai.
+
+ [NRWT] Don't use image hash when it's no need in single test mode.
+ https://bugs.webkit.org/show_bug.cgi?id=48326
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+
+2010-10-27 David Kilzer <ddkilzer@apple.com>
+
+ Fix leak of CFMutableDictionaryRef in createXMLStringFromWebArchiveData()
+
+ Reviewed by Adam Roben.
+
+ Follow-up fix for: <https://bugs.webkit.org/show_bug.cgi?id=48278>
+
+ * DumpRenderTree/cf/WebArchiveDumpSupport.cpp:
+ (createXMLStringFromWebArchiveData): Use RetainPtr<> to fix a
+ leak introduced in r70613.
+
+2010-10-27 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [NRWT] Add platform specific baseline search paths for Qt port
+ https://bugs.webkit.org/show_bug.cgi?id=48428
+
+ * Scripts/webkitpy/layout_tests/port/qt.py:
+
+2010-10-27 Adam Roben <aroben@apple.com>
+
+ Catch exceptions when checking if we're inside a git working directory
+
+ Fixes <http://webkit.org/b/48420> REGRESSION (r70562): test-webkitpy
+ fails on systems without git installed
+
+ Reviewed by Anders Carlsson.
+
+ * Scripts/webkitpy/common/net/credentials.py:
+ (Credentials._credentials_from_git): Put the call to
+ Git.in_working_directory inside the try/except since it, too, attempts
+ to execute git and thus will throw on systems that don't have git
+ installed.
+
+2010-10-27 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Reviewed by David Kilzer.
+
+ Convert DumpRenderTree webarchive code to CoreFoundation
+ https://bugs.webkit.org/show_bug.cgi?id=48278
+
+ CFPropertyListCreateWithData and CFPropertyListCreateData are only available in 10.6+.
+ Replace CFPropertyListCreateWithData by a combination of CFReadStreamCreateWithBytesNoCopy and CFPropertyListCreateFromStream.
+ Replace CFPropertyListCreateData by CFPropertyListCreateXMLData.
+
+ These changes are wrapped in BUILDING_ON_LEOPARD, as the methods are deprecated on 10.6+.
+
+ * DumpRenderTree/cf/WebArchiveDumpSupport.cpp:
+ (createXMLStringFromWebArchiveData):
+
+2010-10-26 Antonio Gomes <agomes@rim.com>
+
+ Reviewed by Martin Robinson.
+
+ Remove the absolute path used to include DumpRenderTreeSupportGtk.h from LayoutTestController.h
+
+ It turns out this is rather unneeded since WebKitTools/GNUMakefile.am has WebKit/gtk/ in its include
+ path, and then we can just do #include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+
+2010-10-26 David Kilzer <ddkilzer@apple.com>
+
+ Rename WebArchiveDumpSupport.mm to WebArchiveDumpSupport.cpp
+
+ Reviewed by Adam Roben.
+
+ Part 4 of 4: <http://webkit.org/b/48278> Convert DumpRenderTree webarchive code to CoreFoundation
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ Updated for file moves and renames.
+ * DumpRenderTree/cf/WebArchiveDumpSupport.cpp: Renamed from DumpRenderTree/mac/WebArchiveDumpSupport.mm.
+ * DumpRenderTree/cf/WebArchiveDumpSupport.h: Renamed from DumpRenderTree/mac/WebArchiveDumpSupport.h.
+
+2010-10-26 David Kilzer <ddkilzer@apple.com>
+
+ Convert WebArchiveDumpSupport.mm from NS objects to CF types
+
+ Reviewed by Adam Roben.
+
+ Part 3 of 4: <http://webkit.org/b/48278> Convert DumpRenderTree webarchive code to CoreFoundation
+
+ In order to share WebArchive code between the Mac and Windows
+ ports, the code in WebArchiveDumpSupport.mm was converted from
+ Cocoa to C++ using CoreFoundation (CF) types.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dump): Renamed serializeWebArchiveToXML() to
+ createXMLStringFromWebArchiveData() and added HardAutorelease()
+ to prevent leaks.
+ * DumpRenderTree/mac/WebArchiveDumpSupport.h:
+ (createXMLStringFromWebArchiveData): Renamed from
+ serializeWebArchiveToXML(). Changed to use CF types.
+ (createCFURLResponseFromResponseData): Renamed from
+ unarchiveNSURLResponseFromResponseData(). Changed to use CF
+ types for its parameter and return type.
+ * DumpRenderTree/mac/WebArchiveDumpSupport.mm: Replaced use of
+ NS objects with CF types. It will be renamed to *.cpp in a
+ future commit.
+ (convertMIMEType): Changed to use case-insensitive string
+ comparisons.
+ (convertWebResourceDataToString):
+ (normalizeHTTPResponseHeaderFields):
+ (normalizeWebResourceURL):
+ (convertWebResourceResponseToDictionary):
+ (compareResourceURLs):
+ (createXMLStringFromWebArchiveData):
+ * DumpRenderTree/mac/WebArchiveDumpSupportMac.mm:
+ (createCFURLResponseFromResponseData): Renamed from
+ unarchiveNSURLResponseFromResponseData(). Changed to use CF
+ types for its parameter and return type.
+
+2010-10-26 David Kilzer <ddkilzer@apple.com>
+
+ Extract use of NSKeyedUnarchiver from WebArchiveDumpSupport.mm
+
+ Reviewed by Adam Roben.
+
+ Part 2 of 4: <http://webkit.org/b/48278> Convert DumpRenderTree webarchive code to CoreFoundation
+
+ There is no equivalent to NSKeyedUnarchiver in CoreFoundation,
+ so extract it into a platform-specific source file.
+
+ * DumpRenderTree/mac/WebArchiveDumpSupport.h:
+ (unarchiveNSURLResponseFromResponseData): Added declaration.
+ * DumpRenderTree/mac/WebArchiveDumpSupport.mm:
+ (convertWebResourceResponseToDictionary): Extracted code to
+ unarchiveNSURLResponseFromResponseData() in
+ WebArchiveDumpSupportMac.mm. Updated logic to return early if
+ nil is returned from unarchiveNSURLResponseFromResponseData().
+ * DumpRenderTree/mac/WebArchiveDumpSupportMac.mm:
+ (unarchiveNSURLResponseFromResponseData): Added. Extracted
+ code from convertWebResourceResponseToDictionary() in
+ WebArchiveDumpSupport.mm.
+
+2010-10-26 David Kilzer <ddkilzer@apple.com>
+
+ Extract call to -[WebHTMLRepresentation supportedNonImageMIMETypes] from WebArchiveDumpSupport.mm
+
+ Reviewed by Adam Roben.
+
+ Part 1 of 4: <http://webkit.org/b/48278> Convert DumpRenderTree webarchive code to CoreFoundation
+
+ The call to -[WebHTMLRepresentation supportedNonImageMIMETypes]
+ is not cross-platform between Mac and Windows, so extract it
+ into a platform-specific source file.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Added
+ WebArchiveDumpSupportMac.mm to the project.
+ * DumpRenderTree/mac/WebArchiveDumpSupport.h:
+ (supportedNonImageMIMETypes): Added declaration.
+ * DumpRenderTree/mac/WebArchiveDumpSupport.mm:
+ (convertWebResourceDataToString): Replaced call to
+ -[WebHTMLRepresentation supportedNonImageMIMETypes] with
+ supportedNonImageMIMETypes().
+ * DumpRenderTree/mac/WebArchiveDumpSupportMac.mm: Added.
+ (supportedNonImageMIMETypes): Added. Extracted from
+ WebArchiveDumpSupport.mm.
+
+2010-10-26 Antonio Gomes <agomes@rim.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Implement DumpRenderTreeSupportGtk (similarly to DumpRenderTreeSupportQt idea)
+ https://bugs.webkit.org/show_bug.cgi?id=48199
+
+ Implements support to WebKitTabToLinksPreferenceKey through LayoutTestController::overridePreference.
+ The corresponding DumpRenderTreeSupportGtk method is called in the DRT context only.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ (createWebView):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::overridePreference):
+
+2010-10-26 Ariya Hidayat <ariya@sencha.com>
+
+ Unreviewed, change the order of my emails for bugzilla autocompletion.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-10-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ build-webkit should collect Visual Studio Express logs and display them
+ https://bugs.webkit.org/show_bug.cgi?id=39199
+
+ * Scripts/build-webkit:
+ * Scripts/print-vse-failure-logs: Added.
+ * Scripts/webkitdirs.pm:
+
+2010-10-26 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/48224> build-webkit: add support for --meter-tag switch
+
+ Reviewed by Csaba Osztrogonác.
+
+ * Scripts/build-webkit: Added support for --meter-tag switch.
+ It should have been added with r60820.
+
+2010-10-26 Ademar de Souza Reis Jr. <ademar.reis@openbossa.org>
+
+ Reviewed by Dumitru Daniliuc.
+
+ check-webkit-style fails on operator+=, operator-=, ... methods
+ https://bugs.webkit.org/show_bug.cgi?id=48258
+
+ * Scripts/webkitpy/style/checkers/cpp.py: Added exceptions
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py: Added unit-tests
+
+2010-10-26 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ remove DEFER support from new-run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=48387
+
+ DEFER was needed when we were trying to ship Chrome beta.
+ Now it's just extra complication.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/style/checkers/test_expectations_unittest.py:
+
+2010-10-26 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Adding import with_statement to fix python 2.5.
+
+ Teach webkit-patch how to read credentials from the environment
+ https://bugs.webkit.org/show_bug.cgi?id=48275
+
+ * Scripts/webkitpy/common/net/credentials_unittest.py:
+ - import with_statement to fix python 2.5.
+
+2010-10-26 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=48375
+ <rdar://problem/8392724> Need delegate calls in PageLoaderClient to indicate if we have
+ loaded insecure content
+
+ Updated for WebKit2 changes.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (didDisplayInsecureContentForFrame):
+ (didRunInsecureContentForFrame):
+ (-[BrowserWindowController awakeFromNib]):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::didDisplayInsecureContentForFrame):
+ (WTR::InjectedBundlePage::didRunInsecureContentForFrame):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize):
+
+2010-10-26 Adam Roben <aroben@apple.com>
+
+ Clear up confusion between "3D rendering" and "accelerated compositing"
+
+ WebKit has no software-based 3D rendering implementation, so 3D
+ rendering can only be enabled when accelerated compositing is. But DRT
+ was falsely reporting that 3D rendering was available on machines that
+ don't support accelerated compositing, leading to much confusion.
+
+ Reviewed by Darin Adler.
+
+ Fixes <http://webkit.org/b/48370> REGRESSION (r70540): Many
+ transforms/3d tests are failing on the XP bots
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main): When ENABLE(3D_RENDERING) is turned on, only report that 3D
+ rendering is available when acclerated compositing is also available.
+
+ * Scripts/old-run-webkit-tests: Skip tests that use the
+ -webkit-transform-3d media query when 3D rendering is disabled,
+ rather than when accelerated compositing is disabled.
+
+2010-10-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Ojan Vafai.
+
+ Remove rietveld code now that it's unused
+ https://bugs.webkit.org/show_bug.cgi?id=48359
+
+ Was cool that we added this support, but now that it's
+ not used it makes little sense to keep it around.
+ We can always restore this code from SVN if we need it.
+
+ * Scripts/webkitpy/common/config/__init__.py:
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+ * Scripts/webkitpy/common/net/rietveld.py: Removed.
+ * Scripts/webkitpy/common/net/rietveld_unittest.py: Removed.
+ * Scripts/webkitpy/thirdparty/__init__.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/__init__.py:
+ * Scripts/webkitpy/tool/steps/postcodereview.py: Removed.
+
+2010-10-26 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ pageDidScroll callback should be on the UI process client rather than (or in addition to) the web process client
+ https://bugs.webkit.org/show_bug.cgi?id=48366
+ <rdar://problem/8595202>
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ (WTR::TestController::initialize):
+
+2010-10-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Tony Chang.
+
+ Teach webkit-patch how to read credentials from the environment
+ https://bugs.webkit.org/show_bug.cgi?id=48275
+
+ This makes it possible for svn users to have their bugzilla credentials
+ stored in their environment instead of typing them every time.
+
+ We need this for making it easy to run the win-ews bot (which currently
+ uses svn instead of git).
+
+ * Scripts/webkitpy/common/net/credentials.py:
+ * Scripts/webkitpy/common/net/credentials_unittest.py:
+
+2010-10-26 Kenichi Ishibashi <bashi@google.com>
+
+ Reviewed by Kent Tamura.
+
+ Input Method inserts conversion candidates unexpectedly
+ https://bugs.webkit.org/show_bug.cgi?id=46868
+
+ Adds setComposition() to TextInputController to make DRT emulate
+ an input method behavior.
+
+ * DumpRenderTree/chromium/TextInputController.cpp:
+ (TextInputController::TextInputController):
+ (TextInputController::setComposition): Added.
+ * DumpRenderTree/chromium/TextInputController.h:
+
+2010-10-26 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Support layoutTestController.layerTreeAsText in WebKitTestRunner
+ https://bugs.webkit.org/show_bug.cgi?id=42145
+
+ Implement layerTreeAsText() in WebKitTestRunner.
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::layerTreeAsText):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+
+2010-10-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch rollout produces incorrect patch when using svn move
+ https://bugs.webkit.org/show_bug.cgi?id=48244
+
+ We need to flush our caches when we modify the working copy.
+
+ * Scripts/webkitpy/tool/steps/revertrevision.py:
+
+2010-10-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue flaky test message can list the same author more than once
+ https://bugs.webkit.org/show_bug.cgi?id=48268
+
+ tonikitoo reported to me over IRC this morning that he's seen
+ the commit-queue report flaky tests with author lists like:
+ "adam, adam and adam", suggesting we're not uniquing authors
+ before writing the message.
+
+ I fixed the uniquing and added a bunch more unit testing.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-10-26 Adam Roben <aroben@apple.com>
+
+ Pull in the FeatureDefines*.vsprops files when building DRT
+
+ This ensures that various ENABLE() macros will get set correctly.
+ (Prior to r70320 we were picking up the ENABLE(3D_RENDERING) flag
+ through wtf/Platform.h.)
+
+ Fixes <http://webkit.org/b/48343> REGRESSION (r70320): DumpRenderTree
+ says 3D_RENDERING is disabled even when it is enabled
+
+ Reviewed by Ada Chan.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Added
+ FeaturesDefines*.vsprops to all configurations.
+
+ * DumpRenderTree/win/DumpRenderTreeWin.h: Touched to force a rebuild.
+
+2010-10-26 Søren Gjesse <sgjesse@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Added options --multiple-loads and --js-flags to chromium DumpRenderTree. The option --multiple-loads=X
+ is used to have DumpRenderTree load each test it runs X times. To be able to have more fine-grained control
+ of how the JavaScript engine behaves for each load the flag --js-flags can specify a list of flag-sets like this
+
+ --js-flags="--xxx,--noxxx --yyy,--noyyy"
+
+ First load will run with --xxx, the second with --yyy and the third without any (the 'no' prefix is handled by
+ V8 to turn off the flag).
+
+ The changes to the Python test runner will be in a separate change.
+
+
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (runTest):
+ (main):
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell):
+ (TestShell::runFileTest):
+ (TestShell::testFinished):
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::loadCount):
+ (TestShell::setLoadCount):
+ (TestShell::javaScriptFlagsForLoad):
+ (TestShell::setJavaScriptFlags):
+ (TestShell::setDumpWhenFinished):
+
+2010-10-26 Adam Roben <aroben@apple.com>
+
+ Skip more tests that depend on accelerated compositing when accelerated
+ compositing is disabled
+
+ Fixes <http://webkit.org/b/48329> Some tests fail when accelerated
+ compositing is disabled
+
+ Reviewed by John Sullivan.
+
+ * Scripts/old-run-webkit-tests: Added more tests to skip when
+ accelerated compositing is disable. The tests all have output that
+ changes depending on whether accelerated compositing is enabled.
+
+2010-10-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch should clean up svn locks when passed --force-clean
+ https://bugs.webkit.org/show_bug.cgi?id=48269
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+
+2010-10-25 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Add a pageDidScroll BundleUIClient callback
+ https://bugs.webkit.org/show_bug.cgi?id=48260
+ <rdar://problem/8531159>
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+
+2010-10-25 Johnny Ding <jnd@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Dump the gesture status of frame in frame load callbacks in DumpRenderTree
+ by adding a new method dumpUserGestureInFrameLoadCallbacks.
+ Now only dump the gesture status in "DidStartProvisionalLoad" callback.
+ https://bugs.webkit.org/show_bug.cgi?id=47849
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (dumpUserGestureInFrameLoadCallbacksCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::dumpUserGestureInFrameLoadCallbacks):
+ (LayoutTestController::setDumpUserGestureInFrameLoadCallbacks):
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::dumpUserGestureInFrameLoadCallbacks):
+ (LayoutTestController::reset):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ (LayoutTestController::shouldDumpUserGestureInFrameLoadCallbacks):
+ (LayoutTestController::setShouldDumpUserGestureInFrameLoadCallbacks):
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::shouldDumpUserGestureInFrameLoadCallbacks):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::didStartProvisionalLoad):
+ (WebViewHost::printFrameUserGestureStatus):
+ * DumpRenderTree/chromium/WebViewHost.h:
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[WebFrame _drt_printFrameUserGestureStatus]):
+ (-[FrameLoadDelegate webView:didStartProvisionalLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didCommitLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didFailProvisionalLoadWithError:forFrame:]):
+ (-[FrameLoadDelegate webView:didFinishLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didFailLoadWithError:forFrame:]):
+ (-[FrameLoadDelegate webView:windowScriptObjectAvailable:]):
+ (-[FrameLoadDelegate webView:didReceiveTitle:forFrame:]):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::dumpUserGestureInFrameLoadCallbacks):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-10-25 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r70442.
+ http://trac.webkit.org/changeset/70442
+ https://bugs.webkit.org/show_bug.cgi?id=48248
+
+ http locking doesn't work on Windows (Requested by Ossy on
+ #webkit).
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-25 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Ojan Vafai.
+
+ Make http locking default in NRWT.
+ https://bugs.webkit.org/show_bug.cgi?id=48053
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-25 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/48185> build-webkit: add support for --progress-tag switch
+ (Re-landing r70413 after Qt minimal buildfix: r70440.)
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ * Scripts/build-webkit: Added support for --progress-tag switch.
+ It should have been added with r57051.
+
+2010-10-24 Adam Barth <abarth@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ webkit-patch upload fails when the patch removes a file
+ https://bugs.webkit.org/show_bug.cgi?id=48187
+
+ We need to use "--" to separate file names from the rest of the
+ command.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+
+2010-10-24 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r70413.
+ http://trac.webkit.org/changeset/70413
+ https://bugs.webkit.org/show_bug.cgi?id=48210
+
+ It broke Qt minimal build (Requested by Ossy on #webkit).
+
+ * Scripts/build-webkit:
+
+2010-10-24 Yi Shen <yi.4.shen@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt][QtTestBrowser] Toggle use of QGraphicsView messes up the menu
+ https://bugs.webkit.org/show_bug.cgi?id=48141
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::init):
+ (LauncherWindow::initializeView):
+ (LauncherWindow::toggleWebView):
+
+2010-10-24 Daniel Bates <dbates@rim.com>
+
+ Reviewed by David Kilzer.
+
+ Fix Perl uninitialized warnings in VCSUtils::svnStatus()
+ and VCSUtils::removeEOL().
+ https://bugs.webkit.org/show_bug.cgi?id=48196
+
+ VCSUtils::svnStatus() concatenates the output of svn status with
+ a new line character and svn status may return no output (say for
+ a file that has not been added, deleted, or modified). We should
+ only concatenate the output of svn status if there is some.
+
+ Also, VCSUtils::removeEOL() should ensure that its argument
+ is initialized before performing a string substitution.
+
+ * Scripts/VCSUtils.pm:
+ - Modified removeEOL() to return "" if its argument is undefined.
+ - Exported removeEOL() so that it can be tested.
+ * Scripts/webkitperl/VCSUtils_unittest/removeEOL.pl: Added.
+
+2010-10-24 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/48185> build-webkit: add support for --progress-tag switch
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ * Scripts/build-webkit: Added support for --progress-tag switch.
+ It should have been added with r57051.
+
+2010-10-24 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/48184> build-webkit: reformat support variables for better maintainability
+
+ Reviewed by Daniel Bates.
+
+ * Scripts/build-webkit: Alphabetized the @features array based
+ on the name of the feature. Reformatted the list of support
+ variables so that they match the order of @features, and so that
+ each has its own line. This makes it easy to add new variables
+ in the correct order.
+
+2010-10-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ EWS never removes invalid patch ids
+ https://bugs.webkit.org/show_bug.cgi?id=48173
+
+ This is just sticking another finger in the dam.
+ However this adds more unit testing which will help
+ us make sure we're always releasing patches once we
+ redesign the release_patch API and call these from
+ a more central place.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ - Added the ability to request invalid patches.
+ Log a warning message to make sure we don't ever have
+ tests use invalid patch fetches by mistake.
+
+2010-10-23 Dan Bernstein <mitz@apple.com>
+
+ Build fix. Add stub implementations for required NSDraggingInfo methods.
+
+ * DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm:
+ (-[DumpRenderTreeDraggingInfo draggingFormation]):
+ (-[DumpRenderTreeDraggingInfo setDraggingFormation:]):
+ (-[DumpRenderTreeDraggingInfo animatesToDestination]):
+ (-[DumpRenderTreeDraggingInfo setAnimatesToDestination:]):
+ (-[DumpRenderTreeDraggingInfo numberOfValidItemsForDrop]):
+ (-[DumpRenderTreeDraggingInfo setNumberOfValidItemsForDrop:]):
+ (-[DumpRenderTreeDraggingInfo enumerateDraggingItemsWithOptions:forView:classes:searchOptions:usingBlock:]):
+
+2010-10-23 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/48186> Remove unneeded WebHTMLRepresentationInternal.h header
+
+ Reviewed by Sam Weinig.
+
+ The only method defined in WebHTMLRepresentationInternal.h is
+ also defined in WebHTMLRepresentation.h, so use that instead.
+
+ * DumpRenderTree/mac/InternalHeaders/WebKit/WebHTMLRepresentationInternal.h: Removed.
+ * DumpRenderTree/mac/WebArchiveDumpSupport.mm: Switched to use
+ WebHTMLRepresentation.h.
+
+2010-10-23 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r70367.
+ http://trac.webkit.org/changeset/70367
+ https://bugs.webkit.org/show_bug.cgi?id=48176
+
+ It made 8-10 tests crash on Qt bot (Requested by Ossy on
+ #webkit).
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setCustomPolicyDelegateCallback):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setCustomPolicyDelegate):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setCustomPolicyDelegate):
+ * DumpRenderTree/mac/PolicyDelegate.h:
+ * DumpRenderTree/mac/PolicyDelegate.mm:
+ (-[PolicyDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]):
+ (-[PolicyDelegate setPermissive:]):
+ (-[PolicyDelegate setControllerToNotifyDone:]):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setCustomPolicyDelegate):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setCustomPolicyDelegate):
+
+2010-10-22 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ EWS never releases patches which fail to apply
+ https://bugs.webkit.org/show_bug.cgi?id=48171
+
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-10-22 Eric Seidel <eric@webkit.org>
+
+ Unreviewed.
+
+ Make the EWS queues restart themselves more often.
+ This matches the commit-queue.
+
+ * EWSTools/start-queue.sh:
+
+2010-10-22 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue should not pass --quiet to subcommands now that the parent command does the reporting
+ https://bugs.webkit.org/show_bug.cgi?id=48165
+
+ * Scripts/webkitpy/tool/bot/commitqueuetask.py:
+ * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-10-22 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Adding myself as a committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-10-20 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam Barth and Darin Adler.
+
+ Using the decidePolicyForMIMEType delegate message in an asynchronous manner does not work
+ https://bugs.webkit.org/show_bug.cgi?id=48014
+ <rdar://problem/8202716>
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setCustomPolicyDelegateCallback):
+ Add callIgnoreInDecidePolicyForMIMETypeAfterOneSecond argument.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setCustomPolicyDelegate):
+ Add callIgnoreInDecidePolicyForMIMETypeAfterOneSecond argument.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setCustomPolicyDelegate):
+ Add callIgnoreInDecidePolicyForMIMETypeAfterOneSecond argument.
+
+ * DumpRenderTree/mac/PolicyDelegate.h:
+ * DumpRenderTree/mac/PolicyDelegate.mm:
+ (-[PolicyDelegate webView:decidePolicyForMIMEType:request:frame:decisionListener:]):
+ If _callIgnoreInDecidePolicyForMIMETypeAfterOneSecond is true, call [listener ignore] after one second.
+
+ (-[PolicyDelegate setCallIgnoreInDecidePolicyForMIMETypeAfterOneSecond:]):
+ Update _callIgnoreInDecidePolicyForMIMETypeAfterOneSecond.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setCustomPolicyDelegate):
+ Add callIgnoreInDecidePolicyForMIMETypeAfterOneSecond argument.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setCustomPolicyDelegate):
+ Add callIgnoreInDecidePolicyForMIMETypeAfterOneSecond argument.
+
+2010-10-22 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Rename the InjectedBundle for TestWebKitAPI to InjectedBundleTestWebKitAPI.bundle
+
+ * TestWebKitAPI/Configurations/InjectedBundle.xcconfig:
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/mac/PlatformUtilitiesMac.mm:
+ (TestWebKitAPI::Util::createInjectedBundlePath):
+
+2010-10-22 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ test-webkitpy fails when passed -v (or any other option)
+
+ Fix port/base_unittest to pass an explicit list of arguments
+ rather than accidentally picking up sys.argv.
+
+ https://bugs.webkit.org/show_bug.cgi?id=48071
+
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+
+2010-10-22 Brian Weinstein <bweinstein@apple.com>
+
+ Windows build fix. Update the createNewPage callback to account for the new
+ arguments.
+
+ * MiniBrowser/win/BrowserView.cpp:
+ (createNewPage):
+
+2010-10-22 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ WebKit2 needs to pass the current event modifier flags when requesting a new window
+ https://bugs.webkit.org/show_bug.cgi?id=48140
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (createNewPage):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ Update for new signature for the WKPageCreateNewPageCallback.
+
+2010-10-22 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Just adding a test case.
+
+ The style-queue was not recognizing new patches. It turns
+ out I had fixed this in an earlier change, but just not
+ deployed to queues.webkit.org. As part of investigating why it
+ was broken, I wrote a test for my previous change which I'm now landing.
+
+ * QueueStatusServer/model/queues_unittest.py:
+
+2010-10-22 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ EWS does not need to process obsolete patches
+ https://bugs.webkit.org/show_bug.cgi?id=48093
+
+ This was an easy change, but to test it I had to pipe
+ real Attachment objects into the queue testing system.
+ Doing so revealed a whole bunch of bugs in our unit tests,
+ which I fixed as part of this patch.
+
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ - This is the actual code change. This will not reduce the
+ backlog in the EWS queues much, but it will make rejections
+ much quicker for obsolete patches or closed bugs.
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+ - Test my new code.
+ - Used a real attachment object and got rid of MockPatch
+ - Shared code between the mac-ews and cr-mac-ews tests.
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ - Can't use MockPatch anymore.
+ - Removing MockPatch found more bugs here!
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ - MockBugzilla should not be a "Mock" object. Right now tool.bugs()
+ is allowed, but wrong. Making it not a Mock will make tool.bugs() correctly fail.
+
+2010-10-22 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r70301.
+ http://trac.webkit.org/changeset/70301
+ https://bugs.webkit.org/show_bug.cgi?id=48126
+
+ "Lang attribute layout tests failing" (Requested by satish on
+ #webkit).
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setMockSpeechInputResultCallback):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+
+2010-10-22 Leandro Gracia Gil <leandrogracia@google.com>
+
+ Reviewed by Jeremy Orlow.
+
+ Added a second parameter to setMockSpeechInputResult for
+ the language used in speech input.
+ https://bugs.webkit.org/show_bug.cgi?id=47089
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setMockSpeechInputResultCallback):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+
+2010-10-21 MORITA Hajime <morrita@google.com>
+
+ Reviewed by Kent Tamura.
+
+ [Win][DRT] should have LayoutTestController.hasSpellingMarker()
+ https://bugs.webkit.org/show_bug.cgi?id=47885
+
+ - Implemented LayoutTestController.hasSpellingMarker(),
+ - Added fake spellcheck implementation.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main):
+ * DumpRenderTree/win/EditingDelegate.cpp:
+ (indexOfFirstWordCharacter):
+ (wordLength):
+ (EditingDelegate::checkSpellingOfString):
+ * DumpRenderTree/win/EditingDelegate.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::hasSpellingMarker):
+
+2010-10-21 Mihai Parparita <mihaip@chromium.org>
+
+ Unreviewed. Re-enable test that was mistakenly disabled by r67974.
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py:
+
+2010-10-21 Mihai Parparita <mihaip@chromium.org>
+
+ Unreviewed fix for rebaseline-chromium-webkit-tests.
+
+ Port.diff_image no longer has a tolerance parameter. Also, use
+ get_option('tolerance') which is safer if the options object doesn't
+ define a tolerance attribute (it doesn't for the one used in
+ rebaseline_chromium_webkit_tests).
+
+ * Scripts/webkitpy/layout_tests/port/port_testcase.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-10-21 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Add support for --tolerance in NRWT
+ https://bugs.webkit.org/show_bug.cgi?id=47959
+
+ Add support for the --tolerance flag in NRWT. The Port.diff_image
+ signature shouldn't need a tolerance parameter (it's not set per test),
+ just have ports that use it (currently only WebKitPort) read it from
+ the options object.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/port_testcase.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-10-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add --suggest-reviewers option to upload to auto-suggest reviewers for your patch
+ https://bugs.webkit.org/show_bug.cgi?id=48088
+
+ This is a first-pass. Works, but we'll eventually
+ turn this on by default, refine the suggestion algorithm
+ and possibly move it to a different place in the upload step order.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/__init__.py:
+ * Scripts/webkitpy/tool/steps/options.py:
+
+2010-10-21 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Chris Fleizach.
+
+ [GTK] Segfault while testing accessibility/iframe-bastardization.html
+ https://bugs.webkit.org/show_bug.cgi?id=30123
+
+ Check m_element before actually using it to get the parent.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::parentElement): Add an extra check to
+ make sure m_element points to a valid value before actually using
+ it to get the parent. Also, assert ATK_IS_OBJECT(m_element).
+
+2010-10-21 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Crash evaluating JavaScript string that throws an exception
+ https://bugs.webkit.org/show_bug.cgi?id=48092
+ <rdar://problem/8487657>
+
+ Add a test that evaluates a JavaScript string that throws an exception and check that
+ the callback is called.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2/EvaluateJavaScript.cpp: Added.
+ (TestWebKitAPI::didRunJavaScript):
+ (TestWebKitAPI::WebKit2_EvaluateJavaScript):
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj:
+
+2010-10-21 Adam Roben <aroben@apple.com>
+
+ Test that the plugin's HWND is invalidated when NPN_InvalidateRect is
+ called
+
+ Test for <http://webkit.org/b/48086> <rdar://problem/8482944>
+ Silverlight doesn't repaint in WebKit2
+
+ Reviewed by Anders Carlsson.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp:
+ (PluginTest::NPN_InvalidateRect): Added. Calls through to the browser.
+ (executeScript): Added. Asks the browser to evaluate the script.
+
+ (PluginTest::waitUntilDone):
+ (PluginTest::notifyDone):
+ Added. Calls through to layoutTestController.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.h: Added
+ * NPN_InvalidateRect and waitUntilDone/notifyDone.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/win/NPNInvalidateRectInvalidatesWindow.cpp: Added.
+ (TemporaryWindowMover::moveSucceeded):
+ (TemporaryWindowMover::TemporaryWindowMover):
+ (TemporaryWindowMover::~TemporaryWindowMover):
+ This class moves a window on-screen and shows it, then moves it back and hides it.
+
+ (NPNInvalidateRectInvalidatesWindow::NPNInvalidateRectInvalidatesWindow):
+ Initialize our members.
+ (NPNInvalidateRectInvalidatesWindow::~NPNInvalidateRectInvalidatesWindow):
+ Delete our window mover if it hasn't been deleted already.
+ (NPNInvalidateRectInvalidatesWindow::NPP_SetWindow): Subclass the
+ plugin HWND and move the test harness window on screen.
+ (NPNInvalidateRectInvalidatesWindow::wndProc): Call through to onPaint
+ when we get a WM_PAINT message.
+ (NPNInvalidateRectInvalidatesWindow::onPaint): Do the test and tell
+ LayoutTestController we're done.
+ (NPNInvalidateRectInvalidatesWindow::testInvalidateRect): Validate
+ ourselves, invalidate our lower-right quadrant via NPN_InvalidateRect,
+ then check that our HWND's invalid region is the rect that we
+ invalidated.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * Added NPNInvalidateRectInvalidatesWindow.
+
+2010-10-21 Daniel Bates <dbates@rim.com>
+
+ Add Git-support to do-file-rename
+ https://bugs.webkit.org/show_bug.cgi?id=48015
+
+ Fix tools. Export function scmMoveOrRenameFile so that it can be called from
+ do-file-rename and do-webcore-rename. I inadvertently left this out of the patch.
+
+ * Scripts/VCSUtils.pm:
+
+2010-10-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ mac-ews is not properly releasing patches
+ https://bugs.webkit.org/show_bug.cgi?id=48076
+
+ mac-ews overrides process_work_item, so it was not calling
+ release_work_item like the default process_work_item would.
+ To fix this I made all the status-reporting methods just
+ release the patch. I expect we'll iterate on this design further.
+
+ * Scripts/webkitpy/common/net/statusserver.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-10-18 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] mathml flaky tests after adding SystemFonts to the theme
+ https://bugs.webkit.org/show_bug.cgi?id=47727
+
+ The Fontconfig setup in the GTK+ now specifically checks for and
+ loads the STIX fonts for MathML tests.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (initializeFonts): Add hooks for loading the STIX fonts specifically.
+
+2010-10-20 Adam Roben <aroben@apple.com>
+
+ Test that the UI client gets notified when WKView receives a WM_CLOSE
+ message
+
+ Test for <http://webkit.org/b/48044> <rdar://problem/8488446> Pressing
+ Ctrl+W when viewing a full-page PDF destroys the WKView but doesn't
+ close its parent window
+
+ Reviewed by Jon Honeycutt.
+
+ * TestWebKitAPI/Tests/WebKit2/win/WMCloseCallsUIClientClose.cpp: Added.
+ (TestWebKitAPI::close): Record that this function was called.
+ (TestWebKitAPI::WebKit2_WMCloseCallsUIClientClose): Create a WKView,
+ send it a WM_CLOSE message, and test that the UI client's close
+ callback got called. Note that this will hang if the bug is
+ reintroduced; <http://webkit.org/b/48043> covers making TestWebKitAPI
+ able to handle hangs.
+
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj: Added the new test.
+
+2010-10-20 Adam Roben <aroben@apple.com>
+
+ Make prepare-ChangeLog much faster when using git
+
+ This change also seems to make it detect renames better in some cases.
+
+ Fixes <http://webkit.org/b/48040> prepare-ChangeLog is slow when using
+ git
+
+ Reviewed by David Kilzer.
+
+ * Scripts/prepare-ChangeLog:
+ (statusCommand):
+ (createPatchCommand):
+ Use "-M -C" instead of "-C -C -M" to tell git-diff to detect renames
+ and copies. The two "-C"s were making it read many more files than were
+ necessary.
+
+2010-10-21 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Null frame passed when running alert from UserScript run at document start
+ <rdar://problem/8573809>
+ https://bugs.webkit.org/show_bug.cgi?id=48036
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/InjectedBundleController.cpp:
+ (TestWebKitAPI::InjectedBundleController::didReceiveMessage):
+ (TestWebKitAPI::InjectedBundleController::initializeTestNamed):
+ * TestWebKitAPI/InjectedBundleController.h:
+ * TestWebKitAPI/InjectedBundleTest.h:
+ (TestWebKitAPI::InjectedBundleTest::initialize):
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp: Added.
+ (TestWebKitAPI::runJavaScriptAlert):
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp: Added.
+ (TestWebKitAPI::DocumentStartUserScriptAlertCrashTest::DocumentStartUserScriptAlertCrashTest):
+ (TestWebKitAPI::DocumentStartUserScriptAlertCrashTest::initialize):
+ Add test for invoking an alert during a UserScript run at document start.
+
+2010-10-21 Andreas Kling <kling@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ TestNetscapePlugIn: Actually call NPP_SetWindow on Unix
+
+ We were just returning NPERR_NO_ERROR previously.
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_set_window):
+
+2010-10-21 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/48051> Move macros from DumpRenderTreeMac.h to config.h
+
+ Reviewed by Adam Roben.
+
+ * DumpRenderTree/config.h: Moved macros to here...
+ * DumpRenderTree/mac/DumpRenderTreeMac.h: ...from here.
+ Addresses a FIXME comment from r28419.
+
+2010-10-21 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/48047> Fix warnings found by check-Xcode-source-file-types
+
+ Reviewed by Adam Roben.
+
+ Fixes the following warnings:
+
+ WARNING: Incorrect file type 'sourcecode.cpp.objcpp' for file 'PixelDumpSupport.cpp'.
+ WARNING: Incorrect file type 'sourcecode.cpp.objcpp' for file 'LayoutTestController.cpp'.
+ WARNING: Incorrect file type 'sourcecode.cpp.objcpp' for file 'WorkQueue.cpp'.
+ WARNING: Incorrect file type 'sourcecode.cpp.objcpp' for file 'cg/PixelDumpSupportCG.cpp'.
+ WARNING: Incorrect file type 'sourcecode.cpp.objcpp' for file 'GCController.cpp'.
+ 5 issues found for WebKitTools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ Removed explicit file type for *.cpp files above to make them
+ match other C++ source files. This exposed the fact that
+ DumpRenderTreeMac.h was not safe to include in C++ source, which
+ caused PixelDumpSupport.cpp and PixelDumpSupportCG.cpp to fail
+ to build.
+ * DumpRenderTree/PixelDumpSupport.cpp: Adjusted header order.
+ * DumpRenderTree/mac/DumpRenderTreeMac.h: Made safe to include
+ in C++ source files. Included CoreFoundation/CoreFoundation.h
+ to make sure all CF types were defined. Removed CFStringRef
+ typedef.
+
+2010-10-21 Adam Roben <aroben@apple.com>
+
+ Attempt to fix plugins/pass-different-npp-struct.html on GTK.
+
+ See <http://webkit.org/b/47690>.
+
+ * GNUmakefile.am: Added PassDifferentNPPStruct.cpp.
+
+2010-10-21 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [NRWT] Set ImageDiff path on Qt port
+ https://bugs.webkit.org/show_bug.cgi?id=48052
+
+ * Scripts/webkitpy/layout_tests/port/qt.py:
+
+2010-10-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Don't CC authors of flaky tests
+ https://bugs.webkit.org/show_bug.cgi?id=48038
+
+ Some authors found this too annoying. We'll look for another way to
+ close the flaky test loop.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-10-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue should run run-webkit-tests with --no-new-test-results
+ https://bugs.webkit.org/show_bug.cgi?id=47998
+
+ * Scripts/webkitpy/tool/steps/runtests.py:
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+
+2010-10-21 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Ojan Vafai.
+
+ [NRWT] Get child process number from an environment variable
+ https://bugs.webkit.org/show_bug.cgi?id=47981
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-20 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/47754> New script to verify explicit source file types in Xcode project files
+
+ Reviewed by Darin Adler.
+
+ The script parses an Xcode project file and makes sure the file
+ extension matches the explicit file type set for all source
+ files. Note that the majority of source files will have their
+ type set by Xcode, so the script doesn't check them since there
+ is no need to second-guess Xcode.
+
+ * Scripts/check-Xcode-source-file-types: Added. Code borrowed
+ heavily from sort-Xcode-project-file.
+
+2010-10-20 Adam Roben <aroben@apple.com>
+
+ Windows build fix
+
+ * TestWebKitAPI/win/PlatformUtilitiesWin.cpp: Added missing #include.
+
+2010-10-20 Adam Roben <aroben@apple.com>
+
+ Qt test fix
+
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro: Added
+ PassDifferentNPPStruct.cpp.
+
+2010-10-20 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Add ability to test injected bundle API using TestWebKitAPI
+ https://bugs.webkit.org/show_bug.cgi?id=48027
+
+ * TestWebKitAPI/InjectedBundleController.cpp: Added.
+ * TestWebKitAPI/InjectedBundleController.h: Added.
+ Shared main object for bundle functionality.
+
+ * TestWebKitAPI/InjectedBundleMain.cpp: Added.
+ Bundle entry point.
+
+ * TestWebKitAPI/InjectedBundleTest.h: Added.
+ Base class for which the bundle portion of a test derives from.
+
+ * TestWebKitAPI/PlatformUtilities.h:
+ * TestWebKitAPI/PlatformUtilities.cpp: Added.
+ * TestWebKitAPI/mac/PlatformUtilitiesMac.mm:
+ * TestWebKitAPI/win/PlatformUtilitiesWin.cpp:
+ (TestWebKitAPI::Util::createInjectedBundlePath):
+ (TestWebKitAPI::Util::createURLForResource):
+ (TestWebKitAPI::Util::URLForNonExistentResource):
+ Add helper to create a context with the shared injected bundle,
+ and send the initial message to set up the test.
+
+ * TestWebKitAPI/Configurations/InjectedBundle.xcconfig: Added.
+ * TestWebKitAPI/InjectedBundle-Info.plist: Added.
+ Add mac configuration files.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ Add the new files.
+
+ * TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic.cpp: Added.
+ * TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic_Bundle.cpp: Added.
+ Add a simple initial bundle test.
+
+2010-10-20 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Fixing /release-patch url used by the EWS bots.
+
+ EWS should test patches with r+
+ https://bugs.webkit.org/show_bug.cgi?id=35460
+
+ * Scripts/webkitpy/common/net/statusserver.py:
+ - I changed the URL during development, and 404s are
+ intentionally silenced during release_patch.
+
+2010-10-14 Adam Roben <aroben@apple.com>
+
+ Test that passing a different NPP struct back to the browser doesn't
+ cause an assertion failure
+
+ Test for <http://webkit.org/b/47690> <rdar://problem/8553020>
+ Assertion failure in NetscapePlugin::fromNPP when using Shockwave in
+ WebKit2
+
+ Reviewed by John Sullivan.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp: Copied from WebKitTools/DumpRenderTree/TestNetscapePlugIn/Tests/win/GetValueNetscapeWindow.cpp.
+ (PassDifferentNPPStruct::PassDifferentNPPStruct): Initialize our
+ members.
+ (PassDifferentNPPStruct::NPP_SetWindow): Pass a different NPP to the
+ browser than the one it gave us in NPP_New and see if it works.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ Added PassDifferentNPPStruct.
+
+2010-10-19 Adam Roben <aroben@apple.com>
+
+ Gently nudge old-run-webkit-tests toward working with Win32 Perl
+
+ This makes old-run-webkit-tests able to build DRT and find all the
+ tests to run. It even invokes DRT and passes it the list of tests. But
+ DRT ends up hung blocking on I/O.
+
+ Fixes <http://webkit.org/b/47961> Get old-run-webkit-tests mostly
+ working with Win32 Perl
+
+ Reviewed by David Kilzer.
+
+ * Scripts/old-run-webkit-tests:
+ - Use File::Spec instead of manually concatenating paths
+ - Use dirname instead of manually stripping off the base name
+ - Use isCygwin/isWindows/isAppleWinWebKit more judiciously
+ - Explicitly invoke Perl when running Perl scripts
+ - Quote paths when using them in regular expressions to allow them
+ to include characters that have special meanings in regular
+ expressions
+
+ * Scripts/run-webkit-tests: Use File::Spec instead of manually
+ concatenating paths.
+
+ * Scripts/webkitdirs.pm:
+ - Remove the unused $windowsTmpPath variable
+ - Use isCygwin/isWindows/isAppleWinWebKit more judiciously
+ - Only pass paths to cygpath when using Cygwin Perl
+ - Only use pdevenv when using Cygwin Perl, for now
+
+2010-10-20 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Martin Robinson.
+
+ Add Git-support to do-file-rename
+ https://bugs.webkit.org/show_bug.cgi?id=48015
+
+ Also, abstracts the SCM move/rename functionality in do-file-rename and
+ do-webcore-rename into a common function VCSUtils::scmMoveOrRenameFile().
+
+ Currently, do-file-rename is hard coded to assume the SCM is Subversion.
+ Instead, we should abstract the rename logic to be SCM-independent. This
+ will allow us to add Git support as well move such functionality into
+ our SCM library VCSUtils, where it can be shared by do-webcore-rename.
+
+ * Scripts/VCSUtils.pm:
+ - Added function scmMoveOrRenameFile.
+ * Scripts/do-file-rename: Modified to call VCSUtils::scmMoveOrRenameFile().
+ * Scripts/do-webcore-rename: Ditto.
+
+2010-10-20 Adam Roben <aroben@apple.com>
+
+ Fix old-run-webkit-tests when there's a space in the path to DRT
+
+ Reviewed by Jon Honeycutt.
+
+ * Scripts/old-run-webkit-tests: Quote the path to DRT before executing
+ it.
+
+2010-10-20 Kenneth Russell <kbr@google.com>
+
+ Reviewed by Dimitri Glazkov.
+
+ Regression in chromium_gpu_unittests after r70175
+ https://bugs.webkit.org/show_bug.cgi?id=48008
+
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py:
+
+2010-10-20 Kenneth Russell <kbr@google.com>
+
+ Reviewed by James Robinson.
+
+ chromium_gpu port of new-run-webkit-tests must do Linux -> Win expectations fallback
+ https://bugs.webkit.org/show_bug.cgi?id=48005
+
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+
+2010-10-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch doesn't get along with git rm
+ https://bugs.webkit.org/show_bug.cgi?id=47940
+
+ Turns out we need to pass "--" to tell git this is a path.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+
+2010-10-20 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] Fix layoutTestController.getJsObjectCount
+
+ Qt Bridge doesn't know size_t so pass result as unsigned int.
+
+ Unskip fast/dom/gc-10.html
+
+ https://bugs.webkit.org/show_bug.cgi?id=47931
+
+ * DumpRenderTree/qt/GCControllerQt.cpp:
+ (GCController::getJSObjectCount):
+ * DumpRenderTree/qt/GCControllerQt.h:
+
+2010-10-20 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r70149.
+ http://trac.webkit.org/changeset/70149
+ https://bugs.webkit.org/show_bug.cgi?id=47989
+
+ "Build breaks in mac and win" (Requested by satish on
+ #webkit).
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setMockSpeechInputResultCallback):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+
+2010-10-20 Leandro Gracia Gil <leandrogracia@google.com>
+
+ Reviewed by Jeremy Orlow.
+
+ Added a second parameter to setMockSpeechInputResult for
+ the language used in speech input.
+ https://bugs.webkit.org/show_bug.cgi?id=47089
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setMockSpeechInputResultCallback):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setMockSpeechInputResult):
+
+2010-10-19 Adam Roben <aroben@apple.com>
+
+ Teach update-webkit-support-libs about the new versioning of
+ WebKitSupportLibrary
+
+ Fixes <http://webkit.org/b/47915> update-webkit-support-libs should
+ check version numbers instead of modification times
+
+ Reviewed by Sam Weinig.
+
+ * Scripts/update-webkit-support-libs: Fetch the expected version
+ number from developer.apple.com, then compare with the version number
+ of the extracted library and of the zipped library to see if anything
+ needs to be done. Removed code that tracked the modified timestamp of
+ the library, as it is no longer needed.
+
+2010-10-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ EWS should test patches with r+
+ https://bugs.webkit.org/show_bug.cgi?id=35460
+
+ * QueueStatusServer/handlers/submittoews.py:
+ * QueueStatusServer/model/queues.py:
+ * Scripts/webkitpy/tool/bot/patchcollection.py: Removed.
+ * Scripts/webkitpy/tool/bot/patchcollection_unittest.py: Removed.
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-10-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Teach feeder-queue how to feed the EWS bots
+ https://bugs.webkit.org/show_bug.cgi?id=47943
+
+ queues.webkit.org already knew how to accept EWS submissions
+ via /submit-to-ews. This teaches the feeder queue how to post
+ to that page with any new r? patches it sees.
+
+ * QueueStatusServer/model/activeworkitems_unitest.py: Added.
+ - More unit testing is always a good thing.
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/statusserver.py:
+ * Scripts/webkitpy/tool/bot/feeders.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-10-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, just fixing test-webkitpy. I'm really on a roll today.
+
+ commit-queue gets stuck when release-patch returns 404
+ https://bugs.webkit.org/show_bug.cgi?id=47935
+
+ Fix test-webkitpy and unittest NetworkTransaction.
+
+ * Scripts/webkitpy/common/net/networktransaction.py:
+ * Scripts/webkitpy/common/net/networktransaction_unittest.py:
+
+2010-10-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed.
+
+ commit-queue gets stuck when release-patch returns 404
+ https://bugs.webkit.org/show_bug.cgi?id=47935
+
+ Turns out ClientForm gets upset if passed an int() instead of a string type.
+ Yay for untestable code.
+
+ * Scripts/webkitpy/common/net/statusserver.py:
+
+2010-10-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Will get Adam's commentary after his meeting
+ for now this gets the commit-cluster back running.
+
+ commit-queue gets stuck when release-patch returns 404
+ https://bugs.webkit.org/show_bug.cgi?id=47935
+
+ I taught NetworkTransaction the basics of 404 handling.
+ We'll want to go back and teach it how to handle urllib2 404's too
+ and then deploy it to the places that want it.
+
+ * QueueStatusServer/handlers/releasepatch.py:
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/networktransaction.py:
+ * Scripts/webkitpy/common/net/statusserver.py:
+
+2010-10-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Fixing typos in my previous commit.
+
+ Make patch release explicit and not a magic part of "retry" status
+ https://bugs.webkit.org/show_bug.cgi?id=47909
+
+ All of these typos again due to our inability to unit
+ test much of this code. I added one unit test where
+ possible. activeworkitems_unittest.py will be in a separate patch.
+
+ * QueueStatusServer/handlers/releasepatch.py:
+ * QueueStatusServer/main.py:
+ * QueueStatusServer/model/activeworkitems.py:
+ * QueueStatusServer/model/workitems.py:
+ * QueueStatusServer/model/workitems_unittest.py:
+ * QueueStatusServer/templates/releasepatch.html:
+ * Scripts/webkitpy/common/net/statusserver.py:
+
+2010-10-19 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] Use webkit's TestNetscapePlugIn in DRT mac
+ https://bugs.webkit.org/show_bug.cgi?id=47850
+
+ * DumpRenderTree/chromium/TestNetscapePlugIn/Info.plist: Added. Forked
+ because we're going to name our plugin WebKitTestNetscapePlugIn
+ temporarily until the chromium forked plugin goes away.
+
+2010-10-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make patch release explicit and not a magic part of "retry" status
+ https://bugs.webkit.org/show_bug.cgi?id=47909
+
+ This moves us another step closer to running r+ patches on the EWS bots.
+ Currently all bots just spam /update-work-items with their list of current
+ work items. queues.webkit.org uses that data for display. As part of making
+ the EWS run r+ patches, we're moving the official list of patches-to-process
+ into the server, and feeding them out to bots one at a time. We need to be
+ able to remove patches from the queues one at a time instead of just spamming
+ /update-work-items with a new complete list. That's what this patch adds.
+
+ * QueueStatusServer/handlers/nextpatch.py:
+ * QueueStatusServer/handlers/queuestatus.py:
+ * QueueStatusServer/handlers/releasepatch.py: Added.
+ * QueueStatusServer/handlers/statusbubble_unittest.py:
+ - Fix a typo causing test failure. This was not caught by the bots
+ because they don't have AppEngineLauncher installed and thus don't run
+ the QueueStatusServer tests.
+ * QueueStatusServer/handlers/updatestatus.py:
+ * QueueStatusServer/model/activeworkitems.py:
+ * QueueStatusServer/templates/releasepatch.html: Added.
+ * Scripts/webkitpy/common/net/statusserver.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-10-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ cr-mac bubble has caused status bubbles to wrap
+ https://bugs.webkit.org/show_bug.cgi?id=47928
+
+ We now have too many EWSes to fit in the bugs.webkit.org
+ status-bubble iframe when more than a couple EWS builds are pending.
+ To fix this I've reduced the space taken up by queue position,
+ and also moved cr-mac to the end of the list (since it's going to be
+ triple-digits for a while).
+
+ * QueueStatusServer/model/queues.py:
+ * QueueStatusServer/templates/statusbubble.html:
+
+2010-10-19 Kenneth Russell <kbr@google.com>
+
+ Reviewed by David Levin.
+
+ chromium_gpu port of new-run-webkit-tests must search chromium-gpu directory for expectations
+ https://bugs.webkit.org/show_bug.cgi?id=47874
+
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py:
+
+2010-10-19 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] DumpRenderTree shouldn't put '.' in include path
+ https://bugs.webkit.org/show_bug.cgi?id=47877
+
+ Fix include paths.
+
+ * DumpRenderTree/chromium/AccessibilityController.cpp:
+ * DumpRenderTree/chromium/AccessibilityUIElement.cpp:
+ * DumpRenderTree/chromium/AccessibilityUIElement.h:
+ * DumpRenderTree/chromium/CppBoundClass.cpp:
+ * DumpRenderTree/chromium/CppVariant.cpp:
+ * DumpRenderTree/chromium/CppVariant.h:
+ * DumpRenderTree/chromium/DRTDevToolsAgent.cpp:
+ * DumpRenderTree/chromium/DRTDevToolsAgent.h:
+ * DumpRenderTree/chromium/DRTDevToolsCallArgs.h:
+ * DumpRenderTree/chromium/DRTDevToolsClient.cpp:
+ * DumpRenderTree/chromium/DRTDevToolsClient.h:
+ * DumpRenderTree/chromium/EventSender.cpp:
+ * DumpRenderTree/chromium/EventSender.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/MockSpellCheck.cpp:
+ * DumpRenderTree/chromium/NotificationPresenter.cpp:
+ * DumpRenderTree/chromium/NotificationPresenter.h:
+ * DumpRenderTree/chromium/PlainTextController.cpp:
+ * DumpRenderTree/chromium/Task.cpp:
+ * DumpRenderTree/chromium/TestNavigationController.h:
+ * DumpRenderTree/chromium/TestShell.cpp:
+ * DumpRenderTree/chromium/TestWebWorker.h:
+ * DumpRenderTree/chromium/TextInputController.cpp:
+ * DumpRenderTree/chromium/WebPreferences.cpp:
+ * DumpRenderTree/chromium/WebPreferences.h:
+ * DumpRenderTree/chromium/WebThemeEngineDRT.cpp:
+ * DumpRenderTree/chromium/WebThemeEngineDRT.h:
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-10-19 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ Need to include WKErrorRef in the WKPageDidFail... functions
+ https://bugs.webkit.org/show_bug.cgi?id=47871
+
+ Update tools for new parameter in failure callbacks.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (didFailProvisionalLoadWithErrorForFrame):
+ (didFailLoadWithErrorForFrame):
+ (-[BrowserWindowController updateProvisionalURLForFrame:]):
+ * TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp:
+ (TestWebKitAPI::didFailProvisionalLoadWithErrorForFrame):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame):
+ (WTR::InjectedBundlePage::didFailLoadWithErrorForFrame):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+
+2010-10-19 Luiz Agostini <luiz.agostini@openbossa.org>
+
+ Reviewed by Antti Koivisto.
+
+ [Qt] WebKit2 MacOS build fix
+ https://bugs.webkit.org/show_bug.cgi?id=47897
+
+ Qt WebKit2 MacOS build fix.
+
+ * WebKitTestRunner/PlatformWebView.h:
+ * WebKitTestRunner/qt/TestControllerQt.cpp:
+
+2010-10-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch stats the filesystem too many times
+ https://bugs.webkit.org/show_bug.cgi?id=47883
+
+ This patch attempts to cache the list of changed files more agressively
+ and to use that list to compute the diff instead of stating the file
+ system again.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ * Scripts/webkitpy/tool/steps/editchangelog.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+
+2010-10-19 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/47741> Make sort-Xcode-project-file a little more friendly
+
+ Reviewed by Darin Adler.
+
+ * Scripts/sort-Xcode-project-file:
+ - Don't print an error message about missing arguments when
+ -h|--help is used.
+ - Allow Xcode project files to be specified as Project.xcodeproj
+ instead of Project.xcodeproj/project.pbxproj.
+
+2010-10-18 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] QtTestBrowser: Prevent calling load() directly from loadFinished() in robot mode.
+ https://bugs.webkit.org/show_bug.cgi?id=47809
+
+ Connecting a call to load from the loadFinished signal can cause
+ re-entrance crashes in WebCore. This patch uses a timer to do so,
+ also giving some time to subsequent frames to finish loading.
+
+ * QtTestBrowser/urlloader.cpp:
+ (UrlLoader::UrlLoader):
+ (UrlLoader::loadNext):
+ (UrlLoader::checkIfFinished):
+ (UrlLoader::frameLoadStarted):
+ (UrlLoader::frameLoadFinished):
+ * QtTestBrowser/urlloader.h:
+
+2010-10-19 Sergio Villar Senín <svillar@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] http/history tests are failing
+ https://bugs.webkit.org/show_bug.cgi?id=36173
+
+ Clear the history each time a test is run. Return the actual
+ history item count when calling
+ LayoutTestController::webHistoryItemCount
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::webHistoryItemCount):
+
+2010-10-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add Chromium Mac EWS to the list of queues at queues.webkit.org
+ https://bugs.webkit.org/show_bug.cgi?id=47878
+
+ * QueueStatusServer/model/queues.py:
+
+2010-10-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ queues.webkit.org/next_patch is always 404
+ https://bugs.webkit.org/show_bug.cgi?id=47881
+
+ With the addition of the Queue class, I changed most of the
+ code to lookup WorkItems using get_or_insert with a key_name
+ instead of WorkItems.all().filter(queue_name=).
+ Because the new get_or_insert code uses an explicit key_name
+ (which is obviously different from the previously autogenerated
+ ones), there were new WorkItem records created for each queue.
+ However, some parts of the code still use WorkItems.all().filter,
+ thus some parts were getting the new record and some parts the old record.
+
+ The same basic bug was occurring with ActiveWorkItems, because I
+ changed the key_name for that class as well.
+
+ To fix this I've moved more of the code over to using Queue.*work_items.
+ I've also enabled the datastore_admin (new in GAE 1.3.8) so that
+ we can go delete the old WorkItems records.
+ I also changed remote_api to use the new builtin: syntax (also added in GAE 1.3.8).
+
+ * QueueStatusServer/app.yaml:
+ * QueueStatusServer/handlers/queuestatus.py:
+ * QueueStatusServer/handlers/recentstatus.py:
+ * QueueStatusServer/handlers/updatestatus.py:
+ * QueueStatusServer/handlers/updateworkitems.py:
+
+2010-10-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Correct a bunch of typos in QueueStatusServer
+ https://bugs.webkit.org/show_bug.cgi?id=47880
+
+ These are all due to our complete lack of unit testing in QueueStatusServer.
+ I added a couple unit tests to cover a few of these fixes, but most of these
+ are still only caught by actually running the application.
+
+ * QueueStatusServer/handlers/nextpatch.py:
+ * QueueStatusServer/handlers/statusbubble.py:
+ * QueueStatusServer/handlers/statusbubble_unittest.py: Added.
+ * QueueStatusServer/handlers/updateworkitems.py:
+ * QueueStatusServer/model/attachment.py:
+ * QueueStatusServer/model/queuepropertymixin.py:
+ * QueueStatusServer/model/queuepropertymixin_unittest.py:
+ * QueueStatusServer/model/workitems.py:
+ * QueueStatusServer/model/workitems_unittest.py: Added.
+
+2010-10-18 Adam Barth <abarth@webkit.org>
+
+ Disable this test because it's failing on the bots and the authors
+ aren't around to fix it.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-10-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ CC authors of flaky tests when the commit-queue hits a flaky test
+ https://bugs.webkit.org/show_bug.cgi?id=47872
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/net/layouttestresults.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-10-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make it possible to run a chromium-mac-ews builder
+ https://bugs.webkit.org/show_bug.cgi?id=47876
+
+ Since we can't run Mac OS X in a VM, we need to only run committer patches.
+ There was a multiple inheritance problem which was holding this patch back,
+ but I decided to just ignore the problem and go with a functional hack for now.
+
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+
+2010-10-18 Kenneth Russell <kbr@google.com>
+
+ Reviewed by Tony Chang.
+
+ Regression in run_webkit_tests_unittest from r70017
+ https://bugs.webkit.org/show_bug.cgi?id=47875
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-10-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Implement webkit-patch suggest-reviewers
+ https://bugs.webkit.org/show_bug.cgi?id=47866
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ - The main logic. We look at the last five changes to each
+ modified (non-ChangeLog) file and collect up the reviewers of
+ those changes as well as the authors of those changes who are
+ reviewers.
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+ - Test the logic with some fun mocks.
+ * Scripts/webkitpy/common/checkout/scm.py:
+ - Fix a bug when you have local git commits.
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ - Test that the bug is fixed.
+ * Scripts/webkitpy/tool/commands/queries.py:
+ - Add the query.
+
+2010-10-18 Kenneth Russell <kbr@google.com>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests produces corrupt PNG baselines on Windows
+ https://bugs.webkit.org/show_bug.cgi?id=47867
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+
+2010-10-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make it possible to submit patches to the EWS bots
+ https://bugs.webkit.org/show_bug.cgi?id=47869
+
+ * QueueStatusServer/handlers/nextpatch.py:
+ - Move more logic into Queue, so that it can be shared with SubmitToEWS.
+ * QueueStatusServer/handlers/queuestatus.py:
+ - Fix two typos from a previous commit.
+ * QueueStatusServer/handlers/submittoews.py: Added.
+ * QueueStatusServer/handlers/updatestatus.py:
+ - Use the new is_retry_request method to share this (hacky) code with SubmitToEWS
+ * QueueStatusServer/main.py:
+ - Add /submit-to-ews
+ * QueueStatusServer/model/queuepropertymixin.py:
+ - Fix circular imports caused by adding Queue.work_items()
+ * QueueStatusServer/model/queues.py:
+ - Add work_items() and active_work_items()
+ * QueueStatusServer/model/queuestatus.py:
+ * QueueStatusServer/model/workitems.py:
+ - Add transaction-safe add/remove methods.
+ * QueueStatusServer/templates/submittoews.html: Added.
+
+2010-10-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Deploy Queue class in more places throughout QueueStatusServer
+ https://bugs.webkit.org/show_bug.cgi?id=47855
+
+ I also caught two typos from the previous change. Unfortunately
+ I don't yet know how to unittest request handlers yet.
+
+ * QueueStatusServer/handlers/dashboard.py:
+ * QueueStatusServer/handlers/statusbubble.py:
+ * QueueStatusServer/handlers/updateworkitems.py:
+ * QueueStatusServer/model/activeworkitems.py:
+ * QueueStatusServer/model/attachment.py:
+ * QueueStatusServer/model/queuepropertymixin.py: Added.
+ * QueueStatusServer/model/queuepropertymixin_unittest.py: Added.
+ * QueueStatusServer/model/queuestatus.py:
+ * QueueStatusServer/model/workitems.py:
+
+2010-10-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ scm.py should be able tell us what revisions made changes to a given file
+ https://bugs.webkit.org/show_bug.cgi?id=47863
+
+ Look again, your SCM.py can now log files.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+
+2010-10-18 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Siedel.
+
+ new-run-webkit-tests: clean up the options-parsing code in the port
+ classes.
+
+ This change modifies the Port interface to have a get_option() and
+ set_option_default() method for accessing the options argument
+ passed to the constructor. If the constructor is not passed an
+ options argument, we default to a MockOptions() argument from
+ mocktool, which has the same semantics we want.
+
+ Note that there is a disadvantage to port.get_option('foo') over
+ port._options.foo, which is that you lose some of the checking
+ for whether 'foo' is set (typos result in the default value, not
+ an exception being raised. This is desired in this case, since the
+ Port class is not allowed to assume that options does have any
+ particular values set, and so this change ensures that all of
+ the subclasses are following the same, intended, logic.
+
+ Arguably this is the wrong semantics to have, and the Port
+ classes should be able to assume a default set of
+ attributes/arguments, but that change will need to wait for a
+ different CL where we can modify new-run-webkit-tests to pull a
+ list of arguments from the port factory routines.
+
+ Also, add unit tests for webkitpy.tool.mocktool.MockOptions .
+
+ https://bugs.webkit.org/show_bug.cgi?id=47510
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+ * Scripts/webkitpy/layout_tests/port/factory_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/mac_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/port_testcase.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py:
+ * Scripts/webkitpy/tool/mocktool_unittest.py: Added.
+
+2010-10-18 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Re-submit a revised version of r69638 - enabling new-run-webkit-tests
+ under cygwin. The initial version had a bug in base:uri_to_test_name
+ that was causing tests to fail. This version corrects that bug, but
+ also makes the code safer by calling cygpath more reliably, and
+ leaving a long-running cygpath process open.
+
+ This patch also corrects a couple of minor bugs in http_lock_unittest,
+ chromium_unittest, and dedpulicate_tests_unittest that showed up
+ while testing this.
+
+ https://bugs.webkit.org/show_bug.cgi?id=47220
+
+ * Scripts/webkitpy/common/system/path.py:
+ * Scripts/webkitpy/common/system/path_unittest.py:
+ * Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/http_lock_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add Queue class and add minimal unittesting of QueueStatusServer code
+ https://bugs.webkit.org/show_bug.cgi?id=47847
+
+ * QueueStatusServer/handlers/dashboard.py:
+ * QueueStatusServer/handlers/queuestatus.py:
+ * QueueStatusServer/handlers/recentstatus.py:
+ * QueueStatusServer/handlers/statusbubble.py:
+ * QueueStatusServer/handlers/updateworkitems.py:
+ * QueueStatusServer/model/attachment.py:
+ * QueueStatusServer/model/queues.py:
+ * QueueStatusServer/model/queues_unittest.py: Added.
+ * QueueStatusServer/model/svnrevision.py:
+ * Scripts/test-webkitpy:
+ * Scripts/webkitpy/test/main.py:
+
+2010-10-18 Anders Carlsson <andersca@apple.com>
+
+ Fix build.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (handleEventCarbon):
+
+2010-10-18 Stuart Morgan <stuartmorgan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Switch to using the new Carbon NPAPI event declarations, and remove
+ the old ones.
+
+ https://bugs.webkit.org/show_bug.cgi?id=40784
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (handleEventCarbon):
+
+2010-10-18 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ check-webkit-style should treat the GObject binding directory like other GTK directories.
+ https://bugs.webkit.org/show_bug.cgi?id=47796
+
+ * Scripts/webkitpy/style/checker.py: Added the GObject binding directory
+ with the other gtk directories (and fixed typo).
+
+2010-10-18 David Levin <levin@chromium.org>
+
+ Reviewed by Oliver Hunt.
+
+ check-webkit-style needs to ignore underscores in opcode names and vm_throw
+ https://bugs.webkit.org/show_bug.cgi?id=47789
+
+ * Scripts/webkitpy/style/checker.py: Added the exception for the assembler directory.
+ * Scripts/webkitpy/style/checkers/cpp.py: Added special cased names.
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py: Added unit tests for the special cases.
+
+2010-10-18 MORITA Hajime <morrita@google.com>
+
+ Reviewed by Kent Tamura.
+
+ TextInputController.hasSpellingMarkers() should be owned by LayoutTestController
+ https://bugs.webkit.org/show_bug.cgi?id=47659
+
+ Moved hasSpellingMarkers() from TextInputController to
+ LayoutTestController. Currently the implementation is available
+ only for Mac and for Chromium.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (hasSpellingMarkerCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::hasSpellingMarker):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/TextInputController.cpp:
+ (TextInputController::TextInputController):
+ (TextInputController::makeAttributedString):
+ * DumpRenderTree/chromium/TextInputController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::hasSpellingMarker):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::hasSpellingMarker):
+ * DumpRenderTree/mac/TextInputController.m:
+ (+[TextInputController isSelectorExcludedFromWebScript:]):
+ (+[TextInputController webScriptNameForSelector:]):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::hasSpellingMarker):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::hasSpellingMarker):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::hasSpellingMarker):
+
+2010-10-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by David Levin.
+
+ commit-queue's flaky test notice is very Pythony
+ https://bugs.webkit.org/show_bug.cgi?id=47790
+
+ This patch make the list of tests delimted by \n instead of just
+ converting the array to a string.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-10-14 Antonio Gomes <agomes@rim.com>
+
+ Reviewed by Martin Robinson and Xan Lopez.
+
+ [Gtk]: DRT does not support frame flattening testing
+ https://bugs.webkit.org/show_bug.cgi?id=38650
+
+ Implement DRT's support for toggling on/off frame flattening
+ support.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setFrameFlatteningEnabled):
+
+2010-10-15 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Siedel.
+
+ mocktool.MockOptions is inheriting from Mock, which has the side
+ effect of defaulting any attribute to another MockObject. So,
+ MockOptions().foo would always evaluate to true. This was
+ covering over bugs in the unit tests, and is probably the wrong
+ default behavior for anything attempting to mock out the options
+ argument returned from optparse.parse_args().
+
+ This patch changes the default behavior. The new MockOptions()
+ class takes an optional list of keyword parameters to set; this
+ patch doesn't use that feature but the fix for bug 47510 will.
+
+ Also, this patch just fills in the default values necessary to
+ get all of the tests to pass; I didn't stare at each test by
+ hand to determine the "right" values. We can either fix that in
+ subsequent patches or let me know if we want to do that now (and
+ give me some guidance on what those values might want to be).
+
+ https://bugs.webkit.org/show_bug.cgi?id=47709
+
+ * Scripts/webkitpy/tool/commands/commandtest.py:
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittest.py:
+
+2010-10-15 Simon Fraser <simon.fraser@apple.com>
+
+ Fix the build; need to add new slot to PageUIClient callbacks.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ (WTR::TestController::initialize):
+
+2010-10-15 Simon Fraser <simon.fraser@apple.com>
+
+ Add Matt Delaney to committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-10-15 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] compile TestNetscapePlugIn on Chromium mac
+ https://bugs.webkit.org/show_bug.cgi?id=47633
+
+ * DumpRenderTree/DumpRenderTree.gypi: files to compile
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp: Use ifdef because gcc was complaining
+ (NP_GetEntryPoints):
+ (NPP_New):
+ (NPP_Destroy):
+ (NPP_HandleEvent):
+ (NPP_GetValue):
+ * DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h: Added.
+ * DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h: Added.
+ * DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h: Added.
+
+2010-10-15 Leandro Pereira <leandro@profusion.mobi>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ build-webkit: Should die when make fails when build a CMake project
+ https://bugs.webkit.org/show_bug.cgi?id=47726
+
+ * Scripts/webkitdirs.pm: If make fails, die immediately.
+
+2010-10-15 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r69809.
+ http://trac.webkit.org/changeset/69809
+ https://bugs.webkit.org/show_bug.cgi?id=47725
+
+ Broke chromium mac compile (Requested by japhet on #webkit).
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NP_GetEntryPoints):
+ (NPP_New):
+ (NPP_Destroy):
+ (NPP_HandleEvent):
+ (NPP_GetValue):
+ * DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h: Removed.
+ * DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h: Removed.
+ * DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h: Removed.
+
+2010-10-15 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ test-webkitpy fails on Linux
+ https://bugs.webkit.org/show_bug.cgi?id=47713
+
+ The old code failed on Linux because the MacPort tries to read
+ something out of platform that doesn't make sense on Linux.
+
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-10-14 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] WTR is sloooow
+ https://bugs.webkit.org/show_bug.cgi?id=47695
+
+ * WebKitTestRunner/qt/TestControllerQt.cpp:
+ Change the timer interval of RunUntilConditionLoop from
+ 50 milliseconds to 1 to avoid wasting time after the
+ test had been finished.
+
+2010-10-14 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, just fixing an exception seen on the commit-queue.
+
+ I should have unit tested this function before.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-10-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue should not fail patches due to flaky tests
+ https://bugs.webkit.org/show_bug.cgi?id=47647
+
+ This patch makes it so that the *same* flaky test has to fail
+ twice in a row to have a false negative from a flaky test.
+
+ If different flaky tests fail (or if a test fails and then passes
+ in a second run) then we will warn in the bug that we encountered
+ a flaky test.
+
+ This patch grew to include moving port off of steps onto tool
+ (which Adam wrote and then I integrated), as well as removing the
+ use of tool from CommitQueueTask.
+
+ * Scripts/webkitpy/common/config/ports.py:
+ - Added a layout_test_results_path method. This covers old-run-webkit-tests
+ but doesn't cover NRWT. This is probably not the long term solution, but
+ putting this knowledge on port makes more sense than in LayoutTestResults.
+ * Scripts/webkitpy/common/net/buildbot.py:
+ - LayoutTestResults shouldn't know how to fetch from the network, make
+ the Build code do that instead.
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+ - Code style fix.
+ * Scripts/webkitpy/common/net/layouttestresults.py:
+ - Remove code for reading from the network.
+ * Scripts/webkitpy/common/net/layouttestresults_unittest.py:
+ - Test the new entrypoint.
+ * Scripts/webkitpy/tool/bot/commitqueuetask.py:
+ - Make the delegate interface explicit.
+ - Remove the _tool member, since using the delegate for
+ everything is cleaner.
+ - Teach the testing logic how to deal with flaky tests.
+ * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py:
+ - Update to match the CommitQueueTask changes.
+ * Scripts/webkitpy/tool/commands/queues.py:
+ - Use the new CommitQueueTaskDelegate interface.
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ - Fix the SecondThoughtsCommitQueue test which was broken.
+ - Add a new test to make sure the flaky test reporting works.
+ * Scripts/webkitpy/tool/main.py:
+ - Store the port on the tool object.
+ * Scripts/webkitpy/tool/mocktool.py:
+ - Add a port() accessor to MockTool
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ - Move port() off of Step and onto Tool.
+ * Scripts/webkitpy/tool/steps/build.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+ * Scripts/webkitpy/tool/steps/runtests.py:
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ - Two tests with the same name! only the latter was being run.
+ * Scripts/webkitpy/tool/steps/update.py:
+
+2010-10-14 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests will now handle missing Ruby installs (or
+ missing PrettyPatch scripts) more cleanly - previously this
+ would be detected when we actually tried to create the diff, and
+ the error message was obscure. Now we'll log a warning up front
+ and otherwise be silent.
+
+ This change also refactors some global variables to be class or
+ instance variables to be slightly more testable and more
+ modular. There are no cases where we create lots of port objects
+ and can't afford to test for configurations repeatedly, so
+ there's no performance concern here.
+
+ https://bugs.webkit.org/show_bug.cgi?id=47466
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-10-08 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Form controls do not respect GTK+ font size
+ https://bugs.webkit.org/show_bug.cgi?id=47134
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (initializeGtkFontSettings): Initialize the font control size when running
+ DumpRenderTree to a standard value.
+
+2010-10-14 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] compile TestNetscapePlugIn on Chromium mac
+ https://bugs.webkit.org/show_bug.cgi?id=47633
+
+ * DumpRenderTree/DumpRenderTree.gypi: files to compile
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp: Use ifdef because gcc was complaining
+ (NP_GetEntryPoints):
+ (NPP_New):
+ (NPP_Destroy):
+ (NPP_HandleEvent):
+ (NPP_GetValue):
+ * DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npapi.h: Added.
+ * DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npfunctions.h: Added.
+ * DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h: Added.
+
+2010-10-14 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Nate Chapin.
+
+ [Chromium] Fix rebaseline_chromium_webkit_tests to use 0 tolerance image diff.
+
+ https://bugs.webkit.org/show_bug.cgi?id=47686
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-10-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ test-webkitpy spews Delegate terminated queue messages
+ https://bugs.webkit.org/show_bug.cgi?id=47678
+
+ * Scripts/webkitpy/tool/bot/queueengine_unittest.py:
+
+2010-10-14 Adam Roben <aroben@apple.com>
+
+ Test that pressing the Alt key generates a WM_SYSCOMMAND message
+
+ Test for <http://webkit.org/b/47671> <rdar://problem/8435594> Pressing
+ the Alt key when MiniBrowser's WKView is focused doesn't send focus to
+ the menu bar
+
+ Reviewed by Steve Falkenburg.
+
+ * TestWebKitAPI/Configurations/TestWebKitAPICommon.vsprops: Added
+ TestWebKitAPI/win to the include path so that WindowMessageObserver
+ can be found.
+
+ * TestWebKitAPI/PlatformWebView.h: Added simulateAltKeyPress and
+ Windows-specific members.
+ (TestWebKitAPI::PlatformWebView::setParentWindowMessageObserver):
+ Added this simple setter.
+
+ * TestWebKitAPI/Tests/WebKit2/win/AltKeyGeneratesWMSysCommand.cpp: Added.
+ (TestWebKitAPI::WMSysCommandObserver::WMSysCommandObserver):
+ Initialize our lone data member.
+ (TestWebKitAPI::WMSysCommandObserver::windowDidReceiveWMSysCommand):
+ Simple getter.
+ (TestWebKitAPI::WMSysCommandObserver::windowReceivedMessage): Record
+ when a WM_SYSCOMMAND message is received.
+ (TestWebKitAPI::didNotHandleKeyEventCallback): Record when a
+ WM_SYSKEYUP message is not handled.
+ (TestWebKitAPI::WebKit2_AltKeyGeneratesWMSysCommand): Simulate
+ pressing the Alt key and check that a WM_SYSCOMMAND message got sent
+ to the WKView's parent window.
+
+ * TestWebKitAPI/win/PlatformWebViewWin.cpp:
+ (TestWebKitAPI::PlatformWebView::registerWindowClass): Made this a
+ member function so it could access PlatformWebView::wndProc. Use
+ PlatformWebView::wndProc as the WNDPROC.
+ (TestWebKitAPI::PlatformWebView::PlatformWebView): Initialize our new
+ data member and pass the this pointer to CreateWindowEx so we can
+ store it on the HWND.
+ (TestWebKitAPI::PlatformWebView::simulateSpacebarKeyPress): Moved some
+ constants from here to the top of the file.
+ (TestWebKitAPI::PlatformWebView::simulateAltKeyPress): Added. Sends
+ the same messages that Notepad receives when you press the Alt key.
+ (TestWebKitAPI::PlatformWebView::wndProc): Added.
+ - When WM_CREATE is received, we set the PlatformWebView instance
+ pointer as a property on the HWND so we can access it later.
+ - For other messages, we try to get the PlatformWebView instance
+ pointer from the HWND property.
+ - When WM_NCDESTROY is received (which is the last message we will
+ receive), we remove the PlatformWebView instance property.
+ - Pass messages to the parent window's message observer, if there is
+ one.
+ - Pass all messages through to ::DefWindowProcW.
+
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj: Added WindowMessageObserver
+ and AltKeyGeneratesWMSysCommand.
+
+ * TestWebKitAPI/win/WindowMessageObserver.h: Added. This class can be
+ used to observe messages sent to one or more windows.
+
+2010-10-01 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Holger Freyther.
+
+ [GTK] REGRESSION: FreeType backend does not respect XSettings font settings after r68558
+ https://bugs.webkit.org/show_bug.cgi?id=47033
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (initializeGtkFontSettings): Added this method which initializes XSettings
+ font settings to consistent values before running a test. For the one test
+ in which we need subpixel aliasing turned on, do that.
+ (initializeFonts): Accepts a testURL parameter now and delegates to initializeGtkFontSettings.
+ (runTest): Pass the testURL to initializeFonts.
+
+2010-10-14 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ ChromiumXVFBPort.run_webkit_tests_command has infinite recursion
+ https://bugs.webkit.org/show_bug.cgi?id=47655
+
+ * Scripts/webkitpy/common/config/ports.py:
+ * Scripts/webkitpy/common/config/ports_unittest.py:
+
+2010-10-13 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ beat diff_parser with the ugly stick
+ https://bugs.webkit.org/show_bug.cgi?id=47626
+
+ * Scripts/webkitpy/common/checkout/diff_parser.py:
+ * Scripts/webkitpy/style/patchreader.py:
+ * Scripts/webkitpy/style/patchreader_unittest.py:
+
+2010-10-13 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Break LayoutTestResults out into its own file
+ https://bugs.webkit.org/show_bug.cgi?id=47637
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+ * Scripts/webkitpy/common/net/layouttestresults.py: Added.
+ * Scripts/webkitpy/common/net/layouttestresults_unittest.py: Added.
+
+2010-10-13 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Chromium port can't run JavaScriptCore tests
+ https://bugs.webkit.org/show_bug.cgi?id=47654
+
+ This lets webkit-patch build-and-test work on Chromium.
+
+ * Scripts/webkitpy/common/config/ports.py:
+ * Scripts/webkitpy/tool/steps/runtests.py:
+
+2010-10-13 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Make --port a global option and pass the port information to the commit-queue subprocess
+ https://bugs.webkit.org/show_bug.cgi?id=47650
+
+ This patch paves the way to run the commit-queue on a non-Mac port.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/steps/options.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+ * Scripts/webkitpy/tool/steps/runtests.py:
+ * Scripts/webkitpy/tool/steps/update.py:
+
+2010-10-13 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Introduce the ChromiumXVFBPort for running commit-queue on EC2
+ https://bugs.webkit.org/show_bug.cgi?id=47653
+
+ I'm not entirely sure this is the best way to do this, but we need to
+ run the tests under XVFB on EC2 because the EC2 instances don't have a
+ real monitor hooked up. This patch adds a ChromiumXVFBPort that runs
+ that way. The idea is that XVFB is like a platform for the Chromium
+ port, but we don't have a real notion of platform separate from port.
+
+ * Scripts/webkitpy/common/config/ports.py:
+
+2010-10-13 Sergio Villar Senin <svillar@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Add HTTP caching support
+ https://bugs.webkit.org/show_bug.cgi?id=44261
+
+ Add include paths for the new soup HTTP cache code.
+
+ * GNUmakefile.am: Add paths for the new soup HTTP cache code.
+
+2010-10-13 Yi Shen <yi.4.shen@nokia.com>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] QtTestBrowser shows two Url input fields
+ https://bugs.webkit.org/show_bug.cgi?id=47613
+
+ * QtTestBrowser/mainwindow.cpp:
+ (MainWindow::MainWindow):
+ (MainWindow::buildUI):
+
+2010-10-13 Yi Shen <yi.4.shen@nokia.com>
+
+ Reviewed by Tony Chang.
+
+ [gdb] Add pretty-print supports for UString, Identifier and JSString
+ https://bugs.webkit.org/show_bug.cgi?id=47601
+
+ * gdb/webkit.py:
+
+2010-10-13 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add list of Ubuntu packages needed by the EWS bots
+ https://bugs.webkit.org/show_bug.cgi?id=47628
+
+ I've been copy/pasting this list between bots, but it's better to have
+ this checked in.
+
+ * EWSTools/ubuntu-ews-packages: Added.
+
+2010-10-13 Leandro Pereira <leandro@profusion.mobi>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [EFL] Adds a build slave.
+ https://bugs.webkit.org/show_bug.cgi?id=47290
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json: Add an
+ entry for a release build of the EFL port.
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: Add platform
+ flag to build the EFL port.
+
+2010-10-13 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ webkit-patch build shouldn't need --build to actually build!
+ https://bugs.webkit.org/show_bug.cgi?id=47438
+
+ Yeah, requiring --build for the build command is really dumb. We did
+ this originally because the build step is usually optional in other
+ commands. We don't have a good way of reversing the default for an
+ option in one command. This approach is slightly hacky since --build
+ still shows up as an option on the help page, but at least it makes
+ progress. Passing --build is harmless, so the EWS bots shouldn't
+ explode because of this change.
+
+ * Scripts/webkitpy/tool/bot/commitqueuetask.py:
+ * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-10-13 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r69638.
+ http://trac.webkit.org/changeset/69638
+ https://bugs.webkit.org/show_bug.cgi?id=47595
+
+ "Broke win and chromium-win bots" (Requested by dglazkov on
+ #webkit).
+
+ * Scripts/webkitpy/common/system/path.py:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-13 John Knottenbelt <jknotten@chromium.org>
+
+ Reviewed by Steve Block.
+
+ First step towards client-based Geolocation in Chromium. Build
+ fixes for CLIENT_BASED_GEOLOCATION preprocessor feature define.
+ https://bugs.webkit.org/show_bug.cgi?id=47586
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-10-13 Adam Roben <aroben@apple.com>
+
+ Test that pressing the spacebar in a text field does not scroll the
+ document
+
+ Test for <http://webkit.org/b/47544> <rdar://problem/8540645>
+ REGRESSION: Pressing spacebar in a text field in WebKit2 does not
+ insert a space, scrolls the page instead
+
+ Reviewed by Sam Weinig.
+
+ * TestWebKitAPI/PlatformUtilities.h: Added isKeyDown.
+
+ * TestWebKitAPI/PlatformWebView.h: Added simulateSpacebarKeyPress.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj:
+ * TestWebKitAPI/win/copy-resources.cmd:
+ Added new files.
+
+ * TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp: Added.
+ (TestWebKitAPI::JavaScriptCallbackContext::JavaScriptCallbackContext):
+ We use this to track what the result of calling into JavaScript was.
+ (TestWebKitAPI::didFinishLoadForFrame): Records when the page
+ finishes loading.
+ (TestWebKitAPI::didNotHandleKeyEventCallback): Records when a key down
+ event is not handled.
+ (TestWebKitAPI::javaScriptCallback): Records that JavaScript finished
+ executing and whether the result matched our expectation.
+ (TestWebKitAPI::wk): Turns a UTF-8 C string into a WKStringRef.
+ (TestWebKitAPI::runJSTest): Calls into JS, waits for the call to
+ complete, and returns whether we got back the expected result.
+ (TestWebKitAPI::WebKit2_SpacebarScrolling): Tests that pressing
+ spacebar inside a text field does not scroll the document and that
+ pressing it outside the text field does scroll the document.
+
+ * TestWebKitAPI/Tests/WebKit2/spacebar-scrolling.html: Added.
+
+ * TestWebKitAPI/mac/PlatformUtilitiesMac.mm:
+ (TestWebKitAPI::Util::isKeyDown): Checks the event's type.
+
+ * TestWebKitAPI/mac/PlatformWebViewMac.mm:
+ (TestWebKitAPI::PlatformWebView::simulateSpacebarKeyPress): Copied
+ code from DRT's EventSendingController.
+
+ * TestWebKitAPI/win/PlatformUtilitiesWin.cpp:
+ (TestWebKitAPI::Util::isKeyDown): Checks the message's type.
+
+ * TestWebKitAPI/win/PlatformWebViewWin.cpp:
+ (TestWebKitAPI::PlatformWebView::simulateSpacebarKeyPress): Send the
+ same messages that get sent when you press spacebar in Notepad.
+
+2010-10-13 Adam Roben <aroben@apple.com>
+
+ Fix a couple of issues with the TestWebKitAPI build
+
+ * TestWebKitAPI/Configurations/TestWebKitAPICFLite.vsprops:
+ * TestWebKitAPI/Configurations/TestWebKitAPICoreFoundation.vsprops:
+ Fixed a typo.
+
+ * TestWebKitAPI/win/TestWebKitAPIGenerated.vcproj: Use common.vsprops
+ to set our output and intermediate directories so that we don't spew
+ files into the source tree.
+
+2010-10-13 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ WTR should accept relative paths
+ https://bugs.webkit.org/show_bug.cgi?id=47486
+
+ * WebKitTestRunner/StringFunctions.h:
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::createWKURL): Moved from StringFunctions.h since it is
+ used only here. Extend relative paths to absolute.
+
+2010-10-12 Adam Roben <aroben@apple.com>
+
+ Make TestWebKitAPI work on Windows
+
+ Fixes <http://webkit.org/b/47552> <rdar://problem/8541708>.
+
+ Reviewed by Sam Weinig.
+
+ * Scripts/build-api-tests: Build TestWebKitAPI.sln on Windows.
+
+ * Scripts/run-api-tests: Fix the PATH so that TestWebKitAPI can be
+ run on Windows.
+ (runTest): Added code to run TestWebKitAPI.exe on Windows and to die
+ on unsupported platforms.
+ (populateTests): Added code to run TestWebKitAPI.exe on Windows and to
+ die on other platforms. Extracted some formerly-Mac-specific code to
+ be cross-platform and made it handle any style of line-endings.
+
+ * TestWebKitAPI/Configurations/TestWebKitAPICFLite.vsprops: Added.
+ Links against CFLite.
+
+ * TestWebKitAPI/Configurations/TestWebKitAPICommon.vsprops: Added.
+ Contains most properties for the project.
+
+ * TestWebKitAPI/Configurations/TestWebKitAPICoreFoundation.vsprops:
+ Added. Links against CoreFoundation.
+
+ * TestWebKitAPI/TestWebKitAPIPrefix.h: Added a Windows-specific
+ section and moved the cross-platform section after the
+ platform-specific parts.
+
+ * TestWebKitAPI/win/PlatformUtilitiesWin.cpp: Added.
+ (TestWebKitAPI::Util::run): Runs a normal message pump until we're
+ done.
+ (TestWebKitAPI::Util::cf): Turns a UTF-8 C string into a CFString.
+ (TestWebKitAPI::Util::createURLForResource): Uses CFBundle to get the
+ resource path.
+ (TestWebKitAPI::Util::URLForNonExistentResource): Creates a bogus
+ WKURL.
+
+ * TestWebKitAPI/win/PlatformWebViewWin.cpp: Added.
+ (TestWebKitAPI::registerWindowClass):
+ (TestWebKitAPI::PlatformWebView::PlatformWebView):
+ (TestWebKitAPI::PlatformWebView::~PlatformWebView):
+ (TestWebKitAPI::PlatformWebView::page):
+ This was mostly copied from WebKitTestRunner's PlatformWebView.
+
+ * TestWebKitAPI/win/TestWebKitAPI.sln: Added. Builds both
+ TestWebKitAPI and TestWebKitAPIGeneratd. This is used by the
+ build-api-tests script.
+
+ * TestWebKitAPI/win/TestWebKitAPI.vcproj: Added. Builds
+ TestWebKitAPI.exe.
+
+ * TestWebKitAPI/win/TestWebKitAPIGenerated.vcproj: Added. Just calls
+ through to copy-resources.cmd.
+
+ * TestWebKitAPI/win/copy-resources.cmd: Added. Copies resources into
+ or deletes resources from TestWebKitAPI.resources.
+
+ * TestWebKitAPI/win/main.cpp: Added.
+ (main): Calls through to TestsController.
+
+2010-10-13 Gyuyoung Kim <gyuyoung.kim@samsung.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [EFL] Support viewport configuration and add new arguments for WebKit EFL
+ https://bugs.webkit.org/show_bug.cgi?id=47084
+
+ Opera spec regarding to viewport meta tag was adjusted to WebCore. So, EFL port
+ needs to be modified according to the changes.
+
+ * EWebLauncher/main.c:
+ (on_viewport_changed):
+
+2010-10-12 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ This patch enables new-run-webkit-tests (in particular the
+ chromium-win port) to run under Cygwin as well as Win32. Mostly
+ this just required some conversions from cygwin paths to Win32
+ paths when we spawn off Win32 binaries like test_shell.
+
+ https://bugs.webkit.org/show_bug.cgi?id=47220
+
+ * Scripts/webkitpy/common/system/path.py:
+ - Expose the cygpath() function for path conversion
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ - shift filename->uri conversion in the TestInfo objects to the
+ dump_render_tree thread
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ - use cygpath()
+
+2010-10-12 Yuta Kitamura <yutak@chromium.org>
+
+ Unreviewed. Add Yuta Kitamura (yutak) to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-10-12 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ When a provisional load fails, the provisional URL returned
+ from WKFrameCopyProvisionalURL should be empty
+ <rdar://problem/8540878>
+ https://bugs.webkit.org/show_bug.cgi?id=47546
+
+ Add test.
+
+ * TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp:
+ (TestWebKitAPI::didFailProvisionalLoadWithErrorForFrame):
+
+2010-10-12 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Start fleshing out find page overlays
+ https://bugs.webkit.org/show_bug.cgi?id=47559
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController find:]):
+ Pass kWKFindOptionsShowOverlay to WKPageFindString.
+
+2010-10-12 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] editing/input/emacs-ctrl-o.html
+
+ ctrl-o is bound to a sequence of commands on Mac, namely:
+ insertParagraphSeparator then moveLeft. In the DRT, we just interpret
+ ctrl-o in EventSenderQt as '\n', i.e. insertParagraphSeparator. As a
+ result we only issue one command, so don't generate the change in caret
+ position that results in the extra editing delegate messages.
+
+ So for the sake of not managing suspicious-looking differences, just
+ make DRT issue the appropriate edit commands to pass the test.
+
+ https://bugs.webkit.org/show_bug.cgi?id=47548
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::keyDown):
+
+2010-10-12 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Add a simple Find UI to MiniBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=47553
+
+ * MiniBrowser/mac/BrowserWindow.xib:
+ Add Find panel.
+
+ * MiniBrowser/mac/BrowserWindowController.h:
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController performFindPanelAction:]):
+ Show the find panel.
+
+ (-[BrowserWindowController find:]):
+ Tell the WKPageRef to find the given string.
+
+2010-10-12 Tony Chang <tony@chromium.org>
+
+ Unreviewed, fixing DRT compile on Windows after r69586.
+
+ * DumpRenderTree/chromium/WebThemeEngineDRT.h:
+
+2010-10-12 Tony Chang <tony@chromium.org>
+
+ Unreviewed, trying to fix NRWT on Windows.
+
+ * Scripts/webkitpy/layout_tests/port/http_lock.py:
+
+2010-10-12 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt][WTR] Checking the path of the injected bundle is bogus
+ https://bugs.webkit.org/show_bug.cgi?id=47541
+
+ * WebKitTestRunner/qt/TestControllerQt.cpp:
+ (WTR::isExistingLibrary): Added (static helper).
+ Extend the path with the appropriate suffix(es) on the
+ platform and check that the file exists.
+ (WTR::TestController::initializeInjectedBundlePath):
+ There were two bugs with the path checking:
+ - the condition should have been inverted
+ - QLibrary::fileName does not give back the filename
+ with the library suffix so we cannot check
+ that existance of the file this way.
+
+2010-10-12 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Tony Chang.
+
+ Implement http locking in NRWT.
+ https://bugs.webkit.org/show_bug.cgi?id=47072
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/http_lock.py: Added.
+ * Scripts/webkitpy/layout_tests/port/http_lock_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-12 Mark Rowe <mrowe@apple.com>
+
+ Fix the 32-bit WebKit2 build.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (getWindowFrame): Use NSRect rather than CGRect since that's what -frame returns.
+ (setWindowFrame): Use NSMakeRect rather than CGRectMake since that's what -setFrame:display: expects.
+
+2010-10-11 Tony Chang <tony@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ change the order of mrobinson's email addresses so bugs.webkit.org suggests the right one
+ https://bugs.webkit.org/show_bug.cgi?id=47513
+
+ bugs.webkit.org suggests mrobinson@igalia.com as an autocomplete,
+ which doesn't actually work.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-10-11 Prasad Tammana <prasadt@chromium.org>
+
+ Reviewed by Dmitry Titov.
+
+ Added support for showModalDialog on chromium port.
+
+ Implement showModalDialog for Layout tests for chromium port
+ https://bugs.webkit.org/show_bug.cgi?id=46759
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::closeWidgetSoon): Quit current message loop if in a modal loop.
+ (WebViewHost::runModal): Start a nested message loop and remember that.
+ (WebViewHost::WebViewHost): Initialize m_inModalLoop.
+ * DumpRenderTree/chromium/WebViewHost.h: Add m_inModalLoop.
+
+2010-10-11 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] Cleanup font selection code for the Freetype backend
+ https://bugs.webkit.org/show_bug.cgi?id=47503
+
+ Update DRT to set values for the cursive and fantasy font families, so
+ that we can generate consistent results for tests that use these families.
+ Add some missing information to fonts.conf.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues): Always set the fantasy and cursive font
+ family names.
+ * DumpRenderTree/gtk/fonts/fonts.conf: Add aliases for cursive and fantasy fonts
+ to our default serif font. Eventually we may want to import or require some "real"
+ fonts, but this should at least ensure consistent rendering during test runs. Also
+ add aliases for some other commonly used fonts in tests (Arial and Lucida Grande).
+ Finally, add a missing oblique specification for DejaVu Serif, which was resulting
+ in some incorrect baselines for the synthetic oblique test.
+
+2010-10-11 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Fix sheriffbot not to crash when there are failing tests. It turns out
+ Python sets don't support the + operator. We need to use union
+ instead. There's a more elegant way to do this in Python 2.6, but we
+ need this code to work in 2.5.
+
+ * Scripts/webkitpy/common/net/failuremap.py:
+ * Scripts/webkitpy/common/net/failuremap_unittest.py:
+
+2010-10-10 Robert Hogan <robert@webkit.org>
+
+ Unreviewed, fix failing test from r69468.
+
+ [Qt] Put all DRT-created pages in a page group
+
+ Fix on r69468.
+
+ Because we don't delete closed pages immediately in DRT we need
+ to remove them from the page group explicitly instead.
+
+ Fixes failure of fast/events/popup-blocked-from-fake-user-gesture.html
+
+ https://bugs.webkit.org/show_bug.cgi?id=47469
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::windowCloseRequested):
+
+2010-10-10 Leandro Pereira <leandro@profusion.mobi>
+
+ Reviewed by Adam Barth.
+
+ commit-queue: Add EFL-EWS status bubble to Bugzilla, now that the
+ EFL-EWS bot is up and running.
+ https://bugs.webkit.org/show_bug.cgi?id=47277
+
+ * QueueStatusServer/handlers/statusbubble.py:
+
+2010-10-10 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] Put all DRT-created pages in a page group
+
+ https://bugs.webkit.org/show_bug.cgi?id=47469
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::createWindow):
+
+2010-10-09 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ WKFrameGetFrameLoadState() returns kWKFrameLoadStateCommitted after the load has been stopped
+ <rdar://problem/8173667>
+ https://bugs.webkit.org/show_bug.cgi?id=47461
+
+ * TestWebKitAPI/PlatformUtilities.h:
+ * TestWebKitAPI/Test.h:
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp: Added.
+ (TestWebKitAPI::didFailProvisionalLoadWithErrorForFrame):
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/mac/PlatformUtilitiesMac.mm:
+ (TestWebKitAPI::Util::URLForNonExistentResource):
+ Adds a test for the frame load state after a failed provisional load. I wanted to test
+ the frame load state after a committed load failed, but I don't believe that is possible
+ to do without hooking up the http server to serve a long loading page.
+
+2010-10-09 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ Add WebKit2 version of runBeforeUnloadConfirmPanelWithMessage
+ <rdar://problem/8447690>
+ https://bugs.webkit.org/show_bug.cgi?id=47459
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (runBeforeUnloadConfirmPanel):
+ (-[BrowserWindowController awakeFromNib]):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ (WTR::TestController::initialize):
+
+2010-10-09 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ Need implementation of ChromeClient windowRect related functions.
+ <rdar://problem/8469476>
+ https://bugs.webkit.org/show_bug.cgi?id=47386
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (getWindowFrame):
+ (setWindowFrame):
+ (-[BrowserWindowController awakeFromNib]):
+ * WebKitTestRunner/PlatformWebView.h:
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize):
+ * WebKitTestRunner/mac/PlatformWebViewMac.mm:
+ (WTR::PlatformWebView::windowFrame):
+ (WTR::PlatformWebView::setWindowFrame):
+ * WebKitTestRunner/qt/PlatformWebViewQt.cpp:
+ (WTR::PlatformWebView::windowFrame):
+ (WTR::PlatformWebView::setWindowFrame):
+ * WebKitTestRunner/win/PlatformWebViewWin.cpp:
+ (WTR::PlatformWebView::windowFrame):
+ (WTR::PlatformWebView::setWindowFrame):
+
+2010-10-08 Adam Barth <abarth@webkit.org>
+
+ Unreviewed (Eric is on vacation in this change is trivial).
+
+ Add a "clean" command to webkit-patch to clean the working directory
+ https://bugs.webkit.org/show_bug.cgi?id=47436
+
+ This command is useful when using SVN because "svn revert" leaves
+ unversioned files behind.
+
+ * Scripts/webkitpy/tool/commands/download.py:
+
+2010-10-08 Andras Becsi <abecsi@webkit.org>
+
+ Unreviewed build fix.
+
+ [Qt] Add missing limits.h include since the Qt version currently
+ ran on the bot does need that.
+
+ * WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp:
+
+2010-10-08 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [Qt] Turn on building WTR
+ https://bugs.webkit.org/show_bug.cgi?id=47349
+
+ * Scripts/webkitdirs.pm:
+
+2010-10-08 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] TestController needs its platform dependent methods
+ https://bugs.webkit.org/show_bug.cgi?id=47413
+
+ * WebKitTestRunner/qt/TestControllerQt.cpp:
+ (WTR::TestController::initializeInjectedBundlePath):
+ If the WTR_INJECTEDBUNDLE_PATH environmental variable is
+ set then use that otherwise use the path where the bundle
+ lives in a normal trunk build.
+ (WTR::TestController::initializeTestPluginDirectory):
+ Set the bundle's value. It is not used currently.
+ (WTR::TestController::platformInitializeContext):
+ * WebKitTestRunner/qt/WebKitTestRunner.pro:
+
+2010-10-08 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ WTR: Prevent sending the Done message twice on test timeout.
+ https://bugs.webkit.org/show_bug.cgi?id=47410
+
+ When InjectedBundle::done() calls stopLoading, this may trigger
+ InjectedBundlePage::didFailLoadWithErrorForFrame which calls
+ InjectedBundle::done() itself later in the stack.
+ This would output the timeout failure message twice and confuse
+ the run-webkit-tests script.
+
+ This patch adds a third state, Stopping, which prevents WebCore
+ errors to trigger done() when testing is over.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::done):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h:
+
+2010-10-08 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Add an activateFonts() implementation similar to DRT's initializeFonts().
+ Original code by Simon Hausmann.
+ https://bugs.webkit.org/show_bug.cgi?id=47402
+
+ * WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp: Added.
+ (WTR::activateFonts):
+
+2010-10-08 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [Qt] Add support for Qt's WebKitTestRunner to old-run-webkit-tests.
+ https://bugs.webkit.org/show_bug.cgi?id=47401
+
+ * Scripts/build-webkittestrunner:
+ * Scripts/old-run-webkit-tests:
+
+2010-10-07 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] WTR first compile: fix compile issues.
+ https://bugs.webkit.org/show_bug.cgi?id=47343
+
+ * WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h:
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ * WebKitTestRunner/TestController.cpp:
+ * WebKitTestRunner/TestInvocation.cpp:
+
+2010-10-07 Antonio Gomes <agomes@rim.com>
+
+ Reviewed by Simon Fraser.
+
+ [Mac] [DRT] implement setSpatialNavigationEnabled
+ https://bugs.webkit.org/show_bug.cgi?id=47291
+
+ Implemented LayoutTestController::setSpatialNavigationEnabled for Mac's DRT
+ so it can track regression on the existing implementation and future improvements
+ we are making.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setSpatialNavigationEnabled):
+
+2010-10-07 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ rebaseline-chromium-webkit-tests relied on the filename_to_uri()
+ hook in the Port infrastructure to generate URIs for the files
+ in its summary HTML report; however, that method is supposed to only
+ be used for test files (and should really be renamed), so this would
+ crash.
+
+ This change adds a new "path" module to the system package with a
+ routine called abspath_to_uri() that handles converting paths to
+ file: URIs independently of anything in the layout_tests package,
+ and changes the code to use this. At some point in the near future
+ the layout_tests/port/* code should use this as well.
+
+ This change also deletes a bunch of unused code and fixes some
+ comments in rebaseline_chromium_webkit_tests.py.
+
+ https://bugs.webkit.org/show_bug.cgi?id=47319
+
+ * Scripts/webkitpy/common/system/path.py: Added.
+ * Scripts/webkitpy/common/system/path_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py:
+
+2010-10-07 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] The FreeType backend does not respect the FC_EMBOLDEN property
+ https://bugs.webkit.org/show_bug.cgi?id=46216
+
+ Fix my latest commit, as it contained some bad changes from a merge gone wrong.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (initializeFonts): Also initialize the DevaVu Sans font.
+
+2010-10-07 Daniel Cheng <dcheng@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [chromium] Minor naming cleanup in WebDragData, part 2
+ https://bugs.webkit.org/show_bug.cgi?id=47227
+
+ Update DRT to use the renamed methods.
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::beginDragWithFiles):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (addDRTFakeFileToDataObject):
+
+2010-10-07 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Add a WKPageFindClient, hook up WKPageCountStringMatches
+ https://bugs.webkit.org/show_bug.cgi?id=47373
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ Remove hard coded paths.
+
+ * TestWebKitAPI/Tests/WTF/VectorBasic.cpp:
+ (TestWebKitAPI::TEST):
+ Fix expected result.
+
+ * TestWebKitAPI/Tests/WebKit2/Find.cpp: Added.
+ (TestWebKitAPI::didFinishLoadForFrame):
+ (TestWebKitAPI::didCountStringMatches):
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/find.html: Added.
+ Add test for WKPageCountStringMatches.
+
+2010-09-21 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Chris Fleizach.
+
+ [GTK] The FreeType backend does not respect the FC_EMBOLDEN property
+ https://bugs.webkit.org/show_bug.cgi?id=46216
+
+ * DumpRenderTree/gtk/fonts/fonts.conf: Add a setting which enables FC_EMBOLDEN
+ for DejaVu Serif when there is no bold version available. This is necessary to
+ properly test the property in layout tests.
+
+2010-10-07 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>, Andras Becsi <abecsi@webkit.org>, Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Add WTR's InjectedBundle build files.
+ https://bugs.webkit.org/show_bug.cgi?id=47333
+
+ * Scripts/webkitdirs.pm:
+ * WebKitTestRunner/DerivedSources.pro: Added.
+ * WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro: Added.
+ * WebKitTestRunner/WebKitTestRunner.pro: Added.
+ * WebKitTestRunner/qt/DerivedSources.pro: Removed.
+ Content merged in ../DerivedSources.pro
+
+2010-10-07 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r69315.
+ http://trac.webkit.org/changeset/69315
+ https://bugs.webkit.org/show_bug.cgi?id=47363
+
+ Forgot to add the new files (Requested by kbalazs on #webkit).
+
+ * Scripts/webkitdirs.pm:
+ * WebKitTestRunner/qt/DerivedSources.pro: Added.
+
+2010-10-07 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Change API tester to ask the executable for the list of all
+ tests instead of relying on the directory structure.
+ https://bugs.webkit.org/show_bug.cgi?id=47359
+
+ * Scripts/run-test-webkit-api: Added.
+ * Scripts/webkitdirs.pm:
+ Add additional script to just launch the api tester with the correct settings.
+
+ * Scripts/run-api-tests:
+ Change to use the new --dump-tests options to build the list of tests and change
+ output to reflect a (suite, testcase) tuple for each test. Also adds some color.
+
+ * TestWebKitAPI/Test.h:
+ (TestWebKitAPI::Test::Register::Register):
+ * TestWebKitAPI/Tests/WTF/VectorBasic.cpp:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.cpp:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.cpp:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/WKString.cpp:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/WKStringJSString.cpp:
+ (TestWebKitAPI::TEST):
+ Give each test a suite name in addition to the test name.
+
+ * TestWebKitAPI/TestsController.cpp:
+ (TestWebKitAPI::TestsController::dumpTestNames):
+ (TestWebKitAPI::TestsController::runTestNamed):
+ * TestWebKitAPI/TestsController.h:
+ * TestWebKitAPI/mac/main.mm:
+ (main):
+ Add option to print all registered tests.
+
+2010-10-07 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>, Andras Becsi <abecsi@webkit.org>, Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Add WTR's InjectedBundle build files.
+ https://bugs.webkit.org/show_bug.cgi?id=47333
+
+ * Scripts/webkitdirs.pm:
+ * WebKitTestRunner/DerivedSources.pro: Added.
+ * WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro: Added.
+ * WebKitTestRunner/WebKitTestRunner.pro: Added.
+ * WebKitTestRunner/qt/DerivedSources.pro: Removed.
+ Content merged in ../DerivedSources.pro
+
+2010-10-07 Balazs Kelemen <kbalazs@webkit.org>
+
+ Unreviewed. Do a renaming that was recommended by the reviewer
+ (Kenneth) but I forgot to do before landing (http://trac.webkit.org/changeset/69253)
+
+ * WebKitTestRunner/qt/TestControllerQt.cpp:
+ (WTR::RunUntilConditionLoop::start):
+ (WTR::RunUntilConditionLoop::RunUntilConditionLoop):
+ (WTR::TestController::runUntil):
+
+2010-10-07 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Watchdog timer implementation for WTR
+ https://bugs.webkit.org/show_bug.cgi?id=47337
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h: Factor out
+ the definition of the timer type to a typedef.
+ * WebKitTestRunner/InjectedBundle/qt/LayoutTestControllerQt.cpp: Added.
+ Timer implementation with QTimer and a helper QObject class.
+ (WTR::WatchdogTimerHelper::instance):
+ (WTR::WatchdogTimerHelper::timerFired):
+ (WTR::WatchdogTimerHelper::WatchdogTimerHelper):
+ (WTR::LayoutTestController::platformInitialize):
+ (WTR::LayoutTestController::invalidateWaitToDumpWatchdogTimer):
+ (WTR::LayoutTestController::initializeWaitToDumpWatchdogTimerIfNeeded):
+
+2010-10-07 Balazs Kelemen <kbalazs@webkit.org>
+
+ Unreviewed buildfix for 69297 again
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::blankURL):
+
+2010-10-07 Balazs Kelemen <Balazs Kelemen>
+
+ Unreviewed trivial build fix for r69297
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::blankURL):
+
+2010-10-07 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ WebKitTestRunner should be portable
+ https://bugs.webkit.org/show_bug.cgi?id=45393
+
+ Use only the WebKit API for working with urls.
+ * WebKitTestRunner/StringFunctions.h:
+ (WTR::createWKURL):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::blankURL):
+ (WTR::TestController::resetStateToConsistentValues):
+ (WTR::TestController::didFinishLoadForFrame):
+
+2010-10-07 Carlos Garcia Campos <cgarcia@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Use gtk_widget_draw() instead of gtk_widget_get_snapshot() in PixelDumpSupportGtk when building with gtk3
+ https://bugs.webkit.org/show_bug.cgi?id=47332
+
+ * DumpRenderTree/gtk/PixelDumpSupportGtk.cpp:
+ (createBitmapContextFromWebView):
+
+2010-10-06 Chris Guillory <chris.guillory@google.com>
+
+ Reviewed by Chris Fleizach.
+
+ Remove unused accessibility functions from webkit.
+ https://bugs.webkit.org/attachment.cgi?bugid=46707
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::postAccessibilityNotification):
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-10-06 Lucas Forschler <lforschler@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Fix the sunspider-compare-results to actually use the passed in value for $root.
+
+ * Scripts/sunspider-compare-results:
+
+2010-10-06 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Runloop implementation for WTR
+ https://bugs.webkit.org/show_bug.cgi?id=47280
+
+ * WebKitTestRunner/qt/TestControllerQt.cpp:
+ Implemented TestController::runUntil by a timerEvent
+ and a QEventLoop. We step into the event loop from runUntil.
+ While we are waiting in the loop a timerEvent is periodically
+ checking the value of the condition. Once the condition has
+ becoming true the timerEvent wakes us up.
+ (WTR::RunUntilLoop::start):
+ (WTR::RunUntilLoop::RunUntilLoop):
+ (WTR::RunUntilLoop::run):
+ (WTR::RunUntilLoop::timerEvent):
+ (WTR::TestController::platformInitialize):
+ (WTR::TestController::runUntil):
+ * WebKitTestRunner/qt/main.cpp:
+ Start the main event loop first and creating the TestController later.
+ (Launcher::Launcher):
+ (Launcher::~Launcher):
+ (Launcher::launch): Creating the TestController.
+ (main): Setting up a timer for calling Launcher::launch from
+ the main event loop.
+
+2010-10-06 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Kenneth Russell.
+
+ new-run-webkit-tests: fix typo in chromium-gpu that was trying to
+ enable 'accelerated-composting' instead of 'accelerated-compositing'.
+
+ https://bugs.webkit.org/show_bug.cgi?id=47312
+
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py:
+
+2010-10-06 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] PlatformWebView implementation for WebKitTestRunner
+ https://bugs.webkit.org/show_bug.cgi?id=47276
+
+ The implementation follows the way how
+ we use the API in MiniBrowser.
+ * WebKitTestRunner/PlatformWebView.h:
+ * WebKitTestRunner/qt/PlatformWebViewQt.cpp:
+ (WTR::WebView::wkView):
+ (WTR::WebView::~WebView):
+ (WTR::WebView::WebView):
+ (WTR::PlatformWebView::PlatformWebView):
+ (WTR::PlatformWebView::~PlatformWebView):
+ (WTR::PlatformWebView::resizeTo):
+ (WTR::PlatformWebView::page):
+ (WTR::PlatformWebView::focus):
+ * WebKitTestRunner/qt/WebKitTestRunner.pro:
+
+2010-10-06 Balazs Kelemen <kbalazs@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Add WebKitTestRunner's build files
+ https://bugs.webkit.org/show_bug.cgi?id=44155
+
+ Parts was taken by Zoltan Horvath's patch.
+
+ * Scripts/generate-forwarding-headers.pl: Moved from WebKit2.
+ * Scripts/webkitdirs.pm: Make the generated files needed by WTR.
+ * WebKitTestRunner/PlatformWebView.h: Addeed typedefs for
+ PlatformWKView and PlatformWindow (void* for now).
+ Buildfix the case when __APPLE__ is not defined.
+ * WebKitTestRunner/qt/DerivedSources.pro: Added.
+ * WebKitTestRunner/qt/PlatformWebViewQt.cpp: Added.
+ Empty stub implementation.
+ (WTR::registerWindowClass):
+ (WTR::PlatformWebView::PlatformWebView):
+ (WTR::PlatformWebView::~PlatformWebView):
+ (WTR::PlatformWebView::resizeTo):
+ (WTR::PlatformWebView::page):
+ (WTR::PlatformWebView::focus):
+ * WebKitTestRunner/qt/TestControllerQt.cpp: Added.
+ Empty stub implementation.
+ (WTR::registerWindowClass):
+ (WTR::TestController::runUntil):
+ (WTR::TestController::platformInitialize):
+ (WTR::TestController::initializeInjectedBundlePath):
+ (WTR::TestController::initializeTestPluginDirectory):
+ (WTR::TestController::platformInitializeContext):
+ * WebKitTestRunner/qt/WebKitTestRunner.pro: Added.
+ * WebKitTestRunner/qt/main.cpp: Added.
+ (main):
+
+2010-10-06 Tony Chang <tony@chromium.org>
+
+ Unreviewed, rolling out r69202.
+ http://trac.webkit.org/changeset/69202
+ https://bugs.webkit.org/show_bug.cgi?id=46937
+
+ Broke compile of test_shell
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::beginDragWithFiles):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (addDRTFakeFileToDataObject):
+
+2010-10-06 Daniel Cheng <dcheng@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [chromium] Minor naming cleanup in WebDragData, part 2
+ https://bugs.webkit.org/show_bug.cgi?id=46937
+
+ Update DRT to use the renamed methods.
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::beginDragWithFiles):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (addDRTFakeFileToDataObject):
+
+2010-10-06 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/47270> Move WebArchive serialization code into its own file
+
+ Reviewed by Adam Roben.
+
+ This is the first step in making webarchive tests work on
+ Windows.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Added
+ new files to the project.
+ * DumpRenderTree/mac/DumpRenderTree.mm: Removed code that moved
+ to WebArchiveDumpSupport.mm.
+ * DumpRenderTree/mac/WebArchiveDumpSupport.h: Added.
+ * DumpRenderTree/mac/WebArchiveDumpSupport.mm: Copied from WebKitTools/DumpRenderTree/mac/DumpRenderTree.mm.
+ (serializeWebArchiveToXML):
+
+2010-10-05 Daniel Bates <dbates@rim.com>
+
+ Reviewed by David Kilzer.
+
+ Add infrastructure to towards detecting change log diffs that aren't at the top of the ChangeLog
+ https://bugs.webkit.org/show_bug.cgi?id=46058
+
+ Make VCSUtils::fixChangeLogPatch() return a reference to a hash
+ structure so as to support returning additional information
+ about a change log diff.
+
+ Currently, VCSUtils::fixChangeLogPatch() returns a string that
+ represents the change log diff. Towards supporting the return
+ of additional information, such as whether the change log diff
+ inserts an entry at the top of the ChangeLog file, we need to
+ make VCSUtils::fixChangeLogPatch() return a reference to hash
+ structure.
+
+ * Scripts/VCSUtils.pm:
+ - Modified fixChangeLogPatch() to return a reference to a
+ hash structure.
+ - Added documentation to fixChangeLogPatch().
+ - Modified call site in mergeChangeLogs() as necessary.
+ * Scripts/svn-apply:
+ - Modified call site in patch() as necessary.
+ * Scripts/svn-create-patch:
+ - Modified call site in generateDiff() as necessary.
+ * Scripts/svn-unapply:
+ - Modified call site in patch() as necessary.
+ * Scripts/webkitperl/VCSUtils_unittest/fixChangeLogPatch.pl:
+ - Modified the unit tests as necessary.
+
+2010-10-05 Tony Chang <tony@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ fix the link to the expected image on windows
+ https://bugs.webkit.org/show_bug.cgi?id=47228
+
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py: On
+ windows, the file must be opened in binary mode when writing
+ binary data.
+
+2010-10-05 Adam Barth <abarth@webkit.org>
+
+ Update expected result of unittest to match Tony's change below.
+
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+
+2010-10-05 Tony Chang <tony@chromium.org>
+
+ Reviewed by Ojan Vafai (over the shoulder).
+
+ Paper over errors in image_diff so we don't crash the whole test run.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-10-05 Tony Chang <tony@chromium.org>
+
+ Unreviewed, make shutil.rmtree more resiliant to errors
+ since windows was raising WindowsError: The process cannot access the file because it
+ is being used by another process.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-10-05 Tony Chang <tony@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ [chromium] fix image diffing in NRWT
+ https://bugs.webkit.org/show_bug.cgi?id=47128
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py: Stop using
+ NamedTemporaryFile since it doesn't work on Windows.
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+
+2010-10-05 Kenneth Russell <kbr@google.com>
+
+ Reviewed by Tony Chang.
+
+ [chromium] Implement layerTreeAsText in DumpRenderTree
+ https://bugs.webkit.org/show_bug.cgi?id=47216
+
+ Plumbed Frame::layerTreeAsText through Chromium's WebKit API to
+ make it callable from DumpRenderTree.
+
+ No new tests; verified with existing compositor layout tests.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::layerTreeAsText):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+
+2010-10-05 Brent Fulgham <bfulgham@webkit.org>
+
+ Unreviewed build correction.
+
+ * DumpRenderTree/win/ImageDiff.vcproj: Use WinCairo debug
+ property sheet so proper libraries are linked.
+
+2010-10-05 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Fix url conversion in QWebHistory
+
+ Converting from KURL to WFT::String to QUrl does not
+ permit proper percent encoding later.
+
+ https://bugs.webkit.org/show_bug.cgi?id=47048
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::dumpHistoryItem):
+
+2010-10-05 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ REGRESSION (r68966?): All dumpAsText test fail on WebKit2
+ https://bugs.webkit.org/show_bug.cgi?id=47188
+ <rdar://problem/8514104>
+
+ When constructing the std::string, use the real string length instead of the maximum buffer size.
+
+ * TestWebKitAPI/PlatformUtilities.h:
+ (TestWebKitAPI::Util::toSTD):
+ * WebKitTestRunner/StringFunctions.h:
+ (WTR::toSTD):
+
+2010-10-04 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Add MIMEType accessor to WKFrame
+ <rdar://problem/8347683>
+ https://bugs.webkit.org/show_bug.cgi?id=47138
+
+ * TestWebKitAPI/PlatformUtilities.h:
+ (TestWebKitAPI::Util::toSTD):
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.cpp: Added.
+ (TestWebKitAPI::didStartProvisionalLoadForFrame):
+ (TestWebKitAPI::didCommitLoadForFrame):
+ (TestWebKitAPI::didFinishLoadForFrame):
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.cpp: Added.
+ (TestWebKitAPI::didStartProvisionalLoadForFrame):
+ (TestWebKitAPI::didCommitLoadForFrame):
+ (TestWebKitAPI::didFinishLoadForFrame):
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/basic-1.html: Removed.
+ * TestWebKitAPI/Tests/WebKit2/icon.png: Added.
+ * TestWebKitAPI/Tests/WebKit2/simple.html: Added.
+ * TestWebKitAPI/mac/PlatformUtilitiesMac.mm:
+ (TestWebKitAPI::Util::createURLForResource):
+
+2010-10-05 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Ojan Vafai.
+
+ [NRWT] Rename current_dir to current_group because it's not a directory
+ https://bugs.webkit.org/show_bug.cgi?id=47169
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-04 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ r69065 broke test-webkitpy by trying to create a '/tmp-X' directory,
+ which can't always be done. This test uses tempfile.mkdtemp(), which
+ should be safe.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-10-04 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Add missing "from __future__ import with_statement" that was
+ breaking test-webkitpy on the Leopard bots (broke in r69040).
+
+ * Scripts/webkitpy/layout_tests/port/google_chrome.py:
+
+2010-10-04 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r69066.
+ http://trac.webkit.org/changeset/69066
+ https://bugs.webkit.org/show_bug.cgi?id=47163
+
+ Made NRWT reliability worse. (Requested by tkent on #webkit).
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+
+2010-10-04 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Tony Chang.
+
+ [NRWT] Reverse the http tests to alphabetical order.
+ https://bugs.webkit.org/show_bug.cgi?id=47075
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-10-04 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Fix timeout on http/tests/navigation/post-goback2.html and postredirect-goback2.html
+
+ We need to queue back and forward navigations in the DRT from the
+ LayoutTestController so that maybeDump() knows about them.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::queueBackNavigation):
+ (LayoutTestController::queueForwardNavigation):
+
+2010-10-04 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] fix image diffing in NRWT
+ https://bugs.webkit.org/show_bug.cgi?id=47128
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py: Flush data to the
+ temp file and check the image_diff error code more carefully
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+
+2010-10-04 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ aroben's change in r68792 actually broke new-run-webkit-tests when
+ running the DRT code path. His change was intended to fix the
+ way we were converting windows paths to URIs when running under
+ Cygwin (the paths were getting one too many "/" on the front).
+ However, the change ended up breaking the chromium_win port, which
+ had slightly different logic.
+
+ This patch removes the port-specific code and adds tests to make
+ sure we're getting the behavior we expect. The Port object no longer
+ exposes a get_absolute_path() method that can be used outside of
+ of converting test filenames, because it's unreliable otherwise
+ (we don't have the right context to know which conversion is intended).
+
+ https://bugs.webkit.org/show_bug.cgi?id=47140
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-10-04 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Handle crash introduced in r69040 if we are not running in a
+ Chromium checkout.
+
+ * Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py:
+
+2010-10-04 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Add a way for us to have test expectations that are specific to the
+ official builds of Google Chrome (as opposed to Chromium). This change
+ looks for an additional "test_expectations_chrome.txt" file in
+ Chromium's repository (webkit/tools/layout_tests), and uses the
+ concatenation of that file and the regular test_expectations.txt
+ file for test overrides.
+
+ https://bugs.webkit.org/show_bug.cgi?id=46854
+
+ * Scripts/webkitpy/layout_tests/port/google_chrome.py:
+ * Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py:
+
+2010-10-04 Simon Fraser <simon.fraser@apple.com>
+
+ Color tests in the list based on existing pass/fail result.
+
+ Fix the summary data to account for htmlOnly and nonHTML tests.
+
+ * CSSTestSuiteHarness/harness/harness.css:
+ (#test-list > option.pass):
+ (#test-list > option.fail):
+ (#test-list > option.skipped):
+ * CSSTestSuiteHarness/harness/harness.js:
+ (Test):
+ (Test.prototype.statusForFormat):
+ (TestSuite.prototype.fillTestList):
+ (TestSuite.prototype.updateTestList):
+ (TestSuite.prototype.recordResult):
+ (TestSuite.prototype.markTestCompleted):
+ (TestSuite.prototype.countTestsWithFlag):
+ (TestSuite.prototype.queryDatabaseForSummary.this.db.transaction):
+ (TestSuite.prototype.queryDatabaseForSummary):
+
+2010-10-04 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ AX: doAXRangeForLine does not work
+ https://bugs.webkit.org/show_bug.cgi?id=47101
+
+ DRT support to handle NSAccessibilityRangeForLineParameterizedAttribute.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (rangeForLineCallback):
+ (AccessibilityUIElement::rangeForLine):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::rangeForLine):
+
+2010-10-04 Andrey Kosyakov <caseq@chromium.org>
+
+ Unreviewed. Adding myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-10-04 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add ability to set the CacheModel in Webkit2
+ https://bugs.webkit.org/show_bug.cgi?id=47066
+
+ * MiniBrowser/mac/AppDelegate.m:
+ (-[BrowserAppDelegate init]): Opt minibrowser into
+ a PrimaryWebBrowser cache model.
+
+2010-10-03 Simon Fraser <simon.fraser@apple.com>
+
+ Make sure to enter all tests when creating the database
+ for the first time.
+
+ When migrating to a new version of the suite, be sure to
+ sync up the database and testinfo.data by removing old
+ tests, and inserting new ones.
+
+ * CSSTestSuiteHarness/harness/harness.js:
+ (TestSuite.prototype.openDatabase.creation):
+ (TestSuite.prototype.databaseCreated):
+ (TestSuite.prototype.populateDatabaseFromTestInfoData):
+ (TestSuite.prototype.insertTest):
+
+2010-10-03 Simon Fraser <simon.fraser@apple.com>
+
+ More work on treating HTML4 and XHTML1 independently; when
+ changing the format, rebuild the test list, and update the
+ numbers in the chapter popup.
+
+ * CSSTestSuiteHarness/harness/harness.js:
+ (Test):
+ (Test.prototype.runForFormat):
+ (Test.prototype.completedForFormat):
+ (ChapterSection):
+ (ChapterSection.prototype.countTests):
+ (Chapter):
+ (Chapter.prototype.description):
+ (Chapter.prototype.countTests):
+ (Chapter.prototype.testCount):
+ (Chapter.prototype.untestedCount):
+ (TestSuite.prototype.buildChapters):
+ (TestSuite.prototype.loadCurrentTest):
+ (TestSuite.prototype.updateProgressLabel):
+ (TestSuite.prototype.processFlags):
+ (TestSuite.prototype.formatChanged):
+
+2010-10-03 Simon Fraser <simon.fraser@apple.com>
+
+ Update test suite version 20101001.
+
+ Handle database migration, and delete tests from the db that are
+ not present in testinfo.data.
+
+ Load about:blank into the test frame before the test url, to make
+ missing tests more obvious.
+
+ * CSSTestSuiteHarness/harness/harness.js:
+ (TestSuite.prototype.loadTest):
+ (TestSuite.prototype.openDatabase.creation):
+ (TestSuite.prototype.openDatabase.migration1_0To1_1):
+ (TestSuite.prototype.openDatabase.if.return):
+ (TestSuite.prototype.databaseReady):
+ (TestSuite.prototype.populateDatabaseFromTestInfoData):
+ (TestSuite.prototype.syncDatabaseWithTestInfoData.this.db.transaction):
+ (TestSuite.prototype.syncDatabaseWithTestInfoData):
+
+2010-10-02 Simon Fraser <simon.fraser@apple.com>
+
+ Add the ability to jump to a specific test.
+
+ * CSSTestSuiteHarness/harness/harness.html:
+ * CSSTestSuiteHarness/harness/harness.js:
+ (TestSuite.prototype.goToTestByName):
+ (TestSuite.prototype.switchToFormat):
+
+2010-10-02 Simon Fraser <simon.fraser@apple.com>
+
+ For a ref test, load the ref in the same format (HTML4 vs XHTML1)
+ as the test.
+
+ * CSSTestSuiteHarness/harness/harness.js:
+ (TestSuite.prototype.loadRef):
+
+2010-10-02 Simon Fraser <simon.fraser@apple.com>
+
+ Update the UI to reflect the fact that each test needs to be tested
+ in both HTML4 and XHTML1 format.
+
+ * CSSTestSuiteHarness/harness/harness.js:
+ (Test):
+ (Chapter.prototype.description):
+ (Chapter.prototype.untestedCount):
+ (TestSuite.prototype.fillChapterPopup):
+ (TestSuite.prototype.updateChapterPopup):
+ (TestSuite.prototype.fillTestList):
+ (TestSuite.prototype.updateTestList):
+ (TestSuite.prototype.goToNextIncompleteTest):
+ (TestSuite.prototype.firstIncompleteTestIndex):
+ (TestSuite.prototype.recordResult):
+ (TestSuite.prototype.formatChanged):
+ (TestSuite.prototype.markTestCompleted):
+ (TestSuite.prototype.resetTestStatus):
+
+2010-10-01 Simon Fraser <simon.fraser@apple.com>
+
+ Add the ability to remove results for re-testing, and
+ to import results.
+
+ * CSSTestSuiteHarness/harness/harness.css:
+ (.custom button):
+ (#overlay):
+ (#overlay.visible):
+ (.overlay-contents):
+ (.overlay-contents textarea):
+ (.overlay-contents .buttons):
+ (.overlay-contents .note):
+ (.overlay-contents .buttons button):
+ * CSSTestSuiteHarness/harness/harness.html:
+ * CSSTestSuiteHarness/harness/harness.js:
+ (TestSuite.prototype.importResults):
+ (TestSuite.prototype.clearResults):
+ (TestSuite.prototype.markTestCompleted):
+ (TestSuite.prototype.resetTestStatus):
+ (TestSuite.prototype.storeTestResult):
+ (TestSuite.prototype.importTestResults):
+ (TestSuite.prototype.clearTestResults):
+
+2010-10-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Jon Honeycutt.
+
+ Deploy the new WKString functions to remove most uses of CF from
+ the WebKitTestRunner.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::didReceiveMessage):
+ (WTR::InjectedBundle::done):
+ * WebKitTestRunner/StringFunctions.h:
+ (WTR::toWK):
+ (WTR::toJS):
+ (WTR::toSTD):
+ (WTR::operator<<):
+ (WTR::copyURLString):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::resetStateToConsistentValues):
+ (WTR::TestController::didFinishLoadForFrame):
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::invoke):
+ (WTR::TestInvocation::didReceiveMessageFromInjectedBundle):
+
+2010-10-01 Mihai Parparita <mihaip@chromium.org>
+
+ Unreviewed TestResultsServer change.
+
+ Add files introduced by http://crrev.com/61273 to the list of dashboard
+ files to update.
+
+ * TestResultServer/handlers/dashboardhandler.py:
+
+2010-10-01 Brian Weinstein <bweinstein@apple.com>
+
+ Build Fix for Windows.
+
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj: Don't copy ForwardingHeaders from
+ WebKitTestRunner/ForwardingHeaders, instead, add $(WebKitOutputDir)/include/WebCore/
+ ForwardingHeaders to the include path.
+
+2010-10-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add SPI to convert a WKStringRef to a JSStringRef and vice-versa.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2/WKString.cpp:
+ (TestWebKitAPI::TEST):
+ * TestWebKitAPI/Tests/WebKit2/WKStringJSString.cpp: Added.
+ (TestWebKitAPI::TEST):
+
+2010-10-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Add additional WKString API
+ https://bugs.webkit.org/show_bug.cgi?id=46958
+
+ Add basic WKStringRef tests.
+
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+ * TestWebKitAPI/Tests/WebKit2/WKString.cpp: Added.
+
+2010-10-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ Add makefile for TestWebKitAPI and call it from the base makefile.
+
+ * Makefile:
+ * TestWebKitAPI/Makefile: Added.
+
+2010-10-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Remove unnecessary ForwardingHeaders from test runners.
+ https://bugs.webkit.org/show_bug.cgi?id=47010
+
+ * TestWebKitAPI/Configurations/Base.xcconfig:
+ * TestWebKitAPI/ForwardingHeaders: Removed.
+ * WebKitTestRunner/Configurations/Base.xcconfig:
+ * WebKitTestRunner/ForwardingHeaders: Removed.
+
+2010-09-30 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ WebSocket tests are flaky
+ https://bugs.webkit.org/show_bug.cgi?id=46956
+
+ Update these tools to understand how to run the WebSocket tests off the
+ Apache server.
+
+ * Scripts/old-run-webkit-tests:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-10-01 Adam Roben <aroben@apple.com>
+
+ Encode Executive command arguments using UTF-8 on Cygwin
+
+ Cygwin's Python's os.execv doesn't support unicode command arguments.
+ Cygwin's execv expects arguments to be encoded using the current code
+ page. But code pages are limited in what characters they can handle,
+ and our tests include characters that the English code page can't
+ handle. So for now we'll just encode everything in UTF-8 on Cygwin,
+ which can handle all characters but might confuse some commands, for
+ expediency's sake. I'm sure we'll run into cases where UTF-8 isn't
+ good enough, but we can deal with that when the problem arises.
+
+ Reviewed by Adam Barth.
+
+ Fixes <http://webkit.org/b/46892> <rdar://problem/8496639>
+ webkitpy.common.system.executive_unittest.ExecutiveTest.test_run_command_with_unicode
+ fails on Windows
+
+ * Scripts/webkitpy/common/system/executive.py:
+ (Executive._run_command_with_teed_output):
+ (Executive.run_command):
+ On Cygwin, encode arguments using UTF-8.
+
+2010-10-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Add simple API tester for WebKit2
+ https://bugs.webkit.org/show_bug.cgi?id=46953
+
+ This adds a very simple testing infrastructure for testing APIs exposed
+ through the WebKit project. It consists of two parts: 1) a project that
+ builds the all the tests 2) a script that searches the tests directory and
+ calls the tester once for each test.
+
+ This adds the infrastructure and two tests:
+ - Tests/WTF/Vector1.cpp - A proof of concept test of WTF data-structures.
+ - Tests/WebKit2/BasicTest1.cpp - A proof of concept test of WebKit2 API.
+
+ This currently only works on the mac, but is designed to be easily ported
+ to any platform.
+
+ * Scripts/run-api-tests: Added.
+ * Scripts/build-api-tests: Added.
+ Scripts to build/run the tests.
+
+ * TestWebKitAPI: Added.
+ * TestWebKitAPI/Configurations: Added.
+ * TestWebKitAPI/Configurations/Base.xcconfig: Added.
+ * TestWebKitAPI/Configurations/DebugRelease.xcconfig: Added.
+ * TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig: Added.
+ * TestWebKitAPI/ForwardingHeaders: Added.
+ * TestWebKitAPI/ForwardingHeaders/wtf: Added.
+ * TestWebKitAPI/PlatformUtilities.h: Added.
+ * TestWebKitAPI/PlatformWebView.h: Added.
+ (TestWebKitAPI::PlatformWebView::platformView):
+ * TestWebKitAPI/StringFunctions.h: Added.
+ * TestWebKitAPI/Test.h: Added.
+ (TestWebKitAPI::Test::~Test):
+ (TestWebKitAPI::Test::name):
+ (TestWebKitAPI::Test::Register::Register):
+ (TestWebKitAPI::Test::Register::create):
+ (TestWebKitAPI::Test::Test):
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj: Added.
+ * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj: Added.
+ * TestWebKitAPI/TestWebKitAPIPrefix.h: Added.
+ * TestWebKitAPI/TestsController.cpp: Added.
+ (TestWebKitAPI::TestsController::shared):
+ (TestWebKitAPI::TestsController::TestsController):
+ (TestWebKitAPI::TestsController::runTestNamed):
+ (TestWebKitAPI::TestsController::testFailed):
+ (TestWebKitAPI::TestsController::registerCreateTestFunction):
+ * TestWebKitAPI/TestsController.h: Added.
+ * TestWebKitAPI/mac: Added.
+ * TestWebKitAPI/mac/PlatformUtilitiesMac.mm: Added.
+ (TestWebKitAPI::Util::run):
+ (TestWebKitAPI::Util::createURLForResource):
+ * TestWebKitAPI/mac/PlatformWebViewMac.mm: Added.
+ (TestWebKitAPI::PlatformWebView::PlatformWebView):
+ (TestWebKitAPI::PlatformWebView::resizeTo):
+ (TestWebKitAPI::PlatformWebView::~PlatformWebView):
+ (TestWebKitAPI::PlatformWebView::page):
+ (TestWebKitAPI::PlatformWebView::focus):
+ * TestWebKitAPI/mac/main.mm: Added.
+ Infrastructure.
+
+ * TestWebKitAPI/Tests: Added.
+ * TestWebKitAPI/Tests/WTF: Added.
+ * TestWebKitAPI/Tests/WTF/Vector1.cpp: Added.
+ * TestWebKitAPI/Tests/WebKit2: Added.
+ * TestWebKitAPI/Tests/WebKit2/BasicTest1.cpp: Added.
+ (TestWebKitAPI::State::State):
+ * TestWebKitAPI/Tests/WebKit2/basic-1.html: Added.
+ Proof of concept tests.
+
+2010-10-01 Adam Roben <aroben@apple.com>
+
+ Don't assume AccessibleObjectFromEvent succeeds
+
+ Fixes <http://webkit.org/b/44136> <rdar://problem/8321684> Crash in
+ DumpRenderTree!notificationListenerProc when running
+ plugins/access-after-page-destroyed.html
+
+ Reviewed by Sam Weinig.
+
+ * DumpRenderTree/win/AccessibilityControllerWin.cpp:
+ (notificationListenerProc): Check both the return value of
+ AccessibleObjectFromEvent and the object it returns, as MSDN
+ recommends.
+
+2010-10-01 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Tony Chang.
+
+ [NRWT] Put the http and websocket tests first in the test list.
+ https://bugs.webkit.org/show_bug.cgi?id=46453
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-10-01 Fady Samuel <fsamuel@chromium.org>
+
+ Unreviewed, adding myself to the committer list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-10-01 Adam Roben <aroben@apple.com>
+
+ Test NPN_GetValue(NPNVnetscapeWindow)
+
+ Test for <http://webkit.org/b/46726> <rdar://problem/8486319>
+ Right-clicking on windowless Flash plugin in WebKit2 makes a context
+ menu appear in the bottom-right corner of the screen
+
+ Reviewed by Anders Carlsson.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp:
+ (PluginTest::NPN_GetValue): Added. Calls through to the browser.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.h: Added NPN_GetValue.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/win/GetValueNetscapeWindow.cpp: Added.
+ (GetValueNetscapeWindow::GetValueNetscapeWindow): Initialize members.
+ (GetValueNetscapeWindow::NPP_SetWindow): Test that
+ NPN_GetValue(NPNVnetscapeWindow) returns a valid HWND and that it
+ isn't our HWND.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ Added GetValueNetscapeWindow.
+
+2010-10-01 Andreas Kling <andreas.kling@nokia.com>
+
+ Unreviewed, adding my webkit.org identity to reviewer list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-30 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ The WebSocket server should flush its logs
+ https://bugs.webkit.org/show_bug.cgi?id=46946
+
+ The WebSocket server logs are truncated because the driver just
+ terminates the child. It should run Python without buffering so we can
+ see the end of the log.
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+
+2010-09-30 Simon Fraser <simon.fraser@apple.com>
+
+ Add a button to jump to the next untested test.
+
+ * CSSTestSuiteHarness/harness/harness.css:
+ (.test-type):
+ (.name > button):
+ * CSSTestSuiteHarness/harness/harness.html:
+ * CSSTestSuiteHarness/harness/harness.js:
+ (Chapter.prototype.description):
+ (Chapter.prototype.untestedCount):
+ (TestSuite.prototype.testInfoDataLoaded):
+ (TestSuite.prototype.fillChapterPopup):
+ (TestSuite.prototype.updateChapterPopup):
+ (TestSuite.prototype.buildTestListForChapter):
+ (TestSuite.prototype.goToNextIncompleteTest):
+ (TestSuite.prototype.firstIncompleteTestIndex):
+ (TestSuite.prototype.testCompletionStateChanged):
+
+2010-09-29 Jon Honeycutt <jhoneycutt@apple.com>
+
+ WebKit2 on Windows should use Windows fonts for the various standard
+ font families
+ https://bugs.webkit.org/show_bug.cgi?id=43499
+ <rdar://problem/8272758>
+
+ Reviewed by Adam Roben.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::resetStateToConsistentValues):
+ Use the Mac fonts for running tests. This matches DRT behavior.
+
+2010-09-30 Adam Barth <abarth@webkit.org>
+
+ Third attempt. We need a better integration test environment.
+
+ * Scripts/webkitpy/common/net/failuremap.py:
+ * Scripts/webkitpy/common/net/failuremap_unittest.py:
+
+2010-09-30 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Support for PlainTextController
+
+ Unskip editing/text-iterator/basic-iteration.html
+
+ https://bugs.webkit.org/show_bug.cgi?id=38805
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::initJSObjects):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/PlainTextControllerQt.cpp: Added.
+ (PlainTextController::PlainTextController):
+ (PlainTextController::plainText):
+ * DumpRenderTree/qt/PlainTextControllerQt.h: Added.
+
+2010-09-30 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Second attempt to fix sheriffbot.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+
+2010-09-30 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ This patch should stop the sheriffbot from throwing an exception.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+
+2010-09-30 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Adam Roben.
+
+ The same bots shouldn't run both Windows Debug Tests and Windows Release Tests.
+ https://bugs.webkit.org/show_bug.cgi?id=46926
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json: Have two bots running Windows
+ Release Tests, and two bots running Windows Debug Tests, instead of four running both.
+
+2010-09-30 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch find-flaky-tests should print results URLs
+ https://bugs.webkit.org/show_bug.cgi?id=46917
+
+ Printing out the results URL makes find-flaky-tests more actionable
+ because you can see what happens when a test fails. The output from
+ the script is still pretty noisy, but it seems useful.
+
+ * Scripts/webkitpy/tool/commands/queries.py:
+
+2010-09-30 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ Make 2D accelerated canvas rendering build on Mac
+ https://bugs.webkit.org/show_bug.cgi?id=46007
+
+ Added ACCELERATED_2D_CANVAS to build-webkit
+
+ * Scripts/build-webkit:
+
+2010-09-29 Kenneth Russell <kbr@google.com>
+
+ Reviewed by Dimitri Glazkov.
+
+ [chromium] Add accelerated compositing support to DumpRenderTree and test_shell
+ https://bugs.webkit.org/show_bug.cgi?id=46849
+
+ Added offscreen code path for WebGraphicsContext3DDefaultImpl which
+ works with the compositor integration in both DumpRenderTree and
+ test_shell, since both pass a non-null WebCanvas* to WebViewImpl::paint
+ and thereby trigger the compositor's readback code path. Added support
+ for --enable-accelerated-compositing to DumpRenderTree.
+
+ Tested in both test_shell and DumpRenderTree on Linux, the latter by
+ modifying a compositing layout test, dumping the pixels and verifying
+ that they matched the output when the compositor was active.
+
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (main):
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell):
+ (TestShell::resetWebSettings):
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::setAcceleratedCompositingEnabled):
+ * DumpRenderTree/chromium/WebPreferences.cpp:
+ (WebPreferences::reset):
+ (WebPreferences::applyTo):
+ * DumpRenderTree/chromium/WebPreferences.h:
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::scheduleComposite):
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-09-30 Adam Roben <aroben@apple.com>
+
+ Ensure that QueueEngine cleans up its log files when its delegate
+ tells it to stop processing work
+
+ Reviewed by Adam Barth.
+
+ Fixes <http://webkit.org/b/46891> <rdar://problem/8496638> Many tests
+ in webkitpy.tool.bot.queueengine_unittest.QueueEngineTest crash on
+ Windows
+
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ (QueueEngine.run): Stop ourselves normally (including cleaning up log
+ files) when the delegate tells us to stop processing work.
+
+ * Scripts/webkitpy/tool/bot/queueengine_unittest.py:
+ (LoggingDelegate.__init__): Moved code here from
+ RaisingDelegate.__init__.
+ (LoggingDelegate.expeced_callbacks): Added the stop_work_queue
+ callback.
+ (LoggingDelegate.stop_work_queue): Moved here from RaisingDelegate.
+ (RaisingDelegate.__init__): Removed code that LoggingDelegate takes
+ care of for us now.
+ (QueueEngineTest.test_trivial): Make sure we got the expected stop
+ message.
+ (QueueEngineTest.test_not_safe_to_proceed): Changed to explicitly
+ remove the callbacks that are related to processing a single work
+ item, rather than removing all callbacks after a certain point, as
+ there are now more callbacks we expect to receive at the end.
+
+2010-09-30 Adam Roben <aroben@apple.com>
+
+ Fix path -> URL conversion on Cygwin
+
+ Reviewed by Adam Barth.
+
+ Fixes <http://webkit.org/b/46890> <rdar://problem/8496637> Many tests
+ in webkitpy.layout_tests.run_webkit_tests_unittest assert on Windows
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ (Port.filename_to_uri): Treat Cygwin like other UNIX-y platforms by
+ assuming paths already have a leading slash.
+
+2010-09-30 Adam Roben <aroben@apple.com>
+
+ Teach WindowGeometryInitializedBeforeSetWindow that NPP_SetWindow can
+ be called more than once
+
+ The NPP_SetWindow call made when the plugin is torn down was confusing
+ us, and was causing us to spew an error into the next test.
+
+ Fixes <http://webkit.org/b/46900> <rdar://problem/8496888> REGRESSION
+ (r68520): plugins/access-after-page-destroyed.html failing on Windows
+
+ Reviewed by Anders Carlsson.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowGeometryInitializedBeforeSetWindow.cpp:
+ (WindowGeometryInitializedBeforeSetWindow::WindowGeometryInitializedBeforeSetWindow):
+ Initialize member.
+ (WindowGeometryInitializedBeforeSetWindow::NPP_SetWindow): Bail if
+ this isn't the first time this is called.
+
+2010-09-30 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch upload warns that I'm using Xcode when I'm not
+ https://bugs.webkit.org/show_bug.cgi?id=46869
+
+ String.find returns -1 when not found, so switched to "in".
+
+ * Scripts/webkitpy/common/system/user.py:
+ * Scripts/webkitpy/common/system/user_unittest.py:
+
+2010-09-30 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch failure-reason dies if non-trunk commits are in the blame range
+ https://bugs.webkit.org/show_bug.cgi?id=46866
+
+ I also made failure-reason use RegressionWindow in a cleaner way.
+
+ * Scripts/webkitpy/tool/commands/queries.py:
+
+2010-09-29 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch find-flaky-tests
+ https://bugs.webkit.org/show_bug.cgi?id=46876
+
+ This command helps us find flaky tests so we can squash them.
+
+ * Scripts/webkitpy/tool/commands/queries.py:
+
+2010-09-29 Simon Fraser <simon.fraser@apple.com>
+
+ Fix export to use '?' instead of 'null' for
+ tests with no results.
+
+ * CSSTestSuiteHarness/harness/harness.js:
+
+2010-09-29 Simon Fraser <simon.fraser@apple.com>
+
+ Add a warning when a test requires special steps.
+ Add a Print Preview button for 'paged' tests that
+ brings up the print dialog, allowing the user to
+ judge paged media tests.
+
+ * CSSTestSuiteHarness/harness/harness.css:
+ * CSSTestSuiteHarness/harness/harness.html:
+ * CSSTestSuiteHarness/harness/harness.js:
+ (TestSuite.prototype.loadTest):
+ (TestSuite.prototype.processFlags):
+
+2010-09-29 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Remove revisions_casuing_failures
+ https://bugs.webkit.org/show_bug.cgi?id=46872
+
+ This function exists only to be unit tested.
+
+ * Scripts/webkitpy/common/net/failuremap.py:
+ * Scripts/webkitpy/common/net/failuremap_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-09-29 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ SheriffBot should post the list of failing tests to bugs
+ https://bugs.webkit.org/show_bug.cgi?id=46871
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/failuremap.py:
+ * Scripts/webkitpy/common/net/regressionwindow.py:
+ * Scripts/webkitpy/tool/bot/sheriff.py:
+ * Scripts/webkitpy/tool/bot/sheriff_unittest.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-09-29 Brent Fulgham <bfulgham@webkit.org>
+
+ Reviewed by Martin Robinson, Eric Seidel, and Mark Rowe.
+
+ [WinCairo] Adds a build slave.
+ https://bugs.webkit.org/show_bug.cgi?id=46360
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json: Add
+ entries for a debug build of the WinCairo port.
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: Add
+ platform flag to configuration for wincairo (like gtk, chromium, etc.)
+ * Scripts/build-webkit: Change 'cairo-win32' labeling to 'wincairo'
+ * Scripts/webkitdirs.pm: Change 'cairo-win32' labeling to 'wincairo'
+
+2010-09-29 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move more SheriffBot smarts into FailureMap
+ https://bugs.webkit.org/show_bug.cgi?id=46703
+
+ This patch pushes the FailureMap model object further into the
+ SheriffBot machine. In addition, it moves a couple operations on this
+ object from SheriffBot itself to the model.
+
+ Eventually, FailureMap will be the canonical context object for
+ SheriffBot operations. FailureMap represents a map of the current
+ failures on the bots that might require remediation.
+
+ * Scripts/webkitpy/common/net/failuremap.py:
+ * Scripts/webkitpy/common/net/regressionwindow.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-09-29 Tony Chang <tony@chromium.org>
+
+ Reviewed by James Robinson.
+
+ [chromium] enable -Werror for DRT and webkit_unit_tests on Linux
+ https://bugs.webkit.org/show_bug.cgi?id=46829
+
+ * DumpRenderTree/chromium/DRTDevToolsClient.cpp:
+ (DRTDevToolsClient::DRTDevToolsClient):
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::postAccessibilityNotification):
+ (WebViewHost::WebViewHost):
+
+2010-09-29 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ AX: implement CSS3 Speech "speak"
+ https://bugs.webkit.org/show_bug.cgi?id=46827
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (speakCallback):
+ (AccessibilityUIElement::speak):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::speak):
+
+2010-09-29 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Record bot ID when updating queue status
+ https://bugs.webkit.org/show_bug.cgi?id=46764
+
+ Since we now have multiple bots handling patches from the commit queue,
+ we need to differentiate status updates from them, so that we can group
+ the queue status page in a less confusing way.
+
+ * QueueStatusServer/handlers/updatestatus.py: Accept bot_id as input
+ * QueueStatusServer/model/queuestatus.py: Add bot_id property
+ * QueueStatusServer/templates/updatestatus.html: Add bot_id input
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py: Extract MockBrowser
+ * Scripts/webkitpy/common/net/statusserver.py: Add bot_id
+ * Scripts/webkitpy/common/net/statusserver_unittest.py: Added.
+ * Scripts/webkitpy/tool/main.py: Add --bot-id
+ * Scripts/webkitpy/tool/mocktool.py: Add MockBrowser
+
+2010-09-29 Simon Fraser <simon.fraser@apple.com>
+
+ No review.
+
+ References always refert to a file in .xht format, even
+ for HTML tests, so fix their loading.
+
+ * CSSTestSuiteHarness/harness/harness.js:
+ (TestSuite.prototype.loadRef):
+
+2010-09-28 Johnny Ding <jnd@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ https://bugs.webkit.org/show_bug.cgi?id=41292
+ Add a new parameter to the test plugin to allow specifying a script
+ and a mouse/keyboard event. The specified script will be evaluated
+ in the browser when the specified event is received by the plugin.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+ (handleEventCarbon):
+ (handleEventCocoa):
+
+2010-09-28 Simon Fraser <simon.fraser@apple.com>
+
+ Fix export by adding missing argument.
+
+ * CSSTestSuiteHarness/harness/harness.js:
+ (TestSuite.prototype.showResultsForAllTests):
+
+2010-09-28 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix, add missing import.
+
+ * wx/packaging/build-win-installer.py:
+
+2010-09-28 Simon Fraser <simon.fraser@apple.com>
+
+ No review
+
+ Show which tests have been run by dimming them out in the test list.
+
+ Adjust some element sizes.
+
+ * CSSTestSuiteHarness/harness/harness.css:
+ (#test-list > option.untested):
+ (#test-list > option.completed):
+ (#output):
+ (.output-options):
+ * CSSTestSuiteHarness/harness/harness.js:
+ (Test):
+ (TestSuite.prototype.fillTestList):
+ (TestSuite.prototype.updateTestList):
+ (TestSuite.prototype.setSelectedChapter):
+ (TestSuite.prototype.recordResult):
+ (TestSuite.prototype.markTestCompleted):
+ (TestSuite.prototype.testCompletionStateChanged):
+ (TestSuite.prototype.loadTestStatus):
+
+2010-09-28 Simon Fraser <simon.fraser@apple.com>
+
+ No review.
+
+ Implement export of various queries on the test database, sharing
+ code with that which displays results inline.
+
+ * CSSTestSuiteHarness/harness/harness.js:
+ ():
+ (TestSuite.prototype.exportResultsCompletion.var):
+ (TestSuite.prototype.exportResultsCompletion):
+ (TestSuite.prototype.showResultsForCompletedTests):
+ (TestSuite.prototype.exportResultsForCompletedTests):
+ (TestSuite.prototype.showResultsForAllTests):
+ (TestSuite.prototype.exportResultsForAllTests):
+ (TestSuite.prototype.exportResultsForTestsNotRun):
+ (TestSuite.prototype.exportResultsForTestsWithStatus):
+ (TestSuite.prototype.exportResultsForTestsWithMismatchedResults):
+
+2010-09-28 Simon Fraser <simon.fraser@apple.com>
+
+ No review.
+
+ Work around uncertainty about the order of database
+ transactions when creating the database, so that we don't
+ try to query the table before it has been created.
+
+ * CSSTestSuiteHarness/harness/harness.js:
+ (TestSuite):
+ (TestSuite.prototype.databaseCreated):
+ (TestSuite.prototype.storeTestResult):
+ (TestSuite.prototype.populateDatabaseFromTestInfoData):
+ (TestSuite.prototype.queryDatabaseForTestsWithStatus):
+ (TestSuite.prototype.queryDatabaseForTestsWithMixedStatus):
+ (TestSuite.prototype.queryDatabaseForCompletedTests):
+ (TestSuite.prototype.queryDatabaseForTestsNotRun):
+
+2010-09-28 Tony Chang <tony@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ add python keyring support to webkit-patch
+ https://bugs.webkit.org/show_bug.cgi?id=41269
+
+ * Scripts/webkitpy/common/net/credentials.py: Add the ability to read passwords using
+ the python keyring module
+ * Scripts/webkitpy/common/net/credentials_unittest.py:
+ * Scripts/webkitpy/common/system/user.py: Allow confirm() to default to no and add testing params.
+ * Scripts/webkitpy/common/system/user_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-09-28 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [Cairo] FreeType fonts should obey FontConfig hinting/anti-aliasing settings
+ https://bugs.webkit.org/show_bug.cgi?id=46740
+
+ * DumpRenderTree/gtk/fonts/fonts.conf: Add specialized variants of common
+ fonts which can be used to fully test FontConfig rendering settings.
+
+2010-09-28 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [gtk] Fedora has a different path for the liberation fonts
+ https://bugs.webkit.org/show_bug.cgi?id=46709
+
+ When searching for DRT fonts, also look in the path where those fonts
+ are commonly found on Fedora systems.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (initializeFonts): Include logic for looking for Fedora-style font paths.
+
+2010-09-28 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Andreas Kling.
+
+ run-webkit-tests needs an updated list of directories with webgl tests
+ https://bugs.webkit.org/show_bug.cgi?id=46747
+
+ Update the list of directories containing WebGL tests and a unit test
+ which depends on this list.
+
+ * Scripts/old-run-webkit-tests: Update the list of directories.
+ * Scripts/webkitpy/layout_tests/port/webkit.py: Ditto.
+ * Scripts/webkitpy/layout_tests/port/webkit_unittest.py: Update the expected result.
+
+2010-09-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Introduce FailureMap to summaries the failures status of all the bots
+ https://bugs.webkit.org/show_bug.cgi?id=46700
+
+ This patch gives the SheriffBot a handle on the list of failing tests.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/failuremap.py: Added.
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-09-28 Adam Roben <aroben@apple.com>
+
+ Update for the addition of WKPageUIClient::didNotHandleKeyEvent
+
+ Fixes <http://webkit.org/b/46660> <rdar://problem/8483465> Need API to
+ tell a WebKit2 client application that a key event was not handled
+
+ Reviewed by Kenneth Rohde Christiansen and Sam Weinig.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]):
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::create):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ (WTR::TestController::initialize):
+
+2010-09-28 Simon Fraser <simon.fraser@apple.com>
+
+ Unreviewed.
+
+ Update the CSSTestSuiteHarness to not scrape the XHTML chapter files
+ for the test order, but instead use information from testinfo.data.
+
+ * CSSTestSuiteHarness/harness/harness.html:
+ * CSSTestSuiteHarness/harness/harness.js:
+
+2010-09-28 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix, don't try to get the svn revision from the git repo when packaging,
+ it causes the process to hang on the gitorious repo.
+
+ * wx/packaging/build-mac-installer.py:
+ * wx/packaging/build-win-installer.py:
+
+2010-09-28 Adam Roben <aroben@apple.com>
+
+ Test that a plugin's HWND is sized/positioned before NPP_SetWindow is
+ called
+
+ Reviewed by Anders Carlsson.
+
+ Test for <http://webkit.org/b/46716> <rdar://problem/8482014>
+ Full-page Adobe Reader does not paint until window is resized
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp:
+ (PluginTest::NPP_SetWindow): Added. Just returns NPERR_NO_ERROR at
+ this level.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.h: Declared
+ NPP_SetWindow.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowGeometryInitializedBeforeSetWindow.cpp: Added.
+ (WindowGeometryInitializedBeforeSetWindow::NPP_SetWindow): Checks that
+ the plugin's HWND has a non-zero size and that its size/position
+ matches that specified in the NPWindow.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_SetWindow): Call through to the PluginTest.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ Added WindowGeometryInitializedBeforeSetWindow.cpp, and let VS reorder
+ the files as it saw fit.
+
+2010-09-28 Benjamin Poulain <benjamin.poulain@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Remove support for Qt 4.5
+ https://bugs.webkit.org/show_bug.cgi?id=46718
+
+ Remove the code for versions of Qt prior to 4.6.
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::addTouchPoint):
+ (EventSender::updateTouchPoint):
+ (EventSender::setTouchModifier):
+ (EventSender::touchStart):
+ (EventSender::touchMove):
+ (EventSender::touchEnd):
+ (EventSender::clearTouchPoints):
+ (EventSender::releaseTouchPoint):
+ (EventSender::sendTouchEvent):
+ * DumpRenderTree/qt/EventSenderQt.h:
+ * DumpRenderTree/qt/TextInputControllerQt.cpp:
+ (TextInputController::setMarkedText):
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::LauncherWindow):
+ (LauncherWindow::initializeView):
+ (LauncherWindow::createChrome):
+ (LauncherWindow::sendTouchEvent):
+ (LauncherWindow::eventFilter):
+ (LauncherWindow::applyZoom):
+ (LauncherWindow::setTouchMocking):
+ * QtTestBrowser/launcherwindow.h:
+ * QtTestBrowser/utils.cpp:
+ (urlFromUserInput):
+ * QtTestBrowser/webview.cpp:
+ (WebViewGraphicsBased::animatedFlip):
+ (WebViewGraphicsBased::animatedYFlip):
+ * QtTestBrowser/webview.h:
+ (WebViewGraphicsBased::setYRotation):
+
+2010-09-28 İsmail Dönmez <ismail@namtrac.org>
+
+ Reviewed by Andreas Kling.
+
+ Fix DRT compilation on WinCE. Introduce a WCECOMPAT variable
+ which should point to wcecompat installation. Needs wcecompat
+ library from http://github.com/mauricek/wcecompat .
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2010-09-28 Daniel Bates <dbates@rim.com>
+
+ Rollout changeset 68493 <http://trac.webkit.org/changeset/68493>
+ <https://bugs.webkit.org/show_bug.cgi?id=39136>
+
+ Rollout changeset 68493 because it broke Sheriffbot's rollout feature.
+ In particular, this change caused Sheriffbot to raise an exception when
+ trying to parse the bug id on a bug page. We need to look into this
+ some more.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+ * Scripts/webkitpy/tool/bot/sheriff.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/steps/closebug.py:
+ * Scripts/webkitpy/tool/steps/obsoletepatches.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py:
+
+2010-09-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move RegressionWindow further up the dependency chain
+ https://bugs.webkit.org/show_bug.cgi?id=46698
+
+ Baby steps towards pushing this information into bug posts.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+ * Scripts/webkitpy/common/net/regressionwindow.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+
+2010-09-27 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Adam Barth.
+
+ sheriffbot can't roll out security patches
+ https://bugs.webkit.org/show_bug.cgi?id=39136
+
+ Make SheriffBot determine if it's authorized to view a bug
+ whose change it wants to rollout before it tries to rollout
+ the change.
+
+ Moreover, make both webkit-patch and Sheriffbot provide human-
+ readable error messages when they are not authorized to view
+ a bug and when a bug number is invalid.
+
+ Currently, Sheriffbot does not parse Bugzilla bugs for
+ <bug error="...">, which indicates an error when retrieving
+ a bug. In particular, error="NotPermitted" if a person (or bot)
+ is not authorized to view a bug. For such error="NotPermitted" bugs,
+ Sheriffbot raises an exception when parsing the bug report and
+ this exception does not explicitly indicate Sheriffbot's lack
+ of authorization. Instead, Sheriffbot should explicitly check
+ for the presence <bug error="..."> before operating on a bug
+ and error with a human-readable message if it's not permitted
+ to view it.
+
+ * Scripts/webkitpy/common/net/bugzilla.py: Added BugzillaError class.
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+ - Added unit test test_bug_parsing_for_bugzilla_not_permitted_error().
+ - Added unit test test_bug_parsing_for_bugzilla_not_found_error().
+ - Added unit test test_bug_parsing_for_bugzilla_invalid_bug_id_error().
+ * Scripts/webkitpy/tool/bot/sheriff.py: Modified to catch BugzillaError.
+ * Scripts/webkitpy/tool/commands/download.py: Ditto.
+ * Scripts/webkitpy/tool/commands/queues.py: Ditto.
+ * Scripts/webkitpy/tool/commands/upload.py: Ditto.
+ * Scripts/webkitpy/tool/steps/closebug.py: Ditto.
+ * Scripts/webkitpy/tool/steps/obsoletepatches.py: Ditto.
+ * Scripts/webkitpy/tool/steps/preparechangelog.py: Ditto.
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py: Ditto.
+
+2010-09-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Expose more more failure information from Buildbot to SheriffBot
+ https://bugs.webkit.org/show_bug.cgi?id=46697
+
+ This patch moves the information about what tests failured closer to
+ SheriffBot. There are still a couple more patches to go before
+ SheriffBot can post this information to bugs, but this is a step in
+ that direction. Yay for unit tests, which caught some bugs in earlier
+ versions of this patch.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+ * Scripts/webkitpy/common/net/regressionwindow.py: Added.
+ * Scripts/webkitpy/tool/commands/queries.py:
+
+2010-09-27 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Fixing 500 error seen in the status server.
+
+ It turns out that a = b = []; b.append(1); then a[0] will be 1!
+ This should have been obvious to me, I guess, but it was not what I was expecting.
+
+ * QueueStatusServer/model/activeworkitems.py:
+
+2010-09-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ commit-queue should reject patches that fail to land
+ https://bugs.webkit.org/show_bug.cgi?id=46694
+
+ This can happen, for example, if there's no reviewer. Without this
+ patch, we'll keep retrying the patch.
+
+ * Scripts/webkitpy/tool/bot/commitqueuetask.py:
+ * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py:
+
+2010-09-27 Simon Fraser <simon.fraser@apple.com>
+
+ Rubber-stamped by Adele Peterson.
+
+ Add a harness for running the CSS 2.1 test suite.
+
+ This harness assumes that you've got a local a copy of the suite
+ adjacent to the 'harness' directory.
+
+ The harness lets you go through the tests in chapter order,
+ denoting pass/fail/skipped for each test.
+
+ It uses a client-side database to store the results of testing.
+
+ * CSSTestSuiteHarness/harness/harness.css: Added.
+ * CSSTestSuiteHarness/harness/harness.html: Added.
+ * CSSTestSuiteHarness/harness/harness.js: Added.
+
+2010-09-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Patch locks should expire if a patch is marked for retry
+ https://bugs.webkit.org/show_bug.cgi?id=46682
+
+ This was part Adam's original CommitQueueTask design,
+ but support for it was missing from the server.
+ I added the support, but triggering lock-release based on this
+ special "retry" status feels a bit strange so I added a FIXME.
+
+ I also changed the text in queuestatus.html to say "Lock Acquired"
+ since "Last Activity" isn't really true. We only update the lock
+ date when the patch is started, not on every status update.
+
+ I also noticed an exception in next-patch, which I fixed by re-writing
+ the unzip logic in activeworkitems.py again.
+
+ * QueueStatusServer/handlers/updatestatus.py:
+ * QueueStatusServer/model/activeworkitems.py:
+ * QueueStatusServer/templates/queuestatus.html:
+
+2010-09-27 Tony Chang <tony@chromium.org>
+
+ Reviewed by David Levin.
+
+ [chromium] fix a warning when compiling DRT on 32-bit linux
+ https://bugs.webkit.org/show_bug.cgi?id=46641
+
+ * DumpRenderTree/chromium/TestEventPrinter.cpp:
+ (DRTPrinter::handleImage):
+
+2010-09-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ queue-status should report when the patch was last locked to a queue
+ https://bugs.webkit.org/show_bug.cgi?id=46674
+
+ This isn't necessarily the best way to expose this information
+ but having this accessible via the web interface is very
+ useful until we come up with a nicer way to display this.
+
+ I also cleaned up the code in activeworkitems.py a little
+ to use list comprehensions and to have the code work with
+ pairs instead of two lists at once. Eventually I think those
+ item/time pairs need to be their own little helper class.
+
+ * QueueStatusServer/handlers/queuestatus.py:
+ * QueueStatusServer/model/activeworkitems.py:
+ * QueueStatusServer/templates/queuestatus.html:
+
+2010-09-27 Tony Chang <tony@chromium.org>
+
+ Reviewed by David Levin.
+
+ [chromium] fix detection of missing fonts on DRT
+ https://bugs.webkit.org/show_bug.cgi?id=46651
+
+ * DumpRenderTree/chromium/TestShellGtk.cpp:
+ (setupFontconfig): Only print an error message if lohit isn't found in both locations.
+
+2010-09-27 Tony Chang <tony@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ add webkit unit tests to the chromium testers
+ https://bugs.webkit.org/show_bug.cgi?id=46669
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+ * Scripts/run-chromium-webkit-unit-tests: Fix a bug where we weren't using the right configuration.
+
+2010-09-27 Kwang Yul Seo <skyul@company100.net>
+
+ Unreviewed.
+
+ Adding myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-27 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ webkitpy.common.system.user_unittest.UserTest.test_prompt_with_list spams the console
+ https://bugs.webkit.org/show_bug.cgi?id=46634
+
+ Use OutputCapture to prevent console spam (and also check for expected
+ output).
+
+ * Scripts/webkitpy/common/system/user_unittest.py:
+
+2010-09-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by James Robinson.
+
+ start-commit-queue should abort any rebases in progress
+ https://bugs.webkit.org/show_bug.cgi?id=46640
+
+ webkit-patch commit-queue would do this itself, but this just
+ helps ensure that the commit-queue script is properly updated
+ before we run it (in the case where a previous rebase is in
+ progress the git svn rebase would not work before we run the
+ commit-queue).
+
+ * EWSTools/start-commit-queue.sh:
+
+2010-09-18 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] Clean up the DRT fonts.conf and switch to Liberation
+ https://bugs.webkit.org/show_bug.cgi?id=46038
+
+ Switch to Liberation fonts for GTK+ layout tests. This will make our
+ test results metric-compatible with many Windows/Chromium results. It
+ also simplifies the fonts.conf that we load and prepares the way for
+ fixing many font bugs.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (initializeFonts): Initialize a known list of fonts instead of loading
+ every font in the WEBKIT_TESTFONTS directory.
+ * DumpRenderTree/gtk/fonts.conf: Removed.
+ * DumpRenderTree/gtk/fonts/AHEM____.TTF: Copied from WebKitTools/DumpRenderTree/qt/fonts/AHEM____.TTF.
+ * DumpRenderTree/gtk/fonts/fonts.conf: Added.
+ * GNUmakefile.am: Modify FONTS_CONF_FILE to be FONTS_CONF_DIR, so that
+ we can load both fonts.conf and AHEM____.TTF from this location.
+ * Scripts/old-run-webkit-tests: Remove the check for WEBKIT_TESTFONTS, since
+ it is no longer used.
+
+2010-09-26 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-httpd fails if Perl is not installed
+ https://bugs.webkit.org/show_bug.cgi?id=46602
+
+ Make Port._read_configuration catch all exceptions, since trying to run
+ perl (because of _webkit_build_directory) when it's not installed throws
+ a WindowsError or OSError, not an IOError (this became an issue after
+ r68268, since ChromiumPort ends up calling Port.default_configuration in
+ its constructor, which means that we're ending up on this codepath in
+ non-NRWT cases too, e.g. for the Chromium NaCl tests, which use
+ new-run-webkit-httpd).
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+
+2010-09-26 Gyuyoung Kim <gyuyoung.kim@samsung.com>
+
+ Reviewed by Antonio Gomes.
+
+ [EFL] Add setting API to set a local storage database path.
+ https://bugs.webkit.org/show_bug.cgi?id=45446
+
+ Add a setting API to set local storage database path.
+
+ * EWebLauncher/main.c:
+ (on_key_down):
+ (browserCreate):
+ (main):
+
+2010-09-26 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Move shared WebKit2 API (used by both bundle and main API) to WebKit2/Shared/API
+ https://bugs.webkit.org/show_bug.cgi?id=46587
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h:
+
+2010-09-26 Antonio Gomes <agomes@rim.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ DRT/Mac nodesFromRect support
+
+ [Mac][DRT] Implement LayoutTestController::nodesFromRect
+ https://bugs.webkit.org/show_bug.cgi?id=46580
+
+ Implements LayoutTestController::nodesFromRect for Mac DRT, and
+ adding stubs for GTK+ and Windows.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (nodesFromRectCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::LayoutTestController::nodesFromRect):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::nodesFromRect):
+
+2010-09-25 Nicolas Weber <thakis@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ https://bugs.webkit.org/show_bug.cgi?id=46555
+ Fix typo in prepare-ChangeLog's help output.
+
+ * Scripts/prepare-ChangeLog:
+
+2010-09-24 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Implement WebKit2 callback equivalent to -[WebUIDelegate mouseDidMoveOverElement:modifierFlags:]
+ <rdar://problem/8359279>
+ https://bugs.webkit.org/show_bug.cgi?id=46546
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (mouseDidMoveOverElement):
+ (-[BrowserWindowController awakeFromNib]):
+ * MiniBrowser/win/BrowserView.cpp:
+ (mouseDidMoveOverElement):
+ (BrowserView::create):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ (WTR::TestController::initialize):
+
+2010-09-24 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Allow rebaselines for webkit-patch rebaseline to be chosen
+ https://bugs.webkit.org/show_bug.cgi?id=46407
+
+ Instead of always rebaselining all failing tests, allow a subset to be
+ chosen.
+
+ * Scripts/webkitpy/common/system/user.py:
+ * Scripts/webkitpy/tool/commands/rebaseline.py:
+
+2010-09-24 Ryosuke Niwa <rniwa@webkit.org>
+
+ Reviewed by Tony Chang.
+
+ [chromium] Implement TextInputController::firstRectForCharacterRange
+ https://bugs.webkit.org/show_bug.cgi?id=38100
+
+ Implemented TextInputController::firstRectForCharacterRange for chromium platform.
+ No new tests are added since we need to implement the same feature in chromium side
+ in order to enable any tests that uses this function.
+
+ * DumpRenderTree/chromium/TextInputController.cpp:
+ (TextInputController::firstRectForCharacterRange): Added.
+
+2010-09-24 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ commit-queue reports land failures as "PASS"
+ https://bugs.webkit.org/show_bug.cgi?id=46530
+
+ We were ignoring the return value of land instead of passing it back to
+ CommitQueue. Of course, this was the one case I forgot to test!
+
+ * Scripts/webkitpy/tool/bot/commitqueuetask.py:
+ * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py:
+
+2010-09-24 Kenichi Ishibashi <bashi@google.com>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests prints out nothing when build-dumprendertree fails
+ https://bugs.webkit.org/show_bug.cgi?id=37563
+
+ Print error message when build-dumprendertree fails.
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-09-24 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ NRWT doesn't respect config set with set-webkit-configuration
+ https://bugs.webkit.org/show_bug.cgi?id=46278
+
+ Use Port.default_configuration() instead of hardcoding Release in
+ ChromiumPort configuration initialization, so that we still inherit the
+ configuration set by set-webkit-configuration.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+
+2010-09-24 Chang Shu <chang.shu@nokia.com>
+
+ Reviewed by Csaba Osztrogonác.
+
+ [Qt] Fix the code to check file existence.
+ https://bugs.webkit.org/show_bug.cgi?id=46465
+
+ * QtTestBrowser/main.cpp:
+ (main):
+
+2010-09-23 Tony Chang <tony@chromium.org>
+
+ Unreviewed, rolling out r68232.
+ http://trac.webkit.org/changeset/68232
+
+ Broken NRWT on the canary bots.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-09-23 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ r68008 broke new-run-webkit-tests in that the chromium ports no
+ longer respect set-webkit-configuration. The correct fix for this
+ is being pursued in bug 46278 (along with a bunch of unit tests),
+ but in the meantime I'm reverting the particular lines that broke
+ things. This was tested by hand.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-09-23 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ WebKit2 API: Need way to know when a frame is removed from the hierarchy
+ <rdar://problem/8414062>
+ https://bugs.webkit.org/show_bug.cgi?id=46432
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (didRemoveFrameFromHierarchy):
+ (-[BrowserWindowController awakeFromNib]):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize):
+
+2010-09-23 Tony Chang <tony@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [chromium] implement layoutTestController.sampleSVGAnimationForElementAtTime
+ https://bugs.webkit.org/show_bug.cgi?id=46426
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+
+2010-09-23 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Nate Chapin.
+
+ [GTK] r68199 introduced two test failures
+ https://bugs.webkit.org/show_bug.cgi?id=46424
+
+ Fix a regression handling preference overrides that are attached to boolean properties.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::overridePreference): g_strcasecmp returns 0 when strings match
+ so we must check for that when converting a string to a boolean.
+
+2010-09-23 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by David Levin.
+
+ Fix a condition check in ServerProcess, which becomes relevant when reading binary data.
+ https://bugs.webkit.org/show_bug.cgi?id=46406
+
+ This breaks when the method is called with specified size of data (image data), and the
+ buffer hasn't yet reached this size.
+
+ * Scripts/webkitpy/layout_tests/port/server_process.py: Changed to check for values of
+ index larger than 0.
+
+2010-09-23 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Nate Chapin.
+
+ [GTK] Some tests from r68174 fail on the GTK+ bots
+ https://bugs.webkit.org/show_bug.cgi?id=46396
+
+ Simplify LayoutTestController::overridePreference to make it easier for
+ people unfamiliar with the code to keep the list of preferences up to date.
+ Add the conversion for enable-hyperlink-auditing.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::overridePreference): Use a simple if-else block to determine
+ out the property name for overrridePreference. Also simplify the logic for setting
+ string properties. Add the conversion for enable-hyperlink-auditing.
+
+2010-09-23 Tony Chang <tony@chromium.org>
+
+ Reviewed by David Levin.
+
+ [chromium] add caretBrowsingEnabled to WebSettings and DRT
+ https://bugs.webkit.org/show_bug.cgi?id=46388
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::overridePreference):
+ * DumpRenderTree/chromium/WebPreferences.cpp:
+ (WebPreferences::reset):
+ (WebPreferences::applyTo):
+ * DumpRenderTree/chromium/WebPreferences.h:
+
+2010-09-23 Nate Chapin <japhet@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ Allow DRT to toggle hyperlink auditing (i.e., <a ping>).
+ https://bugs.webkit.org/show_bug.cgi?id=30458
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::overridePreference):
+ * DumpRenderTree/chromium/WebPreferences.cpp:
+ (WebPreferences::reset):
+ (WebPreferences::applyTo):
+ * DumpRenderTree/chromium/WebPreferences.h:
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::overridePreference):
+
+2010-09-21 Stephen White <senorblanco@chromium.org>
+
+ Reviewed by David Levin.
+
+ Implement --enable-accelerated-2d-canvas flag in DumpRenderTree.
+ https://bugs.webkit.org/show_bug.cgi?id=46208
+
+ This flag allows the layout tests to be run with or without accelerated
+ 2D canvas rendering.
+
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (main):
+ Declare the new flag string, and check for it on startup.
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell):
+ Add a boolean for the new flag, in order to preserve its value over
+ preferences reset.
+ (TestShell::resetWebSettings):
+ Set the new flag to the stored value on reset.
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::setAccelerated2dCanvasEnabled):
+ Add an accessor for the new flag.
+ * DumpRenderTree/chromium/WebPreferences.cpp:
+ (WebPreferences::reset):
+ Initialize the new flag to false.
+ (WebPreferences::applyTo):
+ Copy the flag's value to the WebSettings.
+ * DumpRenderTree/chromium/WebPreferences.h:
+ Add the new flag.
+
+2010-09-23 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Refactor QtWebKitPlatformPlugin interface
+
+ Make it easier to keep source-compability for the
+ QtWebKitPlatformPlugin interface, and run qmake
+ on the example (but not build) for convenience.
+
+ https://bugs.webkit.org/show_bug.cgi?id=46345
+
+ * Scripts/webkitdirs.pm:
+
+2010-09-23 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Tweak some status messages that Eric thought were confusing
+ https://bugs.webkit.org/show_bug.cgi?id=46342
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-09-22 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix comm-queue typo
+ https://bugs.webkit.org/show_bug.cgi?id=46339
+
+ We were missing a "self". The real problem is that we didn't have an
+ integration test for the failure case.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-09-22 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ commit-queue should log more detailed messages to the QueueStatusServer
+ https://bugs.webkit.org/show_bug.cgi?id=46333
+
+ When I created CommitQueueTask, I removed most of the previous logging.
+ This patch adds back more detailed logging so folks can see their patch
+ progress through the queue.
+
+ * Scripts/webkitpy/tool/bot/commitqueuetask.py:
+ * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-09-22 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ [Chromium] User style layout tests don't pass on Chromium
+ https://bugs.webkit.org/show_bug.cgi?id=46069
+
+ Fix a typo in LayoutTestController::addUserStyleSheet that was causing a
+ crash the Chromium DRT. Pass InjectInExistingDocuments to mimic DRT
+ behavior from other ports.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::addUserStyleSheet):
+
+2010-09-22 Brent Fulgham <bfulgham@webkit.org>
+
+ Reviewed by Martin Robinson.
+
+ [WinCairo] Part 2: Update WebKitTestRunner and DumpRenderTree Build.
+ https://bugs.webkit.org/show_bug.cgi?id=46303.
+
+ * MiniBrowser/Configurations/MiniBrowserCFLite.vsprops: Added.
+ * MiniBrowser/Configurations/MiniBrowserCommon.vsprops: Moved
+ CoreFoundation-specific stuff to new MiniBrowserCoreFoundation
+ property sheet.
+ * MiniBrowser/Configurations/MiniBrowserCoreFoundation.vsprops: Added.
+ * MiniBrowser/MiniBrowser.vcproj: Updated configuration to use
+ appropriate property sheet for the build types.
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj: Updated the
+ configuration to use appropriate property sheet for CoreFoundation
+ and CFLite-style builds.
+
+2010-09-22 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Optimize commit-queue performance for green trees
+ https://bugs.webkit.org/show_bug.cgi?id=46254
+
+ This patch redesigns the controller logic for the commit-queue. In the
+ new design, the controller exercises much finer-grained control over
+ the landing process. In particular:
+
+ - Patches that fail to apply now get rejected almost immediately.
+ - Patches that fail to build get rejects after two builds (instead of
+ three builds and one test run).
+ - Patches that run into a flaky test now get accepted after one build
+ and two test runs instead of three full build-and-test runs.
+
+ The main cost of these optimizations is that we don't find out the tree
+ has a failing test until the very end of the process, but if the tree
+ has a busted test, there's not much we can do anyway. We might as well
+ burn commit-queue resources spinning optimisticly.
+
+ * Scripts/webkitpy/tool/bot/commitqueuetask.py: Added.
+ * Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py: Added.
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-09-22 Brent Fulgham <bfulgham@webkit.org>
+
+ Reviewed by Martin Robinson.
+
+ [WinCairo] Update WebKitTestRunner and DumpRenderTree Build.
+ https://bugs.webkit.org/show_bug.cgi?id=46303.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Disable local MD5 sources
+ for Cairo build. Copy wtf MD5 header to ForwardingHeaders for the
+ WinCairo build.
+ * WebKitTestRunner/Configurations/InjectedBundleCFLite.vsprops: Added.
+ * WebKitTestRunner/win/InjectedBundle.vcproj: Update win new *_Cairo
+ build targets that use the new InjectedBundleCFLite.vsprops file.
+
+2010-09-22 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Fix bustage of rebaseline-chromium-webkit-tests resulting from
+ r67974. Really need better unit tests for this tool :(
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-09-22 Adam Roben <aroben@apple.com>
+
+ Unbreak test-webkitpy
+
+ * Scripts/webkitpy/test/main.py:
+ (Tester.run_tests): Add a line that mysteriously got deleted.
+
+2010-09-22 Adam Roben <aroben@apple.com>
+
+ Make test-webkitpy test WebKit2's scripts
+
+ These scripts can't be in WebKitTools due to limitations of Apple's
+ build process. But that doesn't mean we can't test them!
+
+ Fixes <http://webkit.org/b/46297> test-webkitpy should test code in
+ WebKit2/Scripts
+
+ Reviewed by Adam Barth.
+
+ * Scripts/test-webkitpy:
+ (_clean_packages_with_test): Renamed from _clean_webkitpy_with_test.
+ Now takes an external_package_paths parameter and cleans both webkitpy
+ and any external packages.
+ (init): Added an external_package_paths parameter which we pass along
+ to _clean_packages_with_test.
+ (top level): Add WebKit2/Scripts/webkit2 as our only external package
+ and pass it along to init and Tester.run_tests.
+
+ * Scripts/webkitpy/test/main.py:
+ (Tester.run_tests): Added an optional external_package_paths
+ parameter. We modify sys.path so that the external packages can be
+ imported, and search for unittest files inside all external packages
+ in addition to inside webkitpy.
+
+2010-09-22 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: r68063 broke linux python tests
+
+ Add a missing "from __future__ import with_statement" to this
+ new file; the perils of testing only on the Mac and by review :(
+
+ https://bugs.webkit.org/show_bug.cgi?id=46293
+
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+
+2010-09-22 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Add a 'chromium-gpu' set of ports that will test the accelerated
+ GPU paths. This patch adds:
+
+ - support for the '--accelerated-compositing' and
+ 'accelerated-2d-canvas' flags to new-run-webkit-tests (and the
+ 'no-' flags)
+ - adds a new set of Ports that will look under
+ platform/chromium-gpu-$OS/ for baselines before looking in the
+ regular chromium search path
+ - adds a new test_expectations.txt file in platform/chromium-gpu
+ that skips all but the tests we actually want to run with
+ acceleration.
+
+ This patch will allow us to run both with and without acceleration
+ and to change the defaults for both the regular and -gpu options
+ as the code evolves.
+
+ We plan to add both --chromium-$OS and --chromium-gpu-$OS runs to
+ each test bot.
+
+ https://bugs.webkit.org/show_bug.cgi?id=46225
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_gpu.py:
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-09-22 Jamey Hicks <jamey.hicks@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Web Inspector: Remote Web Inspector support for QtWebKit
+ https://bugs.webkit.org/show_bug.cgi?id=43988
+
+ Runs a web debug server on port specified by QtTestBrowser
+ argument -remote-inspector-port. Property
+ _q_webInspectorServerPort of the QWebPage instance will be set
+ according to the argument. All pages with that property set will
+ be remotely inspectable.
+
+ URL for remote inspection of first QWebPage is
+ http://localhost:9222/webkit/inspector/inspector.html?page=1
+ where 1 is the number of the QWebPage instance.
+
+ The base URL yields an index page with links to the individual inspectors:
+ http://localhost:9222/
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::init):
+ * QtTestBrowser/launcherwindow.h:
+ * QtTestBrowser/main.cpp:
+ (LauncherApplication::handleUserOptions):
+
+2010-09-22 Adam Roben <aroben@apple.com>
+
+ Fix webkit-patch failure-reason now that build.webkit.org has been
+ updated
+
+ Fixes <http://webkit.org/b/46273> webkit-patch failure-reason crashes
+ every time
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ (BuildBot._file_cell_text): Added. Travels down the firstChild chain
+ looking for an element that contains text, then returns it.
+ (BuildBot._parse_twisted_file_row): Use _file_cell_text to get the
+ text out of the cells. This way it doesn't matter whether the cells
+ have <b> children (as for cells in directory rows) or not (as for
+ cells in file rows)
+ (BuildBot._parse_twisted_directory_listing): Look for rows that have
+ the "directory" or "file" class, rather than rows with any class,
+ since header rows now have a class attribute.
+
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+ (BuildBotTest._example_directory_listing): Updated to more closely
+ match the markup that build.webkit.org is producing now.
+
+2010-09-21 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ new-run-webkit-tests: fix bug introduced in r68008 where if you
+ specify --chromium and no --platform, and you're running on
+ windows, you use the 'chromium-win' port by default instead of the
+ version-specific port. This breaks the buildbots.
+
+ It will be good for this refactoring to settle down so I can
+ rewrite the logic for default ports and the unit tests to be
+ clearer (and the testing more comprehensive).
+
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+
+2010-09-21 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Modify the Port interface to take only a series of keyword arguments
+ in the constructor, and modify Port/factory.get() to accomodate that,
+ and to accept user=XXX as an argument so we can pass
+ webkitpy.common.system.user.User objects in.
+
+ Then, modify new-run-webkit-tests and rebaseline-chromium-webkit-tests
+ to use the common routine in webkitpy.common.system.user.open_url()
+ to display HTML files.
+
+ There was a routine in the Port interface to do the same thing,
+ but I see no need for a port-specific hook for this, since it is
+ something that will always be executed by the host environment
+ and displaying web pages has nothing to do with running layout tests.
+
+ Note that new-run-webkit-tests used to use test_shell to display
+ the page; this is potentially useful so that you can actually click
+ from a result to the broken page; however, since DumpRenderTree
+ doesn't support this functionality, it will be going away eventually.
+
+ https://bugs.webkit.org/show_bug.cgi?id=46128
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/google_chrome.py:
+ * Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/gtk.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/qt.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/port/win.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-09-21 Lucas De Marchi <lucas.demarchi@profusion.mobi>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [EFL] Get fresh theme when running EWebLauncher
+ https://bugs.webkit.org/show_bug.cgi?id=46210
+
+ If user tried to run EWebLauncher outside of the build tree, it would
+ not find the theme and fallback to the installed one. However, since
+ EWebLauncher is not installed, we always want to take the theme from
+ the just compiled source code. If user had never installed WebKit's
+ EFL port it could even receive a segv since no theme would be found.
+
+ Now EWebLauncher does not fallback to the installed theme and CMake
+ gives as DATA_DIR the directory of the theme it has just built.
+
+ * CMakeListsEfl.txt: Pass the build directory as DATA_DIR to
+ EWebLauncher.
+ * EWebLauncher/main.c: Use only the theme from build director. Do not
+ fallback to others as this could hide real bugs.
+ (quit):
+ (browserCreate):
+ (findThemePath):
+ (main):
+
+2010-09-21 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Don't pass the --test-shell arg to the Chromium Mac port of DRT;
+ it just confuses it.
+
+ https://bugs.webkit.org/show_bug.cgi?id=46230
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-09-21 Lucas Forschler <lforschler@apple.com>
+
+ Reviewed by Stephanie Lewis.
+
+ Make a new buildbot for Leopard Debug Test
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2010-09-21 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Fix breakage of Chromium Mac DRT port caused by r67905.
+
+ https://bugs.webkit.org/show_bug.cgi?id=46230
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-09-21 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Add missing import of 'tempfile'.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-09-17 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: pull the list of tests from the Port, and
+ make it possible to run with no actual test files in the filesystem.
+
+ This set of changes allows us to delete the special
+ webkitpy/layout_tests/data directory and test the generic code without
+ touching the filesystem (except to write results). This speeds up
+ test-webkitpy substantially.
+
+ This also cleans up and removes several code paths in the generic
+ code and fixes some minor bugs, notably in the test_expectations
+ parsing, which was previously fragile if the tests weren't present.
+
+ We also change the way we diff image results to be able to do so
+ in memory, without relying on files. This slows down chromium
+ test_shell, which always writes images to files, but should speed
+ up DRT and ImageDiff-based implementations slightly.
+
+ Note that pulling the list of tests to run from the Port will allow
+ ports to specify what tests to run as an inclusive list; previously
+ you could only do this as an exclusive list by using a
+ test_expectations file or Skipped files; nothing actually uses this
+ feature yet and it's unclear if it should be used.
+
+ Note that there are no functional changes -- apart from now
+ always printing out the location of the checksum file when we are
+ tracing test runs -- and the total number of lines of non-test code
+ actually drops by two.
+
+ There is some more cleanup that can be done in the Port/Driver
+ interface and in some handling of filenames, but I'll save that
+ for another change.
+
+ https://bugs.webkit.org/show_bug.cgi?id=45801
+
+ * Scripts/webkitpy/layout_tests/data/*: Removed.
+ - no longer need special mock layout_tests_directory in the
+ repository.
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+ - add code to display missing text files, checksums when tracing
+ - update to not look at the filesystem directly.
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+ - add more unit tests
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ - remove tests_are_present flag
+ - update with changes in Port interface - no longer access
+ the filesystem directly, although we still use os.path for
+ filename manipulation.
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py:
+ - add more unit tests
+ * Scripts/webkitpy/layout_tests/layout_package/test_files.py: Removed.
+ - renamed to port/test_files.py
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ - change diff_image() to expect actual image data, not filenames
+ - add expected_checksum(), expected_image(), expected_text() to
+ return the content of the files so that we don't need a filesystem
+ - add path_exists(), path_isdir() for filesystem-like access.
+ - add test_dirs() to keep clobber-test-results from needing to
+ actually look at a real layout tests dir
+ - add tests() to return the list of tests to run on the port
+ (calls port/test_files to do the work).
+ - add update_baseline() to be able to save new baselines
+ - add uri_to_test_name() from port/dryrun.py so we can easily check
+ filename_to_uri()
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ - add more unit tests
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ - change diff_image() to accept image content, not filenames.
+ This will be slower for test_shell/image_diff, but faster
+ for DRT/ImageDiff.
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+ - add more unit tests
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+ - simplify greatly
+ * Scripts/webkitpy/layout_tests/port/port_testcase.py:
+ - add more unit tests
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ - massive rewrite to use in-script list of tests and expectations
+ * Scripts/webkitpy/layout_tests/port/test_files.py:
+ - rename from layout_package/test_files.
+ * Scripts/webkitpy/layout_tests/port/test_files_unittest.py:
+ - add unit tests
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ - update diff_image() to take image contents, not files. Should
+ make things slightly faster.
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ - update with changes to diff_image()
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py:
+ - update with changes to diff_image()
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ - remove tests_are_present from test_expectations
+ - pull the list of tests from port.tests() instead
+ of calling test_files.py directly.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+ - update unit tests
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ - update with changes to
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ - update with change in Port interface
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+ - update with change in Port interface
+ * Scripts/webkitpy/style/checkers/test_expectations.py:
+ - remove the tests_are_present flag
+
+2010-09-21 Anders Carlsson <andersca@apple.com>
+
+ Disable logging.
+
+ * MiniBrowser/mac/MiniBrowser_Prefix.pch:
+
+2010-09-21 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ add a script for running webkit_unit_tests
+ https://bugs.webkit.org/show_bug.cgi?id=46014
+
+ * Scripts/run-chromium-webkit-unit-tests: Added.
+
+2010-09-21 Fridrich Strba <fridrich.strba@bluewin.ch>
+
+ Reviewed by Martin Robinson.
+
+ Fix linking problems on Windows.
+ https://bugs.webkit.org/show_bug.cgi?id=45844
+
+ * GNUmakefile.am: link the executables with winmm.dll
+
+2010-09-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ feeder-queue svn updates more often than needed
+ https://bugs.webkit.org/show_bug.cgi?id=46171
+
+ We don't need to poll SVN every time we feed the feeders. Rather, we
+ can count on the wrapper shell script to auto-update the queue.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-09-21 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Add robot loader timeout and extra time options.
+ https://bugs.webkit.org/show_bug.cgi?id=46172
+
+ [-robot-timeout <s>]: Load the next page after s seconds if the current
+ page didn't finish loading.
+ [-robot-extra-time <s>]: Wait s seconds after the current page finished
+ loading before loading the next one. This should allow some time for the
+ page's JavaScript to execute.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::applyPrefs):
+ * QtTestBrowser/main.cpp:
+ (LauncherApplication::robotTimeout):
+ (LauncherApplication::robotExtraTime):
+ (LauncherApplication::LauncherApplication):
+ (LauncherApplication::handleUserOptions):
+ (main):
+ * QtTestBrowser/urlloader.cpp:
+ (UrlLoader::UrlLoader):
+ (UrlLoader::loadNext):
+ (UrlLoader::loadUrlList):
+ * QtTestBrowser/urlloader.h:
+
+2010-09-21 Pavel Podivilov <podivilov@chromium.org>
+
+ Unreviewed.
+
+ Adding myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-20 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by Eric Carlson.
+
+ [GTK] enhanced context menu for media elements
+ https://bugs.webkit.org/show_bug.cgi?id=45021
+
+ EventSender::contextClick() now returns an array of js
+ objects. Each object has a title property and a click() method.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (getMenuItemTitleCallback):
+ (setMenuItemTitleCallback):
+ (menuItemClickCallback):
+ (getMenuItemClass):
+ (contextClickCallback):
+
+2010-09-20 Hayato Ito <hayato@chromium.org>
+
+ Unreviewed.
+ Adding myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ The tool member variable should be called _tool
+ https://bugs.webkit.org/show_bug.cgi?id=46160
+
+ Created by find-and-replace.
+
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/openbugs.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/rebaseline.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/multicommandtool.py:
+
+2010-09-20 Adam Barth <abarth@webkit.org>
+
+ I ran the tests before landing but ignored the fact that they failed. :(
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-09-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add a feeder queue that polls bugs.webkit.org for the commit-cluster
+ https://bugs.webkit.org/show_bug.cgi?id=46141
+
+ The feeder-queue polls bugs.webkit.org every 30 seconds and updates the
+ list of work items on the status server. The individual commit-cluster
+ nodes then grab the patches from the server and process them.
+
+ * Scripts/webkitpy/tool/bot/feeders.py: Added.
+ * Scripts/webkitpy/tool/bot/feeders_unittest.py: Added.
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+
+2010-09-20 Leandro Pereira <leandro@profusion.mobi>
+
+ Reviewed by Darin Adler.
+
+ build-webkit: Add support for CMake build system
+ https://bugs.webkit.org/show_bug.cgi?id=44979
+
+ * Scripts/build-webkit: Add "--efl" command-line option to build the
+ EFL port of WebKit.
+ * Scripts/webkitdirs.pm: Define buildCMakeProject() and
+ buildEflCMakeProject() subroutines.
+
+2010-09-20 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: refactor command line args getting passed to DRT
+
+ This change cleans up some argument parsing between functions to get
+ rid of some overlapping data structures. There should be no functional
+ changes in this patch; it is pure refactoring in preparation for
+ landing the Chrome GPU port and adding a generic way to pass
+ args to DRT/TestShell.
+
+ https://bugs.webkit.org/show_bug.cgi?id=46135
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ - pass the options argument explicitly to the threads and drivers,
+ also consolidate the passing of options to the driver.
+ - pass options directly to process_output() to remove a couple
+ parameters (minor cleanup).
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ - pass the options argument to Port.create_driver().
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ - update Port.create_driver() test
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ - pass the options argument to Port.create_driver(), and clean up
+ building of the cmd line for DRT.
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+ - pass the options argument to Port.create_driver()
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ - pass the options argument to Port.create_driver()
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ - pass the options argument to Port.create_driver(), and clean up
+ building of the cmd line for DRT.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ - consolidate args in _get_dump_render_tree_args and rename to
+ _get_test_args(); move all of the command-line args to the
+ Port implementations.
+
+2010-09-20 Andrew Wilson <atwilson@chromium.org>
+
+ Revert change which was accidentally committed along with some expectation changes.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+
+2010-09-20 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Add explicit --force-patch flag to webkitpy tools
+ https://bugs.webkit.org/show_bug.cgi?id=46103
+
+ It wasn't obvious until I read the applypatch.py source code that
+ --non-interfactive implies passing --force to patch. Add --force-patch
+ as an alias to the flag, so that this behavior is more discoverable.
+
+ * Scripts/webkitpy/tool/steps/applypatch.py:
+ * Scripts/webkitpy/tool/steps/options.py:
+
+2010-09-20 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, adding a line which got dropped and is trivially correct (and tested).
+
+ commit-queue can't land patches
+ https://bugs.webkit.org/show_bug.cgi?id=46138
+
+ Add a line of code I forgot in my last commit.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+
+2010-09-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ The commit-cluster bots still race to lock patch_ids
+ https://bugs.webkit.org/show_bug.cgi?id=46130
+
+ It turns out we need to use a transaction object to make the
+ read/modify/write lock operation atomic. From reading the AppEngine
+ documentation, I think this patch should do what we want. It's hard to
+ test locally because the test instance isn't distributed in the same
+ way the production instance is.
+
+ * QueueStatusServer/handlers/nextpatch.py:
+ * QueueStatusServer/model/activeworkitems.py: Added.
+
+2010-09-20 Andy Estes <aestes@apple.com>
+
+ Reviewed by Adam Barth.
+
+ REGRESSION (HTML5 Parser): Pages broken due to <tag<tag> parsing changes
+ https://bugs.webkit.org/show_bug.cgi?id=40961
+
+ Implement WebKitUsePreHTML5ParserQuirks preference.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues): Reset WebKitUsePreHTML5ParserQuirks
+ to false after a test finishes.
+
+2010-09-20 Adam Roben <aroben@apple.com>
+
+ Windows build fix
+
+ * MiniBrowser/Configurations/MiniBrowserCommon.vsprops: Put
+ $(WebKitOutputDir)\include before $(WebKitLibrariesDir)\include so
+ we'll pick up the most recent versions of the headers.
+
+2010-09-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue should check commit-queue+ again just before committing
+ https://bugs.webkit.org/show_bug.cgi?id=32679
+
+ Added a _revalidate_patch check, right before landing.
+
+ Since _revalidate_patch passes the patch_id from the work item
+ back to bugzilla, I had to fix all of the previous queue tests to
+ use valid attachment ids (that's the majority of this change).
+
+ In order to validate that the bug was still open, I had to teach
+ bugzilla.Bug about open/closed states.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-09-20 Mihai Parparita <mihaip@chromium.org>
+
+ Unreviewed.
+
+ Adding myself as a comitter.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Two instances of commit-queue try to process the same patch
+ https://bugs.webkit.org/show_bug.cgi?id=46113
+
+ This patch makes next-patch atomic so that the server won't vend the
+ same patch twice in the same hour.
+
+ * QueueStatusServer/handlers/nextpatch.py:
+
+2010-09-20 Adam Roben <aroben@apple.com>
+
+ Make WebKitTestRunner's wait-to-dump watchdog timer work on Windows
+
+ We were previously trying to use a CFRunLoopTimer, but since Windows
+ doesn't use CFRunLoop on most threads this doesn't work. Now we use a
+ Windows-style timer on Windows.
+
+ I also replaced all uses of "watchdog" with "watchdog timer".
+
+ Fixes <http://webkit.org/b/46101> WebKitTestRunner's wait-to-dump
+ watchdog timer doesn't work on Windows
+
+ Reviewed by Anders Carlsson.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::dump): Updated for rename.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: Removed
+ platform-specific functions.
+ (WTR::LayoutTestController::LayoutTestController): Added call to
+ platformInitialize.
+ (WTR::LayoutTestController::waitUntilDone): Changed to call
+ initializeWaitToDumpWatchdogTimerIfNeeded instead of doing the work
+ right in this function.
+ (WTR::LayoutTestController::waitToDumpWatchdogTimerFired): Updated for
+ rename.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h: Added new
+ members needed to support the watchdog timer abstraction. Replaced
+ some "watchdog"s with "watchdog timer".
+
+ * WebKitTestRunner/InjectedBundle/mac/LayoutTestControllerMac.mm:
+ Added.
+ (WTR::LayoutTestController::platformInitialize): Does nothing on this
+ platform.
+ (WTR::LayoutTestController::invalidateWaitToDumpWatchdog): Moved here
+ from LayoutTestController.cpp and changed to use an early return.
+ (WTR::waitUntilDoneWatchdogTimerFired): Moved here from
+ LayoutTestController.cpp.
+ (WTR::LayoutTestController::initializeWaitToDumpWatchdogTimerIfNeeded):
+ Moved code here from LayoutTestController::waitUntilDone and changed
+ to use an early return.
+
+ * WebKitTestRunner/InjectedBundle/win/LayoutTestControllerWin.cpp:
+ Added.
+ (WTR::LayoutTestController::platformInitialize): Initialize our
+ watchdog timer.
+ (WTR::LayoutTestController::invalidateWaitToDumpWatchdog): Added.
+ Kills and clears the watchdog timer.
+ (WTR::waitToDumpWatchdogTimerFired): Added. Calls through to the
+ LayoutTestController member function of the same name.
+ (WTR::LayoutTestController::initializeWaitToDumpWatchdogTimerIfNeeded):
+ Added. Sets up the timer if it isn't already set.
+
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj: Added
+ LayoutTestControllerMac.mm.
+
+ * WebKitTestRunner/win/InjectedBundle.vcproj: Added
+ LayoutTestControllerWin.cpp.
+
+2010-09-20 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Daniel Bates.
+
+ [GTK] fast/forms/listbox-selection.html fails
+ https://bugs.webkit.org/show_bug.cgi?id=45942
+
+ Use the gdkModifersFromJSValue helper to parse all appropriate modifier
+ strings in keyDownCallback.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (keyDownCallback): Use the gdkModifersFromJSValue instead of duplicating the
+ modifier parsing logic.
+
+2010-09-19 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ WebKit2 decidePolicyForNavigationAction should include mouse button information
+ <rdar://problem/8413165>
+ https://bugs.webkit.org/show_bug.cgi?id=46060
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (decidePolicyForNavigationAction):
+ (decidePolicyForNewWindowAction):
+
+2010-09-19 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Martin Robinson.
+
+ Add unit tests for diffs that delete or modify a change log entry
+ or describe changes that are far apart
+ https://bugs.webkit.org/show_bug.cgi?id=46046
+
+ Add additional unit tests to test change log diffs that contain
+ deletions or changes that are far apart from each other in the
+ ChangeLog file.
+
+ * Scripts/webkitperl/VCSUtils_unittest/fixChangeLogPatch.pl:
+ - Added the following unit tests:
+ "fixChangeLogPatch: [no change] In-place change."
+ "fixChangeLogPatch: [no change] Remove first entry."
+ "fixChangeLogPatch: [no change] Remove entry in the middle."
+ "fixChangeLogPatch: [no change] Far apart changes (i.e. more than one chunk)."
+
+2010-09-19 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Replace WKBundleRangeRef with WKBundleRangeHandleRef.
+ https://bugs.webkit.org/show_bug.cgi?id=46054
+
+ The new one acts like WKBundleNodeHandleRef and allows for getting a
+ wrapper in a specific world for the handle.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::propertyValue):
+ (WTR::propertyValueDouble):
+ (WTR::propertyValueInt):
+ (WTR::numericWindowPropertyValue):
+ (WTR::toStr):
+ (WTR::InjectedBundlePage::shouldBeginEditing):
+ (WTR::InjectedBundlePage::shouldEndEditing):
+ (WTR::InjectedBundlePage::shouldInsertNode):
+ (WTR::InjectedBundlePage::shouldInsertText):
+ (WTR::InjectedBundlePage::shouldDeleteRange):
+ (WTR::InjectedBundlePage::shouldChangeSelectedRange):
+ (WTR::InjectedBundlePage::shouldApplyStyle):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+
+2010-09-19 Kent Tamura <tkent@chromium.org>
+
+ Unreviewed. Fix WebGL test regressions by r67809.
+
+ * DumpRenderTree/chromium/WebPreferences.cpp:
+ (WebPreferences::applyTo): Call setExperimentalWebGLEnabled().
+
+2010-09-19 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ [DRT/Chromium] Fix a WebSettings handling bug
+ https://bugs.webkit.org/show_bug.cgi?id=45945
+
+ Before this change, Chromium DRT reset WebSettings for every new
+ window. It was wrong.
+ If new window is not the first one, we have to apply the same
+ settings as the first window. So, we introduce WebPreference to
+ store the current settings, and apply it to new windows. It's same
+ as test_shell's behavior.
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ Use WebPreferences instead of WebSettings.
+ (LayoutTestController::setUserStyleSheetEnabled):
+ (LayoutTestController::setUserStyleSheetLocation):
+ (LayoutTestController::setAuthorAndUserStylesEnabled):
+ (LayoutTestController::setPopupBlockingEnabled):
+ (LayoutTestController::disableImageLoading):
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+ (LayoutTestController::setXSSAuditorEnabled):
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+ (LayoutTestController::setAllowFileAccessFromFileURLs):
+ (LayoutTestController::overridePreference):
+ (LayoutTestController::setEditingBehavior):
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::resetWebSettings): Use WebPreferences.
+ (TestShell::runFileTest): ditto.
+ (TestShell::createNewWindow): Apply existing WebPreferences to a new WebView.
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::preferences):
+ (TestShell::applyPreferences):
+ * DumpRenderTree/chromium/WebPreferences.cpp: Added.
+ * DumpRenderTree/chromium/WebPreferences.h: Added.
+
+2010-09-18 Prasad Tammana <prasadt@chromium.org>
+
+ Reviewed by David Levin.
+
+ update-webkit --chromium spitting out a spurious error
+ https://bugs.webkit.org/show_bug.cgi?id=45868
+
+ * Scripts/update-webkit-chromium: Use commandExists() function to check for existence of gclient.
+
+2010-09-18 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ Improve/unify the PageLoadClient interfaces
+ https://bugs.webkit.org/show_bug.cgi?id=46043
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (didStartProvisionalLoadForFrame):
+ (didReceiveServerRedirectForProvisionalLoadForFrame):
+ (didFailProvisionalLoadWithErrorForFrame):
+ (didCommitLoadForFrame):
+ (didFinishDocumentLoadForFrame):
+ (didFinishLoadForFrame):
+ (didFailLoadWithErrorForFrame):
+ (didReceiveTitleForFrame):
+ (didFirstLayoutForFrame):
+ (didFirstVisuallyNonEmptyLayoutForFrame):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::didStartProvisionalLoadForFrame):
+ (WTR::InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame):
+ (WTR::InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame):
+ (WTR::InjectedBundlePage::didCommitLoadForFrame):
+ (WTR::InjectedBundlePage::didFinishLoadForFrame):
+ (WTR::InjectedBundlePage::didFinishDocumentLoadForFrame):
+ (WTR::InjectedBundlePage::didFailLoadWithErrorForFrame):
+ (WTR::InjectedBundlePage::didReceiveTitleForFrame):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::didReceiveMessageFromInjectedBundle):
+ (WTR::TestController::didFinishLoadForFrame):
+ * WebKitTestRunner/TestController.h:
+
+2010-09-17 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Adding a shell script I use to run the
+ commit-queue. Now that multiple machines run the cq,
+ it makes sense to share the script between them.
+
+ * EWSTools/start-commit-queue.sh: Added.
+
+2010-09-17 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Jon Honeycutt.
+
+ The colors on the new build.webkit.org (after upgrading the master to 0.8.1) are
+ slightly harder to read, so this reverts the previous background colors for various
+ states, making it easier to read.
+
+ * BuildSlaveSupport/build.webkit.org-config/public_html/default.css:
+ (.success):
+ (.failure):
+ (.warnings):
+ (.exception):
+ (.start,.running,td.building):
+ (.offline,td.offline):
+
+2010-09-17 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r67692.
+ http://trac.webkit.org/changeset/67692
+ https://bugs.webkit.org/show_bug.cgi?id=46011
+
+ broke layout test dashboard (Requested by johnny_g on
+ #webkit).
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-09-17 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Oliver Hunt.
+
+ Style bot complains about cairo forward declaration naming
+ https://bugs.webkit.org/show_bug.cgi?id=45867
+
+ Exclude Cairo forward declarations from indentifiers with underscores checks.
+
+ * Scripts/webkitpy/style/checkers/cpp.py: Add exclusion for Cairo forward-declarations.
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py: Add some tests for this.
+
+2010-09-16 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Include detailed test modifiers (e.g. FLAKY) in results.json for failing non-layout tests
+ https://bugs.webkit.org/show_bug.cgi?id=45408
+
+ This change also tries to remove duplicated upload_results_json methods
+ in run_webkit_tests.py and json_results_generator.py.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-09-16 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] When switching views (WebViewGraphicsBased <--> WebViewTraditional), QWebPage signals and QActions have to be re-set.
+
+ Recently r67554 changed the way different views use the WebPage class: it was previously being shared between
+ different views, but now for each view switch, a new WebPage class is constructed and set. Signals and QAction's
+ were not being set to the new WebPage though. Patch fix that, by re constructing the toolbar, and then re-hooking
+ all page specific stuff to the UI.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::initializeView):
+ * QtTestBrowser/mainwindow.cpp:
+ (MainWindow::MainWindow):
+ (MainWindow::buildUI):
+ (MainWindow::setPage):
+ * QtTestBrowser/mainwindow.h:
+
+2010-09-12 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ Make all accesses to m_item (GraphicsWebView) done by WebViewGraphicsBased class happen though graphicsWebView getter method.
+
+ This patch is mostly a preparation for another commit, where the ownership of the m_item/GraphicsWebView
+ object will move to the qgraphicsscene instead of the qgraphicsview.
+
+ * QtTestBrowser/webview.cpp:
+ (WebViewGraphicsBased::setPage):
+ (WebViewGraphicsBased::setResizesToContents):
+ (WebViewGraphicsBased::resizeEvent):
+ (WebViewGraphicsBased::animatedFlip):
+ * QtTestBrowser/webview.h:
+ (WebViewGraphicsBased::setItemCacheMode):
+ (WebViewGraphicsBased::itemCacheMode):
+
+2010-09-12 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ Moved setYRotation method body out of the class (WebViewGraphicsBased) definition.
+
+ We usually separate methods whose body are larger than a few lines from the class definition.
+
+ * QtTestBrowser/webview.h:
+ (WebViewGraphicsBased::yRotation):
+ (WebViewGraphicsBased::setYRotation):
+
+2010-09-12 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ Make initializeView method of LauncherWindow private.
+
+ No one else needs to be able to call it but LauncherWindow.
+ Also moving the declation of isGraphicsBased method down in the same file, in order
+ to better group related methods.
+
+ * QtTestBrowser/launcherwindow.h:
+
+2010-09-12 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ Make the getter 'page' method of MainWindow const.
+
+ * QtTestBrowser/mainwindow.cpp:
+ (MainWindow::page):
+ * QtTestBrowser/mainwindow.h:
+
+2010-09-12 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ Remove useless parameter from MainWindow class' constructor.
+
+ The parameter defaults to an empty URL and is not being used by any caller. Apart from that it is also
+ not referred in the constructor body and does not make much sense.
+
+ * QtTestBrowser/mainwindow.cpp:
+ (MainWindow::MainWindow):
+ * QtTestBrowser/mainwindow.h:
+
+2010-09-15 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [Chromium] Needs DRT queueLoadHTMLString and setDeferMainResourceLoad-implementations
+ https://bugs.webkit.org/show_bug.cgi?id=42151
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (WorkItemLoadHTMLString::WorkItemLoadHTMLString):
+ (WorkItemLoadHTMLString::run):
+ (LayoutTestController::queueLoadHTMLString):
+ (LayoutTestController::reset):
+ (LayoutTestController::setDeferMainResourceDataLoad):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ (LayoutTestController::deferMainResourceDataLoad):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::didCreateDataSource):
+
+2010-09-16 Adrienne Walker <enne@google.com>
+
+ Reviewed by Kenneth Russell.
+
+ Add script to synchronize WebKit and Khronos WebGL tests
+ https://bugs.webkit.org/show_bug.cgi?id=42336
+
+ * Scripts/update-webgl-conformance-tests: Added.
+ * Scripts/webkitpy/layout_tests/update_webgl_conformance_tests.py: Added.
+ * Scripts/webkitpy/layout_tests/update_webgl_conformance_tests_unittest.py: Added.
+
+2010-09-16 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add support for sending synchronous messages from the InjectedBundle to the WKContext
+ <rdar://problem/8365320>
+ https://bugs.webkit.org/show_bug.cgi?id=44785
+
+ * MiniBrowser/mac/AppDelegate.m:
+ (didReceiveSynchronousMessageFromInjectedBundle):
+ (-[BrowserAppDelegate init]):
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (didCreatePage):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize):
+
+2010-09-16 Leonid Ebril <leonid.ebril@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] QtTestBrowser: Disable creation of a new window for screenshot on Symbian platform.
+ https://bugs.webkit.org/show_bug.cgi?id=45885
+
+ Avoid creation of an additional window for screenshot to prevent overlapping with original window.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::screenshot):
+
+2010-09-16 Anders Carlsson <andersca@apple.com>
+
+ Fix clang++ build.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController zoomIn:]):
+ (-[BrowserWindowController zoomOut:]):
+ (-[BrowserWindowController resetZoom:]):
+ Remove trailing semicolons.
+
+2010-09-16 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r67628.
+ http://trac.webkit.org/changeset/67628
+ https://bugs.webkit.org/show_bug.cgi?id=45904
+
+ broke the build (Requested by eric_carlson on #webkit).
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (contextClickCallback):
+
+2010-09-16 Balazs Kelemen <kbalazs@webkit.org>
+
+ Unreviewed.
+
+ Adding myself as a comitter.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-15 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by Eric Carlson.
+
+ [GTK] enhanced context menu for media elements
+ https://bugs.webkit.org/show_bug.cgi?id=45021
+
+ EventSender::contextClick() now returns an array of js
+ objects. Each object has a title property and a click() method.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (getMenuItemTitleCallback):
+ (setMenuItemTitleCallback):
+ (menuItemClickCallback):
+ (getMenuItemClass):
+ (contextClickCallback):
+
+2010-09-14 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by Eric Carlson and Martin Robinson.
+
+ [GTK] eventSender.contextClick() should return the contents of the context menu
+ https://bugs.webkit.org/show_bug.cgi?id=39102
+
+ Make the eventSender use the new private WebKitGtk+ API to
+ retrieve the context-menu item titles and store them in an array.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (contextClickCallback):
+
+2010-09-16 Eric Uhrhane <ericu@chromium.org>
+
+ Reviewed by Jian Li.
+
+ Unify FILE_SYSTEM and FILE_WRITER enables under the name FILE_SYSTEM.
+ https://bugs.webkit.org/show_bug.cgi?id=45798
+
+ * Scripts/build-webkit:
+
+2010-09-16 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] Support globalhistory tests
+ https://bugs.webkit.org/show_bug.cgi?id=45774
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::isGlobalHistoryTest):
+ (WebCore::DumpRenderTree::open):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::dumpHistoryCallbacks):
+ (LayoutTestController::removeAllVisitedLinks):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-09-10 Tony Chang <tony@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ deduplicate-tests should be runnable from any WebKit directory
+ https://bugs.webkit.org/show_bug.cgi?id=44709
+
+ * Scripts/webkitpy/layout_tests/deduplicate_tests.py:
+ * Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py:
+
+2010-09-15 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] sort testing methods in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=45850
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::EventSender):
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ * DumpRenderTree/chromium/TextInputController.cpp:
+ (TextInputController::TextInputController):
+
+2010-09-15 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ CQ status shows items out of order
+ https://bugs.webkit.org/show_bug.cgi?id=45846
+
+ Only group consecutive status items with the same patch ID into the same
+ group, so that overall item ordering is preserved.
+
+ Also don't indent status items that only have a single item in their
+ group.
+
+ * QueueStatusServer/handlers/queuestatus.py:
+ * QueueStatusServer/templates/includes/singlequeuestatus.html: Added.
+ * QueueStatusServer/templates/queuestatus.html:
+
+2010-09-15 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add queue start/stop messages
+ https://bugs.webkit.org/show_bug.cgi?id=45853
+
+ I ended up needing to clean up a bunch of our unit testing
+ in order to test this new code path nicely.
+
+ There are also a few PEP8 changes needed to pass check-webkit-style.
+
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/bot/queueengine_unittest.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+
+2010-09-15 Simon Fraser <simon.fraser@apple.com>
+
+ https://bugs.webkit.org/show_bug.cgi?id=45849
+ WKURLCreateWithCFURL crashes with null url
+
+ Fix MiniBrowser crash when the url is not parseable.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController fetch:]):
+
+2010-09-15 Patrick Gansterer <paroga@paroga.com>
+
+ Unreviewed.
+
+ Adding myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make it possible to run more than one commit-queue instance
+ https://bugs.webkit.org/show_bug.cgi?id=45786
+
+ Mostly we need to make sure the two (or more) instances get
+ different patches to work on. To do this, I re-worked
+ the code responsible for getting the next work item to
+ round trip through the status server. The status server only
+ vends patches from the work items list, only if those patches
+ have not had status reported for them in the last hour.
+
+ This is another step towards making all queues go through the
+ status server, thus making it possible to run more than one
+ instance of various EWS bots (as requested in bug 44292).
+
+ The webkitpy changes are already covered by existing unit tests.
+ The QueueStatusSever sadly has no testing infrastructure yet. :(
+
+ * QueueStatusServer/handlers/nextpatch.py: Added.
+ * QueueStatusServer/index.yaml:
+ * QueueStatusServer/main.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-09-15 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ NRWT fails with UnicodeDecodeError on editing/selection/mixed-editability-10.html
+ https://bugs.webkit.org/show_bug.cgi?id=45791
+
+ Force filenames to be raw bytes before running difflib.unified_diff.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+
+2010-09-15 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [Qt] QtTestBrowser crashes when enabling QGraphicsView mode after first loading page without it enabled
+ https://bugs.webkit.org/show_bug.cgi?id=35247
+
+ The main issue when changing the views is that the plugins and any other components that
+ depend on view specific attributes such as the native window id are not teared down.
+ Even if we had a tear-down procedure, we'd have to re-initialize the plugin after
+ switching to the new view (QGraphicsWebView). This is a rather uncommon situation, so
+ we decided to work around this in QtTestBrowser by making toggling between QWebView
+ and QGraphicsWebView also re-create the page.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::initializeView):
+ * QtTestBrowser/mainwindow.h:
+
+2010-09-14 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Send webkit accessibility notifications to Chromium
+ https://bugs.webkit.org/show_bug.cgi?id=45156
+
+ Move printf inside shouldDumpAccessibilityNotifications check.
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::postAccessibilityNotification):
+
+2010-09-14 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] fix http/tests/security/local-user-CSS-from-remote.html
+ https://bugs.webkit.org/show_bug.cgi?id=45788
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setUserStyleSheetLocation): use a base64 url like in Chrome
+
+2010-09-14 Tony Chang <tony@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ [chromium] Remove WebKit::areLayoutTestImagesOpaque since it's no longer needed
+ https://bugs.webkit.org/show_bug.cgi?id=45768
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::dumpImage): new baselines are checked in and Linux will match Windows going forward.
+
+2010-09-14 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix, add newly added directories to the directory list.
+
+ * wx/build/settings.py:
+
+2010-09-14 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Remove WKBundleNodeRef, replacing uses with WKBundleNodeHandleRef.
+ https://bugs.webkit.org/show_bug.cgi?id=45785
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::propertyValue):
+ (WTR::numericWindowPropertyValue):
+ (WTR::dumpPath):
+ (WTR::toStr):
+ (WTR::operator<<):
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::shouldInsertNode):
+ (WTR::InjectedBundlePage::shouldBeginEditing):
+ (WTR::InjectedBundlePage::shouldEndEditing):
+ (WTR::InjectedBundlePage::shouldInsertText):
+ (WTR::InjectedBundlePage::shouldDeleteRange):
+ (WTR::InjectedBundlePage::shouldChangeSelectedRange):
+ (WTR::InjectedBundlePage::shouldApplyStyle):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+
+2010-09-14 Adam Barth <abarth@webkit.org>
+
+ Fix two typos in commit-queue. The first is harmless. The second
+ causes the queue to reject patches when the build is broken. :(
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-09-14 Chris Guillory <chris.guillory@google.com>
+
+ Reviewed by Chris Fleizach.
+
+ Send all accessibility notifications to Chromium.
+ https://bugs.webkit.org/show_bug.cgi?id=45156
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::postAccessibilityNotification):
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-09-14 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ commit-queue is slow during the day
+ https://bugs.webkit.org/show_bug.cgi?id=45780
+
+ Thanks to the new logging, we've noticed that checkout-is-out-of-date
+ errors in the first pass of landing don't retry the land. Instead,
+ they're treated as failures and cause the commit-queue to do two more
+ builds before really trying to land the patch. Worse, in the second
+ build, we can get bitten by a flaky test.
+
+ This patch takes a slightly different approach to the commit-queue's
+ main control logic. We now use a separate subprocess for building and
+ testing and for landing. This means we should very rarely see the
+ checkout-is-out-of-date error, and when we do see it, we should retry
+ more quickly. If my understanding is correct, this should be a big
+ speed win for the commit-queue.
+
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-09-14 Tony Chang <tony@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [chromium] implement layoutTestController.setDomainRelaxationForbiddenForURLScheme
+ https://bugs.webkit.org/show_bug.cgi?id=45762
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::setDomainRelaxationForbiddenForURLScheme):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+
+2010-09-14 Csaba Osztrogonác <ossy@webkit.org>
+
+ Adding myself as a reviewer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-14 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Build-webkit shows a warning when WebKitBuild directory is not exist
+ https://bugs.webkit.org/show_bug.cgi?id=45736
+
+ Build-webkit has showed a warning when WebKitBuild didn't exist, add
+ an additional condition to avoid it.
+
+ * Scripts/build-webkit:
+
+2010-09-13 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue should log when it's retrying due to checkout out of date error
+ https://bugs.webkit.org/show_bug.cgi?id=45725
+
+ This will allow us to better track how often we see these errors
+ and how long it takes the queue to recover from them.
+
+ In order to pass the tests, I had to correct an error
+ from a previous change. The UnitTestPort should not have
+ ever been using the base port method as that will read
+ a file from disk. If the unit tests haven't passed the contents
+ it should raise an IOError as though the file doesn't exist.
+
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-09-13 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Upload results when cq patch landing fails
+ https://bugs.webkit.org/show_bug.cgi?id=45683
+
+ Include script errors when CommitQueue._land fails.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-09-13 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by David Kilzer.
+
+ AX: accessibilityIsIgnored is returning nil when return value expects a BOOL
+ https://bugs.webkit.org/show_bug.cgi?id=45548
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (isIgnoredCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::isIgnored):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::isIgnored):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::isIgnored):
+
+2010-09-13 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ jscPath() is incorrect in Windows' cmd.exe shell
+ https://bugs.webkit.org/show_bug.cgi?id=45651
+
+ * Scripts/webkitdirs.pm: Add ".exe" suffix to $jscName on Windows.
+
+2010-09-13 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ REGRESSION (r64816-r64889): Crash in WebCore::AccessibilityRenderObject
+ https://bugs.webkit.org/show_bug.cgi?id=43807
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (textMarkerForPointCallback):
+ (AccessibilityUIElement::textMarkerForPoint):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::textMarkerForPoint):
+
+2010-09-13 Andreas Kling <andreas.kling@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] build-webkit: Add --v8 option to build against V8
+
+ Note that V8 is picked up from QtScript, so this currently requires building
+ against the experimental qt-script-v8 branch.
+
+ * Scripts/build-webkit:
+
+2010-09-13 Hans Wennborg <hans@chromium.org>
+
+ Reviewed by Jeremy Orlow.
+
+ Add WebDeviceOrientationClientMock::create() and use it from DRT.
+ https://bugs.webkit.org/show_bug.cgi?id=45650
+
+ Do not use the WebDeviceOrientationClientMock constructor directly,
+ but use the create() member function.
+
+ This should fix the linker errors for the multi-DLL Chromium DRT build.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setMockDeviceOrientation):
+ (LayoutTestController::deviceOrientationClient):
+
+2010-08-27 Kenneth Rohde Christiansen <kenneth.christiansen@openbossa.org>
+
+ Reviewed by Antti Koivisto.
+
+ Add support for testing the viewport meta tag algorithm,
+ based on the following draft spec:
+
+ http://people.opera.com/rune/TR/ED-css-viewport-20100806/
+
+ Add common handling of viewport meta tag based on new Opera spec
+ https://bugs.webkit.org/show_bug.cgi?id=44201
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::dumpConfigurationForViewport):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-09-12 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [DRT/Chromium] Remove dependency to base/string16.h and gfx/codec/png_codec.h
+ https://bugs.webkit.org/show_bug.cgi?id=45517
+
+ Use webkit_support_gfx.h for PNG encoding/decoding instead of png_codec.h
+
+ * DumpRenderTree/chromium/ImageDiff.cpp:
+ (Image::craeteFromStdin):
+ (Image::createFromFilename):
+ (diffImages):
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::dumpImage):
+
+2010-09-10 MORITA Hajime <morrita@google.com>
+
+ Reviewed by Tony Chang.
+
+ [Chromium] Implement textInputController.hasSpellingMarker() for Chromium
+ https://bugs.webkit.org/show_bug.cgi?id=45441
+
+ Added TextInputController::hasSpellingMarker().
+
+ * DumpRenderTree/chromium/TextInputController.cpp:
+ (TextInputController::TextInputController):
+ (TextInputController::hasSpellingMarker):
+ * DumpRenderTree/chromium/TextInputController.h:
+
+2010-09-12 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ My last change accidentally contained a local change to the
+ rebaselinig script; webkit-patch land picked it up without telling
+ me and committed it :(
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-09-11 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Anders Carlsson.
+
+ Attempt to fix Windows MiniBrowser build (untested)
+ https://bugs.webkit.org/show_bug.cgi?id=45609
+
+ * MiniBrowser/win/BrowserView.cpp:
+ (runJavaScriptConfirm):
+ (runJavaScriptPrompt):
+
+2010-09-11 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Fix zoom related tests when testing WebKit2.
+
+ * WebKitTestRunner/InjectedBundle/EventSendingController.cpp:
+ (WTR::EventSendingController::zoomPageIn): Zoom in and zoom out are not the same.
+
+2010-09-11 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ Implement WebKit2 callback equivalent to - [WebUIDelegate webView:setStatusText:]
+ <rdar://problem/8359252>
+ https://bugs.webkit.org/show_bug.cgi?id=45605
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (setStatusText):
+ (contentsSizeChanged):
+ (-[BrowserWindowController awakeFromNib]):
+ * MiniBrowser/win/BrowserView.cpp:
+ (runJavaScriptConfirm):
+ (runJavaScriptPrompt):
+ (setStatusText):
+ (contentsSizeChanged):
+ (BrowserView::create):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage):
+ (WTR::TestController::initialize):
+
+2010-09-11 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ Add callback mechanism for the getting the source of a frame
+ <rdar://problem/8364681>
+ https://bugs.webkit.org/show_bug.cgi?id=45604
+
+ Add ability to dump the main frame's source to the console.
+
+ * MiniBrowser/mac/BrowserWindowController.h:
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController dumpSourceToConsole:]):
+ * MiniBrowser/mac/MainMenu.xib:
+
+2010-09-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Remove unneeded Empty Queue messages
+ https://bugs.webkit.org/show_bug.cgi?id=45602
+
+ We already have a /gc job to delete these.
+ recentstatus.py is already smart enough to use the
+ most recent of the workitems last update or the most recent status,
+ so removing these should not change the _last_status_date() return
+ value more than a few milliseconds.
+
+ These messages just spam the recent status log.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-09-11 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Fix Python exception when generating synthetic patch IDs
+ https://bugs.webkit.org/show_bug.cgi?id=45592
+
+ Can't concatenate strings and numbers directly.
+
+ * QueueStatusServer/handlers/queuestatus.py:
+
+2010-09-11 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Group statuses in queue status by patch ID
+ https://bugs.webkit.org/show_bug.cgi?id=45588
+
+ Group statuses by patch ID so that the status page is easier
+ to scan.
+
+ * QueueStatusServer/handlers/queuestatus.py:
+ * QueueStatusServer/stylesheets/dashboard.css:
+ (.status-group):
+ (.status-bug):
+ (.status-group ul):
+ (.status-group ul li):
+ (.status-group ul li:hover):
+ (.status-cell):
+ (.status-cell:hover):
+ (.status-cell.pass):
+ (.status-cell.fail):
+ (.status-cell.pending):
+ (.status-cell.error):
+ * QueueStatusServer/templates/dashboard.html:
+ * QueueStatusServer/templates/queuestatus.html:
+
+2010-09-11 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Implement layoutTestController.dumpResourceResponseMIMETypes in Chromium DRT
+ https://bugs.webkit.org/show_bug.cgi?id=45479
+
+ Implement layoutTestController.dumpResourceResponseMIMETypes (modelled after
+ implementation in ResourceLoadDelegate in the Mac port).
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::dumpResourceResponseMIMETypes):
+ (LayoutTestController::reset):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ (LayoutTestController::setShouldDumpResourceResponseMIMETypes):
+ (LayoutTestController::shouldDumpResourceResponseMIMETypes):
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::shouldDumpResourceResponseMIMETypes):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::didReceiveResponse):
+
+2010-09-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ queues.webkit.org should expose /remote_api for data upload/download
+ https://bugs.webkit.org/show_bug.cgi?id=45559
+
+ * QueueStatusServer/app.yaml:
+ - /remote_api is a standard app-engine service which allows use of
+ the bulk uploader for data upload/download. Exposing this
+ (for admin access only) allows us to use
+
+2010-09-10 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ Add zoom support to WebKit2 API
+ <rdar://problem/7660657>
+ https://bugs.webkit.org/show_bug.cgi?id=45585
+
+ - Add zoom options to MiniBrowser that mimic Safari's options using
+ the new WebKit2 zoom APIs.
+ - Switch uses of float for the zoom APIs to use double.
+
+ * MiniBrowser/mac/BrowserWindowController.h:
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController initWithPageNamespace:]):
+ (-[BrowserWindowController validateMenuItem:]):
+ (-[BrowserWindowController validateUserInterfaceItem:]):
+ (-[BrowserWindowController currentZoomFactor]):
+ (-[BrowserWindowController setCurrentZoomFactor:]):
+ (-[BrowserWindowController canZoomIn]):
+ (-[BrowserWindowController zoomIn:]):
+ (-[BrowserWindowController canZoomOut]):
+ (-[BrowserWindowController zoomOut:]):
+ (-[BrowserWindowController canResetZoom]):
+ (-[BrowserWindowController resetZoom:]):
+ (-[BrowserWindowController toggleZoomMode:]):
+ * MiniBrowser/mac/MainMenu.xib:
+ * WebKitTestRunner/InjectedBundle/EventSendingController.cpp:
+ (WTR::EventSendingController::textZoomIn):
+ (WTR::EventSendingController::textZoomOut):
+ (WTR::EventSendingController::zoomPageIn):
+ (WTR::EventSendingController::zoomPageOut):
+
+2010-09-10 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Fix crash in DRT in standalone mode
+
+ https://bugs.webkit.org/show_bug.cgi?id=45454
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::loadNextTestInStandAloneMode):
+
+2010-09-10 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Remove unnecessary constraint in WebCore of choosing either text zoom or full page zoom.
+ Precursor to <rdar://problem/7660657>
+ https://bugs.webkit.org/show_bug.cgi?id=45522
+
+ Update for changes to the Bundle API to allow separate control of page and text zoom
+ levels.
+
+ * WebKitTestRunner/InjectedBundle/EventSendingController.cpp:
+ (WTR::EventSendingController::textZoomIn):
+ (WTR::EventSendingController::textZoomOut):
+ (WTR::EventSendingController::zoomPageIn):
+ (WTR::EventSendingController::zoomPageOut):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::reset):
+
+2010-09-10 Yael Aharon <yael.aharon@nokia.com>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Support click event for notifications
+ https://bugs.webkit.org/show_bug.cgi?id=44836
+
+ Add support for simulateDesktopNotificationClick by calling
+ back to DumpRenderTreeSupportQt.cpp.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::simulateDesktopNotificationClick):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-09-10 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Update queue status when patches fail their first land attempt
+ https://bugs.webkit.org/show_bug.cgi?id=45583
+
+ Add a few more _update_status calls to make it more obvious if a patch is
+ being retried because tests failed.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-09-10 Balazs Kelemen <kb@inf.u-szeged.hu>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] MiniBrowser crashes with multiply windows when closing one of them
+ https://bugs.webkit.org/show_bug.cgi?id=45536
+
+ * MiniBrowser/qt/BrowserView.cpp:
+ (BrowserView::BrowserView): Reference the context instead of adopting it
+ because it can be shared across different views.
+
+2010-09-10 Tony Chang <tony@chromium.org>
+
+ Unreviewed, rolling out r67241.
+ http://trac.webkit.org/changeset/67241
+ https://bugs.webkit.org/show_bug.cgi?id=44709
+
+ Accidentally committed.
+
+ * Scripts/webkitpy/layout_tests/deduplicate_tests.py:
+ * Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py:
+
+2010-09-10 Tony Chang <tony@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ deduplicate-tests should be runnable from any WebKit directory
+ https://bugs.webkit.org/show_bug.cgi?id=44709
+
+ * Scripts/webkitpy/layout_tests/deduplicate_tests.py:
+ * Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py:
+
+2010-09-10 Tony Chang <tony@chromium.org>
+
+ Unreviewed, rolling out r67216.
+ http://trac.webkit.org/changeset/67216
+ https://bugs.webkit.org/show_bug.cgi?id=44709
+
+ Broke
+
+ * Scripts/webkitpy/layout_tests/deduplicate_tests.py:
+ * Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py:
+
+2010-09-10 Tony Chang <tony@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ deduplicate-tests should be runnable from any WebKit directory
+ https://bugs.webkit.org/show_bug.cgi?id=44709
+
+ * Scripts/webkitpy/layout_tests/deduplicate_tests.py:
+ * Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py:
+
+2010-09-09 Hans Wennborg <hans@chromium.org>
+
+ Reviewed by Jeremy Orlow.
+
+ Hook up LayoutTestController.setMockDeviceOrientation() in Chromium DumpRenderTree.
+ https://bugs.webkit.org/show_bug.cgi?id=45460
+
+ This enables DumpRenderTree to run layout tests for DeviceOrientation.
+
+ Also declare the LayoutTestController destructor out-of-line.
+ Otherwise the implicit destructor would cause compiler errors because
+ of the OwnPtr<WebKit::WebDeviceOrientationClientMock> member.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::~LayoutTestController):
+ (LayoutTestController::setMockDeviceOrientation):
+ (LayoutTestController::deviceOrientationClient):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::deviceOrientationClient):
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-09-09 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r67119.
+ http://trac.webkit.org/changeset/67119
+ https://bugs.webkit.org/show_bug.cgi?id=45505
+
+ Extra newlines in results (Requested by tony^work on #webkit).
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::reset):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/TestShell.h:
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (printResponseDescription):
+ (printNodeDescription):
+ (printRangeDescription):
+ (WebViewHost::shouldBeginEditing):
+ (WebViewHost::shouldEndEditing):
+ (WebViewHost::shouldInsertNode):
+ (WebViewHost::shouldChangeSelectedRange):
+ (WebViewHost::shouldDeleteRange):
+ (WebViewHost::shouldApplyStyle):
+ (WebViewHost::didBeginEditing):
+ (WebViewHost::didChangeSelection):
+ (WebViewHost::didChangeContents):
+ (WebViewHost::didEndEditing):
+ (WebViewHost::decidePolicyForNavigation):
+ (WebViewHost::didCancelClientRedirect):
+ (WebViewHost::didStartProvisionalLoad):
+ (WebViewHost::didReceiveServerRedirectForProvisionalLoad):
+ (WebViewHost::didFailProvisionalLoad):
+ (WebViewHost::didCommitProvisionalLoad):
+ (WebViewHost::didFinishDocumentLoad):
+ (WebViewHost::didHandleOnloadEvents):
+ (WebViewHost::didFailLoad):
+ (WebViewHost::didFinishLoad):
+ (WebViewHost::didChangeLocationWithinPage):
+ (WebViewHost::willSendRequest):
+ (WebViewHost::didReceiveResponse):
+ (WebViewHost::didFinishResourceLoad):
+ (WebViewHost::didFailResourceLoad):
+ (WebViewHost::didDisplayInsecureContent):
+ (WebViewHost::didRunInsecureContent):
+ (WebViewHost::printFrameDescription):
+
+2010-09-09 Michael Saboff <msaboff@apple.com>
+
+ Unreviewed, adding myself to committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-09 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Implement layoutTestController.dumpResourceResponseMIMETypes in Chromium DRT
+ https://bugs.webkit.org/show_bug.cgi?id=45479
+
+ Implement layoutTestController.dumpResourceResponseMIMETypes (modelled after
+ implementation in ResourceLoadDelegate in the Mac port).
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::dumpResourceResponseMIMETypes):
+ (LayoutTestController::reset):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ (LayoutTestController::setShouldDumpResourceResponseMIMETypes):
+ (LayoutTestController::shouldDumpResourceResponseMIMETypes):
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::shouldDumpResourceResponseMIMETypes):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::didReceiveResponse):
+
+2010-09-09 Mihai Parparita <mihaip@chromium.org>
+
+ Reviewed by Daniel Bates.
+
+ svn-apply tries to delete directories it shouldn't
+ https://bugs.webkit.org/show_bug.cgi?id=45424
+
+ isDirectoryEmptyForRemoval had the wrong check. If an item in the
+ directory is itself a directory, then the directory is definitely
+ not empty.
+
+ * Scripts/svn-apply:
+
+2010-09-09 Chris Fleizach <cfleizach@apple.com>
+
+ Fixing GTK and windows build failure.
+
+ AX: Support AccessibilityTextMarkers in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=44778
+
+ * DumpRenderTree/AccessibilityTextMarker.h:
+ (AccessibilityTextMarker::platformTextMarker):
+ (AccessibilityTextMarkerRange::platformTextMarkerRange):
+ * DumpRenderTree/mac/AccessibilityTextMarkerMac.mm:
+ (AccessibilityTextMarker::platformTextMarker):
+ (AccessibilityTextMarkerRange::platformTextMarkerRange):
+
+2010-09-09 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by David Kilzer.
+
+ AX: Support AccessibilityTextMarkers in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=44778
+
+ Add AccessibilityTextMarker and AccessibilityTextMarkerRange which encapsulate the AXTextMarkers
+ that WebCore uses when vending information about its VisiblePositions through AX.
+
+ There are a few new methods in AccessibilityUIElement to retrieve and use text markers, and some basic
+ methods for encapsulating and checking equality.
+
+ This will allow future bug fixes in the text marker system to be adequately tested.
+
+ * DumpRenderTree/AccessibilityTextMarker.cpp: Added.
+ (toTextMarker):
+ (isMarkerEqualCallback):
+ (markerFinalize):
+ (AccessibilityTextMarker::makeJSAccessibilityTextMarker):
+ (AccessibilityTextMarker::getJSClass):
+ (toTextMarkerRange):
+ (isMarkerRangeEqualCallback):
+ (markerRangeFinalize):
+ (AccessibilityTextMarkerRange::makeJSAccessibilityTextMarkerRange):
+ (AccessibilityTextMarkerRange::getJSClass):
+ * DumpRenderTree/AccessibilityTextMarker.h: Added.
+ (AccessibilityTextMarker::platformTextMarker):
+ (AccessibilityTextMarkerRange::platformTextMarkerRange):
+ (AccessibilityTextMarker::AccessibilityTextMarker):
+ (AccessibilityTextMarker::~AccessibilityTextMarker):
+ (AccessibilityTextMarker::isEqual):
+ (AccessibilityTextMarkerRange::AccessibilityTextMarkerRange):
+ (AccessibilityTextMarkerRange::~AccessibilityTextMarkerRange):
+ (AccessibilityTextMarkerRange::isEqual):
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (textMarkerRangeForElementCallback):
+ (textMarkerRangeLengthCallback):
+ (textMarkerRangeForMarkersCallback):
+ (startTextMarkerForTextMarkerRangeCallback):
+ (endTextMarkerForTextMarkerRangeCallback):
+ (accessibilityElementForTextMarkerCallback):
+ (AccessibilityUIElement::textMarkerRangeForElement):
+ (AccessibilityUIElement::textMarkerRangeLength):
+ (AccessibilityUIElement::startTextMarkerForTextMarkerRange):
+ (AccessibilityUIElement::endTextMarkerForTextMarkerRange):
+ (AccessibilityUIElement::accessibilityElementForTextMarker):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/AccessibilityTextMarkerMac.mm: Added.
+ (AccessibilityTextMarker::AccessibilityTextMarker):
+ (AccessibilityTextMarker::~AccessibilityTextMarker):
+ (AccessibilityTextMarker::isEqual):
+ (AccessibilityTextMarkerRange::AccessibilityTextMarkerRange):
+ (AccessibilityTextMarkerRange::~AccessibilityTextMarkerRange):
+ (AccessibilityTextMarkerRange::isEqual):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::textMarkerRangeForElement):
+ (AccessibilityUIElement::textMarkerRangeLength):
+ (AccessibilityUIElement::textMarkerRangeForMarkers):
+ (AccessibilityUIElement::startTextMarkerForTextMarkerRange):
+ (AccessibilityUIElement::endTextMarkerForTextMarkerRange):
+ (AccessibilityUIElement::accessibilityElementForTextMarker):
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+2010-08-25 Tony Chang <tony@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ don't delete duplicates needed because of intermediate results
+ https://bugs.webkit.org/show_bug.cgi?id=44653
+
+ Also, output the full path so we can pipe the output to rm.
+
+ * Scripts/webkitpy/layout_tests/deduplicate_tests.py:
+ * Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py:
+
+2010-09-09 Balazs Kelemen <kb@inf.u-szeged.hu>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] MiniBrowser does not starts properly
+ https://bugs.webkit.org/show_bug.cgi?id=45459
+
+ Do not try set up the first window by calling newWindow on a
+ newly created BrowserWindow since it creates a new object.
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ * MiniBrowser/qt/main.cpp:
+ (main):
+
+2010-09-09 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Get ImageDiff building on Win32
+ https://bugs.webkit.org/show_bug.cgi?id=45353
+
+ * DumpRenderTree/gtk/ImageDiff.cpp:
+ (main): Switch from using strtok to g_strsplit.
+
+2010-09-09 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Andreas Kling.
+
+ [Qt] Modify load method of MiniBrowser's BrowserView class
+ https://bugs.webkit.org/show_bug.cgi?id=45442
+
+ Modify load method to take a QString as argument, remove unnecessary QT_VERSION_CHECK.
+
+ * MiniBrowser/qt/BrowserView.cpp:
+ (BrowserView::load):
+ * MiniBrowser/qt/BrowserView.h:
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::load):
+
+2010-09-09 Tony Chang <tony@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ fix show_results in new-run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=45413
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-09-08 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ [Chromium] Fix test results server to make sure
+ it does not have corrupted data.
+
+ results.json file size coulbe be >1M and we split
+ the data into multiple data store entries in this
+ case. This patch fixes the issue that the data may
+ be corrupted if data store error happens in the middle
+ of saving multiple entries.
+
+ https://bugs.webkit.org/show_bug.cgi?id=45063
+
+ * TestResultServer/model/datastorefile.py:
+
+2010-09-08 Peter Varga <pvarga@inf.u-szeged.hu>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Fix ignoring return value warning in case of gcc 4.4.4
+ https://bugs.webkit.org/show_bug.cgi?id=45384
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (testPostURLFile):
+ If fwrite have written zero byte then the testPostURLFile function
+ returns with false as tempFile can't be opened.
+ * DumpRenderTree/qt/ImageDiff.cpp:
+ (main):
+ Put fwrite function into an if condition without body to avoid
+ warning. It is safe because this function writes to the stdout.
+
+2010-09-08 Satish Sampath <satish@chromium.org>
+
+ Unreviewed, adding myself to committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-08 Hans Wennborg <hans@chromium.org>
+
+ Unreviewed.
+
+ Adding myself as a committer in committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-08 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Refactor MiniBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=45173
+
+ Split BrowserWindow into two source files and headers. Remove unnecessary header includes.
+
+ * MiniBrowser/qt/BrowserView.cpp: Added.
+ (createNewPage):
+ (BrowserView::BrowserView):
+ (BrowserView::resizeEvent):
+ (BrowserView::load):
+ (BrowserView::view):
+ * MiniBrowser/qt/BrowserView.h: Added.
+ (BrowserView::~BrowserView):
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ * MiniBrowser/qt/BrowserWindow.h:
+ * MiniBrowser/qt/MiniBrowser.pro:
+
+2010-09-08 Adam Barth <abarth@webkit.org>
+
+ Rubber-stamped by Eric Seidel.
+
+ Rename DocLoader to CachedResourceLoader because that's what it does.
+
+ * Scripts/do-webcore-rename:
+
+2010-09-07 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Enable incremental results.json generation for non-layout tests.
+ https://bugs.webkit.org/show_bug.cgi?id=45315
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py: Enable generate_incremental_results=True by default. (This still keeps to generate results.json.) Also add a code to upload results json files to the app-engine server. Need a chromium change to actually start the uploading.
+
+ * TestResultServer/model/jsonresults.py: Make sure we save the file with test_type for incremental cases too.
+
+
+2010-09-07 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix
+
+ Missed one test in mac_unittest.py in previous change; for some
+ reason the method is listed twice. I will fix both for now, but will
+ figure this out in a later, not-time-sensitive patch.
+
+ https://bugs.webkit.org/show_bug.cgi?id=45357
+
+ * Scripts/webkitpy/layout_tests/port/mac_unittest.py:
+
+2010-09-07 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ test-webkitpy: Fix load error of
+ webkitpy/layout_tests/port/factory_unittest.py on Win32 Python
+ https://bugs.webkit.org/show_bug.cgi?id=45356 Need a short
+
+ * Scripts/webkitpy/layout_tests/port/server_process.py:
+ Avoid to import fcntl on win32. Win32 Python doesn't have fcntl
+ and we don't use server_process.py on Win32 Python. However
+ unittest.py tries to load everything in a module.
+
+2010-09-07 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ Fix regression introduced in previous change to new-run-webkit-tests
+ (bug 45090) to not try to run unittests for the Mac implementation
+ of the Port interface if we aren't running on a Mac.
+
+ Also fix the overrides implementation mock in the chromium unittests
+ to fix the case where there are overrides checked in that cause
+ problems.
+
+ https://bugs.webkit.org/show_bug.cgi?id=45357
+
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/mac_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/port_testcase.py:
+
+2010-09-01 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: still more unit tests
+
+ Clean up and remove unnecessary code. Biggest notable change is
+ moving the chromium-specific imagediff code from port/base to
+ port/chromium.
+
+ Add more unit tests for run_webkit_tests.py, port/base.py,
+ port/factory.py, port/dryrun.py, and
+ layout_package/dump_render_tree_thread.py
+
+ This covers almost all of the generic and test code paths except for
+ a few error paths involving invalid or port-specific command line
+ arguments, and the code path for uploading results files to the
+ buildbots.
+
+ https://bugs.webkit.org/show_bug.cgi?id=45090
+
+ * Scripts/webkitpy/layout_tests/data/failures/expected/hang.html: Added.
+ * Scripts/webkitpy/layout_tests/data/http/tests/passes/text-expected.txt: Copied from WebKitTools/Scripts/webkitpy/layout_tests/data/passes/text-expected.txt.
+ * Scripts/webkitpy/layout_tests/data/http/tests/passes/text.html: Copied from WebKitTools/Scripts/webkitpy/layout_tests/data/passes/text.html.
+ * Scripts/webkitpy/layout_tests/data/http/tests/ssl/text-expected.txt: Copied from WebKitTools/Scripts/webkitpy/layout_tests/data/passes/text-expected.txt.
+ * Scripts/webkitpy/layout_tests/data/http/tests/ssl/text.html: Copied from WebKitTools/Scripts/webkitpy/layout_tests/data/passes/text.html.
+ * Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt:
+ * Scripts/webkitpy/layout_tests/data/websocket/tests/passes/text-expected.txt: Copied from WebKitTools/Scripts/webkitpy/layout_tests/data/passes/text-expected.txt.
+ * Scripts/webkitpy/layout_tests/data/websocket/tests/passes/text.html: Copied from WebKitTools/Scripts/webkitpy/layout_tests/data/passes/text.html.
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+ * Scripts/webkitpy/layout_tests/port/factory_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/mac_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/port_testcase.py: Added.
+ * Scripts/webkitpy/layout_tests/port/server_process.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-09-07 Joseph Pecoraro <joepeck@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Provide a way to trigger a <select multiple> onchange event on changes
+ https://bugs.webkit.org/show_bug.cgi?id=45192
+
+ Adds a selector on ObjCController for testing
+ -[DOMHTMLSelectElement _activateItemAtIndex:allowMultipleSelection:] and
+ its different uses.
+
+ * DumpRenderTree/mac/ObjCController.m:
+ (+[ObjCController isSelectorExcludedFromWebScript:]):
+ (+[ObjCController webScriptNameForSelector:]):
+ (-[ObjCController setSelectElement:selectedIndex:allowingMultiple:]):
+
+2010-09-07 James Robinson <jamesr@chromium.org>
+
+ Rubber-stamped by Dimitri Glazkov.
+
+ Move myself from the committer to the reviewer list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-07 Tony Chang <tony@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ [chromium] Make a public flag for how DRT generates bitmaps on Linux
+ https://bugs.webkit.org/show_bug.cgi?id=45133
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::dumpImage):
+
+2010-09-07 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Implement --check-layout-test-sys-deps
+ https://bugs.webkit.org/show_bug.cgi?id=45283
+
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (main): Check --check-layout-test-sys-deps and call checkLayoutTestSystemDependencies().
+ * DumpRenderTree/chromium/TestShell.h: Declare checkLayoutTestSystemDependencies().
+ * DumpRenderTree/chromium/TestShellGtk.cpp:
+ (checkLayoutTestSystemDependencies): Add an empty implementation.
+ * DumpRenderTree/chromium/TestShellMac.mm:
+ (checkLayoutTestSystemDependencies): Add an empty implementation.
+ * DumpRenderTree/chromium/TestShellWin.cpp:
+ (checkLayoutTestSystemDependencies): Port similar function of test_shell.
+
+2010-09-07 Jessie Berlin <jberlin@apple.com>
+
+ Unreviewed. Mac build fix.
+
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (didClearWindowObjectForFrame):
+
+2010-09-07 Jessie Berlin <jberlin@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Indicate which one of the ScriptWorlds for a Frame the Window Object has been cleared for
+ https://bugs.webkit.org/show_bug.cgi?id=45217
+
+ Make WebKitTestRunner work with this change.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::didClearWindowForFrame):
+ Make sure the ScriptWorld here is the normal world, since that is no longer being done in
+ WebFrameLoaderClient.
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+
+2010-09-07 Philippe Normand <pnormand@igalia.com>
+
+ Unreviewed, build fix.
+
+ webkit-patch command to find the ports covering a specific layout test
+ https://bugs.webkit.org/show_bug.cgi?id=42832
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py: Don't assume the
+ tests are present when building the expectations. This is needed
+ for the unittests.
+
+2010-09-06 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch command to find the ports covering a specific layout test
+ https://bugs.webkit.org/show_bug.cgi?id=42832
+
+ To use it: webkit-patch skipped-ports some/layout/test.html
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/factory_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/port/webkit_unittest.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/queries_unittest.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-09-07 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Eric Seidel.
+
+ [NRWT] Add temp directory to all running drivers.
+ https://bugs.webkit.org/show_bug.cgi?id=45261
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-09-06 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [Chromium/DRT] Empty out user stylesheet after each test run.
+ https://bugs.webkit.org/show_bug.cgi?id=45282
+
+ This should significantly cut down on the number of the mysterious flaky tests
+ whose diffs looked like the page was blown up to a very lage size. This
+ was indeed the dirty work of platform/mac/fast/loader/user-stylesheet-fast-path.html,
+ which set the base body font to 100px.
+
+ Since the user stylesheet was never reset, _all_ pixel tests that ran after it in
+ the same thread failed.
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::resetWebSettings): Set user stylesheet to an empty URL.
+
+2010-09-06 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Do not generate pixel results for text/plain resources
+ https://bugs.webkit.org/show_bug.cgi?id=45253
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::dump): Clear shouldGeneratePixelResults flag for text/plain.
+
+2010-09-06 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ print out correct error when a DRT thread dies in NRWT
+ https://bugs.webkit.org/show_bug.cgi?id=45281
+
+ Not sure why, but with the parens, python 2.6.5 on Linux
+ gives an error that raise takes 5 arguments and 0 were given.
+ Didn't test other platforms or python versions, but putting it
+ all on one line fixes it and correctly prints the exception
+ from the DRT thread.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-09-06 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, just adding some emails from lists.webkit.org.
+
+ Update committers.py to include emails from lists.webkit.org
+ as found by the validate-committer-lists script.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-06 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Small code cleanup in DumpRenderTreeGtk.cpp
+ https://bugs.webkit.org/show_bug.cgi?id=45213
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (initializeFonts): Made this function do nothing for non-X11 platforms, so we don't
+ have to surround the invocation with #ifdefs.
+ (useLongRunningServerMode): Added.
+ (runTestingServerLoop): Added.
+ (initializeGlobalsFromCommandLineOptions): Added.
+ (runTest): Removed ifdefs.
+ (main): Use new helper functions.
+
+2010-09-06 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] EventSender should support modifier keys with mouseDown and mouseUp events
+ https://bugs.webkit.org/show_bug.cgi?id=45235
+
+ Add support for interpreting the modifier key arguments to the mouseDown and mouseUp
+ methods of the EventSender.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (prepareMouseButtonEvent): Allow passing in a modifier bitmask, which will be OR'd
+ with the current modifiers.
+ (contextClickCallback): Always send no modifiers when preparing the mouse event.
+ (gdkModifersFromJSValue): Added, converts a JSValue array into a GDK modifier bitmask.
+ (mouseDownCallback): Send in the requested modifiers to prepareMouseButtonEvent.
+ (mouseUpCallback): Ditto.
+
+2010-09-05 Peter Kasting <pkasting@google.com>
+
+ Reviewed by Adam Barth.
+
+ Make Chromium/Mac generate continuous mousewheel events with the same wheelDelta values as Safari/Mac.
+ https://bugs.webkit.org/show_bug.cgi?id=45155
+
+ * DumpRenderTree/chromium/EventSender.cpp: Modify Chromium DRT mousewheel event generation to match new behavior on Mac.
+ (EventSender::handleMouseWheel):
+
+2010-09-05 Yury Semikhatsky <yurys@chromium.org>
+
+ Reviewed by Joseph Pecoraro.
+
+ Web Inspector: remove WebDevToolsAgentClient::forceRepaint which is not used
+ https://bugs.webkit.org/show_bug.cgi?id=45179
+
+ * DumpRenderTree/chromium/DRTDevToolsAgent.cpp:
+ * DumpRenderTree/chromium/DRTDevToolsAgent.h:
+
+2010-09-05 Andreas Kling <andreas.kling@nokia.com>
+
+ Rubber-stamped by Daniel Bates.
+
+ Adding myself as reviewer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-04 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Martin Robinson.
+
+ Teach svn-apply/unapply about svn:mergeinfo
+ https://bugs.webkit.org/show_bug.cgi?id=45236
+
+ Recognize the svn:mergeinfo property and ignore it for now.
+
+ Currently, svn-apply/unapply recognize only '+' and '-'
+ property changes within a diff. We should add support
+ to recognize "Merged" and "Reverse-merged" changes as well.
+ Because svn:mergeinfo is metadata that is used only by SVN
+ and tends to be error-prone and/or nuisance (*), we will ignore
+ it for now.
+ (*) See "Parting Thoughts" of <http://www.collab.net/community/subversion/articles/merge-info.html>.
+
+ * Scripts/VCSUtils.pm:
+ - Modified parseSvnProperty() to recognize "Merged" and
+ "Reverse-merged" as the start of a property value.
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl:
+ - Added the following unit tests:
+ "simple: add svn:mergeinfo"
+ "simple: delete svn:mergeinfo"
+ "simple: modified svn:mergeinfo"
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnProperty.pl:
+ - Added the following unit tests:
+ "simple: add svn:mergeinfo"
+ "simple: delete svn:mergeinfo"
+ "simple: modified svn:mergeinfo"
+ "simple: modified svn:mergeinfo using SVN 1.4 syntax"
+ "'Merged' change followed by 'Merged' change"
+ "'Reverse-merged' change followed by 'Reverse-merged' change"
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl:
+ - Added the following unit tests:
+ "'Merged' change"
+ "'Reverse-merged' change"
+ "'Reverse-merged' change followed by 'Merge' change"
+ "'Merged' change followed by 'Merge' change"
+ "'Reverse-merged' change followed by 'Reverse-merged' change"
+ "'Reverse-merged' change followed by 'Reverse-merged' change followed by 'Merged' change"
+
+2010-09-04 Lucas De Marchi <lucas.demarchi@profusion.mobi>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [EFL] Move test browser to WebKitTools directory
+ https://bugs.webkit.org/show_bug.cgi?id=45212
+
+ Follow other ports like QT and GTK which moved the test browser to
+ WebKitTools directory.
+
+ * CMakeListsEfl.txt: Added.
+ * EWebLauncher/main.c: Added.
+ (print_history):
+ (zoom_level_set):
+ (on_ecore_evas_resize):
+ (title_set):
+ (viewport_set):
+ (on_title_changed):
+ (on_progress):
+ (on_load_finished):
+ (on_toolbars_visible_set):
+ (on_toolbars_visible_get):
+ (on_statusbar_visible_set):
+ (on_statusbar_visible_get):
+ (on_scrollbars_visible_set):
+ (on_scrollbars_visible_get):
+ (on_menubar_visible_set):
+ (on_menubar_visible_get):
+ (on_tooltip_text_set):
+ (on_inputmethod_changed):
+ (on_viewport_changed):
+ (on_mouse_down):
+ (on_focus_out):
+ (on_focus_in):
+ (on_resized):
+ (on_key_down):
+ (on_browser_del):
+ (on_closeWindow):
+ (quit):
+ (browserCreate):
+ (browserDestroy):
+ (closeWindow):
+ (main_signal_exit):
+ (findThemePath):
+ (main):
+
+2010-09-03 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Set project dependencies so that they build serially. This fixes
+ issues when running run-webkit-tests if DRT is not built yet.
+
+ * DumpRenderTree/DumpRenderTree.sln:
+
+2010-09-03 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Fix reading configuraiton in NWRT to work on Windows.
+ https://bugs.webkit.org/show_bug.cgi?id=45180
+
+ * Scripts/webkitpy/layout_tests/port/base.py: Added 'perl' argument, because Windows doesn't know what to do
+ with the file otherwise.
+
+2010-09-03 Chris Rogers <crogers@google.com>
+
+ Unreviewed
+
+ Add myself to the committers list
+ https://bugs.webkit.org/show_bug.cgi?id=45189
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-09-03 Andrey Kosyakov <caseq@chromium.org>
+
+ Reviewed by Yury Semikhatsky.
+
+ http/tests/inspector/console-xhr-logging.html and http/tests/inspector/resource-har-conversion.html are failing on chromium win bot
+ Changed MIME type for .js to application/x-javascript for consistency with apache used on other platforms.
+ https://bugs.webkit.org/show_bug.cgi?id=45137
+
+ * Scripts/webkitpy/layout_tests/port/lighttpd.conf:
+
+2010-09-03 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Eric Seidel.
+
+ Add feature detection support to NRWT.
+ https://bugs.webkit.org/show_bug.cgi?id=41842
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/qt.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/port/webkit_unittest.py: Added.
+
+2010-09-03 Hironori Bono <hbono@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ Adds textInputController.hasSpellingMarker() to avoid using pixel tests for spellchecking tests
+ and implements it for Mac.
+ https://bugs.webkit.org/show_bug.cgi?id=41832
+
+ * DumpRenderTree/mac/TextInputController.m: Added [TextInputController hasSpellingMarker:length:]
+ and bind it so we can call it from JavaScript.
+ (+[TextInputController isSelectorExcludedFromWebScript:]):
+ (+[TextInputController webScriptNameForSelector:]):
+ (-[TextInputController hasSpellingMarker:length:]):
+
+2010-09-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add a unit test for commit-queue retries
+ https://bugs.webkit.org/show_bug.cgi?id=45162
+
+ I think commit-queue retries are not correctly avoiding
+ build and test on retries. So I started testing the code.
+ Unfortunately this test did not find the bug. But now
+ that we have the test we might as well keep it.
+ I also fixed a broken import in validate-committer-lists.
+
+ * Scripts/validate-committer-lists:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-09-02 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Remove dependency to base/task.h and base/timer.h
+ https://bugs.webkit.org/show_bug.cgi?id=45091
+
+ Task.{cpp,h} introduces a simpler version of Chromium
+ base/task.h. It doesn't have TupleN and Method.
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+ Add Task.cpp and Task.h
+ * DumpRenderTree/chromium/DRTDevToolsAgent.cpp:
+ (DRTDevToolsAgent::DRTDevToolsAgent):
+ (DRTDevToolsAgent::reset):
+ (DRTDevToolsAgent::asyncCall):
+ (DRTDevToolsAgent::frontendLoaded):
+ * DumpRenderTree/chromium/DRTDevToolsAgent.h:
+ (DRTDevToolsAgent::taskList): Added to use MethodTask<T>.
+ * DumpRenderTree/chromium/DRTDevToolsClient.cpp:
+ (DRTDevToolsClient::DRTDevToolsClient):
+ (DRTDevToolsClient::~DRTDevToolsClient):
+ (DRTDevToolsClient::reset):
+ (DRTDevToolsClient::asyncCall):
+ * DumpRenderTree/chromium/DRTDevToolsClient.h:
+ (DRTDevToolsClient::taskList): Added to use MethodTask<T>.
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::EventSender):
+ (EventSender::reset):
+ (EventSender::scheduleAsynchronousClick):
+ * DumpRenderTree/chromium/EventSender.h:
+ (EventSender::taskList): Added to use MethodTask<T>.
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::WorkQueue::processWorkSoon):
+ (LayoutTestController::waitUntilDone):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::reset):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ (LayoutTestController::taskList): Added to use MethodTask<T>.
+ (LayoutTestController::WorkQueue::taskList): Added to use MethodTask<T>.
+ * DumpRenderTree/chromium/NotificationPresenter.cpp:
+ (deferredDisplayDispatch):
+ (NotificationPresenter::show):
+ * DumpRenderTree/chromium/Task.cpp: Added.
+ * DumpRenderTree/chromium/Task.h: Added.
+
+2010-09-02 Steve Block <steveblock@google.com>
+
+ Reviewed by Adam Barth.
+
+ Hook up LayoutTestController.setMockDeviceOrientation() on Mac.
+ https://bugs.webkit.org/show_bug.cgi?id=43181
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (createWebViewAndOffscreenWindow):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMockDeviceOrientation):
+
+2010-08-31 Adam Roben <aroben@apple.com>
+
+ Fix flashiness when resizing the browser window on Windows
+
+ Reviewed by Sam Weinig.
+
+ * MiniBrowser/win/BrowserWindow.cpp:
+ (BrowserWindow::wndProc): Override WM_ERASEBKGND so Windows won't
+ periodically fill the window with white.
+
+2010-09-02 Peter Kasting <pkasting@google.com>
+
+ Reviewed by Dimitri Glazkov.
+
+ Implement [continuous]MouseScrollBy() on Chromium, and partly on GTK.
+ https://bugs.webkit.org/show_bug.cgi?id=45073
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::EventSender):
+ (EventSender::mouseScrollBy):
+ (EventSender::continuousMouseScrollBy):
+ (EventSender::sendCurrentTouchEvent):
+ (EventSender::handleMouseWheel):
+ * DumpRenderTree/chromium/EventSender.h:
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (mouseScrollByCallback):
+ (continuousMouseScrollByCallback):
+
+2010-09-01 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Land a patched version of r66542 - change TestRunner to have an
+ separate cleanup method and fix the ordering of cleanup between
+ TestRunner and the printing module, and then wrap everything in a
+ try/finally block to ensure reliable cleanup without needing to
+ rely on stuff happening in the destructor of the TestRunner.
+
+ Also refactor run_webkit_tests.run() to be much smaller and cleaner
+ by creating a bunch of helper methods and moving more stuff into
+ the TestRunner class.
+
+ This fixes the crash at the end of the linux test run of
+ new-run-webkit-tests (and undoes the rollout in 66547).
+
+ https://bugs.webkit.org/show_bug.cgi?id=44902
+
+ * Scripts/webkitpy/layout_tests/data/failures/expected/exception.html: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/keyboard.html: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/error-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/error.html: Added.
+ * Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-09-01 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Fix TestNetscapePlugIn to compile without access to QuickDraw private headers.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+
+2010-09-01 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Have kill-old-processes kill debug and release variants of WebKit2WebWebProcess
+ and WebKitTestRunner.
+
+ * BuildSlaveSupport/win/kill-old-processes:
+
+2010-09-01 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] Remove obsolete include path from DumpRenderTree.pro
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+
+2010-09-01 Mahesh Kulkarni <mahesh.kulkarni@nokia.com>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] QWebPage::allowGeolocationRequest should be async API
+ https://bugs.webkit.org/show_bug.cgi?id=41364
+
+ Implements new async API for geolocation permission similar to
+ Notification. WebPage maintains list of geolocation permission request
+ QtWebkit and set's when LayoutTestController gets the access from test JS
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::resetSettings):
+ (WebCore::WebPage::requestPermission):
+ (WebCore::WebPage::cancelPermission):
+ (WebCore::WebPage::permissionSet):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::processLine):
+ (WebCore::DumpRenderTree::geolocationPermissionSet):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::setGeolocationPermission):
+ (LayoutTestController::setGeolocationPermissionCommon):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-09-01 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Antti Koivisto.
+
+ [Qt] Auto-generate WebKit2 forwarding headers
+ https://bugs.webkit.org/show_bug.cgi?id=44692
+
+ * MiniBrowser/qt/BrowserWindow.h: use source style includes
+ * MiniBrowser/qt/MiniBrowser.pro: add missing include paths
+ * Scripts/enumerate-included-framework-headers: Removed.
+
+2010-08-31 Ademar de Souza Reis Jr <ademar.reis@openbossa.org>
+
+ Reviewed by Adam Barth.
+
+ Allow Ctrl+C inside Bugzilla::fetch_bug_dictionary
+ https://bugs.webkit.org/show_bug.cgi?id=44789
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+
+2010-08-31 Leandro Pereira <leandro@profusion.mobi>
+
+ Reviewed by Adam Barth.
+
+ ews: Add support for EFL-EWS
+ https://bugs.webkit.org/show_bug.cgi?id=44982
+
+ * QueueStatusServer/model/queues.py: Add "efl-ews" to queues list.
+ * Scripts/webkitpy/common/config/ports.py: Define a EflPort class
+ and add it to the ports dict.
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py: Define a
+ EflEWS class.
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py: Add
+ a test case for the EFL EWS.
+
+2010-08-31 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=42195
+ <rdar://problem/8186761> WebKitTestRunner needs to support layoutTestController.setXSSAuditorEnabled
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: (WTR::LayoutTestController::setXSSAuditorEnabled):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ Added setXSSAuditorEnabled, calling through to an WKBundle private method. Calling this method
+ makes WebProcess use a different value for this preference than UIProcess thinks it uses.
+
+ * WebKitTestRunner/TestController.cpp: (WTR::TestController::resetStateToConsistentValues):
+ Reset xssAuditorEnabled. Even though the value doesn't change, this calls through to WebProcess,
+ which forgets its override.
+
+2010-08-31 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough.
+
+ WebKitTestRunner needs layoutTestController.addUserStyleSheet
+ https://bugs.webkit.org/show_bug.cgi?id=42680
+
+ WebKitTestRunner needs layoutTestController.addUserScript
+ https://bugs.webkit.org/show_bug.cgi?id=42681
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::beginTesting):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::addUserScript):
+ (WTR::LayoutTestController::addUserStyleSheet):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+
+2010-08-31 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, rolling out r66542.
+ http://trac.webkit.org/changeset/66542
+ https://bugs.webkit.org/show_bug.cgi?id=44902
+
+ r66542 - the weird logging dependencies in Python stuck again ...
+
+ * Scripts/webkitpy/layout_tests/data/failures/expected/exception.html: Removed.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/keyboard.html: Removed.
+ * Scripts/webkitpy/layout_tests/data/passes/error-expected.txt: Removed.
+ * Scripts/webkitpy/layout_tests/data/passes/error.html: Removed.
+ * Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-08-31 Dumitru Daniliuc <dumi@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Implementing LayoutTestController::markerTextForListItem() in Chromium's DRT.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::markerTextForListItem):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+
+2010-08-31 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: add more unit tests
+
+ Add more unit tests for new-run-webkit-tests; we now cover all but
+ the most obscure code paths in the generic code. We still need to
+ add coverage for the http server and web socket paths, and add better
+ coverage of the platform-specific logic. Note that the rebaselining
+ tool is still not well tested.
+
+ Also clean up some of the configuration logic for the printing
+ module and the way it interacts with the Python logging module; that
+ is a crufty interface, to be certain.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44902
+
+ * Scripts/webkitpy/layout_tests/data/failures/expected/exception.html: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/keyboard.html: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/error-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/error.html: Added.
+ * Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-08-31 Darin Adler <darin@apple.com>
+
+ Reviewed by Anders Carlsson.
+
+ * Scripts/check-for-global-initializers: Add a file that ends up having global initializers
+ in a debug build when built with certain compilers.
+
+2010-08-31 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] Isolate all GTK+ typedefs into one file
+ https://bugs.webkit.org/show_bug.cgi?id=44900
+
+ * DumpRenderTree/gtk/EventSender.h: Remove GTK+ typedefs.
+
+2010-08-31 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Show more status on queue status pages
+ https://bugs.webkit.org/show_bug.cgi?id=44938
+
+ I upped the number of status lines from 6 to 15 --
+ this has been bugging me for a while...
+
+ I also disabled showing the chromium-win EWS queue
+ since it's been down for almost 5 months now.
+
+ * QueueStatusServer/handlers/dashboard.py:
+ * QueueStatusServer/handlers/queuestatus.py:
+ * QueueStatusServer/model/queues.py:
+
+2010-08-31 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] Read command line arguments and open them as URLs in new windows
+ https://bugs.webkit.org/show_bug.cgi?id=44944
+
+ Extend MiniBrowser to accept command line arguments and open them as URLs in new browser windows.
+
+ * MiniBrowser/qt/main.cpp:
+ (main):
+
+2010-08-31 Adrian Perez <aperez@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ Support scripts to run Buildbot slaves under daemontools (gtk related)
+ https://bugs.webkit.org/show_bug.cgi?id=40053
+
+ * BuildSlaveSupport/gtk: Added.
+ * BuildSlaveSupport/gtk/README: Added.
+ * BuildSlaveSupport/gtk/buildbot: Added.
+ * BuildSlaveSupport/gtk/buildbot/log: Added.
+ * BuildSlaveSupport/gtk/buildbot/log/run: Added.
+ * BuildSlaveSupport/gtk/buildbot/run: Added.
+ * BuildSlaveSupport/gtk/crashmon: Added.
+ * BuildSlaveSupport/gtk/crashmon/crashmon: Added.
+ * BuildSlaveSupport/gtk/crashmon/log: Added.
+ * BuildSlaveSupport/gtk/crashmon/log/run: Added.
+ * BuildSlaveSupport/gtk/crashmon/run: Added.
+ * BuildSlaveSupport/gtk/daemontools-buildbot.conf: Added.
+ * BuildSlaveSupport/gtk/pulseaudio: Added.
+ * BuildSlaveSupport/gtk/pulseaudio/run: Added.
+ * BuildSlaveSupport/gtk/xvfb: Added.
+ * BuildSlaveSupport/gtk/xvfb/log: Added.
+ * BuildSlaveSupport/gtk/xvfb/log/run: Added.
+ * BuildSlaveSupport/gtk/xvfb/run: Added.
+
+2010-08-27 John Gregg <johnnyg@google.com>
+
+ Reviewed by David Levin.
+
+ Notifications should support a click event.
+ Adds necessary hooks to chromium's DRT so that clicks on desktop notifications
+ can be simulated during a layout test. Requires storing a list of active
+ notifications so that they can be referred to later for clicking.
+ https://bugs.webkit.org/show_bug.cgi?id=44800
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::simulateDesktopNotificationClick):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/NotificationPresenter.cpp:
+ (NotificationPresenter::simulateClick):
+ (NotificationPresenter::show):
+ (NotificationPresenter::cancel):
+ (NotificationPresenter::objectDestroyed):
+ * DumpRenderTree/chromium/NotificationPresenter.h:
+
+2010-08-30 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Add missing parts of didFinishDocumentLoadForFrame
+ https://bugs.webkit.org/show_bug.cgi?id=44913
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (didFinishDocumentLoadForFrame): Added
+ (-[BrowserWindowController awakeFromNib]): Updated struct
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage): Rearranged function ptr
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize): Updated struct
+
+2010-08-30 Vangelis Kokkevis <vangelis@chromium.org>
+
+ Unreviewed: Add myself to the list of Committers.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-08-30 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Fix fast/notifications/notifications-display-close-events.html failure
+ https://bugs.webkit.org/show_bug.cgi?id=44585
+
+ Apply http://crrev.com/48893. We should dispatch display events
+ asynchronously.
+
+ * DumpRenderTree/chromium/NotificationPresenter.cpp:
+ (deferredDisplayDispatch):
+ (NotificationPresenter::show):
+
+2010-08-30 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ allow ports with windowed plugins to support windowless plugin tests
+
+ https://bugs.webkit.org/show_bug.cgi?id=40730
+
+ Ports that implement plugins windowed by default need to have a way of
+ supporting plugin tests that assume the plugin is windowless. Add this
+ feature to the tests and support it in the webkit test plugin. Also
+ add mouse and keyboard event logging to the webkit-test plugin on Unix.
+
+ Unskip the following tests on Qt:
+
+ plugins/mouse-events.html
+ plugins/keyboard-events.html
+ plugins/mouse-events-fixedpos.html
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginSetProperty):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_handle_event):
+
+2010-08-30 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after addition of fileapi directory in WebCore.
+
+ * wx/build/settings.py:
+
+2010-08-30 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ Fixed compilation error, now that we have included the
+ GtkVersioning.h we have to remove some version dependent code from
+ EventSender.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+
+2010-08-30 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [Gtk] gdk_display_get_core_pointer and gdk_device_get_core_pointer
+ are deprecated
+ https://bugs.webkit.org/show_bug.cgi?id=44787
+
+ We have replaced GtkVersioning.cpp with GtkVersioning.c and
+ created a function (getDefaultGDKPointerDevice) to get the pointer
+ of the window with the new APIs. We added that function to DRT and
+ copyandpaste unit test.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (prepareMouseButtonEvent):
+ (mouseMoveToCallback):
+ (keyDownCallback):
+ * GNUmakefile.am:
+
+2010-08-30 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Add new window menu to MiniBrowser
+
+ Implement newWindow function and add a menu item for opening new window in MiniBrowser.
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::newWindow):
+ * MiniBrowser/qt/BrowserWindow.h:
+ * MiniBrowser/qt/main.cpp:
+ (main):
+
+2010-08-29 James Robinson <jamesr@chromium.org>
+
+ Reviewed by David Levin.
+
+ Make failing the download step fail the build
+ https://bugs.webkit.org/show_bug.cgi?id=44298
+
+ If the download step fails on a test bot, this ensures that
+ the build goes red instead of only the download step going red
+ and the overall build staying green.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2010-08-29 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Remove dependency to base/keyboard_codes.h
+ https://bugs.webkit.org/show_bug.cgi?id=44847
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ Use webkit_support::VKEY_* instead of base::VKEY_*.
+
+2010-08-29 Darin Adler <darin@apple.com>
+
+ https://bugs.webkit.org/show_bug.cgi?id=40589
+
+ * Scripts/prepare-ChangeLog: Only prepend namespaces to non-empty
+ function names.
+
+2010-08-26 Holger Hans Peter Freyther <holger@moiji-mobile.com>
+
+ Reviewed by Darin Adler.
+
+ [iExploder] Add new CSS Properties and HTML Attributes
+ https://bugs.webkit.org/show_bug.cgi?id=44746
+
+ Updated the files with the update-iexploder-cssproperties script
+ and manually readded the -webkit-binding CSS Property to the list.
+
+ * iExploder/htdocs/cssproperties.in:
+ * iExploder/htdocs/htmlattrs.in:
+ * iExploder/htdocs/htmltags.in:
+
+2010-08-26 Holger Hans Peter Freyther <holger@moiji-mobile.com>
+
+ Reviewed by Darin Adler.
+
+ Fix Coverage build after the addition of ANGLE
+ https://bugs.webkit.org/show_bug.cgi?id=44744
+
+ ANGLE is using libtool to build a static library and the version of
+ libtool on Leopard refuses to handle the -fprofile-arcs and -ftest-coverage
+ parameters. The easiest way to handle this is to not build ANGLE with
+ coverage information.
+
+ This is achieved by applying the XCode options for each project
+ separately and exclude ANGLE.
+
+ * Scripts/build-webkit: Remove -framework AppKit due link errors.
+ * Scripts/webkitdirs.pm: Do not apply the XCode options for ANGLE.
+
+2010-08-28 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after directory addition.
+
+ * wx/build/settings.py:
+
+2010-08-28 Chris Guillory <chris.guillory@google.com>
+
+ Reviewed by Chris Fleizach.
+
+ Add AX notification for childrenChanged
+ https://bugs.webkit.org/show_bug.cgi?id=44472
+
+ * DumpRenderTree/chromium/AccessibilityController.cpp:
+ (AccessibilityController::AccessibilityController):
+ (AccessibilityController::reset):
+ (AccessibilityController::getRootElement):
+ (AccessibilityController::dumpAccessibilityNotifications):
+ * DumpRenderTree/chromium/AccessibilityController.h:
+ (AccessibilityController::shouldDumpAccessibilityNotifications):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::didChangeAccessibilityObjectChildren):
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-08-28 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Update commit-queue failure message
+ https://bugs.webkit.org/show_bug.cgi?id=44798
+
+ The commit-queue auto-restarts itself and has for a very long time.
+ No need for people to email me to request a restart anymore.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-07-27 Jer Noble <jer.noble@apple.com>
+
+ Reviewed by Eric Carlson.
+
+ Add JavaScript API to allow a page to go fullscreen.
+ rdar://problem/6867795
+
+ Added basic full screen support to DumpRenderTree: when a webView requests
+ that DumpRenderTree go "full screen", just call the provided callback listener object's
+ will/did Enter/Exit full screen methods. Also, register a new user default which
+ enables full screen support.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:supportsFullscreenForElement:]):
+ (-[UIDelegate webView:enterFullscreenForElement:listener:]):
+ (-[UIDelegate webView:exitFullscreenForElement:listener:]):
+
+2010-08-27 Benjamin Poulain <benjamin.poulain@nokia.com>
+
+ Unreviewed. Add myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-08-27 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Pavel Feldman.
+
+ [DRT/Chromium] Fix inspector test failures
+ https://bugs.webkit.org/show_bug.cgi?id=44748
+
+ * DumpRenderTree/chromium/DRTDevToolsAgent.cpp:
+ (DRTDevToolsAgent::createClientMessageLoop):
+ Returns a valid WebKitClientMessageLoop instance
+ * DumpRenderTree/chromium/DRTDevToolsAgent.h:
+
+2010-08-26 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Add Windows WebKit2 Tester to buildbot
+ <rdar://problem/7887703>
+
+ Reviewed by Dan Bernstein.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2010-08-26 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Needs DRT queueLoadHTMLString and setDeferMainResourceLoad-implementations
+ https://bugs.webkit.org/show_bug.cgi?id=42152
+
+ * DumpRenderTree/gtk/WorkQueueItemGtk.cpp:
+ (LoadHTMLStringItem::invoke): Implementation using
+ webkit_web_frame_load_string().
+
+2010-08-25 Jon Honeycutt <jhoneycutt@apple.com>
+
+ <rdar://problem/8334338> run-webkit-tests sometimes hangs when using
+ WebKitTestRunner (44331)
+
+ Reviewed by Darin Adler.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize):
+ The hang occurs when WebKitTestRunner begins launching the WebKit2
+ web process then exits before it finishes launching. Work around this by
+ looking for the --print-supported-features argument and exiting without
+ creating the web process.
+
+2010-08-26 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ new-run-webkit-tests: add rebaselining tests for test_expectations
+
+ This patch adds more unit tests for the rebaselining code in the
+ test_expectations module. It doesn't add any tests for
+ rebaseline_chromium_webkit_tests itself; that will come some other
+ time.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44648
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py:
+
+2010-08-26 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] Add HTTP caching support
+ https://bugs.webkit.org/show_bug.cgi?id=44261
+
+ Ignore new soup API that we decided to merge into the soup backend
+ while it is being cooked. It follows the libsoup style, and will
+ be removed from WebKit as soon as it is merged into libsoup.
+
+ * Scripts/webkitpy/style/checker.py:
+
+2010-08-26 Mahesh Kulkarni <mahesh.kulkarni@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] DumpRenderTree runs only one test from command mode
+ https://bugs.webkit.org/show_bug.cgi?id=44012
+
+ Enables support to run multiple test files and single
+ folder containing html files in stand alone mode
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::processArgsLine):
+ (WebCore::DumpRenderTree::loadNextTestInStandAloneMode):
+ (WebCore::DumpRenderTree::processLine):
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ (WebCore::DumpRenderTree::setStandAloneMode):
+ (WebCore::DumpRenderTree::isStandAloneMode):
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2010-08-25 Martin Robinson <mrobinson@igalia.com>
+
+ Updating webkitpy test expectations.
+
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+
+2010-08-25 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ fix the always squash git config
+ https://bugs.webkit.org/show_bug.cgi?id=44651
+
+ Fix help text and apparently underscores are not allowed
+ in git config keys.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/tool/steps/commit.py:
+
+2010-08-25 Darin Adler <darin@apple.com>
+
+ Reviewed by John Sullivan.
+
+ * Scripts/commit-log-editor: Fix perl warning for people who have no
+ value for SVN_LOG_EDITOR or CVS_LOG_EDITOR.
+
+2010-08-25 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ stop blocking commits when the bots are red
+ https://bugs.webkit.org/show_bug.cgi?id=44644
+
+ This check currently is just annoying. It doesn't actually
+ help keep the tree green. We can always add it back later
+ if we decide the tree is generally more green.
+
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/ensurebuildersaregreen.py:
+
+2010-08-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Simon Fraser.
+
+ REGRESSION: media/video-loop.html is timing out on the commit-queue Leopard Bot
+ https://bugs.webkit.org/show_bug.cgi?id=38912
+
+ I know of nothing else to do but skip all media tests for the cq.
+
+ * Scripts/webkitpy/tool/steps/runtests.py:
+
+2010-08-25 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: add more unit tests for test_expectations
+ This adds unit tests to cover (almost?) all of the non-rebaselining
+ functionality.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44579
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py:
+
+2010-08-25 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: add more unit tests
+
+ This change adds more unit tests for the image_diff, test_failures,
+ and test_files modules, bringing them to 100% coverage (and adds a
+ couple tests to run_webkit_tests while we're at it).
+
+ This test also turns on the "dryrun" port for testing when run on
+ the mac, increasing coverage in a few other places.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44578
+
+ * Scripts/webkitpy/layout_tests/data/failures/expected/checksum-expected.checksum: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/checksum-expected.png: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/checksum-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/checksum.html: Copied from WebKitTools/Scripts/webkitpy/layout_tests/data/failures/expected/image_checksum.html.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/missing_check-expected.png: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/missing_check-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/missing_check.html: Copied from WebKitTools/Scripts/webkitpy/layout_tests/data/failures/expected/missing_image.html.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/timeout.html: Added.
+ * Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt:
+ * Scripts/webkitpy/layout_tests/data/resources/README.txt: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-08-25 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: add more unit tests for layout_package/printing.py
+
+ This change adds more unit tests to get the test coverage to 100%
+ for the printing module. This code is actually pretty crufty and
+ has some layering violations that need to be cleaned up but I'll
+ save that for another CL after we get all the unit tests written and
+ we fix the multithreading issues. At least now we'll be able to tell
+ if we break things.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44576
+
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+
+2010-08-25 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests should respect set-webkit-configuration
+ https://bugs.webkit.org/show_bug.cgi?id=44633
+
+ Moves the getting of the configuration into the base Port so that
+ chromium ports use it as well. In the downstream chromium port,
+ this should still just return Release.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-08-25 Tony Chang <tony@chromium.org>
+
+ Not reviewed, changing svn props for a script.
+
+ * Scripts/deduplicate-tests: Added properties svn:executable and svn:eol-style.
+
+2010-08-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Remove WebKit2 from core builders
+ https://bugs.webkit.org/show_bug.cgi?id=44625
+
+ This builder was added to the core builders by accident. It doesn't
+ appear to be green enough to be a core builder yet.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+
+2010-08-19 Adam Roben <aroben@apple.com>
+
+ Test that NP_Initialize and NP_GetEntryPoints are called in the
+ correct order
+
+ The order differs between Mac and Windows (see r38858).
+
+ Fixes <http://webkit.org/b/44270> <rdar://problem/8330393> Crash in
+ NP_Initialize when loading QuickTime when running
+ plugins/embed-attributes-setting.html in WebKit2 on Windows
+
+ Reviewed by John Sullivan.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp: Added a CRASH macro and
+ a boolean to record whether NP_GetEntryPoints has been called.
+ (NP_Initialize): Crash on Windows if NP_GetEntryPoints hasn't been
+ called yet. This matches Flash and QuickTime's behavior.
+ (NP_GetEntryPoints): Crash on Mac if NP_Initialize hasn't been called
+ yet. This matches Silverlight's behavior.
+
+2010-08-25 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ Cairo and EFL port shouldn't depend on glib.
+ https://bugs.webkit.org/show_bug.cgi?id=44354
+
+ Replace occurrences of GRefPtr and adoptGRef with PlatformRefPtr and
+ adoptPlatformRef.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::isSelected):
+
+2010-08-25 Ojan Vafai <ojan@chromium.org>
+
+ Fix order of Timothy's email address. The script, and
+ other tools all assume that the first email is the bugzilla address.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-08-24 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Pavel Feldman.
+
+ [DRT/Chromium] Fix 26 inspector test crashes
+ https://bugs.webkit.org/show_bug.cgi?id=44580
+
+ - DRTDevToolsAgent has a reference to the main WebView. So we
+ should not clear it in closeDevTools() and should clear it in
+ ~TestShell().
+ - DRTDevToolsClient has a reference to a DevTools WebView and no
+ way to update it. So we should delete DRTDevToolsClient instances
+ in closeDevTools().
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::~TestShell):
+ (TestShell::closeDevTools):
+
+2010-08-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ unicode(Exception(\u"0x1234")) is busted in python 2.5, disable tests which hit this
+ https://bugs.webkit.org/show_bug.cgi?id=44584
+
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-08-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue and EWS bots should report all failures
+ https://bugs.webkit.org/show_bug.cgi?id=41820
+
+ Right now commit-queue/EWS only report failures when the
+ patch under testing fails. We should report all failures
+ to the status server so that we can diagnose when the bots
+ are wedged w/o needing to log into the machines.
+
+ I also reduced the amount of data we upload since we've seen
+ timeouts during status upload.
+
+ * Scripts/webkitpy/common/system/executive.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-08-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Remove HTML5 parser testing infrastructure now that we don't need it
+ https://bugs.webkit.org/show_bug.cgi?id=44581
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ (initializeGlobalsFromCommandLineOptions):
+ * Scripts/old-run-webkit-tests:
+ * Scripts/test-html5-parser: Removed.
+
+2010-08-24 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Fix 28 inspector test crashes
+ https://bugs.webkit.org/show_bug.cgi?id=44574
+
+ Reset DevToolsClient and DevToolsAgent before closing a DevTools
+ WebView in order to avoid accessing to a deleted WebView instance.
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::closeDevTools):
+
+2010-08-24 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: clean up code for test_types, test_failures
+
+ Add a bunch of unit tests for webkitpy.layout_tests.test_types and
+ webkitpy.layout_tests.layout_package.test_failures, and remove
+ some dead code and otherwise clean up things.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44559
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_failures.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-08-24 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests: revise unit testing strategy for test failures
+
+ This change revamps the way we store test data for new-run-webkit-tests.
+ Previously we had a few copies of test files from the main test tree.
+ Now we have a bunch of completely fake test data and use the test
+ data to generate different kinds of test failures, getting
+ much better coverage.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44556
+
+ * Scripts/webkitpy/layout_tests/data/failures/expected/crash.html: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/image-expected.checksum: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/image-expected.png: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/image-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/image.html: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/image_checksum-expected.checksum: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/image_checksum-expected.png: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/image_checksum-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/image_checksum.html: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/missing_image.html: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/missing_text.html: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/text-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/expected/text.html: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/unexpected/text-image-checksum-expected.checksum: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/unexpected/text-image-checksum-expected.png: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/unexpected/text-image-checksum-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/failures/unexpected/text-image-checksum.html: Added.
+ * Scripts/webkitpy/layout_tests/data/image/canvas-bg.html: Removed.
+ * Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.checksum: Removed.
+ * Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.png: Removed.
+ * Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.txt: Removed.
+ * Scripts/webkitpy/layout_tests/data/image/canvas-zoom.html: Removed.
+ * Scripts/webkitpy/layout_tests/data/misc/crash-expected.txt: Removed.
+ * Scripts/webkitpy/layout_tests/data/misc/crash.html: Removed.
+ * Scripts/webkitpy/layout_tests/data/misc/missing-expectation.html: Removed.
+ * Scripts/webkitpy/layout_tests/data/misc/passing-expected.txt: Removed.
+ * Scripts/webkitpy/layout_tests/data/misc/passing.html: Removed.
+ * Scripts/webkitpy/layout_tests/data/passes/image-expected.checksum: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/image-expected.png: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/image-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/image.html: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/platform_image-expected.checksum: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/platform_image-expected.png: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/platform_image-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/platform_image.html: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/text-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/passes/text.html: Added.
+ * Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.checksum: Removed.
+ * Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.png: Removed.
+ * Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.txt: Removed.
+ * Scripts/webkitpy/layout_tests/data/platform/test/passes/platform_image-expected.checksum: Added.
+ * Scripts/webkitpy/layout_tests/data/platform/test/passes/platform_image-expected.png: Added.
+ * Scripts/webkitpy/layout_tests/data/platform/test/passes/platform_image-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt:
+ * Scripts/webkitpy/layout_tests/data/text/article-element-expected.txt: Removed.
+ * Scripts/webkitpy/layout_tests/data/text/article-element.html: Removed.
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+ * Scripts/webkitpy/style/checkers/test_expectations_unittest.py:
+
+2010-08-24 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ speed up new-run-webkit-tests unit tests
+
+ Add a --no-record-results flag that turns off generating the JSON
+ results file on every test run. Generating the file requires us to
+ fetch the old results down from the bots, which can be slow. This
+ flag is off by default.
+
+ Reduce the sleep time in wait_for_threads_to_finish from 0.1s to 0.01s.
+
+ These changes together shorten the test cycle from ~4.5s to ~1.5s
+ - a 3x speedup.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44553
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-08-24 Tony Chang <tony@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [chromium] fix the platform result fallback order on mac/win
+ https://bugs.webkit.org/show_bug.cgi?id=44483
+
+ * Scripts/webkitpy/layout_tests/port/google_chrome.py:
+
+2010-08-24 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ Set a device to the event struct when building with GTK+ 3.x, it's
+ mandatory.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (keyDownCallback):
+
+2010-08-24 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] GTK3: EventSender and API tests should use gdk_event_new when synthesizing events
+ https://bugs.webkit.org/show_bug.cgi?id=44534
+
+ Fix two double-frees introduced in my previous commit.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (contextClickCallback): Copy the event before using it again.
+ (keyDownCallback): Ditto.
+
+2010-08-24 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] GTK3: EventSender and API tests should use gdk_event_new when synthesizing events
+ https://bugs.webkit.org/show_bug.cgi?id=44534
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (prepareMouseButtonEvent): Use gdk_event_new and reference the reference the GdkWindow
+ when setting it on the event. It is dereferenced by gdk_event_free(...).
+ (contextClickCallback): Ditto.
+ (mouseDownCallback): Ditto.
+ (mouseUpCallback): Ditto.
+ (mouseMoveToCallback): Ditto.
+ (mouseWheelToCallback): Ditto.
+ (sendOrQueueEvent): Take a GdkEvent* instead of a GdkEvent.
+ (dispatchEvent): Ditto. Also free the event when we are done with it.
+ (keyDownCallback): Use gdk_event_new and reference the GdkWindow.
+
+2010-08-24 Andras Becsi <abecsi@webkit.org>
+
+ [Qt] WebKit2 build fix.
+
+ * Scripts/enumerate-included-framework-headers:
+ Remove stray global option form sed.
+
+2010-08-24 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Jeremy Orlow.
+
+ [DRT/Chromium] Support for IndexedDB tests
+ https://bugs.webkit.org/show_bug.cgi?id=44490
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell): Enable IndexedDB.
+
+2010-08-23 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] The 64-bit Release bot is showing crashes on tests that use mouse buttons
+ https://bugs.webkit.org/show_bug.cgi?id=44465
+
+ Initialize the axes field of mouse button and motion events to null.
+ This is the value that should be used for events originating from the
+ mouse device.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (prepareMouseButtonEvent): Initalize button event axes field to null.
+ (mouseMoveToCallback): Initialize motion event axes field to null.
+
+2010-08-23 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r65703.
+ http://trac.webkit.org/changeset/65703
+ https://bugs.webkit.org/show_bug.cgi?id=44460
+
+ "Causing lots of crashes on Snow Leopard when running the
+ layout tests" (Requested by eseidel2 on #webkit).
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NP_Initialize):
+ (NP_GetEntryPoints):
+
+2010-08-23 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Layout tests do not run when using WebKitTestRunner in a Debug build.
+ https://bugs.webkit.org/show_bug.cgi?id=44409
+
+ Reviewed by Dan Bernstein.
+
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::initializeInjectedBundlePath):
+ Use InjectedBundle_debug.dll when building Debug.
+
+2010-08-23 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Martin Robinson.
+
+ [GTK] run-launcher fails if WebKitGTK+ compiled with GTK+-3.0 support
+ https://bugs.webkit.org/show_bug.cgi?id=42026
+
+ If a GTK+ 3.x build is present return that as the library to use,
+ otherwise fallback to the GTK+ 2.x build.
+
+ * Scripts/webkitdirs.pm:
+
+2010-08-23 Balazs Kelemen <kb@inf.u-szeged.hu>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] Find needed forwarding headers for WebKit2 automatically
+ https://bugs.webkit.org/show_bug.cgi?id=44336
+
+ * MiniBrowser/qt/BrowserWindow.cpp: Use normal (not framework style) includes here.
+ The new script does not satisfy the needs of this file however using normal includes
+ is generally better here.
+ * MiniBrowser/qt/MiniBrowser.pro: Added include paths.
+ * Scripts/enumerate-included-framework-headers: Enumerates headers included from the
+ given frameworks by files in the current directory (and subdirectories).
+ In the future this needs to be rewritten in perl for being able to use on Windows.
+
+2010-08-22 No'am Rosenthal <noam.rosenthal@nokia.com>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] Qt test browser: enable a QGLWidget viewport with a command line argument
+ https://bugs.webkit.org/show_bug.cgi?id=43010
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::applyPrefs):
+ * QtTestBrowser/main.cpp:
+ (LauncherApplication::handleUserOptions):
+
+2010-08-21 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ Remove specialized retain/release functions in favor of a single one for WKTypeRefs
+ https://bugs.webkit.org/show_bug.cgi?id=44386
+
+ * MiniBrowser/mac/AppDelegate.m:
+ (didRecieveMessageFromInjectedBundle):
+ (didNavigateWithNavigationData):
+ (-[BrowserAppDelegate init]):
+ (-[BrowserAppDelegate applicationWillTerminate:]):
+ * MiniBrowser/mac/BrowserStatisticsWindowController.m:
+ (-[BrowserStatisticsWindowController initWithThreadedWKContextRef:processWKContextRef:]):
+ (-[BrowserStatisticsWindowController dealloc]):
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController initWithPageNamespace:]):
+ (-[BrowserWindowController fetch:]):
+ (-[BrowserWindowController windowWillClose:]):
+ (-[BrowserWindowController applicationTerminating]):
+ (closePage):
+ (runJavaScriptAlert):
+ (runJavaScriptConfirm):
+ (runJavaScriptPrompt):
+ (-[BrowserWindowController updateProvisionalURLForFrame:]):
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (didClearWindowObjectForFrame):
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::goToURL):
+ * WebKitTestRunner/win/PlatformWebViewWin.cpp:
+ (WTR::PlatformWebView::~PlatformWebView):
+
+2010-08-20 Benjamin Poulain <benjamin.poulain@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ WebKit does not build with Python 2.3
+ https://bugs.webkit.org/show_bug.cgi?id=44373
+
+ Replaced the function sorted() by a call to sort()
+ on the entry list.
+ The function sorted() has been added to Python 2.4.
+ The function method sort() of List works with older
+ versions of Python.
+
+ * Scripts/create-html-entity-table:
+
+2010-08-20 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Pavel Feldman.
+
+ Web Inspector: Inspector tests were disabled for GTK.
+ https://bugs.webkit.org/show_bug.cgi?id=43977
+
+ * Scripts/old-run-webkit-tests: Set the WEBKIT_INSPECTOR_PATH to the appropriate
+ path before running tests.
+
+2010-08-20 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Eric Seidel.
+
+ svn-apply doesn't detect empty line with Windows line endings
+ after property value
+ https://bugs.webkit.org/show_bug.cgi?id=43981
+
+ Part 2 of 2
+
+ Add unit tests that were not landed in the first commit.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl:
+ - Added the following test cases:
+ "SVN: binary file (isBinary true) using Windows line endings"
+ "SVN: property diff, followed by file change diff using Windows line endings"
+ "SVN: two consecutive property diffs using Windows line endings"
+ "SVN: binary file with executable bit change usng Windows line endings"
+ "SVN: binary file followed by property change on different file using Windows line endings"
+ "SVN: binary file followed by file change on different file using Windows line endings"
+ "SVN: file change diff with property change, followed by property change diff using Windows line endings"
+ "SVN: file change diff with property change, followed by file change diff using Windows line endings"
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnProperty.pl:
+ - Added the following test cases:
+ "add svn:executable, followed by empty line and start of next diff using Windows line endings"
+ "add svn:executable, followed by empty line and start of next property diff using Windows line endings"
+ "multi-line '+' change, followed by empty line and start of next diff using Windows line endings"
+ "multi-line '+' change, followed by empty line and start of next property diff using Windows line endings"
+ "add svn:executable, followed by empty line and start of binary patch using Windows line endings"
+ "multi-line '+' change, followed by empty line and start of binary patch using Windows line endings"
+ "multi-line '-' change, followed by multi-line '+' change, empty line, and start of binary patch using Windows line endings"
+ "single-line '+' with trailing new line using Windows line endings"
+ "single-line '+' with trailing new line, followed by empty line and start of binary patch using Windows line endings"
+ "single-line '-' change with trailing new line, and single-line '+' change using Windows line endings"
+ "multi-line '-' change with trailing new line, and multi-line '+' change using Windows line endings"
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl:
+ - Added the following test cases:
+ "single-line '-' change followed by empty line with Windows line endings"
+ "multi-line '+' change and start of binary patch with Windows line endings"
+
+2010-08-20 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Eric Seidel.
+
+ svn-apply doesn't detect empty line with Windows line endings
+ after property value
+ https://bugs.webkit.org/show_bug.cgi?id=43981
+
+ Fixes an issue where an empty line following the property value
+ in an SVN property change diff would not be detected if it had
+ Windows line endings (i.e. ended in CRLF). Hence it was consumed
+ as if it was part of a multi-line property value.
+
+ * Scripts/VCSUtils.pm:
+ - Modified parseSvnPropertyValue() to detect empty line
+ with Windows line endings.
+ - Added toWindowsLineEndings().
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl:
+ - Added the following test cases:
+ "SVN: binary file (isBinary true) using Windows line endings"
+ "SVN: property diff, followed by file change diff using Windows line endings"
+ "SVN: two consecutive property diffs using Windows line endings"
+ "SVN: binary file with executable bit change usng Windows line endings"
+ "SVN: binary file followed by property change on different file using Windows line endings"
+ "SVN: binary file followed by file change on different file using Windows line endings"
+ "SVN: file change diff with property change, followed by property change diff using Windows line endings"
+ "SVN: file change diff with property change, followed by file change diff using Windows line endings"
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnProperty.pl:
+ - Added the following test cases:
+ "add svn:executable, followed by empty line and start of next diff using Windows line endings"
+ "add svn:executable, followed by empty line and start of next property diff using Windows line endings"
+ "multi-line '+' change, followed by empty line and start of next diff using Windows line endings"
+ "multi-line '+' change, followed by empty line and start of next property diff using Windows line endings"
+ "add svn:executable, followed by empty line and start of binary patch using Windows line endings"
+ "multi-line '+' change, followed by empty line and start of binary patch using Windows line endings"
+ "multi-line '-' change, followed by multi-line '+' change, empty line, and start of binary patch using Windows line endings"
+ "single-line '+' with trailing new line using Windows line endings"
+ "single-line '+' with trailing new line, followed by empty line and start of binary patch using Windows line endings"
+ "single-line '-' change with trailing new line, and single-line '+' change using Windows line endings"
+ "multi-line '-' change with trailing new line, and multi-line '+' change using Windows line endings"
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl:
+ - Added the following test cases:
+ "single-line '-' change followed by empty line with Windows line endings"
+ "multi-line '+' change and start of binary patch with Windows line endings"
+
+2010-08-19 David Kilzer <ddkilzer@apple.com>
+
+ BUILD FIX: Fix Mac build after Windows WebKit2 changes for Netscape Plug-ins
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (decidePolicyForNavigationAction): Updated method signature.
+ (decidePolicyForNewWindowAction): Updated method signature.
+
+2010-08-19 Adam Roben <aroben@apple.com>
+
+ Test that NP_Initialize and NP_GetEntryPoints are called in the
+ correct order
+
+ The order differs between Mac and Windows (see r38858).
+
+ Fixes <http://webkit.org/b/44270> <rdar://problem/8330393> Crash in
+ NP_Initialize when loading QuickTime when running
+ plugins/embed-attributes-setting.html in WebKit2 on Windows
+
+ Reviewed by Sam Weinig.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp: Added a CRASH macro and
+ a boolean to record whether NP_GetEntryPoints has been called.
+ (NP_Initialize): Crash on Windows if NP_GetEntryPoints hasn't been
+ called yet. This matches Flash and QuickTime's behavior. Crash on Mac
+ if NP_GetEntryPoints has been called already. This matches
+ Silverlight's behavior.
+
+2010-08-19 Adam Roben <aroben@apple.com>
+
+ Make build-webkittestrunner build TestNetscapePlugIn on Windows
+
+ Fixes <http://webkit.org/b/44268> <rdar://problem/8330388>
+
+ Reviewed by Sam Weinig.
+
+ * WebKitTestRunner/WebKitTestRunner.sln: Added TestNetscapePlugIn.
+ Threaded it in between ImageDiff and InjectedBundleGenerated.
+
+2010-08-19 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ install rietveld's upload script from a versioned url
+ https://bugs.webkit.org/show_bug.cgi?id=44291
+
+ autoinstall expects the file at a given URL to never change.
+ In order to be able to update the file, we need to be able to
+ change the path.
+
+ * Scripts/webkitpy/thirdparty/__init__.py:
+
+2010-08-19 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ add --webkit_patch_id to reitveld uploads
+ https://bugs.webkit.org/show_bug.cgi?id=44289
+
+ This is the first step in having rietveld store which
+ patches have been uploaded and getting rid of the
+ in-rietveld flag.
+
+ * Scripts/webkitpy/common/net/rietveld.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/postcodereview.py:
+
+2010-08-19 Kenneth Russell <kbr@google.com>
+
+ Reviewed by David Levin.
+
+ Adjust my status from committer to reviewer
+ https://bugs.webkit.org/show_bug.cgi?id=44277
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-08-19 Pavel Feldman <pfeldman@chromium.org>
+
+ Reviewed by Yury Semikhatsky.
+
+ Chromium DevTools: remove injected script fetcher from test harness.
+ https://bugs.webkit.org/show_bug.cgi?id=44266
+
+ * DumpRenderTree/chromium/DRTDevToolsAgent.cpp:
+ * DumpRenderTree/chromium/DRTDevToolsAgent.h:
+
+2010-08-19 Pavel Feldman <pfeldman@chromium.org>
+
+ Reviewed by Yury Semikhatsky.
+
+ Chromium DevTools: There is no need in resource-based InjectedScript.js source.
+ Now that we populate front-end after its onload handler, we don't need
+ to install injected script early. Exposing injected script source on the WebCore
+ level here.
+ https://bugs.webkit.org/show_bug.cgi?id=44029
+
+ * DumpRenderTree/chromium/DRTDevToolsAgent.cpp:
+ (DRTDevToolsAgent::runtimePropertyChanged):
+ (DRTDevToolsAgent::delayedFrontendLoaded):
+ (DRTDevToolsAgent::frontendLoaded):
+ * DumpRenderTree/chromium/DRTDevToolsAgent.h:
+
+2010-08-19 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Gtk] Enable view mode media feature layout test
+ https://bugs.webkit.org/show_bug.cgi?id=43278
+
+ Add view mode media feature testing infrastructure, and add
+ placeholder methods for the other platforms'
+ LayoutTestControllers.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setViewModeMediaFeatureCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setViewModeMediaFeature):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setViewModeMediaFeature):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setViewModeMediaFeature):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setViewModeMediaFeature):
+
+2010-08-18 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Make it so the WebKit2 test slave runs the WebKit2 tests
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2010-08-18 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Make run-webkit-tests --webkit-test-runner build DumpRenderTree
+ in addition to WebKitTestRunner to get the DumpRenderTreeSupport
+ module and the TestNetscapePlugin.
+
+ * Scripts/old-run-webkit-tests:
+
+2010-08-18 Adam Roben <aroben@apple.com>
+
+ Fix hang when saving crash logs on Windows
+
+ * Scripts/old-run-webkit-tests:
+ (setUpWindowsCrashLogSaving):
+ (END):
+ Pass -s to regtool so it will write the Auto value as a string instead
+ of as a number. This was causing a "do you want to debug?" dialog to
+ appear.
+
+2010-08-17 Victor Wang <victorw@chromium.org>
+
+ Unreviewed. Fixed chromium incremental test json upload.
+ Quote builder name and test results server in url.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+
+2010-08-17 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] [Symbian] Consistently use Q_OS_SYMBIAN to guard all Symbian platform dependencies
+ https://bugs.webkit.org/show_bug.cgi?id=44124
+
+ Q_WS_S60 is not defined for Symbian^4 devices as Q_WS_S60 used to guard
+ Avkon UI framework dependencies. Use Q_OS_SYMBIAN everywhere to mark
+ Symbian dependencies.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::open):
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::init):
+ (LauncherWindow::toggleFullScreenMode):
+ (LauncherWindow::showFPS):
+ (LauncherWindow::updateFPS):
+ * QtTestBrowser/launcherwindow.h:
+ (WindowOptions::WindowOptions):
+ * QtTestBrowser/mainwindow.cpp:
+ (MainWindow::buildUI):
+
+2010-08-17 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by David Levin.
+
+ new-run-webkit-tests: remove --show-sources option
+
+ --show-sources is pretty much obsolete with --trace everything, so
+ I'm removing it.
+
+ Also rename a couple of methods in the TestTextDiff class to make their
+ intended visibility (private) more obvious.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44143
+
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-08-17 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by David Levin.
+
+ remove --fuzzy-image-diff in new-run-webkit-tests (it doesn't work)
+
+ This code bit-rotted at some point more than a year ago, and nobody seems
+ to miss it. old-run-webkit-tests has a --tolerance flag that new-run-webkit-tests
+ should support instead, making this flag unnecessary anyway.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44141
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_failures.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py: Removed.
+
+2010-08-17 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Update json results generator to have incremental json including
+ results for tests that pass in current run but failed before.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44119
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-08-17 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ fix test-webkitpy, add easy way to find a checkout root
+
+ test-webkitpy currently doesn't work right if run from someplace other
+ than the checkout root, and it spews a bunch of debug logging because
+ the deduplicate_tests tests contaminates the test environment.
+
+ This patch cleans up the deduplicate_tests unit tests, and creates
+ two new methods in scm.py: find_checkout_root() and default_scm(),
+ both of which use a single algorithm for guessing what checkout root
+ to use if you aren't explicitly told one from a path.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44001
+
+ * Scripts/deduplicate-tests:
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ * Scripts/webkitpy/layout_tests/deduplicate_tests.py:
+ * Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py:
+ * Scripts/webkitpy/tool/main.py:
+
+2010-08-17 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Add support to the test results server for downloading json that
+ contains test list only.
+
+ This is for json results generator to generate incremental json
+ results so that it includes results not only for tests failed in
+ current run, but also tests failed before.
+
+ Also set the results type to "N" (no data) instead of "P" (pass)
+ if test results cannot be found in incremental json file.
+
+ https://bugs.webkit.org/show_bug.cgi?id=44117
+
+ * TestResultServer/handlers/testfilehandler.py:
+ * TestResultServer/model/jsonresults.py:
+ * TestResultServer/model/jsonresults_unittest.py:
+
+2010-08-17 Adam Roben <aroben@apple.com>
+
+ Use the right path style
+
+ * Scripts/old-run-webkit-tests:
+
+2010-08-17 Adam Roben <aroben@apple.com>
+
+ Fix typo
+
+ * Scripts/old-run-webkit-tests:
+
+2010-08-17 Adam Roben <aroben@apple.com>
+
+ Don't hang when running run-webkit-tests as a non-Administrator on
+ Vista/7
+
+ * Scripts/old-run-webkit-tests:
+ (setUpWindowsCrashLogSaving): Use regtool to set NTSD as the
+ post-mortem debugger, rather than using NTSD itself. The latter waits
+ for user input when it fails to set the registry values; the former
+ does not.
+
+2010-08-17 Adam Roben <aroben@apple.com>
+
+ Teach run-webkit-tests, DumpRenderTree, and WebKitTestRunner how to
+ save crash logs on Windows
+
+ The crash logs are saved to /tmp/layout-test-results and have names
+ like CrashLog_02bc_2010-08-17_14-36-20-108.txt.
+
+ Unfortunately, crashes in the WebKit2 web process are recorded as
+ time-outs by run-webkit-tests. Fixing this is covered by
+ <http://webkit.org/b/44121>.
+
+ Fixes <http://webkit.org/b/37859> <rdar://problem/7883560>
+ DumpRenderTree should save a stack trace and/or dump file when it
+ crashes
+
+ Reviewed by Sam Weinig.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (exceptionFilter):
+ (main):
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::exceptionFilter):
+ (WTR::TestController::platformInitialize):
+ These changes set up an exception filter that prints #CRASHED to
+ stderr, then lets the exception propagate normally. This allows
+ run-webkit-tests to detect when we've crashed even when a post-mortem
+ debugger attaches to the process.
+
+ * Scripts/old-run-webkit-tests:
+ (top level): Declared some variables used by the crash-log-saving
+ code.
+ (openDumpTool): Copy _NT_SYMBOL_PATH into the clean environment so
+ that the post-mortem debugger has access to it.
+ (toCygwinPath): Added. This is the opposite of toWindowsPath.
+ (readFromDumpToolWithTimer): If the dump tool prints #CRASHED to
+ stderr, consider it a crash.
+ (setUpWindowsCrashLogSaving): Added. Saves the current post-mortem
+ debugger, then sets ntsd as the post-mortem debugger. ntsd is
+ configured to save a crash log and then quit automatically.
+ (END): Added. Restores the previous post-mortem debugger when the
+ script exits.
+
+2010-08-17 Victor Wang <victorw@chromium.org>
+
+ Reviewed by ojan@chromium.org.
+
+ Update test results server:
+ 1. Normalize test results and times after merging (prune tests where
+ all runs pass or do not have data, truncate all test items to max
+ number of builds)
+ 2. times should be int not string.
+ 3. when inserting a new test item, should keep old data regardless
+ whether or not they have same item type with new one.
+
+ https://bugs.webkit.org/show_bug.cgi?id=43861
+
+ * TestResultServer/model/jsonresults.py:
+ * TestResultServer/model/jsonresults_unittest.py:
+
+2010-08-16 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Add WebKit2 Mac tester to buildbot.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2010-08-16 Paul Sawaya <psawaya@apple.com>
+
+ Reviewed by Chris Marrin.
+
+ Added shader validation via ANGLE
+ https://bugs.webkit.org/show_bug.cgi?id=42405
+
+ Added ANGLE to webkit build
+
+ * Scripts/build-webkit:
+
+2010-08-16 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix, do not build WebCore as a convenience library as this leads to
+ errors in the Win build w/export symbols and causes problems with DOM bindings
+ debugging in gdb.
+
+ * DumpRenderTree/wscript:
+ * Scripts/build-webkit:
+ * wx/browser/wscript:
+ * wx/build/settings.py:
+ * wx/build/waf_extensions.py:
+
+2010-08-16 Dan Bernstein <mitz@apple.com>
+
+ Build fix.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::createOtherPage): Initialize the contentsSizeChanged member.
+ (WTR::TestController::initialize): Ditto.
+
+2010-08-16 Balazs Kelemen <kb@inf.u-szeged.hu>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Handle content size change in WebKit2
+ Re-landing after fix.
+
+ https://bugs.webkit.org/show_bug.cgi?id=43198
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]): Initialize WKPageUICallback::contetsSizeChanged to 0.
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::create): Initialize WKPageUICallback::contetsSizeChanged to 0.
+
+2010-08-16 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r65419.
+ http://trac.webkit.org/changeset/65419
+ https://bugs.webkit.org/show_bug.cgi?id=44053
+
+ Broke the Windows build (Requested by bbandix on #webkit).
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]):
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::create):
+
+2010-08-16 Balazs Kelemen <kb@inf.u-szeged.hu>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Handle content size change in WebKit2
+
+ https://bugs.webkit.org/show_bug.cgi?id=43198
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]): Initialize WKPageUICallback::contetsSizeChanged to 0.
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::create): Initialize WKPageUICallback::contetsSizeChanged to 0.
+
+2010-08-16 Ariya Hidayat <ariya@sencha.com>
+
+ Add my new email address to committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-08-16 Zoltan Horvath <zoltan@webkit.org>
+
+ Add my old e-mail addresses to committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-08-15 Jon Honeycutt <jhoneycutt@apple.com>
+
+ WebEditorClient::didBeginEditing is never called in WebKit2
+ https://bugs.webkit.org/show_bug.cgi?id=42939
+
+ Reviewed by Sam Weinig.
+
+ * WebKitTestRunner/PlatformWebView.h:
+ Declare focus().
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::resetStateToConsistentValues):
+ Focus the PlatformWebView.
+
+ * WebKitTestRunner/mac/PlatformWebViewMac.mm:
+ (WTR::PlatformWebView::focus):
+ Stubbed.
+
+ * WebKitTestRunner/win/PlatformWebViewWin.cpp:
+ (WTR::PlatformWebView::focus):
+ Focus the view.
+
+2010-08-15 Jon Honeycutt <jhoneycutt@apple.com>
+
+ run-webkit-tests should not strip editing callbacks when using
+ WebKitTestRunner on Windows
+ https://bugs.webkit.org/show_bug.cgi?id=44000
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/old-run-webkit-tests:
+ Leave $stripEditingCallbacks undefined until we look for command-line
+ arguments. If using WebKit2, set it to 0 if not explicity set on the
+ command line. Later, set it to isCygwin() to match old behavior if it is
+ not yet defined.
+
+2010-08-15 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix, remove define always set to the correct value by wtf/Platform.h.
+
+ * wx/build/settings.py:
+
+2010-08-14 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [GTK] autogen.sh not executed if build-webkit options change
+ https://bugs.webkit.org/show_bug.cgi?id=42266
+
+ Rerun autogen.sh in situations where the arguments to build-webkit have
+ changed since the previous build. This will fix some issues on the bots
+ where the build does not notice changes to default build-webkit arguments.
+
+ * Scripts/webkitdirs.pm: Add special logic for detecting changes to build-webkit arguments.
+
+2010-08-14 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Another fix to support python 2.3.
+
+ Add support for MathML entities
+ https://bugs.webkit.org/show_bug.cgi?id=43949
+
+ * Scripts/webkitpy/thirdparty/simplejson/decoder.py:
+ - It looks like our simplejson is version 1.7.3 which
+ should be python 2.3 compatible. But someone modified
+ our copy slightly from the original source.
+ I've removed the relative import in hopes this fixes
+ the problem.
+
+2010-08-13 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Build fix only.
+
+ Add support for MathML entities
+ https://bugs.webkit.org/show_bug.cgi?id=43949
+
+ * Scripts/create-html-entity-table:
+ - Hack sys.path to avoid executing 2.5 dependent python
+ on systems (like chromium-win and Tiger) which do not have 2.5 python.
+
+2010-08-13 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Rename some concepts in HTML entity search to be more self-documenting
+ https://bugs.webkit.org/show_bug.cgi?id=44004
+
+ Reflect name change in generator script.
+
+ * Scripts/create-html-entity-table:
+
+2010-08-12 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add support for MathML entities
+ https://bugs.webkit.org/show_bug.cgi?id=43949
+
+ A script for generating the C++ state data structure describing all the
+ entities from a JSON description.
+
+ * Scripts/create-html-entity-table: Added.
+
+2010-08-13 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Rewrite new-run-webkit-test's wait_for_threads_to_finish loop to
+ check for exceptions on all threads, not just the first thread.
+
+ This change also changes the logging behavior for wedged threads
+ to only dump the stacks of threads that are actually wedged.
+
+ Refactor the thread classes in the dump_render_tree_thread module
+ to make the contract between TestRunner and TestShellThread clearer.
+
+ Added a bunch of unit tests.
+ https://bugs.webkit.org/show_bug.cgi?id=38561
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-08-13 Kenichi Ishibashi <bashi@google.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Add test_expectations.txt syntax checker to check-webkit-style.
+ https://bugs.webkit.org/show_bug.cgi?id=43899
+
+ Just utilizing layout_tests/layout_package/test_expectations.py for checking
+ the syntax of test_expectations.txt.
+ This change also moves tab checking class from style/checkers/text.py to
+ style/checkers/common.py for sharing code.
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/style/checker.py:
+ * Scripts/webkitpy/style/checkers/common.py:
+ * Scripts/webkitpy/style/checkers/common_unittest.py:
+ * Scripts/webkitpy/style/checkers/test_expectations.py: Added.
+ * Scripts/webkitpy/style/checkers/test_expectations_unittest.py: Added.
+ * Scripts/webkitpy/style/checkers/text.py:
+ * Scripts/webkitpy/style_references.py:
+
+2010-08-12 Jon Honeycutt <jhoneycutt@apple.com>
+
+ WebKitTestRunner does not correctly resize WebView for W3C SVG tests
+ https://bugs.webkit.org/show_bug.cgi?id=43945
+
+ Reviewed by Sam Weinig.
+
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::sizeWebViewForCurrentTest):
+ Allow for a Windows-style path.
+
+ * WebKitTestRunner/win/PlatformWebViewWin.cpp:
+ (WTR::PlatformWebView::resizeTo):
+ Call SetWindowPos to resize the view window.
+
+2010-08-12 David Levin <levin@chromium.org>
+
+ Build break fix.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::resetStateToConsistentValues): Removed usage
+ of a variable that doesn't exist in the class.
+
+2010-08-12 Jon Honeycutt <jhoneycutt@apple.com>
+
+ WebKitTestRunner needs to run tests without using native controls
+ https://bugs.webkit.org/show_bug.cgi?id=43772
+
+ Reviewed by Sam Weinig.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize):
+ Call platformInitializeContext().
+
+ * WebKitTestRunner/TestController.h:
+ Declare platformInitializeContext().
+
+ * WebKitTestRunner/mac/TestControllerMac.mm:
+ (WTR::TestController::platformInitializeContext):
+ Stubbed.
+
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::platformInitializeContext):
+ Call WKContextSetShouldPaintNativeControls() to disable native control
+ drawing.
+
+2010-08-12 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ WebKitTestRunner should be more aggressive about ensuring consistent state between tests
+ https://bugs.webkit.org/show_bug.cgi?id=43653
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::InjectedBundle):
+ (WTR::InjectedBundle::didReceiveMessage):
+ (WTR::InjectedBundle::beginTesting):
+ (WTR::InjectedBundle::done):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h:
+ (WTR::InjectedBundle::isTestRunning):
+ (WTR::InjectedBundle::):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::stopLoading):
+ (WTR::InjectedBundlePage::didStartProvisionalLoadForFrame):
+ (WTR::InjectedBundlePage::dump):
+ (WTR::InjectedBundlePage::didFinishLoadForFrame):
+ (WTR::InjectedBundlePage::didFailLoadWithErrorForFrame):
+ (WTR::InjectedBundlePage::didReceiveTitleForFrame):
+ (WTR::InjectedBundlePage::didClearWindowForFrame):
+ (WTR::InjectedBundlePage::didFinishDocumentLoadForFrame):
+ (WTR::InjectedBundlePage::willAddMessageToConsole):
+ (WTR::InjectedBundlePage::willSetStatusbarText):
+ (WTR::InjectedBundlePage::willRunJavaScriptAlert):
+ (WTR::InjectedBundlePage::willRunJavaScriptConfirm):
+ (WTR::InjectedBundlePage::shouldBeginEditing):
+ (WTR::InjectedBundlePage::shouldEndEditing):
+ (WTR::InjectedBundlePage::shouldInsertNode):
+ (WTR::InjectedBundlePage::shouldInsertText):
+ (WTR::InjectedBundlePage::shouldDeleteRange):
+ (WTR::InjectedBundlePage::shouldChangeSelectedRange):
+ (WTR::InjectedBundlePage::shouldApplyStyle):
+ (WTR::InjectedBundlePage::didBeginEditing):
+ (WTR::InjectedBundlePage::didEndEditing):
+ (WTR::InjectedBundlePage::didChange):
+ (WTR::InjectedBundlePage::didChangeSelection):
+ Don't do any work if we are not currently running a test.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+ * WebKitTestRunner/StringFunctions.h:
+ (WTR::toCF):
+ Add conversion function for WKURLRef -> CFURLRef
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::TestController):
+ (WTR::TestController::initialize):
+ (WTR::TestController::resetStateToConsistentValues):
+ (WTR::TestController::runTest):
+ (WTR::TestController::didFinishLoadForFrame):
+ * WebKitTestRunner/TestController.h:
+ (WTR::TestController::):
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::invoke):
+ * WebKitTestRunner/TestInvocation.h:
+ Move resetting code to TestController.
+
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+ * WebKitTestRunner/mac/TestControllerMac.mm:
+ (WTR::TestController::runUntil):
+ * WebKitTestRunner/mac/TestInvocationMac.mm: Removed.
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::runUntil):
+ * WebKitTestRunner/win/TestInvocationWin.cpp: Removed.
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj:
+ Move runUntil to TestController.
+
+2010-08-12 Lucas De Marchi <lucas.demarchi@profusion.mobi>
+
+ Unreviewed.
+
+ Adding myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-08-12 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Merge pretty printers for gdb.
+ https://bugs.webkit.org/show_bug.cgi?id=43850
+
+ We need to update webcore.py because basic string classes have moved to WTF from WebCore.
+ It is good timing to merge webcore.py and wtf.py and name it 'webkit.py'.
+ webcore.py is left for backward compatibility.
+
+ * gdb/webcore.py:
+ * gdb/webkit.py: Added.
+ * gdb/wtf.py: Removed.
+
+2010-08-11 Tony Chang <tony@chromium.org>
+
+ Reviewed by David Levin.
+
+ [chromium] add google-chrome layout test result directories
+ https://bugs.webkit.org/show_bug.cgi?id=43889
+
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/google_chrome.py: Added.
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+
+2010-08-11 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Disable accelerated compositing
+ https://bugs.webkit.org/show_bug.cgi?id=43894
+
+ Disable accelerated compositing because DRT is not ready for
+ it. This change fixes hundreds of test crashes on Windows and
+ Linux.
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::resetWebSettings):
+
+2010-08-11 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Unreviewed. Adding my Collabora personality to the list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-08-11 Martin Robinson <mrobinson@igalia.com>
+
+ Adding myself as a reviewer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-08-11 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Darin Adler.
+
+ Perl warnings when running commit-log-editor
+ https://bugs.webkit.org/show_bug.cgi?id=43856
+
+ Fixes Perl warnings introduced by the patch for Bug #40548.
+
+ Perl doesn't have symbolic names for True/False. Instead, we
+ should use boolean values. Moreover, the variable installedEditorApplication
+ is not be used and should be renamed builtEditorApplication so that it
+ uses the existing machinery to set the commit log editor application.
+
+ * Scripts/commit-log-editor:
+
+2010-08-11 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Trying waiting for httpd lock in the EWS
+ https://bugs.webkit.org/show_bug.cgi?id=43833
+
+ If this works, we can probably run the tests on the mac-ews, which
+ would be very exciting. :)
+
+ * Scripts/webkitpy/tool/steps/runtests.py:
+
+2010-08-11 Marcus Bulach <bulach@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Check in a script to list redundant test outputs.
+ https://bugs.webkit.org/show_bug.cgi?id=37630
+
+ If e.g. platform/mac-leopard is missing an expected test output, we
+ fall back on platform/mac. This means it's possible to grow redundant
+ test outputs, where we have the same expected data in both a platform
+ directory and another platform it falls back on.
+ (original patch by Evan Marting <evan@chromium.org> https://bugs.webkit.org/attachment.cgi?id=53398)
+
+ * Scripts/deduplicate-tests: Added.
+ * Scripts/webkitpy/layout_tests/deduplicate_tests.py: Added.
+ * Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py: Added.
+
+2010-08-11 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] QtTestBrowser: after switching between QWebView and QGraphicsWebView, rotation actions get broken
+ https://bugs.webkit.org/show_bug.cgi?id=43853
+
+ LauncherWindow::createChrome is connecting menu itens to WebViewGraphicsBased's slots directly.
+ It behaviors badly when user launches the QtTestBrowser in QWebView mode, since then switching to
+ QGraphicsWebView mode, createChrome is not called again, and menu items end up not getting connected
+ to slots at all.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::createChrome):
+ (LauncherWindow::animatedFlip):
+ (LauncherWindow::animatedYFlip):
+ * QtTestBrowser/launcherwindow.h:
+
+2010-08-11 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] QtTestBrowser: switching between QWebView and QGraphicsWebView modes is broken
+ https://bugs.webkit.org/show_bug.cgi?id=43851
+
+ All window options data (including the bool holding if the view is either QWebView or
+ QGraphicsWebView based) is stored in m_windowOptions, a class member of LauncherWindow.
+ When toggle the view from QWebView to QGraphicsWebView based (and vice-versa), we were
+ not updating LauncherWindow::WindowOptions::m_useGraphicsView bit, and then things were
+ getting broken.
+
+ Patch addresses this issue.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::createChrome):
+ (LauncherWindow::toggleWebView):
+ (LauncherWindow::toggleAcceleratedCompositing):
+
+2010-08-10 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] QtTestBrowser: lazy instantiate "YRotation" state machine and related objects
+ https://bugs.webkit.org/show_bug.cgi?id=43831
+
+ Only instantiate QStateMachine and friends associated to the YRotation action on demand.
+
+ * QtTestBrowser/webview.cpp:
+ (WebViewGraphicsBased::WebViewGraphicsBased):
+ (WebViewGraphicsBased::animatedYFlip):
+
+2010-08-11 Darin Adler <darin@apple.com>
+
+ Reviewed by John Sullivan.
+
+ Improved editor options for prepare-ChangeLog and commit-log-editor
+ https://bugs.webkit.org/show_bug.cgi?id=40548
+
+ * Scripts/commit-log-editor: Split editor strings on spaces so EDITOR
+ values like "xed --launch --wait" work properly.
+
+ * Scripts/prepare-ChangeLog: Added a new CHANGE_LOG_EDITOR so we can
+ use a command line tool with the $openChangeLogs feature.
+
+2010-08-11 Yury Semikhatsky <yurys@chromium.org>
+
+ Reviewed by Pavel Feldman.
+
+ Web Inspector: remove InjectDispatch.js
+ https://bugs.webkit.org/show_bug.cgi?id=43835
+
+ * DumpRenderTree/chromium/DRTDevToolsAgent.cpp:
+ * DumpRenderTree/chromium/DRTDevToolsAgent.h:
+
+2010-08-10 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch should refuse to run under Win32 Python
+ https://bugs.webkit.org/show_bug.cgi?id=40962
+
+ Given that there are lots of places in webkit-patch's code that
+ assume unix-style filenames (forward slashes), webkit-patch fails
+ with weird file-not-found errors when run under a native windows
+ Python. It would be nice if we just trapped this and errored out
+ at the beginning, rather than producing unpredictable errors.
+
+ * Scripts/webkit-patch:
+
+2010-08-10 Kent Tamura <tkent@chromium.org>
+
+ Unreviewed, build fix.
+
+ Chromium build fix for r65107.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::suspendAnimations):
+ (LayoutTestController::resumeAnimations):
+
+2010-08-10 Sergio Villar Senin <svillar@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] http/tests/media/video-cookie.html fails
+ https://bugs.webkit.org/show_bug.cgi?id=42240
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setAlwaysAcceptCookies): create the
+ SoupCookieJar if it does not exist. Otherwise the accept policy
+ won't be set.
+
+2010-08-10 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Add suspendAnimations/resumeAnimation API to DRT
+ https://bugs.webkit.org/show_bug.cgi?id=43733
+
+ Adds suspendAnimations() and resumeAnimations() to LayoutTestController.
+ Calls functions with the same names on AnimationController for the
+ mainFrame.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/LayoutTestController.cpp:
+ (suspendAnimationsCallback):
+ (resumeAnimationsCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::suspendAnimations):
+ (LayoutTestController::resumeAnimations):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::suspendAnimations):
+ (LayoutTestController::resumeAnimations):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::suspendAnimations):
+ (LayoutTestController::resumeAnimations):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::suspendAnimations):
+ (LayoutTestController::resumeAnimations):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::suspendAnimations):
+ (LayoutTestController::resumeAnimations):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::suspendAnimations):
+ (LayoutTestController::resumeAnimations):
+
+2010-08-10 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ [Chromium/DRT] Enable saving layout test results.
+ https://bugs.webkit.org/show_bug.cgi?id=43796
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: Added more
+ parameters to the new-run-webkit-tests, including the name
+ of the test results server.
+
+2010-08-10 Jian Li <jianli@chromium.org>
+
+ More chromium build fix.
+
+ * DumpRenderTree/chromium/MockSpellCheck.cpp:
+ (MockSpellCheck::spellCheckWord):
+ (MockSpellCheck::initializeIfNeeded):
+ * DumpRenderTree/chromium/NotificationPresenter.cpp:
+ (NotificationPresenter::grantPermission):
+ (NotificationPresenter::show):
+ (NotificationPresenter::checkPermission):
+
+2010-08-10 Jian Li <jianli@chromium.org>
+
+ Chromium build fix.
+
+ * DumpRenderTree/chromium/MockSpellCheck.cpp:
+ * DumpRenderTree/chromium/NotificationPresenter.cpp:
+
+2010-08-10 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Update test results server merge logic so the aggregated
+ results and times are updated for tests that are
+ in aggragated json but not in incremental json.
+
+ Also update unittest to test this case.
+
+ https://bugs.webkit.org/show_bug.cgi?id=43769
+
+ * TestResultServer/model/jsonresults.py:
+ * TestResultServer/model/jsonresults_unittest.py:
+
+2010-08-09 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] QtTestBrowser: proper set scene rect
+
+ When resizesToContents is ON scene's rect is set to the boundary of
+ the mainFrame. However, navigating to other web page should keep resizing
+ scene's rect according to the new document loaded. Patch addresses this issue.
+
+ Now resizesToContents and scrolling properly work on QtTestBrowser.
+
+ * QtTestBrowser/webview.cpp:
+ (WebViewGraphicsBased::setPage):
+ (WebViewGraphicsBased::contentsSizeChanged):
+ (WebViewGraphicsBased::setResizesToContents):
+ (WebViewGraphicsBased::resizeEvent):
+ * QtTestBrowser/webview.h:
+
+2010-08-09 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] QtTestBrowser: Clean up LauncherWindow code.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::LauncherWindow): Moves applyPrefs methods call from the constructor to init().
+ (LauncherWindow::init): Fixed comments.
+ (LauncherWindow::applyPrefs): Move the method around.
+ (LauncherWindow::createChrome): Move more code of this method around, for grouping, and fixing up comments.
+
+2010-08-09 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] QtTestBrowser: make reset-zooming to animate when tiled backing store is on.
+
+ It gets control+0 the same visual effect as control++ or control-.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::toggleZoomTextOnly):
+
+2010-08-09 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] QtTestBrowser:: make m_zoomLevels a static member.
+
+ Not all instances of LauncherWindow need its own m_zoomLevel.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ * QtTestBrowser/launcherwindow.h:
+
+2010-08-09 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Geoffrey Garen.
+
+ Add zoom support for injected bundle
+ https://bugs.webkit.org/show_bug.cgi?id=43759
+
+ Use zoom factor SPI to implement zoom related eventSender functions.
+
+ * WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl:
+ * WebKitTestRunner/InjectedBundle/EventSendingController.cpp:
+ (WTR::EventSendingController::textZoomIn):
+ (WTR::EventSendingController::textZoomOut):
+ (WTR::EventSendingController::zoomPageIn):
+ (WTR::EventSendingController::zoomPageOut):
+ * WebKitTestRunner/InjectedBundle/EventSendingController.h:
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::reset): Reset zoom mode and level for each test.
+
+2010-08-09 Gavin Barraclough <barraclough@apple.com>
+
+ Speculative chromium build fix III.
+
+ * DumpRenderTree/chromium/MockSpellCheck.h:
+ * DumpRenderTree/chromium/NotificationPresenter.h:
+ * DumpRenderTree/chromium/WebViewHost.h:
+ (WebViewHost::addClearHeader):
+ (WebViewHost::clearHeaders):
+
+2010-08-09 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ increase the number of test results that we save
+ https://bugs.webkit.org/show_bug.cgi?id=43763
+
+ Now that we do incremental uploads, we can increase the number of
+ results that we save for http://test-results.appspot.com/dashboards/flakiness_dashboard.html.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+
+2010-08-09 Evan Martin <evan@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ [chromium] DRT error print statement incorrectly tries to print a FILE*
+ https://bugs.webkit.org/show_bug.cgi?id=43747
+
+ * DumpRenderTree/chromium/ImageDiff.cpp:
+ (writeFile): pass the correct pointer.
+
+2010-08-09 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Upload incremental test results json to server by default.
+
+ https://bugs.webkit.org/show_bug.cgi?id=43743
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-08-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ EWS bots wait 2 minutes between patches
+ https://bugs.webkit.org/show_bug.cgi?id=43731
+
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ - Don't sleep after failures. This was a hold-over from
+ an earlier design.
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ - EWS bots were not properly reporting true/false from process_work_item.
+ They were always returning None, thus false, thus always logging
+ as a failure and sleeping 2 minutes after each patch.
+
+2010-08-09 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Stub out EventSender for WebKitTestRunner
+ https://bugs.webkit.org/show_bug.cgi?id=43703
+
+ * WebKitTestRunner/DerivedSources.make:
+ * WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm:
+ Add ability to pass javascript arguments to the wrapped object.
+
+ * WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl: Added.
+ * WebKitTestRunner/InjectedBundle/EventSendingController.cpp: Added.
+ (WTR::EventSendingController::create):
+ (WTR::EventSendingController::EventSendingController):
+ (WTR::EventSendingController::~EventSendingController):
+ (WTR::EventSendingController::wrapperClass):
+ (WTR::setExceptionForString):
+ (WTR::EventSendingController::mouseDown):
+ (WTR::EventSendingController::mouseUp):
+ (WTR::EventSendingController::mouseMoveTo):
+ (WTR::EventSendingController::keyDown):
+ (WTR::EventSendingController::contextClick):
+ (WTR::EventSendingController::leapForward):
+ (WTR::EventSendingController::textZoomIn):
+ (WTR::EventSendingController::textZoomOut):
+ (WTR::EventSendingController::zoomPageIn):
+ (WTR::EventSendingController::zoomPageOut):
+ (WTR::EventSendingController::makeWindowObject):
+ * WebKitTestRunner/InjectedBundle/EventSendingController.h: Added.
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::reset):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h:
+ (WTR::InjectedBundle::eventSendingController):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::didClearWindowForFrame):
+ Add stubbed out EventSenderController.
+
+ * WebKitTestRunner/InjectedBundle/GCController.h:
+ Remove incorrect comment.
+
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+ * WebKitTestRunner/win/InjectedBundle.vcproj:
+ Add new files.
+
+2010-08-08 Kent Tamura <tkent@chromium.org>
+
+ Unreviewed, trivial fix.
+
+ Fix "WindowsError: [Error 32] The process cannot access the file
+ because it is being used by another process" introduced by r64959.
+
+ * BuildSlaveSupport/test-result-archive:
+
+2010-08-08 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Tony Chang.
+
+ Chromium buildbot: Avoid "zip" command dependency
+ https://bugs.webkit.org/show_bug.cgi?id=43470
+
+ * BuildSlaveSupport/test-result-archive:
+ For Chromium port, creates a zip archive with zipfile package of Python
+ instead of external "zip" command. We'd like to avoid additional
+ command installation.
+
+2010-08-08 Jon Honeycutt <jhoneycutt@apple.com>
+
+ WebKitTestRunner should add the QuickTime dir to the PATH environment
+ variable
+ https://bugs.webkit.org/show_bug.cgi?id=43686
+
+ Reviewed by Dan Bernstein.
+
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::addQTDirToPATH):
+ Copied from DRT.
+ (WTR::TestController::platformInitialize):
+ Call addQTDirToPath().
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj:
+ Link to shlwapi.lib for SHGetValue.
+
+2010-08-07 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ WebKitTestRunner needs layoutTestController.dumpTitleChanges
+ <rdar://problem/8213861>
+ https://bugs.webkit.org/show_bug.cgi?id=42683
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::didReceiveTitleForFrame):
+ (WTR::InjectedBundlePage::didFinishDocumentLoadForFrame):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::LayoutTestController):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ (WTR::LayoutTestController::dumpTitleChanges):
+ (WTR::LayoutTestController::shouldDumpTitleChanges):
+
+2010-08-07 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ WebKitTestRunner needs to print onunload handler information
+ <rdar://problem/8213831>
+ https://bugs.webkit.org/show_bug.cgi?id=42703
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::operator<<):
+ (WTR::InjectedBundlePage::didFinishDocumentLoadForFrame):
+
+2010-08-07 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add additional loader client functions need to complete WebKitTestRunner
+ https://bugs.webkit.org/show_bug.cgi?id=43684
+
+ Remove unnecessary and jarring underscores as well.
+
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (didClearWindowObjectForFrame):
+ (didCreatePage):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::didStartProvisionalLoadForFrame):
+ (WTR::InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame):
+ (WTR::InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame):
+ (WTR::InjectedBundlePage::didCommitLoadForFrame):
+ (WTR::InjectedBundlePage::didFinishLoadForFrame):
+ (WTR::InjectedBundlePage::didFailLoadWithErrorForFrame):
+ (WTR::InjectedBundlePage::didReceiveTitleForFrame):
+ (WTR::InjectedBundlePage::didClearWindowForFrame):
+ (WTR::InjectedBundlePage::didCancelClientRedirectForFrame):
+ (WTR::InjectedBundlePage::willPerformClientRedirectForFrame):
+ (WTR::InjectedBundlePage::didChangeLocationWithinPageForFrame):
+ (WTR::InjectedBundlePage::didFinishDocumentLoadForFrame):
+ (WTR::InjectedBundlePage::didHandleOnloadEventsForFrame):
+ (WTR::InjectedBundlePage::didDisplayInsecureContentForFrame):
+ (WTR::InjectedBundlePage::didRunInsecureContentForFrame):
+ (WTR::InjectedBundlePage::willAddMessageToConsole):
+ (WTR::InjectedBundlePage::willSetStatusbarText):
+ (WTR::InjectedBundlePage::willRunJavaScriptAlert):
+ (WTR::InjectedBundlePage::willRunJavaScriptConfirm):
+ (WTR::InjectedBundlePage::willRunJavaScriptPrompt):
+ (WTR::InjectedBundlePage::shouldBeginEditing):
+ (WTR::InjectedBundlePage::shouldEndEditing):
+ (WTR::InjectedBundlePage::shouldInsertNode):
+ (WTR::InjectedBundlePage::shouldInsertText):
+ (WTR::InjectedBundlePage::shouldDeleteRange):
+ (WTR::InjectedBundlePage::shouldChangeSelectedRange):
+ (WTR::InjectedBundlePage::shouldApplyStyle):
+ (WTR::InjectedBundlePage::didBeginEditing):
+ (WTR::InjectedBundlePage::didEndEditing):
+ (WTR::InjectedBundlePage::didChange):
+ (WTR::InjectedBundlePage::didChangeSelection):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+
+2010-08-07 Dan Bernstein <mitz@apple.com>
+
+ Build fix.
+
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj: Made the references
+ to JSGCController.{cpp,h} relative to the build root.
+
+2010-08-07 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ WebKitTestRunner needs GCController
+ <rdar://problem/8213834>
+ https://bugs.webkit.org/show_bug.cgi?id=42701
+
+ * WebKitTestRunner/DerivedSources.make:
+ * WebKitTestRunner/InjectedBundle/Bindings/GCController.idl: Added.
+ * WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h:
+ (WTR::setProperty):
+ * WebKitTestRunner/InjectedBundle/GCController.cpp: Added.
+ (WTR::GCController::create):
+ (WTR::GCController::GCController):
+ (WTR::GCController::~GCController):
+ (WTR::GCController::wrapperClass):
+ (WTR::GCController::collect):
+ (WTR::GCController::collectOnAlternateThread):
+ (WTR::GCController::getJSObjectCount):
+ (WTR::GCController::makeWindowObject):
+ * WebKitTestRunner/InjectedBundle/GCController.h: Added.
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::reset):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h:
+ (WTR::InjectedBundle::bundle):
+ (WTR::InjectedBundle::gcController):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::didClearWindowForFrame):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::keepWebHistory):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+ * WebKitTestRunner/win/InjectedBundle.vcproj:
+
+2010-08-05 Jon Honeycutt <jhoneycutt@apple.com>
+
+ WebKitTestRunner needs to be able to set the font smoothing type
+ https://bugs.webkit.org/show_bug.cgi?id=43406
+
+ Reviewed by Adam Roben.
+
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::resetPreferencesToConsistentValues):
+ Set the font smoothing level to
+ kWKFontSmoothingLevelNoSubpixelAntiAliasing to match DRT.
+
+2010-08-06 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Fix a missed variable rename.
+
+ Unreviewed.
+
+ * Scripts/old-run-webkit-tests:
+
+2010-08-06 Jon Honeycutt <jhoneycutt@apple.com>
+
+ mac-wk2/Skipped should be used on Windows when running regression tests
+ https://bugs.webkit.org/show_bug.cgi?id=43494
+
+ Reviewed by Adam Roben.
+
+ * Scripts/old-run-webkit-tests:
+ If the platform is win-wk2, also read the mac-wk2 skipped list.
+
+2010-08-06 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Should revoke scheduled tasks
+ https://bugs.webkit.org/show_bug.cgi?id=43560
+
+ * DumpRenderTree/chromium/DRTDevToolsAgent.cpp:
+ (DRTDevToolsAgent::reset): Calls RevokeAll().
+ * DumpRenderTree/chromium/DRTDevToolsAgent.h:
+ * DumpRenderTree/chromium/DRTDevToolsClient.cpp:
+ (DRTDevToolsClient::reset): Calls RevokeAll().
+ * DumpRenderTree/chromium/DRTDevToolsClient.h:
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::reset): Calls RevokeAll().
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::reset): Calls RevokeAll().
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::resetTestController): Calls DRTDevToolsAgent::reset() and DRTDevToolsClient::reset().
+
+2010-08-06 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] Fix the DRT build on Mac OS X
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+
+2010-08-06 Jochen Eisinger <jochen@chromium.org>
+
+ Reviewed by Pavel Feldman.
+
+ Rietvield's upload.py moved to a different location.
+ https://bugs.webkit.org/show_bug.cgi?id=43613
+
+ * Scripts/webkitpy/thirdparty/__init__.py:
+
+2010-05-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ QueueStatusServer needs better queue-status pages
+ https://bugs.webkit.org/show_bug.cgi?id=39562
+
+ The primary goal of this patch is to display queue
+ positions somewhere on the site so that it's easier
+ for commit-queue users to know when their pach will
+ be landed. I also tried to improve the root page
+ to be more useful than the previous wall of status text.
+
+ * QueueStatusServer/handlers/recentstatus.py:
+ * QueueStatusServer/main.py:
+ * QueueStatusServer/model/queues.py:
+ * QueueStatusServer/templates/recentstatus.html:
+
+2010-08-05 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Add option to generate/upload incremental json results to test result server.
+ Also refactor the json results generator unittest code to test
+ incremental and aggregated json results.
+
+ https://bugs.webkit.org/show_bug.cgi?id=43519
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-08-05 Jian Li <jianli@chromium.org>
+
+ Reviewed by David Levin.
+
+ Unify blob related feature defines to ENABLE(BLOB).
+ https://bugs.webkit.org/show_bug.cgi?id=43081
+
+ * Scripts/build-webkit:
+
+2010-08-05 Satish Sampath <satish@chromium.org>
+
+ Reviewed by Jeremy Orlow.
+
+ Add speech input controller mock in WebKit and a layout test.
+ https://bugs.webkit.org/show_bug.cgi?id=43477
+
+ Added LayoutTestController::setMockSpeechInputResultCallback method.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setMockSpeechInputResultCallback): Wrapper invoking the member function.
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::setMockSpeechInputResult): Sets the mock result.
+ (LayoutTestController::speechInputController): Creates the mock controller.
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::speechInputController): Creates the mock controller.
+ * DumpRenderTree/chromium/WebViewHost.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setMockSpeechInputResult): dummy method.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMockSpeechInputResult): dummy method.
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setMockSpeechInputResult): dummy method.
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp: dummy method.
+ (LayoutTestController::setMockSpeechInputResult):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp: dummy method.
+ (LayoutTestController::setMockSpeechInputResult):
+
+2010-08-04 Adam Roben <aroben@apple.com>
+
+ Fix the path to TestNetscapePlugin's directory on Windows
+
+ Fixes <http://webkit.org/b/43513> WebKitTestRunner on Windows fails to
+ load TestNetscapePlugin
+
+ Reviewed by Jon Honeycutt.
+
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::initializeTestPluginDirectory):
+ TestNetscapePlugin is in a TestNetscapePlugin[_Debug] directory that's
+ next to WebKitTestRunner.exe. Previously we were passing the directory
+ that contains WebKitTestRunner.exe. Also fixed some leaks.
+
+2010-08-05 Kenichi Ishibashi <bashi@google.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ check-webkit-style returns non-zero when patch is entirely minus lines.
+ https://bugs.webkit.org/show_bug.cgi?id=38169
+
+ * Scripts/check-webkit-style:
+ Check whether a patch contains modified files that are entirely minus lines.
+ * Scripts/webkitpy/style/filereader.py:
+ Add a variable that holds number of files that contain only deleted lines.
+ * Scripts/webkitpy/style/patchreader.py:
+ Count up modified files that contain only deleted lines.
+
+2010-08-05 Pavel Feldman <pfeldman@chromium.org>
+
+ Reviewed by Yury Semikhatsky.
+
+ DevTools: get rid of delayed command dispatching on front-end side.
+
+ https://bugs.webkit.org/show_bug.cgi?id=43479
+
+ * DumpRenderTree/chromium/DRTDevToolsAgent.cpp:
+ (DRTDevToolsAgent::detach):
+ (DRTDevToolsAgent::frontendLoaded):
+ * DumpRenderTree/chromium/DRTDevToolsAgent.h:
+ * DumpRenderTree/chromium/DRTDevToolsClient.cpp:
+ (DRTDevToolsClient::~DRTDevToolsClient):
+ (DRTDevToolsClient::sendFrontendLoaded):
+ * DumpRenderTree/chromium/DRTDevToolsClient.h:
+
+2010-08-04 Kenichi Ishibashi <bashi@google.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Fixes check-webkit-style false positive on "new uint32_t."
+ https://bugs.webkit.org/show_bug.cgi?id=43077
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+
+2010-08-04 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Remove base/linked_ptr.h dependency
+ https://bugs.webkit.org/show_bug.cgi?id=43472
+
+ Replace linked_ptr<TestNavigationEntry> with RefPtr<TestNavigationEntry>.
+ We need to use RefPtr<> because m_pendingEntry points an object in
+ m_entries or not in m_entries.
+
+ * DumpRenderTree/chromium/TestNavigationController.cpp:
+ (TestNavigationEntry::create): Added.
+ (TestNavigationController::activeEntry):
+ (TestNavigationController::didNavigateToEntry):
+ (TestNavigationController::discardPendingEntry):
+ (TestNavigationController::insertEntry):
+ (TestNavigationController::navigateToPendingEntry):
+ * DumpRenderTree/chromium/TestNavigationController.h:
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::loadURLForFrame):
+ Use TestNavigationEntry::create().
+ (WebViewHost::updateURL):
+ Use RefPtr<>.
+ (WebViewHost::updateSessionHistory):
+ Remove unnecessary static_cast<>.
+
+2010-08-04 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Fix a problem that "archived test results" step doesn't work on Chromium buildbots
+ https://bugs.webkit.org/show_bug.cgi?id=43333
+
+ * BuildSlaveSupport/test-result-archive:
+ - Make layoutTestResultsDir local and pass it to archiveTestResults()
+ - Adjust layoutTestResultsDir for Chromium
+
+2010-08-04 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ NRWT: websocket_server startup detection failure
+ https://bugs.webkit.org/show_bug.cgi?id=43466
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ Increase timeout value: 5 second -> 10 second
+
+2010-08-04 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ -. Add result.json incremental merging functionality to test results app engine.
+ -. blobstore is not suitable for AE data merging and there is no API to
+ programatically edit existing blob or write a new one yet, so replace blobstore
+ with datastore. If file is oversize (>1000*1000 bytes), store file data in
+ multiple datastore entries.
+ -. Fix styles.
+
+ Test: jsonresults_unittest to test merging logics.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38599
+
+ * TestResultServer/handlers/dashboardhandler.py:
+ * TestResultServer/handlers/menu.py:
+ * TestResultServer/handlers/testfilehandler.py:
+ * TestResultServer/main.py:
+ * TestResultServer/model/dashboardfile.py:
+ * TestResultServer/model/datastorefile.py: Added.
+ * TestResultServer/model/jsonresults.py: Added.
+ * TestResultServer/model/jsonresults_unittest.py: Added.
+ * TestResultServer/model/testfile.py:
+ * TestResultServer/templates/uploadform.html:
+
+2010-08-04 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ [Qt] [QtTestBrowser] Remove unneeded QAction class members
+ https://bugs.webkit.org/show_bug.cgi?id=43518
+
+ LauncherWindow class has two totally unneeded class members: m_flopAnimated and
+ m_flipYAnimated. Also, in initializeView method there are some dead code block
+ trying to connect them at the wrong time, when they have not been instanciated.
+
+ This patch:
+
+ - removes the two cited class members in favor of local variables in createChrome method;
+ - removes the dead code block.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::LauncherWindow):
+ (LauncherWindow::initializeView):
+ (LauncherWindow::createChrome):
+ * QtTestBrowser/launcherwindow.h:
+
+2010-08-04 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Simon Hausmann and Kenneth Christiansen.
+
+ [Qt] [QtTestBrowser] Clean up static and global menu state controls
+ https://bugs.webkit.org/show_bug.cgi?id=43448
+
+ After LauncherWindow class was refactored out of from main.cpp, all global variables that
+ were hanging in main.cpp became temporarily public static class members of newly added
+ LauncherWindow class. This design was not properly handling the initial purpose of the
+ global variables: newly created launcher windows should inherit the settings of the originating
+ one.
+
+ In order to properly fix the problem, this patch introduces a WindowOptions class, as a POD. It
+ comprises all data needed to handling the goal described above.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::LauncherWindow): The class now receives an optional WindowOptions pointer object
+ holding all user settings configured in the menus and command line.
+ It also receices an optional QGraphicsScene points in case we are doing
+ a "Clone Window".
+ (LauncherWindow::init): Removed the usesGraphics parameter because the class member m_userData holds its
+ value.
+ (LauncherWindow::initializeView): Ditto.
+ (LauncherWindow::createChrome): Changed all references to gXXX to m_userData.XXX
+ (LauncherWindow::applyPrefs): Removed the "LauncherWindow* source" parameter. All data needed to properly
+ apply the preferences is provided by m_userData.
+ (LauncherWindow::toggleAcceleratedCompositing): Change gXXX by m_userData.XXX
+ (LauncherWindow::toggleResizesToContents): Ditto.
+ (LauncherWindow::toggleWebGL): Ditto.
+ (LauncherWindow::toggleFrameFlattening): Ditto.
+ (LauncherWindow::toggleQGLWidgetViewport): Ditto.
+ (LauncherWindow::changeViewportUpdateMode): Ditto.
+ (LauncherWindow::showFPS): Ditto.
+ (LauncherWindow::newWindow): Changed to pass the userData.
+ (LauncherWindow::cloneWindow): Ditto.
+ * QtTestBrowser/launcherwindow.h:
+ (WindowOptions::WindowOptions):
+ * QtTestBrowser/main.cpp:
+ (requiresGraphicsView):
+ (LauncherApplication::handleUserOptions):
+ (main):
+
+2010-08-04 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix for gcc not importing all symbols from convenience libraries.
+ Works on 10.6 only for Mac until the build system is reworked.
+
+ * wx/build/settings.py:
+
+2010-08-04 Markus Goetz <Markus.Goetz@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Change wording in QtTestBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=43241
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::createChrome):
+
+2010-08-04 Aaron Boodman <aa@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ prepare-ChangeLog fails mysteriously if curl doesn't support ssl
+ https://bugs.webkit.org/show_bug.cgi?id=43460
+
+ * Scripts/prepare-ChangeLog:
+
+2010-08-03 MORITA Hajime <morrita@google.com>
+
+ Reviewed by Tony Chang.
+
+ [DRT] Assertion failed when drag and move a draggable element.
+ https://bugs.webkit.org/show_bug.cgi?id=41695
+
+ mouseMoveToX() did call [WebHTMLView mouseDragged] even if dragging started.
+ But Cocoa doesn't call mouseDragged() until dragging is done.
+ Other part of DumpRenderTree also assumes Cocoa behavior and an assertion
+ on UIDelegate failed when mouseDragged() is called during dragging.
+ This change eliminated the mouseDragged() call when dragging begins,
+ which is implicated by draggingInfo instance.
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController mouseMoveToX:Y:]):
+
+ Test: fast/events/dragging-mouse-moves.html
+
+2010-08-02 Steve Block <steveblock@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Adds Geolocation LayoutTests for the case where permission is not granted or denied immediately
+ https://bugs.webkit.org/show_bug.cgi?id=40002
+
+ The code in LayoutTestController::setGeolocationPermission() was moved to
+ setGeolocationPermissionCommon() to allow each port to provide its own
+ implementation of setGeolocationPermission().
+
+ For the Mac port, setGeolocationPermission() notifies the UIDelegate of the
+ new permission, so it can call back to WebCore if permission requests are in
+ progress and are waiting for a response. A minor fix to the Mac
+ MockGeolocationProvider was also required to make sure that the mock provider
+ calls back to WebCore when it is first started.
+
+ For other ports, LayoutTestController::setGeolocationPermission() is not
+ implemented.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::setGeolocationPermissionCommon):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setGeolocationPermission):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setGeolocationPermission):
+ * DumpRenderTree/mac/MockGeolocationProvider.mm:
+ (-[MockGeolocationProvider registerWebView:]):
+ * DumpRenderTree/mac/UIDelegate.h:
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:decidePolicyForGeolocationRequestFromOrigin:frame:listener:]):
+ (-[UIDelegate setGeolocationPermission:]):
+ (-[UIDelegate dealloc]):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setGeolocationPermission):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setGeolocationPermission):
+
+2010-08-03 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Implement --testshell-startup-dialog
+ https://bugs.webkit.org/show_bug.cgi?id=40616
+
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (main): Check --testshell-startup-dialog, and call openStartUpDialog()
+ if it is specfied.
+ * DumpRenderTree/chromium/TestShell.h:
+ Declare openStartUpDialog().
+ * DumpRenderTree/chromium/TestShellGtk.cpp:
+ (openStartupDialog):
+ * DumpRenderTree/chromium/TestShellMac.mm:
+ (openStartupDialog):
+ * DumpRenderTree/chromium/TestShellWin.cpp:
+ (openStartupDialog):
+
+2010-08-03 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Remove dependency of base/md5.h
+ https://bugs.webkit.org/show_bug.cgi?id=43403
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::dumpImage): Use wtf/MD5.h
+
+2010-08-03 Joseph Pecoraro <joepeck@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ Limit ApplicationCache Total and Per-Origin Storage Capacity (Quotas)
+ https://bugs.webkit.org/show_bug.cgi?id=40627
+
+ Part 6 - LayoutTest and Cleanup
+
+ Allow tests to delete application caches and set application cache
+ origin quotas, so they can be tested.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (dumpApplicationCacheDelegateCallbacksCallback): JavaScript callback, delegates to the controller.
+ (clearAllApplicationCachesCallback): should delete all application caches.
+ (setApplicationCacheOriginQuotaCallback): should set the origin quota for the localhost tests.
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::dumpApplicationCacheDelegateCallbacks): accessor to see if application cache callbacks should be output.
+ (LayoutTestController::setDumpApplicationCacheDelegateCallbacks): enable or disable debug output when the application cache quota is reached.
+
+ Mac implementation.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::clearAllApplicationCaches): delete application caches.
+ (LayoutTestController::setApplicationCacheOriginQuota): set the quota for localhost.
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:]): style fix.
+ (-[UIDelegate webView:exceededApplicationCacheOriginQuotaForSecurityOrigin:]): reset the quota.
+
+ Stub implementations for other platforms.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::clearAllApplicationCaches):
+ (LayoutTestController::setApplicationCacheOriginQuota):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::clearAllApplicationCaches):
+ (LayoutTestController::setApplicationCacheOriginQuota):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::clearAllApplicationCaches):
+ (LayoutTestController::setApplicationCacheOriginQuota):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::clearAllApplicationCaches):
+ (LayoutTestController::setApplicationCacheOriginQuota):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::clearAllApplicationCaches):
+ (LayoutTestController::setApplicationCacheOriginQuota):
+
+2010-08-03 Joseph Pecoraro <joepeck@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ Limit ApplicationCache Total and Per-Origin Storage Capacity (Quotas)
+ https://bugs.webkit.org/show_bug.cgi?id=40627
+
+ Part 5 - Refactor Quota Management in WebSecurityOrigin into Managers
+
+ Change old style calls to make use of the managers.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setDatabaseQuota):
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:]):
+
+2010-08-03 Mark Rowe <mrowe@apple.com>
+
+ Add a new Leopard build slave to run the release tests.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2010-08-03 Jon Honeycutt <jhoneycutt@apple.com>
+
+ WebKitTestRunner needs to activate the Mac font ascent hack
+ https://bugs.webkit.org/show_bug.cgi?id=43404
+
+ Reviewed by Darin Adler.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::initialize):
+ Call WKBundleActivateMacFontAscentHack().
+
+2010-08-03 Alex Milowski <alex@milowski.com>
+
+ Reviewed by Beth Dakin.
+
+ Changed the default for MathML support so that is is enabled by default.
+
+ * Scripts/build-webkit:
+
+2010-08-03 Sam Weinig <sam@webkit.org>
+
+ Roll r64566 back in this time with all the overloads in place..
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::shouldInsertNode):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ * WebKitTestRunner/StringFunctions.h:
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::resetPreferencesToConsistentValues):
+ (WTR::TestInvocation::didReceiveMessageFromInjectedBundle):
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+
+2010-08-03 Sam Weinig <sam@webkit.org>
+
+ Rollout r64566. It broke all the WebKit2 tests.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::operator<<):
+ (WTR::InjectedBundlePage::shouldInsertNode):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ * WebKitTestRunner/StringFunctions.h: Removed.
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::createWKURL):
+ (WTR::WKStringToUTF8):
+ (WTR::TestInvocation::resetPreferencesToConsistentValues):
+ (WTR::TestInvocation::didReceiveMessageFromInjectedBundle):
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+
+2010-08-03 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ WTR: Move all the utility functions for working with strings to a shared header.
+ https://bugs.webkit.org/show_bug.cgi?id=43386
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::shouldInsertNode):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ * WebKitTestRunner/StringFunctions.h: Added.
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::resetPreferencesToConsistentValues):
+ (WTR::TestInvocation::didReceiveMessageFromInjectedBundle):
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+
+2010-08-02 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ [Qt] QtTestBrowser not setting preferredContentsSize for resizesToContents
+ https://bugs.webkit.org/show_bug.cgi?id=43168
+
+ QGraphicsWebView resizesToContents property has to work together with QWebPage's
+ setPreferredContentsSize as stated by the docs. Patch addresses that for QtTestBrowser.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::applyPrefs):
+ * QtTestBrowser/webview.cpp:
+ (WebViewGraphicsBased::setResizesToContents): Properly handle scene, webview and viewport sizes
+ needed when toggle resizesToContents on/off.
+ (WebViewGraphicsBased::resizeEvent):
+ * QtTestBrowser/webview.h:
+ (WebViewGraphicsBased::setCustomLayoutSize): Setter helper.
+ (WebViewGraphicsBased::customLayoutSize): Getter helper.
+
+2010-08-03 Jochen Eisinger <jochen@chromium.org>
+
+ Unreviewed. Adding myself as committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-08-02 Pavel Feldman <pfeldman@chromium.org>
+
+ Reviewed by Yury Semikhatsky.
+
+ Chromium DevTools: Get rid of DevTools RPC.
+
+ https://bugs.webkit.org/show_bug.cgi?id=43335
+
+ * DumpRenderTree/chromium/DRTDevToolsAgent.cpp:
+ (DRTDevToolsAgent::sendMessageToInspectorFrontend):
+ (DRTDevToolsAgent::call):
+ * DumpRenderTree/chromium/DRTDevToolsAgent.h:
+ * DumpRenderTree/chromium/DRTDevToolsCallArgs.h:
+ (DRTDevToolsCallArgs::DRTDevToolsCallArgs):
+ * DumpRenderTree/chromium/DRTDevToolsClient.cpp:
+ (DRTDevToolsClient::sendMessageToBackend):
+ (DRTDevToolsClient::call):
+ * DumpRenderTree/chromium/DRTDevToolsClient.h:
+
+2010-08-02 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Remove dependencies to some Chromium headers
+ https://bugs.webkit.org/show_bug.cgi?id=43396
+
+ * DumpRenderTree/chromium/CppVariant.h:
+ Remove base/basictypes.h because webkit_support.h contains it.
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (getCurrentEventTimeSec): Use new wrapper function.
+ * DumpRenderTree/chromium/TestNavigationController.h:
+ Remove base/basictypes.h because webkit_support.h contains it.
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (dumpHistoryItem): Use new wrapper function.
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::cancelledError): Use new wrapper function.
+ (WebViewHost::didFailResourceLoad): Use new wrapper function.
+
+2010-08-02 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] DRT implement execCommand()
+ https://bugs.webkit.org/show_bug.cgi?id=35351
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::execCommand): Implement using webkit_web_view_execute_core_command_by_name.
+ (LayoutTestController::isCommandEnabled): Implement using webkit_web_view_is_command_enabled.
+ (LayoutTestController::setCacheModel): Move below LayoutTestController::isCommandEnabled.
+
+2010-08-02 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add alias for run-webkit-tests --webkit-test-runner (run-webkit-tests -2).
+
+ * Scripts/old-run-webkit-tests:
+
+2010-08-02 Jon Honeycutt <jhoneycutt@apple.com>
+
+ WebKitTestRunner needs to support loading custom fonts (via the
+ WEBKIT_TESTFONTS environment variable)
+ https://bugs.webkit.org/show_bug.cgi?id=42782
+
+ Reviewed by Adam Roben.
+
+ * WebKitTestRunner/InjectedBundle/win/ActivateFonts.cpp:
+ (WTR::fontsPath):
+ Copied from DRT code. Removed the fallback to DumpRenderTree.resources/,
+ as this directory doesn't appear to be created anymore.
+ (WTR::activateFonts):
+ Loop through the fonts, and call AddFontResourceExW() for each.
+
+2010-08-02 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Restore the WebKitTestRunner.sln that was removed, and remove the
+ correct one.
+
+ Rubber-stamped by Sam Weinig.
+
+ * WebKitTestRunner/WebKitTestRunner.sln: Added.
+ * WebKitTestRunner/win/WebKitTestRunner.sln: Removed.
+
+2010-08-02 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Move InjectedBundle.vcproj to where the other WebKitTestRunner vcprojs live.
+
+ Remove the unused WebKitTestRunner.sln.
+
+ Reviewed by Sam Weinig.
+
+ * WebKitTestRunner/Configurations/InjectedBundleCommon.vsprops:
+ * WebKitTestRunner/InjectedBundle/win/InjectedBundle.vcproj: Removed.
+ * WebKitTestRunner/WebKitTestRunner.sln: Removed.
+ * WebKitTestRunner/win/InjectedBundle.vcproj: Added.
+ * WebKitTestRunner/win/WebKitTestRunner.sln:
+
+2010-08-02 Sam Weinig <sam@webkit.org>
+
+ Fix the windows build.
+
+ * WebKitTestRunner/win/main.cpp:
+
+2010-07-29 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Add a Skipped list on Windows, and have run-webkit-tests respect it.
+
+ Part of <rdar://problem/8233237> Fill WebKit2 Windows skipped list so
+ there are zero tests failing
+ https://bugs.webkit.org/show_bug.cgi?id=43374
+
+ Reviewed by Adam Roben.
+
+ * Scripts/old-run-webkit-tests:
+ If using WebKitTestRunner and Apple Windows WebKit, set the platform to
+ win-wk2. When building the result hierarchy, if the platform is win-wk2,
+ add it first to the list of platforms.
+
+2010-08-02 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ WebKitTestRunner needs layoutTestController.setCanOpenWindows
+ https://bugs.webkit.org/show_bug.cgi?id=42321
+
+ WebKitTestRunner needs layoutTestController.setCloseRemainingWindowsWhenComplete
+ https://bugs.webkit.org/show_bug.cgi?id=42779
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: Added
+ setCanOpenWindows, setCloseRemainingWindowsWhenComplete, and windowCount
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::InjectedBundle): Initialize m_mainPage to 0 instead of
+ waiting for the first call to didCreatePage.
+ (WTR::InjectedBundle::didCreatePage): Set m_mainPage only when the first page
+ is created. Put other pages into a map.
+ (WTR::InjectedBundle::willDestroyPage): Added code to handle the destruction
+ of the main page.
+ (WTR::InjectedBundle::closeOtherPages): Added. Closes all the pages other than
+ the main page.
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h: Added pageCount and
+ closeOtherPages functions.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::didFinishLoadForFrame): Don't let pages other than
+ the main page affect dumping.
+ (WTR::InjectedBundlePage::didFailLoadWithErrorForFrame): Ditto.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::LayoutTestController): Initialize the new
+ m_shouldCloseExtraWindows member.
+ (WTR::LayoutTestController::setCanOpenWindows): Added. Empty for now.
+ (WTR::LayoutTestController::windowCount): Added.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ Added setCanOpenWindows, setCloseRemainingWindowsWhenComplete,
+ windowCount, shouldCloseExtraWindowsAfterRunningTest, and
+ m_shouldCloseExtraWindows.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::shared): Return a pointer to the shared copy, but
+ don't allocate and leak it. This seemed cleaner than adding an explicit
+ finalize call to go along with the explicit initialize call.
+ (WTR::TestController::TestController): Added calls to the initialize and
+ run function, which are now done automatically.
+ (WTR::TestController::~TestController): Added, since it's called now.
+ (WTR::closeOtherPage): Added. Used to close pages other than the main page.
+ (WTR::createOtherPage): Added. Used to create pages other than the main page.
+ (WTR::TestController::initialize): Added code to set up createOtherPage.
+ (WTR::TestController::run): Removed unused return value.
+ * WebKitTestRunner/TestController.h: Made constructor and destructor public,
+ and initialize and run private. Changed m_mainWebView to be an OwnPtr.
+
+ * WebKitTestRunner/mac/PlatformWebViewMac.mm:
+ (WTR::PlatformWebView::PlatformWebView): Added a call to setReleasedWhenClosed
+ to avoid releasing the window twice. Another way to handle it would be to
+ remove the release, but this approach is slightly more robust because it works
+ even if some other code calls the close method an extra time.
+
+ * WebKitTestRunner/mac/main.mm:
+ (main): Use a stack-allocated TestController object instead of calling
+ initalize and run on a globally allocated one.
+
+2010-08-02 Tony Chang <tony@chromium.org>
+
+ Reviewed by David Levin.
+
+ add myself to the reviewers list
+ https://bugs.webkit.org/show_bug.cgi?id=43366
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-08-02 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Cache JSNPObjects and fix bugs in the object map
+ https://bugs.webkit.org/show_bug.cgi?id=43368
+
+ Test that we correctly throw exceptions when trying to do things to a JSObject that used to
+ wrap an NPObject that came from a plug-in that is now destroyed.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.h:
+ (PluginTest::Object::getProperty):
+ (PluginTest::Object::NP_GetProperty):
+ (PluginTest::Object::npClass):
+ * DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp: Added.
+ (NPRuntimeObjectFromDestroyedPlugin::NPRuntimeObjectFromDestroyedPlugin):
+ (NPRuntimeObjectFromDestroyedPlugin::ScriptableObject::hasProperty):
+ (NPRuntimeObjectFromDestroyedPlugin::ScriptableObject::getProperty):
+ (NPRuntimeObjectFromDestroyedPlugin::NPP_GetValue):
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+ * GNUmakefile.am:
+
+2010-08-02 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [Gtk] DOM listeners get wrong keycodes for some keys
+ https://bugs.webkit.org/show_bug.cgi?id=35170
+
+ Add support to all event senders for simulating keypad insert
+ and print screen keys.
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::keyDown): Add support for generating keypad insert and print screen.
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (keyDownCallback): Ditto.
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController keyDown:withModifiers:withLocation:]): Ditto.
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::keyDown): Ditto.
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback): Ditto.
+
+2010-08-02 Martin Robinson <mrobinson@igalia.com>
+
+ Build fix for building against development versions of GTK+. GTK 2.22
+ has not yet been released, so these function definitions must be conditionalized
+ on the development version.
+
+ * DumpRenderTree/gtk/EventSender.cpp: Fix GTK+ 2.21 build.
+
+2010-08-02 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] use ChromiumDriver on Linux when running webkit tests
+ https://bugs.webkit.org/show_bug.cgi?id=43273
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-08-02 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Always initialize GTK
+ https://bugs.webkit.org/show_bug.cgi?id=43327
+
+ Call gtk_init() in order to fix plugin test crash.
+
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (main): Pass argc/argv to platformInit().
+ * DumpRenderTree/chromium/TestShell.h:
+ * DumpRenderTree/chromium/TestShellGtk.cpp:
+ (platformInit): Update parameters, call gtk_init().
+ * DumpRenderTree/chromium/TestShellMac.mm:
+ (platformInit): Update parameters.
+ * DumpRenderTree/chromium/TestShellWin.cpp:
+ (platformInit): Update parameters.
+
+2010-08-02 Balazs Kelemen <kb@inf.u-szeged.hu>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Generate forwarding headers for WebKit2
+
+ https://bugs.webkit.org/show_bug.cgi?id=43336
+
+ * Scripts/webkitdirs.pm: Call make on WebKit2/Makefile.DerivedSources.
+
+2010-08-02 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ WebSocket server should start with SO_REUSEADDR
+ https://bugs.webkit.org/show_bug.cgi?id=43329
+
+ Pulls in pywebsocket-0.5.2.
+ pywebsocket-0.5.2 includes a small fix to start server with SO_REUSE_ADDR.
+ http://code.google.com/p/pywebsocket/source/detail?r=273
+
+ * Scripts/webkitpy/thirdparty/__init__.py: Bump pywebsocket version
+
+2010-08-01 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Remove string_util.h dependency
+ https://bugs.webkit.org/show_bug.cgi?id=43312
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::pathToLocalResource):
+ Use string::find() instead of StartsWithASCII().
+ (LayoutTestController::cppVariantToInt32):
+ Use strtol() instead of StringToNumber().
+
+2010-08-01 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add ability to reset frame names for WebKitTestRunner
+ https://bugs.webkit.org/show_bug.cgi?id=43316
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::reset):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::reset):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+
+2010-08-01 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Implement NPN_RemoveProperty
+ https://bugs.webkit.org/show_bug.cgi?id=43315
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ Add NPRuntimeRemoveProperty.cpp
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp:
+ (PluginTest::NPN_GetStringIdentifier):
+ (PluginTest::NPN_GetIntIdentifier):
+ (PluginTest::NPN_RemoveProperty):
+ Add NPN_ helpers.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.h:
+ Support more NPClass functions.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp: Added.
+ (NPRuntimeRemoveProperty::NPRuntimeRemoveProperty):
+ Test for NPN_RemoveProperty.
+
+ (NPRuntimeRemoveProperty::TestObject::hasMethod):
+ (NPRuntimeRemoveProperty::TestObject::invoke):
+ Add a testRemoveProperty method.
+
+ (NPRuntimeRemoveProperty::NPP_GetValue):
+ Return the test object.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+ * GNUmakefile.am:
+ Add NPRuntimeRemoveProperty.cpp
+
+2010-07-30 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Add an NPObject class template helper to TestNetscapePlugin
+ https://bugs.webkit.org/show_bug.cgi?id=43288
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.h:
+ Add some template magic to be able to figure out if a class has a member function of a given type.
+
+ (PluginTest::Object::create):
+ Create an object.
+
+ (PluginTest::Object::invokeDefault):
+ Add dummy function, this should never be called.
+
+ (PluginTest::Object::Object):
+ Initialize m_pluginTest to 0.
+
+ (PluginTest::Object::~Object):
+ Add virtual destructor.
+
+ (PluginTest::Object::NP_Allocate):
+ Create a new object.
+
+ (PluginTest::Object::NP_Deallocate):
+ Delete the object.
+
+ (PluginTest::Object::NP_InvokeDefault):
+ Call invokeDefault.
+
+ (PluginTest::Object::npClass):
+ Initialize the NPClass struct.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp:
+ (DocumentOpenInDestroyStream::NPP_DestroyStream):
+ Move this inline.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp:
+ (PluginScriptableNPObjectInvokeDefault::NPObjectWithInvokeDefault::invokeDefault):
+ (PluginScriptableNPObjectInvokeDefault::NPP_GetValue):
+ Use the PluginTest::Object class template.
+
+2010-07-31 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=43305
+ Add back WKBundleFrameCopyInnerText to fix ~50 test failures
+ due to SVGElements not having the innerText function.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::dumpFrameText):
+
+2010-07-30 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=43290
+ Add structured message passing from the injected bundle to UIProcess
+
+ * MiniBrowser/mac/AppDelegate.m:
+ (didRecieveMessageFromInjectedBundle):
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (didClearWindowForFrame):
+ (didRecieveMessage):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::done):
+ (WTR::InjectedBundle::didReceiveMessage):
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize):
+ (WTR::TestController::didReceiveMessageFromInjectedBundle):
+ * WebKitTestRunner/TestController.h:
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::didReceiveMessageFromInjectedBundle):
+ * WebKitTestRunner/TestInvocation.h:
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+
+2010-07-30 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=43275
+ Make WKArrayRef more usable.
+
+ Remove now unnecessary const_casts.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::dumpDescendantFrameScrollPositions):
+ (WTR::dumpDescendantFramesText):
+
+2010-07-30 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=43274
+ Add first pass of structured message passing.
+
+ Update Minibrowser and WebKitTestRunner to work with the new post message
+ function.
+
+ * MiniBrowser/mac/AppDelegate.m:
+ (didRecieveMessageFromInjectedBundle):
+ (-[BrowserAppDelegate init]):
+ * MiniBrowser/mac/MiniBrowser_Prefix.pch:
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (didStartProvisionalLoadForFrame):
+ (didReceiveServerRedirectForProvisionalLoadForFrame):
+ (didFailProvisionalLoadWithErrorForFrame):
+ (didCommitLoadForFrame):
+ (didFinishLoadForFrame):
+ (didFailLoadWithErrorForFrame):
+ (didReceiveTitleForFrame):
+ (didClearWindowForFrame):
+ (didCreatePage):
+ (willDestroyPage):
+ (didRecieveMessage):
+ (WKBundleInitialize):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::_didReceiveMessage):
+ (WTR::InjectedBundle::didReceiveMessage):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h:
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::invoke):
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+
+2010-07-30 Anders Carlsson <andersca@apple.com>
+
+ Try to fix the layout test failures.
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_get_value):
+
+2010-07-29 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Replace plugins/npruntime/bindings-test.html with a more sophisticated test
+ https://bugs.webkit.org/show_bug.cgi?id=43232
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ Add PluginScriptableNPObjectInvokeDefault.cpp.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ Remove invokeDefault callback function.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp:
+ (PluginTest::create):
+ Move this to the top of the file.
+
+ (PluginTest::NPP_GetValue):
+ Add default implementation.
+
+ (PluginTest::NPN_CreateObject):
+ Add NPN_ wrapper.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.h:
+ (PluginTest::identifier):
+ Add identifier getter.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp:
+ (DocumentOpenInDestroyStream::DocumentOpenInDestroyStream):
+ Add "using namespace std".
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_GetValue):
+ Give PluginTest a chance to return a value.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+ * GNUmakefile.am:
+ Add PluginScriptableNPObjectInvokeDefault.cpp.
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_get_value):
+ Give PluginTest a chance to return a value.
+
+2010-07-30 Steve Block <steveblock@google.com>
+
+ Reviewed by Steve Block.
+
+ Add LayoutTestController methods to test DeviceOrientation
+ https://bugs.webkit.org/show_bug.cgi?id=39589
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setMockDeviceOrientationCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::setMockDeviceOrientation):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setMockDeviceOrientation):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMockDeviceOrientation):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setMockDeviceOrientation):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setMockDeviceOrientation):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setMockDeviceOrientation):
+ * Scripts/build-webkit:
+
+2010-07-29 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ [Qt] QtTestBrowser: -resizes-to-contents command line parameter is broken
+ https://bugs.webkit.org/show_bug.cgi?id=43209
+
+ When -resizes-to-content was being passed as a command line parameter it was simply
+ not being set (although the corresponding menu item was marked as ON).
+ User had to toggle the menu OFF and then ON again for it to take place.
+
+ Reason: LauncherWindow::applyPrefs method sets many user options passed in from
+ the command line, but not resizesToContents. Patch addresses that.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::createChrome):
+ (LauncherWindow::applyPrefs):
+ (LauncherWindow::toggleResizesToContents):
+ * QtTestBrowser/webview.h:
+ (WebViewGraphicsBased::resizesToContents):
+
+2010-07-29 Antonio Gomes <tonikitoo@webkit.org>
+
+ Rubber-stamped by Simon Fraser.
+
+ [Qt] QtTestBrowser: more method grouping and clean ups.
+
+ Moving blocks of code around. Basically grouping related methods close to each.
+
+ * QtTestBrowser/launcherwindow.cpp:
+ (LauncherWindow::initializeView):
+ (LauncherWindow::createChrome):
+ (LauncherWindow::changeViewportUpdateMode):
+ (LauncherWindow::showFPS):
+ (LauncherWindow::newWindow):
+ (LauncherWindow::cloneWindow):
+ * QtTestBrowser/launcherwindow.h:
+
+2010-07-30 Mahesh Kulkarni <mahesh.kulkarni@nokia.com>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [QT][Symbian] QtTestBrowser missing location capabilities
+ https://bugs.webkit.org/show_bug.cgi?id=43235
+
+ QtTestBrowser missing capabilities to use QtMobility::QLocation.
+
+ * QtTestBrowser/QtTestBrowser.pro:
+
+2010-07-29 Anders Carlsson <andersca@apple.com>
+
+ Add PluginTest.cpp
+
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+
+2010-07-29 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Update download URLs for python irclib package; the old URLs
+ pointed at a specific mirror host and not the general sourceforge
+ URLs.
+
+ https://bugs.webkit.org/show_bug.cgi?id=43228
+
+ * Scripts/webkitpy/thirdparty/__init__.py:
+
+2010-07-29 Anders Carlsson <andersca@apple.com>
+
+ Fix typo.
+
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+
+2010-07-29 Anders Carlsson <andersca@apple.com>
+
+ Another attempt at fixing the Qt and GTK+ build.
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance):
+ (webkit_test_plugin_destroy_stream):
+
+2010-07-29 Anders Carlsson <andersca@apple.com>
+
+ Another build fix attempt.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp:
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance):
+ * GNUmakefile.am:
+
+2010-07-29 Anders Carlsson <andersca@apple.com>
+
+ Try to fix Windows and Unix builds.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance):
+ (webkit_test_plugin_destroy_stream):
+
+2010-07-29 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Refactor TestNetscapePlugin so tests can be split in separate files
+ https://bugs.webkit.org/show_bug.cgi?id=43220
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ Add PluginTest.cpp, PluginTest.h and Tests/DocumentOpenInDestroyStream.cpp.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (pluginAllocate):
+ Initialize pluginTest to 0. Remove testDocumentOpenInDestroyStream.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp: Added.
+ (PluginTest::PluginTest):
+ Initialize m_npp and the test identifier.
+
+ (PluginTest::createTestFunctions):
+ Return the map from identifiers to createTest functions.
+
+ (PluginTest::registerCreateTestFunction):
+ Insert the identifier and create function pair in the map.
+
+ (PluginTest::create):
+ Look for a createTest function. If one is found, call it. Otherwise create a vanilla PluginTest object.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginTest.h: Added.
+ (PluginTest::Register::Register):
+ Helper class template for registering plug-in tests.
+
+ (PluginTest::Register::create):
+ Create a new test of the given type.
+
+ * DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp: Added.
+ (DocumentOpenInDestroyStream::DocumentOpenInDestroyStream):
+ Add a test that calls testDocumentOpen from its NPP_DestroyStream callback.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+ Create a PluginTest given the identifier. Remove the check for "testdocumentopenindestroystream".
+
+ (NPP_DestroyStream):
+ Call the plug-in test NPP_DestroyStream member function.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ Add PluginTest.cpp, PluginTest.h and Tests/DocumentOpenInDestroyStream.cpp.
+
+2010-07-29 Martin Robinson <mrobinson@igalia.com>
+
+ Unreviewed build fix.
+
+ Add missing second argument to assert_lint in new style checker tests.
+
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+
+2010-07-29 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam Roben.
+
+ check-webkit-style shouldn't complain about NPAPI functions
+ https://bugs.webkit.org/show_bug.cgi?id=43211
+
+ Allow underscores in functions that start with NPN_, NPP_ or NP_.
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+
+2010-07-29 Victor Wang <victorw@chromium.org>
+
+ Unreviewed, rolling out r64270.
+ http://trac.webkit.org/changeset/64270
+ https://bugs.webkit.org/show_bug.cgi?id=39589
+
+ The patch breaks chromium webkit unittest
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ * Scripts/build-webkit:
+
+2010-07-29 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ [Qt] QtTestBrowser: Move WebPage class methods definitions from main.cpp to webpage.cpp
+ https://bugs.webkit.org/show_bug.cgi?id=43199
+
+ There is no sense in keeping WebPage method definitions in main.cpp once
+ webpage.cpp already exists.
+
+ No behavior change.
+
+ * QtTestBrowser/main.cpp:
+ * QtTestBrowser/webpage.cpp:
+ (WebPage::createWindow):
+ (WebPage::createPlugin):
+
+2010-07-29 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ [Qt] Factor out LauncherWindow class out of main.cpp (QtTestBrowser)
+ https://bugs.webkit.org/show_bug.cgi?id=43170
+
+ Moving LauncherWindow class out of main.cpp to its own .cpp and .h files:
+ launcherwindow.{cpp|h}
+
+ No behavior change.
+
+ Also changed all global static variables (named "gXXX") from main.cpp to
+ static public variables of the LauncherWindow class.
+
+ * QtTestBrowser/QtTestBrowser.pro:
+ * QtTestBrowser/launcherwindow.cpp: Added.
+ * QtTestBrowser/launcherwindow.h: Added.
+ * QtTestBrowser/main.cpp:
+ (LauncherApplication::handleUserOptions):
+ (main):
+
+2010-07-29 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ Build fix for building against GTK+ 3.x. GSEAL requires that we
+ access internals of the GdkDragContext via methods. For older versions
+ of GTK+, define those methods.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (gdk_drag_context_get_selected_action): Added.
+ (gdk_drag_context_get_actions): Added.
+ (dispatchEvent): Use the two new accessor methods.
+
+2010-07-29 Adam Roben <aroben@apple.com>
+
+ Always say "plugins directory" when referring to a directory
+ containing one or more plugins
+
+ Fixes <http://webkit.org/b/43197> WebKit2 often says "plugin
+ directory" when it means "plugins directory"
+
+ Reviewed by John Sullivan.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize): Updated for rename.
+
+2010-07-29 Adam Roben <aroben@apple.com>
+
+ Always say "directory" when referring to a plugin directory
+
+ Fixes <http://webkit.org/b/43195> WebKit2 often says "plugin path"
+ when it means "plugin directory"
+
+ Reviewed by John Sullivan.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize): Updated for renames.
+
+ * WebKitTestRunner/TestController.h: Renamed m_testPluginPath to
+ m_testPluginDirectory.
+ (WTR::TestController::testPluginDirectory): Renamed from
+ testPluginPath.
+
+ * WebKitTestRunner/mac/TestControllerMac.mm:
+ (WTR::TestController::initializeTestPluginDirectory):
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::initializeTestPluginDirectory):
+ Renamed from initializeTestPluginPath and updated for rename.
+
+2010-07-29 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ Initialize all members of NPClass struct.
+ https://bugs.webkit.org/show_bug.cgi?id=43193
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+
+2010-07-29 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ Warning fix on platforms where XP_MACOSX is undefined.
+ https://bugs.webkit.org/show_bug.cgi?id=43192
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.h:
+ Use #if defined(XP_MACOSX) instead of #if XP_MACOSX .
+
+2010-07-29 Adam Roben <aroben@apple.com>
+
+ Give find-included-framework-headers our standard license
+
+ * Scripts/find-included-framework-headers: Used the license from
+ WebCore/LICENSE-APPLE.
+
+2010-07-29 Adam Roben <aroben@apple.com>
+
+ Speed up find-included-framework-headers
+
+ We only do one invocation of find now, no longer pipe to grep, and
+ replace uniq with sort -u.
+
+ Also added a license header.
+
+ * Scripts/find-included-framework-headers:
+
+2010-07-29 Steve Block <steveblock@google.com>
+
+ Reviewed by Jeremy Orlow.
+
+ Add LayoutTestController methods to test DeviceOrientation
+ https://bugs.webkit.org/show_bug.cgi?id=39589
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setMockDeviceOrientationCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setMockDeviceOrientation):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMockDeviceOrientation):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setMockDeviceOrientation):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setMockDeviceOrientation):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setMockDeviceOrientation):
+ * Scripts/build-webkit:
+
+2010-07-28 Kenichi Ishibashi <bashi@google.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Fixed <https://bugs.webkit.org/show_bug.cgi?id=33814>
+ check-webkit-style gives false positives in single-line functions.
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+
+2010-07-28 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ WebKitTestRunner needs to support layoutTestController.execCommand
+ <https://bugs.webkit.org/show_bug.cgi?id=42538>
+
+ WebKitTestRunner needs layoutTestController.isCommandEnabled
+ <https://bugs.webkit.org/show_bug.cgi?id=42671>
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ Added execCommand and isCommandEnabled.
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::execCommand): Added.
+ (WTR::LayoutTestController::isCommandEnabled): Added.
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h: Ditto.
+
+2010-07-28 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Introduce drt_expectations.txt for NRWT
+ https://bugs.webkit.org/show_bug.cgi?id=43123
+
+ Introduce LayoutTests/platform/chromium/drt_expectations.txt,
+ which overrides test expectations only for DumpRenderTree, in
+ order to manage what problems are investigated.
+ This change will be reverted when we switch to DRT completely.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ Add drt_expectations.txt content to the result of
+ test_expectations_overrides() if --use-drt is specified.
+
+2010-07-28 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin Adler.
+
+ First pass at visited link support for WK2
+ https://bugs.webkit.org/show_bug.cgi?id=43157
+
+ * MiniBrowser/mac/AppDelegate.m:
+ (didNavigateWithNavigationData):
+ (didPerformClientRedirect):
+ (didPerformServerRedirect):
+ (didUpdateHistoryTitle):
+ (populateVisitedLinks): Added for the new version of the HistoryClient.
+ (-[BrowserAppDelegate init]): Set the HistoryClient right after creating the context(s)
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]):
+
+2010-07-28 Robin Dunn <robin@alldunn.com>
+
+ Reviewed by Kevin Ollivier.
+
+ Add DOM bindings support for wx port.
+
+ * DumpRenderTree/wscript:
+ * wx/browser/wscript:
+ * wx/build/settings.py:
+
+2010-07-28 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] cleanup temp files left by Linux DRT
+ https://bugs.webkit.org/show_bug.cgi?id=43062
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json: Rename the chromium bots to include the OS
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: add a step on chromium-linux to delete temp files left
+ by crashed DRTs
+
+2010-07-28 Antonio Gomes <tonikitoo@webkit.org>
+
+ Rubber-stamped by Kenneth Christiansen.
+
+ More Developer menu items reordering.
+
+ Grouping related menu items together, visually and logically (in the code).
+
+ No behavior change.
+
+ * QtTestBrowser/main.cpp:
+ (LauncherWindow::createChrome):
+
+2010-07-27 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Add FILE_SYSTEM build flag for FileSystem API
+ https://bugs.webkit.org/show_bug.cgi?id=42915
+
+ * Scripts/build-webkit:
+
+2010-07-27 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by David Levin.
+
+ Stylebot should not complain about NULL usage in calls to gdk_pixbuf_save_to
+ https://bugs.webkit.org/show_bug.cgi?id=43090
+
+ * Scripts/webkitpy/style/checkers/cpp.py: Add exemption for some GdkPixbuf methods.
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py: Added some tests for this behavior.
+
+2010-07-27 Kent Tamura <tkent@chromium.org>
+
+ Unreviewed, trivial typo fix.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ Fix a wrong method name committed by r64109.
+
+2010-07-27 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=43087
+ Clean up handling of strings at the WebKit2 API layer.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (runJavaScriptAlert):
+ (runJavaScriptConfirm):
+ (runJavaScriptPrompt):
+ (didNavigateWithNavigationData):
+ (-[BrowserWindowController updateProvisionalURLForFrame:]):
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (_didClearWindowForFrame):
+
+2010-07-27 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch post-commits is broken: AttributeError: Values instance has no attribute 'no_squash'
+ https://bugs.webkit.org/show_bug.cgi?id=42984
+
+ squash and no_squash have been intentionally erroring for a couple weeks now.
+ But post-commits was just broken. Just remove squash/no_squash.
+
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ * Scripts/webkitpy/tool/steps/options.py:
+
+2010-07-27 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after introduction of EXECUTABLE_ALLOCATOR_DEMAND.
+
+ * wx/build/settings.py:
+
+2010-07-27 Adam Roben <aroben@apple.com>
+
+ Mac build fix
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (processDidExit):
+ (-[BrowserWindowController awakeFromNib]):
+ Added processDidExit support.
+
+2010-07-26 Antonio Gomes <tonikitoo@webkit.org>
+
+ Rubber-stamped by Simon Hausmann.
+
+ [Qt] Reorder some items in Developers' menu so QGraphicsView one is easier accessible.
+
+ Move some less useful menu items on Developers menu from the top to the bottom, so
+ QGraphicsView menu goes to the top, and becomes more quickly accessible.
+
+ * QtTestBrowser/main.cpp:
+ (LauncherWindow::createChrome):
+
+2010-07-26 Adam Roben <aroben@apple.com>
+
+ Fix the path to InjectedBundle.dll in Debug_Internal builds
+
+ Fixes <http://webkit.org/b/42994> WebKitTestRunner fails to load
+ InjectedBundle.dll in the Debug_Internal configuration
+
+ Reviewed by Anders Carlsson.
+
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::initializeInjectedBundlePath): Add the _debug
+ suffix only in Debug_All builds.
+
+2010-07-25 Mahesh Kulkarni <mahesh.kulkarni@nokia.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=42947
+ Check for WEBKIT_TESTFONTS for qt, gtk and windows port and throw
+ error. Without which dumpRenderTree crashes.
+
+ * Scripts/old-run-webkit-tests:
+
+2010-07-27 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ https://bugs.webkit.org/show_bug.cgi?id=42956
+ [DRT/Chromium] Fix "out of sync" assertion error
+
+ Fix an assertion error on Windows like the following:
+ 100721 20:16:46 chromium.py:386 CRITICAL Test got out of sync:
+ |file:///c:/WebKitBuildSlave2/chromium-win-release-tests/build/LayoutTests/http/tests/local/blob/send-data-blob.html|
+ |file:///C:/WebKitBuildSlave2/chromium-win-release-tests/build/LayoutTests/http/tests/local/blob/send-data-blob.html|
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ If the url matches with "file:///[a-z]:", does case-ignore comparison.
+ GURL capitalize the driver letter of a file: URL.
+
+2010-07-26 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ WebKitTestRunner needs to support layoutTestController.counterValueForElementById
+ https://bugs.webkit.org/show_bug.cgi?id=42537
+
+ WebKitTestRunner needs layoutTestController.markerTextForListItem
+ https://bugs.webkit.org/show_bug.cgi?id=42549
+
+ * WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm:
+ Fixed _paramterExpression typo. Improved support for string type as a
+ return value, so we don't try to include DOMString.h and we can convert
+ the string to a JSValue by calling JSValueMakeStringOrNull.
+
+ * WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h:
+ Added JSValueMakeStringOrNull, used by the code generator.
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ Added counterValueForElementById and markerTextForListItem.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ Moved constant to the top of the file.
+ (WTR::toCF): Added. Converts strings to CFStringRef.
+ (WTR::toWK): Added. Converts strings to WKStringRef.
+ (WTR::toJS): Added. Converts strings to JSStringRef.
+ (WTR::setProperty): Moved this function to the top of the file
+ rather than having it down where it's used inside the class. Also
+ renamed it so it's a separate function rather than an overload of
+ JSObjectSetProperty.
+ (WTR::propertyValue): Copied this here from InjectedBundlePage.cpp.
+ Should move it somewhere we can share it.
+ (WTR::propertyObject): Ditto.
+ (WTR::getElementById): Added. Calls getElementById through the magic
+ of JavaScript.
+ (WTR::LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ Chagned to use toWK instead of four local variables.
+ (WTR::LayoutTestController::counterValueForElementById): Added.
+ Calls WKBundleFrameCopyCounterValue.
+ (WTR::LayoutTestController::markerTextForListItem): Added.
+ Calls WKBundleFrameCopyMarkerText.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ Added counterValueForElementById and markerTextForListItem.
+
+2010-07-26 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] The EventSender should support simulating drop events
+ https://bugs.webkit.org/show_bug.cgi?id=39844
+
+ Add initial dropping support to the GTK+ EventSender.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (createWebView): Listen for some new drag-and-drop signals.
+ * DumpRenderTree/gtk/EventSender.cpp: Add currentDragSourceContext.
+ (dispatchEvent):
+ Detect situations where a drag is either starting or ending and massage
+ GTK+ into sending the appropriate signals to the WebView.
+ (replaySavedEvents): Remove comment.
+ (makeEventSender): Clear the currentDragSourceContext when creating a new EventSender.
+ (dragBeginCallback): Capture the new currentDragSourceContext when a drag begins.
+ (dragEndCallback): Clear the currentDragSourceContext when a drag ends.
+ (dragFailedCallback): Disable the GTK+ drag failed animation.
+ * DumpRenderTree/gtk/EventSender.h: Add declarations for new signal callbacks.
+
+2010-07-26 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Darin Adler.
+
+ svn-unapply warns of uninitialized variable when unapplying
+ a patch that describes an svn move operation
+ https://bugs.webkit.org/show_bug.cgi?id=42036
+
+ Fixes Perl uninitialized variable warnings when un-applying
+ a patch that moves a file.
+
+ * Scripts/svn-unapply:
+ - Modified patch() so that it initializes $patch to the empty
+ string when we don't have svnConvertedText (such as when
+ reversing a diff that represents a svn copy/move operation).
+
+2010-07-26 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Move some non-APIish functions into private headers.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+
+2010-07-26 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=42986
+ Add prompt and confirm client functions to WebKit2
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController awakeFromNib]):
+
+2010-07-26 Adam Roben <aroben@apple.com>
+
+ Windows build fix
+
+ * MiniBrowser/MiniBrowser.vcproj:
+ * WebKitTestRunner/InjectedBundle/win/InjectedBundle.vcproj:
+ Removed empty attributes so the values will be picked up from the
+ vsprops files. (Also removed a couple of attributes that accidentally
+ duplicated values from the vsprops files.)
+
+2010-07-26 Brian Weinstein <bweinstein@apple.com>
+
+ Rubber-stamped by Adam Roben.
+
+ Touch MiniBrowser's stdafx to fix the build.
+
+ * MiniBrowser/win/stdafx.h:
+
+2010-07-26 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Add pretty printer of WTF::Vector for GDB 7.
+
+ https://bugs.webkit.org/show_bug.cgi?id=40909
+
+ * gdb/wtf.py: Added.
+
+2010-07-26 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Fix feature detection regexp
+
+ We were missing the last feature
+
+ * Scripts/webkitdirs.pm:
+
+2010-07-25 Darin Adler <darin@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ WebKitTestRunner needs to support layoutTestController.dumpSelectionRect
+ https://bugs.webkit.org/show_bug.cgi?id=42326
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ Added dumpSelectionRect.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ (WTR::LayoutTestController::dumpSelectionRect): Added. For now, this
+ does nothing because its purpose is to change pixel test output and
+ we do not have pixel tests implemented yet.
+
+2010-07-25 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ WebKitTestRunner needs to support layoutTestController.keepWebHistory
+ https://bugs.webkit.org/show_bug.cgi?id=42323
+
+ Added keepWebHistory and computedStyleIncludingVisitedInfo.
+
+ Also fixed misspellings of the word "receive".
+
+ Also tweaked the names of some of the LayoutTestController members.
+
+ * WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm:
+ Added support for a type named "object" that is passed and returns as
+ a JSValueRef.
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ Added keepWebHistory and computedStyleIncludingVisitedInfo. Also
+ put setAcceptsEditing up nearer the top.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::_didReceiveMessage): Fixed mispellings of receive.
+ (WTR::InjectedBundle::initialize): Ditto.
+ (WTR::InjectedBundle::didReceiveMessage): Ditto.
+ (WTR::InjectedBundle::reset): Reset the state of visited links between
+ tests. Also eliminated the unused argument to the LayoutTestController
+ create function.
+ (WTR::InjectedBundle::setShouldTrackVisitedLinks): Added.
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h: Ditto.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::shouldBeginEditing): Call shouldAllowEditing
+ instead of acceptsEditing.
+ (WTR::InjectedBundlePage::shouldEndEditing): Ditto.
+ (WTR::InjectedBundlePage::shouldInsertNode): Ditto.
+ (WTR::InjectedBundlePage::shouldInsertText): Ditto.
+ (WTR::InjectedBundlePage::shouldDeleteRange): Ditto.
+ (WTR::InjectedBundlePage::shouldChangeSelectedRange): Ditto.
+ (WTR::InjectedBundlePage::shouldApplyStyle): Ditto.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::create): Removed uneeded argument.
+ (WTR::LayoutTestController::LayoutTestController): Removed unneeded
+ argument. Updated for rename of m_acceptsEditing to m_shouldAllowEditing.
+ (WTR::LayoutTestController::numberOfActiveAnimations): Added some FIXMEs
+ about the fact that this works on the main frame.
+ (WTR::LayoutTestController::pauseAnimationAtTimeOnElementWithId): Ditto.
+ (WTR::LayoutTestController::keepWebHistory): Added.
+ (WTR::LayoutTestController::computedStyleIncludingVisitedInfo): Added.
+ (WTR::JSObjectSetProperty): Added. Helper to make the function below
+ cleaner.
+ (WTR::LayoutTestController::makeWindowObject): Changed to use the
+ overload of JSObjectSetProperty above.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h: Changes to
+ match above.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize): Fixed mispellings of receive.
+ (WTR::TestController::_didReceiveMessageFromInjectedBundle): Ditto.
+ (WTR::TestController::didReceiveMessageFromInjectedBundle): Ditto.
+ * WebKitTestRunner/TestController.h: Ditto.
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::didReceiveMessageFromInjectedBundle): Ditto.
+ * WebKitTestRunner/TestInvocation.h: Ditto.
+
+2010-07-25 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=42193
+ Support layoutTestController.dumpEditingDelegates in WebKitTestRunner
+
+ Step 2 - add the rest of editing delegates.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::operator<<): Fixed to not crash when range is null.
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::_shouldEndEditing):
+ (WTR::InjectedBundlePage::_shouldInsertNode):
+ (WTR::InjectedBundlePage::_shouldInsertText):
+ (WTR::InjectedBundlePage::_shouldDeleteRange):
+ (WTR::InjectedBundlePage::_shouldChangeSelectedRange):
+ (WTR::InjectedBundlePage::_shouldApplyStyle):
+ (WTR::InjectedBundlePage::_didBeginEditing):
+ (WTR::InjectedBundlePage::_didEndEditing):
+ (WTR::InjectedBundlePage::_didChange):
+ (WTR::InjectedBundlePage::_didChangeSelection):
+ (WTR::InjectedBundlePage::shouldEndEditing):
+ (WTR::InjectedBundlePage::shouldInsertNode):
+ (WTR::InjectedBundlePage::shouldInsertText):
+ (WTR::InjectedBundlePage::shouldDeleteRange):
+ (WTR::InjectedBundlePage::shouldChangeSelectedRange):
+ (WTR::InjectedBundlePage::shouldApplyStyle):
+ (WTR::InjectedBundlePage::didBeginEditing):
+ (WTR::InjectedBundlePage::didEndEditing):
+ (WTR::InjectedBundlePage::didChange):
+ (WTR::InjectedBundlePage::didChangeSelection):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+
+2010-07-24 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by David Kilzer.
+
+ AX: need a layout test testing misspelled words in attributed strings
+ https://bugs.webkit.org/show_bug.cgi?id=42899
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (attributedStringForRangeCallback):
+ (attributedStringRangeIsMisspelledCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::attributedStringForRange):
+ (AccessibilityUIElement::attributedStringRangeIsMisspelled):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::attributedStringForRange):
+ (AccessibilityUIElement::attributedStringRangeIsMisspelled):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::attributedStringForRange):
+ (AccessibilityUIElement::attributedStringRangeIsMisspelled):
+
+2010-07-23 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/42911> Update ruby tools to work with shallow framework bundles
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/check-for-inappropriate-files-in-framework: Added
+ check for the SHALLOW_BUNDLE environment variable so that the
+ script will work with iOS WebKit builds.
+ * Scripts/check-for-webkit-framework-include-consistency: Ditto.
+
+2010-07-22 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Eliminate unneeded WKBundleFrameCopyInnerText function from WebKit2
+ https://bugs.webkit.org/show_bug.cgi?id=42847
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::operator<<): Replaced the WKStringToUTF8 function with
+ a set of overloaded stream operators.
+ (WTR::dumpPath): Changed to use ostringstream and return a string.
+ (WTR::propertyValue): Added.
+ (WTR::propertyObject): Added.
+ (WTR::propertyString): Added.
+ (WTR::numericWindowPropertyValue): Changed to call propertyValue.
+ (WTR::dumpFrameScrollPosition): Removed now unneeded WKStringToUTF8 sequence
+ since we now have suitable streaming functions.
+ (WTR::dumpFrameText): Use propertyObject and propertyString instead of
+ WKBundleFrameCopyInnerText.
+ (WTR::dumpDescendantFramesText): Removed now unneeded WKStringToUTF8 sequence
+ since we now have suitable streaming functions.
+ (WTR::InjectedBundlePage::dump): Ditto.
+ (WTR::InjectedBundlePage::willAddMessageToConsole): Ditto.
+ (WTR::InjectedBundlePage::willSetStatusbarText): Ditto.
+ (WTR::InjectedBundlePage::willRunJavaScriptAlert): Ditto.
+ (WTR::InjectedBundlePage::willRunJavaScriptConfirm): Ditto.
+ (WTR::InjectedBundlePage::willRunJavaScriptPrompt): Ditto.
+
+2010-07-22 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Sam Weinig and Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=42193
+ Support layoutTestController.dumpEditingDelegates in WebKitTestRunner
+
+ Step 1: Add the method, and implement one actual delegate call as proof of concept. No tests
+ fixed, but this makes difference one line smaller on many editing tests.
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ Added dumpEditingCallbacks() and setAcceptsEditing().
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::dumpPath): Dump path to a node in a format that's compatible with DumpRenderTree.
+ (WTR::operator<<): Print a range.
+ (WTR::InjectedBundlePage::InjectedBundlePage): Set editor client in addition to existing
+ clients.
+ (WTR::InjectedBundlePage::_shouldBeginEditing): The only client method implemented so far.
+ (WTR::InjectedBundlePage::shouldBeginEditing): Ditto.
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h: Added a section for editor client
+ calls.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::LayoutTestController):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ (WTR::LayoutTestController::dumpEditingCallbacks):
+ (WTR::LayoutTestController::setAcceptsEditing):
+ (WTR::LayoutTestController::acceptsEditing):
+ (WTR::LayoutTestController::shouldDumpEditingCallbacks):
+ Store m_acceptsEditing and m_dumpEditingCallbacks.
+
+2010-07-22 Yael Aharon <yael.aharon@nokia.com>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] QtWebKit needs public API for Notifications.
+ https://bugs.webkit.org/show_bug.cgi?id=41413
+
+ Update DumpRenderTree and QtTestBrowser to use the new API.
+ Add new DRT API to flag that notifications permission requests should be ignored.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::requestPermission):
+ (WebCore::WebPage::checkPermission):
+ (WebCore::WebPage::cancelRequestsForPermission):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::ignoreDesktopNotificationPermissionRequests):
+ (LayoutTestController::checkDesktopNotificationPermission):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::ignoreReqestForPermission):
+ * QtTestBrowser/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ * QtTestBrowser/webpage.cpp:
+ (WebPage::WebPage):
+ (WebPage::requestPermission):
+ (WebPage::checkPermission):
+ (WebPage::cancelRequestsForPermission):
+ * QtTestBrowser/webpage.h:
+
+2010-07-22 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ WebKitTestRunner needs to support layoutTestController.dumpChildFramesAsText
+ https://bugs.webkit.org/show_bug.cgi?id=42325
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ Added dumpChildFramesAsText.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::dumpFrameText): Added.
+ (WTR::dumpDescendantFramesText): Added.
+ (WTR::InjectedBundlePage::dumpAllFramesText): Added.
+ (WTR::InjectedBundlePage::dump): Changed to use the new whatToDump function
+ instead of the shouldDumpAsText function, and added a case for AllFramesText.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h: Added dumpAllFramesText.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::LayoutTestController): Replaced m_dumpAsText with
+ m_whatToDump.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h: Added
+ dumpChildFramesAsText. Removed shouldDumpAsText, shouldDumpDOMAsWebArchive,
+ and shouldDumpSourceAsWebArchive. Added whatToDump.
+
+2010-07-22 Adam Roben <aroben@apple.com>
+
+ Windows build fix
+
+ Inspired by r63881.
+
+ * MiniBrowser/MiniBrowser.vcproj:
+ * WebKitTestRunner/InjectedBundle/win/InjectedBundle.vcproj:
+ Removed pre- and post-build events so they will be inherited from the
+ vsprops files.
+
+2010-07-21 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ WebKitTestRunner needs layoutTestController.dumpChildFrameScrollPositions
+ https://bugs.webkit.org/show_bug.cgi?id=42548
+
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl:
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::numericWindowPropertyValue): Renamed this and moved it up higher in the file.
+ (WTR::dumpFrameScrollPosition): Added argument telling whether to dump the frame name.
+ Changed to a file-internal function instead of a member function.
+ (WTR::dumpDescendantFrameScrollPositions): Added.
+ (WTR::InjectedBundlePage::dumpAllFrameScrollPositions): Added.
+ (WTR::InjectedBundlePage::dump): Changed to call dumpAllFrameScrollPositions when
+ appropriate. Also streamlined all the WKStringToUTF8 call sites.
+ (WTR::InjectedBundlePage::willAddMessageToConsole): Streamlined use of WKStringToUTF8.
+ (WTR::InjectedBundlePage::willSetStatusbarText): Ditto.
+ (WTR::InjectedBundlePage::willRunJavaScriptAlert): Ditto.
+ (WTR::InjectedBundlePage::willRunJavaScriptConfirm): Ditto.
+ (WTR::InjectedBundlePage::willRunJavaScriptPrompt): Ditto.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h: Updated for above changes.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::LayoutTestController): Initialize
+ m_shouldDumpAllFrameScrollPositions.
+ (WTR::LayoutTestController::shouldDumpMainFrameScrollPosition): Renamed from
+ shouldDumpFrameScrollPositions.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h: Reorganized the file a
+ bit, added dumpChildFrameScrollPositions and shouldDumpAllFrameScrollPositions,
+ and renamed shouldDumpFrameScrollPositions to shouldDumpMainFrameScrollPosition.
+
+2010-07-21 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ WebKitTestRunner needs to support dumping of scroll position
+ https://bugs.webkit.org/show_bug.cgi?id=42514
+
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (_didClearWindowForFrame): Use JSGlobalContextRef instead of JSContextRef.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::_didClearWindowForFrame): Use JSGlobalContextRef
+ instead of JSContextRef.
+ (WTR::InjectedBundlePage::dump): Call dumpFrameScrollPosition when appropriate.
+ (WTR::numericWindowProperty): Added. Helper for dumpFrameScrollPosition.
+ (WTR::InjectedBundlePage::dumpFrameScrollPosition): Added.
+ (WTR::InjectedBundlePage::didClearWindowForFrame): Use JSGlobalContextRef
+ instead of JSContextRef.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h: Removed names from
+ arguments that simply repeat the argument type. Added dumpFrameScrollPosition.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::shouldDumpDOMAsWebArchive): Added. Currently
+ returns false.
+ (WTR::LayoutTestController::shouldDumpSourceAsWebArchive): Added. Currently
+ returns false.
+ (WTR::LayoutTestController::shouldDumpFrameScrollPositions): Added. Matches
+ the logic in DumpRenderTree.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h: Updated for above changes.
+
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj: Added property svn:ignore.
+
+2010-07-21 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix, adding the WebCore/bindings/generic dir to the list of build dirs.
+
+ * wx/build/settings.py:
+
+2010-07-21 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=42539
+ WebKitTestRunner needs to support printing ALERT, PROMPT and CONFIRM messages
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::_willAddMessageToConsole):
+ (WTR::InjectedBundlePage::_willSetStatusbarText):
+ (WTR::InjectedBundlePage::_willRunJavaScriptAlert):
+ (WTR::InjectedBundlePage::_willRunJavaScriptConfirm):
+ (WTR::InjectedBundlePage::_willRunJavaScriptPrompt):
+ (WTR::InjectedBundlePage::willAddMessageToConsole):
+ (WTR::InjectedBundlePage::willSetStatusbarText):
+ (WTR::InjectedBundlePage::willRunJavaScriptAlert):
+ (WTR::InjectedBundlePage::willRunJavaScriptConfirm):
+ (WTR::InjectedBundlePage::willRunJavaScriptPrompt):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+
+2010-07-21 Adam Roben <aroben@apple.com>
+
+ Give InjectedBundle our standard set of configurations (minus the
+ *_Cairo variants)
+
+ InjectedBundle's Debug_All configuration was the same as is Debug
+ configuration, and it was missing a Debug_Internal configuration.
+
+ Fixes <http://webkit.org/b/42749> InjectedBundle's build
+ configurations are screwy
+
+ Reviewed by Darin Adler.
+
+ * WebKitTestRunner/InjectedBundle/win/InjectedBundle.vcproj: Added
+ debug_internal.vsprops and debug_all.vsprops to the Debug_All
+ configuration. Added a Debug_Internal configuration.
+
+ * WebKitTestRunner/WebKitTestRunner.sln: Build the Debug_Internal
+ variant of InjectedBundle when we're using the Debug_Internal solution
+ configuration.
+
+2010-07-21 Adam Roben <aroben@apple.com>
+
+ Move InjectedBundle's settings to a vsprops file
+
+ This will make it easier to change settings for all configurations,
+ and to add new configurations.
+
+ Fixes <http://webkit.org/b/42748> InjectedBundle should use vsprops
+ files
+
+ Reviewed by Darin Adler.
+
+ * WebKitTestRunner/Configurations/InjectedBundleCommon.vsprops: Added.
+ Moved settings here...
+ * WebKitTestRunner/InjectedBundle/win/InjectedBundle.vcproj: ...from
+ here.
+
+2010-07-21 Adam Roben <aroben@apple.com>
+
+ Give MiniBrowser our standard set of configurations (minus the *_Cairo
+ variants)
+
+ MiniBrowser already had a configuration called "Release", but it was
+ using mostly the same settings as Debug. And its Debug configuration
+ was using the settings that Debug_Internal should be using.
+
+ Fixes <http://webkit.org/b/42746> MiniBrowser's build configurations
+ are screwy
+
+ Reviewed by Darin Adler.
+
+ * MiniBrowser/MiniBrowser.vcproj: Removed debug_internal.vsprops from
+ the Debug configuration. Remove debug.vsprops and
+ debug_internal.vsprops from the Release configuration and replace them
+ with release.vsprops. Added Debug_Internal and Debug_All
+ configurations.
+
+2010-07-21 Adam Roben <aroben@apple.com>
+
+ Move MiniBrowser's settings to a vsprops file
+
+ This will make it easier to change settings for all configurations,
+ and to add new configurations.
+
+ MiniBrowser should use vsprops files
+ https://bugs.webkit.org/show_bug.cgi?id=42745
+
+ Reviewed by Darin Adler.
+
+ * MiniBrowser/Configurations/MiniBrowserCommon.vsprops: Added. Moved
+ settings here...
+ * MiniBrowser/MiniBrowser.vcproj: ...from here.
+
+2010-07-21 Adam Roben <aroben@apple.com>
+
+ Fix compiler warnings when building MiniBrowser
+
+ Also cleaned up the .vcproj a bit.
+
+ Fixes <http://webkit.org/b/42743>.
+
+ Reviewed by Darin Adler.
+
+ * MiniBrowser/MiniBrowser.vcproj: Removed all settings that are
+ already defined in .vsprops files. This also fixes a warning about
+ /EDITANDCONTINUE being incompatible with /SAFESEH.
+
+ * MiniBrowser/win/MiniBrowser.rc: Replaced afxres.h with winresrc.h so
+ that we stop getting warnings about ID_FILE_OPEN and ID_FILE_CLOSE
+ being redefined. (I think this will also get us closer to building
+ with VC++ Express.)
+
+2010-07-20 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Jon Honeycutt.
+
+ Fix obvious typo.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::setStatusbarText): Need to call ->data() to actually get the string value.
+
+2010-07-20 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] by default, dumpAsText should disable pixel results
+ https://bugs.webkit.org/show_bug.cgi?id=42715
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::dumpAsText): disable pixel results, but allow JS to override
+
+2010-07-20 Adam Roben <aroben@apple.com>
+
+ Windows build fix
+
+ * MiniBrowser/MiniBrowser.vcproj: Link against the new, shiny
+ WebKit.lib instead of the old, dusty WebKit2.lib.
+
+2010-07-20 Adam Roben <aroben@apple.com>
+
+ Stop linking WebKitTestRunner against getopt
+
+ Use of getopt was removed in r63700.
+
+ Fixes <http://webkit.org/b/42714> WebKitTestRunner links against
+ getopt, but doesn't need to
+
+ Reviewed by Sam Weinig.
+
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj: Removed getopt.lib
+ from all configurations.
+
+2010-07-20 Adam Roben <aroben@apple.com>
+
+ Make run-webkit-tests --webkit-test-runner "work" on Windows
+
+ WebKitTestRunner crashes on launch, but at least the scripts build and
+ launch it!
+
+ Fixes <http://webkit.org/b/42709> run-webkit-tests
+ --webkit-test-runner bails with an error on Windows
+
+ Reviewed by Anders Carlsson.
+
+ * Scripts/build-webkittestrunner: Build WebKitTestRunner.sln on
+ Windows.
+ * WebKitTestRunner/WebKitTestRunner.sln: Added. Contains the following
+ projects (from first-built to last-built): FindSafari, ImageDiff,
+ InjectedBundleGenerated, InjectedBundle, WebKitTestRunner.
+
+2010-07-20 Adam Roben <aroben@apple.com>
+
+ Change build-webkit back to building WebKit.sln on Windows
+
+ WebKit.sln builds all the same projects as WebKit2.sln, and the latter
+ is being removed.
+
+ Rubber-stamped in advance by Steve Falkenburg.
+
+ * Scripts/build-webkit:
+
+2010-07-20 Adam Roben <aroben@apple.com>
+
+ Windows build fix
+
+ * MiniBrowser/win/BrowserWindow.cpp: Added missing #include.
+
+2010-07-20 Joseph Pecoraro <joepeck@webkit.org>
+
+ Reviewed by Geoffrey Garen.
+
+ WebScriptObject Should Allow Safely Checking For Key Existence
+ https://bugs.webkit.org/show_bug.cgi?id=42613
+
+ Normal ObjCController workflow for a WebScriptObject test.
+
+ * DumpRenderTree/mac/ObjCController.m:
+ (+[ObjCController isSelectorExcludedFromWebScript:]):
+ (+[ObjCController webScriptNameForSelector:]):
+ (-[ObjCController testHasWebScriptKey:]):
+
+2010-07-20 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ https://bugs.webkit.org/show_bug.cgi?id=42118
+ Disable compositing/webgl tests if WebGL is not enabled
+
+ * Scripts/old-run-webkit-tests:
+
+2010-07-20 Anton Muhin <antonm@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Print additional information about exception if failed to connect to apache (in verbose mode).
+ https://bugs.webkit.org/show_bug.cgi?id=42627
+
+ * Scripts/webkitpy/layout_tests/port/http_server_base.py:
+
+2010-07-20 Tony Chang <tony@chromium.org>
+
+ Reviewed by David Levin.
+
+ [chromium] only pass --force to gclient sync if explicitly stated
+ https://bugs.webkit.org/show_bug.cgi?id=42581
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: bots should
+ always pass --force since it's hard to do manual cleanups
+ * Scripts/update-webkit-chromium: only pass --force if --force is
+ passed in
+
+2010-07-19 Anders Carlsson <andersca@apple.com>
+
+ Fix build.
+
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+ Paths of generated files should be relative to the build product.
+
+2010-07-19 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Adam Roben.
+
+ [Win] Implement LayoutTestController::markerTextForListItem()
+ https://bugs.webkit.org/show_bug.cgi?id=37930
+
+ Implements DRT support for markerTextForListItem in the Windows port.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::markerTextForListItem): Implemented.
+
+2010-07-19 Jessie Berlin <jberlin@apple.com>
+
+ Windows build fix. Unreviewed.
+
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::initializeTestPluginPath):
+
+2010-07-19 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Jon Honeycutt.
+
+ Remove dependency on getopt from WebKitTestRunner.
+
+ - Simplify options parsing and eliminate unused options.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::TestController):
+ (WTR::TestController::initialize):
+ * WebKitTestRunner/TestController.h:
+ (WTR::TestController::testPluginPath):
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+ * WebKitTestRunner/mac/TestControllerMac.mm:
+ (WTR::TestController::platformInitialize):
+ (WTR::TestController::initializeTestPluginPath):
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::platformInitialize):
+ (WTR::TestController::initializeTestPluginPath):
+
+2010-07-19 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] MiniBrowser: Progress indication at address bar
+ https://bugs.webkit.org/show_bug.cgi?id=42565
+
+ Make possible to see load progress at address bar based on
+ QtTestBrowser solution
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::loadProgress):
+ * MiniBrowser/qt/BrowserWindow.h:
+
+2010-07-19 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] Add MiniBrowser features: urlChanged, titleChanged and from user input load
+ https://bugs.webkit.org/show_bug.cgi?id=42564
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserView::load):
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::titleChanged):
+ (BrowserWindow::urlChanged):
+ * MiniBrowser/qt/BrowserWindow.h:
+
+2010-07-19 Sam Weinig <weinig@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=42532
+ Auto-generate the JS bindings for WebKitTestRunner's script objects.
+
+ * WebKitTestRunner/Configurations/Base.xcconfig:
+ * WebKitTestRunner/Configurations/DebugRelease.xcconfig:
+ * WebKitTestRunner/DerivedSources.make: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/GetPtr.h: Added.
+ * WebKitTestRunner/InjectedBundle/Bindings: Added.
+ * WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm: Added.
+ * WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h: Added.
+ (WTR::JSWrappable::~JSWrappable):
+ * WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp: Added.
+ (WTR::JSWrapper::wrap):
+ (WTR::JSWrapper::unwrap):
+ (WTR::unwrapObject):
+ (WTR::JSWrapper::initialize):
+ (WTR::JSWrapper::finalize):
+ * WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h: Added.
+ (WTR::toJS):
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: Added.
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::dump):
+ (WTR::InjectedBundlePage::setStatusbarText):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::wrapperClass):
+ (WTR::LayoutTestController::waitUntilDone):
+ (WTR::LayoutTestController::makeWindowObject):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ (WTR::LayoutTestController::shouldDumpAsText):
+ (WTR::LayoutTestController::dumpAsText):
+ (WTR::LayoutTestController::shouldDumpStatusCallbacks):
+ (WTR::LayoutTestController::dumpStatusCallbacks):
+ (WTR::LayoutTestController::waitToDump):
+ (WTR::LayoutTestController::testRepaint):
+ (WTR::LayoutTestController::repaintSweepHorizontally):
+ * WebKitTestRunner/InjectedBundle/win/InjectedBundle.vcproj:
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+ * WebKitTestRunner/win/InjectedBundleGenerated.vcproj: Added.
+ * WebKitTestRunner/win/build-generated-files.sh: Added.
+
+2010-07-19 Mark Rowe <mrowe@apple.com>
+
+ Clean up the buildbot configuration a little.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2010-07-19 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=42118
+ Disable WebGL on Leopard for now.
+
+ LayoutTests fail on some graphics hardware on Leopard because one of the features we use,
+ GL_ARB_framebuffer_object, is not universally available in Leopard like it is in
+ SnowLeopard. This will allow LayoutTests to pass on Leopard until we add logic to use a
+ software OpenGL driver on machines without this support.
+
+ * Scripts/build-webkit:
+
+2010-07-19 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Brady Eidson.
+
+ Fix MiniBrowser to update URL as you browse
+ https://bugs.webkit.org/show_bug.cgi?id=42591
+
+ Hook up various loading notifications to update the URL bar in MiniBrowser.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (_didStartProvisionalLoadForFrame):
+ (_didReceiveServerRedirectForProvisionalLoadForFrame):
+ (_didFailProvisionalLoadWithErrorForFrame):
+ (_didCommitLoadForFrame):
+ (_didFailLoadWithErrorForFrame):
+ (-[BrowserWindowController updateProvisionalURLForFrame:]):
+ (-[BrowserWindowController didStartProvisionalLoadForFrame:]):
+ (-[BrowserWindowController didReceiveServerRedirectForProvisionalLoadForFrame:]):
+ (-[BrowserWindowController didFailProvisionalLoadWithErrorForFrame:]):
+ (-[BrowserWindowController didFailLoadWithErrorForFrame:]):
+ (-[BrowserWindowController didCommitLoadForFrame:]):
+
+2010-07-19 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=42586
+ Log all canceled authentication attempts in DumpRenderTree
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:resource:didReceiveAuthenticationChallenge:fromDataSource:]):
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::didReceiveAuthenticationChallenge):
+ It's important to know whether an auth sheet appeared. Added logging to "no preset credentials"
+ case.
+
+2010-07-19 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r63671.
+ http://trac.webkit.org/changeset/63671
+ https://bugs.webkit.org/show_bug.cgi?id=42575
+
+ broke windows (Requested by weinig on #webkit).
+
+ * WebKitTestRunner/Configurations/Base.xcconfig:
+ * WebKitTestRunner/Configurations/DebugRelease.xcconfig:
+ * WebKitTestRunner/DerivedSources.make: Removed.
+ * WebKitTestRunner/ForwardingHeaders/wtf/GetPtr.h: Removed.
+ * WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm: Removed.
+ * WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h: Removed.
+ * WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp: Removed.
+ * WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h: Removed.
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: Removed.
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::dump):
+ (WTR::InjectedBundlePage::setStatusbarText):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::setWaitToDump):
+ (WTR::displayCallback):
+ (WTR::dumpAsTextCallback):
+ (WTR::dumpStatusCallbacksCallback):
+ (WTR::waitUntilDoneCallback):
+ (WTR::notifyDoneCallback):
+ (WTR::numberOfActiveAnimationsCallback):
+ (WTR::pauseAnimationAtTimeOnElementWithIdCallback):
+ (WTR::repaintSweepHorizontallyCallback):
+ (WTR::testRepaintCallback):
+ (WTR::layoutTestControllerObjectFinalize):
+ (WTR::LayoutTestController::makeWindowObject):
+ (WTR::LayoutTestController::getJSClass):
+ (WTR::LayoutTestController::staticFunctions):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ (WTR::LayoutTestController::dumpAsText):
+ (WTR::LayoutTestController::setDumpAsText):
+ (WTR::LayoutTestController::dumpStatusCallbacks):
+ (WTR::LayoutTestController::setDumpStatusCallbacks):
+ (WTR::LayoutTestController::setTestRepaint):
+ (WTR::LayoutTestController::setTestRepaintSweepHorizontally):
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+
+2010-07-19 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=42532
+ Auto-generate the JS bindings for WebKitTestRunner's script objects.
+
+ * WebKitTestRunner/Configurations/Base.xcconfig:
+ * WebKitTestRunner/Configurations/DebugRelease.xcconfig:
+ * WebKitTestRunner/DerivedSources.make: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/GetPtr.h: Added.
+ * WebKitTestRunner/InjectedBundle/Bindings: Added.
+ * WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm: Added.
+ * WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h: Added.
+ (WTR::JSWrappable::~JSWrappable):
+ * WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp: Added.
+ (WTR::JSWrapper::wrap):
+ (WTR::JSWrapper::unwrap):
+ (WTR::unwrapObject):
+ (WTR::JSWrapper::initialize):
+ (WTR::JSWrapper::finalize):
+ * WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h: Added.
+ (WTR::toJS):
+ * WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl: Added.
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::dump):
+ (WTR::InjectedBundlePage::setStatusbarText):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::wrapperClass):
+ (WTR::LayoutTestController::waitUntilDone):
+ (WTR::LayoutTestController::makeWindowObject):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ (WTR::LayoutTestController::shouldDumpAsText):
+ (WTR::LayoutTestController::dumpAsText):
+ (WTR::LayoutTestController::shouldDumpStatusCallbacks):
+ (WTR::LayoutTestController::dumpStatusCallbacks):
+ (WTR::LayoutTestController::waitToDump):
+ (WTR::LayoutTestController::testRepaint):
+ (WTR::LayoutTestController::repaintSweepHorizontally):
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+
+2010-07-19 Tony Chang <tony@chromium.org>
+
+ Reviewed by David Levin.
+
+ fix chromium linux compile on ubuntu maverick
+ https://bugs.webkit.org/show_bug.cgi?id=42528
+
+ * Scripts/webkitdirs.pm: add a chomp to eat a newline that breaks the make command line
+
+2010-07-19 Adam Roben <aroben@apple.com>
+
+ When dumping a response's MIME type, print its URL's last path
+ component rather than its suitable-for-test-result form
+
+ This matches the Mac behavior.
+
+ Fixes <http://webkit.org/b/42276>
+ http/tests/loading/preload-slow-loading.php and
+ http/tests/mime/uppercase-mime-type.html fail on Windows
+
+ Reviewed by Anders Carlsson.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (urlSuitableForTestResult): Moved code to actually extract the last
+ path component from here...
+ (lastPathComponent): ...to here.
+
+ * DumpRenderTree/win/DumpRenderTreeWin.h: Added lastPathComponent.
+
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::didReceiveResponse): Use the URL's last path
+ component, rather than its suitable-for-test-result form, to match
+ Mac.
+
+2010-07-19 Anders carlsson <andersca@apple.com>
+
+ Reviewed by Adam Roben.
+
+ WebKit2 does not have application cache
+ https://bugs.webkit.org/show_bug.cgi?id=42552
+
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::resetPreferencesToConsistentValues):
+ Set up default preferences. Right now just enables the web application cache.
+
+ (WTR::TestInvocation::invoke):
+ Call resetPreferencesToConsistentValues.
+
+ * WebKitTestRunner/TestInvocation.h:
+
+2010-07-19 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Adam Roben.
+
+ Fix NewRunWebKitTests to work on Windows.
+ https://bugs.webkit.org/show_bug.cgi?id=41180
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+ Specifying python explicitly.
+
+2010-07-18 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Add dumping of statusbar text to WebKitTestRunner
+ https://bugs.webkit.org/show_bug.cgi?id=42516
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::_setStatusbarText):
+ (WTR::InjectedBundlePage::setStatusbarText):
+ Dump the statusbar text.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::LayoutTestController):
+ Initialize m_dumpStatusCallbacks to false.
+
+ (WTR::dumpStatusCallbacksCallback):
+ Implement JSC callback.
+
+ (WTR::LayoutTestController::staticFunctions):
+ Add dumpStatusCallbacks.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ (WTR::LayoutTestController::dumpStatusCallbacks):
+ (WTR::LayoutTestController::setDumpStatusCallbacks):
+ Add setter and getter for m_dumpStatusCallbacks.
+
+2010-07-17 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize):
+ Get the test plug-in path and set it on the context.
+
+ * WebKitTestRunner/TestController.h:
+ * WebKitTestRunner/mac/TestControllerMac.mm:
+ (WTR::TestController::initializeInjectedBundlePath):
+ Simplify this code by using NSBundle.
+
+ (WTR::TestController::testPluginPath):
+ Return the test plug-in path.
+
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::testPluginPath):
+ Ditto.
+
+2010-07-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Teach webkitpy about queues.webkit.org
+ https://bugs.webkit.org/show_bug.cgi?id=42492
+
+ * Scripts/webkitpy/common/net/statusserver.py:
+
+2010-07-16 Ada Chan <adachan@apple.com>
+
+ Reviewed by Alice Liu.
+
+ Fix Windows build.
+
+ * WebKitTestRunner/InjectedBundle/win/InjectedBundle.vcproj:
+
+2010-07-16 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=42482
+ <rdar://problem/8197701>
+ Add notification of when the BackForwardList changes
+ to aid invalidation of Back/Forward related UI elements.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (_didStartProvisionalLoadForFrame):
+ (_didCommitLoadForFrame):
+ (_didFailLoadWithErrorForFrame):
+ (_didChangeBackForwardList):
+ (-[BrowserWindowController awakeFromNib]):
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+
+2010-07-16 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ [Chromium] <input type=number> UI implementation for Windows
+ https://bugs.webkit.org/show_bug.cgi?id=42259
+
+ * DumpRenderTree/chromium/WebThemeEngineDRT.cpp:
+ (WebThemeEngineDRT::paintSpinButton):
+ Added. Check state consistency and use existing arrow painting code.
+ * DumpRenderTree/chromium/WebThemeEngineDRT.h:
+
+2010-07-16 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=42430
+ Make WebKitTestRunner on Windows actually load and run a test
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp: Export WKBundleInitialize.
+ (WKBundleInitialize):
+ * WebKitTestRunner/InjectedBundle/win/InjectedBundle.vcproj: Added. Output is a dll.
+ * WebKitTestRunner/TestInvocation.cpp: Create a Windows-style path on Windows
+ (WTR::createWKURL):
+ * WebKitTestRunner/WebKitTestRunnerPrefix.h: Change check for Windows platform to match
+ other existing checks, and avoid including Platform.h
+ * WebKitTestRunner/win/PlatformWebViewWin.cpp:
+ (WTR::registerWindowClass): Added.
+ (WTR::PlatformWebView::PlatformWebView): Implemented.
+ (WTR::PlatformWebView::~PlatformWebView): Implemented.
+ (WTR::PlatformWebView::page): Implemented.
+ * WebKitTestRunner/win/TestControllerWin.cpp:
+ (WTR::TestController::initializeInjectedBundlePath): Implemented. Provide build
+ configuration specific path to InjectedBundle.dll.
+ * WebKitTestRunner/win/TestInvocationWin.cpp:
+ (WTR::TestInvocation::runUntil): Implemented.
+ * WebKitTestRunner/win/WebKitTestRunner.sln: Added InjectedBundle project.
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj: Cleaned up unnecessary dependencies.
+
+2010-07-16 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Make revalidation of back/forward work a little better with page loads
+ https://bugs.webkit.org/show_bug.cgi?id=42470
+
+ * MiniBrowser/mac/BrowserWindow.xib:
+ * MiniBrowser/mac/BrowserWindowController.h:
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController validateToolbar]):
+ (_didStartProvisionalLoadForFrame):
+ (_didCommitLoadForFrame):
+ (_didFailLoadWithErrorForFrame):
+
+2010-07-16 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Reviewed by Dirk Schulze.
+
+ Add possibility to dumpAsText and generate a pixel test result
+ https://bugs.webkit.org/show_bug.cgi?id=42374
+
+ Add optional parameter to setDumpAsText() to allow generating a pixel test result even if dumpAsText mode.
+ setDumpAsText(true) will also generate a pixel test result now, when running run-webkit-tests --pixel-tests.
+
+ This is needed for the svg/dynamic-updates tests, which don't want render tree dumps but text dumps + a pixel test result.
+ At some point DRT changed to not generate pixel test results when using dumpAsText - which makes sense, but breaks the svg/dynamic-updates test.
+
+ Implemented for all DRT platforms, except Qt, as it's not clear how arguments to functions like "setDumpAsText" are handled.
+ (Qt always dumps pixel tests when using --pixel-tests mode, so it does not break anything)
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (dumpAsTextAndPixelsCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::dumpAsTextAndPixels):
+ (LayoutTestController::setDumpAsTextAndPixels):
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::dumpAsTextAndPixels):
+ (LayoutTestController::reset):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ (LayoutTestController::shouldDumpAsTextAndPixels):
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::dump):
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dump):
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dump):
+ * DumpRenderTree/wx/DumpRenderTreeWx.cpp:
+ (dump):
+
+2010-07-16 Kent Hansen <kent.hansen@nokia.com>
+
+ Unreviewed. Adding myself as committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-07-16 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Another uneviewed attempt to fix build.
+
+ Printing test results differ between machines, we should use ImageDiff instead
+ https://bugs.webkit.org/show_bug.cgi?id=20011
+
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (createPagedBitmapContext):
+
+2010-07-16 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Unreviewed tiger build fix.
+
+ Printing test results differ between machines, we should use ImageDiff instead
+ https://bugs.webkit.org/show_bug.cgi?id=20011
+
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (createBitmapContext):
+ (createBitmapContextFromWebView):
+
+2010-07-15 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Unreviewed build fix.
+
+ Printing test results differ between machines, we should use ImageDiff instead
+ https://bugs.webkit.org/show_bug.cgi?id=20011
+
+ * DumpRenderTree/PixelDumpSupport.cpp:
+ (dumpWebViewAsPixelsAndCompareWithExpected):
+
+2010-07-15 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Printing test results differ between machines, we should use ImageDiff instead
+ https://bugs.webkit.org/show_bug.cgi?id=20011
+
+ * DumpRenderTree/PixelDumpSupport.cpp:
+ (dumpWebViewAsPixelsAndCompareWithExpected):
+ * DumpRenderTree/PixelDumpSupport.h:
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (createBitmapContext): This function was added to share bitmap context creation code.
+ (createBitmapContextFromWebView):
+ (createPagedBitmapContext):
+
+2010-07-15 Yuta Kitamura <yutak@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ Pull in pywebsocket-0.5.1
+ https://bugs.webkit.org/show_bug.cgi?id=42353
+
+ pywebsocket-0.5.1 contains a small bug fix (*) that should fix a worker test
+ in Chromium. There is no other functional change.
+
+ (*) http://code.google.com/p/pywebsocket/source/detail?r=265
+
+ * Scripts/webkitpy/thirdparty/__init__.py: Bump pywebsocket version to 0.5.1.
+
+2010-07-15 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Add toolbar and toolbar item validation for MiniBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=42422
+
+ * MiniBrowser/MBToolbarItem.h: Added.
+ * MiniBrowser/MBToolbarItem.m: Added.
+ (-[MBToolbarItem validate]):
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController validateUserInterfaceItem:]):
+
+ * MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj:
+ * MiniBrowser/mac/BrowserWindow.xib:
+
+2010-07-15 Victor Wang <victorw@chromium.org>
+
+ Unreviewed, add victorw irc nickname to committer list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-07-15 Adam Roben <aroben@apple.com>
+
+ Make killing Apache more reliable (on both Mac and Windows)
+
+ We previously had two ways of determining whether we had succeeded in
+ killing Apache:
+ 1) checking the return value of kill(0, $apachePID)
+ 2) checking whether Apache's PID file still exists
+
+ On Cygwin, Apache doesn't always delete its PID file when it exits,
+ making (2) unreliable. We unfortunately misdiagnosed this as an
+ impotency of Perl's kill function, which led to r63177 and r63355.
+
+ Now that we know that the real problem is that Apache doesn't always
+ delete its PID file on Windows, we can make a much better fix: always
+ use method (1) to determine whether we've killed Apache.
+
+ Fixes <http://webkit.org/b/42415> Killing Apache is unreliable,
+ leading to regression test failures (and general annoyance).
+
+ Reviewed by Anders Carlsson.
+
+ * Scripts/webkitperl/httpd.pm:
+ (openHTTPD): Moved killing code from here to killHTTPD. Added a call
+ to delete the PID file in case Apache doesn't do this itself when
+ killed. Our later logic relies on the PID file being deleted after
+ this point.
+ (closeHTTPD): Removed killing logic and changed to just call killHTTPD
+ instead. killHTTPD's logic is a bit different from the logic we had
+ here, for the reasons stated above.
+ (killHTTPD): Added. Code came from openHTTPD.
+ (handleInterrupt): Bonus fix for Mac: don't hang when pressing Ctrl-C!
+ On Mac, don't try to kill Apache when we receive a signal, as Apache
+ will already have been killed by this point (though for some reason
+ this isn't detected by our killing logic in killHTTPD). On Cygwin, we
+ still need to kill Apache manually.
+
+2010-07-15 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=42399
+ Update MiniBrowser for WKFrameNavigationType
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (_decidePolicyForNavigationAction):
+ (_decidePolicyForNewWindowAction):
+
+2010-07-15 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ http://bugs.webkit.org/show_bug.cgi?id=42406
+ Make SunSpider work better with roots.
+
+ * Scripts/sunspider-compare-results: fix argument bug
+ * Scripts/webkitdirs.pm: look inside JavaScriptCore if jsc isn't top-level.
+
+2010-07-15 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Hook up back/forward in MiniBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=42397
+
+ * MiniBrowser/mac/BrowserWindow.xib:
+ * MiniBrowser/mac/BrowserWindowController.h:
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController goBack:]):
+ (-[BrowserWindowController goForward:]):
+
+2010-07-15 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Darin Adler.
+
+ [Mac] Implement LayoutTestController::markerTextForListItem()
+ https://bugs.webkit.org/show_bug.cgi?id=37929
+
+ Implements DRT support for markerTextForListItem in the Mac port.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::markerTextForListItem): Implemented.
+
+2010-07-15 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Update the port names to be more specific. Before this patch,
+ port-specific results for Mac would end up in the wrong place.
+
+ * Scripts/webkitpy/tool/commands/rebaseline.py:
+ * Scripts/webkitpy/tool/commands/rebaseline_unittest.py:
+
+2010-07-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ WebKit needs a rebaselining tool (finally)
+ https://bugs.webkit.org/show_bug.cgi?id=42339
+
+ This is a very basic rebaselining tool. It's not
+ quite as fancy as chromium's as it will only handle
+ updating failing results. It cannot yet handle adding new
+ results, or updating results where the results should not
+ replace existing results.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/tool/commands/__init__.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/rebaseline.py: Added.
+ * Scripts/webkitpy/tool/commands/rebaseline_unittest.py: Added.
+
+2010-07-14 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r63352.
+ http://trac.webkit.org/changeset/63352
+ https://bugs.webkit.org/show_bug.cgi?id=42341
+
+ Broke plugin-initiate-popup-window.html and plugin-javascript-
+ access.html on snow leopard (Requested by abarth on #webkit).
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+ (handleEventCarbon):
+ (handleEventCocoa):
+
+2010-07-14 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Lower WebKitTestRunner notifyDone timeout to 6.0 for now, to make it easier to grind through the failures.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+
+2010-07-14 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r63346.
+ http://trac.webkit.org/changeset/63346
+ https://bugs.webkit.org/show_bug.cgi?id=42295
+
+ Broke lots of tests, some of which probably just need new
+ results (Requested by aroben on #webkit).
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (urlSuitableForTestResult):
+
+2010-07-14 Adam Roben <aroben@apple.com>
+
+ Speed up killing of Apache on Windows
+
+ Fixes <http://webkit.org/b/42289> Killing Apache (and thus quitting
+ run-webkit-tests) takes a long time on Windows
+
+ Reviewed by Darin Adler and Jon Honeycutt.
+
+ * Scripts/webkitperl/httpd.pm:
+ (closeHTTPD): Use taskkill to kill Apache and its child processes.
+ Perl's kill seems ineffectual. We were already using taskkill, but
+ only after trying kill 20 times. Since kill never works, let's just
+ skip it entirely.
+
+2010-07-14 Johnny Ding <jnd@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ https://bugs.webkit.org/show_bug.cgi?id=41292
+ Add a new parameter to the test plugin to allow to specify a script and a
+ mouse/keyboard event. The specified script will be evaluated in the browser
+ when the specified event is received by the plugin.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+ (handleEventCarbon):
+ (handleEventCocoa):
+
+2010-07-14 Adam Roben <aroben@apple.com>
+
+ Make urlSuitableForTestResult work for http: URLs, too
+
+ Fixes <http://webkit.org/b/42276>
+ http/tests/loading/preload-slow-loading.php and
+ http/tests/mime/uppercase-mime-type.html fail on Windows.
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (urlSuitableForTestResult): Don't bail if the URL starts with http://.
+ We want this function to work for those URLs, too!
+
+2010-07-13 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Add placebo versions of some repaint test functions to WebKitTestRunner - good enough for non-pixel tests
+ https://bugs.webkit.org/show_bug.cgi?id=42227
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::LayoutTestController): Initialize new bool
+ members.
+ (WTR::LayoutTestController::display): Dummy method.
+ (WTR::displayCallback): Call the dummy.
+ (WTR::repaintSweepHorizontallyCallback): ditto
+ (WTR::testRepaintCallback): ditto
+ (WTR::LayoutTestController::staticFunctions): Expose new methods.
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ (WTR::LayoutTestController::setTestRepaint): Set the flag (which currently does
+ nothing).
+ (WTR::LayoutTestController::setTestRepaintSweepHorizontally): ditto
+
+2010-07-13 Andreas Kling <andreas.kling@nokia.com>
+
+ Unreviewed. Adding myself as committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-07-07 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Darin Adler.
+
+ Prevent assertion/duplicate loads for non-deferred subtitute-data loads
+
+ https://bugs.webkit.org/show_bug.cgi?id=30879
+
+ MainResourceLoader uses the member m_initialRequest to store requests for future
+ deferred loads. When doing the actual load in handleDataLoadNow(), we therefore
+ have to clear this request so that subsequent entries into the loader will not
+ start yet another load.
+
+ This can happen as a result of a PageGroupLoadDeferrer going out of scope when
+ returning from Chrome::runJavaScriptAlert(), which calls setDeferredLoading(false),
+ but only in the case of using both substitute-data and non-deferred main resource
+ load together. That's why two new DRT functions were added:
+
+ * queueLoadHTMLString()
+ * setDeferMainResourceLoad()
+
+ The change adds DRT hooks for Mac, Win and Qt for these two functions. For Mac
+ and Win the hook uses new SPI in WebDataSource. For Qt a new static member was
+ added to the FrameLoaderClientQt and accessed though DumpRenderTreeSupportQt.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (queueLoadHTMLStringCallback):
+ (setDeferMainResourceDataLoadCallback):
+ (LayoutTestController::staticFunctions):
+ (LayoutTestController::queueLoadHTMLString):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::deferMainResourceDataLoad):
+ (LayoutTestController::setDeferMainResourceDataLoad):
+ * DumpRenderTree/WorkQueueItem.h:
+ (LoadHTMLStringItem::LoadHTMLStringItem):
+ * DumpRenderTree/gtk/WorkQueueItemGtk.cpp:
+ (LoadHTMLStringItem::invoke):
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:resource:willSendRequest:redirectResponse:fromDataSource:]):
+ * DumpRenderTree/mac/WorkQueueItemMac.mm:
+ (LoadHTMLStringItem::invoke):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::setDeferMainResourceDataLoad):
+ (LayoutTestController::queueLoadHTMLString):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/qt/WorkQueueItemQt.cpp:
+ (LoadHTMLStringItem::invoke):
+ * DumpRenderTree/qt/WorkQueueItemQt.h:
+ (LoadHTMLStringItem::LoadHTMLStringItem):
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::willSendRequest):
+ * DumpRenderTree/win/WorkQueueItemWin.cpp:
+ (LoadHTMLStringItem::invoke):
+ * DumpRenderTree/wx/WorkQueueItemWx.cpp:
+ (LoadHTMLStringItem::invoke):
+
+2010-07-13 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Nikolas Zimmermann.
+
+ Activate test fonts for layout tests in WebKitTestRunner (on Mac)
+ https://bugs.webkit.org/show_bug.cgi?id=42153
+
+ * WebKitTestRunner/InjectedBundle/ActivateFonts.h: Added.
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::initialize): Activate fonts on startup.
+ * WebKitTestRunner/InjectedBundle/mac: Added.
+ * WebKitTestRunner/InjectedBundle/mac/ActivateFonts.mm: Added.
+ (WTR::activateFonts): Activate our fonts.
+ * WebKitTestRunner/InjectedBundle/win: Added.
+ * WebKitTestRunner/InjectedBundle/win/ActivateFonts.cpp: Added.
+ (WTR::activateFonts): Dummy version.
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj: Copy fonts to bundle;
+ add more files.
+ * WebKitTestRunner/fonts: Added.
+ * WebKitTestRunner/fonts/AHEM____.TTF: Added.
+ * WebKitTestRunner/fonts/ColorBits-A.png: Added.
+ * WebKitTestRunner/fonts/ColorBits.ttf: Added.
+ * WebKitTestRunner/fonts/WebKit Layout Tests 2.ttf: Added.
+ * WebKitTestRunner/fonts/WebKit Layout Tests.ttf: Added.
+ * WebKitTestRunner/fonts/WebKitWeightWatcher100.ttf: Added.
+ * WebKitTestRunner/fonts/WebKitWeightWatcher200.ttf: Added.
+ * WebKitTestRunner/fonts/WebKitWeightWatcher300.ttf: Added.
+ * WebKitTestRunner/fonts/WebKitWeightWatcher400.ttf: Added.
+ * WebKitTestRunner/fonts/WebKitWeightWatcher500.ttf: Added.
+ * WebKitTestRunner/fonts/WebKitWeightWatcher600.ttf: Added.
+ * WebKitTestRunner/fonts/WebKitWeightWatcher700.ttf: Added.
+ * WebKitTestRunner/fonts/WebKitWeightWatcher800.ttf: Added.
+ * WebKitTestRunner/fonts/WebKitWeightWatcher900.ttf: Added.
+
+2010-07-13 Dumitru Daniliuc <dumi@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Remove check-header-includes, as it didn't turn out to be very useful.
+ https://bugs.webkit.org/show_bug.cgi?id=41970
+
+ * Scripts/check-header-includes: Removed.
+
+2010-07-12 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Make WebKit2 be built by build-webkit (so it will be built by build.webkit.org bots)
+ https://bugs.webkit.org/show_bug.cgi?id=40922
+
+ Always build WebKit2 on Windows. Necessary since our WebKit build on
+ Windows is packaged into a DLL with WebKit2.
+
+ * Scripts/build-webkit: Always build WebKit2 on Windows.
+
+2010-07-12 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Steve Falkenburg.
+
+ One http test timing out on Windows can cause all future tests to time out
+ https://bugs.webkit.org/show_bug.cgi?id=42146
+
+ There have been multiple times on the Windows bots where one http test timing out causes all future
+ http tests to time out. This is because the httpd process becomes unresponsive. When an http test
+ times out, we should restart httpd on Cygwin to prevent this.
+
+ * Scripts/old-run-webkit-tests: If an http test timed out on Cygwin, close httpd and restart it.
+ * Scripts/webkitperl/httpd.pm: Add additional logic to closeHTTPD to teach it about taskkill if
+ using kill fails.
+
+2010-07-12 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Remove use of auto_ptr in WebKitTestRunner
+ https://bugs.webkit.org/show_bug.cgi?id=42134
+
+ Replaced auto_ptr with PassOwnPtr / OwnPtr.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::WKStringToUTF8):
+ (WTR::InjectedBundlePage::dump):
+ (WTR::InjectedBundlePage::addMessageToConsole):
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::WKStringToUTF8):
+ (WTR::TestInvocation::didRecieveMessageFromInjectedBundle):
+
+2010-07-12 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Need support for a WebKit2-specific Skipped list (and initially add accessibility tests to it)
+ https://bugs.webkit.org/show_bug.cgi?id=42132
+
+ * Scripts/old-run-webkit-tests: In --webkit-test-runner mode, add mac-wk2 to list of
+ platform directories.
+
+2010-07-12 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Anders Carlsson.
+
+ Make WebKitTestRunner resize the view specially for the W3C SVG tests.
+ https://bugs.webkit.org/show_bug.cgi?id=42126
+
+ * WebKitTestRunner/PlatformWebView.h:
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::TestInvocation): Store the path as a C
+ string for later use.
+ (WTR::TestInvocation::~TestInvocation):
+ (WTR::sizeWebViewForCurrentTest): Resize the WebView to the proper
+ size, depending on whether this is a W3C SVG test.
+ (WTR::TestInvocation::invoke): Call the size function.
+ * WebKitTestRunner/TestInvocation.h:
+ * WebKitTestRunner/mac/PlatformWebViewMac.mm:
+ (WTR::PlatformWebView::resizeTo): Implement.
+ * WebKitTestRunner/win/PlatformWebViewWin.cpp:
+ (WTR::PlatformWebView::resizeTo): Placeholder.
+
+2010-07-12 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ Ensure DRT loads GAIL (Gtk+ module), for a11y tests
+ https://bugs.webkit.org/show_bug.cgi?id=38648
+
+ Add the GTK_MODULES envvar (set to "gail") to the clean
+ environment when running DRT for the Gtk+ port
+
+ * Scripts/old-run-webkit-tests:
+
+2010-07-12 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Dirk Schulze.
+
+ [GTK] Support pixel tests
+ https://bugs.webkit.org/show_bug.cgi?id=31518
+
+ Finish support for pixel tests on GTK+.
+
+ * DumpRenderTree/PixelDumpSupport.cpp: Remove unecessary RetainPtr include (only
+ works on CoreFoundation systems) and add missing cstdio include.
+ * DumpRenderTree/cairo/PixelDumpSupportCairo.cpp: Switch to using the MD5 support found
+ in JSC library. MD5.cpp and MD5.h are only available for the Windows build.
+ (computeMD5HashStringForBitmapContext): The number of bytes per row should be the row stride
+ of the image, not the row stride multiplied by the width. Use JSC MD5 implementation to calculate
+ the MD5 hash here. According to glibc manpages, using snprintf to build a string in unsupported
+ by the ANSI standard and this fails on Linux, so unroll the loop here.
+ * DumpRenderTree/cairo/PixelDumpSupportCairo.h: Correct some constructor misbehavior.
+ (BitmapContext::BitmapContext): There is no reason to check the value of the
+ m_context member in the constructor and it certainly should not be freed. Instead
+ just initialize it with the incoming value.
+ * DumpRenderTree/gtk/DumpRenderTree.cpp: Fix the order of includes.
+ (dump): Actually call dumpWebViewAsPixelsAndCompareWithExpected when it is time to
+ dump pixels.
+ * DumpRenderTree/gtk/PixelDumpSupportGtk.cpp: Added.
+ (createBitmapContextFromWebView):
+ * GNUmakefile.am: Add new files to the build.
+
+2010-07-12 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Remove stray "raise e" that got included in a previous patch. This
+ caused the EWS bots to turn red instead of purple when a patch failed
+ to apply.
+
+ * Scripts/webkitpy/tool/commands/stepsequence.py:
+
+2010-07-12 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r63101.
+ http://trac.webkit.org/changeset/63101
+ https://bugs.webkit.org/show_bug.cgi?id=42103
+
+ Broke one API test (Requested by xan_ on #webkit).
+
+ * Scripts/old-run-webkit-tests:
+
+2010-07-12 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Adam Roben.
+
+ https://bugs.webkit.org/show_bug.cgi?id=13075
+ XMLHttpRequest with failed authentication should set status to 401
+
+ https://bugs.webkit.org/show_bug.cgi?id=6871
+ <rdar://problem/3363403> 401 error page is never shown
+
+ Fix crashes in Windows DumpRenderTree.
+
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp: (ResourceLoadDelegate::didReceiveAuthenticationChallenge):
+ If we return an error, WebKit will call continueWithoutCredentialForAuthenticationChallenge()
+ again on a destroyed sender.
+
+2010-07-12 Adam Roben <aroben@apple.com>
+
+ Windows failure-to-launch fix
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Copy CoreVideo.dll and
+ CoreVideo.pdb into WebKitOutputDir in the post-build event, too, like
+ we already do for CoreFoundation, CFNetwork, etc.
+
+2010-07-12 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ Ensure DRT loads GAIL (Gtk+ module), for a11y tests
+ https://bugs.webkit.org/show_bug.cgi?id=38648
+
+ Add the GTK_MODULES envvar (set to "gail") to the clean
+ environment when running DRT for the Gtk+ port
+
+ * Scripts/old-run-webkit-tests:
+
+2010-07-09 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=13075
+ XMLHttpRequest with failed authentication should set status to 401
+
+ https://bugs.webkit.org/show_bug.cgi?id=6871
+ <rdar://problem/3363403> 401 error page is never shown
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:resource:didReceiveAuthenticationChallenge:fromDataSource:]):
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::didReceiveAuthenticationChallenge):
+ Do respond even if handlesAuthenticationChallenges() is false. Pretend that the user pressed
+ the Cancel button.
+
+2010-07-12 Andreas Kling <andreas.kling@nokia.com>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [Qt] Add location bar (Ctrl+L) shortcut in QtTestBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=42082
+
+ * QtTestBrowser/main.cpp:
+ (LauncherWindow::createChrome):
+ * QtTestBrowser/mainwindow.cpp:
+ (MainWindow::openLocation):
+ * QtTestBrowser/mainwindow.h:
+
+2010-07-12 Adam Roben <aroben@apple.com>
+
+ Make the Python autoinstaller not use a dead SourceForge server
+
+ Fixes <http://webkit.org/b/42080> webkit-patch is broken due to
+ offline SourceForge server
+
+ Reviewed by Anders Carlsson.
+
+ * Scripts/webkitpy/thirdparty/__init__.py: Use
+ surfnet.dl.sourceforge.net instead of hivelocity.dl.sourceforge.net,
+ which seems to be down.
+
+2010-07-12 Adam Roben <aroben@apple.com>
+
+ Make run-webkit-tests print how many tests timed out when exiting
+ early
+
+ The number of timed-out tests is taken into account when deciding
+ whether to exit early. Leaving it out of the output just makes the
+ script look buggy (because it might say something like "Exiting early
+ after 0 crashes.").
+
+ Fixes <http://webkit.org/b/42077> run-webkit-tests prints confusing
+ messages when exiting early due to crashes and time-outs
+
+ Reviewed by Anders Carlsson.
+
+ * Scripts/old-run-webkit-tests:
+ (stopRunningTestsEarlyIfNeeded): When stopping, print the number of
+ timed-out tests, too.
+
+2010-07-11 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Implement animation-related methods for WebKitTestRunner
+ https://bugs.webkit.org/show_bug.cgi?id=42053
+
+ Implemented numberOfActiveAnimatiosn and pauseAnimationAtTimeOnElementWithId. Many
+ animation tests were hanging otherwise.
+
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::numberOfActiveAnimations):
+ (WTR::LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (WTR::numberOfActiveAnimationsCallback):
+ (WTR::pauseAnimationAtTimeOnElementWithIdCallback):
+ (WTR::LayoutTestController::staticFunctions):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+
+2010-07-11 Daniel Bates <dbates@rim.com>
+
+ Reviewed by David Kilzer.
+
+ Enable executable support for svn-apply and svn-unapply
+ https://bugs.webkit.org/show_bug.cgi?id=39409
+
+ Connect up the Git and SVN executable bit support in parseDiff() so that
+ executable bit changes are propagated via the returned diff hash to the
+ patch function in svn-apply and svn-unapply.
+
+ * Scripts/VCSUtils.pm:
+ - Modified parseDiff() to call parseSvnDiffProperties when
+ it finds the start of an SVN property change diff.
+ - Removed FIXME comment above parseSvnDiffProperties() since
+ it is now being used by parseDiff().
+ - Export method scmToggleExecutableBit() now that we added the
+ executableBitDelta hash key. (This should have been exported
+ when we added this function in Bug #38423 <https://bugs.webkit.org/show_bug.cgi?id=38423>).
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl:
+ - Updated results for:
+ "rename (with executable bit change)"
+ - Test value of executableBitDelta (now that we have support).
+ "SVN: binary file (isBinary true)"
+ - Remove the property change diff from svnConvertedText. We plan
+ to remove svnConvertedText in the future. So, we decided
+ against adding such support to any new code, such as the
+ property parsing routines. Therefore, we do not keep SVN
+ converted text for property change diffs.
+ - Added unit tests:
+ "SVN: file change diff with property change diff"
+ "SVN: file change diff, followed by property change diff on different file"
+ "SVN: property diff, followed by file change diff"
+ "SVN: copied file with property change"
+ "SVN: two consecutive property diffs"
+ "SVN: binary file with executable bit change"
+ "SVN: binary file followed by property change on different file"
+ "SVN: binary file followed by file change on different file"
+ "SVN: file change diff with property change, followed by property change diff"
+ "SVN: file change diff with property change, followed by file change diff"
+
+2010-07-11 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Implement waitUntilDone and notifyDone for WebKitTestRunner
+ https://bugs.webkit.org/show_bug.cgi?id=42049
+
+ With this fix, most of the DOM tests pass.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::didCreatePage): Track the main page. Not
+ a great way to do it in the future case where we may get multiple
+ pages - we really need a way to send it over from the ui process.
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h:
+ (WTR::InjectedBundle::page): A way to get the main page.
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage): Initialize m_isLoading to false.
+ (WTR::InjectedBundlePage::didStartProvisionalLoadForFrame): Track that we
+ are loading.
+ (WTR::InjectedBundlePage::dump): Factor into a method so this can be
+ called by the layout test controller. Also, cancel any pending watchdogs.
+ (WTR::InjectedBundlePage::didFinishLoadForFrame): Note that we are done loading.
+ (WTR::InjectedBundlePage::didFailLoadWithErrorForFrame): Ditto.
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+ (WTR::InjectedBundlePage::isLoading): A way to track if we are loading.
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp:
+ (WTR::LayoutTestController::LayoutTestController): Initialize m_waitToDump
+ to false.
+ (WTR::LayoutTestController::invalidateWaitToDumpWatchdog): Invalidate
+ the watchdog.
+ (WTR::waitUntilDoneWatchdogFired): Static helper for the watchdog timer.
+ (WTR::LayoutTestController::setWaitToDump): Set the flag.
+ (WTR::LayoutTestController::waitToDumpWatchdogTimerFired): Handle the case
+ where waitUntilDone times out.
+ (WTR::LayoutTestController::notifyDone): Dump, if loading is done.
+ (WTR::waitUntilDoneCallback): JS glue for waitUntilDone.
+ (WTR::notifyDoneCallback): JS glue for notifyDone.
+ (WTR::LayoutTestController::staticFunctions): Add waitUntilDone and notifyDone
+ to the layoutController.
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h:
+ (WTR::LayoutTestController::waitToDump): Inline method to get the wait state.
+
+2010-07-09 Brian Weinstein <bweinstein@apple.com>
+
+ Rubber-stamped by Dan Bernstein.
+
+ Windows testers running Windows 7 were hanging during test_kill_process. Changing the
+ number of attempts from 3 to 10 fixes the problem on the new bots (and doesn't seem to
+ slow down the tests).
+
+ * Scripts/webkitpy/common/system/executive.py:
+
+2010-07-09 Luiz Agostini <luiz.agostini@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Mac build fix
+ https://bugs.webkit.org/show_bug.cgi?id=41967
+
+ Adding file PluginObjectMac.mm and frameworks Cocoa and QuartzCore.
+
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+
+2010-07-09 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Antonio Gomes.
+
+ [Qt] [WebKit2] Add navigation actions to MiniBrowser toolbar
+ https://bugs.webkit.org/show_bug.cgi?id=41966
+
+ * MiniBrowser/qt/BrowserWindow.cpp:
+ (BrowserWindow::BrowserWindow):
+
+2010-07-09 Leon Clarke <leonclarke@google.com>
+
+ Reviewed by Adam Barth.
+
+ add support for link prefetching
+ https://bugs.webkit.org/show_bug.cgi?id=3652
+
+ * Scripts/build-webkit:
+
+2010-07-09 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ r63004 broke some python tests
+ https://bugs.webkit.org/show_bug.cgi?id=42007
+
+ AbstractStep now checks options.no_squash and options.squash, so
+ they needed to have real values. Mock would return an object for those,
+ which would then act as if the values were True.
+
+ * Scripts/webkitpy/tool/commands/commandtest.py:
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/commands/stepsequence.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/closebugforlanddiff_unittest.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog_unittest.py:
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittest.py:
+ * Scripts/webkitpy/tool/steps/validatereviewer_unittest.py:
+
+2010-07-09 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ --squash should go away and become the default
+ https://bugs.webkit.org/show_bug.cgi?id=39624
+
+ If there are local commits and working copy changes, then prompt the user
+ whether to continue. Setting git config webkit-patch.commit_should_always_squash
+ true bypasses the prompt.
+
+ --git-commit=HEAD.. operates on working copy changes only.
+ --git-commit=committish operates on a range of commits as a single commit.
+ e.g. --git-commit=HEAD only operates on the HEAD commit.
+ --git-commit=HEAD~4..HEAD~2 will operate on HEAD~3 and HEAD~2 as a single commit.
+
+ --no-squash and --squash are left in with descriptive error messages if used.
+
+ * Scripts/check-webkit-style:
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ * Scripts/webkitpy/common/net/rietveld.py:
+ * Scripts/webkitpy/common/system/user.py:
+ * Scripts/webkitpy/style/optparser.py:
+ * Scripts/webkitpy/style_references.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ * Scripts/webkitpy/tool/steps/applypatchwithlocalcommit.py:
+ * Scripts/webkitpy/tool/steps/checkstyle.py:
+ * Scripts/webkitpy/tool/steps/checkstyle_unittest.py: Removed.
+ * Scripts/webkitpy/tool/steps/commit.py:
+ * Scripts/webkitpy/tool/steps/options.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+ * Scripts/webkitpy/tool/steps/preparechangelogforrevert.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py:
+ * Scripts/webkitpy/tool/steps/validatereviewer.py:
+
+2010-07-09 Mark Rowe <mrowe@apple.com>
+
+ Add two new Windows test build slaves.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2010-07-09 Albert J. Wong <ajwong@chromium.org>
+
+ Reviewed by David Levin.
+
+ rebaseline_chromium_webkit_tests missing --use_drt option on linux
+ https://bugs.webkit.org/show_bug.cgi?id=41985
+
+ This adds in the --use_drt option for rebaseline_chromium_webkit_tests
+ so that it works on linux. This is essentially a "compile-fix" for the
+ script.
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-07-09 Nico Weber <thakis@chromium.org>
+
+ Unreviewed. Adding myself as committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-07-09 David Kilzer <ddkilzer@apple.com>
+
+ Revert "<http://webkit.org/b/41788> commit-log-editor: wrong ChangeLog read when invoked from subdir with git"
+
+ This reverts commit r62692.
+
+ * Scripts/commit-log-editor:
+
+2010-07-08 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ cleanup json_results_generator dependencies so that non-layout-tests can also use it safely
+ https://bugs.webkit.org/show_bug.cgi?id=38693
+
+ Introduced a new base class JSONResultsGeneratorBase that doesn't
+ have any dependency on layout_tests packages.
+ Turned JSONResultsGenerator into a wrapper class of the base class
+ so that the old code can work with it during the cleanup.
+
+ Added json_results_generator_unittest.py.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py: Added
+
+2010-07-09 Abhishek Arya <inferno@chromium.org>
+
+ Unreviewed.
+
+ Marking myself as a committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-07-09 Kenneth Rohde Christiansen <kenneth.christiansen@openbossa.org>
+
+ Reviewed by Antti Koivisto.
+
+ Implement MiniBrowser for Qt.
+ https://bugs.webkit.org/show_bug.cgi?id=40233
+
+ * MiniBrowser/qt/BrowserWindow.cpp: Added.
+ (createNewPage):
+ (BrowserView::BrowserView):
+ (BrowserView::resizeEvent):
+ (BrowserView::load):
+ (BrowserView::view):
+ (BrowserWindow::BrowserWindow):
+ (BrowserWindow::load):
+ (BrowserWindow::changeLocation):
+ (BrowserWindow::~BrowserWindow):
+ * MiniBrowser/qt/BrowserWindow.h: Added.
+ (BrowserView::~BrowserView):
+ * MiniBrowser/qt/MiniBrowser.pro: Added.
+ * MiniBrowser/qt/main.cpp: Added.
+ (main):
+
+2010-07-09 Jedrzej Nowacki <jedrzej.nowacki@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Introduce the Qt autotest launcher.
+
+ Qt autotests should be executed more frequently, ideally by the Qt
+ build bot. This is the first step to provide the tests more accessible.
+
+ [Qt] It should be easier to run all Qt's autotests.
+ https://bugs.webkit.org/show_bug.cgi?id=31625
+
+ * Scripts/run-qtwebkit-tests: Added.
+
+2010-07-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ commit-queue should merge to TOT when checkout needs update
+ https://bugs.webkit.org/show_bug.cgi?id=41944
+
+ There are a bunch of different designs that are possible here. This
+ one merges to top of tree by cleaning out the working copy and
+ re-applying the patch. Once you decide to merge that way, you need to
+ decide who's going to retry. In this patch, we retry in the child
+ process instead of plumbing the failure reason to the master process.
+
+ This patch is difficult to test end-to-end, but hopefully it will work.
+ :)
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/stepsequence.py:
+ * Scripts/webkitpy/tool/multicommandtool.py:
+ * Scripts/webkitpy/tool/multicommandtool_unittest.py:
+
+2010-07-09 Dumitru Daniliuc <dumi@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Add a script to check for unnecessary includes in header files.
+ https://bugs.webkit.org/show_bug.cgi?id=41894
+
+ * Scripts/check-header-includes: Added.
+
+2010-07-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add --html5-treebuilder option to run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=41922
+
+ We're down to one or two regressions in the HTML5lib test suite. It's
+ getting to be time to look at fixing LayoutTests.
+
+ * Scripts/old-run-webkit-tests:
+
+2010-07-08 Simon Fraser <simon.fraser@apple.com>
+
+ Fix Tiger plugin test failures; the #ifdefs were incorrect, resulting
+ in the drawing model never getting set on Tiger.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+
+2010-07-08 Aaron Boodman <aa@chromium.org>
+
+ Reviewed by Timothy Hatcher.
+
+ Add the ability for user scripts and user styles to affect just the top frame.
+
+ https://bugs.webkit.org/show_bug.cgi?id=41529
+
+ * DumpRenderTree/LayoutTestController.h: Added new allFrames param.
+ * DumpRenderTree/LayoutTestController.cpp: Ditto.
+ (addUserScriptCallback):
+ (addUserStyleSheetCallback):
+ * DumpRenderTree/chromium/LayoutTestController.cpp: Ditto.
+ (LayoutTestController::addUserScript):
+ (LayoutTestController::addUserStyleSheet):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: Ditto.
+ (LayoutTestController::addUserScript):
+ (LayoutTestController::addUserStyleSheet):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm: Ditto.
+ (LayoutTestController::addUserScript):
+ (LayoutTestController::addUserStyleSheet):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp: Ditto.
+ (LayoutTestController::addUserScript):
+ (LayoutTestController::addUserStyleSheet):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp: Ditto.
+ (LayoutTestController::addUserScript):
+ (LayoutTestController::addUserStyleSheet):
+
+2010-07-08 Adele Peterson <adele@apple.com>
+
+ Reviewed by Jon Honeycutt, Adam Roben, and Darin Adler.
+
+ Test infrastructure for https://bugs.webkit.org/show_bug.cgi?id=41721
+ <rdar://problem/8158561> Missing plug-in indicator should have a pressed state
+
+ Log when the missing plugin button is pressed.
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:didPressMissingPluginButton:]):
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::QueryInterface):
+ (UIDelegate::createWebViewWithRequest):
+ (UIDelegate::drawBackground):
+ (UIDelegate::decidePolicyForGeolocationRequest):
+ (UIDelegate::didPressMissingPluginButton):
+ * DumpRenderTree/win/UIDelegate.h:
+
+2010-07-08 Simon Fraser <simon.fraser@apple.com>
+
+ Fix the Tiger build.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+
+2010-07-08 Simon Fraser <simon.fraser@apple.com>
+
+ Fix windows build.
+
+ #ifdef code for Mac.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+
+2010-07-08 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Anders Carlsson.
+
+ Allow the TestPlugin to use Core Animation rendering for testing
+ https://bugs.webkit.org/show_bug.cgi?id=41872
+
+ Add the ability for the TestPlugin to use the CoreAnimation rendering model
+ when available, based on the "drawingmodel" attribute of the embed tag:
+ drawingmodel="coreanimation"
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Add PluginObjectMac.mm
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.h: Add some macros so we can detect
+ when building on Tiger. Add a void* coreAnimationLayer member.
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObjectMac.mm: Added.
+ (createCoreAnimationLayer): Obj-C method to create the CALayer.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New): Look for the drawingmodel attribute to decide which drawing
+ model to use.
+ (NPP_Destroy): Release the CALayer if we have one.
+ (NPP_GetValue): Return the retained CALayer.
+
+2010-07-08 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Support pixel tests
+ https://bugs.webkit.org/show_bug.cgi?id=31518
+
+ Convert this file from CRLF to NL line endings. It will soon
+ be used on more than just the WinCairo platform.
+
+ * DumpRenderTree/cairo/PixelDumpSupportCairo.cpp:
+ (writeFunction):
+ (printPNG):
+ (computeMD5HashStringForBitmapContext):
+ (dumpBitmap):
+
+2010-07-08 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Enable Data Execution Prevention for our test harnesses on Windows
+ https://bugs.webkit.org/show_bug.cgi?id=41882
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * WebKitAPITest/WebKitAPITest.vcproj:
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj:
+
+2010-07-07 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Add DRT support for pageProperty etc.
+
+ https://bugs.webkit.org/show_bug.cgi?id=41584
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::isPageBoxVisible):
+ (LayoutTestController::pageSizeAndMarginsInPixels):
+ (LayoutTestController::pageProperty):
+ (LayoutTestController::addUserStyleSheet):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-07-08 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ Remove a warnings from the ImageDiff build by using the proper
+ printf format string for the gsize data type.
+
+ * DumpRenderTree/gtk/ImageDiff.cpp:
+ (printImage): Use the proper printf format string for the gsize data type.
+
+2010-07-08 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=41653
+ Add new WebKitTestRunner project for Windows
+
+ * WebKitTestRunner/WebKitTestRunnerPrefix.h:
+ Similar to how it's done in DumpRenderTree, define max and min early
+ on so that they don't get replaced by a macro requiring 2 arguments.
+
+ * WebKitTestRunner/win: Added.
+ * WebKitTestRunner/win/WebKitTestRunner.sln: Added.
+ * WebKitTestRunner/win/WebKitTestRunner.vcproj: Added.
+ * WebKitTestRunner/win/main.cpp: Added.
+ (main): Implemented
+
+ Added these files with stubbed out functions:
+ * WebKitTestRunner/win/PlatformWebViewWin.cpp: Added.
+ (WTR::PlatformWebView::PlatformWebView):
+ (WTR::PlatformWebView::~PlatformWebView):
+ (WTR::PlatformWebView::page):
+ * WebKitTestRunner/win/TestControllerWin.cpp: Added.
+ (WTR::TestController::initializeInjectedBundlePath):
+ * WebKitTestRunner/win/TestInvocationWin.cpp: Added.
+ (WTR::TestInvocation::runUntil):
+
+2010-07-07 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] Implement ImageDiff and add it to the build system
+ https://bugs.webkit.org/show_bug.cgi?id=41779
+
+ Add the initial implementation of the ImageDiff tool for the GTK+
+ port. This is an essential tool for doing pixel tests. The implementation
+ is based on the Mac and Chromium ports.
+
+ * DumpRenderTree/gtk/ImageDiff.cpp: Added.
+ (readPixbufFromStdin): Added.
+ (differenceImageFromDifferenceBuffer): Ditto.
+ (calculateDifference): Ditto.
+ (printImage): Ditto.
+ (printImageDifferences): Ditto.
+ (main): Ditto.
+ * GNUmakefile.am: Add ImageDiff to the WebKitTools build scripts.
+
+2010-07-08 Jay Civelli <jcivelli@chromium.org>
+
+ Unreviewed. Adding myself as a committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-07-08 Adam Roben <aroben@apple.com>
+
+ Make Windows stop running tests from platform/mac
+
+ r62742 made a change (at my suggestion!) that caused us to start
+ looking for tests in platform/mac, rather than just looking for
+ expected results in platform/mac. This patch just undoes that part of
+ r62742.
+
+ Fixes <http://webkit.org/b/41855> REGRESSION (r62742): Windows runs
+ tests from platform/mac, but shouldn't
+
+ Reviewed by Antti Koivisto and Anders Carlsson.
+
+ * Scripts/old-run-webkit-tests:
+ (top level): Removed "mac-snowleopard" and "mac" from @winPlatforms,
+ so we won't look in those directories for tests to run.
+ (expectedDirectoryForTest): Added back code from pre-r62742 to look in
+ platform/mac-snowleopard and platform/mac for expected results.
+
+2010-07-08 Antonio Gomes <tonikitoo@webkit.org>
+
+ Unreviewed. Adding myself as a reviewer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-07-08 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Update my e-mail in committers.py
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-07-07 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Dumitru Daniliuc.
+
+ VCSUtils.pm complains about uninitialized value $newLine
+ https://bugs.webkit.org/show_bug.cgi?id=41333
+
+ Fixes an issue where VCSUtils::fixChangeLogPatch() may read off the end of
+ an array when fixing a change log entry that overlaps with an earlier
+ entry. In particular, when a patch contains a change log entry inserted
+ earlier in the change log file, but after an entry with the same author
+ and date.
+
+ * Scripts/VCSUtils.pm:
+ - Added for-loop constraint to fixChangeLogPatch() so that it does not
+ read off the end of the @overlappingLines array.
+ * Scripts/webkitperl/VCSUtils_unittest/fixChangeLogPatch.pl: Added unit test.
+
+2010-07-07 Anders Carlsson <andersca@apple.com>
+
+ Comment out a part of TestNetscapePlugin that caused tests to fail on Tiger and Leopard.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+
+2010-07-07 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ [DRT/Chromium] Support for indeterminate checkbox
+ https://bugs.webkit.org/show_bug.cgi?id=41747
+
+ Import http://src.chromium.org/viewvc/chrome?view=rev&revision=51499
+
+ * DumpRenderTree/chromium/WebThemeControlDRT.cpp:
+ (WebThemeControlDRT::draw):
+ * DumpRenderTree/chromium/WebThemeControlDRT.h:
+ (WebThemeControlDRT::):
+ * DumpRenderTree/chromium/WebThemeEngineDRT.cpp:
+ (WebThemeEngineDRT::paintButton):
+
+2010-07-07 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Clean up MiniBrowser Xcode project.
+
+ - Use xcconfig files.
+ - Rename plists to canonical Info.plist
+ - Remove localizations.
+
+ * MiniBrowser/Configurations: Added.
+ * MiniBrowser/Configurations/Base.xcconfig: Added.
+ * MiniBrowser/Configurations/DebugRelease.xcconfig: Added.
+ * MiniBrowser/Configurations/MiniBrowser.xcconfig: Added.
+ * MiniBrowser/Configurations/WebBundle.xcconfig: Added.
+ * MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj:
+ * MiniBrowser/WebBundle-Info.plist: Removed.
+ * MiniBrowser/mac/BrowserStatisticsWindowController.m:
+ (-[BrowserStatisticsWindowController initWithThreadedWKContextRef:processWKContextRef:]):
+ * MiniBrowser/mac/BrowserWindow.xib: Added.
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController initWithPageNamespace:]):
+ * MiniBrowser/mac/English.lproj: Removed.
+ * MiniBrowser/mac/English.lproj/BrowserWindow.xib: Removed.
+ * MiniBrowser/mac/English.lproj/InfoPlist.strings: Removed.
+ * MiniBrowser/mac/English.lproj/MainMenu.xib: Removed.
+ * MiniBrowser/mac/Info.plist: Copied from MiniBrowser/mac/MiniBrowser-Info.plist.
+ * MiniBrowser/mac/MainMenu.xib: Added.
+ * MiniBrowser/mac/MiniBrowser-Info.plist: Removed.
+ * MiniBrowser/mac/WebBundle/Info.plist: Copied from MiniBrowser/WebBundle-Info.plist.
+
+2010-07-07 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Fix two regressions
+ https://bugs.webkit.org/show_bug.cgi?id=41745
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::paintInvalidatedRegion):
+ Repaint three times to fix svg/W3C-SVG-1.1/struct-use-01-t.svg
+ and svg/custom/use-on-g-containing-foreignObject-and-image.svg
+ though test_shell does it twice. Probably DRT needs it because
+ DRT delays painting as possible.
+
+2010-07-07 Anders Carlsson <andersca@apple.com>
+
+ Try to fix build.
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_destroy_stream):
+
+2010-07-07 Anders Carlsson <andersca@apple.com>
+
+ Try to fix the GTK+ and Qt test failures by merging the newly added code from TestNetscapePlugin/main.cpp
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_stream):
+ (webkit_test_plugin_destroy_stream):
+ (webkit_test_plugin_write_ready):
+ (webkit_test_plugin_write):
+
+2010-07-07 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Don't hard code the Mac OS X 10.6 SDK for MiniBrowser.
+
+ * MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj:
+
+2010-07-07 Anders Carlsson <andersca@apple.com>
+
+ Use the correct XP_MACOSX define instead of XP_MAC. This was causing test failures on some platforms.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_New):
+ (NPP_HandleEvent):
+
+2010-07-07 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Need to have a way to specify different results for Windows XP and 7
+ https://bugs.webkit.org/show_bug.cgi?id=41776
+
+ Add the ability to have platform/win-xp, platform/win-vista, and platform/win-7
+ subdirectories, so we can have different results for tests on Windows XP, Windows
+ Vista, and Windows 7.
+
+ Windows XP will try the order: win-xp, win-vista, win-7, win, mac-snowleopard, mac.
+ Windows Vista will try the order: win-vista, win-7, win, mac-snowleopard, mac.
+ Windows 7 will try the order: win-7, win, mac-snowleopard, mac.
+
+ This matches the behavior of the mac.
+
+ * Scripts/old-run-webkit-tests: Add multiple platforms for Windows, and if we are on XP
+ or Vista, try looking in other win-* subdirectories before win.
+ * Scripts/webkitdirs.pm: Add some helper functions to determine what version of Windows
+ we are running.
+
+2010-07-07 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Remove ASSERT_NOT_REACHED in some functions
+ https://bugs.webkit.org/show_bug.cgi?id=41753
+
+ The original code of the following functions in
+ test_shell_devtools_client.cc have NOTIMPLEMENTED(), not
+ ASSERT_NOT_REACHED(). The program shouldn't stop at these
+ functions.
+
+ * DumpRenderTree/chromium/DRTDevToolsClient.cpp:
+ (DRTDevToolsClient::activateWindow):
+ (DRTDevToolsClient::closeWindow):
+ (DRTDevToolsClient::dockWindow):
+ (DRTDevToolsClient::undockWindow):
+
+2010-07-07 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Test that we call NPP_DestroyStream if a plug-in returns -1 from its NPP_Write function
+ https://bugs.webkit.org/show_bug.cgi?id=41821
+
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp:
+ (pluginGetProperty):
+ (pluginSetProperty):
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.h:
+ Add and initialize the returnNegativeOneFromWrite property.
+
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (NPP_NewStream):
+ Set the stream type to NP_NORMAL so we'll get write callbacks.
+
+ (NPP_DestroyStream):
+ Treat the onstreamdestroy attribute as a function name and not a string.
+
+ (NPP_WriteReady):
+ Have this return a nonzero value.
+
+ (NPP_Write):
+ If returnNegativeOneFromWrite is true return -1.
+
+2010-07-07 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix for machines with both MSVC 2005 and 2008 installed. Ensures the
+ latest version is selected by default, and allows the version to be specified.
+
+ * wx/build/settings.py:
+
+2010-07-07 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ AX: TextArea should return AXSelectedTextRange of 0,0 if the cursor is not in the text area
+ https://bugs.webkit.org/show_bug.cgi?id=41810
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::selectedTextRange):
+
+2010-07-07 Martin Robinson <mrobinson@igalia.com>
+
+ Unreviewed.
+
+ Build fix after r62700.
+
+ * GNUmakefile.am: Update the source list to reflect the new TestNetscapePlugIn
+ source file locations.
+
+2010-07-07 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by David Levin.
+
+ change --exit-after-n-crashes to --exit-after-n-crashes-or-timeouts
+ https://bugs.webkit.org/show_bug.cgi?id=41814
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+ * Scripts/old-run-webkit-tests:
+
+2010-07-07 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by David Levin.
+
+ add --exit-after-n-crashes to run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=41811
+
+ Change the bots at build.webkit.org to use --exit-after-n-crashes
+ instead of --exit-after-n-failures since we want to be able to have
+ more than 20 failures on those bots, but more than 20 crashes means
+ something should be rolled out.
+
+ * Scripts/old-run-webkit-tests:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-07-07 Brian Weinstein <bweinstein@apple.com>
+
+ Fix the Windows build by removing win/TestNetscapePlugin/main.cpp from the
+ TestNetscapePlugin project, because this was removed from the tree.
+
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+
+2010-07-07 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ Unify Mac and Windows TestNetscapePlugin main.cpp files
+ https://bugs.webkit.org/show_bug.cgi?id=41798
+
+ * DumpRenderTree/DumpRenderTree.sln:
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp:
+ (strcasecmp):
+ (NP_Initialize):
+ (NP_GetEntryPoints):
+ (NP_Shutdown):
+ (NPP_New):
+ (NPP_Destroy):
+ (NPP_HandleEvent):
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp: Removed.
+
+2010-07-07 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix. pageProperty needs to return a value.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::pageProperty):
+
+2010-07-07 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/41788> commit-log-editor: wrong ChangeLog read when invoked from subdir with git
+
+ Reviewed by Anders Carlsson.
+
+ For both svn and git, commit-log-editor is invoked from the root
+ of the working directory. Unlike svn, git returns a list of
+ changed files that are relative to the directory where the
+ command was invoked. This caused the ChangeLog file in the root
+ directory to be read instead of the ChangeLog in the current
+ directory.
+
+ The fix is to use $ENV{PWD} as the base directory when fixing
+ the path to the ChangeLog files. With svn, this has no net
+ effect since $ENV{PWD} is the root of the working directory and
+ the ChangeLog paths are already relative to that directory.
+ With git, $ENV{PWD} is the directory that the commit was invoked
+ from, which fixes the ChangeLog paths so that the correct files
+ are read when creating the commit log entry.
+
+ Note that the call to makeFilePathRelative() was supposed to
+ address this issue, but it doesn't because (a) it does nothing
+ with svn working directories by design, and (b) it does nothing
+ with git working directories because it's invoked when the
+ current directory is the root of the working directory, thus
+ giving no relative path.
+
+ * Scripts/commit-log-editor: Removed call to
+ makeFilePathRelative() since since it does nothing. Moved code
+ to fix up $changeLog path so that it's fixed before trying to
+ open the file, and use $ENV{PWD} as the base path. Also use
+ canonicalizePath() to clean up paths with "../" in them.
+
+2010-07-07 Anders Carlsson <andersca@apple.com>
+
+ Another attempt at fixing the Qt build.
+
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+
+2010-07-07 Anders Carlsson <andersca@apple.com>
+
+ Try to fix Qt build.
+
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+
+2010-07-07 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ Rename TestNetscapePlugin.subproj and move platform specific files to subdirectories
+ https://bugs.webkit.org/show_bug.cgi?id=41781
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp: Renamed from WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp.
+ * DumpRenderTree/TestNetscapePlugIn/PluginObject.h: Renamed from WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h.
+ * DumpRenderTree/TestNetscapePlugIn/TestObject.cpp: Renamed from WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.cpp.
+ * DumpRenderTree/TestNetscapePlugIn/TestObject.h: Renamed from WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.h.
+ * DumpRenderTree/TestNetscapePlugIn/mac/Info.plist: Renamed from WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/Info.plist.
+ * DumpRenderTree/TestNetscapePlugIn/main.cpp: Renamed from WebKitTools/DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp.
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.def: Renamed from WebKitTools/DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.def.
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.rc: Renamed from WebKitTools/DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.rc.
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj: Added.
+ * DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin_debug.def: Renamed from WebKitTools/DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin_debug.def.
+ * DumpRenderTree/TestNetscapePlugIn/win/resource.h: Renamed from WebKitTools/DumpRenderTree/win/TestNetscapePlugin/resource.h.
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj: Removed.
+
+2010-07-07 Andras Becsi <abecsi@webkit.org>
+
+ Unreviewed trivial fix.
+
+ Remove DUMPRENDERTREE_TEMP environment variable from NRWT
+ which was checked in accidentally in r62635.
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-07-07 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Eric Seidel.
+
+ Pass port specific environment to server process.
+ https://bugs.webkit.org/show_bug.cgi?id=41593
+
+ * Scripts/webkitpy/layout_tests/port/qt.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-07-06 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Fix a wrong dup detection of rebaseline-chromium-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=41644
+
+ rebaseline-chromium-webkit-tests used ImageDiff with 0.1%
+ tolerance. We don't need tolerance for rebaseline.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ Add optional tolerance parameter to diff_image().
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ Add optional tolerance parameter to diff_image().
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ Add optional tolerance parameter to diff_image(), and pass it to ImageDiff command.
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ diff_files() always calls diff_image() with tolerance=0.
+ diff_files() is used only by rebaseline-chromium-webkit-tests.
+
+2010-07-06 Sam Weinig <sam@webkit.org>
+
+ Fix MiniBrowser build.
+
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+
+2010-07-06 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add support for dumping the contents of messages to the console to WebKitTestRunner
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::_addMessageToConsole):
+ (WTR::InjectedBundlePage::addMessageToConsole):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h:
+
+2010-07-06 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=41708
+ Add dumpAsText support for WebKitTestRunner
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::InjectedBundle):
+ (WTR::InjectedBundle::reset): Reset the LayoutTestController for each test.
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::InjectedBundlePage::didFinishLoadForFrame): Use the new WKBundleFrameCopyInnerText
+ API to dump the main frames text.
+
+2010-07-06 Darin Adler <darin@apple.com>
+
+ Fix Chromium build.
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::didCreateDataSource): Call leakPtr instead of release.
+ (WebViewHost::didNavigateWithinPage): Ditto.
+ (WebViewHost::updateURL): Ditto.
+
+2010-07-06 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] build-webkit should not run autogen.sh unconditionally
+ https://bugs.webkit.org/show_bug.cgi?id=41704
+
+ * Scripts/webkitdirs.pm: Only run autogen.sh during a build if GNUmakefile
+ doesn't exist. Autotools should re-run autogen.sh when necessary. Also do
+ some very minor cleanup.
+
+2010-07-06 Darin Adler <darin@apple.com>
+
+ Try to fix Chromium build.
+
+ * DumpRenderTree/chromium/WebViewHost.cpp: Added include of PassOwnPtr.h.
+
+2010-07-06 Darin Adler <darin@apple.com>
+
+ Fix build.
+
+ * WebKitAPITest/TestsController.cpp:
+ (WebKitAPITest::TestsController::addTest): Use leakPtr instead of release.
+
+2010-07-06 Roland Steiner <rolandsteiner@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ Bug 40558 - [DRT/Chromium] Upstream TestShellDevTools for Chromium DRT
+ https://bugs.webkit.org/show_bug.cgi?id=40558
+
+ Upstream DevTools for Chromium DRT.
+ (original Chromium files rev. 51287)
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+ * DumpRenderTree/chromium/DRTDevToolsAgent.cpp: Added.
+ (DRTDevToolsAgent::DRTDevToolsAgent):
+ (DRTDevToolsAgent::setWebView):
+ (DRTDevToolsAgent::sendMessageToFrontend):
+ (DRTDevToolsAgent::forceRepaint):
+ (DRTDevToolsAgent::runtimeFeatureStateChanged):
+ (DRTDevToolsAgent::injectedScriptSource):
+ (DRTDevToolsAgent::injectedScriptDispatcherSource):
+ (DRTDevToolsAgent::debuggerScriptSource):
+ (DRTDevToolsAgent::asyncCall):
+ (DRTDevToolsAgent::call):
+ (DRTDevToolsAgent::webDevToolsAgent):
+ (DRTDevToolsAgent::attach):
+ (DRTDevToolsAgent::detach):
+ (DRTDevToolsAgent::setTimelineProfilingEnabled):
+ (DRTDevToolsAgent::evaluateInWebInspector):
+ (DRTDevToolsAgent::dispatchMessageLoop):
+ * DumpRenderTree/chromium/DRTDevToolsAgent.h: Added.
+ (DRTDevToolsAgent::~DRTDevToolsAgent):
+ (DRTDevToolsAgent::hostIdentifier):
+ * DumpRenderTree/chromium/DRTDevToolsCallArgs.cpp:
+ * DumpRenderTree/chromium/DRTDevToolsCallArgs.h:
+ (DRTDevToolsCallArgs::DRTDevToolsCallArgs):
+ (DRTDevToolsCallArgs::~DRTDevToolsCallArgs):
+ (DRTDevToolsCallArgs::callsCount):
+ * DumpRenderTree/chromium/DRTDevToolsClient.cpp: Added.
+ (DRTDevToolsClient::DRTDevToolsClient):
+ (DRTDevToolsClient::~DRTDevToolsClient):
+ (DRTDevToolsClient::sendMessageToAgent):
+ (DRTDevToolsClient::sendDebuggerCommandToAgent):
+ (DRTDevToolsClient::activateWindow):
+ (DRTDevToolsClient::closeWindow):
+ (DRTDevToolsClient::dockWindow):
+ (DRTDevToolsClient::undockWindow):
+ (DRTDevToolsClient::asyncCall):
+ (DRTDevToolsClient::call):
+ (DRTDevToolsClient::allMessagesProcessed):
+ * DumpRenderTree/chromium/DRTDevToolsClient.h:
+ * DumpRenderTree/chromium/EventSender.cpp:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::closeWebInspector):
+ (LayoutTestController::setTimelineProfilingEnabled):
+ (LayoutTestController::evaluateInWebInspector):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell):
+ (TestShell::~TestShell):
+ (TestShell::createDRTDevToolsClient):
+ (TestShell::showDevTools):
+ (TestShell::closeDevTools):
+ (TestShell::runFileTest):
+ (TestShell::createNewWindow):
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::drtDevToolsAgent):
+ (TestShell::drtDevToolsClient):
+ * DumpRenderTree/chromium/config.h:
+
+2010-07-06 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Eric Seidel.
+
+ Don't pass image hash to DRT when pixel tests are disabled.
+ https://bugs.webkit.org/show_bug.cgi?id=41597
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+
+2010-07-05 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ REGRESSION(r60652): WebKitTools/Scripts/ensure-valid-python should cleanup temporary directory
+ https://bugs.webkit.org/show_bug.cgi?id=41612
+
+ * Scripts/ensure-valid-python: File::Temp::tempdir call fixed.
+
+2010-07-05 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ We should be able to specify a bug to block for webkit-patch upload
+ https://bugs.webkit.org/show_bug.cgi?id=41648
+
+ This will be useful for working on the HTML5 parser.
+
+ * Scripts/webkitpy/tool/steps/createbug.py:
+ * Scripts/webkitpy/tool/steps/options.py:
+
+2010-07-05 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Oliver Hunt.
+
+ The style checker exempts gtk2drawing.h when it should exempt gtkdrawing.h
+ https://bugs.webkit.org/show_bug.cgi?id=41017
+
+ * Scripts/webkitpy/style/checker.py: Exempt gtkdrawing.h instead of gtk2drawing.h
+ * Scripts/webkitpy/style/checker_unittest.py: Update the unit test to reflect the change.
+
+2010-07-04 MORITA Hajime <morrita@google.com>
+
+ rebaseline-chromium-webkit-tests: UnicodeDecodeError
+ https://bugs.webkit.org/show_bug.cgi?id=41589
+
+ * run() method can result non-utf-8 bytes, that causes utf-8
+ decoding fail. Fixed to disable decoding.
+ * Fixed Git.find_checkout_root() to make a test pass.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+
+2010-07-03 Patrick Gansterer <paroga@paroga.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Fix DumpRenderTree userStyleSheet handling.
+ https://bugs.webkit.org/show_bug.cgi?id=41570
+
+ DumpRenderTree did only set the userStyleSheet at
+ layoutTestController.setUserStyleSheetEnabled().
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::setUserStyleSheetLocation):
+ (LayoutTestController::setUserStyleSheetEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-07-03 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] support dumpChildFrameScrollPositions
+
+ https://bugs.webkit.org/show_bug.cgi?id=41088
+
+ Unskip:
+
+ http/tests/navigation/anchor-subframeload.html
+ http/tests/navigation/relativeanchor-frames.html
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::dumpFrameScrollPosition):
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::shouldDumpChildFrameScrollPositions):
+ (LayoutTestController::dumpChildFrameScrollPositions):
+
+2010-07-02 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Rename new scripts so that they don't make autocompleting run-webkit-tests annoying.
+
+ * Scripts/debug-test-runner: Copied from Scripts/debug-webkittestrunner.
+ * Scripts/debug-webkittestrunner: Removed.
+ * Scripts/run-test-runner: Copied from Scripts/run-webkittestrunner.
+ * Scripts/run-webkittestrunner: Removed.
+
+2010-07-02 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Steve Falkenburg.
+
+ Some http tests fail on Windows with Cygwin 1.7
+ https://bugs.webkit.org/show_bug.cgi?id=41537
+
+ With Cygwin 1.7, the registry key at SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\/
+ doesn't exist anymore, because the mount points are stored in /etc/fstab. However, we
+ just need root mount point, which is defined in SOFTWARE\\Cygwin\\setup.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (resolveCygwinPath): Fall back to SOFTWARE\\Cygwin\\setup if
+ SOFTWARE\\Cygnus Solutions\\Cygwin\\mounts v2\\/ doesn't work.
+
+2010-06-23 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] Separate DerivedSources per-project
+ https://bugs.webkit.org/show_bug.cgi?id=41109
+
+ The JavaScriptCore cppflags used to include the top-level DerivedSources directory
+ allowing the tools to build as a side-effect. Now that the top-level directory
+ is no longer in the list of JavaScriptCore includes, include it explicitly.
+
+ * GNUmakefile.am:
+
+2010-07-01 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Make context menus show up in the right place in QTestBrowser
+
+ Context menus were shown at scene-relative coordinates for
+ QGraphicsWebView while QMenu expects them to be global. The
+ change to the QWidget case was to get rid of the mapToGlobal.
+
+ * QtTestBrowser/webview.cpp:
+
+2010-07-01 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] dump frames in ascending alphabetical order of title
+
+ https://bugs.webkit.org/show_bug.cgi?id=41261
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::dumpHistoryItem):
+
+2010-07-01 Martin Robinson <mrobinson@igalia.com>
+
+ Unreviewed.
+
+ Fix the GTK+ build after r62278.
+
+ * Scripts/webkitdirs.pm: If the make arguments have already been specified,
+ let them override the automatic CPU detection for autotools builds.
+
+2010-07-01 Martin Robinson <mrobinson@igalia.com>
+
+ Unreviewed.
+
+ Fix the Windows build after r62278.
+
+ * Scripts/num-cpus: Use FindBin to add the Scripts directory to the list of library directories.
+
+2010-07-01 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] build-webkit does not detect the number of CPUs
+ https://bugs.webkit.org/show_bug.cgi?id=41469
+
+ Pass the appropriate -j<#> flag to make when building autotools builds.
+ This causes make to spawn that many number of child processes for doing
+ parallel builds.
+
+ * Scripts/num-cpus: Use the newly abstracted numberOfCPUs to return the number
+ of CPUs. This makes the script work across more platforms.
+ * Scripts/webkitdirs.pm: Create a numberOfCPUs/determineNumberOfCPUs to determine the
+ number of CPUs across several platforms. Use this new function to determine the appropriate
+ arguments to pass to make for doing parallel builds with autotools build files.
+
+2010-07-01 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Laszlo Gombos.
+
+ [Qt][Symbian] Bumped up the maximum heap size to 96MB
+
+ * QtTestBrowser/QtTestBrowser.pro: Removed explicit heap size declaration
+ and use the one from WebKit.pri instead.
+
+2010-07-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Promote webkit-patch land-safely to main help
+ https://bugs.webkit.org/show_bug.cgi?id=41446
+
+ I've been using this command a bunch and recommending it to folks. We
+ should show it in main help as it's past the experimental phase.
+
+ * Scripts/webkitpy/tool/commands/upload.py:
+
+2010-06-28 MORITA Hajime <morrita@google.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ rebaseline-chromium-webkit-tests doesn't do diffs right with a Git checkout of WebKit
+ https://bugs.webkit.org/show_bug.cgi?id=38775
+
+ - Introduced SCM.show_head() and SCM.diff_for_file().
+ - Replaced direct svn invocations with newly implement SCM methods.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-06-30 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Allow MiniBrowser to open local files
+ https://bugs.webkit.org/show_bug.cgi?id=41104
+
+ Wire up the openDocument: message with an NSOpenPanel, so we can open
+ local files.
+
+ Also change the xib so that the window remembers its size.
+
+ * MiniBrowser/mac/AppDelegate.m:
+ (-[BrowserAppDelegate frontmostBrowserWindowController]):
+ (-[BrowserAppDelegate openDocument:]):
+ (-[BrowserAppDelegate openPanelDidEnd:returnCode:contextInfo:]):
+ * MiniBrowser/mac/English.lproj/BrowserWindow.xib:
+
+2010-06-30 Sam Weinig <sam@webkit.org>
+
+ Rubber-stamped by Anders Carlsson.
+
+ Add debug-webkittestrunner and cleanup related scripts.
+
+ * Scripts/debug-webkittestrunner: Added.
+ * Scripts/run-webkittestrunner:
+ * Scripts/webkitdirs.pm:
+
+2010-06-30 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after recent changes to LayoutTestController.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::pageSizeAndMarginsInPixels):
+
+2010-06-29 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=41389
+ Make WebKitTestRunner work with more than one test at a time.
+
+ This converts WebKitTestRunner to a similar model as DumpRenderTree,
+ where there is a single WKView and each test is run it, rather than
+ the design I was using where each test got its own WKView.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::didRecieveMessage):
+ (WTR::InjectedBundle::reset):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h:
+ * WebKitTestRunner/TestController.cpp:
+ (WTR::TestController::initialize):
+ (WTR::TestController::runTest):
+ (WTR::TestController::_didRecieveMessageFromInjectedBundle):
+ (WTR::TestController::didRecieveMessageFromInjectedBundle):
+ * WebKitTestRunner/TestController.h:
+ (WTR::TestController::mainWebView):
+ (WTR::TestController::pageNamespace):
+ (WTR::TestController::context):
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::TestInvocation):
+ (WTR::TestInvocation::~TestInvocation):
+ (WTR::TestInvocation::invoke):
+ (WTR::TestInvocation::didRecieveMessageFromInjectedBundle):
+ * WebKitTestRunner/TestInvocation.h:
+
+2010-06-30 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt][Symbian] Only 10 websites can be loaded consecutively when using QtWebkit 2.0
+ https://bugs.webkit.org/show_bug.cgi?id=40446
+
+ We quickly run out of memory on Symbian when loading web pages. This is
+ caused by the default heap size, which is not suited for a web browser.
+
+ This change bumps the max heap size to 32MB.
+
+ * QtTestBrowser/QtTestBrowser.pro:
+
+2010-06-30 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch land allow the user to continue even if the builders are red
+ https://bugs.webkit.org/show_bug.cgi?id=41395
+
+ I don't think it's good that we've been teaching people
+ to always pass --ignore-builders. At least land is now
+ useable w/o --ignore-builders.
+
+ * Scripts/webkitpy/tool/steps/ensurebuildersaregreen.py:
+
+2010-06-29 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] support dumpResourceResponseMIMETypes
+ https://bugs.webkit.org/show_bug.cgi?id=41260
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::dumpResourceResponseMIMETypes):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-06-29 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Resize scene when Qt DRT WebPage receives a geometry change request
+ https://bugs.webkit.org/show_bug.cgi?id=41173
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::setViewGeometry):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+
+2010-06-29 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Deal with postEvent in case of graphics based DRT
+ https://bugs.webkit.org/show_bug.cgi?id=41174
+
+ QGraphicsScene does not have a postEvent method, so make scene
+ send the event, in case of graphics based DRT, and delete it after that.
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::scheduleAsynchronousClick):
+ (EventSender::replaySavedEvents):
+ (EventSender::postEvent):
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2010-06-29 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Make switchFocus() method works with QGraphicsWebView in Qt DRT
+ https://bugs.webkit.org/show_bug.cgi?id=41172
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::switchFocus):
+
+2010-06-29 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [Gtk] Make DRT more coherent with other ports to allow reusing more tests
+ https://bugs.webkit.org/show_bug.cgi?id=40009
+
+ Make sure "AXRole: ", "AXTitle: " and "AXDescription: " prefixes
+ are used when returning those values, for coherency with other ports.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::role):
+ (AccessibilityUIElement::title):
+ (AccessibilityUIElement::description):
+
+2010-06-29 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r62106.
+ http://trac.webkit.org/changeset/62106
+ https://bugs.webkit.org/show_bug.cgi?id=41346
+
+ "Broke editing tests" (Requested by xan_ on #webkit).
+
+ * Scripts/old-run-webkit-tests:
+
+2010-06-29 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ Ensure DRT loads GAIL (Gtk+ module), for a11y tests
+ https://bugs.webkit.org/show_bug.cgi?id=38648
+
+ Add the GTK_MODULES envvar (set to "gail") to the clean
+ environment when running DRT for the Gtk+ port
+
+ * Scripts/old-run-webkit-tests:
+
+2010-06-28 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Switch test-html5-parser back to using runner.html.
+
+ * Scripts/test-html5-parser:
+
+2010-06-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Restore webkit-runner.html for use with new tree builder
+ https://bugs.webkit.org/show_bug.cgi?id=41317
+
+ For now, we just want to run webkit-runner when we test-html5-parser.
+
+ * Scripts/test-html5-parser:
+
+2010-06-23 John Gregg <johnnyg@google.com>
+
+ Reviewed by Kent Tamura.
+
+ add ENABLE_DIRECTORY_UPLOAD build support
+ https://bugs.webkit.org/show_bug.cgi?id=41100
+
+ * Scripts/build-webkit:
+
+2010-06-28 Gustavo Noronha Silva <gns@gnome.org>
+
+ Rubber-stamped by Xan Lopez.
+
+ Update webkitdirs's knowledge of our library's name.
+
+ * Scripts/webkitdirs.pm:
+
+2010-06-28 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=41299
+ Build up WebKitTestRunner output in the InjectedBundle
+
+ Simplify WebKitTestRunner by building up the output in the InjectedBundle
+ and sending it over postMessage when done, instead of using the async
+ WKPageRenderTreeExternalRepresentation.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp:
+ (WTR::InjectedBundle::done):
+ (WTR::InjectedBundle::didRecieveMessage):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h:
+ (WTR::InjectedBundle::os):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp:
+ (WTR::WKStringToUTF8):
+ (WTR::InjectedBundlePage::didFinishLoadForFrame):
+ (WTR::InjectedBundlePage::didFailLoadWithErrorForFrame):
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::WKStringToUTF8):
+ (WTR::TestInvocation::TestInvocation):
+ (WTR::TestInvocation::invoke):
+ (WTR::TestInvocation::initializeMainWebView):
+ (WTR::TestInvocation::_didRecieveMessageFromInjectedBundle):
+ (WTR::TestInvocation::didRecieveMessageFromInjectedBundle):
+ * WebKitTestRunner/TestInvocation.h:
+
+2010-06-28 Robert Hogan <robert@webkit.org>
+
+ Unreviewed, rolling out r62021.
+ http://trac.webkit.org/changeset/62021
+ https://bugs.webkit.org/show_bug.cgi?id=41261
+
+ Broke http/navigation tests among other
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::dumpFramesAsText):
+
+2010-06-28 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add run-webkittestrunner to run WebKitTestRunner with the appropriate
+ environment.
+
+ * Scripts/run-webkittestrunner: Added.
+ * Scripts/webkitdirs.pm:
+
+2010-06-28 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] dump frames in ascending alphabetical order of title
+
+ https://bugs.webkit.org/show_bug.cgi?id=41261
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::dumpFramesAsText):
+
+2010-06-28 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] dump bf history of child windows
+
+ https://bugs.webkit.org/show_bug.cgi?id=41266
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::dumpBackForwardList):
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+
+2010-06-28 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=41288
+ WebKit2: Add frame API for InjectedBundle code
+
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (_didClearWindowForFrame):
+
+2010-06-28 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] QtTestBrowser does not have a "Load" button ; therefore, unable to load pages on touch only symbian devices (portrait mode).
+ https://bugs.webkit.org/show_bug.cgi?id=38597
+
+ Fix behavior so reload button really acts as a load and a reload button.
+
+ * QtTestBrowser/mainwindow.cpp:
+ (MainWindow::changeLocation):
+
+2010-06-28 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ [GTK] Does not compile with -DGSEAL_ENABLE
+ https://bugs.webkit.org/show_bug.cgi?id=37851
+
+ Fix build with GSEAL enabled.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (gtk_widget_get_window):
+ (prepareMouseButtonEvent):
+ (mouseMoveToCallback):
+ (mouseWheelToCallback):
+ (keyDownCallback):
+
+2010-06-28 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ [GTK] Add support for GTK+3
+ https://bugs.webkit.org/show_bug.cgi?id=41253
+
+ Adapt build system for 3.x support.
+
+ * GNUmakefile.am:
+
+2010-06-10 Mahesh Kulkarni <mahesh.kulkarni@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [QT][S60] build-webkit scripts picks wrong make spec for windows build
+ https://bugs.webkit.org/show_bug.cgi?id=41198
+
+ Instead of checking for existence of %EPOCROOT% on windows, mandatory use of --symbian flag for symbian builds.
+
+ * Scripts/webkitdirs.pm:
+ (determineIsSymbian): remove check for %EPOCROOT% as one can build for windows port of QT as well
+
+2010-06-28 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make it possible to test the new HTML5 TreeBuilder
+ https://bugs.webkit.org/show_bug.cgi?id=41276
+
+ Adam was concerned that someone might make their port
+ depend on this setting (I guess we had some trouble with that
+ with the HTML5Parser setting), so I littered the code with warnings.
+
+ test-html5-parser now tests this code path.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ (initializeGlobalsFromCommandLineOptions):
+ * Scripts/test-html5-parser:
+
+2010-06-27 MORITA Hajime <morrita@google.com>
+
+ Unreviewed.
+
+ Some never-called @staticmethods touched self.
+ Fixed it to replace these self with a class.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+
+2010-06-27 MORITA Hajime <morrita@google.com>
+
+ Unreviewed.
+
+ Fixed exception raising syntax that is pointed out at
+ https://bugs.webkit.org/show_bug.cgi?id=41153
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ Removed a bad line that I accidentally checked-in at last revision.
+
+2010-06-24 MORITA Hajime <morrita@google.com>
+
+ Reviewed by Eric Seidel.
+
+ rebaseline-chromium-webkit-tests should add or remove files to local git repository
+ https://bugs.webkit.org/show_bug.cgi?id=41153
+
+ - Added SCM.add() and SCM.remove()
+ - Replaced "svn add" and "svn remove"
+ rebaseline_chromium_webkit_tests.py: in with SCM method equivalents.
+ - add "-U" and "-q" options to rebaseline_chromium_webkit_tests.py
+ for debugging purpose.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-06-25 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Improve default value handling for page format properties.
+ https://bugs.webkit.org/show_bug.cgi?id=41150
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (parsePageNumber):
+ (parsePageNumberSizeMarings):
+ (pageSizeAndMarginsInPixelsCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::pageSizeAndMarginsInPixels):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::pageSizeAndMarginsInPixels):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::pageSizeAndMarginsInPixels):
+
+2010-06-21 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] DRT Support for setCustomPolicyDelegate
+
+ https://bugs.webkit.org/show_bug.cgi?id=39564
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setCustomPolicyDelegate):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-06-26 Robert Hogan <robert@webkit.org>
+
+ Unreviewed, Qt build fix following http://trac.webkit.org/changeset/61879
+
+ Remove qwebscriptworld.h from LayoutTestControllerQt.cpp - it is no longer
+ exported.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+
+2010-06-26 Tony Gentilcore <tonyg@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Add a build-webkit option for enabling Web Timing support.
+ https://bugs.webkit.org/show_bug.cgi?id=38924
+
+ * Scripts/build-webkit:
+
+2010-06-25 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] QtTestBrowser does not have a "Load" button ; therefore, unable to load pages on touch only symbian devices (portrait mode).
+ https://bugs.webkit.org/show_bug.cgi?id=38597
+
+ Make the reload button act as a load button as well.
+
+ * QtTestBrowser/mainwindow.cpp:
+ (MainWindow::buildUI):
+ (MainWindow::changeLocation):
+
+2010-06-25 Prasad Tammana <prasadt@chromium.org>
+
+ Reviewed by Dmitry Titov.
+
+ Add empty abortModal() method to all platforms.
+ https://bugs.webkit.org/show_bug.cgi?id=40864
+
+ Add an empty abortModal() stub to LayoutTestController on all platforms to get rid of platform specific #ifs in
+ platform independent LayoutTestController code. Without this change, layout tests using LayoutTestController tests
+ that use abortModal will become mac specific which is not desirable.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (abortModalCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::abortModal):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::abortModal):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::abortModal):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::abortModal):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::abortModal):
+
+2010-06-25 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=41226
+ Flesh out injected bundle code for WebKitTestRunner and add basic LayoutTestController.
+
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.cpp: Added.
+ (WTR::InjectedBundle::shared):
+ (WTR::InjectedBundle::InjectedBundle):
+ (WTR::InjectedBundle::_didCreatePage):
+ (WTR::InjectedBundle::_willDestroyPage):
+ (WTR::InjectedBundle::_didRecieveMessage):
+ (WTR::InjectedBundle::initialize):
+ (WTR::InjectedBundle::didCreatePage):
+ (WTR::InjectedBundle::willDestroyPage):
+ (WTR::InjectedBundle::didRecieveMessage):
+ * WebKitTestRunner/InjectedBundle/InjectedBundle.h: Added.
+ (WTR::InjectedBundle::layoutTestController):
+ * WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp:
+ (WKBundleInitialize):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp: Added.
+ (WTR::InjectedBundlePage::InjectedBundlePage):
+ (WTR::InjectedBundlePage::~InjectedBundlePage):
+ (WTR::InjectedBundlePage::_didStartProvisionalLoadForFrame):
+ (WTR::InjectedBundlePage::_didReceiveServerRedirectForProvisionalLoadForFrame):
+ (WTR::InjectedBundlePage::_didFailProvisionalLoadWithErrorForFrame):
+ (WTR::InjectedBundlePage::_didCommitLoadForFrame):
+ (WTR::InjectedBundlePage::_didFinishLoadForFrame):
+ (WTR::InjectedBundlePage::_didFailLoadWithErrorForFrame):
+ (WTR::InjectedBundlePage::_didReceiveTitleForFrame):
+ (WTR::InjectedBundlePage::_didClearWindowForFrame):
+ (WTR::InjectedBundlePage::didStartProvisionalLoadForFrame):
+ (WTR::InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame):
+ (WTR::InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame):
+ (WTR::InjectedBundlePage::didCommitLoadForFrame):
+ (WTR::InjectedBundlePage::didFinishLoadForFrame):
+ (WTR::InjectedBundlePage::didFailLoadWithErrorForFrame):
+ (WTR::InjectedBundlePage::didReceiveTitleForFrame):
+ (WTR::InjectedBundlePage::didClearWindowForFrame):
+ * WebKitTestRunner/InjectedBundle/InjectedBundlePage.h: Added.
+ (WTR::InjectedBundlePage::page):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.cpp: Added.
+ (WTR::LayoutTestController::create):
+ (WTR::LayoutTestController::LayoutTestController):
+ (WTR::LayoutTestController::~LayoutTestController):
+ (WTR::dumpAsTextCallback):
+ (WTR::layoutTestControllerObjectFinalize):
+ (WTR::LayoutTestController::makeWindowObject):
+ (WTR::LayoutTestController::getJSClass):
+ (WTR::LayoutTestController::staticFunctions):
+ * WebKitTestRunner/InjectedBundle/LayoutTestController.h: Added.
+ (WTR::LayoutTestController::dumpAsText):
+ (WTR::LayoutTestController::setDumpAsText):
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj:
+
+2010-06-25 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Make WebKitTestRunner really work with run-webkit-tests.
+
+ - Add Forwarding headers to allow some cleanup.
+
+ * WebKitTestRunner/ForwardingHeaders: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/ASCIICType.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/Assertions.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/Atomics.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/FastMalloc.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/HashMap.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/HashSet.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/HashTraits.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/Locker.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/MainThread.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/MathExtras.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/Noncopyable.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/OwnPtr.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/OwnPtrCommon.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/PassOwnPtr.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/PassRefPtr.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/Platform.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/RefCounted.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/RefPtr.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/RetainPtr.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/StringExtras.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/ThreadSafeShared.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/Threading.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/ThreadingPrimitives.h: Added.
+ * WebKitTestRunner/ForwardingHeaders/wtf/Vector.h: Added.
+ * WebKitTestRunner/TestInvocation.cpp:
+ (WTR::TestInvocation::dump): Dump the right number of #EOFs.
+ * WebKitTestRunner/TestInvocation.h:
+
+2010-06-25 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Add support for WebKitTestRunner to old-run-webkit-tests
+
+ - Also adds a script to build WebKitTestRunner for old-run-webkit-tests to use.
+
+ * Scripts/build-webkittestrunner: Added.
+ * Scripts/old-run-webkit-tests:
+
+2010-06-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by David Levin.
+
+ Incremental build failed on Chromium ews
+ https://bugs.webkit.org/show_bug.cgi?id=41011
+
+ The division of responsibility between update-webkit --chromium and
+ build-webkit --chromium is slightly unclear. In this patch, we make
+ build-webkit --chromium also update DEPS and re-run GYP in case the
+ developer has changed either since they updated.
+
+ This change is also helpful for the EWS, which wants to update DEPS and
+ re-run GYP after applying patches, but the EWS doesn't want to run
+ update-webkit --chromium because it has a dirty working copy.
+
+ * Scripts/webkitdirs.pm:
+
+2010-06-25 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Support evaluateScriptInIsolatedWorld()
+
+ https://bugs.webkit.org/show_bug.cgi?id=40079
+
+ Remove evaluateScriptInIsolatedWorld() from QtWebKit API.
+ Remove QWebScriptWorld from exported headers.
+ Confine support to DumpRenderTreeSupportQt so that the tests can pass.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::evaluateScriptInIsolatedWorld):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-06-25 Anders Carlsson <andersca@apple.com>
+
+ Revert accidental part and add a newline.
+
+ * MiniBrowser/mac/AppDelegate.m:
+ * MiniBrowser/mac/MiniBrowser_Prefix.pch:
+
+2010-06-25 Anders Carlsson <andersca@apple.com>
+
+ Rubber-stamped by Dan Bernstein.
+
+ Add a LOG macro that expands to a no-op by default.
+
+ * MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj:
+ * MiniBrowser/mac/AppDelegate.m:
+ (_didRecieveMessageFromInjectedBundle):
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController windowShouldClose:]):
+ (_didStartProvisionalLoadForFrame):
+ (_didReceiveServerRedirectForProvisionalLoadForFrame):
+ (_didFailProvisionalLoadWithErrorForFrame):
+ (_didCommitLoadForFrame):
+ (_didFinishLoadForFrame):
+ (_didFailLoadWithErrorForFrame):
+ (_didReceiveTitleForFrame):
+ (_didFirstLayoutForFrame):
+ (_didFirstVisuallyNonEmptyLayoutForFrame):
+ (_didBecomeUnresponsive):
+ (_didBecomeResponsive):
+ (_decidePolicyForNavigationAction):
+ (_decidePolicyForNewWindowAction):
+ (_createNewPage):
+ (_showPage):
+ (_closePage):
+ (_didNavigateWithNavigationData):
+ (_didPerformClientRedirect):
+ (_didPerformServerRedirect):
+ (_didUpdateHistoryTitle):
+ * MiniBrowser/mac/MiniBrowser_Prefix.pch:
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (_didClearWindowForFrame):
+ (_didCreatePage):
+ (_willDestroyPage):
+ (_didRecieveMessage):
+
+2010-06-24 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ commit-queue is taking too long to land patches because of red trees
+ https://bugs.webkit.org/show_bug.cgi?id=41194
+
+ Instead of checking for the tree to be green, we'll just spin hot
+ trying to land patches. This is probably too extreme in ignoring the
+ tree, but I think we should try it for a while to see if we have
+ trouble. That will help us find the right balance.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-06-24 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Clean up the use of gdk_window_get_root_coords in EventSender
+ https://bugs.webkit.org/show_bug.cgi?id=40843
+
+ Define the version for old GTK+s in a way that is forward-compatible
+ and clean up the logic a bit.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (gdk_window_get_root_coords): Renamed and cleaned up.
+ (prepareMouseButtonEvent): Remove #ifdefs.
+ (mouseMoveToCallback): Remove #ifdefs.
+
+2010-06-24 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix NewRunWebKitTests to work on Windows.
+ https://bugs.webkit.org/show_bug.cgi?id=41180
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: Added "perl" as first arguments,
+ because Windows fails to understand what we're asking of it.
+
+2010-06-24 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] The url passed to the WebView during layout tests is invalid
+ https://bugs.webkit.org/show_bug.cgi?id=40832
+
+ Set the test URL to the full real file URL and do a small cleanup.
+ Previously a URL like file://relative/path/to/test.html was passed
+ to the WebView. This malformed file URL would be returned by
+ webkit_web_view_get_url and webkit_web_frame_get_url.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (shouldLogFrameLoadDelegates): Change to take a const string& as the argument.
+ (shouldOpenWebInspector): Change to take a const string& as the argument.
+ (shouldEnableDeveloperExtras): Change to take a const string& as the argument.
+ (runTest): Pass the full file:// URL to the view. Remove the superfluous url variable.
+
+2010-06-24 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Fix WebKitTestRunner Makefile typos.
+
+ * WebKitTestRunner/Makefile:
+
+2010-06-24 Adele Peterson <adele@apple.com>
+
+ Reviewed by Eric Carlson.
+
+ DumpRenderTree part of testing <rdar://problem/8093680> "Paste and Match Style" should fire paste events
+ https://bugs.webkit.org/show_bug.cgi?id=41085
+
+ * DumpRenderTree/mac/DumpRenderTree.mm: (resetWebViewToConsistentStateBeforeTesting):
+ Clear the general pasteboard in between tests so Cut,Copy, and setData on ClipboardData won't have lasting effects.
+
+2010-06-23 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=41086
+ Add new WebKitTestRunner project (ie. DRT for WebKit2).
+
+ - Mac only.
+ - run-webkit-tests has not been modified to call it yet.
+ - Only dumps the render tree at this time.
+
+ * WebKitTestRunner: Added.
+ * WebKitTestRunner/Configurations: Added.
+ * WebKitTestRunner/Configurations/Base.xcconfig: Added.
+ * WebKitTestRunner/Configurations/DebugRelease.xcconfig: Added.
+ * WebKitTestRunner/Configurations/InjectedBundle.xcconfig: Added.
+ * WebKitTestRunner/Configurations/WebKitTestRunner.xcconfig: Added.
+ * WebKitTestRunner/InjectedBundle: Added.
+ * WebKitTestRunner/InjectedBundle-Info.plist: Added.
+ * WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp: Added.
+ (_didStartProvisionalLoadForFrame):
+ (_didReceiveServerRedirectForProvisionalLoadForFrame):
+ (_didFailProvisionalLoadWithErrorForFrame):
+ (_didCommitLoadForFrame):
+ (_didFinishLoadForFrame):
+ (_didFailLoadWithErrorForFrame):
+ (_didReceiveTitleForFrame):
+ (_didClearWindow):
+ (_didCreatePage):
+ (_willDestroyPage):
+ (_didRecieveMessage):
+ (WKBundleInitialize):
+ * WebKitTestRunner/Makefile: Added.
+ * WebKitTestRunner/PlatformWebView.h: Added.
+ (WTR::PlatformWebView::platformView):
+ * WebKitTestRunner/TestController.cpp: Added.
+ (WTR::TestController::shared):
+ (WTR::TestController::TestController):
+ (WTR::TestController::initialize):
+ (WTR::TestController::runTest):
+ (WTR::TestController::runTestingServerLoop):
+ (WTR::TestController::run):
+ * WebKitTestRunner/TestController.h: Added.
+ (WTR::TestController::verbose):
+ (WTR::TestController::injectedBundlePath):
+ * WebKitTestRunner/TestInvocation.cpp: Added.
+ (WTR::createWKURL):
+ (WTR::TestInvocation::TestInvocation):
+ (WTR::TestInvocation::~TestInvocation):
+ (WTR::TestInvocation::invoke):
+ (WTR::TestInvocation::dump):
+ (WTR::TestInvocation::initializeMainWebView):
+ (WTR::TestInvocation::didStartProvisionalLoadForFrame):
+ (WTR::TestInvocation::didReceiveServerRedirectForProvisionalLoadForFrame):
+ (WTR::TestInvocation::didFailProvisionalLoadWithErrorForFrame):
+ (WTR::TestInvocation::didCommitLoadForFrame):
+ (WTR::TestInvocation::didFinishLoadForFrame):
+ (WTR::TestInvocation::didFailLoadForFrame):
+ (WTR::TestInvocation::renderTreeExternalRepresentationFunction):
+ (WTR::TestInvocation::renderTreeExternalRepresentationDisposeFunction):
+ * WebKitTestRunner/TestInvocation.h: Added.
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj: Added.
+ * WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj: Added.
+ * WebKitTestRunner/WebKitTestRunnerPrefix.h: Added.
+ * WebKitTestRunner/mac: Added.
+ * WebKitTestRunner/mac/PlatformWebViewMac.mm: Added.
+ (WTR::PlatformWebView::PlatformWebView):
+ (WTR::PlatformWebView::~PlatformWebView):
+ (WTR::PlatformWebView::page):
+ * WebKitTestRunner/mac/TestInvocationMac.mm: Added.
+ (WTR::TestInvocation::runUntil):
+ * WebKitTestRunner/mac/main.mm: Added.
+ (main):
+
+2010-06-24 Luiz Agostini <luiz.agostini@openbossa.org>
+
+ Unreviewed. Adding myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-06-23 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix, adding new LayoutTestController methods and enabling SVG_FOREIGN_OBJECT.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::isPageBoxVisible):
+ (LayoutTestController::pageAreaRectInPixels):
+ (LayoutTestController::preferredPageSizeInPixels):
+ * wx/build/settings.py:
+
+2010-06-23 James Robinson <jamesr@chromium.org>
+
+ Unreviewed. Add my IRC handle to committers.py so the sheriffbot can yell at me.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-06-23 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Correct Chromium test configuration
+ https://bugs.webkit.org/show_bug.cgi?id=41057
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+ - Add "--use-drt" option for NRWT. It is required for Chromium and
+ ignored for other platforms.
+ - Skip JSC test on Chromium
+ * BuildSlaveSupport/test-result-archive:
+ Add Chromium support.
+
+2010-06-23 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=41073
+ WebKit2: Flesh out more of the InjectedBundle client API
+
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (_didStartProvisionalLoadForFrame):
+ (_didReceiveServerRedirectForProvisionalLoadForFrame):
+ (_didFailProvisionalLoadWithErrorForFrame):
+ (_didCommitLoadForFrame):
+ (_didFinishLoadForFrame):
+ (_didFailLoadWithErrorForFrame):
+ (_didReceiveTitleForFrame):
+ (_didClearWindowForFrame):
+ (_didCreatePage):
+ (_willDestroyPage):
+ (WKBundleInitialize):
+
+2010-06-23 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Implement page format data programming interface.
+ Add methods for testing.
+ https://bugs.webkit.org/show_bug.cgi?id=37538
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (parsePageNumber):
+ (isPageBoxVisibleCallback):
+ (pageAreaRectInPixelsCallback):
+ (preferredPageSizeInPixelsCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::isPageBoxVisible):
+ (LayoutTestController::pageAreaRectInPixels):
+ (LayoutTestController::preferredPageSizeInPixels):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::isPageBoxVisible):
+ (LayoutTestController::pageAreaRectInPixels):
+ (LayoutTestController::preferredPageSizeInPixels):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::isPageBoxVisible):
+ (LayoutTestController::pageAreaRectInPixels):
+ (LayoutTestController::preferredPageSizeInPixels):
+
+2010-06-23 Sam Magnuson <smagnuson@netflix.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Follow proper convention for if/switch/while as I've discovered
+ them to be through my review processes.
+ https://bugs.webkit.org/show_bug.cgi?id=40723
+
+ Modified test so that if( foo ) is not allowed as it appears not
+ to be the accepted convention.
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+
+2010-06-22 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Run clean-header-guards to fix some header guards
+ https://bugs.webkit.org/show_bug.cgi?id=41044
+
+ No functional changes, thus no tests.
+
+ This entire change was generated by running
+ clean-header-guards, and then reverting changes
+ to files which shouldn't be changed. Those which
+ are left all should be updated.
+
+ Some of these changes are just fixing 755 permissions
+ to be 644, since it seems various files have the wrong
+ execute bit which don't need it. clean-header-guards
+ made those (welcome) permission fixes unintentionally.
+
+ * DumpRenderTree/chromium/WebThemeControlDRT.h:
+ * DumpRenderTree/chromium/WebThemeEngineDRT.h:
+ * QtTestBrowser/fpstimer.h:
+
+2010-06-22 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Rename HTMLDocumentParser to LegacyHTMLDocumentParser
+ https://bugs.webkit.org/show_bug.cgi?id=41043
+
+ Update the hash.
+
+ * Scripts/do-webcore-rename:
+
+2010-06-22 Sam Magnuson <smagnuson@netflix.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Follow proper convention for variable declaration spacing.
+ https://bugs.webkit.org/show_bug.cgi?id=40724
+
+ Modified test so that 'int a;' is not allowed.
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+
+2010-06-22 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Add Tony Gentilcore now that he's a committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-06-22 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Remove Gtk 64-Release bot from core since it's broken
+ https://bugs.webkit.org/show_bug.cgi?id=41022
+
+ This bot alone has been responsible for more than 72 hours of
+ commit-queue blockage in the last week. The bot is broken -- keeps
+ losing its display server or similar. Until the Gtk folks can fix the
+ bot, we need to remove it from core. The WebKit community can't keep
+ it green as is.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+
+2010-06-21 Dumitru Daniliuc <dumi@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix the Windows build.
+ https://bugs.webkit.org/show_bug.cgi?id=40972
+
+ * DumpRenderTree/win/ImageDiff.vcproj:
+
+2010-06-21 Prasad Tammana <prasadt@chromium.org>
+
+ Reviewed by Darin Adler, Dmitry Titov.
+
+ DumpRenderTree should allow tests with modal dialogs
+ https://bugs.webkit.org/show_bug.cgi?id=35350
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (abortModalCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::abortModal):
+ Add abortModal method to LayoutTestController and make it available from script.
+
+ * DumpRenderTree/mac/UIDelegate.mm: Add support for showModalDialog.
+ (-[UIDelegate modalWindowWillClose:]): Observer for NSWindowWillCloseNotifications to call
+ abortModal from when modal window closes.
+ (-[UIDelegate webViewRunModal:]): Delegate method for showModalDialog to run the modal loop.
+
+2010-06-21 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Anders Carlsson.
+
+ Rename DrawingAreaProxyUpdateChunk to ChunkedUpdateDrawingArea
+ https://bugs.webkit.org/show_bug.cgi?id=40948
+
+ Have the script look in WebKit2.
+
+ * Scripts/do-webcore-rename:
+
+2010-06-21 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Unskip plugins/get-url-that-the-resource-load-delegate-will-disallow.html
+
+ It's a Mac-specific test so just add the required LayoutTestController
+ function as a no-op to avoid failing. Similar approach adopted by other
+ ports.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33344
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::addDisallowedURL):
+
+2010-06-21 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Patch for https://bugs.webkit.org/show_bug.cgi?id=40940
+ Add message passing support to the WebKit2 API.
+
+ - Add some test messages.
+
+ * MiniBrowser/mac/AppDelegate.m:
+ (_didRecieveMessageFromInjectedBundle):
+ (-[BrowserAppDelegate init]):
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m:
+ (_didClearWindow):
+ (_didCreatePage):
+ (_didRecieveMessage):
+ (WKBundleInitialize):
+
+2010-06-21 Drew Wilson <atwilson@chromium.org>
+
+ Unreviewed.
+
+ Rolling back 61551 and 61555 due to test failures.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setEditingBehavior):
+ * DumpRenderTree/mac/UIDelegate.mm:
+
+2010-06-21 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Make DumpRenderTree build with clang++
+
+ * DumpRenderTree/mac/DumpRenderTreePasteboard.m:
+ (-[LocalPasteboard setPropertyList:forType:]):
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ (-[DumpRenderTreeWindow keyDown:]):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::elementDoesAutoCompleteForElementWithId):
+ (LayoutTestController::isCommandEnabled):
+
+2010-06-21 Satish Sampath <satish@chromium.org>
+
+ Reviewed by Steve Block.
+
+ Speech Input Patch 0: Added compilation argument to conditionally compile pending patches.
+ https://bugs.webkit.org/show_bug.cgi?id=40878
+
+ * Scripts/build-webkit:
+
+2010-06-21 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Initialization for http/tests/loading/
+ https://bugs.webkit.org/show_bug.cgi?id=40902
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::runFileTest):
+
+2010-06-21 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Unreviewed.
+
+ Adding myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-06-20 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Add --allow-external-pages option
+ https://bugs.webkit.org/show_bug.cgi?id=40762
+
+ Add --allow-external-pages introduced by Chromium r45403.
+ http://src.chromium.org/viewvc/chrome?view=rev&revision=45403
+
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (main):
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell):
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::allowExternalPages):
+ (TestShell::setAllowExternalPages):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::willSendRequest):
+
+2010-06-20 Joseph Pecoraro <joepeck@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Sheriffbot: Should allow "r" in SVN_REVISION
+ https://bugs.webkit.org/show_bug.cgi?id=40889
+
+ * Scripts/webkitpy/tool/bot/irc_command.py: remove a leading "r" from SVN_REVISION if it exists
+ * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py: test an SVN_REVISION with a leading r.
+
+2010-06-20 Joseph Pecoraro <joepeck@webkit.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Python Tests Fail after r61508
+ https://bugs.webkit.org/show_bug.cgi?id=40891
+
+ Test's regex list needed to be updated to match the new
+ regex list in the source code. Added new bots to the
+ example_buildbots list.
+
+ Regex list fixed in r61512. Updated bot list.
+
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+
+2010-06-20 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Unreviewed, build fix.
+
+ Tweak test regexp list to match the change in http://trac.webkit.org/changeset/61508.
+
+ * Scripts/webkitpy/common/net/buildbot_unittest.py: Tweaked regexp.
+
+2010-06-19 Justin Schuh <jschuh@chromium.org>
+
+ Unreviewed.
+
+ Adding myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-06-19 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=40882
+ Add ability to have a WebProcess per WebContext.
+
+ Move to use new shared contexts API.
+
+ * MiniBrowser/mac/AppDelegate.h:
+ * MiniBrowser/mac/AppDelegate.m:
+ (-[BrowserAppDelegate init]):
+ (-[BrowserAppDelegate getCurrentPageNamespace]):
+ (-[BrowserAppDelegate validateMenuItem:]):
+ (-[BrowserAppDelegate _setProcessModel:]):
+ (-[BrowserAppDelegate setSharedProcessProcessModel:]):
+ (-[BrowserAppDelegate setSharedThreadProcessModel:]):
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::create):
+
+2010-06-02 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ [Qt] Support evaluateScriptInIsolatedWorld()
+
+ https://bugs.webkit.org/show_bug.cgi?id=40079
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::evaluateScriptInIsolatedWorld):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-06-18 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Add three more non-core Chromium builders to start testing DumpRenderTree.
+ https://bugs.webkit.org/show_bug.cgi?id=40335
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json: Added 3 builders.
+
+2010-06-18 Drew Wilson <atwilson@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ [Chromium] Plumbing for top-level frame names
+ https://bugs.webkit.org/show_bug.cgi?id=40430
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::reset):
+ Changed obsolete call to clearName() to use setName(WebString()) instead.
+
+2010-06-18 Sam Weinig <weinig@apple.com>
+
+ Rolling http://trac.webkit.org/changeset/61297 back in.
+
+ * MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj:
+ * MiniBrowser/mac/WebBundle/WebBundleMain.c: Removed.
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m: Added.
+ (_didClearWindow):
+ (_didCreatePage):
+ (WKBundleInitialize):
+
+2010-06-18 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=40803
+ TestNetscapePlugin has an incorrect implementation of "property" property
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp: (pluginGetProperty): Don't
+ pass a static string back, it's going to be released by NPAPI implementation.
+
+2010-06-18 Leandro Pereira <leandro@profusion.mobi>
+
+ Unreviewed.
+
+ Adding myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-06-17 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] cleanup redundant DEPS value and remove buildbot cleanup code
+ https://bugs.webkit.org/show_bug.cgi?id=40615
+
+ * Scripts/update-webkit-chromium: remove directory removal of third_party in old checkouts
+
+2010-06-17 Ada Chan <adachan@apple.com>
+
+ Rolling out http://trac.webkit.org/changeset/61297 due to build errors.
+
+ * MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj:
+ * MiniBrowser/mac/WebBundle/WebBundleMain.c: Copied from MiniBrowser/mac/WebBundle/WebBundleMain.c.
+ * MiniBrowser/mac/WebBundle/WebBundleMain.m: Removed.
+
+2010-06-17 Darin Adler <darin@apple.com>
+
+ One more try at fix for Chromium build.
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell): Use set again instead of =.
+
+2010-06-17 Darin Adler <darin@apple.com>
+
+ Fix Chromium build.
+
+ I didn't realize that neither Chromium nor Qt share the DumpRenderTree
+ code with all the other platforms! Wow, that should be fixed at some point.
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell): Changed back to using "new".
+ * DumpRenderTree/chromium/TestShell.h: Changed back to OwnPtr.
+
+2010-06-17 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Unreviewed Qt build fix.
+
+ LayoutTestController in the Qt DRT is not using refs :)
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2010-06-17 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Use adoptRef and create functions in more code paths
+ https://bugs.webkit.org/show_bug.cgi?id=40760
+
+ * DumpRenderTree/DumpRenderTree.h: Change gLayoutTestController to a RefPtr.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::create): Added.
+ * DumpRenderTree/LayoutTestController.h: Declare the create function.
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell): Use create instead of new.
+ * DumpRenderTree/chromium/TestShell.h: Use RefPtr instead of OwnPtr.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (runTest): Use RefPtr and create instead of OwnPtr and new.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (runTest): Use RefPtr and create instead of OwnPtr and new.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree): Use create and releaseRef
+ instead of new.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest): Use RefPtr and create instead of OwnPtr and new.
+
+ * DumpRenderTree/wx/DumpRenderTreeWx.cpp:
+ (runTest): Use RefPtr and create instead of OwnPtr and new.
+ (MyApp::OnInit): Removed unneeded code to delete the layout
+ test controller. This is done during each test.
+
+2010-06-17 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ [DRT/Chromium] Fix a bug of Windows pixel tests
+ https://bugs.webkit.org/show_bug.cgi?id=40763
+
+ * DumpRenderTree/chromium/TestEventPrinter.cpp:
+ (TestShellPrinter::handleImage):
+
+2010-06-16 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ [DRT/Chromium] Fix crash on Mac Release
+ https://bugs.webkit.org/show_bug.cgi?id=40759
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::paintRect): We should not use m_canvas directly because
+ it is created lazily in canvas().
+
+2010-06-16 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after new method addition.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::pageProperty):
+
+2010-06-16 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Set current working directory for each of tests
+ https://bugs.webkit.org/show_bug.cgi?id=40668
+
+ This change fixes tests with eventSender.beginDragWithFiles().
+
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (runTest):
+
+2010-06-16 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] r60803 broke media/controls-drag-timebar.html
+ https://bugs.webkit.org/show_bug.cgi?id=40269
+
+ Only queue events while the mouse button is down, if drag mode is enabled. Some
+ tests may disable drag mode, to prevent the queuing of events in this situation.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (sendOrQueueEvent): Only queue events here if dragMode is true.
+
+2010-06-16 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] Remove the abuse of GDK_CURRENT_TIME in the DRT
+ https://bugs.webkit.org/show_bug.cgi?id=40600
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (prepareMouseButtonEvent): Remove logic adding an offset to GDK_CURRENT_TIME.
+
+2010-06-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Add a hidden land-cowboy command to webkit-patch to help land quick
+ build fixes.
+
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+
+2010-06-16 Adam Roben <aroben@apple.com>
+
+ Convert console messages to UTF-8 before printing them
+
+ Speculative fix for <http://webkit.org/b/40731> REGRESSION (r61234):
+ http/tests/security/xssAuditor/embed-tag-null-char.html and
+ http/tests/security/xssAuditor/object-embed-tag-null-char.html fail on
+ Windows. (I can't test the fix because Apache is crashing on my
+ computer.)
+
+ Reviewed by Alexey Proskuryakov.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (toUTF8): Extracted the code into an overload that takes a wide string
+ and a length, then added an overload that takes a wstring.
+
+ * DumpRenderTree/win/DumpRenderTreeWin.h: Declare the new toUTF8
+ overload.
+
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::webViewAddMessageToConsole): Use toUTF8 to convert to
+ UTF-8 instead of letting printf convert to the current code page.
+
+2010-06-16 Drew Wilson <atwilson@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [Chromium] Plumbing for top-level frame names
+ https://bugs.webkit.org/show_bug.cgi?id=40430
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::createView):
+ Migrate to new createView() API.
+ * DumpRenderTree/chromium/WebViewHost.h:
+ Remove obsolete createView() methods, add new createView() API that takes a frameName parameter.
+
+2010-06-16 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Scroll wheel event support to graphics based DRT
+ https://bugs.webkit.org/show_bug.cgi?id=40577
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::continuousMouseScrollBy):
+ (EventSender::createGraphicsSceneWheelEvent):
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2010-06-16 Adam Roben <aroben@apple.com>
+
+ Remove a stray newline from the Windows version of TestNetscapePlugin
+
+ Reviewed by Alexey Proskuryakov.
+
+ Fixes <http://webkit.org/b/40728>
+ plugins/geturlnotify-during-document-teardown.html fails on Windows
+
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp:
+ (NPP_Destroy): Removed extra newline that the Mac version doesn't
+ have.
+
+2010-06-16 Adam Roben <aroben@apple.com>
+
+ Respect LayoutTestController::isPrinting on Windows
+
+ This gets some printing tests closer to passing (like
+ printing/page-rule-in-media-query.html).
+
+ Fixes <http://webkit.org/b/40727>.
+
+ Reviewed by Dan Bernstein.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dump): Pass LayoutTestController::isPrinting to
+ IWebFramePrivate::renderTreeAsExternalRepresentation.
+
+2010-06-15 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Enable HTML5 lexer
+ https://bugs.webkit.org/show_bug.cgi?id=40650
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (initializeGlobalsFromCommandLineOptions):
+
+2010-06-10 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Implement render style selection for pages to support CSS3 Paged Media.
+ https://bugs.webkit.org/show_bug.cgi?id=35961
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (parsePagePropertyParameters):
+ (pagePropertyCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::pageProperty):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::pageProperty):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::pageProperty):
+
+2010-06-15 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=40630
+ WebKit2: Add mechanism to inject code into the WebProcess on startup
+
+ Add initial InjectedBundle support.
+
+ * MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj:
+ * MiniBrowser/WebBundle-Info.plist: Added.
+ Add test InjectedBundle to the project.
+
+ * MiniBrowser/mac/AppDelegate.m:
+ (-[BrowserAppDelegate init]):
+ Get the path to the WebBundle from the the main bundle and pass it to the new
+ WKContextCreateWithInjectedBundlePath function.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (_didChangeProgress):
+ Fix the build. This has been broken for a while.
+
+ * MiniBrowser/mac/WebBundle: Added.
+ * MiniBrowser/mac/WebBundle/WebBundleMain.c: Added.
+ (_didCreatePage):
+ (WKBundleInitialize):
+ Add really basic InjectedBundle.
+
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::create):
+ Switch from WKContextCreateWithProcessModel to WKContextCreate and remove commented out code.
+
+2010-06-15 Dumitru Daniliuc <dumi@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Adding myself to the reviewers list.
+ https://bugs.webkit.org/show_bug.cgi?id=40693
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-06-15 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ Switch to using GIO methods instead of realpath in GtkLauncher to determine
+ the file URI. This should remove warnings about realpath being undefined
+ when compiling with '-ansi'.
+
+ * GtkLauncher/main.c:
+ (filenameToURL): Use GIO instead of realpath to determine file URI.
+
+2010-06-15 Adam Roben <aroben@apple.com>
+
+ Remove the redundant set-apple-windows-environment-variables script
+
+ Apparently update-webkit does this for you these days.
+
+ Rubber-stamped by Steve Falkenburg.
+
+ * Scripts/set-apple-windows-environment-variables: Removed.
+
+2010-06-14 Adam Roben <aroben@apple.com>
+
+ Add a script to set the WebKitOutputDir and WebKitLibrariesDir
+ environment variables
+
+ Fixes <http://webkit.org/b/40595>.
+
+ Reviewed by Steve Falkenburg.
+
+ * Scripts/set-apple-windows-environment-variables: Added.
+ (to_windows_path): Passes the passed-in path through cygpath to
+ generate a Windows-style path.
+ (main): Sets the WebKitOutputDir and WebKitLibrariesDir environment
+ variables to their defaults, if they aren't already set.
+
+2010-06-14 Adam Roben <aroben@apple.com>
+
+ Speed up run-safari/debug-safari on Windows
+
+ Fixes <http://webkit.org/b/40586>.
+
+ Reviewed by Steve Falkenburg.
+
+ * Scripts/webkitdirs.pm:
+ (runSafari): When debugging, set up the environment to run Safari
+ using the built WebKit.dll, then use "devenv /debugexe Safari.exe" to
+ actually launch the debugger. When not debugging, just run WebKit.exe
+ and it will do the rest for us.
+
+2010-06-15 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] DRT EventSender support to graphics context events
+ https://bugs.webkit.org/show_bug.cgi?id=40324
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::contextClick):
+
+2010-06-14 Tony Chang <tony@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ [chromium] checkout chromium third_party directly
+ https://bugs.webkit.org/show_bug.cgi?id=40556
+
+ * Scripts/update-webkit-chromium: some migration code for the bots
+
+2010-06-14 Alexey Proskuryakov <ap@apple.com>
+
+ Chromium build fix.
+
+ * DumpRenderTree/chromium/EventSender.cpp: (EventSender::keyDown): Chromium uses differently
+ named constants for Windows virtual key codes, replacing VK_DELETE with VKEY_DELETE.
+
+2010-06-14 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=40529
+ eventSender.keyDown("delete") incorrectly sends a backspace on some platforms
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController keyDown:withModifiers:withLocation:]): We were sending a broken
+ event for "delete" - it had virtual key code from forward delete, and text from backspace.
+ Fixed "delete" to mean forward delete.
+
+ * DumpRenderTree/chromium/EventSender.cpp: (EventSender::keyDown):
+ * DumpRenderTree/gtk/EventSender.cpp: (keyDownCallback):
+ * DumpRenderTree/win/EventSender.cpp: (keyDownCallback):
+ Mac DRT confusion has propagated to other platforms, fixing those.
+
+2010-06-14 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ Small GtkLauncher build fix for some systems.
+
+ * GtkLauncher/main.c: Add <limit.h> include.
+
+2010-06-14 Mahesh Kulkarni <mahesh.kulkarni@nokia.com>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] navigator.geolocation support for Qt port
+ https://bugs.webkit.org/show_bug.cgi?id=39724
+
+ Implementation for geolocation cases to DumpRenderTreeQt
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::allowGeolocationRequest):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setGeolocationPermission):
+ (LayoutTestController::setMockGeolocationError):
+ (LayoutTestController::setMockGeolocationPosition):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::isGeolocationPermissionSet):
+ (LayoutTestController::geolocationPermission):
+
+2010-06-13 Nathan Lawrence <nlawrence@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Outside of Xcode (make or WebKitTools/Scripts), there doesn't seem to
+ be a way of overwriting the Xcode system path. Making
+ $WEBKITOUTPUTDIR take precedence over the system default would make
+ this possible.
+
+ * Scripts/webkitdirs.pm:
+
+2010-06-13 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ AX: link won't return linked element if URL contains #
+ https://bugs.webkit.org/show_bug.cgi?id=40192
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (linkedUIElementAtIndexCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::linkedUIElementAtIndex):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::linkedUIElementAtIndex):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::linkedUIElementAtIndex):
+
+2010-06-13 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ webkit-patch should add a bug URL to ChangeLogs if they don't have one yet
+ https://bugs.webkit.org/show_bug.cgi?id=39550
+
+ This can cause an extra request to bugs.webkit.org durig upload, but it
+ shouldn't be too bad. Also, this won't work if you remove the
+ boilerplate created by prepare-ChangeLog.
+
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ * Scripts/webkitpy/common/checkout/changelog_unittest.py:
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog_unittest.py: Added.
+
+2010-06-08 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] Add support for callShouldCloseOnWebView() to DRT
+ https://bugs.webkit.org/show_bug.cgi?id=40330
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::callShouldCloseOnWebView):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::setCallCloseOnWebViews):
+
+2010-06-12 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ do-webcore-rename should have a --verbose option
+ https://bugs.webkit.org/show_bug.cgi?id=40497
+
+ * Scripts/do-webcore-rename:
+ - Unified how we handle skipping files/directories
+ this will allow us to "black list" certain files and
+ directories when performing renames.
+ - Made do-webcore-rename log what it's skipping when passed --verbose.
+
+2010-06-12 Darin Adler <darin@apple.com>
+
+ * Scripts/run-bindings-tests: Fixed a typo in a message.
+
+2010-06-12 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [Chromium] new-run-webkit-tests --use-drt should work with Chromium checkout
+ https://bugs.webkit.org/show_bug.cgi?id=40402
+
+ _build_path() of each Chromium port check existence of build path
+ of Chromium checkout first, then check existence of build path of
+ WebKit-only checkout.
+
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+
+2010-06-12 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Back-forward list dumping is incorrect
+
+ https://bugs.webkit.org/show_bug.cgi?id=36392
+
+ Support dumping child history items in DRT.
+
+ Unskip:
+
+ fast/loader/frame-src-change-added-to-history.html
+ fast/loader/frame-src-change-not-added-to-history.html
+ fast/loader/frame-location-change-not-added-to-history.html
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::dumpHistoryItem):
+
+2010-06-10 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ upload all patches that lack in-rietveld to rietveld
+ https://bugs.webkit.org/show_bug.cgi?id=40444
+
+ If it's a patch, then we'll try to upload it as long as it
+ doesn't have in-rietveld set. No longer set in-rietveld? since
+ it's not needed.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+
+2010-06-10 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ Fix rietveld upload when message length > 100 characters
+ https://bugs.webkit.org/show_bug.cgi?id=40457
+
+ * Scripts/webkitpy/common/net/rietveld.py:
+
+2010-06-11 Yael Aharon <yael.aharon@nokia.com>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] There should be a way to enable popups in QtTestBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=40427
+
+ * QtTestBrowser/main.cpp:
+ (LauncherWindow::toggleJavascriptCanOpenWindows):
+ (LauncherWindow::createChrome):
+
+2010-06-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ Make SheriffBot more chatty
+ https://bugs.webkit.org/show_bug.cgi?id=40463
+
+ People seem to like to talk to SheriffBot, so let's make him chat back.
+
+ * Scripts/webkitpy/thirdparty/__init__.py:
+ * Scripts/webkitpy/tool/bot/irc_command.py:
+ * Scripts/webkitpy/tool/bot/irc_command_unittest.py: Added.
+ * Scripts/webkitpy/tool/bot/sheriffircbot.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py:
+
+2010-06-10 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Fix the Windows buildbot when WebKitAuxiliaryLibs.zip cannot be found on our server.
+
+ Robustify update-webkit-auxiliary-libs to be able to handle the case when WebKitAuxiliaryLibs.zip doesn't exist,
+ and allow the script to fall back to an existing file, only failing if there is no fallback file. Also switch to checking
+ WEXITSTATUS on $result instead of just comparing $result to 0.
+
+ * Scripts/update-webkit-auxiliary-libs:
+
+2010-06-10 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ don't use Exception.message as it's deprecated in python 2.6+
+ https://bugs.webkit.org/show_bug.cgi?id=40449
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-06-10 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ fix handle_script_error in rietveld upload queue and add testing for handle_script_error
+ https://bugs.webkit.org/show_bug.cgi?id=40436
+
+ * Scripts/webkitpy/common/system/outputcapture.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-06-10 Jarkko Sakkinen <jarkko.j.sakkinen@gmail.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] *All* WebGL layout tests fail!
+ https://bugs.webkit.org/show_bug.cgi?id=40296
+
+ Added test for WebKitWebGLEnabled to
+ LayoutTestController::overridePreference().
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::overridePreference):
+
+2010-06-10 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] DRT EventSender support to graphics mouse events activation
+ https://bugs.webkit.org/show_bug.cgi?id=40017
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::mouseDown):
+ (EventSender::mouseUp):
+ (EventSender::mouseMoveTo):
+ (EventSender::keyDown):
+ (EventSender::contextClick):
+ (EventSender::sendTouchEvent):
+ (EventSender::sendOrQueueEvent):
+ (EventSender::eventFilter):
+ (EventSender::createGraphicsSceneMouseEvent):
+ (EventSender::sendEvent):
+ * DumpRenderTree/qt/EventSenderQt.h:
+ (EventSender::isGraphicsBased):
+
+2010-06-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Ojan Vafai.
+
+ webkit-patch upload fails for security bugs because there's no rietveld flag
+ https://bugs.webkit.org/show_bug.cgi?id=40309
+
+ There's probably a more elegant way of seeing whether the form control
+ exists, but this seems to work.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+
+2010-06-09 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ make rietveld upload faster and avoid posting to bug on errors
+ https://bugs.webkit.org/show_bug.cgi?id=40389
+
+ Only grab the first item of the upload queue instead of trying
+ to compute the whole list upfront (which is O(n) bugzilla lookups!).
+
+ Also, don't post comments to the bug when uploading fails.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/stepsequence.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-06-09 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Rietveld upload queue fails when setting in-rietveld flag
+ https://bugs.webkit.org/show_bug.cgi?id=40371
+
+ Make the comment arguments to set_flag_on_attachment optional
+ and add it to the MockBugzilla.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-06-09 Kenneth Russell <kbr@google.com>
+
+ Reviewed by Dimitri Glazkov.
+
+ Rename FloatArray to Float32Array
+ https://bugs.webkit.org/show_bug.cgi?id=40323
+
+ Used do-webcore-rename to perform renaming. Manually undid
+ incorrect changes to WebCore/bridge/jni/jsc/JNIBridgeJSC.cpp,
+ WebCore/manual-tests/resources/ArrayParameterTestApplet.java and
+ ArrayParameterTestApplet.class. Updated LayoutTests. Built and ran
+ all layout tests on Safari; built Chromium and ran selected WebGL
+ tests.
+
+ * Scripts/do-webcore-rename:
+
+2010-06-08 Tony Chang <tony@chromium.org>
+
+ Reviewed by David Levin.
+
+ [chromium] compile linux chromium in WebKit/out instead of WebKit/WebKit/chromium/out
+ https://bugs.webkit.org/show_bug.cgi?id=40285
+
+ * Scripts/webkitdirs.pm:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+
+2010-06-03 Roland Steiner <rolandsteiner@chromium.org>
+
+ Reviewed by Tamura Kent.
+
+ Bug 40052 - [DRT/Chromium] Upstream test_shell_webthemeengine as WebThemeEngineDRT
+ https://bugs.webkit.org/show_bug.cgi?id=40052
+
+ Add WebThemeEngineDRT and WebThemeControlDRT ported from Chromium rev. 48907
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+ * DumpRenderTree/chromium/TestShellWin.cpp:
+ (platformInit):
+ * DumpRenderTree/chromium/WebThemeControlDRT.cpp: Added.
+ (WebKit::):
+ (WebKit::WebThemeControlDRT::WebThemeControlDRT):
+ (WebKit::WebThemeControlDRT::~WebThemeControlDRT):
+ (WebKit::WebThemeControlDRT::box):
+ (WebKit::WebThemeControlDRT::line):
+ (WebKit::WebThemeControlDRT::triangle):
+ (WebKit::WebThemeControlDRT::roundRect):
+ (WebKit::WebThemeControlDRT::oval):
+ (WebKit::WebThemeControlDRT::circle):
+ (WebKit::WebThemeControlDRT::nestedBoxes):
+ (WebKit::WebThemeControlDRT::markState):
+ (WebKit::WebThemeControlDRT::draw):
+ (WebKit::WebThemeControlDRT::drawTextField):
+ (WebKit::WebThemeControlDRT::drawProgressBar):
+ * DumpRenderTree/chromium/WebThemeControlDRT.h: Added.
+ (WebKit::WebThemeControlDRT::):
+ * DumpRenderTree/chromium/WebThemeEngineDRT.cpp: Added.
+ (WebKit::):
+ (WebKit::WebThemeEngineDRT::paintButton):
+ (WebKit::WebThemeEngineDRT::paintMenuList):
+ (WebKit::WebThemeEngineDRT::paintScrollbarArrow):
+ (WebKit::WebThemeEngineDRT::paintScrollbarThumb):
+ (WebKit::WebThemeEngineDRT::paintScrollbarTrack):
+ (WebKit::WebThemeEngineDRT::paintTextField):
+ (WebKit::WebThemeEngineDRT::paintTrackbar):
+ (WebKit::WebThemeEngineDRT::paintProgressBar):
+ * DumpRenderTree/chromium/WebThemeEngineDRT.h: Added.
+ (WebKit::WebThemeEngineDRT::WebThemeEngineDRT):
+
+2010-06-08 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r60878.
+ http://trac.webkit.org/changeset/60878
+ https://bugs.webkit.org/show_bug.cgi?id=40349
+
+ broke linux build (Requested by tony^work on #webkit).
+
+ * Scripts/webkitdirs.pm:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+
+2010-06-08 Tony Chang <tony@chromium.org>
+
+ Reviewed by David Levin.
+
+ [chromium] compile linux chromium in WebKit/out instead of WebKit/WebKit/chromium/out
+ https://bugs.webkit.org/show_bug.cgi?id=40285
+
+ * Scripts/webkitdirs.pm:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+
+2010-06-08 Kenneth Russell <kbr@google.com>
+
+ Unreviewed, build fix.
+
+ Fix build breakage from 38145
+ https://bugs.webkit.org/show_bug.cgi?id=40346
+
+ The fix for bug 38145 broke the Chromium Win build because
+ Microsoft's cmath doesn't define log2. Suggested fix by zmo is to
+ change log2(x) to log(x) / log(2). Built and ran WebGL layout
+ tests in Safari on Mac OS X. Changed download mirrors for
+ python-irclib to working ones.
+
+ * Scripts/webkitpy/thirdparty/__init__.py:
+
+2010-06-08 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ old-run-webkit-tests should use ensure-valid-python to check if it can run the websockets tests
+ https://bugs.webkit.org/show_bug.cgi?id=39058
+
+ * Scripts/old-run-webkit-tests:
+ use sourceDir() to find ensure-valid-python in checkPythonVersion()
+
+2010-06-08 Andras Becsi <abecsi@webkit.org>
+
+ Unreviewed buildfix after r60479.
+
+ [GTK] Move the declaration of getRootCoords higher up to fix the build on GTK
+ versions other than 2.17.3.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (getRootCoords):
+
+2010-06-07 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Oliver Hunt.
+
+ [GTK] Mouse movement should not trigger a replay of saved events in the event sender
+ https://bugs.webkit.org/show_bug.cgi?id=40267
+
+ When a mouse button is down, automatically queue mouse motion events and
+ do not play them back until the mouse button is released. This matches the
+ behavior of other ports' EventSenders.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (mouseMoveToCallback): Don't automatically replaySavedEvents for mouse motion.
+ (sendOrQueueEvent): Add a shouldReplaySavedEvents argument defaulting to true.
+
+2010-06-07 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Reviewed by Sam Weinig.
+
+ Add CPP bindings generator
+ https://bugs.webkit.org/show_bug.cgi?id=38279
+
+ Integrate CPP bindings in run-bindings-tests.
+
+ * Scripts/run-bindings-tests:
+
+2010-06-04 Tony Gentilcore <tonyg@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ Rename 'svn_merge_base' -> 'remote_merge_base'. This was left out of r60633.
+ https://bugs.webkit.org/show_bug.cgi?id=40183
+
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+
+2010-06-04 Martin Robinson <mrobinson@igalia.com>
+
+ Unreviewed.
+
+ Add my new email and IRC nick to committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-06-04 Kinuko Yasuda <kinuko@chromium.org>
+
+ Unreviewed.
+
+ Revert changes in json_results_generator.py's _get_svn_revision.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+
+2010-06-04 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] GtkLauncher should support relative file paths
+ https://bugs.webkit.org/show_bug.cgi?id=39944
+
+ Allow GtkLauncher to handle relative file paths passed via command-line arguments.
+
+ * GtkLauncher/main.c:
+ (filename_to_url): Added.
+ (main): Try to resolve arguments as relative file URLs first.
+
+2010-06-04 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] EventSender should call gtk_main_do_event instead of invoking signal handlers directly
+ https://bugs.webkit.org/show_bug.cgi?id=40182
+
+ Instead of invoking signal handlers directly via g_signal_emit_by_name, call
+ gtk_main_do_event. This will allow us to call gtk_get_current_event() in WebKit
+ without breaking DRT.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (dispatchEvent): Use gtk_main_do_event instead of invoking signal handlers directly.
+ (keyDownCallback): Use dispatchEvent here which now uses gtk_main_do_event.
+
+2010-06-04 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by David Hyatt.
+
+ Make the editing/spelling/context-menu-suggestions.html test more robust
+ https://bugs.webkit.org/show_bug.cgi?id=40178
+
+ Change the contextClick method to return an array of strings describing the context menu items.
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (+[EventSendingController webScriptNameForSelector:]):
+ (-[EventSendingController contextClick]):
+
+2010-06-03 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Clean up chromium-specific code from json_results_generator.py.
+ https://bugs.webkit.org/show_bug.cgi?id=39665
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-06-04 Tony Gentilcore <tonyg@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Utilize new takeFirst() method where appropriate.
+ https://bugs.webkit.org/show_bug.cgi?id=40089
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::replaySavedEvents):
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::WorkQueue::processWork):
+ (LayoutTestController::WorkQueue::reset):
+
+2010-06-04 Yael Aharon <yael.aharon@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] QtTestLauncher should allow notifications by default.
+ https://bugs.webkit.org/show_bug.cgi?id=40078
+
+ * QtTestBrowser/main.cpp:
+ (NotificationsPermissionController::NotificationsPermissionController):
+ (NotificationsPermissionController::checkPermission):
+ (NotificationsPermissionController::requestPermission):
+ (LauncherWindow::LauncherWindow):
+
+2010-06-04 Tony Gentilcore <tonyg@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Detect whether the user's environment can open a browser.
+ https://bugs.webkit.org/show_bug.cgi?id=40136
+
+ Some environments like cygwin silently fail webbrowser.open() causing
+ webkit-patch upload not to display any diff. This detects environments
+ where webbrowser.open() would fail by testing if webbrowser.get()
+ raises an exception.
+
+ * Scripts/webkitpy/common/system/user.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/confirmdiff.py:
+
+2010-06-03 Tony Gentilcore <tonyg@chromium.org>
+
+ Reviewed by David Levin.
+
+ Add dependencies required to link with VS Express 2005.
+ https://bugs.webkit.org/show_bug.cgi?id=40038
+
+ Visual Studio implicitly links against these libs.
+ VC++ Express does not.
+
+ * WebKitAPITest/WebKitAPITestCommon.vsprops:
+ * WinLauncher/WinLauncher.vcproj:
+
+2010-06-03 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by David Levin.
+
+ bad codecs.open in webkitpy/layout_tests/ports/websocket_server.py
+ https://bugs.webkit.org/show_bug.cgi?id=40105
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ - kill pywebsocket process when url is not alive and the process is not
+ terminated, not to leave pywebsocket server running.
+ - fix codecs.open parameters.
+
+2010-06-03 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ old-run-webkit-tests should use ensure-valid-python to check if it can run the websockets tests
+ https://bugs.webkit.org/show_bug.cgi?id=39058
+
+ * Scripts/ensure-valid-python:
+ - Perl 5.8 doesn't have File::Temp->newdir(). Use File::Temp->tempdir() instead.
+ - Add --check-only and --help option.
+ - --check-only option only checks python version and don't try to install Python 2.5.
+ - Set executable bit.
+ * Scripts/old-run-webkit-tests:
+ - Check if it can run the websocket tests by calling ensure-valid-python --check-only.
+
+2010-05-14 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ add a RietveldUploadQueue to upload in-rietveld? patches to rietveld
+ https://bugs.webkit.org/show_bug.cgi?id=38918
+
+ Patches with in-rietveld? get uploaded to rietveld and get marked
+ in-rietveld+. If the upload fails, they are marked in-rietveld-
+ and an error is logged to the bug, like the commit-queue.
+
+ Also, get rid of --fancy-review and the ability to upload to rietveld
+ using webkit-patch upload/post.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/options.py:
+ * Scripts/webkitpy/tool/steps/postcodereview.py:
+
+2010-05-24 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Chris Jerdonek.
+
+ many webkit-patch commands fail in a non-svn tracking git checkout
+ https://bugs.webkit.org/show_bug.cgi?id=38156
+
+ If the svn-tracking-branch (trunk) doesn't exist, fallback to the git remote-tracking-branch (master).
+ If neither exists, then error out. This makes webkit-patch work
+ for anyone that follows the intructions at http://trac.webkit.org/wiki/UsingGitWithWebKit
+ to checkout webkit. The fallback to master is for people who don't
+ do the steps on that page for tracking svn.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+
+2010-06-03 Mike Fenton <mifenton@rim.com>
+
+ Unreviewed.
+
+ Reverse e-mail for myself in committers.py to correspond with bugzilla account.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-06-03 Pavel Feldman <pfeldman@chromium.org>
+
+ Reviewed by Yury Semikhatsky.
+
+ Web Inspector: a number of fixes that make InspectorController
+ happy with null redirects.
+
+ https://bugs.webkit.org/show_bug.cgi?id=40109
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (runTest):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (runTest):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest):
+
+2010-06-02 Tasuku Suzuki <tasuku.suzuki@nokia.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ [Qt] Fix compilation with QT_NO_PROPERTIES
+ https://bugs.webkit.org/show_bug.cgi?id=38324
+
+ * QtTestBrowser/main.cpp:
+ (LauncherWindow::init):
+
+2010-06-02 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Make possible run DRT with QGraphicsWebView
+ https://bugs.webkit.org/show_bug.cgi?id=40016
+
+ Make possible to use a environment variable for switching backend.
+ Usage: QT_DRT_WEBVIEW_MODE=graphics WebKitTools/Scripts/run-webkit-tests --qt
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebViewGraphicsBased::WebViewGraphicsBased):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ (WebCore::DumpRenderTree::setGraphicsBased):
+ (WebCore::DumpRenderTree::isGraphicsBased):
+ (WebCore::WebViewGraphicsBased::graphicsView):
+ (WebCore::WebViewGraphicsBased::setPage):
+ * Scripts/old-run-webkit-tests:
+
+2010-06-02 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Slave lost shouldn't be recognized as build failed.
+ https://bugs.webkit.org/show_bug.cgi?id=39282
+
+ * Scripts/webkitpy/common/net/buildbot.py: Treat slave lost as green.
+ * Scripts/webkitpy/common/net/buildbot_unittest.py: Add unit test for slave lost.
+
+2010-06-01 Yael Aharon <yael.aharon@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Fix the lifecycle of notification objects
+ https://bugs.webkit.org/show_bug.cgi?id=40003
+
+ Remove the dependency of notifications on QWebPage.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::requestPermissionCallback):
+ (WebCore::WebPage::WebPage):
+ (WebCore::DumpRenderTree::requestPermission):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+
+2010-06-02 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r60559.
+ http://trac.webkit.org/changeset/60559
+ https://bugs.webkit.org/show_bug.cgi?id=40055
+
+ It broke python unit test (Requested by Ossy on #webkit).
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+
+2010-06-02 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Slave lost shouldn't be recognized as build failed.
+ https://bugs.webkit.org/show_bug.cgi?id=39282
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+
+2010-06-02 Tony Gentilcore <tonyg@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix crash caused when assigned_to is disabled
+ https://bugs.webkit.org/show_bug.cgi?id=40039
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+
+2010-06-02 Sterling Swigart <sswigart@google.com>
+
+ Reviewed by David Levin.
+
+ Image Resizer Patch 0: Added compilation argument to conditionally compile pending patches.
+ https://bugs.webkit.org/show_bug.cgi?id=39906
+
+ * Scripts/build-webkit:
+
+2010-06-01 Raine Makelainen <raine.makelainen@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Fixed tests to use QWebSettings::JavascriptCanAccessClipboard instead of QWebSettings::JavaScriptCanAccessClipboard.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+
+2010-06-01 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ A nicer Tiger build fix.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/Configurations/Base.xcconfig:
+ Enable GCC_OBJC_CALL_CXX_CDTORS via .xcconfig.
+
+2010-06-01 Alexey Proskuryakov <ap@apple.com>
+
+ A real Tiger build fix.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Enable GCC_OBJC_CALL_CXX_CDTORS
+ for all configurations, not just debug.
+
+2010-06-01 Alexey Proskuryakov <ap@apple.com>
+
+ Tiger build fix.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Enable GCC_OBJC_CALL_CXX_CDTORS.
+
+2010-06-01 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Get more mouse tests passing
+ https://bugs.webkit.org/show_bug.cgi?id=39040
+
+ Reproduce the logic from the Windows EventSender for mapping
+ button numbers to GDK button numbers. Move this logic to the
+ prepareMouseButtonEvent helper.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (prepareMouseButtonEvent): Reproduce Windows logic.
+ (contextClickCallback): Move mapping logic to prepareMouseButtonEvent.
+ (mouseDownCallback): Ditto.
+ (mouseUpCallback): Ditto.
+
+2010-06-01 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=39434
+ REGRESSION (r59811): Geolocation callbacks cannot be created
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Added MockGeolocationProvider.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (createWebViewAndOffscreenWindow): Tell the view to use MockGeolocationProvider.
+ (resetWebViewToConsistentStateBeforeTesting): Make sure that mock notifications don't leak
+ into subsequent tests.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMockGeolocationPosition): Changed to use MockGeolocationProvider.
+ (LayoutTestController::setMockGeolocationError): Ditto.
+
+ * DumpRenderTree/mac/MockGeolocationProvider.h: Added.
+ * DumpRenderTree/mac/MockGeolocationProvider.mm: Added.
+ (+[MockGeolocationProvider shared]):
+ (-[MockGeolocationProvider dealloc]):
+ (-[MockGeolocationProvider setPosition:]):
+ (-[MockGeolocationProvider setError:]):
+ (-[MockGeolocationProvider registerWebView:]):
+ (-[MockGeolocationProvider unregisterWebView:]):
+ (-[MockGeolocationProvider lastPosition]):
+ (-[MockGeolocationProvider stopTimer]):
+ (-[MockGeolocationProvider timerFired]):
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:decidePolicyForGeolocationRequestFromOrigin:frame:listener:]):
+ This delegate method must send a response. I'm not sure what the two-stage check is supposed
+ to achieve, it seems unnecessary.
+
+2010-05-12 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Double clicks cause three button press events
+ https://bugs.webkit.org/show_bug.cgi?id=38853
+
+ WebKit now filters the extra GDK_BUTTON_PRESS before GDK_2BUTTON_PRESS
+ and GDK_3BUTTON_PRESS via gdk_event_peek(). Since EventSender bypasses
+ the GDK event queue entirely, we simply do not send the extra event.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (mouseDownCallback): Do not send extra event. Send GDK_3BUTTON_PRESS appropriately.
+ (dispatchEvent): Properly handle GDK_3BUTTON_PRESS.
+
+2010-06-01 Martin Robinson <mrobinson@igalia.com>
+
+ Not reviewed. Build fix.
+
+ Fix GTK+ build caused by a bad merge.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (prepareMouseButtonEvent): Use the GdkEvent union as a pointer here.
+
+2010-06-01 Martin Robinson <mrobinson@webkit.org>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Double clicks cause three button press events
+ https://bugs.webkit.org/show_bug.cgi?id=38853
+
+ Small EventSender cleanups. Consolidate some common code. Style fixes.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (prepareMouseButtonEvent): Added.
+ (contextClickCallback): Use prepareMouseButtonEvent.
+ (mouseDownCallback): Use prepareMouseButtonEvent.
+ (mouseUpCallback): Use prepareMouseButtonEvent.
+ (mouseMoveToCallback): Small style fix.
+
+2010-06-01 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Double clicks cause three button press events
+ https://bugs.webkit.org/show_bug.cgi?id=38853
+
+ Add rudimentary leapForward support to the GTK+ DRT. leapForward allows a test
+ to pause for a specified amount of time. It is used in the processing of drag-
+ -and-drop data as well as to separate distinct mouse double-clicks in some tests.
+ This patch enables tests that rely on the latter behavior to pass.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewWindowObjectCleared): Only initialize the EventSender when loading the top frame.
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (leapForwardCallback): Add support for adjusting the time offset on leapForward().
+ (contextClickCallback): Use sendOrQueueEvent.
+ (updateClickCount): Take the time offset into account when counting clicks.
+ (mouseDownCallback): Use sendOrQueueEvent.
+ (getStateFlags): Change down/currentEventButton into buttonCurrentlyDown/lastClickButton.
+ (mouseUpCallback): Use sendOrQueueEvent.
+ (mouseMoveToCallback): Ditto.
+ (mouseWheelToCallback): Ditto.
+ (sendOrQueueEvent): Added.
+ (dispatchEvent): Added.
+ (replaySavedEvents): Pause when an event has a delay and defer to dispatchEvent.
+ (makeEventSender): Only initialize the EventSender when loading the top frame.
+ * DumpRenderTree/gtk/EventSender.h: Ditto.
+
+2010-06-01 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] css1/color_and_background/background_attachment.html fails on the 32-bit debug bot
+ https://bugs.webkit.org/show_bug.cgi?id=39101
+
+ Work around timing issues for render tree dumps by pumping the
+ main loop before doing the dump. Resize events are asynchronous
+ in GTK+, so sometimes resize requests are still pending when DRT
+ dumps the tree.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump): Pump the main loop before dumping the render tree.
+
+2010-05-31 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Fix crash of a test after another test with multiple windows
+ https://bugs.webkit.org/show_bug.cgi?id=39942
+
+ If a test opens multiple windows, focuses on non-main window, and
+ the focused window is closed, TestShell::m_focusedWidget points a
+ deleted object.
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::closeWindow): Clear m_focusedWidget.
+
+2010-05-30 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ new-run-webkit-tests: Support DRT on Chromium-win
+ https://bugs.webkit.org/show_bug.cgi?id=39810
+
+ Add --test-shell flag to DRT/Chromium, and it changes DRT so that
+ it behaves like test_shell about command analysis, printing
+ format, pixel dumping, and timeout handling.
+
+ chromium.py and chromium_win.py supports the --test-shell flag and
+ DRT/Chromium-win binary names.
+
+ * DumpRenderTree/DumpRenderTree.gypi: Add new files.
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (runTest): Support for test_shell-style command.
+ (main): Introduce --test-shell.
+ * DumpRenderTree/chromium/TestEventPrinter.cpp: Added.
+ * DumpRenderTree/chromium/TestEventPrinter.h: Added.
+ TestEventPrinter class manages stdio output and image output.
+ TestEventPrinter.cpp has two implementations; DRTPrinter and
+ TestShellPrinter.
+ * DumpRenderTree/chromium/TestShell.cpp:
+ Some changes for TestEventPrinter.
+ (TestShell::TestShell):
+ (TestShell::runFileTest):
+ (TestShell::testTimedOut):
+ (TestShell::dump):
+ (TestShell::dumpImage):
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::printer):
+ (TestShell::layoutTestTimeout):
+ (TestShell::layoutTestTimeoutForWatchDog):
+ (TestShell::setLayoutTestTimeout):
+ * DumpRenderTree/chromium/TestShellWin.cpp:
+ (watchDogThread): Use TestShell::layoutTestTimeoutForWatchDog().
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+
+2010-05-30 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Enhance Qt DRT implementation to support platform scroll wheel events.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36004
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::EventSender): QApplication::setWheelScrollLines(2) in order to match
+ Scrollbar::pixelsPerLineStep() for DRT testing.
+ (EventSender::mouseScrollBy): Added
+ (EventSender::continuousMouseScrollBy): Added
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2010-05-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by David Levin.
+
+ webkit-patch should support CHANGE_LOG_EDIT_APPLICATION
+ https://bugs.webkit.org/show_bug.cgi?id=39546
+
+ One sublty is that we want to wait for the user to finish editing the
+ ChangeLog before moving on to the next step. That means we want to pass
+ -W to open. However, if the user is using Xcode to edit the ChangeLog,
+ we don't want them to have to exit the Xcode application. For this reason,
+ we create a new instance of the application with -n.
+
+ Overall, xed seems like a better solution, so we recommend that too.
+
+ * Scripts/webkitpy/common/system/user.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/editchangelog.py:
+
+2010-05-21 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: fix handling of Ctrl-C to exit even if some
+ threads are wedged. Also, the script will print the results of the
+ tests completed when the interrupt occurs.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33238
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-05-28 Darin Adler <darin@apple.com>
+
+ Ignore more Python messiness.
+
+ * Scripts/webkitpy/layout_tests/data/platform/test: Added property svn:ignore.
+ * Scripts/webkitpy/layout_tests/layout_package: Added property svn:ignore.
+ * Scripts/webkitpy/layout_tests/test_types: Added property svn:ignore.
+ * Scripts/webkitpy/test: Added property svn:ignore.
+ * Scripts/webkitpy/thirdparty/simplejson: Added property svn:ignore.
+
+2010-05-28 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Adding myself as a reviewer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-05-28 Chris Fleizach <cfleizach@apple.com>
+
+ Build fix. No review.
+
+ AX: need to catch NSAccessibilityExceptions in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=39881
+
+ It looks like Tiger doesn't like seeing a NSMakeRange inside a @try.
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::rowIndexRange):
+ (AccessibilityUIElement::columnIndexRange):
+ (AccessibilityUIElement::selectedTextRange):
+
+2010-05-28 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ AX: need to catch NSAccessibilityExceptions in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=39881
+
+ Normally, accessibility exceptions are caught in the AX Runtime on the Mac, but
+ because DRT is its own AX client, no one is there to catch these otherwise innocuous exceptions.
+
+ So DRT should wrap exception handlers around its AX related calls.
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (attributesOfElement):
+ (AccessibilityUIElement::getLinkedUIElements):
+ (AccessibilityUIElement::getDocumentLinks):
+ (AccessibilityUIElement::getChildren):
+ (AccessibilityUIElement::getChildrenWithRange):
+ (AccessibilityUIElement::ariaOwnsElementAtIndex):
+ (AccessibilityUIElement::ariaFlowToElementAtIndex):
+ (AccessibilityUIElement::disclosedRowAtIndex):
+ (AccessibilityUIElement::selectedRowAtIndex):
+ (AccessibilityUIElement::titleUIElement):
+ (AccessibilityUIElement::parentElement):
+ (AccessibilityUIElement::disclosedByRow):
+ (AccessibilityUIElement::stringAttributeValue):
+ (AccessibilityUIElement::boolAttributeValue):
+ (AccessibilityUIElement::isAttributeSettable):
+ (AccessibilityUIElement::isAttributeSupported):
+ (AccessibilityUIElement::role):
+ (AccessibilityUIElement::subrole):
+ (AccessibilityUIElement::roleDescription):
+ (AccessibilityUIElement::title):
+ (AccessibilityUIElement::description):
+ (AccessibilityUIElement::orientation):
+ (AccessibilityUIElement::stringValue):
+ (AccessibilityUIElement::language):
+ (AccessibilityUIElement::helpText):
+ (AccessibilityUIElement::x):
+ (AccessibilityUIElement::y):
+ (AccessibilityUIElement::width):
+ (AccessibilityUIElement::height):
+ (AccessibilityUIElement::clickPointX):
+ (AccessibilityUIElement::clickPointY):
+ (AccessibilityUIElement::intValue):
+ (AccessibilityUIElement::minValue):
+ (AccessibilityUIElement::maxValue):
+ (AccessibilityUIElement::valueDescription):
+ (AccessibilityUIElement::insertionPointLineNumber):
+ (AccessibilityUIElement::isActionSupported):
+ (AccessibilityUIElement::isEnabled):
+ (AccessibilityUIElement::isRequired):
+ (AccessibilityUIElement::isSelected):
+ (AccessibilityUIElement::isExpanded):
+ (AccessibilityUIElement::hierarchicalLevel):
+ (AccessibilityUIElement::ariaIsGrabbed):
+ (AccessibilityUIElement::ariaDropEffects):
+ (AccessibilityUIElement::lineForIndex):
+ (AccessibilityUIElement::boundsForRange):
+ (AccessibilityUIElement::stringForRange):
+ (AccessibilityUIElement::attributesOfColumnHeaders):
+ (AccessibilityUIElement::attributesOfRowHeaders):
+ (AccessibilityUIElement::attributesOfColumns):
+ (AccessibilityUIElement::attributesOfRows):
+ (AccessibilityUIElement::attributesOfVisibleCells):
+ (AccessibilityUIElement::attributesOfHeader):
+ (AccessibilityUIElement::rowCount):
+ (AccessibilityUIElement::columnCount):
+ (AccessibilityUIElement::indexInTable):
+ (AccessibilityUIElement::rowIndexRange):
+ (AccessibilityUIElement::columnIndexRange):
+ (AccessibilityUIElement::cellForColumnAndRow):
+ (AccessibilityUIElement::selectedTextRange):
+ (AccessibilityUIElement::setSelectedTextRange):
+ (AccessibilityUIElement::increment):
+ (AccessibilityUIElement::decrement):
+ (AccessibilityUIElement::showMenu):
+ (AccessibilityUIElement::press):
+ (AccessibilityUIElement::url):
+ (AccessibilityUIElement::hasPopup):
+
+2010-05-28 Yael Aharon <yael.aharon@nokia.com>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] Pass all web notification layout tests
+ https://bugs.webkit.org/show_bug.cgi?id=39146
+
+ Mimic Chromium's test_shell security model in Qt's DRT.
+ It makes a list of origins which were granted permission to display
+ notifications, and only those origins can display notifications.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::checkPermissionCallback):
+ (WebCore::requestPermissionCallback):
+ (WebCore::WebPage::WebPage):
+ (WebCore::DumpRenderTree::checkPermission):
+ (WebCore::DumpRenderTree::requestPermission):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::grantDesktopNotificationPermission):
+ (LayoutTestController::checkDesktopNotificationPermission):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-05-27 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ check-webkit-style complains about use of NULL in GTK function calls that require sentinels
+ https://bugs.webkit.org/show_bug.cgi?id=39372
+
+ Don't warn about NULL in g_*() calls. Zero can't be used instead
+ for calls like g_build_filename and g_object_get/set.
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+
+2010-05-27 Luiz Agostini <luiz.agostini@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Platform plugin example
+ https://bugs.webkit.org/show_bug.cgi?id=39489
+
+ Exempting directory WebKit/qt/examples/ from style guide.
+
+ * Scripts/webkitpy/style/checker.py:
+
+2010-05-26 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by David Levin.
+
+ [style] Allow usage of NULL in gst_*_many()
+ https://bugs.webkit.org/show_bug.cgi?id=39740
+
+ Don't warn if NULL is used by gst_*_many() functions. Zero can't
+ be used for the reason explained in Bug 32858.
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+
+2010-05-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Update script to run the normal version of the parser tests.
+
+ * Scripts/test-html5-parser:
+
+2010-05-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add HTML5 parser support to run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=39815
+
+ * Scripts/old-run-webkit-tests:
+
+2010-05-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Make HTML5 lexer not ASSERT when resuming partial parses
+ https://bugs.webkit.org/show_bug.cgi?id=39755
+
+ Add webkit-resumer.html to the HTML5 parser test suite.
+
+ * Scripts/test-html5-parser:
+
+2010-05-24 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] setup fonts on chromium linux DRT
+ https://bugs.webkit.org/show_bug.cgi?id=39644
+
+ * DumpRenderTree/chromium/TestShellGtk.cpp:
+ (setupFontconfig):
+ (platformInit):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::paintRect): Fix a bug where in release builds, we didn't initialize m_canvas.
+ * DumpRenderTree/chromium/fonts.conf: Added.
+
+2010-05-24 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Re-commit r58765 - it had been rolled out to see if it was causing
+ a perf regression (in r59787 and r59789), but that does not seem to
+ have been the case.
+
+ https://bugs.webkit.org/show_bug.cgi?id=39605
+
+ * DumpRenderTree/chromium/NotificationPresenter.cpp:
+ (NotificationPresenter::show):
+
+2010-05-25 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Chris Jerdonek.
+
+ remove suppression of rietveld logging
+ https://bugs.webkit.org/show_bug.cgi?id=39693
+
+ Now that we only upload to rietveld explicitly, e.g. on the bot
+ or via webkit-patch post-attachment-to-rietveld, we should print
+ all the rietveld logging. It was suppressed before to avoid making
+ webkit-patch upload too noisy.
+
+ * Scripts/webkitpy/common/net/rietveld.py:
+
+2010-05-25 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Ojan Vafai.
+
+ [Qt] Expose the editing behavior setting in DRT to test all editing code paths
+ https://bugs.webkit.org/show_bug.cgi?id=39680
+
+ Implement LayoutTestController::setEditingBehavior in Qt's DRT.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setEditingBehavior):
+
+2010-05-25 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after API change and addition of WebCore/platform/text/transcoder dir.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setEditingBehavior):
+ * wx/build/settings.py:
+
+2010-05-24 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Eric Seidel and Kent Tamura (for the Chromium part).
+
+ editingBehavior settings needs to be set back to a reasonable default between tests
+ https://bugs.webkit.org/show_bug.cgi?id=39433
+
+ Similarly to r59861, hard code the default setting during reset for Gtk and Chromium,
+ so that the serialized version of the setting stays in sync with expectations.
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::resetWebSettings):
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2010-05-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch land calls scm.changed_files 4 times!
+ https://bugs.webkit.org/show_bug.cgi?id=39584
+
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ - Assert that we don't call modified_changelogs too often.
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py:
+ - Use cached changelogs list instead of calling modified_changelogs directly.
+ * Scripts/webkitpy/tool/steps/validatereviewer.py:
+ - ditto.
+
+2010-05-24 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Import layout_test_helper for Windows
+ https://bugs.webkit.org/show_bug.cgi?id=39581
+
+ Import Chromium win/layout_test_helper.cc as LayoutTestHelperWin.cpp.
+ http://src.chromium.org/viewvc/chrome/trunk/src/webkit/tools/test_shell/win/layout_test_helper.cc
+
+ * DumpRenderTree/chromium/LayoutTestHelperWin.cpp: Added.
+
+2010-05-24 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Reset frame name
+ https://bugs.webkit.org/show_bug.cgi?id=39586
+
+ This change fixes about 70 unexpected results.
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::reset):
+
+2010-05-24 Marcus Bulach <bulach@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] Adds WebGeolocationServiceMockImpl to remove public dependency on wtf/HashMap.h
+ https://bugs.webkit.org/show_bug.cgi?id=39587
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::geolocationService):
+
+2010-05-24 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] DRT Support for removeOriginAccessWhitelistEntry
+
+ Unskips http/tests/xmlhttprequest/origin-whitelisting-removal.html
+
+ [Qt] DRT Support for removeOriginAccessWhitelistEntry
+ https://bugs.webkit.org/show_bug.cgi?id=39565
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::removeOriginAccessWhitelistEntry):
+
+2010-05-24 Marcus Bulach <bulach@google.com>
+
+ Reviewed by Ojan Vafai.
+
+ _svn_branch_has_extra_commits needs to check for ^HEAD instead of ^head.
+ https://bugs.webkit.org/show_bug.cgi?id=39603
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+
+== Rolled over to ChangeLog-2010-05-24 ==
diff --git a/Tools/ChangeLog-2009-06-16 b/Tools/ChangeLog-2009-06-16
new file mode 100644
index 0000000..534b2e6
--- /dev/null
+++ b/Tools/ChangeLog-2009-06-16
@@ -0,0 +1,25221 @@
+2009-06-15 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Add a script to automate the rolling over of ChangeLog files when they grow too large.
+
+ * Scripts/roll-over-ChangeLogs: Added.
+
+2009-06-15 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ <rdar://problem/6974857>
+
+ Build with ENABLE_3D_RENDERING turned on by default on SnowLeopard.
+
+ * Scripts/build-webkit:
+
+2009-06-12 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Mark Rowe.
+ Reviewed by Simon Hausmann.
+
+ Refactor handling of options in the build-webkit script
+
+ Options are now defined in one place, and then reused when creating
+ the usage help text, the arguments to GetOptions(), and when passing
+ the options on to the underlying port-dependent build systems.
+
+ This allows the Qt port to read the defaults for the options from the
+ pro file (dynamically), and to pass the options on to qmake at build.
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2009-06-15 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Cameron Zwarich.
+
+ Fix <https://bugs.webkit.org/show_bug.cgi?id=26312>.
+ Bug 26312: Multiple copies of Safari opened with WebKit nightly and Safari 3.2.3
+
+ Skip the trampoline detection for versions of Safari < 4.0 as they don't play these
+ tricks, and having WebKitNightlyEnabler assume that we were in the trampoline was
+ preventing our LaunchServices trickery from being run. This led to fresh copies of
+ WebKit.app being launched when a URL or file was opened from an external application
+ rather than the existing instance being reused.
+
+ * WebKitLauncher/WebKitNightlyEnabler.m:
+ (insideSafari4OnTigerTrampoline):
+ (enableWebKitNightlyBehaviour):
+
+2009-06-13 Sam Weinig <sam@webkit.org>
+
+ Rubber-stamped by Mark "Snowy" Rowe.
+
+ Update iExploder/htdocs/cssproperties.in by running update-iexploder-cssproperties.
+
+ * iExploder/htdocs/cssproperties.in:
+
+2009-06-13 John Abd-El-Malek <jam@chromium.org>
+
+ Reviewed by Eric Seidel. Landed by Adam Barth.
+
+ Removed dead file.
+ https://bugs.webkit.org/show_bug.cgi?id=26308
+
+ * DumpRenderTree/win/TestNetscapePlugin/main.c: Removed.
+
+2009-06-12 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Gustavo Noronha.
+
+ [Gtk] use strlen instead of g_utf8_strlen so we can enable more tests.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dumpHistoryItem):
+
+2009-06-12 Gustavo Noronha Silva <gns@gnome.org>
+
+ Reviewed by Jan Alonzo.
+
+ https://bugs.webkit.org/show_bug.cgi?id=25599
+ [GTK] Enable more tests
+
+ Implement dumping of status callback.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewStatusBarTextChanged):
+ (main):
+
+2009-06-11 John Abd-El-Malek <jam@chromium.org>
+
+ Reviewed by Steve Falkenburg.
+
+ https://bugs.webkit.org/show_bug.cgi?id=26306
+
+ Revert 42565 as it leads to DumpRenderTree crashing on startup because
+ Windows can't find CFURLCacheCopySharedURLCache in CoreNetwork.dll.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+
+2009-06-10 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Jan Alonzo.
+
+ [gtk] Change DumpRenderTree to use a GtkScrolledWindow instead of GtkFixed
+
+ Change the code to use GtkScrolledWindow and resize the GtkScrolledWindow
+ to pass more tests. Make sure the content is bigger than a thumbnail.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (runTest):
+ (main):
+
+2009-06-10 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Gustavo Noronha.
+
+ Clear the frame name before we run each tests so we don't get
+ "someFloaString" or "3" in the target frame name.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+
+2009-06-10 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ - add a LayoutTestController method for temporarily changing the WebKit
+ cache model
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setCacheModelCallback): Added. Calls
+ LayoutTestController::setCacheModel() with the first argument as an
+ integer.
+ (LayoutTestController::staticFunctions): Added setCacheModel.
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setCacheModel):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (setDefaultsToConsistentValuesForTesting): Reset the cache model to
+ WebCacheModelDocumentBrowser.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setCacheModel): Added. Calls -[WebPreferences
+ setCacheModel:].
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setCacheModel):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setCacheModel):
+
+2009-06-09 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Have sunspider-compare-results use the system version of the jsc
+ command line binary as there's no good reason to rebuild from source
+ to simply compare results.
+
+ * Scripts/sunspider-compare-results:
+
+2009-06-09 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Ariya Hidayat.
+
+ Removed setUseFixedLayout and renamed setFixedLayoutSize to
+ setFixedContentsSize.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::setFixedContentsSize):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-06-09 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Fix the Qt build, add missing function declaration.
+
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-06-09 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Fix <https://bugs.webkit.org/show_bug.cgi?id=24642>.
+ Bug 24642: REGRESSION: Nightly builds sometimes erroneously display a message about failing to launch successfully
+
+ Safari 4 on Tiger plays some shenanigans during launch that can confuse the nightly launcher application
+ in to running its initialization code too soon.
+
+ * WebKitLauncher/WebKitNightlyEnabler.m:
+ (insideSafariOnTigerTrampoline): Detect these shenanigans.
+ (enableWebKitNightlyBehaviour): Delay initialization when needed.
+
+2009-06-08 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Antti Koivisto
+
+ Add dispatchPendingLoadRequests() to test fix for <rdar://problem/6727495>
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (dispatchPendingLoadRequestsCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::dispatchPendingLoadRequests): Implement using [WebView _dispatchPendingLoadRequests] SPI
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::dispatchPendingLoadRequests): Need implementations.
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::dispatchPendingLoadRequests): Ditto.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::dispatchPendingLoadRequests): Ditto.
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::dispatchPendingLoadRequests): Ditto.
+
+2009-06-07 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Cameron Zwarich.
+
+ Delete the AccessibilityController that we allocated in -init.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate dealloc]):
+
+2009-06-06 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Factor out the code to check whether a library contains a given symbol in to a helper function.
+
+ * Scripts/webkitdirs.pm:
+
+2009-06-06 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Detect when XHTML MP and WCSS are disabled and skip their associated regression tests.
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2009-06-06 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Brady Eidson.
+
+ <rdar://problem/6778101> Four SSL-related test failures
+
+ With newer versions of CFNetwork we receive a NSURLErrorServerCertificateUntrusted error
+ code rather than the more specific NSURLErrorServerCertificateHasUnknownRoot that DumpRenderTree
+ was looking for. Update DumpRenderTree to accommodate the different error code.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate webView:didFailProvisionalLoadWithError:forFrame:]):
+
+2009-06-03 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Rubber-stamped by Simon Hausmann.
+
+ [Qt] Fix Perl warning when calling chdir with an empty/undefined path
+
+ This happened when the included makespec was in the same directory as
+ the parent makespec, so the relative path between the two was empty.
+
+ * Scripts/webkitdirs.pm:
+
+2009-06-04 Darin Adler <darin@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ Fix crashes due to unbalanced start/stop observer calls.
+
+ * DumpRenderTree/mac/DumpRenderTreeWindow.h: Added observingWebView.
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ (-[DumpRenderTreeWindow startObservingWebView]): Call stopObservingWebView
+ in case we're already observing some other WebView. Set observingWebView.
+ (-[DumpRenderTreeWindow stopObservingWebView]): Do nothing if
+ observingWebView is already NO. Clear observingWebView.
+
+2009-06-03 David Hyatt <hyatt@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate webView:didCommitLoadForFrame:]):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMainFrameIsFirstResponder):
+ Remove explicit calls to _updateFocusedActiveState when the view is made first responder.
+ Focused state already properly updates when views become first responders, so these calls
+ are unnecessary.
+
+ (LayoutTestController::setWindowIsKey):
+ Explicitly call _updateActiveState when our window becomes key, since we're just faking it
+ and the notification won't be sent.
+
+2009-06-02 Jessie Berlin <jberlin@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Add "replace" behavior so that it shows the addition part of the
+ replacement of the file first, and then shows the changes.
+
+ Future: Add in showing the removal part of the replacement.
+
+ * Scripts/svn-create-patch:
+
+2009-06-02 Brent Fulgham <bfulgham@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Update WinLauncher for WebKitCreateInstance.
+ https://bugs.webkit.org/show_bug.cgi?id=26136
+
+ * WinLauncher/WinLauncher.cpp: Revise implementation to
+ use WebKitCreateInstance (rather than CoCreateInstance).
+ * WinLauncher/WinLauncher.h: Modify include path for
+ WebKit.h to match DumpRenderTree style.
+ * WinLauncher/WinLauncher.vcproj: Remove unnecessary
+ WebKit.tlb and EmbeddedIDL flags from build.
+
+2009-06-02 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Rubber-stamped by Adam Roben.
+
+ [Qt] Fix Perl warning about uninitialized value (passedConfiguration())
+
+ * Scripts/webkitdirs.pm:
+
+2009-06-02 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Rubber-stamped by Simon Hausmann.
+
+ Use File::Spec->tmpdir instead of hardcoded paths for tempfile() dir
+
+ This fixes the Windows-build if the user does not have a /tmp directory.
+
+ * Scripts/bisect-builds:
+
+2009-06-01 Yongjun Zhang <yongjun.zhang@nokia.com>>
+
+ Reviewed by Holger Freyther. Landed by Adam Barth.
+
+ <https://bugs.webkit.org/show_bug.cgi?id=26070>
+
+ [Qt] EventSender.keyDown doesn't support Arrow Up and Down keys.
+ Add Down and Up key support.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (EventSender::keyDown):
+
+2009-06-01 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ svn-create-patch displays confusing "Broken pipe" errors from Subversion
+ when files have been renamed in local working copy. This was happening
+ because we invoke 'svn info' to determine the URL that the file was copied
+ from, but we were closing the pipe to the subprocess before SVN had finished
+ writing its output.
+
+ * Scripts/prepare-ChangeLog: Consume all 'svn info' output before closing the file handle.
+ * Scripts/svn-create-patch: Ditto.
+
+2009-05-31 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ - implement LayoutTestController::clearAllDatabases() on
+ Windows.
+
+ Needed for storage/transaction-error-callback.html.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::clearAllDatabases):
+
+2009-05-28 Dirk Schulze <krit@webkit.org>
+
+ Reviewed by Nikolas Zimmermann.
+
+ Added new build flag --filters. More details in WebCore/ChangeLog.
+
+ * Scripts/build-webkit:
+
+2009-05-28 Olivier DOLE <odole@pleyo.com>
+
+ Reviewed by Maciej.
+
+ Add options to sunspider-compare-results to know which test suite to
+ compare (see bug #15941).
+
+ * Scripts/sunspider-compare-results:
+
+2009-05-27 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Dan Bernstein.
+
+ Update build-webkit to handle a new version of WebKitSystemInterface.
+
+ * Scripts/build-webkit:
+
+2009-05-27 Fridrich Strba <fridrich.strba@bluewin.ch>
+
+ Reviewed by Maciej Stachowiak.
+
+ When building with MinGW, don't use the __declspec(dl{import,export})
+ decorations and rely on the linker to use its nifty auto-import feature.
+ It is extremely hard to get the decorations right with MinGW in general
+ and impossible in WebKit, where the resulting shared library is linking
+ together some static libraries.
+
+ * DumpRenderTree/config.h:
+
+2009-05-23 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Land the updated version of WebKitLauncher that the nightly builds have been using.
+
+ Changes include:
+ 1) Support for self-updating via Sparkle.
+ 2) Now respects the "Open using Rosetta" preference.
+ 3) Passes environment variables through to the spawned Safari process.
+ 4) Logs a list of extensions that are detected to the system console.
+ 5) Disables extensions that are known to cause crashes too early in the
+ launch process to be detected by the extension-detection code.
+
+ * WebKitLauncher/Configurations/Base.xcconfig: Added.
+ * WebKitLauncher/Configurations/WebKitLauncher.xcconfig: Added.
+ * WebKitLauncher/Configurations/WebKitNightlyEnabler.xcconfig: Added.
+ * WebKitLauncher/Info.plist:
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj:
+ * WebKitLauncher/WebKitNightlyEnabler.h: Added.
+ * WebKitLauncher/WebKitNightlyEnabler.m:
+ (myBundleDidLoad):
+ (myApplicationWillFinishLaunching):
+ (poseAsWebKitApp):
+ (webKitLauncherBundle):
+ (enableWebKitNightlyBehaviour):
+ * WebKitLauncher/WebKitNightlyEnablerSparkle.h: Added.
+ * WebKitLauncher/WebKitNightlyEnablerSparkle.m: Added.
+ (initializeSparkle):
+ (updatePermissionPromptDescription):
+ (skipSignatureVerificationInDownloadDidFinish):
+ (updateAlertPanel):
+ (updateAlertInitForAlertPanel):
+ (-[NSAlert webKitHandleButtonPress:]):
+ (setMethodImplementation):
+ * WebKitLauncher/main.m:
+ (displayErrorAndQuit):
+ (getLastVersionShown):
+ (saveLastVersionShown):
+ (getPathForStartPage):
+ (getCurrentVersion):
+ (getShowStartPageVersion):
+ (startPageDisabled):
+ (addStartPageToArgumentsIfNeeded):
+ (preferredArchitecture):
+ (myExecve):
+ (locateSafariBundle):
+ (currentMacOSXVersion):
+ (checkFrameworkPath):
+ (main):
+
+2009-05-23 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Gustavo Noronha and Xan Lopez.
+
+ [Gtk] Enable database and localStorage support
+ https://bugs.webkit.org/show_bug.cgi?id=25629
+
+ Enable database and localStorage for running the storage/ tests.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+
+2009-05-23 David Kilzer <ddkilzer@apple.com>
+
+ Part 1 of 2: Bug 25495: Implement PassOwnPtr and replace uses of std::auto_ptr
+
+ <https://bugs.webkit.org/show_bug.cgi?id=25495>
+
+ Reviewed by Oliver Hunt.
+
+ * DumpRenderTree/ForwardingHeaders/wtf/OwnPtrCommon.h: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf/PassOwnPtr.h: Added.
+
+2009-05-23 David Kilzer <ddkilzer@apple.com>
+
+ resolve-ChangeLogs: Add missing newline to status message
+
+ * Scripts/resolve-ChangeLogs: Added newline to status message
+ that is printed when the -c|--continue switch is used but there
+ are unmerged files remaining in the git working directory.
+
+2009-05-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Add an error message to a die statement in run-webkit-tests
+ I hit this die when two users tried to run-webkit-tests at the same time. :(
+
+ * Scripts/run-webkit-tests:
+
+2009-05-22 Andre Pedralho <andre.pedralho@openbossa.org>
+
+ Reviewed by Simon Hausmann.
+
+ Fixed --makeargs usage in Qt build.
+
+ * Scripts/build-webkit:
+
+2009-05-22 Zoltan Horvath <horvath.zoltan.6@stud.u-szeged.hu>
+
+ Reviewed by Simon Hausmann.
+
+ Correcting error message on missing WEBKIT_TESTFONTS
+ environment varible in Qt-port.
+
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2009-05-21 Eric Seidel <eric@webkit.org>
+
+ Rubber-stamped by Antti Koivisto.
+
+ Make it possible to write js-only http tests by exposing a /js-test-resources alias.
+ https://bugs.webkit.org/show_bug.cgi?id=25915
+
+ Second attempt at landing, now using -c instead of -C to make sure
+ that mod_alias is loaded on Apache 1.x instances before using Alias.
+
+ * Scripts/run-webkit-httpd:
+ * Scripts/run-webkit-tests:
+
+2009-05-21 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Xan Lopez.
+
+ Default to running HTTP tests for GTK+.
+
+ * Scripts/run-webkit-tests:
+
+2009-05-21 Darin Adler <darin@apple.com>
+
+ Rolled the httpd changes out, since many machines (including the bots)
+ have an older version of Apache that does not support the Alias command.
+ Or maybe it's something else, but the bots are failing.
+
+ * Scripts/run-webkit-httpd: Rolled back.
+ * Scripts/run-webkit-tests: Ditto.
+
+2009-05-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Geoffrey Garen.
+
+ Make it possible to write js-only http tests by exposing a /js-test-resources alias.
+ https://bugs.webkit.org/show_bug.cgi?id=25915
+
+ * Scripts/run-webkit-httpd:
+ * Scripts/run-webkit-tests:
+
+2009-05-21 Andre Pedralho <andre.pedralho@openbossa.org>
+
+ Reviewed by Gustavo Noronha.
+
+ Added --makeargs flag to the build script.
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2009-05-14 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Anders Carlsson.
+
+ https://bugs.webkit.org/show_bug.cgi?id=24510 where
+
+ Add testHasProperty and testHasMethod to the existing functions
+ of the PluginObject to be able to test the browser hasproperty
+ and hasmethod implementation. Invoke them from pluginInvoke.
+
+ Change the defines to an enum to avoid manually updating
+ NUM_METHOD_IDENTIFIERS and assigning numbers.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (testHasProperty): test hasproperty
+ (testHasMethod): test hasmethod
+ (pluginInvoke): invoke the two
+
+2009-05-20 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by George Staikos.
+
+ BUG 25843: [Qt] Remove qt-port build flag
+ <https://bugs.webkit.org/show_bug.cgi?id=25843>
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * Scripts/webkitdirs.pm:
+
+2009-05-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Oliver Hunt.
+
+ Remove layoutTestController.addFileToPasteboardOnDrag and add eventSender.beginDragWithFiles
+ https://bugs.webkit.org/show_bug.cgi?id=25852
+
+ This allows us to now test multi-file file drags in DumpRenderTree per:
+ https://bugs.webkit.org/show_bug.cgi?id=25862
+
+ I removed the existing tests using addFileToPasteboardOnDrag()
+ and replaced them with a new test (editing/pasteboard/file-input-files-access)
+ which covers several more drag-drop cases.
+
+ I added a DumpRenderTreeFileDraggingSource class to avoid
+ the hack of if (!draggingSource) in [DumpRenderTreeDraggingInfo draggingSourceOperationMask]
+
+ New Test: editing/pasteboard/file-input-files-access.html
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/DumpRenderTreeFileDraggingSource.h: Added.
+ * DumpRenderTree/DumpRenderTreeFileDraggingSource.m: Added.
+ (-[DumpRenderTreeFileDraggingSource draggingSourceOperationMaskForLocal:]):
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::staticValues): removed addFileToPasteboardOnDrag support
+ (LayoutTestController::staticFunctions): removed addFileToPasteboardOnDrag support
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (runTest): ASSERT that draggingInfo has been cleared
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]): Sorted selectors.
+ (+[EventSendingController webScriptNameForSelector:]): Sorted selectors.
+ (-[EventSendingController beginDragWithFiles:]):
+ (-[EventSendingController mouseMoveToX:Y:]):
+ (-[EventSendingController keyDown:withModifiers:]):
+ (-[EventSendingController fireKeyboardEventsToElement:]): removed spurious { }
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:dragImage:at:offset:event:pasteboard:source:slideBack:forView:]): removed addFileToPasteboardOnDrag support
+
+2009-05-19 Kevin Ollivier <kevino@theolliviers.com>
+
+ wxMSW build fixes for DRT.
+
+ * DumpRenderTree/wx/DumpRenderTreeWx.cpp:
+ (runTest):
+ * DumpRenderTree/wx/WorkQueueItemWx.cpp:
+ (LoadItem::invoke):
+ (ReloadItem::invoke):
+ (ScriptItem::invoke):
+ (BackForwardItem::invoke):
+
+2009-05-18 Julien Chaffraix <jchaffraix@webkit.org>
+
+ Bug 24569: Add some cookies tests
+
+ <https://bugs.webkit.org/show_bug.cgi?id=24569>
+
+ Patch by David Kilzer.
+
+ * Scripts/make-js-test-wrappers: Added regex to skip
+ cookies-test-(post|pre).js files.
+
+2009-05-18 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Use python-config to get Python linking info on Unix OSes.
+
+ * wx/build-wxwebkit:
+
+2009-05-18 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix, initialize variable that doesn't get set on Windows.
+
+ * DumpRenderTree/wx/DumpRenderTreeWx.cpp:
+ (MyApp::OnInit):
+
+2009-05-18 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Xan Lopez.
+
+ [Gtk] Various autotools build refactoring and fixes
+ https://bugs.webkit.org/show_bug.cgi?id=25286
+
+ Add -no-install and -no-fast-install to programs and tests that we
+ don't install. Also remove -O2 since this is already handled at
+ configure time.
+
+ * GNUmakefile.am:
+
+2009-05-18 Julie Parent <jparent@google.com>
+
+ Reviewed by Oliver Hunt.
+
+ https://bugs.webkit.org/show_bug.cgi?id=25846
+ Make eventSender dispatch a drag over event.
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:dragImage:at:offset:event:pasteboard:source:slideBack:forView:]):
+
+2009-05-18 Julie Parent <jparent@google.com>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=25716
+
+ * Scripts/make-js-test-wrappers: Added exception to avoid overwriting a custom-written test.
+
+2009-05-18 Julie Parent <jparent@google.com>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=25716
+
+ * Scripts/make-js-test-wrappers: Added exception to avoid overwriting a custom-written test.
+
+2009-05-11 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Jan Michael Alonzo.
+
+ https://bugs.webkit.org/show_bug.cgi?id=25787
+
+ Merge r41819 into Gtk. Do not use printf but send messages
+ through the log command.
+
+ * DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (log):
+ (webkit_test_plugin_new_instance):
+ (webkit_test_plugin_destroy_instance):
+ (webkit_test_plugin_set_window):
+ (webkit_test_plugin_handle_event):
+
+2009-05-11 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Jan Michael Alonzo.
+
+ https://bugs.webkit.org/show_bug.cgi?id=25787
+
+ Forward port r39877 from main.c of OSX to TestNetscapePlugin
+ of Gtk.
+
+ * DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance):
+
+2009-05-15 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Don't parse args using getopt since it isn't available on Windows.
+
+ * DumpRenderTree/wx/DumpRenderTreeWx.cpp:
+ (MyApp::OnInit):
+
+2009-05-15 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [GTK] Implement layoutTestController.waitForPolicyDelegate
+ https://bugs.webkit.org/show_bug.cgi?id=25036
+
+ Connect to 'navigation-policy-decision-requested' and handle
+ waitForPolicy in the callback.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (invalidateAnyPreviousWaitToDumpWatchdog):
+ (webViewNavigationPolicyDecisionRequested):
+ (main):
+ * DumpRenderTree/gtk/DumpRenderTreeGtk.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::waitForPolicyDelegate):
+
+2009-05-14 David Levin <levin@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=24704
+
+ Make paths where data is saved be scoped to the ~ directory,
+ so that one can run independent instances by setting CFFIXED_USER_HOME.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (libraryPath):
+ (setDefaultsToConsistentValuesForTesting):
+ (dumpFrameAsPDF):
+
+2009-05-13 David Kilzer <ddkilzer@apple.com>
+
+ Fix resolve-ChangeLogs when used with Subversion
+
+ Reviewed by Darin Adler.
+
+ Fixes the following issue when run on a Subversion repository:
+
+ $ ./WebKitTools/Scripts/resolve-ChangeLogs
+ ERROR: --continue may only be used with a git repository
+
+ * Scripts/resolve-ChangeLogs: Check for the boolean value of
+ $gitRebaseContinue, not whether it's defined, when validating
+ command-line switches.
+
+2009-05-12 David Kilzer <ddkilzer@apple.com>
+
+ Bug 21418: resolve-ChangeLogs should have a --continue option which does git rebase --continue
+
+ <https://bugs.webkit.org/show_bug.cgi?id=21418>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/resolve-ChangeLogs: Added -c|--continue switch that
+ runs "git rebase --continue" before exiting the script.
+ (hasGitUnmergedFiles): Added. Returns true if there are
+ unmerged files in the git repository.
+
+2009-05-11 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Holger Freyther.
+
+ [Qt] Make sure that public APIs are properly exported on all Qt platforms
+ https://bugs.webkit.org/show_bug.cgi?id=25601
+
+ * Scripts/webkitdirs.pm: Remove QT_SHARED define from Qt builds, define QT_MAKEDLL in WebCore.pro instead
+
+2009-05-07 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fixes for Python extension and DRT.
+
+ * DumpRenderTree/wx/DumpRenderTreeWx.cpp:
+ (MyApp::OnInit):
+ * wx/build-wxwebkit:
+
+2009-05-07 Steve Falkenburg <sfalken@apple.com>
+
+ Remove manifest fixup from r42729 to fix clean builds.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+2009-05-06 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix, fixes for wx trunk builds.
+
+ * DumpRenderTree/wx/DumpRenderTreeWx.cpp:
+ (MyApp::OnInit):
+ * wx/build-wxwebkit:
+
+2009-05-06 Steve Falkenburg <sfalken@apple.com>
+
+ Explicitly set WebKitPaintNativeControls to false to allow Windows results to match Mac.
+
+ Reviewed by Adam Roben.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+
+2009-05-06 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Build QtWebKit as a framework on Mac
+
+ This implies both debug and release build by default, unless
+ one of the --debug or --release config options are passed to
+ the build-webkit script.
+
+ Frameworks can be disabled by passing CONFIG+=webkit_no_framework
+ to the build-webkit script.
+
+ To be able to build both debug and release targets in parallel
+ we have to use separate output directories for the generated
+ sources, which is not optimal, but required to avoid race conditions.
+
+ An optimization would be to only require this spit-up on Mac.
+
+ * Scripts/webkitdirs.pm:
+
+2009-05-05 Darin Adler <darin@apple.com>
+
+ Try to fix Mac build.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp: (elementAtPointCallback): Initialize x and y.
+
+2009-05-05 Maclolm MacLeod <mmacleod@webmail.co.za>
+
+ Reviewed by Kevin Ollivier.
+
+ Have wxWebkit make use of gcc(4 and greater) hidden visibility feature
+
+ https://bugs.webkit.org/show_bug.cgi?id=24345
+
+ * wx/build-wxwebkit:
+
+2009-05-05 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Bug 25574: AXImageMap children links don't respond properly to accessibilityHitTest:
+ https://bugs.webkit.org/show_bug.cgi?id=25574
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (elementAtPointCallback):
+ (getXCallback):
+ (getYCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (descriptionOfValue):
+ (AccessibilityUIElement::elementAtPoint):
+ (AccessibilityUIElement::role):
+ (AccessibilityUIElement::title):
+ (AccessibilityUIElement::description):
+ (AccessibilityUIElement::x):
+ (AccessibilityUIElement::y):
+ (AccessibilityUIElement::width):
+ (AccessibilityUIElement::height):
+ (AccessibilityUIElement::intValue):
+ (AccessibilityUIElement::minValue):
+ (AccessibilityUIElement::maxValue):
+ (AccessibilityUIElement::insertionPointLineNumber):
+ (AccessibilityUIElement::supportsPressAction):
+ (AccessibilityUIElement::lineForIndex):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::elementAtPoint):
+ (AccessibilityUIElement::x):
+ (AccessibilityUIElement::y):
+
+2009-05-06 Christian Dywan <christian@twotoasts.de>
+
+ Reviewed by Gustavo Noronha.
+
+ http://bugs.webkit.org/show_bug.cgi?id=17066
+ [GTK] Improve frameloader signals
+
+ Update GtkLauncher to use the new load-status and progress properties
+ instead of the previous loading signals.
+
+ * GtkLauncher/main.c:
+ (update_title):
+ (notify_load_status_cb):
+ (notify_progress_cb):
+ (create_browser):
+ (create_window):
+
+2009-05-05 Adam Roben <aroben@apple.com>
+
+ Don't use pdevenv when building with VC++ Express
+
+ Fixes Bug 25308: REGRESSION (r42182): Build fails after following
+ build instructions on webkit.org fail when using VC++ Express
+ <https://bugs.webkit.org/show_bug.cgi?id=25308>
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/webkitdirs.pm:
+ (setupCygwinEnv): When Visual Studio is installed, set $vcBuildPath to
+ point to pdevenv. When VC++ Express is installed, set $vcBuildPath to
+ point to VC++ Express, as before.
+ (buildVisualStudioProject): Use $vcBuildPath to build instead of
+ hard-coding pdevenv.
+
+2009-05-05 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Rubber-stamped by Simon Hausmann.
+
+ Mention --qt as an option in the build-webkit help
+
+ * Scripts/build-webkit:
+
+2009-05-04 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Enable spell-checking in DumpRenderTree.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+
+2009-05-04 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Eric Seidel.
+
+ Initial DRT implementation for wx.
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/wx: Added.
+ * DumpRenderTree/wx/DumpRenderTree.bkl: Added.
+ * DumpRenderTree/wx/DumpRenderTreeWx.cpp: Added.
+ (LayoutWebViewEventHandler::LayoutWebViewEventHandler):
+ (LayoutWebViewEventHandler::bindEvents):
+ (LayoutWebViewEventHandler::OnLoadEvent):
+ (LayoutWebViewEventHandler::OnAlertEvent):
+ (LayoutWebViewEventHandler::OnConfirmEvent):
+ (LayoutWebViewEventHandler::OnPromptEvent):
+ (LayoutWebViewEventHandler::OnConsoleMessageEvent):
+ (LayoutWebViewEventHandler::OnReceivedTitleEvent):
+ (LayoutWebViewEventHandler::OnWindowObjectClearedEvent):
+ (notifyDoneFired):
+ (dumpFramesAsText):
+ (dump):
+ (runTest):
+ (MyApp::OnInit):
+ * DumpRenderTree/wx/DumpRenderTreeWx.h: Added.
+ * DumpRenderTree/wx/GCControllerWx.cpp: Added.
+ (GCController::collect):
+ (GCController::collectOnAlternateThread):
+ (GCController::getJSObjectCount):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp: Added.
+ (LayoutTestController::~LayoutTestController):
+ (LayoutTestController::addDisallowedURL):
+ (LayoutTestController::clearBackForwardList):
+ (LayoutTestController::copyDecodedHostName):
+ (LayoutTestController::copyEncodedHostName):
+ (LayoutTestController::display):
+ (LayoutTestController::keepWebHistory):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::pathToLocalResource):
+ (LayoutTestController::queueLoad):
+ (LayoutTestController::setAcceptsEditing):
+ (LayoutTestController::setCustomPolicyDelegate):
+ (LayoutTestController::setMainFrameIsFirstResponder):
+ (LayoutTestController::setTabKeyCyclesThroughElements):
+ (LayoutTestController::setUseDashboardCompatibilityMode):
+ (LayoutTestController::setUserStyleSheetEnabled):
+ (LayoutTestController::setUserStyleSheetLocation):
+ (LayoutTestController::setWindowIsKey):
+ (LayoutTestController::setSmartInsertDeleteEnabled):
+ (LayoutTestController::setJavaScriptProfilingEnabled):
+ (LayoutTestController::setWaitToDump):
+ (LayoutTestController::windowCount):
+ (LayoutTestController::setPrivateBrowsingEnabled):
+ (LayoutTestController::setAuthorAndUserStylesEnabled):
+ (LayoutTestController::setPopupBlockingEnabled):
+ (LayoutTestController::elementDoesAutoCompleteForElementWithId):
+ (LayoutTestController::execCommand):
+ (LayoutTestController::setPersistentUserStyleSheetLocation):
+ (LayoutTestController::clearPersistentUserStyleSheet):
+ (LayoutTestController::clearAllDatabases):
+ (LayoutTestController::setDatabaseQuota):
+ (LayoutTestController::numberOfActiveAnimations):
+ (LayoutTestController::setSelectTrailingWhitespaceEnabled):
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+ (LayoutTestController::setIconDatabaseEnabled):
+ (LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (LayoutTestController::isCommandEnabled):
+ (LayoutTestController::webHistoryItemCount):
+ (LayoutTestController::waitForPolicyDelegate):
+ * DumpRenderTree/wx/WorkQueueItemWx.cpp: Added.
+ (LoadItem::invoke):
+ (ReloadItem::invoke):
+ (ScriptItem::invoke):
+ (BackForwardItem::invoke):
+ * Scripts/build-dumprendertree:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+ * wx/build-wxwebkit:
+
+2009-05-03 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Geoffrey Garen.
+
+ Don't pass an exception parameter if we don't care about the value.
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback):
+
+2009-05-02 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Another cut at getting tests passing on Windows again.
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::didStartProvisionalLoadForFrame): Tweak formatting.
+ (FrameLoadDelegate::didFailProvisionalLoadWithError): Ditto.
+ (FrameLoadDelegate::didCommitLoadForFrame): Ditto.
+ (FrameLoadDelegate::didFinishLoadForFrame): Ditto.
+ (FrameLoadDelegate::didFailLoadWithError): Added missing logging.
+
+2009-05-02 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Try to get tests passing on Windows again.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (shouldLogFrameLoadDelegates): Allow either "/" or "\" as a path
+ separator. Also require separator before as well as after path name.
+
+2009-04-30 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix, define ENABLE_JAVASCRIPT_DEBUGGER.
+
+ * wx/build-wxwebkit:
+
+2009-04-30 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by Timothy Hatcher.
+
+ https://bugs.webkit.org/show_bug.cgi?id=25470
+ Extend the cover of ENABLE_JAVASCRIPT_DEBUGGER to profiler.
+
+ * Scripts/build-webkit: Added ENABLE_JAVASCRIPT_DEBUGGER define.
+
+2009-04-29 Mark Rowe <mrowe@apple.com>
+
+ Update build.webkit.org configuration for the addition of the new GTK buildbot.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2009-04-29 Mark Rowe <mrowe@apple.com>
+
+ Ignore the --use-remote-links-to-tests option for GTK as it leads to
+ perl errors being spewed at the end of run-webkit-tests.
+
+ * Scripts/run-webkit-tests:
+
+2009-04-29 Mark Rowe <mrowe@apple.com>
+
+ Implement test-result-archive for GTK.
+
+ * BuildSlaveSupport/test-result-archive:
+
+2009-04-28 Pierre d'Herbemont <pdherbemont@apple.com>
+
+ Reviewed by David Kilzer.
+
+ https://bugs.webkit.org/show_bug.cgi?id=25462
+
+ Make sure "--pixel --add-platform-exceptions" produces platform
+ specific pixel test results.
+
+ * Scripts/run-webkit-tests: Support "--pixel
+ --add-platform-exceptions"
+
+2009-04-28 Steve Falkenburg <sfalken@apple.com>
+
+ Fix link warnings building TestNetscapePlugin on Windows due to mismatched
+ DLL name vs. LIBRARY directive name.
+
+ Reviewed by Jon Honeycutt.
+
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.def:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin_debug.def: Added.
+
+2009-04-28 Steve Falkenburg <sfalken@apple.com>
+
+ Fix warnings about PRODUCTION and ARCHIVE_BUILD on Windows builds
+ of ImageDiff and DumpRenderTree.
+
+ Rubber stamped by Adam Roben.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+
+2009-04-28 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Add ability to get the children count of an AX element.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getChildrenCountCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::childrenCount):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::childrenCount):
+
+2009-04-27 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Gustavo Noronha.
+
+ [GTK] Make layout tests / jsc tests usable without build-webkit
+ https://bugs.webkit.org/show_bug.cgi?id=21784
+
+ This requires WEBKITOUTPUTDIR to be set to the build directory.
+ Set the location of the product dir to the location pointed to by
+ WEBKITOUTPUTDIR.
+
+ * Scripts/webkitdirs.pm:
+
+2009-04-27 Gustavo Noronha Silva <gns@gnome.org>
+
+ Reviewed by Adam Roben.
+
+ Use libsoup's facilities to resolve relative URLs, instead, since
+ it is a more robust method.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::queueLoad):
+
+2009-04-26 Gustavo Noronha Silva <gns@gnome.org>
+
+ Reviewed by Xan Lopez.
+
+ Resolve relative URLs when queueing loads. This fixes
+ post-goback-same-url.html timing out.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::queueLoad):
+
+2009-04-24 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Switching JSCore from a static lib to a dynamic lib
+ to match the Apple build and fix symbol exports.
+
+ * wx/build-wxwebkit:
+
+2009-04-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Add PrettyPatch support to run-webkit-tests
+
+ * Scripts/run-webkit-tests:
+
+2009-04-24 Steve Falkenburg <sfalken@apple.com>
+
+ Fix nightly for Windows x64 users.
+ Installed browser location is written to a slightly different registry key in that case.
+
+ * FindSafari/FindSafari.cpp:
+ (getInstalledWebKitDirectory):
+
+2009-04-23 Mark Rowe <mrowe@apple.com>
+
+ Fix the Windows DRT build.
+
+ * DumpRenderTree/win/PolicyDelegate.h:
+
+2009-04-23 Brady Eidson <beidson@apple.com>
+
+ Fix Windows DRT build.
+
+ * DumpRenderTree/win/PolicyDelegate.cpp:
+ (PolicyDelegate::unableToImplementPolicyWithError):
+
+2009-04-22 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Maciej Stachowiak
+
+ Add additional support for test:
+ <rdar://problem/5689748> - Cannot redirect to protocols handled by external applications.
+
+ * DumpRenderTree/mac/PolicyDelegate.mm:
+ (-[PolicyDelegate webView:unableToImplementPolicyWithError:frame:]): Dump formatted information when
+ a policy cannot be implemented.
+
+ * DumpRenderTree/win/PolicyDelegate.cpp:
+ (PolicyDelegate::unableToImplementPolicyWithError): Ditto.
+ * DumpRenderTree/win/PolicyDelegate.h:
+
+2009-04-22 Sam Weinig <sam@webkit.org>
+
+ Rubber-stamped by Darin Adler.
+
+ Fix for <rdar://problem/6816957>
+ Turn off Geolocation by default
+
+ * Scripts/build-webkit:
+
+2009-04-21 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Jon Honeycutt.
+
+ - dump the node in the element dictionary in the action information
+ passed to the policy delegate
+
+ * DumpRenderTree/mac/PolicyDelegate.mm:
+ (-[PolicyDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]):
+ * DumpRenderTree/win/PolicyDelegate.cpp:
+ (dumpPath):
+ (PolicyDelegate::decidePolicyForNavigationAction):
+
+2009-04-21 Adam Roben <aroben@apple.com>
+
+ Windows build fix after r42726
+
+ * DumpRenderTree/win/DumpRenderTree.cpp: Touched to force a rebuild.
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Delete any pre-r42726
+ manifest files during the pre-build event.
+
+2009-04-21 Steve Falkenburg <sfalken@apple.com>
+
+ Use new WebKitCreateInstance API instead of CoCreateInstance
+ or COMPtr's createInstance to instantiate WebKit COM objects.
+
+ Reviewed by Adam Roben.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (initialize):
+ (runTest):
+ (createWebViewAndOffscreenWindow):
+ (main):
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/GCControllerWin.cpp:
+ (GCController::collect):
+ (GCController::collectOnAlternateThread):
+ (GCController::getJSObjectCount):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::keepWebHistory):
+ (LayoutTestController::webHistoryItemCount):
+ (LayoutTestController::setIconDatabaseEnabled):
+ * DumpRenderTree/win/WorkQueueItemWin.cpp:
+ (LoadItem::invoke):
+
+2009-04-20 Timothy Hatcher <timothy@apple.com>
+
+ Stop using the fullDocumentTeardownEnabled WebPreference methods.
+ Just set the WebKitEnableFullDocumentTeardownPreferenceKey default.
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (setDefaultsToConsistentValuesForTesting):
+ (resetWebViewToConsistentStateBeforeTesting):
+
+2009-04-21 Geoffrey Garen <ggaren@apple.com>
+
+ Rubber-stamped by Adam Roben.
+
+ Disabled one more Mozilla JS test because it fails intermittently on Windows.
+ (See https://bugs.webkit.org/show_bug.cgi?id=25160.)
+
+ * Scripts/run-javascriptcore-tests:
+
+2009-04-21 Adam Roben <aroben@apple.com>
+
+ Fix running run-safari and run-webkit-tests from the paths recommended
+ on webkit.org
+
+ Reviewed by Steve Falkenburg and Sam Weinig.
+
+ * Scripts/run-webkit-nightly.cmd: Moved quotes from variable
+ definitions to variable uses. Otherwise cmd.exe can get confused about
+ the quoting.
+ * Scripts/run-webkit-tests: Changed to use an absolute path to
+ execAppWithEnv so that run-webkit-tests will work when run from
+ outside the source tree.
+
+2009-04-21 Adam Roben <aroben@apple.com>
+
+ Rename JavaScriptCore_debug.dll to JavaScriptCore.dll in the Debug
+ configuration
+
+ This matches the naming scheme for WebKit.dll, and will be necessary
+ once Safari links against JavaScriptCore.dll. This change also causes
+ run-safari not to fail (because the launcher printed by FindSafari was
+ always looking for JavaScriptCore.dll, never
+ JavaScriptCore_debug.dll).
+
+ Part of Bug 25305: can't run safari or drt on windows
+ <https://bugs.webkit.org/show_bug.cgi?id=25305>
+
+ Reviewed by Steve Falkenburg and Sam Weinig.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Use
+ $(WebKitDLLConfigSuffix) for naming JavaScriptCore.{dll,lib}.
+
+2009-04-21 Steve Falkenburg <sfalken@apple.com>
+
+ Update FindSafari for JavaScriptCore DLL changes.
+ Also removed code previously needed to support running nightlies against Safari 3 on Windows.
+
+ Reviewed by Mark Rowe.
+
+ * FindSafari/FindSafari.cpp:
+ (getStringValue):
+ (getInstalledWebKitDirectory):
+ (_tmain):
+
+2009-04-20 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Added PlainTextController.h
+ and PlainTextController.mm.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate webView:didClearWindowObject:forFrame:]): Added PlainTextController
+ as "window.plainText".
+
+ * DumpRenderTree/mac/PlainTextController.h: Added.
+ * DumpRenderTree/mac/PlainTextController.mm: Added.
+
+2009-04-20 Steve Falkenburg <sfalken@apple.com>
+
+ Separate JavaScriptCore.dll from WebKit.dll.
+ Slight performance improvement or no change on benchmarks.
+
+ Allows us to break a circular dependency between CFNetwork and WebKit on Windows,
+ and simplifies standalone JavaScriptCore builds.
+
+ Reviewed by Oliver Hunt.
+
+ * DumpRenderTree/config.h: Specify JS, WebKit exported data as __declspec(dllimport)
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Link against JavaScriptCore.dll
+
+2009-04-20 Sam Weinig <sam@webkit.org>
+
+ Rubber-stamped by Tim Hatcher.
+
+ Add licenses for xcconfig files.
+
+ * DumpRenderTree/mac/Configurations/Base.xcconfig:
+ * DumpRenderTree/mac/Configurations/DebugRelease.xcconfig:
+ * DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig:
+ * DumpRenderTree/mac/Configurations/ImageDiff.xcconfig:
+ * DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig:
+
+2009-04-19 David Kilzer <ddkilzer@apple.com>
+
+ Make FEATURE_DEFINES completely dynamic
+
+ Reviewed by Darin Adler.
+
+ Make FEATURE_DEFINES depend on individual ENABLE_FEATURE_NAME
+ variables for each feature, making it possible to remove all
+ knowledge of FEATURE_DEFINES from build-webkit.
+
+ * Scripts/build-webkit: Define individual ENABLE_FEATURE_NAME
+ variables instead of the whole FEATURE_DEFINES string when
+ building with Xcode. Miscellaneous clean up:
+ - Reordered/sorted command-line switch variables.
+ - Reordered/sorted command-line switches in $usage.
+ - Reordered/sorted command-line switches in GetOptions().
+ - Defined $svgSupport to true if any --svg-feature switch is
+ set in order to match "Implies SVG Support" claim.
+ - Build JavaScriptGlue after JavaScriptCore again!
+ - Fixed --[no-]geolocation for GTK+ port and sorted GTK+
+ command-line switches.
+ - Added "exit 0" statement at the end of the script.
+
+2009-04-17 David Kilzer <ddkilzer@apple.com>
+
+ Simplify FEATURE_DEFINES definition
+
+ Reviewed by Darin Adler.
+
+ This moves FEATURE_DEFINES and its related ENABLE_FEATURE_NAME
+ variables to their own FeatureDefines.xcconfig file. It also
+ extracts a new ENABLE_GEOLOCATION variable so that
+ FEATURE_DEFINES only needs to be defined once.
+
+ * Scripts/build-webkit: Realphabetized code related to enabling
+ Geolation features for WebKit. Also set ENABLE_GEOLOCATION
+ variable for xcodebuild.
+
+2009-04-16 Darin Fisher <darin@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=25223
+ REGRESSION: Back button after form submission to the same URL fails to navigate.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate processWork:]): Need to defer processing the work
+ queue if a navigation started between locationChangeDone and our
+ delayed processWork call. This can happen when using queueLoadingScript
+ to load script that simulates a click on a link or submit button since
+ those clicks happen asynchronously.
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::processWork): Same as above.
+
+2009-04-16 Geoffrey Garen <ggaren@apple.com>
+
+ Build fix: updated check-for-global-initializers to account for code motion.
+
+ * Scripts/check-for-global-initializers:
+
+2009-04-16 Zan Dobersek <zandobersek@gmail.com>
+
+ Reviewed by Adam Roben.
+
+ Compare test's response mime type and dump test as text properly.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump):
+
+
+2009-04-16 Adam Roben <aroben@apple.com>
+
+ Skip yet another JavaScriptCore test that sometimes fails on Windows
+
+ See Bug 25160: Various ecma/Date tests sometimes fail on Windows (but
+ not Mac)
+ <https://bugs.webkit.org/show_bug.cgi?id=25160>
+
+ * Scripts/run-javascriptcore-tests: Skip ecma/Date/15.9.2.2-6.js.
+
+2009-04-15 Steve Falkenburg <sfalken@apple.com>
+
+ Redo last build fix in a more straightforward way.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (sharedCFURLCache):
+
+2009-04-15 Steve Falkenburg <sfalken@apple.com>
+
+ Fix Windows build of DumpRenderTree.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (sharedCFURLCache):
+ (main):
+
+2009-04-15 Adam Roben <aroben@apple.com>
+
+ Skip yet another JavaScriptCore test that sometimes fails on Windows
+
+ See Bug 25160: Various ecma/Date tests sometimes fail on Windows (but
+ not Mac)
+ <https://bugs.webkit.org/show_bug.cgi?id=25160>
+
+ * Scripts/run-javascriptcore-tests: Skip ecma/Date/15.9.2.2-2.js (who
+ didn't see it coming?).
+
+2009-04-14 Adam Roben <aroben@apple.com>
+
+ Skip another JavaScriptCore test that sometimes fails on Windows
+
+ See Bug 25160: Various ecma/Date tests sometimes fail on Windows (but
+ not Mac)
+ <https://bugs.webkit.org/show_bug.cgi?id=25160>
+
+ Rubber-stamped by Geoff Garen.
+
+ * Scripts/run-javascriptcore-tests: Skip ecma/Date/15.9.2.2-3.js.
+
+2009-04-14 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Move the DerivedSources.make calls into build-wxwebkit so that
+ the FEATURE_DEFINES are parsed properly.
+
+ * wx/build-wxwebkit:
+
+2009-04-14 Adam Roben <aroben@apple.com>
+
+ Small run-javascriptcore-tests cleanup
+
+ Reviewed by Cameron Zwarich.
+
+ * Scripts/run-javascriptcore-tests: Move the list of tests to skip
+ into its own variable, annotated with the bugs that are filed about
+ the various failures.
+
+2009-04-14 Adam Roben <aroben@apple.com>
+
+ Skip another sometimes-failing ecma/Date test on Windows
+
+ These failing tests are covered by Bug 25160: Various ecma/Date tests
+ sometimes fail on Windows (but not Mac)
+ <https://bugs.webkit.org/show_bug.cgi?id=25160>
+
+ Reviewed by Cameron Zwarich.
+
+ * Scripts/run-javascriptcore-tests: Added ecma/Date/15.9.2.1.js to the
+ list of tests to skip.
+
+2009-04-14 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Gtk] disable soup auth dialog when running DRT
+ https://bugs.webkit.org/show_bug.cgi?id=24598
+
+ Disable soup's auth dialog when running the tests.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (setDefaultsToConsistentStateValuesForTesting):
+ * GNUmakefile.am:
+
+2009-04-13 Darin Adler <darin@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/check-for-exit-time-destructors: Add ERROR: and WARNING: prefixes to
+ make these scripts work better with the build window in new versions of Xcode.
+ * Scripts/check-for-global-initializers: Ditto.
+ * Scripts/check-for-weak-vtables: Ditto.
+
+2009-04-13 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Disabled another JavaScriptCore test because it fails on Windows but
+ not Mac, so it makes the bots red.
+
+ * Scripts/run-javascriptcore-tests:
+
+2009-04-13 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Disabled two JavaScriptCore tests because they fail on Window or Mac but
+ not both, so they make the bots red.
+
+ * Scripts/run-javascriptcore-tests:
+
+2009-04-13 Darin Adler <darin@apple.com>
+
+ * Scripts/make-js-test-wrappers: Added another exception.
+
+2009-04-10 Adam Roben <aroben@apple.com>
+
+ Add our new test font to the list that DRT knows about
+
+ Reviewed by Dan Bernstein.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (initialize): Added WebKit Layout Tests 2.ttf.
+
+2009-04-09 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Unreviewed Gtk build fix for undefined reference: g_thread_init.
+ Add GLIB_LIBS to DRT and GtkLauncher build config.
+
+ * GNUmakefile.am:
+
+2009-04-09 David Kilzer <ddkilzer@apple.com>
+
+ Reinstating <rdar://problem/6718589> Option to turn off SVG DOM Objective-C bindings
+
+ Rolled r42345 back in. The build failure was caused by an
+ internal script which had not been updated the same way that
+ build-webkit was updated.
+
+ * Scripts/build-webkit:
+
+2009-04-09 David Levin <levin@chromium.org>
+
+ Reviewed by David Kilzer.
+
+ https://bugs.webkit.org/show_bug.cgi?id=25101
+
+ Launch DumpRenderTree and the image diff tool in a way that will work from perl threads.
+ This is a workaround due to a perl limitation. When perl does open* calls on a thread, it ignores
+ the environment of the current thread and simply uses the environment of the main thread instead.
+
+ * Scripts/execAppWithEnv: Added.
+ * Scripts/run-webkit-tests:
+
+2009-04-09 Alexey Proskuryakov <ap@webkit.org>
+
+ Reverting <rdar://problem/6718589> Option to turn off SVG DOM Objective-C bindings.
+ It broke Mac build, and I don't know how to fix it.
+
+ * Scripts/build-webkit:
+
+2009-04-08 David Kilzer <ddkilzer@apple.com>
+
+ <rdar://problem/6718589> Option to turn off SVG DOM Objective-C bindings
+
+ Reviewed by Darin Adler and Maciej Stachowiak.
+
+ Introduce the ENABLE_SVG_DOM_OBJC_BINDINGS feature define so
+ that SVG DOM Objective-C bindings may be optionally disabled.
+
+ * Scripts/build-webkit: Added --[no-]svg-dom-objc-bindings
+ command-line argument. Set special ENABLE_SVG_DOM_OBJC_BINDINGS
+ Xcode variable required by WebCore.xcconfig.
+
+2009-04-07 Adam Roben <aroben@apple.com>
+
+ Print the number of files being compiled when using pdevenv
+
+ * Scripts/parallelcl:
+
+2009-04-07 Mark Rowe <mrowe@apple.com>
+
+ Land the current build.webkit.org configuration for safekeeping.
+
+ * BuildSlaveSupport/build.webkit.org-config/README: Added.
+ * BuildSlaveSupport/build.webkit.org-config/Makefile:
+ * BuildSlaveSupport/build.webkit.org-config/buildbot.tac:
+ * BuildSlaveSupport/build.webkit.org-config/config.json: Added.
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+ * BuildSlaveSupport/build.webkit.org-config/public_html/buildbot.css: Renamed from BuildSlaveSupport/build.webkit.org-config/buildbot.css.
+ * BuildSlaveSupport/build.webkit.org-config/public_html/index.html: Added.
+ * BuildSlaveSupport/build.webkit.org-config/public_html/robots.txt: Added.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/__init__.py: Removed.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/auth.py: Removed.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/basesteps.py: Removed.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/builders.py: Removed.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/factories.py: Removed.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/schedulers.py: Removed.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/status.py: Removed.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/steps.py: Removed.
+
+2009-04-07 Mark Rowe <mrowe@apple.com>
+
+ Ignore the mysterious exception that Cygwin's Python is throwing when attempting
+ to remove the layout-test-results directory.
+
+ * BuildSlaveSupport/test-result-archive:
+
+2009-04-07 Mark Rowe <mrowe@apple.com>
+
+ Change the working directory before removing the test result directory
+ in the hopes of making the Windows build slaves happier.
+
+ * BuildSlaveSupport/test-result-archive:
+
+2009-04-07 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Make the links to tests in the uploaded results.html files on build.webkit.org point to the test files.
+
+ * Scripts/VCSUtils.pm: Add a function that will return the location of a file relative to the root of the working copy.
+ * Scripts/run-webkit-tests: Convert the path in to a remote URL if the path is below the layout tests directory.
+
+2009-04-07 Mark Rowe <mrowe@apple.com>
+
+ Remove the layout-test-results directory after we have archived it so that
+ log files and results are reset between runs of the tests.
+
+ * BuildSlaveSupport/test-result-archive:
+
+2009-04-07 Mark Rowe <mrowe@apple.com>
+
+ Helper script for uploading layout test results for display on build.webkit.org.
+
+ * BuildSlaveSupport/test-result-archive: Copied from WebKitTools/BuildSlaveSupport/built-product-archive.
+
+2009-04-11 Brian Weinstein <bweinstein@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=24908
+
+ Allows timeout to be set in run-webkit-tests as a command line argument.
+
+ * Scripts/run-webkit-tests:
+
+2009-04-06 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Rubber-stamped by Tor Arne Vestbø.
+
+ Add /Programs to the productDir for GTK+, instead of adding
+ /JavaScriptCore, when running jsc.
+
+ * Scripts/run-sunspider:
+
+2009-04-04 Kevin Ollivier <kevino@theolliviers.com>
+
+ Build fixes for wxMac/Tiger and PPC builds.
+
+ * wx/build-wxwebkit:
+
+2009-04-04 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Update the version of ICU dlls.
+
+ * wx/build-wxwebkit:
+
+2009-04-03 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Fix running DumpRenderTree with a root.
+
+ * Scripts/run-webkit-tests:
+
+2009-04-02 Adam Roben <aroben@apple.com>
+
+ Build fix for Windows machines that don't have WebKitTools/Scipts in
+ their PATH
+
+ * Scripts/pdevenv: Add WebKitTools/Scripts to PATH when launching
+ Visual Studio/VC++ Express.
+
+2009-04-02 Adam Roben <aroben@apple.com>
+
+ Use pdevenv when building .vcproj files via our scripts
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/webkitdirs.pm:
+ (sub buildVisualStudioProject): Use pdevenv instead of invoking Visual
+ Studio/VC++ Express directly.
+
+2009-04-01 Mark Rowe <mrowe@apple.com>
+
+ Windows support for built-product-archive.
+
+ * BuildSlaveSupport/built-product-archive:
+
+2009-03-31 Adam Roben <aroben@apple.com>
+
+ Make resolve-ChangeLogs -f work when the working tree has spaces in
+ its path
+
+ Reviewed by Mark Rowe and David Kilzer.
+
+ * Scripts/resolve-ChangeLogs:
+ (sub fixMergedChangeLogs): Quote the path to resolve-ChangeLogs in
+ case it contains spaces.
+
+2009-03-31 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=24777
+ WebKit tools are broken on Tiger
+
+ * Scripts/webkitdirs.pm: Don't use arch command with options on Tiger.
+
+2009-03-31 Darin Adler <darin@apple.com>
+
+ * Scripts/add-include: Added.
+
+2009-03-31 Mark Rowe <mrowe@apple.com>
+
+ Fix use of incorrect constant.
+
+ * BuildSlaveSupport/built-product-archive:
+
+2009-03-30 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Stephanie Lewis.
+
+ Add a script in support of the new build.webkit.org configuration.
+
+ * BuildSlaveSupport/built-product-archive: Added.
+
+2009-03-30 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Make policy-delegate logging work even for local files by processing the URLs as we
+ do for other delegates.
+
+ * DumpRenderTree/mac/PolicyDelegate.mm:
+ (-[PolicyDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]):
+ Use _drt_descriptionSuitableForTestResult on the URL.
+
+ * DumpRenderTree/win/PolicyDelegate.cpp:
+ (PolicyDelegate::decidePolicyForNavigationAction): Use urlSuitableForTestResult on the URL.
+
+2009-03-30 Adam Roben <aroben@apple.com>
+
+ Windows build fix
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::waitForPolicyDelegate): Added this empty stub.
+
+ * DumpRenderTree/win/WorkQueueItemWin.cpp:
+ (LoadItem::invoke):
+ (ScriptItem::invoke):
+ Changed to use data members instead of removed member functions.
+
+2009-03-30 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Gtk DRT build fix per changeset
+ http://trac.webkit.org/changeset/42082. Not reviewed.
+
+ * DumpRenderTree/gtk/WorkQueueItemGtk.cpp:
+ (LoadItem::invoke):
+ (ScriptItem::invoke):
+
+2009-03-29 Darin Adler <darin@apple.com>
+
+ * DumpRenderTree/qt/jsobjects.cpp: Rolled out changes to this file. Maybe this will fix
+ Qt building of DumpRenderTree.
+
+2009-03-29 Darin Adler <darin@apple.com>
+
+ Reviewed by Cameron Zwarich.
+
+ Bug 24922: change WorkQueue-based navigation tests to not depend on synchronous form submission
+ https://bugs.webkit.org/show_bug.cgi?id=24922
+
+ Don't rely on delegate methods to guess whether a queued step starts a load or not, because
+ script-triggered loads can't be detected that way. Instead have the steps themselves indicate
+ whether or not a load was triggered.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (queueLoadingScriptCallback): Added. Version for scripts that perform loads.
+ (queueNonLoadingScriptCallback): Added. Version for scripts that do not perform loads.
+ (LayoutTestController::staticFunctions): Replaced queueScript with queueLoadingScript and
+ queueNonLoadingScript.
+ (LayoutTestController::queueBackNavigation): Moved here since it's platform-independent now.
+ (LayoutTestController::queueForwardNavigation): Ditto.
+ (LayoutTestController::queueLoadingScript): Replacement for queueScript. Here since it's
+ platform-independent.
+ (LayoutTestController::queueNonLoadingScript): Ditto.
+ (LayoutTestController::queueReload): Moved here since it's platform-independent now.
+ * DumpRenderTree/LayoutTestController.h: Ditto.
+
+ * DumpRenderTree/WorkQueue.cpp:
+ (WorkQueue::processWork): Added. Shared by the different platform's work queue implementations.
+ * DumpRenderTree/WorkQueue.h: Ditto.
+
+ * DumpRenderTree/WorkQueueItem.h: Changed the invoke function to return true if the item
+ started a load. Removed unused getter functions. Made invoke functions private.
+ Added LoadingScriptItem and NonLoadingScriptItem, making ScriptItem an abstract base.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (processWork): Use the new WorkQueue::processWork function to implement the new rule.
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: Removed queue functions that are now
+ platform-independent and in LayoutTestController.cpp.
+ * DumpRenderTree/gtk/WorkQueueItemGtk.cpp:
+ (LoadItem::invoke): Return true.
+ (ReloadItem::invoke): Ditto.
+ (ScriptItem::invoke): Ditto.
+ (BackForwardItem::invoke): Ditto.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate processWork:]): Use the new WorkQueue::processWork function to implement
+ the new rule.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm: Removed queue functions that are now
+ platform-independent and in LayoutTestController.cpp.
+ * DumpRenderTree/mac/WorkQueueItemMac.mm:
+ (LoadItem::invoke): Return true.
+ (ReloadItem::invoke): Ditto.
+ (ScriptItem::invoke): Ditto.
+ (BackForwardItem::invoke): Ditto.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::processWork): Use the new WorkQueue::processWork function to implement
+ the new rule. Removed queue functions that are now platform-independent and in
+ LayoutTestController.cpp.
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::processWork): Use the new WorkQueue::processWork function to implement
+ the new rule.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp: Removed queue functions that are now
+ platform-independent and in LayoutTestController.cpp.
+ * DumpRenderTree/win/WorkQueueItemWin.cpp:
+ (LoadItem::invoke): Return false when we fail, true when we succeed.
+ (ReloadItem::invoke): Ditto.
+ (ScriptItem::invoke): Ditto.
+ (BackForwardItem::invoke): Ditto.
+
+2009-03-28 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Eric Seidel.
+
+ Always use wxGraphicsContext on Mac to ensure path, matrix, etc. support.
+
+ * wx/build-wxwebkit:
+
+2009-03-27 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ * Scripts/extract-localizable-strings: Fixed version check for perl 5.10 compatibility.
+
+2009-03-27 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Added waitForPolicyDelegate, a more-reliable way to make our mailto form submission
+ tests work.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (getFocusedElementCallback): Use static_cast instead of reinterpret_cast because there's
+ no reason to use reinterpret_cast just to get from void* to a specific type.
+ (getRootElementCallback): Ditto.
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (toAXElement): Ditto.
+ * DumpRenderTree/GCController.cpp:
+ (collectCallback): Ditto.
+ (collectOnAlternateThreadCallback): Ditto.
+ (getJSObjectCountCallback): Ditto.
+ * DumpRenderTree/LayoutTestController.cpp:
+ (many functions): Ditto.
+ (waitForPolicyDelegateCallback): Added.
+ (LayoutTestController::staticFunctions): Sorted functions by name.
+ Added waitForPolicyDelegate.
+
+ * DumpRenderTree/LayoutTestController.h: Sorted functions by name.
+ Added waitForPolicyDelegate.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting): Added code to reset the state of the
+ policy delegate.
+ (runTest): Added an additional call to resetWebViewToConsistentStateBeforeTesting just
+ before loading an empty page. This prevents extra policy delegate calls from being logged.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::waitForPolicyDelegate): Added. Puts us into wait mode, and then
+ tells the policy delegate to notify when done, then points the web view at the policy delegate.
+
+ * DumpRenderTree/mac/PolicyDelegate.h: Added setControllerToNotifyDone: method.
+
+ * DumpRenderTree/mac/PolicyDelegate.mm:
+ (-[PolicyDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]):
+ Added code to do notifyDone if controllerToNotifyDone is set.
+ (-[PolicyDelegate setControllerToNotifyDone:]): Added.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting): Added code to reset the state of the
+ policy delegate. Also moved the call to resetUndoManager in here.
+ (runTest): Removed the call to resetUndoManager (see above). Added an additional call to
+ resetWebViewToConsistentStateBeforeTesting to match the Mac code.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setCustomPolicyDelegate): 0, not NULL.
+
+ * DumpRenderTree/win/PolicyDelegate.cpp:
+ (PolicyDelegate::PolicyDelegate): Initialize m_controllerToNotifyDone to 0.
+ (PolicyDelegate::decidePolicyForNavigationAction): Added code to do notifyDone if
+ m_controllerToNotifyDone is set.
+
+ * DumpRenderTree/win/PolicyDelegate.h: Added setControllerToNotifyDone and
+ m_controllerToNotifyDone.
+
+2009-03-27 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=24765
+ prepare-ChangeLog and svn-create-patch doesn't work with svn 1.6
+
+ * Scripts/prepare-ChangeLog:
+ * Scripts/svn-create-patch:
+
+2009-03-26 Darin Adler <darin@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ * Scripts/do-webcore-rename:Update for rename of JSUnprotectedEventListener to
+ JSEventListener.
+
+2009-03-26 Darin Adler <darin@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ * Scripts/do-webcore-rename: Update for rename of JSEventListener to
+ JSProtectedEventListener. This includes all the related renames, but
+ not that one because that one renames the file.
+
+2009-03-26 Adam Roben <aroben@apple.com>
+
+ Reduce run-webkit-tests's time out limit to 15 seconds (or 2.5 minutes
+ under GuardMalloc)
+
+ The previous limit was 60 seconds (or 10 minutes under GuardMalloc).
+ There's no evidence that we need the limit to be this long, and having
+ it be so long just makes timed-out tests take forever to complete.
+ DRT's watchdog timer is 10 seconds, so still has time to fire before
+ run-webkit-tests will cut it off.
+
+ Reviewed by Simon Fraser.
+
+ * Scripts/run-webkit-tests:
+ (sub readFromDumpToolWithTimer): Reduced the limit to 15 seconds (or
+ 2.5 mintues under GuardMalloc).
+
+2009-03-26 Adam Roben <aroben@apple.com>
+
+ Make DRT's watchdog timer actually work on Windows
+
+ We were previously trying to use a CFRunLoopTimer for the watchdog
+ timer on Windows. This doesn't work because we don't use a CFRunLoop
+ on the main thread on Windows.
+
+ This patch changes the watchdog timer on Windows be a normal Windows
+ timer.
+
+ Reviewed by Simon Fraser.
+
+ * DumpRenderTree/DumpRenderTree.h: Moved declaration of
+ waitToDumpWatchdog from here...
+ * DumpRenderTree/mac/DumpRenderTreeMac.h: ...to here.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (invalidateAnyPreviousWaitToDumpWatchdog): Added. This function
+ cancels an existing watchdog timer.
+ (dump): Call invalidateAnyPreviousWaitToDumpWatchdog. This will
+ prevent watchdogs from previous tests firing during subsequent ones.
+ This matches Mac's behavior.
+
+ * DumpRenderTree/win/DumpRenderTreeWin.h: Added a declaration of
+ waitToDumpWatchdog.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (waitUntilDoneWatchdogFired): Converted this to be a Windows
+ TIMERPROC.
+ (LayoutTestController::setWaitToDump): Changed to use SetTimer instead
+ of CFRunLoopAddTimer.
+
+2009-03-25 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Steve Falkenburg.
+
+ Update test result search path for Windows now that it has updated versions of ICU, libxml2, and friends.
+
+ * Scripts/run-webkit-tests:
+
+2009-03-24 Mark Rowe <mrowe@apple.com>
+
+ Fix the Tiger build some more.
+
+ * DumpRenderTree/mac/TextInputController.m:
+
+2009-03-24 Mark Rowe <mrowe@apple.com>
+
+ Fix the Tiger build.
+
+ * DumpRenderTree/mac/TextInputController.m:
+
+2009-03-24 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Jon "The Most Boring Man in the World" Honeycutt.
+
+ Explicitly map NSNotFound to -1 so that the result of-characterIndexForPointX:Y: does
+ not differ between 32- and 64-bit.
+
+ * DumpRenderTree/mac/TextInputController.m:
+ (-[TextInputController characterIndexForPointX:Y:]):
+
+2009-03-24 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Use a different platform search path for tests and skip lists, so that Tiger doesn't end up
+ using the Leopard skip list. Tests and skip lists are now looked for in the directory for
+ the current OS and the generic "mac" directory. Tests and skip lists for newer OS versions are
+ ignored.
+
+ * Scripts/run-webkit-tests:
+
+2009-03-23 Stephanie <slewis@apple.com>
+
+ Fix root build.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2009-03-23 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Add production configuration for creating roots of WebKitTools.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2009-03-23 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ Make testapi run as part of the standard JavaScriptCore tests.
+
+ We only run testapi on the mac as currently windows webkit doesn't
+ place all the necessary files for testapi, and we also test the
+ JSC/CF APIs as well.
+
+ * Scripts/run-javascriptcore-tests:
+
+2009-03-21 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Make build-jsc build testapi and minidom in addition to jsc itself.
+
+ * Scripts/build-jsc:
+
+2009-03-20 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Only release the result NPVariant if the call to NPN_Invoke was successful.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (testNPRuntime):
+
+2009-03-19 Gustavo Noronha Silva <gns@gnome.org>
+
+ Reviewed by Mark Rowe.
+
+ Make determinePassedArchitecture always consume the --32-bit
+ option, also in non-AppleMacWebkit platforms. Solution pointed out
+ by Mark Rowe.
+
+ * Scripts/webkitdirs.pm:
+
+2009-03-19 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Work around <rdar://problem/6698023> by activating fonts from disk.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Copy fonts into DumpRenderTree.resources
+ in the built products directory.
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (activateFonts): Activate the fonts from disk.
+
+2009-03-18 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ <rdar://problem/6693300> Don't rely on printf from TestNetscapePlugIn appearing in test results
+
+ Switch from using printf to using the NPAPI to invoke console.log so that plug-in messages appear
+ in test results even when the plug-in's stdout differs from DumpRenderTree's stdout.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (log): Invoke console.log via the NPAPI.
+ (NPP_Destroy): Call log instead of printf.
+ (NPP_SetWindow): Ditto.
+ (handleEventCarbon): Ditto.
+ (handleEventCocoa): Ditto.
+ (NPP_HandleEvent): Pass the instance in to the event handler.
+
+2009-03-17 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Use the normal search rules for tests inside the platform directory.
+
+ This allows tests inside the platform directory to have different results
+ on different versions of Mac OS X.
+
+ * Scripts/run-webkit-tests:
+
+2009-03-17 David Kilzer <ddkilzer@apple.com>
+
+ resolve-ChangeLogs should not die on unmerged non-ChangeLog files
+
+ Reviewed by Adam Roben.
+
+ Fixes the following bug in resolve-ChangeLogs:
+
+ Use of uninitialized value in -e at ./WebKitTools/Scripts/resolve-ChangeLogs line 132.
+ Died at ./WebKitTools/Scripts/resolve-ChangeLogs line 164.
+
+ * Scripts/resolve-ChangeLogs:
+ (findUnmergedChangeLogs): Check the result of findChangeLog() to
+ make sure we don't add undef values to the list of files being
+ returned.
+
+2009-03-17 Gustavo Noronha Silva <gns@gnome.org>
+
+ Reviewed by Simon Fraser.
+
+ Fix the usage of the $architecture variable for non-Apple-Mac
+ ports.
+
+ * Scripts/webkitdirs.pm:
+
+2009-03-17 David Kilzer <ddkilzer@apple.com>
+
+ Bug 24645: bisect-builds script doesn't work with Safari 4 Public Beta (version string)
+
+ <https://bugs.webkit.org/show_bug.cgi?id=24645>
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/bisect-builds:
+ (makeNightlyList): Added checks for Safari 4 Public Beta on
+ Tiger and Leopard.
+
+2009-03-17 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Darin Adler
+
+ https://bugs.webkit.org/show_bug.cgi?id=24396
+
+ Change the terminology from '3D transforms' to '3D rendering'.
+
+ * Scripts/build-webkit:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2009-03-17 Gustavo Noronha Silva <gns@gnome.org>
+
+ Reviewed by Mark Rowe.
+
+ Enable HTML5 media elements support by default also for the GTK+
+ port.
+
+ * Scripts/build-webkit:
+
+2009-03-17 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Mark Rowe.
+
+ Tweak the BUILDING_ON_* defines so that they work with the default values set by
+ AvailabilityMacros.h.
+
+ https://bugs.webkit.org/show_bug.cgi?id=24630
+
+ * DumpRenderTree/mac/DumpRenderTreeMac.h:
+
+2009-03-17 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Make coverage testing more reliable by ensuring --coverage does not
+ clobber configuration settings, and by removing the unnecessary
+ dependency on matplotlib.
+
+ * CodeCoverage/regenerate-coverage-display:
+ * Scripts/webkitdirs.pm:
+
+2009-03-16 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Darin Adler and John Sullivan.
+
+ When a plug-in instance is torn down, all plug-in objects will first be invalidated and then deallocated.
+ Since objects can be deallocated in any order, it is not safe to call NPN_ReleaseObject on member variables.
+
+ Instead, just zero out the member variable in invalidate.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginInvalidate):
+ (pluginDeallocate):
+
+2009-03-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Sam Weinig.
+
+ REGRESSION: undo-iframe-location-change.html is failing on the buildbots
+ https://bugs.webkit.org/show_bug.cgi?id=24626
+
+ Added a call to [[webview undoManager] removeAllActions]
+ to make sure anything left on the undo stack after one test
+ will not affect any later test.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting):
+
+2009-03-14 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Change the layout test result search policy for Mac OS X to fit better with the idea of
+ newer OS versions improving on previous OS versions.
+
+ The results for the latest version of Mac OS X are placed in the "mac" directory. The
+ results for older versions of Mac OS X are structured as a series of overlays. When
+ running on Leopard, the results in "mac-leopard" are searched before those in "mac".
+ When running on Tiger, the results in "mac-tiger" are searched before those in
+ "mac-leopard" and "mac".
+
+ * Scripts/run-webkit-tests:
+
+2009-03-13 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Dan Bernstein.
+
+ Take advantage of the ability of recent versions of Xcode to easily switch the active
+ architecture.
+
+ * DumpRenderTree/mac/Configurations/DebugRelease.xcconfig:
+
+2009-03-13 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Timothy Hatcher.
+
+ Remove the --64-bit argument from scripts in favor of them detecting when 64-bit should be preferred.
+
+ The scripts will automatically target 64-bit if the system and hardware support it. This can be
+ overridden by passing --32-bit to individual scripts, or using set-webkit-configuration --32-bit
+ to make the override persistent.
+
+ * Scripts/build-webkit: Remove architecture-related code.
+ * Scripts/gdb-safari: Remove architecture-related code, and clean up how the environment variables are passed to gdb.
+ * Scripts/run-javascriptcore-tests: Remove architecture-related code.
+ * Scripts/run-safari: Ditto.
+ * Scripts/run-webkit-tests: Ditto.
+ * Scripts/set-webkit-configuration: Handle the --32-bit and --64-bit arguments. The --32-bit argument will set the
+ architecture preference to the 32-bit architecture of the machine. The --64-bit argument will remove any architecture
+ override that is in effect so that 64-bit support will be automatically detected.
+ * Scripts/webkitdirs.pm: Add auto-detection of the best architecture for the machine, and the ability to override the
+ auto-detection.
+
+2009-03-13 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ <rdar://problem/6610666> Revise the Cocoa event model text API
+
+ Add a case statement for NPCocoaEventTextInput.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (handleEventCocoa):
+
+2009-03-12 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Let DerivedSources.make know we want database APIs.
+
+ * wx/build-wxwebkit:
+
+2009-03-12 David Kilzer <ddkilzer@apple.com>
+
+ Bug 24378: resolve-ChangeLogs should use git status or svn status to find and fix unmerged ChangeLogs
+
+ <https://bugs.webkit.org/show_bug.cgi?id=24378>
+
+ Reviewed by Adam Roben.
+
+ * Scripts/resolve-ChangeLogs: If -f|--fix-merged is not passed
+ and no file or directory names are specified on the command-line
+ then try to find unmerged ChangeLog files based on 'svn stat' or
+ 'git diff'. Added global $isGit and $isSVN variables so that
+ isGit() and isSVN() only have to be called once.
+ (findUnmergedChangeLogs): Added.
+
+2009-03-11 David Kilzer <ddkilzer@apple.com>
+
+ Clarify comments regarding order of FEATURE_DEFINES
+
+ Rubber-stamped by Mark Rowe.
+
+ * Scripts/build-webkit: Added warning about keeping
+ FEATURE_DEFINES in order and the consequences when they are not.
+
+2009-03-11 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ Gtk] Implement LayoutTestControllerGtk::setPrivateBrowsingEnabled
+ https://bugs.webkit.org/show_bug.cgi?id=24487
+
+ Also reset WebSettings to its default state for JavaScript
+ profiling, Developer Extras and Private Browsing before running
+ the test (can be after each test but we want to be consistent with
+ other ports in this regard)
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+ (runTest):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setPrivateBrowsingEnabled):
+
+2009-03-11 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [GTK]DumpRenderTree doesn't compile for non-X11 GTK ports anymore
+ https://bugs.webkit.org/show_bug.cgi?id=2260
+
+ Add plugin support only for X11 builds
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (setDefaultsToConsistentStateValuesForTesting):
+ * GNUmakefile.am:
+
+2009-03-08 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Mark Rowe.
+
+ Implement setJavaScriptProfilingEnabled by enabling the Developer
+ Extras and the JavaScript profiling on the WebKitWebInspector. After
+ this change we pass the three enabled tests in fast/profiler.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (runTest): Reset setJavaScriptProfilingEnabled after each test run
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setJavaScriptProfilingEnabled):
+
+2009-03-07 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Gtk] Enable http history tests
+ https://bugs.webkit.org/show_bug.cgi?id=24394
+
+ Get the index of the current item from the list of (history) items
+ to print before adding the back history items to the list. This
+ will make the 'curr' pointer point to the correct item in the
+ actual results, therefore, passing some of the http/tests/history
+ tests.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dumpBackForwardListForWebView):
+
+2009-03-06 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by George Staikos.
+
+ When building QtWebKit in release mode make sure that QT_SHARED is defined
+ otherwise none of the public API will be exported. This leads to missing
+ symbols and link errors if hidden-visibility is used.
+
+ * Scripts/webkitdirs.pm:
+
+2009-03-06 Adam Roben <aroben@apple.com>
+
+ Change the isCygwin check in update-webkit to isAppleWinWebKit
+
+ This matches a similar check in build-webkit, and is more correct.
+
+ Reviewed by Alexey Proskuryakov.
+
+ * Scripts/update-webkit: Only call update-webkit-auxiliary-libs if
+ isAppleWinWebKit is true.
+
+2009-03-06 Adam Roben <aroben@apple.com>
+
+ Make update-webkit-support-libs fail if WebKitSupportLibrary.zip is
+ present but out of date
+
+ Reviewed by Alexey Proskuryakov.
+
+ * Scripts/update-webkit-support-libs: Changed to use
+ dieAndInstructToDownload when the zip file doesn't exist. Added an MD5
+ check to make sure the file is up-to-date. If it is out of date, print
+ an error message and quit.
+ (sub dieAndInstructToDownload): Added. Prints an error message and
+ quits with an error.
+
+2009-03-03 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by John Sullivan.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22884
+ <rdar://problem/6449783>
+ modified layout test crashes Safari
+
+ Add destroyNullStream test function to the test plug-in.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (destroyNullStream):
+ (pluginInvoke):
+
+2009-03-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin Adler
+
+ Support layout test covering <rdar://problem/6616664>
+
+ Change NSURLRequest/IWebURLRequest dumping to include the mainDocumentURL
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[NSURLRequest _drt_descriptionSuitableForTestResult]): Return both the request URL and the
+ mainDocumentURL.
+
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (descriptionSuitableForTestResult): Return both the request URL and the mainDocumentURL.
+
+2009-03-02 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Enable Geolocation (except on Tiger and Leopard).
+
+ * Scripts/build-webkit:
+
+2009-03-02 Kevin Ollivier <kevino@theolliviers.com>
+
+ Build fixes for wxWidgets Mac trunk build.
+
+ * wx/build-wxwebkit:
+
+2009-03-02 Timothy Hatcher <timothy@apple.com>
+
+ Allow for multiline quoted text in JavaScript files when looking for function names.
+
+ https://bugs.webkit.org/show_bug.cgi?id=24296
+
+ Reviewed by David Kilzer.
+
+ * Scripts/prepare-ChangeLog:
+
+2009-03-02 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by Eric Seidel.
+
+ Add three new drt helper functions that enable all of the tests in
+ LayoutTests/animation/* and LayoutTests/transitions/* to now pass.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+ (LayoutTestController::numberOfActiveAnimations):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-03-02 Adam Roben <aroben@apple.com>
+
+ Windows build fix after r41349
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::getChildrenWithRange):
+
+2009-03-01 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Bug 24282: AX Palindrome error when asking for a specific index of the AXChildren array
+
+ Change getChildAtIndex() to get a range of children instead of all the children.
+ This exercises code in WebCore that returns elements when asked for from a range.
+
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::getChildrenWithRange):
+ (AccessibilityUIElement::getChildAtIndex):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::getChildrenWithRange):
+
+2009-03-01 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Gtk] get the HTTP layout tests going
+ https://bugs.webkit.org/show_bug.cgi?id=24259
+
+ Determine the frame's response and decide whether to dump as text
+ or the render tree
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump):
+
+2009-03-01 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Gtk] get the HTTP layout tests going
+ https://bugs.webkit.org/show_bug.cgi?id=24259
+
+ Implement dumping of WebKitWebBackForwardList and its history
+ items.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (compareHistoryItems):
+ (dumpHistoryItem):
+ (dumpBackForwardListForWebView):
+ (dump):
+ (runTest):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::clearBackForwardList):
+ * DumpRenderTree/gtk/WorkQueueItemGtk.cpp:
+ (BackForwardItem::invoke):
+
+2009-02-28 Zan Dobersek <zandobersek@gmail.com>
+
+ Reviewed by Holger Freyther.
+
+ Set the resolution for the default screen to 72.0.
+ This way, setting font sizes results in expected values.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (setDefaultsToConsistentStateValuesForTesting):
+
+2009-02-28 Gustavo Noronha Silva <gns@gnome.org>
+
+ Reviewed by Holger Freyther.
+
+ Adds a WebKitMakeArguments environment variable to enable passing
+ of arguments such as '-j2' to make for the autotools build.
+
+ * Scripts/webkitdirs.pm:
+
+2009-02-28 Gustavo Noronha Silva <gns@gnome.org>
+
+ Reviewed by Holger Freyther.
+
+ Add a GTK+-only option to enable GNOME Keyring when building.
+
+ * Scripts/build-webkit:
+
+2009-02-28 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Gtk] webkitdirs.pm modify path in when detecting 3D transforms and accelerated compositing
+ https://bugs.webkit.org/show_bug.cgi?id=24076
+
+ Refactor gtk lib detection and put it in builtDylibPathForName
+
+ * Scripts/webkitdirs.pm:
+
+2009-02-28 Christian Dywan <christian@twotoasts.de>
+
+ Rubber-stamped by Holger Freyther.
+
+ * GtkLauncher/main.c:
+ (activate_uri_entry_cb):
+ (main): Use the new webkit_web_view_load_uri to open URIs.
+
+2009-02-27 Xan Lopez <xan@gnome.org>
+
+ Rubber-stamped by Alexey Proskuryakov.
+
+ https://bugs.webkit.org/show_bug.cgi?id=24222
+ [GTK] Remove checks for old glib versions
+
+ libsoup, which is a hard dependency, needs at least glib 2.15.3,
+ so remove all glib checks for versions older than that.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setWaitToDump):
+
+2009-02-25 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Eric Seidel
+
+ Fix spew about a WebView being deallocated while key value observers are
+ still registered with it by making sure that we always stop observing
+ _isUsingAcceleratedCompositing in -[DumpRenderTreeWindow close].
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpRenderTree):
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ (-[DumpRenderTreeWindow close]):
+
+2009-02-25 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Do not queue the calls to 'DumpRenderTree::dump()' as this can result
+ in more than one call as a test that calls 'notifyDone()' can then be
+ subsequently fully loaded and initiate a second dump. Also make sure
+ to stop any existing page load that is happening before running the next
+ test. Combined this serves to produce 217 more passing tests for the
+ Qt port or roughly 5% at this point.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+
+2009-02-25 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Dan Bernstein
+
+ https://bugs.webkit.org/show_bug.cgi?id=23854
+
+ Have the DumpRenderTreeWindow observe the -_isUsingAcceleratedCompositing
+ property of the WebView, and use that to turn -autodisplay on and off.
+ This is necessary so that accelerated animations start correctly.
+ We can thus remove the -display hack in createBitmapContextFromWebView().
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (createWebViewAndOffscreenWindow):
+ (dumpRenderTree):
+ * DumpRenderTree/mac/DumpRenderTreeWindow.h:
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ (-[DumpRenderTreeWindow close]):
+ (-[DumpRenderTreeWindow webView]):
+ (-[DumpRenderTreeWindow startObservingWebView]):
+ (-[DumpRenderTreeWindow stopObservingWebView]):
+ (-[DumpRenderTreeWindow observeValueForKeyPath:ofObject:change:context:]):
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (createBitmapContextFromWebView):
+
+2009-02-25 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by Zack Rusin.
+
+ https://bugs.webkit.org/show_bug.cgi?id=24158
+ Implement the queue*() methods of the layoutTestController and begin
+ implementing the dump of the back/forward list. This results in 2% more
+ tests passing as well as 23 currently skipped tests now passing.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::dumpBackForwardList):
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (findFrameNamed):
+ (LoadItem::invoke):
+ (ReloadItem::invoke):
+ (ScriptItem::invoke):
+ (BackForwardItem::invoke):
+ (LayoutTestController::reset):
+ (LayoutTestController::processWork):
+ (LayoutTestController::maybeDump):
+ (LayoutTestController::queueBackNavigation):
+ (LayoutTestController::queueForwardNavigation):
+ (LayoutTestController::queueLoad):
+ (LayoutTestController::queueReload):
+ (LayoutTestController::queueScript):
+ * DumpRenderTree/qt/jsobjects.h:
+ (LayoutTestController::shouldDumpBackForwardList):
+ (LayoutTestController::dumpBackForwardList):
+
+2009-02-24 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Don't print out that you are generating new results if you are not in fact
+ generating new results and disable generating new results by default for
+ the all ports other than the canonical Apple Mac port since this can litter
+ the source directory with hundreds of new results since other ports
+ are not as up to date.
+
+ * Scripts/run-webkit-tests:
+
+2009-02-24 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by Cameron Zwarich.
+
+ The Qt port does not support these yet nor does the nm check work with
+ QMake based build.
+
+ * Scripts/webkitdirs.pm:
+
+2009-02-24 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ [Gtk] add options for 3D transforms and HTML5 channel messaging to the build
+ https://bugs.webkit.org/show_bug.cgi?id=24072
+
+ Allow toggling of 3D transforms and HTML5 channel messaging
+ support for the Autotools (Gtk) build.
+
+ Also add '--gtk' in the build-webkit help doc and fix autotools
+ option for web-workers support.
+
+ * Scripts/build-webkit:
+
+2009-02-23 Xan Lopez <xan@gnome.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22624
+ [SOUP][GTK] Need API to get SoupSession from WebKit.
+
+ Add soup flags now that dependency is explicit.
+
+ * GNUmakefile.am:
+
+2009-02-22 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Fix assertion failures in editing/pasteboard/paste-RTFD.html and editing/pasteboard/paste-TIFF.html in 64-bit.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (swizzleAllMethods): When adding a new method to a class, use the implementation and type of the new method rather
+ than of an arbitrary existing method on the class.
+
+2009-02-13 Eric Seidel <eric@webkit.org>
+
+ Rubber-stamped by Alexey Proskuryakov.
+
+ Add a few ignores to make-js-test-wrappers.
+
+ * Scripts/make-js-test-wrappers:
+
+2009-02-17 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Prepend file:// to the test result filename to make
+ GtkLauncher display the result page.
+
+ * Scripts/run-webkit-tests:
+
+2009-02-16 Gustavo Noronha Silva <gns@gnome.org>
+
+ Reviewed by Adam Roben
+
+ Actually use the installation prefix defined in WebKitInstallationPrefix,
+ in autotools builds.
+
+ * Scripts/webkitdirs.pm:
+
+2009-02-12 Simon Fraser <simon.fraser@apple.com>
+
+ No review.
+
+ Remove debugging code which was committed by mistake.
+
+ * Scripts/run-webkit-tests:
+
+2009-02-12 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Adam Roben
+
+ https://bugs.webkit.org/show_bug.cgi?id=23928
+
+ Add detection of accelerated compositing and 3d transforms,
+ and add various directories to $ignoredDirectories when these
+ features are off.
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2009-02-12 Adam Roben <aroben@apple.com>
+
+ Fix Bug 23922: Warning message from run-webkit-tests when Skipped file
+ contains non-existent tests is confusing and is given for disabled
+ tests
+
+ <https://bugs.webkit.org/show_bug.cgi?id=23922>
+
+ We now no longer warn about disabled tests. The warning now reads:
+
+ Skipped list contained '$item', but no file of that name could be
+ found
+
+ Reviewed by John Sullivan.
+
+ * Scripts/run-webkit-tests:
+ (top level): Pass the list name to processIgnoreTests so it can print
+ out a reasonable warning message.
+ (processIgnoreTests): Take a list name as a second parameter and use
+ it to display a better warning message. Also check for a "-disabled"
+ version of the test before warning about it not existing.
+
+2009-02-11 Adam Roben <aroben@apple.com>
+
+ Windows fix for Bug 22239: Implement missing animation & transition
+ APIs on LayoutTestController for non-mac platforms
+
+ <https://bugs.webkit.org/show_bug.cgi?id=22239>
+
+ Reviewed by Simon Fraser.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+ (LayoutTestController::numberOfActiveAnimations):
+ Implemented these by calling through to IWebFramePrivate.
+
+2009-02-10 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ * Scripts/build-webkit:
+
+ https://bugs.webkit.org/show_bug.cgi?id=23883
+
+ Added support --3d-transforms. Defaults to off
+
+2009-02-11 Adam Roben <aroben@apple.com>
+
+ Fix crashes in http/tests/history/redirect-301.pl and friends on
+ Windows
+
+ Reviewed by Alexey Proskuryakov.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::webHistoryItemCount): Null-check the shared
+ WebHistory instance before dereferencing it.
+
+2009-02-10 Adam Roben <aroben@apple.com>
+
+ Fix Bug 23869: Pixel tests can't be run on Windows
+
+ <https://bugs.webkit.org/show_bug.cgi?id=23869>
+
+ This patch gets the pixel tests limping along on Windows again.
+
+ Reviewed by Dan Bernstein.
+
+ * DumpRenderTree/DumpRenderTree.sln: Changed to use the new
+ Debug_Internal configuration of ImageDiff in the Debug_Internal
+ configuration of this solution.
+
+ * DumpRenderTree/cg/PixelDumpSupportCG.cpp:
+ (printPNG): Changed to call fwrite in a loop, since this call was
+ failing due to the buffer being too large on Windows.
+ (dumpWebViewAsPixelsAndCompareWithExpected): Removed an unnecessary
+ #if PLATFORM(MAC)/#endif.
+
+ * DumpRenderTree/win/ImageDiff.vcproj: Added a Debug_Internal
+ configuration that matches the Debug configuration but also references
+ debug_internal.vsprops.
+
+ * DumpRenderTree/win/PixelDumpSupportWin.cpp:
+ (createBitmapContextFromWebView): Renamed from
+ getBitmapContextFromWebView to match the name used in the
+ cross-platform code.
+
+2009-02-10 Adam Roben <aroben@apple.com>
+
+ Robustify DumpRenderTree/win a little
+
+ DumpRenderTree was previously not holding a ref to the WebViews it
+ created via window.open. It was getting away with this because
+ WebViews get reffed by being preference notification observers and by
+ registering for drag-n-drop messages. Now DRT does hold a ref, in case
+ this situation changes in the future.
+
+ Reviewed by Alexey Proskuryakov.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dumpBackForwardListForAllWindows): Added a .get().
+ (windowToWebViewMap): Changed to use the WindowToWebViewMap typedef.
+ * DumpRenderTree/win/DumpRenderTreeWin.h: Changed the
+ windowToWebViewMap() to hold a ref to the WebViews it contains.
+
+2009-02-05 Simon Fraser <simon.fraser@apple.com>
+
+ Fix the #include file order, per review comments.
+
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+
+2009-02-05 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Dan Bernstein
+
+ https://bugs.webkit.org/show_bug.cgi?id=23362
+
+ If the WebHTMLView uses accelerated compositing, we need for force
+ the on-screen capture path and also force animations to start with -display
+ since the DRT window has autodisplay disabled.
+
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (createBitmapContextFromWebView):
+
+2009-02-03 miggilin <mr.diggilin@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ Change the way wxWidgets build gets arguments.
+ Change "checkForArgumentAndRemoveFromARGV" in build-webkit to check if the
+ argument passed matches one in ARGV exactly (allows, ie, --wx-args not to be
+ removed when --wx is checked for).
+
+ https://bugs.webkit.org/show_bug.cgi?id=23701
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2009-01-30 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Catch exceptions thrown by AppKit when accessing an attribute than an element
+ doesn't return.
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (attributesOfElement):
+
+2009-01-29 David Kilzer <ddkilzer@apple.com>
+
+ Remove semi-colons from the end of ObjC method implementations
+
+ Rubber-stamped by Adam Roben.
+
+ $ find WebKitTools -name \*.m -o -name \*.mm -exec perl -e 'undef $/; $s = <>; while ($s =~ m/[\n\r][-+].*;[\s\r\n]+\{/g) { print "$ARGV: $&\n"; }' {} \;
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate webView:didFailLoadWithError:forFrame:]):
+ (-[FrameLoadDelegate webView:windowScriptObjectAvailable:]):
+ (-[FrameLoadDelegate webView:didFinishDocumentLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didHandleOnloadEventsForFrame:]):
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webViewFrame:]):
+
+2009-01-28 Geoffrey Garen <ggaren@apple.com>
+
+ Build fix for GTK.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::webHistoryItemCount):
+
+2009-01-28 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Added support for querying how many history items were created during a
+ layout test.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (getWebHistoryItemCountCallback):
+ (LayoutTestController::staticValues):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::webHistoryItemCount):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::webHistoryItemCount):
+
+2009-01-26 Pierre-Olivier Latour <pol@apple.com>
+
+ Tweaked again earlier fix, this time just to print a warning and not abort if
+ attempting to generate pixel results and Perian is installed.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22615
+
+ * Scripts/run-webkit-tests:
+
+2009-01-26 Christian Dywan <christian@twotoasts.de>
+
+ Rubber stamped by Holger Freyther.
+
+ * GtkLauncher/main.c:
+ (main): Initialize threads, which is required for libSoup.
+
+2009-01-23 David Kilzer <ddkilzer@apple.com>
+
+ * Scripts/do-webcore-rename: Removed 10 header guard renames that
+ had already been fixed, and updated 4 renames whose original values
+ had changed.
+
+2009-01-22 Anders Carlsson <andersca@apple.com>
+
+ Fix Windows build.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+
+2009-01-22 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Clean up the test plug-in code. We now always use the CG drawing model and the
+ Cocoa event model. It is however possible to revert to the old Carbon event model by
+ specifying forcecarbon=true in the embed/object tag.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+ (handleEventCarbon):
+ (handleEventCocoa):
+ (NPP_HandleEvent):
+
+2009-01-21 Pierre-Olivier Latour <pol@apple.com>
+
+ Tweaked earlier fix to only print a warning when Perian is installed,
+ and fail completely only if attempting to generate new pixel test results.
+
+ https://bugs.webkit.org/show_bug.cgi?id=23392
+
+ * Scripts/run-webkit-tests:
+
+2009-01-20 Darin Adler <darin@apple.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Bug 23450: string leaks seen in DumpRenderTree accessibility test code
+ https://bugs.webkit.org/show_bug.cgi?id=23450
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (isAttributeSettableCallback): Add the missing JSStringRelease call.
+ (attributeValueCallback): Ditto.
+
+2009-01-20 Pierre-Olivier Latour <pol@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Print warning regarding display color profile change in run-webkit-tests instead of DRT.
+
+ https://bugs.webkit.org/show_bug.cgi?id=23392
+
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (setupMainDisplayColorProfile):
+ * Scripts/run-webkit-tests:
+
+2009-01-20 Pierre-Olivier Latour <pol@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Changed run-webkit-tests to abort on the Mac if pixel tests are enabled and Perian is installed,
+ in order to avoid result differences in some media tests.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22615
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2009-01-19 Sam Weinig <sam@webkit.org>
+
+ * Scripts/do-webcore-rename: Add JSValuePtr and ProtectedJSValuePtr.
+
+2009-01-16 Gabor Loki <loki@inf.u-szeged.hu>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/webkitdirs.pm: Added '--makeargs' parameter which can pass additional
+ parameters to make command in QMake projects.
+
+2009-01-16 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Add AX methods to retrieve the parent of an element.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (parentElementCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::parentElement):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::parentElement):
+
+2009-01-16 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Set the count to the right number of elements.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.cpp:
+ (testEnumerate):
+
+2009-01-14 David Kilzer <ddkilzer@apple.com>
+
+ BUILD FIX: Use COM API on Windows in LayoutTestController::setIconDatabaseEnabled()
+
+ Rubber-stamped by Alice Liu.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setIconDatabaseEnabled): Use COM API
+ to get the shared WebIconDatabase.
+
+2009-01-14 Jeremy Moskovich <jeremy@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ <https://bugs.webkit.org/show_bug.cgi?id=16829>
+ Implement NPN_SetException()
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginInvoke):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.cpp:
+ (initializeIdentifiers):
+ (testHasMethod):
+ (testInvoke):
+
+2009-01-13 Dmitry Titov <dimich@chromium.org>
+
+ Reviewed by David Kilzer.
+
+ https://bugs.webkit.org/show_bug.cgi?id=23304
+ Fix svn-apply to match svn-unapply to recognize added files in 'git diff' patches.
+
+ * Scripts/svn-apply: Added a check (similar to svn-unapply) to recognize added files.
+
+2009-01-14 David Kilzer <ddkilzer@apple.com>
+
+ BUILD FIX: Implement LayoutTestController::setIconDatabaseEnabled(bool) for GTK
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (runTest): Added call to reset the icon database to match Mac
+ and Windows ports.
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setIconDatabaseEnabled): Implemented
+ stub method.
+
+2009-01-14 David Kilzer <ddkilzer@apple.com>
+
+ Bug 22795: favicons should be saved to webarchives
+
+ <https://bugs.webkit.org/show_bug.cgi?id=22795>
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setIconDatabaseEnabledCallback): Added.
+ (setJavaScriptProfilingEnabledCallback): Realphabetized.
+ (LayoutTestController::staticFunctions): Added entry for calling
+ LayoutTestController.setIconDatabaseEnabled(bool) from JavaScript.
+ * DumpRenderTree/LayoutTestController.h:
+ (setIconDatabaseEnabledCallback): Added declaration.
+ (setJavaScriptProfilingEnabledCallback): Realphabetized.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (runTest): Disable the icon database before each test.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setIconDatabaseEnabled): Added.
+ (LayoutTestController::setJavaScriptProfilingEnabled): Realphabetized.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest): Disable the icon database before each test.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setIconDatabaseEnabled): Added.
+
+2009-01-14 Steve Falkenburg <sfalken@apple.com>
+
+ Update copyright year in version resources.
+
+ Reviewed by Adam Roben.
+
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.rc:
+
+2009-01-14 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by John Sullivan.
+
+ - update copyright
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/Info.plist:
+ * WebKitLauncher/Info.plist:
+
+2009-01-13 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Add NPRuntime test.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (testNPRuntime):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+ (NPP_GetValue):
+
+2009-01-12 Mark Rowe <mrowe@apple.com>
+
+ Use the modern spelling of WebKit.
+
+ * Scripts/find-extra-includes:
+ * Scripts/report-include-statistics:
+ * Scripts/run-webkit-app:
+ * Scripts/svn-unapply:
+ * Scripts/update-webkit:
+
+2009-01-11 Darin Adler <darin@apple.com>
+
+ * Scripts/make-js-test-wrappers: Updated so it won't overwrite tests in the svg/dom
+ directory that aren't using standard wrappers.
+
+2009-01-11 Robert Blaut <webkit@blaut.biz>
+
+ Reviewed by Eric Seidel.
+
+ <https://bugs.webkit.org/show_bug.cgi?id=23134>
+ Update bisect-builds for Safari 3.2 to prevent crashes
+
+ * Scripts/bisect-builds: Added Safari 3.2 and the corresponding minimal revision, r37348.
+
+2009-01-08 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by Simon Hausmann.
+
+ Explicitly set these so that the layout tests do not break.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+
+2009-01-07 Glenn Wilson <gwilson@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Changed DumpRenderTree to re-enable Javascript in web preferences on every test.
+ This fixes the case when a user mistakenly disables Javascript, and all layout tests crash.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (testStringByEvaluatingJavaScriptFromString):
+ (setDefaultsToConsistentValuesForTesting):
+
+2009-01-07 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Implement numberOfActiveAnimations to fix the build
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::numberOfActiveAnimations):
+
+2009-01-07 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by George Staikos.
+
+ Fix unused variable warnings
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::javaScriptAlert):
+ (WebCore::WebPage::javaScriptConfirm):
+ (WebCore::WebPage::javaScriptPrompt):
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::maybeDump):
+ * DumpRenderTree/qt/main.cpp:
+ (get_backtrace):
+ * DumpRenderTree/qt/testplugin.cpp:
+ (TestPlugin::create):
+
+2009-01-06 Pierre-Olivier Latour <pol@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Added new JS API numberOfActiveAnimations() that returns the number of active CSS transitions & animations.
+ This effectively exposes the new AnimationController::numberOfActiveAnimations() API from WebCore.
+
+ https://bugs.webkit.org/show_bug.cgi?id=23126
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (numberOfActiveAnimationsCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::numberOfActiveAnimations):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::numberOfActiveAnimations):
+
+2009-01-04 David Kilzer <ddkilzer@apple.com>
+
+ Don't install internal headers in WebKit framework
+
+ Reviewed by Darin Adler.
+
+ Since WebHTMLRepresentationInternal.h and WebTypesInternal.h are
+ no longer installed in WebKit.framework/PrivateHeaders, use the
+ special relationship of DumpRenderTree within the WebKit source
+ tree to include the internal headers through relative paths.
+ Created the concept of mac/InternalHeaders to hide the ugly
+ paths.
+
+ * DumpRenderTree/mac/Configurations/Base.xcconfig: Added
+ mac/InternalHeaders to HEADER_SEARCH_PATHS.
+ * DumpRenderTree/mac/InternalHeaders/WebKit/WebHTMLRepresentationInternal.h: Added.
+ * DumpRenderTree/mac/InternalHeaders/WebKit/WebTypesInternal.h: Added.
+
+2009-01-02 Adam Treat <treat@kde.org>
+
+ Reviewed by George Staikos.
+
+ Add support for fixedLayoutSize to the qt DRT
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::setFixedLayoutSize):
+ (LayoutTestController::setUseFixedLayout):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-01-03 David D. Kilzer <ddkilzer@webkit.org>
+
+ Bug 23091: Some webarchive http tests intermittently fail due to Connection/Keep-Alive header differences
+
+ <https://bugs.webkit.org/show_bug.cgi?id=23091>
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (normalizeHTTPResponseHeaderFields): Remove Keep-Alive and
+ Connection headers from webarchive results.
+
+2008-12-31 Zan Dobersek <zandobersek@gmail.com>
+
+ Reviewed by Holger Freyther.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22812
+
+ Prevent TestNetscapePlugin from installing system-wide.
+
+ * GNUmakefile.am:
+
+2008-12-31 Zan Dobersek <zandobersek@gmail.com>
+
+ Reviewed by Holger Freyther.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22842
+
+ Move WebKitWebView's size allocation into a proper place.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump):
+ (runTest):
+
+2008-12-24 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Timothy Hatcher.
+
+ Move the guts of determineCurrentSVNRevision to VCSUtils as svnRevisionForDirectory,
+ and make it work for git too.
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/webkitdirs.pm:
+
+2008-12-22 Nikolas Zimmermann <nikolas.zimmermann@torchmobile.com>
+
+ Reviewed by George Staikos.
+
+ Ignore http/tests/wml, if no WML support is present.
+ Add http/tests/wml to list of HTTP tests, allowed to access local resources.
+
+ * Scripts/run-webkit-tests:
+
+2008-12-19 David Levin <levin@chromium.org>
+
+ Reviewed by Mark Rowe.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22930
+
+ Make the git diff command used for preparing the change log avoid using any external diff tools.
+
+ * Scripts/prepare-ChangeLog:
+
+2008-12-19 Gustavo Noronha Silva <gns@gnome.org>
+
+ Reviewed by Holger Freyther.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22686
+
+ Added files which were missing from the TestNetscapePlugin
+ directory to the SOURCES variable, so that they will be
+ distributed in a make dist.
+
+ * GNUMakefile.am:
+
+2008-12-18 Cameron Zwarich <zwarich@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ Add tests for bug 21855: REGRESSION (r37323): Gmail complains about popup blocking when opening a link
+ <https://bugs.webkit.org/show_bug.cgi?id=21855>
+ <rdar://problem/6278244>
+
+ Add support for scheduling asynchronous clicks to DumpRenderTree, but
+ only on the Mac.
+
+ * DumpRenderTree/mac/EventSendingController.h:
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]): Expose
+ scheduleAsynchronousClick to JavaScript.
+ (-[EventSendingController scheduleAsynchronousClick]): Add.
+
+2008-12-15 Darin Adler <darin@apple.com>
+
+ * Scripts/make-js-test-wrappers: Added another exception to avoid overwriting
+ a custom-written test.
+
+2008-12-15 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ Implement setJavaScriptProfilingEnabled in the Qt DRT to pass fast/profiler.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::setJavaScriptProfilingEnabled):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2008-12-13 Zan Dobersek <zandobersek@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22039
+
+ Implement animation and transition pausing.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+
+2008-12-12 Brent Fulgham <bfulgham@gmail.com>
+
+ Reviewed by Adam Roben.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22809
+
+ Increase timeout in call to initWithURL so that people actually see
+ new web pages when they type URLs rather than a blank screen.
+
+ * WinLauncher/WinLauncher.cpp:
+ (loadURL): Increase timeout in initWithURL from 0 to 60 seconds.
+
+2008-12-12 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Add a renaming idea.
+
+2008-12-12 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Simon Hausmann.
+
+ Update the WebKit.qrc and add a script to automatically generate the file.
+
+ With the way rcc and qmake work this can not be done at build time
+ as the WebKit.qrc must sit inside the directory that contains the files
+ and at build time we may not change the content of the source directory.
+
+ * Scripts/generate-qt-inspector-resource: Added.
+
+2008-12-11 Cameron Zwarich <zwarich@apple.com>
+
+ Rubber-stamped by Mark Rowe.
+
+ Roll out r39212 due to assertion failures during layout tests, multiple
+ layout test failures, memory leaks, and obvious incorrectness.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+
+2008-12-10 Glenn Wilson <gwilson@google.com>
+
+ Reviewed by Adam Roben.
+
+ Changed LayoutTestController and DumpRenderTree to allow for manual
+ overriding of default preferences at test time. Also added support for
+ resetting the preferences after each test.
+ https://bugs.webkit.org/show_bug.cgi?id=20534
+
+ * DumpRenderTree/LayoutTestController.cpp: Added callback method for overriding preferences
+ * DumpRenderTree/LayoutTestController.h: Added signature for callback
+ * DumpRenderTree/win/DumpRenderTree.cpp: Added calls to reset preferences after each test if necessary
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp: Added JS override function
+ * DumpRenderTree/mac/DumpRenderTree.mm: Added calls to reset preferences after each test if necessary
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm: Added JS override function
+
+2008-12-10 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Implement the new policy delegate (including navigation type and permissive mode) for DRT/win
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ * DumpRenderTree/win/DumpRenderTreeWin.h:
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setCustomPolicyDelegate):
+
+ * DumpRenderTree/win/PolicyDelegate.cpp:
+ (PolicyDelegate::PolicyDelegate):
+ (PolicyDelegate::decidePolicyForNavigationAction):
+ * DumpRenderTree/win/PolicyDelegate.h:
+ (PolicyDelegate::setPermissive):
+
+2008-12-10 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin
+
+ Change the custom policy delegate to actually allow navigation for tests that need it.
+ The new behavior is opt-in and doesn't require any changes in old tests.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setCustomPolicyDelegateCallback): Allow for a second boolean argument to set the permissive flag on the custom
+ policy delegate, which will be false by default to maintain original behavior.
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setCustomPolicyDelegate):
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setCustomPolicyDelegate): Partially stubbed out for now.
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setCustomPolicyDelegate): Still stubbed out, but with new param.
+
+ * DumpRenderTree/mac/PolicyDelegate.h:
+ * DumpRenderTree/mac/PolicyDelegate.mm:
+ (-[PolicyDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]): If the permissive flag
+ is set, allow the navigation.
+ (-[PolicyDelegate setPermissive:]): Change the behavior between "use" and "ignore" - allowing navigation or not.
+
+2008-12-09 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Ada Chan.
+
+ Fix gdb-safari on Tiger.
+
+ gdb on Tiger does not take the -arch flag, so do not pass it.
+
+ * Scripts/gdb-safari:
+
+2008-12-09 Nikolas Zimmermann <nikolas.zimmermann@torchmobile.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Ignore WML tests, if no WML support available.
+
+ * Scripts/run-webkit-tests:
+
+2008-12-08 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Added a shortcut for --jsDriver-args, which I use a lot.
+
+ * Scripts/run-javascriptcore-tests:
+
+2008-12-08 Stephanie Lewis <slewis@apple.com>
+
+ Fix Tiger build.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+
+2008-12-08 Darin Adler <darin@apple.com>
+
+ Reviewed by John Sullivan.
+
+ - test machinery for https://bugs.webkit.org/show_bug.cgi?id=22409
+ REGRESSION: cmd-shift-left/right don't switch tabs, instead select text
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (isCommandEnabledCallback): Added.
+ (LayoutTestController::staticFunctions): Added "isCommandEnabled".
+ * DumpRenderTree/LayoutTestController.h: Ditto.
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::isCommandEnabled): Ditto.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (-[CommandValidationTarget initWithAction:]): Added. Used to get the
+ command validation system to tell us if a comment is enabled.
+ (-[CommandValidationTarget action]): Ditto.
+ (-[CommandValidationTarget tag]): Ditto.
+ (LayoutTestController::isCommandEnabled): Ditto.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::isCommandEnabled): Ditto.
+
+2008-12-08 David Kilzer <ddkilzer@apple.com>
+
+ Bug 22555: Sort "children" sections in Xcode project files
+
+ <https://bugs.webkit.org/show_bug.cgi?id=22555>
+
+ Reviewed by Eric Seidel.
+
+ * DrawTest/DrawTest.xcodeproj/project.pbxproj: Sorted.
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Sorted.
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj: Sorted.
+
+2008-12-08 David Kilzer <ddkilzer@apple.com>
+
+ Bug 22555: Sort "children" sections in Xcode project files
+
+ <https://bugs.webkit.org/show_bug.cgi?id=22555>
+
+ Reviewed by Timothy Hatcher.
+
+ * Scripts/sort-Xcode-project-file: By popular request, don't sort
+ the mainGroup in the project (the list of items below the top-level
+ project file).
+
+2008-12-05 David Kilzer <ddkilzer@apple.com>
+
+ Bug 22555: Sort "children" sections in Xcode project files
+
+ <https://bugs.webkit.org/show_bug.cgi?id=22555>
+
+ Reviewed by Darin Adler.
+
+ Sort "children" sections alphabetically, moving groups (folders) to
+ the top of each of the lists. Files are assumed to have extensions,
+ so %isFile is used to override this behavior.
+
+ * Scripts/sort-Xcode-project-file:
+ (sortChildrenByFileName): Added.
+ (sortFilesByFileName): Renamed from sortByFileName().
+
+2008-12-05 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Geoff Garen.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22683
+ Fix gtk and qt builds which depend on --qt and --gtk being removed from ARGV
+ Add a new argumentsForConfiguration() function and clean up some old code to use it.
+ Rename checkArgV to checkForArgumentAndRemoveFromARGV to be more self-documenting.
+
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/run-launcher:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2008-12-03 Nikolas Zimmermann <nikolas.zimmermann@torchmobile.com>
+
+ Reviewed by Cameron Zwarich.
+
+ Further preparations for WML layout tests.
+ Ignore WMLTestCase.js, that's going to be in trunk soon.
+
+ * Scripts/make-js-test-wrappers:
+
+2008-12-03 Eric Seidel <eric@webkit.org>
+
+ Build fix for --gtk and --chromium, no review.
+
+ Fix run-javascriptcore-tests to pass --gtk, --qt, --chromium, etc.
+ through to build-jsc.
+
+ * Scripts/build-jsc:
+ * Scripts/webkitdirs.pm:
+
+2008-12-03 Eric Seidel <eric@webkit.org>
+
+ Build fix only, no review.
+
+ Remove support for build-webkit --svg-experimental.
+ All of the "experimental" svg features have their own toggles anyway.
+ I broke --svg-experimental in my last commit (which then broke clean builds)
+ I can't find any use of --svg-experimental in our source tree, so removing it.
+
+ * Scripts/build-webkit:
+
+2008-12-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Hyatt (and Mark Rowe).
+
+ Move --coverage support from build-webkit to webkitdirs.pm to share it with build-jsc
+ Move --coverage support out of run-javascriptcore-tests and into build-jsc
+
+ Finally add a buildXCodeProject function to webkitdirs.pm and move --clean support
+ there from build-webkit (to allow future sharing with other build-* scripts)
+
+ Change run-javascriptcore-tests to expect a --jsDriver-args= argument instead of
+ picking through ARGV with a blacklist of what arguments weren't jsDriver args
+ this makes run-javascriptcore-tests transparently support all arguments which
+ webkitdirs.pm gives it support for.
+
+ Make run-javascriptcore-tests actually print what commands it's running before running them.
+
+ Add --help support to build-jsc and run-javascriptcore-tests!
+
+ Make code to support --svg-experimental defaults take up half as many lines.
+
+ * Scripts/build-jsc:
+ * Scripts/build-webkit:
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/webkitdirs.pm:
+
+2008-12-03 Adam Roben <aroben@apple.com>
+
+ Fix a leak in WinLauncher shutdown
+
+ Reviewed by Sam Weinig.
+
+ * WinLauncher/WinLauncher.cpp:
+ (_tWinMain): Replaced a delete with a Release. We can't delete the
+ WebView properly since we only have a pointer to one of its
+ interfaces. We also shouldn't be deleting COM objects directly anyway,
+ for a number of reasons.
+
+2008-12-03 Adam Roben <aroben@apple.com>
+
+ Fix a crash on exit in WinLauncher
+
+ Reviewed by Sam Weinig.
+
+ * WinLauncher/WinLauncher.cpp:
+ (_tWinMain): Call shutDownWebKit before exiting.
+
+2008-12-03 Adam Roben <aroben@apple.com>
+
+ Add a Debug_Internal configuration to WinLauncher
+
+ This matches our other projects.
+
+ Reviewed by Sam Weinig.
+
+ * WinLauncher/WinLauncher.vcproj: Added a Debug_Internal
+ configuration, which is identical to Debug except that it also
+ references debug_internal.vsprops. Also removed some settings that we
+ should be picking up from the .vsprops files.
+
+2008-12-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ Hack build-webkit --chromium to use Win32 python instead
+ of using the default cygwin python. Scons + CYGWIN tries
+ to build with GCC by default, we force MSVC in our file
+ but that just results in errors from Scons. Until we can fix
+ this latest round of errors, at least make build-webkit --chromium
+ actually "work" under CYGWIN instead of forcing users to use
+ a cmd shell directly.
+
+ This is working around a Scons bug:
+ http://scons.tigris.org/issues/show_bug.cgi?id=2266
+
+ * Scripts/webkitdirs.pm:
+
+2008-12-01 David Kilzer <ddkilzer@apple.com>
+
+ Bug 22466: REGRESSION (35867): Many resources missing when saving webarchive of webkit.org
+
+ <https://bugs.webkit.org/show_bug.cgi?id=22466>
+ <rdar://problem/6403593>
+
+ Reviewed by Brady Eidson.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (normalizeHTTPResponseHeaderFields): Added. Normalizes Date, Etag,
+ Keep-Alive, Last-Modified and Server header fields to prevent false
+ positive test failures.
+ (convertWebResourceResponseToDictionary): Call
+ normalizeHTTPResponseHeaderFields() to noramlize HTTP response
+ header fields.
+
+2008-12-01 David D. Kilzer <ddkilzer@webkit.org>
+
+ Bug 22559: Report builds left to test in bisect-builds (like git-bisect)
+
+ <https://bugs.webkit.org/show_bug.cgi?id=22559>
+
+ Reviewed by Adam Roben.
+
+ * Scripts/bisect-builds: Updated status message to report the
+ maximum number of builds left to test after the current one.
+ (max): Added.
+
+2008-11-27 Alp Toker <alp@nuanti.com>
+
+ Build GtkLauncher and minidom with the '-ansi' compiler flag to detect
+ API header breakage at build time.
+
+ * GNUmakefile.am:
+
+2008-11-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Nikolas Zimmermann and Mark Rowe.
+
+ Add support for build-webkit --chromium
+ https://bugs.webkit.org/show_bug.cgi?id=22515
+ More cleanups changing isCygwin calls to isAppleWinWebKit and deploying isAppleWebKit where necessary.
+
+ * Scripts/build-dumprendertree:
+ * Scripts/build-jsc:
+ * Scripts/build-webkit:
+ * Scripts/gdb-safari:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2008-11-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Nikolas Zimmermann.
+
+ Add support for build-webkit --chromium (tested on mac)
+ https://bugs.webkit.org/show_bug.cgi?id=22515
+ Also simplified some code using checkArgv
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2008-11-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Nikolas Zimmermann.
+
+ More pre-work for adding a build-webkit --chromium which works on Mac and Windows
+ https://bugs.webkit.org/show_bug.cgi?id=22515
+ Change a few calls to isCygwin to isAppleWinWebKit and a few calls to isAppleMacWebKit to isDarwin
+ in preparation for having a chromium cygwin and chromium mac build
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2008-11-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Nikolas Zimmermann.
+
+ Pre-work for getting build-webkit --chromium to work
+ https://bugs.webkit.org/show_bug.cgi?id=22515
+ Rename isOSX to isAppleMacWebKit to match what the code does, and add isChromium()
+
+ * Scripts/build-dumprendertree:
+ * Scripts/build-jsc:
+ * Scripts/build-webkit:
+ * Scripts/gdb-safari:
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2008-11-26 David Kilzer <ddkilzer@apple.com>
+
+ Bug 22488: Make DRT smarter about charset encoding when post-processing webarchive content
+
+ <https://bugs.webkit.org/show_bug.cgi?id=22488>
+
+ Reviewed by Brady Eidson.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (convertWebResourceDataToString): If an IANA charset encoding string
+ is provided, convert it to a CFStringEncoding value and then to an
+ NSStringEncoding value, else fall back to NSUTF8StringEncoding. We
+ also nil-check dataAsString, so the worst-case scenario is that the
+ data won't be decoded to a string (versus crashing DumpRenderTree).
+
+2008-11-26 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Gtk] add/remove tests from Skipped and fix netscape plugin test
+ https://bugs.webkit.org/show_bug.cgi?id=22484
+
+ Remove print'ing to stderr
+
+ * DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (NP_Initialize):
+ (NP_Shutdown):
+
+2008-11-25 Steve Falkenburg <sfalken@apple.com>
+
+ Windows build fix.
+
+ * DumpRenderTree/cg/PixelDumpSupportCG.h:
+
+2008-11-25 Steve Falkenburg <sfalken@apple.com>
+
+ Windows build fix.
+
+ * DumpRenderTree/cg/ImageDiffCG.cpp:
+
+2008-11-24 Darin Fisher <darin@chromium.org>
+
+ Fix bustage.
+
+ https://bugs.webkit.org/show_bug.cgi?id=15643
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setSelectTrailingWhitespaceEnabled):
+
+2008-11-24 Glenn Wilson <gwilson@chromium.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ http://bugs.webkit.org/show_bug.cgi?id=15643
+
+ Added support for changing the "trailing whitespace" work-around
+ in LayoutTestController (so layout tests can verify this functionality)
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setSelectTrailingWhitespaceEnabledCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setSelectTrailingWhitespaceEnabled):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setSelectTrailingWhitespaceEnabled):
+
+2008-11-24 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Darin Adler
+
+ https://bugs.webkit.org/show_bug.cgi?id=22433
+
+ Add script that attempts to detect virtual methods
+ whose signatures differ only by constness (which can
+ indicate a programming error).
+
+ * Scripts/detect-mismatched-virtual-const: Added.
+
+2008-11-24 Zan Dobersek <zandobersek@gmail.com>
+
+ Reviewed by Holger Freyther.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22039
+
+ [Gtk+] Implement TestNetscapePlugin for Gtk+ port and add it to the
+ build.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.cpp:
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (setDefaultsToConsistentStateValuesForTesting):
+ * DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h: Added.
+ * DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h: Added.
+ * DumpRenderTree/gtk/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h: Added.
+ * GNUmakefile.am:
+
+2008-11-24 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Mark Rowe.
+
+ [Gtk+] Add configure option to enable Web Workers and enable it by default
+
+ Add --enable-workers to the buildsystem (used by build-webkit) add
+ the to be build files to the GNUmakefile.am and change build-webkit
+ to enable Web Workers by default.
+
+ * Scripts/build-webkit:
+
+2008-11-24 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Let gdb-safari accept the --debug and --release options once more.
+
+ * Scripts/gdb-safari:
+
+2008-11-23 Zan Dobersek <zandobersek@gmail.com>
+
+ Reviewed by Holger Freyther. Landed by Jan Alonzo.
+
+ Get SVG tests tested on GTK port.
+
+ * Scripts/webkitdirs.pm:
+
+2008-11-19 Greg Bolsinga <bolsinga@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21810
+ Remove use of static C++ objects that are destroyed at exit time (destructors)
+
+ All static C++ objects that create atexit calls are gone. Update script
+ to indicate how to fix the problem should a new one appear.
+
+ * Scripts/check-for-exit-time-destructors:
+
+2008-11-18 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22337
+ Enable workers by default
+
+ * Scripts/build-webkit: Changed the default to enabled.
+
+2008-11-18 Alexey Proskuryakov <ap@webkit.org>
+
+ Rubber-stamped by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22306
+ Disable channel messaging support
+
+ * Scripts/build-webkit: Add an option to enable channel messaging.
+
+2008-11-17 Nikolas Zimmermann <nikolas.zimmermann@torchmobile.com>
+
+ Reviewed by George Staikos.
+
+ Add --(no-)wml build flags.
+
+ * Scripts/build-webkit:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2008-11-17 Geoffrey Garen <ggaren@apple.com>
+
+ Not reviewed.
+
+ Try to fix gtk build.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+
+2008-11-17 Pierre-Olivier Latour <pol@apple.com>
+
+ Reviewed by Maciej.
+
+ Pixel tests should use a default tolerance of 0.1% on Leopard and 1.0%
+ on Tiger.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22271
+
+ * Scripts/run-webkit-tests:
+
+2008-11-17 Pierre-Olivier Latour <pol@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Added new JavaScript API on LayoutController to pause a running
+ CSS transition or animation at a given time.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21261
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (pauseAnimationAtTimeOnElementWithIdCallback):
+ (pauseTransitionAtTimeOnElementWithIdCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+
+2008-11-17 Gabor Loki <loki@inf.u-szeged.hu>
+
+ Reviewed by Darin Adler.
+
+ <https://bugs.webkit.org/show_bug.cgi?id=22309>
+ Pass the remaining options to build system on Qt-port
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2008-11-16 Greg Bolsinga <bolsinga@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21810
+ Remove use of static C++ objects that are destroyed at exit time (destructors)
+
+ Remove .o files from the exclude list that have had their exit-time destructors removed.
+ Handle case when there is no current symbol.
+
+ * Scripts/check-for-exit-time-destructors:
+
+2008-11-16 Sam Weinig <sam@webkit.org>
+
+ * Scripts/do-webcore-rename: Remove now fixed renames.
+
+2008-11-16 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Plan some future renames.
+
+2008-11-15 Darin Adler <darin@apple.com>
+
+ Rubber stamped by Geoff Garen.
+
+ - do the long-planned StructureID -> Structure rename
+
+ * Scripts/check-for-global-initializers: Update name of StructureID.o.
+ * Scripts/do-webcore-rename: Renaming script that I used.
+
+2008-11-15 Greg Bolsinga <bolsinga@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21810
+ Remove use of static C++ objects that are destroyed at exit time (destructors)
+
+ Create DEFINE_STATIC_LOCAL macro. Change static local objects to leak to avoid
+ exit-time destructor. Update code that was changed to fix this issue that ran
+ into a gcc bug (<rdar://problem/6354696> Codegen issue with C++ static reference
+ in gcc build 5465). Also typdefs for template types needed to be added in some
+ cases so the type could make it through the macro successfully.
+
+ Basically code of the form:
+ static T m;
+ becomes:
+ DEFINE_STATIC_LOCAL(T, m, ());
+
+ Also any code of the form:
+ static T& m = *new T;
+ also becomes:
+ DEFINE_STATIC_LOCAL(T, m, ());
+
+ Remove .o files from the exclude list that have had their exit-time destructors removed.
+
+ * Scripts/check-for-exit-time-destructors:
+
+2008-11-14 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx mac buildbot fix. Also, make sure we don't keep hitting this problem.
+
+ * wx/install-unix-extras:
+
+2008-11-14 Alp Toker <alp@nuanti.com>
+
+ GTK DRT build fix for gcc 4.4 snapshot. Add missing stdio include.
+
+ Fixes Debian bug #505723
+ http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=505723
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+
+2008-11-14 Krishna <krishnamurty.podipireddy@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Fix hanging DRT with Qt.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22209
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::dump):
+ Send empty pixel test data 'block', which is now
+ expected by run-layout-tests.
+
+2008-11-12 Dmitry Titov <dimich@chromium.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22216
+
+ * Scripts/build-webkit:
+ Addes ENABLE_WORKERS to build-webkit so it's possible to build with workers enabled.
+
+2008-11-06 David Kilzer <ddkilzer@apple.com>
+
+ BUILD FIX: Backed out r38189 (and r38203) for Xcode 3.0.
+
+ Apparently older versions of gcc have issues with this patch.
+ Backing out a second time until the issues are resolved.
+
+2008-11-06 David Kilzer <ddkilzer@apple.com>
+
+ BUILD WAS NOT BROKEN: Rolling r38189 back in.
+
+ Please perform a clean build if you see crashes.
+
+2008-11-06 David Kilzer <ddkilzer@apple.com>
+
+ BUILD FIX: Backed out r38189 since it apparently broke the world.
+
+2008-11-06 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Add ability to query an attribute's settable status and the
+ ability to retrieve a single attribute from an AXObject
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (isAttributeSettableCallback):
+ (attributeValueCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (+[NSString stringWithJSStringRef:]):
+ (AccessibilityUIElement::attributeValue):
+ (AccessibilityUIElement::isAttributeSettable):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::attributeValue):
+ (AccessibilityUIElement::isAttributeSettable):
+
+2008-11-06 Greg Bolsinga <bolsinga@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 21810: Remove use of static C++ objects that are destroyed at exit time (destructors)
+ https://bugs.webkit.org/show_bug.cgi?id=21810
+
+ Remove .o files from the exclude list that have had their exit-time destructors removed.
+
+ * Scripts/check-for-exit-time-destructors:
+
+2008-11-05 Alp Toker <alp@nuanti.com>
+
+ GTK build script tweak.
+
+ Make the path relative since it will appear in all -I compiler flags.
+ Long argument lists cause bizarre slowdowns in libtool and result
+ in huge build logs.
+
+ * Scripts/webkitdirs.pm:
+
+2008-11-05 Anders Carlsson <andersca@apple.com>
+
+ Fix 64-bit build.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (setDefaultsToConsistentValuesForTesting):
+
+2008-11-04 Simon Fraser <simon.fraser@apple.com>
+
+ Add AccessibilityObject.o to the exclude list for the
+ check for global destructors.
+
+ * Scripts/check-for-exit-time-destructors:
+
+2008-11-04 Darin Adler <darin@apple.com>
+
+ * Scripts/check-for-exit-time-destructors: Fix failures seen on the
+ bot, but for some reason not on my computer.
+
+2008-11-03 Darin Adler <darin@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ - https://bugs.webkit.org/show_bug.cgi?id=22061
+ create script to check for exit-time destructors
+
+ * Scripts/check-for-exit-time-destructors: Added.
+ Started as a copy of check-for-global-initializers.
+
+ * Scripts/check-for-global-initializers: Added code to make
+ this script rerun any time it's modified, and also to properly
+ run again after the first time it reports an error.
+
+2008-11-03 Pierre-Olivier Latour <pol@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Fixed the override of the "AppleScrollBarVariant" system setting to also work with HIToolbox.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22054
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (setDefaultsToConsistentValuesForTesting):
+
+2008-10-31 Cameron Zwarich <zwarich@apple.com>
+
+ Not reviewed.
+
+ * Scripts/do-webcore-rename:
+
+ Add some renames to contemplate for the future.
+
+2008-10-31 Darin Adler <darin@apple.com>
+
+ Requested by Mark Rowe.
+
+ * Scripts/check-for-global-initializers: s/Web Kit/WebKit/.
+
+2008-10-31 David Kilzer <ddkilzer@apple.com>
+
+ Bug 21997: prepare-ChangeLog should filter out ChangeLog files
+
+ <https://bugs.webkit.org/show_bug.cgi?id=21997>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/prepare-ChangeLog:
+ (generateFileList): Don't add ChangeLog files to %{$functionLists}.
+ This prevents them from showing up in the new ChangeLog entry. They
+ were already excluded from @{$changedFiles}.
+
+2008-10-30 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Jon Homeycutt.
+
+ Explicitly default to building for only the native architecture in debug and release builds.
+
+ * DumpRenderTree/mac/Configurations/DebugRelease.xcconfig:
+
+2008-10-30 Pierre-Olivier Latour <pol@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Fixed 64 bit build failure.
+
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (setupMainDisplayColorProfile):
+ (createBitmapContextFromWebView):
+
+2008-10-28 Alp Toker <alp@nuanti.com>
+
+ Fix GTK DRT following build breakage in r37928.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump):
+ (runTest):
+ (main):
+
+2008-10-28 Alp Toker <alp@nuanti.com>
+
+ Reviewed by Mark Rowe.
+
+ Fix recently introduced double-free crashes in GTK DRT.
+
+ LayoutTestController was made ref-counted in r36606 and Mac/Win DRT
+ were updated to call ->deref() but GTK DRT was still deleting
+ gLayoutTestController manually. This patch updates GTK to match the
+ other ports and resolves the memory allocation issues.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (runTest):
+
+2008-10-28 Alp Toker <alp@nuanti.com>
+
+ Reviewed by Mark Rowe.
+
+ Fix GTK DRT hang when running the tests.
+
+ Update output from the DRT tool to print an additional '#EOF' to match
+ breaking changes that were made in r37434.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump):
+
+2008-10-28 Adele Peterson <adele@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Specify which Localizable.strings to update since we don't always want to update the file in the same
+ directory where we're searching for the strings to localize.
+
+ * Scripts/extract-localizable-strings:
+ * Scripts/update-webkit-localizable-strings:
+
+2008-10-28 Timothy Hatcher <timothy@apple.com>
+
+ Add support for enabling the profiler, so the profiling tests can continue
+ work now that the profiler is not always enabled.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21927
+
+ <rdar://problem/6211578> Make the JavaScript profiler opt-in, so it does
+ not slow down JavaScript all the time
+
+ Reviewed by Darin Adler and Kevin McCullough.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Make the editor use spaces.
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setJavaScriptProfilingEnabledCallback): Added. Calls LayoutTestController::setJavaScriptProfilingEnabled.
+ (LayoutTestController::staticFunctions): Added setJavaScriptProfilingEnabled to the script class.
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setJavaScriptProfilingEnabled): Stubbed out with a FIXME.
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting): Disables the developer extras and disables the profiler.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setJavaScriptProfilingEnabled): Toggles the developer extras and profiler.
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting): Disables the developer extras and disables the profiler.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setJavaScriptProfilingEnabled): Toggles the developer extras and profiler.
+
+2008-10-28 Pierre-Olivier Latour <pol@apple.com>
+
+ Reviewed by Dan Bernstein
+
+ Primary changes in DumpRenderTree:
+ - Ensure font smoothing is disabled (this is also called LCD anti-aliasing and
+ is different from regular font CG anti-aliasing) as font-smoothing settings
+ depends on the display and can also be changed by the user
+ - Use a new cleared buffer for each test instead of the reusing same one to
+ avoid potential result corruption across tests
+ - Can now receive the expected pixel hash as a suffix to the test path or
+ url as "path'hash"
+ - Make sure hash is computed in a endian-independent way
+ - Improve the code that sets/restores the screen color profile
+ - Make the code more cross-platformy with std::string goodness
+ - Added an "on-screen" mode where the snapshot will take into account surfaces
+ on the window (like OpenGL content): this uses the new CG APIs on 10.5 or
+ reading from the display framebuffer on 10.4. This mode is not active by
+ default for performance reason, but must be explicitly activated from the test
+ file using the new "testOnscreen()" JS API.
+
+ Primary changes in ImageDiff:
+ - Provide a new comparison algorithm that is more tolerant to "acceptable"
+ failures (i.e. very small differences in font rendering, which --threshold is
+ not really good at handling)
+ - Generate normalized intensity-only diff images
+
+ Primary changes in run-webkit-tests:
+ - Take advantage of hashes for pixel tests which makes them much faster by
+ minimizing image comparisons
+ - Removed repaint options as these should be set from within test files using
+ JS API
+ - Replaced "threshold" option in by "tolerance" expressed in percents
+ - Added more logging when in "verbose" mode
+
+ https://bugs.webkit.org/show_bug.cgi?id=21322
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/ForwardingHeaders/wtf/PassRefPtr.h: Copied from JavaScriptGlue/ForwardingHeaders/wtf/PassRefPtr.h.
+ * DumpRenderTree/ForwardingHeaders/wtf/RefPtr.h: Copied from JavaScriptGlue/ForwardingHeaders/wtf/RefPtr.h.
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (testOnscreenCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::testOnscreen):
+ (LayoutTestController::setTestOnscreen):
+ (LayoutTestController::testPathOrURL):
+ (LayoutTestController::expectedPixelHash):
+ * DumpRenderTree/PixelDumpSupport.h:
+ * DumpRenderTree/cg/ImageDiffCG.cpp:
+ (strtof):
+ (releaseMallocBuffer):
+ (createDifferenceImage):
+ (imageHasAlpha):
+ (main):
+ * DumpRenderTree/cg/PixelDumpSupportCG.cpp:
+ (computeMD5HashStringForBitmapContext):
+ (dumpWebViewAsPixelsAndCompareWithExpected):
+ * DumpRenderTree/cg/PixelDumpSupportCG.h:
+ (BitmapContext::createByAdoptingBitmapAndContext):
+ (BitmapContext::~BitmapContext):
+ (BitmapContext::cgContext):
+ (BitmapContext::BitmapContext):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (shouldIgnoreWebCoreNodeLeaks):
+ (setDefaultsToConsistentValuesForTesting):
+ (crashHandler):
+ (initializeGlobalsFromCommandLineOptions):
+ (prepareConsistentTestingEnvironment):
+ (dumpRenderTree):
+ (sizeWebViewForCurrentTest):
+ (dump):
+ (runTest):
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (restoreMainDisplayColorProfile):
+ (setupMainDisplayColorProfile):
+ (createBitmapContextFromWebView):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dump):
+ (runTest):
+ * DumpRenderTree/win/PixelDumpSupportWin.cpp:
+ (getBitmapContextFromWebView):
+ * Scripts/run-webkit-tests:
+
+2008-10-27 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix on Linux/GTK. Enable support for #include <JavaScriptCore/XYZ.h> style includes.
+
+ * wx/build-wxwebkit:
+
+2008-10-24 Anders Carlsson <andersca@apple.com>
+
+ Try fixing the 64-bit build.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.cpp:
+ (testGetProperty):
+
+2008-10-24 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/5440917> Support NPN_Construct
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (testCallback):
+ Fix a memory leak.
+
+ (testConstruct):
+ New test method that treats it first argument as a constructor and invokes it with the rest of the arguments.
+
+ (pluginInvoke):
+ Handle testConstruct.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.cpp:
+ (testGetProperty):
+ Add objectPointer property.
+
+ (testEnumerate):
+ Only enumerate the two first properties.
+
+ (testConstruct):
+ Add a simple construct implementation that just returns the test object.
+
+2008-10-24 David Kilzer <ddkilzer@apple.com>
+
+ Bug 21850: svn-apply and svn-unapply should preserve patch line endings
+
+ <https://bugs.webkit.org/show_bug.cgi?id=21850>
+
+ Reviewed by Adam Roben.
+
+ * Scripts/svn-apply: Save end-of-line characters when stripping them
+ off each line of a patch so that they may be restored after
+ processing the line.
+ * Scripts/svn-unapply: Ditto.
+
+2008-10-23 David Kilzer <ddkilzer@apple.com>
+
+ Bug 21832: Fix scripts using 'new File::Temp' for Perl 5.10
+
+ <https://bugs.webkit.org/show_bug.cgi?id=21832>
+
+ Reviewed by Sam Weinig.
+
+ * Scripts/bisect-builds: Use imported tempfile() from File::Temp
+ instead of 'new File::Temp' to make the script work with Perl 5.10.
+ * Scripts/sort-Xcode-project-file: Ditto.
+
+2008-10-22 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Adam Roben
+
+ <rdar://6261773> - autocomplete="off" doesn't work on Windows
+
+ Implement LayoutTestController::elementDoesAutoCompleteForElementWithId() on Windows
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+
+2008-10-22 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: More renaming plans.
+
+2008-10-21 Steve Falkenburg <sfalken@apple.com>
+
+ Exclude strings marked with UNLOCALIZED_STRING or UNLOCALIZED_LPCTSTR.
+
+ * Scripts/extract-localizable-strings:
+
+2008-10-17 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ - default to 1000 tests per dump tool instance again, now that CTI no longer causes
+ excess different stack logs.
+
+ (Also fix a small bug in my last change.)
+
+ * Scripts/run-webkit-tests:
+
+2008-10-17 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Fix layout tests that use prologues and epilogues.
+
+ * Scripts/run-webkit-tests:
+
+2008-10-17 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ - make sure MallocStackLogging is only on for tools we want to
+ leak check, not other random stuff as well.
+
+ * Scripts/run-webkit-tests:
+
+2008-10-17 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Stephanie Lewis.
+
+ - make run-webkit-tests --leaks default to 100 tests per run instead of 1000
+
+ This should reduce or eliminate crashes on the buildbot due to
+ running out of memory while stack logging.
+
+ * Scripts/run-webkit-tests:
+
+2008-10-16 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Gtk build fix. Not reviewed.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setSmartInsertDeleteEnabled):
+
+2008-10-15 Glenn Wilson <gwilson@google.com>
+
+ Added new method to allow tests to disable smart editing in the course of a test.
+ This is a possible solution to bug .20655
+
+ Reviewed by Tim Hatcher.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setSmartInsertDeleteEnabledCallback): new method
+ (LayoutTestController::staticFunctions): added new method to static list of callbacks
+ * DumpRenderTree/LayoutTestController.h: added signature of new method
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting): added state resetting
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setSmartInsertDeleteEnabled): added new method
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting): added state resetting
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setSmartInsertDeleteEnabled): added new method
+
+2008-10-14 Ada Chan <adachan@apple.com>
+
+ Fix windows build.
+
+ Reviewed by Sam Weinig.
+
+ * DumpRenderTree/cg/PixelDumpSupportCG.cpp:
+ * DumpRenderTree/config.h:
+ * DumpRenderTree/win/DumpRenderTreeWin.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ * DumpRenderTree/win/UIDelegate.cpp:
+
+2008-10-13 Timothy Hatcher <timothy@apple.com>
+
+ Make prepare-ChangeLog populate the changed functions for JavaScript files.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21567
+
+ Reviewed by David Kilzer.
+
+ * Scripts/prepare-ChangeLog:
+ (get_function_line_ranges): Call get_function_line_ranges_for_javascript for
+ files that end with ".js".
+ (get_function_line_ranges_for_javascript): Find functions, anonymous functions
+ and getters/setters.
+
+2008-10-14 Alp Toker <alp@nuanti.com>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=16299
+ Add a config.h file to DRT
+
+ Add a config.h to DumpRenderTree and reduce use of DumpRenderTree.h as
+ an ad-hoc config header.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/GCController.cpp:
+ * DumpRenderTree/LayoutTestController.cpp:
+ * DumpRenderTree/WorkQueue.cpp:
+ * DumpRenderTree/config.h: Added.
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ * DumpRenderTree/gtk/GCControllerGtk.cpp:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ * DumpRenderTree/gtk/WorkQueueItemGtk.cpp:
+ * DumpRenderTree/win/AccessibilityControllerWin.cpp:
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ * DumpRenderTree/win/DumpRenderTreeWin.h:
+ * DumpRenderTree/win/EditingDelegate.cpp:
+ * DumpRenderTree/win/EventSender.cpp:
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ * DumpRenderTree/win/GCControllerWin.cpp:
+ * DumpRenderTree/win/MD5.cpp:
+ * DumpRenderTree/win/PixelDumpSupportWin.cpp:
+ * DumpRenderTree/win/PolicyDelegate.cpp:
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ * DumpRenderTree/win/WorkQueueItemWin.cpp:
+ * GNUmakefile.am:
+
+2008-10-13 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Added a method to get the links in a webpage
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (attributesOfDocumentLinksCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::getDocumentLinks):
+ (AccessibilityUIElement::attributesOfDocumentLinks):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::getDocumentLinks):
+ (AccessibilityUIElement::attributesOfDocumentLinks):
+
+2008-10-13 David Kilzer <ddkilzer@apple.com>
+
+ Bug 21457: resolve-ChangeLogs should be able to operate on a git revision range
+
+ <https://bugs.webkit.org/show_bug.cgi?id=21457>
+
+ Reviewed by Adam.
+
+ * Scripts/resolve-ChangeLogs: Added optional parameter to
+ -f|--fix-merged switch to run the script on a revision range.
+ Updated command-line validation checks.
+ (findChangeLog): Fixed long-standing bug that should have used
+ $_[0] instead of $_.
+ (fixMergedChangeLog): Renamed to fixOneMergedChangeLog($). Updated
+ to work when called from git filter-branch. It always restores a
+ copy of the previous revision before reapplying the patch.
+ (fixMergedChangeLogs): Added. Calls itself through git filter-branch
+ to re-merge ChangeLog files across a revision range. Removes
+ .git/refs/original directory on success.
+ (parseFixMerged): Added. Custom method to parse the -f|--fix-merged
+ switch.
+ (removeChangeLogArguments): Added. Removes items from @ARGV when
+ they are ChangeLog paths, and return a list of paths. This makes it
+ easier to validate the command-line.
+ (resolveChangeLog): Added. Extracted from main code block. Runs
+ the traditional single-file merge algorithm.
+ (usageAndExit): Added. Extracted from main code block. Prints
+ usage statement and exits with error status.
+
+2008-10-12 Darin Adler <darin@apple.com>
+
+ * Scripts/make-js-test-wrappers: Update exceptions list so the script
+ won't overwrite files and mangle tests.
+
+2008-10-11 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Sam Weinig and Anders Carlsson.
+
+ - update Mac DumpRenderTree to use the new WebView SPI for forcing the
+ complex text code path
+ - add --complex-text support to Windows DumpRenderTree
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpRenderTree):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (createWebViewAndOffscreenWindow):
+ (main):
+ * Scripts/run-webkit-tests:
+
+2008-10-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Oliver Hunt.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21498
+
+ * Scripts/make-js-test-wrappers: ignore resources/shadow-offset.js
+
+2008-10-09 Cameron Zwarich <zwarich@apple.com>
+
+ Not reviewed.
+
+ Add StructureID.o to the exclusion list in the global initializers
+ script to fix the Debug build.
+
+ * Scripts/check-for-global-initializers:
+
+2008-10-08 Mark Rowe <mrowe@apple.com>
+
+ Fix the Windows build after r37434.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dump): Update code to approximate valid C++ syntax.
+
+2008-10-08 Timothy Hatcher <timothy@apple.com>
+
+ Add SVGElementInstance to the list of exceptions that have
+ global initializers in debug builds.
+
+ Rubber-stamped by Mark Rowe.
+
+ * Scripts/check-for-global-initializers: Add SVGElementInstance.o.
+
+2008-10-08 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Dan Bernstein
+
+ Avoid disconnect between DRT and run-webkit-tests
+ about whether to expect PNG dumps by having DRT always
+ print two blocks terminated by #EOF, the second of which
+ may be empty.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21483
+
+ * DumpRenderTree/cg/PixelDumpSupportCG.cpp:
+ (printPNG):
+ (dumpWebViewAsPixelsAndCompareWithExpected):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dump):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dump):
+ * Scripts/run-webkit-tests:
+
+2008-10-07 Adam Roben <aroben@apple.com>
+
+ Make sure short functions get included in ChangeLog output for git
+ repositories
+
+ Reviewed by Dave Kilzer.
+
+ * Scripts/prepare-ChangeLog:
+ (sub diffCommand): Pass -U0 to git diff so that each contiguous change
+ will get its own chunk without any surrounding context.
+ (sub extractLineRange): Use the line numbers from the chunk header
+ without modifying them now that they're accurate.
+
+2008-10-04 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ Update check-for-weak-vtables to check only the final linked image for weak vtables.
+ This gives more useful results than checking each object file independently.
+
+ * Scripts/check-for-weak-vtables:
+
+2008-10-03 Pierre-Olivier Latour <pol@apple.com>
+
+ Reviewed by Darin Adler
+
+ Render images to RGBA8 bitmaps independently of platform endianness.
+
+ Create image difference bitmap in reference image colorspace instead of device colorspace
+ (which depends on the main display profile), so that no color matching happens.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21336
+
+ * DumpRenderTree/cg/ImageDiffCG.cpp:
+ (createDifferenceBitmap):
+ (computePercentageDifferent):
+ (compareImages):
+
+2008-10-02 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Darin Adler
+
+ Fix hang when running with --pixel --reset, which occurs
+ because DRT spews PNG data when the script does not expect it.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21323
+
+ * Scripts/run-webkit-tests:
+
+2008-09-30 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Add a leak counter for CachedResources since we've had two recent leaks involving them.
+
+ * Scripts/check-for-global-initializers:
+
+2008-09-30 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Dan Bernstein.
+
+ Fix many leaks seen on fast/backgrounds/svg-as-background-1.html.
+
+ JavaScript wrappers were keeping DOM objects alive, which was leading to the SVG background image
+ being kept alive in the memory cache past our last attempt to empty the cache prior to quitting.
+ We need to empty the memory cache after forcing a JavaScript garbage collection to ensure that
+ any live JavaScript wrappers are collected and their corresponding DOM objects have a chance to be
+ torn down before we exit.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpRenderTree):
+ (main):
+
+2008-09-30 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Dan Bernstein
+
+ Don't run pixel comparison for text-only tests.
+ https://bugs.webkit.org/show_bug.cgi?id=21124
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dump):
+ * Scripts/run-webkit-tests:
+
+2008-09-29 Thiago Macieira <thiago.macieira@nokia.com>
+
+ Reviewed by Simon.
+
+ Changed copyright from Trolltech ASA to Nokia.
+
+ Nokia acquired Trolltech ASA, assets were transferred on September 26th 2008.
+
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ * DumpRenderTree/qt/jsobjects.cpp:
+ * DumpRenderTree/qt/jsobjects.h:
+ * DumpRenderTree/qt/main.cpp:
+ * DumpRenderTree/qt/testplugin.cpp:
+ * DumpRenderTree/qt/testplugin.h:
+
+2008-09-28 David Kilzer <ddkilzer@apple.com>
+
+ Bug 21185: resolve-ChangeLogs should be able to fix poorly merged ChangeLog entries after a git svn rebase
+
+ <https://bugs.webkit.org/show_bug.cgi?id=21185>
+
+ Reviewed by Adam.
+
+ * Scripts/resolve-ChangeLogs: Added new -f|--fix-merge switch that
+ will attempt to reapply the last commit to a ChangeLog file such
+ that the ChangeLog entry appears at the top of the file.
+ (findChangeLog): Added prototype and moved method below the exit
+ statement.
+ (fixMergedChangeLog): Added. Method to fix incorrectly merged
+ ChangeLog entries.
+
+2008-09-27 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=21178
+ <rdar://problem/6248651>
+
+ Return the result value from getURL.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (getURL):
+
+2008-09-26 Matt Lilek <webkit@mattlilek.com>
+
+ Reviewed by Tim Hatcher.
+
+ Update FEATURE_DEFINES after ENABLE_CROSS_DOCUMENT_MESSAGING was removed.
+
+ * Scripts/build-webkit:
+
+2008-09-26 Alice Liu <alice.liu@apple.com>
+
+ Remove usage of atlstr.h and CString for VCExpress compatibility
+
+ Reviewed by Stephanie Lewis.
+
+ * record-memory-win/main.cpp:
+ (ProcessArgs):
+ (UseImage):
+ (QueryContinuously):
+ (OneQuery):
+ (OneQueryMP):
+
+2008-09-26 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Update the version of libpng.
+
+ * wx/install-unix-extras:
+
+2008-09-24 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=21080
+ <rdar://problem/6243534>
+ Crash below Function.apply when using a runtime array as the argument list
+
+ Add method to ObjCController to return a runtime array.
+
+ * DumpRenderTree/mac/ObjCController.m:
+ (+[ObjCController isSelectorExcludedFromWebScript:]):
+ (+[ObjCController webScriptNameForSelector:]):
+ (-[ObjCController testArray]):
+
+2008-09-24 Beth Dakin <bdakin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Speculative build fix.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::supportsPressAction):
+
+2008-09-23 Beth Dakin <bdakin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ This patch extends DumpRenderTree's AccessibilityController to ask
+ if the focused element supports the press action.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getSupportsPressActionCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::supportsPressAction):
+
+2008-09-22 Alice Liu <alice.liu@apple.com>
+
+ Adding a stand-alone Windows console application to record a process's memory usage
+
+ Reviewed by Steve Falkenburg.
+
+ * record-memory-win: Added.
+ * record-memory-win/main.cpp: Added.
+ * record-memory-win/record-memory-win.vcproj: Added.
+
+2008-09-22 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Support ability to get/set selected text ranges for text controls through AX.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (setSelectedTextRangeCallback):
+ (getSelectedTextRangeCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::attributesOfRowHeaders):
+ (AccessibilityUIElement::attributesOfVisibleCells):
+ (AccessibilityUIElement::rowIndexRange):
+ (AccessibilityUIElement::columnIndexRange):
+ (AccessibilityUIElement::cellForColumnAndRow):
+ (AccessibilityUIElement::selectedTextRange):
+ (AccessibilityUIElement::setSelectedTextRange):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::selectedTextRange):
+ (AccessibilityUIElement::setSelectedTextRange):
+
+2008-09-20 Darin Adler <darin@apple.com>
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (convertMIMEType): Turn on Stephanie's workaround for Tiger too.
+
+2008-09-19 Alp Toker <alp@nuanti.com>
+
+ Build fix for the 'gold' linker and recent binutils. New behaviour
+ requires that we link to used libraries explicitly.
+
+ * GNUmakefile.am:
+
+2008-09-19 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Implement a workaround for an incorrect mime-type on machines with
+ Dashcode 2.0.1. Dashcode is overriding the UTI type for .js files.
+ See radar <rdar://problem/6234318>.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (convertMIMEType):
+
+2008-09-19 Chris Fleizach <cfleizach@apple.com>
+
+ Fixed Windows bustage
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::titleUIElement):
+
+2008-09-18 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Expose titleUIElement call for DumpRenderTree
+
+ * ChangeLog:
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (titleUIElementCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::titleUIElement):
+
+2008-09-18 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: More renaming plans.
+
+2008-09-18 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Clear the main frame's name between tests to get more consistent test results
+ when running the WebKit tests with --nthly.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+
+2008-09-18 Stephanie Lewis <slewis@apple.com>
+
+ Really fix tiger jsc tests.
+
+ * Scripts/run-javascriptcore-tests:
+
+2008-09-18 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Fix jsc tests on Tiger. Make jsc tests smarter about when to use the arch flag.
+
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/webkitdirs.pm:
+
+2008-09-18 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Sam Weinig.
+
+ Print warning to stdout rather than stderr when a test attempts to access a remote resource.
+ This should make it more obvious when a test does this, as stderr output tends to be obscured
+ by noise in the test results.
+
+ Also fixes some coding style issues in ResourceLoadDelegate.mm.
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[NSError _drt_descriptionSuitableForTestResult]):
+ (-[NSURL _drt_descriptionSuitableForTestResult]):
+ (-[ResourceLoadDelegate webView:identifierForInitialRequest:fromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:willSendRequest:redirectResponse:fromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:didReceiveResponse:fromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:didFinishLoadingFromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:didFailLoadingWithError:fromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:willCacheResponse:fromDataSource:]):
+
+2008-09-18 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Mark Rowe and Maciej Stachowiak..
+
+ add a --64-bit option and specify which architecture to run on Mac.
+
+ * Scripts/run-javascriptcore-tests:
+
+2008-09-17 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Fix a crash seen running DumpRenderTree on fast/dom/null-document-window-open-crash.html under guard malloc.
+
+ The JS wrapper for LayoutTestController could outlive the wrapped instance, and would crash when
+ attempting to access the wrapped instance within layoutTestControllerObjectFinalize. We fix this by making
+ LayoutTestController ref-counted to ensure that it is not outlived by the JS wrapper.
+
+ * DumpRenderTree/ForwardingHeaders/wtf/RefCounted.h: Copied from JavaScriptGlue/ForwardingHeaders/wtf/RefCounted.h.
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (notifyDoneCallback): Remove code that is no longer needed now that we must always have a wrapped instance.
+ (layoutTestControllerObjectFinalize): Deref the wrapped object.
+ (LayoutTestController::makeWindowObject): Ref the wrapped object.
+ * DumpRenderTree/LayoutTestController.h: Make LayoutTestController RefCounted.
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (runTest): Deref the LayoutTestController object rather than explicitly deleting it.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm: Remove code that is no longer needed.
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest): Deref the LayoutTestController object rather than explicitly deleting it.
+
+2008-09-16 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Add flag to disable running sample on tests that timeout.
+
+ * Scripts/run-webkit-tests:
+
+2008-09-16 Adam Roben <aroben@apple.com>
+
+ Windows build fix after r36511
+
+ Update for rename of layoutTestController to gLayoutTestController.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ * DumpRenderTree/win/EditingDelegate.cpp:
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ * DumpRenderTree/win/UIDelegate.cpp:
+
+2008-09-16 Adam Roben <aroben@apple.com>
+
+ Add a script to print out the dependency tree of a Visual Studio
+ solution file
+
+ * Scripts/print-msvc-project-dependencies: Added.
+
+2008-09-16 Mark Rowe <mrowe@apple.com>
+
+ Fix the build.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (notifyDoneCallback): Call fprintf in a safer manner.
+
+2008-09-16 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Eric Seidel
+
+ Protect against tests that call layoutTestController.notifyDone()
+ more than once, which would lead to memory corruption, by nulling
+ out the LayoutTestController on the JSObjectRef on destruction. Also
+ add a finalize callback on the class so that if the LTC outlives
+ the JSObjectRef, the JSObjectRef backpointer on the LTC can be
+ nulled out.
+
+ https://bugs.webkit.org/show_bug.cgi?id=20875
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (notifyDoneCallback):
+ (layoutTestControllerObjectFinalize):
+ (LayoutTestController::makeWindowObject):
+ (LayoutTestController::getJSClass):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::~LayoutTestController):
+
+2008-09-16 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Eric Seidel
+
+ Step 1 patch: rename global variable for clarity.
+ https://bugs.webkit.org/show_bug.cgi?id=20875
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/cg/PixelDumpSupportCG.cpp:
+ (dumpWebViewAsPixelsAndCompareWithExpected):
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dumpFramesAsText):
+ (dump):
+ (runTest):
+ (processWork):
+ (webViewLoadFinished):
+ (webViewWindowObjectCleared):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (allocateGlobalControllers):
+ (dumpFrameScrollPosition):
+ (dumpFramesAsText):
+ (methodNameStringForFailedTest):
+ (dump):
+ (runTest):
+ * DumpRenderTree/mac/DumpRenderTreeMac.h:
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ * DumpRenderTree/mac/EditingDelegate.mm:
+ (-[EditingDelegate webView:shouldBeginEditingInDOMRange:]):
+ (-[EditingDelegate webView:shouldInsertNode:replacingDOMRange:givenAction:]):
+ (-[EditingDelegate webView:shouldInsertText:replacingDOMRange:givenAction:]):
+ (-[EditingDelegate webView:shouldChangeSelectedDOMRange:toDOMRange:affinity:stillSelecting:]):
+ (-[EditingDelegate webView:shouldApplyStyle:toElementsInDOMRange:]):
+ (-[EditingDelegate webView:shouldChangeTypingStyle:toStyle:]):
+ (-[EditingDelegate webViewDidBeginEditing:]):
+ (-[EditingDelegate webViewDidChange:]):
+ (-[EditingDelegate webViewDidEndEditing:]):
+ (-[EditingDelegate webViewDidChangeTypingStyle:]):
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate processWork:]):
+ (-[FrameLoadDelegate webView:locationChangeDone:forDataSource:]):
+ (-[FrameLoadDelegate webView:didStartProvisionalLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didCommitLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didFinishLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didClearWindowObject:forFrame:]):
+ (-[FrameLoadDelegate webView:didReceiveTitle:forFrame:]):
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:identifierForInitialRequest:fromDataSource:]):
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:dragImage:at:offset:event:pasteboard:source:slideBack:forView:]):
+ (-[UIDelegate webViewFocus:]):
+ (-[UIDelegate webViewUnfocus:]):
+ (-[UIDelegate webView:createWebViewWithRequest:]):
+ (-[UIDelegate webViewClose:]):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dumpFrameScrollPosition):
+ (dumpFramesAsText):
+ (dump):
+ (runTest):
+
+2008-09-15 Alice Liu <alice.liu@apple.com>
+
+ A change needed to make PPC bots pass accessibility/table-cell-spans.html layout test
+
+ Reviewed by Stephanie Lewis.
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ Calling -[NSValue rangeValue] on nil object was returning bogus results on PPC,
+ but not Intel. Add a check for nil before calling.
+ (AccessibilityUIElement::rowIndexRange):
+ (AccessibilityUIElement::columnIndexRange):
+
+2008-09-14 Mark Rowe <mrowe@apple.com>
+
+ Build fix.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (waitUntilDoneWatchdogFired):
+ * DumpRenderTree/mac/ObjCPlugin.m:
+
+2008-09-08 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ - add an option to run-webkit-tests to always use the complex text code path
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (initializeGlobalsFromCommandLineOptions):
+ (dumpRenderTree):
+ * Scripts/run-webkit-tests:
+
+2008-09-08 Steve Falkenburg <sfalken@apple.com>
+
+ Another Windows nightly build fix.
+
+ Reviewed by Sam Weinig.
+
+ * FindSafari/FindSafari.cpp:
+ (_tmain): Delete existing WebKitNightly directory in temp.
+ * FindSafari/Safari.exe.manifest: Add PROGIDs for each COM class. Remove non-production classes.
+
+2008-09-07 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Fix DRT build
+
+ * DumpRenderTree/DumpRenderTreePrefix.h:
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+2008-09-06 Steve Falkenburg <sfalken@apple.com>
+
+ Fix Windows nightlies.
+
+ Copy WebKit.dll alongside application so registry-free COM can find it.
+ Update embedded manifest to force use registry-free COM.
+
+ Reviewed by Dave Hyatt.
+
+ * FindSafari/FindSafari.cpp:
+ (copyManifest):
+ (replaceManifest):
+ (_tmain):
+ * FindSafari/FindSafari.rc: Added.
+ * FindSafari/FindSafari.vcproj:
+ * FindSafari/Safari.exe.manifest: Added.
+ * FindSafari/resource.h: Added.
+
+=== End merge of squirrelfish-extreme ===
+
+2008-08-31 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Add a --profile flag to run-sunspider.
+
+ * Scripts/webkitdirs.pm: Detect --profile or --profiling passed as a command-line argument
+ to build scripts as indicating that we should use the "Profiling" configuration. At present
+ this is only supported by JavaScriptCore, so using this argument to build any other project
+ will likely result in unexpected behaviour.
+
+2008-08-27 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Fix run-webkit-tests to handle DRT exiting early.
+
+ * Scripts/run-webkit-tests: Initialize $expectedResultPaths{$base} before it will be used.
+
+=== Start merge of squirrelfish-extreme ===
+
+2008-09-04 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Eric Seidel.
+
+ Fix https://bugs.webkit.org/show_bug.cgi?id=20639.
+ Bug 20639: ENABLE_DASHBOARD_SUPPORT does not need to be a FEATURE_DEFINE
+
+ * Scripts/build-webkit: Remove ENABLE_DASHBOARD_SUPPORT-related code.
+
+2008-09-04 Cameron Zwarich <cwzwarich@uwaterloo.ca>
+
+ Reviewed by Oliver Hunt.
+
+ Bug 20616: Incorporate V8 benchmarks in testing
+ <https://bugs.webkit.org/show_bug.cgi?id=20616>
+
+ Add support for the --v8 option to run-sunspider.
+
+ * Scripts/run-sunspider:
+
+2008-09-04 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx buildbot fix. More robust handling of clean when makefiles are not built or
+ are not completely made.
+
+ * wx/build-wxwebkit:
+
+2008-09-03 Mark Rowe <mrowe@apple.com>
+
+ More Mac build fixes.
+
+ Set ENABLE_DASHBOARD_SUPPORT when building for Mac via build-webkit.
+ Also set ENABLE_CROSS_DOCUMENT_MESSAGING in order to match the
+ default configuration specified in the .xcconfig files.
+
+ * Scripts/build-webkit:
+
+2008-09-03 Mark Rowe <mrowe@apple.com>
+
+ Mac build fix. Ensure that dashboard support is enabled.
+
+ * DumpRenderTree/mac/Configurations/Base.xcconfig:
+
+2008-08-25 Steve Falkenburg <sfalken@apple.com>
+
+ Build fix. Copy correct version of ICU.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+2008-08-25 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Simon.
+
+ [run-webkit-tests] Use QtLauncher to show the results of the tests
+ konqueror might not be installed, xdg-open might not be installed but the
+ QtLauncher should be present.
+
+ * Scripts/run-webkit-tests:
+
+2008-08-24 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Initial support for accessibility layout tests on Windows.
+ https://bugs.webkit.org/show_bug.cgi?id=20497
+
+ Reviewed by Sam Weinig.
+
+ * DumpRenderTree/AccessibilityController.h: Fix typos.
+ * DumpRenderTree/AccessibilityUIElement.cpp: Change #import to #include.
+ * DumpRenderTree/AccessibilityUIElement.h: Define _WINSOCKAPI_ to
+ prevent oleacc.h, which includes windows.h, from including winsock.h.
+ Fixed typos.
+ * DumpRenderTree/win/AccessibilityControllerWin.cpp: Added.
+ (AccessibilityController::AccessibilityController):
+ (AccessibilityController::~AccessibilityController):
+ (AccessibilityController::focusedElement): Get the root element, and
+ request its focused object.
+ (AccessibilityController::rootElement): Query Windows for the
+ accessible client object for the WebView's window.
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp: Added.
+ (AccessibilityUIElement::AccessibilityUIElement):
+ (AccessibilityUIElement::~AccessibilityUIElement):
+ (AccessibilityUIElement::getLinkedUIElements): Not implemented.
+ (AccessibilityUIElement::getChildren): Get the child count, and append
+ each child.
+ (AccessibilityUIElement::getChildAtIndex): Get the child at the given
+ index offset by 1. In MSAA, child 0 is the object itself.
+ (AccessibilityUIElement::allAttributes): Not implemented.
+ (AccessibilityUIElement::attributesOfLinkedUIElements): Same.
+ (AccessibilityUIElement::attributesOfChildren): Same.
+ (AccessibilityUIElement::parameterizedAttributeNames): Same.
+ (self): Return a VARIANT representing the "self" object. This is used
+ when calling methods that require a child variant.
+ (AccessibilityUIElement::role): Get the MSAA role, a long value, and
+ convert it into a string with GetRoleText().
+ (AccessibilityUIElement::title): Get the element's title, and convert
+ it to a JS String.
+ (AccessibilityUIElement::description): Same, for description.
+ (AccessibilityUIElement::width):
+ (AccessibilityUIElement::height):
+ (AccessibilityUIElement::intValue): Get the object's value as a string,
+ and convert the string to a double.
+ (AccessibilityUIElement::minValue): Not implemented.
+ (AccessibilityUIElement::maxValue): Same.
+ (AccessibilityUIElement::insertionPointLineNumber): Same.
+ (AccessibilityUIElement::attributesOfColumnHeaders): Same.
+ (AccessibilityUIElement::attributesOfRowHeaders): Same.
+ (AccessibilityUIElement::attributesOfColumns): Same.
+ (AccessibilityUIElement::attributesOfRows): Same.
+ (AccessibilityUIElement::attributesOfVisibleCells): Same.
+ (AccessibilityUIElement::attributesOfHeader): Same.
+ (AccessibilityUIElement::indexInTable): Same.
+ (AccessibilityUIElement::rowIndexRange): Same.
+ (AccessibilityUIElement::columnIndexRange): Same.
+ (AccessibilityUIElement::lineForIndex): Same.
+ (AccessibilityUIElement::boundsForRange): Same.
+ (AccessibilityUIElement::cellForColumnAndRow): Same.
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Add accessibility files to
+ project. Link to oleacc.lib, the MSAA library.
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::FrameLoadDelegate): Initialize the accessibility
+ controller.
+ (FrameLoadDelegate::didClearWindowObject): Create a new window object
+ for the accessibility controller.
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+
+2008-08-21 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Mark Rowe
+
+ Make build-launcher-app work when run from a git repository.
+ https://bugs.webkit.org/show_bug.cgi?id=20478
+
+ * BuildSlaveSupport/build-launcher-app:
+
+2008-08-20 Maxime Britto <britto@apple.com>
+
+ Reviewed by Ada Chan.
+
+ rdar://5259746
+ Mouse events are sent to page while resizing window (affects Gmail)
+
+ * DumpRenderTree/win/UIDelegate.h:
+ (UIDelegate::webViewSendResizeMessage): Add the new interface method, not implemented.
+
+2008-08-19 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Add snowleopard platform in layout tests
+
+ Added support for accessing the attributes of
+ accessibility tables through the accessibility controller
+ in DumpRenderTree
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (attributesOfColumnHeadersCallback):
+ (attributesOfRowHeadersCallback):
+ (attributesOfColumnsCallback):
+ (attributesOfRowsCallback):
+ (attributesOfVisibleCellsCallback):
+ (attributesOfHeaderCallback):
+ (indexInTableCallback):
+ (rowIndexRangeCallback):
+ (columnIndexRangeCallback):
+ (childAtIndexCallback):
+ (cellForColumnAndRowCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (convertNSArrayToVector):
+ (descriptionOfElements):
+ (AccessibilityUIElement::getLinkedUIElements):
+ (AccessibilityUIElement::getChildren):
+ (AccessibilityUIElement::attributesOfLinkedUIElements):
+ (AccessibilityUIElement::attributesOfChildren):
+ (AccessibilityUIElement::attributesOfColumnHeaders):
+ (AccessibilityUIElement::attributesOfRowHeaders):
+ (AccessibilityUIElement::attributesOfColumns):
+ (AccessibilityUIElement::attributesOfRows):
+ (AccessibilityUIElement::attributesOfVisibleCells):
+ (AccessibilityUIElement::attributesOfHeader):
+ (AccessibilityUIElement::indexInTable):
+ (AccessibilityUIElement::rowIndexRange):
+ (AccessibilityUIElement::columnIndexRange):
+ (AccessibilityUIElement::cellForColumnAndRow):
+ * Scripts/run-webkit-tests:
+
+2008-08-19 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Fix run-webkit-tests misreporting crashed tests as timed out ones because DumpRenderTree
+ is waiting for crash reporter to let it exit.
+
+ The fix does not work on Tiger, because the state of the process is indistinguishable from
+ other waiting processes, at least not with this technique.
+
+ * Scripts/run-webkit-tests:
+
+2008-08-18 Alp Toker <alp@nuanti.com>
+
+ Reviewed by Holger Freyther.
+
+ https://bugs.webkit.org/show_bug.cgi?id=20350
+ [GTK] Get DumpRenderTree working
+
+ Fixes and enhancements to DumpRenderTree. With these changes, the test
+ suite can now complete a run producing text and render tree dumps.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dumpFramesAsText):
+ (dump):
+ (runTest):
+ (webViewLoadFinished):
+ (webViewWindowObjectCleared):
+ (webViewConsoleMessage):
+ (webViewScriptAlert):
+ (webViewScriptPrompt):
+ (webViewScriptConfirm):
+ (webViewTitleChanged):
+ (main):
+ * DumpRenderTree/gtk/DumpRenderTreeGtk.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::clearBackForwardList):
+ (LayoutTestController::pathToLocalResource):
+ (LayoutTestController::setAcceptsEditing):
+ (LayoutTestController::setUserStyleSheetEnabled):
+ (LayoutTestController::setUserStyleSheetLocation):
+ (waitToDumpWatchdogFired):
+ (LayoutTestController::windowCount):
+ * DumpRenderTree/gtk/WorkQueueItemGtk.cpp:
+ (JSStringCopyUTF8CString):
+ (ScriptItem::invoke):
+
+2008-08-17 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Cameron Zwarich.
+
+ Updated project files to XCode 3.1.
+
+ * DrawTest/DrawTest.xcodeproj/project.pbxproj:
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj:
+
+2008-08-15 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Geoff Garen.
+
+ <rdar://problem/6139914> Please include a _debug version of JavaScriptCore framework
+
+ * Scripts/check-for-global-initializers: Ignore initializers when building the debug variant.
+
+2008-08-13 Simon Hausmann <hausmann@webkit.org>
+
+ Rubber-stamped by Holger.
+
+ Revert r31585 and disable http tests for the Qt build again unless
+ explicitly enabled.
+
+ Running the http tests unfortunately currently still triggers
+ failures in non-http tests due to side-effects. Disable them by default for
+ now, for more reliable results.
+
+ * Scripts/run-webkit-tests:
+
+2008-08-10 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed (and updated) by Alp Toker.
+
+ https://bugs.webkit.org/show_bug.cgi?id=16620
+ [GTK] Autotools make dist and make check support
+
+ Get make dist working.
+
+ Note that not all possible configurations have been tested yet.
+
+ * GNUmakefile.am:
+
+2008-08-10 Alp Toker <alp@nuanti.com>
+
+ Remove leftover qmake/GTK+ build files.
+
+ * DumpRenderTree/gtk/DumpRenderTree.pro: Removed.
+ * GtkLauncher/GtkLauncher.pro: Removed.
+
+2008-08-06 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin
+
+ AX functions shouldn't return position information because it changes
+ based on the platform
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::boundsForRange):
+
+2008-08-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by darin.
+
+ Fix leaks seen on build-bot by fixing memory management of AccessibilityUIElement.
+ <https://bugs.webkit.org/show_bug.cgi?id=20297>
+ <rdar://problem/6093153>
+
+ I've made AccessibilityUIElement a stack object for now. It could be
+ made RefCounted, but I figured that might be overkill for the moment.
+ Essentially it's just a RefPtr itself. :)
+
+ I also fixed a few typos, such as AccessibilityUIElement() instead of ~AccessibilityUIElement()
+ which was causing additional leaks. :)
+
+ I added toAXElement to remove a bunch of copy/paste code.
+
+ * DumpRenderTree/AccessibilityController.h:
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (toAXElement):
+ (allAttributesCallback):
+ (attributesOfLinkedUIElementsCallback):
+ (attributesOfChildrenCallback):
+ (lineForIndexCallback):
+ (boundsForRangeCallback):
+ (childAtIndexCallback):
+ (getRoleCallback):
+ (getTitleCallback):
+ (getDescriptionCallback):
+ (getWidthCallback):
+ (getHeightCallback):
+ (getIntValueCallback):
+ (getMinValueCallback):
+ (getMaxValueCallback):
+ (getInsertionPointLineNumberCallback):
+ (finalize):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ (AccessibilityUIElement::platformUIElement):
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::focusedElement):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::AccessibilityUIElement):
+ (AccessibilityUIElement::getLinkedUIElements):
+ (AccessibilityUIElement::getChildren):
+ (AccessibilityUIElement::getChildAtIndex):
+ (AccessibilityUIElement::attributesOfLinkedUIElements):
+ (AccessibilityUIElement::attributesOfChildren):
+
+2008-08-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Cameron Zwarich.
+
+ Speculative fix for an error I keep seeing in my Cygwin build
+
+ * Scripts/webkitdirs.pm: make determineConfigurationProductDir() always call determineConfiguration() even on cygwin
+
+2008-08-02 Kevin Ollivier <kevino@theolliviers.com>
+
+ Forgot to commit licensing correction in last commit.
+
+ * wx/packaging/wxWebKitInstaller.iss.in:
+
+2008-08-02 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Eric Seidel.
+
+ Scripts for building a wxWebKit installer for wxPython on Win, eventually will
+ be used for nightlies.
+
+ https://bugs.webkit.org/show_bug.cgi?id=20036
+
+ * wx/packaging: Added.
+ * wx/packaging/build-win-installer.py: Added.
+ * wx/packaging/wxWebKitInstaller.iss.in: Added.
+
+2008-07-31 Adam Roben <aroben@apple.com>
+
+ Follow-up to r35500
+
+ * WinLauncher/WinLauncher.vcproj: Set the manifest properties for the
+ Release configuration, too.
+
+2008-07-31 Stefan Landvogt <stefan.landvogt@gmail.com>
+
+ Fix Bug 20245: WinLauncher does not start in WebKit-debug right out of
+ the box
+
+ <https://bugs.webkit.org/show_bug.cgi?id=20245>
+
+ Reviewed by Adam Roben.
+
+ * WinLauncher/WinLauncher.vcproj: adding the following properties to
+ WinLauncher > Properties > Manifest Tool > Isolated COM
+ Type Library File: $(WebKitOutputDir)\lib\WebKit.tlb
+ Component File Name: WebKit$(WebKitDLLConfigSuffix)
+ Doing the change on "All Configurations"
+
+2008-07-31 Adam Roben <aroben@apple.com>
+
+ Windows build bot fix
+
+ * DumpRenderTree/win/ImageDiff.vcproj: Don't fail if files that only
+ exist for people at Apple can't be found. Also updated the ICU version
+ to 3.8.
+
+2008-07-31 David Kilzer <ddkilzer@apple.com>
+
+ Fix layout test results for webarchive/test-xml-stylesheet.xml
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (convertMIMEType): Work around the "text/xml" local file type
+ regression in Leopard using the BUILDING_ON_LEOPARD macro. Also
+ stop mangling "application/x-javascript" into "text/javascript".
+ (convertWebResourceDataToString): When checking whether to dump a
+ resource as text, also check to see if the MIME type is in the
+ -[WebHTMLRepresentation supportedNonImageMIMETypes] array.
+ * DumpRenderTree/mac/DumpRenderTreeMac.h: Added BUILDING_ON_LEOPARD
+ macro.
+
+2008-07-31 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Alice Liu
+
+ Add AX support to get the bounds for a range of text
+ Add AX support to get the child of an element
+ Add AX support to get all the parameterized attribute names of an element
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (parameterizedAttributeNamesCallback):
+ (boundsForRangeCallback):
+ (childAtIndexCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::getChildAtIndex):
+ (AccessibilityUIElement::parameterizedAttributeNames):
+ (AccessibilityUIElement::boundsForRange):
+
+2008-07-31 Erik Bunce <elbunce@thehive.com>
+
+ Reviewed by Simon.
+
+ Make run-launcher set DYLD_LIBRARY_PATH to make things work on Mac OS X.
+
+ * Scripts/run-launcher:
+
+2008-07-30 Jessica Kahn <jess@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Slightly stricter checking for previous change, suggested by Adam.
+
+ * Scripts/extract-localizable-strings:
+
+2008-07-30 Jessica Kahn <jess@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Added support for UI_STRING and UI_STRING_KEY macros with flexible prefixes.
+
+ * Scripts/extract-localizable-strings:
+
+2008-07-30 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam.
+
+ Copy icu38* files instead of icu36* files.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+2008-07-25 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ DRT/Gtk build fix for r35362
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::elementDoesAutoCompleteForElementWithId):
+
+2008-07-25 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam
+
+ Add the ability to dump whether-or-not an element should have autocomplete enabled,
+ from the perspective of the WebKit API
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (elementDoesAutoCompleteForElementWithIdCallback):
+ (LayoutTestController::staticFunctions):
+
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::elementDoesAutoCompleteForElementWithId):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::elementDoesAutoCompleteForElementWithId): Stub for now until I can get on Windows
+
+2008-07-25 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin
+
+ Add support for AXLineForIndex and AXInsertionPointIndex through the
+ accessibility controller
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (lineForIndexCallback):
+ (getInsertionPointLineNumberCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::insertionPointLineNumber):
+ (AccessibilityUIElement::lineForIndex):
+
+2008-07-25 Adam Roben <aroben@apple.com>
+
+ Try to fix the Windows build bot
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Don't try to copy files
+ that don't exist for people outside of Apple.
+
+2008-07-18 Landry Breuil <landry@openbsd.org>
+
+ Bug 19975: [OpenBSD] Patches to enable build of WebKit
+
+ <https://bugs.webkit.org/show_bug.cgi?id=19975>
+
+ Reviewed by David Kilzer.
+
+ * DumpRenderTree/DumpRenderTree.h: OpenBSD doesn't support wide characters.
+
+2008-07-16 Jon Honeycutt <jhoneycutt@apple.com>
+
+ CygwinDownloader fails to install necessary packages
+ https://bugs.webkit.org/show_bug.cgi?id=20075
+
+ Reviewed by Mark Rowe.
+
+ * CygwinDownloader/cygwin-downloader.zip: Rebuilt after two broken
+ mirrors removed in r34116. Set MIME type to application/octet-stream.
+
+2008-07-16 Jon Honeycutt <jhoneycutt@apple.com>
+
+ CygwinDownloader's make-zip.sh script fails
+ https://bugs.webkit.org/show_bug.cgi?id=20074
+
+ Reviewed by Mark Rowe.
+
+ * CygwinDownloader/cygwin-downloader.py:
+
+2008-07-15 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Refactor accessibility testing code.
+
+ We now have:
+ - AccessibilityController
+ Controller which has access to the WebView and can provide the focused element, root element
+ and in the future, elementAtPoint.
+
+ - AccessibilityUIElement
+ Object which provides access to the data provided by the Accessibility APIs.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (getFocusedElementCallback):
+ (getRootElementCallback):
+ (AccessibilityController::getJSClass):
+ * DumpRenderTree/AccessibilityController.h:
+ * DumpRenderTree/AccessibilityUIElement.cpp: Added.
+ (allAttributesCallback):
+ (attributesOfLinkedUIElementsCallback):
+ (attributesOfChildrenCallback):
+ (getRoleCallback):
+ (getTitleCallback):
+ (getDescriptionCallback):
+ (getWidthCallback):
+ (getHeightCallback):
+ (getIntValueCallback):
+ (getMinValueCallback):
+ (getMaxValueCallback):
+ (finalize):
+ (AccessibilityUIElement::makeJSAccessibilityUIElement):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h: Added.
+ (AccessibilityUIElement::platformUIElement):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::AccessibilityController):
+ (AccessibilityController::~AccessibilityController):
+ (AccessibilityController::focusedElement):
+ (AccessibilityController::rootElement):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm: Added.
+ (AccessibilityUIElement::AccessibilityUIElement):
+ (descriptionOfValue):
+ (attributesOfElement):
+ (nsStringToJSStringRef):
+ (concatenateAttributeAndValue):
+ (AccessibilityUIElement::getLinkedUIElements):
+ (AccessibilityUIElement::getChildren):
+ (AccessibilityUIElement::attributesOfLinkedUIElements):
+ (AccessibilityUIElement::attributesOfChildren):
+ (AccessibilityUIElement::allAttributes):
+ (AccessibilityUIElement::role):
+ (AccessibilityUIElement::title):
+ (AccessibilityUIElement::description):
+ (AccessibilityUIElement::width):
+ (AccessibilityUIElement::height):
+ (AccessibilityUIElement::intValue):
+ (AccessibilityUIElement::minValue):
+ (AccessibilityUIElement::maxValue):
+
+2008-07-14 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin
+
+ Add support to get attributes of the AXChildren of an objecty
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (attributesOfChildrenForFocusedElementCallback):
+ (AccessibilityController::staticFunctions):
+ * DumpRenderTree/AccessibilityController.h:
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (descriptionOfValue):
+ (AccessibilityController::attributesOfChildrenForFocusedElement):
+
+2008-07-14 Steve Falkenburg <sfalken@apple.com>
+
+ Build fix.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+2008-07-14 Adam Roben <aroben@apple.com>
+
+ Attempted Windows build fix
+
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj: Add
+ CoreFoundation/OSXCompatibilityHeaders[/GNUCompatibility] to the
+ include path.
+
+2008-07-14 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Geoff Garen.
+
+ Eliminate per-thread JavaScript global data instance support and make arbitrary
+ global data/global object combinations possible.
+
+ * DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp:
+ (runJavaScriptThread): Don't pass a released context reference to JSGarbageCollect.
+ In this scenario, it was causing crashes after each 10-20 tests, because there was a large
+ chance for a different thread to cause GC after the context was released.
+
+2008-07-11 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Make sure we read WebCore Leak messages. Force full document teardown for DumpRenderTree.
+
+ Up timeout limit, some slower machines were timing out before crashtracer finished writing out to disk and quitting DRT.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (setDefaultsToConsistentValuesForTesting):
+ (resetWebViewToConsistentStateBeforeTesting):
+ * Scripts/run-webkit-tests:
+
+2008-07-10 Steve Falkenburg <sfalken@apple.com>
+
+ Build fix.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+2008-07-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Print <div> backgrounds when printing from DRT.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (setDefaultsToConsistentValuesForTesting):
+
+2008-07-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Fix copying of expected results to correct location
+
+ * Scripts/run-webkit-tests:
+
+2008-07-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by aroben.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (dumpAsPDFCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::dumpAsPDF):
+ (LayoutTestController::setDumpAsPDF):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpFrameAsPDF):
+ (dump):
+
+2008-07-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by weinig.
+
+ Add Content-Type support to DumpRenderTree and run-webkit-tests
+ and move expected.txt files to expected.webarchive
+
+ https://bugs.webkit.org/show_bug.cgi?id=15565
+
+ * DumpRenderTree/cg/ImageDiffCG.cpp:
+ (compareImages):
+ (main):
+ * DumpRenderTree/cg/PixelDumpSupportCG.cpp:
+ (printPNG):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dump):
+ * Scripts/run-webkit-tests:
+
+2008-07-08 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Reviewed by Anders.
+
+ Port r34988 to Mac: allow tests to define JavaScript to execute when
+ NPP_DestroyStream or NPP_URLNotify is called.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New): Remove initialization that happens in pluginAllocate. Look
+ for new arguments onStreamDestroy and onURLNotify.
+ (NPP_Destroy): Free onStreamDestroy and onURLNotify.
+ (executeScript): Code moved from onStreamLoad.
+ (NPP_NewStream): Call executeScript.
+ (NPP_DestroyStream): Same.
+ (NPP_URLNotify): Same.
+
+2008-07-07 Beth Dakin <bdakin@apple.com>
+
+ Reviewed by Anders.
+
+ This patch extends DRT accessibility tests to add the ability to
+ query the intValue, minValue, and maxValue of the focused element.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (intValueOfFocusedElementCallback):
+ (minValueOfFocusedElementCallback):
+ (maxValueOfFocusedElementCallback):
+ (AccessibilityController::staticFunctions):
+ * DumpRenderTree/AccessibilityController.h:
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::intValueOfFocusedElement):
+ (AccessibilityController::minValueOfFocusedElement):
+ (AccessibilityController::maxValueOfFocusedElement):
+
+2008-07-07 Steve Falkenburg <sfalken@apple.com>
+
+ Fix build.
+
+ * DumpRenderTree/win/ImageDiff.vcproj:
+
+2008-07-02 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Allow tests to define JavaScript to execute when NPP_DestroyStream or
+ NPP_URLNotify is called.
+
+ Reviewed by Anders.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp: Add a new
+ property, "returnErrorFromNewStream." This is to support the test for
+ <rdar://5983747> Safari crashes trying to load the SilverLight plugin,
+ caused by WebKit calling NPP_DestroyStream after a plug-in returns an
+ error from NPP_NewStream.
+ (pluginGetProperty):
+ (pluginSetProperty):
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h: Added new
+ members, onStreamDestroy and onURLNotify.
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp:
+ (NPP_New): Remove initialization of onStreamLoad; this was moved to
+ pluginAllocate. Look for new arguments onStreamDestroy and
+ onURLNotify, and store their values.
+ (NPP_Destroy): Free new members.
+ (executeScript): Code moved from onStreamLoad
+ (NPP_NewStream): If returnErrorFromNewStream has been set to true,
+ return a generic error code. If onStreamLoad is set, execute it as
+ JavaScript.
+ (NPP_DestroyStream): If onStreamDestroy is set, execute it as JS.
+ (NPP_URLNotify): Same, for onURLNotify.
+
+2008-07-02 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Mitz Pettel and John Sullivan
+
+ Add the ability to tell DRT to call stopLoading on a WebFrame inside of a didStartProvisionalLoadForFrame
+ load delegate.
+
+ Required to add a layout test for the fix for <rdar://problem/5549871>
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate webView:didStartProvisionalLoadForFrame:]): If stopProvisionalFrameLoads is set, call
+ [WebFrame stopLoading] to test for the crash reflected in 5549871
+
+ All of the following are infrastructure to add the layoutTestController.setStopProvisionalFrameLoads() call:
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (setStopProvisionalFrameLoadsCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::stopProvisionalFrameLoads):
+ (LayoutTestController::setStopProvisionalFrameLoads):
+
+2008-07-01 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin
+
+ Support ability to get width and height of an element through accessibility
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (widthOfFocusedElementCallback):
+ (heightOfFocusedElementCallback):
+ (AccessibilityController::staticFunctions):
+ * DumpRenderTree/AccessibilityController.h:
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::widthOfFocusedElement):
+ (AccessibilityController::heightOfFocusedElement):
+
+2008-06-30 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin
+
+ Support the ability to get the linked ui elements of an object
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (attributesOfLinkedUIElementsForFocusedElementCallback):
+ (AccessibilityController::staticFunctions):
+ * DumpRenderTree/AccessibilityController.h:
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::attributesOfLinkedUIElementsForFocusedElement):
+ (AccessibilityController::allAttributesOfFocusedElement):
+ (attributesOfElement):
+ (nsStringToJSStringRef):
+
+2008-06-29 Sam Weinig <sam@webkit.org>
+
+ Fix Tiger build.
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (eventTypeForMouseButtonAndAction):
+
+2008-06-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by darin.
+
+ Add multi-button mouseevent support to DRT
+ https://bugs.webkit.org/show_bug.cgi?id=15173
+
+ It's now possible to specify the mouse button with:
+ eventSender.mouseDown(1); eventSender.mouseUp(1); etc.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/EventSendingController.h:
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (+[EventSendingController webScriptNameForSelector:]):
+ (eventTypeForMouseButtonAndAction):
+ (-[EventSendingController updateClickCountForButton:]):
+ (-[EventSendingController mouseDown:]):
+ (-[EventSendingController mouseUp:]):
+ (-[EventSendingController mouseMoveToX:Y:]):
+ (-[EventSendingController contextClick]):
+
+2008-06-28 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Oliver.
+
+ Copy <test>-expected.png from the right location to /tmp/layout-test-results.
+ Use $expectedPixelDir instead of $expectedDir. Allows using SVG pixel tests again.
+
+ * Scripts/run-webkit-tests:
+
+2008-06-27 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Christian Dywan.
+
+ [Gtk] Initialize webview settings before running DRT tests
+ http://bugs.webkit.org/show_bug.cgi?id=19778
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (setDefaultsToConsistentStateValuesForTesting):
+ (main):
+
+2008-06-26 Darin Adler <darin@apple.com>
+
+ * Scripts/check-for-weak-vtables: Fixed comment.
+
+2008-06-26 Darin Adler <darin@apple.com>
+
+ * Scripts/check-for-weak-vtables: Added.
+
+2008-06-26 Beth Dakin <bdakin@apple.com>
+
+ Reviewed by Sam.
+
+ Do not include AXPosition in the dump of all of the accessibility
+ attributes since it is screen-specific.
+
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::allAttributesOfFocusedElement):
+
+2008-06-26 Beth Dakin <bdakin@apple.com>
+
+ Reviewed by Anders.
+
+ This is a speculative fix for the failing layout test on the build
+ bot. It seems that the problem that the Build Bot is having is
+ Tiger-specific. On Tiger, [NSValue description] was not very smart.
+ So I replaced our call to description with a hand-rolled equivalent
+ that will match on both platforms.
+
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (descriptionOfValue):
+
+2008-06-25 Beth Dakin <bdakin@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ This patch adds support to the AccessibilityController to query the
+ following attributes specifically, without a full attribute dump:
+ AXRole, AXTitle, and AXDescription.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (allAttributesForFocusedElementCallback):
+ (roleOfFocusedElementCallback):
+ (titleOfFocusedElementCallback):
+ (descriptionOfFocusedElementCallback):
+ (AccessibilityController::staticFunctions):
+ * DumpRenderTree/AccessibilityController.h:
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::allAttributesForFocusedElement):
+ (concatenateAttributeAndValue):
+ (AccessibilityController::roleOfFocusedElement):
+ (AccessibilityController::titleOfFocusedElement):
+ (AccessibilityController::descriptionOfFocusedElement):
+
+2008-06-24 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Stephanie Lewis.
+
+ - move the linker flags from the debug configuration in the project
+ to the shared configuration
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig:
+
+2008-06-24 Dan Bernstein <mitz@apple.com>
+
+ - try to fix the Tiger build
+
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+
+2008-06-24 Sam Weinig and Beth Dakin <bdakin@apple.com and sam@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Fix for <rdar://problem/5884881> Make DumpRenderTree support
+ accessibility tests
+
+ This patch adds some basic support for accessibility layout tests
+ on the Mac.
+
+ * DumpRenderTree/AccessibilityController.cpp: Added.
+ (AccessibilityController::AccessibilityController):
+ (AccessibilityController::~AccessibilityController):
+ (dumpCurrentAttributesCallback):
+ (AccessibilityController::makeWindowObject):
+ (AccessibilityController::getJSClass):
+ (AccessibilityController::staticFunctions):
+ * DumpRenderTree/AccessibilityController.h: Added.
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm: Added.
+ (descriptionOfValue):
+ (AccessibilityController::dumpCurrentAttributes):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ * DumpRenderTree/mac/FrameLoadDelegate.h:
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate init]):
+ (-[FrameLoadDelegate webView:didClearWindowObject:forFrame:]):
+
+2008-06-24 John Sullivan <sullivan@apple.com>
+
+ Reviewed by Dan Bernstein
+
+ * Scripts/extract-localizable-strings:
+ add UI_STRING_LOCALIZE_LATER, LPCTSTR_UI_STRING_LOCALIZE_LATER, and LOG_WARNING to the
+ list of debugging macros, to avoid noise when keeping the list of localized string
+ exceptions up to date
+
+2008-06-24 Dan Bernstein <mitz@apple.com>
+
+ Rubber-stamped by Darin Adler.
+
+ - add a font family for testing font-weight
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Added linker
+ flags to create data sections for the WeightWatcher fonts.
+ * DumpRenderTree/fonts: Added.
+ * DumpRenderTree/fonts/WebKitWeightWatcher100.ttf: Added.
+ * DumpRenderTree/fonts/WebKitWeightWatcher200.ttf: Added.
+ * DumpRenderTree/fonts/WebKitWeightWatcher300.ttf: Added.
+ * DumpRenderTree/fonts/WebKitWeightWatcher400.ttf: Added.
+ * DumpRenderTree/fonts/WebKitWeightWatcher500.ttf: Added.
+ * DumpRenderTree/fonts/WebKitWeightWatcher600.ttf: Added.
+ * DumpRenderTree/fonts/WebKitWeightWatcher700.ttf: Added.
+ * DumpRenderTree/fonts/WebKitWeightWatcher800.ttf: Added.
+ * DumpRenderTree/fonts/WebKitWeightWatcher900.ttf: Added.
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (activateFonts): Renamed activateAhemFont to this and made it activate
+ the WeightWatcher fonts in addition to Ahem.
+ (prepareConsistentTestingEnvironment): Adjusted for the name change.
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (initialize): Added the WeightWatcher fonts.
+
+2008-06-20 Brent Fulgham <bfulgham@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ Extend the build-webkit (and set-webkit-configuration) script to
+ support Cairo-based webkit builds. (see http://bugs.webkit.org/show_bug.cgi?17952)
+
+ * Scripts/build-webkit: Add --cairo-win32 to the help message
+ * Scripts/webkitdirs.pm: Extend the 'determinePassedConfiguration
+ subroutine to recognize the --cairo-win32 flag. When present,
+ the build configuration is changed from Debug/Release to
+ Debug_Cairo/Release_Cairo. This flag is only active when the
+ isCygwin() test is true.
+
+2008-06-17 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Justin Garcia.
+
+ - prefer Leopard results when running on Snow Leopard.
+
+ * Scripts/run-webkit-tests: Added a mapping of Snow Leopard to
+ mac-leopard.
+ * Scripts/webkitdirs.pm: Added isSnowLeopard().
+
+2008-06-15 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Updated for the latest round of renaming.
+
+2008-06-15 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Updated for the latest round of renaming.
+
+2008-06-15 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Updated for the latest round of renaming.
+
+2008-06-15 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Updated for the latest round of renaming.
+
+2008-06-15 Darin Adler <darin@apple.com>
+
+ * Scripts/do-file-rename: Updated.
+ * Scripts/do-webcore-rename: Updated for the latest round of renaming.
+
+2008-06-15 Darin Adler <darin@apple.com>
+
+ * Scripts/do-file-rename: Updated for the latest round of renaming.
+ * Scripts/do-webcore-rename: Tweaked and reorganized a bit.
+
+2008-06-15 Darin Adler <darin@apple.com>
+
+ * Scripts/create-exports: Added.
+ * Scripts/do-file-rename: Added some planned renames.
+ * Scripts/do-webcore-rename: Updated for the latest round of renaming.
+
+2008-06-15 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Updated for the latest round of renaming.
+
+2008-06-15 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Oliver.
+
+ - rename testkjs to jsc
+
+ * Scripts/build-jsc: Copied from Scripts/build-testkjs.
+ * Scripts/build-testkjs: Removed.
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/run-jsc: Copied from Scripts/run-testkjs.
+ * Scripts/run-sunspider:
+ * Scripts/run-testkjs: Removed.
+ * Scripts/sunspider-compare-results:
+
+2008-06-14 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Moved planned renames into a separate hash
+ from the actual renames. Removed many renames that are either done or
+ no longer planned.
+
+2008-06-14 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Fixed obvious typo.
+
+2008-06-13 Darin Adler <darin@apple.com>
+
+ * Scripts/make-js-test-wrappers: Added three more exceptions.
+
+2008-06-10 Joerg Bornemann <joerg.bornemann@trolltech.com>
+
+ Reviewed by Simon.
+
+ For the qmake based build make it possible to build against makespecs where
+ QMAKE_CC is defined in a configuration file included from qmake.conf.
+
+ * Scripts/webkitdirs.pm: Added support for include() statements in
+ qmake.conf.
+
+2008-06-09 Alp Toker <alp@nuanti.com>
+
+ gcc3/autotools build fix. Add explicit -O2 -fno-strict-aliasing to
+ each of the tools since these are no longer set globally.
+
+ * GNUmakefile.am:
+
+2008-06-08 Darin Adler <darin@apple.com>
+
+ * Scripts/make-js-test-wrappers: Added another exception.
+
+2008-06-07 Cameron Zwarich <cwzwarich@uwaterloo.ca>
+
+ Reviewed by Timothy.
+
+ Remove the --squirrelfish option from SunSpider, as it is no longer needed.
+
+ * Scripts/run-sunspider:
+
+2008-06-05 Alp Toker <alp@nuanti.com>
+
+ Build fix for r34387.
+
+ * GNUmakefile.am:
+
+2008-06-04 Cameron Zwarich <cwzwarich@uwaterloo.ca>
+
+ Reviewed by Oliver.
+
+ Add an exception for Opcode.o to the global initializers check so that
+ we can dump instruction statistics in the JavaScript virtual machine.
+
+ * Scripts/check-for-global-initializers:
+
+2008-05-30 Steve Falkenburg <sfalken@apple.com>
+
+ Generate an isolated COM manifest for registry free COM.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+2008-06-02 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by David Hyatt and Mitz.
+
+ <rdar://problem/5704119>
+ repro crash in WebCore::RenderPart::setWidget (plugin-related?)
+
+ Call -[WebView display] in the "plug-in" failed delegate method, simulating
+ the sheet that Safari puts up.
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:plugInFailedWithError:dataSource:]):
+
+2008-05-30 Timothy Hatcher <timothy@apple.com>
+
+ Made the starting line number of scripts be 1-based throughout the engine.
+ This cleans up script line numbers so they are all consistent now.
+
+ Reviewed by Oliver Hunt.
+
+ * DumpRenderTree/mac/ObjCController.m:
+ (runJavaScriptThread): Pass a line number of 1 instead of 0 to JSEvaluateScript.
+ * DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp:
+ (runJavaScriptThread): Ditto.
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runJavaScriptThread): Ditto.
+
+2008-05-29 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Fixed VCSUtils.pm to work with git repositories inside symlinks.
+
+ * Scripts/VCSUtils.pm: Compute a relative path from the git repository
+ root, instead of the root of the filesystem, to work around a bug in
+ abs2rel when traversing symlinked home directories.
+
+2008-05-29 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Darin Adler.
+
+ Restore original behavior of isOSX() referring to the Mac port, not the OS itself.
+
+ https://bugs.webkit.org/show_bug.cgi?id=19311
+
+ * Scripts/webkitdirs.pm:
+
+2008-05-29 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Fix run-iexploder-tests and run-mangleme-tests to work with updated shared scripts and
+ configuration files.
+
+ * Scripts/run-iexploder-tests:
+ * Scripts/run-mangleme-tests:
+ Renamed runSafari to not conflict with the one in webkitdirs.
+ Added SSLCertificateFile option for httpd, as now needed.
+
+2008-05-27 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Update the sample app after wxWebFrame->wxWebBrowserShell rename.
+
+ * wx/browser/browser.cpp:
+ (MyApp::OnInit):
+
+2008-05-24 Andreia Gaita <shana@isninja.com>
+
+ Reviewed by Alp Toker.
+
+ cygwin-downloader.py fixes.
+
+ Remove two non-working mirrors. Add a check for missing dependency
+ packages to avoid bailing out on an inconsistent Cygwin package list.
+
+ * CygwinDownloader/cygwin-downloader.py:
+
+2008-05-24 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Remove useQmake usage. QMake build doesn't support Gtk port
+ anymore.
+
+ Also fix 2 occurences of "Web Kit". Should be WebKit.
+
+ * Scripts/build-webkit:
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/run-launcher:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2008-05-22 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Dan.
+
+ implement the beforeUnload UI delegate so that DRT will dispatch beforeunload events.
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:runBeforeUnloadConfirmPanelWithMessage:initiatedByFrame:]):
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (SearchableWebViewHost::runBeforeUnloadConfirmPanelWithMessage):
+
+2008-05-21 Adele Peterson <adele@apple.com>
+
+ Reviewed by Adam.
+
+ DumpRenderTree support for <rdar://problem/5787733> fast/dom/HTMLDocument/hasFocus.html fails on Windows
+
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::webViewFocus): Added.
+ (UIDelegate::webViewUnfocus): Added.
+ * DumpRenderTree/win/UIDelegate.h:
+
+2008-05-21 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Stephanie Lewis.
+
+ Set the pass_through flag on Getopt so that extra arguments can be passed through to Safari,
+ rather than trigger an unknown argument message. This allows run-webkit-tests to display results
+ once more.
+
+ * Scripts/run-safari:
+
+2008-05-21 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Maciej, Mark.
+
+ arch doesn't take arguments on tiger. expand DRT timeout for guardMalloc.
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2008-05-20 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Stephanie Lewis.
+
+ Improve the behavior of run-webkit-tests with 64-bit WebKit by automatically inferring whether to run 64-bit.
+
+ If --64-bit is not passed to run-webkit-tests, attempt to guess whether we should run 64-bit.
+ This decision is made based on the 64-bitness of the built WebKit framework if it exists, and
+ can be manually overridden by passing --64-bit or --no-64-bit. This removes the need to always
+ pass an argument to run-webkit-tests after having built with "make x86_64".
+
+ * Scripts/gdb-safari:
+ * Scripts/run-safari:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm: Split the setting of the 64-bit flag, the determination of the
+ preferred architecture, and exporting of the environment variables for 'arch' out into
+ separate subroutines.
+
+2008-05-20 Mark Rowe <mrowe@apple.com>
+
+ Fix "make x86_64" by adding x86_64 target to WebKitTools Makefile.
+
+ * Makefile:
+
+=== End merge of squirrelfish ===
+
+2008-04-14 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Oliver.
+
+ - added support for --ubench mode
+
+ * Scripts/run-sunspider:
+
+2008-03-26 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ --squirrelfish mode: pared down tests for squirrelfish to chew on.
+
+ * Scripts/run-sunspider:
+
+=== Start merge of squirrelfish ===
+
+2008-05-21 Darin Adler <darin@apple.com>
+
+ * Scripts/make-js-test-wrappers: Added another exception.
+
+2008-05-19 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Adam.
+
+ Explicitly set run mode to 32bit unless overridden to avoid
+ confusion when running tests
+
+ * Scripts/build-dumprendertree:
+ * Scripts/gdb-safari:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2008-05-16 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Steve.
+
+ Print out pending unload event count. Also print out main frame name to match Mac.
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (descriptionSuitableForTestResult):
+ (FrameLoadDelegate::didFinishDocumentLoadForFrame):
+
+2008-05-16 Timothy Hatcher <timothy@apple.com>
+
+ Remove the Drosera project, code and resources since it has been
+ replaced with the Web Inspector's debugger. Removes references to
+ Drosera in various scripts and makefiles.
+
+ Rubber-stamped by Mark Rowe.
+
+ * BuildSlaveSupport/build-launcher-app:
+ * Drosera/DebuggerDocument.cpp: Removed.
+ * Drosera/DebuggerDocument.h: Removed.
+ * Drosera/Drosera.icns: Removed.
+ * Drosera/DroseraWin.make: Removed.
+ * Drosera/English.lproj/Debugger.nib/classes.nib: Removed.
+ * Drosera/English.lproj/Debugger.nib/info.nib: Removed.
+ * Drosera/English.lproj/Debugger.nib/keyedobjects.nib: Removed.
+ * Drosera/English.lproj/MainMenu.nib/classes.nib: Removed.
+ * Drosera/English.lproj/MainMenu.nib/info.nib: Removed.
+ * Drosera/English.lproj/MainMenu.nib/keyedobjects.nib: Removed.
+ * Drosera/ForwardingHeaders/wtf/Assertions.h: Removed.
+ * Drosera/ForwardingHeaders/wtf/HashTraits.h: Removed.
+ * Drosera/ForwardingHeaders/wtf/Noncopyable.h: Removed.
+ * Drosera/ForwardingHeaders/wtf/OwnPtr.h: Removed.
+ * Drosera/ForwardingHeaders/wtf/Platform.h: Removed.
+ * Drosera/ForwardingHeaders/wtf/RetainPtr.h: Removed.
+ * Drosera/Images/Drosera.ico: Removed.
+ * Drosera/Images/SourceArrow.png: Removed.
+ * Drosera/Images/SourceArrowBlank.png: Removed.
+ * Drosera/Images/SourceArrowOpen.png: Removed.
+ * Drosera/Images/background_stripe.png: Removed.
+ * Drosera/Images/breakPoint.tif: Removed.
+ * Drosera/Images/breakPointDisabled.tif: Removed.
+ * Drosera/Images/breakpointeditor.png: Removed.
+ * Drosera/Images/close.tif: Removed.
+ * Drosera/Images/close_active.tif: Removed.
+ * Drosera/Images/close_hover.tif: Removed.
+ * Drosera/Images/console.png: Removed.
+ * Drosera/Images/continue.tif: Removed.
+ * Drosera/Images/fileIcon.jpg: Removed.
+ * Drosera/Images/finishFunction.tif: Removed.
+ * Drosera/Images/glossyFooterFill.tif: Removed.
+ * Drosera/Images/glossyHeader.png: Removed.
+ * Drosera/Images/glossyHeaderPressed.png: Removed.
+ * Drosera/Images/gradientBackground.png: Removed.
+ * Drosera/Images/gutter.png: Removed.
+ * Drosera/Images/navLeftDisabled.png: Removed.
+ * Drosera/Images/navLeftNormal.png: Removed.
+ * Drosera/Images/navLeftPressed.png: Removed.
+ * Drosera/Images/navRightDisabled.png: Removed.
+ * Drosera/Images/navRightNormal.png: Removed.
+ * Drosera/Images/navRightPressed.png: Removed.
+ * Drosera/Images/pause.tif: Removed.
+ * Drosera/Images/popUpArrows.png: Removed.
+ * Drosera/Images/programCounter.tif: Removed.
+ * Drosera/Images/programCounterBreakPoint.tif: Removed.
+ * Drosera/Images/programCounterBreakPointDisabled.tif: Removed.
+ * Drosera/Images/run.tif: Removed.
+ * Drosera/Images/siteCollapsed.tif: Removed.
+ * Drosera/Images/siteExpanded.tif: Removed.
+ * Drosera/Images/siteIcon.tif: Removed.
+ * Drosera/Images/small.ico: Removed.
+ * Drosera/Images/splitterBar.tif: Removed.
+ * Drosera/Images/splitterDimple.tif: Removed.
+ * Drosera/Images/step.tif: Removed.
+ * Drosera/Images/stepOut.tif: Removed.
+ * Drosera/Images/stepOver.tif: Removed.
+ * Drosera/Images/stop.tif: Removed.
+ * Drosera/Images/toolbarBackground.png: Removed.
+ * Drosera/Images/verticalSplitterBar.tiff: Removed.
+ * Drosera/Images/verticalSplitterDimple.tiff: Removed.
+ * Drosera/Makefile: Removed.
+ * Drosera/breakpointEditor.html: Removed.
+ * Drosera/config.h: Removed.
+ * Drosera/console.css: Removed.
+ * Drosera/console.html: Removed.
+ * Drosera/console.js: Removed.
+ * Drosera/debugger.css: Removed.
+ * Drosera/debugger.html: Removed.
+ * Drosera/debugger.js: Removed.
+ * Drosera/mac/DebuggerApplication.h: Removed.
+ * Drosera/mac/DebuggerApplication.mm: Removed.
+ * Drosera/mac/DebuggerClient.h: Removed.
+ * Drosera/mac/DebuggerClient.mm: Removed.
+ * Drosera/mac/DebuggerDocumentPlatform.mm: Removed.
+ * Drosera/mac/Drosera.xcodeproj/project.pbxproj: Removed.
+ * Drosera/mac/Info.plist: Removed.
+ * Drosera/mac/LauncherInfo.plist: Removed.
+ * Drosera/mac/Makefile: Removed.
+ * Drosera/mac/ServerConnection.h: Removed.
+ * Drosera/mac/ServerConnection.mm: Removed.
+ * Drosera/mac/launcher.m: Removed.
+ * Drosera/mac/main.m: Removed.
+ * Drosera/viewer.css: Removed.
+ * Drosera/viewer.html: Removed.
+ * Drosera/win/BaseDelegate.h: Removed.
+ * Drosera/win/DebuggerClient.cpp: Removed.
+ * Drosera/win/DebuggerClient.h: Removed.
+ * Drosera/win/DebuggerDocumentPlatform.cpp: Removed.
+ * Drosera/win/Drosera.cpp: Removed.
+ * Drosera/win/Drosera.h: Removed.
+ * Drosera/win/Drosera.vcproj/Drosera.rc: Removed.
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj: Removed.
+ * Drosera/win/DroseraPrefix.cpp: Removed.
+ * Drosera/win/DroseraPrefix.h: Removed.
+ * Drosera/win/Info.plist: Removed.
+ * Drosera/win/ServerConnection.cpp: Removed.
+ * Drosera/win/ServerConnection.h: Removed.
+ * Drosera/win/resource.h: Removed.
+ * Makefile:
+ * Scripts/build-drosera: Removed.
+ * Scripts/gdb-drosera: Removed.
+ * Scripts/run-drosera: Removed.
+ * Scripts/run-drosera-nightly.cmd: Removed.
+ * Scripts/run-drosera.cmd: Removed.
+ * Scripts/webkitdirs.pm:
+
+2008-05-15 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Anders.
+
+ Dump the unload count for a frame after parsing is finished.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate webView:didFinishDocumentLoadForFrame:]):
+
+2008-05-15 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ https://bugs.webkit.org/show_bug.cgi?id=10707
+ DumpRenderTree should not be able to access non-local resources
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:resource:willSendRequest:redirectResponse:fromDataSource:]):
+ Block them, and complain.
+
+2008-05-15 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Update the version of libpng to download and instsall.
+
+ * wx/install-unix-extras:
+
+2008-05-14 Julien Chaffraix <jchaffraix@webkit.org>
+
+ Reviewed by Eric.
+
+ - isDarwin() and isCygwin() returned an empty string if the platform equality check fails.
+ We now force the return value to be numeric.
+
+ - Removed platform checks as it was a work around the previous issue.
+
+ - Replaced isDarwin() by isOSX() as they have now the same behaviour.
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2008-05-12 Adam Roben <aroben@apple.com>
+
+ Support for testing NPN_PostURL
+
+ Reviewed by Anders Carlsson.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (toCString): Added this helper function.
+ (testPostURLFile): Added. Writes the passed-in content to the
+ passed-in file and calls NPN_PostURL with the passed-in URL and
+ target.
+ (pluginInvoke): Added a case for testPostURLFile.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (followShortcuts): Changed to allow paths that don't yet exist.
+
+2008-05-12 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Minor cleanup of the DRT Xcode project.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Use GCC_OPTIMIZATION_LEVEL rather than
+ OPTIMIZATION_CFLAGS. Don't include Info.plist in the "Copy Bundle Resources" build phase as it does
+ not need to be there.
+
+2008-05-12 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam.
+
+ Add support for testing application caches.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpRenderTree):
+ Empty the cache.
+
+ (resetWebViewToConsistentStateBeforeTesting):
+ Turn on support for the application cache.
+
+2008-05-09 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Anders Carlsson.
+
+ Update TestNetscapePlugIn to build 64-bit using the Cocoa event model.
+
+ It currently does not attempt to print events which means that plugins/mouse-events.html
+ will fail when run 64-bit. All other tests that use this plugin pass.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (testGetIntIdentifier):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+ (NPP_HandleEvent):
+
+2008-05-09 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Adam Roben
+
+ Explicitly call shutDownWebKit() before quitting.
+
+ * Drosera/win/Drosera.cpp:
+ (_tWinMain):
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main):
+
+2008-05-09 Mark Rowe <mrowe@apple.com>
+
+ Fix the Tiger build of Drosera.
+
+ * Drosera/config.h: Define BUILDING_ON_TIGER when building on Tiger.
+
+2008-05-09 Sam Weinig <sam@webkit.org>
+
+ Rubber-stamped by Mark Rowe.
+
+ Remove the ENABLE_CROSS_DOCUMENT_MESSAGING #ifdefs.
+
+ * Scripts/build-webkit:
+
+2008-05-08 Mark Rowe <mrowe@apple.com>
+
+ Another attempt at a Tiger build fix.
+
+ Use DumpRenderTreeMac.h rather than DumpRenderTree.h as DumpRenderTreePasteboard is not an Obj-C++ file.
+
+ * DumpRenderTree/mac/DumpRenderTreePasteboard.m:
+
+2008-05-08 Mark Rowe <mrowe@apple.com>
+
+ Tiger build fix. Include DumpRenderTree.h so that BUILDING_ON_TIGER will be defined.
+
+ * DumpRenderTree/mac/DumpRenderTreePasteboard.m:
+
+2008-05-08 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt and Dan Bernstein.
+
+ Update DumpRenderTree to build 64-bit.
+
+ The three major changes here are:
+ 1) Use NSInteger in the appropriate places.
+ 2) Use ColorSync API that is available in 64-bit to switch display profiles.
+ 3) Use method-swizzling to achieve similar results to class posing when using the Obj-C 2.0 runtime.
+
+ The build of DumpRenderTree will still fail in 64-bit for now as the TestNetscapePlugIn target also
+ needs updated to successfully build.
+
+ * DumpRenderTree/mac/Configurations/Base.xcconfig: Don't prevent Xcode from building 64-bit.
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (swizzleAllMethods):
+ (poseAsClass):
+ (prepareConsistentTestingEnvironment):
+ * DumpRenderTree/mac/DumpRenderTreeMac.h:
+ * DumpRenderTree/mac/DumpRenderTreePasteboard.h:
+ * DumpRenderTree/mac/DumpRenderTreePasteboard.m:
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (restoreColorSpace):
+ (failedGettingCurrentProfile):
+ (setDefaultColorProfileToRGB):
+
+2008-05-08 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Clean up Drosera so that it will build 64-bit.
+
+ * Drosera/mac/DebuggerApplication.mm:
+ (-[DebuggerApplication numberOfRowsInTableView:]): Use NSInteger rather than int.
+ (-[DebuggerApplication tableView:objectValueForTableColumn:row:]): Ditto.
+ * Drosera/mac/Drosera.xcodeproj/project.pbxproj: Use the default value for VALID_ARCHS.
+
+2008-05-07 David Kilzer <ddkilzer@apple.com>
+
+ Use File::Find and Getopt::Long in make-js-test-wrappers
+
+ Reviewed by Darin Adler.
+
+ * Scripts/make-js-test-wrappers:
+ - Updated Apple copyright statement.
+ - Added command-line switch parsing and -h|--help switch.
+ - Allowed user to pass list of files/directories on which to do
+ a restricted search for TEMPLATE.html files. The default
+ behavior is still to search the entire LayoutTests directory.
+ - Removed duplicate 'use strict' statement.
+ - Replaced use of `find` statements with File::Find::find().
+ - Remove unneeded chomp() calls now that we use File::Find.
+ (directoryFilter): Added. Filters .svn directories when used
+ with File::Find::find().
+ (findTemplateFiles): Added. Returns a list of TEMPLATE.html
+ files found.
+
+2008-05-05 Steve Falkenburg <sfalken@apple.com>
+
+ Copy dependencies of ImageDiff, DumpRenderTree in post-build step.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+
+2008-05-05 Adele Peterson <adele@apple.com>
+
+ Reviewed by Adam.
+
+ Look for the right ImageDiff executable for debug builds.
+
+ * Scripts/run-webkit-tests:
+
+2008-05-05 Darin Adler <darin@apple.com>
+
+ * Scripts/run-webkit-tests: Ignore a Java leak showing up in the WebKit
+ leak tests.
+
+2008-05-05 Ariya Hidayat <ariya.hidayat@trolltech.com>
+
+ Reviewed by Simon.
+
+ In the Qt's DumpRenderTree, adjust the web view properly (because W3C SVG
+ tests expect to be 480x360)
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::open):
+
+2008-05-02 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Adam Roben.
+
+ - add an option to svn-apply to set the reviewer name in change logs
+
+ * Scripts/svn-apply: Added a [-r|--reviewer name] option.
+
+2008-05-01 David Kilzer <ddkilzer@apple.com>
+
+ Clean up configuration usage in run-webkit-tests
+
+ Reviewed by Adam.
+
+ * Scripts/run-webkit-tests: Parse configuration switches using
+ passedConfiguration() from webkitdirs.pm like every other script.
+ Note that we must still call setConfiguration() afterwards in
+ case the --configuration switch was used. Use $configurationOption
+ when running build-dumprendertree instead of recreating the switch.
+
+2008-04-29 Adam Roben <aroben@apple.com>
+
+ Restore the beloved COMPtr::operator&
+
+2008-04-29 Adam Roben <aroben@apple.com>
+
+ Windows build fixes
+
+ Replace COMPtr::operator& with COMPtr::adoptionPointer.
+
+2008-04-25 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Fix run-webkit-tests --threading
+ and provisionally fix <https://bugs.webkit.org/show_bug.cgi?id=18661>
+ Proxy server issue in Sunday's Nightly
+
+ * DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp:
+ (runJavaScriptThread):
+ (startJavaScriptThreads):
+ (stopJavaScriptThreads):
+ Spawned threads were immediately detached, unlike the original ones, so joining them
+ made no sense. Now, all threads are created detached, and stopJavaScriptThreads() just
+ waits for them all to exit.
+
+2008-04-28 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Simon.
+
+ Reset dumping resource load callbacks to false for the next test
+
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::reset):
+
+2008-04-28 Tor Arne Vestbø <tavestbo@trolltech.com>
+
+ Reviewed by Simon.
+
+ Adapt to the latest API changes in WebKit/qt/Api.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ * DumpRenderTree/qt/jsobjects.cpp:
+
+2008-04-26 Robin Dunn <robin@alldunn.com>
+
+ Reviewed by Kevin Ollivier.
+
+ Delete the DerivedSources after make clean has been done so that the DerivedSources
+ don't get re-created. Also, use the proper extension for the Win wxPython extension.
+
+ https://bugs.webkit.org/show_bug.cgi?id=18756
+
+ * wx/build-wxwebkit:
+
+2008-04-26 Adam Barth <hk9565@gmail.com>
+
+ Reviewed by Adam Roben and Sam Weinig.
+
+ Updates LayoutTestController to use host instead of domain.
+
+ Collin Jackson <collinj-webkit@collinjackson.com> also contributed to this patch.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setDatabaseQuota):
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:]):
+
+2008-04-26 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Need the latest libpng. (Somehow my initial test passed without it.)
+
+ * wx/install-unix-extras:
+
+2008-04-26 Robin Dunn <robin@alldunn.com>
+
+ Reviewed by Kevin Ollivier.
+
+ Allow the user to set the path to SWIG using an environment variable.
+
+ https://bugs.webkit.org/show_bug.cgi?id=18660
+
+ * wx/build-wxwebkit:
+
+2008-04-26 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Download the latest libpng version for building the
+ dependencies.
+
+ * wx/install-unix-extras:
+
+2008-04-25 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Simon.
+
+ Implement dumping of resource load callbacks to pass http/tests/xmlhttprequest/abort-should-cancel-load.html
+
+ Similar to Editing and Frameloading we do the dumping within WebCore
+
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::dumpResourceLoadCallbacks):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2008-04-24 Jan Michael Alonzo <jmalonzo@unpluggable.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ http://bugs.webkit.org/show_bug.cgi?id=18485
+ Typo and documentation fix for build-webkit
+
+ * Scripts/build-webkit:
+
+2008-04-24 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam.
+
+ Don't call fprintf from the signal handler.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (crashHandler):
+
+2008-04-23 Adam Roben <aroben@apple.com>
+
+ Make crashes be reported as crashes, not hangs
+
+ Reviewed by David Kilzer.
+
+ * Scripts/run-webkit-tests:
+ (top level): Use the new status field of the output from
+ readFromDumpToolWithTimer to determine if the test crashed or hung.
+ (sub readFromDumpToolWithTimer):
+ - If we fail to read a line and $! is not EAGAIN, then we've crashed
+ and should not try to read any more.
+ - Changed the timedout field to a more general status field.
+
+2008-04-22 David Kilzer <ddkilzer@apple.com>
+
+ Bug 18683: update-webkit returns 0 even if it fails
+
+ <https://bugs.webkit.org/show_bug.cgi?id=18683>
+
+ Reviewed by Mitz Pettel.
+
+ * Scripts/update-webkit:
+ (runSvnUpdate): Die if close() fails.
+
+2008-04-21 Adam Roben <aroben@apple.com>
+
+ Flush stdout/stderr after printing every #EOF separator
+
+ This fixes a hang when running the pixel tests on Windows
+
+ Reviewed by Mitz Pettel.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dump):
+ (main): We don't have to flush stdout/stderr in the arguments loop
+ anymore, as runTest flushes for us.
+
+2008-04-21 Adam Roben <aroben@apple.com>
+
+ Fix pixel tests
+
+ * Scripts/run-webkit-tests:
+ (sub readFromDumpToolWithTimer): Use readline instead of read to
+ ensure that we don't read past the #EOF marker.
+
+2008-04-21 Holger Hans Peter Freyther <holger.freyther@trolltech.com>
+
+ Reviewed by Simon.
+
+ Build fix for Qt 4.3
+
+ * When building WebCore/internal make sure the QT_[BEGIN,END]_NAMESPACE is
+ always defined. Do this by adding defines to the compiler line
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+
+2008-04-19 Mike Hommey <glandium@debian.org>
+
+ Reviewed by Alp Toker.
+
+ Don't build GtkLauncher and DumpRenderTree with rpath.
+
+ * GNUmakefile.am:
+
+2008-04-18 Jan Michael Alonzo <jmalonzo@unpluggable.com>
+
+ Reviewed by Alp Toker.
+
+ http://bugs.webkit.org/show_bug.cgi?id=16620
+ [GTK] Autotools make dist and make check support
+
+ Cleanups.
+
+ * GNUmakefile.am:
+
+2008-04-18 Adam Roben <aroben@apple.com>
+
+ Drop the hang timer to 30 seconds
+
+ This matches what DRT/mac was using.
+
+ Reviewed by Mitz Pettel.
+
+ * Scripts/run-webkit-tests:
+
+2008-04-18 Adam Roben <aroben@apple.com>
+
+ Get rid of DRT's Watchdog
+
+ run-webkit-tests now detects hangs and samples DRT as needed.
+
+ Reviewed by Mitz Pettel.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Removed
+ Watchdog* files from the project.
+ * DumpRenderTree/Watchdog.cpp: Removed.
+ * DumpRenderTree/Watchdog.h: Removed.
+ * DumpRenderTree/mac/DumpRenderTree.mm: Removed uses of Watchdog
+ (dumpRenderTree):
+ (runTest):
+ * DumpRenderTree/mac/WatchdogMac.h: Removed.
+ * DumpRenderTree/mac/WatchdogMac.mm: Removed.
+ * Scripts/run-webkit-tests:
+ (sub testCrashedOrTimedOut): Call sampleDumpTool() if we timed out.
+ (sub sampleDumpTool): Added. Writes a sample report to
+ ~/Library/Logs/DumpRenderTree/HangReport.txt.
+
+2008-04-18 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Holger.
+
+ Adapt to the API changes in WebKit/qt
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::initJSObjects):
+ (WebCore::DumpRenderTree::dumpFramesAsText):
+ (WebCore::DumpRenderTree::dump):
+
+2008-04-17 Adam Roben <aroben@apple.com>
+
+ Fix many tests on Windows
+
+ * Scripts/run-webkit-tests:
+ (readFromDumpToolWithTimer):
+ - Use read instead of sysread to ensure that we don't interfere with
+ other uses of buffered IO in this script.
+ (setFileHandleNonBlocking): Actually set the filehandle to blocking
+ when specified.
+
+2008-04-17 Adam Roben <aroben@apple.com>
+
+ Fix ~10 tests
+
+ * Scripts/run-webkit-tests: Only remove the newline after #EOF, not
+ whatever newline happens to be at the end of what we've read.
+
+2008-04-17 Adam Roben <aroben@apple.com>
+
+ Remove DRT/win's hang timer
+
+ run-webkit-tests takes care of this for us now
+
+ Reviewed by Anders Carlsson.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+
+2008-04-17 Adam Roben <aroben@apple.com>
+
+ Don't wait for the hang timer twice in the case of a hang
+
+ Previously we'd wait for a hang while reading both stdout and stderr
+ from DRT. Now we'll only wait for one or the other.
+
+ Reviewed by Anders Carlsson.
+
+ * Scripts/run-webkit-tests:
+ (top level): Don't wait for stderr to time out if stdout already timed
+ out.
+ (readFromDumpToolWithTimer): If $dontWaitForTimeOut is true, quit
+ after the first read that returns no data.
+
+2008-04-17 Adam Roben <aroben@apple.com>
+
+ Don't throw away the output from timed out tests
+
+ Reviewed by Anders Carlsson.
+
+ * Scripts/run-webkit-tests:
+ (top level): Updated for changes to readFromDumpToolWithTimer.
+ (readFromDumpToolWithTimer): Return a hash that contains both the
+ output and whether or not the test timed out.
+
+2008-04-17 Adam Roben <aroben@apple.com>
+
+ Make the hang timer 60 seconds
+
+ * Scripts/run-webkit-tests:
+
+2008-04-17 Adam Roben <aroben@apple.com>
+
+ Get rid of carriage returns in DRT/win's stderr
+
+ Reviewed by Eric Seidel.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main): Mark stderr as binary like we already do for stdout.
+
+2008-04-17 Adam Roben <aroben@apple.com>
+
+ Fix Bug 17678: run-webkit-tests should have a watchdog timer (and
+ timeout long tests)
+
+ <https://bugs.webkit.org/show_bug.cgi?id=17678>
+
+ We now abort tests that take longer than 60 seconds to produce output.
+ This matches the watchdog timer in DRT/mac and DRT/win (which we can
+ now remove).
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/run-webkit-tests:
+ (top level): Read DRT's output using the new readFromDumpToolWithTimer
+ subroutine. If readFromDumpToolWithTimer returns undefined it means
+ the test timed out, so we register the test as a hang and move on.
+ (sub testCrashedOrTimedOut): Renamed from testCrashed. Now handles
+ both crashed and timed out tests. If the test timed out, we kill DRT
+ before returning.
+ (sub linksForTimedOutTest): Added. We don't have any output to link to for
+ tests that timed out.
+ (sub recordActualResultsAndDiff): Don't call length on undefined.
+ (sub readFromDumpToolWithTimer): Added. Performs non-blocking reads
+ from a filehandle until an #EOF is reached or
+ $maximumSecondsWithoutOutput have elapsed.
+ (sub setFileHandleNonBlocking): Marks a filehandle as blocking or
+ non-blocking.
+
+2008-04-17 Adam Roben <aroben@apple.com>
+
+ Refactor test results page generation
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/run-webkit-tests:
+ (sub htmlForResultsSection): Added. Takes a set of tests, a
+ description, and a subroutine to generate the links for each test, and
+ creates a HTML string containing a table of the tests and their
+ links.
+ (sub linksForExpectedAndActualResults): Added. Replaces the
+ htmlForExpectedAndActualResults subroutine.
+ (sub linksForMismatchTest): Added.
+ (sub linksForCrashOrErrorTest): Added.
+ (sub linksForNewTest): Added.
+
+2008-04-17 Adam Roben <aroben@apple.com>
+
+ Print the extension for all tests in the test results page
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/run-webkit-tests:
+
+2008-04-17 Adam Roben <aroben@apple.com>
+
+ Move code that counts finished tests into a subroutine
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/run-webkit-tests:
+ (sub countFinishedTest): Added.
+
+2008-04-17 Adam Roben <aroben@apple.com>
+
+ Move code that handles a crash into a subroutine
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/run-webkit-tests:
+ (sub testCrashed): Added.
+
+2008-04-17 Eric Seidel <eric@webkit.org>
+
+ Reviewed by hyatt.
+
+ Rename RenderView to RenderViewport in the next rename patch.
+
+ * Scripts/do-webcore-rename:
+
+2008-04-17 Mario Bensi <mbensi@pleyo.com>
+
+ Reviewed by Alp Toker.
+
+ http://bugs.webkit.org/show_bug.cgi?id=18543
+ DumpRenderTree gtk freeze
+
+ fix DumpRenderTree gtk freeze
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump):
+
+2008-04-15 Anders Carlsson <andersca@apple.com>
+
+ Add missing ;
+
+ * Scripts/build-webkit:
+
+2008-04-15 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam.
+
+ Add ENABLE_OFFLINE_WEB_APPLICATIONS to FEATURE_DEFINES.
+
+ * Scripts/build-webkit:
+
+2008-04-15 Andre Poenitz <andre.poenitz@trolltech.com>
+
+ Reviewed by Simon.
+
+ Fix compilation with Qt namespaces
+
+ Qt can be configured to have all of its classes inside a specified namespaces.
+ This is for example used in plugin/component environments like Eclipse.
+
+ This change makes it possible to let the Qt port compile against a namespaced
+ Qt by the use of macros Qt provides to properly forward declare Qt classes in
+ the namespace.
+
+ * DumpRenderTree/qt/DumpRenderTree.h:
+
+2008-04-08 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Darin Adler.
+
+ Add a script that propagates any file changes made to the Bakefiles
+ over to GTK and Qt build systems. Still needs to be wired into
+ those ports though.
+
+ * Scripts/update-sources-list.py: Added.
+
+2008-04-08 Mark Rowe <mrowe@apple.com>
+
+ Clean up after Brady.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm: Add an include so that NSInteger can be found.
+
+2008-04-08 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Mitzpettel
+
+ Fixed http://bugs.webkit.org/show_bug.cgi?id=18302
+ -WebArchive subresources dump in random order, intermittent failures
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (compareResourceURLs): Sorting function based on the resource URLs
+ (serializeWebArchiveToXML): Sort the subresource array
+
+2008-04-07 Brady Eidson <beidson@apple.com>
+
+ OMG, BUILD - please!
+
+ * Scripts/build-webkit:
+
+2008-04-03 Holger Hans Peter Freyther <holger.freyther@trolltech.com>
+
+ Reviewed by Simon.
+
+ * Enable running http tests for Qt again. Failing tests can be put into the skipped list.
+ * Running these tests on windows and other platforms might need some work.
+
+ * Scripts/run-webkit-tests:
+
+2008-04-03 Holger Hans Peter Freyther <holger.freyther@trolltech.com>
+
+ Reviewed by Simon.
+
+ * For the http tests we need the output of the FrameLoaderClient. The QtWebKit API
+ is not exporting enough to create the output in DRT itself. Settle with the approach
+ Lars has taken for the Editing support and add branches to our FrameLoaderClient code.
+ * run-webkit-tests http/tests(/loading) can now be executed.
+ * For tests in loading/ directories we are going to throw away the dirty
+ QWebPage to start with something clean.
+
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+
+2008-04-03 Holger Hans Peter Freyther <holger.freyther@trolltech.com>
+
+ Reviewed by Simon.
+
+ * Treat http and https as special URLs as well. Change the main.cpp and
+ DumpRenderTree.cpp to handle http and https URIs as input.
+ * I'm not doing the clean up and merging of these two checks now.
+
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::readStdin):
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2008-04-03 Holger Hans Peter Freyther <holger.freyther@trolltech.com>
+
+ Reviewed by Simon.
+
+ * Remove dumpFrameLoadCallbacks from simple-subframe.html because it is
+ located in a directory with the name "loading". And this will autoamtically
+ enable dumping.
+ * Remove this method from the LayoutTestController as it is unused now and this
+ avoids adding it to the DRT of the Qt port.
+
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setPrivateBrowsingEnabledCallback):
+
+2008-04-01 Christian Dywan <christian@imendio.com>
+
+ Build fix for GCC 4.3.
+
+ * DumpRenderTree/gtk/WorkQueueItemGtk.cpp: include string.h
+
+2008-04-01 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Holger.
+
+ Fix Qt DRT run by also printing EOF on stderr, as expected by
+ run-webkit-tests.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::dump):
+
+2008-03-31 Julien Chaffraix <julien.chaffraix@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 17665: determineSourceDir() dies if $sourceDir has a trailing backslash
+
+ Remove trailing '/' in $sourceDir in determineSourceDir().
+
+ Fix suggested by Dmitriy Kazachkov.
+
+ * Scripts/webkitdirs.pm:
+
+2008-03-29 Adam Roben <aroben@apple.com>
+
+ Update for rename of an IWebViewPrivate method
+
+ Reviewed by Mitz Pettel.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (createWebViewAndOffscreenWindow):
+
+2008-03-26 Antti Koivisto <antti@apple.com>
+
+ Reviewed by Anders.
+
+ Enable SVG animation support by default.
+
+ * Scripts/build-webkit:
+
+2008-03-25 Adam Roben <aroben@apple.com>
+
+ Windows build fix
+
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+ Add $(WebKitLibrariesDir)\include to the include path so we can find
+ stdint.h there.
+
+2008-03-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark.
+
+ Clean up SVG features message to be less confusing.
+
+ * Scripts/build-webkit:
+
+2008-03-24 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dave Hyatt.
+
+ Add EventSender.zoomPageIn/zoomPageOut support to DRT.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (-[EventSendingController zoomPageIn]):
+ (-[EventSendingController zoomPageOut]):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/win/EventSender.cpp:
+ (textZoomInCallback):
+ (textZoomOutCallback):
+ (zoomPageInCallback):
+ (zoomPageOutCallback):
+
+2008-03-24 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ - update bisect-builds for Safari 3.1
+
+ * Scripts/bisect-builds: Added Safari 3.1 and the corresponding minimal
+ revision, r29711.
+
+2008-03-21 Rodney Dawes <dobey@wayofthemonkey.com>
+
+ Reviewed by Holger.
+
+ http://bugs.webkit.org/show_bug.cgi?id=17981
+
+ Add webcore and javascriptcore cppflags to programs' _CPPFLAGS.
+
+ * GNUmakefile.am:
+
+2008-03-21 Adam Roben <aroben@apple.com>
+
+ Remove a non-working mirror from cygwin-downloader and add the ruby package
+
+ * CygwinDownloader/cygwin-downloader.py:
+ * CygwinDownloader/cygwin-downloader.zip: Updated.
+
+2008-03-20 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Ensure that the defines generated for FEATURE_DEFINES are sorted so that they will match the default settings of each project.
+ This will prevent the world from being rebuilt if you happen to switch between building in Xcode and with build-webkit on the
+ command-line.
+
+ * Scripts/build-webkit:
+
+2008-03-17 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ Fix bogus argCount check breaking plugin test.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+
+2008-03-17 Eric Seidel <eric@webkit.org>
+
+ Reviewed by darin.
+
+ Cleanup PluginObject.cpp and add support for testing
+ converting from int -> identifier -> string
+ and from string -> identifier -> int
+ as well as round-tripping ints and stings through identifiers
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginGetProperty):
+ (pluginSetProperty):
+ (testDOMAccess):
+ (stringVariantToIdentifier):
+ (int32VariantToIdentifier):
+ (doubleVariantToIdentifier):
+ (variantToIdentifier):
+ (testIdentifierToString):
+ (testIdentifierToInt):
+ (testCallback):
+ (getURL):
+ (removeDefaultMethod):
+ (getURLNotify):
+ (testInvokeDefault):
+ (destroyStream):
+ (testEnumerate):
+ (testGetIntIdentifier):
+ (testGetProperty):
+ (testEvaluate):
+ (testGetPropertyReturnValue):
+ (pluginInvoke):
+ (pluginInvokeDefault):
+ (pluginInvalidate):
+ (pluginAllocate):
+ (pluginDeallocate):
+ (handleCallback):
+
+2008-03-16 Kevin Ollivier <kevino@theolliviers.com>
+
+ Rubber stamped by Darin Adler.
+
+ Add set-webkit-configuration support for wx port, and centralize
+ build dir location setting.
+
+ http://bugs.webkit.org/show_bug.cgi?id=17790
+
+ * wx/browser/browser.bkl:
+ * wx/build-wxwebkit:
+
+2008-03-15 Darin Adler <darin@apple.com>
+
+ * Scripts/commit-log-editor: Include the name line of the change log entry.
+ A long time ago I designed this script to not include the name because I
+ thought it was redundant (same as the name of the person checking in), but
+ nowadays it's more common for someone to check something in done by someone
+ else.
+
+ * Scripts/do-webcore-rename: Added some more planned renames and removed
+ some that were already done "by hand".
+
+2008-03-13 Brent Fulgham <bfulgham@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ Correct paths to vsprops files so they use the environment
+ variable, rather than hard-coded path.
+ http://bugs.webkit.org/show_bug.cgi?id=17797.
+
+ * WinLauncher/WinLauncher.vcproj: Correct paths to vsprops.
+
+2008-03-12 Steve Falkenburg <sfalken@apple.com>
+
+ VSExpress build fix
+
+ * WinLauncher/WinLauncher.vcproj:
+
+2008-03-12 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Alp Toker.
+
+ Run testkjs in the correct productsDir in the GTK+ port.
+
+ * Scripts/run-javascriptcore-tests:
+
+2008-03-11 Brent Fulgham <bfulgham@gmail.com>
+
+ Reviewed by Adam Roben.
+
+ Enabled WinLauncher as part of normal Windows build.
+ http://bugs.webkit.org/show_bug.cgi?id=17715.
+
+ * WinLauncher/WinLauncher.vcproj: Update to use vsprops so that
+ it can find the proper libraries to link against.
+
+2008-03-10 Julien Chaffraix <julien.chaffraix@gmail.com>
+
+ Reviewed and landed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=17581
+ Bug 17581: Use of uninitialized value in string ne at WebKitTools/Scripts/run-webkit-tests line 1576.
+
+ Remove the previous warning which occurs when the --random option is used.
+
+ * Scripts/run-webkit-tests: verify that $component[0] is defined before checking for
+ its inequality
+
+2008-03-07 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Done with Lars.
+
+ Ported the netscape test plugin to QWebPluginFactory.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ * DumpRenderTree/qt/main.cpp:
+ * DumpRenderTree/qt/testplugin.cpp:
+ (TestPlugin::plugins):
+ (TestPlugin::create):
+ * DumpRenderTree/qt/testplugin.h:
+
+2008-03-09 Steve Falkenburg <sfalken@apple.com>
+
+ Stop Windows build if an error occurs in a prior project.
+
+ Rubber stamped by Darin Adler.
+
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj:
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+
+2008-03-08 Julien Chaffraix <julien.chaffraix@gmail.com>
+
+ Reviewed by Mark Rowe.
+
+ DRT build fix for Tiger.
+
+ * DumpRenderTree/mac/DumpRenderTreeMac.h: Define BUILDING_ON_TIGER.
+
+2008-03-07 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Fix WebKit build with GCC 4.2.
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm: Use correct argument type in method signature.
+
+2008-03-07 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Oliver.
+
+ Add Windows part of <rdar://problem/5693690>
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dump):
+ (main):
+
+2008-03-07 Alp Toker <alp@atoker.com>
+
+ Back out the r30818, r30819 build fix attempts now the GTK+ build
+ server has been upgraded.
+
+ * Scripts/webkitdirs.pm:
+
+2008-03-07 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Geoff.
+
+ <rdar://problem/5693690> run-webkit-tests swallows STDERR output, including WebCore LEAK messages
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dump): push EOF to stderr after every test
+ * Scripts/run-webkit-tests: collect stderr output and print it
+
+2008-03-07 Steve Falkenburg <sfalken@apple.com>
+
+ Get pdevenv working with Visual Studio Express.
+
+ Reviewed by Adam.
+
+ * Scripts/pdevenv:
+
+2008-03-06 Adele Peterson <adele@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Updated for testing <rdar://problem/5785895> Implement hasFocus() for HTMLDocument (HTML5)
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webViewFocus:]): Remove duplicate code that was also in LayoutTestController::setWindowIsKey
+ (-[UIDelegate webViewUnfocus:]): Added. In Safari, the default is to focus another window if there is one.
+ To easily test cases where the window is unfocused, I made this just call setWindowIsKey(false).
+
+2008-03-06 Matt Lilek <webkit@mattlilek.com>
+
+ Reviewed by Adam Roben.
+
+ Bug 17691: REGRESSION: FindSafari doesn't work
+ http://bugs.webkit.org/show_bug.cgi?id=17691
+
+ Swap my change from r30394 to use the Release libraries instead of Debug
+ since some machines don't have the Debug version.
+
+ * FindSafari/FindSafari.vcproj:
+
+2008-03-06 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Sam and Tim.
+
+ <rdar://5631450> Drosera: breakpoint indicators disappear after the
+ script is finished running.
+ - If there is a pre-existing breakpoint on a line when the file is
+ updated we need to redraw it.
+
+ * Drosera/debugger.js:
+
+2008-03-06 Brady Eidson <beidson@apple.com>
+
+ Tiger build fix...?
+
+ * DumpRenderTree/mac/WatchdogMac.mm:
+
+2008-03-06 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin
+
+ Added a cross-platform Watchdog thread to DRT.
+
+ The current watchdog in both DRTWin and DRTMac is Timer based. Therefore, deadlocks and long running
+ main thread hangs still affect DRT.
+
+ By placing the watchdog on a thread and having DRT "check in" after each test, long-running hangs
+ and true deadlocks can be caught.
+
+ There is one hook for platform specific code. As I did my development and testing on Mac, and Mac has
+ `sample` available, the Mac implementation of this hook samples the process before it is killed.
+
+ I arbitrarily chose 30 seconds as the timeout for now - this can be tweaked easily if we find a need.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/Configurations/Base.xcconfig: Added LINKER_DISPLAYS_MANGLED_NAMES
+
+ * DumpRenderTree/ForwardingHeaders/wtf/Locker.h: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf/Threading.h: Added.
+
+ * DumpRenderTree/Watchdog.cpp: Added.
+ (Watchdog::Watchdog):
+ (Watchdog::~Watchdog):
+ (Watchdog::start):
+ (Watchdog::stop):
+ (Watchdog::checkIn):
+ (Watchdog::setWatchdogInterval):
+ (Watchdog::handleHang):
+ (Watchdog::watchdogThreadStart):
+ (Watchdog::watchdogThread):
+ * DumpRenderTree/Watchdog.h: Added.
+
+ * DumpRenderTree/mac/WatchdogMac.h: Added.
+ * DumpRenderTree/mac/WatchdogMac.mm: Added.
+ (WatchdogMac::handleHang): Sample the process and write it out to a file
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpRenderTree): Setup and start the watchdog before running any tests
+ (runTest): Checkin with the watchdog after each test
+
+2008-03-05 Alp Toker <alp@atoker.com>
+
+ Attempt to get the autotools build working again on the bot with
+ build-webkit.
+
+ Force the use of /bin/bash since we seem to have bash-isms in the
+ configure script right now.
+
+ * Scripts/webkitdirs.pm:
+
+2008-03-05 Alp Toker <alp@atoker.com>
+
+ Re-attempt to switch to the autotools build system for GTK+.
+
+ Change scripts to continue when distclean fails.
+
+ * Scripts/webkitdirs.pm:
+
+2008-03-05 Alp Toker <alp@atoker.com>
+
+ Force qmake for the GTK+ build until we get the build bot to succeed
+ with autotools (currently dies at make distclean)
+
+ * Scripts/webkitdirs.pm:
+
+2008-03-04 Alp Toker <alp@atoker.com>
+
+ Reviewed by Mark Rowe.
+
+ Switch the default GTK+ build system from qmake to autotools.
+
+ qmake can still be used by defining WEBKIT_BUILD_SYSTEM=qmake
+
+ * Scripts/build-webkit:
+ * Scripts/run-launcher:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2008-03-04 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/do-webcore-rename: Update renaming plan.
+
+2008-03-02 Brent Fulgham <bfulgham@gmail.com>
+
+ Reviewed by Alp Toker.
+
+ Remove some needless LIBS.
+
+ * GNUmakefile.am:
+
+2008-03-02 Alp Toker <alp@atoker.com>
+
+ Reviewed by Mark Rowe.
+
+ Split the WebKit GTK+ build out of the WebCore build and change the
+ shared object name to match the package name.
+
+ * GNUmakefile.am:
+
+2008-03-01 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ Update Xcode configuration to support building debug and release from the mysterious future.
+
+ * DumpRenderTree/mac/Configurations/Base.xcconfig:
+
+2008-02-29 David Kilzer <ddkilzer@apple.com>
+
+ Pass the correct configuration switch (--Debug|--Release) to build-testkjs.
+
+ Reviewed by Dan.
+
+ Originally broken in r26838.
+
+ * Scripts/run-javascriptcore-tests: Push configuration switch onto @xcodeArgs
+ not local, unused @args variable.
+
+2008-02-29 David Kilzer <ddkilzer@apple.com>
+
+ Bug 15754: webarchive layout tests fail when WebKit directory path contains symlinks
+
+ <http://bugs.webkit.org/show_bug.cgi?id=15754>
+
+ Reviewed by Geoff and Darin.
+
+ We were using -[NSFileManager currentDirectoryPath] to get the current working directory,
+ then removing that path from all file:/// URLs in the WebArchive output so these tests
+ would pass no matter where they were run.
+
+ The problem was that -[NSFileManager currentDirectoryPath] resolves symlinks in the
+ current working directory, but the WebArchive does not. This left the current working
+ directory in all file:/// URLs in the test output, and thus all tests failed, for any
+ developer that used symlinks to get to their WebKit source directory.
+
+ The fix is to look backwards for "/LayoutTests/" in the URL we're passed, and simply
+ remove the current working directory path (no matter what it is) after "file://" but
+ before "/LayoutTests/".
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (normalizeWebResourceURL): Removed unused oldURLBase argument. We now replace the
+ current working directory as described above.
+ (convertWebResourceResponseToDictionary): Remove unused oldURLBase argument. Update
+ calls to normalizeWebResourceURL().
+ (serializeWebArchiveToXML): Removed now unused cwdURL variable. Update calls to
+ normalizeWebResourceURL() and convertWebResourceResponseToDictionary().
+
+2008-02-26 Robin Dunn <robin@alldunn.com>
+
+ Reviewed by Kevin Ollivier.
+
+ Improvements to the wx build script.
+
+ http://bugs.webkit.org/show_bug.cgi?id=17492
+
+ * wx/build-wxwebkit:
+ - Update the Windows dll copying logic to copy dlls inside WebKitLibraries/win
+ - Allow the build script to properly find wxPython includes under different setups
+ - Make sure WX_PREFIX is set to WXWIN (wxWindows dir environment var.) if not defined
+
+2008-02-26 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/build-webkit: Add --universal and --64-bit flags to make building
+ 64-bit architectures easy. Combine the two flags to build 4-way universal.
+ * Makefile: Add "64" and "64u" make rules. Fix the universal rule to return
+ non-zero when the build failes.
+
+2008-02-26 Jessica Kahn <jess@apple.com>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/gdb-safari: Set WEBKIT_UNSET_DYLD_FRAMEWORK_PATH in gdb's environment,
+ so that Safari inherits it when launched. Preexisting code in WebKit checks this
+ environment variable, and if set, unsets DYLD_FRAMEWORK_PATH, so that applications
+ launched by Safari continue to use the standard system WebKit.
+
+2008-02-25 Adam Roben <aroben@apple.com>
+
+ Fix run-webkit-tests after r30394
+
+ * Scripts/webkitdirs.pm: Never append _debug to FindSafari's
+ executable name.
+
+2008-02-24 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Make some updates based on a trial run of
+ the renaming script.
+
+2008-02-24 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: More renaming plans.
+
+2008-02-23 Jan Michael Alonzo <jmalonzo@unpluggable.com>
+
+ Rubber stamped by Darin Adler.
+
+ Add separator '\' after libJavaScriptCore_la_LIBADD and cleanup
+ whitespaces introduced in the previous commit.
+
+ * GNUmakefile.am:
+
+2008-02-23 Jan Michael Alonzo <jmalonzo@unpluggable.com>
+
+ Rubber-stamped by Darin Adler.
+
+ * GNUmakefile.am: Add both GLOBALDEPS and WEBKITDEPS instead of DEPENDENCIES.
+
+2008-02-23 David Kilzer <ddkilzer@apple.com>
+
+ Please clarify licensing for some files
+ <http://bugs.webkit.org/show_bug.cgi?id=14970>
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp: Added
+ copyright statement. Replaced license with newer Apple BSD-style license.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h: Ditto.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.cpp: Ditto.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.h: Ditto.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp: Ditto.
+ * DumpRenderTree/win/TestNetscapePlugin/main.c: Ditto.
+ * mangleme/LICENSE: Added (LGPL).
+
+2008-02-22 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam.
+
+ <rdar://problem/5748781>
+ https://bugs.webkit.org/show_bug.cgi?id=17413
+ REGRESSION: Latest Nightly doesn't load Java plugin w/Safari 3.1b
+
+ Copy the Java plug-in over to the new location.
+
+ * FindSafari/FindSafari.cpp:
+ (_tmain):
+
+2008-02-22 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam.
+
+ <rdar://problem/5747325> REGRESSION: HTTP layout tests hang
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest):
+ Init the URL request with the correct timeout.
+
+2008-02-21 Mike Auty <mike.auty@gmail.com>
+
+ Reviewed by Alp Toker.
+
+ http://bugs.webkit.org/show_bug.cgi?id=17445
+ [GTK] WebKit doesn't compile with LDFLAGS="-Wl,--as-needed"
+
+ GTK+/autotools build system improvements
+
+ The GNUmakefile.am files make use of the LDFLAGS variable to include library
+ additions such as -ljpeg etc. Unfortunately, if these inclusions aren't made
+ in LIBADD/LDADD variables, then they are mis-ordered during the linking.
+
+ The as-needed flag discards libraries whose functions have not been needed by
+ earlier libraries, which therefore makes the ordering important.
+
+ This moves all -l library inclusion statements from LDFLAGS variables to
+ LIBADD/LDADD variables.
+
+ * GNUmakefile.am:
+
+2008-02-20 Brent Fulgham <bfulgham@gmail.com>
+
+ Reviewed by Alp.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=17428
+ Reenable a Windows-based launcher
+
+ This patch reenables the venerable Spinneret application,
+ changing its name to match the other lanch applications.
+
+ * WinLauncher: Added.
+ * WinLauncher/WinLauncher.cpp: Added.
+ (WinLauncherWebHost::updateAddressBar):
+ (WinLauncherWebHost::QueryInterface):
+ (WinLauncherWebHost::AddRef):
+ (WinLauncherWebHost::Release):
+ (resizeSubViews):
+ (_tWinMain):
+ (MyRegisterClass):
+ (InitInstance):
+ (WndProc):
+ (MyEditProc):
+ (About):
+ (loadURL):
+ * WinLauncher/WinLauncher.h: Added.
+ (WinLauncherWebHost::WinLauncherWebHost):
+ (WinLauncherWebHost::didStartProvisionalLoadForFrame):
+ (WinLauncherWebHost::didReceiveServerRedirectForProvisionalLoadForFrame):
+ (WinLauncherWebHost::didFailProvisionalLoadWithError):
+ (WinLauncherWebHost::didCommitLoadForFrame):
+ (WinLauncherWebHost::didReceiveTitle):
+ (WinLauncherWebHost::didReceiveIcon):
+ (WinLauncherWebHost::didFinishLoadForFrame):
+ (WinLauncherWebHost::didFailLoadWithError):
+ (WinLauncherWebHost::didChangeLocationWithinPageForFrame):
+ (WinLauncherWebHost::willPerformClientRedirectToURL):
+ (WinLauncherWebHost::didCancelClientRedirectForFrame):
+ (WinLauncherWebHost::willCloseFrame):
+ (WinLauncherWebHost::windowScriptObjectAvailable):
+ * WinLauncher/WinLauncher.ico: Added.
+ * WinLauncher/WinLauncher.rc: Added.
+ * WinLauncher/WinLauncher.vcproj: Added.
+ * WinLauncher/resource.h: Added.
+ * WinLauncher/small.ico: Added.
+ * WinLauncher/stdafx.cpp: Added.
+ * WinLauncher/stdafx.h: Added.
+
+2008-02-19 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Geoff
+
+ Fixed a bug in DRT --threaded mode
+
+ * DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp:
+ (startJavaScriptThreads): Don't detach the newly created thread. The later call to stopJavaScriptThreads() tries
+ to pthread_join() each thread that had been created, but you can't join a detached thread!
+
+2008-02-18 Brady Eidson <beidson@apple.com>
+
+ Changes by Geoff Garen, Reviewed by Darin
+
+ Fix for <rdar://5747529> - ObjC Exception can cause JSLock to never be released
+
+ DRT changes for test: platform/mac/plugins/webScriptObject-exception-deadlock.html
+
+ [WebScriptObject valueForKey:] might throw an exception, and previously might have "leaked" the global JSLock
+ This test calls valueForKey, then runs some arbitrary Javascript on a 2ndary thread. If the lock has leaked,
+ this series of method calls will deadlock. If things are good, it will complete successfully.
+
+ * DumpRenderTree/mac/ObjCController.m:
+ (runJavaScriptThread):
+ (+[ObjCController isSelectorExcludedFromWebScript:]):
+ (+[ObjCController webScriptNameForSelector:]):
+ (-[ObjCController testValueForKey]):
+
+2008-02-18 Matt Lilek <webkit@mattlilek.com>
+
+ Reviewed by Adam.
+
+ Remove FindSafari's Release configuration.
+
+ * FindSafari/FindSafari.vcproj:
+
+2008-02-15 Adam Roben <aroben@apple.com>
+
+ Fix a typo that broke the Mac build
+
+ Reviewed by Mark.
+
+ * Scripts/build-webkit:
+
+2008-02-14 Adam Roben <aroben@apple.com>
+
+ Turn on cross-document messaging support by default
+
+ Reviewed by Darin Adler.
+
+ * Scripts/build-webkit:
+
+2008-02-14 Adam Roben <aroben@apple.com>
+
+ Conditionalize cross-document messaging support
+
+ The cross-document messaging parts of HTML 5 are in flux and we want
+ ports to be able to turn off the support as needed.
+
+ Note that the support is turned off by default right now. A subsequent
+ commit will turn it on by default.
+
+ Reviewed by Darin Adler.
+
+ * Scripts/build-webkit:
+
+2008-02-14 Darin Adler <darin@apple.com>
+
+ - fix Windows build
+
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::setStatusText): Update parameter types to match declaration.
+
+2008-02-14 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Geoff G and Weinig.
+
+ Add ability for DRT to report tests setting the status text.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (dumpStatusCallbacksCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:setStatusText:]):
+ * DumpRenderTree/win/UIDelegate.cpp:
+ * DumpRenderTree/win/UIDelegate.h:
+
+2008-02-13 Adam Roben <aroben@apple.com>
+
+ Windows build fix
+
+ * DumpRenderTree/ForwardingHeaders/wtf/MathExtras.h: Added.
+
+2008-02-13 Adam Roben <aroben@apple.com>
+
+ Windows/GTK+ build fix
+
+ * DumpRenderTree/LayoutTestController.cpp: #include MathExtras.h to
+ get isnan.
+
+2008-02-13 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin Adler
+
+ Add some much needed Database support to DRT
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (dumpDatabaseCallbacksCallback): Flag to control if the UIDelegate methods related to
+ databases are called
+ (clearAllDatabasesCallback): Allow a test to delete all databases
+ (setDatabaseQuotaCallback): Allow a test to set the quota new origins will get
+ (LayoutTestController::staticFunctions):
+
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::dumpDatabaseCallbacks):
+ (LayoutTestController::setDumpDatabaseCallbacks):
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::clearAllDatabases):
+ (LayoutTestController::setDatabaseQuota):
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::clearAllDatabases): Stubbed out
+ (LayoutTestController::setDatabaseQuota): Ditto
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::clearAllDatabases): Stubbed out with error message
+ (LayoutTestController::setDatabaseQuota): Ditto
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:]): Print a
+ message with details about the event then return a 5mb quota like before
+
+
+2008-02-12 Steve Falkenburg <sfalken@apple.com>
+
+ Changes to support merged MIDL output.
+
+ All COM interfaces are now generated to WebKit.h.
+
+ Reviewed by Sam, Ada.
+
+ * Drosera/win/BaseDelegate.h:
+ * Drosera/win/DebuggerClient.cpp:
+ * Drosera/win/DebuggerDocumentPlatform.cpp:
+ * Drosera/win/Drosera.cpp:
+ * Drosera/win/ServerConnection.cpp:
+ * Drosera/win/ServerConnection.h:
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ * DumpRenderTree/win/EditingDelegate.h:
+ * DumpRenderTree/win/EventSender.cpp:
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+ * DumpRenderTree/win/GCControllerWin.cpp:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ * DumpRenderTree/win/PolicyDelegate.h:
+ * DumpRenderTree/win/ResourceLoadDelegate.h:
+ * DumpRenderTree/win/UIDelegate.cpp:
+ * DumpRenderTree/win/UIDelegate.h:
+ * DumpRenderTree/win/WorkQueueItemWin.cpp:
+
+2008-02-10 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ - fix a memory leak
+
+ * DumpRenderTree/cg/ImageDiffCG.cpp:
+ (getDifferenceBitmap): Use a static CFMutableData instead of allocating
+ and leaking the buffer each time.
+
+2008-02-07 Adam Roben <aroben@apple.com>
+
+ Fix error in bisect-builds when responding "broken" for the first
+ build
+
+ Reviewed by Dave Kilzer.
+
+ * Scripts/bisect-builds: Only try to test the build if the nightly
+ info for the current index has not been deleted.
+
+2008-02-07 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Fixed two minor typos in the --root option, to get it working.
+
+ * Scripts/run-sunspider:
+ 1. Actually assign the function argument to our local variable.
+ 2. Actually set the $root variable, so we don't try to build later.
+
+2008-02-05 Oliver Hunt <oliver@apple.com>
+
+ RS=Eric.
+
+ Re-enable foreignObject by default as it is needed for a number of non-fO
+ related SVG tests and none of the old known crashes occur anymore.
+
+ * Scripts/build-webkit:
+
+2008-02-05 Steve Falkenburg <sfalken@apple.com>
+
+ Build fix. Don't override intermediate directory.
+
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj:
+
+2008-02-05 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Build fix for Windows. willCloseFrame is a pure virtual and we are
+ forced to have an implementation.
+
+ This partially reverts r30014.
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::willCloseFrame):
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+
+2008-02-05 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Holger.
+
+ Don't build wrapper for SVGTestCase.js (special file for svg/dynamic-updates)
+
+ * Scripts/make-js-test-wrappers:
+
+2008-02-05 Holger Freyther <zecke@selfish.org>
+
+ Reviewed by Darin Adler.
+
+ In http://bugs.webkit.org/show_bug.cgi?id=16853 it was identified that the
+ the output of the willCloseFrame and didClearWindowObject FrameLoadDelegate
+ depends on the order the tests are executed.
+
+ Propose to remove willCloseFrame and didlCearWindowObject output from the
+ FrameLoadDelegate and update the test results. The output of didClearWindowObject
+ is not interesting for any of the current tests and we have other ways to find
+ out if a frame was closed or not.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::didClearWindowObject):
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+
+2008-02-04 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Workaround for http://bugs.webkit.org/show_bug.cgi?id=16842
+ Bug 16842: Hang in DRT in leaks mode due to signal handler doing unsafe things
+
+ Don't install the signal handler unless we are running the pixel tests.
+ It is currently only used to restore the color profile, but by catching
+ signals we can trigger a deadlock in DRT while running leak tests.
+ The deadlock is tracked by http://bugs.webkit.org/show_bug.cgi?id=16842,
+ and a more complete fix will need to be developed to address this for
+ pixel tests as well.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpRenderTree):
+
+2008-02-04 Mark Rowe <mrowe@apple.com>
+
+ Gtk qmake build fix.
+
+ * Scripts/webkitdirs.pm: Fix perl's complaint about an odd number of elements in anonymous hash.
+
+2008-02-04 Jan Michael Alonzo <jmalonzo@unpluggable.com>
+
+ Reviewed by Alp Toker and Mark Rowe.
+
+ http://bugs.webkit.org/show_bug.cgi?id=16618
+ [GTK] build-webkit and run-webkit-tests autootools support
+
+ * Scripts/build-webkit: added --database and --icon-database options
+ * Scripts/run-launcher:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2008-02-04 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Steve F.
+
+ Partial fix for <rdar://5621244> Drag & Drop doesn't work correctly in DRT
+
+ Implement required DRT functionality to allow majority of Drag and Drop testcases to work.
+ Issues include:
+ * Uses Sleep() to implement leapForward reliably.
+ * 3 DND tests still fail for reasons that i have not yet determined
+ * Has to explicitly ignore an extraneous WM_MOUSELEAVE that i am at a loss to explain
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (leapForwardCallback):
+ (mouseDownCallback):
+ (doMouseUp):
+ (mouseUpCallback):
+ (doMouseMove):
+ (mouseMoveToCallback):
+ Minor updates to these functions to handle the different message queue structure.
+
+ (replaySavedEvents):
+ More complicated now. Where possible we just use the old while-loop model of execution,
+ but when leapForward has been used we have to jump through some hoops and set up an
+ inner event loop so that we can ensure messages get the correct time stamp.
+
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::doDragDrop):
+ Call replaySavedEvents directly to force synchronous handling of drag and drop.
+
+2008-02-04 Rodney Dawes <dobey@wayofthemonkey.com>
+
+ Reviewed by Alp Toker and Mark Rowe.
+
+ Fix http://bugs.webkit.org/show_bug.cgi?id=17175.
+ Bug 17175: Use of C++ compiler flags in CFLAGS
+
+ * GNUmakefile.am: Use global_cxxflags as well as global_cflags in CXXFLAGS.
+
+2008-02-04 Darin Adler <darin@apple.com>
+
+ Reviewed by Geoff.
+
+ * Scripts/make-js-test-wrappers: Look at the whole LayoutTests tree, not just the fast
+ and svg subdirectories. Added some more exceptions for the benefit of the fast/dom
+ subdirectory.
+
+2008-02-04 Adam Roben <aroben@apple.com>
+
+ Windows Apple-only build fix
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Added a new include
+ directory.
+
+2008-02-04 Alp Toker <alp@atoker.com>
+
+ Rubber-stamped by Mark Rowe.
+
+ Remove all trailing whitespace in the GTK+ port and related
+ components.
+
+ * DumpRenderTree/gtk/DumpRenderTreeGtk.h:
+ * DumpRenderTree/gtk/GCControllerGtk.cpp:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ * GNUmakefile.am:
+
+2008-02-01 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Oliver.
+
+ Also search LayoutTests/svg for js-based tests.
+
+ * Scripts/make-js-test-wrappers:
+
+2008-01-31 Alp Toker <alp@atoker.com>
+
+ Rubber-stamped by Adam Roben.
+
+ http://bugs.webkit.org/show_bug.cgi?id=17006
+ [GTK] Header path should be webkit/webkit.h
+
+ Move the GTK+ API sources as needed and update the build systems.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ * DumpRenderTree/gtk/DumpRenderTreeGtk.h:
+ * DumpRenderTree/gtk/WorkQueueItemGtk.cpp:
+ * GNUmakefile.am:
+ * GtkLauncher/main.c:
+
+2008-01-30 Stephanie <slewis@apple.com>
+
+ Reviewed by Geoff.
+
+ Add an option to run-webkit-tests to merge leaks results and print the number of unique leaks found under a certain call depth. This should make it easier for the buildbots to track new leaks.
+
+ * Scripts/run-webkit-tests:
+
+2008-01-30 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ One more debug (external) fix.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp: TestNetscapePlugin is built with a _debug suffix in both DebugInternal
+ and Debug configurations.
+
+2008-01-29 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Sam Weinig. Sam Weinig.
+
+ Fixed <rdar://problem/5692566> fast/encoding/mailto-always-utf-8.html
+ fails when run after fast/dom/Window/window-property-shadowing.html (16902)
+
+ Modified our policy delegates not to output window.name. Since a
+ previous test may have explicitly set window.name, we can't rely on its
+ implicit value in test results.
+
+ * DumpRenderTree/mac/PolicyDelegate.mm:
+ (-[PolicyDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]):
+
+ * DumpRenderTree/win/PolicyDelegate.cpp:
+ (PolicyDelegate::decidePolicyForNavigationAction):
+
+2008-01-29 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ <rdar://problem/5600926> WebCore on Tiger must link to its own copy of SQLite 3.4 or newer (so HTML database behavior will be correct).
+
+ * Scripts/build-webkit: Copy SQLite static library and headers into the build directory.
+
+2008-01-29 David Kilzer <ddkilzer@apple.com>
+
+ Refactor ChangeLog path code
+
+ Reviewed by Adam.
+
+ * Scripts/prepare-ChangeLog: Simplify code in one foreach() loop, and extract
+ duplicate code in another foreach() loop.
+
+2008-01-29 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ <rdar://problem/5710692> All storage tests fail/crash
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:frame:exceededDatabaseQuotaForSecurityOrigin:database:]): Set an
+ arbitrary quota of 5 megabytes.
+
+ (-[UIDelegate webView:frame:quotaForSecurityOrigin:toCreateDatabase:withEstimatedSize:]):
+ (-[UIDelegate webView:frame:quotaForSecurityOrigin:fromProposedQuota:database:]):
+ Removed unused (I think) code.
+
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::QueryInterface): IWebUIDelegatePrivate3 is now supported.
+ (UIDelegate::webViewPainted): A stub implementation.
+ (UIDelegate::exceededDatabaseQuota): Set an arbitrary quota of 5 megabytes.
+ * DumpRenderTree/win/UIDelegate.h:
+
+2008-01-27 Jan Michael Alonzo <jmalonzo@unpluggable.com>
+
+ GTK+ DRT build fix for breakage introduced in r29822.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setPersistentUserStyleSheetLocation):
+ (LayoutTestController::clearPersistentUserStyleSheet):
+
+2008-01-27 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - add support for directory prologues and epilogues to run-webkit-tests
+ - allow setting a persistent user style sheet in DumpRenderTree
+ - activate the WebKit Layout Tests font in Windows DumpRenderTree
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (clearPersistentUserStyleSheetCallback): Added.
+ (setPersistentUserStyleSheetLocationCallback): Added.
+ (LayoutTestController::staticFunctions): Added.
+ clearPersistentUserStyleSheet and setPersistentUserStyleSheet.
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (setPersistentUserStyleSheetLocation): Added.
+ (resetWebViewToConsistentStateBeforeTesting): Added the user style sheet
+ to the set of things this function resets. Now it either disables the
+ user style sheet or sets it to the persistent user style sheet and
+ enables it.
+ * DumpRenderTree/mac/DumpRenderTreeMac.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setPersistentUserStyleSheetLocation): Added.
+ (LayoutTestController::clearPersistentUserStyleSheet): Added.
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (setPersistentUserStyleSheetLocation): Added.
+ (initialize): Added the WebKit Layout Tests font to the set of fonts to
+ install.
+ (resetWebViewToConsistentStateBeforeTesting): See DumpRenderTree.mm.
+ * DumpRenderTree/win/DumpRenderTreeWin.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setPersistentUserStyleSheetLocation): Added.
+ (LayoutTestController::clearPersistentUserStyleSheet): Added.
+ * Scripts/run-webkit-tests: Changed to look for, and if found process in
+ DumpRenderTree, files named run-webkit-tests-prologue.html and
+ run-webkit-tests-epilogue.html in the resources subdirectory of any
+ test directory and platform test results directory. The prologues are
+ processed before the first test from the directory (and its
+ subdirectories) is run, and the epilogues are processed after the last
+ test from the directory is run. Platform-specific prologues and
+ epilogues are processed in order of specificity.
+
+2008-01-25 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ <rdar://problem/5699933> http/tests/security/cross-frame-access-get.html is still failing
+
+ * DumpRenderTree/win/DumpRenderTree.cpp: (main): Clear HTTP cache to ensure consistent test environment
+ (matching Mac DRT).
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Link to CFNetwork.
+
+2008-01-24 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Ada Chan.
+
+ Fix for <rdar://5131975> DumpRenderTree doesn't support undo/redo
+
+ - Adds simplified UndoManager to windows DRT to allow testing the
+ undo/redo code paths in WebCore and WebKit. This is a temporary
+ solution to an issue that should eventually be solved by having a
+ shared UndoManager in WebKit.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest):
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (DRTUndoObject::DRTUndoObject):
+ (DRTUndoObject::invoke):
+ (DRTUndoStack::~DRTUndoStack):
+ (DRTUndoStack::isEmpty):
+ (DRTUndoStack::clear):
+ (DRTUndoStack::push):
+ (DRTUndoStack::pop):
+ (DRTUndoManager::canRedo):
+ (DRTUndoManager::canUndo):
+ (DRTUndoManager::DRTUndoManager):
+ (DRTUndoManager::removeAllActions):
+ (DRTUndoManager::registerUndoWithTarget):
+ (DRTUndoManager::redo):
+ (DRTUndoManager::undo):
+ (UIDelegate::UIDelegate):
+ (UIDelegate::resetUndoManager):
+ (UIDelegate::registerUndoWithTarget):
+ (UIDelegate::removeAllActionsWithTarget):
+ (UIDelegate::setActionTitle):
+ (UIDelegate::undo):
+ (UIDelegate::redo):
+ (UIDelegate::canUndo):
+ (UIDelegate::canRedo):
+ * DumpRenderTree/win/UIDelegate.h:
+
+2008-01-23 Adam Roben <aroben@apple.com>
+
+ Allow directories containing ChangeLogs to be passed to
+ resolve-ChangeLogs
+
+ Reviewed by David Kilzer.
+
+ * Scripts/resolve-ChangeLogs:
+ (sub findChangeLog): Return a ChangeLog contained within the specified
+ directory if one exists.
+
+2008-01-23 Steve Falkenburg <sfalken@apple.com>
+
+ <rdar://problem/5698732> Copyright strings should include 2008
+
+ Reviewed by Sam.
+
+ * Drosera/win/Drosera.vcproj/Drosera.rc:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.rc:
+
+2008-01-23 Alp Toker <alp@atoker.com>
+
+ Rubber-stamped by Mark Rowe.
+
+ Remove whitespace after -I in automake include lists.
+
+ * GNUmakefile.am:
+
+2008-01-23 Michael Goddard <michael.goddard@trolltech.com>
+
+ Reviewed by Lars Knoll <lars@trolltech.com>.
+
+ Reworked the JavaScriptCore Qt bindings:
+
+ * Update JS DRT controller for Qt JS binding changes.
+ There were two functions that needed some changes
+ so that the layout tests would work, so this makes
+ a few tests pass again.
+
+ * Bump the timeout for layout tests up to 11s.
+ At least some tests have an internal timeout of
+ 10 seconds, so make the waitUntilDone approach
+ wait at least 11s. fast/dom/open-and-close-by-DOM.html
+ is one of these - now the failure message is more
+ accurate.
+
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::waitUntilDone):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2008-01-22 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Darin and Adam.
+
+ <rdar://problem/5688975>
+ div element on microsoft site has wrong left offset.
+
+ Add new method for testing the return vale of NPN_GetProperty.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginInvoke):
+
+2008-01-22 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ <rdar://problem/5670257> editing/selection/4895428-3.html makes editing/selection/5131716-2.html fail
+
+ * DumpRenderTree/win/EventSender.cpp: (makeEventSender): Reset static variables for a new test.
+
+2008-01-21 Jan Michael Alonzo <jmalonzo@unpluggable.com>
+
+ Reviewed by Alp Toker.
+
+ http://bugs.webkit.org/show_bug.cgi?id=16955
+ Get errors when cross-compile webkit-gtk
+
+ * GNUmakefile.am: Removed ICU_CFLAGS
+
+2008-01-21 Darin Adler <darin@apple.com>
+
+ Reviewed by Mitz and Adam.
+
+ * Scripts/svn-create-patch: Sort ChangeLog files first. Also slightly improved the
+ sorting speed by doing all sort criteria in a single pass instead of three sorts.
+
+2008-01-21 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Holger.
+
+ Fix focus chain handling and cycling through focusable objects (links) using tab/backtab.
+
+ * Fix GraphicsContext::drawFocusRing to also draw single focus rects.
+ * Implemented QWebPage::focusNextPrevChild by sending fake tab/shift-tab events
+ and make the return value depend on whether we successfully determined a focusable
+ node or not.
+ * Changed QWebView::focusNextPrevChild() to call the base QWidget implementation correctly
+ if we could not handle the focus chain ourselves.
+ * Changed the focus policy of QWebView to correctly use WheelFocus instead of ClickFocus.
+ * Made ChromeClientQt::canTakeFocus() and takeFocus() dummy method since they are only
+ used to control the situation of stepping out of the focus chain inside the page.
+ * Made inclusion of links in the focus chain configurable through QWebSettings::LinksIncludedInFocusChain.
+ The layout tests expect this to be disabled but for the user it seems sensible to have it
+ on by default, hence the default in qwebsettings.cpp
+
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+
+2008-01-19 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Alp Toker.
+
+ Allow the --http flag to run-webkit-tests to override
+ the default behaviour of disabling HTTP tests for Qt,
+ Gtk and Wx.
+
+ * Scripts/run-webkit-tests:
+
+2008-01-19 David Kilzer <ddkilzer@apple.com>
+
+ <rdar://problem/5695344> check-for-global-initializers script never checks any object files
+
+ Reviewed by Darin Adler.
+
+ We now touch a check-for-global-initializers.timestamp file in
+ the TARGET_TEMP_DIR directory to determine when new object files
+ have been compiled and thus need to be checked. If the timestamp
+ file doesn't exist, all object files will be checked.
+
+ Previously the modification time of the "executable" (the
+ framework binary, e.g., WebKit.framework/WebKit) was used, but
+ since this was the last file modified at the end of the compile
+ phase, no object files would ever get checked!
+
+ Also added JSCustomSQLTransactionCallback.o to the list of files
+ since it has static initializers in Debug builds of WebCore.
+
+ * Scripts/check-for-global-initializers:
+
+2008-01-18 Adam Roben <aroben@apple.com>
+
+ Build fix
+
+ * Scripts/build-webkit:
+
+2008-01-18 Beth Dakin <bdakin@apple.com>
+
+ Reviewed by Oliver.
+
+ Update build-webkit to account for foreign-object being disabled by
+ default.
+
+ * Scripts/build-webkit:
+
+2008-01-18 Adam Roben <aroben@apple.com>
+
+ Updated for method renames
+
+ Reviewed by Adele.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate webView:didCommitLoadForFrame:]):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setMainFrameIsFirstResponder):
+ (LayoutTestController::setWindowIsKey):
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webViewFocus:]):
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::didCommitLoadForFrame):
+
+2008-01-18 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Fix plugin-related tests in Debug_Internal configuration, which are failing because of CRT version mismatch
+ between DRT and TestNetscapePlugin.
+
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj: Added a Debug_Internal configuration.
+ * DumpRenderTree/DumpRenderTree.sln: Use this configuration.
+
+2008-01-18 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Holger.
+
+ Fix fast/dom/Window/window-resize.html
+
+ In DRT connect the page's geometryChangeRequest signal to a slot that
+ sets the geometry of the view widget.
+
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::setViewGeometry):
+ (WebCore::WebPage::WebPage):
+
+2008-01-17 Steve Falkenburg <sfalken@apple.com>
+
+ Build fix.
+
+ * Drosera/DroseraWin.make:
+
+2008-01-17 Darin Adler <darin@apple.com>
+
+ * Scripts/run-webkit-tests: Fixed a bug number.
+
+2008-01-17 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ http://bugs.webkit.org/show_bug.cgi?id=16908
+ run-webkit-tests complains about missing FindSafari.exe
+
+ * Scripts/webkitdirs.pm: Append _debug as appropriate.
+
+2008-01-17 Steve Falkenburg <sfalken@apple.com>
+
+ Re-add DEBUG_WEBKIT_HAS_SUFFIX.
+
+ Rubber-stamped by Jon Honeycutt.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+2008-01-16 Alp Toker <alp@atoker.com>
+
+ Reviewed by Mark Rowe.
+
+ http://bugs.webkit.org/show_bug.cgi?id=16218
+ [GTK] API: Should this entry point be called go_back rather than go_backward?
+
+ Track back/forward API changes in the tools.
+
+ * DumpRenderTree/gtk/WorkQueueItemGtk.cpp:
+ (BackForwardItem::invoke):
+ * GtkLauncher/main.c:
+ (go_back_cb):
+
+2008-01-16 Adam Roben <aroben@apple.com>
+
+ Windows build fix after r29488
+
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+ Build into a subdirectory of $WebKitOutputDir\bin to match where DRT
+ expects to find the plugin.
+
+2008-01-11 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Fixed the waitUntilDone watchdog timer -- the old code never added the
+ timer to the run loop, so it didn't do anything.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setWaitToDump):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setWaitToDump):
+
+2008-01-14 Steve Falkenburg <sfalken@apple.com>
+
+ Use shared vsprops for most vcproj properties.
+
+ Reviewed by Darin Adler.
+
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj:
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+ * FindSafari/FindSafari.vcproj:
+
+2008-01-14 Stephanie <slewis@apple.com>
+
+ Reviewed by NOBODY.
+
+ revert accidental character.
+
+ * Scripts/run-webkit-tests:
+
+2008-01-14 Stephanie <slewis@apple.com>
+
+ RS=Oliver
+
+ add Quicktime PPC only leaks to Leopard exclude list. See <rdar://problem/5667132>
+
+ * Scripts/run-webkit-tests:
+
+2008-01-14 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Queue up another rename.
+
+2008-01-14 Holger Hans Peter Freyther <holger.freyther@trolltech.com>
+
+ Reviewed by Darin Adler.
+
+ * Allow to run the tests in reverse order to spot test cases where the result depends on the order
+ the tests were ran.
+ * This is from http://bugs.webkit.org/show_bug.cgi?id=16869
+
+ * Scripts/run-webkit-tests:
+
+2008-01-14 Holger Hans Peter Freyther <holger.freyther@trolltech.com>
+
+ Reviewed by Darin Adler.
+
+ * Randomize tests array to spot test cases where the results depends on the order
+ the tests are ran.
+ * This is from http://bugs.webkit.org/show_bug.cgi?id=16869
+
+ * Scripts/run-webkit-tests:
+
+2008-01-14 Darin Adler <darin@apple.com>
+
+ * Scripts/run-webkit-tests: More ignore list tweaking.
+
+2008-01-14 Darin Adler <darin@apple.com>
+
+ * Scripts/run-webkit-tests: Add another leak to the ignore list.
+
+2008-01-14 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Adam Roben.
+
+ - try to fix failure in fast/dom/Window/window-onFocus.html seen on the
+ build bots
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting): Focus the web view.
+
+2008-01-13 Steve Falkenburg <sfalken@apple.com>
+
+ Share common files across projects.
+
+ Unify vsprops files
+ Debug: common.vsprops, debug.vsprops
+ Debug_Internal: common.vsprops, debug.vsprops, debug_internal.vsprops
+ Release: common.vsprops, release.vsprops
+
+ Shared properties can go into common.vsprops, shared debug settings can go into debug.vsprops.
+ debug_internal.vsprops will be mostly empty except for file path prefix modifiers.
+
+ Pull auto-version.sh, VERSION, and PRODUCTVERSION from tools.
+
+ Reviewed by Adam Roben.
+
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj:
+ * Drosera/win/Drosera.vcproj/PRODUCTVERSION: Removed.
+ * Drosera/win/Drosera.vcproj/VERSION: Removed.
+ * Drosera/win/Drosera.vcproj/auto-version.sh: Removed.
+ * Drosera/win/Drosera.vcproj/debug.vsprops: Removed.
+ * Drosera/win/Drosera.vcproj/debug_internal.vsprops: Removed.
+ * Drosera/win/Drosera.vcproj/release.vsprops: Removed.
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/win/debug.vsprops: Removed.
+ * DumpRenderTree/win/debug_internal.vsprops: Removed.
+ * DumpRenderTree/win/release.vsprops: Removed.
+
+2008-01-13 Brent Fulgham <bfulgham@gmail.com>
+
+ Reviewed by Maciej.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=16314
+ Script to launch Drosera
+
+ * Scripts/gdb-drosera: Added.
+ * Scripts/run-drosera: Added.
+ * Scripts/run-drosera-nightly.cmd: Added.
+ * Scripts/webkitdirs.pm: Added runDrosera function.
+
+2008-01-13 Dan Bernstein <mitz@apple.com>
+
+ - fix breakage due to last-minute change
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest): Declare the loop variable.
+
+2008-01-13 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Adam Roben.
+
+ - fix <rdar://problem/5132009> Windows DRT does not support multiple windows
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (DumpRenderTreeWndProc):
+ (initialize):
+ (dumpBackForwardList):
+ (dumpBackForwardListForAllWindows):
+ (dump):
+ (resetWebViewToConsistentStateBeforeTesting): Factored out of
+ runTest().
+ (runTest):
+ (allWindows): Added. Returns a vector of all open windows.
+ (windowToWebViewMap): Added. Returns a map from open windows to their
+ WebViews.
+ (createWebViewAndOffscreenWindow): Factored out of main() to be
+ reusable for creating extra windows.
+ (main):
+ * DumpRenderTree/win/DumpRenderTreeWin.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::windowCount): Implemented.
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::createWebViewWithRequest): Implemented.
+ (UIDelegate::webViewClose): Implemented.
+ * DumpRenderTree/win/UIDelegate.h:
+
+2008-01-12 Alp Toker <alp@atoker.com>
+
+ Reviewed by Mark Rowe.
+
+ Hide non-public symbols in GTK+/autotools release builds.
+
+ * GNUmakefile.am:
+
+2008-01-12 Holger Hans Peter Freyther <holger.freyther@trolltech.com>
+
+ Reviewed by Ap.
+
+ * Make launching of the WebKit httpd work on GNU/Debian/Linux
+
+ The configuration of Apache2 and installation does not depend on
+ the kernel but on the distribution policy. Make launching of httpd
+ work for Debian derived distributions.
+
+ * Scripts/run-webkit-httpd:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2008-01-12 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Fix crash in http/tests/security/local-JavaScript-from-remote.html under guard malloc.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm: Retain string before returning it to
+ match the callers expectations that it can take ownership of the string.
+
+2008-01-11 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ <rdar://problem/5667275> fast/dynamic/layer-hit-test-crash.html is failing
+
+ * DumpRenderTree/win/DumpRenderTree.cpp: (runTest): Ignore WM_MOUSELEAVE events,
+ as these are only posted because the test window is not a normal visible one, and
+ they confuse drag&drop machinery.
+
+2008-01-11 Adam Roben <aroben@apple.com>
+
+ Fix a crash when pathToLocalResource fails and a leak
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (pathToLocalResourceCallback): Dont leak the JSStringRef, and make
+ sure not to pass null to JSValueMakeString.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::pathToLocalResource): Print an error message if
+ the conversion fails so it's clear what happened.
+
+2008-01-11 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by John Sullivan.
+
+ * DumpRenderTree/mac/GCControllerMac.mm:
+ (GCController::collectOnAlternateThread): Updated for name change.
+
+2008-01-10 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Don't build dftables any longer since it's now a Perl
+ script.
+
+ * wx/build-wxwebkit:
+
+2008-01-10 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Make DRT track open windows instead of allocated windows so that
+ we can avoid ASSERTION due to late deallocs out of our control.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpBackForwardListForAllWindows):
+ (runTest):
+ * DumpRenderTree/mac/DumpRenderTreeMac.h:
+ * DumpRenderTree/mac/DumpRenderTreeWindow.h:
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ (+[DumpRenderTreeWindow openWindows]):
+ (-[DumpRenderTreeWindow initWithContentRect:styleMask:backing:defer:]):
+ (-[DumpRenderTreeWindow close]):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::windowCount):
+
+2008-01-10 Ada Chan <adachan@apple.com>
+
+ Meta key is not the same as Alt key on windows.
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback):
+
+2008-01-09 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Darin, Sam and Adam.
+
+ -<rdar://problem/5654486> REGRESSION (Safari 3.0.4-TOT): clicking on
+ link in gmail message displays JavaScript alert falsely complaining
+ about pop-up blocking.
+ - Added the ability to enable the pop-up blocker via the
+ LayoutTestController.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setPopupBlockingEnabledCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (setDefaultsToConsistentValuesForTesting):
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setPopupBlockingEnabled):
+
+2008-01-10 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ rename QWebPageHistory to QWebHistory.
+
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+
+2008-01-09 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - add some more renames, adjust some
+
+ * Scripts/do-webcore-rename:
+
+2008-01-07 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Oliver.
+
+ Enable SVG Fonts support by default.
+
+ * Scripts/build-webkit:
+
+2008-01-07 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Adam.
+
+ Fixes: http://bugs.webkit.org/show_bug.cgi?id=16244
+ DRT doesn't handle platform specific pixel test results correctly.
+
+ <test>-expected.txt files and <test>-expected.png files may now live
+ in different directories (ie. a cross-platform <test>-expected.txt file
+ and a platform-specific <test>-expected.png file).
+
+ * Scripts/run-webkit-tests:
+
+2008-01-04 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - <rdar://problem/5666914> fast/regex/test{1,4}.html are failing
+ DRT did not correctly handle printing the '\0' char. Now it does.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dumpFramesAsText):
+ (dump):
+
+2008-01-07 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Lars.
+
+ Ported of the network backend of the Qt platform to Qt 4.4's new networking API.
+
+
+ * DumpRenderTree/qt/main.cpp:
+ * DumpRenderTree/qt/testplugin.cpp:
+ * DumpRenderTree/qt/testplugin.h:
+
+2008-01-05 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Alp Toker.
+
+ Fix hang in fast/frames/frame-display-none-focus.html during Gtk layout tests.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (processWork): Process pending work.
+ (webViewLoadFinished): Schedule processing of pending work.
+ * DumpRenderTree/gtk/WorkQueueItemGtk.cpp: Use webkit_web_frame_reload.
+
+2008-01-05 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Some more renaming plans.
+
+2008-01-04 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Alexey and Darin.
+
+ Adding "home" and "end" to DRT's keydown since
+ DOM key events can't handle keyIdentifiers at this point.
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController keyDown:withModifiers:]):
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback):
+
+2008-01-04 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ fix DRT after the changes to QWebPage.
+
+ The great thing is that we actually don't have
+ any regressions from the QWebPage change :)
+
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2008-01-04 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ make QWebPage a QObject and get things to compile.
+
+ Nothing works currently though.
+
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2008-01-04 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ take a QString as identifier in QWebFrame::addToJSWindowObject.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::initJSObjects):
+
+2008-01-04 Alp Toker <alp@atoker.com>
+
+ GTK+ DRT build fix for breakage introduced in r29149.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::execCommand):
+
+2008-01-03 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ <rdar://problem/5463489> A number of layout tests should be using execCommand instead of textInputController
+
+ Added layoutTestController.execCommand to access editor commands that are not available
+ via document.execCommand.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (execCommandCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::execCommand):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::queueLoad):
+ (LayoutTestController::execCommand):
+
+2008-01-03 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Darin, Mitz.
+
+ fixed <rdar://5130762> mousedowns in different locations increase the clickcount incorrectly
+
+ the clickcount should not increase if the last click was at a different location. it's a new click.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (runTest):
+ * DumpRenderTree/mac/EventSendingController.h:
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController mouseDown]):
+ (-[EventSendingController mouseUp]):
+
+2008-01-03 Darin Adler <darin@apple.com>
+
+ Reviewed by Adam.
+
+ * Scripts/update-webkit: Make this work a little better for the people at Apple
+ who have a directory named Internal.
+
+2008-01-03 Adam Roben <aroben@apple.com>
+
+ Use HTTP::Date instead of Date::Parse because it's installed by Cygwin by default
+
+ Rubberstamped by Mark.
+
+ * Scripts/update-webkit-auxiliary-libs:
+
+2008-01-03 Adam Roben <aroben@apple.com>
+
+ Fix Bug 15663: update-webkit re-downloads WebKitAuxiliaryLibrary unnecessarily
+
+ http://bugs.webkit.org/show_bug.cgi?id=15663
+
+ Added a fuzz factor into the Last-Modified comparison for downloading
+ WebKitAuxiliaryLibrary.zip.
+
+ The zip file is served from a set of mirrors who give Last-Modified
+ times that are off by 1-3 seconds from each other. This was causing
+ the build bots to redownload WebKitAuxiliaryLibrary for every build,
+ which would then cause all of WebCore to rebuild each time.
+
+ Reviewed by Mark.
+
+ * Scripts/update-webkit-auxiliary-libs: Check if the new zip file is
+ at least 30 seconds newer than the old one -- otherwise we assume that
+ the difference in time is due to the mirrors being slightly offset
+ from each other.
+ (sub lastModifiedToUnixTime): Added.
+
+2008-01-03 Alexey Proskuryakov <ap@webkit.org>
+
+ Windows build fix.
+
+ * DumpRenderTree/ForwardingHeaders/wtf/HashTraits.h: Added (needed by COMPtr.h).
+
+2008-01-03 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Lars.
+
+ Moved QWebPage::open to QWebFrame::load and added setHtml.
+
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::open):
+
+2008-01-03 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Lars.
+
+ Added the first revision of QWebView and started moving functionality from QWebPave over to QWebView and QWebFrame.
+
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2008-01-02 Sam Weinig <sam@webkit.org>
+
+ * Scripts/do-webcore-rename: Yet more renaming ideas.
+
+2008-01-02 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: More renaming ideas. (Maciej, please merge yours with mine.)
+
+2008-01-02 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ fixing assertion hit with editing/selection/move-begin-end.html
+
+ * DumpRenderTree/ForwardingHeaders/wtf/ASCIICType.h: Added.
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback):
+ using isupper will cause an assertion for inputs outside of ascii range. use isASCIIUpper instead.
+
+2008-01-02 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Some more name change plans.
+
+2008-01-02 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Maciej.
+
+ Added handling for page up and page down in EventSender
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController keyDown:withModifiers:]):
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback):
+
+2008-01-02 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Fix fast/events/arrow-keys-on-body.html for real.
+
+ * DumpRenderTree/win/EventSender.cpp: (keyDownCallback): Pass proper keyData for WM_KEYUP, too.
+
+2008-01-02 Luca Bruno <lethalman88@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=16674
+ [GTK] run-launcher sets wrong LD_LIBRARY_PATH
+
+ * Scripts/run-launcher:
+
+2007-12-31 Darin Adler <darin@apple.com>
+
+ Suggested by Antti.
+
+ * Scripts/webkitdirs.pm: Turned off the QuickTime requirement for Windows until
+ we get it installed on the build bots.
+
+2007-12-30 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Sam.
+
+ * Scripts/do-webcore-rename: Add a few more planned renames s/(\w+)Imp/\1/
+
+2007-12-29 Darin Adler <darin@apple.com>
+
+ Reviewed by Oliver.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=16663
+ leak bot shows createCStringFromNPVariant result leaking
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginInvoke): Added a missing free.
+
+2007-12-26 Jan Michael Alonzo <jmalonzo@unpluggable.com>
+
+ Reviewed by Alp Toker.
+
+ http://bugs.webkit.org/show_bug.cgi?id=16390
+ Use autotools or GNU make as the build system for the GTK port
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: include glib.h
+ * GNUmakefile.am: Added.
+
+2007-12-24 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Oliver.
+
+ Fix fast/events/arrow-keys-on-body.html, failing on Windows.
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback): Add KF_EXTENDED flag to arrow keys. Also add a count
+ of 1, even though WebKit currently ignores it.
+
+2007-12-23 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx buildbot fix. Update libpng dl script to the latest version.
+
+ * wx/install-unix-extras:
+
+2007-12-22 Antti Koivisto <antti@apple.com>
+
+ Fix a typo.
+
+ * Scripts/webkitdirs.pm:
+
+2007-12-21 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ - Disable the back/forward cache using the new WebPreferences API
+ instead of through the BackForwardList. This makes us match what
+ we do on Windows.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (createWebViewAndOffscreenWindow):
+ (setDefaultsToConsistentValuesForTesting):
+
+2007-12-21 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ - disable the back/forward cache in Windows DumpRenderTree. It is
+ already disabled in Mac DumpRenderTree.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (initializePreferences):
+
+2007-12-13 Antti Koivisto <antti@apple.com>
+
+ Reviewed by Darin and Steve.
+
+ - check for QuickTime SDK on Windows.
+ - build media support on Windows by default
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2007-12-21 Kevin Ollivier <kevino@theolliviers.com>
+
+ Build script fix for buildbot.
+
+ * wx/build-wxwebkit:
+
+2007-12-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by mjs.
+
+ * Scripts/run-sunspider: change --runs default to 10 for better accuracy
+
+2007-12-20 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Steve.
+
+ - <rdar://5656485> Drosera: Win: Nightly does not reliably connect to
+ WebKit.
+
+ - Drosera and Safari need to use the same ProgIDs in order for
+ CoCreateInstance to work properly. The most robust way to do this is
+ for WebKit to dynamically publish those ProgIDs.
+
+ * Drosera/win/DebuggerClient.cpp: Use the published ProgIDs
+ (DebuggerClient::createWebViewWithRequest):
+ * Drosera/win/Drosera.cpp: Use the published ProgIDs and rename some
+ statics.
+ (Drosera::initUI):
+ (Drosera::attach):
+ (Drosera::attemptToCreateServerConnection):
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj: Fix a runtime failure.
+ * Drosera/win/ServerConnection.cpp: Reformat the connection function and
+ make use of the published ProgIDs.
+ (ServerConnection::attemptToCreateServerConnection):
+
+2007-12-20 Kevin McCullough <kmccullough@apple.com>
+
+ - <rdar://problem/5658317> REGRESSION: 20+ leaks seen on buildbots.
+ - Build bot and leak fix.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (pathToLocalResourceCallback):
+
+2007-12-19 David Kilzer <ddkilzer@apple.com>
+
+ Make svn-apply/svn-unapply work with patches from git-format-patch.
+
+ Reviewed by Darin Adler.
+
+ * Scripts/svn-apply:
+ (patch): If 'Index:' can't be found in the text passed in, print it
+ out with a warning and return early.
+ * Scripts/svn-unapply:
+ (patch): Ditto.
+
+2007-12-18 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Alp Toker.
+
+ Build related fixes.
+
+ * wx/build-wxwebkit:
+ - Check to make sure the user is running a supported wx port
+ - More robust checks for Cygwin
+ - Only run install-unix-extras on Mac, it's not the right solution
+ for Linux distros.
+ - Remove outdated Linux instructions after successful build
+ - Clean Bakefile-generated files during a clean operation
+
+2007-12-18 Darin Adler <darin@apple.com>
+
+ * Scripts/make-js-test-wrappers: Don't generate a wrapper for select-options-remove.js.
+
+2007-12-18 Steve Falkenburg <sfalken@apple.com>
+
+ Add script to run Drosera as part of the nightly.
+
+ Reviewed by Kevin M.
+
+ * Scripts/run-drosera.cmd: Added.
+
+2007-12-18 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Remove a stray K.
+
+2007-12-18 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Plan more renaming.
+
+2007-12-14 Juan A. Suarez Romero <jasuarez@igalia.com>
+
+ Reviewed by Alp Toker.
+
+ http://bugs.webkit.org/show_bug.cgi?id=16042
+ [GTK] Eliminate webkit_init()
+
+ Moving webkit initialization to WebView class init.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (main):
+ * GtkLauncher/main.c:
+ (main):
+
+2007-12-17 Luca Bruno <lethalman88@gmail.com>
+
+ Reviewed by Alp Toker.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13542
+ gdklauncher doesnt change URL in adress GTKEntry.
+
+ * GtkLauncher/main.c:
+ (load_commit_cb): added
+ (title_change_cb):
+ (create_browser):
+
+2007-12-16 Dimitri Glazkov <dimitri@glazkov.com>
+
+ Reviewed by Adam Roben.
+
+ Remove the double-quotes around the PATH variable value, in order to make it work in Windows shell.
+
+ * FindSafari/FindSafari.cpp:
+ (_tmain):
+
+2007-12-16 Brent Fulgham <bfulgham@gmail.com>
+
+ Reviewed by Adam Roben.
+
+ http://bugs.webkit.org/show_bug.cgi?id=16315
+ FindSafari needs a path-only option.
+
+ * FindSafari/FindSafari.cpp:
+ (_tmain):
+
+2007-12-16 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=16462
+ REGRESSION: access keys broken on Windows
+
+ * DumpRenderTree/win/EventSender.cpp: (keyDownCallback): Send system key events
+ if Alt is pressed.
+
+2007-12-15 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Fix urlSuitableForTestResult to correctly identify wstring::npos as
+ the case when wstring.find doesn't find anything.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (urlSuitableForTestResult):
+
+2007-12-15 Alp Toker <alp@atoker.com>
+
+ GTK+ DRT build fix for GLib < 2.14.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setWaitToDump):
+
+2007-12-05 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Alp Toker.
+
+ Add a watchdog timer to Gtk DumpRenderTree, and implement alert/prompt/confirm. This prevents
+ many layout tests from hanging while waiting on user responses to dialogs.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (invalidateAnyPreviousWaitToDumpWatchdog):
+ (webViewScriptAlert):
+ (webViewScriptPrompt):
+ (webViewScriptConfirm):
+ (main):
+ * DumpRenderTree/gtk/DumpRenderTreeGtk.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (waitToDumpWatchdogFired):
+ (LayoutTestController::setWaitToDump):
+
+2007-12-05 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Alp Toker.
+
+ Flesh out DumpRenderTree for Gtk. After these changes, the majority of the tests in fast/js pass.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dumpFramesAsText): Don't print the frame name when dumping the main frame as text.
+ (dump):
+ (runTest):
+ (webViewLoadStarted): Store the top frame when it starts loading so we can use it to determine when to dump.
+ (webViewLoadFinished): Dump when the top frame load completes if we're not waiting for a JS callback and the
+ work queue is empty.
+ (webViewWindowObjectCleared): Set up window.layoutTestController.
+ (webViewConsoleMessage): Match the console message format expected by the layout test results.
+ (main): Hook up the new signals.
+ * DumpRenderTree/gtk/DumpRenderTreeGtk.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: Only notify done if the top frame has completed loading to avoid
+ dumping multiple times.
+ * Scripts/build-dumprendertree: Ensure build-dumprendertree is a no-op for Gtk too.
+ * Scripts/run-webkit-tests: Teach run-webkit-tests that Gtk is like Qt in many ways. Use run-launcher to open test results.
+
+2007-12-14 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Brady.
+
+ Assert that a web frame that's loading a resource always has either a data source or
+ a provisional data source.
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:identifierForInitialRequest:fromDataSource:]):
+
+2007-12-14 Darin Adler <darin@apple.com>
+
+ - fix mistake causing nearly all tests to fail on Windows
+
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::webViewAddMessageToConsole): Need to compare the result of find with
+ npos, not 0. Also pass URL in to URL function rather than passing the entire message.
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:addMessageToConsole:]): Pass path only to path function rather
+ than passing the entire message.
+
+2007-12-14 Darin Adler <darin@apple.com>
+
+ - fix Tiger build
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:addMessageToConsole:]): Re-implement this without using any
+ new-to-Leopard methods.
+
+2007-12-14 Darin Adler <darin@apple.com>
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm: Don't implement didReceiveIcon delegate method
+ since it now triggers unwanted icon loading. We only had it because we implemented "all"
+ delegate methods here.
+
+2007-12-14 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Darin and Geoff.
+
+ <rdar://problem/5619295>
+ REGRESSION: 303-304: Embedded YouTube video fails to render- JS errors (16150) (Flash 9)
+
+ Add property getting methods to the plug-in.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginInvoke):
+
+2007-12-14 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - Layout test fix for mac. When dumped to the console local file paths
+ now only show the name of the resource not the whole path. This is to
+ make the results machine and OS independent.
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:addMessageToConsole:]):
+
+2007-12-13 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Layout tests fix. We need a way to remove machine-dependent
+ information from paths in layout test results. The UIDelegate now does
+ this.
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (urlSuitableForTestResult):
+ * DumpRenderTree/win/DumpRenderTreeWin.h:
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::webViewAddMessageToConsole):
+
+2007-12-13 Alp Toker <alp@atoker.com>
+
+ Build fix for DRT breakage introduced in r28690.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::pathToLocalResource):
+
+2007-12-12 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Alice and Sam.
+
+ - <rdar://5621435> Need a way to specify local resources (being loaded
+ from HTTP tests) on Windows.
+ - Implemented pathToLocalResource which exposes the functionality of
+ converting a given unix path to the correct location on Windows.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (pathToLocalResourceCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::pathToLocalResource):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::pathToLocalResource):
+
+2007-12-12 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam.
+
+ <rdar://problem/5132003>
+ dumpResourceLoadCallbacks is not implemented in DRT on Windows.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main):
+ Set the resource load delegate.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp: Added.
+ * DumpRenderTree/win/ResourceLoadDelegate.h: Added.
+
+2007-12-12 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Fix conversion from double to LPARAM in dispatchMessage().
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (dispatchMessageCallback):
+
+2007-12-11 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Mark Rowe and Sam Weinig too!
+
+ - added Helvetica Oblique and Helvetica Bold Oblique to the list of
+ fonts DumpRenderTree registers.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (initialize):
+
+2007-12-11 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Anders
+
+ Make DumpRenderTree on mac use its own path for Databases testing
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (setDefaultsToConsistentValuesForTesting): Keep a string to ~/Library/Application Support/DumpRenderTree
+ for future DRT-only use, then use it to construct the Databases path and set that default
+
+2007-12-07 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ <rdar://problem/5535636>
+ Have to press 4 times instead of 2 times to get the expected result of ^^ with german keyboard.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13916
+ JavaScript detects Tab as a character input on a textfield validation
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController keyDown:withModifiers:]): Added a few more named keys.
+ Dispatch a keyup to better match what happens when a key is physically pressed.
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback): Ditto. Also make sure that WM_CHAR is consistently dispatched before
+ returning from keyDown().
+ (getConstantCallback): Fixed a couple copy/paste mistakes.
+
+2007-12-07 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Oliver.
+
+ - <rdar://5599845> Drosera: Does not show loal files in the file list
+ on the left side.
+
+ * Drosera/debugger.js: - Updated url dividing regex to handle %s and :s.
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj: - Updated Debug settings
+ so the open source community can build.
+
+2007-12-10 Brady Eidson <beidson@apple.com>
+
+ Rubberstamped by Sam Weinig
+
+ Update DRT Mac to reflect the new UI Delegate methods I just checked into WebKit/mac
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:frame:quotaForSecurityOrigin:toCreateDatabase:withEstimatedSize:]):
+ (-[UIDelegate webView:frame:quotaForSecurityOrigin:fromProposedQuota:database:]):
+
+2007-12-08 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Sam W.
+
+ Split the ENABLE_SVG_EXPERIMENTAL_FEATURES flag into separate flags.
+
+ Fixes <rdar://problem/5620249> Must disable SVG animation
+ <rdar://problem/5612772> Disable SVG filters on Mac to match Windows behavior
+
+ In order to allow finer grained control over the set of SVG features
+ this patch splits ENABLE_SVG_EXPERIMENTAL_FEATURES into the following
+ distinct flags:
+ ENABLE_SVG_ANIMATION
+ ENABLE_SVG_FILTERS
+ ENABLE_SVG_FONTS
+ ENABLE_SVG_AS_IMAGE
+ ENABLE_SVG_USE
+
+ by default only ENABLE_SVG_AS_IMAGE and ENABLE_SVG_USE are set.
+
+ Script handles all the new build flags, and allows --svg-experimental
+ to automatically enable all features.
+
+ * Scripts/build-webkit:
+
+2007-12-07 Steve Falkenburg <sfalken@apple.com>
+
+ Fix version parsing.
+
+ Rubber-stamped by Oliver.
+
+ * Drosera/win/Drosera.vcproj/auto-version.sh:
+
+2007-12-07 Steve Falkenburg <sfalken@apple.com>
+
+ Build modifications for Drosera.
+
+ Reviewed by Adam.
+
+ * Drosera/DroseraWin.make: Added.
+ * Drosera/win/Drosera.vcproj/Drosera.rc:
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj:
+ * Drosera/win/Drosera.vcproj/PRODUCTVERSION: Added.
+ * Drosera/win/Drosera.vcproj/VERSION: Added.
+ * Drosera/win/Drosera.vcproj/auto-version.sh: Added.
+
+2007-12-06 Adam Roben <aroben@apple.com>
+
+ Explicitly turn on the Mac font ascent hack on Windows
+
+ This keeps our font metrics matching those from Mac.
+
+ Reviewed by Hyatt.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main):
+
+2007-12-06 Anders Carlsson <andersca@apple.com>
+
+ Rename main.c to main.cpp here too.
+
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp: Copied from DumpRenderTree/win/TestNetscapePlugin/main.c.
+
+2007-12-06 Sam Weinig <sam@webkit.org>
+
+ Rubber stamped by Geoff.
+
+ * Scripts/do-webcore-rename: Don't rename kjs_css twice.
+
+2007-12-06 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Some more renaming plans.
+
+2007-12-06 Anders Carlsson <andersca@apple.com>
+
+ Restore implementation of testGetIntIdentifier that was accidentally
+ removed somehow (possibly when I made PluginObject be a cpp file).
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginInvoke):
+
+2007-12-05 Anders Carlsson <andersca@apple.com>
+
+ Make the entry points extern "C".
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+
+2007-12-05 Anders Carlsson <andersca@apple.com>
+
+ C++ warning fixes.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+ (NPP_Destroy):
+ (NPP_SetWindow):
+ (NPP_NewStream):
+ (NPP_HandleEvent):
+ (NPP_URLNotify):
+ (NPP_GetValue):
+
+2007-12-05 Anders Carlsson <andersca@apple.com>
+
+ Add the .cpp files to the TestNetscapePlugIn target.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-12-05 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Geoff.
+
+ Rename the TestNetscapePlugIn .c files to be .cpp.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c: Removed.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp: Copied from DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.c: Removed.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.cpp: Copied from DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.c.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c: Removed.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp: Copied from DumpRenderTree/TestNetscapePlugIn.subproj/main.c.
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+
+2007-12-05 Adam Roben <aroben@apple.com>
+
+ Fix case of keypresses from the Windows implementation of eventSender.keyDown
+
+ This fixes several regression tests.
+
+ Reviewed by Alice.
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback): Virtual keycodes for ASCII characters are always
+ uppercase, so we need to check the case of the original character
+ passed in to eventSender.keyDown.
+
+2007-12-05 Adam Roben <aroben@apple.com>
+
+ Learn from Tim's mistakes
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest): Reset the authorAndUserStylesEnabled preference for each
+ test.
+
+2007-12-05 Alp Toker <alp@atoker.com>
+
+ Reviewed by Mark Rowe.
+
+ Initialize GTK+ and WebKit so the tests can run.
+
+ Reorganize the headers a little.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (main):
+
+2007-12-04 Anders Carlsson <andersca@apple.com>
+
+ Remove IWebScriptScope include.
+
+ * Drosera/win/DebuggerDocumentPlatform.cpp:
+
+2007-12-04 Sam Weinig <sam@webkit.org>
+
+ Rubber stamped by Mark Rowe.
+
+ Define CF as platform for mac and revert r28409
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/mac/DumpRenderTreeMac.h:
+
+2007-12-04 Sam Weinig <sam@webkit.org>
+
+ Define CF as platform for windows.
+
+ Reviewed by Adam Roben.
+
+ * DumpRenderTree/win/DumpRenderTreeWin.h:
+
+2007-12-04 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam and Darin.
+
+ - Removed a needless BSTR cleanup.
+
+ * Drosera/win/DebuggerDocumentPlatform.cpp:
+ (DebuggerDocument::getPlatformCurrentFunctionStack):
+
+2007-11-27 Adam Roben <aroben@apple.com>
+
+ Fix <rdar://5614497> setAuthorAndUserStylesEnabled is not implemented in DRT
+
+ Reviewed by Maciej.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setAuthorAndUserStylesEnabled): Implemented.
+
+2007-12-04 Alp Toker <alp@atoker.com>
+
+ Prospective Win DRT build fix.
+
+ * DumpRenderTree/DumpRenderTree.h:
+
+2007-12-04 Alp Toker <alp@atoker.com>
+
+ Fix a clobbered copyright header.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+
+2007-12-04 Xan Lopez <xan@gnome.org>
+
+ Reviewed by Alp Toker.
+
+ http://bugs.webkit.org/show_bug.cgi?id=15561
+ GTK port needs DumpRenderTree implementation
+
+ Start work on the GTK+ DRT.
+
+ This does not work yet, and there are a few lingering style issues
+ (nothing major) but this patch has been stuck in the bug tracker for
+ too long already.
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/gtk: Added.
+ * DumpRenderTree/gtk/DumpRenderTree.cpp: Added.
+ (autocorrectURL):
+ (shouldLogFrameLoadDelegates):
+ (dumpFrameScrollPosition):
+ (displayWebView):
+ (appendString):
+ (dumpFramesAsText):
+ (dumpRenderTreeAsText):
+ (dump):
+ (runTest):
+ (main):
+ * DumpRenderTree/gtk/DumpRenderTree.pro: Added.
+ * DumpRenderTree/gtk/DumpRenderTreeGtk.h: Added.
+ * DumpRenderTree/gtk/GCControllerGtk.cpp: Added.
+ (GCController::collect):
+ (GCController::collectOnAlternateThread):
+ (GCController::getJSObjectCount):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: Added.
+ (LayoutTestController::~LayoutTestController):
+ (LayoutTestController::addDisallowedURL):
+ (LayoutTestController::clearBackForwardList):
+ (LayoutTestController::copyDecodedHostName):
+ (LayoutTestController::copyEncodedHostName):
+ (LayoutTestController::display):
+ (LayoutTestController::keepWebHistory):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::queueBackNavigation):
+ (LayoutTestController::queueForwardNavigation):
+ (LayoutTestController::queueLoad):
+ (LayoutTestController::queueReload):
+ (LayoutTestController::queueScript):
+ (LayoutTestController::setAcceptsEditing):
+ (LayoutTestController::setCustomPolicyDelegate):
+ (LayoutTestController::setMainFrameIsFirstResponder):
+ (LayoutTestController::setTabKeyCyclesThroughElements):
+ (LayoutTestController::setUseDashboardCompatibilityMode):
+ (LayoutTestController::setUserStyleSheetEnabled):
+ (LayoutTestController::setUserStyleSheetLocation):
+ (LayoutTestController::setWindowIsKey):
+ (LayoutTestController::setWaitToDump):
+ (LayoutTestController::windowCount):
+ (LayoutTestController::setPrivateBrowsingEnabled):
+ (LayoutTestController::setAuthorAndUserStylesEnabled):
+ * DumpRenderTree/gtk/WorkQueueItemGtk.cpp: Added.
+ (JSStringCopyUTF8CString):
+ (LoadItem::invoke):
+ (ReloadItem::invoke):
+ (ScriptItem::invoke):
+ (BackForwardItem::invoke):
+
+2007-12-03 Sam Weinig <sam@webkit.org>
+
+ Move JavaScriptCore thread testing code to pthread specific directory
+ and remove the dependance on CoreFoundation by using WTF::HashSet.
+
+ Reviewed by Geoff and Oliver.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/ForwardingHeaders/wtf/HashMap.h: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf/HashSet.h: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf/Vector.h: Added.
+ * DumpRenderTree/JavaScriptThreading.h: Copied from DumpRenderTree/mac/JavaScriptThreading.h.
+ * DumpRenderTree/mac/JavaScriptThreading.cpp: Removed.
+ * DumpRenderTree/mac/JavaScriptThreading.h: Removed.
+ * DumpRenderTree/pthreads: Added.
+ * DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp: Copied from DumpRenderTree/mac/JavaScriptThreading.cpp.
+ (javaScriptThreads):
+ (runJavaScriptThread):
+ (startJavaScriptThreads):
+ (stopJavaScriptThreads):
+
+2007-12-03 Andrew Bonventre <andybons@google.com>
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=16267
+ Symbol lookup menu broken in debugger view
+
+ * Drosera/debugger.js: Fixed javascript error where document property
+ should have been used instead of contentDocument in switchFunction that
+ was breaking the select symbol dropdown menu. This is because
+ window.frames will return a Window object and not a frame object like
+ the author was originally expecting.
+
+2007-12-03 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - <rdar://5618942> Drosera: Console window does not process everything
+ correctly.
+ - <rdar://5619005> Drosera: could be sped up by moving the
+ WebScriptScope stuff into the WebScriptCallFrame.
+ - Now the console can correctly process objects and does not receive
+ notifications from JavaScriptCore about the JavaScript in Drosera's
+ own process.
+
+ * Drosera/win/DebuggerDocumentPlatform.cpp:
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ (DebuggerDocument::platformValueForScopeVariableNamed):
+
+2007-12-03 Stephanie <slewis@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Check to see if we are building a debug root
+
+ * Scripts/check-for-global-initializers:
+
+2007-12-03 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - added a testGetIntIdentifier() method to TestNetscapePlugIn
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (pluginInvoke):
+
+2007-12-03 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Oliver.
+
+ Added eventSender.dispatchMessage() - will be used to test Windows keyboard input
+ in a more fine-grained manner than eventSender.keyDown().
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (getConstantCallback):
+ (dispatchMessageCallback):
+
+2007-12-02 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: More planned renaming.
+
+2007-12-02 Sam Weinig <sam@webkit.org>
+
+ Rubber stamped by Anders.
+
+ Use [NSURL absoluteString] instead of [NSURL description] in order to get
+ more uniform results cross platform.
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[NSURL _drt_descriptionSuitableForTestResult]):
+
+2007-12-02 Sam Weinig <sam@webkit.org>
+
+ Rubber stamped by Niko.
+
+ Rename FrameLoaderDelegate.h/cpp to FrameLoadDelegate.h/cpp.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/FrameLoadDelegate.cpp: Copied from DumpRenderTree/win/FrameLoaderDelegate.cpp.
+ * DumpRenderTree/win/FrameLoadDelegate.h: Copied from DumpRenderTree/win/FrameLoaderDelegate.h.
+ * DumpRenderTree/win/FrameLoaderDelegate.cpp: Removed.
+ * DumpRenderTree/win/FrameLoaderDelegate.h: Removed.
+
+2007-12-01 Alp Toker <alp@atoker.com>
+
+ Reviewed by Adam Roben.
+
+ Make use of the newly introduced webkit.h convenience header.
+
+ * GtkLauncher/main.c:
+
+2007-12-01 Adam Treat <treat@kde.org>
+
+ Reviewed by Simon.
+
+ * Check to see if the directory exists and exit if not.
+
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2007-12-01 Adam Treat <treat@kde.org>
+
+ Reviewed by Simon.
+
+ * Don't hide symbols when in Debug mode
+ * On Linux (glibc) provide a backtrace in the test output for debugging purposes
+
+
+ * DumpRenderTree/qt/main.cpp:
+ (messageHandler):
+
+2007-11-30 Alp Toker <alp@atoker.com>
+
+ Reviewed by Adam Roben.
+
+ http://bugs.webkit.org/show_bug.cgi?id=15691
+ [GTK] Public API does not follow GTK+ conventions
+
+ Refactor the WebKit/GTK+ public API. Changes:
+ WebKitPage -> WebKitWebView
+ WebKitFrame -> WebKitWebFrame
+
+ Public API source and header names have been updated to mirror the API
+ changes.
+
+ The API is now kept in WebKit/gtk/WebView to match other ports in the
+ same class such as Mac and Win.
+
+ * GtkLauncher/main.c:
+ (activate_uri_entry_cb):
+ (link_hover_cb):
+ (title_change_cb):
+ (progress_change_cb):
+ (go_back_cb):
+ (go_forward_cb):
+ (create_browser):
+ (main):
+
+2007-11-30 Adam Roben <aroben@apple.com>
+
+ Hopefully the final build fix
+
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj: Link against WTF.lib to
+ pull in WTF's assertion/logging functions.
+
+2007-11-30 Adam Roben <aroben@apple.com>
+
+ Another build fix
+
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj: Use the right suffix for
+ WebKit.lib.
+
+2007-11-30 Adam Roben <aroben@apple.com>
+
+ Debug build fix
+
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj: Added a Debug_Internal
+ configuration.
+ * Drosera/win/Drosera.vcproj/debug.vsprops: Updated to match other
+ projects.
+ * Drosera/win/Drosera.vcproj/release.vsprops: Ditto.
+ * Drosera/win/Drosera.vcproj/debug_internal.vsprops: Copied from
+ WebKitTools/DumpRenderTree/win/debug_internal.vsprops.
+
+2007-11-30 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Fix drawSelectionRect to actually draw the selection rect.
+
+ * DumpRenderTree/cg/PixelDumpSupportCG.cpp:
+ (drawSelectionRect):
+
+2007-11-30 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: WildFox already did the TextStyle -> FontStyle one.
+
+2007-11-30 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Get ready for some future renaming.
+
+2007-11-29 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Removed some unnecessary functions and changed an unused return type.
+
+ * Drosera/win/DebuggerClient.cpp:
+ (registerConsoleClass):
+ * Drosera/win/DebuggerClient.h:
+ * Drosera/win/Drosera.cpp:
+ (registerDroseraClass):
+
+2007-11-28 Alp Toker <alp@atoker.com>
+
+ Reviewed by Timothy Hatcher.
+
+ http://bugs.webkit.org/show_bug.cgi?id=16174
+ [GTK] Use "URI" not "URL" in public API
+
+ Replace use of the term "URL" with "URI" in public headers,
+ documentation and some internal code to match GLib/GTK+ convention.
+
+ This is now mentioned in the API guidelines:
+ http://trac.webkit.org/projects/webkit/wiki/HackingGtk
+
+ * GtkLauncher/main.c:
+ (activate_uri_entry_cb):
+ (title_change_cb):
+ (create_toolbar):
+ (main):
+
+2007-11-29 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam.
+
+ <rdar://problem/5230478>
+ FrameLoadDelegate callbacks are not dumped in DRT.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (shouldLogFrameLoadDelegates):
+ (runTest):
+ (main):
+ * DumpRenderTree/win/FrameLoaderDelegate.cpp:
+ (BSTRtoString):
+ (descriptionSuitableForTestResult):
+ (FrameLoadDelegate::QueryInterface):
+ (FrameLoadDelegate::didStartProvisionalLoadForFrame):
+ (FrameLoadDelegate::didFailProvisionalLoadWithError):
+ (FrameLoadDelegate::didCommitLoadForFrame):
+ (FrameLoadDelegate::didFinishLoadForFrame):
+ (FrameLoadDelegate::willCloseFrame):
+ (FrameLoadDelegate::didClearWindowObject):
+ (FrameLoadDelegate::didFinishDocumentLoadForFrame):
+ (FrameLoadDelegate::didHandleOnloadEventsForFrame):
+ * DumpRenderTree/win/FrameLoaderDelegate.h:
+ (FrameLoadDelegate::windowScriptObjectAvailable):
+ (FrameLoadDelegate::didFirstLayoutInFrame):
+
+2007-11-29 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders.
+
+ Add database quota UIDelegates methods to DRT UIDelegate.
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:quotaForSecurityOrigin:toCreateDatabase:withEstimatedSize:]):
+ (-[UIDelegate webView:quotaForSecurityOrigin:fromProposedQuota:database:]):
+
+2007-11-29 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Sam.
+
+ - <rdar://5618976> Drosera: should listen for the WebScriptDebugServer
+ dying and vice versa.
+ - This fix will allow Drosera and Safari to reconnect if either of them
+ closes correctly, but does not fix the case where one of them dies
+ silently.
+
+ * Drosera/win/ServerConnection.cpp:
+ (ServerConnection::attemptToCreateServerConnection): Added a safety
+ check, because it's possilbe to try to connect to a server that's dying.
+ (ServerConnection::serverDidDie): Implemented. This resets Drosera when
+ the server has died.
+ * Drosera/win/ServerConnection.h: Added the new function and removed
+ an unnecessary member.
+
+2007-11-29 Anders Carlsson <andersca@apple.com>
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ Add shlwapi.lib to all configurations.
+
+2007-11-29 Kevin McCullough <kmccullough@apple.com>
+
+ - Build fix. Added additional includes for VS Express to the Release
+ project.
+
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj:
+
+2007-11-29 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam.
+
+ <rdar://problem/5132005>
+ setUserStyleSheetEnabled is not fully implemented in Windows DRT.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ Add shlwapi.lib
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setUserStyleSheetEnabled):
+ Implement this.
+
+ (appendComponentToPath):
+ New method which wraps the Win32 API PathAppend.
+
+ (followShortcuts):
+ New method which checks if a file points to a shortcut and
+ follows the shortcut.
+
+ (resolveCygwinPath):
+ New method that takes a cygwin unix-style path and returns the Win32 path.
+
+ (cfStringRefToWString):
+
+ (LayoutTestController::setUserStyleSheetLocation):
+ Implement this.
+
+2007-11-29 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Adam.
+
+ Fixed <rdar://5133828> fast/frames/iframe-window-focus.html output is lowercase
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback):
+ uppercase letters were being sent as lowercase letters without the shift key down.
+
+2007-11-29 Kevin McCullough <kmccullough@apple.com>
+
+ - Windows build fix. VS express needs some love.
+
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj:
+
+2007-11-28 Darin Adler <darin@apple.com>
+
+ Reviewed by Adam Roben.
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController keyDown:withModifiers:]):
+ Send capital letters through as lowercase letters with the shift key down
+ rather than sending them as if they were highly unusual "capital letter keys".
+
+ * Scripts/update-javascriptcore-test-results: Add a "--force" option for cases
+ where you need to update results and more tests are failing than before.
+
+2007-11-28 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Darin Adler.
+
+ <rdar://problem/5132001>
+ contextClick is not implemented in DRT on Windows.
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (contextClickCallback):
+ Add a callback for contextClick, which sends a WM_RBUTTONDOWN message followed
+ by a WM_RBUTTONUP message.
+
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::hasCustomMenuImplementation):
+ (UIDelegate::trackCustomPopupMenu):
+ * DumpRenderTree/win/UIDelegate.h:
+ Add a no-op implementation of trackCustomPopupMenu, to prevent the default popup
+ menu from being shown (and causing the DRT to hang).
+
+2007-11-27 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Fix DumpRenderTree ObjC bug comparing strings.
+
+ * DumpRenderTree/mac/ObjCController.m:
+ (-[ObjCController identityIsEqual::]): Compare strings with string
+ equality instead of identiy equality.
+
+2007-11-27 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Sam.
+
+ Reset the authorAndUserStylesEnabled preference
+ back to YES for each test. Fixes the broken tests.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting):
+
+2007-11-27 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Drosera now displays the console window, although it cannot currently
+ process JavaScript.
+
+ * Drosera/win/DebuggerClient.cpp: Shows the console window.
+ (registerConsoleClass): Implemented.
+ (consoleWndProc): Implemented.
+ (DebuggerClient::onSize): Implemented.
+ (DebuggerClient::createWebViewWithRequest): Implemented, now creates a
+ new window.
+ * Drosera/win/DebuggerClient.h: Added needed method and members for
+ creating and maintaining a new window.
+ * Drosera/win/Drosera.cpp: Fixed some minor bugs, and moved a couple of
+ lines of code to more appropriate places.
+ (Drosera::handleCommand):
+ (Drosera::initUI):
+ (Drosera::onSize):
+ (Drosera::attach):
+
+2007-11-27 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Dave Hyatt.
+
+ <rdar://problem/5569233> Add the ability to disable author and user CSS styles
+
+ Add support for disabling author and user styles for testing.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setAuthorAndUserStylesEnabledCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setAuthorAndUserStylesEnabled):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setAuthorAndUserStylesEnabled):
+
+2007-11-26 Dan Bernstein <mitz@apple.com>
+
+ - Tiger build fix.
+
+ * DumpRenderTree/mac/Configurations/Base.xcconfig:
+
+2007-11-26 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Maciej.
+
+ - Implemented displaying variables for Drosera on Win.
+
+ * Drosera/win/DebuggerDocumentPlatform.cpp: Changed Drosera functions
+ that retrieve variables to not hold onto the return value since it's
+ not returned. Also changed to use the new signatures of the retrieval
+ functions.
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ (DebuggerDocument::platformValueForScopeVariableNamed):
+ * Drosera/win/Drosera.cpp: Removed a needless TODO.
+ (droseraWndProc):
+
+2007-11-26 Sam Weinig <sam@webkit.org>
+
+ Cleanup names of painting and repainting functions.
+
+ Reviewed by Adam Roben.
+
+ * DumpRenderTree/cg/PixelDumpSupportCG.cpp:
+ (drawSelectionRect): was drawSelectionRectIntoContext.
+ (dumpWebViewAsPixelsAndCompareWithExpected):
+ * DumpRenderTree/cg/PixelDumpSupportCG.h:
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (paintWebView): was drawWebViewIntoContext.
+ (repaintWebView): was repaintWithVerticalSweep and repaintWithHorizontalSweep.
+
+2007-11-26 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Dan Bernstein.
+
+ - Leopard build fix
+
+ * DumpRenderTree/mac/Configurations/Base.xcconfig:
+
+2007-11-26 Sam Weinig <sam@webkit.org>
+
+ Fix for http://bugs.webkit.org/show_bug.cgi?id=16136
+ Use shared PixelDumpSupport for Mac DRT
+
+ Reviewed by Adam Roben.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/PixelDumpSupport.h: Copied from DumpRenderTree/win/PixelDumpSupport.h.
+ * DumpRenderTree/cg/ImageDiffCG.cpp:
+ * DumpRenderTree/cg/PixelDumpSupportCG.cpp:
+ (drawSelectionRectIntoContext):
+ (dumpWebViewAsPixelsAndCompareWithExpected):
+ * DumpRenderTree/cg/PixelDumpSupportCG.h:
+ * DumpRenderTree/mac/Configurations/Base.xcconfig:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dump):
+ * DumpRenderTree/mac/ImageDiff.m: Removed.
+ * DumpRenderTree/mac/PixelDumpSupport.h: Removed.
+ * DumpRenderTree/mac/PixelDumpSupport.mm: Removed.
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm: Copied from DumpRenderTree/mac/PixelDumpSupport.mm.
+ (setDefaultColorProfileToRGB):
+ (getBitmapContextFromWebView):
+ (drawWebViewIntoContext):
+ (repaintWithVerticalSweep):
+ (repaintWithHorizontalSweep):
+ (getSelectionRect):
+ * DumpRenderTree/win/PixelDumpSupport.h: Removed.
+
+2007-11-25 David D. Kilzer <ddkilzer@webkit.org>
+
+ Bug 16052: prepare-ChangeLog doesn't report deleted files
+ <http://bugs.webkit.org/show_bug.cgi?id=16052>
+
+ Reviewed by Sam.
+
+ * Scripts/prepare-ChangeLog: Fixed logic that checks for removed files.
+
+2007-11-25 David Kilzer <ddkilzer@webkit.org>
+
+ Bug 15864: Replace merge-changelog with resolve-ChangeLogs
+ <http://bugs.webkit.org/show_bug.cgi?id=15864>
+
+ Reviewed by Adam.
+
+ Roll functionality of merge-changelog into resolve-ChangeLogs
+ script. The script now checks for ChangeLog.rej and
+ ChangeLog.orig files first. If it finds them, it uses the
+ ChangeLog.rej file as a patch (in old contextual diff format) to
+ apply with --fuzz=3.
+
+ * Scripts/merge-changelog: Removed.
+ * Scripts/resolve-ChangeLogs: Handle traditional rejected patches.
+
+2007-11-25 Sam Weinig <sam@webkit.org>
+
+ Add .xcconfig files for the ImageDiff and TestNetscapePlugIn targets of the DumpRenderTree.
+
+ Reviewed by Mark Rowe.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/Configurations/Base.xcconfig:
+ * DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig:
+ * DumpRenderTree/mac/Configurations/ImageDiff.xcconfig: Added.
+ * DumpRenderTree/mac/Configurations/TestNetscapePlugIn.xcconfig: Added.
+
+2007-11-25 Sam Weinig <sam@webkit.org>
+
+ Convert DumpRenderTree to ues .xcconfig files.
+
+ Reviewed by Mark Rowe.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/Configurations: Added.
+ * DumpRenderTree/mac/Configurations/Base.xcconfig: Added.
+ * DumpRenderTree/mac/Configurations/DebugRelease.xcconfig: Added.
+ * DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig: Added.
+
+2007-11-25 Sam Weinig <sam@webkit.org>
+
+ Add ForwardingHeaders to wtf for DumpRenderTree.
+
+ Reviewed by Mark Rowe.
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/ForwardingHeaders: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf/Assertions.h: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf/Noncopyable.h: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf/OwnPtr.h: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf/Platform.h: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf/RetainPtr.h: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf/StringExtras.h: Added.
+ * DumpRenderTree/LayoutTestController.cpp:
+ * DumpRenderTree/WorkQueue.cpp:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ * DumpRenderTree/mac/JavaScriptThreading.cpp:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ * DumpRenderTree/mac/ObjCController.m:
+ * DumpRenderTree/mac/UIDelegate.mm:
+ * DumpRenderTree/mac/WorkQueueItemMac.mm:
+
+2007-11-25 Adam Roben <aroben@apple.com>
+
+ Fix some test failures caused by r28019
+
+ Now that stdout is in binary mode, we need to always use printf
+ instead of wprintf. Otherwise we'll end up with UTF-16 characters in
+ the output.
+
+ Reviewed by Sam.
+
+ * DumpRenderTree/win/UIDelegate.cpp: Replaced uses of wprintf with
+ printf.
+ (UIDelegate::runJavaScriptAlertPanelWithMessage):
+ (UIDelegate::runJavaScriptConfirmPanelWithMessage):
+ (UIDelegate::runJavaScriptTextInputPanelWithPrompt):
+ (UIDelegate::webViewAddMessageToConsole):
+
+2007-11-25 Adam Roben <aroben@apple.com>
+
+ Set the font smoothing preference in DRT
+
+ This makes the pixel results on Windows closer to the Mac results.
+
+ Reviewed by Mitz.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (initializePreferences):
+
+2007-11-25 Adam Roben <aroben@apple.com>
+
+ Port ImageDiff to CG and C++
+
+ Final part of http://bugs.webkit.org/show_bug.cgi?id=16133
+ <rdar://5071708>
+
+ Reviewed by Sam.
+
+ * DumpRenderTree/DumpRenderTree.sln: Added ImageDiff.vcproj.
+ * DumpRenderTree/cg/ImageDiffCG.cpp: Added.
+ (main):
+ (createImageFromStdin):
+ (compareImages):
+ (getDifferenceBitmap):
+ (computePercentageDifferent):
+ * DumpRenderTree/win/ImageDiff.vcproj: Added.
+
+2007-11-25 Adam Roben <aroben@apple.com>
+
+ Fix image diff link generation on Windows
+
+ Reviewed by Sam.
+
+ * Scripts/run-webkit-tests: Removed unnecessary and incorrect calls
+ to toURL.
+
+2007-11-25 Adam Roben <aroben@apple.com>
+
+ Implement pixel dumping in Windows DRT
+
+ Part of http://bugs.webkit.org/show_bug.cgi?id=16133
+ <rdar://5071708>
+
+ Reviewed by Sam.
+
+ * DumpRenderTree/cg/PixelDumpSupportCG.cpp: Added.
+ (printPNG): Dumps a CGImageRef as a PNG to stdout, along with a
+ Content-Length header.
+ (getMD5HashStringForBitmap):
+ (dumpWebViewAsPixelsAndCompareWithExpected):
+ * DumpRenderTree/cg/PixelDumpSupportCG.h: Copied from WebKitTools/DumpRenderTree/mac/DumpRenderTreePasteboard.h.
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dump): Do a pixel dump if requested.
+ (main): Parse pixel test options.
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Added new files and added
+ the cg/ subdirectory to the include path.
+ * DumpRenderTree/win/MD5.cpp: Added. Windows MD5 functions aren't
+ available in a header or import library, so we have to go through this
+ LoadLibrary/GetProcAddress dance to use them.
+ (cryptDLL):
+ (init):
+ (update):
+ (final):
+ (MD5_Init):
+ (MD5_Update):
+ (MD5_Final):
+ * DumpRenderTree/win/MD5.h: Added.
+ * DumpRenderTree/win/PixelDumpSupport.h: Added. This file should be
+ moved up to the top level to share it with Mac eventually.
+ * DumpRenderTree/win/PixelDumpSupportWin.cpp: Added.
+ (getBitmapContextFromWebView): Forces the WebView to paint using a
+ WM_PRINTCLIENT message, and puts the result in a CGBitmapContext.
+
+2007-11-25 Adam Roben <aroben@apple.com>
+
+ Clean up Windows DRT's option parsing a little bit
+
+ Reviewed by Sam.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main): Put non-option arguments into a Vector.
+
+2007-11-25 Adam Roben <aroben@apple.com>
+
+ Make Windows DRT stop changing LF into CRLF
+
+ Reviewed by Sam.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main): Put stdout in binary mode.
+ * Scripts/run-webkit-tests: Remove the CRLF hack.
+
+2007-11-24 David Kilzer <ddkilzer@webkit.org>
+
+ Removed empty directory.
+
+ * Scripts/resources: Removed.
+
+2007-11-23 David D. Kilzer <ddkilzer@webkit.org>
+
+ Fix bisect-builds to work with recent WebKit nightly builds.
+
+ Reviewed by Dan.
+
+ * Scripts/bisect-builds: Check for the
+ WebKit.app/Contents/Frameworks/10.[45] directory. If it exists, use
+ it for the DYLD_FRAMEWORK_PATH environment variable, else fallback
+ to WebKit.app/Contents/Resources.
+
+2007-11-23 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Maciej.
+
+ <rdar://problem/5539306> REGRESSION: redirect fails when subframe's document is opened but
+ not closed (affects digg.com)
+
+ * DumpRenderTree/mac/DumpRenderTree.mm: (runTest): Replace the current document with a blank
+ one after finishing with a test to avoid having its delayed onload handler firing when
+ replaced with the next one. This is ugly and still unreliable (see LayoutTests ChangeLog),
+ but it helps somewhat.
+
+2007-11-22 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Alp Toker.
+
+ Fix build-webkit to propagate make's exit status if it fails.
+
+ * Scripts/webkitdirs.pm:
+
+2007-11-22 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ - fix crash when running pixel tests
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpRenderTree): Parse the command line options before setting up the
+ environment so that we know if we need to set up the pixel dump
+ machinery.
+
+2007-11-21 Eric Seidel <eric@webkit.org>
+
+ Speculative build fix for Tiger.
+
+ * DumpRenderTree/mac/PixelDumpSupport.mm: include unistd.h
+
+2007-11-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Tim Hatcher.
+
+ Break out more of DumpRenderTree.mm into individual files
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/CheckedMalloc.cpp: Added.
+ (checkedMalloc):
+ (checkedRealloc):
+ (makeLargeMallocFailSilently):
+ * DumpRenderTree/mac/CheckedMalloc.h: Added.
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (crashHandler):
+ (dump):
+ * DumpRenderTree/mac/DumpRenderTreeMac.h:
+ * DumpRenderTree/mac/DumpRenderTreePasteboard.h:
+ * DumpRenderTree/mac/DumpRenderTreePasteboard.m:
+ * DumpRenderTree/mac/DumpRenderTreeWindow.h:
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ * DumpRenderTree/mac/JavaScriptThreading.cpp: Added.
+ (javaScriptThreads):
+ (runJavaScriptThread):
+ (startJavaScriptThreads):
+ (stopJavaScriptThreads):
+ * DumpRenderTree/mac/JavaScriptThreading.h: Added.
+ * DumpRenderTree/mac/PixelDumpSupport.h: Added.
+ * DumpRenderTree/mac/PixelDumpSupport.mm: Added.
+ (restoreColorSpace):
+ (setDefaultColorProfileToRGB):
+ (initializeColorSpaceAndScreeBufferForPixelTests):
+ (md5HashStringForBitmap):
+ (dumpWebViewAsPixelsAndCompareWithExpected):
+
+2007-11-21 Kevin Ollivier <kevino@theolliviers.com>
+
+ Move install-unix-extras to wx directory as it seems only to be used by that
+ port now. It now supports universal binaries on Mac and adds libpng and libjpeg.
+ Also, have build-wxwebkit run it in order to fix the Mac buildbot, and
+ have install-unix-extras install into WebKitLibraries as per
+ convention.
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/install-unix-extras: Removed.
+ * wx/build-wxwebkit:
+ * wx/install-unix-extras: Copied from WebKitTools/Scripts/install-unix-extras.
+
+2007-11-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam.
+
+ More refactoring for greater code readability
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (initializeGlobalsFromCommandLineOptions):
+ (initializeColorSpaceAndScreeBufferForPixelTests):
+ (addTestPluginsToPluginSearchPath):
+ (useLongRunningServerMode):
+ (runTestingServerLoop):
+ (prepareConsistentTestingEnvironment):
+ (dumpRenderTree):
+ (main):
+ (dumpFramesAsText):
+ (dumpBackForwardListForWebView):
+ (sizeWebViewForCurrentTest):
+ (methodNameStringForFailedTest):
+ (dumpBackForwardListForAllWindows):
+ (dumpWebViewAsPixelsAndCompareWithExpected):
+ (invalidateAnyPreviousWaitToDumpWatchdog):
+ (dump):
+ * DumpRenderTree/mac/DumpRenderTreeMac.h:
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:createWebViewWithRequest:]):
+
+2007-11-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Tim Hatcher.
+
+ Abstract more of DRT into static methods
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (setDefaultsToConsistentValuesForTesting):
+ (setupSignalHandlers):
+ (allocateGlobalControllers):
+ (releaseAndZero):
+ (releaseGlobalControllers):
+ (dumpRenderTree):
+ (shouldLogFrameLoadDelegates):
+ (createCFURLFromPathOrURL):
+ (resetWebViewToConsistentStateBeforeTesting):
+ (runTest):
+
+2007-11-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Tim Hatcher.
+
+ Pull DumpRenderTreeWindow and DumpRenderTreePasteboard out into their own files
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpRenderTree):
+ (dump):
+ (runTest):
+ * DumpRenderTree/mac/DumpRenderTreePasteboard.h: Added.
+ * DumpRenderTree/mac/DumpRenderTreePasteboard.m: Added.
+ (+[DumpRenderTreePasteboard _pasteboardWithName:]):
+ (+[DumpRenderTreePasteboard releaseLocalPasteboards]):
+ (-[DumpRenderTreePasteboard declareType:owner:]):
+ (+[LocalPasteboard alloc]):
+ (-[LocalPasteboard init]):
+ (-[LocalPasteboard dealloc]):
+ (-[LocalPasteboard name]):
+ (-[LocalPasteboard releaseGlobally]):
+ (-[LocalPasteboard declareTypes:owner:]):
+ (-[LocalPasteboard addTypes:owner:]):
+ (-[LocalPasteboard changeCount]):
+ (-[LocalPasteboard types]):
+ (-[LocalPasteboard availableTypeFromArray:]):
+ (-[LocalPasteboard setData:forType:]):
+ (-[LocalPasteboard dataForType:]):
+ (-[LocalPasteboard setPropertyList:forType:]):
+ (-[LocalPasteboard setString:forType:]):
+ * DumpRenderTree/mac/DumpRenderTreeWindow.h: Added.
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm: Added.
+ (+[DumpRenderTreeWindow allWindows]):
+ (-[DumpRenderTreeWindow initWithContentRect:styleMask:backing:defer:]):
+ (-[DumpRenderTreeWindow dealloc]):
+ (-[DumpRenderTreeWindow isKeyWindow]):
+ (-[DumpRenderTreeWindow keyDown:]):
+
+2007-11-20 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix for Windows. Don't use WebCore/move-js-headers.sh as
+ it indiscriminately copies any headers inside JavaScriptCore,
+ which includes Tiger ICU headers.
+
+ * wx/build-wxwebkit:
+ Don't run WebCore/move-js-headers.sh any longer.
+
+2007-11-20 Adam Treat <treat@kde.org>
+
+ Reviewed by David Kilzer.
+
+ * Prepend git branch name to $baseProductDir
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/webkitdirs.pm:
+
+2007-11-20 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Simon Hausmann.
+
+ * Scripts/build-webkit: Pass "clean" flag down into buildQMakeProject.
+ * Scripts/webkitdirs.pm: Respect the "clean" flag passed down from build-webkit.
+ Have it trigger a "make distclean" rather than "make clean" to ensure that the
+ built product and generated Makefile's are removed.
+
+2007-11-19 Alp Toker <alp@atoker.com>
+
+ Reviewed by Mark Rowe.
+
+ http://bugs.webkit.org/show_bug.cgi?id=16040
+ [GTK] GtkLauncher should be written in C
+
+ Port GtkLauncher to plain C.
+
+ Use a more conventional GTK+ coding style.
+
+ Use a toolbar instead of menus.
+
+ Various signature fixes and cleanups.
+
+ Add a license header. Assume all previous modifications were copyright
+ assigned to Apple Inc. by default.
+
+ * GtkLauncher/GtkLauncher.pro:
+ * GtkLauncher/main.c: Added.
+ (activate_url_entry_cb):
+ (update_title):
+ (link_hover_cb):
+ (title_change_cb):
+ (progress_change_cb):
+ (destroy_cb):
+ (go_back_cb):
+ (go_forward_cb):
+ (create_browser):
+ (create_statusbar):
+ (create_toolbar):
+ (create_window):
+ (main):
+ * GtkLauncher/main.cpp: Removed.
+
+2007-11-19 Kevin Ollivier <kevino@theolliviers.com>
+
+ Build script fixes to ensure they do the right thing for the
+ wx port, and update build-wxwebkit to reflect the way the
+ build scripts now work.
+
+ Reviewed by Adam.
+
+ * Scripts/build-testkjs:
+ * Scripts/build-webkit:
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/webkitdirs.pm:
+ * wx/build-wxwebkit:
+
+2007-11-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Anders.
+
+ Make run-javascriptcore-tests report failures on exit (to support git bisect)
+
+ * Scripts/run-javascriptcore-tests:
+
+2007-11-18 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Make run-webkit-tests work with Windows debug build.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp: (main): Only use memory checks with debug CRT.
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Switched Debug configuration to release CRT,
+ as it is supposed to run with release Apple libraries. Removed _DEBUG preprocessor
+ symbol, as it goes with debug CRT (AFAIK, it is supposed to be added automatically,
+ and shouldn't be needed in Debug_internal configuration, but I didn't dare to change that).
+
+2007-11-18 Kevin Ollivier <kevino@theolliviers.com>
+
+ Add wxWebKit sample and build script, and integrate it with
+ build-webkit. Also make build-webkit --clean work for all
+ ports.
+
+ Reviewed by Darin Adler.
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+ * wx: Added.
+ * wx/browser: Added.
+ * wx/browser/browser.bkl: Added.
+ * wx/browser/browser.cpp: Added.
+ * wx/build-wxwebkit: Added.
+
+2007-11-17 Adam Roben <aroben@apple.com>
+
+ Make it easy to run Safari in the debugger on Windows
+
+ I've added a new script, debug-safari, which launches Safari in the
+ debugger. On OS X it just calls gdb-safari.
+
+ Reviewed by Mark Rowe.
+
+ * FindSafari/FindSafari.cpp:
+ (_tmain): Added a /debugger flag, which in combination with
+ /printSafariLauncher will print a script that launches Safari in the
+ debugger.
+ * Scripts/debug-safari: Added.
+ * Scripts/run-safari: Changed to call runSafari().
+ * Scripts/run-webkit-nightly.cmd: Prepends the launcher script with
+ vsvars32.bat, which will let us find VS/VC++ Express, and passes the
+ first argument along to FindSafari.
+ * Scripts/webkitdirs.pm:
+ (sub runSafari): Added.
+
+2007-11-16 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ * Scripts/run-webkit-tests: Avoid an uninitialized warning if WEBKIT_TESTFONTS is not defined.
+
+2007-11-16 Ryan Leavengood <leavengood@gmail.com>
+
+ Reviewed by David Kilzer.
+
+ The git config command was renamed to repo-config at some point. This
+ change tries git config and then git repo-config if the first fails.
+
+ * Scripts/prepare-ChangeLog:
+ (gitConfig):
+
+2007-11-16 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Darin Adler and Sam Weinig.
+
+ - fix <rdar://problem/5134075> fast/forms/select-type-ahead-non-latin.html fails on Windows
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback): For characters that cannot be entered on the active
+ keyboard layout, send a WM_CHAR message with the character along with
+ a WM_KEYDOWN message with a virtual key code of 255.
+
+2007-11-16 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ Don't weak link against WebCore now that it is a sub-framework of WebKit in all configurations.
+
+ * Drosera/mac/Drosera.xcodeproj/project.pbxproj:
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-11-15 Adam Roben <aroben@apple.com>
+
+ Make run-safari actually work on Windows
+
+ * Scripts/run-safari: Fixed the order of arguments to cp, and added a
+ chdir call.
+
+2007-11-14 Adam Roben <aroben@apple.com>
+
+ Updates to Safari launching now that 3.0.4 is released
+
+ Reviewed by Sam.
+
+ * FindSafari/FindSafari.cpp:
+ (getWebViewCLSID): Use version-independent ProgID.
+ * Scripts/run-safari: Use run-webkit-nightly.cmd.
+
+2007-11-14 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam.
+
+ <rdar://problem/5309081>
+ In DRT, "plugin.logDestroy = true" not working on Windows.
+
+ * DumpRenderTree/win/TestNetscapePlugin/main.c:
+ (NPP_Destroy):
+
+2007-11-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Sam.
+
+ * Scripts/run-sunspider: add --shark-cache for L2 Cache Miss profiling
+
+2007-11-14 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam.
+
+ <rdar://problem/5141186>
+ window.layoutTestController.setWindowIsKey is not implemented in DRT.
+
+ Implement setWindowIsKey.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setWindowIsKey):
+
+2007-11-13 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Fix for <rdar://problem/5382579>
+ http/tests/security/cross-frame-access-put.html reports large
+ negative numbers for screenLeft and screenTop (Mac reports "0")
+
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::UIDelegate): Initialize the RECT.
+ (UIDelegate::setFrame): copy the contents of the rect, not the pointer.
+ (UIDelegate::webViewFrame): ditto.
+ * DumpRenderTree/win/UIDelegate.h: Use a RECT not a RECT*
+
+2007-11-13 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Make Drosera show source, source URLs, and function stack on Windows,
+ and some minor fixes.
+
+ * Drosera/DebuggerDocument.cpp: Force source to always update display.
+ (DebuggerDocument::updateFileSource):
+ * Drosera/debugger.js: Force source to always update display.
+ * Drosera/win/DebuggerClient.cpp: Create the needed functions for the
+ menu controls.
+ (DebuggerClient::resume):
+ (DebuggerClient::pause):
+ (DebuggerClient::stepInto):
+ (DebuggerClient::stepOver):
+ (DebuggerClient::stepOut):
+ (DebuggerClient::showConsole):
+ (DebuggerClient::closeCurrentFile):
+ * Drosera/win/DebuggerClient.h: Ditto.
+ * Drosera/win/DebuggerDocumentPlatform.cpp: Changed
+ getPlatformCurrentFunctionStack to not use an unecessary HRESULT and
+ removed two bugs. 1) caller could be in a bad state when asked to
+ assign into it. 2) BSTRs were not created correctly.
+ (DebuggerDocument::getPlatformCurrentFunctionStack):
+ * Drosera/win/Drosera.cpp: Hook up the menu controls.
+ (droseraWndProc):
+ (handleCommand):
+ (Drosera::resume):
+ (Drosera::pause):
+ (Drosera::stepInto):
+ (Drosera::stepOver):
+ (Drosera::stepOut):
+ (Drosera::showConsole):
+ (Drosera::closeCurrentFile):
+ * Drosera/win/Drosera.h: Hook up the menu controls.
+ * Drosera/win/ServerConnection.cpp: Removed unncessary server connection
+ functions, added a null check, and fixed another bug where caller could
+ be in a bad state when asked to assign into it.
+ (ServerConnection::didLoadMainResourceForDataSource):
+ (ServerConnection::getCallerFrame):
+ * Drosera/win/ServerConnection.h: Safety first.
+
+2007-11-13 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - fix <http://bugs.webkit.org/show_bug.cgi?id=13371>
+ DumpRenderTree --pixel-tests renders each test twice
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpRenderTree): Removed the --paint option because the painting code
+ is always exercised as a result of
+ -[FrameLoadDelegate webView:didFinishLoadFromFrame:]
+ calling -displayIfNeeded.
+ (dump): Changed to always grab the image from the window since the view
+ is always displayed.
+ (runTest):
+ (displayWebView):
+ * Scripts/run-webkit-tests: No need to pass --paint to DumpRenderTree
+ because it always paints.
+
+2007-11-12 Antti Koivisto <antti@apple.com>
+
+ Reviewed by Adele.
+
+ Add support for http media tests
+
+ * Scripts/run-webkit-tests:
+
+2007-11-12 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Implement LayoutTestController.setPrivateBrowsingEnabled(bool) for windows.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setPrivateBrowsingEnabled):
+
+2007-11-12 Adam Roben <aroben@apple.com>
+
+ * Scripts/update-webkit-localizable-strings: Changed to only scan the
+ mac and win subdirectories.
+
+2007-11-11 Adam Roben <aroben@apple.com>
+
+ Fix <rdar://5133816> keepWebHistory is not implemented
+
+ Fixes fast/history/clicked-link-is-visited.html.
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest): Clear the optionalSharedHistory.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::keepWebHistory): Set the optionalSharedHistory.
+
+2007-11-10 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Tim Hatcher.
+
+ Follow up to <rdar://problem/5394877> Safari should not log unsafe JavaScript
+ attempts when in private browsing mode (only an issue if Log JavaScript Exceptions
+ is turned on)
+
+ - Add LayoutTestController.setPrivateBrowsingEnabled(bool) (stub out implementation for windows)
+
+ Added test: http/tests/security/cross-frame-access-private-browsing.html
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setPrivateBrowsingEnabledCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (runTest): Default to private browsing disabled.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setPrivateBrowsingEnabled):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setPrivateBrowsingEnabled):
+
+2007-11-08 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Changed the vcproj file to use Drosera's ForwardingHeaders and not
+ WebCore's!
+
+ * Drosera/ForwardingHeaders/wtf/Assertions.h: Added.
+ * Drosera/ForwardingHeaders/wtf/HashTraits.h: Added.
+ * Drosera/ForwardingHeaders/wtf/Noncopyable.h: Added.
+ * Drosera/ForwardingHeaders/wtf/OwnPtr.h: Added.
+ * Drosera/ForwardingHeaders/wtf/RetainPtr.h: Added.
+ * Drosera/win/Drosera.cpp:
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj:
+
+2007-11-08 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Sam.
+
+ - Use the new IWebFrame [local] function signature and get the shared
+ server correctly.
+
+ * Drosera/win/DebuggerClient.cpp:
+ (DebuggerClient::didFinishLoadForFrame):
+ * Drosera/win/ServerConnection.cpp:
+ (ServerConnection::attemptToCreateServerConnection):
+
+2007-11-07 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - add an option to run-webkit-tests to ignore pixel test failures where
+ all pixels differ by no more than a specified threshold
+
+ * DumpRenderTree/mac/ImageDiff.m:
+ (main):
+ (compareImages):
+ (computePercentageDifferent):
+ * Scripts/run-webkit-tests:
+
+2007-11-07 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by Lars.
+
+ Make the setting of letting Javascript access the clipboard configurable through QWebSettings, turn it off by default and turn it on in DumpRenderTree.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+
+2007-11-07 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by Lars.
+
+ Reworked the QWebSettings API.
+ QWebPage now returns a pointer to its mutable QWebSettings object and the settings of newly created QWebPageObjects are initialized from QWebSettings::defaultSettings().
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+
+2007-11-07 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by Lars.
+
+ Make QWebHistory an explicitly shared object, returned as a pointer by QWebPage::history().
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+
+2007-11-07 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by Lars Knoll <lars@trolltech.com>.
+
+ Add a QWebPage::frameCreated() signal and fix DRT
+
+ The removal of createFrame in QWebPage broke the re-implementation
+ in DumpRenderTree. Instead emit a frameCreated() signal and
+ connect to it in DumpRenderTree.
+
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::DumpRenderTree::dump):
+ (WebCore::DumpRenderTree::connectFrame):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+
+2007-11-07 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by Lars Knoll <lars@trolltech.com>.
+
+ Moved all the event handlers from QWebFrame into QWebPage.
+
+ This cleans up the public API and allows us to remove the
+ HackWebFrame hack in DumpRenderTree.
+
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (EventSender::mouseDown):
+ (EventSender::mouseUp):
+ (EventSender::mouseMoveTo):
+
+2007-11-07 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by Mark.
+
+ Implemented the two Javascript prompt callbacks in qt/DumpRenderTree
+ to prevent the default implementation from popping up messageboxes.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::javaScriptConfirm):
+ (WebCore::WebPage::javaScriptPrompt):
+
+2007-11-06 Eric Seidel <eric@webkit.org>
+
+ * Scripts/build-testkjs: build fix... too many $$
+
+2007-11-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/build-testkjs: return xcodebuild's exit status, instead of grep's
+
+2007-11-05 Adam Roben <aroben@apple.com>
+
+ Add support on Windows for WEBKIT_TESTFONTS
+
+ This environment variable lets you specify where the fonts to be used
+ by DumpRenderTree reside. The Qt port is already using this, so I'm
+ just following their lead.
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (exePath): Refactored code out of initialize().
+ (fontsPath): Returns either $WEBKIT_TESTFONTS or
+ DumpRenderTree.resources.
+ (initialize): Use the new fontsPath function.
+ (main): Use the new exePath function.
+ * Scripts/run-webkit-tests: Propagate the WEBKIT_TESTFONTS environment
+ variable to DRT, like Qt does.
+
+2007-11-05 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Alp Toker.
+
+ Remove buggy "autocomplete" from GtkLauncher as it causes more problems than it solves.
+
+ * GtkLauncher/main.cpp:
+ (goToURLBarText):
+ (main):
+
+2007-11-04 David D. Kilzer <ddkilzer@webkit.org>
+
+ bisect-builds doesn't work with nightly build r19992 or newer on Leopard
+ <http://bugs.webkit.org/show_bug.cgi?id=15830>
+
+ Reviewed by Timothy.
+
+ Restrict the range of nightly builds used by the bisect-builds script
+ based on the version of Safari and the version of Mac OS X being used.
+
+ Mac OS X 10.4: Safari 2.0: r11976 or newer
+ Mac OS X 10.4: Safari 3.0: r19992 or newer
+
+ Mac OS X 10.5: Safari 2.0: r19594 or newer
+ Mac OS X 10.5: Safari 3.0: r25124 or newer
+
+ * Scripts/bisect-builds:
+ (findMacOSXVersion): Added.
+ (makeNightlyList): Added argument to provide version of Mac OS X.
+ Restrict range of nightly builds based on Safari and Mac OS X versions.
+
+2007-11-04 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Maciej.
+
+ - This patch involves several changes, all of them were noticed that
+ they were needed by the work being done in WebKit to get Drosera and
+ WebKit working together on Windows.
+ - The changes are:
+ 1) Added a debugger console for output messages.
+ 2) Drosera now listens for the WebKit server (before, the server would
+ have to be running before Drosera was started.)
+ 3) Fixed a bug where the WebView started out as 0x0 pixels.
+ 4) Fixed a bug when there is no scope.
+ 5) Added the HTML, JS, and CSS to the project file to make them easy to
+ find.
+ 6) Made the ServerConnection functions virtual.
+
+ * Drosera/win/DebuggerClient.cpp: This is part of how Drosera listens
+ for the WebKit server.
+ (DebuggerClient::DebuggerClient):
+ (DebuggerClient::~DebuggerClient):
+ (DebuggerClient::didFinishLoadForFrame):
+ (DebuggerClient::serverConnected):
+ (DebuggerClient::attemptToCreateServerConnection):
+ * Drosera/win/DebuggerClient.h: Ditto.
+ * Drosera/win/DebuggerDocumentPlatform.cpp: Fixed a bug when there is no
+ scope.
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ (DebuggerDocument::platformValueForScopeVariableNamed):
+ * Drosera/win/Drosera.cpp:
+ (_tWinMain): Added a console in debug for output messages.
+ (Drosera::Drosera): Listen for server.
+ (Drosera::initUI): The server now Initializes COM.
+ (Drosera::serverConnected): Part of the listening for the server.
+ (Drosera::attemptToCreateServerConnection): Ditto.
+ * Drosera/win/Drosera.h: New interface for listening for the server.
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj: Added HTML, JS, and CSS
+ files to the VS project.
+ * Drosera/win/ServerConnection.cpp: Part of listening for the server
+ connection.
+ (ServerConnection::ServerConnection):
+ (ServerConnection::attemptToCreateServerConnection):
+ * Drosera/win/ServerConnection.h: Ditto and virtualized the Interface
+ methods.
+ (ServerConnection::serverConnected):
+
+2007-11-04 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Maciej.
+
+ http://bugs.webkit.org/show_bug.cgi?id=15832
+ fast/dom/gc-10.html crashes when run alone
+
+ Check for !done before using objects that can be already deallocated.
+
+ * DumpRenderTree/mac/EditingDelegate.mm:
+ (-[EditingDelegate webView:shouldBeginEditingInDOMRange:]):
+ (-[EditingDelegate webView:shouldEndEditingInDOMRange:]):
+ (-[EditingDelegate webView:shouldInsertNode:replacingDOMRange:givenAction:]):
+ (-[EditingDelegate webView:shouldInsertText:replacingDOMRange:givenAction:]):
+ (-[EditingDelegate webView:shouldDeleteDOMRange:]):
+ (-[EditingDelegate webView:shouldChangeSelectedDOMRange:toDOMRange:affinity:stillSelecting:]):
+ (-[EditingDelegate webView:shouldApplyStyle:toElementsInDOMRange:]):
+ (-[EditingDelegate webView:shouldChangeTypingStyle:toStyle:]):
+ (-[EditingDelegate webViewDidBeginEditing:]):
+ (-[EditingDelegate webViewDidChange:]):
+ (-[EditingDelegate webViewDidEndEditing:]):
+ (-[EditingDelegate webViewDidChangeTypingStyle:]):
+ (-[EditingDelegate webViewDidChangeSelection:]):
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate webView:didStartProvisionalLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didCommitLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didFailProvisionalLoadWithError:forFrame:]):
+ (-[FrameLoadDelegate webView:didFinishLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didFailLoadWithError:forFrame:]):
+ (-[FrameLoadDelegate webView:windowScriptObjectAvailable:]):
+ (-[FrameLoadDelegate webView:didClearWindowObject:forFrame:]):
+ (-[FrameLoadDelegate webView:didReceiveTitle:forFrame:]):
+ (-[FrameLoadDelegate webView:didReceiveServerRedirectForProvisionalLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didReceiveIcon:forFrame:]):
+ (-[FrameLoadDelegate webView:didChangeLocationWithinPageForFrame:]):
+ (-[FrameLoadDelegate webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:]):
+ (-[FrameLoadDelegate webView:didCancelClientRedirectForFrame:]):
+ (-[FrameLoadDelegate webView:willCloseFrame:]):
+ (-[FrameLoadDelegate webView:didFinishDocumentLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didHandleOnloadEventsForFrame:]):
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:identifierForInitialRequest:fromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:willSendRequest:redirectResponse:fromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:didReceiveResponse:fromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:didFinishLoadingFromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:didFailLoadingWithError:fromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:willCacheResponse:fromDataSource:]):
+
+2007-11-04 Mark Rowe <mrowe@apple.com>
+
+ Build fix. Don't use Carbon.h as the prefix header as it triggers
+ warnings that would otherwise be suppressed due to it being a system header.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-11-03 Maciej Stachowiak <mjs@apple.com>
+
+ Rubber stamped by Adam.
+
+ - Turn off deprecated function warnings for TestNetscapePlugin because Carbon.h triggers them
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-11-03 David D. Kilzer <ddkilzer@webkit.org>
+
+ Sort files(...); sections of Xcode project files.
+
+ Rubber-stamped by Darin Adler.
+
+ * DrawTest/DrawTest.xcodeproj/project.pbxproj:
+ * Drosera/mac/Drosera.xcodeproj/project.pbxproj:
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj:
+
+2007-11-03 David D. Kilzer <ddkilzer@webkit.org>
+
+ Script to sort "files(...);" sections in Xcode project.pbxproj files.
+
+ Reviewed by Darin Adler.
+
+ * Scripts/sort-Xcode-project-file: Added.
+
+2007-11-02 Darin Adler <darin@apple.com>
+
+ * Scripts/run-sunspider: Changed "--base" to "--set-baseline".
+
+2007-11-02 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej.
+
+ * Scripts/run-sunspider: Pass the "--base" option through.
+
+ * Scripts/sunspider-compare-results: Don't check the number of parameters; let
+ the real script do that. Default configuration to Release to match run-sunspider
+ so we don't end up building Debug just to compare results.
+
+2007-11-01 Adam Roben <aroben@apple.com>
+
+ Make changes in WebKit/win show up under "WebKit/win:" instead of just "win:"
+
+ Reviewed by Sam.
+
+ * Scripts/commit-log-editor: Show all the directories beneath the
+ source root, instead of just the last one.
+
+2007-11-01 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Adam Roben.
+
+ Print out an error message when the Windows build fails
+ and provide guidance on how to find out what went wrong.
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2007-11-01 Alexey Proskuryakov <ap@webkit.org>
+
+ Rubber-stamped by Adam Roben.
+
+ Rolled out r27326 - debug CRT seems to cause no problems after all.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+2007-10-31 Adam Roben <aroben@apple.com>
+
+ Switch the Debug configuration to using the non-debug CRT
+
+ This matches WebKit.
+
+ Reviewed by Steve.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+2007-10-31 Antti Koivisto <antti@apple.com>
+
+ Reviewed by bdash.
+
+ Disable media tests when doing leak checking on Tiger.
+ They crash in QuickTime (rdar://problem/5537157).
+
+ * Scripts/run-webkit-tests:
+
+2007-10-29 Antti Koivisto <antti@apple.com>
+
+ Reviewed by Maciej.
+
+ Build media support by default on OSX only.
+
+ * Scripts/build-webkit:
+
+2007-10-30 Kevin McCullough <kmccullough@apple.com>
+
+ - Made Adam the reviewer for a previous checkin. Not sure how it didn't
+ get caught by the pre-commit hooks.
+
+2007-10-30 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - This is a collection of relatively unrelated changes and cleanups
+ to Drosera to prepare it for interacting with WebKit. A lot of these
+ changes are just correcting mistakes, for example removing included
+ headers that are no longer needed.
+
+ * Drosera/DebuggerDocument.h: Added accessor for the ServerConnection
+ this will be needed by the DebuggerClient.
+ (DebuggerDocument::server):
+ * Drosera/win/BaseDelegate.h: Removed unnecessary include.
+ * Drosera/win/DebuggerClient.cpp:
+ (DebuggerClient::didFinishLoadForFrame): Finished implementing.
+ (DebuggerClient::didReceiveTitle): Added comment about its purpose.
+ (DebuggerClient::createWebViewWithRequest): Added comment about its
+ purpose.
+ * Drosera/win/DebuggerClient.h: Removed unnecessary include, and forward
+ declarations.
+ (DebuggerClient::webViewLoaded): Moved.
+ * Drosera/win/Drosera.cpp: Moved a function from the HelperFunctions
+ file, since this was the only place it was used.
+ (cfStringToBSTR):
+ * Drosera/win/Drosera.h: Cleaned up the includes.
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj: Removed HelperFunctions.h
+ * Drosera/win/HelperFunctions.h: Removed.
+
+2007-10-30 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Small cleanup in the ServerConnection class.
+
+ * Drosera/win/ServerConnection.cpp: Added comments, moved some functions
+ and added an include.
+ (ServerConnection::currentFrame):
+ (ServerConnection::getCallerFrame):
+ * Drosera/win/ServerConnection.h: Added comments, moved some functions,
+ made a pointer into a COMPtr, and cleaned up the includes.
+
+2007-10-29 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by John Sullivan.
+
+ - Place the Localizable.strings file in mac or win directories
+ if that location exists.
+ - Also look for UI_STRING in .c files.
+
+ * Scripts/extract-localizable-strings:
+
+2007-10-30 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Set the eol-style to native and made all the line endings the same
+ so that I avoid messy diffs that show eol changes.
+
+ * Drosera/win/ServerConnection.cpp:
+ (ServerConnection::didParseSource):
+ (ServerConnection::didEnterCallFrame):
+ (ServerConnection::willExecuteStatement):
+ (ServerConnection::willLeaveCallFrame):
+ (ServerConnection::exceptionWasRaised):
+
+2007-10-30 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ * Drosera/win/DebuggerDocumentPlatform.cpp:Implemented much of the
+ functionality that could not have existed previously without the new
+ interfaces.
+ (JSValueRefCreateWithBSTR): Added a helper function to easily convert
+ from a BSTR to a JSValueRef.
+ (DebuggerDocument::platformEvaluateScript): Implemented.
+ (DebuggerDocument::getPlatformCurrentFunctionStack): Implemented.
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ Implemented.
+ (DebuggerDocument::platformValueForScopeVariableNamed): Implemented.
+ * Drosera/win/HelperFunctions.h: Cleaned up some comments.
+ * Drosera/win/ServerConnection.cpp: Added a helper function.
+ (ServerConnection::getCallerFrame):
+ * Drosera/win/ServerConnection.h: Added a helper function.
+
+2007-10-29 Kevin McCullough <kmccullough@apple.com>
+
+ updated reviewers for my previous changelog.
+
+2007-10-29 Kevin McCullough <kmccullough@apple.com>
+ Reviewed by Maciej and Adam and Geoff.
+
+ - Minor mac-side improvements including moving a function to a more
+ appropriate location, fixing a warning, and correctly checking
+ exceptions.
+
+ * Drosera/DebuggerDocument.cpp: Corrected the exception checking.
+ (DebuggerDocument::willExecuteStatement):
+ (DebuggerDocument::didEnterCallFrame):
+ (DebuggerDocument::willLeaveCallFrame):
+ (DebuggerDocument::windowScriptObjectAvailable):
+ (DebuggerDocument::callFunctionOnObject):
+ * Drosera/mac/DebuggerClient.mm: Fixes a warning.
+ * Drosera/mac/DebuggerDocumentPlatform.mm: Moved
+ webScriptAttributeKeysForScriptObject to DebuggerDocumentPlatform
+ because it doesn't require the ServerConnection at all.
+ (NSStringCreateWithJSStringRef): Made an argument const.
+ (JSValueRefCreateWithNSString): Made an argument const.
+ (+[WebScriptObject webScriptAttributeKeysForScriptObject:]):
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ * Drosera/mac/ServerConnection.h: Moved aforementioned function.
+ * Drosera/mac/ServerConnection.mm: Ditto.
+ (-[ServerConnection webView:didLoadMainResourceForDataSource:]):
+
+2007-10-29 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Add a globalFlag property to the LayoutTestController to allow cross-domain indications.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (getGlobalFlagCallback):
+ (setGlobalFlagCallback):
+ (LayoutTestController::getJSClass):
+ (LayoutTestController::staticValues):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::globalFlag):
+ (LayoutTestController::setGlobalFlag):
+
+2007-10-29 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej.
+
+ * Scripts/run-sunspider: Added --shark20 option, to run Shark at its highest sample
+ resolution instead of its default.
+
+2007-10-29 David Kilzer <ddkilzer@webkit.org>
+
+ Fixed showStatus() to print status for successfully resolved conflicts when using git.
+
+ Reviewed by Mark Rowe.
+
+ Previously showStatus() would run "git diff --name-status" after a ChangeLog conflict
+ was successfully resolved, but this would not show any status because the change had
+ already been cached in the index using "git add". The solution is to add an optional
+ second argument to showStatus() which adds the "--cached" switch to the command.
+
+ * Scripts/resolve-ChangeLogs:
+ (showStatus):
+
+2007-10-28 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Maciej and Geoff, in unison.
+
+ * Scripts/run-webkit-tests: remove broken --svg option
+
+2007-10-28 Darin Adler <darin@apple.com>
+
+ Reviewed by Adam.
+
+ * Scripts/run-sunspider: Default to "Release" configuration rather than
+ defaulting to the last configuration used as other scripts do. This can
+ still be overriden on the command line with "--debug" if there's some
+ reason to do so. Also fix a typo.
+
+ * Scripts/sunspider-compare-results: Fix a typo.
+
+2007-10-26 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Implemented the WebScriptDebugListener functions now that the
+ WebScriptDebugServer exists
+
+ * Drosera/win/ServerConnection.cpp: Implemented WebScriptDebugListener
+ functions.
+ (ServerConnection::currentFrame):
+ (ServerConnection::didLoadMainResourceForDataSource):
+ (ServerConnection::didParseSource):
+ (ServerConnection::failedToParseSource):
+ (ServerConnection::didEnterCallFrame):
+ (ServerConnection::willExecuteStatement):
+ (ServerConnection::willLeaveCallFrame):
+ (ServerConnection::exceptionWasRaised):
+ * Drosera/win/ServerConnection.h: Removed unused arguments from the
+ members arguments list.
+
+2007-10-26 David Kilzer <ddkilzer@webkit.org>
+
+ prepare-ChangeLog and update-webkit create needless ChangeLog conflicts
+ <http://bugs.webkit.org/show_bug.cgi?id=15600>
+
+ Reviewed by Darin Adler.
+
+ The resolve-ChangeLog script merges conflicted ChangeLogs in svn or git by creating
+ a patch of the local changes and applying it with a fuzz level of 3 to the new file.
+ If the patch is successful, it runs 'svn resolved' or 'git add' on the new ChangeLog
+ file. Note that it may also be used as a stand-alone script.
+
+ * Scripts/prepare-ChangeLog: Call resolve-ChangeLogs for conflicted ChangeLog files.
+ * Scripts/resolve-ChangeLogs: Added.
+ * Scripts/update-webkit: Call resolve-ChangeLogs for conflicted ChangeLog files.
+
+2007-10-26 Mark Rowe <mrowe@apple.com>
+
+ Qt build fix. r27084 added a destructor implementation for LayoutTestController
+ to the Qt port on the assumption that it was an implementation of the cross-platform
+ LayoutTestController class. It is not, so it did not need to be changed.
+
+ * DumpRenderTree/qt/jsobjects.cpp: Remove empty destructor.
+
+2007-10-25 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Maciej.
+
+ Fix builds with code coverage enabled.
+
+ * Scripts/build-webkit: Don't overwrite the existing value of OTHER_LDFLAGS.
+
+2007-10-25 Darin Adler <darin@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/make-js-test-wrappers: Don't generate a wrapper for intersectsNode.js.
+ * Scripts/prepare-ChangeLog: Add a special case for prefix of empty string.
+
+2007-10-25 Stephanie <slewis@apple.com>
+
+ build Fix
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-10-25 Stephanie <slewis@apple.com>
+
+ Reviewed by Mark Rowe, Adam Roben.
+
+ Weak link against WebCore so DumpRenderTree can be bundled with production roots.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-10-25 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Adam.
+
+ Fixed <rdar://5549689> 2 tests in fast/forms fail when run with other tests on Windows
+
+ Moving destructor into platform-specific files
+ * DumpRenderTree/LayoutTestController.cpp:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::~LayoutTestController):
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::~LayoutTestController):
+
+ LayoutTestController wasn't being destroyed
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest):
+
+ Added declspec
+ * DumpRenderTree/win/EditingDelegate.h:
+
+ Reset certain values on the webview (or related delegate) that might
+ have changed while running a test
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::~LayoutTestController):
+
+2007-10-25 Adam Roben <aroben@apple.com>
+
+ Make sunspider-compare-results work with relative paths
+
+ Reviewed by Sam.
+
+ * Scripts/sunspider-compare-results: Convert arguments to absolute
+ paths before we chdir.
+
+2007-10-25 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Sam.
+
+ - Implemented server calls now the WebScriptDebugServer exists.
+ - Also removed no longer needed call to initialize CG.
+
+ * Drosera/win/Drosera.cpp: No longer initializes CG because this happens
+ automatically now.
+ (_tWinMain):
+ * Drosera/win/ServerConnection.cpp: Now uses the COM class.
+ (ServerConnection::ServerConnection):
+ (ServerConnection::~ServerConnection):
+ (ServerConnection::pause):
+ (ServerConnection::resume):
+ (ServerConnection::stepInto):
+ (ServerConnection::applicationTerminating):
+ (ServerConnection::serverConnectionDidDie):
+ * Drosera/win/ServerConnection.h: Now uses the COM class.
+
+2007-10-24 George Staikos <staikos@kde.org>
+
+ Unbreak Qt build.
+
+ * Scripts/build-webkit:
+
+2007-10-24 Adam Roben <aroben@apple.com>
+
+ Remove now-unnecessary call to InitializeCoreGraphics
+
+ WebKit takes care of this now.
+
+ Reviewed by Ada.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (initialize):
+
+2007-10-24 Adam Roben <aroben@apple.com>
+
+ Use WebTextRenderer in DRT
+
+ Reviewed by Ada.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (initialize): Use WebTextRenderer instead of using AddFontResourceEx.
+
+2007-10-24 Sven Herzberg <sven@imendio.com>
+
+ Reviewed by Mark Rowe.
+
+ Fixes http://bugs.webkit.org/show_bug.cgi?id=15614
+ Bug 15614: [GTK] qmake based backends don't build on OS X
+
+ * Scripts/build-webkit: set QMAKESPEC correctly if building the QT or
+ GTK backend on a Mac
+ * Scripts/webkitdirs.pm: extracted the darwin-test from isOSX() into
+ isDarwin() to make it reusable in other places (like the workaround-
+ for-prebuilt-qmake in build-webkit)
+
+2007-10-24 David Kilzer <ddkilzer@webkit.org>
+
+ Refurbish update-webkit script.
+
+ Reviewed by Adam.
+
+ * Scripts/update-webkit: Add -h|--help switch and usage statement. Check result of
+ GetOptions() call. Fix -q|--quiet switch to be passed to svn command properly. Use
+ multi-argument version of system() for flexibility and security. Check for existence
+ of Internal directory using -d test instead of -x.
+
+2007-10-24 David Kilzer <ddkilzer@webkit.org>
+
+ Minor clean-up of prepare-ChangeLog script.
+
+ Reviewed by Adam.
+
+ * Scripts/prepare-ChangeLog: Keep list of updated ChangeLog files in an array instead
+ of a string. Use multi-argument versions of open() and system() for flexibility and
+ security.
+
+2007-10-24 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Oliver.
+
+ Fix <rdar://5410959> editing/selection/drag-to-contenteditable-iframe.html fails on Windows
+
+ Move the call to replaySavedEvents from doDragDrop to doMouseMove because we don't want to
+ replay the saved events when we're still processing the mousedown that starts the drag
+ * DumpRenderTree/win/EventSender.cpp:
+ (doMouseMove):
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::doDragDrop):
+
+2007-10-24 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Sam, Steve and Darin.
+
+ - Stubbed out the WebScriptDebugListener functionality in the Server
+ Connection class to prepare it for receiving those callbacks.
+ - Also I changed the instantiation of DebuggerClient, DebuggerDocument
+ and the ServerConnection to not need to be initialized with a server
+ name, since that is not the way we connect to the WebKit server.
+
+ * Drosera/DebuggerDocument.cpp: Fixed a bug where I was always logging
+ no exception. Now it only loggs when there is an exception
+ (DebuggerDocument::willExecuteStatement):
+ (DebuggerDocument::didEnterCallFrame):
+ (DebuggerDocument::willLeaveCallFrame):
+ (DebuggerDocument::windowScriptObjectAvailable):
+ (DebuggerDocument::callFunctionOnObject):
+ * Drosera/win/DebuggerClient.cpp: No longer needs the ServerConnection
+ to be instantiated with a server's name.
+ (DebuggerClient::DebuggerClient):
+ (DebuggerClient::didFinishLoadForFrame):
+ * Drosera/win/DebuggerClient.h: Removed unsued variable.
+ * Drosera/win/Drosera.cpp: Client no longer needs to be initialized with
+ a server name.
+ (Drosera::init):
+ (Drosera::initServer):
+ * Drosera/win/Drosera.h: No longer need the ServerConnection to be
+ instantiated with a server's name.
+ * Drosera/win/ServerConnection.cpp:
+ (ServerConnection::ServerConnection): No longer needs a server name
+ (ServerConnection::~ServerConnection): Only release the global context
+ if there is one.
+ (ServerConnection::serverConnectionDidDie): Stub for
+ IWebScriptDebugListener
+ (ServerConnection::QueryInterface): ditto
+ (ServerConnection::AddRef): ditto
+ (ServerConnection::Release): ditto
+ (ServerConnection::didLoadMainResourceForDataSource): ditto
+ (ServerConnection::didParseSource): ditto
+ (ServerConnection::failedToParseSource): ditto
+ (ServerConnection::didEnterCallFrame): ditto
+ (ServerConnection::willExecuteStatement): ditto
+ (ServerConnection::willLeaveCallFrame): ditto
+ (ServerConnection::exceptionWasRaised): ditto
+ * Drosera/win/ServerConnection.h: Stubbed out the
+ IWebScriptDebugListener functions, and this class no longer needs to be
+ instantiated with a server name.
+
+2007-10-24 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ add a layoutTestController.dumpSelectionRect() dummy. It only has an effect on mac pixel tests anyway. Makes us pass another 5 test cases.
+
+ * DumpRenderTree/qt/jsobjects.h:
+
+2007-10-24 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ add another command.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (TextInputController::doCommand):
+
+2007-10-24 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ add empty eventSender.clearKillRing(), and map some of the special keys used in eventSender.keyDown() to things that work on Qt/X11.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (EventSender::keyDown):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2007-10-24 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ implement eventSender.keyDown().
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (EventSender::keyDown):
+
+2007-10-24 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ some smaller fixes to the editing support in DRT. Makes another few tests pass.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::initJSObjects):
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (TextInputController::doCommand):
+
+2007-10-24 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ first bit of implementation for the textinputcontroller.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (TextInputController::TextInputController):
+ (TextInputController::doCommand):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2007-10-24 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ make the man webpage believe it has focus, so the editing tests work correctly.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2007-10-24 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ implement layoutTestController.dumpEditingCallbacks() correctly.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::dumpEditingCallbacks):
+
+2007-10-24 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ Implement support for testing editing.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2007-10-23 Sam Weinig <sam@webkit.org>
+
+ Check for null BSTR that can be passed to the UIDelegate methods
+ from javascript null and undefined. Fixes a failing test case on
+ Windows (fast/dom/Window/alert-undefined.html)
+
+ Reviewed by Eric Seidel.
+
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::runJavaScriptAlertPanelWithMessage):
+ (UIDelegate::runJavaScriptConfirmPanelWithMessage):
+ (UIDelegate::runJavaScriptTextInputPanelWithPrompt):
+ (UIDelegate::webViewAddMessageToConsole):
+
+2007-10-23 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Don't print a massive pile of setenvs from tools that automatically build testkjs.
+
+ * Scripts/build-testkjs:
+
+2007-10-23 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - add wrapper that finds the right copy of testkjs
+
+ * Scripts/sunspider-compare-results: Added.
+
+2007-10-23 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Sam.
+
+ - After talking with Steve I now see that the WebKit server must be
+ running for DCOM to create the distributed objects, which makes sense
+ and currently WebKit only allows one instance to be running at a time
+ which avoids accidentally connecting to the wrong server
+ - In light of this I have removed the code for the attach box and
+ NotificationServer and known server names, since they are all extranious
+ now.
+
+ * Drosera/win/Drosera.cpp: Removed notification classes and known server
+ names.
+ (_tWinMain): Uses init instead of initUI.
+ (droseraWndProc): No longer creats an attach dialog box.
+ (Drosera::Drosera): Does the OleInitialize so COM is ready to go and
+ it's not manditory to call init before doing COM stuff.
+ (Drosera::init): calls initUI and will call attach when the
+ functionality exists.
+ (Drosera::initUI): Has changed very little.
+ (Drosera::attach): Changed the signature to reflect that we no longer
+ need the dictionary of known server names.
+ * Drosera/win/Drosera.h: Removed notification classes and known server
+ names. Also renamed and moved some functions.
+ * Drosera/win/Drosera.vcproj/Drosera.rc: Removed the Attach box.
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj: Moved resource.h from the
+ headers to the resources folder.
+ * Drosera/win/resource.h: Removed the Attach box.
+
+2007-10-22 Adam Roben <aroben@apple.com>
+
+ Windows build fix
+
+ * Scripts/build-dumprendertree: Fix path to DumpRenderTree.sln.
+
+2007-10-22 Kevin McCullough <kmccullough@apple.com>
+
+ - Removed a leak that was fixed.
+
+ * Scripts/run-webkit-tests:
+
+2007-10-19 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - Changed the Client so that the DebuggerDocument now own the
+ ServerConnection. This simplifies ownership and cleanup.
+
+ * Drosera/win/DebuggerClient.cpp: The DebuggerDocument now owns the
+ ServerConnection.
+ (DebuggerClient::initWithServerName):
+ (DebuggerClient::didFinishLoadForFrame):
+ * Drosera/win/DebuggerClient.h: DebuggerDocument now owns the
+ ServerConnection.
+ * Drosera/win/Drosera.cpp: Moved some WebFrame initialization logic to
+ until after we have a server which we are attached to.
+ (Drosera::initUI):
+ (Drosera::attach):
+ * Drosera/win/Drosera.h: Removed two needless pointers I forgot to take
+ out previously.
+
+2007-10-22 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by Nikolas.
+
+ When running build-testkjs make sure it's called through the perl interpreter, to fix the build for Qt/Windows.
+
+ * Scripts/run-javascriptcore-tests:
+
+2007-10-22 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by Nikolas.
+
+ Wrap WEXITSTATUS with a little exitStatus() helper function that falls back to the use of $returnvalue >> 8 on Windows to determine the exit status on platforms without WEXITSTATUS.
+
+ * Scripts/build-drosera:
+ * Scripts/build-dumprendertree:
+ * Scripts/build-testkjs:
+ * Scripts/build-webkit:
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/run-sunspider:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2007-10-22 Andrew Wellington <proton@wiretapped.net>
+
+ Reviewed by Mark Rowe.
+
+ Fix for local database support after r26879
+ Ensure that ENABLE_DATABASE and ENABLE_ICONDATABASE are correctly set
+
+ * Scripts/build-webkit:
+
+2007-10-22 Holger Freyther <zecke@selfish.org>
+
+ Reviewed by Simon Hausmann <hausmann@kde.org>.
+
+ - Do not build testkjs as an application bundle. This is
+ needed for run-javascriptcore-tests on OSX.
+ - Also, based on r26633, allow to test the WebKit/Qt port on OSX.
+ - Set DYLD_LIBRARY_PATH if it was set in the environment. It must be set
+ as we do not have -rpath on OSX.
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * Scripts/run-webkit-tests:
+
+2007-10-22 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by aroben.
+
+ Fix support for Signed-off-by detection in prepare-ChangeLog
+ --git-commit. The Signed-off-by tag does not appear in the header
+ but usually at the end.
+
+ * Scripts/prepare-ChangeLog:
+
+2007-10-21 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Eric.
+
+ Fix run-javascriptcore-tests for Gtk.
+
+ * Scripts/build-testkjs: testkjs is built by build-webkit for Gtk.
+
+2007-10-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by aroben.
+
+ * Scripts/find-extra-includes: fix path matching regex to not match ".patch"
+
+2007-10-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by darin.
+
+ Add improved argument handling to run-sunspider, including
+ --runs=<number>, --shell=<path>, --tests=<pattern>, --shark, and --help
+ Also re-factor code into subroutines
+
+ * Scripts/build-dumprendertree: removed bogus comments
+ * Scripts/build-testkjs: Added.
+ * Scripts/run-javascriptcore-tests: use build-testkjs
+ * Scripts/run-sunspider: improved argument handling, abstraction
+ * Scripts/run-webkit-tests: improved abstraction
+
+2007-10-20 Matt Lilek <webkit@mattlilek.com>
+
+ Not reviewed, Windows build fix.
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback):
+
+2007-10-20 Darin Adler <darin@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=15544
+ <rdar://problem/5076426> fast/events/arrow-navigation.html needs to
+ not rely on Apple-specific key codes
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController keyDown:withModifiers:]):
+ Added named key "rightArrow". Later we could have a whole table of these.
+ Also tweaked modifiers code a little.
+
+ * DumpRenderTree/win/EventSender.cpp: (keyDownCallback): Ditto.
+
+2007-10-19 Darin Adler <darin@apple.com>
+
+ Reviewed by Eric.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=15566
+ possible fix for leak seen in DumpRenderTree
+
+ * DumpRenderTree/WorkQueue.cpp: (WorkQueue::queue):
+ Delete the item if it's not put on the queue, since the caller has
+ no way of knowing that. Would be better to have the parameter type
+ be auto_ptr to express the fact that we take ownership.
+
+ - unrelated change
+
+ * Drosera/mac/main.m: Add missing include.
+
+2007-10-19 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - This change should be identical but for some reason was not working
+ on my machine.
+
+ * Scripts/prepare-ChangeLog:
+
+2007-10-19 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Oliver and Tim.
+
+ - Made use of RetainPtr to avoid retain and release issues and moved the
+ log function to DebuggerDocumentPlatform, which seems to be a more
+ logical place for it to live.
+ - Also moved knownServers from the ServerConnection to
+ DebuggerApplication to match the Windows code and because it makes sense
+ that a connection knows its own server but not all of them.
+
+ * Drosera/mac/DebuggerClient.h: Moved the log function to
+ DebuggerDocumentPlatform.
+ * Drosera/mac/DebuggerClient.mm: Ditto. Also do not release the server
+ Because it's owned by an own Ptr in DebuggerDocument. Also moved the
+ call for the server name up from the ServerConnection class.
+ (-[DebuggerClient dealloc]):
+ (-[DebuggerClient webView:didReceiveTitle:forFrame:]): Moved the call
+ for the server name up from the ServerConnection.
+ * Drosera/mac/DebuggerDocumentPlatform.mm: Made the server an OwnPtr.
+ (DebuggerDocument::platformPause):
+ (DebuggerDocument::platformResume):
+ (DebuggerDocument::platformStepInto):
+ (DebuggerDocument::platformEvaluateScript):
+ (DebuggerDocument::getPlatformCurrentFunctionStack):
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ (DebuggerDocument::platformValueForScopeVariableNamed):
+ (DebuggerDocument::platformLog): Log directly from here. No need to call
+ DebuggerClient.
+ * Drosera/mac/ServerConnection.h: Removed the knownServers function. The
+ way I see it, a ServerConnection should only know about its connection
+ and the group of all possible servers should be kept by the
+ application.
+ * Drosera/mac/ServerConnection.mm: Removed knownServer but added
+ currentServerName, it makes sense that the connection should know that
+ name.
+ (-[ServerConnection currentServerName]):
+
+2007-10-19 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Integrated changes from mac drosera. Recently I've encapsulated
+ out the server connection object from the rest of Drosera because
+ it is very platform dependent right now and RPC is not implemented on
+ windows. This functionality, of communicating with the WebKit server
+ is the next area I will be focusing on in Windows.
+
+ - Other changes and cleanup were made to organize the code and add notes
+ on which parts still need work. Also some mac code is added and
+ commented out, to act as pseudocode for the logic of those parts.
+
+ * Drosera/DebuggerDocument.h: Make the ServerConnection live in a smart
+ pointer.
+ * Drosera/config.h: Added whitespace.
+ * Drosera/win/DebuggerApplication.cpp: Removed. The functionality of
+ these files got moved into Drosera.h/cpp
+ * Drosera/win/DebuggerApplication.h: Removed.
+ * Drosera/win/DebuggerClient.cpp: Lots of cleanup and restructuring
+ happened here to better match the logic flow of the same code on the
+ mac side and to use the new ServerConnection class.
+ (DebuggerClient::DebuggerClient): Constructor that takes a server name.
+ (DebuggerClient::initWithServerName): Initializer that will set up the
+ class to use a ServerConnection object. This was necessary so I could
+ create a DebuggerClient without having to initilaize it at
+ construction.
+ (DebuggerClient::QueryInterface): Moved from Drosera.cpp, the Client
+ will be the UIDelegate and FrameLoadDelegate.
+ (DebuggerClient::AddRef): For IUnknown.
+ (DebuggerClient::Release): For IUnknown.
+ (DebuggerClient::didFinishLoadForFrame): Part of the FrameLoadDelegate
+ this still needs to set the global context of the server, but
+ IWebFrame does not have an accessor for the global context yet.
+ (DebuggerClient::windowScriptObjectAvailable): Part of FrameLoadDelegate
+ this is a pass through for the same function in the document.
+ (DebuggerClient::didReceiveTitle): Unimplemented part of
+ FrameLoadDelegate this would change the title of the window.
+ (DebuggerClient::createWebViewWithRequest): Part of the
+ FrameLoadDelegate. This is about new windows via Window.open() and
+ how their delegates are set.
+ (DebuggerClient::runJavaScriptAlertPanelWithMessage): Part of the
+ UIDelegate. Just a debug function for printing messages.
+ * Drosera/win/DebuggerClient.h: Moved functionality from Drosera.h
+ because the Client should be the UIDelegate and FrameLoadDelegate
+ to match the delegates on mac.
+ (DebuggerClient::webViewLoaded): Added accessor method.
+ * Drosera/win/DebuggerDocumentPlatform.cpp: Added. I had apperently
+ forgotten to add this file before. This is where the platform
+ dependent versions of the Documents functions live. Most of these are
+ unimplemented because some piece of functionality does not exist on
+ Windows yet.
+ (DebuggerDocument::platformPause):
+ (DebuggerDocument::platformResume):
+ (DebuggerDocument::platformStepInto):
+ (DebuggerDocument::platformEvaluateScript):
+ (DebuggerDocument::getPlatformCurrentFunctionStack):
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ (DebuggerDocument::platformValueForScopeVariableNamed):
+ (DebuggerDocument::platformLog):
+ * Drosera/win/Drosera.cpp: Removed UIDelegate and FrameLoadDelegate
+ responsibilities becaue they belong in the Client. Also I laid the
+ groundwork for attaching Drosera to a WebKit process
+ (attachWndProc): Now if a server is selected the Client becomes it's
+ delegate.
+ (Drosera::Drosera): Added the construction of the Client and dictionary
+ of server names.
+ (Drosera::initUI): This is no longer the delegates, the Client is.
+ (Drosera::webViewLoaded): Now asks the Client instead of holding local
+ state.
+ (Drosera::applicationDidFinishLaunching): Placeholder for needed
+ notification registration when it's possible to implement.
+ (Drosera::serverLoaded): Ditto
+ (Drosera::serverUnloaded): Ditto
+ (Drosera::attach): Attach Drosera to the WebKit server.
+ * Drosera/win/Drosera.h: Ditto for Drosera.cpp comment.
+ (Drosera::getInst):
+ (Drosera::setInst):
+ (Drosera::knownServers):
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj: Removed DebuggerApplication
+ and added the ServerConnection.
+ * Drosera/win/DroseraPrefix.h: Added an ifndef check.
+ * Drosera/win/ServerConnection.cpp: Added. This is the interesting part
+ Most of the functions are completely unimlemented because they cannot
+ connect with the WebKit server, because one does not exist on Windows
+ yet.
+ (ServerConnection::initWithServerName):
+ (ServerConnection::~ServerConnection):
+ (ServerConnection::setGlobalContext):
+ (ServerConnection::pause):
+ (ServerConnection::resume):
+ (ServerConnection::stepInto):
+ (ServerConnection::switchToServerNamed):
+ (ServerConnection::applicationTerminating):
+ (ServerConnection::serverConnectionDidDie):
+ (ServerConnection::currentFrame):
+ * Drosera/win/ServerConnection.h: Added. Ditto.
+ (ServerConnection::ServerConnection):
+
+2007-10-19 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Fix for these broken layout tests on Windows:
+
+ fast/forms/focus-selection-input.html
+ fast/forms/focus-selection-textarea.html
+ fast/forms/select-accesskey.html
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback):
+ correct the VK code for alt key.
+
+2007-10-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Make the GtkLauncher code slightly more readable.
+
+ * GtkLauncher/main.cpp:
+ (setupMainMenu): Added.
+ (setupMainWindowUI): Added.
+ (main):
+
+2007-10-19 Maciej Stachowiak <mjs@apple.com>
+
+ Rubber stamped by Adam.
+
+ - don't delay-load WebKit in DumpRenderTree.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+2007-10-18 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Adam Roben.
+
+ - fix <rdar://problem/5313523>
+ REGRESSION(Leopard): http/tests/incremental/slow-utf8-text.pl fails on Leopard
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dump): Changed to use _responseMIMEType.
+
+2007-10-17 Adam Roben <aroben@apple.com>
+
+ Make it possible to have Windows-specific tests and results
+
+ When searching for tests to run and the Skipped file, we will only
+ look in platform/win and the cross-platform directory. When looking
+ for expected results, we will look in platform/win, then
+ platform/mac-leopard, then platform/mac, then finally the
+ cross-platform directory.
+
+ Reviewed by Sam.
+
+ * Scripts/run-webkit-tests:
+ (sub expectedDirectoryForTest): Search in mac-leopard and mac before
+ searching in the cross-platform directory.
+ (sub buildPlatformHierarchy): Removed some unneeded calls to
+ dirname/basename.
+
+2007-10-17 Adam Roben <aroben@apple.com>
+
+ Add back the call to register WebKit that we had before WebKitInitializer existed
+
+ This is needed to ensure that the right WebKit is used when
+ instantiating COM objects.
+
+ Reviewed by Oliver.
+
+ * DumpRenderTree/win/debug_internal.vsprops: Define
+ DEBUG_WEBKIT_HAS_SUFFIX.
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (initialize):
+
+2007-10-17 Adam Roben <aroben@apple.com>
+
+ Import File::Basename in webkitdirs since we use it
+
+ * Scripts/webkitdirs.pm:
+
+2007-10-17 Kevin McCullough <kmccullough@apple.com>
+
+ - Updated the tiger leaks list to make the internal bots green.
+
+ * Scripts/run-webkit-tests:
+
+2007-10-17 Adam Roben <aroben@apple.com>
+
+ Build fix for VC++ Express
+
+ * FindSafari/FindSafari.vcproj: Explicitly link against advapi32.lib
+ and ole32.lib.
+
+2007-10-16 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Sam.
+
+ - Minor mac improvements based on observations I made while implementing the
+ Windows code.
+
+ * Drosera/mac/DebuggerApplication.mm: Attach does not need to create the server
+ then hand it to the Client who will retain it, it should just be the client who
+ creates and owns the server.
+ (-[DebuggerApplication attach:]):
+ * Drosera/mac/DebuggerClient.h: Can now be created with just a server name.
+ * Drosera/mac/DebuggerClient.mm: Creates the server.
+ (-[DebuggerClient initWithServerName:]):
+ * Drosera/mac/ServerConnection.mm: Does not need to include 2 header files, but
+ can instead forward declare what it needs.
+
+2007-10-16 Darin Adler <darin@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ * Scripts/run-webkit-tests: Added --add-platform-exceptions; useful when you
+ want to turn failing tests into platform-specific test results. Also did a
+ number of tweaks, including fixing a potential bug where expectedDirectoryForTest
+ would take the type of results into account only some of the time.
+
+2007-10-16 Adam Roben <aroben@apple.com>
+
+ Add a new nightly launcher script for Windows
+
+ This new script is for versions of Safari that don't delay-load
+ WebKit. I had to make FindSafari be able to print out the nightly
+ launcher script on stdout because Windows shell scripts can't capture
+ the output from a command into an environment variable.
+
+ Reviewed by Steve.
+
+ * FindSafari/FindSafari.cpp:
+ (_tmain): Added /printSafariLauncher option.
+ * Scripts/run-webkit-nightly.cmd: Added.
+
+2007-10-16 Adam Roben <aroben@apple.com>
+
+ Replace WebKitInitializer with FindSafari
+
+ We now rely on setting the PATH environment variable to tell Windows
+ where to find WebKit and its dependencies (similar to
+ DYLD_FRAMEWORK_PATH on Mac).
+
+ This change also make DumpRenderTree no longer delay-load WebKit.
+
+ Reviewed by Sam.
+
+ * DumpRenderTree/DumpRenderTree.sln: Removed WebKitInitializer, added
+ FindSafari.
+ * DumpRenderTree/win/DumpRenderTree.cpp: Don't use WebKitInitializer.
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Don't link against
+ WebKitInitializer, don't delay-load WebKit.
+ * Scripts/run-javascriptcore-tests: Call setPathForRunningWebKitApp.
+ * Scripts/run-webkit-tests: Ditto.
+ * Scripts/webkitdirs.pm:
+ (sub setPathForRunningWebKitApp): Added.
+ * WebKitInitializer/WebKitInitializer.cpp: Removed.
+ * WebKitInitializer/WebKitInitializer.h: Removed.
+ * WebKitInitializer/WebKitInitializer.vcproj: Removed.
+ * WebKitInitializer/debug.vsprops: Removed.
+ * WebKitInitializer/debug_internal.vsprops: Removed.
+ * WebKitInitializer/release.vsprops: Removed.
+
+2007-10-16 Adam Roben <aroben@apple.com>
+
+ Fix Bug 15532: run-safari fails if Safari is installed in a non-default location
+
+ http://bugs.webkit.org/show_bug.cgi?id=15532
+
+ FindSafari simply prints the location of an installed Safari.exe on
+ stdout.
+
+ Reviewed by Darin Adler.
+
+ * FindSafari/FindSafari.cpp: Copied from WebKitTools/WebKitInitializer/WebKitInitializer.cpp.
+ (getStringValue):
+ (getWebViewCLSID):
+ (getInstalledWebKitDirectory):
+ (_tmain):
+ * FindSafari/FindSafari.vcproj: Added.
+ * Scripts/webkitdirs.pm:
+ (sub installedSafariPath): Added. Calls FindSafari on Windows.
+
+2007-10-16 Adam Roben <aroben@apple.com>
+
+ Updated for rename of WebKit_debug.dll to WebKit.dll for the Debug configuration
+
+ Reviewed by Kevin McCullough.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Use WebKitDLLConfigSuffix
+ when referring to WebKit.dll.
+ * DumpRenderTree/win/debug.vsprops: Added WebKitDLLConfigSuffix.
+ * DumpRenderTree/win/debug_internal.vsprops: Ditto.
+ * DumpRenderTree/win/release.vsprops: Ditto.
+ * Scripts/run-safari: Don't pass /debug to Safari anymore because we
+ never have a _debug suffix on WebKit.dll.
+ * WebKitInitializer/WebKitInitializer.cpp:
+ (initializeWebKit): Only use the _debug suffix for WebKit.dll when
+ specified.
+ * WebKitInitializer/debug_internal.vsprops: Added
+ DEBUG_WEBKIT_HAS_SUFFIX preprocessor definition.
+
+2007-10-16 Darin Adler <darin@apple.com>
+
+ Reviewed by Adele.
+
+ * DumpRenderTree/win/EventSender.cpp: (keyDownCallback):
+ Remove now-unneeded control/alt key hack; the tests have been updated.
+
+2007-10-16 Kevin McCullough <kmccullough@apple.com>
+
+ - Updated leaks list because our internal bot upgraded it's version of leopard and
+ one of the leaks was fixed between that revision and the bot's previous version of
+ leopard.
+
+ * Scripts/run-webkit-tests:
+
+2007-10-15 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Tim.
+
+ - I encapsulated out the server connecton functionality because it is a specific part
+ of Drosera that will be platform dependant until the WebScriptDebugServer can be moved
+ into WebCore and C++. But if it is encapsulated out it can be easily replaced on
+ Windows. So the majority of this patch is moving preexisting functionality.
+
+ - Also I removed the prefix header and changed to use config.h because it is more
+ standard on how we use config.h in windows and it didn't make much sense to keep
+ the prefix header and the config.h
+
+ * Drosera/DebuggerDocument.cpp:
+ (DebuggerDocument::DebuggerDocument):
+ * Drosera/DebuggerDocument.h:
+ * Drosera/config.h:
+ * Drosera/mac/DebuggerApplication.mm:
+ (-[DebuggerApplication attach:]):
+ * Drosera/mac/DebuggerClient.h:
+ * Drosera/mac/DebuggerClient.mm:
+ (-[DebuggerClient initWithServerConnection:]):
+ (-[DebuggerClient dealloc]):
+ (-[DebuggerClient windowDidLoad]):
+ (-[DebuggerClient windowWillClose:]):
+ (-[DebuggerClient webView:didFinishLoadForFrame:]):
+ (-[DebuggerClient webView:didReceiveTitle:forFrame:]):
+ * Drosera/mac/DebuggerDocumentPlatform.mm:
+ (DebuggerDocument::platformPause):
+ (DebuggerDocument::platformResume):
+ (DebuggerDocument::platformStepInto):
+ (DebuggerDocument::platformEvaluateScript):
+ (DebuggerDocument::getPlatformCurrentFunctionStack):
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ (DebuggerDocument::platformValueForScopeVariableNamed):
+ (DebuggerDocument::platformLog):
+ * Drosera/mac/Drosera.pch: Removed.
+ * Drosera/mac/Drosera.xcodeproj/project.pbxproj:
+ * Drosera/mac/ServerConnection.h: Added.
+ * Drosera/mac/ServerConnection.mm: Added.
+ (-[ServerConnection initWithServerName:]):
+ (-[ServerConnection dealloc]):
+ (-[ServerConnection setGlobalContext:]):
+ (-[ServerConnection pause]):
+ (-[ServerConnection resume]):
+ (-[ServerConnection stepInto]):
+ (-[ServerConnection switchToServerNamed:]):
+ (-[ServerConnection applicationTerminating:]):
+ (-[ServerConnection serverConnectionDidDie:]):
+ (-[ServerConnection webView:didLoadMainResourceForDataSource:]):
+ (-[ServerConnection webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:]):
+ (-[ServerConnection webView:failedToParseSource:baseLineNumber:fromURL:withError:forWebFrame:]):
+ (-[ServerConnection webView:didEnterCallFrame:sourceId:line:forWebFrame:]):
+ (-[ServerConnection webView:willExecuteStatement:sourceId:line:forWebFrame:]):
+ (-[ServerConnection webView:willLeaveCallFrame:sourceId:line:forWebFrame:]):
+ (-[ServerConnection webView:exceptionWasRaised:sourceId:line:forWebFrame:]):
+ (-[ServerConnection currentFrame]):
+ (-[ServerConnection webScriptAttributeKeysForScriptObject:]):
+ (-[ServerConnection knownServers]):
+
+2007-10-15 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Eric.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=15002
+ Script to automatically search nightly builds for regressions (bisect-builds)
+
+ * Scripts/bisect-builds: Added.
+
+2007-10-14 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - New JavaScript benchmark
+ http://bugs.webkit.org/show_bug.cgi?id=15515
+
+ * Scripts/run-sunspider: Added. Wrapper to run sunspider on the
+ current development or release build of JavaScriptCore.
+
+2007-10-15 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam.
+
+ Fix 'run-webkit-tests --qt' complaining about the --qt argument.
+
+ * Scripts/webkitdirs.pm:
+ - Change checkArgv to remove the options from @ARGV to prevent
+ them from interfering with further option processing.
+ - Fix logic error in determineIsQt that would prevent it from bailing out early.
+ - Change isOSX to mean OS X and not Qt or Gtk. Most of our uses of isOSX assume that this is the meaning
+ already, so this change fixes several broken areas of the scripts including 'run-webkit-tests --qt' on a Mac
+ incorrectly using the Mac results, and 'run-webkit-tests --gtk' attempting to build the Mac DumpRenderTree.
+
+2007-10-15 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam.
+
+ - added logging of window.prompt and window.confirm
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:]):
+ Implement the recommended delegate rather than the deprecated one.
+ (-[UIDelegate webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:]):
+ Added.
+ (-[UIDelegate webView:runJavaScriptTextInputPanelWithPrompt:defaultText:initiatedByFrame:]):
+ Added.
+
+ * DumpRenderTree/win/UIDelegate.h:
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::runJavaScriptAlertPanelWithMessage): Got rid of unnecessary check for null string.
+ (UIDelegate::runJavaScriptConfirmPanelWithMessage): Added.
+ (UIDelegate::runJavaScriptTextInputPanelWithPrompt): Added.
+ (UIDelegate::webViewAddMessageToConsole): Got rid of unnecessary check for null string.
+
+2007-10-15 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Fixed <rdar://5382546> layoutTestController.setCustomPolicyDelegate is unimplemented causing tests to fail
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest): Like on mac, before running each test, set the webview's policy delegate to null
+ (main): allocate the global policy delegate for DRT's custom use
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ Adding files to project
+ * DumpRenderTree/win/DumpRenderTreeWin.h: declaring global DRT policy delegate
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setCustomPolicyDelegate):
+ set the webview's policy delegate to DRT's custom one if the test requests it.
+ * DumpRenderTree/win/PolicyDelegate.cpp: Added.
+ Implementation is a direct port of DumpRenderTree/mac/PolicyDelegate.mm
+ (PolicyDelegate::PolicyDelegate):
+ (PolicyDelegate::QueryInterface):
+ (PolicyDelegate::AddRef):
+ (PolicyDelegate::Release):
+ (PolicyDelegate::decidePolicyForNavigationAction):
+ * DumpRenderTree/win/PolicyDelegate.h: Added.
+ (PolicyDelegate::decidePolicyForNewWindowAction):
+ (PolicyDelegate::decidePolicyForMIMEType):
+ (PolicyDelegate::unableToImplementPolicyWithError):
+
+2007-10-14 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Mark.
+
+ * Scripts/webkitdirs.pm: Use qmake binary specified via --qmake on command-line
+ when querying for QMAKE_MKSPECS.
+
+2007-10-14 Andrew Wellington <proton@wiretapped.net>
+
+ Reviewed by Adam Roben.
+
+ Fix run-webkit-tests is too greedy calculating platform hierarchy
+ http://bugs.webkit.org/show_bug.cgi?id=15465
+
+ Fix run-webkit-tests being too greedy in trying to split the platform name up
+ causing it to try and find tests in every directory above the first "-" in the
+ path to the LayoutTests
+
+ * Scripts/run-webkit-tests:
+
+2007-10-14 Oleg Sukhodolsky <son.two@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=15006
+ Refactoring of buildQMakeGdkProject()/buildQMakeQtProject() and isGdk()/isQt()
+ to reduce code duplication.
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+ buildQMakeProject() renamed to buildQMakeQtProject().
+ buildQMakeGdkProject()/buildQMakeQtProject() now take just one parameter (directory),
+ unused $colorize has been removed.
+
+=== Start merge of feature-branch 2007-10-12 ===
+
+2007-10-08 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/build-webkit: add --help, remove unused --color
+
+2007-10-07 Eric Seidel <eric@webkit.org>
+
+ Reviewed by darin.
+
+ * Drosera/mac/DebuggerDocumentPlatform.mm:
+ (DebuggerDocument::platformEvaluateScript): null check before trying to make a JSString
+
+2007-10-03 Rob Buis <buis@kde.org>
+
+ Reviewed by Olliej.
+
+ Adapt to changed location of Ahem font.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-10-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Make pixel tests more useful!
+ Finally fix the image diff 0.00% mystery problem
+ Highlight any image differences in the image diff.
+ Add a link from image diffs back to original test file.
+
+ * DumpRenderTree/mac/ImageDiff.m:
+ (compareImages): highlight any differences
+ (computePercentageDifferent): round to two decimal places
+ * Scripts/run-webkit-tests: add a few more toURL calls for the windows folks
+
+2007-10-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ * Scripts/run-webkit-tests: print the % image difference on main results page
+
+2007-10-02 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver.
+
+ Update WebKitLauncher to notify you of new builds from the correct branch, rather than always checking trunk.
+
+ * BuildSlaveSupport/build-launcher-app: Generate a file named BRANCH into WebKit.app so that it knows which branch it was built from.
+ * WebKitLauncher/start.html: Use the new URL format that includes the branch we were built from.
+
+2007-10-01 Mark Rowe <mrowe@apple.com>
+
+ * BuildSlaveSupport/build-launcher-dmg: Tweak once more to handle nightly builds for branches.
+
+2007-09-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ DerivedSources.make was finding "ENABLE_SVG" in the string
+ "ENABLE_SVG_EXPERIMENTAL_FEATURES" thus --no-svg wasn't functioning
+ quite correctly.
+
+ * Scripts/build-webkit: make --no-svg imply --no-svg-experimental
+
+2007-09-25 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Eric.
+
+ * BuildSlaveSupport/build-launcher-dmg: Allow the platform tag to be specified on the command line.
+ This makes it possible to automate nightly builds for the feature-branch.
+
+2007-07-11 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Rubber stamped by Mark.
+
+ Enable svg experimental features as default here in feature-branch.
+
+ * Scripts/build-webkit:
+
+2007-06-29 Antti Koivisto <antti@apple.com>
+
+ Reviewed by Weinig.
+
+ Add VIDEO flag for timed media features
+
+ * Scripts/build-webkit
+
+=== End merge of feature-branch 2007-10-12 ===
+
+2007-10-11 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - Updated rational for the leaks list to be more clear.
+
+ * Scripts/run-webkit-tests:
+
+2007-10-11 Kevin McCullough <kmccullough@apple.com>
+
+ Rubber Stamp by Sam.
+
+ Adding a known Leopard leak that is already fixed but the bot is on an old version of Leopard.
+ I believe there was a radar on this leak, it looks familiar to me, but I could not find it.
+
+ * Scripts/run-webkit-tests:
+
+2007-10-10 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by Lars.
+
+ Fix compilation using gcc 4.3. Header files have been reorganized and as a result some extra
+ includes are needed for INT_MAX, std::auto_ptr and the like.
+
+ * DumpRenderTree/qt/main.cpp:
+
+2007-10-09 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ implement layoutTestController.encode/decodeHostName. We still don't pass fast/encoding/idn-security.html, since our QUrl::from/toACE is somewhat stricter than ICU.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::encodeHostName):
+ (LayoutTestController::decodeHostName):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2007-10-09 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ Don't set up connections inside QWebPage::createFrame, as users might be reimplementing that method. Make sure we get only one titleChanged() signal per title change, and implement the support for testing this in DRT.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::createFrame):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::titleChanged):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::reset):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2007-10-09 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ add a dummy implementation for layoutTestController.display() and implement layoutTestController.clearBackForwardList().
+
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::clearBackForwardList):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2007-10-09 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ make --git-reviewer work again.
+
+ * Scripts/prepare-ChangeLog:
+
+2007-10-07 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Rubber stamped by Eric.
+
+ Connect to the "hovering-over-link" signal emitted by WebKitPage and
+ show the current link inside the statusbar.
+ This shows how to make use of this signal and allows to easily test
+ http://bugs.webkit.org/show_bug.cgi?id=15299.
+
+ * GtkLauncher/main.cpp:
+ (hoveringOverLink):
+ (main):
+
+2007-10-05 Lars Knoll <lars@trolltech.com>
+
+ add proper error messages to the FrameLoaderClient.
+ Implement ChromeClientQt::closeWindowSoon and
+ FrameLoaderClientQt::dispatchCreatePage (which should go away IMO).
+ Some fixes in DRT to make it work correctly with multiple windows.
+
+ Reviewed by Maciej.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::createWindow):
+ (WebCore::DumpRenderTree::windowCount):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::maybeDump):
+ (LayoutTestController::windowCount):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2007-10-05 Lars Knoll <lars@trolltech.com>
+
+ Add a dummy plugin to DRT to fix fast/dom/Window/Plug-Ins.html.
+ Add support for layoutTextController.setCanOpenWindows() to DRT
+ fixing another 2 test cases in fast/dom/Window.
+
+ Reviewed by Maciej.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::createWindow):
+ (WebCore::DumpRenderTree::resetJSObjects):
+ (WebCore::DumpRenderTree::createWindow):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::reset):
+ * DumpRenderTree/qt/jsobjects.h:
+ * DumpRenderTree/qt/main.cpp:
+ * DumpRenderTree/qt/testplugin.cpp: Added.
+ * DumpRenderTree/qt/testplugin.h: Added.
+
+2007-10-04 Sam Weinig <sam@webkit.org>
+
+ Rubber stamped by Adam.
+
+ Remove empty directories.
+
+ * DumpRenderTree/DumpRenderTree.qtproj: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts: Removed.
+
+2007-10-03 Darin Adler <darin@apple.com>
+
+ Reviewed by Adam.
+
+ * Scripts/webkitdirs.pm: Automatically use "Debug_Internal" if
+ we find the internal libraries in the libraries directory. This
+ is helpful for Safari team engineers at Apple.
+
+2007-10-03 Adam Roben <aroben@apple.com>
+
+ Update the location of AHEM___.TTF after r25968
+
+ Reviewed by Sam.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-10-03 Alp Toker <alp@atoker.com>
+
+ Reviewed by Adam.
+
+ http://bugs.webkit.org/show_bug.cgi?id=14726
+ [gtk] API design. Mapping the WebView delegates to signals.
+
+ Change the API namespace of the Gtk+ port from 'WebKitGtk' to 'WebKit'.
+
+ * GtkLauncher/main.cpp:
+ (goToURLBarText):
+ (titleChanged):
+ (progressChanged):
+ (menuMainBackCallback):
+ (menuMainForwardCallback):
+ (main):
+
+2007-10-03 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Rob.
+
+ This fixes --strict mode in run-webkit-tests again after
+ the platform dependent test results have been moved.
+
+ * Scripts/run-webkit-tests:
+
+2007-10-03 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by bdash.
+
+ remove the hack in run-webkit-tests that forced text only test
+ to be taken from the platform independent dir. It was only left
+ there from early days.
+
+ Remove platform dependent results for tests that are text only nowadays,
+ and add one platform dependent result for a text only test that requires it.
+
+ * Scripts/run-webkit-tests:
+
+2007-10-03 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by olliej.
+
+ Move the Qt version of DRT into the correct place and put the binary into BUILDDIR/bin.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp: Renamed from WebKitTools/DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp.
+ (WebCore::WebFrame::WebFrame):
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::createFrame):
+ (WebCore::WebPage::javaScriptAlert):
+ (WebCore::WebPage::javaScriptConsoleMessage):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::~DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::readStdin):
+ (WebCore::DumpRenderTree::resetJSObjects):
+ (WebCore::DumpRenderTree::initJSObjects):
+ (WebCore::DumpRenderTree::dumpFramesAsText):
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/qt/DumpRenderTree.h: Renamed from WebKitTools/DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h.
+ (WebCore::DumpRenderTree::layoutTestController):
+ (WebCore::DumpRenderTree::eventSender):
+ * DumpRenderTree/qt/DumpRenderTree.pro: Renamed from WebKitTools/DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro.
+ * DumpRenderTree/qt/fonts.conf: Renamed from WebKitTools/DumpRenderTree/DumpRenderTree.qtproj/fonts.conf.
+ * DumpRenderTree/qt/fonts/AHEM____.TTF: Renamed from WebKitTools/DumpRenderTree/DumpRenderTree.qtproj/fonts/AHEM____.TTF.
+ * DumpRenderTree/qt/jsobjects.cpp: Renamed from WebKitTools/DumpRenderTree/DumpRenderTree.qtproj/jsobjects.cpp.
+ (HackWebFrame::mousePressEvent):
+ (HackWebFrame::mouseReleaseEvent):
+ (HackWebFrame::mouseMoveEvent):
+ (HackWebFrame::HackWebFrame):
+ (HackWebFrame::~HackWebFrame):
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::reset):
+ (LayoutTestController::maybeDump):
+ (LayoutTestController::waitUntilDone):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::dumpEditingCallbacks):
+ (LayoutTestController::queueReload):
+ (LayoutTestController::provisionalLoad):
+ (LayoutTestController::timerEvent):
+ (EventSender::EventSender):
+ (EventSender::mouseDown):
+ (EventSender::mouseUp):
+ (EventSender::mouseMoveTo):
+ (EventSender::leapForward):
+ (EventSender::keyDown):
+ (EventSender::frameUnderMouse):
+ * DumpRenderTree/qt/jsobjects.h: Renamed from WebKitTools/DumpRenderTree/DumpRenderTree.qtproj/jsobjects.h.
+ (LayoutTestController::isLoading):
+ (LayoutTestController::setLoading):
+ (LayoutTestController::shouldDumpAsText):
+ (LayoutTestController::shouldDumpChildrenAsText):
+ (LayoutTestController::shouldWaitUntilDone):
+ (LayoutTestController::dumpAsText):
+ (LayoutTestController::dumpChildFramesAsText):
+ * DumpRenderTree/qt/main.cpp: Renamed from WebKitTools/DumpRenderTree/DumpRenderTree.qtproj/main.cpp.
+ (messageHandler):
+ (crashHandler):
+ (main):
+ * Scripts/run-webkit-tests:
+
+2007-10-03 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Alp Toker.
+
+ Fix build-webkit when both QTDIR and --gtk are set. The presence of --gtk
+ should take precedence over QTDIR when determining which port we are working with.
+
+ * Scripts/webkitdirs.pm:
+
+2007-10-02 Adam Roben <aroben@apple.com>
+
+ Add keychain to the list of default packages to install
+
+ Rubberstamped by Sam.
+
+ * CygwinDownloader/cygwin-downloader.py:
+ * CygwinDownloader/cygwin-downloader.zip: Regenerated.
+
+2007-10-02 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Adam.
+
+ Make "--git-commit trunk..HEAD" work with prepare-ChangeLog.
+ Also makes WebCore regression test case logic work when using git.
+
+ * Scripts/prepare-ChangeLog:
+ (reviewerAndDescriptionForGitCommit): Added.
+
+2007-10-02 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by bdash.
+
+ Add API to retrieve the frame name from QWebFrame.
+ Implement support for DRT::dumpChildrenAsText.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::dumpFramesAsText):
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::reset):
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.h:
+
+2007-10-02 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by bdash.
+
+ Fix the handling of the response header for data urls. Make sure we always pass absolute URLs to WebKit from both DRT and QtLauncher.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::readStdin):
+
+2007-10-02 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver.
+
+ Update WebKitLauncher to notify you of new builds from the correct branch, rather than always checking trunk.
+
+ * BuildSlaveSupport/build-launcher-app: Generate a file named BRANCH into WebKit.app so that it knows which branch it was built from.
+ * WebKitLauncher/start.html: Use the new URL format that includes the branch we were built from.
+
+2007-10-02 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Maciej.
+
+ Configuration changes from build.webkit.org. The major change is refactoring to work
+ with Buildbot 0.7.6, but it does include other smaller changes that have been made in the
+ last few weeks.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+ * BuildSlaveSupport/build.webkit.org-config/webkit/auth.py:
+ * BuildSlaveSupport/build.webkit.org-config/webkit/basesteps.py:
+ * BuildSlaveSupport/build.webkit.org-config/webkit/builders.py:
+ * BuildSlaveSupport/build.webkit.org-config/webkit/factories.py:
+ * BuildSlaveSupport/build.webkit.org-config/webkit/schedulers.py:
+ * BuildSlaveSupport/build.webkit.org-config/webkit/status.py:
+ * BuildSlaveSupport/build.webkit.org-config/webkit/steps.py:
+
+2007-10-02 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Maciej.
+
+ Add support for eventSender.mouseMove to DRT.
+ Fixes fast/css/hover-affects-child.html
+
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.cpp:
+ (EventSender::mouseMoveTo):
+
+2007-10-01 Mark Rowe <mrowe@apple.com>
+
+ * BuildSlaveSupport/build-launcher-dmg: Tweak once more to handle nightly builds for branches.
+
+2007-10-01 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Hyatt.
+
+ Make svn-apply and svn-unapply work with added files in git-diff formatted patches.
+
+ * Scripts/svn-apply:
+ (gitdiff2svndiff): Ignore lines beginning with "new file".
+ * Scripts/svn-unapply:
+ (gitdiff2svndiff): Ditto.
+
+2007-09-30 George Staikos <staikos@kde.org>
+
+ Qt build fix (Mac OS X specific)
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro:
+
+2007-09-29 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Mark.
+
+ -Fix http://bugs.webkit.org/show_bug.cgi?id=13226.
+ Remove Bakefiles from svn.
+
+ * GtkLauncher/Bakefiles.bkgen: Removed.
+ * GtkLauncher/ENV: Removed.
+ * GtkLauncher/gdklauncher.bkl: Removed.
+ * GtkLauncher/mk: Removed.
+ * Scripts/regenerate-makefiles: Removed.
+
+2007-09-25 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by John.
+
+ - Updating leopard leak list to refelct bugs that have been fixed and no longer leak.
+
+ * Scripts/run-webkit-tests:
+
+2007-09-26 Adam Roben <aroben@apple.com>
+
+ Make not finding an installed WebKit non-fatal
+
+ What really matters is that we are able to load WebKit and its
+ dependencies, not whether we think we've found an installed WebKit.
+
+ Reviewed by Sam.
+
+ * WebKitInitializer/WebKitInitializer.cpp:
+ (getWebViewCLSID): Use new LOG_WARNING macro.
+ (getInstalledWebKitDirectory): Ditto.
+ (initializeWebKit): Don't die if we didn't find an installed WebKit,
+ and use new macros.
+ * WebKitInitializer/WebKitInitializer.vcproj: Disabled a warning.
+
+2007-09-26 Adam Roben <aroben@apple.com>
+
+ Committed this file before saving it
+
+ * WebKitInitializer/debug_internal.vsprops:
+
+2007-09-26 Adam Roben <aroben@apple.com>
+
+ Load WebKit and its dependencies manually so they come from DllDirectory
+
+ I had to change WebKitInitializer to use malloc/free instead of
+ new/delete to avoid pulling in WebKit (and its dependencies) early
+ through use of fastMalloc.
+
+ Reviewed by Oliver.
+
+ * WebKitInitializer/WebKitInitializer.cpp:
+ (getStringValue): Changed to use malloc/free.
+ (getInstalledWebKitDirectory): Ditto.
+ (initializeWebKit): Call SetDllDirectory first, then load all of
+ WebKit's dependencies manually, finally followed by WebKit itself.
+ * WebKitInitializer/WebKitInitializer.vcproj: Added a new
+ configuration to match our other projects.
+ * WebKitInitializer/debug_internal.vsprops: Added.
+
+2007-09-25 Adam Roben <aroben@apple.com>
+
+ Actually define DEBUG/NDEBUG so that we load WebKit correctly
+
+ Rubberstamped by Sam.
+
+ * WebKitInitializer/WebKitInitializer.vcproj:
+
+2007-09-25 Adam Roben <aroben@apple.com>
+
+ Make DumpRenderTree delay-load its dependencies
+
+ This lets WebKitInitializer re-route the dependencies to be loaded out
+ of the Safari installation directory.
+
+ Also replaced all uses of kCFAllocatorDefault with 0 (which means the
+ same thing), since we can't import the kCFAllocatorDefault symbol when
+ delay-loading CoreFoundation.dll.
+
+ Rubberstamped by Sam.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (runTest):
+ (javaScriptThreads):
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setWaitToDump):
+
+2007-09-25 Adam Roben <aroben@apple.com>
+
+ Pull ole32.lib into WebKitInitializer
+
+ Rubberstamped by Sam.
+
+ * WebKitInitializer/WebKitInitializer.vcproj:
+
+2007-09-25 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Adam.
+
+ - Fix http://bugs.webkit.org/show_bug.cgi?id=14885
+ LGPL'ed files contain incorrect FSF address
+
+ * Drosera/config.h:
+
+2007-09-25 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Adam.
+
+ Make svn-apply and svn-unapply work with git-diff formatted patches.
+
+ * Scripts/svn-apply: Apply a filter to the input if we find a git-diff marker before a patch.
+ (gitdiff2svndiff): Added.
+ * Scripts/svn-unapply: Ditto.
+ (gitdiff2svndiff): Added.
+
+2007-09-25 Adam Roben <aroben@apple.com>
+
+ Pull advapi32.lib into WebKitInitializer
+
+ This is needed to get the registry functions we use.
+
+ Rubberstamped by Sam.
+
+ * WebKitInitializer/WebKitInitializer.vcproj:
+
+2007-09-25 Adam Roben <aroben@apple.com>
+
+ Add python and rsync to cygwin-downloader
+
+ Our build slaves need this, and it can't hurt for everyone else to
+ have it, too.
+
+ Reviewed by Sam.
+
+ * CygwinDownloader/cygwin-downloader.py: Added python and rsync.
+ * CygwinDownloader/cygwin-downloader.zip: Regenerated.
+
+2007-09-25 Adam Roben <aroben@apple.com>
+
+ Add WebKitInitializer and use it in DumpRenderTree
+
+ WebKitInitializer is a static library that has one function,
+ initializeWebKit(). This registers WebKit and sets up the DLL search
+ path so that WebKit's dependencies that are installed with Safari can
+ be found.
+
+ Reviewed by Sam.
+
+ * DumpRenderTree/DumpRenderTree.sln: Added WebKitInitializer and made
+ DumpRenderTree depend on it.
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (initialize): Call initializeWebKit.
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Link against
+ WebKitInitializer.lib.
+ * WebKitInitializer/WebKitInitializer.cpp: Added.
+ (getStringValue):
+ (getWebViewCLSID):
+ (getInstalledWebKitDirectory):
+ (initializeWebKit):
+ * WebKitInitializer/WebKitInitializer.h: Added.
+ * WebKitInitializer/WebKitInitializer.vcproj: Added.
+ * WebKitInitializer/debug.vsprops: Added.
+ * WebKitInitializer/release.vsprops: Added.
+
+2007-09-25 Adam Roben <aroben@apple.com>
+
+ Make run-webkit-tests respect set-webkit-configuration
+
+ Reviewed by Sam.
+
+ * Scripts/run-webkit-tests: Initialize $configuration to whatever
+ set-webkit-configuration was last set to.
+
+2007-09-25 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Eric.
+
+ * BuildSlaveSupport/build-launcher-dmg: Allow the platform tag to be specified on the command line.
+ This makes it possible to automate nightly builds for the feature-branch.
+
+2007-09-25 Adam Roben <aroben@apple.com>
+
+ A couple of fixes/enhancements to update-webkit-*-libs
+
+ You can now specify WEBKITSUPPORTLIBRARIESZIPDIR=C:\my\special\place
+ to tell update-webkit-support-libraries where it should find the
+ WebKitSupportLibrary.zip file you downloaded.
+
+ These scripts also now correctly interpret WEBKITLIBRARIESDIR as a
+ Windows-style path.
+
+ Reviewed by Sam.
+
+ * Scripts/update-webkit-auxiliary-libs: Also renamed $supportLibsURL
+ to $auxiliaryLibsURL and removed an irrelevant comment.
+ * Scripts/update-webkit-support-libs:
+
+2007-09-25 Adam Treat <treat@kde.org>
+
+ Reviewed by Simon and Lars.
+
+ Refactors and cleans up Qt DRT member variable names, member variable
+ initialization, style fixes and general code cleanup.
+
+ Adds queueReload slot to LayoutTestController that some tests require.
+
+ Subclasses QWebFrame to make sure that all frames have an associated
+ LayoutTestController JS window object.
+
+ Takes advantage of new QWebFrame provisionalLoad signal to ensure frames
+ aren't dumped twice.
+
+ EOF fixes.
+
+ Together, this patch fixes some 20+ layout tests in QtWebKit.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::WebFrame::WebFrame):
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::createFrame):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::readStdin):
+ (WebCore::DumpRenderTree::initJSObjects):
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h:
+ (WebCore::DumpRenderTree::layoutTestController):
+ (WebCore::DumpRenderTree::eventSender):
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::reset):
+ (LayoutTestController::maybeDump):
+ (LayoutTestController::waitUntilDone):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::queueReload):
+ (LayoutTestController::provisionalLoad):
+ (EventSender::EventSender):
+ (EventSender::mouseDown):
+ (EventSender::mouseUp):
+ (EventSender::mouseMoveTo):
+ (EventSender::frameUnderMouse):
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.h:
+ (LayoutTestController::isLoading):
+ (LayoutTestController::setLoading):
+ (LayoutTestController::dumpAsText):
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+ (main):
+
+2007-09-24 Kevin McCullough <kmccullough@apple.com>
+
+
+ - Reverted an accidentally checked in file.
+
+ * Drosera/win/DebuggerDocumentPlatform.cpp: Removed.
+
+2007-09-24 Kevin McCullough <kmccullough@apple.com>
+ Reviewed by Sam.
+
+ - Updated project files to not use Edit and Continue for Debug Information since it doesn't work and breaks some functionality.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+
+2007-09-20 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Rubber stamped by Adam.
+
+ * GdkLauncher: Removed.
+ * GdkLauncher/Bakefiles.bkgen: Removed.
+ * GdkLauncher/ENV: Removed.
+ * GdkLauncher/GdkLauncher.pro: Removed.
+ * GdkLauncher/gdklauncher.bkl: Removed.
+ * GdkLauncher/main.cpp: Removed.
+ * GdkLauncher/mk: Removed.
+ * GdkLauncher/simple.svg: Removed.
+ * GdkLauncher/text.html: Removed.
+ * GtkLauncher: Added.
+ * GtkLauncher/GdkLauncher.pro: Removed.
+ * GtkLauncher/GtkLauncher.pro: Added.
+ * GtkLauncher/main.cpp:
+ (updateWindowTitle):
+ (main):
+ * Scripts/build-webkit:
+ * Scripts/regenerate-makefiles:
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/run-launcher:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2007-09-21 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Darin Adler.
+
+ <rdar://problem/5491013> REGRESSION: -[WebView windowScriptObject] returns a dummy object or nil if a page hasn't loaded (breaks EA Sports Online)
+
+ Assert that the -[WebScriptObject JSObject] return value is only NULL for non-window objects.
+ This is tested by plugins/root-object-premature-delete-crash.html.
+
+ * DumpRenderTree/mac/ObjCController.m:
+ (-[ObjCController accessStoredWebScriptObject]):
+
+2007-09-21 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Oliver.
+
+ - We need to initialize the ref count to 1 at initialization so that objects are not garbage collected. (actual patch written by Oliver)
+
+ * DumpRenderTree/win/FrameLoaderDelegate.cpp:
+ (FrameLoadDelegate::FrameLoadDelegate):
+
+2007-09-20 Julien Chaffraix <julien.chaffraix@gmail.com>
+
+ Reviewed by Adam.
+
+ Fix: http://bugs.webkit.org/show_bug.cgi?id=15223
+ webkitdir.pm::isQt() is not working properly in run-webkit-tests under Linux/Qt
+
+ Added determineIsQt() and determineIsGdk() to webkitdirs.pm.
+ Now isQt() and isGdk() use global variables that are only set once.
+
+ An array of all the parameters is now given to build-dumprender which includes
+ the platform on linux.
+
+ * Scripts/build-dumprendertree:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2007-09-19 Adam Roben <aroben@apple.com>
+
+ Rubberstamped by Hyatt.
+
+ * Spinneret: Removed.
+
+2007-09-19 Tuukka Hastrup <Tuukka.Hastrup@iki.fi>
+
+ Reviewed by David Kilzer.
+
+ * Scripts/webkitdirs.pm: On Gdk and Qt, check that flex, bison, gperf are available.
+
+2007-09-18 Sam Weinig <sam@webkit.org>
+
+ Add JSRetainPtr.h #include to fix some builds.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+
+2007-09-18 Mike Hommey <glandium@debian.org>
+
+ Reviewed by Adam.
+
+ * Scripts/prepare-ChangeLog:
+ - Properly parse GECOS field.
+ - Use git configuration for user name and email when appropriate.
+
+2007-09-17 Sam Weinig <sam@webkit.org>
+
+ Build fix.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-09-17 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Share more code between mac and windows DRT.
+ - GCController is now shared.
+ - Rename WaitUntilDoneDelegate to FrameLoadDelegate for consistency.
+
+ * DumpRenderTree/GCController.cpp:
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/FrameLoaderDelegate.cpp: Copied from DumpRenderTree/win/WaitUntilDoneDelegate.cpp.
+ (FrameLoadDelegate::FrameLoadDelegate):
+ (FrameLoadDelegate::~FrameLoadDelegate):
+ (FrameLoadDelegate::windowScriptObjectAvailable):
+ * DumpRenderTree/win/FrameLoaderDelegate.h: Copied from DumpRenderTree/win/WaitUntilDoneDelegate.h.
+ * DumpRenderTree/win/GCController.cpp: Removed.
+ * DumpRenderTree/win/GCController.h: Removed.
+ * DumpRenderTree/win/GCControllerWin.cpp: Copied from DumpRenderTree/win/GCController.cpp.
+ (GCController::collect):
+ (GCController::collectOnAlternateThread):
+ (GCController::getJSObjectCount):
+ * DumpRenderTree/win/WaitUntilDoneDelegate.cpp: Removed.
+ * DumpRenderTree/win/WaitUntilDoneDelegate.h: Removed.
+
+2007-09-17 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Begin sharing code between mac and windows DRT.
+ - both now share LayoutTestController.h/cpp and implement platform dependant
+ operations in LayoutTestControllerMac/Win.
+ - DumpRenderTree.h is now shared.
+ - WorkQueue and WorkQueueItem are also shared.
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/LayoutTestController.cpp:
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (displayWebView):
+ (dumpFrameScrollPosition):
+ (dumpFramesAsText):
+ (dump):
+ (runTest):
+ * DumpRenderTree/win/DumpRenderTree.h: Removed.
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/DumpRenderTreeWin.h: Copied from DumpRenderTree/win/DumpRenderTree.h.
+ * DumpRenderTree/win/EditingDelegate.cpp:
+ (EditingDelegate::shouldBeginEditingInDOMRange):
+ (EditingDelegate::shouldEndEditingInDOMRange):
+ (EditingDelegate::shouldInsertNode):
+ (EditingDelegate::shouldInsertText):
+ (EditingDelegate::shouldDeleteDOMRange):
+ (EditingDelegate::shouldChangeSelectedDOMRange):
+ (EditingDelegate::shouldApplyStyle):
+ (EditingDelegate::shouldChangeTypingStyle):
+ (EditingDelegate::doPlatformCommand):
+ (EditingDelegate::webViewDidBeginEditing):
+ (EditingDelegate::webViewDidChange):
+ (EditingDelegate::webViewDidEndEditing):
+ (EditingDelegate::webViewDidChangeTypingStyle):
+ (EditingDelegate::webViewDidChangeSelection):
+ * DumpRenderTree/win/LayoutTestController.cpp: Removed.
+ * DumpRenderTree/win/LayoutTestController.h: Removed.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp: Copied from DumpRenderTree/win/LayoutTestController.cpp.
+ (LayoutTestController::addDisallowedURL):
+ (LayoutTestController::clearBackForwardList):
+ (LayoutTestController::copyDecodedHostName):
+ (LayoutTestController::copyEncodedHostName):
+ (LayoutTestController::display):
+ (LayoutTestController::keepWebHistory):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::queueBackNavigation):
+ (LayoutTestController::queueForwardNavigation):
+ (jsStringRefToWString):
+ (LayoutTestController::queueLoad):
+ (LayoutTestController::queueReload):
+ (LayoutTestController::queueScript):
+ (LayoutTestController::setAcceptsEditing):
+ (LayoutTestController::setCustomPolicyDelegate):
+ (LayoutTestController::setMainFrameIsFirstResponder):
+ (LayoutTestController::setTabKeyCyclesThroughElements):
+ (LayoutTestController::setUseDashboardCompatibilityMode):
+ (LayoutTestController::setUserStyleSheetEnabled):
+ (LayoutTestController::setUserStyleSheetLocation):
+ (LayoutTestController::setWindowIsKey):
+ (waitUntilDoneWatchdogFired):
+ (LayoutTestController::setWaitToDump):
+ (LayoutTestController::windowCount):
+ * DumpRenderTree/win/WaitUntilDoneDelegate.cpp:
+ (FrameLoadDelegate::didReceiveTitle):
+ (FrameLoadDelegate::processWork):
+ (FrameLoadDelegate::locationChangeDone):
+ (FrameLoadDelegate::windowScriptObjectAvailable):
+ * DumpRenderTree/win/WorkQueue.cpp: Removed.
+ * DumpRenderTree/win/WorkQueue.h: Removed.
+ * DumpRenderTree/win/WorkQueueItem.cpp: Removed.
+ * DumpRenderTree/win/WorkQueueItem.h: Removed.
+ * DumpRenderTree/win/WorkQueueItemWin.cpp: Copied from DumpRenderTree/win/WorkQueueItem.cpp.
+ (jsStringRefToWString):
+ (LoadItem::invoke):
+ (ScriptItem::invoke):
+
+2007-09-17 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ - Move Windows DumpRenderTree and TestNetscapePlugin to WebCoreTools/DumpRenderTree/win
+
+ * DumpRenderTree/DumpRenderTree.sln: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree.sln.
+ * DumpRenderTree/DumpRenderTree.vcproj: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree.sln: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DraggingInfo.h: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.h: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.vcproj: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/EditingDelegate.cpp: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/EditingDelegate.h: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/EventSender.cpp: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/EventSender.h: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/GCController.cpp: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/GCController.h: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/LayoutTestController.cpp: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/LayoutTestController.h: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/UIDelegate.cpp: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/UIDelegate.h: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WaitUntilDoneDelegate.cpp: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WaitUntilDoneDelegate.h: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WorkQueue.cpp: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WorkQueue.h: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WorkQueueItem.cpp: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WorkQueueItem.h: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/debug.vsprops: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/debug_internal.vsprops: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/release.vsprops: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/TestNetscapePlugin: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/TestNetscapePlugin/TestNetscapePlugin.def: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/TestNetscapePlugin/TestNetscapePlugin.rc: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/TestNetscapePlugin/TestNetscapePlugin.vcproj: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/TestNetscapePlugin/main.c: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/TestNetscapePlugin/resource.h: Removed.
+ * DumpRenderTree/win: Added.
+ * DumpRenderTree/win/DraggingInfo.h: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DraggingInfo.h.
+ * DumpRenderTree/win/DumpRenderTree.cpp: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp.
+ * DumpRenderTree/win/DumpRenderTree.h: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.h.
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.vcproj.
+ * DumpRenderTree/win/EditingDelegate.cpp: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/EditingDelegate.cpp.
+ * DumpRenderTree/win/EditingDelegate.h: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/EditingDelegate.h.
+ * DumpRenderTree/win/EventSender.cpp: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/EventSender.cpp.
+ * DumpRenderTree/win/EventSender.h: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/EventSender.h.
+ * DumpRenderTree/win/GCController.cpp: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/GCController.cpp.
+ * DumpRenderTree/win/GCController.h: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/GCController.h.
+ * DumpRenderTree/win/LayoutTestController.cpp: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/LayoutTestController.cpp.
+ * DumpRenderTree/win/LayoutTestController.h: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/LayoutTestController.h.
+ * DumpRenderTree/win/TestNetscapePlugin: Copied from DumpRenderTree/DumpRenderTree.vcproj/TestNetscapePlugin.
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+ * DumpRenderTree/win/UIDelegate.cpp: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/UIDelegate.cpp.
+ * DumpRenderTree/win/UIDelegate.h: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/UIDelegate.h.
+ * DumpRenderTree/win/WaitUntilDoneDelegate.cpp: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WaitUntilDoneDelegate.cpp.
+ * DumpRenderTree/win/WaitUntilDoneDelegate.h: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WaitUntilDoneDelegate.h.
+ * DumpRenderTree/win/WorkQueue.cpp: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WorkQueue.cpp.
+ * DumpRenderTree/win/WorkQueue.h: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WorkQueue.h.
+ * DumpRenderTree/win/WorkQueueItem.cpp: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WorkQueueItem.cpp.
+ * DumpRenderTree/win/WorkQueueItem.h: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WorkQueueItem.h.
+ * DumpRenderTree/win/debug.vsprops: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/debug.vsprops.
+ * DumpRenderTree/win/debug_internal.vsprops: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/debug_internal.vsprops.
+ * DumpRenderTree/win/release.vsprops: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/release.vsprops.
+ * Scripts/run-webkit-tests: Update to point to the new location of the sln.
+
+2007-09-15 Mark Rowe <mrowe@apple.com>
+
+ Build fix for DumpRenderTree.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Reinstate -Wno-deprecated-declarations on DumpRenderTree.mm.
+
+2007-09-14 Sam Weinig <sam@webkit.org>
+
+ Rubber stamped by Adam Roben.
+
+ Split the WaitUntilDoneDelegate into a UIDelegate and a FrameLoadDelegate.
+ - The UIDelegate was put into a new file while the FrameLoadDelegate was
+ kept in the WaitUntilDoneDelegate file for the time being.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (main):
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.vcproj:
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/UIDelegate.cpp: Added.
+ (UIDelegate::QueryInterface):
+ (UIDelegate::AddRef):
+ (UIDelegate::Release):
+ (UIDelegate::hasCustomMenuImplementation):
+ (UIDelegate::setFrame):
+ (UIDelegate::webViewFrame):
+ (UIDelegate::runJavaScriptAlertPanelWithMessage):
+ (UIDelegate::webViewAddMessageToConsole):
+ (UIDelegate::doDragDrop):
+ (UIDelegate::webViewGetDlgCode):
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/UIDelegate.h: Added.
+ (UIDelegate::UIDelegate):
+ (UIDelegate::createWebViewWithRequest):
+ (UIDelegate::webViewShow):
+ (UIDelegate::webViewClose):
+ (UIDelegate::webViewFocus):
+ (UIDelegate::webViewUnfocus):
+ (UIDelegate::webViewFirstResponder):
+ (UIDelegate::makeFirstResponder):
+ (UIDelegate::setStatusText):
+ (UIDelegate::webViewStatusText):
+ (UIDelegate::webViewAreToolbarsVisible):
+ (UIDelegate::setToolbarsVisible):
+ (UIDelegate::webViewIsStatusBarVisible):
+ (UIDelegate::setStatusBarVisible):
+ (UIDelegate::webViewIsResizable):
+ (UIDelegate::setResizable):
+ (UIDelegate::setContentRect):
+ (UIDelegate::webViewContentRect):
+ (UIDelegate::runJavaScriptConfirmPanelWithMessage):
+ (UIDelegate::runJavaScriptTextInputPanelWithPrompt):
+ (UIDelegate::runBeforeUnloadConfirmPanelWithMessage):
+ (UIDelegate::runOpenPanelForFileButtonWithResultListener):
+ (UIDelegate::mouseDidMoveOverElement):
+ (UIDelegate::contextMenuItemsForElement):
+ (UIDelegate::validateUserInterfaceItem):
+ (UIDelegate::shouldPerformAction):
+ (UIDelegate::dragDestinationActionMaskForDraggingInfo):
+ (UIDelegate::willPerformDragDestinationAction):
+ (UIDelegate::dragSourceActionMaskForPoint):
+ (UIDelegate::willPerformDragSourceAction):
+ (UIDelegate::contextMenuItemSelected):
+ (UIDelegate::trackCustomPopupMenu):
+ (UIDelegate::measureCustomMenuItem):
+ (UIDelegate::drawCustomMenuItem):
+ (UIDelegate::addCustomMenuDrawingData):
+ (UIDelegate::cleanUpCustomMenuDrawingData):
+ (UIDelegate::canTakeFocus):
+ (UIDelegate::takeFocus):
+ (UIDelegate::registerUndoWithTarget):
+ (UIDelegate::removeAllActionsWithTarget):
+ (UIDelegate::setActionTitle):
+ (UIDelegate::undo):
+ (UIDelegate::redo):
+ (UIDelegate::canUndo):
+ (UIDelegate::canRedo):
+ (UIDelegate::webViewResizerRect):
+ (UIDelegate::webViewDrawResizer):
+ (UIDelegate::webViewScrolled):
+ (UIDelegate::webViewShouldInterruptJavaScript):
+ (UIDelegate::webViewReceivedFocus):
+ (UIDelegate::webViewLostFocus):
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WaitUntilDoneDelegate.cpp:
+ (FrameLoadDelegate::QueryInterface):
+ (FrameLoadDelegate::AddRef):
+ (FrameLoadDelegate::Release):
+ (FrameLoadDelegate::didStartProvisionalLoadForFrame):
+ (FrameLoadDelegate::didCommitLoadForFrame):
+ (FrameLoadDelegate::didReceiveTitle):
+ (FrameLoadDelegate::processWork):
+ (processWorkTimer):
+ (FrameLoadDelegate::locationChangeDone):
+ (FrameLoadDelegate::didFinishLoadForFrame):
+ (FrameLoadDelegate::didFailLoadWithError):
+ (FrameLoadDelegate::windowScriptObjectAvailable):
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WaitUntilDoneDelegate.h:
+ (FrameLoadDelegate::FrameLoadDelegate):
+
+2007-09-14 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Kevin McCullough.
+
+ Move mac specific globals in to mac/DumpRenderTreeMac.h
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.mm: Removed.
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/DumpRenderTree.mm: Copied from DumpRenderTree/DumpRenderTree.mm.
+ * DumpRenderTree/mac/DumpRenderTreeMac.h: Added.
+
+2007-09-14 Brady Eidson <beidson@apple.com>
+
+ Rubberstamped by Weinig
+
+ You know, Sam, some of us use case-sensitve filesystems...
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/mac/UIDelegate.mm:
+
+2007-09-14 Sam Weinig <sam@webkit.org>
+
+ Rubber stamped by Adam Roben.
+
+ - Move dump state data to LayoutTestContoller and add getter/setters to accommodate.
+ - Move mac specific DumpRenderTree files to DumpRenderTree/mac
+
+ * DumpRenderTree/AppleScriptController.h: Removed.
+ * DumpRenderTree/AppleScriptController.m: Removed.
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.mm:
+ (startJavaScriptThreads):
+ (stopJavaScriptThreads):
+ (activateAhemFont):
+ (setDefaultColorProfileToRGB):
+ (makeLargeMallocFailSilently):
+ (dumpFrameScrollPosition):
+ (dumpFramesAsText):
+ (dump):
+ (runTest):
+ (-[DumpRenderTreeWindow isKeyWindow]):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/DumpRenderTreeDraggingInfo.h: Removed.
+ * DumpRenderTree/DumpRenderTreeDraggingInfo.m: Removed.
+ * DumpRenderTree/EditingDelegate.h: Removed.
+ * DumpRenderTree/EditingDelegate.m: Removed.
+ * DumpRenderTree/EventSendingController.h: Removed.
+ * DumpRenderTree/EventSendingController.m: Removed.
+ * DumpRenderTree/FrameLoadDelegate.h: Removed.
+ * DumpRenderTree/FrameLoadDelegate.mm: Removed.
+ * DumpRenderTree/GCController.mm: Removed.
+ * DumpRenderTree/ImageDiff.m: Removed.
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (dumpAsTextCallback):
+ (dumpBackForwardListCallback):
+ (dumpChildFramesAsTextCallback):
+ (dumpChildFrameScrollPositionsCallback):
+ (dumpDOMAsWebArchiveCallback):
+ (dumpEditingCallbacksCallback):
+ (dumpFrameLoadCallbacksCallback):
+ (dumpResourceLoadCallbacksCallback):
+ (dumpSelectionRectCallback):
+ (dumpSourceAsWebArchiveCallback):
+ (dumpTitleChangesCallback):
+ (repaintSweepHorizontallyCallback):
+ (setCallCloseOnWebViewsCallback):
+ (setCanOpenWindowsCallback):
+ (setCloseRemainingWindowsWhenCompleteCallback):
+ (testRepaintCallback):
+ (addFileToPasteboardOnDragCallback):
+ (waitUntilDoneCallback):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::dumpAsText):
+ (LayoutTestController::setDumpAsText):
+ (LayoutTestController::dumpBackForwardList):
+ (LayoutTestController::setDumpBackForwardList):
+ (LayoutTestController::dumpChildFrameScrollPositions):
+ (LayoutTestController::setDumpChildFrameScrollPositions):
+ (LayoutTestController::dumpChildFramesAsText):
+ (LayoutTestController::setDumpChildFramesAsText):
+ (LayoutTestController::dumpDOMAsWebArchive):
+ (LayoutTestController::setDumpDOMAsWebArchive):
+ (LayoutTestController::dumpSelectionRect):
+ (LayoutTestController::setDumpSelectionRect):
+ (LayoutTestController::dumpSourceAsWebArchive):
+ (LayoutTestController::setDumpSourceAsWebArchive):
+ (LayoutTestController::dumpTitleChanges):
+ (LayoutTestController::setDumpTitleChanges):
+ (LayoutTestController::dumpEditingCallbacks):
+ (LayoutTestController::setDumpEditingCallbacks):
+ (LayoutTestController::dumpResourceLoadCallbacks):
+ (LayoutTestController::setDumpResourceLoadCallbacks):
+ (LayoutTestController::dumpFrameLoadCallbacks):
+ (LayoutTestController::setDumpFrameLoadCallbacks):
+ (LayoutTestController::addFileToPasteboardOnDrag):
+ (LayoutTestController::setAddFileToPasteboardOnDrag):
+ (LayoutTestController::callCloseOnWebViews):
+ (LayoutTestController::setCallCloseOnWebViews):
+ (LayoutTestController::canOpenWindows):
+ (LayoutTestController::setCanOpenWindows):
+ (LayoutTestController::closeRemainingWindowsWhenComplete):
+ (LayoutTestController::setCloseRemainingWindowsWhenComplete):
+ (LayoutTestController::testRepaint):
+ (LayoutTestController::setTestRepaint):
+ (LayoutTestController::testRepaintSweepHorizontally):
+ (LayoutTestController::setTestRepaintSweepHorizontally):
+ (LayoutTestController::waitToDump):
+ (LayoutTestController::windowIsKey):
+ * DumpRenderTree/LayoutTestControllerMac.mm: Removed.
+ * DumpRenderTree/NavigationController.h: Removed.
+ * DumpRenderTree/NavigationController.m: Removed.
+ * DumpRenderTree/ObjCController.h: Removed.
+ * DumpRenderTree/ObjCController.m: Removed.
+ * DumpRenderTree/ObjCPlugin.h: Removed.
+ * DumpRenderTree/ObjCPlugin.m: Removed.
+ * DumpRenderTree/ObjCPluginFunction.h: Removed.
+ * DumpRenderTree/ObjCPluginFunction.m: Removed.
+ * DumpRenderTree/PolicyDelegate.h: Removed.
+ * DumpRenderTree/PolicyDelegate.m: Removed.
+ * DumpRenderTree/ResourceLoadDelegate.h: Removed.
+ * DumpRenderTree/ResourceLoadDelegate.m: Removed.
+ * DumpRenderTree/TextInputController.h: Removed.
+ * DumpRenderTree/TextInputController.m: Removed.
+ * DumpRenderTree/UIDelegate.h: Removed.
+ * DumpRenderTree/UIDelegate.mm: Removed.
+ * DumpRenderTree/WorkQueueItemMac.mm: Removed.
+ * DumpRenderTree/mac: Added.
+ * DumpRenderTree/mac/AppleScriptController.h: Copied from DumpRenderTree/AppleScriptController.h.
+ * DumpRenderTree/mac/AppleScriptController.m: Copied from DumpRenderTree/AppleScriptController.m.
+ * DumpRenderTree/mac/DumpRenderTreeDraggingInfo.h: Copied from DumpRenderTree/DumpRenderTreeDraggingInfo.h.
+ * DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm: Copied from DumpRenderTree/DumpRenderTreeDraggingInfo.m.
+ * DumpRenderTree/mac/EditingDelegate.h: Copied from DumpRenderTree/EditingDelegate.h.
+ * DumpRenderTree/mac/EditingDelegate.mm: Copied from DumpRenderTree/EditingDelegate.m.
+ (-[EditingDelegate webView:shouldBeginEditingInDOMRange:]):
+ (-[EditingDelegate webView:shouldEndEditingInDOMRange:]):
+ (-[EditingDelegate webView:shouldInsertNode:replacingDOMRange:givenAction:]):
+ (-[EditingDelegate webView:shouldInsertText:replacingDOMRange:givenAction:]):
+ (-[EditingDelegate webView:shouldDeleteDOMRange:]):
+ (-[EditingDelegate webView:shouldChangeSelectedDOMRange:toDOMRange:affinity:stillSelecting:]):
+ (-[EditingDelegate webView:shouldApplyStyle:toElementsInDOMRange:]):
+ (-[EditingDelegate webView:shouldChangeTypingStyle:toStyle:]):
+ (-[EditingDelegate webViewDidBeginEditing:]):
+ (-[EditingDelegate webViewDidChange:]):
+ (-[EditingDelegate webViewDidEndEditing:]):
+ (-[EditingDelegate webViewDidChangeTypingStyle:]):
+ (-[EditingDelegate webViewDidChangeSelection:]):
+ * DumpRenderTree/mac/EventSendingController.h: Copied from DumpRenderTree/EventSendingController.h.
+ * DumpRenderTree/mac/EventSendingController.mm: Copied from DumpRenderTree/EventSendingController.m.
+ * DumpRenderTree/mac/FrameLoadDelegate.h: Copied from DumpRenderTree/FrameLoadDelegate.h.
+ * DumpRenderTree/mac/FrameLoadDelegate.mm: Copied from DumpRenderTree/FrameLoadDelegate.mm.
+ (-[FrameLoadDelegate init]):
+ (-[FrameLoadDelegate dealloc]):
+ (-[FrameLoadDelegate processWork:]):
+ (-[FrameLoadDelegate webView:locationChangeDone:forDataSource:]):
+ (-[FrameLoadDelegate webView:didStartProvisionalLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didCommitLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didFailProvisionalLoadWithError:forFrame:]):
+ (-[FrameLoadDelegate webView:didFinishLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didFailLoadWithError:forFrame:]):
+ (-[FrameLoadDelegate webView:windowScriptObjectAvailable:]):
+ (-[FrameLoadDelegate webView:didClearWindowObject:forFrame:]):
+ (-[FrameLoadDelegate webView:didReceiveTitle:forFrame:]):
+ (-[FrameLoadDelegate webView:didReceiveServerRedirectForProvisionalLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didReceiveIcon:forFrame:]):
+ (-[FrameLoadDelegate webView:didChangeLocationWithinPageForFrame:]):
+ (-[FrameLoadDelegate webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:]):
+ (-[FrameLoadDelegate webView:didCancelClientRedirectForFrame:]):
+ (-[FrameLoadDelegate webView:willCloseFrame:]):
+ (-[FrameLoadDelegate webView:didFinishDocumentLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didHandleOnloadEventsForFrame:]):
+ * DumpRenderTree/mac/GCControllerMac.mm: Copied from DumpRenderTree/GCController.mm.
+ * DumpRenderTree/mac/ImageDiff.m: Copied from DumpRenderTree/ImageDiff.m.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm: Copied from DumpRenderTree/LayoutTestControllerMac.mm.
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::setWindowIsKey):
+ (LayoutTestController::setWaitToDump):
+ * DumpRenderTree/mac/NavigationController.h: Copied from DumpRenderTree/NavigationController.h.
+ * DumpRenderTree/mac/NavigationController.m: Copied from DumpRenderTree/NavigationController.m.
+ * DumpRenderTree/mac/ObjCController.h: Copied from DumpRenderTree/ObjCController.h.
+ * DumpRenderTree/mac/ObjCController.m: Copied from DumpRenderTree/ObjCController.m.
+ * DumpRenderTree/mac/ObjCPlugin.h: Copied from DumpRenderTree/ObjCPlugin.h.
+ * DumpRenderTree/mac/ObjCPlugin.m: Copied from DumpRenderTree/ObjCPlugin.m.
+ * DumpRenderTree/mac/ObjCPluginFunction.h: Copied from DumpRenderTree/ObjCPluginFunction.h.
+ * DumpRenderTree/mac/ObjCPluginFunction.m: Copied from DumpRenderTree/ObjCPluginFunction.m.
+ * DumpRenderTree/mac/PolicyDelegate.h: Copied from DumpRenderTree/PolicyDelegate.h.
+ * DumpRenderTree/mac/PolicyDelegate.mm: Copied from DumpRenderTree/PolicyDelegate.m.
+ * DumpRenderTree/mac/ResourceLoadDelegate.h: Copied from DumpRenderTree/ResourceLoadDelegate.h.
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm: Copied from DumpRenderTree/ResourceLoadDelegate.m.
+ (-[ResourceLoadDelegate webView:identifierForInitialRequest:fromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:willSendRequest:redirectResponse:fromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:didReceiveResponse:fromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:didFinishLoadingFromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:didFailLoadingWithError:fromDataSource:]):
+ (-[ResourceLoadDelegate webView:resource:willCacheResponse:fromDataSource:]):
+ * DumpRenderTree/mac/TextInputController.h: Copied from DumpRenderTree/TextInputController.h.
+ * DumpRenderTree/mac/TextInputController.m: Copied from DumpRenderTree/TextInputController.m.
+ * DumpRenderTree/mac/UIDelegate.h: Copied from DumpRenderTree/UIDelegate.h.
+ * DumpRenderTree/mac/UIDelegate.mm: Copied from DumpRenderTree/UIDelegate.mm.
+ (-[UIDelegate webView:dragImage:at:offset:event:pasteboard:source:slideBack:forView:]):
+ (-[UIDelegate webViewFocus:]):
+ (-[UIDelegate webView:createWebViewWithRequest:]):
+ (-[UIDelegate webViewClose:]):
+ * DumpRenderTree/mac/WorkQueueItemMac.mm: Copied from DumpRenderTree/WorkQueueItemMac.mm.
+
+2007-09-14 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Changing Win version of Drosera work with recent changes.
+
+ * Drosera/DebuggerDocument.cpp:
+ * Drosera/DebuggerDocument.h:
+ * Drosera/mac/DebuggerDocumentPlatform.mm:
+ (NSStringCreateWithJSStringRef):
+ (JSValueRefCreateWithNSString):
+ * Drosera/win/DebuggerClient.cpp:
+ (DebuggerClient::stepInto):
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj:
+
+2007-09-13 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Tim.
+
+ - Moved isPaused into the JS for efficiency and simplicity.
+
+ * Drosera/DebuggerDocument.cpp:
+ (DebuggerDocument::DebuggerDocument):
+ (DebuggerDocument::pauseCallback):
+ (DebuggerDocument::resumeCallback):
+ (DebuggerDocument::isPaused):
+ (DebuggerDocument::staticFunctions):
+ * Drosera/DebuggerDocument.h:
+ * Drosera/console.js:
+ * Drosera/debugger.js:
+ * Drosera/mac/DebuggerClient.mm:
+ (-[DebuggerClient validateUserInterfaceItem:]):
+
+2007-09-13 Sam Weinig <sam@webkit.org>
+
+ Rubber stamped by Darin Adler.
+
+ Make DumpRenderTree more cross platform ready.
+ - Convert GCController to use the JSCore API instead of the WebScriptObject.
+ - Use CF types instead of NS objects.
+ - General cleanup.
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.mm:
+ (dumpRenderTree):
+ (dump):
+ (runTest):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/EditingDelegate.m:
+ * DumpRenderTree/FrameLoadDelegate.h:
+ * DumpRenderTree/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate init]):
+ (-[FrameLoadDelegate dealloc]):
+ (-[FrameLoadDelegate webView:didClearWindowObject:forFrame:]):
+ * DumpRenderTree/GCController.cpp: Added.
+ (GCController::GCController):
+ (GCController::~GCController):
+ (collectCallback):
+ (collectOnAlternateThreadCallback):
+ (getJSObjectCountCallback):
+ (GCController::makeWindowObject):
+ (GCController::getJSClass):
+ (GCController::staticFunctions):
+ * DumpRenderTree/GCController.h:
+ * DumpRenderTree/GCController.mm:
+ (GCController::collect):
+ (GCController::collectOnAlternateThread):
+ (GCController::getJSObjectCount):
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::makeWindowObject):
+ (LayoutTestController::getJSClass):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/LayoutTestControllerMac.mm:
+ (LayoutTestController::addDisallowedURL):
+ (waitUntilDoneWatchdogFired):
+ (LayoutTestController::waitUntilDone):
+ * DumpRenderTree/ResourceLoadDelegate.m:
+ (-[ResourceLoadDelegate webView:resource:willSendRequest:redirectResponse:fromDataSource:]):
+
+2007-09-12 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Stephanie.
+
+ Fix leaks in mac DumpRenderTree.
+
+ * DumpRenderTree/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate init]): Initalize in the correct order.
+ (-[FrameLoadDelegate processWork:]): Delete WorkQueueItem's after dequeueing them.
+ * DumpRenderTree/LayoutTestController.cpp:
+ (decodeHostNameCallback): Put return value in a temporary JSRetainPtr to ensure it gets released.
+ (encodeHostNameCallback): ditto.
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/LayoutTestControllerMac.mm:
+ (LayoutTestController::copyDecodedHostName): Rename function to signal that it follows the Create rule.
+ (LayoutTestController::copyEncodedHostName): ditto
+ (LayoutTestController::queueLoad): Use a JSRetainPtr to ensure the url gets released.
+
+2007-09-12 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Geof.
+
+ - Updated Leopard leak list to include a leak which appears to be fixed in 9A549 but not the version the bot is on. This will allow us to get the bot green, but later we should remove it.
+
+ * Scripts/run-webkit-tests:
+
+2007-09-12 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - Simplified code paths and extracted out functions to increase encapsulation.
+
+ * Drosera/DebuggerDocument.cpp:
+ (DebuggerDocument::breakpointEditorHTMLCallback):
+ (DebuggerDocument::isPausedCallback):
+ (DebuggerDocument::pauseCallback):
+ (DebuggerDocument::resumeCallback):
+ (DebuggerDocument::stepIntoCallback):
+ (DebuggerDocument::evaluateScriptCallback):
+ (DebuggerDocument::currentFunctionStackCallback):
+ (DebuggerDocument::localScopeVariableNamesForCallFrameCallback):
+ (DebuggerDocument::valueForScopeVariableNamedCallback):
+ (DebuggerDocument::logCallback):
+ * Drosera/DebuggerDocument.h:
+ (DebuggerDocument::getPaused):
+ * Drosera/mac/DebuggerClient.mm:
+ (-[DebuggerClient pause:]):
+ (-[DebuggerClient resume:]):
+ (-[DebuggerClient stepInto:]):
+ (-[DebuggerClient stepOver:]):
+ (-[DebuggerClient stepOut:]):
+ (-[DebuggerClient showConsole:]):
+ (-[DebuggerClient closeCurrentFile:]):
+ (-[DebuggerClient validateUserInterfaceItem:]):
+ * Drosera/mac/DebuggerDocumentPlatform.mm: Added.
+ (+[NSString stringOrNilFromWebScriptResult:]):
+ (DebuggerDocument::platformPause):
+ (DebuggerDocument::platformResume):
+ (DebuggerDocument::platformStepInto):
+ (DebuggerDocument::platformEvaluateScript):
+ (DebuggerDocument::getPlatformCurrentFunctionStack):
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ (DebuggerDocument::platformValueForScopeVariableNamed):
+ (DebuggerDocument::platformLog):
+ * Drosera/mac/Drosera.xcodeproj/project.pbxproj:
+
+2007-09-12 Sam Weinig <sam@webkit.org>
+
+ Build fix for Buildbot.
+
+ * DumpRenderTree/DumpRenderTree.mm:
+ (dump):
+
+2007-09-12 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Geoff.
+
+ - Updated the leaks list for leopard to help identify regressions.
+
+ * Scripts/run-webkit-tests:
+
+2007-09-12 Sam Weinig <sam@webkit.org>
+
+ Rubber stamped by Darin Adler.
+
+ Convert the LayoutTestController to use the JSCore API instead of WebScriptObject.
+
+ * DumpRenderTree/DumpRenderTree.h: Re-order variables.
+ * DumpRenderTree/DumpRenderTree.m: Removed.
+ * DumpRenderTree/DumpRenderTree.mm: Copied from DumpRenderTree/DumpRenderTree.m.
+ (stopJavaScriptThreads): Fix initialization.
+ (setDefaultColorProfileToRGB): Add explicit cast from void*.
+ (dumpRenderTree): Ditto.
+ (runTest):
+ Used the WorkQueue from the windows DRT instead of the old NSMutableArray one.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/FrameLoadDelegate.h: Add LayoutTestController instance variable.
+ * DumpRenderTree/FrameLoadDelegate.m: Removed.
+ * DumpRenderTree/FrameLoadDelegate.mm: Copied from DumpRenderTree/FrameLoadDelegate.m.
+ (-[FrameLoadDelegate init]):
+ (-[FrameLoadDelegate dealloc]):
+ (-[FrameLoadDelegate processWork:]):
+ (-[FrameLoadDelegate webView:locationChangeDone:forDataSource:]):
+ (-[FrameLoadDelegate webView:didClearWindowObject:forFrame:]):
+ Convert to use the new JSCore based LayoutTestController and the new WorkQueue.
+
+ * DumpRenderTree/LayoutTestController.cpp: Added.
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::~LayoutTestController):
+ (dumpAsTextCallback):
+ (dumpBackForwardListCallback):
+ (dumpChildFramesAsTextCallback):
+ (dumpChildFrameScrollPositionsCallback):
+ (dumpDOMAsWebArchiveCallback):
+ (dumpEditingCallbacksCallback):
+ (dumpFrameLoadCallbacksCallback):
+ (dumpResourceLoadCallbacksCallback):
+ (dumpSelectionRectCallback):
+ (dumpSourceAsWebArchiveCallback):
+ (dumpTitleChangesCallback):
+ (repaintSweepHorizontallyCallback):
+ (setCallCloseOnWebViewsCallback):
+ (setCanOpenWindowsCallback):
+ (setCloseRemainingWindowsWhenCompleteCallback):
+ (testRepaintCallback):
+ (addFileToPasteboardOnDragCallback):
+ (addDisallowedURLCallback):
+ (clearBackForwardListCallback):
+ (decodeHostNameCallback):
+ (displayCallback):
+ (encodeHostNameCallback):
+ (keepWebHistoryCallback):
+ (notifyDoneCallback):
+ (queueBackNavigationCallback):
+ (queueForwardNavigationCallback):
+ (queueLoadCallback):
+ (queueReloadCallback):
+ (queueScriptCallback):
+ (setAcceptsEditingCallback):
+ (setCustomPolicyDelegateCallback):
+ (setMainFrameIsFirstResponderCallback):
+ (setTabKeyCyclesThroughElementsCallback):
+ (setUseDashboardCompatibilityModeCallback):
+ (setUserStyleSheetEnabledCallback):
+ (setUserStyleSheetLocationCallback):
+ (setWindowIsKeyCallback):
+ (waitUntilDoneCallback):
+ (windowCountCallback):
+ (LayoutTestController::makeWindowObject):
+ (LayoutTestController::getLayoutTestControllerJSClass):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h: Replaced.
+ * DumpRenderTree/LayoutTestController.m: Removed.
+ * DumpRenderTree/LayoutTestControllerMac.mm: Added.
+ (LayoutTestController::dumpAsText):
+ (LayoutTestController::dumpBackForwardList):
+ (LayoutTestController::dumpChildFramesAsText):
+ (LayoutTestController::dumpChildFrameScrollPositions):
+ (LayoutTestController::dumpDOMAsWebArchive):
+ (LayoutTestController::dumpEditingCallbacks):
+ (LayoutTestController::dumpFrameLoadCallbacks):
+ (LayoutTestController::dumpResourceLoadCallbacks):
+ (LayoutTestController::dumpSelectionRect):
+ (LayoutTestController::dumpSourceAsWebArchive):
+ (LayoutTestController::dumpTitleChanges):
+ (LayoutTestController::repaintSweepHorizontally):
+ (LayoutTestController::setCallCloseOnWebViews):
+ (LayoutTestController::setCanOpenWindows):
+ (LayoutTestController::setCloseRemainingWindowsWhenComplete):
+ (LayoutTestController::testRepaint):
+ (LayoutTestController::addFileToPasteboardOnDrag):
+ (LayoutTestController::addDisallowedURL):
+ (LayoutTestController::clearBackForwardList):
+ (LayoutTestController::decodeHostName):
+ (LayoutTestController::encodeHostName):
+ (LayoutTestController::display):
+ (LayoutTestController::keepWebHistory):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::queueBackNavigation):
+ (LayoutTestController::queueForwardNavigation):
+ (LayoutTestController::queueLoad):
+ (LayoutTestController::queueReload):
+ (LayoutTestController::queueScript):
+ (LayoutTestController::setAcceptsEditing):
+ (LayoutTestController::setCustomPolicyDelegate):
+ (LayoutTestController::setMainFrameIsFirstResponder):
+ (LayoutTestController::setTabKeyCyclesThroughElements):
+ (LayoutTestController::setUseDashboardCompatibilityMode):
+ (LayoutTestController::setUserStyleSheetEnabled):
+ (LayoutTestController::setUserStyleSheetLocation):
+ (LayoutTestController::setWindowIsKey):
+ (+[WaitToDumpWatchdog waitUntilDoneWatchdogFired]):
+ (LayoutTestController::waitUntilDone):
+ (LayoutTestController::windowCount):
+ Use the JSCore API to implement the LayoutTestController.
+
+ * DumpRenderTree/ObjCController.h:
+ * DumpRenderTree/ObjCController.m:
+ (+[ObjCController isSelectorExcludedFromWebScript:]):
+ (+[ObjCController webScriptNameForSelector:]):
+ (-[ObjCController accessStoredWebScriptObject]):
+ (-[ObjCController storeWebScriptObject:]):
+ (-[ObjCController dealloc]):
+ (-[ObjCController invokeUndefinedMethodFromWebScript:withArguments:]):
+ Move WebScriptObject tests to ObjCController.
+
+ * DumpRenderTree/UIDelegate.m: Removed.
+ * DumpRenderTree/UIDelegate.mm: Copied from DumpRenderTree/UIDelegate.m.
+
+ * DumpRenderTree/WorkQueue.cpp: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WorkQueue.cpp.
+ * DumpRenderTree/WorkQueue.h: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WorkQueue.h.
+ * DumpRenderTree/WorkQueueItem.h: Copied from DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WorkQueueItem.h.
+ (WorkQueueItem::~WorkQueueItem):
+ (LoadItem::LoadItem):
+ (LoadItem::url):
+ (LoadItem::target):
+ (ScriptItem::ScriptItem):
+ (ScriptItem::script):
+ * DumpRenderTree/WorkQueueItemMac.mm: Added.
+ (LoadItem::invoke):
+ (ReloadItem::invoke):
+ (ScriptItem::invoke):
+ (BackForwardItem::invoke):
+ Copy WorkQueue and WorkQueueItem from windows DRT. Changed the WorkQueueItem to use JSStringRefs instead of wstrings
+ to avoid conversion until the last possible moment. These changes will be merged with the windows DRT when we start
+ sharing code.
+
+2007-09-11 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Maciej.
+
+ - Updated Win side to take advantage of the platform separating changes.
+
+ * Drosera/DebuggerDocument.cpp:
+ (DebuggerDocument::localScopeVariableNamesForCallFrame):
+ * Drosera/DebuggerDocument.h:
+ * Drosera/win/DebuggerClient.cpp:
+ (DebuggerClient::pause):
+ (DebuggerClient::resume):
+ (DebuggerClient::stepInto):
+ (DebuggerDocument::platformPause):
+ (DebuggerDocument::platformResume):
+ (DebuggerDocument::platformStepInto):
+ (DebuggerDocument::platformEvaluateScript):
+ (DebuggerDocument::getPlatformCurrentFunctionStack):
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ (DebuggerDocument::platformValueForScopeVariableNamed):
+ (DebuggerDocument::platformLog):
+ * Drosera/win/DebuggerClient.h:
+ * Drosera/win/Drosera.cpp:
+ (Drosera::Drosera):
+ (Drosera::windowScriptObjectAvailable):
+ (Drosera::initWithServerName):
+ (Drosera::switchToServerNamed):
+ * Drosera/win/Drosera.h:
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj:
+
+2007-09-11 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Just doing the moves in a separate patch so the changes are easier to see.
+
+ * Drosera/win/DebuggerClient.cpp: Copied from Drosera/win/DebuggerDocumentWin.cpp.
+ * Drosera/win/DebuggerClient.h: Copied from Drosera/win/DebuggerDocumentWin.h.
+ * Drosera/win/DebuggerDocumentWin.cpp: Removed.
+ * Drosera/win/DebuggerDocumentWin.h: Removed.
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj:
+
+2007-09-11 Sven Herzberg <sven@imendio.com>
+
+ Don't overwrite LD_LIBRARY_PATH, prepend to it. Fixes:
+ http://bugs.webkit.org/show_bug.cgi?id=15176
+
+ * Scripts/run-launcher: don't replace LD_LIBRARY_PATH with
+ $projectDir, but prepend $projectDir to LD_LIBRARY_PATH (to preserve
+ other paths eg. from jhbuild)
+
+2007-09-10 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Made an order-of-deletion mistake.
+
+ * Drosera/DebuggerDocument.h:
+ * Drosera/ForwardingHeaders/wtf/Assertions.h: Removed.
+ * Drosera/ForwardingHeaders/wtf/Noncopyable.h: Removed.
+ * Drosera/ForwardingHeaders/wtf/OwnPtr.h: Removed.
+ * Drosera/mac/DebuggerClient.mm:
+ (DebuggerDocument::platformPause):
+ (DebuggerDocument::platformResume):
+ (DebuggerDocument::platformStepInto):
+ (DebuggerDocument::platformEvaluateScript):
+ (DebuggerDocument::getPlatformCurrentFunctionStack):
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ (DebuggerDocument::platformValueForScopeVariableNamed):
+ * Drosera/mac/Drosera.xcodeproj/project.pbxproj:
+
+2007-09-10 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - Renaming DebuggerDocument[platform] to DebuggerClient to be more clear.
+
+ * Drosera/DebuggerDocument.cpp:
+ (DebuggerDocument::DebuggerDocument):
+ * Drosera/DebuggerDocument.h:
+ * Drosera/ForwardingHeaders/wtf/Assertions.h: Added.
+ * Drosera/ForwardingHeaders/wtf/Noncopyable.h: Added.
+ * Drosera/ForwardingHeaders/wtf/OwnPtr.h: Added.
+ * Drosera/mac/DebuggerApplication.mm:
+ (-[DebuggerApplication attach:]):
+ * Drosera/mac/DebuggerClient.h: Copied from Drosera/mac/DebuggerDocumentMac.h.
+ * Drosera/mac/DebuggerClient.mm: Copied from Drosera/mac/DebuggerDocumentMac.mm.
+ (DebuggerDocument::platformPause):
+ (DebuggerDocument::platformResume):
+ (DebuggerDocument::platformStepInto):
+ (DebuggerDocument::platformEvaluateScript):
+ (DebuggerDocument::getPlatformCurrentFunctionStack):
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ (DebuggerDocument::platformValueForScopeVariableNamed):
+ (DebuggerDocument::platformLog):
+ * Drosera/mac/DebuggerDocumentMac.h: Removed.
+ * Drosera/mac/DebuggerDocumentMac.mm: Removed.
+ * Drosera/mac/Drosera.xcodeproj/project.pbxproj:
+
+2007-09-09 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Remove 'objC' prefix from methods now in the ObjCController.
+
+ * DumpRenderTree/ObjCController.m:
+ (+[ObjCController isSelectorExcludedFromWebScript:]):
+ (+[ObjCController webScriptNameForSelector:]):
+ (-[ObjCController classNameOf:]):
+ (-[ObjCController objectOfClass:]):
+ (-[ObjCController identityIsEqual::]):
+ (-[ObjCController longLongRoundTrip:]):
+ (-[ObjCController unsignedLongLongRoundTrip:]):
+
+2007-09-09 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Oliver.
+
+ Initial refactor of DumpRenderTree in preparation of making it more platform independent.
+ - Move LayoutTestController into its own file.
+ - Move Objective-C only functions on LayoutTestController into a new controller called the
+ ObjCController.
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.m:
+ (displayWebView):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/FrameLoadDelegate.m:
+ (-[FrameLoadDelegate webView:didClearWindowObject:forFrame:]):
+ * DumpRenderTree/LayoutTestController.h: Added.
+ * DumpRenderTree/LayoutTestController.m: Added.
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController clearBackForwardList]):
+ (-[LayoutTestController setUseDashboardCompatibilityMode:]):
+ (-[LayoutTestController setCloseRemainingWindowsWhenComplete:]):
+ (-[LayoutTestController setCustomPolicyDelegate:]):
+ (-[LayoutTestController keepWebHistory]):
+ (-[LayoutTestController setCallCloseOnWebViews:]):
+ (-[LayoutTestController setCanOpenWindows]):
+ (-[LayoutTestController waitUntilDone]):
+ (-[LayoutTestController waitUntilDoneWatchdogFired]):
+ (-[LayoutTestController notifyDone]):
+ (-[LayoutTestController dumpAsText]):
+ (-[LayoutTestController addFileToPasteboardOnDrag]):
+ (-[LayoutTestController addDisallowedURL:]):
+ (-[LayoutTestController setUserStyleSheetLocation:]):
+ (-[LayoutTestController setUserStyleSheetEnabled:]):
+ (-[LayoutTestController dumpDOMAsWebArchive]):
+ (-[LayoutTestController dumpSourceAsWebArchive]):
+ (-[LayoutTestController dumpSelectionRect]):
+ (-[LayoutTestController dumpTitleChanges]):
+ (-[LayoutTestController dumpBackForwardList]):
+ (-[LayoutTestController windowCount]):
+ (-[LayoutTestController dumpChildFrameScrollPositions]):
+ (-[LayoutTestController dumpChildFramesAsText]):
+ (-[LayoutTestController dumpEditingCallbacks]):
+ (-[LayoutTestController dumpResourceLoadCallbacks]):
+ (-[LayoutTestController dumpFrameLoadCallbacks]):
+ (-[LayoutTestController setWindowIsKey:]):
+ (-[LayoutTestController setMainFrameIsFirstResponder:]):
+ (-[LayoutTestController display]):
+ (-[LayoutTestController testRepaint]):
+ (-[LayoutTestController repaintSweepHorizontally]):
+ (-[LayoutTestController invokeUndefinedMethodFromWebScript:withArguments:]):
+ (-[LayoutTestController _addWorkForTarget:selector:arg1:arg2:]):
+ (-[LayoutTestController _doLoad:target:]):
+ (-[LayoutTestController _doBackOrForwardNavigation:]):
+ (-[LayoutTestController queueBackNavigation:]):
+ (-[LayoutTestController queueForwardNavigation:]):
+ (-[LayoutTestController queueReload]):
+ (-[LayoutTestController queueScript:]):
+ (-[LayoutTestController queueLoad:target:]):
+ (-[LayoutTestController setAcceptsEditing:]):
+ (-[LayoutTestController setTabKeyCyclesThroughElements:]):
+ (-[LayoutTestController storeWebScriptObject:]):
+ (-[LayoutTestController accessStoredWebScriptObject]):
+ (-[LayoutTestController dealloc]):
+ (-[LayoutTestController decodeHostName:]):
+ (-[LayoutTestController encodeHostName:]):
+ * DumpRenderTree/ObjCController.h: Added.
+ * DumpRenderTree/ObjCController.m: Added.
+ (+[ObjCController isSelectorExcludedFromWebScript:]):
+ (+[ObjCController webScriptNameForSelector:]):
+ (-[ObjCController objCClassNameOf:]):
+ (-[ObjCController objCObjectOfClass:]):
+ (-[ObjCController objCIdentityIsEqual::]):
+ (-[ObjCController objCLongLongRoundTrip:]):
+ (-[ObjCController objCUnsignedLongLongRoundTrip:]):
+ (-[ObjCController testWrapperRoundTripping:]):
+
+2007-09-07 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Alice.
+
+ Strip trailing and leading space/newline characters from skiplist file names.
+
+ * Scripts/run-webkit-tests:
+
+2007-09-06 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Maciej.
+
+ - Changed Drosera to take advantage of the JSRetainPtr changes.
+
+ * Drosera/DebuggerDocument.cpp:
+ (DebuggerDocument::breakpointEditorHTML):
+ (DebuggerDocument::evaluateScript):
+ (DebuggerDocument::valueForScopeVariableNamed):
+ (DebuggerDocument::log):
+ (DebuggerDocument::windowScriptObjectAvailable):
+ (DebuggerDocument::toJSArray):
+ (DebuggerDocument::callFunctionOnObject):
+ (DebuggerDocument::logException):
+ * Drosera/mac/DebuggerDocumentMac.mm:
+ (-[DebuggerClientMac webView:didLoadMainResourceForDataSource:]):
+ (-[DebuggerClientMac webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:]):
+ (DebuggerDocument::platformEvaluateScript):
+ (DebuggerDocument::getPlatformCurrentFunctionStack):
+ (DebuggerDocument::getPlatformLocalScopeVariableNamesForCallFrame):
+ (DebuggerDocument::platformValueForScopeVariableNamed):
+
+2007-09-05 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam, Sam, Darin.
+
+ - Separated what is platform dependant from what is not. Creating the structure needed for Drosera for Win.
+
+ * Drosera/Debugger.h: Added.
+ * Drosera/DebuggerDocument.cpp:
+ (DebuggerDocument::breakpointEditorHTMLCallback):
+ (DebuggerDocument::isPausedCallback):
+ (DebuggerDocument::pauseCallback):
+ (DebuggerDocument::resumeCallback):
+ (DebuggerDocument::stepIntoCallback):
+ (DebuggerDocument::evaluateScriptCallback):
+ (DebuggerDocument::currentFunctionStackCallback):
+ (DebuggerDocument::localScopeVariableNamesForCallFrameCallback):
+ (DebuggerDocument::valueForScopeVariableNamedCallback):
+ (DebuggerDocument::logCallback):
+ (DebuggerDocument::breakpointEditorHTML):
+ (DebuggerDocument::isPaused):
+ (DebuggerDocument::pause):
+ (DebuggerDocument::resume):
+ (DebuggerDocument::stepInto):
+ (DebuggerDocument::evaluateScript):
+ (DebuggerDocument::currentFunctionStack):
+ (DebuggerDocument::localScopeVariableNamesForCallFrame):
+ (DebuggerDocument::valueForScopeVariableNamed):
+ (DebuggerDocument::log):
+ (DebuggerDocument::toolbarPause):
+ (DebuggerDocument::toolbarResume):
+ (DebuggerDocument::toolbarStepInto):
+ (DebuggerDocument::toolbarStepOver):
+ (DebuggerDocument::toolbarStepOut):
+ (DebuggerDocument::toolbarShowConsole):
+ (DebuggerDocument::toolbarCloseCurrentFile):
+ (DebuggerDocument::updateFileSource):
+ (DebuggerDocument::didParseScript):
+ (DebuggerDocument::willExecuteStatement):
+ (DebuggerDocument::didEnterCallFrame):
+ (DebuggerDocument::willLeaveCallFrame):
+ (DebuggerDocument::exceptionWasRaised):
+ (DebuggerDocument::windowScriptObjectAvailable):
+ (DebuggerDocument::toJSArray):
+ (DebuggerDocument::callGlobalFunction):
+ (DebuggerDocument::callFunctionOnObject):
+ (DebuggerDocument::getDroseraJSClass):
+ (DebuggerDocument::staticFunctions):
+ (DebuggerDocument::logException):
+ * Drosera/DebuggerDocument.h:
+ (DebuggerDocument::DebuggerDocument):
+ * Drosera/ForwardingHeaders: Added.
+ * Drosera/ForwardingHeaders/wtf: Added.
+ * Drosera/ForwardingHeaders/wtf/Platform.h: Added.
+ * Drosera/config.h:
+ * Drosera/console.html:
+ * Drosera/console.js:
+ * Drosera/debugger.js:
+ * Drosera/mac/DebuggerApplication.mm:
+ (-[DebuggerApplication attach:]):
+ * Drosera/mac/DebuggerDocumentMac.h:
+ * Drosera/mac/DebuggerDocumentMac.mm:
+ (+[NSString stringOrNilFromWebScriptResult:]):
+ (+[DebuggerClientMac log:]):
+ (-[DebuggerClientMac initWithServerName:]):
+ (-[DebuggerClientMac dealloc]):
+ (-[DebuggerClientMac pause]):
+ (-[DebuggerClientMac resume]):
+ (-[DebuggerClientMac pause:]):
+ (-[DebuggerClientMac resume:]):
+ (-[DebuggerClientMac stepInto:]):
+ (-[DebuggerClientMac stepOver:]):
+ (-[DebuggerClientMac stepOut:]):
+ (-[DebuggerClientMac showConsole:]):
+ (-[DebuggerClientMac closeCurrentFile:]):
+ (-[DebuggerClientMac validateUserInterfaceItem:]):
+ (-[DebuggerClientMac webView:windowScriptObjectAvailable:]):
+ (-[DebuggerClientMac webView:didEnterCallFrame:sourceId:line:forWebFrame:]):
+ (-[DebuggerClientMac webView:willExecuteStatement:sourceId:line:forWebFrame:]):
+ (-[DebuggerClientMac webView:willLeaveCallFrame:sourceId:line:forWebFrame:]):
+ (-[DebuggerClientMac webView:exceptionWasRaised:sourceId:line:forWebFrame:]):
+ (DebuggerDocument::platformPause):
+ (DebuggerDocument::platformResume):
+ (DebuggerDocument::platformStepInto):
+ (DebuggerDocument::platformEvaluateScript):
+ (DebuggerDocument::platformCurrentFunctionStack):
+ (DebuggerDocument::platformLocalScopeVariableNamesForCallFrame):
+ (DebuggerDocument::platformValueForScopeVariableNamed):
+ (DebuggerDocument::platformLog):
+ * Drosera/mac/Drosera.xcodeproj/project.pbxproj:
+
+2007-09-06 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Register the WebKit DLL on initialization of the DumpRenderTree.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (initialize):
+
+2007-09-05 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Oliver.
+
+ Fix many layout test failures caused by r25364.
+ Set text size to standand size at the begining of each test matching the mac.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (runTest):
+
+2007-09-04 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam.
+
+ Fix for <rdar://problem/5382277>
+ Implement eventSender.textZoomIn and eventSender.textZoomOut for windows DRT.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/EventSender.cpp:
+ (textZoomInCallback):
+ (textZoomOutCallback):
+
+2007-08-29 David Kilzer <ddkilzer@apple.com>
+
+ Reviewed by Adam.
+
+ Added case-insensitivity to checks for adding regression tests.
+
+ * Scripts/prepare-ChangeLog:
+ (generateFileList):
+
+2007-08-28 David Kilzer <ddkilzer@apple.com>
+
+ Reviewed by Maciej.
+
+ Ignore files in /resources/ subdirectories when creating a list of added tests.
+
+ * Scripts/prepare-ChangeLog:
+ (generateFileList):
+
+2007-08-27 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by John.
+
+ - Removed Leopard leaks list since all of those radars were fixed.
+
+ * Scripts/run-webkit-tests:
+
+2007-08-27 Adam Roben <aroben@apple.com>
+
+ Rubberstamped by Mark.
+
+ * Scripts/pdevenv: Pass arguments along to devenv.com.
+
+2007-08-26 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Update prepare-ChangeLog to generate the datestamp in the correct timezone.
+
+ * Scripts/prepare-ChangeLog:
+ (changeLogDate): Added.
+
+2007-08-24 Sam Weinig <sam@webkit.org>
+
+ Revert r25216 which renamed the COM DOM bindings to use Deprecated prefix.
+
+2007-08-24 Sam Weinig <sam@webkit.org>
+
+ Rubber-stamped by Adam Roben.
+
+ <rdar://problem/5434593> Deprecate current manually written COM DOM bindings in anticipation of autogeneration
+
+ Rename COM DOM bindings to use Deprecated prefix.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (dumpFramesAsText):
+ (dump):
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/EditingDelegate.cpp:
+ (dumpPath):
+ (dump):
+ (EditingDelegate::shouldBeginEditingInDOMRange):
+ (EditingDelegate::shouldEndEditingInDOMRange):
+ (EditingDelegate::shouldInsertNode):
+ (EditingDelegate::shouldInsertText):
+ (EditingDelegate::shouldDeleteDOMRange):
+ (EditingDelegate::shouldChangeSelectedDOMRange):
+ (EditingDelegate::shouldApplyStyle):
+ (EditingDelegate::shouldChangeTypingStyle):
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/EditingDelegate.h:
+
+2007-08-24 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by John H.
+
+ WebDataSource::response can legitimately have a null response, so we
+ must check that case.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/LayoutTestController.cpp:
+ (queueLoadCallback):
+
+2007-08-23 Mitz Pettel <mitz@webkit.org>
+
+ Reviewed by Darin and Adam.
+
+ - DumpRenderTree changes to allow testing for
+ http://bugs.webkit.org/show_bug.cgi?id=11756
+ REGRESSION: link targeting a frame in another window does not work
+ <rdar://problem/5286420>
+
+ Use a frame group name for all WebViews created by DumpRenderTree to
+ allow testing of cross-page frame lookup.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (createWebView): Pass group name to -[WebView initWithFrame:frameName:groupName:].
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (main): Pass group name to WebView::initWithFrame(RECT, BSTR, BSTR).
+
+2007-08-23 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Adam.
+
+ Quote the $sslCertificate path in case it contains a space.
+
+ * Scripts/run-webkit-httpd:
+ * Scripts/run-webkit-tests:
+
+2007-08-22 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by John and Adam.
+
+ WebDataSource::response can legitimately have a null response, so we
+ must check that case.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (dump):
+
+2007-08-21 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Geof.
+
+ - Changing the usage to be more clear.
+
+ * Scripts/run-testkjs:
+
+2007-08-20 John Sullivan <sullivan@apple.com>
+
+ Reviewed by Adam Roben
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (runTest):
+ call new +[WebView _setUsesTestModeFocusRingColor:YES] so we get the same focus ring colors
+ in layout tests on Tiger and Leopard
+
+2007-08-20 Adam Roben <aroben@apple.com>
+
+ Put LayoutTests after all other ChangeLogs in commit logs
+
+ We use "~" to sort LayoutTests after all the other ChangeLogs because
+ "~" is the last ASCII character (other than "DEL").
+
+ Reviewed by Sam.
+
+ * Scripts/commit-log-editor:
+
+2007-08-20 Adam Roben <aroben@apple.com>
+
+ Detect that DRT crashed even if a crash dialog is running
+
+ On Windows, when DRT crashes a crash dialog commonly appears. The DRT
+ process is still running at this point, so run-webkit-tests wouldn't
+ detect that DRT had crashed. We now record the crash in our SIGPIPE
+ handler so that we know if DRT crashed even if the crash dialog is up.
+
+ Reviewed by Sam.
+
+ * Scripts/run-webkit-tests:
+ (sub catch_pipe): Set the crashed bit.
+ (sub openDumpTool): Reset the crashed bit.
+ (sub dumpToolDidCrash): Check the crashed bit.
+
+2007-08-20 Adam Roben <aroben@apple.com>
+
+ Fix Bug 15026: prepare-ChangeLog should list new tests in WebCore/ChangeLog
+
+ http://bugs.webkit.org/show_bug.cgi?id=15026
+
+ Reviewed by David Kilzer and Darin Adler.
+
+ * Scripts/prepare-ChangeLog:
+ (sub isModifiedStatus): Split out from isModifiedOrAddedStatus.
+ (sub isAddedStatus): Ditto.
+ (sub testListForChangeLog): Added.
+
+2007-08-19 Oleg Sukhodolsky <son.two@gmail.com>
+
+ Reviewed by Mark.
+
+ -fixes http://bugs.webkit.org/show_bug.cgi?id=14632
+
+ * Scripts/webkitdirs.pm:
+ qt and gtk ports now explicitly pass debug (or release) mode to qmake.
+
+2007-08-17 Darin Adler <darin@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ - don't look for Apple-style localizable strings in the GTK version of WebKit
+
+ * Scripts/extract-localizable-strings: Add a feature where you can pass in the
+ name of subdirectories to skip.
+ * Scripts/update-webkit-localizable-strings: Pass WebKit/gtk as a subdirectory
+ to skip.
+
+2007-08-17 Anders Carlsson <andersca@apple.com>
+
+ Build fix.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c:
+ (NPP_SetWindow):
+
+2007-08-17 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Dave Hyatt.
+
+ <rdar://problem/5379040>
+ REGRESSION (Tiger-Leopard): ADOBE: Safari calls NPP_SetWindow with bad values sometimes
+
+ Add a way for the plug-in to dump the width and height when it gets its NPP_SetWindow call.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c:
+ (NPP_New):
+ (NPP_SetWindow):
+
+2007-08-16 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Maciej.
+
+ Fix <rdar://problem/5360135> REGRESSION (Leopard only): editing/selection/5354455-1.html is causing subsequent tests to fail
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (createWebView):
+ Create a DumpRenderTreeWindow instead of a NSWindow, now that a DumpRenderTreeWindow no longer poses as a NSWindow.
+ (dumpRenderTree):
+ Don't pose as a NSWindow, since when the spelling panel gets created, it creates an NSWindow which ends up creating a DumpRenderTreeWindow.
+
+2007-08-16 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Added tests for regressions in other components. In this case we also need to add a skipped list for Tiger since this functionality didn't exist in 10.4.
+
+ * Scripts/run-webkit-tests:
+
+2007-08-15 Timothy Hatcher <timothy@apple.com>
+
+ Look for the new Xcode 3 preference key (PBXApplicationwideBuildSettings) for the global build locations.
+ The value of PBXApplicationwideBuildSettings is a dictionary, so we have to pull the SYMROOT out of it.
+
+ Also pass xcodebuild OBJROOT with the same value as SYMROOT if we fallback to the default WebKitBuild,
+ this prevents making "build" directories in each project folder.
+
+ * Scripts/webkitdirs.pm:
+
+2007-08-14 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Kevin Mccullough.
+
+ Removed special case that didn't belong. (It would allow a global
+ initializer to sneak into production builds, which would cause a
+ system-wide performance regression on Mac OS X.)
+
+ * Scripts/check-for-global-initializers:
+
+2007-08-14 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by Tim.
+
+ <rdar://problem/5408255> REGRESSION: In Mail, clicking the containing element's UI closebox doesn't delete element
+
+ * DumpRenderTree/EditingDelegate.m:
+ (-[EditingDelegate webView:shouldShowDeleteInterfaceForElement:]): Added, return YES
+ only for elements with the class needsDeletionUI.
+
+2007-08-14 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=14965
+ svn-create-patch uses deprecated tail switch
+
+ * Scripts/svn-create-patch: Use 'tail -n +3' instead of 'tail +3'.
+
+2007-08-13 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Use the cygwin specific Apache config file under cygwin.
+
+ * Scripts/run-webkit-httpd:
+
+2007-08-12 Adam Roben <aroben@apple.com>
+
+ Generate results for new tests in a more logical location
+
+ New platform-specific tests always have their results generated right
+ next to the test. New cross-platform tests will have their results
+ generated a) in the cross-platform directory, if they are text-only,
+ or b) in the least-specific platform directory, if they are render
+ tree dumps.
+
+ Reviewed by Lars.
+
+ * Scripts/run-webkit-tests:
+
+2007-08-12 Adam Roben <aroben@apple.com>
+
+ Print the actual directory where new results are generated.
+
+ Before, we were printing an unpredictable, context-specific substring
+ of the directory.
+
+ Reviewed by Lars.
+
+ * Scripts/run-webkit-tests:
+
+2007-08-12 Adam Roben <aroben@apple.com>
+
+ Factor some common code into a stripExtension() subroutine.
+
+ Reviewed by Lars.
+
+ * Scripts/run-webkit-tests: Also removed some debugging output.
+
+2007-08-11 Matt Lilek <pewtermoose@gmail.com>
+
+ Reviewed over and over and over by Adam Roben.
+
+ Bug 14740: Hierarchical layout tests and platform organization
+ http://bugs.webkit.org/show_bug.cgi?id=14740
+
+ Add support for platform-specific layout tests and results.
+
+ * Scripts/run-webkit-tests:
+
+2007-08-11 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Adam.
+
+ Refactored svn-create-path to use a hash-of-hashes data structure to keep
+ track of changed files. In the top level hash, keys are paths to files and
+ values are 'fileData' hashes with the following keys and values:
+
+ - isBinary: boolean value (set to true for non-text files like images, etc.)
+ - isTestFile: boolean value (set to true if file exists within a known test
+ directory)
+ - modificationType: string equal to one of 'addition', 'additionWithHistory',
+ 'modification' or 'deletion'
+ - path: string equal to the path to the file (this may seem redundant, but it
+ is required to use the second-level 'fileData' hash independent of the
+ top-level hash)
+ - sourceFile: [optional] string equal to the path of the original file that was
+ copied or moved
+ - sourceRevision: [optional] string equal to the revision of the original file
+ that was copied or moved
+
+ * Scripts/svn-create-patch: Moved call to GetOptions() to its own statement
+ that saves the return value in $result, then checks it before printing help.
+ Combined sourceFiles, %testFiles, and %binaryFiles into single %diffFiles hash
+ and eliminated two for() loops.
+ (binarycmp): Added. Used with sort() to order non-binary files before binary
+ files.
+ (findBaseUrl): Added. Extracted from findSourceFileAndRevision().
+ (findMimeType): Added optional second argument that takes a revision number.
+ (generateDiff): Updated to take one fileData argument instead of three ($file,
+ $modificationType, $isBinary).
+ (generateFileList): Updated to take one hash ref argument (%diffFiles)
+ instead of three (%sourceFiles, %testFiles, %binaryFiles). Populates
+ %diffFiles using paths for keys and fileData hashes for values.
+ (manufacturePatchForAdditionWithHistory): Updated to take one fileData
+ argument.
+ (pathcmp): Updated to take two fileData arguments instead of two strings.
+ (testfilecmp): Added. Used with sort() to order non-test files before test
+ files.
+
+2007-08-11 Darin Adler <darin@apple.com>
+
+ * Scripts/run-webkit-tests: Give a different message when only the pixel test failed.
+
+2007-08-06 Nigel Tao <nigeltao@gnome.org>
+
+ Reviewed by David Kilzer.
+
+ Fix bug 14745: WebKitTools/Scripts/run-launcher doesn't speak --gdk
+ http://bugs.webkit.org/show_bug.cgi?id=14745
+
+ * Scripts/run-launcher:
+ Scrub the "--gdk" out of the command line args, if given, so that
+ GdkLauncher doesn't try to interpret it as a URL.
+
+2007-08-03 Adam Roben <aroben@apple.com>
+
+ Catch SIGPIPE on Windows so that run-webkit-tests doesn't quit when DRT crashes
+
+ Reviewed by Sam.
+
+ * Scripts/run-webkit-tests: Also close ERROR when we finish running the tests.
+
+2007-08-03 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Recursively dump all frames as text using new
+ layoutTestController.dumpChildFramesAsText() function.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dumpFramesAsText):
+ (dump):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController dumpChildFramesAsText]):
+ (runTest):
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (dumpFramesAsText):
+ (dump):
+ (runTest):
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/LayoutTestController.cpp:
+ (dumpChildFramesAsTextCallback):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-08-02 Adam Roben <aroben@apple.com>
+
+ Fix fast/dom/Window/alert-undefined.html
+
+ Reviewed by Sam.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/WaitUntilDoneDelegate.cpp:
+ (WaitUntilDoneDelegate::runJavaScriptAlertPanelWithMessage): Don't let
+ Windows translate a null BSTR into "(null)"
+
+2007-08-02 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Tim.
+
+ - It would help if I actually called the right function.
+
+ * Drosera/DebuggerDocument.cpp:
+ (DebuggerDocument::showConsole):
+
+2007-08-02 Adam Roben <aroben@apple.com>
+
+ Don't delete the stderr file right after creating it
+
+ * Scripts/run-webkit-tests:
+
+2007-08-01 Adam Roben <aroben@apple.com>
+
+ When DRT crashes, record stderr and restart DRT
+
+ This prevents a DRT crash from causing the next few hundred tests to
+ "fail" because DRT is no longer running.
+
+ I also changed the terminology that run-webkit-tests uses in its
+ output a bit, so that crashing tests are referred to as "crashes"
+ instead of "failures".
+
+ Reviewed by Mark.
+
+ * Scripts/run-webkit-tests: Detect a crash and record it as a tool
+ failure.
+ (sub openDumpTool): Use open3 so that we can access stderr.
+ (sub dumpToolCrashed): Added.
+ (sub printFailureMessageForTest): Added.
+ (sub htmlForExpectedAndActualResults): Added.
+ (sub deleteExpectedAndActualResults): Added.
+ (sub recordActualResultsAndDiff): Added.
+
+2007-07-30 Darin Adler <darin@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ * DumpRenderTree/DumpRenderTree.m: (dump): Fix dumping for documents that include null
+ characters. This turned out not to be needed for the test case that motivated me to
+ do it, but it's nice to have this for the future.
+
+2007-07-30 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by Lars.
+
+ Link QtLauncher into $$OUTPUT_DIR/bin
+
+ * Scripts/run-launcher:
+
+2007-07-27 David Kilzer <ddkilzer@apple.com>
+
+ Reviewed by Geoff and Darin.
+
+ Use a subroutine for validating the --skipped switch.
+
+ * Scripts/run-webkit-tests:
+
+2007-07-27 Darin Adler <darin@apple.com>
+
+ Reviewed by Sam.
+
+ * Scripts/run-webkit-tests: Remove exception for leaks bug that has been fixed on Leopard.
+
+2007-07-27 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Mark.
+
+ Correct the path of GdkLauncher and make checkFrameworks work on OSX
+ when building the Qt or Gtk+ port.
+
+ * GdkLauncher/GdkLauncher.pro: Don't create an app bundle on OSX
+ * Scripts/run-launcher:
+ * Scripts/webkitdirs.pm: Don't add WebKit if we build the Qt or Gtk+ port.
+
+2007-07-27 Simon Hausmann <hausmann@kde.org>
+
+ Done with and reviewed by Lars and Zack.
+
+ Fix build-webkit for the Qt build on Windows with msvc/nmake by trying to detect the Qt mkspec and using "nmake" instead of "make" as build command.
+
+ * Scripts/webkitdirs.pm:
+
+2007-07-27 Simon Hausmann <hausmann@kde.org>
+
+ Done with and reviewed by Lars and Zack.
+
+ For detecting the SVG support for the Qt build don't do the nm hack. Just always claim SVG support is enabled because that's what it is. The nm hack doesn't work on Windows anyway.
+
+ * Scripts/webkitdirs.pm:
+
+2007-07-26 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Darin, Geoff, Sam.
+
+ - <rdar://problem/5150461> Resizing the window larger than the screen causes no resize.
+
+ - Added delegate methods to intercept and fake the frame location so methods like resizeTo and moveTo can change the window location without actually making the window appear on-screen.
+
+ * DumpRenderTree/UIDelegate.h:
+ * DumpRenderTree/UIDelegate.m:
+ (-[UIDelegate webView:setFrame:]):
+ (-[UIDelegate webViewFrame:]):
+
+2007-07-26 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Lars wanted this check for Qt but it breaks platform specific layout tests.
+
+ * Scripts/run-webkit-tests:
+
+2007-07-25 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Tim, Darin, Oliver.
+
+ - <rdar://problem/5329440> REGRESSION: Clicking links with the feed:// protocol in Safari 3 does nothing
+ - Change DRT to be able to intercept the requst to load so it can check if a scheme was allowed or not.
+
+ * ChangeLog:
+ * DumpRenderTree/DumpRenderTree.m:
+ (createWebView):
+ (dumpRenderTree):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController setCustomPolicyDelegate:]):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/FrameLoadDelegate.h:
+ * DumpRenderTree/PolicyDelegate.h: Added.
+ * DumpRenderTree/PolicyDelegate.m: Added.
+ (-[PolicyDelegate webView:decidePolicyForNavigationAction:request:frame:decisionListener:]):
+ * DumpRenderTree/ResourceLoadDelegate.h:
+
+2007-07-25 Adam Treat <treat@kde.org>
+
+ Reviewed by Niko.
+
+ Fix build for some reported systems.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.cpp:
+
+2007-07-23 Adam Treat <treat@kde.org>
+
+ Reviewed by Nikolas.
+
+ Fix qt DRT to suppress js popup alerts and log instead.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::WebPage::javaScriptAlert):
+
+2007-07-22 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Adam.
+
+ Make the GdkLauncher use the new WebKit/Gtk API. Change webkitdirs.pm to
+ honor --qmakearg for the Gdk/Gtk build as well.
+
+ * GdkLauncher/main.cpp: Switch to the new API
+ * Scripts/webkitdirs.pm: Allow to specify --qmakearg, e.g. to control the WEBKIT_{INC,LIB}_DIR
+
+2007-07-22 Darin Adler <darin@apple.com>
+
+ * DumpRenderTree/TextInputController.m: (-[TextInputController interpretKeyEvents:withSender:]):
+ Fix a leak by releasing the array used here.
+
+2007-07-22 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=14713
+ Script to update iExploder cssproperties.in file based on CSSPropertyNames.in
+
+ Added script to update WebKitTools/iExploder/htdocs/cssproperties.in based on the contents
+ of WebCore/css/CSSPropertyNames.in. Also updated cssproperties.in.
+
+ * Scripts/update-iexploder-cssproperties: Added.
+ * iExploder/htdocs/cssproperties.in: Updated by running update-iexploder-cssproperties script.
+ Added new CSS3 property section and Moved box-sizing property to it.
+
+2007-07-22 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=14710
+
+ Add preliminary support for testing Input Method/WebKit behaviour and interaction
+ in DRT. This provides the NSTextInput API which is most of what should be necessary
+ to mimic the event sequences Input Methods trigger.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/TextInputController.h:
+ * DumpRenderTree/TextInputController.m:
+ (-[WebHTMLView interpretKeyEvents:]):
+ (+[TextInputController isSelectorExcludedFromWebScript:]):
+ (+[TextInputController webScriptNameForSelector:]):
+ (-[TextInputController initWithWebView:]):
+ (-[TextInputController dealloc]):
+ (-[TextInputController textInput]):
+ (-[TextInputController setInputMethodHandler:]):
+ (-[TextInputController interpretKeyEvents:withSender:]):
+
+2007-07-20 Adam Roben <aroben@apple.com>
+
+ * Scripts/commit-log-editor: Small fix to make an all-whitespace log
+ message not count as an existing log.
+
+2007-07-19 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Updated DumpRenderTree for <rdar://problem/5348384> Restore old return
+ value behavior of stringByEvaluatingJavaScriptFromString
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (testStringByEvaluatingJavaScriptFromString):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-07-19 Adam Roben <aroben@apple.com>
+
+ Make commit-log-editor work with git
+
+ Reviewed by Sam.
+
+ * Scripts/commit-log-editor: Use VCSUtils and accept a git-style
+ commit message template. Also removed the unused $breakPoint variable.
+
+2007-07-19 Adam Roben <aroben@apple.com>
+
+ Move generally-useful VCS code into a new VCSUtils.pm module
+
+ This is in preparation for making commit-log-editor git-friendly.
+
+ Reviewed by Sam.
+
+ * Scripts/VCSUtils.pm: Added. Code moved here from prepare-ChangeLog.
+ * Scripts/prepare-ChangeLog: Use VCSUtils.
+
+2007-07-19 Lars Knoll <lars@trolltech.com>
+
+ Fix a crash on exit when running DRT against a current
+ Qt 4.4 snapshot.
+
+ Reviewed by Zack
+
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+ (main):
+
+2007-07-18 Adam Roben <aroben@apple.com>
+
+ Don't try to use an SSL certificate on Windows until <rdar://problem/5345985> is fixed
+
+ Reviewed by Mark.
+
+ * Scripts/run-webkit-httpd:
+ * Scripts/run-webkit-tests:
+
+2007-07-18 Adam Roben <aroben@apple.com>
+
+ More git friendliness for prepare-ChangeLog
+
+ The overall change is to remove the use of git-status and replace it
+ with git-diff --name-status (which we were already using in the
+ --git-commit case).
+
+ This lets us respect directories specified on the command line when
+ using git, just as we do for Subversion. It also speeds things up a
+ bit, especially in the subdirectory case, as git-status is pretty slow.
+
+ I also fixed some issues where we wouldn't detect copied files and
+ would reverse the new filename and the original filename for renamed files.
+
+ Reviewed by Mark.
+
+ * Scripts/prepare-ChangeLog:
+ (sub diffFromToString): Added.
+ (sub diffCommand): Don't append the paths in the --git-commit case, as
+ we should be operating on the entire commit.
+ (sub statusCommand): Always use git-diff --name-status, and added an
+ extra -C option to git-diff to make it find a few more copied files.
+ (sub createPatchCommand): Collapsed the two git cases a bit, and added
+ the extra -C option as above.
+ (sub generateFileList): Remove the git-status codepath, and recognize
+ file copies in the --name-status output.
+ (sub isModifiedOrAddedStatus): Collapsed the status codes into one
+ dictionary.
+ (sub isConflictStatus): Updated the git dictionary.
+ (sub statusDescription): Updated the git dictionary.
+
+2007-07-18 Timothy Hatcher <timothy@apple.com>
+
+ * Scripts/build-drosera: Update where we look for the Xcode project.
+
+2007-07-18 Adam Treat <treat@kde.org>
+
+ Reviewed by bdash.
+
+ Use the old wording for Safari.
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2007-07-18 Adam Treat <treat@kde.org>
+
+ Reviewed by bdash.
+
+ Add convenience script for launching test apps for Qt and Gdk ports.
+ Change the build-webkit script accordingly.
+
+ * Scripts/build-webkit:
+ * Scripts/run-launcher: Added.
+ * Scripts/webkitdirs.pm:
+
+2007-07-18 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Adam.
+
+ Make the Page with the now required InspectorClient.
+
+ * GdkLauncher/main.cpp:
+ (main):
+
+2007-07-18 Timothy Hatcher <timothy@apple.com>
+
+ Remove the redundant copies of Makefile.shared and the new Makefile.Drosera.
+ Now included the main Makefile.shared and change the SCRIPTS_PATH variable as needed.
+
+ * Drosera/Makefile: Added.
+ * Drosera/mac/Makefile:
+ * DumpRenderTree/Makefile:
+ * Makefile:
+ * Makefile.Drosera: Removed.
+ * Makefile.shared: Removed.
+
+2007-07-18 Timothy Hatcher <timothy@apple.com>
+
+ The console log was 20px down from the top for no reason, move it up.
+
+ * Drosera/console.css:
+
+2007-07-18 Timothy Hatcher <timothy@apple.com>
+
+ Use contentDocument to get the source view's iframe document.
+ Also adds a null/undefined check for localVariableNames.
+
+ * Drosera/debugger.js:
+
+2007-07-18 Lars Knoll <lars@trolltech.com>
+
+ We really don't want to compare non text only tests to the
+ Mac results if we don't have a result for Qt, as this would
+ give a failure and not a notification that the test is new.
+
+ Reviewed by Zack
+
+ * Scripts/run-webkit-tests:
+
+2007-07-18 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack & Simon
+
+ Adjust to changed API in QWebFrame
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2007-07-18 Mark Rowe <mrowe@apple.com>
+
+ Update path to the Drosera Xcode project now that it has moved into a subdirectory.
+
+ * BuildSlaveSupport/build-launcher-app:
+
+2007-07-17 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Antti Koivisto.
+
+ Added watchdog timer to waitUntilDone to prevent a run-away test from
+ hanging the test harness.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dump):
+ (-[LayoutTestController waitUntilDone]):
+ (-[LayoutTestController waitUntilDoneWatchdogFired]):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-07-17 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam.
+
+ - Implemented cross-platform code for functions calling into the JavaScript.
+
+ * Drosera/DebuggerDocument.cpp:
+ (DebuggerDocument::callAsFunction):
+ (DebuggerDocument::pauseJS):
+ (DebuggerDocument::resumeJS):
+ (DebuggerDocument::stepIntoJS):
+ (DebuggerDocument::stepOverJS):
+ (DebuggerDocument::stepOutJS):
+ (DebuggerDocument::showConsoleJS):
+ (DebuggerDocument::closeCurrentFileJS):
+ (DebuggerDocument::updateFileSource):
+ (DebuggerDocument::didParseScript):
+ (DebuggerDocument::willExecuteStatement):
+ (DebuggerDocument::didEnterCallFrame):
+ (DebuggerDocument::willLeaveCallFrame):
+ (DebuggerDocument::exceptionWasRaised):
+ * Drosera/DebuggerDocument.h:
+ * Drosera/mac/DebuggerDocumentMac.mm:
+ (-[DebuggerDocumentMac pause:]):
+ (-[DebuggerDocumentMac resume:]):
+ (-[DebuggerDocumentMac stepInto:]):
+ (-[DebuggerDocumentMac stepOver:]):
+ (-[DebuggerDocumentMac stepOut:]):
+ (-[DebuggerDocumentMac showConsole:]):
+ (-[DebuggerDocumentMac closeCurrentFile:]):
+ (-[DebuggerDocumentMac webView:didLoadMainResourceForDataSource:]):
+ (-[DebuggerDocumentMac webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:]):
+ (-[DebuggerDocumentMac webView:didEnterCallFrame:sourceId:line:forWebFrame:]):
+ (-[DebuggerDocumentMac webView:willExecuteStatement:sourceId:line:forWebFrame:]):
+ (-[DebuggerDocumentMac webView:willLeaveCallFrame:sourceId:line:forWebFrame:]):
+ (-[DebuggerDocumentMac webView:exceptionWasRaised:sourceId:line:forWebFrame:]):
+
+2007-07-16 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - Continued x-platform modifications.
+
+ * Drosera/win/DebuggerDocumentWin.cpp: Copied from Drosera/win/DebuggerObjectCallbacks.cpp.
+ * Drosera/win/DebuggerDocumentWin.h: Copied from Drosera/win/DebuggerObjectCallbacks.h.
+ * Drosera/win/DebuggerObjectCallbacks.cpp: Removed.
+ * Drosera/win/DebuggerObjectCallbacks.h: Removed.
+ * Drosera/win/Drosera.cpp:
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj:
+ * Drosera/win/stdafx.cpp: Removed.
+ * Drosera/win/stdafx.h: Removed.
+
+2007-07-16 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Sam.
+
+ - Modified files to use cross-platform code.
+
+ * Drosera/DebuggerDocument.cpp: Added.
+ (DebuggerDocument::breakpointEditorHTML):
+ (DebuggerDocument::isPaused):
+ (DebuggerDocument::pause):
+ (DebuggerDocument::resume):
+ (DebuggerDocument::stepInto):
+ (DebuggerDocument::evaluateScript):
+ (DebuggerDocument::currentFunctionStack):
+ (DebuggerDocument::localScopeVariableNamesForCallFrame):
+ (DebuggerDocument::valueForScopeVariableNamed):
+ * Drosera/DebuggerDocument.h: Added.
+ (DebuggerDocument::DebuggerDocument):
+ * Drosera/config.h: Added.
+ * Drosera/mac/DebuggerApplication.mm:
+ (-[DebuggerApplication attach:]):
+ * Drosera/mac/DebuggerDocument.h: Removed.
+ * Drosera/mac/DebuggerDocument.mm: Removed.
+ * Drosera/mac/DebuggerDocumentMac.h: Copied from Drosera/mac/DebuggerDocument.h.
+ * Drosera/mac/DebuggerDocumentMac.mm: Copied from Drosera/mac/DebuggerDocument.mm.
+ (-[DebuggerDocumentMac initWithServerName:]):
+ (-[DebuggerDocumentMac dealloc]):
+ (-[DebuggerDocumentMac breakpointEditorHTML]):
+ (-[DebuggerDocumentMac isPaused]):
+ (-[DebuggerDocumentMac pause]):
+ (-[DebuggerDocumentMac resume]):
+ * Drosera/mac/Drosera.xcodeproj/project.pbxproj:
+ * Drosera/win/DebuggerApplication.cpp:
+ * Drosera/win/DebuggerObjectCallbacks.cpp:
+ (breakpointEditorHTMLCallback):
+ (currentFunctionStackCallback):
+ (evaluateScript_inCallFrame_Callback):
+ (isPausedCallback):
+ (localScopeVariableNamesForCallFrame_Callback):
+ (pauseCallback):
+ (resumeCallback):
+ (stepIntoCallback):
+ (valueForScopeVariableNamed_inCallFrame_Callback):
+ (staticFunctions):
+ * Drosera/win/Drosera.cpp:
+ * Drosera/win/DroseraPrefix.cpp: Added.
+ * Drosera/win/DroseraPrefix.h: Added.
+
+2007-07-16 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam, Sam and Tim.
+
+ - Moving files to prepare for cross-platform architecture.
+
+ * Drosera/DebuggerApplication.h: Removed.
+ * Drosera/DebuggerApplication.m: Removed.
+ * Drosera/DebuggerDocument.h: Removed.
+ * Drosera/DebuggerDocument.m: Removed.
+ * Drosera/Drosera.pch: Removed.
+ * Drosera/Drosera.xcodeproj: Removed.
+ * Drosera/Drosera.xcodeproj/project.pbxproj: Removed.
+ * Drosera/Info.plist: Removed.
+ * Drosera/LauncherInfo.plist: Removed.
+ * Drosera/Makefile: Removed.
+ * Drosera/launcher.m: Removed.
+ * Drosera/mac: Added.
+ * Drosera/mac/DebuggerApplication.h: Copied from Drosera/DebuggerApplication.h.
+ * Drosera/mac/DebuggerApplication.mm: Copied from Drosera/DebuggerApplication.m.
+ * Drosera/mac/DebuggerDocument.h: Copied from Drosera/DebuggerDocument.h.
+ * Drosera/mac/DebuggerDocument.mm: Copied from Drosera/DebuggerDocument.m.
+ * Drosera/mac/Drosera.pch: Copied from Drosera/Drosera.pch.
+ * Drosera/mac/Drosera.xcodeproj: Copied from Drosera/Drosera.xcodeproj.
+ * Drosera/mac/Drosera.xcodeproj/project.pbxproj:
+ * Drosera/mac/Info.plist: Copied from Drosera/Info.plist.
+ * Drosera/mac/LauncherInfo.plist: Copied from Drosera/LauncherInfo.plist.
+ * Drosera/mac/Makefile: Copied from Drosera/Makefile.
+ * Drosera/mac/launcher.m: Copied from Drosera/launcher.m.
+ * Drosera/mac/main.m: Copied from Drosera/main.m.
+ * Drosera/main.m: Removed.
+ * Makefile:
+ * Makefile.Drosera: Added.
+
+2007-07-15 Mark Rowe <mrowe@apple.com>
+
+ * Scripts/generate-coverage-data: Don't fail if WebKitBuild directory does not exist.
+
+2007-07-13 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Geoff Garen.
+
+ Add support for running SSL tests over HTTPS.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (runTest):
+ * DumpRenderTree/FrameLoadDelegate.m:
+ (-[FrameLoadDelegate webView:didFailProvisionalLoadWithError:forFrame:]):
+ * Scripts/run-webkit-httpd:
+ * Scripts/run-webkit-tests:
+
+2007-07-13 David Kilzer <ddkilzer@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Added support for -h|--help argument and verify that all command line arguments parse
+ correctly.
+
+ * Scripts/run-webkit-httpd:
+
+2007-07-12 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Ada.
+
+ Remove leak suppression for xmlDocPtrForString now that <rdar://problem/5329877> is fixed.
+
+ * Scripts/run-webkit-tests:
+
+2007-07-12 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Made the leaks tests pass on Leopard.
+
+ * Scripts/run-webkit-tests: Added some leaks to exclude on Leopard.
+ * Scripts/run-leaks: Updated parser for slight change in text output.
+
+2007-07-11 David Kilzer <ddkilzer@apple.com>
+
+ Reviewed by Maciej.
+
+ Update the iExploder list of CSS properties after box-sizing was renamed to
+ -webkit-box-sizing in r21026 to fix <rdar://problem/4667227>.
+
+ * iExploder/htdocs/cssproperties.in: Added -webkit-box-sizing. Both box-sizing and
+ -moz-box-sizing remain.
+
+2007-07-10 Darin Adler <darin@apple.com>
+
+ * Scripts/run-webkit-tests: Add an ignore item for a leak in Tiger's
+ Foundation's multipart/mixed-replace support -- I already verified that
+ the bug has been fixed.
+
+2007-07-10 Alice Liu <alice.liu@apple.com>
+
+ rubber stamped by Maciej.
+
+ fixed <rdar://5137972> editing/selection/editable-links.html fails on Windows
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (initializePreferences):
+ set editable link behavior to match Mac DRT.
+
+2007-07-10 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ Ignore Page.o in debug builds because it now has a static PageCounter
+ object.
+
+ * Scripts/check-for-global-initializers:
+
+2007-07-09 Darin Adler <darin@apple.com>
+
+ * Scripts/run-webkit-tests: Moved leaks from Tiger that are marked as fixed in Leopard to a Tiger-only section.
+
+2007-07-09 Alice Liu <alice.liu@apple.com>
+
+ Reviewed by Adam Roben.
+
+ setting DOM Paste Allowed Pref
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (initializePreferences):
+
+2007-07-05 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Adam, Sam, and Ada.
+
+ - Inital checkin of Drosera for Win. This isn't pretty and doesn't connect to Safari but debug builds and runs.
+
+ * Drosera/Images/Drosera.ico: Added.
+ * Drosera/Images/small.ico: Added.
+ * Drosera/win: Added.
+ * Drosera/win/BaseDelegate.h: Added.
+ (BaseDelegate::QueryInterface):
+ (BaseDelegate::didFinishLoadForFrame):
+ (BaseDelegate::windowScriptObjectAvailable):
+ (BaseDelegate::didStartProvisionalLoadForFrame):
+ (BaseDelegate::didReceiveServerRedirectForProvisionalLoadForFrame):
+ (BaseDelegate::didFailProvisionalLoadWithError):
+ (BaseDelegate::didCommitLoadForFrame):
+ (BaseDelegate::didReceiveTitle):
+ (BaseDelegate::didReceiveIcon):
+ (BaseDelegate::didFailLoadWithError):
+ (BaseDelegate::didChangeLocationWithinPageForFrame):
+ (BaseDelegate::willPerformClientRedirectToURL):
+ (BaseDelegate::didCancelClientRedirectForFrame):
+ (BaseDelegate::willCloseFrame):
+ (BaseDelegate::createWebViewWithRequest):
+ (BaseDelegate::webViewShow):
+ (BaseDelegate::webViewClose):
+ (BaseDelegate::webViewFocus):
+ (BaseDelegate::webViewUnfocus):
+ (BaseDelegate::webViewFirstResponder):
+ (BaseDelegate::makeFirstResponder):
+ (BaseDelegate::setStatusText):
+ (BaseDelegate::webViewStatusText):
+ (BaseDelegate::webViewAreToolbarsVisible):
+ (BaseDelegate::setToolbarsVisible):
+ (BaseDelegate::webViewIsStatusBarVisible):
+ (BaseDelegate::setStatusBarVisible):
+ (BaseDelegate::webViewIsResizable):
+ (BaseDelegate::setResizable):
+ (BaseDelegate::setFrame):
+ (BaseDelegate::webViewFrame):
+ (BaseDelegate::setContentRect):
+ (BaseDelegate::webViewContentRect):
+ (BaseDelegate::runJavaScriptAlertPanelWithMessage):
+ (BaseDelegate::runJavaScriptConfirmPanelWithMessage):
+ (BaseDelegate::runJavaScriptTextInputPanelWithPrompt):
+ (BaseDelegate::runBeforeUnloadConfirmPanelWithMessage):
+ (BaseDelegate::runOpenPanelForFileButtonWithResultListener):
+ (BaseDelegate::mouseDidMoveOverElement):
+ (BaseDelegate::contextMenuItemsForElement):
+ (BaseDelegate::validateUserInterfaceItem):
+ (BaseDelegate::shouldPerformAction):
+ (BaseDelegate::dragDestinationActionMaskForDraggingInfo):
+ (BaseDelegate::willPerformDragDestinationAction):
+ (BaseDelegate::dragSourceActionMaskForPoint):
+ (BaseDelegate::willPerformDragSourceAction):
+ (BaseDelegate::contextMenuItemSelected):
+ (BaseDelegate::hasCustomMenuImplementation):
+ (BaseDelegate::trackCustomPopupMenu):
+ (BaseDelegate::measureCustomMenuItem):
+ (BaseDelegate::drawCustomMenuItem):
+ (BaseDelegate::addCustomMenuDrawingData):
+ (BaseDelegate::cleanUpCustomMenuDrawingData):
+ (BaseDelegate::canTakeFocus):
+ (BaseDelegate::takeFocus):
+ (BaseDelegate::registerUndoWithTarget):
+ (BaseDelegate::removeAllActionsWithTarget):
+ (BaseDelegate::setActionTitle):
+ (BaseDelegate::undo):
+ (BaseDelegate::redo):
+ (BaseDelegate::canUndo):
+ (BaseDelegate::canRedo):
+ * Drosera/win/DebuggerApplication.cpp: Added.
+ (DebuggerApplication::serverLoaded):
+ (DebuggerApplication::serverUnloaded):
+ (DebuggerApplication::attach):
+ (DebuggerApplication::numberOfRowsInTableView):
+ (DebuggerApplication::tableView):
+ * Drosera/win/DebuggerApplication.h: Added.
+ (DebuggerApplication::DebuggerApplication):
+ (DebuggerApplication::knownServers):
+ * Drosera/win/DebuggerObjectCallbacks.cpp: Added.
+ (breakpointEditorHTMLCallback):
+ (currentFunctionStackCallback):
+ (doubleClickMillisecondsCallback):
+ (evaluateScript_inCallFrame_Callback):
+ (isPausedCallback):
+ (localScopeVariableNamesForCallFrame_Callback):
+ (pauseCallback):
+ (resumeCallback):
+ (stepIntoCallback):
+ (valueForScopeVariableNamed_inCallFrame_Callback):
+ (staticFunctions):
+ * Drosera/win/DebuggerObjectCallbacks.h: Added.
+ * Drosera/win/Drosera.cpp: Added.
+ (_tWinMain):
+ (RegisterDroseraClass):
+ (DroseraWndProc):
+ (About):
+ (Attach):
+ (Drosera::Drosera):
+ (Drosera::initUI):
+ (Drosera::QueryInterface):
+ (Drosera::AddRef):
+ (Drosera::Release):
+ (Drosera::didFinishLoadForFrame):
+ (getDroseraJSClass):
+ (Drosera::windowScriptObjectAvailable):
+ (Drosera::webViewClose):
+ (Drosera::validateUserInterfaceItem):
+ (Drosera::runJavaScriptAlertPanelWithMessage):
+ (Drosera::onSize):
+ * Drosera/win/Drosera.h: Added.
+ (Drosera::webViewLoaded):
+ * Drosera/win/Drosera.vcproj: Added.
+ * Drosera/win/Drosera.vcproj/Drosera.rc: Added.
+ * Drosera/win/Drosera.vcproj/Drosera.vcproj: Added.
+ * Drosera/win/Drosera.vcproj/debug.vsprops: Added.
+ * Drosera/win/Drosera.vcproj/release.vsprops: Added.
+ * Drosera/win/HelperFunctions.h: Added.
+ (CFStringToBSTR):
+ * Drosera/win/Info.plist: Added.
+ * Drosera/win/resource.h: Added.
+ * Drosera/win/stdafx.cpp: Added.
+ * Drosera/win/stdafx.h: Added.
+
+2007-07-09 Adam Treat <adam@staikos.net>
+
+ Reviewed by George Staikos.
+
+ Convert QWebFrame from a QFrame to a pure QObject to eliminate all
+ traces of widgets.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2007-07-09 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Oliver.
+
+ <rdar://problem/4954319>
+ Acrobat 7 / Safari crash: CrashTracer: 99 crashes in Safari at
+ com.apple.WebCore: WebCore::NetscapePlugInStreamLoader::isDone const + 0
+
+ If the src url is "data:application/x-webkit-test-netscape,returnerrorfromnewstream",
+ return an error from NPP_NewStream.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c:
+ (NPP_New):
+ (NPP_NewStream):
+
+2007-07-08 Mark Rowe <mrowe@apple.com>
+
+ Change name from WebKit/Qt to WebKit.
+
+ * CodeCoverage/regenerate-coverage-display:
+
+2007-07-08 Rob Buis <buis@kde.org>
+
+ Reviewed by Mitz.
+
+ http://bugs.webkit.org/show_bug.cgi?id=14209
+ DRT should be able to deal with text zoom
+
+ Allow increasing/decreasing text zoom using eventSender.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (runTest):
+ * DumpRenderTree/EventSendingController.m:
+ (+[EventSendingController initialize]):
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (-[EventSendingController textZoomIn]):
+ (-[EventSendingController textZoomOut]):
+
+2007-07-07 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (convertWebResourceResponseToDictionary): Fix leak of two NSMutableString's introduced in r24076.
+
+2007-07-06 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by David Kilzer.
+
+ <rdar://problem/5313502>
+ Many webarchive tests fail due to different NSURLResponse serialization on Leopard
+
+ Don't dump the serialized form of NSURLResponse. Instead, create a dictionary with the
+ response's attributes. Also change the JavaScript MIME type to be "text/javascript".
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (convertMIMEType):
+ (convertWebResourceDataToString):
+ (convertWebResourceResponseToDictionary):
+ (serializeWebArchiveToXML):
+
+2007-07-06 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Oliver.
+
+ Initialize the NSMutableAttributedString directly instead of creating
+ a NSAttributedString first.
+
+ * DumpRenderTree/TextInputController.m:
+ (-[TextInputController attributedStringWithString:]):
+
+2007-07-06 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by David Kilzer.
+
+ Replace "Apple Computer" with "Apple" in the DTD declaration.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (serializeWebArchiveToXML):
+
+2007-07-06 Adam Treat <adam@staikos.net>
+
+ Reviewed by George Staikos.
+
+ Adjust for conversion of QWebFrame to a QFrame from a scroll area.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2007-07-06 George Staikos <staikos@kde.org>
+
+ Reviewed by Anders.
+
+ Allow passing of additional arguments to qmake with --qmakearg=
+
+ * Scripts/webkitdirs.pm:
+
+2007-07-05 George Staikos <staikos@kde.org>
+
+ Reviewed by Maciej.
+
+ Add --qt and --qmake= to force Qt even when QTDIR isn't present and to
+ give a path to a specific qmake binary. Both are optional.
+
+ * Scripts/webkitdirs.pm:
+
+2007-07-05 Adam Roben <aroben@apple.com>
+
+ Warn about tests in the Skipped file that succeeded
+
+ * Scripts/run-webkit-tests:
+
+2007-07-05 Adam Roben <aroben@apple.com>
+
+ Removed unused install-win-extras script
+
+ Rubberstamped by Mark.
+
+ * Scripts/install-win-extras: Removed.
+
+2007-07-05 Adam Roben <aroben@apple.com>
+
+ Show the test's extension in the results page
+
+ * Scripts/run-webkit-tests:
+
+2007-07-05 Adam Roben <aroben@apple.com>
+
+ Add more options for controlling the interpretation of the Skipped file
+
+ Reviewed by Mark.
+
+ * Scripts/run-webkit-tests:
+
+2007-07-04 Adam Roben <aroben@apple.com>
+
+ Add --skipped-only option to run-webkit-tests
+
+ When this option is specified, only those tests listed in the Skipped
+ file are run.
+
+ Reviewed by Mark.
+
+ * Scripts/run-webkit-tests:
+
+2007-07-04 Adam Roben <aroben@apple.com>
+
+ Clean up/alphabetize the run-webkit-tests help message
+
+ * Scripts/run-webkit-tests:
+
+2007-07-04 Adam Roben <aroben@apple.com>
+
+ Enable a Leopard-specific Skipped list.
+
+ Reviewed by Mark.
+
+ * Scripts/run-webkit-tests: Check for Leopard.
+ * Scripts/webkitdirs.pm: Added isTiger/isLeopard.
+
+2007-07-03 Adam Roben <aroben@apple.com>
+
+ Fixed update-webkit-localizable-strings to work with new extract-localizable-strings
+
+ Got rid of extract-webkit-localizable-strings because it was trying to
+ do update-webkit-localizable-strings' job.
+
+ Rubberstamped by Darin Adler.
+
+ * Scripts/extract-webkit-localizable-strings: Removed.
+ * Scripts/update-webkit-localizable-strings: Renamed from
+ extract-localizable-strings.
+
+2007-07-03 Adam Roben <aroben@apple.com>
+
+ Modify scripts to keep Mac/Windows localized strings in sync
+
+ extract-webkit-localizable-strings now handles extracting strings from
+ both the Mac and Windows WebKit ports and updating their respective
+ Localizable.strings files. extract-localizable-strings is now really a
+ piece of plumbing rather than a top-level tool.
+
+ Reviewed by Darin and Anders.
+
+ * Scripts/extract-localizable-strings: Changed to handle multiple
+ directories.
+ * Scripts/extract-webkit-localizable-strings: Added.
+
+2007-07-03 Adele Peterson <adele@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Extended DumpRenderTree to test encoding and decoding host names.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]): Added cases for encodeHostName and decodeHostName.
+ (+[LayoutTestController webScriptNameForSelector:]): ditto.
+ (-[LayoutTestController decodeHostName:]): Added.
+ (-[LayoutTestController encodeHostName:]): Added.
+
+2007-07-03 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Eleventh round of fixes for implicit 64-32 bit conversion errors.
+ <rdar://problem/5292262>
+
+ Add functions to test long long and unsigned long long.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController objCLongLongRoundTrip:]):
+ (-[LayoutTestController objCUnsignedLongLongRoundTrip:]):
+
+2007-07-01 Adam Roben <aroben@apple.com>
+
+ Fix some paths to make http tests work again on Windows
+
+ Rubberstamped by Sam.
+
+ * Scripts/run-webkit-tests:
+
+2007-06-28 Stephanie <slewis@apple.com>
+
+ Reviewed by Adam,
+
+ Allow tests to use pre-built roots instead of building the tests.
+
+ * Scripts/run-javascriptcore-tests: added --root option
+ * Scripts/run-webkit-tests: added --root option
+ * Scripts/webkitdirs.pm: added support for using a root
+
+2007-06-25 Adam Roben <aroben@apple.com>
+
+ Fix Bug 14405: LayoutTestResults/qt should be in LayoutTests/qt
+ http://bugs.webkit.org/show_bug.cgi?id=14405
+
+ Reviewed by Anders.
+
+ * Scripts/run-webkit-tests:
+
+2007-06-25 Adam Roben <aroben@apple.com>
+
+ Enable running the regression tests on Windows.
+
+ These changes were developed alongside the Windows WebKit port and
+ have been well tested.
+
+ Rubberstamped by Sam.
+
+ * Scripts/run-webkit-tests:
+
+2007-06-25 Adam Roben <aroben@apple.com>
+
+ Fix Bug 14403: prepare-ChangeLog --git-commit doesn't support --diff
+ http://bugs.webkit.org/show_bug.cgi?id=14403
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/prepare-ChangeLog: Don't spew to stdout, use stderr instead.
+ (sub createPatchCommand): Generate a correct diff in the $gitCommit
+ case.
+
+2007-06-25 Adam Roben <aroben@apple.com>
+
+ Land pdevenv and supporting scripts/programs
+
+ pdevenv is a script that will open an instance of Visual Studio that
+ can compile multiple files in parallel, similar to make -jN. It uses
+ the following scripts/programs to accomplish this:
+
+ CLWrapper: Compiles to vcbin/cl.exe. Calls Scripts/parallelcl.
+
+ parallelcl: Actually performs the parallel compilation by forking
+ multiple instances of the Microsoft-supplied cl.exe.
+
+ MIDLWrapper: Compiles to vcbin/midl.exe. Calls through to the
+ Microsoft-supplied midl.exe. This avoids having to invoke perl for
+ every invocation of midl.exe, which would be quite slow.
+
+ Rubberstamped by Sam.
+
+ * CLWrapper/CLWrapper.cpp: Added.
+ (wmain):
+ * CLWrapper/CLWrapper.sln: Added.
+ * CLWrapper/CLWrapper.vcproj: Added.
+ * MIDLWrapper/MIDLWrapper.cpp: Added.
+ (wmain):
+ * MIDLWrapper/MIDLWrapper.sln: Added.
+ * MIDLWrapper/MIDLWrapper.vcproj: Added.
+ * Scripts/parallelcl: Added.
+ * Scripts/pdevenv: Added.
+ * vcbin/cl.exe: Added.
+ * vcbin/midl.exe: Added.
+
+2007-06-23 Adam Roben <aroben@apple.com>
+
+ Land num-cpus for the Windows build.
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/num-cpus: Added.
+
+2007-06-22 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by Adam Roben.
+
+ Added support for populating ChangeLog entries from given git commits
+ using --git-commit=<commitish> and --git-reviewer=<name>.
+
+ * Scripts/prepare-ChangeLog:
+
+2007-06-22 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Anders.
+
+ <rdar://problem/5228168> Leopard regression test failures: fast/applescript
+
+ There were some changes in Leopard that made our test output inconsistent with Tiger.
+
+ NSAppleEventDescriptor no longer returns a stringValue for typeType descriptors
+ on Leopard, so output our own readable string for typeType descriptors.
+
+ NSArray's description also changed on Leopard to output more whitespace, so
+ make our own string representation for typeAEList descriptors. This requires
+ a special case typeUnicodeText too, so the output is a quoted string.
+
+ * DumpRenderTree/AppleScriptController.m:
+ (convertAEDescToObject):
+
+2007-06-21 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Geoff.
+
+ Don't dump didFirstLayout callbacks, they happen intermittently.
+
+ * DumpRenderTree/FrameLoadDelegate.m:
+
+2007-06-21 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon.
+
+ look for the Qt library in the installed location
+
+ * Scripts/webkitdirs.pm:
+
+2007-06-20 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Adele Peterson, Oliver Hunt, Anders Carlsson.
+
+ Added tests for stringByEvaluatingJavaScriptFromString.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (testStringByEvaluatingJavaScriptFromString):
+ (dumpRenderTree):
+
+2007-06-19 Andrew Wellington <proton@wiretapped.net>
+
+ Reviewed by Mark Rowe.
+
+ Support applications with spaces or special characters in their names
+
+ * Scripts/run-webkit-app:
+
+2007-06-18 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by John Sullivan.
+
+ Assert that the frame has a dataSource.
+
+ * DumpRenderTree/FrameLoadDelegate.m:
+ (-[FrameLoadDelegate webView:didFinishLoadForFrame:]):
+
+2007-06-18 Adam Treat <adam@staikos.net>
+
+ Reviewed by George.
+
+ Reflect the library name change.
+
+ * Scripts/webkitdirs.pm:
+
+2007-06-18 Jake Helfert <jake@jakeonthenet.com>
+
+ Reviewed by Adam.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=14154
+ Spinneret doesn't build against the new Win32 port.
+
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (_tWinMain):
+ -Changed IWebViewExt to IWebViewPrivate
+ -Changed Co[Un]initialize to Ole[Un]initialize because WebKit now calls
+ the WIN32 function RegisterDragDrop which requires the Ole* calls.
+ * Spinneret/Spinneret/Spinneret.h:
+ (SpinneretWebHost::didReceiveIcon): Updated method signature.
+ (SpinneretWebHost::willPerformClientRedirectToURL): Updated method signature.
+ (SpinneretWebHost::windowScriptObjectAvailable): Updated method signature.
+
+2007-06-14 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Brady.
+
+ Update set of files to download for cygwin to include
+ diffutils and regenerate the zip file. This should fix
+ an issue on vista where svn-create-patch doesn't work.
+
+ * CygwinDownloader/cygwin-downloader.py:
+ * CygwinDownloader/cygwin-downloader.zip:
+
+2007-06-14 Mark Rowe <mrowe@apple.com>
+
+ Update script to match new nightly.webkit.org infrastructure.
+
+ * BuildSlaveSupport/build-launcher-dmg: Upload to the live web server, not the caching proxy. Let the server know it's a Mac build.
+
+2007-06-12 Adam Roben <aroben@apple.com>
+
+ Land CygwinDownloader.
+
+ Rubberstamped by Hyatt.
+
+ * CygwinDownloader/cygwin-downloader.py: Added.
+ * CygwinDownloader/cygwin-downloader.zip: Added.
+ * CygwinDownloader/make-zip.sh: Added.
+ * CygwinDownloader/setup.py: Added.
+
+2007-06-06 Vladimir Olexa <vladimir.olexa@gmail.com>
+
+ Reviewed by Mark Rowe.
+
+ Fixes Bug 13996: http://bugs.webkit.org/show_bug.cgi?id=13996
+ [Drosera] Items in the file list don't get un-highlighted when
+ files are selected from the file drop-down
+
+ * Drosera/debugger.js: currentFile was getting modified before file in the file
+ browser got un-highlighted. Changed the order in which the functions execute.
+
+2007-06-06 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Maciej.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13988
+ Bug 13988: Colon in file path crashes WebKit Nightly
+
+ The WebKit launcher makes use of two `dyld' variables to coerce Safari into running with
+ the bundled WebKit framework. Both of these variables are interpreted as containing a
+ colon-delimited list of paths. There is no escaping mechanism defined, so if we detect
+ a path with a colon in it we need to bail out to prevent `dyld' from throwing an error
+ when we execute Safari.
+
+ * WebKitLauncher/main.m:
+ (main):
+
+2007-06-05 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Anders.
+
+ * WebKitLauncher/Info.plist: Update CFBundleGetInfoString, and add CFBundleShortVersionString.
+
+2007-05-30 Alp Toker <alp.toker@collabora.co.uk>
+
+ Reviewed by Brady.
+
+ Enable logging in the Gdk port.
+ http://bugs.webkit.org/show_bug.cgi?id=13936
+
+ * GdkLauncher/main.cpp:
+ (main):
+
+2007-05-29 Holger Freyther <zecke@selfish.org>
+
+ Reviewed by Anders.
+
+ Create a GtkLayout and pass it to the FrameView/ScrollView. Embed the GtkLayout into a GtkScrolledWindow
+ to provide ScrollBars for the FrameView.
+
+ * GdkLauncher/main.cpp:
+ (registerRenderingAreaEvents):
+ (layout_realize_callback): Only after realization we can access the GtkLayout::bin_window
+ (frameResizeCallback): Inform the ScrollView about its new viewport size, and ask the FrameView to adjust
+ (main):
+
+2007-05-29 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=13901
+ run-pageloadtest does not obey testName on command-line
+
+ * Scripts/run-pageloadtest: Grab $testName from the command-line if it is present,
+ otherwise default to "svg". Added dummy check to make sure $testName.pltsuite
+ exists.
+
+2007-05-29 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=13900
+ svnStatus($) subroutine in svn-[un]apply does not work properly with directories
+
+ This patch also fixes an instance of the "broken pipe" warning that happened when
+ a directory contained modified files that were not part of an applied or unapplied
+ patch.
+
+ * Scripts/svn-apply:
+ (svnStatus($)): If we're trying to get status on a directory (instead of a file),
+ make sure we actually get the directory's status (if it has one), not the first
+ file's status reported within the directory. Fix "broken pipe" warnings by
+ reading all of the output from the SVN filehandle before closing it.
+ * Scripts/svn-unapply:
+ (svnStatus($)): Ditto.
+
+2007-05-28 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=10342
+ prepare-ChangeLog only shows removed files but not added files when files are moved
+ - fix prepare-ChangeLog part of http://bugs.webkit.org/show_bug.cgi?id=13408
+ prepare-ChangeLog and svn-create-patch don't show replaced files
+
+ Switched method used to find list of changed files from "diff" to "status". This
+ makes added and replaced files with history appear in the changed file list for svn.
+ Added check for "+" in output from the svn status command to detect file history, and
+ handle it in the generateFileList(\@\@\%) and in statusDescription($$) subroutines.
+
+ * Scripts/prepare-ChangeLog:
+ (diffCommand(@)): Switched argument from hash ref to array to match statusCommand(@).
+ (statusCommand(@)): Switched argument from array ref to array. Necessary to use
+ the output of "keys $paths" without creating a temporary array variable.
+ (findOriginalFileFromSvn($)): Added. Based on findSourceFileAndRevision($)
+ subroutine in svn-create-patch.
+ (generateFileList(\@\@\%)): Added. Extracted from main body of script. Runs status
+ command using command-line arguments instead of list of changed files from the diff
+ command. Changed svn regex to only accept file statuses that we know how to handle.
+ Identify original file when an added/replaced status with history is present.
+ (statusDescription($$)): Handled added/replaced statuses with history. Added
+ fall-through return statement.
+
+2007-05-28 Holger Freyther <zecke@selfish.org>
+
+ Reviewed by Mark Rowe.
+
+ Add scripts and data to generate a coverage data for WebKit.
+
+ * CodeCoverage/README: Added.
+ * CodeCoverage/amber.png: Added.
+ * CodeCoverage/cov.py: Added.
+ * CodeCoverage/emerald.png: Added.
+ * CodeCoverage/gcov.css: Added.
+ * CodeCoverage/glass.png: Added.
+ * CodeCoverage/regenerate-coverage-display: Added.
+ * CodeCoverage/ruby.png: Added.
+ * CodeCoverage/run-generate-coverage-data: Added.
+ * CodeCoverage/snow.png: Added.
+ * Scripts/build-webkit: Add --coverage by Niko
+ * Scripts/check-for-global-initializers: Skip the check on coverage builds
+ * Scripts/generate-coverage-data: Added.
+ * Scripts/run-javascriptcore-tests: Add --coverage by Niko
+
+2007-05-29 Mark Rowe <mrowe@apple.com>
+
+ Build fix after r21745.
+
+ * Scripts/check-for-global-initializers: Skip CachedPage.o as it now has a global initializer in debug builds.
+
+2007-05-25 Anders Carlsson <andersca@apple.com>
+
+ Fix build.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ * DumpRenderTree/FrameLoadDelegate.m:
+
+2007-05-25 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by Zack.
+
+ For the keyDown binding use QStringList instead of QList<QString>. The former is a default
+ registered metatype. Also print out critical messages in dumprendertree's qt message handler.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.cpp:
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+
+2007-05-20 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=13565
+ Change svn-create-patch to put LayoutTests in the end
+
+ In addition to reordering test files under the LayoutTests directory so that they
+ appear after source code files, this patch fixes an issue with prepare-ChangeLog
+ if the first argument passed to it is a file name instead of a directory name.
+
+ * Scripts/prepare-ChangeLog:
+ (isGIT()): If first value in @dirs array is a file, use dirname() to get the directory.
+ (isSVN()): Ditto.
+ * Scripts/svn-create-patch:
+ (generateFileList($\%\%\%)): Differentiate test files in the LayoutTests directory from
+ source code files.
+
+2007-05-18 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver.
+
+ Force LC_ALL to C when parsing locale-specific strings in 'svn' output.
+
+ * Scripts/svn-create-patch:
+ * Scripts/webkitdirs.pm:
+
+2007-05-18 Holger Freyther <zecke@selfish.org>
+
+ Reviewed by Maciej.
+
+ * GdkLauncher/main.cpp: Call setGtkWidget
+ (main):
+
+2007-05-18 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Mark Rowe.
+
+ * GdkLauncher/main.cpp:
+ (main): Call Frame::init to catch up with Maciej's changes.
+ * Scripts/run-javascriptcore-tests: Remove --gdk from the command line
+ passed to the helper scripts.
+
+2007-05-16 Brady Eidson <beidson@apple.com>
+
+ Build fix for some dev configurations
+
+ * DumpRenderTree/DumpRenderTree.m:
+
+2007-05-16 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Justin.
+
+ - created a new mechanism to log FrameLoadDelegate callbacks in directories named "loading"
+
+ The reason for doing things in this slightly odd way is to make sure we don't miss the load delegates
+ that happen before the load commits.
+
+ Basically I moved WaitUntilDoneDelegate into a separate file (FrameLoadDelegate.m) and added
+ optional logging for every FrameLoadDelegate callback, including SPI callbacks.
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.m:
+ (createWebView):
+ (dumpRenderTree):
+ (dump):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController clearBackForwardList]):
+ (-[LayoutTestController setUseDashboardCompatibilityMode:]):
+ (-[LayoutTestController dumpFrameLoadCallbacks]):
+ (-[LayoutTestController setWindowIsKey:]):
+ (-[LayoutTestController setMainFrameIsFirstResponder:]):
+ (-[LayoutTestController _doLoad:target:]):
+ (-[LayoutTestController _doBackOrForwardNavigation:]):
+ (-[LayoutTestController queueReload]):
+ (-[LayoutTestController queueScript:]):
+ (-[LayoutTestController queueLoad:target:]):
+ (-[LayoutTestController setAcceptsEditing:]):
+ (-[LayoutTestController setTabKeyCyclesThroughElements:]):
+ (shouldLogFrameLoadDelegates):
+ (runTest):
+ (displayWebView):
+ (+[DumpRenderTreeEvent mouseLocation]):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/DumpRenderTreeDraggingInfo.m:
+ (-[DumpRenderTreeDraggingInfo draggingDestinationWindow]):
+ * DumpRenderTree/EventSendingController.m:
+ (-[EventSendingController mouseDown]):
+ (-[EventSendingController mouseUp]):
+ (-[EventSendingController mouseMoveToX:Y:]):
+ (-[EventSendingController contextClick]):
+ * DumpRenderTree/FrameLoadDelegate.h: Added.
+ * DumpRenderTree/FrameLoadDelegate.m: Added.
+ (-[WebFrame _drt_descriptionSuitableForTestResult]):
+ (-[FrameLoadDelegate processWork:]):
+ (-[FrameLoadDelegate webView:locationChangeDone:forDataSource:]):
+ (-[FrameLoadDelegate webView:didStartProvisionalLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didCommitLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didFailProvisionalLoadWithError:forFrame:]):
+ (-[FrameLoadDelegate webView:didFinishLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didFailLoadWithError:forFrame:]):
+ (-[FrameLoadDelegate webView:windowScriptObjectAvailable:]):
+ (-[FrameLoadDelegate webView:didClearWindowObject:forFrame:]):
+ (-[FrameLoadDelegate webView:didReceiveTitle:forFrame:]):
+ (-[FrameLoadDelegate webView:didReceiveServerRedirectForProvisionalLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didReceiveIcon:forFrame:]):
+ (-[FrameLoadDelegate webView:didChangeLocationWithinPageForFrame:]):
+ (-[FrameLoadDelegate webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:]):
+ (-[FrameLoadDelegate webView:didCancelClientRedirectForFrame:]):
+ (-[FrameLoadDelegate webView:willCloseFrame:]):
+ (-[FrameLoadDelegate webView:didFirstLayoutInFrame:]):
+ (-[FrameLoadDelegate webView:didFinishDocumentLoadForFrame:]):
+ (-[FrameLoadDelegate webView:didHandleOnloadEventsForFrame:]):
+ * DumpRenderTree/ResourceLoadDelegate.m:
+ (-[NSURL _drt_descriptionSuitableForTestResult]):
+ * DumpRenderTree/UIDelegate.m:
+ (-[UIDelegate webViewFocus:]):
+
+2007-05-16 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Darin and Geoff.
+
+ - rdar://problem/4981886
+ - Now windows opened by the DOM can be closed by JS.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController windowCount]):
+
+2007-05-15 Adam Roben <aroben@apple.com>
+
+ Reviewed by David Kilzer.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13732
+ prepare-ChangeLog should work with git
+
+ * Scripts/prepare-ChangeLog: Added support for Git.
+
+2007-05-15 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Add the EventSender object to DRT. Currently it implements
+ mouseDown, mouseUp and mouseMoveTo.
+
+ Make run-webkit-tests --strict work somewhat better for form elements.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::initJSObjects):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.cpp:
+ (HackWebFrame::mousePressEvent):
+ (HackWebFrame::mouseReleaseEvent):
+ (EventSender::EventSender):
+ (EventSender::mouseDown):
+ (EventSender::mouseUp):
+ (EventSender::mouseMoveTo):
+ (EventSender::leapForward):
+ (EventSender::keyDown):
+ (EventSender::frameUnderMouse):
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.h:
+ * Scripts/run-webkit-tests:
+
+2007-05-12 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Hyatt.
+
+ Add new api to DRT to allow us to test a file being dragged
+ onto <input type="file">
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController addFileToPasteboardOnDrag]):
+ (runTest):
+ * DumpRenderTree/UIDelegate.m:
+ (-[UIDelegate webView:dragImage:at:offset:event:pasteboard:source:slideBack:forView:]):
+
+2007-05-11 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Maciej.
+
+ Bug 13656: [gdk] Resize the drawing area of the GdkLauncher
+ http://bugs.webkit.org/show_bug.cgi?id=13656
+
+ * GdkLauncher/main.cpp: Handle resizing the drawing area
+ (frameResizeCallback):
+ (main):
+
+2007-05-11 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Updated test now that +[WebScriptObject scriptObjectForJSObject:frame:]
+ is gone.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:didClearWindowObject:forFrame:]):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController testWrapperRoundTripping:]):
+
+2007-05-08 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Oliver.
+
+ - don't clear events whenever an EventSendingController goes away, only do it at predictable times,
+ since destroying a subframe can make one go away
+
+ (Discovered while fixing:
+
+ <rdar://problem/5063277> blank screen after login to Citibank Online (accessing document before frame starts loading cancels load)
+ <rdar://problem/5159541> REGRESSION (r20972): Wall Street Journal pages replaced by advertisements (13465)
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (runTest): explicitly clear saved events after every page load
+ * DumpRenderTree/EventSendingController.h:
+ * DumpRenderTree/EventSendingController.m:
+ (-[EventSendingController dealloc]): don't clear saved events here...
+ (+[EventSendingController clearSavedEvents]): do it here
+ * Scripts/check-for-global-initializers:
+
+2007-05-10 Mark Rowe <mrowe@apple.com>
+
+ Build fix for DumpRenderTree. Enable Objective-C exceptions in Release configuration.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-05-09 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Added support for testing ObjC/JS type bridging.
+
+ Added ASSERT that -JSObject returns nil when the underlying JSObject
+ is no longer GC protected.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (returnThisCallback):
+ (returnThisClass):
+ (-[WaitUntilDoneDelegate webView:didClearWindowObject:forFrame:]):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController accessStoredWebScriptObject]):
+ (-[LayoutTestController testWrapperRoundTripping]):
+ (-[LayoutTestController objCClassNameOf:]):
+ (-[LayoutTestController objCObjectOfClass:]):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-05-10 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Simon
+
+ Move setting of the DPI value a few lines up. Should fix
+ the last two remaining failures in the layout tests.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+ (main):
+
+2007-05-09 Holger Freyther <zecke@selfish.org>
+
+ Reviewed by Mark Rowe.
+
+ * GdkLauncher/main.cpp: Always include config.h.
+
+2007-05-08 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Added support for testing ObjC object identity.
+
+ Added ASSERT to verify that you can round-trip the object passed to you
+ in -didClearWindowObject:forFrame:.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:didClearWindowObject:forFrame:]):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController accessStoredWebScriptObject]):
+ (-[LayoutTestController objCIdentityIsEqual::]):
+
+2007-05-07 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Added tests for new APIs: -[WebFrame windowObject], -[WebFrame globalContext],
+ and - (void)webView:(WebView *)webView didClearWindowObject:(WebScriptObject *)windowObject
+ forFrame:(WebFrame *)frame, in the form of ASSERTs.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (runJavaScriptThread): Fixed quote mismatch that prepare-changelog likes
+ to complain about.
+
+ (-[WaitUntilDoneDelegate webView:windowScriptObjectAvailable:]):
+ (-[WaitUntilDoneDelegate webView:didClearWindowObject:forFrame:]):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-05-08 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack.
+
+ Dump JavaScript console messages as well. Also requires a slight
+ change in run-webkit-tests, so we still correctly differentiate
+ between text only and rendertree tests.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::javaScriptConsoleMessage):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::dump):
+ * Scripts/run-webkit-tests:
+
+2007-05-08 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Specify what the serif, sans-serif and monospace aliases
+ should map to and explicitly select the Gui style of
+ DRT to be plastique.
+
+ Fixes most of the test failures still seen on the build bot.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts.conf:
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+ (main):
+
+2007-05-07 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Fix the default font to 9pt Sans Serif.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+ (main):
+
+2007-05-04 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Revert on line of the last commit. We still want to keep the RPATH
+ support in the pro file.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro:
+
+2007-05-04 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Remove the old bitmap fonts I tried using to get reliable results from
+ DumpRenderTree on X11. Instead we now use the URW Type1 fonts from
+ ghostscript. I've added a mirror to simply check them out at
+ svn://labs.trolltech.com/svn/webkit/testfonts.
+
+ Fixed DumpRenderTree to make sure these fonts are the only ones we use
+ on X11 and added a fonts.conf file to get a well defined fontconfig
+ configuration.
+
+ Made sure run-webkit-tests forwards the WEBKIT_TESTFONTS environment variable
+ I use to find the fonts to DumpRenderTree.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro:
+ * DumpRenderTree/DumpRenderTree.qtproj/fontoverload.cpp: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/COPYING: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/CourierBold.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/CourierBoldOblique.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/CourierMedium.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/CourierMediumOblique.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/HelveticaBold.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/HelveticaBoldOblique.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/HelveticaMedium.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/HelveticaMediumOblique.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/SymbolMedium.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/TimesBold.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/TimesBoldItalic.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/TimesMedium.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/TimesMediumItalic.ttf: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts.conf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+ (main):
+ * Scripts/run-webkit-tests:
+
+2007-05-03 Holger Freyther <freyther@kde.org>
+
+ Reviewed by Zack, landed by Simon.
+ This is bugzilla bug 13499.
+
+ * GdkLauncher/GdkLauncher.pro: Build the GdkLauncher using qmake
+ * GdkLauncher/main.cpp: We don't have a config.h with the qmake build
+ * Scripts/build-webkit: Add --gdk for the Gdk port
+ * Scripts/webkitdirs.pm: Add helper methods for the Gdk port
+
+2007-05-03 Geoffrey Garen <ggaren@apple.com>
+
+ Build fix: Add AllInOneFile.o to the ignore list, since it includes files
+ in the ignore list.
+
+ * Scripts/check-for-global-initializers:
+
+2007-05-02 Holger Freyther <freyther@kde.org>
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/build-webkit: Remove the CMake call.
+ * Scripts/webkitdirs.pm: Remove isQtWithQMake as QMake is now the only
+ buildsystem for the Qt port.
+
+2007-04-27 Kevin McCullough <kmccullough@apple.com>
+
+ - Removed debugging statements and took out the removal of the deletion
+ of the symlink. This is because multiple instances of run-webkit-tests
+ can be running at the same time.
+ * Scripts/run-webkit-tests:
+
+2007-04-27 Adam Roben <aroben@apple.com>
+
+ Reviewed by Maciej.
+
+ Cleaned up prepare-ChangeLog
+
+ * Scripts/prepare-ChangeLog: No code changes, but style now matches
+ the prevalent style of our perl scripts.
+
+2007-04-27 Nazar Kulyk <schamane@myeburg.net>
+
+ Reviewed by Mark Rowe.
+
+ Basic auto-correction of user-entered URLs.
+
+ * GdkLauncher/main.cpp:
+ (autocorrectURL):
+ (goToURLBarText):
+ (main):
+
+2007-04-28 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Anders.
+
+ Rename some methods and variables to match the style guidelines.
+
+ * GdkLauncher/main.cpp:
+ (stringIsEmpty):
+ (stringIsEqual):
+ (goToURLBarText):
+ (goButtonClickedCallback):
+ (urlBarEnterCallback):
+ (frameResizeCallback):
+ (frameDestroyCallback):
+ (menuMainBackCallback):
+ (menuMainForwardCallback):
+ (menuMainQuitCallback):
+ (main):
+
+2007-04-27 Holger Freyther <freyther@kde.org>
+
+ Reviewed by Maciej.
+
+ Remove unmaintained CMake build system.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/CMakeLists.txt: Removed.
+ * Scripts/build-webkit: Remove references to CMake.
+ * Scripts/webkitdirs.pm: Remove references to CMake.
+
+2007-04-26 Alp Toker <alp@atoker.com>
+
+ Reviewed by Mark Rowe.
+
+ * GdkLauncher/main.cpp:
+ (main): Avoid use of deprecated API.
+
+2007-04-26 Kevin McCullough <kmccullough@apple.com>
+
+ - Changed debugging statements for more information.
+
+ * Scripts/run-webkit-tests:
+
+2007-04-26 Kevin McCullough <kmccullough@apple.com>
+
+ - Adding debugging statements to see why these tests fail. These will be removed.
+
+ * Scripts/run-webkit-tests:
+
+2007-04-25 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Mitz.
+
+ Add a setUseDashboardCompatibilityMode method to LayoutTestController which is used to toggle
+ the dashboard compatibility mode.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController setUseDashboardCompatibilityMode:]):
+ (runTest):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-04-24 Timothy Hatcher <timothy@apple.com>
+
+ Setting the valid architectures to 32-bit only, so these projects
+ will ignore requests to build them 64-bit. Once they can be built 64-bit,
+ the valid architectures can be updated.
+
+ * Drosera/Drosera.xcodeproj/project.pbxproj:
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2007-04-23 Adam Roben <aroben@apple.com>
+
+ Reviewed by Mark Rowe and David Kilzer.
+
+ * Scripts/build-webkit: Print the path to the run-safari script when
+ finished building so that users can copy-and-paste the command to
+ execute it.
+
+2007-04-23 Darin Adler <darin@apple.com>
+
+ Reviewed by Hyatt.
+
+ - rename box-sizing to -webkit-box-sizing
+
+ * Drosera/console.css: Here.
+ * Drosera/debugger.css: And here.
+ * Drosera/viewer.css: And here.
+
+2007-04-21 Mitz Pettel <mitz@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=13350
+ Build Ahem into DumpRenderTree
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (activateAhemFont): Added. Activates the copy of Ahem included in the
+ DumpRenderTree binary.
+ (dumpRenderTree): Replaced the check that Ahem is available with a call
+ to activateAhemFont().
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ Added linker options to include Ahem in the data section of the
+ DumpRenderTree binary.
+
+2007-04-20 Adam Roben <aroben@apple.com>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13421
+ Bug 13421: prepare-ChangeLog should use svn-create-patch when spewing diffs
+
+ * Scripts/prepare-ChangeLog: Use svn-create-patch instead of svn diff.
+
+2007-04-18 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Tim
+
+ <rdar://problem/5008925>
+ Expose the NSURLConnection delegate willCacheResponse API to WebResourceLoadDelegate
+
+ * DumpRenderTree/ResourceLoadDelegate.m:
+ (-[ResourceLoadDelegate webView:resource:willCacheResponse:fromDataSource:]):
+ Add the willCacheResponse delegate call
+
+2007-04-18 Adam Roben <aroben@apple.com>
+
+ Reviewed by David Kilzer.
+
+ * Scripts/webkitdirs.pm:
+ (sub setConfiguration): Added an optional argument to set the
+ configuration instead of parsing it from ARGV.
+
+2007-04-17 Adam Roben <aroben@apple.com>
+
+ * Scripts/find-included-framework-headers: Search Obj-C and Obj-C++
+ files as well.
+
+2007-04-17 Adam Roben <aroben@apple.com>
+
+ Added a simple shell script to find all the headers from a specified
+ framework or frameworks that are included by files beneath the working
+ directory.
+
+ * Scripts/find-included-framework-headers: Added.
+
+2007-04-16 Timothy Hatcher <timothy@apple.com>
+
+ * Drosera/debugger.css: hide the borders for iframes
+
+2007-04-13 Adam Roben <aroben@apple.com>
+
+ Rubberstamped by Anders.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c: #include
+ stdio.h so that snprintf is defined.
+
+2007-04-13 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Anders
+
+ Add the ability to dump the back/forward history of all windows open at the end of a test
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dumpBackForwardListForWebView): Dump B/F list for the given WebView
+ (dump): Call dumpBackForwardListForWebView for each WebView open after the test
+
+2007-04-13 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Brady.
+
+ By default, close any windows that have been opened during a test. This can be overridden by
+ calling setCloseRemainingWindowsWhenComplete(false).
+
+ Change the windows set to an array so we can gurantee the enumeration order.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController setCloseRemainingWindowsWhenComplete:]):
+ (runTest):
+ (-[DumpRenderTreeWindow initWithContentRect:styleMask:backing:defer:]):
+ (-[DumpRenderTreeWindow dealloc]):
+
+2007-04-13 Geoffrey Garen <ggaren@apple.com>
+
+ Build fix.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (handleCallback): Explicitly cast the void* returned by malloc.
+
+2007-04-12 Deneb Meketa <dmeketa@adobe.com>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=13029
+ rdar://problem/4994849
+ Bug 13029: Permit NPAPI plug-ins to see HTTP response headers.
+ Changes in WebKitTools are only for the NPAPI test plugin.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c: main test logic.
+ (pluginInvoke): support null window argument for NPStream creation.
+ (pluginAllocate): initialization.
+ (pluginDeallocate): cleanup.
+ (handleCallback): add second JS callback arg: header dump.
+ (notifyStream): added; hook from NPP_NewStream to record headers.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h: declarations.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c: call new header hook.
+ (NPP_NewStream): call new header hook.
+
+2007-04-09 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Fixed fast/forms/textarea-paste-newline.html.
+
+ This failure was pretty funny. run-webkit-tests kills and respawns
+ DumpRenderTree once every 1000 runs. Adding a few tests caused
+ textarea-paste-newline.html to run right at the beginning of DumpRenderTree's
+ lifetime, before any render tree dumps had occurred. However, WebCore
+ used a render tree dump as the hook that set a global flag to allow
+ pasting through the DOM API, so running before any render tree dumps had
+ occurred caused this test to fail.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dumpRenderTree): Explicitly tell WebKit to allow pasting through the DOM
+ API, instead of hoping it will read the tea leaves.
+
+2007-04-07 Mark Rowe <mrowe@apple.com>
+
+ Not reviewed. Update to match some configuration changes that have been active on build.webkit.org.
+
+ * BuildSlaveSupport/build.webkit.org-config/webkit/status.py:
+
+2007-04-05 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam.
+
+ Add support for opening new windows in DumpRenderTree.
+
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController setCallCloseOnWebViews:]):
+ (-[LayoutTestController setCanOpenWindows]):
+ Add two new methods callable from JavaScript. setCanOpenWindows controls whether a test
+ can open new windows, and setCallCloseOnWebViews controls whether -[WebView close] should be called on
+ web views that are about to be closed.
+
+ (runTest):
+ Make sure that only the main window is around when a test has finished running.
+
+ (-[DumpRenderTreeWindow initWithContentRect:styleMask:backing:defer:]):
+ (-[DumpRenderTreeWindow dealloc]):
+ Manage the set of windows.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c:
+ (NPP_Destroy):
+ Add a "logDestroy" property which controls whether plugins should print when they are destroyed or not.
+
+ * DumpRenderTree/UIDelegate.m:
+ (-[UIDelegate webView:createWebViewWithRequest:]):
+ Create new windows.
+
+ (-[UIDelegate webViewClose:]):
+ Close windows.
+
+2007-04-05 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Maciej.
+
+ Move WebView and NSWindow creation to a separate function in preparation of supporting opening new
+ windows in DRT.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (createWebView):
+ (dumpRenderTree):
+
+2007-04-03 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Add the notion of a "disallowed URL", which the resource loader won't allow to be loaded.
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.m:
+ (dumpRenderTree):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController addDisallowedURL:]):
+ (runTest):
+ * DumpRenderTree/ResourceLoadDelegate.m:
+ (-[ResourceLoadDelegate webView:resource:willSendRequest:redirectResponse:fromDataSource:]):
+
+2007-04-03 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Antti.
+
+ * BuildSlaveSupport/build-launcher-dmg: Use bzip2 compression in nightly build disk images rather than gzip.
+
+2007-04-02 Anders Carlsson <andersca@apple.com>
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ Don't use #import in a header included by C files.
+
+2007-03-31 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Mitz.
+
+ Fix http://bugs.webkit.org/show_bug.cgi?id=13239
+ Bug 13239: REGRESSION (r20343): Drosera hits exception trying to call "count" cross-process
+
+ Use -[WebScriptObject valueForKey:@"length"] to retrieve the length of a JavaScript array
+ rather than -[WebScriptObject count].
+
+ * Drosera/DebuggerDocument.m:
+ (-[DebuggerDocument webScriptAttributeKeysForScriptObject:]):
+
+2007-03-30 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Geoff.
+
+ Add an "onstreamload" attribute to the plugin which is called when a stream starts loading.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c:
+ (NPP_New):
+ Look for the onstreamload attribute.
+
+ (NPP_Destroy):
+ Free the onstreamload attribute.
+
+ (NPP_NewStream):
+ Call the onstreamload handler.
+
+2007-03-30 Geoffrey Garen <ggaren@apple.com>
+
+ Removing an assertion I just added because it's crashing the Leopard
+ buildbot. The related layout test will still report a failure, so we
+ don't really need this assertion.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (pluginInvoke):
+
+2007-03-30 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Geoff.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.c:
+ (testAllocate):
+ (testEnumerate):
+ Add casts.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.h:
+ Don't use #import, use #include.
+
+2007-03-30 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Alexey.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (pluginInvoke):
+ Free the identifier string.
+
+2007-03-30 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Geoff.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ Add TestObject.c and TestObject.h
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (pluginGetProperty):
+ Implement the testObject property.
+
+ (pluginInvoke):
+ Implement testEnumerate which takes an object and an array and enumerates
+ the properties of the object and adds them to the array.
+
+ (pluginAllocate):
+ Allocate the test object.
+
+ (pluginDeallocate):
+ Free the test object.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.c: Added.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.h: Added.
+ Add a test object with two enumerable properties.
+
+2007-03-29 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Layout test for <rdar://problem/5091330> REGRESSION: Repro crash in
+ -[WebBaseNetscapePluginView(WebNPPCallbacks) destroyStream:reason:]
+ navigating away from page with DivX movie plug-in (13203)
+
+ Added hasStream property and destroyStream function, used by layout test.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (pluginGetProperty):
+ (pluginInvoke):
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c:
+ (NPP_NewStream):
+
+2007-03-27 Anders Carlsson <acarlsson@apple.com>
+
+ Reviewed by Geoff.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (pluginInvoke):
+ Add new function which takes a function and calls it using NPN_InvokeDefault.
+
+2007-03-27 Adele Peterson <adele@apple.com>
+
+ Adding comment.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:didFinishLoadForFrame:]):
+
+2007-03-27 Adele Peterson <adele@apple.com>
+
+ Fix svg tests by calling displayIfNeeded.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:didFinishLoadForFrame:]):
+
+2007-03-26 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Upload crash logs from DumpRenderTree as part of the test results to ease debugging
+ of hard-to-reproduce crashes.
+
+ * BuildSlaveSupport/build.webkit.org-config/webkit/steps.py:
+
+2007-03-23 Adam Treat <adam@staikos.net>
+
+ Reviewed and committed by George.
+
+ Patch by Adam Treat. Removes hardcoded path to .pro file.
+
+2007-03-22 Adam Roben <aroben@apple.com>
+
+ Reviewed by Geoff.
+
+ Removed eventSender.mouseClick because it was only useful for AppKit
+ controls, which we don't use anymore.
+
+ * DumpRenderTree/EventSendingController.m:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]): Removed
+ mouseClick.
+
+2007-03-22 Adam Roben <aroben@apple.com>
+
+ Reviewed by Ada.
+
+ Make eventSender.mouseClick actually send a mouse up event.
+
+ * DumpRenderTree/EventSendingController.m:
+ (-[EventSendingController mouseClick]):
+
+2007-03-19 David Hyatt <hyatt@apple.com>
+
+ Update the minimum font size pref to match the actual default setting in Safari. It should have been 1
+ all this time and not 9.
+
+ Reviewed by aroben
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dumpRenderTree):
+
+2007-03-18 Dan Waylonis <waylonis@mac.com>
+
+ Reviewed by Tim Hatcher.
+
+ DumpRenderTree changes for http://bugs.webkit.org/show_bug.cgi?id=13005
+ Bug 13005: WebScriptObject +throwException needs NULL check.
+
+ Add tests to ensure that a plugin can safely throw an exception in dealloc.
+
+ * DumpRenderTree/ObjCPlugin.h:
+ * DumpRenderTree/ObjCPlugin.m:
+ (+[ObjCPlugin webScriptNameForKey:]):
+ (+[ObjCPlugin isKeyExcludedFromWebScript:]):
+ (-[ObjCPlugin dealloc]):
+
+2007-03-13 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Maciej.
+
+ Have the nightly launcher prefer Safari found in /Applications or ~/Applications
+ if present, otherwise fall back on using LaunchServices to locate it elsewhere
+ on the system. The motivation for this is to make the behaviour of the nightly
+ builds more predictable on machines with multiple copies of Safari present.
+
+ * WebKitLauncher/main.m:
+ (locateSafariBundle):
+ (main):
+
+2007-03-12 Darin Adler <darin@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ - add a DumpRenderTree feature where you can get the Objective-C
+ class name of a JavaScript object
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]): Add the
+ objCClassNameOf: selector.
+ (+[LayoutTestController webScriptNameForSelector:]): Add the
+ objCClassNameOf: selector, with the name "objCClassName".
+ (-[LayoutTestController objCClassNameOf:]): Added.
+
+2007-03-11 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Beefed up --threaded mode in light of <rdar://problem/4681051> Installer
+ crashes in KJS::Collector::markOtherThreadConservatively(KJS::Collector::Thread*)
+ trying to install iLife 06 using Rosetta on an Intel Machine
+
+ --threaded mode now runs a bunch of different JavaScript threads, randomly
+ killing and respawning them. This was sufficient for reproducing the
+ bug on my MacBook Pro.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (javaScriptThreads):
+ (runJavaScriptThread):
+ (startJavaScriptThreads):
+ (stopJavaScriptThreads):
+ (dumpRenderTree):
+
+2007-03-11 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+
+ Reviewed by Brady Eidson.
+
+ Add forward/backward/quit menus for easier testing.
+
+ * GdkLauncher/main.cpp:
+ (menuMainBackCb):
+ (menuMainForwardCb):
+ (menuMainQuitCb):
+ (main):
+
+2007-03-09 Andrew Wellington <proton@wiretapped.net>
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=13007
+ svn-create-patch doesn't handle UTF files with BOMs as text
+
+ Force diff to treat files that svn-create-patch thinks are text as text.
+
+ * Scripts/svn-create-patch: Added -a switch to diff command.
+
+2007-03-09 Mark Rowe <mrowe@apple.com>
+
+ Unreviewed. Use the new SVN URL on the buildbot.
+
+ * BuildSlaveSupport/build.webkit.org-config/webkit/steps.py:
+
+2007-03-08 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Antti.
+
+ Fix compiler warnings when building Drosera as 64-bit.
+
+ * Drosera/DebuggerDocument.m:
+ (-[DebuggerDocument breakpointEditorHTML]): Move away from deprecated NSString method.
+ (-[DebuggerDocument scriptConfirmSheetDidEnd:returnCode:contextInfo:]): Update type.
+ (-[DebuggerDocument webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:]): Update type to accommodate constant.
+
+2007-03-07 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Maciej.
+
+ Update check-for-global-initializers to ignore new debug initializers in bidi.o and kjs_events.o.
+
+ * Scripts/check-for-global-initializers:
+
+2007-03-07 Anders Carlsson <acarlsson@apple.com>
+
+ Reviewed by Adam.
+
+ Add some assertions.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:didStartProvisionalLoadForFrame:]):
+ (-[WaitUntilDoneDelegate webView:didCommitLoadForFrame:]):
+ (-[WaitUntilDoneDelegate webView:didFailProvisionalLoadWithError:forFrame:]):
+ (-[WaitUntilDoneDelegate webView:didFailLoadWithError:forFrame:]):
+
+2007-03-07 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ - WebKitTools part of fix for http://bugs.webkit.org/show_bug.cgi?id=12463
+ WebArchiver - attempt to insert nil exception when archive empty iframe
+
+ The dumpDOMAsWebArchive() test method uses the DOMDocument as a basis for creating
+ a webarchive while the dumpSourceAsWebArchive() test method uses the original
+ dataSource (page source) to create a webarchive. Most tests currently use
+ dumpDOMAsWebArchive() since this is what Safari does when saving a web page as a
+ webarchive.
+
+ * DumpRenderTree/DumpRenderTree.m: Renamed dumpAsWebArchive to dumpDOMAsWebArchive.
+ Added dumpSourceAsWebArchive.
+ (dump):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController dumpDOMAsWebArchive]):
+ (-[LayoutTestController dumpSourceAsWebArchive]):
+ (runTest):
+
+2007-03-05 Kevin McCullough <kmccullough@apple.com>
+
+ Reviewed by Mark and Dave H.
+
+ - rdar://problem/4922454
+ - This fixes a security issue by making remote referrers not able to access local
+ resources, unless they register their schemes to be treated as local. The result is
+ that those schemes can access local resources and cannot be accessed by remote
+ referrers.
+ Because this behavior is new a link-on-or-after check is made to determine if the
+ app should use the older, less safe, behavior.
+
+ * DumpRenderTree/DumpRenderTree.m: Add ability to set user style sheet to DRT.
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController setUserStyleSheetLocation:]):
+ (-[LayoutTestController setUserStyleSheetEnabled:]):
+
+2007-03-05 Anders Carlsson <acarlsson@apple.com>
+
+ Reviewed by Adam, Darin.
+
+ <rdar://problem/5025212>
+ In Mail, a crash occurs at WebCore::Frame::tree() when clicking on embedded flash object
+
+ Add a "getURLNotify" method to the plugin object. This lets you pass a URL, a target and a callback function
+ to be run when the URL has finished (or failed) loading.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (pluginInvoke):
+ (handleCallback):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c:
+ (NPP_URLNotify):
+
+2007-03-04 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+
+ Reviewed by Nikolas Zimmermann.
+
+ Load a url given on a command line in a way that also
+ works for local (file://) urls.
+
+ * GdkLauncher/main.cpp:
+ (main):
+
+2007-03-02 Geoffrey Garen <ggaren@apple.com>
+
+ Tweaked parse-malloc-history to work with new malloc_history output format.
+
+ * Scripts/parse-malloc-history:
+
+2007-02-28 Vladimir Olexa <vladimir.olexa@gmail.com>
+
+ Reviewed by Tim H.
+
+ Fixes: http://bugs.webkit.org/show_bug.cgi?id=12887
+ Bug#12887: [Drosera] Add ability to close loaded files
+
+ * Drosera/DebuggerDocument.h:
+ * Drosera/DebuggerDocument.m:
+ (-[DebuggerDocument closeCurrentFile:]): Adds delegation to call a JS script to close files
+ * Drosera/Drosera.xcodeproj/project.pbxproj:
+ * Drosera/English.lproj/MainMenu.nib/classes.nib:
+ * Drosera/English.lproj/MainMenu.nib/info.nib:
+ * Drosera/English.lproj/MainMenu.nib/keyedobjects.nib: Adds Close Current File menu item
+ * Drosera/debugger.html: Changed "no files loaded" to "<No files loaded>" to match Xcode style
+ * Drosera/debugger.js: Adds implementation of closeFile() to unload currently loaded file
+
+2007-02-28 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Maciej.
+
+ Add new flags to build-webkit to be able to switch on/off xpath, xslt, etc. easily.
+
+ * Scripts/build-webkit:
+
+2007-02-27 Geoffrey Garen <ggaren@apple.com>
+
+ Small tweak to run-webkit-tests.
+
+ * Scripts/run-webkit-tests: Allow people with lots of RAM to run more than
+ 1000 MallocStackLogging tests at a time.
+
+2007-02-26 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Lars.
+
+ - set ENABLE_XSLT even when compiling without SVG support, since that is no
+ longer hardcoded into config.h.
+
+ * Scripts/build-webkit:
+
+2007-02-26 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+
+ Reviewed by Adam Roben.
+
+ Rename *_SUPPORT defines to ENABLE_*.
+
+ * GdkLauncher/gdklauncher.bkl:
+
+2007-02-24 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/run-webkit-tests: Stop ignoring BidiRun leaks, now that they're
+ fixed.
+
+2007-02-24 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+
+ Reviewed by Adam Roben.
+
+ Improve gdklauncher: add text field for entering url.
+
+ * GdkLauncher/gdklauncher.bkl:
+ * GdkLauncher/main.cpp:
+ (strEmpty):
+ (strEq):
+ (handleGdkEvent):
+ (goToUrlBarText):
+ (goButtonClickedCb):
+ (urlBarEnterCb):
+ (registerRenderingAreaEvents):
+ (frameResizeCb):
+ (frameDestroyCb):
+ (main):
+
+2007-02-22 Vladimir Olexa <vladimir.olexa@gmail.com>
+
+ Reviewed by Tim H.
+
+ Fixes: http://bugs.webkit.org/show_bug.cgi?id=12852
+ Bug#12852: Drosera should select function name, not "function" keyword when selecting from function list pop-up
+ * Drosera/debugger.js: Fixed some logic errors resulting in generating double IDs and names.
+
+2007-02-22 Adele Peterson <adele@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Added option in layoutTestController to setTabKeyCyclesThroughElements, so we
+ can test <rdar://problem/5014970> 9A374: Tabs don't work in the message body
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController setTabKeyCyclesThroughElements:]):
+
+2007-02-22 Geoffrey Garen <ggaren@apple.com>
+
+ Used svn merge -r19786:19785 to roll out previous hack to work around
+ SVG painting issue in DRT.
+
+ Implemented new work-around, which makes --paint paint *after* dumping
+ the render tree instead of before, so that painting doesn't influence
+ the SVG render tree.
+
+ This should fix the ~400 new pixel failures introduced in r19786.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dump):
+ * Scripts/run-webkit-tests:
+
+2007-02-22 Geoffrey Garen <ggaren@apple.com>
+
+ Resetting --leaks mode default to run 1000 tests at a time because setting it
+ to 750 didn't stop the stack logging related crashes, and running more tests
+ at a time is faster. The crashes seem to be a real bug in stack logging,
+ not an out of memory condition.
+
+ * Scripts/run-webkit-tests:
+
+2007-02-21 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Added hack to force painting when running an SVG test. This is a work-around
+ for http://bugs.webkit.org/show_bug.cgi?id=12849 SVG renderers update at
+ paint time instead of style resolution time.
+
+ We need this so that --leaks mode, which always paints, doesn't appear to
+ fail SVG tests. We also need this if we ever want to test style application
+ in SVG, since many SVGs don't apply style to their renderers until they paint.
+
+ * Scripts/run-webkit-tests:
+
+2007-02-21 Geoffrey Garen <ggaren@apple.com>
+
+ Reduced --leaks mode to running only 750 tests at a time, in the hopes
+ of fixing intermittent crasher that may be caused by out of memory
+ conditions.
+
+ * Scripts/run-webkit-tests:
+
+2007-02-21 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Made DRT paint when running run-webkit-tests in --leaks mode, to check
+ for painting leaks.
+
+ * DumpRenderTree/DumpRenderTree.m: Removed some "NO" initializations, since
+ that's the default for statics.
+ (dumpRenderTree): Added --paint command line option, which specifies that
+ DRT should paint at the end of every test.
+ (displayWebView): New function, called by dump() and -[LayoutTestController display].
+ * Scripts/run-webkit-tests: Use the --paint command line option when checking
+ for leaks.
+
+ * Scripts/run-webkit-tests: Added a new, painting leak to the ignore list.
+ Removed stale comment about THRD leaks -- we now ignore them reliably.
+
+2007-02-21 Geoffrey Garen <ggaren@apple.com>
+
+ Tools tweak. No review necessary.
+
+ * Scripts/parse-malloc-history: Enabled multiple merge-regexp command line
+ arguments. Changed command line argument variables from special implicit
+ no-op values to specific empty values that we test explicitly.
+
+2007-02-21 Vladimir Olexa <vladimir.olexa@gmail.com>
+
+ Reviewed by Tim H.
+
+ Bug 12834: Drosera should remember scroll position of open files like Xcode
+ http://bugs.webkit.org/show_bug.cgi?id=12834
+
+ * Drosera/debugger.js: Implemented scrolling memory
+
+2007-02-20 Geoffrey Garen <ggaren@apple.com>
+
+ Tools tweak. No review necessary.
+
+ Made parse-malloc-history executable. (Oops!)
+
+ Made parse-malloc-history parse 'leaks' output in addition to 'malloc_history"
+ output.
+
+ Added the ability to merge callstacks by regexp, not just depth, so you
+ can ask questions like, "How many of these allocations were due to that one
+ call to ...?"
+
+ * Scripts/parse-malloc-history:
+
+2007-02-20 Geoffrey Garen <ggaren@apple.com>
+
+ * Scripts/parse-malloc-history: Added copyright info.
+
+2007-02-20 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Darin Adler.
+
+ New script to parse the output from malloc_history, so we can determine
+ what's using memory in WebKit.
+
+ * Scripts/parse-malloc-history: Added.
+
+2007-02-20 Graham Dennis <graham.dennis@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ Fix for http://bugs.webkit.org/show_bug.cgi?id=12802
+ WebKit.framework is built with SVG_SUPPORT for No-SVG build
+
+ * Scripts/build-webkit: Pass the "FEATURE_DEFINES=" option when building WebKit as well.
+
+2007-02-19 Geoffrey Garen <ggaren@apple.com>
+
+ Build fix.
+
+ * Scripts/check-for-global-initializers: Ignore the global counter I added
+ for SubresourceLoaders.
+
+2007-02-19 Darin Adler <darin@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ * Scripts/check-for-global-initializers: Delete the linked executable if the check fails.
+ Without this, you only see the global initializer error once, which makes it very easy
+ to miss them.
+
+2007-02-16 Mark Rowe <mrowe@apple.com>
+
+ Not reviewed.
+
+ <rdar://problem/4982312> leaks bot should run in normal mode, rather than quiet mode
+
+ * BuildSlaveSupport/build.webkit.org-config/webkit/steps.py: Switch back to default verbosity for output of leaks tests.
+
+2007-02-15 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ * DumpRenderTree/DumpRenderTree.m: Don't ignore NSAttributedString WebCore::Node
+ leaks anymore, either, since r19486 fixed them, too.
+ (shouldIgnoreWebCoreNodeLeaks):
+
+2007-02-15 Darin Adler <darin@apple.com>
+
+ * Scripts/run-webkit-tests: Don't ignore NSAttributedString leaks any more. Those were
+ fixed by change 19486.
+
+2007-02-15 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Ignore another leak, seen recently on the buildbot.
+
+ * Scripts/run-webkit-tests:
+
+2007-02-14 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Ignore another leak, seen recently on the buildbot.
+
+ * Scripts/run-webkit-tests:
+
+2007-02-13 Darin Adler <darin@apple.com>
+
+ * Scripts/run-webkit-tests: Fix a bug where --reset-results output would all go in one
+ giant line.
+
+2007-02-11 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Mitz.
+
+ - add contextClick() operation to eventSender to be able to test this
+
+ * DumpRenderTree/EventSendingController.m:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (-[EventSendingController contextClick]):
+
+2007-02-11 Darin Adler <darin@apple.com>
+
+ * Scripts/check-for-global-initializers: Fix case where executable doesn't exist at all
+ so it doesn't give a perl exception (happens in clean builds, for example).
+
+2007-02-10 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Adam.
+
+ * Scripts/svn-create-patch:
+ (findSourceFileAndRevision($)): Use File::Spec->abs2rel() instead of substr() to generate
+ a relative path to the copied file.
+
+2007-02-10 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ * Drosera/Drosera.icns: updated the icon with 512px and 256px variants
+
+2007-02-10 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Timothy.
+
+ * Scripts/svn-apply:
+ (handleBinaryChange($$)): Binary patches don't need a trailing newline after the base64
+ encoded text.
+
+2007-02-10 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Maciej
+
+ <rdar://problem/4965133> WebKit sends file:// url referrers
+
+ * Scripts/run-webkit-tests: Enhanced the http tests so that we can run layout tests
+ on local files, but have an httpd for remote resources
+
+2007-02-08 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Ignore another false leak report.
+
+ * Scripts/run-webkit-tests:
+
+2007-02-08 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Kevin McCullough.
+
+ * Scripts/run-webkit-tests: Don't try to create /tmp/LayoutTests if it
+ already exists, to avoid confusing error message.
+
+ Also, remove /tmp/LayoutTests after running so unsupecting fools don't
+ try to rm -rf it, only later to discover that they have completely hosed
+ their machines.
+
+2007-02-08 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+
+ Reviewed by Adam Roben.
+
+ Linux/gdk build fixes.
+
+ * GdkLauncher/main.cpp: Add -exit-after-loading and
+ -dump-render-tree as debugging aid.
+ (strEq):
+ (main):
+
+2007-02-08 Geoffrey Garen <ggaren@apple.com>
+
+ Minor fixup based on Maciej's review last night.
+
+ * Scripts/run-webkit-tests: Use normal "increment at end of loop" behavior,
+ and do a little math to make it work.
+
+2007-02-08 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+
+ Reviewed by Adam Roben.
+
+ Linux/gdk build fixes.
+
+ * GdkLauncher/gdklauncher.bkl:
+
+2007-02-08 Kevin McCullough <KMcCullough@apple.com>
+
+ - Fix layout test failures.
+
+ * Scripts/run-webkit-tests:
+
+2007-02-08 Darin Adler <darin@apple.com>
+
+ Reviewed by Anders.
+
+ * Scripts/check-for-global-initializers: For speed, only check files that
+ have been modified since the last time we linked. For tidiness, capture
+ stderr from nm, and prevent "nm: no name list" messages from going out.
+
+2007-02-08 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej Stachowiak, Adam Roben.
+
+ Added 'nthly' support to run-webkit-tests. It's like 'singly', for an
+ arbitrary number n.
+
+ Plus some renames:
+ - DumpRenderTree => "dumpTool" (to match abstraction elsewhere)
+ - checkLeaks => "shouldCheckLeaks" (to match style guidelines)
+ - tool => dumpTool (to match abstraction elsewhere)
+ - httpdOpen => isHttpdOpen (to match style guidelines)
+
+ Plus a few logic fixups:
+ - Don't check isDumpToolOpen when we know we've called openDumpTool().
+ - Use a single code path to decide when to shut down dumpTool and
+ when to check for leaks, since the operations are coincidental.
+ - Use a single code path for running the leaks tool, since the only
+ thing that varies between configurations is the output file name.
+ - Increment $count after each test finishes, instead of at the end
+ of the loop, to help with comparing to the length of the array
+ and %-ing by n.
+ - Use a more robust test inside the loop to determine if we need to
+ close dumpTool, instead of copying the closing code outside the loop.
+
+ Layout tests pass.
+
+ * Scripts/run-webkit-tests:
+
+2007-02-06 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Beth Dakin, evil twin to Bethany P. Dakin.
+
+ Ignore known leaks in CFRunLoop. Exclude THRD leaks by type so that we can
+ catch all reports of them, not just those inside pthread_create.
+
+ Also, use "\\" instead of "\" because we need the actual \ to get into the
+ regexp string if it's going to do any escaping. (Oops!)
+
+ * Scripts/run-webkit-tests:
+
+2007-02-06 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Bethany P. Dakin.
+
+ The 's' is optional when the leaks tool reports 'leaks'.
+
+ * Scripts/run-leaks:
+
+2007-02-06 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Bethany P. Dakin.
+
+ Hooked up run-webkit-tests to the run-leaks script. No change in behavior yet.
+
+ * Scripts/run-webkit-tests: Changed symbol names to valid regular expressions.
+
+2007-02-06 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ Patch for http://bugs.webkit.org/show_bug.cgi?id=12566
+ [Drosera] Console history fixups
+
+ * Drosera/console.js: assorted cleanups and fixes
+
+2007-02-05 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Darin Adler.
+
+ New script that allows you to ignore leaks by regular expression.
+
+ * Scripts/run-leaks: Added.
+
+2007-02-03 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark.
+
+ Patch for http://bugs.webkit.org/show_bug.cgi?id=12555
+ Drosera doesn't handle CR ( carriage returns ) well
+
+ - Normalize all the line endings.
+
+ * Drosera/debugger.js:
+
+2007-02-02 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Added some more known leaks to the leaks ignore list.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Why does XCode
+ hate itself so much?
+ * Scripts/run-webkit-tests:
+
+2007-02-02 Geoffrey Garen <ggaren@apple.com>
+
+ Even better build fix than the last.
+
+ * ChangeLog:
+ * DumpRenderTree/DumpRenderTree.m:
+ (shouldIgnoreWebCoreNodeLeaks):
+
+2007-02-02 Geoffrey Garen <ggaren@apple.com>
+
+ Fixed build. Added work-around for GCC bug.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (shouldIgnoreWebCoreNodeLeaks):
+
+2007-02-01 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Added support for selectively ignoring WebCore::Node leaks during layout
+ tests, so that we can ignore known leaks in other components.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (shouldIgnoreWebCoreNodeLeaks): Implements a black list of tests whose
+ WebCore::Node leaks we have to ignore. Does this CFString gobbledy-gook
+ confuse anyone else?
+ (runTest):
+
+2007-02-01 Anders Carlsson <acarlsson@apple.com>
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/UIDelegate.m:
+ (-[UIDelegate webView:addMessageToConsole:]):
+ Dump console messages.
+
+2007-01-31 Anders Carlsson <acarlsson@apple.com>
+
+ * DumpRenderTree/ResourceLoadDelegate.m:
+ (-[ResourceLoadDelegate webView:identifierForInitialRequest:fromDataSource:]):
+ Use an NSString here so we can guarantee that -description always returns the same value.
+
+2007-01-31 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Added Selection::toRange to the leaks -exclude list, since it comes up
+ as a false positive (Radar 4967949).
+
+ Also added RangeCounter to the global initializer exclude list. I added
+ a RangeCounter since leaks won't detect all Range leaks anymore.
+
+ * Scripts/check-for-global-initializers:
+ * Scripts/run-webkit-tests:
+
+2007-01-31 Anders Carlsson <acarlsson@apple.com>
+
+ * DumpRenderTree/ResourceLoadDelegate.m:
+ (-[ResourceLoadDelegate webView:identifierForInitialRequest:fromDataSource:]):
+ Don't try to create an identifier if resource loads shouldn't be dumped.
+
+2007-01-31 Anders Carlsson <acarlsson@apple.com>
+
+ Reviewed by Geoff.
+
+ Add dumping of resource loads. This isn't completely tweaked yet since the test results would
+ rely on resources being delivered in the same order which might not always be true. However, it works good
+ enough for the simple webarchive tests I want to do right now.
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.m:
+ (dumpRenderTree):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController dumpResourceLoadCallbacks]):
+ (runTest):
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/ResourceLoadDelegate.h: Added.
+ * DumpRenderTree/ResourceLoadDelegate.m: Added.
+ Add new resource load delegate.
+
+2007-01-31 Geoffrey Garen <ggaren@apple.com>
+
+ Backing out the CFRunLoopRunSpecific exclude command because it was overly
+ broad. We'll either need to work around this leak in DRT, or do some
+ custom grep-based leak ignoring.
+
+ * Scripts/run-webkit-tests:
+
+2007-01-30 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Filed some more Radars in other components, added some more leaks to the
+ exclusion list.
+
+ * Scripts/run-webkit-tests: Ignore leaks in CFNotificationCenterAddObserver,
+ CFRunLoopRunSpecific, and NSSpellChecker.
+
+2007-01-30 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=11882
+ Need a way to regression test .webarchive output files
+
+ Implement layoutTestController.dumpAsWebArchive() to test WebArchive format.
+ Alters WebResourceResponse and WebResourceURL properties within WebArchive format
+ to normalize URLs to remove path where WebKit was checked out. Also converts
+ WebDataResource properties from data to string if the corresponding
+ WebResourceMIMEType property starts with "text/" or equals
+ "application/x-javascript".
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (convertWebResourceDataToString): Added.
+ (normalizeWebResourceURL): Added.
+ (normalizeWebResourceResponse): Added.
+ (serializeWebArchiveToXML): Added.
+ (dump):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController dumpAsWebArchive]): Added.
+ (runTest):
+
+2007-01-30 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ http://bugs.webkit.org/show_bug.cgi?id=12470
+ svn-create-patch creates duplicate patches for files within an added/modified directory
+
+ * Scripts/svn-create-patch:
+ (sub generateFileList($\%\%)): Ignore directories when generating the file list.
+
+2007-01-29 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Fixed <rdar://problem/4485644> REGRESSION: JavaScriptCore has init routines
+
+ No more mollycoddling for you, FastMalloc.o!
+
+ * Scripts/check-for-global-initializers:
+
+2007-01-29 Graham Dennis <graham.dennis@gmail.com>
+
+ Reviewed by Maciej.
+
+ Enables layout test for: http://bugs.webkit.org/show_bug.cgi?id=10725
+ Image data in from RTFD clipboard data thrown away
+
+ - This method is needed because NSArrays are bridged to JS Arrays,
+ which in turn are bridged back to WebScriptObjects when passed from
+ JS to ObjC. Hence it is not possbile to pass an NSArray from JS.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[DumpRenderTreePasteboard declareType:owner:]): Added a convenience method for JS.
+
+2007-01-25 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Added support for test for <rdar://problem/4608404> WebScriptObject's
+ _rootObject lack of ownership policy causes crashes (e.g., in Dashcode)
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController storeWebScriptObject:]):
+ (-[LayoutTestController accessStoredWebScriptObject]):
+ (-[LayoutTestController dealloc]):
+
+2007-01-26 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Small hack to ensure that our top level frame actually has the
+ correct size. Unfortunately this means I'll have to regenerate
+ all test cases :/
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2007-01-25 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Darin and Zack
+
+ Move the test results for Qt into a directory of it's own
+ (WebKit/LayoutTestResults/qt). Leave the Mac results where
+ they are for now and share the text only results between
+ Mac and Qt.
+
+ Add support for a LayoutTestResults/platform/Skipped file
+ to run-webkit-tests to be able to ignore certain tests
+
+ Remove the old tests-skipped.txt from Qts DumpRenderTree
+ implementation.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/tests-skipped.txt: Removed.
+ * Scripts/run-webkit-tests:
+
+2007-01-24 Darin Adler <darin@apple.com>
+
+ Reviewed by Oliver.
+
+ - fix crash seen in layout tests
+
+ * DumpRenderTree/EventSendingController.m: (-[EventSendingController dealloc]):
+ Add back the line of code that sets savedMouseEvents to nil. I thought it was
+ a field of the EventSendingController, but it's actually a global.
+
+2007-01-24 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej.
+
+ - changed dragMode to be a property instead of a function
+
+ * DumpRenderTree/EventSendingController.h: Renamed inDragMode to dragMode.
+ * DumpRenderTree/EventSendingController.m:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]): Removed setDragMode.
+ (+[EventSendingController isKeyExcludedFromWebScript:]): Added dragMode.
+ (-[EventSendingController init]): Updated for name change.
+ (-[EventSendingController leapForward:]): Ditto.
+ (-[EventSendingController mouseUp]): Ditto.
+ (-[EventSendingController mouseMoveToX:Y:]): Ditto.
+
+2007-01-24 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej.
+
+ - made the deferral of mouse events until drag completes conditional
+ it's needed for drag testing, and harmful for selection testing
+
+ * DumpRenderTree/EventSendingController.h: Added inDragMode boolean.
+ * DumpRenderTree/EventSendingController.m:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]): Added setDragMode:.
+ (+[EventSendingController webScriptNameForSelector:]): Added name for setDragMode,
+ and remove unneeded clearKillRing name.
+ (-[EventSendingController init]): Initialize inDragMode to true.
+ (-[EventSendingController dealloc]): Removed overzealous assertions -- we should
+ not be asserting things that are dependent on the test content!
+ (-[EventSendingController leapForward:]): Only queue events in drag mode.
+ (-[EventSendingController setDragMode:]): Added.
+ (-[EventSendingController mouseDown]): Removed overzealous assertion.
+ (-[EventSendingController mouseUp]): Removed overzealous assertions.
+ Only queue events in drag mode.
+ (-[EventSendingController mouseMoveToX:Y:]): Only queue events in drag mode.
+
+2007-01-24 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Add a signal handler, always dump immediately if we get an
+ error during a page load and raise the timeout to 5 seconds
+ (as we get a lot less such failures now)
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::maybeDump):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.cpp:
+ (LayoutTestController::waitUntilDone):
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+ (crashHandler):
+ (main):
+ * DumpRenderTree/DumpRenderTree.qtproj/tests-skipped.txt:
+
+2007-01-22 Darin Adler <darin@apple.com>
+
+ Reviewed by Mitz.
+
+ - a couple tiny tweaks to make --reset-results work better
+
+ * Scripts/run-webkit-tests: Always generate results when --reset-results is specified.
+ Don't make a separate "new" entry while generating results when --reset-results
+ is specified since new results are the norm in that case.
+
+2007-01-21 Sanjay Madhav <sanjay12@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ Test support for: <rdar://problem/4928583> Memory usage grows when reloading google.com/ig
+
+ This adds a getJSObjectCount test-accessible function to allow test scripts to track JSObject usage.
+
+ * DumpRenderTree/GCController.h:
+ * DumpRenderTree/GCController.mm:
+ (+[GCController isSelectorExcludedFromWebScript:]):
+ (-[GCController getJSObjectCount]):
+
+2007-01-20 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Maciej.
+
+ * BuildSlaveSupport/build.webkit.org-config/webkit/steps.py: Track the output of run-javascriptcore-tests,
+ catch single regressions, and don't generate tests results for new tests.
+
+2007-01-20 Adam Roben <aroben@apple.com>
+
+ Rubberstamped by Maciej.
+
+ * Scripts/run-webkit-tests: Change the default behavior back to
+ generating results for new tests (this can be disabled with
+ --no-new-test-results)
+
+2007-01-19 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Adam Roben.
+
+ run-webkit-tests does now not generate new results by default anymore.
+ You'll have to pass the --new-tests flag to it to force it to do so.
+
+ This is required to make it possible to have tests running on multiple
+ platforms peacefully together.
+
+ * Scripts/run-webkit-tests:
+
+2007-01-18 Darin Adler <darin@apple.com>
+
+ Reviewed by John Sullivan.
+
+ * Scripts/run-webkit-tests: Fix handling of configuration so it
+ does the right thing when no explicit configuration is passed in.
+ The old code assumed that the result of setConfiguration() was the
+ configuration, but it's undefined when no configuration is
+ explicitly passed in. The correct function to use is
+ configuration(), and I also streamlined the code.
+
+2007-01-17 Lars Knoll <lars@trolltech.com>
+
+ Fix my last commit to actually work in all cases.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::readStdin):
+
+2007-01-17 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Maciej
+
+ Make sure DumpRenderTree exits when run-webkit-tests
+ is done.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::readStdin):
+
+2007-01-17 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Small fixes in DumpRenderTree, so we don't by
+ accident dump twice for the same test.
+
+ Exclude one more test as it currently causes DumpRenderTree to
+ hang forever.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::readStdin):
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.cpp:
+ (LayoutTestController::notifyDone):
+ * DumpRenderTree/DumpRenderTree.qtproj/tests-skipped.txt:
+
+2007-01-17 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Add a message handler to DumpRenderTree that will
+ suppress all debug output coming from qDebug() statements.
+ Like this we can get rid of all the noise coming
+ from the notImplemented() macro when running the
+ layout tests. You can get it back by adding -v to
+ DumpRenderTree's command line.
+
+ Changed run-webkit-tests slightly, so we by default
+ don't fail anymore when our output differs from what
+ is generated on the Mac. Added a --strict option, so
+ that we can still see this cases and fix them one by one.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+ (messageHandler):
+ (main):
+ * Scripts/run-webkit-tests:
+
+2007-01-16 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Use the new public API for the Qt build, and don't rely on
+ WebKit internals anymore.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::~DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::readStdin):
+ (WebCore::DumpRenderTree::initJSObjects):
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro:
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTreeClient.cpp: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTreeClient.h: Removed.
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.cpp:
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::timerEvent):
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+ (main):
+ * DumpRenderTree/DumpRenderTree.qtproj/tests-skipped.txt:
+
+2007-01-15 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by mjs
+
+ <rdar://problem/4810960>
+ Gmail Editor: window.focus() called on keyDown (9640)
+
+ * DumpRenderTree/EventSendingController.m: Send the keyDown event
+ to the firstResponder, not the event's locationInWindow. A
+ key press's locationInWindow is meaningless and just a dummy
+ coordinate.
+
+2007-01-15 Eric Seidel <eric@webkit.org>
+
+ Reviewed by bdash.
+
+ Add a script to keep our header guards squeaky clean.
+
+ * Scripts/clean-header-guards: Added.
+
+2007-01-15 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Fix a few smaller issues in here, and update
+ our list of skipped tests.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::readStdin):
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::reset):
+ (LayoutTestController::waitUntilDone):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::dumpEditingCallbacks):
+ (LayoutTestController::timerEvent):
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/tests-skipped.txt:
+
+2007-01-14 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Adam.
+
+ <rdar://problem/4908909> Need to create Leopard nightly build
+
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj: Always use the 10.4 Universal SDK. The disk images don't mount pre-10.4 so we aren't losing anything here.
+ * WebKitLauncher/WebKitNightlyEnabler.m:
+ (poseAsWebKitApp): Simplify CoreFoundation-related hackery by using _CFGetProcessPath instead of walking the mach-o symbol tables. The smaller timeframe where the
+ CFProcessPath environment variable is set allows this to work correctly on Leopard where the old code failed.
+ (enableWebKitNightlyBehaviour):
+ * WebKitLauncher/main.m:
+ (main): Pass executable path as WebKitAppPath rather than CFProcessPath to prevent it being picked up too early by CoreFoundation.
+ * Drosera/launcher.m:
+ (main): Ditto
+
+2007-01-12 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Get DumpRenderTree to work again for the Qt build.
+
+ Make run-webkit-tests a little less verbose when testing
+ Qt, and add an option to run DumpRenderTree inside valgrind
+ (useful for debugging)
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::~DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::dump):
+ (WebCore::DumpRenderTree::maybeDump):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTreeClient.cpp:
+ (WebCore::DumpRenderTreeClient::dispatchDidHandleOnloadEvents):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTreeClient.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/tests-skipped.txt:
+ * Scripts/run-webkit-tests:
+
+2007-01-12 Zack Rusin <zack@kde.org>
+
+ Add WEBKIT_FULLBUILD env variable to get the
+ build do a make clean before make to cleanout the
+ stale depenendencies (for buildbot mainly).
+
+ * Scripts/webkitdirs.pm:
+
+2007-01-11 Mitz Pettel <mitz@webkit.org>
+
+ Reviewed by Hyatt.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=10249
+ Temporarily disable tests that are causing kernel panics
+
+ Changed the ImageDiff tool not to use CoreImage filters.
+
+ * DumpRenderTree/ImageDiff.m:
+ (main):
+ (createImageFromStdin):
+ (compareImages):
+ (getDifferenceBitmap):
+
+2007-01-11 Lars Knoll <lars@trolltech.com>
+
+ Fix compilation
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro:
+
+2007-01-11 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Darin Adler.
+
+ Adjust to loader changes.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2007-01-06 George Staikos <staikos@kde.org>
+
+ This doesn't build on all unix platforms!
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro:
+
+2007-01-05 Zack Rusin <zack@kde.org>
+
+ Reviewed by Simon.
+
+ Fix the undefined warnings and try to detect
+ the DISPLAY properly.
+
+ * Scripts/run-webkit-tests:
+
+2007-01-05 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Speed up svn-create-patch for copied and moved files.
+
+ * Scripts/svn-create-patch:
+ (manufacturePatchForAdditionWithHistory($$)): Use 'svn cat' instead of 'svn cat -rNNNNN'
+ so svn pulls original from local disk.
+
+2007-01-04 Lars Knoll <lars@trolltech.com>
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro:
+ Link with RPATH to (hopefully) get the automatic tests working.
+
+2007-01-03 Mark Rowe <bdash@webkit.org>
+
+ Reviewed by Anders.
+
+ * Scripts/run-webkit-tests: Launch Safari using the same WebKit build configuration as the layout tests used.
+
+2007-01-02 Zack Rusin <zack@kde.org>
+
+ Make it work after javascriptcore/bindings changes.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::initJSObjects):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro:
+
+2007-01-01 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=12023
+ svn-create-patch and friends should handle moved/copied files
+
+ * Scripts/svn-apply: Identify copied files and handle those before all other patches.
+ * Scripts/svn-create-patch: Generate patches with subtle changes for copied files.
+ (findMimeType($)): Added.
+ (findModificationTime($)): Added.
+ (findSourceFileAndRevision($)): Added.
+ (generateDiff($$$)): Changed to use svn stat instead of svn diff.
+ (isBinaryMimeType($)): Added.
+ (manufacturePatchForAdditionWithHistory($$)): Added.
+ * Scripts/svn-unapply: Identify copied files and handle those after unapplying all other patches.
+
+2006-12-29 Eric Seidel <eric@webkit.org>
+
+ Reviewed by olliej.
+
+ Stop DumpRenderTree from reporting false Frame/Node leaks due to new SVGImage
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dumpRenderTree): clear WebCore cache before exiting
+
+2006-12-29 David Kilzer <ddkilzer@webkit.org>
+
+ Reverted last commit until WebResourceData issue is fixed.
+
+ http://bugs.webkit.org/show_bug.cgi?id=11882
+ Need a way to regression test .webarchive output files
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (serializeWebArchiveToXML): Removed.
+ (dump):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController dumpAsWebArchive]): Removed.
+ (runTest):
+
+2006-12-28 David Kilzer <ddkilzer@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=11882
+ Need a way to regression test .webarchive output files
+
+ Implement layoutTestController.dumpAsWebArchive() to test WebArchive format.
+ Saves WebArchive plist in xml format, then alters file:// URLs to remove path
+ where WebKit was checked out.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (serializeWebArchiveToXML): Added.
+ (dump):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController dumpAsWebArchive]): Added.
+ (runTest):
+
+2006-12-28 George Staikos <staikos@kde.org>
+
+ Reviewed by Olliej.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro: don't build on non-X11
+
+2006-12-27 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Eric Seidel. Prose edited by Mitz Pettel.
+
+ Some cleanup I did while debugging the regression in plugins/netscape-dom-access.html.
+
+ No behavior change. Layout tests pass.
+
+ * DumpRenderTree/DumpRenderTree.h: Exported the done BOOL in place of the
+ doneLoading() accessor function. This matches the rest of DRT's exports and
+ makes it easier to search for clients who check (!done).
+
+ * DumpRenderTree/DumpRenderTree.m: Moved fflush() call to runTest() so
+ it would cover both code paths for calling runTest().
+
+ (dumpRenderTree): "doneLoading()" => "done"
+ (dump): ditto
+ * DumpRenderTree/EditingDelegate.m: ditto
+ (-[EditingDelegate webView:shouldBeginEditingInDOMRange:]): ditto
+ (-[EditingDelegate webView:shouldEndEditingInDOMRange:]): ditto
+ (-[EditingDelegate webView:shouldInsertNode:replacingDOMRange:givenAction:]): ditto
+ (-[EditingDelegate webView:shouldInsertText:replacingDOMRange:givenAction:]): ditto
+ (-[EditingDelegate webView:shouldDeleteDOMRange:]): ditto
+ (-[EditingDelegate webView:shouldChangeSelectedDOMRange:toDOMRange:affinity:stillSelecting:]): ditto
+ (-[EditingDelegate webView:shouldApplyStyle:toElementsInDOMRange:]): ditto
+ (-[EditingDelegate webView:shouldChangeTypingStyle:toStyle:]): ditto
+ (-[EditingDelegate webViewDidBeginEditing:]): ditto
+ (-[EditingDelegate webViewDidChange:]): ditto
+ (-[EditingDelegate webViewDidEndEditing:]): ditto
+ (-[EditingDelegate webViewDidChangeTypingStyle:]): ditto
+ (-[EditingDelegate webViewDidChangeSelection:]): ditto
+ * DumpRenderTree/UIDelegate.m: ditto
+ (-[UIDelegate webView:runJavaScriptAlertPanelWithMessage:]): ditto
+
+2006-12-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by bradee-oh.
+
+ Add very simple run-pageloadtest script for running SVG page load test.
+
+ * Scripts/run-pageloadtest: Added.
+
+2006-12-26 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Eric Seidel.
+
+ Some cleanup in preparation for fixing <rdar://problem/4740328> Safari
+ crash on quit in _NPN_ReleaseObject from KJS::Bindings::CInstance::~CInstance
+
+ (dumpRenderTree): Renamed "installedPlugins" to "sharedDatabase."
+
+2006-12-23 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Added --threaded support to run-webkit-tests and DumpRenderTree.
+
+ In "threaded" mode, DRT runs a concurrent JavaScript thread with each test,
+ stressing the thread safety of JavaScriptCore and the JavaScriptCore/WebCore
+ interface. This is useful for tracking down bugs you might see on a system
+ configured to use a PAC file.
+
+ Ironically, I can proudly state that very few layout tests pass.
+
+ * DumpRenderTree/DumpRenderTree.m: Added javaScriptThread and helper functions
+ for starting and stopping it.
+ (runJavaScriptThread): helper function
+ (startJavaScriptThread): helper function
+ (stopJavaScriptThread): helper function
+
+ (dumpRenderTree): Added --threaded command line argument.
+ * Scripts/run-webkit-tests: ditto
+
+2006-12-22 Mark Rowe <bdash@webkit.org>
+
+ Reviewed by Brady.
+
+ Fix for <rdar://problem/4265976>
+ prepare-ChangeLog sometimes lists the wrong Objective-C class name for a changed method
+
+ * Scripts/prepare-ChangeLog: Treat @end as the end of both the interface and the method declaration.
+
+2006-12-21 Mark Rowe <bdash@webkit.org>
+
+ Reviewed by Tim Hatcher.
+
+ http://bugs.webkit.org/show_bug.cgi?id=11922
+ Bug 11922: REGRESSION(r17128): Drosera no longer shows local variables in stack frame
+
+ * Drosera/DebuggerDocument.m:
+ (-[WebScriptObject webScriptAttributeKeysForScriptObject:]): Use an anonymous function with function.call to
+ ensure that the properties are being retrieved from the correct scope object.
+
+2006-12-21 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Add support for the layoutTestController JavaScript object
+ to be able to get textOnly dumps.
+ Added a Qt specific hack to always get the same fonts (the ones
+ added in this submit) and the same dpi when running the layout tests.
+ Modified the run-webkit-tests script to also do a comparison to the
+ Mac generated outputs (by stripping out positioning information).
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::resetJSObjects):
+ (WebCore::DumpRenderTree::initJSObjects):
+ (WebCore::DumpRenderTree::dump):
+ (WebCore::DumpRenderTree::checkLoaded):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro:
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTreeClient.cpp:
+ (WebCore::DumpRenderTreeClient::DumpRenderTreeClient):
+ (WebCore::DumpRenderTreeClient::partClearedInBegin):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTreeClient.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/fontoverload.cpp: Added.
+ (QX11Info::appDpiY):
+ (QX11Info::appDpiX):
+ (qt_x11ft_convert_pattern):
+ (LayoutTestController::LayoutTestController):
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.h: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/jsobjects.cpp: Added.
+ (LayoutTestController::shouldDumpAsText):
+ (LayoutTestController::shouldWaitUntilDone):
+ (LayoutTestController::reset):
+ (LayoutTestController::dumpAsText):
+ (LayoutTestController::waitUntilDone):
+ (LayoutTestController::notifyDone):
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/AHEM____.TTF: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/COPYING: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/CourierBold.ttf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/CourierBoldOblique.ttf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/CourierMedium.ttf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/CourierMediumOblique.ttf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/HelveticaBold.ttf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/HelveticaBoldOblique.ttf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/HelveticaMedium.ttf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/HelveticaMediumOblique.ttf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/SymbolMedium.ttf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/TimesBold.ttf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/TimesBoldItalic.ttf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/TimesMedium.ttf: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/fonts/TimesMediumItalic.ttf: Added.
+ * Scripts/run-webkit-tests:
+
+2006-12-21 Mark Rowe <bdash@webkit.org>
+
+ Reviewed by Geoff.
+
+ http://bugs.webkit.org/show_bug.cgi?id=11888
+ Bug 11888: REGRESSION (r18320): Web Inspector panes broken
+
+ * Drosera/debugger.js: Use removeProperty to reset a style property to its initial value.
+
+2006-12-18 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Updated EventSender to be able to send mouse up events outside the WebView.
+ This is a minor tweak to a hackish implementation. The real solution
+ should be to use NSApplication's event sending model instead of rolling
+ our own, but I don't have time for that right now.
+
+ * DumpRenderTree/EventSendingController.m:
+ (-[EventSendingController mouseUp]):
+
+2006-12-15 Marvin Decker <marv.decker@gmail.com>
+
+ Reviewed by Darin and Alexey.
+
+ Fix the Windows build, move various Client implementations out of
+ WebCore and into WebKit.
+
+ * Spinneret/Spinneret.sln:
+
+2006-12-14 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Brady.
+
+ * Makefile.shared: use $PIPESTATUS[0] and a sub-shell to exit with xcodebuild's exit status
+
+2006-12-13 Zack Rusin <zack@kde.org>
+
+ Reviewed by rwlbuis
+
+ Use the qmake build by default with Qt - it's the one that works
+ currently.
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2006-12-10 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Some more fixes to the dumprendertree application.
+ Fix the run-webkit-tests script for Qt.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::readStdin):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro: Added.
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2006-12-10 Rob Buis <buis@kde.org>
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dump):
+
+2006-12-10 Lars Knoll <lars@trolltech.com>
+
+ Reviewed by Zack
+
+ Get the DumpRenderTree app to compile again
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::readStdin):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.pro: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTreeClient.cpp:
+ (WebCore::DumpRenderTreeClient::DumpRenderTreeClient):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTreeClient.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+ (main):
+
+2006-12-09 George Staikos <staikos@kde.org>
+
+ Reviewed by Zack.
+
+ Repair QMake build on OS X.
+
+ * Scripts/build-webkit:
+
+2006-12-09 Zack Rusin <zack@kde.org>
+
+ Fixing small mistakes in the build scripts for
+ the qmake builds.
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2006-12-09 Simon Hausmann <hausmann@kde.org>
+
+ Reviewed by hyatt.
+
+ Add support for a QMake build using build-webkit --qmake
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2006-12-09 George Staikos <staikos@kde.org>
+
+ Reviewed by Zack.
+
+ Remove reference to Unity.
+
+ * Scripts/webkitdirs.pm:
+
+2006-12-08 Zack Rusin <zack@kde.org>
+
+ Reviewed by Maciej.
+
+ Fix the compile after recent API changes.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+ (main):
+
+2006-12-08 George Staikos <staikos@kde.org>
+
+ Reviewed by Maciej.
+
+ Build Qt webkit on non-linux, and prefer it if $QTDIR is set
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2006-12-06 Steve Falkenburg <sfalken@apple.com>
+
+ Support C strings for localization
+
+ * Scripts/extract-localizable-strings:
+
+2006-12-04 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Make extract-localizable-strings compatible with cpp file extensions.
+
+ * Scripts/extract-localizable-strings:
+
+2006-11-21 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej.
+
+ - a couple changes to reduce the chance of false positives on the leakbot
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dumpRenderTree): Move the main function into a separate function so we can run
+ a final garbage collect afterward without any stray values on the stack. Replaced
+ the old way of closing down a WebView (setting the delegates to nil) with the new
+ way (calling the close method), which does a more complete job of shutting
+ everything down without waiting for the WebView object to be deallocated.
+ (main): Put auto-release pool here and added an explicit call to garbage collect.
+ With a separate function, we greatly reduce the chance that a stray address on the
+ stack will keep an object alive.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Let Xcode do its thing,
+ because I don't have what it takes to fight the power.
+
+2006-11-17 Zack Rusin <zack@kde.org>
+
+ Reviewed by Mitz. Landed by Niko.
+
+ Fixing compilation.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree): Adding
+ ContextMenuClient to the constructor
+
+2006-11-12 Mark Rowe <bdash@webkit.org>
+
+ Reviewed by Mitz.
+
+ Clean up of GdkLauncher bakefile.
+
+ * GdkLauncher/gdklauncher.bkl:
+
+2006-11-11 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed and landed by Anders.
+
+ Make DRT work again on Qt/Linux.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2006-11-10 Zack Rusin <zack@kde.org>
+
+ Reviewed and landed by Anders.
+
+ Adjusting to the recent loader changes, making it compile
+ and work.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::checkLoaded):
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+
+2006-11-10 Zack Rusin <zack@kde.org>
+
+ Reviewed by Anders.
+
+ Making the Qt code work after refactorings in WebCore.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::checkLoaded):
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp:
+
+2006-11-08 Darin Adler <darin@apple.com>
+
+ Reviewed by Anders.
+
+ - same change as below, only tested this time
+
+ * DumpRenderTree/DumpRenderTree.m: (main): Explicitly turn "tab to links"
+ mode off. I think we need to do this because WebPreferences saves things
+ for us automatically. It would be good to turn that off for DumpRenderTree,
+ but for now lets handle this like the other preferences (set it explicitly
+ each time).
+
+2006-11-08 Darin Adler <darin@apple.com>
+
+ Reviewed by Anders.
+
+ * DumpRenderTree/DumpRenderTree.m: (main): Get rid of code to turn on
+ "tab to links" mode. No current tests depend on this, and there's a new
+ test I want to land that depends on the default setting.
+
+2006-11-06 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+
+ Reviewed by Maciej.
+
+ Linux\gdk build fixes.
+
+ * GdkLauncher/main.cpp:
+ (LauncherFrameGdk::LauncherFrameGdk):
+ (main):
+
+2006-11-06 Alexey Proskuryakov <ap@nypop.com>
+
+ Build fix, approved in principle by Tim H.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ Disable deprecated warnings for main.c (TestNetscapePlugin),
+ as it now uses QuickDraw to convert mouse event coordinates.
+
+2006-11-05 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Maciej.
+
+ Bug 11525: [Drosera] function menu doesn't understand object.method = function() {} syntax
+ http://bugs.webkit.org/show_bug.cgi?id=11525
+
+ * Drosera/debugger.js: imporved the function name code
+
+2006-11-06 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Maciej.
+
+ Make sure that alerts and delegate output made after notifyDone() are ignored, rather than
+ being attributed to the next test.
+
+ * DumpRenderTree/EditingDelegate.m:
+ (-[EditingDelegate webView:shouldBeginEditingInDOMRange:]):
+ (-[EditingDelegate webView:shouldEndEditingInDOMRange:]):
+ (-[EditingDelegate webView:shouldInsertNode:replacingDOMRange:givenAction:]):
+ (-[EditingDelegate webView:shouldInsertText:replacingDOMRange:givenAction:]):
+ (-[EditingDelegate webView:shouldDeleteDOMRange:]):
+ (-[EditingDelegate webView:shouldChangeSelectedDOMRange:toDOMRange:affinity:stillSelecting:]):
+ (-[EditingDelegate webView:shouldApplyStyle:toElementsInDOMRange:]):
+ (-[EditingDelegate webView:shouldChangeTypingStyle:toStyle:]):
+ (-[EditingDelegate webViewDidBeginEditing:]):
+ (-[EditingDelegate webViewDidChange:]):
+ (-[EditingDelegate webViewDidEndEditing:]):
+ (-[EditingDelegate webViewDidChangeTypingStyle:]):
+ (-[EditingDelegate webViewDidChangeSelection:]):
+ * DumpRenderTree/UIDelegate.m:
+ (-[UIDelegate webView:runJavaScriptAlertPanelWithMessage:]):
+
+2006-11-06 Mark Rowe <bdash@webkit.org>
+
+ Reviewed by Alexey.
+
+ Fix "Undefined subroutine &main::WEXITSTATUS" when build-dumprendertree fails.
+
+ * Scripts/run-webkit-tests: import the POSIX module.
+
+2006-11-06 Alexey Proskuryakov <ap@webkit.org>
+
+ Reviewed by Maciej.
+
+ Test for http://bugs.webkit.org/show_bug.cgi?id=11517
+ REGRESSION: Flash clicks/interactivity not working properly
+
+ Teach TestNetscapePlugin to log events passed to it. To enable, set eventLoggingEnabled to true:
+
+ <embed name="plg" type="application/x-webkit-test-netscape" width=100 height=100></embed>
+ <script>
+ plg.eventLoggingEnabled = true;
+ // use eventSender to simulate events...
+ </script>
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (pluginGetProperty):
+ (pluginSetProperty):
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c:
+ (NPP_HandleEvent):
+
+2006-11-04 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Tim H.
+
+ Fixes: http://bugs.webkit.org/show_bug.cgi?id=11521
+ Bug 11521: [Drosera] Breakpoint editor UI behaves incorrectly when multiple editors are open
+
+ * Drosera/debugger.js: Use .// instead of // so that it doesn't root the search at the document.
+
+2006-11-04 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Tim H.
+
+ Fixes: http://bugs.webkit.org/show_bug.cgi?id=11513
+ Bug 11513: [Drosera] Function popup fails to appear when clicking supposedly valid areas.
+
+ * Drosera/debugger.css: Stick a min-width on the menu to keep it from becoming smaller than the control.
+
+2006-11-04 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Tim H.
+
+ Fixes: http://bugs.webkit.org/show_bug.cgi?id=11512
+ Bug 11512: [Drosera] Scrolling via keyboard breaks after clicking in function popup.
+
+ * Drosera/debugger.js: blur() the function popup when we're done with it.
+
+2006-11-04 Mark Rowe <bdash@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Fix use of uninitialized value in pattern match.
+
+ * Scripts/webkitdirs.pm:
+
+2006-11-04 Darin Adler <darin@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ * Scripts/webkitdirs.pm: Don't try to use the Xcode build setting if it's project-relative.
+
+2006-11-03 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Tim H.
+
+ Fixes: http://bugs.webkit.org/show_bug.cgi?id=11510
+ Bug 11510: [Drosera] Doubleclicking the attach table should attach to the clicked item.
+
+ * Drosera/DebuggerApplication.m:
+ (-[DebuggerApplication showAttachPanel:]): Set the doubleAction for the table view
+
+2006-11-03 Vladimir Olexa <vladimir.olexa@gmail.com>
+
+ Reviewed by Tim H.
+
+ Fixes: http://bugs.webkit.org/show_bug.cgi?id=9596
+ Bug 9596: [Drosera] add a function popup to the source pane
+
+ * Drosera/debugger.css: Added styles for function popup
+ * Drosera/debugger.html: Added function popup button and select
+ * Drosera/debugger.js: Added function popup functionality
+
+2006-11-03 Michael Emmel <mike.emmel@gmail.com>
+
+ Reviewed by Maciej.
+
+ http://bugs.webkit.org/show_bug.cgi?id=9671
+
+ * Scripts/wkstyle:
+ Adds astyle sed script formats according to most of the style guidelines.
+
+2006-11-03 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Adele.
+
+ http://bugs.webkit.org/show_bug.cgi?id=7323
+ REGRESSION (10.4.4): ondrag* events don't fire on page in a frame
+
+ When dragging, do not send EventSendingController's events immediately. Dragging
+ is supposed to be modal, so we need to perform it from within the delegate, without
+ returning to JS to make the next mouse movement.
+
+ When the mouse is down, mouse events are now recorded, and executed when mouseUp is sent.
+
+ * DumpRenderTree/EventSendingController.h:
+ * DumpRenderTree/EventSendingController.m:
+ (-[EventSendingController dealloc]):
+ (-[EventSendingController leapForward:]):
+ (-[EventSendingController mouseDown]):
+ (-[EventSendingController mouseUp]):
+ (-[EventSendingController mouseMoveToX:Y:]):
+ (+[EventSendingController saveEvent:]):
+ (+[EventSendingController replaySavedEvents]):
+ * DumpRenderTree/UIDelegate.m:
+ (-[UIDelegate webView:dragImage:at:offset:event:pasteboard:source:slideBack:forView:]):
+
+2006-11-02 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Justin Garcia.
+
+ Made dumping of editing callbacks opt-in, so that editing spew doesn't
+ cloud non-editing tests.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController shouldDumpEditingCallbacks]):
+ (runTest):
+ * DumpRenderTree/EditingDelegate.m:
+ (-[EditingDelegate webView:shouldBeginEditingInDOMRange:]):
+ (-[EditingDelegate webView:shouldEndEditingInDOMRange:]):
+ (-[EditingDelegate webView:shouldInsertNode:replacingDOMRange:givenAction:]):
+ (-[EditingDelegate webView:shouldInsertText:replacingDOMRange:givenAction:]):
+ (-[EditingDelegate webView:shouldDeleteDOMRange:]):
+ (-[EditingDelegate webView:shouldChangeSelectedDOMRange:toDOMRange:affinity:stillSelecting:]):
+ (-[EditingDelegate webView:shouldApplyStyle:toElementsInDOMRange:]):
+ (-[EditingDelegate webView:shouldChangeTypingStyle:toStyle:]):
+ (-[EditingDelegate webViewDidBeginEditing:]):
+ (-[EditingDelegate webViewDidChange:]):
+ (-[EditingDelegate webViewDidEndEditing:]):
+ (-[EditingDelegate webViewDidChangeTypingStyle:]):
+ (-[EditingDelegate webViewDidChangeSelection:]):
+
+2006-11-02 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Maciej, landed by Anders.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=7802
+ devenv.com not available in VC++ Express installations
+
+ * Scripts/webkitdirs.pm: Make Windows build work with Visual C++ Express.
+ * Scripts/install-win-extras: Make setx.exe actually run.
+
+2006-11-01 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Kevin.
+
+ Fixed bug where additional arguments got fed to xcode and jsdriver.pl
+ Since testkjs is being built before the tests are run, we don't need
+ to build it with webkit.
+
+ Fixes bugs
+ http://bugs.webkit.org/show_bug.cgi?id=11462
+ http://bugs.webkit.org/show_bug.cgi?id=6168
+
+ * Scripts/build-webkit:
+ * Scripts/run-javascriptcore-tests:
+
+2006-11-01 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Tim Hatcher
+
+ Added accessor to get the source directory for use in client scripts
+
+ * Scripts/webkitdirs.pm:
+
+2006-11-01 Mark Rowe <bdash@webkit.org>
+
+ Reviewed by Mitz.
+
+ Update references to webkit.opendarwin.org to webkit.org in Spinneret and WebKit.app.
+
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (_tWinMain):
+ * WebKitLauncher/WebKitNightlyEnabler.m:
+ (cleanUpAfterOurselves):
+
+2006-10-31 Mark Rowe <bdash@webkit.org>
+
+ Reviewed by Stephanie.
+
+ Limit build slaves to a single build to prevent concurrent builds on a single slave from significantly increasing build time.
+
+ * BuildSlaveSupport/build.webkit.org-config/webkit/builders.py: Adjust slave distribution, and make use of a SlaveLock.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/factories.py: Remove unused Qt build factory.
+
+2006-10-31 Darin Adler <darin@apple.com>
+
+ * DumpRenderTree/DumpRenderTree.m: Instead of allocating a single local
+ pasteboard, allocate any number of local pasteboards.
+ (main): Allocate the dictionary of pasteboards.
+ (+[DumpRenderTreePasteboard _pasteboardWithName:]): Allocate a pasteboard,
+ given a name.
+ (+[LocalPasteboard alloc]): Added, so we don't have to call NSAllocateObject
+ explicitly elsewhere.
+ (-[LocalPasteboard addTypes:owner:]): Added a check that the owner responds
+ to the selector rather than calling unconditionally.
+
+2006-10-30 Darin Adler <darin@apple.com>
+
+ - fixed build
+
+ * DumpRenderTree/DumpRenderTree.m: (-[LocalPasteboard setString:forType:]):
+ Don't use CFPasteboard.
+
+2006-10-30 Vladimir Olexa <vladimir.olexa@gmail.com>
+
+ Reviewed by Tim H.
+
+ Fixes: http://bugs.webkit.org/show_bug.cgi?id=11353
+
+ * Drosera/debugger.js: ParsedURL() object now recognizes local files
+
+2006-10-30 Darin Adler <darin@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ * DumpRenderTree/DumpRenderTree.m: Changed to allocate a local pasteboard.
+ This should make our buildbot tests no longer need a pasteboard server.
+
+2006-10-30 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Beth.
+
+ Reorganized project file into Delegates and Controllers groups, and split
+ UIDelegate stuff into a UIDelegate class.
+
+ A little birdy told me that I might end up adding some UIDelegate methods
+ to DRT soon.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main):
+ (runTest):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2006-10-31 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Oliver.
+
+ Add new platform/graphics include directory.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/CMakeLists.txt:
+
+2006-10-30 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Stephanie.
+
+ Add a special case for the Internal makefiles, so it can find the OepnSource.
+
+ * Scripts/webkitdirs.pm:
+
+2006-10-30 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Change Makefiles to return non-zero when module make fails.
+ Fix bug where if xcode options are not set, modules can build in the
+ wrong directory.
+
+ * Makefile:
+ * Scripts/webkitdirs.pm:
+
+2006-10-30 Matt Lilek <pewtermoose@gmail.com>
+
+ Reviewed by Tim H.
+
+ Fix for http://bugs.webkit.org/show_bug.cgi?id=10468
+ [Drosera] The Console toolbar button should bring the console window to the front.
+
+ The console now gets focus when its activated but already open. Command + L also
+ now activates/focuses the console.
+
+ * Drosera/English.lproj/MainMenu.nib/classes.nib:
+ * Drosera/English.lproj/MainMenu.nib/info.nib:
+ * Drosera/English.lproj/MainMenu.nib/keyedobjects.nib:
+ * Drosera/debugger.js:
+
+2006-10-29 Darin Adler <darin@apple.com>
+
+ * Scripts/do-file-rename: Renames done, ready for the next round.
+ * Scripts/do-webcore-rename: Ditto.
+
+2006-10-29 Darin Adler <darin@apple.com>
+
+ * Scripts/do-file-rename: And again.
+
+2006-10-29 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Tweaked plans for renaming again.
+
+2006-10-29 Darin Adler <darin@apple.com>
+
+ Reviewed by Mitz.
+
+ * DumpRenderTree/DumpRenderTree.m: (-[DumpRenderTreeWindow keyDown:]):
+ Added. Does nothing, which prevents a beep.
+
+ * Scripts/do-webcore-rename: Tweaked plans for renaming a bit.
+
+2006-10-27 Brady Eidson <beidson@apple.com>
+
+ Rubber stamped by Tim Hatcher
+
+ Added "make universal" to build universal binaries
+
+ * Makefile:
+ * Makefile.shared:
+
+2006-10-26 Sam Weinig <sam.weinig@gmail.com>
+
+ Reviewed by Geoff.
+
+ Fix for http://bugs.webkit.org/show_bug.cgi?id=11419
+ REGRESSION (r17299): Assertion failure in -[WebHTMLView(WebPrivate) _topHTMLView]
+ ([view isKindOfClass:[WebHTMLView class]]) when running the layout tests
+
+ * DumpRenderTree/EventSendingController.m:
+ (-[EventSendingController mouseMoveToX:Y:]):
+
+2006-10-26 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Darin Adler.
+
+ Fix Qt/Linux build.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::open):
+
+2006-10-24 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Maciej.
+
+ - Changed run-javascriptcore tests to build testkjs before running.
+
+ * Scripts/run-javascriptcore-tests:
+
+2006-10-24 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Maciej.
+
+ Fix Qt/Linux build.
+
+ - Remove BrowserExtensionQt, move it's methods to Page/FrameQt.
+ - Fix CMakeLists.txt to include platform/network.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/CMakeLists.txt:
+
+2006-10-24 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Tim H.
+
+ Bug 11382: [Drosera] Dragging breakpoints onto each other can mess up inline editor
+ http://bugs.webkit.org/show_bug.cgi?id=11382
+
+ * Drosera/debugger.js: Breakpoint dragging now ensures that editors aren't orphaned.
+
+2006-10-21 Darin Adler <darin@apple.com>
+
+ * Scripts/commit-log-editor: Use baseProductDir() to find the base product directory.
+ This was still using "symroots" so it almost never worked!
+
+2006-10-21 Darin Adler <darin@apple.com>
+
+ * Makefile: Build DumpRenderTree too.
+ * Scripts/do-webcore-rename: Removed bogus comment.
+
+2006-10-20 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Tim H.
+
+ Bug 11367: Inline Breakpoint Editor Improvements: Act III
+ http://bugs.webkit.org/show_bug.cgi?id=11367
+
+ Major breakpoint editor changes:
+ * Breakpoints can now either pause or log to console
+ * Code cleanup through use of XPath and converting breakpoints to objects
+ * Breakpoints now track how many times they've been reached
+ * UI tweaks
+ * The breakpoint editor now saves changes as they're entered
+ * Because changes are auto-saved now, the save button has been converted to a close button (images from PSMTabBarControl, BSD licensed)
+ * If an expression with no return is entered as a condition, it will be wrapped transparently with a return statement.
+
+ * Drosera/DebuggerDocument.m:
+ (-[WebScriptObject breakpointEditorHTML]): A way of loading this from an external file, as it was getting too complex to include inline.
+ * Drosera/Drosera.xcodeproj/project.pbxproj:
+ * Drosera/Images/close.tif: Added.
+ * Drosera/Images/close_active.tif: Added.
+ * Drosera/Images/close_hover.tif: Added.
+ * Drosera/breakpointEditor.html: Added.
+ * Drosera/console.js: Added a way to append messages from outside the console window.
+ * Drosera/debugger.js:
+ * Drosera/viewer.css:
+ * Drosera/viewer.html:
+
+2006-10-18 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Tim H.
+
+ Improve the doubleclick behavior of breakpoints, and make breakpoints with no custom condition set appear blank instead of return [-1, 1] depending on enabled state.
+
+ * Drosera/DebuggerDocument.m:
+ (-[WebScriptObject getDoubleClickMillis]): Add an ObjC wrapper for GetDblTime() so that JS can call it
+ * Drosera/Drosera.xcodeproj/project.pbxproj: link Carbon for GetDblTime()
+ * Drosera/debugger.js:
+
+2006-10-18 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Anders.
+
+ Bug 10851: Crash with Drosera
+ http://bugs.webkit.org/show_bug.cgi?id=10851
+
+ This crash results in an assert in debug builds.
+
+ assert(implementsCall());
+
+ The __drosera_introspection propery was not callable. Now we just assign
+ this.__drosera_introspection in the evaluateWebScript call.
+ This change also removes one DO message.
+
+ * Drosera/DebuggerDocument.m:
+ (-[WebScriptObject webScriptAttributeKeysForScriptObject:]):
+
+2006-10-18 Mark Rowe <bdash@webkit.org>
+
+ Reviewed by Tim H.
+
+ http://bugs.webkit.org/show_bug.cgi?id=11304
+ Bug 11304: Drosera fails to link as universal binary on PowerPC machine
+
+ * Drosera/Drosera.xcodeproj/project.pbxproj: Use -weak_framework to link against JavaScriptCore and WebCore directly
+ when they are not part of the WebKit umbrella framework.
+
+2006-10-18 Adam Roben <aroben@apple.com>
+
+ fixo el buildo II: Release's Pride.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2006-10-18 Geoffrey Garen <ggaren@apple.com>
+
+ fixo el buildo.
+
+ Work around #import of <PDFKit/PDFView.h>.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2006-10-18 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Tim H.
+
+ Add Xcode 3 style inline breakpoint editor. Credit to xenon for the CSS wizardry to get the appearance working properly.
+
+ * Drosera/Drosera.xcodeproj/project.pbxproj:
+ * Drosera/Images/breakpointeditor.png: Added.
+ * Drosera/breakpointEditor.css: Removed.
+ * Drosera/breakpointEditor.html: Removed.
+ * Drosera/breakpointEditor.js: Removed.
+ * Drosera/debugger.js:
+ * Drosera/viewer.css:
+
+2006-10-18 David Harrison <harrison@apple.com>
+
+ Reviewed by Tim H.
+
+ Bug 11341: REGRESSION (r16760): editing/selection/editable-links is failing
+ http://bugs.webkit.org/show_bug.cgi?id=11341
+
+ Link editing behavior became a preference. DumpRenderTree needs to specify the
+ non-default behavior it wants (WebKitEditableLinkOnlyLiveWithShiftKey).
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main):
+
+2006-10-15 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+
+ Reviewed by Anders.
+
+ Make compiler not complain about unused gk. SpinneretWebHost was not setting
+ initial refcount upon creation, so it is completely bogus.
+
+ * GdkLauncher/main.cpp:
+ (main):
+ * Spinneret/Spinneret/Spinneret.h:
+ (SpinneretWebHost::SpinneretWebHost):
+
+2006-10-15 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Oliver.
+
+ Add another hanging test, to the "to be skipped" list.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/tests-skipped.txt:
+
+2006-10-14 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Anders.
+
+ Some fixes to get the Qt BuildSlave to run the LayoutTests.
+
+ * Scripts/build-dumprendertree: No need to call cmake again.
+ * Scripts/run-webkit-tests: Expose LD_LIBRARY_PATH.
+
+2006-10-13 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Eric.
+
+ Force --no-http on Qt/Linux.
+
+ * Scripts/run-webkit-tests:
+
+2006-10-13 Kevin McCullough <KMcCullough@apple.com>
+
+ Reviewed by Adam.
+
+ Gets JavaScripCore tests running on windows.
+
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/webkitdirs.pm:
+
+2006-10-12 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Maciej.
+
+ Exclude some tests which crash or hang from Qt/Linux DRT.
+ These are known to fail, and will be fixed at some point :-)
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::readStdin):
+ (WebCore::DumpRenderTree::readSkipFile):
+ (WebCore::DumpRenderTree::checkLoaded):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/tests-skipped.txt: Added.
+
+2006-10-12 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Maciej.
+
+ Specialization of alert() for DumpRenderTree - just log the output, don't show any message box.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTreeClient.cpp:
+ (WebCore::DumpRenderTreeClient::runJavaScriptAlert):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTreeClient.h:
+
+2006-10-12 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+
+ Reviewed by Maciej.
+
+ Also regenerate GdkLauncher makefiles, since not doing that might
+ lead to mismatch between WebCore and GdkLauncher compiler settings.
+
+ * Scripts/regenerate-makefiles:
+
+2006-10-10 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Tim H.
+
+ Bug 11246: Minor Drosera code cleanup
+ http://bugs.webkit.org/show_bug.cgi?id=11246
+
+ * Drosera/debugger.js: Change [has, add, remove]StyleClass to be a function on Element rather than taking an Element as an argument.
+
+2006-10-10 Vladimir Olexa <vladimir.olexa@gmail.com>
+
+ Reviewed by Tim H.
+
+ Bug 9778: http://bugs.webkit.org/show_bug.cgi?id=9778
+
+ * Drosera/Drosera.xcodeproj/project.pbxproj: Added files
+ * Drosera/English.lproj/Debugger.nib/info.nib: Resized the main window and WebView
+ * Drosera/English.lproj/Debugger.nib/keyedobjects.nib: Resized the main window and WebView
+ * Drosera/Images/SourceArrowOpen.png: Added.
+ * Drosera/Images/fileIcon.jpg: Added.
+ * Drosera/Images/siteCollapsed.tif: Added.
+ * Drosera/Images/siteExpanded.tif: Added.
+ * Drosera/Images/siteIcon.tif: Added.
+ * Drosera/debugger.css: Added File Browser styles
+ * Drosera/debugger.html: Added File Browser UI
+ * Drosera/debugger.js: Added File Browser functionality
+
+2006-10-10 Darin Adler <darin@apple.com>
+
+ * Scripts/do-file-rename: Added.
+
+2006-10-09 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+
+ Reviewed by Geoff.
+
+ Add -exit-after-loading option to make gdklauncher quit after fully loading and rendering
+ a page. This allows automatic testing via e.g. valgrind.
+
+ * GdkLauncher/gdklauncher.bkl:
+ * GdkLauncher/main.cpp:
+ (LauncherFrameGdk::LauncherFrameGdk):
+ (LauncherFrameGdk::setExitAfterLoading):
+ (LauncherFrameGdk::handledOnloadEvents):
+ (handle_event):
+ (main):
+
+2006-10-06 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Timothy.
+
+ Bug 9665: [Drosera] Conditional breakpoints. http://bugs.webkit.org/show_bug.cgi?id=9665
+
+ * Drosera/Drosera.xcodeproj/project.pbxproj: Added new files
+ * Drosera/breakpointEditor.css: Added.
+ * Drosera/breakpointEditor.html: Added.
+ * Drosera/breakpointEditor.js: Added.
+ * Drosera/debugger.js: Added conditional breakpoint support, and the ability to open the breakpoint editor window on option-clicking a breakpoint.
+
+2006-10-06 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Tim H.
+
+ Fix Qt/Linux build by adapting the s/ScrollBar/Scrollbar/ changes.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2006-10-05 Oliver Hunt <ohunt@apple.com>
+
+ Reviewed by Anders.
+
+ * Scripts/run-webkit-tests:
+ Fix pixel tests.
+
+2006-10-04 Anders Carlsson <acarlsson@apple.com>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/run-webkit-tests:
+ Add an environment variable, WebKitExpectedTestResultsDirectory, which controls where expected test
+ results should be.
+
+2006-10-05 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed and landed by ap.
+
+ Cmake: make it possible to install the libraries after having built using 'build-webkit'.
+ Just set the "WebKitInstallationPrefix" environment variable to your desired prefix.
+
+ * Scripts/webkitdirs.pm:
+
+2006-10-04 Mark Rowe <bdash@webkit.org>
+
+ Reviewed by Stephanie.
+
+ Switch the Qt buildbot to the standard set of build steps.
+ Have JavaScriptCoreTest check the output of run-javascriptcore-tests to
+ see if any regressions were spotted, and fail the test if so.
+
+ * BuildSlaveSupport/build.webkit.org-config/webkit/builders.py:
+ * BuildSlaveSupport/build.webkit.org-config/webkit/factories.py:
+ * BuildSlaveSupport/build.webkit.org-config/webkit/steps.py:
+
+2006-10-04 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Mitz Pettel!
+
+ Bug 10708: [Drosera] Make the console input plaintext-only
+ http://bugs.webkit.org/show_bug.cgi?id=10708
+
+ Change the console input -webkit-user-modify property to
+ read-write-plaintext-only.
+
+ * Drosera/console.css:
+
+2006-10-04 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Tim H.
+
+ Bug 10473: [Drosera] Overlapping text in JavaScript Console
+ http://bugs.webkit.org/show_bug.cgi?id=10473
+
+ Using min-height instead of height to avoid overlapping text.
+
+ * Drosera/console.css:
+
+2006-10-04 David Smith <catfish.man@gmail.com>
+
+ Reviewed by Tim H.
+
+ Added a bash-style command history.
+
+ * Drosera/console.js:
+
+2006-10-03 Anders Carlsson <acarlsson@apple.com>
+
+ Reviewed by Adam and Brady.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main):
+ Update URL to Ahem.ttf
+
+2006-10-03 Darin Adler <darin@apple.com>
+
+ * Scripts/commit-log-editor: Added missing "close" call. Oops!
+
+2006-10-03 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by eseidel. Landed by eseidel.
+
+ Offer a way for BuildBot to not colorize the cmake output, when building
+ with the 'build-webkit' script. Add "--color" / "--no-color" option pair.
+
+ Default is colorize output, though only Qt platform handles this for now.
+
+ * Scripts/build-dumprendertree:
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2006-10-03 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by eseidel. Landed by eseidel.
+
+ Make all important scripts work with Qt/Linux.
+
+ You can safely use this now:
+ set-configuration-release --debug && build-webkit && run-javascriptcore-tests && run-webkit-tests
+
+ * Scripts/build-dumprendertree:
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2006-10-03 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Eric.
+
+ build-webkit tweak: Use WebKitBuild/$config as output dir (Release/Debug).
+
+ * Scripts/webkitdirs.pm:
+
+2006-10-02 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed/landed by Adam.
+
+ Proper build-webkit support for Qt/Linux.
+
+ Compilation process is similar to OSX now, aka.
+ the build directory is RootCheckoutDir/WebKitBuild now.
+
+ * Scripts/build-webkit: Recognize Qt.
+ * Scripts/webkitdirs.pm: Add buildCMakeProject() logic.
+
+2006-10-01 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Maciej.
+
+ Add QT build slave to Buildbot.
+
+ * BuildSlaveSupport/build.webkit.org-config/webkit/builders.py: Add QT build slave, fix existing errors.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/factories.py: Add QT build factory.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/status.py: Disable forcing of builds via web interface to prevent spamming. Use the IRC bot in #webkit-build instead.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/steps.py: Add CMake build step.
+
+2006-09-28 David Harrison <harrison@apple.com>
+
+ Suggested by Darin Adler.
+
+ Moved an extern declaration from inside a method to the top of the file.
+
+ * DumpRenderTree/EventSendingController.m:
+ (-[EventSendingController clearKillRing]):
+
+2006-09-28 David Harrison <harrison@apple.com>
+
+ Reviewed by Justin.
+
+ Add clearKillRing so we can test emacs support with empty kill ring.
+
+ * DumpRenderTree/EventSendingController.m:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (+[EventSendingController webScriptNameForSelector:]):
+ (-[EventSendingController clearKillRing]):
+
+2006-09-27 MorganL <morganl.webkit@yahoo.com>
+
+ Reviewed by Maciej, landed by Brady
+
+ Fix URL bar updating.
+
+ * Spinneret/Spinneret/Spinneret.h:
+ (SpinneretWebHost::didStartProvisionalLoadForFrame):
+ (SpinneretWebHost::didCommitLoadForFrame):
+ (SpinneretWebHost::didFinishLoadForFrame):
+
+2006-09-23 Sam Weinig <sam.weinig@gmail.com>
+
+ Reviewed by Eric.
+
+ Build Fix.
+
+ * DumpRenderTree/EventSendingController.m:
+ (-[EventSendingController enableDOMUIEventLogging:]):
+
+2006-09-22 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by darin
+
+ * Scripts/do-webcore-rename:
+
+2006-09-21 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Adam.
+
+ Bug 10923: Frame scroll layout test failures on the buildbot
+ http://bugs.webkit.org/show_bug.cgi?id=10923
+
+ Added a new method that will toggle on the recursive dump of
+ child frame scroll positions.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dumpFrameScrollPosition):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController dumpChildFrameScrollPositions]):
+
+2006-09-19 Krzysztof Kowalczyk <kkowalczyk@gmail.com>
+
+ Reviewed by eseidel. Landed by eseidel.
+
+ Detect that close button was pressed and exit cleanly.
+
+ * GdkLauncher/main.cpp:
+ (handle_event):
+ (main):
+
+2006-09-17 Adam Roben <aroben@apple.com>
+
+ Reviewed by hyatt, sfalken.
+
+ Get DumpRenderTree compiling and limping along on Windows.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (loadResourceIntoArray): Added this function that WebCore::ImageWin needs from WebKit
+ (main): Add NULL argument to Page constructor.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.vcproj: Remove incorrect "wininet.dll" argument to CC, fix JavaScriptCore.lib path, add *_SECURE_NO_DEPRECATE #defines
+ * Scripts/webkitdirs.pm: Fix JavaScriptCore.lib path
+
+2006-09-15 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Brady.
+
+ http://bugs.webkit.org/show_bug.cgi?id=10635
+ Bug 10635: Buildbot configuration in SVN is out of sync with build.webkit.org
+
+ * BuildSlaveSupport/build.webkit.org-config/webkit/builders.py: Reorder build slaves within build factories in an attempt to spread the load evenly.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/status.py: Return to sending status emails to <svnuser>@opensource.apple.com addresses.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/steps.py: Update configuration to match changes in Buildbot. Always do clean SVG builds.
+
+2006-09-09 Sam Weinig <sam.weinig@gmail.com>
+
+ Reviewed by Eric.
+
+ Patch for http://bugs.webkit.org/show_bug.cgi?id=10791
+ Even More Objective-C DOM auto-generation cleanup
+
+ - Change to use new, more Objectice-C'ish version of
+ DOMKeyboardEvent's initKeyboardEvent. Fixes an error with
+ regression test for fast/events/dblclick-addEventListener.html.
+
+ * DumpRenderTree/EventSendingController.m:
+ (-[EventSendingController fireKeyboardEventsToElement:]):
+
+2006-09-04 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Tim H.
+
+ Fixes last part of: http://bugs.webkit.org/show_bug.cgi?id=10644
+ Move QtLauncher down to WebKitQt.
+
+ * QtLauncher/CMakeLists.txt: Removed.
+ * QtLauncher/main.cpp: Removed.
+
+2006-09-04 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Darin Adler.
+
+ Fixes parts of: http://bugs.webkit.org/show_bug.cgi?id=10644
+ Adjust DumpRenderTree to the FrameQtClient changes.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/CMakeLists.txt:
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::~DumpRenderTree):
+ (WebCore::DumpRenderTree::frame):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h:
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTreeClient.cpp: Added.
+ (WebCore::DumpRenderTreeClient::DumpRenderTreeClient):
+ (WebCore::DumpRenderTreeClient::~DumpRenderTreeClient):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTreeClient.h: Added.
+
+2006-09-03 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: More renaming plans.
+
+2006-09-03 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Tim H.
+
+ http://bugs.webkit.org/show_bug.cgi?id=10693
+ Convert JavaScript arrays to AppleScript lists
+
+ * DumpRenderTree/AppleScriptController.m:
+ (convertAEDescToObject):
+ (-[AppleScriptController doJavaScript:]): Support printing AEDescLists.
+
+2006-08-31 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Prepare for another round of renaming.
+
+2006-08-29 Dan Waylonis <waylonis@google.com>
+
+ Reviewed by ggaren.
+
+ - Verification of exceptions thrown in a plugin. Test for bug 10114.
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/ObjCPlugin.m:
+ (+[ObjCPlugin isSelectorExcludedFromWebScript:]):
+ (+[ObjCPlugin webScriptNameForSelector:]):
+ (-[ObjCPlugin throwIfArgumentIsNotHello:]):
+
+2006-08-30 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Tim H.
+
+ Commit KDE related tweaks, to be able to
+ differentiate between a Qt-only or a KDE build.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/CMakeLists.txt: Add ksvg2/ includes.
+ * QtLauncher/CMakeLists.txt: Add ksvg2/ includes.
+
+2006-08-29 Darin Adler <darin@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ * Scripts/gdb-safari: Set DYLD_FRAMEWORK_PATH inside gdb instead of setting it in gdb's environment
+ to work around what seems to be a bug in some versions of gdb.
+
+2006-08-16 Tim Omernick <timo@apple.com>
+
+ Reviewed by John Sullivan.
+
+ Part of <rdar://problem/4481553> NetscapeMoviePlugIn example code scripting doesn't work in Firefox (4319)
+ <http://bugs.webkit.org/show_bug.cgi?id=4319>: NetscapeMoviePlugIn example code scripting doesn't work
+ in Firefox
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c:
+ (NPP_GetValue):
+ WebKit's NPP_GetValue() reference counting behavior has been changed to match Firefox. NPObject return values
+ are expected to be retained by the plug-in, and released by the caller.
+
+2006-08-28 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Tim Hatcher.
+
+ Fixes one chunk of: http://bugs.webkit.org/show_bug.cgi?id=10604
+
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::checkLoaded): Faster polling for isLoaded() in
+ Qt's DumpRenderTree.
+
+ * Scripts/run-webkit-tests:
+ Use -expected-qt.txt etc.. output in run-webkit-test if isQt().
+
+2006-08-28 Darin Adler <darin@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ * Scripts/build-drosera: Fix behavior when there are multiple options.
+
+2006-08-27 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Anders.
+
+ Drosera will be built when you type make.
+
+ * Drosera/Makefile: Added.
+ * Makefile: Added.
+ * Makefile.shared: Added.
+
+2006-08-27 Anders Carlsson <acarlsson@apple.com>
+
+ Forgot to add these.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/CMakeLists.txt: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp: Added.
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::~DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::readStdin):
+ (WebCore::DumpRenderTree::checkLoaded):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp: Added.
+ (main):
+
+2006-08-27 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Eric, landed by Anders.
+
+ Add DumpRenderTree support for Qt/Linux.
+
+ * DumpRenderTree/DumpRenderTree.qtproj/CMakeLists.txt: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.cpp: Added.
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::~DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::readStdin):
+ (WebCore::DumpRenderTree::checkLoaded):
+ * DumpRenderTree/DumpRenderTree.qtproj/DumpRenderTree.h: Added.
+ * DumpRenderTree/DumpRenderTree.qtproj/main.cpp: Added.
+ (main):
+ * Scripts/build-dumprendertree:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2006-08-24 Nikolas Zimmermann <zimmermann@kde.org>
+
+ Reviewed by Eric. Landed by rwlbuis.
+
+ Add QtLauncher (was testunity before), which provides a
+ standalone "browser" to test the Qt platform stuff.
+
+ * QtLauncher/CMakeLists.txt: Added.
+ * QtLauncher/main.cpp: Added.
+ (main):
+
+2006-08-22 Trey Matteson <trey@usa.net>
+
+ Reviewed by ggaren.
+
+ Added support for a new set of browser navigation tests. The main feature
+ is the ability for a test to queue up a set of future actions that will
+ happen after that first page is loaded. This is used to simulate a sequence
+ of user actions such as filling out forms, loading additional pages or
+ going back. In addition we can now dump out the state of the back/forward
+ list, and the scroll position is dumped if not at 0,0.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): Init new state
+ (compareHistoryItems): New utility to support sorting.
+ (dumpHistoryItem): Write out a WebHistoryItem and kids.
+ (dumpFrameScrollPosition): Write out the scroll position.
+ (dump): Optionally write b/f list or scroll position.
+ (-[WaitUntilDoneDelegate processWork:]): Perform queued work.
+ (-[WaitUntilDoneDelegate webView:locationChangeDone:forDataSource:]):
+ Kick off any queued actions. Fixed for the case of loads started in
+ a subframe instead of the root frame.
+ (-[WaitUntilDoneDelegate webView:didStartProvisionalLoadForFrame:]):
+ Grab the topmost frame that is being loaded. Do this as early as possible,
+ instead of in didCommitLoadForFrame.
+ (-[WaitUntilDoneDelegate webView:didCommitLoadForFrame:]):
+ Noting a load has started now happens in previous method.
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]): Boilerplate
+ (+[LayoutTestController webScriptNameForSelector:]): Boilerplate
+ (-[LayoutTestController notifyDone]): readyToDump var is subsumed by
+ topFrameLoading
+ (-[LayoutTestController dumpBackForwardList]): New impl, just set a bit.
+ (-[LayoutTestController _addWorkForTarget:selector:arg1:arg2:]):
+ Add new work to the queue.
+ (-[LayoutTestController _doLoad:target:]): Do a queued load.
+ (-[LayoutTestController _doBackOrForwardNav:]): Do a queued back/forward.
+ (-[LayoutTestController scheduleBackNav:]): Ways for scripts to queue actions
+ (-[LayoutTestController scheduleForwardNav:]):
+ (-[LayoutTestController scheduleReload]):
+ (-[LayoutTestController scheduleScript:]):
+ (-[LayoutTestController scheduleLoad:target:]):
+ (runTest): Clear new state for each test. Renamed from "dumpRenderTree"
+ since it's not one of the functions that does any dumping.
+
+2006-08-15 Jonas Witt <jonas.witt@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ - added a function to create a few DOMKeyboardEvents and dispatch
+ them to a specified HTML element
+ http://bugs.webkit.org/show_bug.cgi?id=9736
+
+ * DumpRenderTree/EventSendingController.m:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (+[EventSendingController webScriptNameForSelector:]):
+ (-[EventSendingController fireKeyboardEventsToElement:]):
+
+2006-08-15 Duncan Wilcox <duncan@mclink.it>
+
+ Reviewed and tweaked by Darin Adler.
+
+ - added DumpRenderTree support so editing delegate can be made to refuse edits
+ to enable tests for http://bugs.webkit.org/show_bug.cgi?id=10129
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]): Add setAcceptsEditing:
+ to the list of methods.
+ (+[LayoutTestController webScriptNameForSelector:]): Use the name setAcceptsEditing,
+ without the colon, for the JavaScript name.
+ (-[LayoutTestController setAcceptsEditing:]): Added. Calls through to the editing
+ delegate.
+ (dumpRenderTree): Set the acceptsEditing flag to YES before each test.
+
+ * DumpRenderTree/EditingDelegate.h: Added an "acceptsEditing" flag and getter and
+ setter methods to the class.
+ * DumpRenderTree/EditingDelegate.m:
+ (-[EditingDelegate init]): Initialize acceptsEditing to YES.
+ (-[EditingDelegate webView:shouldBeginEditingInDOMRange:]): Instead of always returning YES,
+ return the value of acceptsEditing.
+ (-[EditingDelegate webView:shouldEndEditingInDOMRange:]): Ditto.
+ (-[EditingDelegate webView:shouldInsertNode:replacingDOMRange:givenAction:]): Ditto.
+ (-[EditingDelegate webView:shouldInsertText:replacingDOMRange:givenAction:]): Ditto.
+ (-[EditingDelegate webView:shouldDeleteDOMRange:]): Ditto.
+ (-[EditingDelegate webView:shouldChangeSelectedDOMRange:toDOMRange:affinity:stillSelecting:]):
+ Ditto.
+ (-[EditingDelegate webView:shouldApplyStyle:toElementsInDOMRange:]): Ditto.
+ (-[EditingDelegate webView:shouldChangeTypingStyle:toStyle:]): Ditto.
+ (-[EditingDelegate setAcceptsEditing:]): Added.
+
+2006-08-03 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Darin Adler.
+
+ Bug 10224: [Drosera] Drosera icon should be set on DroseraLauncher so it appears in nightly builds
+ http://bugs.webkit.org/show_bug.cgi?id=10224
+
+ * Drosera/Drosera.xcodeproj/project.pbxproj:
+ * Drosera/LauncherInfo.plist:
+
+2006-08-03 Mitz Pettel <opendarwin.org@mitzpettel.com>
+
+ - fix ASSERTION FAILURE: draggingDocumentView == nil in -[WebViewPrivate dealloc]
+ when a test performs an unsuccessful drag and drop operation.
+
+ * DumpRenderTree/EventSendingController.m:
+ (-[EventSendingController mouseUp]): Added a call to -draggingExited: if the
+ drag operation for the mouse release is NSDragOperationNone.
+
+2006-08-02 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 9632: [Drosera] syntax highlighting is slow (reproducible 40 second hang)
+ http://bugs.webkit.org/show_bug.cgi?id=9632
+
+ Do not change the file source when normalizing the line endings.
+ We use this file source to compare against new versions of the source
+ as it comes in, so we can skip re-syntax highlighting if they are the same.
+ The problem is apparent on yahoo.com since they have mixed line endings and
+ once we normalize them the source will always be different. This was
+ compounded by the fact that yahoo has around 40 inline scripts. Each
+ inline script causes us to check if the main document has more loaded,
+ that is when we compare the source strings. Since they are always different
+ we would syntax highlight yahoo.com 40 times! We do check source length before
+ doing a more expensive string comparison, but the lengths were the same.
+
+ * Drosera/debugger.js:
+
+2006-08-02 Niels Leenheer <niels.leenheer@gmail.com>
+
+ Reviewed by Timothy.
+
+ Bug 9931: [Drosera] Needs a cool icon
+ http://bugs.webkit.org/show_bug.cgi?id=9931
+
+ * Drosera/Drosera.icns: Added.
+ * Drosera/Drosera.xcodeproj/project.pbxproj:
+ * Drosera/Info.plist:
+
+2006-08-01 Darin Adler <darin@apple.com>
+
+ - fix a bug in my recent change where the mouse position at the end of
+ the last test would affect the results of the next test
+
+ * DumpRenderTree/DumpRenderTree.m: (dumpRenderTree): Set lastMousePosition to 0.
+
+2006-07-31 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Maciej.
+
+ http://bugs.webkit.org/show_bug.cgi?id=10182
+ Bug 10182: [Drosera] Evaluating expressions in Console is slow when current frame has many variables
+
+ * Drosera/console.js: String.indexOf returns -1 when the string is not found.
+ Correct the logic to not reload local variable list unless an '=' character is in the expression.
+
+2006-07-31 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=10171
+ REGRESSION: failing layout test: fast/events/objc-event-api.html
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): Add pose so we can implement +[NSEvent mouseLocation]. Put the window at a predictable
+ location in flipped coordinates, since those are the coordinates that we use.
+ (+[DumpRenderTreeEvent mouseLocation]): Implement this, since it's used for mouse event handling
+ inside WebHTMLView.
+
+ * DumpRenderTree/EventSendingController.m:
+ (+[EventSendingController initialize]): Removed unused webkitDomEventProperties array.
+ (-[EventSendingController init]): Removed, since the whole thing was a no-op.
+ (-[EventSendingController mouseMoveToX:Y:]): Convert the x,y pair to window coordinates. The old code
+ probably worked OK, but this is needed to be correct.
+ (-[EventSendingController handleEvent:]): Put clientX/Y before screenX/Y and removed the flipping
+ code from screenY. We didn't really need to flip screenY -- what was actually happening was that the
+ position that DumpRenderTree chose was in non-flipped coordinates, and with that fixed we can just
+ dump the screenY as-is.
+
+2006-07-31 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=10178
+ Bug 10178: [Drosera] Selecting a frame in the stack list should take you to that location in the source
+
+ * Drosera/debugger.js: Keep a stack that contains the source file and line number references for outer
+ frames. Use this stack to determine which file and line to highlight when a stack frame is selected.
+
+2006-07-31 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=10175
+ Bug 10175: [Drosera] Anonymous functions show up as "(global scope)" in stack list
+
+ * Drosera/DebuggerDocument.m:
+ (-[WebScriptObject currentFunctionStack]): If the frame has a caller it isn't the global scope.
+
+2006-07-31 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=10167
+ Bug 10167: REGRESSION(r15688): ASSERTION FAILED: _private->mouseDownEvent != nil in layout tests
+
+ * DumpRenderTree/EventSendingController.m: Don't set the mouse down flag
+ in keyDown handler.
+
+2006-07-30 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Maciej.
+
+ Bug 9686: [Drosera] Need the ability to break into Drosera on Javascript exceptions
+ http://bugs.webkit.org/show_bug.cgi?id=9686
+
+ * Drosera/DebuggerDocument.m:
+ (-[WebScriptObject switchToServerNamed:]): Remove as listener before resuming to
+ ensure that the server does not try and notify us of events related to the resumption.
+ (-[WebScriptObject webView:exceptionWasRaised:sourceId:line:forWebFrame:]): Delegate
+ call through to JavaScript.
+ * Drosera/debugger.js: Pause debugger when exception is raised.
+
+2006-07-29 Mike Emmel <mike.emmel@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ - fixes for Linux build
+
+ * GdkLauncher/mk: Added call to bakefile_gen before calling make.
+ * GdkLauncher/gdklauncher.bkl: Tweak comment.
+
+2006-07-24 Dan Waylonis <waylonis@google.com>
+
+ Reviewed and tweaked a bit by Darin Adler.
+
+ * DumpRenderTree/ObjCPlugin.m:
+ (+[ObjCPlugin isSelectorExcludedFromWebScript:]): Added "echo:".
+ (+[ObjCPlugin webScriptNameForSelector:]): Use the name "echo" for
+ "echo:" so it's nice to call from JavaScript.
+ (-[ObjCPlugin echo:]): Just returns the same object -- can be used
+ to test a round trip through Objective-C types.
+
+2006-07-24 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ Fix http://bugs.webkit.org/show_bug.cgi?id=10060
+ Improve iExploder results parsing
+
+ * Scripts/run-iexploder-tests: Fix Apach logs parsing to produce a correct results
+ in random mode, too.
+
+2006-07-18 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by Timothy.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=9964
+ Add switch to prepare-ChangeLog to skip svn update of ChangeLog files
+
+ * Scripts/prepare-ChangeLog: Added --[no-]update switch.
+
+2006-07-16 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by Darin Adler.
+
+ * BuildSlaveSupport/build.webkit.org-config/buildbot.css:
+ Removed "No newline at end of file" that snuck in as part of the "apply patch" process.
+ * GdkLauncher/mk:
+ Removed "Property changes" that snuck in as part of the "apply patch" process.
+
+2006-07-16 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=9875
+ Teach svn-apply and svn-unapply to use patch(1) for additions and deletions
+
+ * Scripts/svn-apply:
+ (addDirectoriesIfNeeded): Don't try to add a directory that's already in svn.
+ (checksum): Added.
+ (patch): Use patch(1) for non-binary additions and deletions.
+ * Scripts/svn-unapply:
+ (checksum): Added.
+ (patch): Use patch(1) for reverting non-binary additions and deletions.
+ (revertDirectories): Don't try to revert a directory that hasn't changed in svn.
+
+2006-07-13 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Timothy.
+
+ Bug 9889: [Drosera] Stepping out when paused after last statement in function skips a frame
+ http://bugs.webkit.org/show_bug.cgi?id=9889
+
+ * Drosera/debugger.js: Track whether we paused during the execution of willLeaveFrame. If
+ so, have stepOut pause on the next call to willExecuteStatement rather than second.
+
+2006-07-12 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=9848
+ Teach svn-create-patch and friends to fix ChangeLog patches
+
+ * Scripts/svn-apply: Added fixChangeLogPatch() and invoked it in the proper place.
+ * Scripts/svn-create-patch: Ditto.
+ * Scripts/svn-unapply: Ditto.
+
+2006-07-12 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by ggaren.
+
+ Bug 9869: [Drosera] JS Console fails to evaluate input when paused in global scope
+ http://bugs.webkit.org/show_bug.cgi?id=9869
+
+ * Drosera/DebuggerDocument.m:
+ (-[WebScriptObject currentFunctionStack]): Include the global frame in the stack.
+
+2006-07-12 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by ggaren.
+
+ Bug 9863: Drosera needs to show something at launch
+ http://bugs.webkit.org/show_bug.cgi?id=9863
+
+ * Drosera/DebuggerApplication.m:
+ (-[DebuggerApplication applicationDidFinishLaunching:]): Show the attach window on launch.
+
+2006-07-12 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Timothy.
+
+ Lets Drosera build universal for the nightlies. Right now it is not
+ possible to build a universal binary on a PPC machine because of a
+ conflict with the universal SDK.
+
+ * BuildSlaveSupport/build-launcher-app:
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj:
+
+2006-07-11 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Tim O.
+
+ - test for http://bugs.webkit.org/show_bug.cgi?id=7808
+ Assertion failure in -[WebBaseNetscapePluginStream dealloc] when requesting an invalid URL
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (pluginInvoke): treat getURL() with one parameter as if the second parameter were NULL -
+ should open a new stream and deliver the data to the current instance.
+
+2006-07-11 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 9598: [Drosera] add a JavaScript evaluator console
+ http://bugs.webkit.org/show_bug.cgi?id=9598
+
+ * Drosera/DebuggerApplication.h:
+ * Drosera/DebuggerApplication.m:
+ (-[DebuggerApplication knownServers]):
+ * Drosera/DebuggerDocument.h:
+ * Drosera/DebuggerDocument.m:
+ (-[WebScriptObject evaluateScript:inCallFrame:]):
+ (-[WebScriptObject showConsole:]):
+ (-[WebScriptObject toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:]):
+ (-[WebScriptObject toolbarDefaultItemIdentifiers:]):
+ (-[WebScriptObject toolbarAllowedItemIdentifiers:]):
+ (-[WebScriptObject webView:createWebViewWithRequest:]):
+ (-[WebScriptObject webViewShow:]):
+ (-[WebScriptObject webViewAreToolbarsVisible:]):
+ (-[WebScriptObject webView:setToolbarsVisible:]):
+ (-[WebScriptObject webView:setResizable:]):
+ (-[WebScriptObject webView:runJavaScriptAlertPanelWithMessage:initiatedByFrame:]):
+ (-[WebScriptObject scriptConfirmSheetDidEnd:returnCode:contextInfo:]):
+ (-[WebScriptObject webView:runJavaScriptConfirmPanelWithMessage:initiatedByFrame:]):
+ (-[WebScriptObject webView:windowScriptObjectAvailable:]):
+ (-[WebScriptObject webView:didFinishLoadForFrame:]):
+ (-[WebScriptObject webView:didReceiveTitle:forFrame:]):
+ * Drosera/Drosera.xcodeproj/project.pbxproj:
+ * Drosera/Images/console.png: Added.
+ * Drosera/console.css: Added.
+ * Drosera/console.html: Added.
+ * Drosera/console.js: Added.
+
+2006-07-11 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by a tired Geoff.
+
+ Bug 9597: [Drosera] hook up the variables table to show stack variables
+ http://bugs.webkit.org/show_bug.cgi?id=9597
+
+ * Drosera/DebuggerDocument.m:
+ (-[WebScriptObject isSelectorExcludedFromWebScript:]):
+ (-[WebScriptObject webScriptAttributeKeysForScriptObject:]):
+ (-[WebScriptObject localScopeVariableNamesForCallFrame:]):
+ (-[WebScriptObject valueForScopeVariableNamed:inCallFrame:]):
+ (-[WebScriptObject webView:didReceiveTitle:forFrame:]):
+ (-[WebScriptObject webView:didLoadMainResourceForDataSource:]):
+ (-[WebScriptObject webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:]):
+ (-[WebScriptObject webView:didEnterCallFrame:sourceId:line:forWebFrame:]):
+ (-[WebScriptObject webView:willExecuteStatement:sourceId:line:forWebFrame:]):
+ (-[WebScriptObject webView:willLeaveCallFrame:sourceId:line:forWebFrame:]):
+ * Drosera/debugger.css:
+ * Drosera/debugger.html:
+ * Drosera/debugger.js:
+
+2006-07-10 Tim Omernick <timo@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ <http://bugs.webkit.org/show_bug.cgi?id=9844>:
+ Add DOM access test to DumpRenderTree's Netscape plug-in
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (testDOMAccess):
+ (pluginInvoke):
+
+2006-07-10 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=9839
+ Bug 9839: Nightly launcher fails to detect extensions when extension causes crash on load
+
+ Now track three states: initializing, running, and closed. If we are launched and the previous
+ state was initializing then we likely just experienced a crash on launch.
+
+ * WebKitLauncher/WebKitNightlyEnabler.m:
+ (myApplicationWillFinishLaunching): Improve wording of dialog. Update to set new running state.
+ (myApplicationWillTerminate): Update to use new states.
+ (cleanUpAfterOurselves): Display alert if previous state was initializing. Set state as
+ initializing as early as practical.
+ (symbol_lookup): Bring code up to speed with formatting guidelines.
+ (GDSymbolLookup): Ditto.
+
+2006-07-10 Darin Adler <darin@apple.com>
+
+ - try to fix Windows build
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.vcproj:
+ Remove include paths with "khtml" in them. Add one for "html" subdir or WebCore.
+
+2006-07-09 David Kilzer <ddkilzer@kilzer.net>
+
+ Build fix.
+
+ - Backed out http://bugs.webkit.org/show_bug.cgi?id=7802
+ devenv.com not available in VC++ Express installations
+
+ * Scripts/webkitdirs.pm: Backed out previous change.
+
+2006-07-09 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=9693
+ svn-apply should set ChangeLog date correctly when applying patches
+
+ * Scripts/svn-apply: Set the ChangeLog entry date using a configurable timezone
+ before applying the patch.
+ * Scripts/svn-unapply: Reset the ChangeLog entry date before unapplying the patch.
+
+2006-07-09 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Final version of this round of renaming for posterity.
+
+2006-07-09 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Next round of renaming. (Last round was done.)
+
+2006-07-09 David Kilzer <ddkilzer@kilzer.net>
+
+ - http://bugs.webkit.org/show_bug.cgi?id=7802
+ devenv.com not available in VC++ Express installations
+
+ * Scripts/webkitdirs.pm: Restore Hyatt's original logic to make buildbot
+ work again. Add VC++ Express check as the fallback.
+
+2006-07-09 Bjoern Graf <bjoern.graf@gmail.com>
+
+ Reviewed by Timothy Hatcher.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=7802
+ devenv.com not available in VC++ Express installations
+
+ * Scripts/webkitdirs.pm: Make Windows build work with Visual C++ Express.
+
+2006-07-09 Joost de Valk <jdevalk@opendarwin.org>
+
+ Reviewed by Eric.
+
+ Fixes bug http://bugs.webkit.org/show_bug.cgi?id=9804 .
+ Patch by coldwinter@katamail.com.
+
+ In the congratulations message, "capatibilies" should be "capabilities".
+
+ * Scripts/build-webkit:
+
+2006-07-09 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by Timothy Hatcher.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=9794
+ Teach run-webkit-tests how to ignore tests with performance improvements
+
+ * Scripts/run-webkit-tests: Speed up test list generation, implement --ignore-tests
+ feature, and minor clean up.
+
+2006-07-08 Darin Adler <darin@apple.com>
+
+ Reviewed by Geoff (well, half of it at least).
+
+ - http://bugs.webkit.org/show_bug.cgi?id=9788
+ storage leaks in Objective-C tests
+
+ * DumpRenderTree/DumpRenderTree.m: (-[LayoutTestController keepWebHistory]):
+ * DumpRenderTree/ObjCPlugin.m: (-[ObjCPlugin removeBridgeRestrictions:]):
+ Add a release to fix a storage leak.
+
+2006-07-08 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: A few more.
+
+2006-07-08 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Another cut at renames. About ready to go (later today).
+
+2006-07-04 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=9734
+ - add support for dumping non-HTML as text - in this case use textContent
+ instead of innerText
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dump):
+
+2006-07-02 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Eric.
+
+ Bug 9631: [Drosera] Add "Step Over" and "Step Out"
+ http://bugs.webkit.org/show_bug.cgi?id=9631
+
+ Adds step over and step out. Along with a little code cleanup
+ that was minor enough to piggyback on this fix.
+
+ * Drosera/DebuggerDocument.h:
+ * Drosera/DebuggerDocument.m:
+ (-[DebuggerDocument stepOver:]):
+ (-[DebuggerDocument stepOut:]):
+ (-[DebuggerDocument windowDidLoad]):
+ (-[DebuggerDocument windowWillClose:]):
+ (-[DebuggerDocument toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:]):
+ (-[DebuggerDocument toolbarDefaultItemIdentifiers:]):
+ (-[DebuggerDocument toolbarAllowedItemIdentifiers:]):
+ (-[DebuggerDocument validateUserInterfaceItem:]):
+ * Drosera/Drosera.xcodeproj/project.pbxproj:
+ * Drosera/debugger.html:
+ * Drosera/debugger.js:
+ * Drosera/viewer.css:
+
+2006-07-02 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Eric.
+
+ Bug 9628: [Drosera] Split Views acting oddly
+ http://bugs.webkit.org/show_bug.cgi?id=9628
+
+ Only update the last X or Y coordinate if the new
+ size was not constrained. Also adds the resize cursor to
+ the body during the drag incase there is a constrained
+ over drag off of the resizer element.
+
+ * Drosera/debugger.js:
+
+2006-07-02 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Bug 9692: Warning about Safari extensions on every launch is obnoxious
+ http://bugs.webkit.org/show_bug.cgi?id=9692
+
+ * WebKitLauncher/WebKitNightlyEnabler.m:
+ (myApplicationWillTerminate): Note that we are exiting cleanly.
+ (cleanUpAfterOurselves): Install bundle load tracking only if we failed
+ to exit cleanly on our last invocation. This doesn't play nicely with
+ multiple concurrent instances of WebKit.app so it can be disabled via
+ defaults write com.apple.Safari WKNEShouldMonitorShutdowns -bool NO.
+
+2006-07-02 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Bug 9654: Refresh Loop when accessing feed URLs
+ http://bugs.webkit.org/show_bug.cgi?id=9654
+
+ * WebKitLauncher/Info.plist: Don't claim to handle feed:// URLs.
+
+2006-07-02 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Timothy Hatcher.
+
+ Bug 9689: Nightly builds should warn a user about potential problems when using
+ "Safari extensions"
+ http://bugs.webkit.org/show_bug.cgi?id=9689
+
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj:
+ * WebKitLauncher/WebKitNightlyEnabler.m:
+ (myBundleDidLoad): Keep track of if any bundles that are loaded.
+ (myApplicationWillFinishLaunching): Notify user if any bundles are loaded.
+ (cleanUpAfterOurselves): Register for NSBundleDidLoadNotification and
+ NSApplicationWillFinishLaunchingNotification notifications so that we can
+ track bundle loads and notify the user at launch completion.
+
+2006-06-30 Mike Emmel <mike.emmel@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ - first check-in of a Gdk shell for testing WebKit
+
+ * GdkLauncher: Added.
+
+2006-06-29 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Need to call window close so WebView tears-down completly.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): call [window close]
+
+2006-06-29 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Darin Adler.
+
+ Bug 9615: Buildbot configuration should be in SVN repository
+ http://bugs.webkit.org/show_bug.cgi?id=9615
+
+ Import BuildBot configuration files as used by build.webkit.org.
+ auth.py has been stubbed out so that slave passwords are not disclosed.
+
+ * BuildSlaveSupport/build.webkit.org-config/Makefile: Added.
+ * BuildSlaveSupport/build.webkit.org-config/buildbot.css: Added.
+ * BuildSlaveSupport/build.webkit.org-config/buildbot.tac: Added.
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: Added.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/__init__.py: Added.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/auth.py: Added.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/basesteps.py: Added.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/builders.py: Added.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/factories.py: Added.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/schedulers.py: Added.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/status.py: Added.
+ * BuildSlaveSupport/build.webkit.org-config/webkit/steps.py: Added.
+
+2006-06-29 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Darin Adler.
+
+ Bug 9614: Nightly builds should notify user if a newer build is available
+ http://bugs.webkit.org/show_bug.cgi?id=9614
+
+ * BuildSlaveSupport/build-launcher-app: Write revision number to WebKit.app's VERSION file.
+ * BuildSlaveSupport/build-launcher-dmg: Pass revision number to server-side nightly maintenance
+ script so it can keep track of the latest revision.
+ * Scripts/run-webkit-tests: Pass build-dumprendertree's exit status through correctly.
+ * WebKitLauncher/VERSION: Added. Placeholder for SVN revision number
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj:
+ * WebKitLauncher/start.html: Retrieve revision number from VERSION file, and pass it through to
+ the nightly start page.
+
+2006-06-26 Jonas Witt <jonas.witt@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 9579: LayoutTests/fast/events/objc-event-api.html failing due to screenY output
+ http://bugs.webkit.org/show_bug.cgi?id=9579
+
+ Report screenY values as (height of zero screen - screenY)
+
+ * DumpRenderTree/EventSendingController.m: (-[EventSendingController handleEvent:]):
+
+2006-06-25 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Geoff.
+
+ Bug 9591: [Drosera] breakpoints should be dragable and deletable by dragging off the gutter
+ http://bugs.webkit.org/show_bug.cgi?id=9591
+
+ Makes breakpoints dragable. If dragged off the gutter they are deleted.
+
+ * Drosera/debugger.js:
+ * Drosera/viewer.css:
+
+2006-06-25 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 9568: assertion failure in Safari after quitting Drosera
+ http://bugs.webkit.org/show_bug.cgi?id=9568
+
+ Call switchToServerNamed:nil and not removeLister to make sure
+ the server object is set to nil to prevent further removeListener calls.
+
+ * Drosera/DebuggerDocument.m:
+ (-[DebuggerDocument applicationTerminating:]):
+
+2006-06-25 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/svn-apply: Speed up isDirectoryEmptyForRemoval() by returning as soon as we find
+ that the directory is not empty instead of reading in every single file and directory first,
+ then checking the count. Avoid warning in removeDirectoriesIfNeeded() if $svnOutput is not
+ defined.
+
+2006-06-25 Darin Adler <darin@apple.com>
+
+ * Scripts/svn-apply: Tweak comments.
+ * Scripts/svn-create-patch: Ditto.
+ * Scripts/svn-unapply: Ditto.
+
+2006-06-25 David Kilzer <ddkilzer@kilzer.net>
+
+ Formatting fix per Bug 9571 Comment #2.
+
+ http://bugs.webkit.org/show_bug.cgi?id=9571#c2
+
+ * Scripts/svn-apply: Formatting fix.
+
+2006-06-25 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=9571
+ Teach svn-apply and svn-unapply to handle directory adds and removes better
+
+ * Scripts/svn-apply: Handle directory adds more intelligently. Handle directory removes.
+ * Scripts/svn-unapply: Handle undoing both directory adds and removes.
+
+2006-06-25 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 9574: Drosera should show inline scripts within the original HTML
+ http://bugs.webkit.org/show_bug.cgi?id=9574
+
+ Refactor the JavaScript code to have a distinction between files
+ and scripts. Show the script in the context of the HTML file if
+ it's URL is the same as the frame's main resource. At the time of
+ the disParseScript callback the main resource might not be completely
+ loaded, but Drosera needs to show whatever we have at the time. Once
+ the main resource is finished, update the file source and reload the file.
+
+ * Drosera/DebuggerDocument.m:
+ (-[DebuggerDocument pause]):
+ (-[DebuggerDocument webView:didLoadMainResourceForDataSource:]):
+ (-[DebuggerDocument webView:didParseSource:baseLineNumber:fromURL:sourceId:forWebFrame:]):
+ (-[DebuggerDocument webView:failedToParseSource:baseLineNumber:fromURL:withError:forWebFrame:]):
+ * Drosera/debugger.css:
+ * Drosera/debugger.js:
+
+2006-06-24 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=9570
+ Teach prepare-ChangeLog to operate on a list of files or directories
+
+ * Scripts/prepare-ChangeLog: Accept a list of files and/or directories when running.
+ * Scripts/svn-create-patch: Code refactoring.
+
+2006-06-24 James G. Speth <speth@end.com>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=8843
+ add a way to build Objective-C test cases in HTML
+
+ Tests running in DumpRenderTree can choose to relax some restrictions of the JavaScript/Objective-C bridge
+ allowing more extensive testing of the Obj-C API. (and by more extensive, I mean this lets scripts do
+ pretty much whatever they want, including acting as delegates, generating events, instantiating obj-c
+ objects, etc... )
+
+ * DumpRenderTree/ObjCPlugin.h:
+ * DumpRenderTree/ObjCPlugin.m: this ability is only exposed to scripts running in DumpRenderTree
+ (+[ObjCPlugin isSelectorExcludedFromWebScript:]):
+ (+[ObjCPlugin webScriptNameForSelector:]):
+ (-[ObjCPlugin removeBridgeRestrictions:]): scripts call this to open up obj-c for extensive testing
+ (+[NSObject setAllowsScriptsFullAccess:]): makes NSObject allow all selectors to be invoked from script
+ (+[NSObject allowsScriptsFullAccess]):
+ (+[NSObject isSelectorExcludedFromWebScript:]): when full access is enabled, no selector is excluded
+ (+[NSObject webScriptNameForSelector:]): always return nil for the default selector mutation
+ (-[JSObjC classNameOfObject:isSelectorExcludedFromWebScript:]):
+ (+[JSObjC webScriptNameForSelector:]):
+ (-[JSObjC invokeDefaultMethodWithArguments:]): shortcut for accessing classes
+ (-[JSObjC lookUpClass:]): allow scripts to retrieve obj-c classes by name
+ (-[JSObjC log:]): access to NSLog function
+ (-[JSObjC retainObject:]): useful obj-c functions that are otherwise hard to reach from javascript
+ (-[JSObjC classOfObject:]):
+ (-[JSObjC classNameOfObject:]):
+
+2006-06-24 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by Timothy.
+
+ * DrawTest/Info.plist: Added copyright statement.
+ * Drosera/Info.plist: Ditto.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/Info.plist: Ditto.
+ * WebKitLauncher/Info.plist: Ditto.
+
+2006-06-24 David Kilzer <ddkilzer@kilzer.net>
+
+ Build fix.
+
+ - Backed out http://bugs.webkit.org/show_bug.cgi?id=7802
+ devenv.com not available in VC++ Express installations
+
+ * Scripts/webkitdirs.pm: Backed out previous change.
+
+2006-06-24 Bjoern Graf <bjoern.graf@gmail.com>
+
+ Reviewed by Maciej.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=7802
+ devenv.com not available in VC++ Express installations
+
+ * Scripts/webkitdirs.pm: Make Windows build work with Visual C++ Express.
+
+2006-06-24 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=9564
+ A bunch of fixes to run-webkit-httpd
+
+ - Add an -all-interfaces (-a) flag to bind to all interfaces, not just
+ 127.0.0.1. Useful for testing with WinIE running on another machine;
+ - don't call checkFrameworks() - we do not need a built WebKit here;
+ - changed tabs to spaces;
+ - disable HTTP keepalive (since Apache doesn't spawn sub-processes in
+ interactive mode, they were a hassle when testing with several browsers, as one
+ had to wait for connection to expire);
+ - remove httpd.pid when done, so that Apache doesn't complain next time.
+
+ * Scripts/run-webkit-httpd:
+
+2006-06-24 Jonas Witt <jonas.witt@gmail.com>
+
+ Reviewed by ggaren, landed by ap.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=9181
+ Complete DOMUIEvent Obj-C API to reflect UIEvent
+
+ Add function to enable logging of all events of one DOM node to stdout.
+
+ * DumpRenderTree/EventSendingController.h:
+ * DumpRenderTree/EventSendingController.m:
+ (+[EventSendingController initialize]):
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (+[EventSendingController webScriptNameForSelector:]):
+ (-[EventSendingController enableDOMUIEventLogging:]):
+ (-[EventSendingController handleEvent:]):
+
+2006-06-23 Kevin Decker <kdecker@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ - Made column headers in Drosera resizable.
+
+2006-06-22 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by ggaren.
+
+ - see http://bugs.webkit.org/show_bug.cgi?id=9539
+ Another case error preventing build
+
+ * Scripts/webkitdirs.pm: Building WebKit now requires Xcode 2.3.
+
+2006-06-22 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Eric.
+
+ Adds a native toolbar to Drosera to be a good citizen.
+ Adds a Debug menu with key-commands for Continue, Pause and Step Into.
+ Fixes a dragging bug from an earlier fix to the divider code.
+ Fixes some poor indenting in debugger.js.
+
+ * Drosera/DebuggerDocument.h:
+ * Drosera/DebuggerDocument.m:
+ (-[DebuggerDocument stepInto]):
+ (-[DebuggerDocument pause:]):
+ (-[DebuggerDocument resume:]):
+ (-[DebuggerDocument stepInto:]):
+ (-[DebuggerDocument windowDidLoad]):
+ (-[DebuggerDocument toolbar:itemForItemIdentifier:willBeInsertedIntoToolbar:]):
+ (-[DebuggerDocument toolbarDefaultItemIdentifiers:]):
+ (-[DebuggerDocument toolbarAllowedItemIdentifiers:]):
+ (-[DebuggerDocument validateUserInterfaceItem:]):
+ * Drosera/English.lproj/MainMenu.nib/classes.nib:
+ * Drosera/English.lproj/MainMenu.nib/info.nib:
+ * Drosera/English.lproj/MainMenu.nib/keyedobjects.nib:
+ * Drosera/debugger.css:
+ * Drosera/debugger.html:
+ * Drosera/debugger.js:
+ * Drosera/viewer.html:
+
+2006-06-22 Kevin Decker <kdecker@apple.com>
+
+ Reviewed by Anders.
+
+ - Added pressed column header image.
+ - Made column headers behave more like Xcode.
+
+2006-06-22 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Kevin Decker.
+
+ Code clean up. Adds the stackframe and makes only the body
+ of the tables scrollable keeping the header visible.
+ Shows the current function stack when paused or stepping.
+
+ * Drosera/DebuggerApplication.m:
+ (-[DebuggerApplication awakeFromNib]):
+ (-[DebuggerApplication numberOfRowsInTableView:]):
+ (-[DebuggerApplication tableView:objectValueForTableColumn:row:]):
+ * Drosera/DebuggerDocument.h:
+ * Drosera/DebuggerDocument.m:
+ (-[DebuggerDocument dealloc]):
+ (-[DebuggerDocument currentFrame]):
+ (-[DebuggerDocument currentFrameFunctionName]):
+ (-[DebuggerDocument currentFunctionStack]):
+ (-[DebuggerDocument log:]):
+ (-[DebuggerDocument windowWillClose:]):
+ (-[DebuggerDocument webView:didEnterCallFrame:sourceId:line:forWebFrame:]):
+ (-[DebuggerDocument webView:willLeaveCallFrame:sourceId:line:forWebFrame:]):
+ * Drosera/Drosera.xcodeproj/project.pbxproj:
+ * Drosera/debugger.css:
+ * Drosera/debugger.html:
+ * Drosera/debugger.js:
+
+2006-06-22 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Anders.
+
+ Teach run-webkit-httpd to properly look for webkitdirs.pm.
+
+ * Scripts/run-webkit-httpd:
+
+2006-06-22 Kevin Decker <kdecker@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ - More progress toward Javascript Debugger.
+ - Added some new images to the project.
+
+2006-06-21 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Anders.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=9516
+ Would like a script to run a httpd server with the same configuration as run-webkit-tests http
+
+ * Scripts/run-webkit-httpd: Added.
+
+2006-06-20 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Eric.
+
+ Builds Drosera and a launcher to include with the nightly.
+
+ * BuildSlaveSupport/build-launcher-app:
+ * BuildSlaveSupport/build-launcher-dmg:
+ * Drosera/Drosera.xcodeproj/project.pbxproj:
+ * Drosera/Info.plist:
+ * Drosera/LauncherInfo.plist: Added.
+ * Drosera/launcher.m: Added.
+ (displayErrorAndQuit):
+ (checkMacOSXVersion):
+ (myExecve):
+ (main):
+ * Scripts/build-drosera
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj:
+ * WebKitLauncher/main.m:
+ (main):
+
+2006-06-20 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Adds a JavaScript debugger, called Drosera. Named after
+ a genus of bug eating plants.
+
+ * Drosera/DebuggerApplication.h: Added.
+ * Drosera/DebuggerApplication.m: Added.
+ (-[DebuggerApplication applicationDidFinishLaunching:]):
+ (-[DebuggerApplication serverLoaded:]):
+ (-[DebuggerApplication serverUnloaded:]):
+ (-[DebuggerApplication awakeFromNib]):
+ (-[DebuggerApplication showAttachPanel:]):
+ (-[DebuggerApplication attach:]):
+ (-[DebuggerApplication numberOfRowsInTableView:]):
+ (-[DebuggerApplication tableView:objectValueForTableColumn:row:]):
+ (-[DebuggerApplication tableView:willDisplayCell:forTableColumn:row:]):
+ (-[DebuggerApplication tableViewSelectionDidChange:]):
+ * Drosera/DebuggerDocument.h: Added.
+ * Drosera/DebuggerDocument.m: Added.
+ (+[WebScriptCallFrame isSelectorExcludedFromWebScript:]):
+ (+[WebScriptCallFrame isKeyExcludedFromWebScript:]):
+ (+[DebuggerDocument isSelectorExcludedFromWebScript:]):
+ (+[DebuggerDocument isKeyExcludedFromWebScript:]):
+ (-[DebuggerDocument initWithServerName:]):
+ (-[DebuggerDocument windowWillClose:]):
+ (-[DebuggerDocument dealloc]):
+ (-[DebuggerDocument isPaused]):
+ (-[DebuggerDocument pause]):
+ (-[DebuggerDocument resume]):
+ (-[DebuggerDocument step]):
+ (-[DebuggerDocument windowNibName]):
+ (-[DebuggerDocument windowDidLoad]):
+ (-[DebuggerDocument switchToServerNamed:]):
+ (-[DebuggerDocument applicationTerminating:]):
+ (-[DebuggerDocument serverConnectionDidDie:]):
+ (-[DebuggerDocument webView:windowScriptObjectAvailable:]):
+ (-[DebuggerDocument webView:didFinishLoadForFrame:]):
+ (-[DebuggerDocument webView:didParseSource:fromURL:sourceId:forWebFrame:]):
+ (-[DebuggerDocument webView:didEnterCallFrame:sourceId:line:forWebFrame:]):
+ (-[DebuggerDocument webView:willExecuteStatement:sourceId:line:forWebFrame:]):
+ (-[DebuggerDocument webView:willLeaveCallFrame:sourceId:line:forWebFrame:]):
+ * Drosera/Drosera.pch: Added.
+ * Drosera/Drosera.xcodeproj/project.pbxproj: Added.
+ * Drosera/English.lproj/Debugger.nib/classes.nib: Added.
+ * Drosera/English.lproj/Debugger.nib/info.nib: Added.
+ * Drosera/English.lproj/Debugger.nib/keyedobjects.nib: Added.
+ * Drosera/English.lproj/MainMenu.nib/classes.nib: Added.
+ * Drosera/English.lproj/MainMenu.nib/info.nib: Added.
+ * Drosera/English.lproj/MainMenu.nib/keyedobjects.nib: Added.
+ * Drosera/Images/breakPoint.tif: Added.
+ * Drosera/Images/breakPointDisabled.tif: Added.
+ * Drosera/Images/continue.tif: Added.
+ * Drosera/Images/finishFunction.tif: Added.
+ * Drosera/Images/glossyFooterFill.tif: Added.
+ * Drosera/Images/glossyHeader.png: Added.
+ * Drosera/Images/gradientBackground.png: Added.
+ * Drosera/Images/gutter.png: Added.
+ * Drosera/Images/navLeftDisabled.png: Added.
+ * Drosera/Images/navLeftNormal.png: Added.
+ * Drosera/Images/navLeftPressed.png: Added.
+ * Drosera/Images/navRightDisabled.png: Added.
+ * Drosera/Images/navRightNormal.png: Added.
+ * Drosera/Images/navRightPressed.png: Added.
+ * Drosera/Images/pause.tif: Added.
+ * Drosera/Images/popUpArrows.png: Added.
+ * Drosera/Images/programCounter.tif: Added.
+ * Drosera/Images/programCounterBreakPoint.tif: Added.
+ * Drosera/Images/programCounterBreakPointDisabled.tif: Added.
+ * Drosera/Images/run.tif: Added.
+ * Drosera/Images/splitterBar.tif: Added.
+ * Drosera/Images/splitterDimple.tif: Added.
+ * Drosera/Images/step.tif: Added.
+ * Drosera/Images/stepOver.tif: Added.
+ * Drosera/Images/stop.tif: Added.
+ * Drosera/Images/toolbarBackground.png: Added.
+ * Drosera/Info.plist: Added.
+ * Drosera/debugger.css: Added.
+ * Drosera/debugger.html: Added.
+ * Drosera/debugger.js: Added.
+ * Drosera/main.m: Added.
+ (main):
+ * Drosera/viewer.css: Added.
+ * Drosera/viewer.html: Added.
+
+2006-06-18 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by darin.
+
+ http://bugs.webkit.org/show_bug.cgi?id=9485
+ Teach svn-apply and svn-unapply to use full path names
+
+ * Scripts/svn-apply: Changed to use full path names. Cleaned up code.
+ * Scripts/svn-unapply: Ditto.
+
+2006-06-18 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by ggaren.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=9150
+ DumpRenderTree should be able to keep URL history during runs
+
+ Test: LayoutTests/fast/history/clicked-link-is-visited.html
+
+ * DumpRenderTree/DumpRenderTree.m: Add keepWebHistory function to layoutTestController
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]): Updated for keepWebHistory.
+ (-[LayoutTestController keepWebHistory]): Added. We only set optional shared history if
+ it is currently nil since keepWebHistory() might be called more than once incidentally
+ for the same test.
+ (dumpRenderTree): Set optional shared history in WebHistory to nil by default.
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Xcode 2.3 clean up.
+
+2006-06-11 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by darin.
+
+ http://bugs.webkit.org/show_bug.cgi?id=9395
+ Make prepare-ChangeLog faster
+
+ * Scripts/prepare-ChangeLog: Use "svn diff" instead of "svn stat" to find changed files,
+ then save the diff output for reuse. Keep a status variable if changes are made to
+ LayoutTests so "svn diff LayoutTests" doesn't have to be run to check for changes when
+ WebCore is updated. Added -h|--help command-line switch and help message. Move test
+ for no changed files closer to the beginning of the program.
+
+2006-06-10 Mitz Pettel <opendarwin.org@mitzpettel.com>
+
+ Reviewed and landed by ap.
+
+ - make DumpRenderTree build
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:didCommitLoadForFrame:]): Changed _updateFocusState to _updateActiveState
+ (-[WaitUntilDoneDelegate webViewFocus:]): Ditto.
+ (-[LayoutTestController setWindowIsKey:]): Ditto.
+ (-[LayoutTestController setMainFrameIsFirstResponder:]): Ditto.
+
+2006-06-09 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by Darin, landed by Geoff.
+
+ http://bugs.webkit.org/show_bug.cgi?id=9350
+ Use pathcmp() when sorting paths in svn-create-patch
+
+ * Scripts/run-webkit-tests: Fixed splitpath() to use File::Basename subroutines instead of regex.
+ * Scripts/svn-create-patch: Copied numericcmp(), pathcmp() and splitpath() from run-webkit-tests.
+ Changed sort() functions to use pathcmp(). Added subroutine prototypes. Added -h command-line
+ switch and printUsage() subroutine.
+
+2006-06-06 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by darin.
+
+ http://bugs.webkit.org/show_bug.cgi?id=9322
+ Teach svn-create-patch to sort its output
+
+ * Scripts/svn-create-patch: Clean up perl code. Sort patch output alphabetically
+ by text files first, then by binary files.
+
+2006-06-04 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by darin.
+
+ http://bugs.webkit.org/show_bug.cgi?id=9299
+ Teach svn-create-patch and friends to work with binary files
+
+ * Scripts/svn-apply: Updated to use base64-encoded text for binary files when applying patches.
+ * Scripts/svn-create-patch: Updated to include binary file content as base64-encoded text in patches.
+ * Scripts/svn-unapply: Updated to recognize binary files when unapplying patches.
+
+2006-06-03 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by Maciej.
+
+ http://bugs.webkit.org/show_bug.cgi?id=9296
+ Performance improvement for svn-create-patch
+
+ * Scripts/svn-create-patch: Undef $indexPath after all paths have been fixed for a given patch.
+
+2006-06-03 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by darin.
+
+ http://bugs.webkit.org/show_bug.cgi?id=9290
+ Teach svn-apply and svn-unapply to patch ChangeLogs cleanly
+
+ * Scripts/svn-apply: Fixed to apply ChangeLog patches without failing.
+ * Scripts/svn-unapply: Ditto. Also simplified reversing a deletion.
+
+2006-06-03 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by hyatt.
+
+ Switch Spinneret to new hosting mechanism
+
+ * Spinneret/Spinneret.sln:
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (SpinneretWebHost::updateAddressBar):
+ (SpinneretWebHost::QueryInterface):
+ (SpinneretWebHost::AddRef):
+ (SpinneretWebHost::Release):
+ (resizeSubViews):
+ (_tWinMain):
+ (WndProc):
+ (MyEditProc):
+ (About):
+ (loadURL):
+ * Spinneret/Spinneret/Spinneret.h:
+ (SpinneretWebHost::didStartProvisionalLoadForFrame):
+ (SpinneretWebHost::didReceiveServerRedirectForProvisionalLoadForFrame):
+ (SpinneretWebHost::didFailProvisionalLoadWithError):
+ (SpinneretWebHost::didCommitLoadForFrame):
+ (SpinneretWebHost::didReceiveTitle):
+ (SpinneretWebHost::didReceiveIcon):
+ (SpinneretWebHost::didFinishLoadForFrame):
+ (SpinneretWebHost::didFailLoadWithError):
+ (SpinneretWebHost::didChangeLocationWithinPageForFrame):
+ (SpinneretWebHost::willPerformClientRedirectToURL):
+ (SpinneretWebHost::didCancelClientRedirectForFrame):
+ (SpinneretWebHost::willCloseFrame):
+ (SpinneretWebHost::windowScriptObjectAvailable):
+ * Spinneret/Spinneret/Spinneret.vcproj:
+
+2006-06-02 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by darin.
+
+ Updated build script
+
+ * Scripts/build-webkit:
+
+2006-06-01 Anders Carlsson <acarlsson@apple.com>
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController clearBackForwardList]):
+ Add clearBackForwardList function to layoutTestController
+
+2006-06-01 Anders Carlsson <acarlsson@apple.com>
+
+ Reviewed by Darin Adler.
+
+ http://bugs.webkit.org/show_bug.cgi?id=8996
+ slow-utf8-text layout test case failing (no longer deterministic?)
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dump):
+ Dump as text when the response MIME type is text/plain
+
+2006-05-26 Steve Falkenburg <sfalken@apple.com>
+
+ Build fixes/tweaks
+
+ * Spinneret/Spinneret.sln:
+ * Spinneret/Spinneret/Spinneret.vcproj:
+
+2006-05-24 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by mjs.
+
+ Added 'GCController' to DRT to support garbage collection layout tests.
+
+ GCController.collect() and GCController.collectOnAlternateThread() do
+ what you would expect. The latter takes a boolean argument sepcifying
+ whether to wait for garbage collection to finish before continuing to
+ execute script.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:windowScriptObjectAvailable:]):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/GCController.h: Added.
+ * DumpRenderTree/GCController.mm: Added.
+ (+[GCController isSelectorExcludedFromWebScript:]):
+ (+[GCController webScriptNameForSelector:]):
+ (-[GCController collect]):
+ (-[GCController collectOnAlternateThread:]):
+
+2006-05-23 John Sullivan <sullivan@apple.com>
+
+ Reviewed by Maciej.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ Newer Xcode removed some obsolete cruft
+
+ * DumpRenderTree/TextInputController.m:
+ (-[TextInputController textInput]):
+ added (id) cast to make newer compiler happy
+
+2006-05-22 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by adele.
+
+ Fix build.
+
+ * Spinneret/Spinneret.sln:
+
+2006-05-18 Darin Adler <darin@apple.com>
+
+ - try to fix no-SVG, no-XPATH build, again
+
+ * Scripts/build-webkit: Use FEATURE_DEFINES= instead of FEATURE_DEFINES=''.
+
+2006-05-18 Darin Adler <darin@apple.com>
+
+ - try to fix no-SVG, no-XPATH build
+
+ * Scripts/build-webkit: Pass FEATURE_DEFINES rather than GCC_PREPROCESSOR_DEFINITIONS,
+ since the former is what's used in the WebCore project now.
+
+2006-05-17 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Some more future renames.
+
+2006-05-16 Adele Peterson <adele@apple.com>
+
+ Reviewed by Hyatt.
+
+ * Scripts/do-webcore-rename: Added RenderTextField => RenderTextControl and
+ HTMLTextFieldInnerElement => HTMLTextControlInnerElement to list for future renames.
+
+2006-05-15 Alexey Proskuryakov <ap@nypop.com>
+
+ * Scripts/install-unix-extras: Changed to be executable and removed
+ text in the file generated by "svn diff".
+ * Scripts/regenerate-makefiles: Ditto.
+
+2006-05-13 Kevin M. Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Darin, landed by ap.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=8528
+ Bakefiles (and generated Makefiles) for wx and gdk ports
+
+ * Scripts/install-unix-extras: Added.
+ * Scripts/regenerate-makefiles: Added.
+
+2006-05-10 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Maciej.
+
+ Fix registry usage from perl script. Turns out libwin32's
+ SetRegValueEx, even for REG_DWORD, always takes its value as a string!
+
+ * Scripts/install-win-extras:
+
+2006-05-09 Steve Falkenburg <sfalken@apple.com>
+
+ Fix Windows build.
+ Add load ended callback.
+
+ Reviewed by kevin.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.vcproj: Fix include paths
+ * Scripts/build-webkit: Build WebKitWin instead of WebCore/JavaScriptCore (WebKitWin builds those indirectly).
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (SpinneretWebHost::loadEnd): Add callback for loadEnd() to determine success/failure of page load.
+ (_tWinMain): Load built-in test content here instead of in lower-level code.
+ * Spinneret/Spinneret/Spinneret.h: Add loadEnd() callback.
+
+2006-05-08 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Anders.
+
+ * Scripts/extract-localizable-strings: Update for correct names of log macros.
+
+2006-05-09 Anders Carlsson <acarlsson@apple.com>
+
+ Reviewed by Maciej.
+
+ * Scripts/check-dom-results:
+ Add XPath to the list of results.
+
+2006-05-08 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Add another rename.
+
+2006-05-01 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by eric.
+
+ Spinneret now links against the new separate lib.
+
+ * Spinneret/Spinneret.sln:
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (SpinneretWebHost::updateLocationBar):
+ (_tWinMain):
+ * Spinneret/Spinneret/Spinneret.h:
+ * Spinneret/Spinneret/Spinneret.vcproj:
+ * Spinneret/Spinneret/WebFrame.cpp: Removed.
+ * Spinneret/Spinneret/WebFrame.h: Removed.
+ * Spinneret/Spinneret/WebView.cpp: Removed.
+ * Spinneret/Spinneret/WebView.h: Removed.
+
+2006-04-28 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by kdecker
+
+ Modify error reporting registry keys to disable Dr. Watson.
+ This allows Javascript test cases to complete without blocking UI.
+
+ * Scripts/install-win-extras:
+ - Use Perl Win32 registry functions to disable blocking UI
+
+
+2006-04-28 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by eric.
+
+ Turned off C++ exceptions, fixed memory leaks
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.vcproj:
+ * Spinneret/Spinneret.sln:
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (_tWinMain):
+ * Spinneret/Spinneret/Spinneret.vcproj:
+ * Spinneret/Spinneret/WebFrame.cpp:
+ (WebKit::WebFrame::WebFramePrivate::~WebFramePrivate):
+ (WebKit::WebFrame::WebFrame):
+ (WebKit::WebFrame::~WebFrame):
+ (WebKit::WebFrame::impl):
+ * Spinneret/Spinneret/WebFrame.h:
+ * Spinneret/Spinneret/WebView.cpp:
+ * Spinneret/Spinneret/stdafx.h:
+
+2006-04-28 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=8633
+ DumpRenderTree should reset the URL cache
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): Call [[NSURLCache sharedURLCache] removeAllCachedResponses].
+
+2006-04-28 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by andersca.
+
+ * Scripts/do-webcore-rename: rename KCanvasContainer too
+ * Scripts/run-webkit-tests: output total time
+
+2006-04-26 Mitz Pettel <opendarwin.org@mitzpettel.com>
+
+ Reviewed by hyatt. Landed by eseidel.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=8549
+ Enable detection of excessive repainting with DumpRenderTree
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[LayoutTestController display]):
+
+2006-04-23 Mitz Pettel <opendarwin.org@mitzpettel.com>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=6905
+ DumpRenderTree needs a way to force painting (to allow invalidation tests)
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dump): If display() has been called during the test, grab the pixels from
+ the view, after letting it repaint invalidated rects.
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController display]): Added. Calls -display on the view
+ and changes the subsequent behavior of dump().
+ (dumpRenderTree):
+
+2006-04-22 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Maciej.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=8532
+ Update iExploder to 1.3.2
+
+ Test case numbers are not compatible with iExploder 1.2.
+
+ * Scripts/run-iexploder-tests: Print the numbers of the last five tests that were accessed.
+
+ * iExploder/CHANGELOG.txt: Added.
+ * iExploder/LICENSE.txt: Changed to a standard zlib/png license.
+ * iExploder/README.txt: Added some performance hints.
+
+ * iExploder/htdocs/config.rb: Added.
+ * iExploder/htdocs/cssproperties.in:
+ * iExploder/htdocs/cssvalues.in:
+ * iExploder/htdocs/htmlattrs.in:
+ * iExploder/htdocs/htmltags.in:
+ * iExploder/htdocs/iexploder.cgi:
+ - Updated to support the latest HTML & CSS tags, properties, and values from both
+ the WebKit and Mozilla CVS tree
+ - cssproperties.in cleanup
+ - Modularized the code a little bit.
+ - Fix subtest bug that was causing last 5 tags to be missed
+ - new subtest algorithm to deal better with larger tag counts
+ - default HTML_MAX_TAGS increased from 32 to 96
+
+ * iExploder/htdocs/index.html: Updated version to 1.3.2.
+ * iExploder/htdocs/webserver.rb: Added. New standalone webserver, can be used as an
+ alternative to our run-iexploder-tests.
+ * iExploder/tools/showtest.rb: Added. Similar to run-iexploder-tests --get.
+ * iExploder/htdocs/iexploder.rb: Added. Used by webserver.rb.
+ * iExploder/tools/osx_last_crash.rb: Find logs modified in the last two days.
+
+2006-04-22 Alexey Proskuryakov <ap@nypop.com>
+
+ - commit Scripts/run-mangleme-tests (missed it the previous time).
+
+2006-04-18 Darin Adler <darin@apple.com>
+
+ - attempt to fix Windows buildbot
+
+ * Scripts/install-win-extras: Temporarily changed URLs to fr.rpmfind.net.
+ We need a better long-term solution for this.
+
+2006-04-17 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=8444
+ Integrate mangleme test script.
+
+ Works in a similar way to run-iexploder-tests.
+
+ * Scripts/run-mangleme-tests: Added.
+ * mangleme: Added.
+ * mangleme/Makefile: Added.
+ * mangleme/README: Added.
+ * mangleme/mangle.cgi.c: Added.
+ * mangleme/remangle.cgi.c: Added.
+ * mangleme/tags.h: Added.
+
+2006-04-17 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=8443
+ An easier way to save iExploder tests.
+
+ * Scripts/run-iexploder-tests: Added a --get option to save a test into a file.
+
+2006-04-17 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=8421
+ Integrate iExploder test script.
+
+ This script generates artificially mangled HTML documents, to test that the browser
+ doesn't crash when handling ill-formed code.
+
+ How to use:
+ run-iexploder-tests Open an interactive test page in Safari+ToT.
+ run-iexploder-tests nnnnn Open test #nnnnn.
+
+ Command line options:
+ --guard-malloc (-g) Use Guard Malloc.
+ --port=nnnn Run Apache on port nnnn (default is 8000).
+
+ To save a crashing test, you can use curl while the crash reporter dialog is on the screen
+ (thus, Apache is still running), e.g.:
+ curl -o iexploder293.html "http://127.0.0.1:8000/iexploder.cgi?lookup=1&test=293"
+
+ Additionally, there are some useful scripts in WebKitTools/iExploder/tools directory.
+
+ * Scripts/run-iexploder-tests: Added.
+ * iExploder: Added.
+ * iExploder/LICENSE.txt: Added.
+ * iExploder/README.txt: Added.
+ * iExploder/htdocs: Added.
+ * iExploder/htdocs/cssproperties.in: Added.
+ * iExploder/htdocs/cssvalues.in: Added.
+ * iExploder/htdocs/htmlattrs.in: Added.
+ * iExploder/htdocs/htmltags.in: Added.
+ * iExploder/htdocs/htmlvalues.in: Added.
+ * iExploder/htdocs/iexploder.cgi: Added.
+ * iExploder/htdocs/index.html: Added.
+ * iExploder/tools: Added.
+ * iExploder/tools/lasthit.rb: Added.
+ * iExploder/tools/osx_last_crash.rb: Added.
+
+2006-04-16 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=8412
+ Restore color profile after a crash
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (crashHandler): Added a handler for signals that are raised on a crash. Keeping separate
+ from the existing handler for manual interruption (SIGINT/SIGHUP/SIGTERM), because
+ I'm trying to find a way to prevent the Crash Reporter dialog from appearing on crash,
+ and this code may change significantly.
+
+ (main): Install crashHandler.
+
+ (setDefaultColorProfileToRGB): Properly convert CFStringRef to a char buffer
+ (CFStringGetCStringPtr should NEVER EVER be used!).
+
+2006-04-15 Darin Adler <darin@apple.com>
+
+ Reviewed by Eric.
+
+ * Scripts/install-win-extras: Try to fix the Windows build by fixing the URLs here.
+ Seems xmlsoft.org's HTTP no longer has what we need.
+
+2006-04-13 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Rubber-stamped by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=8348
+ upload-disk-image stage on buildslaves fail with "No space left on device"
+
+ * BuildSlaveSupport/build-launcher-dmg: Use the -srcfolder option to
+ 'hdiutil create'. This creates the initial disk image based on the size of
+ the source folder, and copies the contents to the new disk image. The file
+ extension on the temporary uncompressed disk image has also been altered from
+ ".uncompressed" to ".uncompressed.dmg" as hdiutil on 10.4.6 Intel fails when
+ the extension is not ".dmg".
+
+2006-04-12 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by Tim H.
+
+ * Scripts/update-webkit: Make this return non-zero when svn fails.
+
+2006-04-10 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=8157
+ Make HTTP tests using Perl use .pl extension
+
+ * Scripts/run-webkit-tests: Added support for running .pl and .php tests,
+ removed support for .text. Reduced the number of places that explicitly list supported
+ extensions. Some of the changes come from bug 8121, the patch for which got landed only
+ partially.
+
+2006-04-06 Darin Adler <darin@apple.com>
+
+ Changes requested by Mark Rowe.
+
+ * BuildSlaveSupport/build-launcher-app: Set executable bit, removed property change
+ trash at the end of the file.
+ * BuildSlaveSupport/build-launcher-dmg: Ditto.
+
+ * WebKitLauncher/main.m: Removed trash at end of file.
+
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj: Let Xcode update comments
+ to make name match.
+
+2006-04-06 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Darin, landed by Maciej.
+
+ * BuildSlaveSupport/build-launcher-app: Added. Builds WebKit.app from WebKitLauncher
+ and bundles the WebKit frameworks inside it.
+ * BuildSlaveSupport/build-launcher-dmg: Added. Builds, and optionally uploads, a disk image
+ containing WebKit.app.
+ * BuildSlaveSupport/run-performance-tests: Use currentSVNRevision.
+ * Scripts/webkitdirs.pm: Add currentSVNRevision to retrieve the revision
+ number of the SVN working copy.
+ * WebKitLauncher: Added.
+ * WebKitLauncher/Info.plist: Added.
+ * WebKitLauncher/WebKitLauncher.xcodeproj: Added.
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj: Added.
+ * WebKitLauncher/WebKitNightlyEnabler.m: Added. This makes
+ up the WebKitNightlyEnabler dylib which is loaded into Safari's address space
+ to cause LaunchServices to treat Safari.app as WebKit.app when it is run from
+ the nightly launcher.
+ * WebKitLauncher/main.m: Added. The WebKit.app launcher.
+ It sets up the environment to have Safari use the bundled frameworks
+ and load the WebKitNightlyEnabler dylib before exec'ing Safari
+ * WebKitLauncher/start.html: Added.
+ * WebKitLauncher/webkit.icns: Added.
+
+2006-04-05 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej.
+
+ * Scripts/check-for-global-initializers: Remove StringImpl from the list of files that
+ are allowed to have global initializers.
+
+2006-04-05 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by OMG BETH
+
+ * Scripts/run-testkjs:
+ - pipe STDERR to /dev/null by default; new --verbose option overrides
+ this behavior
+ - set DYLD_FRAMEWORK_PATH to the webkit-configured path
+ - output run command in a format that can be copied and pasted into the
+ terminal to run manually
+
+2006-04-03 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by harrison
+
+ <http://bugs.webkit.org/show_bug.cgi?id=7567>
+ A drag and drop in DumpRenderTree copies the source, instead of cutting it
+
+ Tell the source that the drag is over after the drag is performed, not before.
+
+ * DumpRenderTree/EventSendingController.m:
+ (-[EventSendingController mouseUp]):
+
+2006-04-01 Darin Adler <darin@apple.com>
+
+ Reviewed by Justin.
+
+ * DumpRenderTree/EventSendingController.m: (-[EventSendingController keyDown:withModifiers:]):
+ Fixed keyDown function so that it will work if you don't pass an array of modifiers or if
+ elements in that array are not strings.
+
+2006-03-31 Darin Adler <darin@apple.com>
+
+ Reviewed by John Sullivan.
+
+ - added a "--reset-results" option to run-webkit-tests so you can reset
+ the results without first deleting expected results
+ - <rdar://problem/4185878> add scroll position to dumpRenderTree
+
+ * Scripts/run-webkit-tests: Rearranged the code a bit to make the sequence
+ more logical. Moved all the subroutines to the end of the file. Added a
+ "--force" option.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): Added a new --dump-all-pixels option, used when forcing run-webkit-tests
+ to generate new output for all tests it runs.
+ (dump): Dump the scroll position if it's non-zero. Always dump the image when
+ the --dump-all-pixels option is passed. Also tightened up the image dumping
+ code and replaced the incorrect use of +[NSGraphicsContext saveGraphicsState]
+ with code to save and restore the context.
+
+ * DumpRenderTree/DumpRenderTree.h: Tweaked includes a bit and added (void).
+ * DumpRenderTree/EventSendingController.m: Added now-needed include.
+
+2006-03-30 Tim Omernick <timo@apple.com>
+
+ * DumpRenderTree/ObjCPlugin.h:
+ Fixed copyright.
+ * DumpRenderTree/ObjCPlugin.m: ditto
+ * DumpRenderTree/ObjCPluginFunction.h: ditto
+ * DumpRenderTree/ObjCPluginFunction.m: ditto
+
+2006-03-30 Tim Omernick <timo@apple.com>
+
+ Reviewed by Geoff.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:windowScriptObjectAvailable:]):
+ Add "objCPlugin", "objCPluginFunction" properties to the window. objCPlugin simulates
+ an Objective C object exposed to JS; objCPluginFunction simulates an Objective C method
+ exposed to JS as a callable object.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ Added ObjCPlugin.[hm], ObjCPluginFunction.[hm].
+
+ * DumpRenderTree/ObjCPlugin.h: Added.
+ * DumpRenderTree/ObjCPlugin.m: Added.
+ * DumpRenderTree/ObjCPluginFunction.h: Added.
+ * DumpRenderTree/ObjCPluginFunction.m: Added.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ Added a new method, "removeDefaultMethod", which removes the default method from the
+ plugin object's class. The effect is that the plugin object is mutated from a callable
+ function to a simple object.
+ (pluginInvoke):
+ Handle "removeDefaultMethod".
+ (pluginInvokeDefault):
+ Made the default method actually do something (return 1).
+
+2006-03-30 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by ggaren.
+
+ Remove WebFrame::viewImpl(), setMainFrame on page.
+
+ * Spinneret/Spinneret/WebFrame.cpp:
+ (WebKit::WebFrame::WebFrame):
+ * Spinneret/Spinneret/WebFrame.h:
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::WebView::mouseMoved):
+ (WebKit::WebView::mouseDown):
+ (WebKit::WebView::mouseUp):
+ (WebKit::WebView::mouseDoubleClick):
+ (WebKit::WebViewWndProc):
+
+2006-03-30 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ Fix html editing input & basic form submission.
+
+ * Spinneret/Spinneret/WebFrame.cpp:
+ (WebKit::WebFrame::submitForm):
+ (WebKit::WebFrame::loadURL):
+ * Spinneret/Spinneret/WebFrame.h:
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::WebView::keyPress):
+ (WebKit::WebViewWndProc):
+
+2006-03-28 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by darin
+
+ <rdar://problem/4402375>
+ REGRESSION (417.8-TOT): selectionRect sometimes includes adjacent images
+
+ Added an option to draw the selectionRect.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dump):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (-[LayoutTestController dumpSelectionRect]):
+ (dumpRenderTree):
+
+2006-03-29 Darin Adler <darin@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ - make the global initializer check work on Xcode 2.1 (although it's better on 2.2)
+
+ * Scripts/check-for-global-initializers: Use NATIVE_ARCH if there is no CURRENT_ARCH.
+
+2006-03-28 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ * Scripts/check-for-global-initializers: remove svg exceptions.
+
+2006-03-28 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Exit gracefully if $ENV{'CURRENT_ARCH'} is undefined. Rolling out my previous change.
+
+ * Scripts/check-for-global-initializers:
+
+2006-03-28 Timothy Hatcher <timothy@apple.com>
+
+ Build fix. Turn off uninitialized warnings for the first block of code.
+
+ * Scripts/check-for-global-initializers:
+
+2006-03-28 Darin Adler <darin@apple.com>
+
+ Reviewed by Geoff.
+
+ * Scripts/check-for-global-initializers: Added.
+
+2006-03-24 Mitz Pettel <opendarwin.org@mitzpettel.com>
+
+ Reviewed by darin. Landed by eseidel.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=7947
+ Add repaint testing support to run-webkit-tests
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): Added --repaint and --horizontal-sweep options.
+ (dump): Repaint line-by-line or column-by-column when the appropriate option
+ is selected.
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]): Added testRepaint()
+ and repaintSweepHorizontally() methods to layoutTestController.
+ (-[LayoutTestController testRepaint]):
+ (-[LayoutTestController repaintSweepHorizontally]):
+ (dumpRenderTree):
+ * Scripts/run-webkit-tests: Added --repaint and --horizontal-sweep options
+ to force these settings on tests that do not ask for them.
+
+2006-03-24 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Build fix.
+
+ * Spinneret/Spinneret/WebFrame.cpp:
+ (WebKit::WebFrame::openURL): replace QString with DeprecatedString
+
+2006-03-21 Beth Dakin <bdakin@apple.com>
+
+ Reviewed by Maciej
+
+ Add support for keyDown() to DumpRenderTree.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): Set the preference for tabbing to links.
+ * DumpRenderTree/EventSendingController.m:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (+[EventSendingController webScriptNameForSelector:]):
+ (-[EventSendingController keyDown:withModifiers:]):
+
+2006-03-20 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ Fix win32 build.
+
+ * Spinneret/Spinneret/Spinneret.vcproj:
+ * Spinneret/Spinneret/WebFrame.h:
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::WebView::mouseMoved):
+ (WebKit::WebView::mouseDown):
+ (WebKit::WebView::mouseUp):
+ (WebKit::WebView::mouseDoubleClick):
+ (WebKit::WebView::keyPress):
+ (WebKit::WebViewWndProc):
+
+2006-03-19 Darin Adler <darin@apple.com>
+
+ Reviewed by Anders.
+
+ * DumpRenderTree/DumpRenderTree.m: (main): Turn on pop-up blocking so that
+ we can test it in layout tests. We don't really need tests that run with
+ pop-up blocking off at the moment. If we do some day, we can add some
+ API for turning it off in the layout test controller.
+
+ * Scripts/run-webkit-tests: Since we don't use NSLanguage at all any more,
+ don't ignore the leak; it should no longer show up.
+
+2006-03-17 Anders Carlsson <andersca@mac.com>
+
+ Reviewed by Eric.
+
+ * Scripts/install-win-extras:
+ Fetch "Program Files" location from the environment.
+
+2006-03-17 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by ggaren.
+
+ Fix Spinneret to pass Events as const & not as pointers.
+
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::WebView::mouseMoved):
+ (WebKit::WebView::mouseDown):
+ (WebKit::WebView::mouseUp):
+ (WebKit::WebView::mouseDoubleClick):
+ (WebKit::WebView::keyPress):
+
+2006-03-17 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by justing.
+
+ Add support for basic HTML editing.
+
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::WebView::WebView):
+ (WebKit::WebView::keyPress):
+
+2006-03-17 Eric Seidel <eseidel@apple.com>
+
+ Rubber-stamped by ggaren.
+
+ Break DumpRenderTree.m up into several files to make the code more readable.
+
+ * DumpRenderTree/DumpRenderTree.h: Added.
+ * DumpRenderTree/DumpRenderTree.m:
+ (doneLoading): new accessor function for "done" global.
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/DumpRenderTreeDraggingInfo.h: Added.
+ * DumpRenderTree/DumpRenderTreeDraggingInfo.m: Added.
+ * DumpRenderTree/EditingDelegate.h: Added.
+ * DumpRenderTree/EditingDelegate.m: Added.
+ (-[EditingDelegate webViewDidChangeSelection:]):
+ * DumpRenderTree/EventSendingController.h: Added.
+ * DumpRenderTree/EventSendingController.m: Added.
+
+2006-03-16 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ Add resize, scroll event support.
+
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::WebView::mouseMoved):
+ (WebKit::WebView::mouseDown):
+ (WebKit::WebView::mouseUp):
+ (WebKit::WebView::mouseDoubleClick):
+ (WebKit::WebView::keyPress):
+ (WebKit::WebViewWndProc):
+ * Spinneret/Spinneret/WebView.h:
+
+2006-03-16 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ Make build-webkit print correctly to stdout on windows.
+
+ * Scripts/webkitdirs.pm: Fix to use devenv.com instead of devenv.exe
+
+2006-03-15 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Fix eventSender.mouseClick() to update lastClick timestamp.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[EventSendingController mouseClick]):
+
+2006-03-15 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Fix path
+ that had a lowercase "i" in it so this builds on case-sensitive
+ file systems.
+
+2006-03-15 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Eric.
+
+ Added run-testkjs and compare-timing-files scripts, to support super
+ accurate JS iBench.
+
+ * Scripts/compare-timing-files: Added.
+ * Scripts/run-testkjs: Added.
+
+2006-03-14 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Make the URL bar relinquish focus on page load.
+
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (MyEditProc):
+
+2006-03-14 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Fix WebView to allow KeyFocus.
+ Add handling of space and shift-space for scrolling.
+
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::scrollMessageForKey):
+ (WebKit::WebViewWndProc):
+
+2006-03-10 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ Add scrolling support into Spinneret.
+
+ * Spinneret/Spinneret/WebFrame.cpp:
+ (WebKit::WebFrame::paint):
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::WebView::createWebView):
+ (WebKit::calculateScrollDelta):
+ (WebKit::scrollMessageForKey):
+ (WebKit::WebViewWndProc):
+
+2006-03-13 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Fix checksum generation on Intel machines.
+ Also moved to CGImage APIs instead of NSBitmapImageRep, may possibly
+ give a small speed boost now that it uses a shared buffer.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main):
+ (dump):
+ (md5HashStringForBitmap):
+ * DumpRenderTree/ImageDiff.m:
+ (computePercentageDifferent):
+
+2006-03-13 Darin Adler <darin@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ * Scripts/run-webkit-tests: Fix httpd handling to work on systems that
+ have it named httpd-1.3 instead.
+
+2006-03-13 Alexey Proskuryakov <ap@nypop.com>
+
+ Fix proposed by Mitz Pettel, reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=7718
+ run-webkit-tests fast/dom/HTMLObjectElement/ hangs
+
+ * Scripts/run-webkit-tests: Make test paths canonical, to form proper URLs
+ (sequences of slashes are equivalent to a single slash in POSIX paths, but not
+ in URLs).
+
+2006-03-09 Darin Adler <darin@apple.com>
+
+ Reviewed by John Sullivan.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=7681
+ memory leak in the plug-in tests
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c:
+ (NPP_Destroy): Added code to release the plug-in object. This is the leak fix.
+ (NPP_SetWindow): Remove unneeded code to store the window pointer.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ Moved the browser global in here since it's declared in this file's header.
+ Changed the code to set up the pluginClass structure to not use function
+ pointer casts. Those are dangerous because they can hide many types of mismatch.
+ And indeed when I did this I discovered that many functions were missing their
+ boolean return values or had parameter declarations with the wrong types.
+ (pluginGetProperty): Use STRINGZ_TO_NPVARIANT macro for greater simplicity and
+ clarity. Added boolean return value: return true when successful and false when not.
+ (pluginSetProperty): Added boolean return value, return false since we have no
+ properties we can set.
+ (pluginInvoke): Added boolean return value. Return true when successful and false
+ when not. Use NPVARIANT macros where appropriate. Added a missing release for the
+ return value from calling the browser. Changed code to put the strings in malloc
+ buffers instead of relying on GCC's extension that allows variable-sized arrays
+ on the stack.
+ (pluginInvokeDefault): Added boolean return value, return false since we have no
+ default function to call.
+ (pluginInvalidate): Added missing parameter. Removed comment.
+ (pluginAllocate): Removed unneeded cast. This is C code, not C++, so you don't have
+ to cast the result of malloc.
+ (pluginDeallocate): Removed uneeded cast.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h: Removed some unneeded
+ includes. Changed our PluginObject to use NPObject instead of re-declaring fields
+ that match NPObject's fields. Removed unused NPWindow pointer.
+
+2006-03-09 Mitz Pettel <opendarwin.org@mitzpettel.com>
+
+ Test: fast/events/event-sender-mouse-click.html
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=7583
+ DRT hangs when doing eventSender.mouseDown on native widgets
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (-[EventSendingController mouseClick]): Simulates a click in a native
+ widget by queueing a mouseUp before sending the mouseDown, so that
+ the widget's mouse tracking event loop doesn't hang indefinitely.
+
+2006-03-09 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Eric.
+
+ - make link clicks work by handling link click requests
+ from WebCore
+
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (updateLocationBar):
+ * Spinneret/Spinneret/Spinneret.h:
+ * Spinneret/Spinneret/WebFrame.cpp:
+ (WebKit::WebFrame::WebFrame):
+ (WebKit::WebFrame::openURL):
+ (WebKit::WebFrame::loadURL):
+ * Spinneret/Spinneret/WebFrame.h:
+
+2006-03-08 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Focus URL bar on Spinneret launch, remove border from WebView.
+ Stop WebFrame from deleting the job (prevent crash).
+
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (_tWinMain):
+ * Spinneret/Spinneret/WebFrame.cpp:
+ (WebKit::WebFrame::receivedAllData):
+ (WebKit::WebFrame::paint):
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::WebView::createWebView):
+
+2006-03-09 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c:
+ (pluginInvoke): Added a method to test getURL.
+
+2006-03-08 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Eric.
+
+ - load URLs, not file paths, in Spinneret
+
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (MyEditProc):
+ * Spinneret/Spinneret/Spinneret.vcproj:
+ * Spinneret/Spinneret/WebFrame.cpp:
+ (WebKit::WebFrame::loadURL):
+ (WebKit::WebFrame::receivedData):
+ (WebKit::WebFrame::receivedAllData):
+ * Spinneret/Spinneret/WebFrame.h:
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::WebView::WebView):
+
+2006-03-08 Darin Adler <darin@apple.com>
+
+ Reviewed by Eric.
+
+ - fixed AppleScript layout test results to not be endian-dependent
+ (Hyatt complained to me about this one)
+
+ * DumpRenderTree/AppleScriptController.m: (-[AppleScriptController doJavaScript:]):
+ Added specific code for dumping LongDateTime, instead of dumping the raw bytes
+ (which are endian-dependent).
+
+2006-03-07 Darin Adler <darin@apple.com>
+
+ Reviewed by Anders.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=7655
+ unwanted output while running layout tests
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (checkedMalloc): Added.
+ (checkedRealloc): Added.
+ (makeLargeMallocFailSilently): Added.
+ (main): Call makeLargeMallocFailSilently.
+
+2006-03-06 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Add some more planned renaming.
+
+2006-03-06 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ * Spinneret/Spinneret/WebFrame.cpp:
+ (WebKit::WebFrame::paint): force layout before painting
+
+2006-03-06 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by darin
+
+ Sent the windowNumber when sending events.
+ Added leapForward so that we don't have to spend time waiting
+ in layout tests that do mouse operations that require delays.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (+[EventSendingController webScriptNameForSelector:]):
+ (-[EventSendingController currentEventTime]):
+ (-[EventSendingController leapForward:]):
+ (-[EventSendingController mouseDown]):
+ (-[EventSendingController mouseUp]):
+ (-[EventSendingController mouseMoveToX:Y:]):
+
+2006-03-05 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Fix a couple of things found while testing.
+ Script now works (after landing my two pending patches).
+
+2006-03-05 Darin Adler <darin@apple.com>
+
+ - check in a script to do a "big" rename in WebCore
+ (can be run whenever we're ready to do it)
+
+ * Scripts/do-webcore-rename: Added.
+
+2006-03-05 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Eric.
+
+ * Spinneret/Spinneret/WebFrame.cpp:
+ (WebKit::WebFrame::loadFilePath): Close file when done.
+
+2006-03-05 Mitz Pettel <opendarwin.org@mitzpettel.com>
+
+ Reviewed by Darin, landed by ap.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=7589
+ Mouse moved events do not work in DumpRenderTree
+
+ Test: fast/events/event-sender-mouse-moved.html
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[EventSendingController mouseMoveToX:Y:]): Pass the correct windowNumber in the event.
+
+2006-03-04 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ Take advantage of new GraphicsContext constructor to implement double buffering to avoid tearing.
+ Disable background erase to avoid tearing.
+ Fix potential memory smasher from extra long urls.
+
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (MyRegisterClass):
+ * Spinneret/Spinneret/Spinneret.vcproj:
+ * Spinneret/Spinneret/WebFrame.cpp:
+ (WebKit::WebFrame::loadFilePath):
+ (WebKit::WebFrame::paint):
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::registerWebViewWithInstance):
+
+2006-03-04 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by ggaren.
+
+ Hang WebView pointer off of HWND (gets rid of global hack).
+ Remove MessageBox displayed on url change.
+
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (WndProc):
+ (MyEditProc):
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::registerWebViewWithInstance):
+ (WebKit::WebView::createWebView):
+ (WebKit::WebViewWndProc):
+
+2006-03-04 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Eric.
+
+ Automatically kill httpd if it appears to be already running.
+
+ * Scripts/run-webkit-tests:
+
+2006-03-04 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Eric.
+
+ * Spinneret/Spinneret/WebFrame.cpp:
+ (WebKit::WebFrame::loadFilePath): Improved local file loading.
+
+2006-03-03 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ A few more fixes to make run-webkit-tests really work on win32.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (localFileTest):
+ * Scripts/run-webkit-tests:
+
+2006-03-03 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ Make run-webkit-tests work on win32.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (localFileTest):
+ (dumpRenderTreeMain):
+ (dumpRenderTreeToStdOut):
+ (serializeToStdOut):
+ (main):
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::WebView::WebView):
+
+2006-03-03 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Add WebFrame class (to hold Frame and FrameView).
+ Add Location bar support to Spinneret.
+
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (resizeSubViews):
+ (_tWinMain):
+ (WndProc):
+ (MyEditProc):
+ * Spinneret/Spinneret/Spinneret.vcproj:
+ * Spinneret/Spinneret/WebFrame.cpp: Added.
+ (WebKit::WebFrame::WebFramePrivate::WebFramePrivate):
+ (WebKit::WebFrame::WebFramePrivate::~WebFramePrivate):
+ (WebKit::WebFrame::WebFrame):
+ (WebKit::WebFrame::loadFilePath):
+ (WebKit::WebFrame::loadHTMLString):
+ (WebKit::WebFrame::paint):
+ (WebKit::WebFrame::impl):
+ (WebKit::WebFrame::viewImpl):
+ * Spinneret/Spinneret/WebFrame.h: Added.
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::WebView::WebViewPrivate::~WebViewPrivate):
+ (WebKit::WebView::WebView):
+ (WebKit::WebView::windowHandle):
+ (WebKit::WebView::mainFrame):
+ (WebKit::WebView::mouseMoved):
+ (WebKit::WebView::mouseDown):
+ (WebKit::WebView::mouseUp):
+ (WebKit::WebView::mouseDoubleClick):
+ (WebKit::WebViewWndProc):
+ * Spinneret/Spinneret/WebView.h:
+
+2006-03-02 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by ggaren.
+
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::registerWebViewWithInstance):
+ (WebKit::WebView::WebView):
+ (WebKit::WebView::mouseMoved):
+ (WebKit::WebView::mouseDown):
+ (WebKit::WebView::mouseUp):
+ (WebKit::WebView::mouseDoubleClick):
+ (WebKit::WebViewWndProc):
+ * Spinneret/Spinneret/WebView.h:
+
+2006-03-01 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by andersca.
+
+ Make spinneret take advantage of the new GraphicsContextCairo.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (main): updated to match style guidelines.
+ * Spinneret/Spinneret/Spinneret.cpp:
+ (_tWinMain):
+ * Spinneret/Spinneret/WebView.cpp:
+ (WebKit::registerWebViewWithInstance):
+ (WebKit::WebView::WebView):
+ (WebKit::WebView::~WebView):
+ (WebKit::WebView::drawRect):
+ (WebKit::WndProc):
+ * Spinneret/Spinneret/WebView.h:
+
+2006-03-01 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by darin
+
+ Give the events that eventSender sends a unique eventNumber
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[EventSendingController mouseDown]):
+ (-[EventSendingController mouseUp]):
+ (-[EventSendingController mouseMoveToX:Y:]):
+
+2006-03-01 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ Add a stub win32 application to test WebCore drawing on windows.
+
+ * Spinneret: Added.
+ * Spinneret/Spinneret: Added.
+ * Spinneret/Spinneret.sln: Added.
+ * Spinneret/Spinneret/Resource.h: Added.
+ * Spinneret/Spinneret/Spinneret.cpp: Added.
+ (_tWinMain):
+ (MyRegisterClass):
+ (InitInstance):
+ (WndProc):
+ (About):
+ * Spinneret/Spinneret/Spinneret.h: Added.
+ * Spinneret/Spinneret/Spinneret.ico: Added.
+ * Spinneret/Spinneret/Spinneret.rc: Added.
+ * Spinneret/Spinneret/Spinneret.vcproj: Added.
+ * Spinneret/Spinneret/WebView.cpp: Added.
+ (WebKit::WebView::WebViewPrivate::WebViewPrivate):
+ (WebKit::WebView::WebViewPrivate::~WebViewPrivate):
+ (WebKit::registerWebViewWithInstance):
+ (WebKit::WebView::createWebView):
+ (WebKit::WebView::WebView):
+ (WebKit::WebView::~WebView):
+ (WebKit::WebView::drawRect):
+ (WebKit::WebView::windowHandle):
+ (WebKit::WndProc):
+ * Spinneret/Spinneret/WebView.h: Added.
+ * Spinneret/Spinneret/small.ico: Added.
+ * Spinneret/Spinneret/stdafx.cpp: Added.
+ * Spinneret/Spinneret/stdafx.h: Added.
+
+2006-02-28 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (main): add ability to dump render tree and read from a local file.
+
+2006-02-27 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ * Scripts/install-win-extras: fix dll permissions & download zlib too.
+
+2006-02-27 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by ggaren.
+
+ Test new KConfig -> PlugInInfoStore change.
+ http://bugs.webkit.org/show_bug.cgi?id=7498
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): load test netscape plugin
+ * Scripts/run-webkit-tests: style update
+
+2006-02-24 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Make DumpRenderTree link against icu.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.vcproj:
+
+2006-02-24 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Make DumpRenderTree link against libxml, etc.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.vcproj:
+
+2006-02-24 Mitz Pettel <opendarwin.org@mitzpettel.com>
+
+ Reviewed and landed by Anders.
+
+ Prevent rendering to the offscreen window. -[NSWindow displayIfNeeded] was
+ getting called from the run loop, making the view render each test and thus slowing
+ down the tests.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): Set the offscreen window to not autodisplay.
+
+2006-02-23 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ - Turn http tests back on by default.
+ - Wait for Apache to actually start serving requests.
+ - Get user id from a built-in variable rather than an external command;
+ don't pass the group.
+
+ * Scripts/run-webkit-tests:
+
+2006-02-23 Alexey Proskuryakov <ap@nypop.com>
+
+ Suggested by Mitz Pettel, reviewed by Darin Adler.
+
+ * Scripts/run-webkit-tests: Pass User and Group directives, so that Apache
+ can run CGIs even if the permissions are 700 or 600.
+
+2006-02-23 Darin Adler <darin@apple.com>
+
+ Collaborating with Alexey.
+
+ - turn off http tests by default until we figure out how to get them
+ to run even when permissions on CGI files are 700 instead of 755
+
+ * Scripts/run-webkit-tests: Set $testHTTP to 0 instead of 1 for now.
+
+2006-02-23 Eric Seidel <eseidel@apple.com>
+
+ Add *.user to ignore list.
+
+2006-02-23 Eric Seidel <eseidel@apple.com>
+
+ Remove binary file which shouldn't have been commited (and add to ignore list).
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree.ncb: Removed.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree.suo: Removed.
+
+2006-02-22 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Eric.
+
+ * Scripts/run-webkit-tests: Put Apache log files in the right directory.
+
+2006-02-22 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ Fix install-win-extras to not try to re-install setx if installed.
+
+ * Scripts/install-win-extras:
+
+2006-02-22 Eric Seidel <eseidel@apple.com>
+
+ One more file possibly missing from previous commit?
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree.ncb:
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree.suo:
+
+2006-02-22 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by justing.
+
+ Files missing from previous commit.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree.suo:
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.vcproj:
+
+2006-02-22 Eric Seidel <eseidel@apple.com>
+
+ Rubber-stamped by justing.
+
+ Corrected path for DumpRenderTree.intermediate files
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree.suo:
+
+2006-02-22 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by justing.
+
+ Fixed build-dumprendertree to exit with correct error codes.
+
+ * Scripts/build-dumprendertree:
+
+2006-02-22 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by justing.
+
+ Update build scripts to generalize building on Win32, and allow
+ building of DumpRenderTree on Win32 from build-dumprendertree.
+
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp:
+ (main):
+ * Scripts/build-dumprendertree:
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2006-02-22 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ * DumpRenderTree/DumpRenderTree.vcproj: Added.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree: Added.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree.ncb: Added.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree.sln: Added.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree.suo: Added.
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.cpp: Added.
+ (_tmain):
+ * DumpRenderTree/DumpRenderTree.vcproj/DumpRenderTree/DumpRenderTree.vcproj: Added.
+ * Scripts/build-webkit: make build-webkit cleanup after itself
+
+2006-02-22 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=7409
+ Some minor fixes to http tests.
+
+ * Scripts/run-webkit-tests: Pass CustomLog and ErrorLog directives to httpd.
+
+2006-02-21 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=6197
+ Would like to use locally installed Apache for testing.
+
+ Added two run-webkit-tests options:
+ --http (--nohttp) - whether to launch Apache (defaults to yes);
+ --port - which port to listen on (defaults to 8000).
+
+ Tests in LayoutTests/http are not run directly, and Apache is used instead.
+ For example, http/tests/xmlhttprequest/post-content-type.html is loaded as
+ http://127.0.0.1:8000/xmlhttprequest/post-content-type.html.
+
+ Also added support for .shtml and .text files. Text files give an empty
+ *-expected.txt, but a correct image.
+
+ Apache only listens on the loopback interface. It writes logs to /tmp/WebKit.
+
+ * Scripts/run-webkit-tests:
+
+2006-02-21 Darin Adler <darin@apple.com>
+
+ Suggested by Mark Rowe.
+
+ * Scripts/run-webkit-tests: Don't include the number of excluded leaks when
+ reporting leak counts.
+
+2006-02-18 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - Added install-win-extras script which installs some extra
+ programs and libraries, and does Windows first-time setup.
+
+ * Scripts/build-webkit: Add a newline between build results.
+ * Scripts/install-win-extras: Added.
+
+2006-02-19 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ - http://bugs.webkit.org/show_bug.cgi?id=7308
+ DumpRenderTree should be able to load files via HTTP
+
+ * DumpRenderTree/DumpRenderTree.m: (dumpRenderTree):
+ Handle tests starting with "http://" as real URLs, not file system paths.
+
+2006-02-19 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Maciej.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=7357
+ REGRESSION: Warnings from WebKit scripts if PBXProductDirectory is undefined
+
+ * Scripts/webkitdirs.pm: only call chomp if PBXProductDirectory is configured.
+
+2006-02-18 Darin Adler <darin@apple.com>
+
+ * Scripts/commit-log-editor: Added.
+
+2006-02-17 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ Make Win32 have the same default "WebKitBuild" directory behavior.
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2006-02-17 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by Beth.
+
+ * Scripts/build-webkit: make win32 actually report errors
+
+2006-02-17 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by adele.
+
+ * Scripts/run-webkit-tests: Ignore quicktime plugin leaks
+
+2006-02-17 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by adele.
+
+ * Scripts/run-webkit-tests: Ignore flash leaks
+
+2006-02-15 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by darin
+
+ <http://bugs.webkit.org/show_bug.cgi?id=7148>
+ Add drag and drop support to DumpRenderTree
+
+ Intercept the drag start using the new UI delegate method, package an NSDraggingInfo,
+ and send dragging updates. Put DumpRenderTree's WebView into an offscreen window.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main):
+ (-[WaitUntilDoneDelegate webView:didCommitLoadForFrame:]):
+ (-[WaitUntilDoneDelegate webView:dragImage:at:offset:event:pasteboard:source:slideBack:forView:]):
+ (-[WaitUntilDoneDelegate webViewFocus:]):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController setWindowIsKey:]):
+ (-[LayoutTestController setMainFrameIsFirstResponder:]):
+ (-[EventSendingController init]):
+ (-[EventSendingController mouseDown]):
+ (-[EventSendingController mouseUp]):
+ (-[EventSendingController mouseMoveToX:Y:]):
+ (dumpRenderTree):
+ (-[DumpRenderTreeWindow isKeyWindow]):
+ (-[DumpRenderTreeDraggingInfo initWithImage:offset:pasteboard:source:]):
+ (-[DumpRenderTreeDraggingInfo dealloc]):
+ (-[DumpRenderTreeDraggingInfo draggingDestinationWindow]):
+ (-[DumpRenderTreeDraggingInfo draggingSourceOperationMask]):
+ (-[DumpRenderTreeDraggingInfo draggingLocation]):
+ (-[DumpRenderTreeDraggingInfo draggedImageLocation]):
+ (-[DumpRenderTreeDraggingInfo draggedImage]):
+ (-[DumpRenderTreeDraggingInfo draggingPasteboard]):
+ (-[DumpRenderTreeDraggingInfo draggingSource]):
+ (-[DumpRenderTreeDraggingInfo draggingSequenceNumber]):
+ (-[DumpRenderTreeDraggingInfo slideDraggedImageTo:]):
+ (-[DumpRenderTreeDraggingInfo namesOfPromisedFilesDroppedAtDestination:]):
+ * DumpRenderTree/TextInputController.m:
+ (-[TextInputController firstRectForCharactersFrom:length:]):
+ (-[TextInputController characterIndexForPointX:Y:]):
+
+2006-02-15 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Eric.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[LayoutTestController invokeUndefinedMethodFromWebScript:withArguments:]):
+ Added a dummy method for the sake of LayoutTests/plugins/
+ undefined-property-crash.html. (It tests a crash due to fallback
+ object use. WebCore won't create a fallback object if the method is
+ not defined.)
+
+2006-02-14 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by adele.
+
+ * Scripts/run-webkit-tests: added --results-directory (-o) option
+
+2006-02-09 Eric Seidel <eseidel@apple.com>
+
+ Rubber-stamped by mjs.
+
+ Renamed split-class to split-file-by-class.
+
+ * Scripts/build-webkit: Updated copyright.
+ * Scripts/split-class: Removed.
+ * Scripts/split-file-by-class: Added.
+
+2006-02-08 Eric Seidel <eseidel@apple.com>
+
+ Rubber-stamped by mjs.
+
+ Adding new script for splitting multi-class files.
+ Also adding supporting perl module with space removing heuristics.
+
+ * Scripts/SpacingHeuristics.pm: Added.
+ * Scripts/build-drawtest: updated copyright header
+ * Scripts/split-class: Added.
+
+2006-02-08 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by thatcher
+
+ Changes to test fix for:
+ <http://bugs.webkit.org/show_bug.cgi?id=3982>
+ webViewDidBeginEditing, webViewDidEndEditing notification methods not called on delegate
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:didCommitLoadForFrame:]):
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]):
+ (+[LayoutTestController webScriptNameForSelector:]):
+ (-[LayoutTestController setWindowHasFocus:]):
+ (-[LayoutTestController setDisplaysWithFocusAttributes:]):
+
+2006-02-07 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Timothy.
+
+ Support automated testing of AppleScript "do JavaScript" command
+ http://bugs.webkit.org/show_bug.cgi?id=7012
+
+ * DumpRenderTree/AppleScriptController.h: Added.
+ * DumpRenderTree/AppleScriptController.m: Added.
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:windowScriptObjectAvailable:]):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+2006-02-06 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ Fix build-webkit for use on win32 (unblocks buildbot usage).
+ http://bugs.webkit.org/show_bug.cgi?id=7122
+
+ * Scripts/build-webkit: use ifCygwin() to conditionalize builds
+ * Scripts/webkitdirs.pm: add ifOSX() and ifCygwin()
+
+2006-02-06 Eric Seidel <eseidel@apple.com>
+
+ Rubber-stamped by darin & mjs.
+
+ Added new support directory for build slave scripts.
+ Committing the first script, for use by the PLT's build slave.
+ This script is used to kick of the PLT (Page Load Test) slave.
+
+ * BuildSlaveSupport: Added.
+ * BuildSlaveSupport/run-performance-tests: Added.
+
+2006-02-06 Eric Seidel <eseidel@apple.com>
+
+ Rubber-stamped by darin.
+
+ Adding setSourceDir for scripts stored in non-standard locations.
+
+ * Scripts/webkitdirs.pm:
+
+2006-02-04 Darin Adler <darin@apple.com>
+
+ * Scripts/webkitdirs.pm: Add a compatibilty hack for people with old
+ Configuration files that say Development or Deployment in them.
+
+2006-02-04 Darin Adler <darin@apple.com>
+
+ * Scripts/make-js-test-wrappers: Don't create a wrapper if there's a disabled
+ wrapper already in the directory.
+ * Scripts/svn-apply: Handle additions and deletions properly -- I've been noticing
+ these haven't been working at all.
+ * Scripts/svn-unapply: Ditto.
+
+2006-02-03 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Justin.
+
+ Renamed configuration names to Debug, Release and Production.
+
+ * DrawTest/DrawTest.xcodeproj/project.pbxproj:
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * Scripts/set-webkit-configuration:
+ * Scripts/webkitdirs.pm:
+
+2006-02-02 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by thatcher
+
+ Enabled spell checking for layout tests.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main):
+
+2006-01-29 Darin Adler <darin@apple.com>
+
+ * Scripts/svn-apply: Added comments about things we should do to improve.
+ * Scripts/svn-create-patch: Ditto.
+ * Scripts/svn-unapply: Ditto.
+
+2006-01-28 Darin Adler <darin@apple.com>
+
+ * DumpRenderTree/DumpRenderTree.m: (dump): Dump the image if it's not
+ already there, even if the checksum is correct.
+
+2006-01-27 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by adele.
+
+ * Scripts/run-webkit-tests: make new tests use absolute urls
+
+2006-01-27 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ make run-webkit-tests output total leaks count
+
+ * Scripts/run-webkit-tests:
+
+2006-01-27 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ run-webkit-test --leaks crashes (malloc logging runs out of memory)
+ http://bugs.webkit.org/show_bug.cgi?id=6869
+
+ * Scripts/run-webkit-tests: fix --leaks to not crash
+
+2006-01-26 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ run-webkit-tests should produce a self-contained results directory
+ http://bugs.webkit.org/show_bug.cgi?id=6864
+
+ * Scripts/run-webkit-tests: copy failing items to results dir.
+
+2006-01-23 Darin Adler <darin@apple.com>
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=3608
+ need script to update localizable strings file in WebKit
+
+ * Scripts/update-webkit-localizable-strings: Added.
+
+2006-01-23 Darin Adler <darin@apple.com>
+
+ - added a couple of scripts -- more about these two soon
+
+ * Scripts/extract-localizable-strings: Added.
+ * Scripts/merge-changelog: Added.
+
+2006-01-22 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by Anders.
+
+ Build fix. build-webkit dies with "invalid build action: (empty string)"
+
+ * Scripts/build-webkit:
+ Use svgOptions in an array context so xcodebuild doesn't choke on an empty argument.
+
+2006-01-22 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by anders.
+
+ Fix --no-svg option to use XCode flags instead of gcc flags.
+
+ * Scripts/build-webkit:
+
+2006-01-22 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by anders.
+
+ Update build-webkit to use -USVG_SUPPORT instead of -no-SVG target.
+
+ * Scripts/build-webkit:
+
+2006-01-20 David Kilzer <ddkilzer@kilzer.net>
+
+ Reviewed by eseidel.
+
+ - fix for http://bugs.webkit.org/show_bug.cgi?id=6682
+ Call to checkWebCoreSVGSupport() broken in build-drawtest and run-drawtest
+
+ * Scripts/build-drawtest: Changed bareword 'true' to 1.
+ * Scripts/run-drawtest: Changed bareword 'true' to 1.
+
+2006-01-19 Darin Adler <darin@apple.com>
+
+ * Scripts/report-include-statistics: Added a new script.
+
+2006-01-19 Timothy Hatcher <timothy@apple.com>
+
+ * Scripts/build-webkit: include JavaScriptGlue in the build
+
+2006-01-19 Darin Adler <darin@apple.com>
+
+ * Scripts/webkitdirs.pm: Changed SVG check to work even if the path has
+ spaces in it by using the form of open that treats each argument as a string
+ rather than backtick syntax for reading the output of the nm tool.
+
+2006-01-12 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - make prepare-ChangeLog way faster by using svn diff instead of svn status to
+ detect if there are any new tests
+
+ * Scripts/prepare-ChangeLog:
+
+2006-01-12 Darin Adler <darin@apple.com>
+
+ - removed some of the cvs-specific scripts -- not needed for this project any more
+
+ * Scripts/cvs-abandon: Removed.
+ * Scripts/cvs-apply: Removed.
+ * Scripts/cvs-create-patch: Removed.
+ * Scripts/cvs-unapply: Removed.
+
+2006-01-10 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by eseidel. Committed by eseidel.
+
+ - run-webkit-tests always launches Safari when tests fail
+ http://bugs.webkit.org/show_bug.cgi?id=6456
+
+ * Scripts/run-webkit-tests:
+ Add a command-line flag to prevent Safari being launched to display failed
+ tests. Always exit with non-zero status when tests have failed.
+
+2006-01-10 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed by eseidel. Committed by eseidel.
+
+ - build-webkit should exit with non-zero status when build fails
+ http://bugs.webkit.org/show_bug.cgi?id=6459
+
+ * Scripts/build-webkit:
+ Use correct bits of subprocess exit code when passing back through
+ as build-webkit's exit code.
+
+2006-01-10 Eric Seidel <eseidel@apple.com>
+
+ Restored corrupted nibs from TOT CVS.
+
+ * DrawTest/English.lproj/DrawTestDocument.nib: Replaced.
+ * DrawTest/English.lproj/DrawTestDocument.nib/classes.nib: Replaced.
+ * DrawTest/English.lproj/DrawTestDocument.nib/info.nib: Replaced.
+ * DrawTest/English.lproj/DrawTestDocument.nib/keyedobjects.nib: Replaced.
+ * DrawTest/English.lproj/Inspector.nib: Replaced.
+ * DrawTest/English.lproj/Inspector.nib/classes.nib: Replaced.
+ * DrawTest/English.lproj/Inspector.nib/info.nib: Replaced.
+ * DrawTest/English.lproj/Inspector.nib/keyedobjects.nib: Replaced.
+ * DrawTest/English.lproj/MainMenu.nib: Replaced.
+ * DrawTest/English.lproj/MainMenu.nib/classes.nib: Replaced.
+ * DrawTest/English.lproj/MainMenu.nib/info.nib: Replaced.
+ * DrawTest/English.lproj/MainMenu.nib/keyedobjects.nib: Replaced.
+ * DrawTest/English.lproj/TestViewer.nib: Replaced.
+ * DrawTest/English.lproj/TestViewer.nib/classes.nib: Replaced.
+ * DrawTest/English.lproj/TestViewer.nib/info.nib: Replaced.
+ * DrawTest/English.lproj/TestViewer.nib/keyedobjects.nib: Replaced.
+
+2006-01-10 Nefaur Khandker <nefaurk@gmail.com>
+
+ Reviewed by eseidel. Committed by eseidel.
+
+ DrawTestView now subclasses WebView instead of DrawView.
+
+ * DrawTest/DrawTest.xcodeproj/project.pbxproj:
+ * DrawTest/DrawTestDocument.h:
+ * DrawTest/DrawTestDocument.m:
+ (-[DrawTestDocument dealloc]):
+ (-[DrawTestDocument readFromFile:ofType:]):
+ (-[DrawTestDocument windowControllerDidLoadNib:]):
+ (-[DrawTestDocument dumpSVGToConsole:]):
+ (-[DrawTestDocument openSourceForSelection:]):
+ (-[DrawTestDocument dataRepresentationOfType:]):
+ * DrawTest/DrawTestToolbarController.h:
+ * DrawTest/DrawTestToolbarController.m:
+ (-[DrawTestToolbarController initWithDrawView:]):
+ (-[DrawTestToolbarController clickedToolbarItem:]):
+ (-[DrawTestToolbarController validateToolbarItem:]):
+ * DrawTest/DrawTestView.h:
+ * DrawTest/DrawTestView.m:
+ (-[DrawTestView initWithFrame:]):
+ (-[DrawTestView setDocument:]):
+ * DrawTest/SVGTest.h:
+ * DrawTest/SVGTest.m:
+ (+[SVGTest sharedDrawView]):
+ (-[SVGTest generateCompositeIfNecessary]):
+ * DrawTest/TestController.h:
+ * DrawTest/TestController.m:
+ (-[TestController awakeFromNib]):
+ (-[TestController setSelectedTest:]):
+ (-[TestController openTestViewerForSelection:]):
+ (-[TestController toggleViewersScaleRule:]):
+ * DrawTest/TestViewerSplitView.m:
+ (-[TestViewerSplitView drawRect:]):
+
+2006-01-10 Anders Carlsson <andersca@mac.com>
+
+ Reviewed by Timothy.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): Set the default language to "en", so language tests will work.
+
+2006-01-08 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Eric.
+
+ - script to generate HTML wrappers for JS tests
+ http://bugs.webkit.org/show_bug.cgi?id=6441
+
+ * Scripts/make-js-test-wrappers: Added.
+
+2006-01-08 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Eric.
+
+ * Scripts/svn-create-patch: Fix to work when passed directory names.
+
+2006-01-08 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Eric.
+
+ - Added back/forward navigation support to DumpRenderTree. Hopefully we
+ can start writing automated loader tests now. I have one in the works.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): Construct global navigationController on entry, destroy on exit.
+ Set frame to nil on exit too, to match all the other global objects.
+ (Probably academic, since the process is exiting, anyway.)
+ (-[WaitUntilDoneDelegate webView:didFinishLoadForFrame:]): Notify the
+ navigationController, in case it wants to kick off a load.
+ (-[WaitUntilDoneDelegate webView:windowScriptObjectAvailable:]): Expose
+ the navigationController to scripting.
+
+ New class, should be straightforward:
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/NavigationController.h: Added.
+ * DumpRenderTree/NavigationController.m: Added.
+
+ (+[NavigationController isSelectorExcludedFromWebScript:]):
+ (+[NavigationController webScriptNameForSelector:]):
+ (-[NavigationController setPendingScript:]):
+ (-[NavigationController setPendingRequest:]):
+ (-[NavigationController evaluateWebScript:afterBackForwardNavigation:]):
+ (-[NavigationController webView:didFinishLoadForFrame:]):
+ (-[NavigationController dealloc]):
+
+2006-01-08 Timothy Hatcher <timothy@apple.com>
+
+ Removed this script, no longer needs with the Subversion switch.
+
+ * checkout: Removed.
+
+2006-01-08 Timothy Hatcher <timothy@apple.com>
+
+ Removes some stray tabs.
+
+ * Scripts/update-webkit:
+
+2005-01-07 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ build-webkit should pass on build arguments from command line
+ http://bugs.webkit.org/show_bug.cgi?id=5854
+
+ * Scripts/build-webkit:
+
+2006-01-07 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs & xenon.
+
+ * Scripts/update-webkit: support Internal updates as well
+
+2006-01-06 Geoffrey Garen <ggaren@apple.com>
+
+ Temporarily rolling out plugin support from DumpRenderTree because it
+ caused lots of layout test regressions.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): Remove invisible window added to support plugins.
+
+2006-01-06 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by darin.
+
+ - Fixed http://bugs.webkit.org/show_bug.cgi?id=6361
+ Add plugin support to DumpRenderTree
+
+ Also wrote first test plugin.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main):
+ (1) Put the WebView in an invisible window, because PlugIns are
+ optimized not to load if there's no parent window.
+ (2) Tell WebKit to load any PlugIns in the directory from which we
+ loaded. This means we can build nasty PlugIns alongside DumpRenderTree
+ and they'll load automagically during layout testing, but they won't be
+ added to the user's system, hosing apps like Safari.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Added new
+ test PlugIn to project.
+
+ PlugIn added to project:
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/Info.plist: Added.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.c: Added.
+ (getPluginClass):
+ (initializeIdentifiers):
+ (pluginHasProperty):
+ (pluginHasMethod):
+ (pluginGetProperty):
+ (pluginSetProperty):
+ (pluginInvoke):
+ (pluginInvokeDefault):
+ (pluginInvalidate):
+ (pluginAllocate):
+ (pluginDeallocate):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h: Added.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.c: Added.
+ (NP_Initialize):
+ (NP_GetEntryPoints):
+ (NP_Shutdown):
+ (NPP_New):
+ (NPP_Destroy):
+ (NPP_SetWindow):
+ (NPP_NewStream):
+ (NPP_DestroyStream):
+ (NPP_WriteReady):
+ (NPP_Write):
+ (NPP_StreamAsFile):
+ (NPP_Print):
+ (NPP_HandleEvent):
+ (NPP_URLNotify):
+ (NPP_GetValue):
+ (NPP_SetValue):
+
+2006-01-04 Timothy Hatcher <timothy@apple.com>
+
+ Reviewed by Darin Adler.
+ Created by Eric.
+ Tweaked and tested by me.
+
+ New scripts to work with Subversion when the switch happens.
+ These will replace cvs-apply, cvs-unapply, and cvs-create-patch.
+
+ * Scripts/svn-apply: Added.
+ * Scripts/svn-create-patch: Added.
+ * Scripts/svn-unapply: Added.
+
+2005-12-30 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Move WebView width/height logic into DumpRenderTree to support
+ running the W3C SVG 1.1 tests along side other tests. The W3C
+ SVG 1.1 tests require a 480x360 view.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): don't accept width/height
+ (dump): override width/height for SVG/W3C
+ * Scripts/run-webkit-tests: don't pass width/height
+
+2005-12-30 Eric Seidel <eseidel@apple.com>
+
+ No review, only removing dead code.
+
+ * DumpKCanvasTree/DumpKCanvasTree.m: Removed.
+ * DumpKCanvasTree/DumpKCanvasTree.xcodeproj/project.pbxproj: Removed.
+
+2005-12-30 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ DumpRenderTree should set a consistent color profile while running
+ http://bugs.webkit.org/show_bug.cgi?id=6155
+
+ Creates consistent colormatched renderings on every test machine
+ using the only way possible with Tiger APIs: by setting the
+ system color profile on the test machine for the duration of the
+ tests. This will (unfortunately) cause colors to change while
+ running DumpRenderTree. This can also cause "permanent" color
+ changes to occur if DRT is to crash (SIGSEGV, etc.) while running.
+ This is far from ideal, but it's be best way we've found to deal
+ with the issue for now.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (restoreColorSpace):
+ (setDefaultColorProfileToRGB):
+ (main):
+
+2005-12-20 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=5846
+ cvs-create-patch --include produces incorrect paths
+
+ * Scripts/cvs-create-patch: Handle newly-added directories using chdir.
+
+2005-12-19 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ * Scripts/run-webkit-tests: stop /etc/catalog warnings
+
+2005-12-19 Darin Adler <darin@apple.com>
+
+ Reviewed by Eric Seidel.
+
+ - fix http://bugs.webkit.org/show_bug.cgi?id=4990
+ WebKit needs to use a local pasteboard during testing
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): Call poseAs to substitute our NSPasteboard class for the default one.
+ Create a local pasteboard (really a global one with a unique name) and release
+ it when exiting from the function so we don't leave it in the pasteboard server.
+ (dumpRenderTree): Added an autorelease pool around one small bit of code that
+ ddn't have one. Fixed a leak in an unlikely error case.
+ (+[DumpRenderTreePasteboard generalPasteboard]): Override the default version
+ of this method to return our local pasteboard.
+
+2005-12-15 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ * Scripts/build-webkit: --svg is now default!
+
+2005-12-15 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Don't run svg test automatically if +SVG is built (yet).
+
+ * Scripts/run-webkit-tests:
+
+2005-12-15 Darin Adler <darin@apple.com>
+
+ * Scripts/run-webkit-tests: Don't run tests in directories named "svg" if SVG
+ support is not compiled in. Report the 10 slowest tests if "--slowest" is
+ passed on the command line.
+
+2005-12-06 John Sullivan <sullivan@apple.com>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/prepare-ChangeLog:
+ Remove special-case handling for nib files. This avoided trouble with cvs diff
+ when we were using wrappers for nib files. Now that we aren't using wrappers,
+ there's no reason to avoid adding the modified nib files to the file list that
+ gets diffed.
+
+2005-12-05 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Script updates for SVG files move (remove references to SVGSupport)
+
+ * Scripts/build-webkit: remove SVGSupport
+ * Scripts/run-webkit-tests: Resources -> resources for --svg
+ * Scripts/update-webkit: remove SVGSupport
+
+2005-12-05 Eric Seidel <eseidel@apple.com>
+
+ Reviewed mjs.
+
+ * checkout: remove --svg support, SVG is now checked out by default
+
+2005-11-29 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ Update scripts to run SVG tests automatically (w/o --svg) if
+ WebCore is built with SVG support.
+
+ * Scripts/build-drawtest: SVG support required
+ * Scripts/build-dumpkcanvastree: Removed.
+ * Scripts/run-drawtest: SVG support required to run
+ * Scripts/run-webkit-tests: pass *.svg files if WebCore has support
+ * Scripts/webkitdirs.pm: changed CheckWebCoreSVGSupport
+
+2005-11-28 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed by Darin Adler. Committed by Maciej.
+
+ - fixed "DumpRenderTree should test for Ahem before doing anything else"
+ (http://bugs.webkit.org/show_bug.cgi?id=5838)
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main):
+
+2005-11-28 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by sullivan and GGAREN.
+
+ Minor additions to make error messages more clear from cvs-apply.
+
+ * Scripts/cvs-apply: make errors more clear
+
+2005-11-27 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+
+ Reviewed and committed by Maciej.
+
+ - fixed cvs-create-patch --include produces incorrect paths
+ (http://bugs.webkit.org/show_bug.cgi?id=5846)
+
+ * Scripts/cvs-create-patch: produce proper paths for new files.
+
+2005-11-21 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ Some simple fixes to the build/test scripts now that SVG uses the
+ WebCore DOM. JSC+SVG is no longer needed, nor is RTTI support
+ or symlinks for KDOM.
+
+ * Scripts/build-webkit: No longer builds JavaScriptCore+SVG
+ * Scripts/prepare-ChangeLog: handles missing LayoutTests directory
+ * Scripts/run-webkit-tests: now runs SVG tests using DRT
+ * Scripts/webkitdirs.pm: use SVG symbols instead of RTTI
+ * checkout: no longer symlink kdom
+
+2005-11-10 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by ggaren.
+
+ * Scripts/build-webkit: Pass through options to xcodebuild
+
+2005-11-07 Darin Adler <darin@apple.com>
+
+ * Scripts/cvs-apply: Fix case where the patch has files at the top level.
+
+2005-11-03 John Sullivan <sullivan@apple.com>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/run-safari:
+ changed message to say "Starting Safari" instead of odd "Start Safari"
+ * Scripts/run-webkit-tests:
+ changed the way we pass the file parameter to use -NSOpen rather than relying on
+ unlabeled arguments being treated as files. This was failing on some machines that
+ (mysteriously) had NSTreatUnknownArgumentsAsOpen set to NO in com.apple.Safari.plist.
+
+2005-10-27 Geoffrey Garen <ggaren@apple.com>
+
+ Patch by Alexey Proskuryakov.
+
+ Reviewed by Maciej.
+
+ Fixes http://bugs.webkit.org/show_bug.cgi?id=5303
+ TextInputController should support attributed strings
+
+ * DumpRenderTree/TextInputController.m:
+ (+[NSMutableAttributedString isSelectorExcludedFromWebScript:]):
+ (+[NSMutableAttributedString webScriptNameForSelector:]):
+ (-[NSMutableAttributedString getLength]):
+ (-[NSMutableAttributedString attributeNamesAtIndex:]):
+ (-[NSMutableAttributedString valueOfAttribute:atIndex:]):
+ (-[NSMutableAttributedString addAttribute:value:]):
+ (-[NSMutableAttributedString addAttribute:value:from:length:]):
+ (-[NSMutableAttributedString addColorAttribute:red:green:blue:alpha:]):
+ (-[NSMutableAttributedString addColorAttribute:red:green:blue:alpha:from:length:]):
+ (-[NSMutableAttributedString addFontAttribute:fontName:size:]):
+ (-[NSMutableAttributedString addFontAttribute:fontName:size:from:length:]):
+ (+[TextInputController isSelectorExcludedFromWebScript:]):
+ (+[TextInputController webScriptNameForSelector:]):
+ (-[TextInputController insertText:]):
+ (-[TextInputController attributedSubstringFrom:length:]):
+ (-[TextInputController attributedStringWithString:]):
+
+2005-10-11 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ Checks for leaks in ImageDiff too.
+
+ * Scripts/run-webkit-tests:
+
+2005-10-09 Darin Adler <darin@apple.com>
+
+ * Scripts/check-dom-results: Dump ".xhtml" for tests in the xhtml directory.
+ * Scripts/cvs-apply: Handle added/deleted files in the current directory.
+ * Scripts/cvs-unapply: Ditto.
+ * Scripts/run-webkit-tests: Add a few more false-positive leaks.
+
+2005-10-08 Alexey Proskuryakov <ap@nypop.com>
+
+ Reviewed, rearranged and landed by Darin Adler.
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=4707
+ Need a way to automatically test for regressions in NSTextInput implementation
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:windowScriptObjectAvailable:]):
+ Create a text input controller and put it in a property of the window object.
+
+ * DumpRenderTree/TextInputController.h: Added.
+ * DumpRenderTree/TextInputController.m: Added.
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Added files.
+
+2005-10-06 Darin Adler <darin@apple.com>
+
+ * Scripts/cvs-apply: Fixed merge option to work better when not all directories
+ are controlled by cvs, or when changes cross multiple repositories.
+ * Scripts/update-webkit: Don't print messages if the "quiet" flag is set.
+
+2005-10-03 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Make mouseDown and mouseUp force layout before acting.
+ This is used by a new test case for 4233558.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[EventSendingController mouseDown]): force layout
+ (-[EventSendingController mouseUp]): force layout
+
+2005-09-30 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by xenon.
+
+ Updated all the scripts for the move:
+ WebCore/layout-tests -> LayoutTests
+
+ * Scripts/check-dom-results:
+ * Scripts/prepare-ChangeLog:
+ * Scripts/run-webkit-tests:
+ * Scripts/update-webkit: added --no-tests
+ * checkout: added --no-tests
+
+2005-09-28 Darin Adler <darin@apple.com>
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=5144
+ pixel test should run even if render trees differ
+
+ * Scripts/run-webkit-tests: Don't check if the text dump matches.
+
+2005-09-27 Eric Seidel <eseidel@apple.com>
+
+ No review needed, SVG build fix only.
+
+ * DumpKCanvasTree/DumpKCanvasTree.m:
+ Missed one in my previous checkin.
+ http://bugs.webkit.org/show_bug.cgi?id=5141
+
+2005-09-26 Eric Seidel <eseidel@apple.com>
+
+ No review needed, SVG build fix only.
+
+ * DrawTest/DrawTestDocument.m:
+ * DrawTest/DrawTestToolbarController.m:
+ * DrawTest/DrawTestView.h:
+ * DrawTest/DrawTestView.m:
+ * DrawTest/SVGTest.m:
+ * DrawTest/TestController.m:
+ Updated for WebCore+SVG -> WebCore rename.
+ http://bugs.webkit.org/show_bug.cgi?id=5141
+
+2005-09-26 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (dump): updated error message
+ * Scripts/check-dom-results: now includes xhtml
+ Tool updates for xhtml.
+ http://bugs.webkit.org/show_bug.cgi?id=4907
+
+2005-09-22 Duncan Wilcox <duncan@mclink.it>
+
+ Reviewed by Maciej.
+ Landed by Darin Adler.
+
+ - patch for <http://bugs.webkit.org/show_bug.cgi?id=4963>
+ "Would like to simulate human interaction with webview"
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:windowScriptObjectAvailable:]):
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (+[EventSendingController webScriptNameForSelector:]):
+ (-[EventSendingController init]):
+ (-[EventSendingController mouseDown]):
+ (-[EventSendingController mouseUp]):
+ (-[EventSendingController mouseMoveToX:Y:]):
+ Add eventSender javascript object, that sends fake mouse events to the webview.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ link with Carbon.framework
+
+2005-09-22 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ Update tools for WebCore+SVG -> WebCore rename.
+ Also fold several SVG specific tools into their original
+ WebCore counterparts.
+ http://bugs.webkit.org/show_bug.cgi?id=5003
+
+ * DrawTest/DrawTest.xcodeproj/project.pbxproj:
+ * DumpKCanvasTree/DumpKCanvasTree.xcodeproj/project.pbxproj:
+ * Scripts/build-drawtest:
+ * Scripts/build-dumpkcanvastree:
+ * Scripts/build-webcore-svg: Removed.
+ * Scripts/build-webkit: added --svg option
+ * Scripts/run-drawtest:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm: various additions.
+ * checkout: added --svg option
+ * checkout-svg: Removed.
+
+2005-09-19 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ * Scripts/run-webkit-tests: added --guard-malloc option
+ http://bugs.webkit.org/show_bug.cgi?id=4613
+
+2005-09-16 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by geoff
+
+ Removed a script that is only used by apple internal developers
+
+ * Scripts/update-webkitsysteminterface: Removed.
+
+2005-09-16 Adele Peterson <adele@apple.com>
+
+ Reviewed by Maciej.
+
+ * Scripts/prepare-ChangeLog: Allow semicolons for protocols too.
+
+2005-09-14 Darin Adler <darin@apple.com>
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=4291
+ dumpAsText doesn't work with XHTML documents
+
+ * DumpRenderTree/DumpRenderTree.m: (dump): Dump the innerText of the document element
+ rather than of the body element. This works with typical XHTML documents. We can probably
+ do something even better in the long run, but this fixes the immediate issue.
+
+ - separate tweak
+
+ * Scripts/run-webkit-tests: Show the results in the current built Safari by using
+ run-safari instead of just using "open", which often runs another copy of Safari instead.
+
+2005-09-11 Mark Rowe <opendarwin.org@bdash.net.nz>
+
+ Reviewed, tweaked, and landed by Darin Adler.
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=4286
+ .Mac prefpane crashes when Safari using CVS WebKit is running
+
+ * Scripts/run-safari: Set WEBKIT_UNSET_DYLD_FRAMEWORK_PATH.
+ * Scripts/run-webkit-app: Ditto.
+
+2005-09-11 Darin Adler <darin@apple.com>
+
+ * Scripts/run-webkit-tests: Oops. Use spaces, not tabs.
+
+2005-09-11 Darin Adler <darin@apple.com>
+
+ Reviewed by Eric.
+
+ * Scripts/run-webkit-tests: Sort tests with a new "pathcmp" function that's better in
+ two ways: 1) puts all files in a directory before any files in a subdirectory, and
+ 2) sort file names with numeric digits in them in a logical way, so test-33 will come
+ before test-3.
+
+2005-09-08 Justin Garcia <justin.garcia@apple.com>
+
+ Reviewed by darin
+
+ * Scripts/update-webkitsysteminterface: Added.
+ Builds webkitsysteminterface and moves the built product and header into WebKitLibraries
+
+2005-09-01 John Sullivan <sullivan@apple.com>
+
+ * Scripts/run-webkit-tests:
+ Excluded a known system leak to reduce noise; added comments about which leaks
+ are being excluded.
+
+2005-09-01 Tim Omernick <tomernick@apple.com>
+
+ Change made by Darin, reviewed by John and myself.
+
+ - Allow semicolons at the end of method declarations (this is for method implementations; the semicolon is required for interface declarations).
+
+ * Scripts/prepare-ChangeLog:
+
+2005-08-31 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - set color variant and font settings to a consistent value.
+ (http://bugs.webkit.org/show_bug.cgi?id=4769)
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main):
+
+2005-08-30 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ * Scripts/build-svg2png: Removed.
+ * svg2png/ImageDiff.h: Removed.
+ * svg2png/ImageDiff.m: Removed.
+ * svg2png/svg2png.m: Removed.
+ * svg2png/svg2png.xcodeproj/project.pbxproj: Removed.
+ * svg2png/svg2png_Prefix.pch: Removed.
+ svg2png is no longer needed.
+
+2005-08-30 Darin Adler <darin@apple.com>
+
+ * Scripts/check-dom-results: Special case 100% to say something nice.
+ * Scripts/cvs-apply: Added "--merge" which automatically rolls back the tree before
+ applying the patch (need a better name).
+ * Scripts/find-extra-includes: Added. Experimental tool to find unneeded includes.
+
+2005-08-30 Darin Adler <darin@apple.com>
+
+ * Scripts/run-webkit-tests: Small formatting fix for leaks mode.
+
+2005-08-29 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=4723
+ (some pixel tests fail when AA settings are changed)
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): set AA settings to the default values
+
+2005-08-29 Darin Adler <darin@apple.com>
+
+ Reviewed by John Sullivan.
+
+ * Scripts/run-webkit-tests: Added a mode where each test is run with a separate
+ executable -- much slower but can help pinpoint leaks. Changed formatting of some
+ messages too.
+
+2005-08-28 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Eric.
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=4720
+ (webkit pixel tests don't give consistent results with changed scrollbar arrow setting)
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): set scrollbar arrow setting to a consistent value
+
+2005-08-27 Jussi Hagman <juhagman@abo.fi>
+
+ Reviewed and landed by Darin Adler.
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=4676
+ output of update-webkit is too verbose
+
+ * Scripts/update-webkit:
+ Added option --quiet (-q) to decrease the amount of output.
+
+2005-08-27 Darin Adler <darin@apple.com>
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=4596
+ cvs-create-patch --include-unknowns should ignore hidden files
+
+ * Scripts/cvs-create-patch: Add code to check for files starting with ".".
+
+2005-08-25 Ben La Monica <ben.lamonica@gmail.com>
+
+ Reviewed, tweaked, and landed by Darin Adler.
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=4585
+ update-webkit doesn't notice when you have SVGSupport and update properly
+
+ * Scripts/update-webkit: Build SVGSupport directory if it's present.
+
+2005-08-25 Anders Carlsson <andersca@mac.com>
+
+ Reviewed and landed by Darin Adler.
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=4572
+ layout test machinery can't handle tests with applets that have code attributes
+
+ * DumpRenderTree/DumpRenderTree.m: (main): Disable Java while running tests.
+
+2005-08-24 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej.
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=4625
+ DumpRenderTree --pixel-tests crash
+ - landed some other small changes I had sitting in my tree
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): Don't bother saving and restoring the preferences. Not sure
+ why this was ever done since the preferences are specific to DumpRenderTree.
+ Clear delegates before releasing the WebView, because you can't count on the
+ order of object deallocation.
+ (dumpRenderTree): Fix code that releases a string before storing it in a
+ global variable.
+
+ * Scripts/run-webkit-tests: Use "-s" rather than a function to get the size
+ of a file. Fix lots of cases that were using tabs for indenting to use spaces instead.
+
+2005-08-23 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ * Scripts/run-webkit-tests:
+ Made --leaks option more readable by printing to a file.
+ http://bugs.webkit.org/show_bug.cgi?id=4590
+
+2005-08-22 Eric Seidel <eseidel@apple.com>
+ Fix by Tobias Lidskog <tobiaslidskog@mac.com>
+
+ Reviewed by darin.
+
+ * Scripts/run-webkit-tests: hides "expected actual diffs" links
+ when they are not needed (for pixel-only failures)
+ http://bugs.webkit.org/show_bug.cgi?id=4584
+
+2005-08-22 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ * Scripts/run-webkit-tests: Added the ability to display more than
+ just two images as part of the image-diff "slideshow".
+ Added display of "-w3c.png" baseline images for SVG.
+ http://bugs.webkit.org/show_bug.cgi?id=4581
+
+2005-08-20 Eric Seidel <eseidel@apple.com>
+
+ * Scripts/run-webkit-tests:
+ "build" fix after committing incorrect version.
+
+2005-08-20 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main): cleans up delegates
+ (dumpRenderTree): closes CFString/CFURL leak
+ * Scripts/run-webkit-tests:
+ Adds --leaks option to run-webkit-tests
+ http://bugs.webkit.org/show_bug.cgi?id=4542
+
+2005-08-19 Ben La Monica <ben.lamonica@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/cvs-create-patch: Add an --include-unknowns option that will cause
+ new files to be included in the patch even without "cvs add".
+
+2005-08-19 Darin Adler <darin@apple.com>
+
+ * Scripts/cvs-apply: Fix to not garble patches that are mix of cvs-style and
+ non-cvs-generated patches. Anders has been creating these, so it's bad that
+ the script can't handle them.
+ * Scripts/cvs-unapply: Ditto.
+
+2005-08-18 Darin Adler <darin@apple.com>
+
+ * Scripts/webkitdirs.pm: Fix version checking to work on Xcode versions with
+ "." in them -- based on complaint by someone here at Apple.
+
+2005-08-18 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ * Scripts/run-webkit-tests:
+ Made --svg imply --pixel-tests (pixel tests on-by-default for svg).
+
+2005-08-17 Maciej Stachowiak <mjs@apple.com>
+
+ - add file that I forgot in the last checkin
+
+ * DumpRenderTree/ImageDiff.m: Added.
+ (main):
+ (getImageFromStdin):
+ (compareImages):
+ (getDifferenceBitmap):
+ (computePercentageDifferent):
+
+2005-08-17 Maciej Stachowiak <mjs@apple.com>
+
+ Changes by Ben Lamonica and Eric Seidel, reviewed mostly by Eric and
+ somewhat by me, and also tweaked by me a little bit.
+
+ - better support for pixel-dumping
+ - use checksums of the images so the tests are fast
+ - change output format to make the tests run faster
+ - don't dump pixel results for tests that dump as text
+
+ * DumpKCanvasTree/DumpKCanvasTree.m:
+ (main):
+ (dumpRenderTree):
+ (md5HashStringForBitmap):
+ (dumpPixelTests):
+ (constrainSizeToMaximum):
+ (getBitmapImageRepForSVGDocument):
+ * DumpKCanvasTree/DumpKCanvasTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/DumpRenderTree.m:
+ (main):
+ (dump):
+ (dumpRenderTree):
+ (md5HashStringForBitmap):
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * Scripts/run-webkit-tests:
+
+2005-08-17 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - hacked DumpRenderTree to make the scrollbars appear and disappear properly.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main):
+
+2005-08-14 Oliver Hunt <ojh16@student.canterbury.ac.nz>
+
+ Reviewed and landed by Darin Adler.
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=4251
+ Ideally would be able to pass arguments to apps using run-safari and run-webkit-app scripts
+
+ * Scripts/run-safari: Pass arguments through to Safari on command line.
+ * Scripts/run-webkit-app: Pass arguments through to "open" tool on command line.
+
+2005-08-11 Eric Seidel <eseidel@apple.com>
+ Fix by Tobias Lidskog <tobiaslidskog@mac.com>
+
+ Reviewed by eseidel.
+
+ * DrawTest/TestController.m:
+ (-[TestController imagePathForSVGPath:]):
+ Fixed support for using TextViewer with the layout-tests.
+ http://bugs.webkit.org/show_bug.cgi?id=4385
+
+2005-08-11 Maciej Stachowiak <mjs@apple.com>
+
+ At Least Roughly Glanced At by Anders.
+
+ - fix change with totally breaks the layout tests.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:didCommitLoadForFrame:]): Make tests unready if you start another
+ load, to avoid dumping twice accidentally.
+
+2005-08-10 Eric Seidel <eseidel@apple.com>
+ Fixed made by Mitz Pettel <opendarwin.org@mitzpettel.com>
+
+ Reviewed by darin.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ Added support for rendering to a PNG file.
+ http://bugs.webkit.org/show_bug.cgi?id=3840
+
+2005-08-07 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ * Scripts/run-webkit-tests: added --svg option
+ * Scripts/run-webkit-tests-svg: Removed.
+ http://bugs.webkit.org/show_bug.cgi?id=4300
+
+2005-08-07 Eric Seidel <eseidel@apple.com>
+ Changes by Ben La Monica <ben.lamonica@gmail.com>
+
+ Reviewed by darin.
+
+ * svg2png/ImageDiff.h: Added.
+ * svg2png/ImageDiff.m: Added.
+ (getDifferenceBitmap):
+ (computePercentageDifferent):
+ (saveAnimatedGIFToFile):
+ * svg2png/svg2png.m:
+ (usage): added several new options
+ (getBitmapForSVG): added NSBitmapImageRep generation
+ (main): various argument changes.
+ * svg2png/svg2png.xcodeproj/project.pbxproj:
+ Several additions to provide image differencing functionality.
+ http://bugs.webkit.org/show_bug.cgi?id=4193
+
+2005-08-07 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ * Scripts/run-webkit-tests-svg: now uses WebCore/svg-tests
+ * checkout-svg: links WebCore/svg-tests to SVGSupport/layout-tests
+ Adding the first SVG layout tests:
+ http://bugs.webkit.org/show_bug.cgi?id=4303
+
+2005-08-07 Darin Adler <darin@apple.com>
+
+ * Scripts/cvs-create-patch: Do all the directories at once, for speed.
+
+2005-08-06 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ * DumpKCanvasTree/DumpKCanvasTree.m: Added.
+ * DumpKCanvasTree/DumpKCanvasTree.xcodeproj/project.pbxproj: Added.
+ * Scripts/build-dumpkcanvastree: Added.
+ * Scripts/run-webkit-tests-svg: Added.
+ Adds a DumpRenderTree-like tool for SVG which allows us to do
+ text-based layout regression testing. This (like most of the
+ SVG specific stuff) is temporary and will be replaced by
+ DumpRenderTree once the DOMs and RenderTrees merge.
+ http://bugs.webkit.org/show_bug.cgi?id=3917
+
+2005-08-06 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ * DrawTest/DrawTestView.m:
+ (-[DrawTestView toggleFilterSupport:]): missing negation.
+ One half of fix for toggling filter support.
+ http://bugs.webkit.org/show_bug.cgi?id=4252
+
+2005-08-04 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by darin.
+
+ * Scripts/build-drawtest:
+ * Scripts/build-dumprendertree:
+ * Scripts/build-svg2png:
+ * Scripts/build-webcore-svg:
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm: added checkRequiredSystemConfig()
+ Added checkRequiredSystemConfig and made all the build-* scripts
+ use it to print a pretty warning when trying to compile on an
+ unsupported system (less than 10.4, Xcode 2.1).
+ http://bugs.webkit.org/show_bug.cgi?id=4280
+
+2005-08-04 Darin Adler <darin@apple.com>
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Bring this file back from
+ the dead. It was removed by accident when someone was trying to work on the branch.
+
+2005-07-31 Darin Adler <darin@apple.com>
+
+ - a little tools cleanup
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Moved options from target to
+ project as a whole. Removed unused Default configuration.
+
+ * Scripts/check-dom-results: Added license header, comment to explain purpose of tool.
+
+2005-07-31 Duncan Wilcox <duncan@mclink.it>
+
+ Reviewed and landed by Darin Adler.
+
+ Add logging of editing delegate calls for regression checking.
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (main):
+ setup editing delegate
+
+ (-[DOMNode dumpPath]):
+ (-[DOMRange dump]):
+ utility for editing delegate logging
+
+ (-[EditingDelegate webView:shouldBeginEditingInDOMRange:]):
+ (-[EditingDelegate webView:shouldEndEditingInDOMRange:]):
+ (-[EditingDelegate webView:shouldInsertNode:replacingDOMRange:givenAction:]):
+ (-[EditingDelegate webView:shouldInsertText:replacingDOMRange:givenAction:]):
+ (-[EditingDelegate webView:shouldDeleteDOMRange:]):
+ (-[EditingDelegate webView:shouldChangeSelectedDOMRange:toDOMRange:affinity:stillSelecting:]):
+ (-[EditingDelegate webView:shouldApplyStyle:toElementsInDOMRange:]):
+ (-[EditingDelegate webView:shouldChangeTypingStyle:toStyle:]):
+ (-[EditingDelegate webViewDidBeginEditing:]):
+ (-[EditingDelegate webViewDidChange:]):
+ (-[EditingDelegate webViewDidEndEditing:]):
+ (-[EditingDelegate webViewDidChangeTypingStyle:]):
+ log corresponding editing delegate methods
+
+ (-[EditingDelegate webViewDidChangeSelection:]):
+ log selection except when clearing selection after end of test (uses existing "done" flag)
+
+ (dumpRenderTree):
+ added clearing of selection after test
+
+2005-07-31 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by hyatt.
+
+ * Scripts/build-drawtest: Added.
+ * Scripts/build-svg2png: Added.
+ * Scripts/build-webcore-svg: Added.
+ * Scripts/run-drawtest: Added.
+ * Scripts/webkitdirs.pm: added checkSVGFrameworks
+ Made it much easier to build WebCore+SVG.
+ http://bugs.webkit.org/show_bug.cgi?id=4208
+
+2005-07-29 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by vicki.
+
+ * DrawTest/DrawTest.xcodeproj/project.pbxproj:
+ Build fix. Removed bad path.
+
+2005-07-29 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by sullivan.
+
+ * DrawTest/AppDelegate.h: Added.
+ * DrawTest/AppDelegate.m: Added.
+ * DrawTest/DrawTest.xcodeproj/project.pbxproj: Added.
+ * DrawTest/DrawTestDocument.h: Added.
+ * DrawTest/DrawTestDocument.m: Added.
+ * DrawTest/DrawTestInspectorController.h: Added.
+ * DrawTest/DrawTestInspectorController.m: Added.
+ * DrawTest/DrawTestToolbarController.h: Added.
+ * DrawTest/DrawTestToolbarController.m: Added.
+ * DrawTest/DrawTestView.h: Added.
+ * DrawTest/DrawTestView.m: Added.
+ * DrawTest/DrawTest_Prefix.pch: Added.
+ * DrawTest/English.lproj/DrawTestDocument.nib/classes.nib: Added.
+ * DrawTest/English.lproj/DrawTestDocument.nib/info.nib: Added.
+ * DrawTest/English.lproj/DrawTestDocument.nib/keyedobjects.nib: Added.
+ * DrawTest/English.lproj/InfoPlist.strings: Added.
+ * DrawTest/English.lproj/Inspector.nib/classes.nib: Added.
+ * DrawTest/English.lproj/Inspector.nib/info.nib: Added.
+ * DrawTest/English.lproj/Inspector.nib/keyedobjects.nib: Added.
+ * DrawTest/English.lproj/MainMenu.nib/classes.nib: Added.
+ * DrawTest/English.lproj/MainMenu.nib/info.nib: Added.
+ * DrawTest/English.lproj/MainMenu.nib/keyedobjects.nib: Added.
+ * DrawTest/English.lproj/TestViewer.nib/classes.nib: Added.
+ * DrawTest/English.lproj/TestViewer.nib/info.nib: Added.
+ * DrawTest/English.lproj/TestViewer.nib/keyedobjects.nib: Added.
+ * DrawTest/Info.plist: Added.
+ * DrawTest/SVGTest.h: Added.
+ * DrawTest/SVGTest.m: Added.
+ * DrawTest/ScalingImageView.h: Added.
+ * DrawTest/ScalingImageView.m: Added.
+ * DrawTest/TestController.h: Added.
+ * DrawTest/TestController.m: Added.
+ * DrawTest/TestViewerSplitView.h: Added.
+ * DrawTest/TestViewerSplitView.m: Added.
+ * DrawTest/main.m: Added.
+ Adding simple cocoa app for testing SVG rendering, interaction.
+ http://bugs.webkit.org/show_bug.cgi?id=4157
+
+2005-07-28 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by ggaren.
+
+ * svg2png/svg2png.m: Added.
+ * svg2png/svg2png.xcodeproj/project.pbxproj: Added.
+ * svg2png/svg2png_Prefix.pch: Added.
+ Added a simple test tool which dumps a PNG from an SVG using
+ WebCore+SVG's SVG rendering support.
+ http://bugs.webkit.org/show_bug.cgi?id=4156
+
+2005-07-26 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Adler.
+
+ - new script to review the DOM layout test results and see where we stand
+ on actual success and failure
+
+ * Scripts/check-dom-results: Added.
+
+2005-07-25 Darin Adler <darin@apple.com>
+
+ * Scripts/webkitdirs.pm: Check in missing line of code.
+
+2005-07-25 Darin Adler <darin@apple.com>
+
+ - fixed problem that was causing JavaScriptCore test to fail
+ (except for people who had set DYLD_FRAMEWORK_PATH)
+
+ * Scripts/run-javascriptcore-tests: Add code to set DYLD_FRAMEWORK_PATH.
+ Add code to parse configuration parameter so you can pass --deployment if you like.
+ * Scripts/run-webkit-tests: Add code to parse configuration parameter.
+
+ * Scripts/update-javascriptcore-test-results: Add license header.
+
+ * Scripts/webkitdirs.pm: Change code that reads configuration option to remove it
+ from @ARGV. This lets us use this option in commands that take other options and
+ pass them along to a subsequent tool.
+
+2005-07-25 Darin Adler <darin@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ - Fixed run-safari and gdb-safari to use the Safari application in the build results
+ directory, if any, falling back to the one in the Applications directory otherwise.
+ Does no harm for open source contributors who don't build Safari, and helps out the
+ Safari team, since we do build Safari.
+
+ * Scripts/webkitdirs.pm: Added safariPath function that uses WEBKIT_SAFARI environment
+ variable, and if that's not present, looks in either the build results directory or
+ /Applications; factors code that was in both scripts before into a shared function.
+ Also removed some Xcode 2.0 support which is no longer relevant since our projects are
+ now in Xcode 2.1 format and incompatible with older versions of Xcode.
+
+ * Scripts/gdb-safari: Use safariPath.
+ * Scripts/run-safari: Use safariPath.
+
+2005-07-22 Geoffrey Garen <ggaren@apple.com>
+
+ Moved Tools/Scripts/run-mozilla-tests to WebKitTools/Scripts/run-javascriptcore-tests.
+ run-javascriptcore-tests now passes its command-line arguments to jsDriver.pl
+
+ Moved Tools/Scripts/update-mozilla-js-test-results to
+ WebKitTools/Scripts/update-javascriptcore-test-results.
+
+ Reviewed by darin.
+
+ * Scripts/run-javascriptcore-tests: Added.
+
+2005-07-21 Geoffrey Garen <ggaren@apple.com>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/build-dumprendertree: changed XCode 2.0 project file reference to 2.1
+
+2005-07-21 Geoffrey Garen <ggaren@apple.com>
+
+ * DumpRenderTree/DumpRenderTree.xcode/.cvsignore: Removed.
+
+2005-07-21 Geoffrey Garen <ggaren@apple.com>
+
+ * DumpRenderTree/DumpRenderTree.xcode/project.pbxproj: Removed.
+
+2005-07-21 Geoffrey Garen <ggaren@apple.com>
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/.cvsignore: Added.
+
+2005-07-21 Geoffrey Garen <ggaren@apple.com>
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Added.
+
+2005-07-21 Geoffrey Garen <ggaren@apple.com>
+
+ * Scripts/build-webkit:
+
+2005-07-12 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ * checkout-svg: Fixed error with symlink creation.
+
+2005-07-12 Eric Seidel <eseidel@apple.com>
+
+ Reviewed by mjs.
+
+ * checkout-svg: Added.
+ Script to check out WebCore+SVG
+
+2005-06-30 Darin Adler <darin@apple.com>
+
+ Changes based on input from Michael Kahl.
+
+ * Scripts/cvs-create-patch: Use "-f" so we are compatible with .cvsrc files that
+ specify different style of "diff".
+ * Scripts/webkitdirs.pm: Add missing call to determineBaseProductDir, so that
+ determineConfigurationProductDir works in all cases.
+
+2005-06-29 Darin Adler <darin@apple.com>
+
+ - fixed bug which would result in multiple unwanted dumps in a single layout test
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:locationChangeDone:forDataSource:]): Set new
+ "readyToDump" flag.
+ (-[LayoutTestController waitUntilDone]): Update for name change.
+ (-[LayoutTestController notifyDone]): Dump only if ready.
+ (dumpRenderTree): Set up new boolean and update for name change.
+
+2005-06-29 Darin Adler <darin@apple.com>
+
+ Changes by Timothy Hatcher.
+ Reviewed by me.
+
+ * Scripts/run-webkit-app: Added script to open an arbritrary application with
+ a CVS built WebKit. Example: ./run-webkit-app Colloquy
+
+ * Scripts/gdb-safari: Added support for WEBKIT_SAFARI environment variable to specify
+ a custom location to the Safari.app bundle. This is optional, script defaults to the stock location.
+ * Scripts/run-safari: Ditto.
+
+2005-06-26 Darin Adler <darin@apple.com>
+
+ * Scripts/build-dumprendertree: Pass -project option so that having a second
+ copy of the project (like the one Xcode 2.1 offers to make for you) that's
+ out of date won't screw you up.
+ * Scripts/build-webkit: Ditto.
+
+2005-06-23 Darin Adler <darin@apple.com>
+
+ * Scripts/webkitdirs.pm: Fixed a regular expression in the code I just landed.
+
+2005-06-23 Darin Adler <darin@apple.com>
+
+ Changes based on input from Michael Kahl.
+
+ * Scripts/cvs-create-patch: Added code to handle getting changes in the top-level
+ directory passed in.
+
+ * Scripts/webkitdirs.pm: Eliminate use of changing the current directory and using
+ getcwd() in the code to find the base product dir. Added code to handle unusual
+ base product directory values that use SRCROOT.
+
+2005-06-22 Darin Adler <darin@apple.com>
+
+ Change by Anders Carlsson.
+
+ - added support for dumping title changes
+
+ * DumpRenderTree/DumpRenderTree.m:
+ (-[WaitUntilDoneDelegate webView:didReceiveTitle:forFrame:]): Added. Dump title change
+ if requested by JavaScript.
+ (+[LayoutTestController isSelectorExcludedFromWebScript:]): Added dumpTitleChanges.
+ (-[LayoutTestController dumpTitleChanges]): Added, sets flag.
+ (dumpRenderTree): Start flag as NO.
+
+2005-06-20 Darin Adler <darin@apple.com>
+
+ Reviewed by Justin Garcia.
+
+ * Scripts/run-webkit-tests: Report number of tests when they succeed.
+
+2005-06-18 Darin Adler <darin@apple.com>
+
+ * DumpRenderTree/DumpRenderTree.m: (dumpRenderTree): Add more auto-release pools
+ in the hope of making the tool use less memory and run faster.
+
+2005-06-18 Darin Adler <darin@apple.com>
+
+ * Scripts/cvs-apply: Improve handling of patches with CR characters in them.
+ * Scripts/cvs-unapply: Ditto.
+
+2005-06-17 Maciej Stachowiak <mjs@apple.com>
+
+ - added prepare-ChangeLog script which we use internally to make ChangeLogs, for
+ benefit of all WebKit hackerdom
+
+ * Scripts/prepare-ChangeLog: Added.
+
+2005-06-16 Darin Adler <darin@apple.com>
+
+ - recent changes to XcodeOptions made it depend on the current directory
+ The intent was to have the WebKitBuild directory be next to WebKitTools,
+ not inside the various build directories. Workaround for now is to call
+ XcodeOptions when the directory is set to the WebKit directory.
+
+ * Scripts/build-dumprendertree: Use a local variable for XcodeOptions and get it
+ at the start of the script.
+ * Scripts/build-webkit: Ditto.
+
+2005-06-15 Darin Adler <darin@apple.com>
+
+ * Scripts/webkitdirs.pm: Recognize all 1.X versions of Xcode as old too, not just 2.0.
+
+2005-06-14 Darin Adler <darin@apple.com>
+
+ Changes by Anders Carlsson.
+ Reviewed by me.
+
+ - fixed <http://bugs.webkit.org/show_bug.cgi?id=3496>
+ Add gdb-safari script to launch Safari under gdb
+
+ * Scripts/gdb-safari: Added.
+
+2005-06-12 Darin Adler <darin@apple.com>
+
+ Changes by Stuart Morgan.
+ Reviewed by me.
+
+ * Scripts/cvs-abandon: Use cwd instead of `pwd`.
+ * Scripts/cvs-apply: Ditto.
+ * Scripts/cvs-create-patch: Ditto.
+ * Scripts/cvs-unapply: Ditto.
+ * Scripts/run-webkit-tests: Ditto.
+ * Scripts/webkitdirs.pm: Ditto. Also improve handling when there's no "Configuration" file.
+
+2005-06-12 Darin Adler <darin@apple.com>
+
+ * Scripts/cvs-apply: Handle case of an empty patch better.
+ * Scripts/cvs-unapply: Ditto.
+
+2005-06-12 Darin Adler <darin@apple.com>
+
+ Changes by Michael Gaiman.
+ Reviewed by me.
+
+ - fixed <http://bugs.webkit.org/show_bug.cgi?id=3487>
+ WebKit no longer builds after configuration supporting build changes
+
+ * Scripts/webkitdirs.pm: Chomp off the result of `pwd`, and don't die when no Configuration file.
+
+2005-06-12 Darin Adler <darin@apple.com>
+
+ * Scripts/update-webkit: Make this script work when called from any directory.
+
+2005-06-12 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej.
+ Includes changes by Stuart Morgan as well as my own.
+
+ * Scripts/build-dumprendertree: Call the new setConfiguration function, and use XcodeOptions instead of
+ symrootXcodeOptions to set the -buildstyle option.
+ * Scripts/build-webkit: Ditto. Also remove the old way of supporting Xcode 2.1 and the old --debug option.
+ The new --development option does the same thing.
+ * Scripts/run-safari: Ditto.
+ * Scripts/run-webkit-tests: Ditto.
+ * Scripts/update-webkit: Ditto.
+ * Scripts/set-webkit-configuration: Added. Sets the default configuration to Development or Deployment.
+
+ * Scripts/webkitdirs.pm: use FindBin to find the WebKit directory; works no matter what the current
+ directory is when invoking a script. Add code to determine the Xcode version so we can do the right
+ thing for 2.0 and 2.1. Change the productDir function to return the appropriate per-configuration
+ product directory. Read the default configuration from a file, overridable by a passed-in command-line
+ option.
+
+2005-06-11 Darin Adler <darin@apple.com>
+
+ * Scripts/cvs-create-patch: Improve handling of directories with mixed CVS roots by going into each directory
+ to execute the cvs diff commands.
+
+2005-06-11 Darin Adler <darin@apple.com>
+
+ - added first cuts at some cvs scripts
+
+ cvs-abandon is for throwing away changes; discards any local changes, reverting to the state in CVS
+ cvs-create-patch is for making patches; runs cvs diff with all the right options and handles added/deleted files
+ cvs-apply is for applying patches; runs patch and cvs add and cvs rm
+ cvs-unapply is for unapplying patches; does the opposite of cvs-apply
+
+ An argument against these is "waste of time if we switch to Subversion", but they should be good for a while.
+
+ * Scripts/cvs-abandon: Added.
+ * Scripts/cvs-apply: Added.
+ * Scripts/cvs-create-patch: Added.
+ * Scripts/cvs-unapply: Added.
+
+2005-06-09 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej.
+
+ - fixed http://bugs.webkit.org/show_bug.cgi?id=3397
+ Build DumpRenderTree fails with unresolved NSAutoreleasePool, etc
+
+ * DumpRenderTree/DumpRenderTree.xcode/project.pbxproj: Change type from "folder" to "wrapper.framework"
+ for Foundation.framework. How was it ever wrong?
+
+ - finally, I tested making the default build directory work; it works now
+
+ * Scripts/webkitdirs.pm: Changed structure of the code a little bit, added symrootXcodeOptions function
+ that sets SYMROOT on the command line in case there's no product directory set in Xcode preferences.
+ * Scripts/build-webkit: Pass symrootXcodeOptions when invoking Xcode.
+ * Scripts/build-dumprendertree: Ditto.
+
+2005-06-09 Darin Adler <darin@apple.com>
+
+ * Scripts/webkitdirs.pm: Another try at making the default build directory of ~/WebKitBuild
+ work. Someone should try building without setting the Xcode build product directory now,
+ and let me know if it works.
+
+2005-06-08 Darin Adler <darin@apple.com>
+
+ - quick fix to try to get build scripts working again
+
+ * Scripts/build-dumprendertree: Add FindBin.
+ * Scripts/build-webkit: Ditto.
+ * Scripts/run-safari: Ditto.
+ * Scripts/run-webkit-tests: Ditto.
+ * Scripts/update-webkit: Ditto.
+
+2005-06-08 Darin Adler <darin@apple.com>
+
+ Reviewed by Maciej.
+
+ - some build script enhancements
+
+ * Scripts/build-dumprendertree: Changed to use webkitdirs.
+ * Scripts/build-webkit: Changed to use webkitdirs, also only copy files from WebKitLibraries if
+ they are newer.
+ * Scripts/run-safari: Reduce number of log messages, change to respect "-d" flag and get Development
+ before Deplyment in that case.
+ * Scripts/run-webkit-tests: Changed to use webkitdirs.
+ * Scripts/update-webkit: Changed to use webkitdirs.
+
+ * Scripts/webkitdirs.pm: Added.
+
+2005-06-08 Maciej Stachowiak <mjs@apple.com>
+
+ Code change by Toby Peterson <toby@opendarwin.org>
+ Reviewed by me.
+
+ * Scripts/run-safari: Fix to work with Xcode 2.0 again. The script would
+ get confused because build-webkit now makes even 2.0 build directories look
+ like 2.1.
+
+2005-06-07 Darin Adler <darin@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ * DumpRenderTree/DumpRenderTree.xcode/project.pbxproj: Added Deployment build style.
+ * Scripts/build-dumprendertree: For now, always use Deployment build style. This may fix things
+ so we can run tests with Xcode 2.1.
+
+2005-06-07 Darin Adler <darin@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ * Scripts/run-webkit-tests: Pass -L to find command to follow symlinks. This allows symlinks in the
+ layout-tests directory to include additional sets of tests.
+
+2005-06-07 Darin Adler <darin@apple.com>
+
+ * checkout: Added license.
+ * Scripts/build-dumprendertree: Ditto.
+ * Scripts/run-webkit-tests: Ditto.
+ * Scripts/update-webkit: Ditto.
+
+2005-06-07 Darin Adler <darin@apple.com>
+
+ Change by Toby Peterson <toby@opendarwin.org>.
+ Reviewed by me.
+
+ * Scripts/build-webkit: Changes so you can build with Xcode 2.1. (I also added a license to this file.)
+ * Scripts/run-safari: Ditto.
+
+2005-06-06 Maciej Stachowiak <mjs@apple.com>
+
+ * Scripts/build-webkit: run ranlib on libWebKitSystemInterface.a
+
+2005-06-06 Maciej Stachowiak <mjs@apple.com>
+
+ * Scripts/build-webkit: Chop newline off of $productDir to avoid problems with logic to copy files ther.
+
+2005-06-06 Maciej Stachowiak <mjs@apple.com>
+
+ * Scripts/build-webkit: Install WebKitSystemInterface stuff into build products dir.
+
+2005-06-05 Darin Adler <darin@apple.com>
+
+ * DumpRenderTree/DumpRenderTree.xcode/project.pbxproj: Tweak, simplify.
+ * Scripts/build-dumprendertree: Added.
+ * Scripts/build-webkit: Build All in the JavaScriptCore directory.
+ * Scripts/run-webkit-tests: Build DumpRenderTree before running.
+
+2005-06-05 Darin Adler <darin@apple.com>
+
+ * Scripts/run-safari: Fix path to Safari executable. Add check for frameworks.
+
+2005-06-05 Darin Adler <darin@apple.com>
+
+ - add run-webkit-tests script; not working yet but the pieces are there
+
+ * Scripts/run-webkit-tests: Added.
+
+ * DumpRenderTree/DumpRenderTree.m: Added.
+ * DumpRenderTree/DumpRenderTree.xcode/.cvsignore: Added.
+ * DumpRenderTree/DumpRenderTree.xcode/project.pbxproj: Added.
+ * DumpRenderTree/DumpRenderTreePrefix.h: Added.
+
+2005-06-05 Darin Adler <darin@apple.com>
+
+ - created module, first cut at Web Kit Open Source Project scripts
+
+ * ChangeLog: Added.
+ * Scripts/build-webkit: Added.
+ * Scripts/run-safari: Added.
+ * Scripts/update-webkit: Added.
+ * checkout: Added.
+
+=== creation of WebKitTools module ===
diff --git a/Tools/ChangeLog-2010-05-24 b/Tools/ChangeLog-2010-05-24
new file mode 100644
index 0000000..f3f21b2
--- /dev/null
+++ b/Tools/ChangeLog-2010-05-24
@@ -0,0 +1,35303 @@
+2010-05-24 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ add tests to ensure that --git-commit ranges are exclusive of the start of the range
+ https://bugs.webkit.org/show_bug.cgi?id=39612
+
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+
+2010-05-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add a temporary script for testing the html5 parser until it can run more layout tests
+ https://bugs.webkit.org/show_bug.cgi?id=39611
+
+ * Scripts/test-html5-parser: Added.
+
+2010-05-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Chris Jerdonek.
+
+ webkit-patch needs --verbose flag to enable DEBUG logging
+ https://bugs.webkit.org/show_bug.cgi?id=39208
+
+ I also added some code to print out how long commands take to run.
+
+ * Scripts/webkit-patch:
+ - Add hackish -v/--verbose parsing (similar to check-webkit-style)
+ * Scripts/webkitpy/common/system/executive.py:
+ - Log how long commands take to run.
+ * Scripts/webkitpy/tool/main.py:
+ - Add -v/--verbose option to global options.
+
+2010-05-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ Split PatchReader out into its own file
+ https://bugs.webkit.org/show_bug.cgi?id=39576
+
+ This is in preparation for making check-webkit-style
+ support being passed paths to patch files on the command line.
+
+ * Scripts/check-webkit-style:
+ * Scripts/webkitpy/style/checker.py:
+ * Scripts/webkitpy/style/checker_unittest.py:
+ * Scripts/webkitpy/style/patchreader.py: Added.
+ * Scripts/webkitpy/style/patchreader_unittest.py: Added.
+ * Scripts/webkitpy/style_references.py:
+
+2010-05-23 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ webkit-patch should let you add a comment when uploading a patch
+ https://bugs.webkit.org/show_bug.cgi?id=39552
+
+ As requested by Dan "the man" Bates.
+
+ * Scripts/webkitpy/tool/steps/options.py:
+ * Scripts/webkitpy/tool/steps/postdiff.py:
+
+2010-05-23 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch should assign newly created bugs to their creator
+ https://bugs.webkit.org/show_bug.cgi?id=39548
+
+ As requested on webkit-dev.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+
+2010-05-23 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Hide prepare and post commands for webkit-patch
+ https://bugs.webkit.org/show_bug.cgi?id=39539
+
+ It turns out these commands aren't very popular and they confuse new
+ users. They'll still be there for advanced users, however.
+
+ * Scripts/webkitpy/tool/commands/upload.py:
+
+2010-05-23 Jesus Sanchez-Palencia <jesus@webkit.org>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] QtTestBrowser has two graphicsview options that aren't enabled correctly
+ https://bugs.webkit.org/show_bug.cgi?id=39491
+
+ Making toggleResizesToContents and toggleTiledBackingStore checkable when
+ QtTestBrowser is started on graphics view mode.
+
+ * QtTestBrowser/main.cpp:
+ (LauncherWindow::createChrome):
+
+2010-05-23 Jesus Sanchez-Palencia <jesus@webkit.org>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] QtTestBrowser is still called QtLauncher in the code
+ https://bugs.webkit.org/show_bug.cgi?id=39488
+
+ Finish the name change of QtLauncher to QtTestBrowser.
+
+ * QtTestBrowser/main.cpp:
+ (LauncherApplication::LauncherApplication):
+ (LauncherApplication::handleUserOptions):
+ * QtTestBrowser/mainwindow.cpp:
+ (MainWindow::MainWindow):
+ * QtTestBrowser/useragentlist.txt:
+
+2010-05-23 Marcus Bulach <bulach@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] Adds Geolocation support to DumpRenderTree.
+ https://bugs.webkit.org/show_bug.cgi?id=39440
+
+ Existing LayoutTests/fast/dom/Geolocation/* should pass.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::setGeolocationPermission):
+ (LayoutTestController::setMockGeolocationPosition):
+ (LayoutTestController::setMockGeolocationError):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::geolocationService):
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-05-22 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Re-order Yong's email addresses because his gmail account is the one he
+ uses for bugs.webkit.org.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-05-22 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Chris Jerdonek.
+
+ Add infrastructure to parse SVN property changes
+ https://bugs.webkit.org/show_bug.cgi?id=38885
+
+ Adds function VCSUtils::parseSvnDiffFooter to parse an SVN footer
+ that consists of one or more properties.
+
+ Note, the first line of an SVN footer begins with "Property changes on".
+
+ * Scripts/VCSUtils.pm:
+ - Added function parseSvnDiffFooter. Will use this function
+ towards resolving Bug #39409 <https://bugs.webkit.org/show_bug.cgi?id=39409>.
+ - Removed FIXME comment above function parseSvnProperty, since
+ it is being used by parseSvnDiffFooter.
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl: Added.
+ - Added unit tests.
+
+2010-05-22 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, fixing test results only.
+
+ Disable compositing tests on the commit-queue as a workaround for bug 38912
+ https://bugs.webkit.org/show_bug.cgi?id=39067
+
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ - Update test results after my previous change.
+
+2010-05-22 Eric Seidel <eric@webkit.org>
+
+ Unreviewed.
+
+ Disable compositing tests on the commit-queue as a workaround for bug 38912
+ https://bugs.webkit.org/show_bug.cgi?id=39067
+
+ * Scripts/webkitpy/tool/steps/runtests.py:
+ - Disable all of compositing, not just compositing/iframes
+
+2010-05-22 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Link resources and load Ahem font for Windows
+ https://bugs.webkit.org/show_bug.cgi?id=39473
+
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (main): Call platformInit().
+ * DumpRenderTree/chromium/TestShell.h:
+ Declare platformInit(). It is not related to TestShell class, but the
+ implementation of paltformInit() is placed at TestShell*.{cpp,mm}.
+ * DumpRenderTree/chromium/TestShellGtk.cpp:
+ (platformInit):
+ * DumpRenderTree/chromium/TestShellMac.mm:
+ (platformInit):
+ * DumpRenderTree/chromium/TestShellWin.cpp:
+ (platformInit):
+ - Make stdout/stderr binary mode
+ - Load Ahem font
+
+2010-05-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, EWS build fix only.
+
+ QueueStatusServer returns 500 error when EWS bots post empty queues
+ https://bugs.webkit.org/show_bug.cgi?id=39523
+
+ Mac python seems to have some built-in timezone support
+ however other python installs don't. So we need to ignore
+ timezones in our parsing.
+
+ Date parsing is tested by existing unit tests.
+
+ * QueueStatusServer/handlers/updateworkitems.py:
+ - Fix typo causing exception on server.
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ - Fix exception due to python's lack of timezone support.
+
+2010-05-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ QueueStatusServer returns 500 error when EWS bots post empty queues
+ https://bugs.webkit.org/show_bug.cgi?id=39523
+
+ updateworkitems handler was raising an exception because
+ int() couldn't convert "" to a number.
+
+ I attempted to unit test this but we don't yet have a system by
+ which to load unit tests for appengine classes which depend on
+ google.appengine libraries which are not in the python default install.
+
+ We'll need to write a wrapper script to load those into the python path
+ and then run the unit test files.
+
+ * QueueStatusServer/handlers/statusbubble.py:
+ - Hide cr-win-ews since we're not currently running this bot.
+ * QueueStatusServer/handlers/updateworkitems.py:
+ - Fix the parsing logic to be able to understand "".
+ * Scripts/webkitpy/common/net/statusserver.py:
+ - Only log the work items posted to the server to the debug log channel.
+
+2010-05-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, fixing the commit-queue to run again.
+
+ Make the EWSes report queue position in white bubbles
+ https://bugs.webkit.org/show_bug.cgi?id=39519
+
+ * Scripts/webkitpy/common/net/statusserver.py:
+ - Fix exception in _post_work_items_to_server when passed
+ integers. Unfortunately we have no good way to mock
+ the Browser object yet, and after several attempts I was
+ not able to create a good one, so no tests. :(
+
+2010-05-14 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch land --squash commits too much if branch is not up to date
+ https://bugs.webkit.org/show_bug.cgi?id=38852
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+
+2010-05-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make the EWSes report queue position in white bubbles
+ https://bugs.webkit.org/show_bug.cgi?id=39519
+
+ This also fixes sorting of commit-queue patches
+ to be in order of patch attachment.
+ https://bugs.webkit.org/show_bug.cgi?id=33395
+
+ This makes the various Queues post what patches they are about to process
+ so that we can display a list of patches on status server pages, as well
+ as report queue position in status bubbles.
+
+ This is the first step towards creating a control-channel for the queues.
+ Next step will be to have them read back the patches in order from the server
+ and finally we will add the ability for the server to control that order.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ - Teach bugzilla how to parse attach_date for attachments.
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+ - Test that we're parsing dates correctly.
+ This may have timezone issues for non-PST contributers, unsure.
+ * Scripts/webkitpy/common/net/statusserver.py:
+ - Post work items to the status server for display.
+ * Scripts/webkitpy/tool/bot/patchcollection.py:
+ - Call StatusServer.update_work_items
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+ - Update unit test results now that we're posting work item list.
+ * Scripts/webkitpy/tool/commands/queues.py:
+ - Call StatusSever.update_work_items
+ - Sort patches so that the server's list understands
+ that the commit-queue gives priority to rollout patches.
+ - I also fixed patch sorting per bug 33395 while I was here.
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ - Update results after update_work_items changes.
+ - Test attachment sorting.
+ * Scripts/webkitpy/tool/mocktool.py:
+ - Add mock for update_work_items
+
+2010-05-21 Robin Cao <robin.cao@torchmobile.com.cn>
+
+ Reviewed by Adam Roben.
+
+ fast/dom/HTMLObjectElement/children-changed.html times out on Windows run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=31315
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::didFailProvisionalLoadWithError): Need to invoke locationChangeDone here as mac port does.
+
+2010-05-20 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Dan Bernstein.
+
+ <rdar://problem/7848154> Remove the dependency on Foundation's private __COCOA_FORMAL_PROTOCOLS_2__ define.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+
+2010-05-20 Tony Gentilcore <tonyg@chromium.org>
+
+ Reviewed by Daniel Bates.
+
+ Look in /proc/registry64 for the Platform SDK on 64-bit Windows.
+ https://bugs.webkit.org/show_bug.cgi?id=39296
+
+ The build-webkit script failed for me on Vista 64. A web search turned
+ up this blog post with a patch that worked for me:
+ http://www.nicholaswilson.me.uk/2010/04/hacking-webkit-fail/
+
+ * Scripts/webkitdirs.pm:
+
+2010-05-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ ThreadedMessageQueue should use with_statement for exception safety
+ https://bugs.webkit.org/show_bug.cgi?id=39233
+
+ * Scripts/webkitpy/common/thread/threadedmessagequeue.py:
+
+2010-05-20 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] QtTestBrowser does not support websites which requires HTTP Authentication via dialogs
+ https://bugs.webkit.org/show_bug.cgi?id=38456
+
+ * QtTestBrowser/webpage.cpp:
+ (WebPage::WebPage):
+ (WebPage::authenticationRequired):
+ * QtTestBrowser/webpage.h:
+
+2010-05-20 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Eric Seidel.
+
+ editingBehavior settings needs to be set back to a reasonable default between tests
+ https://bugs.webkit.org/show_bug.cgi?id=39433
+
+ For now, hard code the default setting during reset, so that the serialized
+ version of the setting stays in sync with expectations.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues): Reset editing behavior to the appropriate platform default.
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues): Ditto.
+
+2010-05-20 Brent Fulgham <bfulgham@webkit.org>
+
+ Build fix. No review.
+
+ The WebKitAPITest targets do not use the "_debug" suffix needed
+ by the WinCairo port. Added Debug_Cairo target to correct this.
+
+ * WebKitAPITest/WebKitAPITest.vcproj:
+
+2010-05-20 Martin Robinson <mrobinson@igalia.com>
+
+ Reviewed by Ojan Vafai.
+
+ editing/selection/extend-selection-after-double-click.html crashes on the Leopard Intel release bot
+ https://bugs.webkit.org/show_bug.cgi?id=39431
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setEditingBehavior):
+ Prevent a double-free by not having this variable be in the auto-release pool.
+
+2010-05-20 Martin Robinson <mrobinson@webkit.org>
+
+ Reviewed by Ojan Vafai.
+
+ Expose the editing behavior setting in DRT to test all editing code paths
+ https://bugs.webkit.org/show_bug.cgi?id=38603
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setEditingBehaviorCallback): Added.
+ (LayoutTestController::staticFunctions): Expose the setEditingBehaviorCallback function.
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp: Add callback method for setting editing behavior.
+ * DumpRenderTree/chromium/LayoutTestController.h: Declaration for this method.
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setEditingBehavior): Implementation of editing behavior control.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setEditingBehavior): Ditto
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setEditingBehavior): Added stub implementation of editing behavior control.
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::setEditingBehavior): Add slot for controlling editor behavior.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setEditingBehavior): Implementation of editing behavior control.
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setEditingBehavior): Added stub implementation of editing behavior control.
+
+2010-05-20 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [DRT/Chromium] Increase the time out value
+ https://bugs.webkit.org/show_bug.cgi?id=39203
+
+ Change the time out value of Chromium DRT to 30 seconds, which is
+ the same as other ports.
+ If a DRT process exits before new-run-webkit-tests detects time
+ out, new-run-webkit-tests assumes the DRT process crashed.
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::layoutTestTimeout):
+ Change the time out value from 10 seconds to 30 seconds.
+
+2010-05-20 Chris Evans <cevans@google.com>
+
+ Unreviewed.
+
+ Marking myself as a committer.
+
+ * Scripts/webkitpy/common/config/committers.py: Add cevans@google.com.
+
+2010-05-20 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Tor Arne Vestbo.
+
+ [Qt] Weekly binary builds on Mac OS X don't work when launched in the Finder
+ https://bugs.webkit.org/show_bug.cgi?id=37273
+
+ * QtTestBrowser/QtTestBrowser.pro: Build QtLauncher as bundle in package builds
+
+2010-05-20 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed fix for websocket test failures.
+
+ * Scripts/new-run-webkit-websocketserver:
+ options is named parameter for factory.get().
+
+2010-05-20 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Chromium: Add --chromium option to new-run-webkit-websocketserver
+ https://bugs.webkit.org/show_bug.cgi?id=37664
+
+ Missed to pass options to factory.get() in r59595
+
+ * Scripts/new-run-webkit-websocketserver:
+ Pass options to factory.get().
+
+2010-05-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ WinEWS should build Debug instead of Release
+ https://bugs.webkit.org/show_bug.cgi?id=39242
+
+ This is a workaround for
+ https://bugs.webkit.org/show_bug.cgi?id=39197
+ Adam Roben and Brian Weinstein believe this may
+ also make building faster since Debug builds
+ take less time to link.
+
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+
+2010-05-19 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ * DumpRenderTree/chromium/NotificationPresenter.cpp:
+ (NotificationPresenter::show):
+
+2010-05-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ user.py throws exception when readline module is missing
+ https://bugs.webkit.org/show_bug.cgi?id=39239
+
+ * Scripts/webkitpy/common/system/user.py:
+ - The error handling path requires the "sys" module,
+ so added an import sys at the top of the file.
+
+2010-05-18 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Fix a repaint issue and textarea tests
+ https://bugs.webkit.org/show_bug.cgi?id=39054
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::canvas): Remove m_paintRect initialization in canvas().
+ This line updated m_paintRect unexpectedly during paintRect().
+ We don't need to initialize m_paintRect because show() does it.
+
+2010-05-18 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] new-run-webkit-tests --use-drt should run on Linux
+ https://bugs.webkit.org/show_bug.cgi?id=37845
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+
+2010-05-18 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Fix some initialization/reset issues
+ https://bugs.webkit.org/show_bug.cgi?id=39281
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::reset): Reset m_userStyleSheetLocation.
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ Remove unused variable, m_workQueueFrozen.
+ (LayoutTestController::WorkQueue::WorkQueue): Initialize m_frozen.
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::resetTestController): Reset WebSettings too.
+
+2010-05-18 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Ojan Vafai.
+
+ new-run-webkit-tests: implement '--reset-results' flag to complement
+ the '--new-baseline' flag. '--new-baseline' will always write the
+ results into the platform directory; '--reset-results' will update the
+ existing baseline wherever it happens to be. Both sets of behavior
+ are useful in different circumstances.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38879
+
+ * Scripts/webkitpy/layout_tests/data/image/canvas-bg.html: Added.
+ * Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.checksum: Added.
+ * Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.png: Added.
+ * Scripts/webkitpy/layout_tests/data/image/canvas-zoom-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/image/canvas-zoom.html: Added.
+ * Scripts/webkitpy/layout_tests/data/misc/crash-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/misc/crash.html: Added.
+ * Scripts/webkitpy/layout_tests/data/misc/missing-expectation.html: Added.
+ * Scripts/webkitpy/layout_tests/data/misc/passing-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/misc/passing.html: Added.
+ * Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.checksum: Added.
+ * Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.png: Added.
+ * Scripts/webkitpy/layout_tests/data/platform/test/image/canvas-bg-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/platform/test/test_expectations.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/text/article-element-expected.txt: Added.
+ * Scripts/webkitpy/layout_tests/data/text/article-element.html: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+
+2010-05-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Add an --html5-parser option to DumpRenderTree to allow testing the new HTML5Lexer
+ https://bugs.webkit.org/show_bug.cgi?id=39311
+
+ This flag allows us to run the new HTML5Lexer code.
+ Right now all documents parse as empty documents, but
+ now that we're able to run the code we can fix that.
+
+ Once we're able to lex a few basic documents I'll add
+ an --html5-parser flag to run-webkit-tests so that we test
+ running all of the layout tests with the HTML5 parser.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ (initializeGlobalsFromCommandLineOptions):
+
+2010-05-08 Robert Hogan <robert@roberthogan.net>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Fix http/tests/xmlhttprequest/cross-origin-no-authorization.html
+ and http/tests/xmlhttprequest/cross-origin-authorization.html
+
+ QHttpNetworkRequest adds Authorization and Cookie headers to XHRs
+ without knowing if this is valid behaviour or not. In order to allow
+ Qt to decide whether Cookie/Authorization headers should be added
+ to an XHR QtWebKit needs to use an attribute added to QNetworkRequest.
+ These new attributes are: QNetworkRequest::CookieLoadControlAttribute,
+ QNetworkRequest::CookieSaveControlAttribute,and
+ QNetworkRequest::AuthenticationReuseControlAttribute.
+
+ In order to properly support the tests, Qt's DRT needs to use one
+ NetworkAccessManager for all pages. This allows it to use cached
+ credentials where appropriate.
+
+ The tests now pass when run individually but there seems to be a problem with
+ leaking the results of requests across tests when run with the others in
+ http/tests. This will be addressed in a separate patch.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32967
+
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+
+
+2010-05-18 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ run_webkit_tests_unittest fails on SnowLeopard
+ https://bugs.webkit.org/show_bug.cgi?id=39279
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ Return copy of os.environ.
+ * Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py:
+ Check os.environ was not modified.
+
+2010-05-18 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Chromium: new-run-webkit-httpd fails to setup_mount
+ https://bugs.webkit.org/show_bug.cgi?id=39257
+
+ * Scripts/webkitpy/common/system/executive.py:
+ Assert type of args in run_command.
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ Add test_run_command_args_type
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ Executive.run_command takes array for command line.
+ * Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py:
+ Test if setup_environ_for_server() run setup_mount.bat.
+
+2010-05-17 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by David Levin.
+
+ Chromium Windows build system does not rebuild correctly when
+ enabling/disabling a feature
+ https://bugs.webkit.org/show_bug.cgi?id=38926
+
+ Add a workaround of this issue.
+
+ * Scripts/update-webkit:
+ Chromium-Windows only: If WebKit/chromium/features.gyp has been
+ updated, remove WebKit/chromium/Debug and WebKit/chromium/Release.
+
+2010-05-17 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r59631.
+ http://trac.webkit.org/changeset/59631
+ https://bugs.webkit.org/show_bug.cgi?id=39255
+
+ chromium canaries can no longer run webkit_tests, suspect this
+ change. (Requested by atwilson on #webkit).
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-05-17 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Attempt to make new-run-webkit-tests --help more sane
+ https://bugs.webkit.org/show_bug.cgi?id=37836
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ - Add a FIXME about options.singly and options.batch_size being different.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ - Add support for hidden options.
+ - Add option groupings to attempt to simplify --help.
+ - Fix a bunch of option helps to start with a capitalized verb.
+ - Hide a bunch of options which make no sense to users.
+ - Sort options in --help.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+ - Add tests for option sorting.
+
+2010-05-17 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Disable Icon Database by default in Qt DRT
+
+ Unskip:
+ http/tests/misc/favicon-loads-with-images-disabled.html
+ http/tests/security/XFrameOptions/x-frame-options-deny-meta-tag-in-body.html
+ http/tests/security/XFrameOptions/x-frame-options-deny-meta-tag-parent-same-origin-deny.html
+ http/tests/security/XFrameOptions/x-frame-options-deny-meta-tag.html
+
+ https://bugs.webkit.org/show_bug.cgi?id=37382
+
+ Add support for layoutTestController.setIconDatabaseEnabled and layoutTestController.disableImageLoading().
+ The XFrameOptions tests were failing because of an extra resource load callback for favicon.ico requests.
+ These extra callbacks are removed by supporting both of the above layoutTestContoller commands.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::resetSettings):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ (WebCore::DumpRenderTree::drtStoragePath):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::disableImageLoading):
+ (LayoutTestController::setIconDatabaseEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-05-17 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Chromium: Add --chromium option to new-run-webkit-websocketserver
+ https://bugs.webkit.org/show_bug.cgi?id=37664
+
+ os.environ setup and setup_mount for cygwin are moved in ChromiumWinPort.setup_environ_for_server.
+
+ * Scripts/new-run-webkit-httpd:
+ Remove passing register_cygwin.
+ * Scripts/new-run-webkit-websocketserver:
+ Add --chromium flag.
+ Remove passing register_cygwin.
+ Create port object using options.
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ Add setup_environ_for_server().
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ Ditto.
+ * Scripts/webkitpy/layout_tests/port/factory_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/port/http_server.py:
+ Remove register_cygwin_parameter.
+ Call setup_environ_for_server().
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ Ditto.
+
+2010-05-16 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Chris Jerdonek.
+
+ https://bugs.webkit.org/show_bug.cgi?id=39184
+
+ Adds function VCSUtils::parseSvnProperty to parse an SVN property with
+ either a single-line or multi-line value change.
+
+ * Scripts/VCSUtils.pm:
+ - Added function parseSvnProperty. We will use this function
+ towards resolving Bug #38885 <https://bugs.webkit.org/show_bug.cgi?id=38885>.
+ - Removed FIXME comment above function parseSvnPropertyValue, since
+ it is being used by parseSvnProperty.
+ - Modified function parseSvnPropertyValue to break out of "while (<$fileHandle>)"
+ loop when it encounters the start of the next property so that it can be
+ processed by its caller, parseSvnPropertyValue. We reference this bullet below
+ by (*).
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnProperty.pl: Added.
+ - Added unit tests.
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl:
+ - Changed the name of the unit test "simple multi-line '-' change" to
+ "single-line '-' change followed by empty line" since the former was an
+ incorrect description of this test.
+ - Added unit test "single-line '-' change followed by the next property", and
+ "multi-line '-' change followed by the next property" to test (*) above.
+
+2010-05-16 Tony Chang <tony@chromium.org>
+
+ Not reviewed, fixing layout test.
+
+ Don't output Inspect Element since this is not enabled on the bots,
+ but most developers probably have it installed.
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController contextClick:]):
+
+2010-05-12 Tony Chang <tony@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Spellcheck disabling does not disable context menu
+ https://bugs.webkit.org/show_bug.cgi?id=25639
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (+[EventSendingController webScriptNameForSelector:]):
+ (-[EventSendingController contextClick:]): add a bool parameter that
+ when true, dumps the context menu items to stdout.
+
+2010-05-16 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Unskip fast/loader/main-document-url-for-non-http-loads.html
+
+ Update Qt DRT to use frame loader, editor client and notification presenter
+ functions in DumpRenderTreeSupportQt.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38867
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::reset):
+ (LayoutTestController::dumpEditingCallbacks):
+ (LayoutTestController::dumpFrameLoadCallbacks):
+ (LayoutTestController::dumpResourceLoadCallbacks):
+ (LayoutTestController::setWillSendRequestReturnsNullOnRedirect):
+ (LayoutTestController::setWillSendRequestReturnsNull):
+ (LayoutTestController::setWillSendRequestClearHeader):
+
+2010-05-16 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r59571.
+ http://trac.webkit.org/changeset/59571
+ https://bugs.webkit.org/show_bug.cgi?id=39054
+
+ Broke Cr Win, but we didn't notice immediately due to
+ https://bugs.webkit.org/show_bug.cgi?id=38926. It's possible
+ that this didn't actually break Cr Win, but rather that bug
+ 38926 necessitates a clean compile after this and sucessive
+ checkins only produced a partial recompile and thus failed to
+ build.
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::canvas):
+
+2010-05-16 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt]Unskip security/set-form-autocomplete-attribute.html
+
+ Add support for layoutTestController.elementDoesAutoCompleteForElementWithId().
+
+ https://bugs.webkit.org/show_bug.cgi?id=38859
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::elementDoesAutoCompleteForElementWithId):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-05-16 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Fix repaint, WebGL, textarea tests
+ https://bugs.webkit.org/show_bug.cgi?id=39054
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::canvas): Remove m_paintRect initialization in canvas().
+ This line updated m_paintRect unexpectedly during paintRect().
+ We don't need to initialize m_paintRect because show() does it.
+
+2010-05-16 Sergio Villar Senin <svillar@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] Improve reporting of frame loader callbacks in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=36454
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewLoadStatusNotified):
+ (createWebView): added connection to notify::load-status and
+ signal callback
+
+2010-05-15 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Chris Jerdonek.
+
+ https://bugs.webkit.org/show_bug.cgi?id=39170
+
+ Add function parseSvnPropertyValue to parse single-line and multi-line
+ property values of an SVN property change.
+
+ * Scripts/VCSUtils.pm:
+ Added function parseSvnPropertyValue. We will use this as part of
+ Bug #38885 <https://bugs.webkit.org/show_bug.cgi?id=38885>.
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl: Added.
+
+2010-05-15 Jochen Eisinger <jochen@chromium.org>
+
+ Reviewed by Dmitry Titov.
+
+ Add allowDatabase method to TestWebWorker.
+ https://bugs.webkit.org/show_bug.cgi?id=38742
+
+ * DumpRenderTree/chromium/TestWebWorker.h:
+ (TestWebWorker::allowDatabase):
+
+2010-05-15 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Antti Koivisto.
+
+ [Qt] Rename QtLauncher to QtTestBrowser
+ https://bugs.webkit.org/show_bug.cgi?id=37665
+
+ Forgot to remove the original directory after the rename.
+
+ * QtLauncher: Removed.
+
+2010-05-15 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r59544.
+ http://trac.webkit.org/changeset/59544
+ https://bugs.webkit.org/show_bug.cgi?id=39165
+
+ Cased LayoutTest to start crashing (Requested by abarth on
+ #webkit).
+
+ * Scripts/old-run-webkit-tests:
+
+2010-05-15 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ Ensure DRT loads GAIL (Gtk+ module), for a11y tests
+ https://bugs.webkit.org/show_bug.cgi?id=38648
+
+ Add the GTK_MODULES envvar (set to "gail") to the clean
+ environment when running DRT for the Gtk+ port
+
+ * Scripts/old-run-webkit-tests:
+
+2010-05-15 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Add script to check for minimum python version and install if missing on Tiger
+ https://bugs.webkit.org/show_bug.cgi?id=38886
+
+ Per Maciej's request on webkit-dev:
+ https://lists.webkit.org/pipermail/webkit-dev/2010-May/012785.html
+ provide a script which can automatically install Python on Tiger where
+ the system provided version is too old to be of use.
+
+ Note this uses the official Mac Python installer from python.org.
+ This installs a copy of Python in /Library/Frameworks/Python.framework.
+ It also makes symlinks from /usr/local/bin to the Python.framework/bin.
+
+ I have tested this script on Leopard and it worked fine. I have not
+ tested it on Tiger as I do not have access to a Tiger machine. In
+ either case this should provide a great starting point for someone
+ wishing to upgrade their copy of Python on Tiger.
+
+ Future patches can make our scripts depend on a success return from this
+ script and then they can either skip tests/sections for which python is
+ insufficient, or they can fail themselves.
+
+ * Scripts/ensure-valid-python: Added.
+
+2010-05-15 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Display queue position inside EWS bubbles
+ https://bugs.webkit.org/show_bug.cgi?id=38979
+
+ This ended up being a lot of clean-up to our status server code.
+
+ Added a new WorkItems model, a form with which to fill it,
+ and taught the Attachment class how to calculate the current queue
+ postion for an attachment using the data in WorkItems.
+
+ I also finally made statusbubble.* and dashboard.* not use copy-paste code.
+
+ The Attachment class has this summary() method which is very
+ controller/view-like and does not belong in a model class.
+ This patch got rid of all direct uses of summary().
+
+ * QueueStatusServer/handlers/dashboard.py:
+ - Build row objects to hand off to the view instead of handing off a
+ summary object and expecting the view to process it directly.
+ * QueueStatusServer/handlers/statusbubble.py:
+ - Build bubble object and hand them off to the view.
+ * QueueStatusServer/handlers/updatestatus.py:
+ - Code cleanup. Just move some code into _queue_status_from_request
+ to make the main put() handler easier to read.
+ * QueueStatusServer/handlers/updateworkitems.py: Added.
+ - Controller to handle storing WorkItems model objects.
+ * QueueStatusServer/main.py:
+ - Add route for /update-work-items
+ * QueueStatusServer/model/attachment.py:
+ - Add new methods to replace direct summary() access.
+ - Teach attachment how to calculate queue positions from WorkItems data.
+ * QueueStatusServer/model/queues.py:
+ - Move name_with_underscores here for easier re-use.
+ * QueueStatusServer/model/workitems.py: Added.
+ - New model for storing what items are currently queue for any bot.
+ * QueueStatusServer/templates/dashboard.html:
+ - Kill the copy/paste code!
+ * QueueStatusServer/templates/statusbubble.html:
+ - Kill the copy/paste code!
+ * QueueStatusServer/templates/updateworkitems.html: Added.
+ - Simple form for updating a queue's current work items.
+
+2010-05-15 Joanmarie Diggs <joanmarie.diggs@gmail.com>
+
+ Reviewed by Xan Lopez.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30500
+ [Gtk] Find a way for WebKit to "announce" itself so that ATs can readily distinguish it from true Gtk/Gail
+
+ The "announcement" is now made in the form of an object attribute
+ associated with the AtkObject.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::allAttributes):
+ (attributeSetToString):
+
+2010-05-15 Mario Sanchez Prada <msanchez@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ Accessibility: Implement isSelected in DRT for GTK
+ https://bugs.webkit.org/show_bug.cgi?id=31018
+
+ Implement AccessibilityUIElement::isSelected() for Gtk
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::isSelected):
+
+2010-05-14 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ scm.py should use self.run instead of run_command
+ https://bugs.webkit.org/show_bug.cgi?id=38957
+
+ We've wanted to do this for a while, but it's a prerequiste for running
+ SVN from the cwd instead of the checkout_root.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+
+2010-05-14 Anton Muhin <antonm@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ [Chromium] Consider implementing addOriginAccessWhitelistEntry method
+ https://bugs.webkit.org/show_bug.cgi?id=37578
+
+ Remove deprecated methods.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp
+ * DumpRenderTree/chromium/LayoutTestController.h
+
+2010-05-14 Kenneth Russell <kbr@google.com>
+
+ Reviewed by Darin Adler.
+
+ Rename WebGLArray types to TypedArray types
+ https://bugs.webkit.org/show_bug.cgi?id=39091
+
+ Extended functionality of do-webcore-rename script and used it to
+ rename the WebGLArray types to the TypedArray naming convention.
+ The only source files which were touched by hand, and which are
+ being manually reviewed, are:
+ WebCore/page/DOMWindow.idl
+ WebCore/bindings/generic/RuntimeEnabledFeatures.h (script's changes undone)
+ WebKit/WebCore/bindings/js/JSDOMWindowCustom.cpp
+ WebKit/WebCore/bindings/v8/custom/V8DOMWindowCustom.cpp
+ These only needed to be touched to update the aliases between the
+ WebGLArray and TypedArray names introduced in bug 39036. (It was
+ not feasible to have do-webcore-rename handle this as it would
+ introduce circular renamings.) These aliases will be removed in
+ roughly a month once existing WebGL content has been updated.
+
+ No new tests; covered under existing WebGL tests. Updated
+ constructed-objects-prototypes and prototype-inheritance-2 tests.
+ Ran all layout tests in Safari and all WebGL tests in Chromium.
+
+ * Scripts/do-webcore-rename:
+ Handle the case where some renames are substrings of others.
+ Support renaming files containing custom JS bindings. If
+ isDOMTypeRename is non-zero, expand the regexp which rewrites
+ the file's contents in order to support custom JS bindings.
+
+2010-05-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch rollout throws exception if bug is already open
+ https://bugs.webkit.org/show_bug.cgi?id=38803
+
+ This was caused by someone incorrectly wrapping the code. :p
+ I'm going to have to start demanding unit tests for wrapping changes...
+
+ I also fixed the code to be able to reopen bugs which were never confirmed.
+ Before it regressed, the code would just log in that case. Now it actually
+ will reopen the bug, but there is a FIXME about how the logic is a bit backwards.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+ - Yay testing!
+
+2010-05-14 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Antti Koivisto.
+
+ [Qt] Rename QtLauncher to QtTestBrowser
+
+ * QtTestBrowser: Copied from WebKitTools/QtLauncher.
+ * QtTestBrowser/QtLauncher.pro: Removed.
+ * QtTestBrowser/QtLauncher.qrc: Removed.
+ * QtTestBrowser/QtTestBrowser.pro: Copied from WebKitTools/QtLauncher/QtLauncher.pro.
+ * QtTestBrowser/QtTestBrowser.qrc: Copied from WebKitTools/QtLauncher/QtLauncher.qrc.
+ * Scripts/run-launcher:
+ * Scripts/webkitdirs.pm:
+
+2010-05-14 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Stop CCing webkit-bot-watchers
+ https://bugs.webkit.org/show_bug.cgi?id=39020
+
+ webkit-bot-watchers is somewhat of a failed experiment. No one
+ subscribed to the list (not even me). Removing it from the code
+ because wms says it bounces email sometimes.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+
+2010-05-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ REGRESSION: webkit-patch commit-message throws exception
+ https://bugs.webkit.org/show_bug.cgi?id=38997
+
+ * Scripts/webkitpy/tool/commands/upload.py:
+ - Fix to respect and pass the --squash and --git-commit options.
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ - Fix the unit test to use the central MockCheckout instead of
+ its own custom Mock which didn't require enough parameters.
+
+2010-05-13 Diego Gonzalez <diegohcg@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Improve QtLauncher user agent dialog resize
+ https://bugs.webkit.org/show_bug.cgi?id=39062
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::showUserAgentDialog):
+
+2010-05-13 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Ojan Vafai.
+
+ Disable compositing/iframes tests on the commit-queue as a workaround for bug 38912
+ https://bugs.webkit.org/show_bug.cgi?id=39067
+
+ Fix yet another typo in my original hack.
+ I also added another unit test for this fix.
+
+ * Scripts/webkitpy/common/config/ports.py:
+ * Scripts/webkitpy/common/config/ports_unittest.py:
+
+2010-05-13 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Ojan Vafai.
+
+ Disable compositing/iframes tests on the commit-queue as a workaround for bug 38912
+ https://bugs.webkit.org/show_bug.cgi?id=39067
+
+ My previous (unreviewed) hack didn't actually work due to checking "mac" instead of "Mac".
+ This change fixes my hack, and unit tests it.
+
+ * Scripts/webkitpy/tool/mocktool.py:
+ - Make it possible to make run_command log too.
+ * Scripts/webkitpy/tool/steps/runtests.py:
+ - Fix my hack to actually work.
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ - Test my hack (and basic RunTests behavior as well).
+
+2010-05-13 Antonio Gomes <tonikitoo@webkit.org>, Yi Shen <yi.4.shen@nokia.com>
+
+ Reviewed by Kenneth Christiansen.
+
+ [Qt] Add LayoutTestController interface: computedStyleIncludingVisitedInfo
+ https://bugs.webkit.org/show_bug.cgi?id=37759
+
+ WebKitTools:
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::computedStyleIncludingVisitedInfo):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-05-10 Adam Roben <aroben@apple.com>
+
+ Convert status bar text to UTF-8 before logging it on Windows
+
+ We were previously logging the text using printf("%S", bstr). This
+ converts the UTF-16 BSTR to a multibyte string using wctomb, which
+ uses the codepage for the current locale to perform the conversion.
+ The conversion was failing, causing printf to bail and truncate the
+ string. By converting to UTF-8 manually before logging, we avoid this
+ issue (and also end up with UTF-8 output, which is what the expected
+ results contain). We may have to do this in other places in DRT,
+ eventually.
+
+ Fixes <http://webkit.org/b/38849> REGRESSION (r59016):
+ plugins/set-status.html fails on Windows
+
+ Reviewed by Alexey Proskuryakov.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (toUTF8): Moved this here from FrameLoadDelegate. Renamed from
+ BSTRtoString.
+
+ * DumpRenderTree/win/DumpRenderTreeWin.h: Added declaration of toUTF8.
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp: Removed BSTRtoString.
+ (descriptionSuitableForTestResult): Updated for rename.
+
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::setStatusText): Convert the status bar text to UTF-8
+ before logging it so that Windows won't try (and fail) to convert it
+ to the current locale's codepage.
+
+2010-05-13 Eric Seidel <eric@webkit.org>
+
+ Unreviewed hack, attempting to get the commit-queue running again.
+
+ Disable compositing/iframes tests on the commit-queue as a workaround for bug 38912
+ https://bugs.webkit.org/show_bug.cgi?id=39067
+
+ I had this hack locally on the commit-queue, but it's fragile
+ and broke this morning. It will work much better if committed
+ to the repository. In either case it's temporary while we
+ work up a real fix for bug 38912.
+
+ * Scripts/webkitpy/common/config/ports.py:
+ - Expose an is_leopard() method.
+ * Scripts/webkitpy/tool/steps/runtests.py:
+ - Don't run compositing/iframes tests on the commit-queue under leopard.
+
+2010-05-13 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed fix. Revert previous change.
+
+ Even if with-statments are changed in websocket_server.py, it also claims syntax error for with statement in http_server.py.
+ Until python 2.5 is installed on tiger bot, skips websocket/tests on tiger.
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py: use with statement
+
+2010-05-13 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed fix.
+
+ On tiger bot, it claims syntax error for with statement.
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py: rewrite with statement with try-finally.
+
+2010-05-13 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by David Levin.
+
+ WebSocket: pywebsocket 0.5
+ https://bugs.webkit.org/show_bug.cgi?id=38034
+
+ Remove pywebsocket from webkitpy/thirdparty.
+ Make pywebsocket autoinstalled.
+
+ * Scripts/new-run-webkit-websocketserver:
+ Add --output-dir option.
+ * Scripts/old-run-webkit-tests:
+ Use new-run-webkit-websocketserver, rather than directly run pywebsocket's standalone.py
+ * Scripts/run-webkit-websocketserver:
+ Ditto.
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ Use autoinstalled pywebsocket.
+ * Scripts/webkitpy/thirdparty/__init__.py:
+ Autoinstall pywebsocket
+ * Scripts/webkitpy/thirdparty/pywebsocket: Removed.
+
+2010-05-12 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ Fixed a bug in svn-apply whereby the reviewer would not get set if
+ the portion of the patch for the ChangeLog contains "NOBODY (**PS!)"
+ in the leading junk.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38998
+
+ * Scripts/VCSUtils.pm:
+ - Added the $changeLogTimeZone variable from svn-apply.
+ - Added setChangeLogDateAndReviewer() from svn-apply.
+ - Added a localTimeInProjectTimeZone() subroutine.
+ - In setChangeLogDateAndReviewer():
+ - Added an $epochTime parameter to make the subroutine more testable.
+ - Made the "NOBODY (**PS!)" regular expression more specific so that
+ it will not apply to text in the leading junk.
+ - Updated to call localTimeInProjectTimeZone().
+ * Scripts/svn-apply:
+ - Removed the $changeLogTimeZone file variable.
+ - Added an $epochTime file variable to represent the current time.
+ - Removed the setChangeLogDateAndReviewer() subroutine.
+ - Updated patch() to use the new setChangeLogDateAndReviewer() syntax.
+ * Scripts/webkitperl/VCSUtils_unittest/setChangeLogDateAndReviewer.pl: Added.
+ - Added unit tests.
+
+2010-05-12 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ test-webkitpy fails on windows due to lack of readline module
+ https://bugs.webkit.org/show_bug.cgi?id=38884
+
+ Win32 Python does not have a readline module, so we should
+ not exit(1) if the import fails.
+
+ Also the failure message is mac-specific and doesn't need to be.
+ Only print the mac-specific install instructions on mac.
+
+ * Scripts/webkitpy/common/system/user.py:
+
+2010-05-12 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Nate Chapin.
+
+ [DRT/Chromium] Add a missing Sans-serif font setting
+ https://bugs.webkit.org/show_bug.cgi?id=38981
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::resetWebSettings):
+ Set "Helvetica" for Sans-serif. It is the same as the default setting of test_shell.
+
+2010-05-10 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch upload --fancy-review now uses the bugzilla bug ID as the rietveld ID
+ https://bugs.webkit.org/show_bug.cgi?id=38866
+
+ wkrietveld.appspot.com has already been updated to allow you to
+ pass --issue for the issue creation as well as subsequent uploads.
+
+ Also, remove the extra code for trying to read out the issue ID
+ from the changelog description since we just use the bugzilla ID now.
+
+ * Scripts/webkitpy/common/config/__init__.py:
+ * Scripts/webkitpy/common/net/rietveld.py:
+ * Scripts/webkitpy/tool/steps/postcodereview.py:
+ * Scripts/webkitpy/tool/steps/postdiff.py:
+
+2010-05-12 Ojan Vafai <ojan@chromium.org>
+
+ No review needed.
+
+ Marking myself as a reviewer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-05-12 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests: add a --print default option so that you can
+ easily get the default output plus something (e.g., you can say
+ '--print default,config' instead of '--print misc,one-line-progress,
+ one-line-summary,unexpected,unexpected-results,updates,config'.
+
+ Also, add more unit tests for --verbose, --print everything, etc.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38877
+
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+
+2010-05-12 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Qt build failures cause SheriffBot false positives
+ https://bugs.webkit.org/show_bug.cgi?id=38969
+
+ Add Qt bots back to the core builders, because bug fixed by r59261.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+
+2010-05-12 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Slave losts cause build break on bots
+ https://bugs.webkit.org/show_bug.cgi?id=38980
+
+ * Scripts/build-webkit: Remove 0 byte sized files from productDir before build.
+
+2010-05-12 Csaba Osztrogonác <ossy@webkit.org>
+
+ Unreviewed trivial fix after r59254.
+
+ * Scripts/old-run-webkit-tests:
+
+2010-05-12 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ run-webkit-tests --exit-after-N-failures should not count new tests as failures
+ https://bugs.webkit.org/show_bug.cgi?id=31829
+
+ * Scripts/old-run-webkit-tests:
+
+2010-05-12 James Robinson <jamesr@chromium.org>
+
+ Reviewed by Simon Fraser.
+
+ Disable smooth scrolling on OS X when running tests
+ https://bugs.webkit.org/show_bug.cgi?id=38964
+
+ Some tests (like fast/repaint/fixed-move-after-keyboard-scroll.html)
+ depend on smooth scrolling behavior. Since this is off by default
+ in Leopard and on by default in Snow Leopard, DRT should turn it
+ off always to ensure a consistent test environment.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+
+2010-05-10 Rodrigo Belem <rodrigo.belem@openbossa.org>
+
+ Reviewed by Kenneth Christiansen , Simon Hausmann and Gustavo Noronha.
+
+ [Qt, Gtk] Allows build-webkit script to receive an install prefix as parameter
+ https://bugs.webkit.org/show_bug.cgi?id=26224
+
+ Added more parameters to build-webkit script, the --prefix for gkt
+ and --install-libs, --install-headers for qt. Now it is possible
+ to change the install prefix for gtk and install path for qt.
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2010-05-12 Philippe Normand <pnormand@igalia.com>
+
+ Unreviewed, added my IRC nickname.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-05-11 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Fixed two FIXME's in svn-apply: eliminated the unnecessary %copiedFiles
+ variable and changed gitKnowsOfFile() to use exitStatus().
+
+ https://bugs.webkit.org/show_bug.cgi?id=38862
+
+ * Scripts/svn-apply:
+
+2010-05-11 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, just fixing python typo.
+
+ EWS bots should poll more often than every 5 minutes
+ https://bugs.webkit.org/show_bug.cgi?id=38968
+
+ Typo in _now(), add a unittest to prove I fixed it.
+
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/bot/queueengine_unittest.py:
+
+2010-05-11 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Qt build failures cause SheriffBot false positives
+ https://bugs.webkit.org/show_bug.cgi?id=38969
+
+ The Qt buildbot randomly fails to compile occasionally because its
+ network connection causes SVn to leave zero-byte files around. These
+ compile failures confuse SheriffBot into thinking someone's patch
+ caused a build break.
+
+ In this patch, I've temporarily removed Qt from the list of core
+ builders. Ossy is working on a script to clean up the zero byte files.
+ Once that goes in, we can add Qt back to the core builders.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+
+2010-05-11 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ sheriffbot is spammy.
+ https://bugs.webkit.org/show_bug.cgi?id=38936
+
+ Reduce sheriffbot spam by not warning about new blameworthy revisions
+ that can be explained by previously blamed revisions. This might cause
+ us to not warn about some real failures, but we're getting too much
+ spam from slow builders that have large blamelists (and we've already
+ poked the responsible folks using data from a fast builder).
+
+ * Scripts/webkitpy/tool/bot/sheriff_unittest.py:
+ - Removed unneeded import
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ - The logic change
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+ - Tests of the change
+ * Scripts/webkitpy/tool/mocktool.py:
+ - Merged two declarations of MockBuilder
+
+2010-05-11 Tony Chang <tony@chromium.org>
+
+ Reviewed by David Levin.
+
+ [chromium] detect num processors to pass to make -j on Linux
+ https://bugs.webkit.org/show_bug.cgi?id=38833
+
+ * Scripts/webkitdirs.pm:
+
+2010-05-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ EWS bots should poll more often than every 5 minutes
+ https://bugs.webkit.org/show_bug.cgi?id=38968
+
+ We'll make them poll every 2 minutes to start with.
+ I'm going to re-write how polling works soon, so this is
+ a stop-gap to try and make the bots more responsive.
+
+ If Bill notices any additional load on bugzilla we'll drop
+ the polling frequency back to 5 minutes. He's historically said
+ that the EWS bots appear to be a drop in the bucket and thus
+ should be able to poll much more frequently w/o causing trouble.
+
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/bot/queueengine_unittest.py:
+ - Add a test for sleep_message
+
+2010-05-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue should commit rollouts without running tests
+ https://bugs.webkit.org/show_bug.cgi?id=38940
+
+ Most of this change is improving our test coverage for the commit-queue.
+ The only functional change is removing the --test flag when the commit-queue
+ is running in rollouts mode.
+
+ I added test coverage for status updates, and updated the commit-queue status
+ messages to distinguish rollout vs. normal landing mode in its empty queue
+ and land patch messages.
+
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+ - Got rid of a bunch of copy/paste code using _default_expected_stderr
+ * Scripts/webkitpy/tool/commands/queues.py:
+ - Moved rollout patch filtering out of _validate_patches_in_commit_queue
+ so that we only have to check if the builders are green in one place.
+ - Make the "empty queue" message note which queue it is referring to.
+ - Don't pass --text to land-attachment when in rollout mode.
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ - Update results now that we're testing status updates.
+ - Test _can_build_and_test since I made a typo in that call while
+ writing this change and the unit tests failed to catch it!
+ * Scripts/webkitpy/tool/mocktool.py:
+ - Log status updates to make them testable in our unit tests.
+
+2010-05-11 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Apply recent changes of test_shell to DRT
+ https://bugs.webkit.org/show_bug.cgi?id=38895
+
+ Port the changes to test_shell during (r40492, r46810] of Chromium.
+ Highlights:
+ - Introduce NotificationPresenter
+ - Fix parameter mismatch of WebViewClient::startDragging()
+
+ This change fixes dozens of unexpected behaviors.
+
+ * DumpRenderTree/DumpRenderTree.gypi:
+ Add NotificationPresenter.{cpp,h}
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (applyKeyModifier):
+ (EventSender::EventSender):
+ (EventSender::reset):
+ (EventSender::webview):
+ (EventSender::doDragDrop):
+ (EventSender::keyDown):
+ (EventSender::addTouchPoint):
+ (EventSender::clearTouchPoints):
+ (EventSender::releaseTouchPoint):
+ (EventSender::setTouchModifier):
+ (EventSender::updateTouchPoint):
+ (EventSender::cancelTouchPoint):
+ (EventSender::sendCurrentTouchEvent):
+ (EventSender::touchEnd):
+ (EventSender::touchMove):
+ (EventSender::touchStart):
+ (EventSender::touchCancel):
+ * DumpRenderTree/chromium/EventSender.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::reset):
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::setAuthorAndUserStylesEnabled):
+ (LayoutTestController::setScrollbarPolicy):
+ (LayoutTestController::setWillSendRequestClearHeader):
+ (LayoutTestController::callShouldCloseOnWebView):
+ (LayoutTestController::grantDesktopNotificationPermission):
+ (LayoutTestController::removeOriginAccessWhitelistEntry):
+ (LayoutTestController::addUserScript):
+ (LayoutTestController::addUserStyleSheet):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/NotificationPresenter.cpp: Added.
+ * DumpRenderTree/chromium/NotificationPresenter.h: Added.
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::TestShell):
+ (TestShell::runFileTest):
+ (TestShell::resetTestController):
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::eventSender):
+ (TestShell::notificationPresenter):
+ (TestShell::showDevTools):
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::createView):
+ (WebViewHost::createPopupMenu):
+ (WebViewHost::startDragging):
+ (WebViewHost::notificationPresenter):
+ (WebViewHost::createApplicationCacheHost):
+ (WebViewHost::willSendRequest):
+ (WebViewHost::updateAddressBar):
+ (WebViewHost::updateURL):
+ * DumpRenderTree/chromium/WebViewHost.h:
+ (WebViewHost::addClearHeader):
+ (WebViewHost::clearHeaders):
+
+2010-05-10 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests: fix a path-handling bug that was breaking the
+ dryrun ports on windows, and add a comment about why we don't run
+ the chromium dryrun tests by default on every port.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38796
+
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-05-11 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Darin Adler.
+
+ <http://webkit.org/b/38941> build-webkit shouldn't always override ENABLE_FOO Xcode configuration settings
+
+ * Scripts/build-webkit: Don't pass the ENABLE setting to xcodebuild if the value matches the default.
+ This will lead to xcodebuild picking up the settings from FeatureDefines.xcconfig, and will aid in
+ revealing problems that are due to inconsistent values for settings across projects.
+
+2010-05-11 Mark Rowe <mrowe@apple.com>
+
+ Build fix.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+
+2010-05-10 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by David Levin.
+
+ CheckStyle was eating script errors when there were local-commits and working copy changes
+ https://bugs.webkit.org/show_bug.cgi?id=38880
+
+ * Scripts/webkitpy/tool/steps/checkstyle.py:
+ * Scripts/webkitpy/tool/steps/checkstyle_unittest.py: Added.
+
+2010-05-11 Jian Li <jianli@chromium.org>
+
+ Reviewed by Dmitry Titov.
+
+ Expose FileReader interface.
+ https://bugs.webkit.org/show_bug.cgi?id=38609
+
+ * Scripts/build-webkit: turn on building FileReader for Apple's WebKit.
+
+2010-05-10 Tony Chang <tony@chromium.org>
+
+ Reviewed by Kent Tamura.
+
+ [chromium] Build DRT when running build-webkit --chromium
+ https://bugs.webkit.org/show_bug.cgi?id=38730
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp: Removed.
+ * Scripts/build-dumprendertree: This does nothing now.
+
+2010-05-10 Jon Honeycutt <jhoneycutt@apple.com>
+
+ REGRESSION(r59100): Added test is broken on many platforms.
+ https://bugs.webkit.org/show_bug.cgi?id=38881
+
+ Reviewed by Eric Seidel.
+
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp:
+ (NPP_Destroy):
+ Use pluginLog, rather than printf, to match other platforms.
+
+2010-05-10 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Fix a build failure caused by assuming the default platform in
+ a unit test for new-run-webkit-tests instead of specifying
+ --platform test.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-05-10 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build-fix
+
+ new-run-webkit-tests: fix test failure caused by me failing to update
+ the expected output. Also, run '--platform test' instead of
+ 'platform dryrun' since the former is guaranteed to work and the
+ latter isn't.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-05-10 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by David Levin.
+
+ new-run-webkit-tests: looks like the unicode conversion broke
+ --print-last-failures and --retest-last-failures. Fixing.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-05-10 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by David Levin.
+
+ Re-attempt to fix 38616 - newline handling in new-run-webkit-tests.
+ I didn't handle some cases correctly before and the solution was
+ confusing. The new patch assumes all calls to the printing module
+ don't have newlines, and will append newlines where necessary, just
+ like logging does.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38790
+
+ * Scripts/webkitpy/layout_tests/layout_package/metered_stream.py:
+ * Scripts/webkitpy/layout_tests/layout_package/metered_stream_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-05-10 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Make tkent a reviewer
+ https://bugs.webkit.org/show_bug.cgi?id=38875
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-05-07 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Crash closing window containing Flash plug-in
+ https://bugs.webkit.org/show_bug.cgi?id=38797
+ <rdar://problem/7935266>
+
+ Reviewed by Eric Seidel.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginAllocate):
+ Initialize new member to false.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ Added a new member.
+
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp:
+ (NPP_New):
+ Check whether the element has the "testGetURLOnDestroy" attribute, and
+ record that.
+ (NPP_Destroy):
+ If "testGetURLOnDestroy" is set, perform a load while destroying the
+ plug-in.
+
+2010-05-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ Executive.kill_* do not work with windows python
+ https://bugs.webkit.org/show_bug.cgi?id=38872
+
+ http://trac.webkit.org/changeset/57444 is where the original
+ breakage occurred.
+ http://trac.webkit.org/changeset/58314 is where the regression
+ started affecting chromium.
+
+ I have since learned that sys.platform has no "windows" value.
+ "win32" is always the value, under 32 or 64 bit windows
+
+ The tests for this code are not run anywhere because
+ test-webkitpy does not yet work on "win32". Mostly due to
+ depending on unixisms like "cat" and "yes".
+
+ * Scripts/webkitpy/common/system/executive.py:
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+
+2010-05-10 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix a bug in rebaseline-chromium-webkit-tests where we would crash
+ instead of logging an error and exiting if it couldn't find either a
+ debug or a release build of the image diff binary.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38692
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py: Added.
+
+2010-05-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests fails when run under sys.platform == "windows" due to undefined signal.SIGKILL
+ https://bugs.webkit.org/show_bug.cgi?id=38861
+
+ * Scripts/webkitpy/common/system/executive.py:
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+
+2010-05-10 Jer Noble <jer.noble@apple.com>
+
+ Unreviewed.
+
+ Adding myself as a committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-05-10 Hans Wennborg <hans@chromium.org>
+
+ Reviewed by Jeremy Orlow.
+
+ [Chromium] Add quota parameter to WebViewClient::createSessionStorageNamespace()
+ https://bugs.webkit.org/show_bug.cgi?id=38750
+
+ Put a per-origin quota on session storage since it is using memory in
+ the browser process, and should not be allowed to grow arbitrarily
+ large. See also http://trac.webkit.org/changeset/58828.
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::createSessionStorageNamespace):
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-05-10 Csaba Osztrogonác <ossy@webkit.org>
+
+ Rubber-stamped by Simon Hausmann.
+
+ [Qt] Roll-out r59020 and r59021, because the Qt part of these changes
+ haven't been landed in Qt trunk yet. Should be rolled-in again after the merge.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32967
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+
+2010-05-09 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Chris Jerdonek.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38812
+
+ Make the regular expressions for parsing the start of an SVN
+ and Git header global variables since they are used throughout
+ VCSUtils.pm.
+
+ * Scripts/VCSUtils.pm:
+
+2010-05-09 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ Finished moving the header-parsing logic from svn-apply and -unapply
+ to VCSUtils.pm's parsing methods.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38802
+
+ * Scripts/VCSUtils.pm:
+ - Added to parseGitDiffHeader() the ability to parse and store
+ whether a file is new or deleted.
+ - Also reordered in parseGitDiffHeader() some of the else statements
+ to a more readable ordering.
+ - Added to parseSvnDiffHeader() the ability to parse and store
+ whether a file is new.
+ * Scripts/svn-apply:
+ - Changed handleGitBinaryChange() to use the new "isNew" and "isDeletion"
+ diffHash key-values.
+ - Changed patch() to use the new "isNew" diffHash key-value.
+ * Scripts/svn-unapply:
+ - Changed patch() to use the new "isNew" and "isDeletion" diffHash key-values.
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl:
+ - Added unit tests for new and deleted files.
+ * Scripts/webkitperl/VCSUtils_unittest/parseGitDiffHeader.pl:
+ - Updated the unit tests as necessary.
+ - Added a unit test for a deleted file.
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffHeader.pl:
+ - Updated the unit tests as necessary.
+
+2010-05-08 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ Added to svn-apply support for git renames and copies with similarity
+ index less than 100%.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32834
+
+ * Scripts/VCSUtils.pm:
+ - Added to parseGitDiffHeader() support for renames and similarity
+ index less than 100%.
+ - Added to parseDiff() support for processing renames, renames with
+ changes, and copies with changes.
+ - Added to parsePatch() the ability to process multiple return
+ values from parseDiff().
+ * Scripts/svn-apply:
+ - Added to patch() the ability to process diff hashes with the
+ isDeletion key-value set.
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl:
+ - Updated the unit tests as necessary.
+ - Added unit tests for rename with similarity index 100%,
+ rename with similarity index < 100%, and rename with a change
+ to the executable bit.
+ * Scripts/webkitperl/VCSUtils_unittest/parseGitDiffHeader.pl:
+ - Added unit tests for rename with similarity index 100%,
+ rename with similarity index < 100%, and rename with a change
+ to the executable bit.
+ * Scripts/webkitperl/VCSUtils_unittest/parsePatch.pl:
+ - Updated the unit tests as necessary.
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffHeader.pl:
+ - Simplified the carriage-return unit test to more narrowly test
+ only carriage returns.
+
+2010-05-08 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ This revision suppresses the misleading "error: pathspec..." messages
+ when using svn-apply to add a binary file from a Git diff.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38047
+
+ When adding a new binary file from a Git diff, svn-apply prints
+ a misleading error of the form -- "error: pathspec '<filename>' did
+ not match any file(s) known to git. Did you forget to 'git add'?"
+ This patch suppresses these messages since they are normal.
+
+ * Scripts/VCSUtils.pm:
+ Added the callSilently() subroutine from runPatchCommand.pl, which
+ executes a Perl function while suppressing STDERR.
+ * Scripts/svn-apply:
+ Refactored the Git portion of scmKnowsOfFile() into a
+ gitKnowsOfFile(), and called this new subroutine using callSilently().
+ * Scripts/webkitperl/VCSUtils_unittest/runPatchCommand.pl:
+ Removed callSilently() since it was moved to VCSUtils.pm in this patch.
+
+2010-05-08 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ [chromium]: Upload test results json files to app engine server
+ Add an option to run_webkit_tests.py to upload generated
+ JSON files to app engine server. These JSON files will be used
+ by chromium layout test falkiness dashboard.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36063
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_results_uploader.py: Added.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-05-08 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Build the ImageDiff tool for all platforms including Windows and Symbian
+ https://bugs.webkit.org/show_bug.cgi?id=38706
+
+ Use qmath.h instead of math.h to make it portable.
+
+ * DumpRenderTree/qt/ImageDiff.cpp:
+ (main):
+
+2010-05-08 Robert Hogan <robert@roberthogan.net>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Fix http/tests/xmlhttprequest/cross-origin-no-authorization.html
+ and http/tests/xmlhttprequest/cross-origin-authorization.html
+
+ QHttpNetworkRequest adds Authorization and Cookie headers to XHRs
+ without knowing if this is valid behaviour or not. In order to allow
+ Qt to decide whether Cookie/Authorization headers should be added
+ to an XHR QtWebKit needs to use an attribute added to QNetworkRequest.
+ These new attributes are: QNetworkRequest::CookieLoadControlAttribute,
+ QNetworkRequest::CookieSaveControlAttribute,and
+ QNetworkRequest::AuthenticationReuseControlAttribute.
+
+ In order to properly support the tests, Qt's DRT needs to use one
+ NetworkAccessManager for all pages. This allows it to use cached
+ credentials where appropriate.
+
+ The tests now pass when run individually but there seems to be a problem with
+ leaking the results of requests across tests when run with the others in
+ http/tests. This will be addressed in a separate patch.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32967
+
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+
+
+2010-05-04 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] unskip http/tests/plugins/npapi-response-headers.html
+
+ Turns out this failed because run-webkit-tests was eating the first occurrence
+ of 'Content-Type: text/plain' in the test output as a header. Strange but true.
+ So do as Chromium does and preface all text dumps with the
+ 'Content-Type: text/plain' header.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38541
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::dump):
+
+2010-05-08 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ test-webkitpy fails under cygwin
+ https://bugs.webkit.org/show_bug.cgi?id=38718
+
+ * Scripts/webkitpy/common/system/executive.py:
+ - Add _KILL_PROCESS_KILLED_PROCESS_EXIT_CODE and
+ _KILL_ALL_KILLED_PROCESS_EXIT_CODE to store the expected
+ exit codes of processes killed by kill_process and kill_all.
+ These two constants are only used by the unit tests but are
+ stored in executive.py so they can be right next to the platform ifs.
+ - Remove unnecessary str() conversion, run_command does that for us.
+ - Make os.kill retry on cygwin on EAGAIN. It's unclear why CYGWIN
+ throws EAGAIN, but it only does so sometimes. 3 may not be enough
+ retries, but we'll try it to start with.
+ - Add _windows_image_name to automatically convert "yes" to "yes.exe"
+ for use with taskkill.exe /im. Various callers to kill_all could
+ be updated to remove the .exe, but that can be done in another patch.
+ - Use taskkill.exe for killall on cygwin.
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ - Use the new *_KILLED_PROCESS_EXIT_CODE constants which are correctly
+ set to 0 on windows/cygwin systems where taskkill.exe is used.
+ - Test _windows_image_name
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ - Add FIXME about including mac-snowleopard in baseline_search_path.
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ - Make default_configuration actually read from the Configuration file.
+ * Scripts/webkitpy/layout_tests/port/webkit_unittest.py: Added.
+ - Test default_configuration
+ * Scripts/webkitpy/layout_tests/port/win.py:
+ - Need a basic baseline_search_path if --platform dryrun is to work.
+
+2010-05-08 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, just reverting commit.
+
+ REGRESSION(59000): r59000 contained all sorts of changes it should not have, needs revert.
+ https://bugs.webkit.org/show_bug.cgi?id=38798
+
+ * Scripts/webkitpy/common/system/executive.py:
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/port/webkit_unittest.py: Removed.
+ * Scripts/webkitpy/layout_tests/port/win.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+
+2010-05-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ test-webkitpy fails under cygwin
+ https://bugs.webkit.org/show_bug.cgi?id=38718
+
+ * Scripts/webkitpy/common/system/executive.py:
+ - Add _KILL_PROCESS_KILLED_PROCESS_EXIT_CODE and
+ _KILL_ALL_KILLED_PROCESS_EXIT_CODE to store the expected
+ exit codes of processes killed by kill_process and kill_all.
+ These two constants are only used by the unit tests but are
+ stored in executive.py so they can be right next to the platform ifs.
+ - Remove unnecessary str() conversion, run_command does that for us.
+ - Make os.kill retry on cygwin on EAGAIN. It's unclear why CYGWIN
+ throws EAGAIN, but it only does so sometimes. 3 may not be enough
+ retries, but we'll try it to start with.
+ - Add _windows_image_name to automatically convert "yes" to "yes.exe"
+ for use with taskkill.exe /im. Various callers to kill_all could
+ be updated to remove the .exe, but that can be done in another patch.
+ - Use taskkill.exe for killall on cygwin.
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ - Use the new *_KILLED_PROCESS_EXIT_CODE constants which are correctly
+ set to 0 on windows/cygwin systems where taskkill.exe is used.
+ - Test _windows_image_name
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ - Add FIXME about including mac-snowleopard in baseline_search_path.
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ - Make default_configuration actually read from the Configuration file.
+ * Scripts/webkitpy/layout_tests/port/webkit_unittest.py: Added.
+ - Test default_configuration
+ * Scripts/webkitpy/layout_tests/port/win.py:
+ - Need a basic baseline_search_path if --platform dryrun is to work.
+
+ 2010-05-07 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Nikolas Zimmermann.
+
+ DryrunTest fails on every platform other than mac
+ https://bugs.webkit.org/show_bug.cgi?id=38796
+
+ The test uses the port detection logic to find a suitable
+ port to use results from. However that detection logic assumes
+ chromium on linux, which requires a chromium checkout which the
+ bots don't have. The test is broken and we'll need to fix it.
+ For now I'm just going to disable the test on all platforms besides mac.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+ 2010-05-07 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ Clean up baseline_search_path to use map to reduce copy/paste code
+ https://bugs.webkit.org/show_bug.cgi?id=38792
+
+ Reading which portnames a port falls back to is easier if
+ we convert port names to paths with map instead of using copy/paste code.
+
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+
+ 2010-05-07 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ rollout commands fail when commit is missing bug number
+ https://bugs.webkit.org/show_bug.cgi?id=38791
+
+ * Scripts/webkitpy/tool/commands/download.py:
+ - _commit_info failed to actually return the CommitInfo in the no-bug-id case.
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ - Test that the fix worked.
+
+2010-05-07 Darin Fisher <darin@chromium.org>
+
+ Fix build bustage: toElement<T> should be to<T>.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::elementDoesAutoCompleteForElementWithId):
+
+2010-05-07 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ Refactored VCSUtils.pm's parse-related methods to leave inapplicable
+ hash values unset instead of setting them to "undef".
+
+ https://bugs.webkit.org/show_bug.cgi?id=38724
+
+ Preferring "not set" over "undef" keeps the unit tests smaller and
+ easier to maintain. Otherwise, we would have to update every unit
+ test case each time we add support for a new key-value pair --
+ instead of just the relevant ones.
+
+ * Scripts/VCSUtils.pm:
+ - In parseGitDiffHeader(), adjusted the handling of these key-values:
+ executableBitDelta and isBinary.
+ - In parseSvnDiffHeader(), adjusted the handling of these key-values:
+ copiedFromPath, isBinary, and sourceRevision.
+ - In parseDiffHeader(), adjusted the handling of these key-values:
+ isGit and isSvn.
+ - In parseDiff(), adjusted the handling of these key-values:
+ isBinary, isGit, isSvn, and sourceRevision.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl:
+ - Updated the unit tests as necessary.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl:
+ - Updated the unit tests as necessary.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseGitDiffHeader.pl:
+ - Updated the unit tests as necessary.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffHeader.pl:
+ - Updated the unit tests as necessary.
+
+2010-05-06 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Dan Bernstein.
+
+ Exclude leaks due to <rdar://problem/7815391> from the output.
+
+ * Scripts/old-run-webkit-tests:
+
+2010-05-06 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r58933.
+ http://trac.webkit.org/changeset/58933
+ https://bugs.webkit.org/show_bug.cgi?id=38717
+
+ "Broke all websocket tests on Tiger" (Requested by eseidel on
+ #webkit).
+
+ * Scripts/new-run-webkit-websocketserver:
+ * Scripts/old-run-webkit-tests:
+ * Scripts/run-webkit-websocketserver:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ * Scripts/webkitpy/thirdparty/__init__.py:
+ * Scripts/webkitpy/thirdparty/pywebsocket/COPYING: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/MANIFEST.in: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/README: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/README.webkit: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/example/echo_client.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/example/echo_wsh.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/example/handler_map.txt: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/mod_pywebsocket/__init__.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/mod_pywebsocket/dispatch.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/mod_pywebsocket/handshake.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/mod_pywebsocket/headerparserhandler.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/mod_pywebsocket/memorizingfile.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/mod_pywebsocket/msgutil.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/mod_pywebsocket/standalone.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/mod_pywebsocket/util.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/setup.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/config.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/mock.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/run_all.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/test_dispatch.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/test_handshake.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/test_memorizingfile.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/test_mock.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/test_msgutil.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/test_util.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/testdata/README: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/testdata/handlers/blank_wsh.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/testdata/handlers/origin_check_wsh.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/testdata/handlers/sub/exception_in_transfer_wsh.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/testdata/handlers/sub/no_wsh_at_the_end.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/testdata/handlers/sub/non_callable_wsh.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/testdata/handlers/sub/plain_wsh.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/testdata/handlers/sub/wrong_handshake_sig_wsh.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/testdata/handlers/sub/wrong_transfer_sig_wsh.py: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/testdata/hello.pl: Added.
+
+2010-05-06 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by David Levin.
+
+ WebSocket: pywebsocket 0.5
+ https://bugs.webkit.org/show_bug.cgi?id=38034
+
+ Remove pywebsocket from webkitpy/thirdparty.
+ Make pywebsocket autoinstalled.
+
+ * Scripts/new-run-webkit-websocketserver:
+ Add --output-dir option.
+ * Scripts/old-run-webkit-tests:
+ Use new-run-webkit-websocketserver, rather than directly run pywebsocket's standalone.py
+ * Scripts/run-webkit-websocketserver:
+ Ditto.
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ Use autoinstalled pywebsocket.
+ * Scripts/webkitpy/thirdparty/__init__.py:
+ Autoinstall pywebsocket
+ * Scripts/webkitpy/thirdparty/pywebsocket: Removed.
+
+2010-05-06 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ svn-apply now understands the Git diff "copy from" syntax when the
+ similarity index is 100%.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38628
+
+ * Scripts/VCSUtils.pm:
+ - Adjusted parseGitDiffHeader() to parse the "copy from" and
+ "similarity index" lines.
+
+ * Scripts/svn-unapply:
+ - Adjusted the patch() subroutine so that copies are recognized
+ as file additions.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseGitDiffHeader.pl:
+ - Added unit tests for the cases of a copy with similarity index
+ 100% and less than 100%.
+
+2010-05-06 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ Removed the need for svn-apply and -unapply to re-parse whether
+ a diff is binary or not.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38320
+
+ * Scripts/VCSUtils.pm:
+ - Adjusted parseGitDiffHeader() to set the isBinary key.
+ - Adjusted parseSvnDiffHeader() to set the isBinary key.
+ - Adjusted parseDiffHeader() to set the isBinary key.
+ - Changed the scmFormat key set by parseDiffHeader() to
+ isGit and isSvn keys.
+ - Adjusted parseDiff() to set the isBinary, isGit, and isSvn keys.
+
+ * Scripts/svn-apply:
+ - Updated the patch() method to use the isBinary, isGit, and
+ isSvn keys.
+
+ * Scripts/svn-unapply:
+ - Updated the patch() method to use the isBinary and isSvn keys.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl:
+ - Updated the unit tests as necessary.
+ - Added a test case to test that the isBinary key is getting set properly.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl:
+ - Updated the unit tests as necessary.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseGitDiffHeader.pl:
+ - Updated the unit tests as necessary.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffHeader.pl:
+ - Updated the unit tests as necessary.
+
+2010-05-06 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Add support for resources on Mac
+ https://bugs.webkit.org/show_bug.cgi?id=38637
+
+ Repack webkit_chromium_resources.pak, webkit_strings_en-US.pak,
+ and webkit_resources.pak, and put them as Mac bundle resource.
+ The 'actions' section is almost same as a part of test_shell.gypi.
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp:
+
+2010-05-06 Csaba Osztrogonác <ossy@webkit.org>
+
+ [Qt] Unreviewed buildfix after r58917.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.h: Missing function declaration added.
+
+2010-05-06 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Darin Adler and Dan Bernstein..
+
+ REGRESSION (r51617): when plugins are disabled, plugins show up as garbage characters
+ https://bugs.webkit.org/show_bug.cgi?id=38698
+ <rdar://problem/7942075>
+
+ Add a 'setPluginsEnabled' layoutTestController function for disabling plug-ins. This is only implemented on Mac currently
+ because the bug that needs this functionality is mac specific.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setPluginsEnabledCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setPluginsEnabled):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setPluginsEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setPluginsEnabled):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setPluginsEnabled):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setPluginsEnabled):
+
+2010-05-06 Jochen Eisinger <jochen@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Make ImageDiff depend on WebKit. When compiled from within Chromium, WTF is not a standalone dynamic library but depends on WebKit.
+ https://bugs.webkit.org/show_bug.cgi?id=38632
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp:
+
+2010-05-06 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Replace public inspector url with private property for QtLauncher
+ https://bugs.webkit.org/show_bug.cgi?id=35340
+
+ Replace the public API with a private dynamic property until this feature
+ is ready.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::init):
+
+2010-05-05 Joseph Pecoraro <joepeck@webkit.org>
+
+ Reviewed by Pavel Feldman.
+
+ Web Inspector: build-webkit --inspector-frontend Should Exclude *.re2js
+ https://bugs.webkit.org/show_bug.cgi?id=38449
+
+ * Scripts/webkitdirs.pm:
+
+2010-05-05 Charles Wei <charles.wei@torchmobile.com.cn>
+
+ Reviewed by George Staikos
+
+ This patch adds WCSS -wap-input-format and -wap-input-required support to WebKit
+ Make the test cases in fast/wcss optionional only when WCSS is enabled.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37848
+
+ * Scripts/old-run-webkit-tests:
+ * Scripts/webkitperl/features.pm:
+
+2010-05-05 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [DRT/Chromium] Remove InitWebCoreSystemInterface() call
+ https://bugs.webkit.org/show_bug.cgi?id=38624
+
+ Chromium r45167 <http://src.chromium.org/viewvc/chrome?view=rev&revision=45167>
+ added InitWebCoreSystemInterface() to webkit/support/platform_support_mac.mm.
+ So we don't need to call it from DumpRenderTree.cpp anymore.
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp:
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (main): Remove InitWebCoreSystemInterface().
+
+2010-05-05 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests: clean up newline handling in printing
+
+ The new printing module seems to handle newlines somewhat
+ inconsistently, especially in --verbose mode. This change cleans up
+ the code to make things more consistent and adds a bunch of unit tests.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38616
+
+ * Scripts/webkitpy/common/array_stream.py: Added.
+ * Scripts/webkitpy/common/array_stream_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/metered_stream.py:
+ * Scripts/webkitpy/layout_tests/layout_package/metered_stream_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-05-05 James Robinson <jamesr@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Ban the single letter 'l' as an identifier name
+ http://trac.webkit.org/changeset/58844
+
+ Add a lint rule to ban the single letter 'l' as an identifier name
+ since it is very easy to confuse with the numeral '1', especially
+ in code like WebCore/css/CSSHelper.cpp.
+
+ See http://trac.webkit.org/changeset/58844 as an example of a bug
+ caused by confusing short variable names.
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+
+2010-05-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ PrettyPatch.pretty_diff("") should not hang
+ https://bugs.webkit.org/show_bug.cgi?id=38552
+
+ Also found a bug in PrettyPatch.pretty_diff where it would
+ hang when passed "" as input.
+
+ I suspect there may be bugs in prettify.rb (or our use there-of)
+ where it can hang, which would then cause the testing thread to hang.
+
+ * Scripts/webkitpy/common/prettypatch.py:
+ - Don't hang when passed ""
+ * Scripts/webkitpy/common/prettypatch_unittest.py:
+ - Test that we don't hang when passed ""
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ - Add a FIXME that we should share code with prettypatch.rb
+
+2010-05-04 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests: turn off threading on the Chromium Mac port until
+ we can stabilize the port more and figure out why it is hanging so
+ frequently.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38553
+
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ - override default_child_processes() and log a warning
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ - fix a typo that caused us to print a method object instead of the
+ value the method object returns in the case where there is only
+ one child process.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+ - Add unit tests for the output of run_webkit_tests - in this case,
+ the handling of --child-processes and --print config
+
+2010-05-04 Timothy Hatcher <timothy@apple.com>
+
+ Fix the find command in extract-localizable-strings so skip
+ directories are correctly skipped and header files are searched.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38545
+ rdar://problem/7941295
+
+ Reviewed by Darin Adler.
+
+ * Scripts/extract-localizable-strings: Append -o after each -prune
+ so -and isn't implied. Surround all the -name arguments so they get
+ an implied -print action. Removed check for "icu". Skip any header that
+ ends in LocalizableStrings.h, so SafariLocalizableStrings.h is skipped.
+ * Scripts/update-webkit-localizable-strings: Add the two icu directories
+ to the skip list.
+
+2010-05-04 Jesus Sanchez-Palencia <jesus@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Wrong documentation on 'webkit-patch help land'.
+ https://bugs.webkit.org/show_bug.cgi?id=37871
+
+ Small fix on the help documentation for webkit-patch
+ land.
+
+ * Scripts/webkitpy/tool/commands/download.py:
+
+2010-05-04 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] QWebPage viewMode property
+ https://bugs.webkit.org/show_bug.cgi?id=38119
+
+ Rename the property from wrt_viewMode to _q_viewMode.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setViewModeMediaFeature):
+
+2010-05-04 Jochen Eisinger <jochen@chromium.org>
+
+ Reviewed by Jeremy Orlow.
+
+ Fix typo in run_webkit_tests.py: s/_print\./_printer./
+ https://bugs.webkit.org/show_bug.cgi?id=38515
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-05-04 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ This revision completes the terminology change from "processor" to
+ "checker" for the CarriageReturnProcessor, CppProcessor,
+ PythonProcessor, and TextProcessor classes, etc.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38262
+
+ The word "processor" currently has two uses in our code. This
+ revision renames the lower-level use to "checker" and preserves the
+ word "processor" for higher-level, more general uses. This
+ revision also makes whatever other name changes that logically
+ followed from this change.
+
+ * Scripts/check-webkit-style:
+ - Updated references to PatchChecker.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Renamed the StyleCheckerConfiguration class to
+ StyleProcessorConfiguration.
+ - Renamed the ProcessorDispatcher class to CheckerDispatcher, and
+ made similar changes for the class's method names.
+ - Renamed the PatchChecker class to PatchReader.
+ - Updated the file as necessary to accommodate the other class
+ renames in this patch.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated the unit test code as necessary.
+
+ * Scripts/webkitpy/style/checkers/common.py:
+ - Renamed the CarriageReturnProcessor class to CarriageReturnChecker,
+ and changed its process() method to check().
+
+ * Scripts/webkitpy/style/checkers/common_unittest.py:
+ - Updated the unit test code as necessary.
+
+ * Scripts/webkitpy/style/checkers/cpp.py:
+ - Renamed the CppProcessor class to CppChecker, and renamed its
+ process() method to check().
+
+ * Scripts/webkitpy/style/checkers/cpp_unittest.py:
+ - Updated the unit test code as necessary.
+
+ * Scripts/webkitpy/style/checkers/python.py:
+ - Renamed the PythonProcessor class to PythonChecker, and renamed
+ its process() method to check().
+
+ * Scripts/webkitpy/style/checkers/python_unittest.py:
+ - Updated the unit test code as necessary.
+
+ * Scripts/webkitpy/style/checkers/text.py:
+ - Renamed the TextProcessor class to TextChecker, and renamed
+ its process() method to check().
+
+ * Scripts/webkitpy/style/checkers/text_unittest.py:
+ - Updated the unit test code as necessary.
+
+ * Scripts/webkitpy/style/error_handlers.py:
+ - Updated the code as necessary.
+
+ * Scripts/webkitpy/style/error_handlers_unittest.py:
+ - Updated the unit test code as necessary.
+
+2010-05-04 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Adjusted svn-apply and -unapply to accept git diffs generated
+ using the --no-prefix flag.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32438
+
+ * Scripts/VCSUtils.pm:
+ - Loosened the regular expression for the "diff --git" line to
+ match when the --no-prefix flag is used with "git diff".
+ - Also refactored the code parsing the first line so that the
+ script exits with an error message if the first line cannot
+ be parsed.
+ * Scripts/webkitperl/VCSUtils_unittest/parseGitDiffHeader.pl:
+ - Added a unit test case for the --no-prefix case.
+
+2010-05-04 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ Changed VCSUtils.pm's parseDiffHeader() to call the new
+ parseGitDiffHeader() method.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38454
+
+ This revision makes more progress towards adding executable-bit
+ support to svn-apply and svn-unapply. It also makes more progress
+ towards refactoring the code into a more maintainable form.
+
+ * Scripts/VCSUtils.pm:
+ - Removed gitdiff2svndiff().
+ - Removed the Git-specific logic from parseDiffHeader() and
+ renamed it parseSvnDiffHeader().
+ - Added a new parseDiffHeader() subroutine which calls
+ parseSvnDiffHeader() or parseGitDiffHeader() depending on
+ the format of the first header line.
+
+ * Scripts/webkitperl/VCSUtils_unittest/gitdiff2svndiff.pl: Removed.
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl:
+ - Removed most of the test cases since these cases are now
+ covered by the unit tests for parseSvnDiffHeader() and
+ parseGitDiffHeader().
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffHeader.pl: Added.
+ - Copied the SVN unit tests from parseDiffHeader.pl and updated
+ them as necessary.
+
+2010-05-03 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Builders should run the perl and python unit tests on every commit
+ https://bugs.webkit.org/show_bug.cgi?id=37976
+
+ The unit tests take a few seconds to run, so they should not
+ have any noticable effect on builder speed.
+
+ We're running the tests everywhere but Tiger as Tiger's
+ Python version is ancient.
+ I would have rather have detected the python version of the
+ slave but I couldn't find any API to do that, and I didn't want
+ to hack version detection into test-webkitpy (at least not yet).
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2010-05-03 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Fixed a recent REGRESSION that caused svn-apply and -unapply to
+ skip over changes to the first file in a diff if leading junk was
+ present (like in an e-mail diff) and if the --force option was used.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38507
+
+ * Scripts/svn-apply:
+ - Removed the bit of code at the beginning of the patch()
+ subroutine that checks for the "Index:" line at the beginning
+ of a file diff (since the parsePatch() subroutine already
+ checks this).
+
+ * Scripts/svn-unapply:
+ - Removed the bit of code at the beginning of the patch()
+ subroutine that checks for the "Index:" line at the beginning
+ of a file diff (since the parsePatch() subroutine already
+ checks this).
+
+2010-05-03 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Unreviewed.
+
+ Adjusted the ChangeLog entry below for r58732 (bug 35804) to reflect
+ the fact that the change will not become active until the patch
+ for bug 38454 lands.
+
+2010-05-03 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Added code for svn-apply and -unapply to display an instructive error
+ message if the --binary flag is left off the "git diff" command
+ for diffs containing binary file differences.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35804
+
+ This change will become active when parseDiffHeader() is modified
+ to call parseGitDiffHeader (see bug 38454).
+
+ * Scripts/VCSUtils.pm:
+ - Adjusted parseDiffHeader() to exit with an appropriate error message
+ if it encounters a line of the form "Binary files <path1> and
+ <path2> differ".
+
+2010-05-03 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ new-run-webkit-tests: r58728 broke the buildbot logic for parsing the
+ output of the log; specifying --verbose should basically be equivalent
+ to --print everything, but instead it was equivalent to not specifying
+ --print and getting the default set. Now, --verbose acts as if
+ --print everything was implicitly specified as the default (you can
+ still override it if you specify both; this is a somewhat debatable
+ call).
+
+ https://bugs.webkit.org/show_bug.cgi?id=38504
+
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+
+2010-05-03 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ new-run-webkit-tests: Fix minor precedence bug introduced in r58728 where we printed
+ "-\n" 78 times instead of "-" 78 times followed by a single "\n".
+
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py:
+
+2010-05-03 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests: refactor a large chunk of the printing/logging
+ code out of run-webkit-tests py (almost 300 lines out of 1900).
+
+ This change also renames --log to --print (to be slightly more
+ descriptive). I've also added better help messages for printing.
+
+ The new code has unit tests!
+
+ There is still more code to be moved, but this patch is big enough as
+ it is. Namely, still to move are the printing of the actual results
+ and the timing statistics, which should move another 300-400 lines
+ out of the file.
+
+ Notable changes to run_webkit_tests.py beyond code simply moving:
+ * MeteredStream is now hidden under the new printing.Printer class.
+ All the references to self._meter now point to self._printer.
+ * All logging configuration is done in printing.configure_logging()
+ * Instead of using write() lambdas to control what is and isn't
+ printed, we use separate methods on the printer object. This will
+ make it easier to grep which print statements are printed
+ under protection of each flag.
+ * The print_results flag I added a few revs back to suppress printing
+ in the unit tests has been replaced with --print nothing.
+ * The ResultSummary class now stores the entire TestResult for each
+ test, not just the actual result type.
+ * summarize_unexpected_results() got moved from a method on TestRunner
+ to a standalone function. This should move into a separate file
+ along with the ResultSummary class and the TestResult class
+ * The --trace option added recently has been replaced by
+ '--print trace-everything' and '--print trace-unexpected'
+
+ https://bugs.webkit.org/show_bug.cgi?id=38018
+
+ * Scripts/new-run-webkit-tests:
+ - update to new entry points in run_webkit_tests.py
+ * Scripts/webkitpy/layout_tests/layout_package/metered_stream.py:
+ - fix a minor nit where we were printing an empty string where
+ we didn't need to
+ * Scripts/webkitpy/layout_tests/layout_package/printing.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py: Added
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ - implement relative_test_filename() and expected_filename() so
+ we can test printing unexpected results in a platform-neutral
+ way
+ * Scripts/webkitpy/run_webkit_test.py:
+ - move a lot of the printing code into printing.py
+ - change the signatures of the exported entry points for easier
+ unit testing
+ * Scripts/webkitpy/run_webkit_tests_unittest.py:
+ - update w/ changes to run_webkit_tests entry points.
+
+2010-05-03 Kevin Watters <kevinwatters@gmail.com>
+
+ Reviewed by Kevin Ollivier.
+
+ [wx] Build and use Mac's ComplexTextController to support complex text in wx.
+ https://bugs.webkit.org/show_bug.cgi?id=38482
+
+ * wx/build/settings.py:
+
+2010-05-03 Abhishek Arya <inferno@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Add support for controlling clipboard access from javascript.
+ Clipboard access from javascript is enabled in test framework.
+ https://bugs.webkit.org/show_bug.cgi?id=27751
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setJavaScriptCanAccessClipboardCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+ (LayoutTestController::overridePreference):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::resetWebSettings):
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+
+2010-05-03 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Maui MiniBrowser: Add an option to show/hide the web view
+ https://bugs.webkit.org/show_bug.cgi?id=38486
+
+ * MiniBrowser/win/BrowserWindow.cpp:
+ (BrowserWindow::createWindow):
+ Set the background brush to something other than null.
+
+ (BrowserWindow::onCommand):
+ Show and hide the web view accordingly.
+
+ * MiniBrowser/win/MiniBrowser.rc:
+ * MiniBrowser/win/resource.h:
+ Add new menu item.
+
+2010-05-03 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ Added a parseGitDiffHeader() subroutine to VCSUtils.pm that
+ parses any changes to the executable bit in a Git diff.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38425
+
+ This revision is more preparation towards adding "executable bit"
+ support to svn-apply and svn-unapply. No code is going "live" in
+ this change except for the new unit tests in test-webkitperl.
+
+ * Scripts/VCSUtils.pm:
+ - Added isExecutable() to determine whether a file mode has the
+ executable bit set or not.
+ - Added parseGitDiffHeader() to parse the header of a Git diff.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseGitDiffHeader.pl: Added.
+ - Added unit tests for parseGitDiffHeader().
+
+2010-05-03 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Chris Jerdonek.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38447
+
+ Refactor the unit tests in VCSUtils_unittest/parseDiff.pl to use
+ Test::More::is_deeply like we do in VCSUtils_unittest/parseDiffHeader.pl.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl:
+
+2010-05-02 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Unreviewed.
+
+ Corrected a file path in the ChangeLog entry for r58663 (bug 38319) below.
+
+2010-05-02 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38319
+
+ * Scripts/VCSUtils.pm:
+ - In parseDiffHeader()--
+ - Added an "scmFormat" hash key to the return value to represent
+ whether the diff is Git or SVN formatted.
+ - Adjusted the code so the value of "copiedFromPath" will
+ be undef rather than "does not exist" if the file was not
+ copied.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl:
+ - Added a FIXME to refactor these unit tests to use is_deeply().
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl:
+ - Updated the unit tests to test the "scmFormat" value.
+ - Simplified the unit tests by refactoring them to use is_deeply().
+
+2010-05-01 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Chris Jerdonek.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38423
+
+ Adds infrastructure to change the file mode of a file using
+ the appropriate SCM-specific routines.
+
+ No functionality was changed, so no new tests.
+
+ * Scripts/VCSUtils.pm: Added subroutines scmToggleExecutableBit,
+ scmAddExecutableBit, and scmRemoveExecutableBit.
+ * Scripts/svn-apply: Check for the hash key executableBitDelta
+ and toggle the executable bit.
+ * Scripts/svn-unapply: Ditto.
+
+2010-04-30 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ Enabled accelerated compositing in DRT for Windows
+ https://bugs.webkit.org/show_bug.cgi?id=38404
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main):
+
+2010-04-30 Anders Carlsson <andersca@apple.com>
+
+ Try to fix GTK+ build.
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_stream):
+
+2010-04-30 Anders Carlsson <andersca@apple.com>
+
+ Fix build.
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+
+2010-04-30 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Timothy Hatcher.
+
+ Next step towards fixing
+
+ https://bugs.webkit.org/show_bug.cgi?id=20784
+ move npapi.h to C99 integer types
+
+ Use the C99 types everywhere. The "old" types are still around but will be removed
+ in a subsequent commit.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (int32VariantToIdentifier):
+ (doubleVariantToIdentifier):
+ (testIdentifierToInt):
+ (testGetIntIdentifier):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+ (NPP_NewStream):
+ (NPP_WriteReady):
+ (NPP_Write):
+ (NPP_HandleEvent):
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp:
+ (NPP_New):
+ (NPP_NewStream):
+ (NPP_WriteReady):
+ (NPP_Write):
+ (NPP_HandleEvent):
+
+2010-04-30 Steve Block <steveblock@google.com>
+
+ Reviewed by Jeremy Orlow.
+
+ Changed Steve Block from committer to reviewer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-28 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch doesn't work if a git repo is tracking multiple svn repos
+ https://bugs.webkit.org/show_bug.cgi?id=38290
+
+ Getting the tests to pass required getting our SVN repo to more closely
+ match the real svn.webkit.org repo by having a trunk directory.
+ That involved adding an extra commit at the beginning and thus changing
+ all the commit numbers in the tests.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+
+2010-04-29 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests can deadlock with Chromium's TestShell
+ https://bugs.webkit.org/show_bug.cgi?id=38298
+
+ Fix _write_command_and_read_line to never send unicode() to
+ test_shell, instead to always encode as utf-8. This was causing
+ random hangs because if test_shell ever encounters a \0 in the
+ stream it can deadlock with NRWT.
+
+ There is still a deadlock bug to fix in NRWT/test_shell design, however
+ this fix should make the deadlock occur less often.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py:
+
+2010-04-29 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Refactored svn-apply and svn-unapply to use the new
+ parsePatch() subroutine.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34033
+
+ * Scripts/VCSUtils.pm:
+ - Consolidated %diffHash documentation.
+ - Added prepareParsedPatch().
+
+ * Scripts/svn-apply:
+ - Replaced main while loop with calls to parsePatch() and
+ prepareParsedPatch().
+
+ * Scripts/svn-unapply:
+ - Replaced main while loop with calls to parsePatch() and
+ prepareParsedPatch().
+
+ * Scripts/test-webkitperl:
+ - Changed to render relative test paths rather than absolute
+ test paths.
+
+ * Scripts/webkitperl/VCSUtils_unittest/prepareParsedPatch.pl: Added.
+ - Added unit tests for prepareParsedPatch().
+
+2010-04-28 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Added to VCSUtils's parseDiffHeader() support for binary patches.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38094
+
+ The parseDiffHeader() function is part of new patch-parsing code
+ for svn-apply and svn-unapply that will go live in a subsequent
+ revision.
+
+ * Scripts/VCSUtils.pm:
+ - Added logic to parseDiffHeader() to recognize the ending of
+ the header portion of a binary diff.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl:
+ - Added unit test cases for SVN and Git binary diffs.
+
+2010-04-28 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ Document that subprocess.poll/wait are not threadsafe
+ https://bugs.webkit.org/show_bug.cgi?id=38289
+
+ * Scripts/webkitpy/common/system/executive.py:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/http_server.py:
+ * Scripts/webkitpy/layout_tests/port/server_process.py:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+
+2010-04-28 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Daniel Bates.
+
+ Removed the dividing line (i.e. "====...") logic from the code
+ called by svn-apply and svn-unapply.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38093
+
+ The dividing line logic is unnecessary. Removing it simplifies the
+ code and makes some subsequent changes easier.
+
+ * Scripts/VCSUtils.pm:
+ - Removed the logic in gitdiff2svndiff() to convert the git
+ "index" line to an SVN dividing line.
+ - Adjusted the logic similarly in parseDiffHeader().
+
+ * Scripts/webkitperl/VCSUtils_unittest/gitdiff2svndiff.pl:
+ - Updated the unit tests as necessary.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl:
+ - Updated the unit tests as necessary.
+ - Corrected an error in the unit tests whereby all elements
+ of an array were referencing the same element rather than
+ distinct elements -- causing unit test failures to be masked.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl:
+ - Updated the unit tests as necessary.
+ - Made the same unit test correction as above for parseDiff.pl.
+
+2010-04-28 Evan Stade <estade@chromium.org>
+
+ Unreviewed.
+
+ * Scripts/webkitpy/common/config/committers.py: adding myself as a committer
+
+2010-04-28 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Add MiniBrowser to the lists of modules to build and only build it on
+ SnowLeopard and later.
+
+ * Makefile:
+ * MiniBrowser/Makefile:
+
+2010-04-28 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Make running MiniBrowser.app without explicitly setting DYLD_FRAMEWORK_PATH.
+
+ * MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj:
+ * MiniBrowser/mac/make-launchable.sh: Added.
+
+2010-04-28 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ Audit all uses of subprocess in webkitpy
+ https://bugs.webkit.org/show_bug.cgi?id=38284
+
+ After further discussions with Jeffrey Yasskin
+ about http://bugs.python.org/issue2320
+ and related issues of using subprocess from
+ multiple threads, I have learned that subprocess
+ is known to be non-threadsafe through recent
+ Python 2.7 builds.
+
+ I'm attempting to lessen our exposure to these
+ subprocess bugs by auditing each use of subprocess
+ in webkitpy. I did not find any unsafe calls
+ in my audit, but I did remove numerous unneeded
+ import subprocess lines.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/system/deprecated_logging_unittest.py:
+ * Scripts/webkitpy/common/system/user.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py: Added.
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/gtk.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/qt.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/port/win.py:
+
+2010-04-28 Darin Adler <darin@apple.com>
+
+ Ignore a directory the Python tools creates.
+
+ * Scripts/webkitpy/style: Modified property svn:ignore.
+
+2010-04-28 Darin Adler <darin@apple.com>
+
+ * Scripts/extract-localizable-strings: Fix minor mistake in
+ argument checking.
+
+2010-04-28 Luiz Agostini <luiz.agostini@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] QWebPage viewMode property
+ https://bugs.webkit.org/show_bug.cgi?id=38119
+
+ Replacing method qt_wrt_setViewMode by wrt_viewMode property.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setViewModeMediaFeature):
+
+2010-04-28 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Adjusted check-webkit-style so that files with file type NONE
+ are automatically skipped without warning.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38197
+
+ This change simplifies configuring which files to skip. It also
+ addresses an issue whereby check-webkit-style was unintentionally
+ checking .vcproj files for carriage returns.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Moved the C++, Python, and text file extensions to new
+ module-level configuration variables.
+ - Removed .pyc from the _SKIPPED_FILES_WITHOUT_WARNING configuration
+ variable.
+ - Changed the numeric values of the FileType enum so that
+ FileType.NONE evaluates to False.
+ - For ProcessorDispatcher.should_skip_without_warning():
+ - Changed the method to return True for FileType.NONE files.
+ - Made ChangeLog files an exception to getting skipped.
+ - Changed the StyleProcessor.process() method to raise an
+ exception if given a file path that should not be processed.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated the unit tests and added more test cases as necessary.
+
+2010-04-28 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Jeremy Orlow.
+
+ webkitpy: ScriptError('Failed to run "[u\'taskkill.exe\', u\'/f\', u\'/im\', u\'httpd.exe\']" exit_code: 128',)
+ https://bugs.webkit.org/show_bug.cgi?id=38248
+
+ The previous code did not check the return code of taskkill.
+ When I moved that callsite from using subprocess.call to
+ Executive.run_command having a non-zero return code became an error.
+
+ In this change I've centralized our killall handling in executive,
+ and added tests for it to make sure it works.
+
+ Currently kill_process and kill_all swallow exceptions in the cases
+ where the process(es) to be killed do(es) not exist.
+
+ * Scripts/webkitpy/common/system/executive.py:
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/gtk.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/qt.py:
+ * Scripts/webkitpy/layout_tests/port/win.py:
+
+2010-04-28 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ wdiff_text throws ScriptError because wdiff returns non-zero when files differ
+ https://bugs.webkit.org/show_bug.cgi?id=38246
+
+ wdiff returns 0 when files are the same, 1 when they differ.
+ run_command by default raises ScriptError if the return code is non-zero.
+ Fixed this by adding a custom error handler which only raises if the
+ return code is not 1.
+
+ I broke up the huge wdiff_text() method into little pieces
+ for easier unit testing. There is only one functional change here
+ and that is the addition of the custom error handler.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py:
+
+2010-04-28 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed build fix.
+
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::dumpImage): format '%u' expects type 'unsigned int', but argument 2 has type 'size_t'.
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::willSendRequest): too few arguments for format.
+
+2010-04-27 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Darin Adler and Eric Seidel.
+
+ Add layoutTestController.setPrinting()
+ https://bugs.webkit.org/show_bug.cgi?id=37203
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (setPrintingCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::isPrinting):
+ (LayoutTestController::setIsPrinting):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dump):
+
+2010-04-27 Michael Nordman <michaeln@google.com>
+
+ Reviewed by Dmitry Titov.
+
+ [Chromium] Add two things to the webkit API to support appcaches in workers.
+ 1) WebURLRequest TargetTypes for worker and shared worker main resources.
+ 2) Factory method on class WebCommonWorkerClient to
+ createApplicationCacheHost() for the associated worker.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38147
+
+ * DumpRenderTree/chromium/TestWebWorker.h add a stub impl of the factory method
+ (TestWebWorker::createApplicationCacheHost):
+
+2010-04-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ run-bindings-tests doesn't work in an SVN checkout
+ https://bugs.webkit.org/show_bug.cgi?id=38225
+
+ Previously detect_scm_system needed an absolute path for SVN. Now we
+ accept a relative path.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+
+2010-04-27 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Stephanie Lewis.
+
+ Always build WebKit2 when building on SnowLeopard and later.
+
+ * Scripts/build-webkit:
+
+2010-04-27 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=38238
+ Allow both WebKit and WebKit2 to link to the same WebCore.framework
+
+ * Scripts/build-webkit: Remove the UMBRELLA_LDFLAGS override when building
+ WebCore for WebKit2, it is no longer necessary.
+
+2010-04-27 James Robinson <jamesr@chromium.org>
+
+ Reviewed by David Levin.
+
+ Fix a typo in chromium.py that causes NRWT to fail in --verbose
+ mode in a Chromium checkout.
+ https://bugs.webkit.org/show_bug.cgi?id=38234
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-04-27 Darin Fisher <darin@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [Chromium] Remove deprecated form of didChangeLocationWithinPage
+ https://bugs.webkit.org/show_bug.cgi?id=38178
+
+ Switch over to implementing didNavigateWithinPage.
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (TestWebViewDelegate::didNavigateWithinPage):
+ (WebViewHost::didChangeLocationWithinPage):
+ * DumpRenderTree/chromium/WebViewHost.h:
+
+2010-04-27 Evan Martin <evan@chromium.org>
+
+ Unreviewed.
+
+ Adding myself to commmitters list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ run-bindings-tests should use --reset-results instead of --overwrite
+ https://bugs.webkit.org/show_bug.cgi?id=38200
+
+ As requested by Ojan.
+
+ * Scripts/run-bindings-tests:
+
+2010-04-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ REGRESSION(r58261): webkit-patch edit-changelogs is broken
+ https://bugs.webkit.org/show_bug.cgi?id=38204
+
+ In 58261, we added code to abstract step that interrogates the squash
+ and git_commit options, but it doesn't declare that it uses those
+ options. That means any command that doesn't happen to declare those
+ options might be broken if it uses the cached_lookup mechanism.
+
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ * Scripts/webkitpy/tool/steps/applypatch.py:
+ * Scripts/webkitpy/tool/steps/applypatchwithlocalcommit.py:
+ * Scripts/webkitpy/tool/steps/build.py:
+ * Scripts/webkitpy/tool/steps/checkstyle.py:
+ * Scripts/webkitpy/tool/steps/cleanworkingdirectory.py:
+ * Scripts/webkitpy/tool/steps/closebug.py:
+ * Scripts/webkitpy/tool/steps/closebugforlanddiff.py:
+ * Scripts/webkitpy/tool/steps/commit.py:
+ * Scripts/webkitpy/tool/steps/confirmdiff.py:
+ * Scripts/webkitpy/tool/steps/createbug.py:
+ * Scripts/webkitpy/tool/steps/ensurebuildersaregreen.py:
+ * Scripts/webkitpy/tool/steps/ensurelocalcommitifneeded.py:
+ * Scripts/webkitpy/tool/steps/obsoletepatches.py:
+ * Scripts/webkitpy/tool/steps/postcodereview.py:
+ * Scripts/webkitpy/tool/steps/postdiff.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+ * Scripts/webkitpy/tool/steps/runtests.py:
+ * Scripts/webkitpy/tool/steps/update.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py:
+ * Scripts/webkitpy/tool/steps/validatereviewer.py:
+
+2010-04-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ prepare-ChangeLog --bug fails on some CYGWIN installs due to missing certs
+ https://bugs.webkit.org/show_bug.cgi?id=38212
+
+ * Scripts/prepare-ChangeLog:
+ - Pass --insecure to curl to work around CYGWIN missing certs.
+
+2010-04-27 Sam Weinig <sam@webkit.org>
+
+ Rubber-stamped by Beth Dakin.
+
+ It is no longer necessary to set ENABLE_EXPERIMENTAL_SINGLE_VIEW_MODE
+ or WTF_USE_WEB_THREAD. Remove them.
+
+ * Scripts/build-webkit:
+
+2010-04-27 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by David Levin.
+
+ Changed Chris Jerdonek from committer to reviewer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-27 Benjamin Poulain <benjamin.poulain@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] QGraphicsWebView: Arrow keys scroll the graphics-view instead of the web-page
+ https://bugs.webkit.org/show_bug.cgi?id=35834
+
+ The scene should always have the size of the web view otherwhise it is
+ possible to scroll the graphics view.
+
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::resizeEvent):
+
+2010-04-27 Diego Gonzalez <diegohcg@webkit.org>
+
+ Unreviewed.
+
+ Adding myself to committers.py
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ [chromium] new-run-webkit-tests hangs on Chromium Bots (OS X and Linux)
+ https://bugs.webkit.org/show_bug.cgi?id=37987
+
+ After further research, I believe the hang is caused by:
+ http://bugs.python.org/issue2320
+ Basically Popen() is not reentrant.
+ The workaround is to pass close_fds=True to Popen() on Mac/Linux.
+
+ I fixed our main Popen wrapper "Executive.run_command" to use close_fds=True
+ when appropriate.
+
+ I audited all places we call Popen() and either moved them to run_command
+ or left a FIXME that they are not thread safe. A few places I added the
+ close_fds workaround there and left an explanitory note.
+
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ - Added note that this Popen use is not threadsafe.
+ * Scripts/webkitpy/common/system/executive.py:
+ - Fixed our Executive.run_* to workaround python bug 2320.
+ * Scripts/webkitpy/common/system/user.py:
+ _ Added note that this Popen use is not threadsafe.
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py: ditto.
+ * Scripts/webkitpy/layout_tests/port/apache_http_server.py: ditto.
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ - Change wdiff back to using run_command now that we believe it
+ to be threadsafe.
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ - Fix to use Executive in places.
+ - Pass self._executive down to the Driver for easier unit testing.
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ - Re-factor to use a _kill_all method.
+ - Made the _kill_all method use run_command to be threadsafe.
+ * Scripts/webkitpy/layout_tests/port/http_server.py:
+ - Add FIXME about using Executive.
+ * Scripts/webkitpy/layout_tests/port/server_process.py:
+ - Use Executive to be threadsafe.
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ - Pass self._executive down to the Driver.
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ - Add note about Popen not being threadsafe.
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ - Move one caller to run_command add notes about moving others.
+
+2010-04-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ REGRESSION(r58261): webkit-patch upload does not work in an SVN checkout.
+ https://bugs.webkit.org/show_bug.cgi?id=38186
+
+ Unfortunately, we don't have a good way of testing this change because
+ our test coverage of the scm.py API is poor...
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+
+2010-04-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Remove unused code from text_diff.py
+ https://bugs.webkit.org/show_bug.cgi?id=38170
+
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+ - Remove is_render_tree_dump which appears unused.
+
+2010-04-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch pretty-diff is broken
+ https://bugs.webkit.org/show_bug.cgi?id=38172
+
+ We need to register for these options because they're used when we look
+ up the diff.
+
+ * Scripts/webkitpy/tool/steps/confirmdiff.py:
+
+2010-04-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add ObjC and GObject to run-bindings-test
+ https://bugs.webkit.org/show_bug.cgi?id=38168
+
+ * Scripts/run-bindings-tests:
+
+2010-04-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add testing infrastructure for JSC bindings generator
+ https://bugs.webkit.org/show_bug.cgi?id=38167
+
+ Add support for testing more than one bindings. Also, converted the
+ script to PEP8 style.
+
+ * Scripts/run-bindings-tests:
+
+2010-04-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Refactor results.html generation out into a new method and test it
+ https://bugs.webkit.org/show_bug.cgi?id=38164
+
+ Hopefully this results in no change in functionality.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-04-26 Adam Barth <abarth@webkit.org>
+
+ Unreviewed, rolling out r58265.
+ http://trac.webkit.org/changeset/58265
+ https://bugs.webkit.org/show_bug.cgi?id=38021
+
+ This change prevents me from uploading patches. It also breaks sheriff-bot.
+
+ * Scripts/webkitpy/tool/steps/options.py:
+
+2010-04-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ [chromium] new-run-webkit-tests hangs on Chromium Bots (OS X and Linux)
+ https://bugs.webkit.org/show_bug.cgi?id=37987
+
+ Rolled out:
+ http://trac.webkit.org/changeset/58062
+ http://trac.webkit.org/changeset/58060
+ http://trac.webkit.org/changeset/58059
+ http://trac.webkit.org/changeset/58055
+ http://trac.webkit.org/changeset/58054
+ and parts of:
+ http://trac.webkit.org/changeset/58050
+
+ I also wrote some new comments and a tiny amount of new
+ code to help make ChromiumDriver.run_test easier to read.
+
+ In order to unit-test my new code, I had to change ChromiumDriver
+ to not automatically start itself when created. That ended up
+ being a lot of plumbing, but is hopefully easier to understand now.
+
+ There are no tests for the (restored) wdiff code. wdiff does not
+ exist on all systems, so for now we will assume it worked since
+ it is just old code being reverted.
+
+ * Scripts/webkitpy/layout_tests/driver_test.py:
+ - Use create_driver instead of start_driver, and be sure to call .stop()
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ - Use create_driver instead of start_driver
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ - Added a comment to explain that diffs are binary files.
+ - Various patch reverts relating to wdiff
+ - Add Driver._command_wrapper to share code between WebKitDriver and ChromiumDriver.
+ - Made _command_wrapper use shlex.split to get rid of the FIXME.
+ * Scripts/webkitpy/layout_tests/port/base_unittest.py: Added.
+ - test the new _command_wrapper
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ - Use _command_wrapper to get rid of a bunch of ugly code.
+ - Make __init__ stop auto-starting.
+ - Rename create_driver to start_driver.
+ - Added _write_command_and_read_line to make it possible to
+ put a FIXME next to read_line() w/o having to put it in two places.
+ - Moved test_shell command building into _test_shell_command and tested it.
+ - Fix comments to say test_shell since ChromiumDriver is test_shell only.
+ * Scripts/webkitpy/layout_tests/port/chromium_unittest.py: Added.
+ - Test the new test_shell_command method.
+ * Scripts/webkitpy/layout_tests/port/dryrun.py:
+ - Rename create_driver to start_driver.
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ - Rename create_driver to start_driver.
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ - Rename create_driver to start_driver.
+ - Treat output as binary arrays.
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ - Treat diff files as binary.
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+ - Treat diff files as binary.
+
+2010-04-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move bindings test directory into the scripts directory
+ https://bugs.webkit.org/show_bug.cgi?id=38161
+
+ Change script to point to the new location of these data files.
+
+ * Scripts/run-bindings-tests:
+
+2010-04-26 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Mark run-bindings-tests executable so we can execute it.
+
+ * Scripts/run-bindings-tests:
+
+2010-04-26 Tony Chang <tony@chromium.org>
+
+ Reviewed by David Levin.
+
+ [chromium] build-webkit --chromium should build release by default
+ https://bugs.webkit.org/show_bug.cgi?id=38028
+
+ * Scripts/build-dumprendertree: Also should build release by default
+ * Scripts/build-webkit: Make sure to pass command line args through
+ * Scripts/webkitdirs.pm: Build the right configuration
+
+2010-04-26 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ complete rietveld bugzilla integration
+ https://bugs.webkit.org/show_bug.cgi?id=38021
+
+ Makes --fancy-review the default. All this means is that the patch will
+ be uploaded to rietveld in addition to bugs.webkit.org.
+
+ * Scripts/webkitpy/tool/steps/options.py:
+
+2010-04-26 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ For check-webkit-style, renamed the style/processors/ directory
+ to style/checkers/.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38122
+
+ * Scripts/webkitpy/style/checker.py:
+ - Updated import statements.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated import statements.
+
+ * Scripts/webkitpy/style/checkers: Copied from WebKitTools/Scripts/webkitpy/style/processors.
+ * Scripts/webkitpy/style/processors: Removed.
+ * Scripts/webkitpy/style/processors/__init__.py: Removed.
+ * Scripts/webkitpy/style/processors/common.py: Removed.
+ * Scripts/webkitpy/style/processors/common_unittest.py: Removed.
+ * Scripts/webkitpy/style/processors/cpp.py: Removed.
+ * Scripts/webkitpy/style/processors/cpp_unittest.py: Removed.
+ * Scripts/webkitpy/style/processors/python.py: Removed.
+ * Scripts/webkitpy/style/processors/python_unittest.py: Removed.
+ * Scripts/webkitpy/style/processors/python_unittest_input.py: Removed.
+ * Scripts/webkitpy/style/processors/text.py: Removed.
+ * Scripts/webkitpy/style/processors/text_unittest.py: Removed.
+
+2010-04-06 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Include git commits in the diff for webkit-patch upload/land.
+ https://bugs.webkit.org/show_bug.cgi?id=36394
+
+ Adds --squash, --no-squash and --git-commit.
+
+ --git-commit will use a specific local commit for land/upload.
+ If a commit-range is specified, then that range is treated as
+ a single squashed commit.
+
+ --squash will squash all local changes including working copy changes
+ into a single patch.
+
+ --no-squash is the legacy behavior (upload only considers the working copy,
+ land commits the working copy and then each local commit separately to SVN)
+
+ If neither is specified, then an informative error is raised if there is
+ more than one local commit or when there are local commit(s) and working
+ copy changes.
+
+ If the webkit-patch.squash git config parameter is set, then
+ that will be respected instead of raising an error.
+
+ * Scripts/check-webkit-style:
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ * Scripts/webkitpy/style/optparser.py:
+ --git-since is removed and --git-commit no longer implies commit_id..
+ Instead, it treats that individual commit, but also supports commit ranges
+ (e.g. commit_id..) as arguments.
+ * Scripts/webkitpy/style/optparser_unittest.py:
+ * Scripts/webkitpy/style_references.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ * Scripts/webkitpy/tool/steps/applypatchwithlocalcommit.py:
+ * Scripts/webkitpy/tool/steps/checkstyle.py:
+ * Scripts/webkitpy/tool/steps/commit.py:
+ * Scripts/webkitpy/tool/steps/options.py:
+ * Scripts/webkitpy/tool/steps/postdiff.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+ * Scripts/webkitpy/tool/steps/preparechangelogforrevert.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py:
+ * Scripts/webkitpy/tool/steps/validatereviewer.py:
+
+2010-04-26 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Deleted the StyleChecker-related classes that are no longer
+ being used.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38118
+
+ * Scripts/webkitpy/style/checker.py:
+ - Deleted the DeprecatedStyleChecker class.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Deleted the StyleCheckerTest, StyleCheckerCheckFileBase,
+ StyleCheckerCheckFileTest, and StyleCheckerCheckPathsTest classes.
+
+2010-04-26 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Changed the StyleChecker class to use the new TextFileReader class.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37066
+
+ This revision separates the code responsible for reading and iterating
+ over text files from the rest of check-webkit-style.
+
+ * Scripts/check-webkit-style:
+ - Changed the script to use the new StyleProcessor and
+ TextFileReader classes instead of the StyleChecker class.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added a FIXME to rename many of uses of the word "processor" to
+ "checker". We did this to clarify the difference between
+ ProcessorBase instances passed to the TextFileReader and
+ classes that process and check lines for style.
+ - Added a FIXME to remove FileType.NONE as a possible return value
+ of ProcessorDispatcher._file_type(). This will better consolidate
+ the logic of which files should be skipped.
+ - Added a FIXME to delete the StyleChecker class.
+ - Added the StyleProcessor class which implements ProcessorBase.
+ This class is responsible for processing lines to check style
+ (but not for reading files). For each file, this class creates
+ creates both a carriage-return checker and a format-specific
+ style checker (e.g. one of C++, Python, etc).
+ - Updated the PatchChecker class to use a TextFileReader instance
+ instead of a StyleChecker.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Added the StyleProcessor_EndToEndTest class to do "end-to-end"
+ tests of the StyleProcessor class.
+ - Added the StyleProcessor_CodeCoverageTest to test the
+ StyleProcessor class with more complete code coverage.
+ Unlike the StyleProcessor_EndToEndTest class, this class makes
+ heavy use of mock parameters.
+ - Added FIXME's to delete the unit test classes that are no
+ longer needed.
+ - Updated the PatchCheckerTest class to use a MockTextFileReader
+ instead of a MockStyleChecker.
+
+ * Scripts/webkitpy/style/filereader.py:
+ - Updated the TextFileReader class to use the preferred logic
+ of checking file existence at the beginning of the process_file()
+ method instead of in the except block, per
+ https://bugs.webkit.org/show_bug.cgi?id=37122
+
+ * Scripts/webkitpy/style/filereader_unittest.py:
+ - In the TextFileReaderTest class:
+ - Moved the test_process_file__should_not_process() method.
+ - Added a test_process_file__file_stdin() method to test
+ the file path "-".
+
+2010-04-20 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Add more support for textInputController
+
+ Add support for selectedRange(), setMarkedText(), insertText(),
+ and firstRectForCharacterRange().
+
+ Unskip tests:
+
+ fast/forms/input-maxlength-ime-preedit.html
+ fast/forms/input-maxlength-ime-completed.html
+ fast/text/international/thai-cursor-position.html
+ fast/events/ime-composition-events-001.html
+ editing/selection/5825350-1.html
+ editing/selection/5825350-2.html
+ editing/selection/mixed-editability-10.html
+
+ https://bugs.webkit.org/show_bug.cgi?id=35702
+
+ * DumpRenderTree/qt/TextInputControllerQt.cpp:
+ (TextInputController::setMarkedText):
+ (TextInputController::insertText):
+ (TextInputController::selectedRange):
+ (TextInputController::firstRectForCharacterRange):
+ * DumpRenderTree/qt/TextInputControllerQt.h:
+
+2010-04-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ check-webkit-style complains about non-utf8 data in layout test result
+ https://bugs.webkit.org/show_bug.cgi?id=38027
+
+ The problem was we were assuming patch files/diff output as utf-8.
+ Turns out they're not. We have to treat them as binary data because
+ a single patch may have multiple text files in it with conflicting encodings!
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ - contents_at_revision returns a byte array, so decode it to unicode
+ before passing it to parse_latest_entry_from_file
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+ - Update our mock mock_contents_at_revision to match the encoding
+ semantics of the real one.
+ * Scripts/webkitpy/common/checkout/scm.py:
+ - Be careful not to decode output which may contain file contents
+ (like diff, cat or show) as the encoding for that content is unknown.
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ - Update our tests to use both latin1 and utf-8 encoded data.
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ - _fill_attachment_form should not assume unicode data. Callers
+ may wish to attach other types of files to bugs.
+ * Scripts/webkitpy/common/prettypatch.py:
+ - Diffs are byte arrays, deal with them as such.
+ * Scripts/webkitpy/common/prettypatch_unittest.py:
+ - Test to make sure we handle diffs with multiple conflicting encodings.
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ - Make sure that our unicode support does not break our
+ byte array input support for run_command.
+
+2010-04-23 Sam Weinig <sam@webkit.org>
+
+ Reviewed by David Levin.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=38060
+ Split up Threading.h
+
+ Add necessary forwarding headers.
+
+ * DumpRenderTree/ForwardingHeaders/wtf/Atomics.h: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf/ThreadSafeShared.h: Added.
+ * DumpRenderTree/ForwardingHeaders/wtf/ThreadingPrimitives.h: Added.
+
+2010-04-23 Xiaomei Ji <xji@chromium.org>
+
+ No need to review.
+
+ Add xji as committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-23 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix, add platform stub for new LayoutTestController method.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::markerTextForListItem):
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests: add a "--retry-failures" flag and a
+ "--no-retry-failures" flag (the former is the default). Also, rename
+ "--print-unexpected-results" and "--retry-unexpected-results" to
+ "--print-last-failures" and "--retry-last-failures" because the
+ retry flag was confusing. The new flag names aren't great, but
+ hopefully they're less confusing.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37838
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-22 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=38022
+ Move isMainThread predicate function to MainThread.h
+
+ Added forwarding header for MainThread.h
+
+ * DumpRenderTree/ForwardingHeaders/wtf/MainThread.h: Added.
+
+2010-04-23 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Disable Netscape plugin support for minimal configuration
+ https://bugs.webkit.org/show_bug.cgi?id=38026
+
+ Pass the minimal configuration option to Qt build system
+ as part of the CONFIG variable.
+
+ * Scripts/build-webkit:
+
+2010-04-22 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed fix.
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py: fix NameError: global name 'f' is not defined.
+
+2010-04-22 James Robinson <jamesr@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Revert 58077 and follow-ups. It's broken.
+ https://bugs.webkit.org/show_bug.cgi?id=37664
+
+ * Scripts/new-run-webkit-httpd:
+ * Scripts/new-run-webkit-websocketserver:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/http_server.py:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+
+2010-04-22 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Integrate v8 testing utility with webkit tests
+ https://bugs.webkit.org/show_bug.cgi?id=37731
+
+ * Scripts/run-bindings-tests: Added.
+
+2010-04-22 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ new-run-webkit-tests --verbose shows ever-increasing #EOF lines
+ https://bugs.webkit.org/show_bug.cgi?id=37794
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ - Remove the assert() since our ServerProcess code does not always
+ seem to be reading the full stderr output (or we're not waiting for it to).
+
+2010-04-22 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add code to help debug new-run-webkit-test hangs on the Chromium bots
+ https://bugs.webkit.org/show_bug.cgi?id=38011
+
+ I can see no reasonable way to test this change.
+ Stubbing out sys._current_frames() and traceback.extract_stack
+ seems folly. Dumping real data would have line number
+ (and possibly other call stack) variance between runs.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ - Add _dump_thread_states and _dump_thread_states_if_necessary
+ to have our main thread dump the states of all threads every
+ 60 seconds when running in verbose mode.
+ - Better document what is going on in our main loop.
+
+2010-04-22 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=38002
+ Add rudimentary statistics gathering for WebKit2
+
+ * MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj:
+ * MiniBrowser/mac/AppDelegate.h:
+ * MiniBrowser/mac/AppDelegate.m:
+ (-[BrowserAppDelegate init]):
+ (-[BrowserAppDelegate newWindow:]):
+ (-[BrowserAppDelegate getCurrentPageNamespace]):
+ (-[BrowserAppDelegate _setProcessModel:]):
+ (-[BrowserAppDelegate showStatisticsWindow:]):
+ (-[BrowserAppDelegate applicationWillTerminate:]):
+ * MiniBrowser/mac/BrowserStatisticsWindow.xib: Added.
+ * MiniBrowser/mac/BrowserStatisticsWindowController.h: Added.
+ * MiniBrowser/mac/BrowserStatisticsWindowController.m: Added.
+ (-[BrowserStatisticsWindowController initWithThreadedWKContextRef:processWKContextRef:]):
+ (-[BrowserStatisticsWindowController dealloc]):
+ (-[BrowserStatisticsWindowController windowDidLoad]):
+ (-[BrowserStatisticsWindowController refreshStatistics:]):
+ * MiniBrowser/mac/BrowserWindowController.h:
+ * MiniBrowser/mac/English.lproj/MainMenu.xib:
+ * MiniBrowser/mac/MiniBrowser_Prefix.pch:
+
+2010-04-22 Dave Moore <davemoore@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Add test support for icon changes.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33812
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (dumpIconChangesCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::dumpIconChanges):
+ (LayoutTestController::setDumpIconChanges):
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::didChangeIcons):
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+ * WinLauncher/WinLauncher.h:
+ (WinLauncherWebHost::didChangeIcons):
+
+2010-04-22 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Script fix. Will ask dpranke to look tomorrow.
+
+ new-run-webkit-tests --verbose shows ever-increasing #EOF lines
+ https://bugs.webkit.org/show_bug.cgi?id=37794
+
+ The bots are seeing cases where .error is sometimes empty.
+ Lets make the code not crash in that case for now.
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-04-22 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed fix.
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py: fix NameError: global name 'f' is not defined.
+
+2010-04-22 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed fix.
+
+ * Scripts/new-run-webkit-websocketserver: PyWebSocket no longer takes keyword argument 'register_cygwin'.
+
+2010-04-22 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Restore the Leopard bots to using
+ old-run-webkit-tests for now.
+
+ * Scripts/run-webkit-tests:
+
+2010-04-22 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed fix.
+
+ * Scripts/webkitpy/layout_tests/port/http_server.py: fix NameError: global name 'env' is not defined.
+
+2010-04-22 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed fix.
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py: fix NameError: global name 'env' is not defined.
+
+2010-04-22 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Chromium: Add --chromium option to new-run-webkit-websocketserver
+ https://bugs.webkit.org/show_bug.cgi?id=37664
+
+ Move cygwin setup logic in chromium_win.py.
+
+ * Scripts/new-run-webkit-httpd: remove register_cygwin parameter to pass http_server.
+ * Scripts/new-run-webkit-websocketserver: add --chromium flag
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py: setup for cygwin
+ * Scripts/webkitpy/layout_tests/port/http_server.py: remove cygwin setup logic
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py: remove cygwin setup logic
+
+2010-04-22 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests --verbose shows ever-increasing #EOF lines
+ https://bugs.webkit.org/show_bug.cgi?id=37794
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ - Fix the log message to explain that this is stderr output, not test output.
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ - Be sure to reset the server_process.error after reading (seems like the wrong
+ place to do this, but at least this fixes the bug and dpranke and I can talk
+ about better designs later).
+ - Also remove the #EOF from the stderr output before returning it.
+
+2010-04-22 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Fixing new-run-webkit-tests on the bots.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ - Fixing _compat_shim_option to take variable keyword args.
+ - Turns out that nargs + callback is ignored unless type is specified.
+ So I added the type so that the option was properly consumed.
+ This was why new-run-webkit-tests couldn't find any tests, it
+ was looking for them under "20" because that was the argument
+ which should have been consumed by --exit-after-n-failures.
+
+2010-04-22 Tony Chang <tony@chromium.org>
+
+ Not reviewed, build fix for chromium Windows.
+
+ [chromium] fix ImageDiff compile on windows
+ https://bugs.webkit.org/show_bug.cgi?id=37979
+
+ * DumpRenderTree/chromium/ImageDiff.cpp:
+
+2010-04-22 Adam Barth <abarth@webkit.org>
+
+ Unreviewed, rolling out r58069.
+ http://trac.webkit.org/changeset/58069
+ https://bugs.webkit.org/show_bug.cgi?id=27751
+
+ Broke compile on Windows.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::overridePreference):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::resetWebSettings):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+
+2010-04-22 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Just adding logging.
+
+ Adding logging to help debug why the Leopard Bot
+ can't find any tests to run.
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_files.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ - Make it a fatal error to have no tests to run.
+
+2010-04-22 Abhishek Arya <inferno@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Add support for controlling clipboard access from javascript.
+ Clipboard access from javascript is enabled in test framework.
+ https://bugs.webkit.org/show_bug.cgi?id=27751
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setJavaScriptCanAccessClipboardCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+ (LayoutTestController::overridePreference):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/chromium/TestShell.cpp:
+ (TestShell::resetWebSettings):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setJavaScriptCanAccessClipboard):
+
+2010-04-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch can't fetch attachments on security bugs
+ https://bugs.webkit.org/show_bug.cgi?id=37975
+
+ Instead of calling CURL, we just need to use our Mechanize object,
+ which understand bugs.webkit.org authentication.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/net/bugzilla.py:
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Temporary commit, will roll-out before morning.
+
+ Turning on new-run-webkit-tests for the Leopard build bot
+ for testing of the harness.
+ Users should not noctice (except for the results.html difference).
+
+ * Scripts/run-webkit-tests:
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Fix typo in my previous fix attempt.
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ More on-the-bot debugging, sigh. I wish I had a local build.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Fix typo in my previous fix attempt.
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ - Add self. to class variable access.
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Another attempt to fix NRWT for chromium.
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ - wdiff_text was returning a byte array instead of a
+ unicode string. The simple fix was to just decode
+ the result. However, seeing so much duplicated code
+ with Executive made me cry, so I re-wrote the function
+ to be more like pretty_patch_text and use run_command
+ (which already knows how to handle unicode).
+
+2010-04-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Windows tests buildbots are too slow to be core builders
+ https://bugs.webkit.org/show_bug.cgi?id=37970
+
+ It's 10:45. The Windows test bots are still hours behind. They're too
+ slow to be core builders. When they get fast, we can add them back.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Attempt one more time to fix NRWT for chromium.
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ I'm debugging in the blind because I don't have a chromium
+ build on this laptop.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ - Apply the previous fix to a second caller.
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Attempt one more time to fix NRWT for chromium.
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ - Fix handling of test_shell output so that we always
+ decode it as utf-8.
+ Unlike DumpRenderTree test_shell does not ever return
+ pixel data. It spits out the pixel dumps in a separate
+ file, thus all output over stdout is utf-8 text.
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Attempt one more time to fix NRWT for chromium.
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ - Pass encoding to _save_baseline_data and write_output_files
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ - Make _save_baseline_data and write_output_files take an encoding.
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+ - Pass encoding to _save_baseline_data and write_output_files
+
+2010-04-21 No'am Rosenthal <noam.rosenthal@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] QtLauncher: make FPS measurement accurate
+ https://bugs.webkit.org/show_bug.cgi?id=37934
+
+ Instead of counting paints, which are not interchangeable with frames that
+ the user sees, we now set an arbitrary timer for FPS measurements. The idea is
+ that if the main thread is delayed for any reason, that timer would be delayed
+ as well.
+
+ * QtLauncher/QtLauncher.pro:
+ * QtLauncher/fpstimer.cpp: Added.
+ (FpsTimer::FpsTimer):
+ (FpsTimer::numFrames):
+ (FpsTimer::start):
+ (FpsTimer::stop):
+ (FpsTimer::timerEvent):
+ * QtLauncher/fpstimer.h: Added.
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::setFrameRateMeasurementEnabled):
+ (WebViewGraphicsBased::updateFrameRate):
+ (WebViewGraphicsBased::paintEvent):
+ * QtLauncher/webview.h:
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, just adding missing ":" in python file.
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ new-run-webkit-tests --chromium was borked.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ Third time is the charm. I've fixed all the
+ new-run-webkit-tests regressions from previous attempts.
+
+ I fixed the queue to not ignore Tor as a reviwer in r57531,
+ but instead it throws an exception every time his name is in a patch.
+
+ This fixes our Executive.run_command code to work around a Popen
+ bug http://bugs.python.org/issue5290 whereby python versions before 2.6
+ do not correctly handle unicode objects as input or output to
+ Popen.communicate.
+
+ Following the advice of:
+ http://farmdev.com/talks/unicode/
+ I have changed all of webkitpy to use unicode() objects as strings
+ instead of str objects (which in Python 3 are renamed "bytes").
+
+ String literals were left as "foo" instead of converting to u"foo"
+ as u"foo" is only required if the string has a non-ascii code point.
+ Python is smart about comparing str() and unicode() values and will
+ log an error to the console if the comparison is ever invalid.
+
+ Executive.run* now correctly accept and return unicode() objects.
+ I attempted to fix all the places that we call .write() to make sure we
+ encode any unicode() objects into utf-8.
+
+ I removed several uses of StringIO. StringIO should generally always be
+ passed a unicode() value.
+
+ Likewise I replaced most calls to open() with codecs.open().
+ codecs.open() matches Python 3 open semantics in requiring an encoding
+ parameter. Files opened with codecs.open() with a unicode-compatible
+ encoding will vend unicode() objects from their read() calls, like how
+ StringIO created with a unicode() object will do.
+
+ I also deployed "with" statements wider (now that the project has
+ settled on Python 2.5) to close a bunch of file descriptor leaks.
+
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+ - Read/write utf-8 files instead of ascii.
+ - Update the tests to use test for proper unicode() handling.
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ - Document that parse_latest_entry_from_file expects
+ file-like objects which return unicode strings.
+ * Scripts/webkitpy/common/checkout/changelog_unittest.py:
+ - Use unicode() strings instead of str() byte arrays.
+ - Deploy "with" to close file descriptor leaks.
+ * Scripts/webkitpy/common/checkout/commitinfo.py:
+ - Remove unneeded import.
+ * Scripts/webkitpy/common/checkout/scm.py:
+ - Remove use of str().
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ - Read/write utf-8 files and use unicode() strings in testing.
+ * Scripts/webkitpy/common/config/committers.py:
+ - Use \u instead of \x to make slightly clearer what we're doing.
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ - Add a new _string_contents() method and explain why
+ we have to call unicode() on the result of soup.string
+ and why it's safe to do so w/o needing to pass a codec name.
+ - Remove the (unused) support for passing a file object to add_patch_to_bug().
+ * Scripts/webkitpy/common/net/buildbot.py:
+ - Use unicode() instead of str() when needing to coax a
+ NavigableString object into a unicode() object.
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+ - Add a test which contains a unicode builder name.
+ * Scripts/webkitpy/common/net/statusserver.py:
+ - Remove use of str()
+ * Scripts/webkitpy/common/prettypatch.py:
+ - Write out the patch file as utf-8.
+ * Scripts/webkitpy/common/system/autoinstall.py:
+ - Write out files with a explicit encodings.
+ - Deploy "with" to close file descriptor leaks.
+ * Scripts/webkitpy/common/system/deprecated_logging.py:
+ - Write out log files as utf-8.
+ * Scripts/webkitpy/common/system/executive.py:
+ - Make run* properly take and return unicode() objects.
+ - Cleaned up input handling in run_command a little by adding
+ a _compute_input() method which can return early instead of having
+ such a long/cluttered if-block.
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ - Added a unit test to make sure we don't break Tor again!
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ - Write out the test list as utf-8.
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ - Write out json files as utf-8.
+ * Scripts/webkitpy/layout_tests/port/apache_http_server.py:
+ - Deploy "with" to close file descriptor leaks.
+ * Scripts/webkitpy/layout_tests/port/chromium.py: Add Executive.py FIXME.
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py: ditto.
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py: ditto.
+ * Scripts/webkitpy/layout_tests/port/gtk.py: ditto.
+ * Scripts/webkitpy/layout_tests/port/mac.py: ditto.
+ * Scripts/webkitpy/layout_tests/port/mac_unittest.py:
+ - Make the skipped file parsing test unicode.
+ * Scripts/webkitpy/layout_tests/port/qt.py: Add Executive.py FIXME.
+ * Scripts/webkitpy/layout_tests/port/server_process.py: ditto.
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ - Deploy "with" to close file descriptor leaks.
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ - Make explicit the encodings of log files and pid files.
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ - Make encodings explicit and deploy "with".
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py: ditto.
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py: ditto.
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py: ditto.
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py: ditto.
+ * Scripts/webkitpy/style/filereader_unittest.py: ditto.
+ * Scripts/webkitpy/thirdparty/__init__.py: ditto.
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ - Removed extra import.
+ * Scripts/webkitpy/tool/commands/queues.py:
+ - No need to map args to strings now that run_command does.
+ - Update test results to match args changes.
+ - Document our global argument hacks.
+ * Scripts/webkitpy/tool/commands/upload.py:
+ - Pass the diff directly to add_patch_to_bug instead of creating a StringIO file wrapper.
+ * Scripts/webkitpy/tool/mocktool.py:
+ - Rename add_patch_to_bug argument to match bugzilla.py
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ - Executive.run_* now require lists instead of strings.
+ The lack of this change was what broke webkit-patch
+ for svn users the first time this was landed.
+ * Scripts/webkitpy/tool/steps/postdiff.py:
+ - Pass the diff directly to add_patch_to_bug instead of creating a StringIO file wrapper.
+ * Scripts/webkitpy/tool/steps/postdiffforcommit.py: ditto
+ * Scripts/webkitpy/tool/steps/postdiffforrevert.py: ditto
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ - Fixed spurious logging seen when running test-webkitpy
+
+2010-04-21 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ aria-liveregion-notifications.html fails on leopard release bot
+ https://bugs.webkit.org/show_bug.cgi?id=37112
+
+ Change the way that notifications are listened for by forcing clients
+ to call a remove listener as well to match the add listener. DRT will
+ assert if those are not done in the correct order.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (removeNotificationListenerCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::removeNotificationListener):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (-[AccessibilityNotificationHandler initWithPlatformElement:]):
+ (-[AccessibilityNotificationHandler dealloc]):
+ (-[AccessibilityNotificationHandler _notificationReceived:]):
+ (-[AccessibilityNotificationHandler setCallback:]):
+ (AccessibilityUIElement::AccessibilityUIElement):
+ (AccessibilityUIElement::~AccessibilityUIElement):
+ (AccessibilityUIElement::addNotificationListener):
+ (AccessibilityUIElement::removeNotificationListener):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::removeNotificationListener):
+
+2010-04-21 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Add debug menu items to show/hide the Web View.
+ https://bugs.webkit.org/show_bug.cgi?id=37958
+
+ * MiniBrowser/mac/BrowserWindowController.h:
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController showHideWebView:]):
+ (-[BrowserWindowController removeReinsertWebView:]):
+ (-[BrowserWindowController validateMenuItem:]):
+ * MiniBrowser/mac/English.lproj/MainMenu.xib:
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Rolling out unicode() changes as they broke NRWT for chromium.
+ Rolling out:
+ http://trac.webkit.org/changeset/58014
+ http://trac.webkit.org/changeset/58016
+ http://trac.webkit.org/changeset/58020
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbo
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ * Scripts/webkitpy/common/checkout/changelog_unittest.py:
+ * Scripts/webkitpy/common/checkout/commitinfo.py:
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ * Scripts/webkitpy/common/config/committers.py:
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+ * Scripts/webkitpy/common/net/statusserver.py:
+ * Scripts/webkitpy/common/prettypatch.py:
+ * Scripts/webkitpy/common/system/autoinstall.py:
+ * Scripts/webkitpy/common/system/deprecated_logging.py:
+ * Scripts/webkitpy/common/system/executive.py:
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/port/apache_http_server.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/gtk.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/mac_unittest.py:
+ * Scripts/webkitpy/layout_tests/port/qt.py:
+ * Scripts/webkitpy/layout_tests/port/server_process.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+ * Scripts/webkitpy/style/filereader_unittest.py:
+ * Scripts/webkitpy/thirdparty/__init__.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ * Scripts/webkitpy/tool/steps/postdiff.py:
+ * Scripts/webkitpy/tool/steps/postdiffforcommit.py:
+ * Scripts/webkitpy/tool/steps/postdiffforrevert.py:
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, fixing NRWT for real this time.
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ - Add a hack to fix new-run-webkit-tests
+ my understanding of codecs.open(encoding=None)
+ must have been wrong.
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, just fixing exception seen on builders.
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ - Pass and encoding to _write_into_file_at_path
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ I fixed the queue to not ignore Tor as a reviwer in r57531,
+ but instead it throws an exception every time his name is in a patch.
+
+ This fixes our Executive.run_command code to work around a Popen
+ bug http://bugs.python.org/issue5290 whereby python versions before 2.6
+ do not correctly handle unicode objects as input or output to
+ Popen.communicate.
+
+ Following the advice of:
+ http://farmdev.com/talks/unicode/
+ I have changed all of webkitpy to use unicode() objects as strings
+ instead of str objects (which in Python 3 are renamed "bytes").
+
+ String literals were left as "foo" instead of converting to u"foo"
+ as u"foo" is only required if the string has a non-ascii code point.
+ Python is smart about comparing str() and unicode() values and will
+ log an error to the console if the comparison is ever invalid.
+
+ Executive.run* now correctly accept and return unicode() objects.
+ I attempted to fix all the places that we call .write() to make sure we
+ encode any unicode() objects into utf-8.
+
+ I removed several uses of StringIO. StringIO should generally always be
+ passed a unicode() value.
+
+ Likewise I replaced most calls to open() with codecs.open().
+ codecs.open() matches Python 3 open semantics in requiring an encoding
+ parameter. Files opened with codecs.open() with a unicode-compatible
+ encoding will vend unicode() objects from their read() calls, like how
+ StringIO created with a unicode() object will do.
+
+ I also deployed "with" statements wider (now that the project has
+ settled on Python 2.5) to close a bunch of file descriptor leaks.
+
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+ - Read/write utf-8 files instead of ascii.
+ - Update the tests to use test for proper unicode() handling.
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ - Document that parse_latest_entry_from_file expects
+ file-like objects which return unicode strings.
+ * Scripts/webkitpy/common/checkout/changelog_unittest.py:
+ - Use unicode() strings instead of str() byte arrays.
+ - Deploy "with" to close file descriptor leaks.
+ * Scripts/webkitpy/common/checkout/commitinfo.py:
+ - Remove unneeded import.
+ * Scripts/webkitpy/common/checkout/scm.py:
+ - Remove use of str().
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ - Read/write utf-8 files and use unicode() strings in testing.
+ * Scripts/webkitpy/common/config/committers.py:
+ - Use \u instead of \x to make slightly clearer what we're doing.
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ - Add a new _string_contents() method and explain why
+ we have to call unicode() on the result of soup.string
+ and why it's safe to do so w/o needing to pass a codec name.
+ - Remove the (unused) support for passing a file object to add_patch_to_bug().
+ * Scripts/webkitpy/common/net/buildbot.py:
+ - Use unicode() instead of str() when needing to coax a
+ NavigableString object into a unicode() object.
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+ - Add a test which contains a unicode builder name.
+ * Scripts/webkitpy/common/net/statusserver.py:
+ - Remove use of str()
+ * Scripts/webkitpy/common/prettypatch.py:
+ - Write out the patch file as utf-8.
+ * Scripts/webkitpy/common/system/autoinstall.py:
+ - Write out files with a explicit encodings.
+ - Deploy "with" to close file descriptor leaks.
+ * Scripts/webkitpy/common/system/deprecated_logging.py:
+ - Write out log files as utf-8.
+ * Scripts/webkitpy/common/system/executive.py:
+ - Make run* properly take and return unicode() objects.
+ - Cleaned up input handling in run_command a little by adding
+ a _compute_input() method which can return early instead of having
+ such a long/cluttered if-block.
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ - Added a unit test to make sure we don't break Tor again!
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ - Write out the test list as utf-8.
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ - Write out json files as utf-8.
+ * Scripts/webkitpy/layout_tests/port/apache_http_server.py:
+ - Deploy "with" to close file descriptor leaks.
+ * Scripts/webkitpy/layout_tests/port/chromium.py: Add Executive.py FIXME.
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py: ditto.
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py: ditto.
+ * Scripts/webkitpy/layout_tests/port/gtk.py: ditto.
+ * Scripts/webkitpy/layout_tests/port/mac.py: ditto.
+ * Scripts/webkitpy/layout_tests/port/mac_unittest.py:
+ - Make the skipped file parsing test unicode.
+ * Scripts/webkitpy/layout_tests/port/qt.py: Add Executive.py FIXME.
+ * Scripts/webkitpy/layout_tests/port/server_process.py: ditto.
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ - Deploy "with" to close file descriptor leaks.
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ - Make explicit the encodings of log files and pid files.
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ - Make encodings explicit and deploy "with".
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py: ditto.
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py: ditto.
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py: ditto.
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py: ditto.
+ * Scripts/webkitpy/style/filereader_unittest.py: ditto.
+ * Scripts/webkitpy/thirdparty/__init__.py: ditto.
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ - Removed extra import.
+ * Scripts/webkitpy/tool/commands/queues.py:
+ - No need to map args to strings now that run_command does.
+ - Update test results to match args changes.
+ - Document our global argument hacks.
+ * Scripts/webkitpy/tool/commands/upload.py:
+ - Pass the diff directly to add_patch_to_bug instead of creating a StringIO file wrapper.
+ * Scripts/webkitpy/tool/mocktool.py:
+ - Rename add_patch_to_bug argument to match bugzilla.py
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ - Executive.run_* now require lists instead of strings.
+ The lack of this change was what broke webkit-patch
+ for svn users the first time this was landed.
+ * Scripts/webkitpy/tool/steps/postdiff.py:
+ - Pass the diff directly to add_patch_to_bug instead of creating a StringIO file wrapper.
+ * Scripts/webkitpy/tool/steps/postdiffforcommit.py: ditto
+ * Scripts/webkitpy/tool/steps/postdiffforrevert.py: ditto
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ - Fixed spurious logging seen when running test-webkitpy
+
+2010-04-21 Kinuko Yasuda <kinuko@chromium.org>
+
+ Unreviewed.
+
+ Add myself in committers.py.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-21 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ new-run-webkit-tests: fix a bug in the Chromium port where we would
+ try to talk to a crashed test_shell and raise exceptions that weren't
+ being caught.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37941
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-04-21 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Unreviewed.
+
+ [Qt] [Symbian] Build fix.
+
+ Work around a Qt quirk. Some versions of Symbian port Qt
+ QFontDatabase::removeAllApplicationFonts symbol is not available.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::open):
+
+2010-04-21 Alexey Proskuryakov <ap@apple.com>
+
+ Unreviewed.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37933
+ <rdar://problem/7719540> XMLHttpRequest.withCredentials should be better enforced.
+
+ Adding stub implementation of authenticateSession(). Depending on platform loader behavior,
+ a real implementation may or may not be necessary for the one test that currently uses it
+ to pass.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::authenticateSession):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-04-21 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Brady Eidson.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37933
+ <rdar://problem/7719540> XMLHttpRequest.withCredentials should be better enforced.
+
+ Adding authenticateSession() method that adds credentials to per-process credential storage
+ (for platforms that even have such). No Windows implementation, because writing another
+ loader for DRT is painful.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (authenticateSessionCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (-[SynchronousLoader dealloc]):
+ (-[SynchronousLoader connectionShouldUseCredentialStorage:]):
+ (-[SynchronousLoader connection:didReceiveAuthenticationChallenge:]):
+ (-[SynchronousLoader connection:didFailWithError:]):
+ (-[SynchronousLoader connectionDidFinishLoading:]):
+ (+[SynchronousLoader makeRequest:withUsername:password:]):
+ (LayoutTestController::authenticateSession):
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::authenticateSession):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::authenticateSession):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::authenticateSession):
+ Stub implementations.
+
+2010-04-21 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Make DRT compilable in Chromium tree
+ https://bugs.webkit.org/show_bug.cgi?id=37923
+
+ We need to use different GYPs in a case of WebKit-only checkout
+ and a case of whole Chromium checkout because the relative paths
+ from webkit/ to WebKit/chromium/features.gypi are different in
+ these cases and we can't use 'conditions' for 'includes' in GYPs.
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp:
+
+2010-04-21 Jakub Wieczorek <jwieczorek@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ List item markers are not always updated after changes in the DOM.
+ https://bugs.webkit.org/show_bug.cgi?id=37060
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (markerTextForListItemCallback): A function that returns the marker text for a given list item.
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::markerTextForListItem): Implement it in the GTK port.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::markerTextForListItem): Add a stub.
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::markerTextForListItem): Implement it in the Qt port.
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::markerTextForListItem): Add a stub.
+
+2010-04-21 Adam Roben <aroben@apple.com>
+
+ Exclude leaks in CGGradientCreateWithColorComponents from
+ run-webkit-tests leaks output
+
+ The leak in CG is covered by <rdar://problem/7888492>.
+
+ Fixes <http://webkit.org/b/37927>.
+
+ Reviewed by Eric Carlson.
+
+ * Scripts/old-run-webkit-tests:
+ (sub countAndPrintLeaks): Exclude leaks in
+ CGGradientCreateWithColorComponents on certain OSs.
+
+2010-04-21 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ [DRT/Chromium] Import MockSpellCheck from Chromium
+ https://bugs.webkit.org/show_bug.cgi?id=37910
+
+ Import webkit/tools/test_shell/mock_spellcheck.{cc,h} rev.37241 of Chromium.
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp:
+ Add ICU explicitly because WTFString.h includes ICU headers.
+ Add MockSpellCheck.{cpp,h}.
+ * DumpRenderTree/chromium/MockSpellCheck.cpp: Added.
+ * DumpRenderTree/chromium/MockSpellCheck.h: Added.
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (WebViewHost::spellCheck):
+ * DumpRenderTree/chromium/WebViewHost.h:
+ * DumpRenderTree/chromium/config.h: Define JS_EXPORTDATA, which is used
+ by wtf/text/AtomicString.h included by wtf/text/WTFString.h.
+
+2010-04-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add webkit-patch pretty-diff
+ https://bugs.webkit.org/show_bug.cgi?id=37892
+
+ This is slightly lame because it asks you whether the diff is correct,
+ but it's a starting point.
+
+ * Scripts/webkitpy/tool/commands/__init__.py:
+ * Scripts/webkitpy/tool/commands/prettydiff.py: Added.
+ * Scripts/webkitpy/tool/main.py:
+
+2010-04-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Remove mention of non-existant --no-build option
+ https://bugs.webkit.org/show_bug.cgi?id=37893
+
+ The option doesn't exist!
+
+ * Scripts/webkitpy/tool/commands/stepsequence.py:
+
+2010-04-21 Balazs Kelemen <kb@inf.u-szeged.hu>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Interrupting JavaScript is cumbersome when you use QtLaucher for testing or profiling.
+ https://bugs.webkit.org/show_bug.cgi?id=37198
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::toggleInterruptingJavaScriptEnabled):
+ (LauncherWindow::newWindow):
+ (LauncherWindow::cloneWindow):
+ (LauncherWindow::createChrome):
+ (main):
+ * QtLauncher/webpage.cpp:
+ (WebPage::WebPage):
+ (WebPage::shouldInterruptJavaScript):
+ * QtLauncher/webpage.h:
+ (WebPage::setInterruptingJavaScriptEnabled):
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r57963.
+ http://trac.webkit.org/changeset/57963
+ https://bugs.webkit.org/show_bug.cgi?id=37759
+
+ Three tests started crashing on the Qt bot.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-04-21 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ Make new-run-webkit-tests work for the Qt port
+ https://bugs.webkit.org/show_bug.cgi?id=37588
+
+ * Scripts/webkitpy/layout_tests/port/qt.py:
+
+2010-04-21 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests: try to detect alternate apache path
+ https://bugs.webkit.org/show_bug.cgi?id=37587
+
+ _check_port_build() also needs to return true in the
+ base implementation to not fail the check_build step.
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-04-21 Yi Shen <yi.4.shen@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Add LayoutTestController interface: computedStyleIncludingVisitedInfo
+ https://bugs.webkit.org/show_bug.cgi?id=37759
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::computedStyleIncludingVisitedInfo):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-04-21 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, test fix only.
+
+ new-run-webkit-tests: implement a --log trace message to be able to display detailed output of an individual test run
+ https://bugs.webkit.org/show_bug.cgi?id=37726
+
+ This change seems to have broken a test.
+ Attempting to handle the case where we don't have any
+ timing information. Dirk may have to correct this change.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests has much higher startup latency than run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=37643
+
+ I got rid of the -expected.checksum reads during startup.
+ This makes startup noticably better on my laptop.
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ - Use image_hash() instead of .image_hash now that expected.checksum
+ file reads are done lazily.
+ * Scripts/webkitpy/layout_tests/port/http_server_base.py:
+ - Add debug logging for this sleep call.
+ In my testing I never saw this sleep() hit.
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ - Sleep a shorter interval to make websocket server
+ startup more responsive. On my machine startup was
+ taking around 1 second.
+ - Remove the unconditional .5s delay on startup.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ - Make image_hash file reads done lazily in a new image_hash() function.
+ - Add a "Starting testing ..." meter update after DRT threads have
+ been started, but before we get updates from the first one.
+ - Rename variable "t" to a full english name to match WebKit style.
+
+2010-04-20 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37748
+
+ Make Sheriffbot more inspirational.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+ * Scripts/webkitpy/tool/bot/irc_command.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-04-20 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Import Chromium image_diff as ImageDiff
+ https://bugs.webkit.org/show_bug.cgi?id=37790
+
+ ImageDiff.cpp is based on tools/imagediff/image_diff.cc r41911 of Chromium.
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp:
+ * DumpRenderTree/chromium/ImageDiff.cpp: Added.
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+
+2010-04-20 Dirk Pranke <dpranke@chromium.org>
+
+ This patch to new-run-webkit-tests adds a --log 'trace' option
+ that prints out detailed info about a given test as it executes
+ (where the baselines are, what the expectation is, what we got,
+ how long it took).
+
+ https://bugs.webkit.org/show_bug.cgi?id=37726
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ - use the newly exposed TestResult class and implement
+ --log trace
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_thread.py:
+ - rename TestStats to TestResult and make it more public, resulting
+ in cleaner code
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ - add expectation_to_string() as a separate callable function
+
+2010-04-20 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r57907.
+ http://trac.webkit.org/changeset/57907
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ Appears to have broken MacEWS and possibly webkit-patch upload
+ for svn users. Needs further investigation.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ * Scripts/webkitpy/common/checkout/changelog_unittest.py:
+ * Scripts/webkitpy/common/checkout/commitinfo.py:
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ * Scripts/webkitpy/common/config/committers.py:
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+ * Scripts/webkitpy/common/net/statusserver.py:
+ * Scripts/webkitpy/common/prettypatch.py:
+ * Scripts/webkitpy/common/system/autoinstall.py:
+ * Scripts/webkitpy/common/system/deprecated_logging.py:
+ * Scripts/webkitpy/common/system/executive.py:
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/metered_stream.py:
+ * Scripts/webkitpy/layout_tests/port/mac_unittest.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ * Scripts/webkitpy/tool/steps/postdiff.py:
+ * Scripts/webkitpy/tool/steps/postdiffforcommit.py:
+ * Scripts/webkitpy/tool/steps/postdiffforrevert.py:
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+
+2010-04-20 Nate Chapin <japhet@chromium.org>
+
+ Unreviewed.
+
+ Update my irc handle in committers.py (natechapin -> japhet).
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ REGRESSION(57531): the commit-queue still hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37765
+
+ I fixed the queue to not ignore Tor as a reviwer in r57531,
+ but instead it throws an exception every time his name is in a patch.
+
+ This fixes our Executive.run_command code to work around a Popen
+ bug http://bugs.python.org/issue5290 whereby python versions before 2.6
+ do not correctly handle unicode objects as input or output to
+ Popen.communicate.
+
+ Following the advice of:
+ http://farmdev.com/talks/unicode/
+ I'm attempting to take the python unicode plunge and use unicode()
+ objects as strings instead of str() objects everywhere in webkitpy.
+
+ We do not have to use u"" instead of "" because u"a" == "a" as expected
+ in Python. Python will generate a warning to the console in cases where
+ a unicode() == str() operation cannot be performed.
+
+ I also cleaned up the input handling in run_command a little by adding
+ a new _compute_input() method which can return early instead of having
+ such a long/cluttered if-block.
+
+ Executive.run* now correctly accept and return unicode() objects.
+ I attempted to fix all the places that we call .write() to make sure we
+ encode any unicode() objects into utf-8.
+
+ All places which use StringIO need to be sure to pass StringIO a
+ pre-encoded byte-array (str object) instead of unicode so that
+ clients which read from the StringIO don't have encoding exceptions.
+ To make this easier, I removed the patch_file_object support from
+ add_patch_to_bug, and changed the 4 places which previously used
+ StringIO to create a fake patch file.
+
+ I attempted to document any places where we are not correctly converting
+ to/from bytes (str() objects) to strings (unicode() objects).
+
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+ - Read/write utf-8 files instead of ascii.
+ - Update the tests to use test for proper unicode() handling.
+ * Scripts/webkitpy/common/checkout/changelog_unittest.py:
+ - Use unicode() strings instead of str() byte arrays.
+ * Scripts/webkitpy/common/checkout/scm.py:
+ - Remove use of str().
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ - Read/write utf-8 files and use unicode() strings in testing.
+ * Scripts/webkitpy/common/config/committers.py:
+ - Use \u instead of \x to make slightly clearer what we're doing.
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ - Add a new _string_contents() method and explain why
+ we have to call unicode() on the result of soup.string
+ and why it's safe to do so w/o needing to pass a codec name.
+ - Remove the (unused) support for passing a file object to add_patch_to_bug().
+ * Scripts/webkitpy/common/net/buildbot.py:
+ - Use unicode() instead of str() when needing to coax a
+ NavigableString object into a unicode() object.
+ * Scripts/webkitpy/common/net/statusserver.py:
+ - Remove use of str()
+ * Scripts/webkitpy/common/prettypatch.py:
+ - Write out the patch file as utf-8.
+ * Scripts/webkitpy/common/system/autoinstall.py:
+ - Add a FIXME about encoding.
+ * Scripts/webkitpy/common/system/deprecated_logging.py:
+ - Document that tee() works on bytes, not strings.
+ * Scripts/webkitpy/common/system/executive.py:
+ - Make run* properly take and return unicode() objects.
+ * Scripts/webkitpy/common/system/executive_unittest.py:
+ - Added a unit test to make sure we don't break Tor again!
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ - Write out the test list as utf-8.
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ - Write out json files as utf-8.
+ * Scripts/webkitpy/layout_tests/layout_package/metered_stream.py:
+ - Add FIXME about encoding handling.
+ * Scripts/webkitpy/tool/commands/upload.py:
+ - Pass the diff directly to add_patch_to_bug instead of creating a StringIO file wrapper.
+ * Scripts/webkitpy/tool/mocktool.py:
+ - Rename add_patch_to_bug argument to match bugzilla.py
+ * Scripts/webkitpy/tool/steps/postdiff.py:
+ - Pass the diff directly to add_patch_to_bug instead of creating a StringIO file wrapper.
+ * Scripts/webkitpy/tool/steps/postdiffforcommit.py: ditto.
+ * Scripts/webkitpy/tool/steps/postdiffforrevert.py: ditto.
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ - Fixed spurious logging seen when running test-webkitpy
+
+2010-04-20 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ For check-webkit-style, implemented __eq__() and __ne__() (the
+ built-in equality and inequality methods) for the
+ DefaultStyleErrorHandler class.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37850
+
+ This will facilitate unit-testing for a subsequent patch,
+ namely for https://bugs.webkit.org/show_bug.cgi?id=37850
+
+ * Scripts/webkitpy/style/error_handlers.py:
+ - Added __eq__() and __ne__() to the DefaultStyleErrorHandler
+ class.
+
+ * Scripts/webkitpy/style/error_handlers_unittest.py:
+ - Added unit tests for __eq__() and __ne__().
+ - Also included a minor clean-up refactoring of combining the
+ StyleErrorHandlerTestBase class (which has not needed to
+ be separate due to previous changes) into the
+ DefaultStyleErrorHandlerTest class.
+
+2010-04-20 Jakub Wieczorek <jwieczorek@webkit.org>
+
+ Unreviewed.
+
+ Add my IRC nick to the committers.py list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-20 Kim Grönholm <kim.gronholm@nomovok.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Multitouch mocking in QtLauncher doesn't work with QGraphicsView
+ https://bugs.webkit.org/show_bug.cgi?id=37816
+
+ Fix multi-touch mocking in QtLauncher when using QGraphicsView.
+ Test: https://bug-32434-attachments.webkit.org/attachment.cgi?id=44955
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::eventFilter):
+ (LauncherWindow::initializeView):
+
+2010-04-20 MORITA Hajime <morrita@google.com>
+
+ Unreviewed, add myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-20 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ [DRT/Chromium] Fix some unexpected results of editing
+ https://bugs.webkit.org/show_bug.cgi?id=37843
+
+ This change fixes about 70 unexpected results.
+ The original test_webview_delegate.cc doesn't have this bug.
+ The bug was introduced when I ported it to WebKit tree.
+
+ * DumpRenderTree/chromium/WebViewHost.cpp:
+ (printRangeDescription): Replace the latter startContainer() with endContainer().
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Turn off some unit tests for now - the new-run-webkit-tests dryrun
+ tests for chromium won't work if you don't have a chromium checkout.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37841
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ (Re-)add dryrun.py; this was renamed from passing.py in the previous
+ CL but apparently somehow didn't get checked in.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37841
+
+ * Scripts/webkitpy/layout_tests/port/dryrun.py: Added.
+
+2010-04-19 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ check-webkit-style: exits when encountering a deleted file
+ https://bugs.webkit.org/show_bug.cgi?id=37122
+
+ This reverts the quick fix done by r57119 and makes check_patch
+ not call check_file for deleted files.
+
+ Also this change fixes the behavior for "-", which should mean
+ stdin. Before this change, the style checker just ignored "-"
+ with a warning message.
+
+ * Scripts/webkitpy/style/checker.py:
+ * Scripts/webkitpy/style/checker_unittest.py:
+
+2010-04-19 Daniel Bates <dbates@rim.com>
+
+ No review, rolling out 57868.
+ http://trac.webkit.org/changeset/57868
+ https://bugs.webkit.org/show_bug.cgi?id=37748
+
+ Sheriffbot wasn't very inspirational after this patch.
+ Instead, he was silent when you said hi :-(. Rolling
+ out this patch so that I can debug/test this some more.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+ * Scripts/webkitpy/tool/bot/irc_command.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-04-19 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Adam Barth.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37748
+
+ Make Sheriffbot more inspirational.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+ * Scripts/webkitpy/tool/bot/irc_command.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-04-19 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix, add missing header.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests - repurpose the "Passing" port as "Dryrun" port
+ that can be used to test platforms other than the one you are running
+ on. This can be useful for checking baselines and testing code
+ coverage.
+
+ Note that running the code on the "wrong" port requires each
+ port-specific implementation to actually not require any
+ platform-specific python code (e.g., the chromium-win port must
+ test for the existence of windows functions before calling them).
+
+ https://bugs.webkit.org/show_bug.cgi?id=37782
+
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/dryrun.py: Renamed from WebKitTools/Scripts/webkitpy/layout_tests/port/passing.py.
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py:
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests: add --build (default) and --no-build
+ options to make that step optional. This flag modifies what happens
+ in port.check_build().
+
+ https://bugs.webkit.org/show_bug.cgi?id=37786
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ new-run-webkit-tests - fix a typo in r57480 that caused us to stop
+ logging the actual list of unexpected results.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37831
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ From a patch by Tor Arne Vestbo <tor.arne.vestbo@nokia.com>
+
+ new-run-webkit-tests: make the retry step more explicit
+ https://bugs.webkit.org/show_bug.cgi?id=37606
+
+ It might be confusing to see the test and percent counters
+ reset without any notice of what's going on, so we make the
+ message that a retry-run is started explicit.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-19 Sam Weinig <weinig@apple.com>
+
+ Reviewed by Anders Carlsson.
+
+ Add support for opening a new window (File->New Window) to
+ Windows MiniBrowser. Accelerator doesn't work.
+
+ * MiniBrowser/win/BrowserView.cpp:
+ (createNewPage): Use BrowserView::create.
+ * MiniBrowser/win/BrowserWindow.cpp:
+ (BrowserWindow::onCommand): Respond to ID_FILE_NEW_WINDOW
+ by creating a new window.
+ * MiniBrowser/win/BrowserWindow.h:
+ (BrowserWindow::create): Added. Don't allow creating
+ BrowserWindows on the stack by making constructor
+ private and exposing the create function.
+ * MiniBrowser/win/MiniBrowser.cpp:
+ (MiniBrowser::createNewWindow): Move new window creation
+ logic here.
+ * MiniBrowser/win/MiniBrowser.h:
+ * MiniBrowser/win/MiniBrowser.rc:
+ * MiniBrowser/win/main.cpp:
+ (_tWinMain): Use the new MiniBrowser::createNewWindow().
+
+2010-04-19 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ AX: aria-haspopup needs to be exposed
+ https://bugs.webkit.org/show_bug.cgi?id=37808
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::hasPopup):
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Submit a better workaround for r57806 than the one in r57831 - log
+ an error and exit if you try to run new-run-webkit-tests with --use-drt
+ on Windows.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37822
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-04-19 Jesus Sanchez-Palencia <jesus@webkit.org>
+
+ Unreviewed.
+
+ Just adding myself as a committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Add slightly better logging to the websocket python wrapper script,
+ including a --verbose flag for debug output.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37233
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ * Scripts/new-run-webkit-websocketserver:
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests: add a way (--print-unexpected-results) to
+ (re-)print out the tests that produced unexpected results in the
+ last run. Also add a way (--retry-unexpected-results) to
+ automatically re-test them.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37783
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Restructure the logging in new-run-webkit-tests so that many of log
+ messages that were logged to the MeteredStream also get logged in
+ --verbose mode.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37780
+
+ * Scripts/webkitpy/layout_tests/layout_package/metered_stream.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests: add 'summary' and 'unexpected-results' options
+ to the --log flag. Also add a 'progress' flag to enable the regular
+ progress bar (as opposed to 'detailed-progress', which enables the
+ dots). Also add a 'nothing' flag to allow you to be explicit that
+ you don't want any logging on the command line.
+
+ The default is
+ '--log detailed-progress,summary,unexpected,unexpected-results'
+
+ (The default logging is unchanged by this patch, this just makes things
+ properly configurable).
+
+ Note that 'nothing' doesn't work properly yet; I need a couple other
+ patches to land to avoid rewriting things several different ways.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37785
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-19 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Make the URL change on committed load.
+
+ * QtLauncher/mainwindow.cpp:
+ (MainWindow::buildUI):
+ (MainWindow::setAddressUrl):
+ * QtLauncher/mainwindow.h:
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix a typo in the rebaselining tool that causes us to use "debug"
+ instead of "Debug" in a directory path, which fails on platforms with
+ case-sensitive filesystems.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37819
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-04-19 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix.
+
+ Fix breakage of chromium-win canary bots caused by r57806. That patch
+ introduced the option of using Chrome's new port of DumpRenderTree,
+ but unfortunately that port relies on the webkit.py class
+ implementation which uses non-blocking I/O that isn't available on
+ Windows. This patch turns off that option and doesn't import the
+ class if we're running on Windows.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37817
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-04-19 James Robinson <jamesr@chromium.org>
+
+ Reviewed by abarth.
+
+ Fix a typo
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-04-19 Adam Roben <aroben@apple.com>
+
+ Fix run-webkit-tests when there are spaces in the path
+
+ Fixes <http://webkit.org/b/37809>
+
+ Reviewed by Adam Barth.
+
+ * Scripts/run-webkit-tests: Use an "indirect object" to specify the
+ path to the harness to exec(). According to perldoc, this usage will
+ prohibit perl from parsing the arguments to exec() via the shell,
+ which would incorrectly split paths with spaces in them, etc.
+
+2010-04-19 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by Adam Roben.
+
+ WinLauncher.h should use LF line-endings and use native line-endings style.
+ https://bugs.webkit.org/show_bug.cgi?id=37807
+
+ * WinLauncher/WinLauncher.h: Added property svn:eol-style, converted to LF line-endings.
+
+2010-04-19 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ [DRT/Chromium] Fix a test initialization problem
+ https://bugs.webkit.org/show_bug.cgi?id=37791
+
+ * DumpRenderTree/chromium/DumpRenderTree.cpp:
+ (runTest): Call resetTestController() before runFileTest(). Some
+ controllers initialize their fields in reset() and not in their
+ constructors.
+
+2010-04-19 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [Chromium] new-run-webkit-tests should use WebKitDriver for --use-drt
+ https://bugs.webkit.org/show_bug.cgi?id=37793
+
+ We need to use WebKitDriver instead of ChromiumDriver for Chromium
+ DRT because its interface is different from test_shell.
+
+ Chromium DRT has no UI. So we can't use it to show test results.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-04-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Make failure-reason more forgiving
+ https://bugs.webkit.org/show_bug.cgi?id=37525
+
+ Removed search_limit, which wasn't very useful anyway.
+ Added a log about the long load time loading from the builders.
+ Prompt the user for what revision to start walking from (makes it easy to restart upon failure).
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+
+2010-04-18 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Created a class for check-webkit-style that encapsulates iterating
+ over text files and reading them.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37754
+
+ This revision is an intermediate step towards separating our
+ style-checking code from the logic of iterating over files and
+ reading them.
+
+ * Scripts/webkitpy/common/system/logtesting.py:
+ - Added a logMessages() method to the LoggingTestCase class.
+ This method provides unit tests with access to the raw list
+ of log messages in case the tester needs to do something more
+ than simply assert the list of existing messages.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added a ProcessorBase class that processors of lists of lines
+ should eventually inherit from.
+ - Also added a FIXME to use the ProcessorBase class and the
+ TextFileReader class added below.
+
+ * Scripts/webkitpy/style/filereader.py: Added.
+ - Created a TextFileReader class that encapsulates reading
+ and iterating over text files.
+
+ * Scripts/webkitpy/style/filereader_unittest.py: Added.
+ - Added a TextFileReaderTest class to unit-test the
+ new TextFileReader class.
+
+2010-04-15 Tony Chang <tony@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ [chromium] new-run-webkit-tests should be able to use chromium DRT
+ https://bugs.webkit.org/show_bug.cgi?id=37645
+
+ Make sure that the lack of a chromium checkout doesn't cause the script to
+ fail.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py: Fix up a few paths
+ to be relative to an upstream output dir.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py: Add --use-drt flag.
+
+2010-04-18 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, fixing the Qt bot.
+
+ Add a layer of indirection when calling run-webkit-tests to allow testing new-run-webkit-tests on various platforms
+ https://bugs.webkit.org/show_bug.cgi?id=37632
+
+ * Scripts/run-webkit-tests:
+ - Exit non-zero of launching the harness fails.
+
+2010-04-18 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, fixing the Qt bot.
+
+ Add a layer of indirection when calling run-webkit-tests to allow testing new-run-webkit-tests on various platforms
+ https://bugs.webkit.org/show_bug.cgi?id=37632
+
+ * Scripts/run-webkit-tests:
+ - Fix the wrapper to work for users who do not
+ have WebKitTools/Scripts in their path.
+
+2010-04-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add a layer of indirection when calling run-webkit-tests to
+ allow testing new-run-webkit-tests on various platforms.
+ https://bugs.webkit.org/show_bug.cgi?id=37632
+
+ This will let us test and fix bugs in new-run-webkit-tests
+ without needing to restart the buildbot master between tests.
+
+ Currently this change leaves run-webkit-tests as-is, but once
+ its landed we will easily be able to turn on/off
+ new-run-webkit-tests for various ports/configurations.
+
+ I will send a note out to webkit-dev about how we will
+ be using this launcher script to test on the bots.
+
+ * Scripts/old-run-webkit-tests: Copied from WebKitTools/Scripts/run-webkit-tests.
+ * Scripts/run-webkit-tests:
+ - A new script which decides whether to run new- or old-
+ run-webkit-tests based on the platform.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ - Add some dummy argument handling for arguments which
+ old-run-webkit-tests supports but new-run-webkit-tests
+ does not yet.
+
+2010-04-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add Gtk bots to the list of "core builders" (builders which stop the commit-queue when they turn red)
+ https://bugs.webkit.org/show_bug.cgi?id=33295
+
+ The Gtk builders have been green every time I've looked
+ at them in the last 5 days or so. It would appear webkit
+ is now keeping them green and we should update the core
+ builder list to match reality.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+
+2010-04-18 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Add support for LayoutTestController commands:
+ setSmartInsertDeleteEnabled
+ setSelectTrailingWhitespaceEnabled
+ execCommand
+ isCommandEnabled
+
+ https://bugs.webkit.org/show_bug.cgi?id=35844
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setSmartInsertDeleteEnabled):
+ (LayoutTestController::setSelectTrailingWhitespaceEnabled):
+ (LayoutTestController::execCommand):
+ (LayoutTestController::isCommandEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-04-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Remove steps_references and commands_references
+ https://bugs.webkit.org/show_bug.cgi?id=37758
+
+ We tried using the mumble_references convention to manage our
+ dependencies, but it doesn't seem to be providing much value for the
+ steps and commands module because these modules are small pieces of the
+ larger tool module. In this patch, I've removed the references file
+ for these modules.
+
+ I've left the style_references file for the style module because that
+ module seems better isolated from the rest of webkitpy and the
+ style_references file appears to be providing some value.
+
+ * Scripts/webkitpy/tool/commands/commandtest.py:
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+ * Scripts/webkitpy/tool/commands/queries_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/commands_references.py: Removed.
+ * Scripts/webkitpy/tool/steps/closebugforlanddiff_unittest.py:
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittest.py:
+ * Scripts/webkitpy/tool/steps/validatereviewer_unittest.py:
+ * Scripts/webkitpy/tool/steps_references.py: Removed.
+
+2010-04-17 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ WebKit needs a Chromium Mac EWS Builder
+ https://bugs.webkit.org/show_bug.cgi?id=37742
+
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+
+2010-04-17 Adam Barth <abarth@webkit.org>
+
+ Fix expected results for unit test broken by
+ http://trac.webkit.org/changeset/57772
+
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+
+2010-04-17 Sam Weinig <weinig@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Teach windows MiniBrowser how to work with window.open()
+ and targeted links.
+
+ * MiniBrowser/win/BrowserView.cpp:
+ (createNewPage): Create a new BrowserWindow and return its page.
+ (showPage): Show the page.
+ (closePage): Empty implementation.
+ (runJavaScriptAlert): Empty implementation.
+ (BrowserView::create): Register a UIClient.
+ * MiniBrowser/win/BrowserView.h:
+ (BrowserView::webView): Added.
+ Change create to take a BrowserWindow instead of an HWND.
+
+ * MiniBrowser/win/BrowserWindow.cpp:
+ (BrowserWindow::wndProc): Respond to WM_NCDESTROY.
+ (BrowserWindow::goToURL): Added. Forwards to BrowserView.
+ (BrowserWindow::onCreate): Don't always go to the default
+ url. Let the caller do this.
+ (BrowserWindow::onNCDestroy): Delete the window.
+ * MiniBrowser/win/BrowserWindow.h:
+ (BrowserWindow::view): Added.
+ (BrowserWindow::window): Added.
+
+ * MiniBrowser/win/main.cpp:
+ (_tWinMain):
+ Go to the default URL for the initial page. Allocate the initial
+ window on the heap for correctness.
+
+2010-04-16 Adam Roben <aroben@apple.com>
+
+ Add the Windows Debug (Test) builder to the list of core builders
+
+ It's been green for a few days now, and all the known Windows
+ flakiness is Release-only.
+
+ Rubber-stamped by Mark Rowe.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ (BuildBot.core_builder_name_regexps): Added a regular expression to
+ match the "Windows Debug (Test)" builder.
+
+2010-04-16 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Fix window.open() and targeted links.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (_createNewPage): Use the correct initializer to and load the window.
+
+2010-04-16 Adam Roben <aroben@apple.com>
+
+ Fix links to layout test results from build status pages
+
+ Reviewed by Mark Rowe.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+ (ExtractTestResults.finished): Prepend "/" on the URL of the test
+ results page so that it is treated as an absolute URL.
+
+2010-04-16 Tony Chang <tony@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [chromium] build DRT on Linux
+ https://bugs.webkit.org/show_bug.cgi?id=37690
+
+ * Scripts/build-dumprendertree: Add support for win and linux
+
+2010-04-16 Sam Weinig <weinig@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Use the threaded process model for MiniBrowser if holding down
+ the shift key on startup.
+
+ * MiniBrowser/win/BrowserView.cpp:
+ (BrowserView::create):
+
+2010-04-15 Tony Chang <tony@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [chromium] Add TestShellGtk.cpp so we can link on Linux
+ https://bugs.webkit.org/show_bug.cgi?id=37561
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp: Add new file and
+ add platform file exceptions.
+ * DumpRenderTree/chromium/TestShellGtk.cpp: Added.
+ (AlarmHandler):
+ (TestShell::waitTestFinished):
+
+2010-04-15 Tony Chang <tony@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ build DRT on chromium mac
+ https://bugs.webkit.org/show_bug.cgi?id=37639
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp:
+ * Scripts/build-dumprendertree: enable build-dumprendertree --chromium
+
+2010-04-15 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Add LayoutTestHelper for Mac
+ https://bugs.webkit.org/show_bug.cgi?id=37668
+
+ LayouTestHelper.mm is based on webkit/tools/test_shell/mac/layout_test_helper.mm
+ of Chromium.
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp:
+ * DumpRenderTree/chromium/LayoutTestHelper.mm: Added.
+
+2010-04-15 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37494
+ <rdar://problem/7857060> REGRESSION (r57340): fast/events/mouse-drag-from-frame-to-other-frame.html
+ fails on Windows
+
+ * DumpRenderTree/win/EventSender.cpp: (makeEventSender):
+ * DumpRenderTree/win/EventSender.h:
+ Tell EventSender if it's being created for a top frame.
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld): We only want to reset
+ EventSender machinery when a new test is loaded, not when an iframe (or just its global
+ object) is created.
+
+2010-04-15 Adam Roben <aroben@apple.com>
+
+ Fix Windows WebKit2 build.
+
+ * MiniBrowser/win/MiniBrowser.cpp:
+
+2010-04-15 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Include codereview issue number in patch description
+ https://bugs.webkit.org/show_bug.cgi?id=37677
+
+ This lets us know which rietveld issue this patch is tied to.
+
+ Also, make it so that --fancy-review overrides --no-review.
+
+ * Scripts/webkitpy/tool/steps/postcodereview.py:
+ * Scripts/webkitpy/tool/steps/postdiff.py:
+
+2010-04-15 Adam Roben <aroben@apple.com>
+
+ Make --exit-after-n-failures work when all tests are timing out or crashing
+
+ Fixes <http://webkit.org/b/37679>.
+
+ Reviewed by Jon Honeycutt.
+
+ * Scripts/run-webkit-tests:
+ (top level): When a test crashes or times out, break out of the main loop if
+ stopRunningTestsEarlyIfNeeded returns true. Moved some code from the bottom of the main loop
+ from here...
+ (stopRunningTestsEarlyIfNeeded): ...to here.
+
+2010-04-15 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Add WebHistoryClient support.
+ https://bugs.webkit.org/show_bug.cgi?id=37671
+
+ Add HistoryClient logging.
+
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (_didNavigateWithNavigationData):
+ (_didPerformClientRedirect):
+ (_didPerformServerRedirect):
+ (_didUpdateHistoryTitle):
+ (-[BrowserWindowController awakeFromNib]):
+
+2010-04-15 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Start the mini browser in threaded mode if shift is pressed during startup.
+ https://bugs.webkit.org/show_bug.cgi?id=37670
+
+ * MiniBrowser/mac/AppDelegate.m:
+ (-[BrowserAppDelegate init]):
+
+2010-04-15 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ AXHelp is being appended from ancestors incorrectly
+ https://bugs.webkit.org/show_bug.cgi?id=37659
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getHelpTextCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::helpText):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::helpText):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::helpText):
+
+2010-04-15 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Re-format run-webkit-tests to fit in 80-columns for PEP-8 compliance.
+ (broken by r57463 and r57381, at least). I've also filed bug 37477
+ to fix check-webkit-style to catch these things.
+
+ https://bugs.webkit.org/show_bug.cgi?id=38586
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-15 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Add a way to override the user-visible name for the test binary since
+ some ports don't call it DumpRenderTree (e.g., Chromium Win uses
+ test_shell, Chromium Mac uses TestShell) by adding a driver_name()
+ method to the Port interface.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37631
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-14 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Add "Force Repaint" to debug menu.
+ https://bugs.webkit.org/show_bug.cgi?id=37627
+
+ * MiniBrowser/mac/BrowserWindowController.h:
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController forceRepaint:]):
+ * MiniBrowser/mac/English.lproj/MainMenu.xib:
+
+2010-04-15 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Add debug-minibrowser script.
+
+ * Scripts/debug-minibrowser: Copied from Scripts/run-minibrowser.
+ * Scripts/webkitdirs.pm:
+
+2010-04-15 Roland Steiner <rolandsteiner@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Bug 37636 - [DRT/Chromium] Implement DRT/Chromium for Windows
+ https://bugs.webkit.org/show_bug.cgi?id=37636
+
+ Second patch: add Windows-specific implementation parts
+ of TestShell.
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp:
+ * DumpRenderTree/chromium/TestShell.h:
+ (TestShell::finishedEvent):
+ * DumpRenderTree/chromium/TestShellWin.cpp:
+ (watchDogThread):
+ (TestShell::waitTestFinished):
+
+2010-04-15 Roland Steiner <rolandsteiner@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Bug 37636 - [DRT/Chromium] Implement DRT/Chromium for Windows
+ https://bugs.webkit.org/show_bug.cgi?id=37636
+
+ First patch: fix compiler errors.
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::reset):
+ (EventSender::dispatchMessage):
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::pathToLocalResource):
+ * DumpRenderTree/chromium/TestWebWorker.h:
+ * DumpRenderTree/chromium/TextInputController.cpp:
+ * DumpRenderTree/chromium/WebViewHost.h:
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp:
+
+2010-04-14 Luiz Agostini <luiz.agostini@openbossa.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Moving setViewMode from DumpRenderTreeSupportQt to qwebpage.cpp
+ https://bugs.webkit.org/show_bug.cgi?id=37622
+
+ Method qt_wrt_setViewMode was removed from qwebpage.cpp by mistake in r57433
+ (bug 35844). Moving it back.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setViewModeMediaFeature):
+
+2010-04-15 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Add some very minimal unit tests for new-run-webkit-tests. This should
+ be enough to catch egregious brokenness like syntax errors and import
+ declaration issues.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37432
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py: Added.
+
+2010-04-14 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Add a way for the buildbot to kill any old processes that are running. This
+ is useful because the Windows bots can get in states where a process remains
+ running (httpd.exe, DumpRenderTree.exe), which causes the bots to get in a red
+ state, and the processes must be killed manually.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: If we are on Windows, kill
+ the old processes that might be running.
+ * BuildSlaveSupport/win/kill-old-processes: Added.
+
+2010-04-14 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Tear down WebKit more completely on window closing and application
+ termination. We still don't block application termination for pending
+ close, but this is a step in the right direction.
+
+ * MiniBrowser/mac/AppDelegate.m:
+ (-[BrowserAppDelegate applicationWillTerminate:]):
+ * MiniBrowser/mac/BrowserWindowController.h:
+ * MiniBrowser/mac/BrowserWindowController.m:
+ (-[BrowserWindowController dealloc]):
+ (-[BrowserWindowController windowWillClose:]):
+ (-[BrowserWindowController applicationTerminating]):
+
+2010-04-14 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Use pretty patch for confirming webkit-patch diffs
+ https://bugs.webkit.org/show_bug.cgi?id=37489
+
+ * Scripts/webkitpy/common/prettypatch.py: Added.
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/confirmdiff.py:
+
+2010-04-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Teach webkit-patch how to handle revisions missing ChangeLogs
+ https://bugs.webkit.org/show_bug.cgi?id=37519
+
+ Make commit_info_for_revision return None when revision
+ is missing a ChangeLog. Previously we would throw an array index
+ exception.
+ Teach callers how to handle None.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+
+2010-04-13 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Add Qt Bot to the list of "core builders" (builders which block the commit-queue when red)
+ https://bugs.webkit.org/show_bug.cgi?id=33297
+
+ This is an experiment. The bots have been green for
+ a while. We'll see if adding them under sheriff-bot protection
+ will keep them green.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+
+2010-04-13 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, just fixing a constant in the Rietveld unit test.
+
+ * Scripts/webkitpy/common/net/rietveld_unittest.py
+
+2010-04-13 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, just adding missing Mock to fix python tests.
+
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-04-13 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by David Levin.
+
+ Add experimental prototype Rietveld integration to webkit-patch upload
+ https://bugs.webkit.org/show_bug.cgi?id=37418
+
+ This patch adds bare-bones integration with Rietveld for code reviews.
+ The behavior is hidden behind the --fancy-review command line flag.
+ Currently, there's no support for uploading more than one patch per
+ issue (which is a nice feature of Rietveld). The plan is to play with
+ this for a bit and see if it's useful.
+
+ Modified from Adam's original patch to autoinstall the rietveld upload script.
+
+ * Scripts/webkitpy/common/config/__init__.py:
+ * Scripts/webkitpy/common/net/rietveld.py: Added.
+ * Scripts/webkitpy/common/net/rietveld_unitttest.py: Added.
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/__init__.py:
+ * Scripts/webkitpy/tool/steps/options.py:
+ * Scripts/webkitpy/tool/steps/postcodereview.py: Added.
+ * Scripts/webkitpy/tool/steps/postdiff.py:
+
+2010-04-13 Sam Weinig <sam@webkit.org>
+
+ Rubber-stamped by Mark Rowe.
+
+ Add Makefile to MiniBrowser.
+
+ * MiniBrowser/Makefile: Added.
+
+2010-04-13 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, just adding a sanity check.
+
+ Add check to make sure commit-queue can never commit too short a message
+ https://bugs.webkit.org/show_bug.cgi?id=37528
+
+ The commit-queue made bogus messages here:
+ http://trac.webkit.org/changeset/57532
+ http://trac.webkit.org/changeset/57534
+
+ This was a regression caused by adding unicode parsing for
+ our ChangeLog files. Popen does not seem to play nice with
+ unicode strings.
+
+ I'm also adding an "assert" to make sure short ChangeLogs never happen again.
+
+ * Scripts/webkitpy/common/system/executive.py:
+ - Cast input to strings before passing to POpen
+ * Scripts/webkitpy/tool/steps/commit.py:
+ - Validate that commit messages are not to short.
+
+2010-04-13 Adam Roben <aroben@apple.com>
+
+ Robustify new-run-webkit-tests against paths with spaces in them
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/webkitpy/layout_tests/port/apache_http_server.py:
+ (LayoutTestApacheHttpd.__init__): Quote all paths that we pass to
+ Apache to ensure that paths with spaces in them are interpreted
+ correctly.
+
+2010-04-13 Csaba Osztrogonác <ossy@webkit.org>
+
+ Unreviewed buildfix after r57537.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.h: Declaration of removeOriginAccessWhitelistEntry() added.
+
+2010-04-13 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Make building new webkit API and MiniBrowser a little easier.
+
+ * Scripts/build-webkit: Make building with --webkit2 build the
+ MiniBrowser as well and tell you how to use it.
+ * Scripts/run-minibrowser: Copied from Scripts/run-safari.
+ * Scripts/webkitdirs.pm: Add runMiniBrowser function.
+
+2010-04-12 Timothy Hatcher <timothy@apple.com>
+
+ SecurityOrigin needs a way to remove individual OriginAccessEntries
+ https://bugs.webkit.org/show_bug.cgi?id=37449
+
+ Reviewed by Dave Hyatt.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (removeOriginAccessWhitelistEntryCallback): Added. Call LayoutTestController::removeOriginAccessWhitelistEntry.
+ (LayoutTestController::staticFunctions): Added removeOriginAccessWhitelistEntry.
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::removeOriginAccessWhitelistEntry): Added. FIXME to implement.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::removeOriginAccessWhitelistEntry): Added.
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::removeOriginAccessWhitelistEntry): Added. FIXME to implement.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::removeOriginAccessWhitelistEntry): Added.
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::whiteListAccessFromOrigin): FIXME to implement.
+ (LayoutTestController::removeOriginAccessWhitelistEntry): Added. FIXME to implement.
+
+2010-04-13 Timothy Hatcher <timothy@apple.com>
+
+ Rename SecurityOrigin::whiteListAccessFromOrigin to addOriginAccessWhitelistEntry.
+ And LayoutTestController.whiteListAccessFromOrigin to addOriginAccessWhitelistEntry.
+ And SecurityOrigin::resetOriginAccessWhiteLists to resetOriginAccessWhitelists.
+
+ SecurityOrigin needs a way to remove individual OriginAccessEntries
+ https://bugs.webkit.org/show_bug.cgi?id=37449
+
+ Reviewed by Dave Hyatt.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (addOriginAccessWhitelistEntryCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::addOriginAccessWhitelistEntry):
+ * DumpRenderTree/chromium/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::addOriginAccessWhitelistEntry):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::addOriginAccessWhitelistEntry):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::addOriginAccessWhitelistEntry):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::addOriginAccessWhitelistEntry):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::addOriginAccessWhitelistEntry):
+
+2010-04-13 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ Remove duplicate function for new-run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=37517
+
+ The version() function was already implemented.
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-04-13 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ the commit-queue hates Tor Arne Vestbø
+ https://bugs.webkit.org/show_bug.cgi?id=37511
+
+ We were failing to read reviewers out of ChangeLogs
+ when the reviewer has unicode characters in his/her name.
+ I fixed this by explicitly decoding from utf8 every time we
+ read in a ChangeLog file (they are always UTF8).
+
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ * Scripts/webkitpy/common/checkout/changelog_unittest.py:
+
+2010-04-13 Adam Roben <aroben@apple.com>
+
+ Fix run-webkit-tests on Windows with spaces in the path
+
+ Fixes <http://webkit.org/b/37509>.
+
+ Reviewed by Steve Falkenburg.
+
+ * Scripts/run-webkit-tests:
+ (convertPathUsingCygpath): Remove spaces from the path before passing
+ them to cygpath, then add them back in after conversion, as some
+ versions of cygpath seem to convert spaces into newlines.
+
+2010-04-13 Adam Barth <abarth@webkit.org>
+
+ Unreviewed, but approved by Dumitru Daniliuc. (This patch is intended
+ to fix the downstream Chromium build bots. Hopefully it will work!)
+
+ Add a driver script for the new websocket server
+ https://bugs.webkit.org/show_bug.cgi?id=37495
+
+ websocket_server.py can't be run directly because its a module and not
+ a standalone script. This used to work by accident because it didn't
+ depend on any other modules.
+
+ * Scripts/new-run-webkit-websocketserver: Added.
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+
+2010-04-12 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make new-run-webkit-test PrettyPatch failure reporting more awesome
+ https://bugs.webkit.org/show_bug.cgi?id=37487
+
+ I also fixed an Executive/executive typo.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+
+2010-04-12 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests should only build java support files on Mac
+ https://bugs.webkit.org/show_bug.cgi?id=37482
+
+ Only the mac needs java support files, so I pushed _build_java
+ down into the Mac port using a new hook "_check_port_build".
+ In the process I noticed a bunch of code which could be shared
+ between all ports and thus got rid of _tests_for_disabled_features
+ and version() copy/paste between all webkit ports.
+ I also made check_build only bother to check for ImageDiff if we're
+ using pixel tests.
+
+ * Scripts/webkitpy/layout_tests/port/gtk.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/qt.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/port/win.py:
+
+2010-04-12 Dumitru Daniliuc <dumi@chromium.org>
+
+ Unreviewed, trying to make scripts work on machines without
+ Ruby...
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+
+2010-04-12 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ Add stub files for running new-run-webkit-tests for the Qt port
+
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/qt.py: Added.
+
+2010-04-12 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Modify run_webkit_tests.py to not call sys.exit() at the end of test
+ run; doing so makes it more difficult to embed the routine for,
+ among other things, unit tests. We push the exit calling up into
+ new-run-webkit-tests.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37464
+
+ * Scripts/new-run-webkit-tests:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-12 Eric Seidel <eric@webkit.org>
+
+ Unreviewed.
+
+ Add stub Gtk implementation for new-run-webkit-tests.
+
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/gtk.py: Added.
+
+2010-04-12 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests fails with exception on systems missing ruby
+ https://bugs.webkit.org/show_bug.cgi?id=37441
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ - Catch failures similar to how wdiff code path does.
+ - After one failure, stop trying.
+
+2010-04-12 Tony Chang <tony@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix how we import simplejson based on how it's used in this file.
+ This fixes exceptions raised when trying to write the simplejson output.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-11 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Refactored check-webkit-style so that the StyleChecker class
+ has no dependencies on patch-related concepts.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37065
+
+ This patch is an intermediate step towards making the StyleChecker
+ class a generalized file processor that can do arbitary operations
+ on the files corresponding to a list of paths. This patch
+ also simplifies the unit-testing of patch-checking code.
+
+ * Scripts/check-webkit-style:
+ - Updated to use the new PatchChecker class.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Refactored the StyleChecker.check_patch() method into the
+ check() method of a new PatchChecker class.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Refactored the unit tests as necessary, changing the
+ StyleCheckerCheckPatchTest class to a PatchCheckerTest class.
+
+2010-04-11 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Fix new-run-webkit-tests regressions cased by Eric's option parsing patch
+ https://bugs.webkit.org/show_bug.cgi?id=37430
+
+ We need some basic unit testing of this script, or we're going to keep
+ breaking it like this. Added missing namespace qualifiers and
+ propagated renaming of an option.
+
+ * Scripts/webkitpy/common/config/ports.py:
+ * Scripts/webkitpy/layout_tests/driver_test.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Break new-run-webkit-tests options into groups for easier re-use and possible relocation
+ https://bugs.webkit.org/show_bug.cgi?id=37408
+
+ new-run-webkit-tests currently has one huge function for
+ dealing with all options-parsing.
+ This patch is a first attempt at trying to split that large
+ function down into smaller (hopefully more readable?) chunks
+ dealing with the different areas of options.
+ For example, it would make sense to move configuration
+ options off into some module which deals with the vagries of
+ WebKit's configuration system. It would also make sense to move
+ Chromium options off onto the Chromium port object (where they are used).
+ It may make sense to move results.json options over to the results.json code.
+ This change is a first iteration, and we will certainly need more
+ refinement to this code over time. Hopefully I didn't make things
+ harder to read here.
+
+ * Scripts/webkitpy/layout_tests/driver_test.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-11 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ create-rollout copy needs to be updated to reflect removal of --no-build
+ https://bugs.webkit.org/show_bug.cgi?id=37425
+
+ Removed --no-build and --no-test from the instructions because these
+ don't exist anymore.
+
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ - Updated the expected results to reflect the new copy.
+ * Scripts/webkitpy/tool/steps/postdiffforrevert.py:
+
+2010-04-11 Sheriff Bot <webkit.review.bot@gmail.com>
+
+ Unreviewed, rolling out r57460.
+ http://trac.webkit.org/changeset/57460
+ https://bugs.webkit.org/show_bug.cgi?id=37424
+
+ broke chromium builders (Requested by tony^work on #webkit).
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp:
+
+2010-04-11 Tony Chang <tony@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ [chromium] update chromium DEPS for upstream compile
+ https://bugs.webkit.org/show_bug.cgi?id=36578
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp: Small fix to avoid a circular dependency between
+ WebKit.gyp and webkit.gyp.
+
+2010-04-11 Joseph Pecoraro <joepeck@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ svn-apply errors out when removing directories in git
+ https://bugs.webkit.org/show_bug.cgi?id=34871
+
+ * Scripts/svn-apply:
+ (isDirectoryEmptyForRemoval): early break if the directory doesn't exist
+ (scmRemove): have git ignore unmatched files
+
+2010-04-11 Daniel Bates <dbates@rim.com>
+
+ No review, rolling out 57440.
+ http://trac.webkit.org/changeset/57440
+ https://bugs.webkit.org/show_bug.cgi?id=27204
+
+ Did not handle Git patches that included both file and property
+ changes to the same file. Rolling this change out while I look
+ into this.
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/svn-apply:
+ * Scripts/svn-unapply:
+ * Scripts/webkitperl/VCSUtils_unittest/appendSVNExecutableBitChangeToPatch.pl: Removed.
+ * Scripts/webkitperl/VCSUtils_unittest/parseGitFileMode.pl: Removed.
+ * Scripts/webkitperl/VCSUtils_unittest/parseStartOfPatchOrPropertyChangeAndEndOfPropertyChange.pl: Removed.
+
+2010-04-11 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix typo in log path for AbstractQueue
+ https://bugs.webkit.org/show_bug.cgi?id=37414
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+
+2010-04-11 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Add missing import statement.
+
+ * Scripts/webkitpy/common/system/executive.py:
+
+2010-04-11 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Add setWillSendRequestReturnsNull and setWillSendRequestClearHeader
+
+ https://bugs.webkit.org/show_bug.cgi?id=37410
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::setWillSendRequestReturnsNull):
+ (LayoutTestController::setWillSendRequestClearHeader):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-04-11 Csaba Osztrogonác <ossy@webkit.org>
+
+ [Qt] Unreviewed buildfix for --debug build after r57433.
+
+ Refactor Qt DRT support in QtWebKit
+ https://bugs.webkit.org/show_bug.cgi?id=35844
+
+ * QtLauncher/main.cpp: qt_drt_garbageCollector_collect(); renamed to DumpRenderTreeSupportQt::garbageCollectorCollect();
+ (launcherMain):
+
+2010-04-11 Joseph Pecoraro <joepeck@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Make commit-log-editor Rubber-stamp aware. And other minor cleanups.
+ https://bugs.webkit.org/show_bug.cgi?id=37407
+
+ * Scripts/commit-log-editor:
+
+2010-04-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add PrettyPatch links to new-run-webkit-tests output
+ https://bugs.webkit.org/show_bug.cgi?id=37406
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py:
+ - We're leaking a file handle here, add a FIXME.
+ * Scripts/webkitpy/layout_tests/layout_package/test_failures.py:
+ - Add pretty diff links.
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ - Add support for generating pretty diffs using PrettyPatch.
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ - We're leaking another file handle here, another FIXME.
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ - Update write_output_files signature.
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ - Remove unused arguments from write_output_files.
+ - Add support for dumping pretty diffs to write_output_files.
+ - Fix a bunch of file descriptor leaks in this file.
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+ - Update write_output_files signature.
+
+2010-04-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ kill_process is copy/pasted in five places
+ https://bugs.webkit.org/show_bug.cgi?id=37405
+
+ We shouldn't replicate the kill_process logic in every port. Instead,
+ we should move the process interaction to Executive.
+
+ Dirk mentioned that he wanted this abstraction to make it easier to
+ mock things out for testing. It turns out this function is only used
+ in one place where it can't be used as a mock point for testing because
+ the corresponding create process actually creates a real process. In
+ the long term, we should indirect both these calls through a non-static
+ Executive as a mock point. However, we should wait on that until we
+ actually want to write the test.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ * Scripts/webkitpy/layout_tests/port/win.py:
+
+2010-04-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests shouldn't alter its path to import packages
+ https://bugs.webkit.org/show_bug.cgi?id=37404
+
+ * Scripts/new-run-webkit-tests:
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+ * Scripts/webkitpy/thirdparty/simplejson/decoder.py:
+
+2010-04-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests should store results to a directory under the build tree
+ https://bugs.webkit.org/show_bug.cgi?id=37380
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-04-10 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27204
+
+ Implement support for changing the executable bit of a file.
+ The executable bit is among the most changed file properties.
+ Future support can include other property changes.
+
+ Currently, if a patch changes the executable bit of a file
+ it is not respected by svn-apply or svn-unapply. Since the
+ commit-queue bot uses these tools as part of its workflow,
+ such patches cannot be committed by it. That is, such patches
+ need to be committed by hand. Instead, we should add support
+ for the executable bit so that such patches can be committed
+ by the commit-queue bot.
+
+ * Scripts/VCSUtils.pm: Also change reference to Apple Computer, Inc.
+ in copyright to Apple, Inc.
+ * Scripts/svn-apply:
+ * Scripts/svn-unapply:
+ * Scripts/webkitperl/VCSUtils_unittest/appendSVNExecutableBitChangeToPatch.pl: Added.
+ * Scripts/webkitperl/VCSUtils_unittest/parseGitFileMode.pl: Added.
+ * Scripts/webkitperl/VCSUtils_unittest/parseStartOfPatchOrPropertyChangeAndEndOfPropertyChange.pl: Added.
+
+2010-04-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ WinEWS bot fails to svn update because scm.clean_working_directory leaves files around
+ https://bugs.webkit.org/show_bug.cgi?id=37401
+
+ The Git-based bots don't have this trouble because
+ Git.clean_working_directory fully removes files that were
+ marked as "add". SVN.clean_working_directory previously just
+ called "svn revert" which would leave added files in the
+ working directory untracked. This patch makes
+ SVN.clean_working_directory function more like
+ Git.clean_working_directory by removing added files after revert.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ - Add SCM.absolute_path for easy conversion between
+ repository-relative paths and absolute paths.
+ - Add SCM.add and SCM.added_files
+ - Make SVN.clean_working_directory remove any added_files after svn revert.
+ - The new unit tests found a bug in Git.status_command, change to use git diff --name-status instead.
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ - Add tests for added code.
+
+2010-04-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests can't find ImageDiff on Windows
+ https://bugs.webkit.org/show_bug.cgi?id=37403
+
+ It turns out the build directory on Windows is structured differently
+ than it is on other platforms. Instead of assuming the normal
+ structure, we should just ask perl to figure it out for us.
+
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-04-10 Adam Barth <abarth@webkit.org>
+
+ Rubber-stamped by Eric Seidel.
+
+ Change "Gathering files" status line to "Collecting tests". Gathering
+ the files sounds silly to me.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix bugs to make new-run-webkit-tests almost run on windows
+ https://bugs.webkit.org/show_bug.cgi?id=37400
+
+ Fix some minor bugs that prevent new-run-webkit-tests from being run on
+ Windows. I still haven't run it to completion, but I'm getting
+ further.
+
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+
+2010-04-10 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Refactor Qt DRT support in QtWebKit
+
+ Update Qt DRT to use new DumpRenderTreeSupportQt static class.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35844
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ (WebCore::DumpRenderTree::dumpFramesAsText):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/GCControllerQt.cpp:
+ (GCController::collect):
+ (GCController::collectOnAlternateThread):
+ (GCController::getJSObjectCount):
+ * DumpRenderTree/qt/GCControllerQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::counterValueForElementById):
+ (LayoutTestController::setViewModeMediaFeature):
+ (LayoutTestController::setMediaType):
+ (LayoutTestController::closeWebInspector):
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::evaluateInWebInspector):
+ (LayoutTestController::setFrameFlatteningEnabled):
+ (LayoutTestController::setJavaScriptProfilingEnabled):
+ (LayoutTestController::setTimelineProfilingEnabled):
+ (LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+ (LayoutTestController::numberOfActiveAnimations):
+ (LayoutTestController::whiteListAccessFromOrigin):
+ (LayoutTestController::setCaretBrowsingEnabled):
+ (LayoutTestController::setDomainRelaxationForbiddenForURLScheme):
+ (LayoutTestController::workerThreadCount):
+ (LayoutTestController::pageNumberForElementById):
+ (LayoutTestController::numberOfPages):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-04-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move global queue log to the logs directory so it survives git clean -f
+ https://bugs.webkit.org/show_bug.cgi?id=37395
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-04-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ SheriffBot should spam when it encounters errors
+ https://bugs.webkit.org/show_bug.cgi?id=37329
+
+ We need to always update the status server so we don't get stuck in a
+ spam loop. I tried writing a test for this change, but it kind of
+ got out of control. We need a better way to do failure injection.
+
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+
+2010-04-10 Adam Barth <abarth@webkit.org>
+
+ Unreviewed attempt to fix the Chromium Mac canary.
+
+ * Scripts/webkitpy/common/config/ports.py:
+ * Scripts/webkitpy/common/config/ports_unittest.py:
+ * Scripts/webkitpy/common/system/executive.py:
+
+2010-04-10 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Add the Apache bits to win.py for new-run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=37397
+
+ I still have run this yet, but I looked around to figure out what the
+ various paths appear to be. I'll figure out a way to remove the
+ copy/paste code in a future patch.
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/port/win.py:
+
+2010-04-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Sketch out the win port for new-run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=37393
+
+ I haven't tried running this yet, but we've got to start somewhere.
+
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py:
+ * Scripts/webkitpy/layout_tests/port/win.py: Added.
+
+2010-04-10 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch land should not build and test by default
+ https://bugs.webkit.org/show_bug.cgi?id=33631
+
+ Reverse the sense of --no-build and --no-test to be --build and --test.
+ Also, decoupled the build and test options so you can test without
+ building.
+
+ (Patch manngled by Adam Barth. All bugs are his fault.)
+
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/steps/options.py:
+ * Scripts/webkitpy/tool/steps/runtests.py:
+
+2010-04-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Factor WebKitPort out of MacPort to allow for WinPort
+ https://bugs.webkit.org/show_bug.cgi?id=37388
+
+ The split is a bit of a guess. We might have to adjust things once we
+ actually have a second port to work with.
+
+ * Scripts/webkitpy/layout_tests/port/apache_http_server.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/webkit.py: Added.
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+
+2010-04-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ run_webkit_tests.py shouldn't have platform-specific logic
+ https://bugs.webkit.org/show_bug.cgi?id=37387
+
+ Dirk Pranke pointed out that my last patch was wrong because I
+ introduced platform-specific logic into run_webkit_tests.py, limiting
+ the parallelism in Chromium to work around a bug in the main Mac port.
+
+ * Scripts/webkitpy/common/system/executive.py:
+ - Fix a typo pointed out by Chris Jerdonek.
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-10 Robert Hogan <robert@webkit.org>
+
+ Unreviewed fix to regressions in r57416.
+
+ [Qt] Fix regressions in http/tests/navigation from r57416
+
+ Reset willSendRequestReturnsNullOnRedirect after each test to
+ prevent it leaking to subsequent tests.
+
+ Error pointed out by Jakub Wieczorek.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37237
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+
+2010-04-11 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Update layoutTestController.DumpResourceLoadCallbacks to match other ports.
+
+ Add support for layoutTestController.setWillSendRequestReturnsNullOnRedirect to Qt DRT.
+ Prevent dumping resource load callbacks once layout test has dumped.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37237
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setWillSendRequestReturnsNullOnRedirect):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-04-10 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Implement Desktop Notifications API for QtWebKit
+ https://bugs.webkit.org/show_bug.cgi?id=35503
+
+ DRT stubs for notification. Enables to run and pass
+ 3 (currently disabled) tests.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::grantDesktopNotificationPermission):
+ (LayoutTestController::checkDesktopNotificationPermission):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-04-09 Dumitru Daniliuc <dumi@chromium.org>
+
+ Unreviewed, another change to executive.py to make it run with
+ python 2.4.
+
+ * Scripts/webkitpy/common/system/executive.py:
+
+2010-04-09 Dumitru Daniliuc <dumi@chromium.org>
+
+ Unreviewed, attempting to make executive.py run with python 2.4
+ (which is still used on Chromium's Windows canary bot).
+
+ * Scripts/webkitpy/common/system/executive.py:
+
+2010-04-09 Kevin Watters <kevinwatters@gmail.com>
+
+ Reviewed by Eric Seidel.
+
+ [wx] Basic implementation of SVG support for wx port.
+
+ * wx/build/settings.py:
+
+2010-04-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Don't reinvent Executive.cpu_count for every port
+ https://bugs.webkit.org/show_bug.cgi?id=37377
+
+ mac.py and chromium_mac.py had some copy/paste code. This code doesn't
+ actually have anything to do with WebKit ports. It's really just
+ something in the multiprocessing package. The lame bit is that package
+ isn't available in older versions of Python, so we need to implement a
+ fallback. However, we already have the fallback in common. We don't
+ need to reinvent it specificly for layout_tests.
+
+ * Scripts/webkitpy/common/system/executive.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests --release fails to build release DRT when global configuration is Debug
+ https://bugs.webkit.org/show_bug.cgi?id=37376
+
+ We need to explicitly pass the --release flag. I bet there are more
+ instances of this bug.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+
+2010-04-09 Tony Chang <tony@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [chromium] DRT compile fix on win/linux
+ https://bugs.webkit.org/show_bug.cgi?id=37314
+
+ Looks like this was missed when upstreaming.
+
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (applyKeyModifier):
+
+2010-04-09 Adam Barth <abarth@webkit.org>
+
+ Unreviewed, but approved by Dirk Pranke.
+
+ rename test_expectations_test.py to test_expectations_unittest.py so it actually gets run
+ https://bugs.webkit.org/show_bug.cgi?id=37372
+
+ We need to end unit tests with _unittest.py for them to be autodetected
+ by the test harness. +6 tests.
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py: Renamed from WebKitTools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_test.py.
+
+2010-04-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests should talk about DumpRenderTree not test_shell
+ https://bugs.webkit.org/show_bug.cgi?id=37371
+
+ test_shell is some strange Chromium thing.
+ DumpRenderTree (tm) is the real deal.
+
+ * Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_failures.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_shell_thread.py: Removed.
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/server_process.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-09 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Fix 2 issues (what were introduced in r56524) in svn-create-patch's generateDiff()
+ https://bugs.webkit.org/show_bug.cgi?id=32582
+
+ Add missing return variable. Initialize $patch variable and remove unnecessary condition.
+
+ * Scripts/svn-create-patch:
+
+2010-04-09 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after addition of LayoutTestController method.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::computedStyleIncludingVisitedInfo):
+
+2010-04-09 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=37368
+ Add MiniBrowser.
+
+ * MiniBrowser: Added.
+ * MiniBrowser/MiniBrowser.vcproj: Added.
+ * MiniBrowser/MiniBrowser.xcodeproj: Added.
+ * MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj: Added.
+ * MiniBrowser/mac: Added.
+ * MiniBrowser/mac/AppDelegate.h: Added.
+ * MiniBrowser/mac/AppDelegate.m: Added.
+ * MiniBrowser/mac/BrowserWindowController.h: Added.
+ * MiniBrowser/mac/BrowserWindowController.m: Added.
+ * MiniBrowser/mac/English.lproj: Added.
+ * MiniBrowser/mac/English.lproj/BrowserWindow.xib: Added.
+ * MiniBrowser/mac/English.lproj/InfoPlist.strings: Added.
+ * MiniBrowser/mac/English.lproj/MainMenu.xib: Added.
+ * MiniBrowser/mac/MiniBrowser-Info.plist: Added.
+ * MiniBrowser/mac/MiniBrowser_Prefix.pch: Added.
+ * MiniBrowser/mac/main.m: Added.
+ * MiniBrowser/win: Added.
+ * MiniBrowser/win/BrowserView.cpp: Added.
+ * MiniBrowser/win/BrowserView.h: Added.
+ * MiniBrowser/win/BrowserWindow.cpp: Added.
+ * MiniBrowser/win/BrowserWindow.h: Added.
+ * MiniBrowser/win/MiniBrowser.cpp: Added.
+ * MiniBrowser/win/MiniBrowser.h: Added.
+ * MiniBrowser/win/MiniBrowser.rc: Added.
+ * MiniBrowser/win/Resources: Added.
+ * MiniBrowser/win/main.cpp: Added.
+ * MiniBrowser/win/resource.h: Added.
+ * MiniBrowser/win/stdafx.cpp: Added.
+ * MiniBrowser/win/stdafx.h: Added.
+
+2010-04-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch attached my patch to the wrong bug
+ https://bugs.webkit.org/show_bug.cgi?id=37015
+
+ The problem here is that SVN was violating SCM's implicit
+ contract of always returning paths relative to the repository root.
+ That can easily be fixed by telling SVN that the CWD is the repository root.
+
+ When fixing this I realized there are a large number of places in SCM.py where
+ we want to consider explicitly passing self.checkout_root as the CWD.
+ That would allow scm methods to be executed even when the CWD is not inside
+ the scm tree at all, and would also make sure (in the case of SVN) that paths
+ returned are relative to the root. Git (almost always) returns paths relative
+ to the repository root.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ - Explicitly pass self.checkout_root as cwd in run_status_and_extract_filenames
+ - Add a ton of FIXMEs about the need to go back and decide which methods require cwd=self.checkout_root
+ and which do not. We'll probably add a helper function to scm (likely SCM._run) which
+ always passes cwd=self.checkout_root to Executive.run_command
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ - Add a test for this change.
+ * Scripts/webkitpy/tool/commands/upload.py:
+ - Removed the explicit os.chdir to the repository root, since scm.py methods
+ should be robust against the cwd not being equal to the root.
+
+2010-04-09 Adam Roben <aroben@apple.com>
+
+ Don't return 0 as a JSValueRef
+
+ That is an illegal use of the JSC API.
+
+ Fixes <http://webkit.org/b/37333> REGRESSION (r57292): :visited tests
+ are asserting on debug Windows and GTK builds
+
+ Reviewed by Anders Carlsson.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::computedStyleIncludingVisitedInfo):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::computedStyleIncludingVisitedInfo):
+ Return an "undefined" JSValueRef instead of 0.
+
+2010-04-09 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Make DumpRenderTree parallelizable
+ https://bugs.webkit.org/show_bug.cgi?id=36899
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (libraryPathForDumpRenderTree): Use DUMPRENDERTREE_TEMP if exist.
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree): Use DUMPRENDERTREE_TEMP if exist.
+ * Scripts/run-webkit-tests:
+ - Create a unique temporary directory and pass its path to
+ DumpRenderTree with DUMPRENDERTREE_TEMP environment variable.
+
+2010-04-09 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ <http://webkit.org/b/37326> IDL files are being copied in to the WebCore framework again
+
+ Add a script to detect the presence of inappropriate files in the frameworks. At present
+ it only looks for .css, .idl and .in files in the top level of WebCore.framework/Resources,
+ as these are the only cases we've encountered recently. It can be extended to check the
+ other frameworks or for other inappropriate files in the future.
+
+ * Scripts/check-for-inappropriate-files-in-framework: Added.
+
+2010-04-08 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Add option to build WebKit2 to build-webkit.
+
+ * Scripts/build-webkit:
+
+2010-04-08 Darin Adler <darin@apple.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ run-webkit-tests should respect argument order
+ https://bugs.webkit.org/show_bug.cgi?id=37257
+
+ * Scripts/run-webkit-tests: Changed so that sorting is done only
+ on the results of iterating directories. Test order is based on
+ what's passed on the command line. Removed code that aimed to
+ eliminate duplicates since it can be useful to run the same test
+ more than once.
+
+2010-04-07 David Hyatt <hyatt@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ https://bugs.webkit.org/show_bug.cgi?id=24300, don't expose history info via CSS. Add a new method for
+ obtaining computed style with :visited info included. This allows layout tests to actually tell that
+ :visited is in effect.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (computedStyleIncludingVisitedInfoCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::computedStyleIncludingVisitedInfo):
+
+2010-04-07 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Enable rebaseline-chromium-webkit-tests to run from a webkit-only
+ checkout (i.e., you don't need anything from the Chromium tree checked
+ out). This requires us to introduce the concept of a "target"
+ port/platform that we use to get configuration information from as well
+ as the "running" port that we use to make directories and diff images
+ and the "rebaselining" port we use to actually manage baselines.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37238
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-04-05 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] REGRESSION:(r50665) QWebFrame::setScrollBarPolicy(Qt::Vertical,Qt::ScrollBarAlwaysOff) has no effect.
+ https://bugs.webkit.org/show_bug.cgi?id=29431
+
+ Added stubs for Mac, win, gtk and wx DRTs to implement setScrollbarPolicy method.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setScrollbarPolicyCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setScrollbarPolicy):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setScrollbarPolicy):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setScrollbarPolicy):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setScrollbarPolicy):
+
+2010-04-01 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by David Hyatt.
+
+ [Qt] REGRESSION:(r50665) QWebFrame::setScrollBarPolicy(Qt::Vertical,Qt::ScrollBarAlwaysOff) has no effect.
+ https://bugs.webkit.org/show_bug.cgi?id=29431
+
+ Make possible to DRT to set scrollbar policies (on, off or auto).
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setScrollbarPolicy):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * QtLauncher/main.cpp:
+ (LauncherWindow::toggleScrollbars):
+ (LauncherWindow::createChrome):
+
+2010-04-08 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests should give a percent complete indication
+ https://bugs.webkit.org/show_bug.cgi?id=37258
+
+ Because it's awesome.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-08 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Add back the --target option because it's needed by the downstream
+ Chromium bots.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-08 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ new-run-webkit-tests should understand set-webkit-configuration
+ https://bugs.webkit.org/show_bug.cgi?id=37252
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-08 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Rename target to configuration in new-run-webkit-tests to match the rest of WebKit
+ https://bugs.webkit.org/show_bug.cgi?id=37251
+
+ The rest of our tools call --debug or --release the configuration.
+ It's confusing to call it target in this script.
+
+ * Scripts/webkitpy/layout_tests/driver_test.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_shell_thread.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-04-07 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Remove depricated op.popen2 call in new-run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=37249
+
+ Python complains that this API is depricated. We already solved this
+ problem in executive.py.
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+
+2010-04-07 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests crashes when run on a 64-bit machine
+ https://bugs.webkit.org/show_bug.cgi?id=37248
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ - The code was trying to always run the 32-bit intel version
+ of the DumpRenderTree binary. DRT does not build 32-bit on 64-bit
+ machines so that makes no sense. This may have made sense for test_shell
+ at some point, but I think we should just remove this for DRT.
+
+2010-04-07 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ WebKit Apache configs only listen on IPv4 addresses, causing random timeouts
+ https://bugs.webkit.org/show_bug.cgi?id=37104
+
+ Add warnings that the partial support for specifying what port numbers
+ apache should bind to is even more broken after this fix.
+
+ * Scripts/run-webkit-httpd:
+ * Scripts/run-webkit-tests:
+
+2010-04-07 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ LayoutTestController::m_handlesAuthenticationChallenges isn't initialized
+ https://bugs.webkit.org/show_bug.cgi?id=37190
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+
+2010-03-31 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add webkit-patch command to crawl buildbot history and find when tests
+ started to fail.
+ https://bugs.webkit.org/show_bug.cgi?id=36911
+
+ This is a very bare-bones implementation, which works, but isn't pretty.
+ We will need further re-factoring and improvement to this code, but
+ after long discussions with Adam, I think it's best that we land this
+ and iterate from there.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ - Add revision_build_pairs_with_results for cleaner code and possible
+ optimization of this command.
+ - Return None if a build number can't be found for a revision in
+ build_for_revision
+ - Separate out suspect_revisions_for_transition for re-use by
+ FailureReason
+ - Add LayoutTestResults.failing_tests() and make our parsing code
+ explict about what tables it accepts.
+ * Scripts/webkitpy/tool/commands/queries.py:
+ - Move _print_blame_information_for_commit out of WhatBroke for re-use
+ by FailureReason.
+ - Add FailureReason command which can crawl a given builder and explain
+ why it is currently red on a per-test basis.
+
+2010-04-06 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Add DumpRenderTree.gyp, and some small fixes
+ https://bugs.webkit.org/show_bug.cgi?id=37137
+
+ - Add DumpRenderTree.gyp
+ - Remove some dependencies to base/string_util.h,
+ base/compiler_specific.h, base/file_path.h, base/file_util.h,
+ base/message_loop.h, base/sys_string_conversions.h,
+
+ * DumpRenderTree/DumpRenderTree.gyp/DumpRenderTree.gyp: Added.
+ * DumpRenderTree/chromium/CppVariant.cpp:
+ (CppVariant::toStringVector):
+ * DumpRenderTree/chromium/EventSender.cpp:
+ (EventSender::EventSender):
+ (EventSender::keyDown):
+ (EventSender::scheduleAsynchronousClick):
+ (EventSender::beginDragWithFiles):
+ * DumpRenderTree/chromium/LayoutTestController.cpp:
+ (LayoutTestController::setUserStyleSheetLocation):
+ (LayoutTestController::pathToLocalResource):
+ * DumpRenderTree/chromium/TextInputController.cpp:
+ (TextInputController::markedRange):
+ (TextInputController::selectedRange):
+
+2010-04-06 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Write stack traces into the results directory for new-run-webkit-tests,
+ instead of writing them alongside the test file.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36504
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_shell_thread.py:
+
+2010-04-06 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed build fix.
+
+ Enable pixel tests by default in new-run-webkit-tests unless
+ explicitly set by the port or by the command line. This was broken in
+ the fix for bug 36801 (rev. 57173).
+
+ https://bugs.webkit.org/show_bug.cgi?id=37184
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-06 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Disable pixel tests on the mac port by default.
+
+ Also, revamp the way we check for pixel tests being enabled or
+ disabled. We now look for options.pixel_tests instead of
+ options.no_pixel_tests, and we have the "--pixel-tests" (force enable)
+ and "--no-pixel-tests" (force disable) flags.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36801
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_test.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-04-06 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] Added the iPhone and iPad latest user agent in QtLauncher UA switcher
+ https://bugs.webkit.org/show_bug.cgi?id=37159
+
+ * QtLauncher/useragentlist.txt:
+
+2010-04-06 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Add current user-agent string for Symbian for QtLauncher
+ https://bugs.webkit.org/show_bug.cgi?id=37131
+
+ * QtLauncher/useragentlist.txt:
+
+2010-04-06 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Explain how to handle rollout patches
+ https://bugs.webkit.org/show_bug.cgi?id=37139
+
+ We need to set expectations for how long landing rollout patches with
+ the commit-queue takes. The commit-queue is optimized for safety, not
+ performance. Also, give folks an alternative way to land patches
+ quickly.
+
+ In addition, improve our testing of add_patch_to_bug by having
+ MockBugzilla log. This caused me to tighten a bunch of tests and
+ notice that one of our tests wasn't being run.
+
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/postdiffforrevert.py:
+
+2010-04-06 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Turns out commit_info.committer() can be None
+ https://bugs.webkit.org/show_bug.cgi?id=37106
+
+ When the committer isn't in committers.py, the committer() property on
+ commit_info can be None. We need to handle that case gracefully.
+
+ * Scripts/webkitpy/common/checkout/commitinfo.py:
+ * Scripts/webkitpy/tool/bot/sheriff.py:
+ * Scripts/webkitpy/tool/bot/sheriff_unittest.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+
+2010-04-06 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] [Symbian] Build fix for Dumprendertree if Qt printing is not supported
+ https://bugs.webkit.org/show_bug.cgi?id=37082
+
+ Use the QT_NO_PRINTER guard to flag QPrinter dependent code.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::dryRunPrint):
+
+2010-04-05 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ SheriffBot should force_build builders that are idle and have failed exactly once
+ https://bugs.webkit.org/show_bug.cgi?id=37059
+
+ We can get into a deadlocked state where the commit-queue is stopped
+ because the builders are red but the SheriffBot hasn't taken action
+ because the builder has failed only once. The SheriffBot should force
+ build idle builders that have failed exactly once to either turn the
+ tree green again (if the test was flaky) or trigger the "failed twice"
+ remedies (IRC and bug posts).
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/tool/bot/sheriff.py:
+ * Scripts/webkitpy/tool/bot/sheriff_unittest.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-04-05 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Fixed check-webkit-style issue where the script was prematurely
+ exiting when encountering deleted files in patches.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37122
+
+ * Scripts/webkitpy/style/checker.py:
+ - Changed non-existent file message from ERROR to WARN.
+ - StyleChecker.check_file() no longer raises an exception when
+ a file is not found.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated unit tests as necessary.
+
+2010-04-05 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ SheriffBot should include blamelist when posting to bugs
+ https://bugs.webkit.org/show_bug.cgi?id=37113
+
+ When posting on bugs, we should include the full list of SVN revisions
+ that caused the regression to folks have a better sense of whether they
+ are to blame.
+
+ * Scripts/webkitpy/tool/bot/sheriff.py:
+ * Scripts/webkitpy/tool/bot/sheriff_unittest.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-04-05 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Unreviewed after discussion with Adam, Darin, and Eric.
+
+ Deleted the auto-install directory since it is no longer needed in
+ source control (it is auto-generated).
+
+ Also added webkitpy/thirdparty/autoinstalled to webkitpy/thirdparty's
+ svn:ignore property.
+
+ * Scripts/webkitpy/thirdparty/autoinstalled: Removed.
+
+2010-04-05 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ Test case for <http://webkit.org/b/37115> / <rdar://problem/7829331>.
+ REGRESSION(r56989): Crash in Mail in WebCore::Position::isCandidate when deleting block using block deletion UI
+
+ Add a JavaScript hook in DRT to call through to WebView's -setEditable:. This is required in order to reproduce
+ the crash.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setWebViewEditableCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setWebViewEditable):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setWebViewEditable):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setWebViewEditable):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setWebViewEditable):
+ (LayoutTestController::layerTreeAsText):
+
+2010-04-05 Darin Adler <darin@apple.com>
+
+ Ignore more files the Python tools strew about the working directory.
+
+ * Scripts/webkitpy: Added property svn:ignore.
+ * Scripts/webkitpy/common: Added property svn:ignore.
+ * Scripts/webkitpy/common/checkout: Added property svn:ignore.
+ * Scripts/webkitpy/common/config: Added property svn:ignore.
+ * Scripts/webkitpy/common/net: Added property svn:ignore.
+ * Scripts/webkitpy/common/thread: Added property svn:ignore.
+ * Scripts/webkitpy/python24: Added property svn:ignore.
+ * Scripts/webkitpy/thirdparty/autoinstalled: Modified property svn:ignore.
+ * Scripts/webkitpy/tool/bot: Added property svn:ignore.
+
+2010-04-05 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Add Vitaly Repeshko as a committer.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-05 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Update kenne's IRC nick to his registered nick.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-05 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ assorted helper functions and cleanup of git utilities
+ https://bugs.webkit.org/show_bug.cgi?id=37103
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ No code currently uses the optional dry_run argument. So removing it.
+ Change all uses of "trunk" to read the correct value out of the git config.
+ Made the dcommit call actually get called when dry_run==true.
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ * Scripts/webkitpy/common/net/credentials.py:
+ Move the git config call into scm.
+ * Scripts/webkitpy/common/net/credentials_unittest.py:
+ * Scripts/webkitpy/common/system/executive.py:
+ If return_exit_code==true, don't error out, just return the exit_code.
+
+2010-04-05 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ prepare-ChangeLog should take a merge-base for which git branch to diff against.
+ https://bugs.webkit.org/show_bug.cgi?id=36394
+
+ * Scripts/prepare-ChangeLog:
+
+2010-04-05 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Removed the PatchStyleErrorHandler class and incorporated its
+ functionality into the DefaultStyleErrorHandler class.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37067
+
+ * Scripts/webkitpy/style/checker.py:
+ - In the StyleChecker class:
+ - Added a line_number parameter to the check_file() method.
+ - Renamed the handle_style_error parameter to
+ mock_handle_style_error to be consistent with the other mock_*
+ parameter names.
+ - Added a mock_check_file parameter to the check_patch() method
+ to facilitate unit testing the changes in this patch.
+ - Rewrote the check_patch() method with the patch-parsing logic
+ taken from the PatchStyleErrorHandler class.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Added a StyleCheckerCheckFileBase class and sub-classed the
+ existing StyleCheckerCheckFileTest class from it.
+ - Added a StyleCheckerCheckPatchTest class to unit-test the
+ rewritten check_patch() method.
+ - Removed the vestigial __main__ code at the bottom of the file.
+ This is left over from when check-webkit-style was implemented
+ as a module and a wrapper module.
+
+ * Scripts/webkitpy/style/error_handlers.py:
+ - Added an optional line_numbers parameter to the
+ DefaultStyleErrorHandler class constructor and adjusted the
+ __call__() method as necessary.
+ - Removed the PatchStyleErrorHandler class.
+
+ * Scripts/webkitpy/style/error_handlers_unittest.py:
+ - Removed the PatchStyleErrorHandlerTest class which unit-tested
+ the PatchStyleErrorHandler class which is being removed in this
+ patch.
+ - Added a test_line_numbers() test method to the
+ DefaultStyleErrorHandlerTest class to test use of the
+ DefaultStyleErrorHandler's new line_numbers attribute.
+
+2010-04-05 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Tighten SheriffBot's flaky test detector
+ https://bugs.webkit.org/show_bug.cgi?id=37063
+
+ Instead of just looking for two sequential red builds, look for two
+ sequential failures of the same test. This should reduce sheriffbot
+ false positive substantially.
+
+ I'm landing this change unreviewed because I've noticed SheriffBot
+ triggering a lot more false positives now that we've expanded the set
+ of core builders. I've tried to take Eric's comments on Bug 37063 into
+ account. I'm happy to iterate on this patch tomorrow once Eric wakes
+ up.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+
+2010-04-04 John Gregg <johnnyg@google.com>
+
+ Unreviewed, add myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-04 Robert Hogan <robert@webkit.org>
+
+ Unreviewed, add myself to the committers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-04 Dumitru Daniliuc <dumi@chromium.org>
+
+ Unreviewed, adding my IRC nickname to committers.py
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-04 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Refactored check-webkit-style's option-parsing code.
+
+ https://bugs.webkit.org/show_bug.cgi?id=37064
+
+ * Scripts/check-webkit-style:
+ - Moved the "WebKit checkout not found" check from
+ ArgumentParser.parse() to the calling code.
+ - Moved the --git-commit argument validation from the calling
+ code to ArgumentParser.parse().
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated a unit test as necessary.
+
+ * Scripts/webkitpy/style/optparser.py:
+ - Renamed ArgumentParser._exit_with_help() to _parse_error()
+ and made its error_message parameter required.
+ - Removed the found_checkout parameter from ArgumentParser.parse().
+ - Removed the "WebKit checkout not found" check and moved it
+ to the calling code.
+ - Added --git-commit argument checking.
+
+ * Scripts/webkitpy/style/optparser_unittest.py:
+ - Adjusted the import statements to be fully qualified.
+ - Changed the ArgumentParserTest class to inherit from
+ LoggingTestCase, and updated the class as necessary.
+ - Added a unit-test for the --git-commit validation.
+ - Added unit tests for the --git-diff and --git-since variants
+ of --git-commit.
+
+2010-04-03 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ The check-webkit-style script now logs an ERROR and exits when
+ encountering a file path that does not exist. Previously, it failed
+ silently on such paths.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36957
+
+ * Scripts/webkitpy/common/system/logtesting.py:
+ - Added a FIXME to rename the LoggingTestCase class to
+ LoggingTestCaseBase.
+
+ * Scripts/webkitpy/style/checker.py:
+ - In the StyleChecker.check_file() method:
+ - Added a mock_os_path_exists parameter.
+ - Renamed the process_file parameter to mock_process_file.
+ - Added logic to log an error and exist if the given path does
+ not exist.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Refactored the StyleCheckerCheckFileTest class slightly to
+ inherit from LoggingTestCase.
+ - Added a test method to unit-test the case of a file that
+ does not exist.
+ - Adjusted the other test methods as necessary.
+
+2010-04-03 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add Tiger Bot to the list of "core builders" (builders which block the commit-queue when red)
+ https://bugs.webkit.org/show_bug.cgi?id=33289
+
+ Add Tiger and SnowLeopard Tests to the core builders. This is a bit of
+ an experiment now that the bots are green. Hopefully we can keep them
+ on the list and have the tree stay greener.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+
+2010-04-02 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Have Eric and Adam watch the SheriffBot
+ https://bugs.webkit.org/show_bug.cgi?id=37054
+
+ * Scripts/webkitpy/tool/bot/sheriff.py:
+ * Scripts/webkitpy/tool/bot/sheriff_unittest.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+
+2010-04-02 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ commit-queue should ignore builders when landing rollouts
+ https://bugs.webkit.org/show_bug.cgi?id=37051
+
+ When we moved the "builders are red" check into the master process, we
+ forgot about rollouts. I thought we had a test covering this case, but
+ looking at the test, it was a bit too loose. I added a new test and
+ introduced some new logging technology into MockTool to make the test
+ tighter.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-04-02 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ sherrifbot should ensure that the rollout reason doesn't start with - (and fix webkit-patch upload).
+ https://bugs.webkit.org/show_bug.cgi?id=37030
+
+ * Scripts/webkitpy/tool/bot/sheriff.py: Ensure that the rollout reason doesn't
+ start with -.
+ * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py: A test with a rollout
+ reason which starts with -.
+ * Scripts/webkitpy/tool/steps/createbug.py: Fix webkit-patch upload.
+
+2010-04-02 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Unreviewed.
+
+ Fixed check-webkit-style to recognize the short form of the
+ --verbose option, as stated in --help.
+
+ * Scripts/check-webkit-style:
+ - Tweaked one line.
+
+2010-04-02 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix for DumpRenderTree after addition of layerTreeAsText.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::layerTreeAsText):
+
+2010-04-02 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ Accept XHTML-MP content type as XHTML content
+ https://bugs.webkit.org/show_bug.cgi?id=34262
+
+ Register xhtmlmp file extension as the new type
+ for XHTML-MP test content.
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitpy/layout_tests/layout_package/test_files.py:
+ * Scripts/webkitpy/layout_tests/port/lighttpd.conf:
+
+2010-04-02 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ create-rollout doesn't fill out ChangeLog
+ https://bugs.webkit.org/show_bug.cgi?id=37010
+
+ The contract between apply_reverse_diff and PrepareChangeLogForRevert
+ was unclear. I broke filling out the ChangeLog during rollout earlier
+ when I changed apply_reverse_diff to revert the ChangeLogs because
+ PrepareChangeLogForRevert thought that it was supposed to do that.
+ I've now taught PrepareChangeLogsForRevert the new contract.
+
+ It's unclear to me how to test this change because it's essentially an
+ integration issue that requires the file system. At some point we
+ should think about a testing strategy for integration. As the system
+ becomes larger, we're running into more of these issues.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/tool/steps/preparechangelogforrevert.py:
+
+2010-04-02 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add cr-win-ews to QueueStatusServer
+ https://bugs.webkit.org/show_bug.cgi?id=37004
+
+ * QueueStatusServer/model/queues.py:
+ * QueueStatusServer/templates/dashboard.html:
+ * QueueStatusServer/templates/statusbubble.html:
+
+2010-04-02 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Unit-test networktransaction.py's log messages, and add a base
+ class to make unit-testing log messages even easier.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36958
+
+ The purpose of this patch is also to provide a mini-tutorial on
+ how to unit-test Python logging.py messages.
+
+ * Scripts/webkitpy/common/net/networktransaction_unittest.py:
+ - Unit-tested the log messages in test_retry().
+
+ * Scripts/webkitpy/common/system/logtesting.py:
+ - Adjusted the LogTesting class by moving the code that clears
+ the array of log messages into a finally block. This prevents
+ redundant AssertionErrors from getting rendered to the screen
+ while running unit tests.
+ - Added a LoggingTestCase class so the setUp() and tearDown()
+ methods do not need to be implemented in order to test logging.
+ Rather, TestCase classes can simply inherit from this class.
+
+2010-04-02 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Re-wrote check-webkit-style's argument parsing code to use
+ Python's optparser module and more uniform error-handling logic.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34676
+
+ * Scripts/webkitpy/style/optparser.py:
+ - Removed "option help" from check-webkit-style's usage string
+ since that is provided separately by the OptionParser class.
+ - Also changed the usage string from a function to a constant
+ string _USAGE.
+ - Added an _EPILOG string which renders after OptionParser's
+ usage string and option help.
+ - In the ArgumentParser class:
+ - Changed the constructor's stderr_write parameter to a
+ mock_stderr since the OptionParser accepts a sys.stderr
+ substitute rather than a sys.stderr.write substitute.
+ - Changed the constructor to set a _parser data attribute with
+ an OptionParser instance.
+ - Added a _create_option_parser() method which instantiates
+ the OptionParser.
+ - Updated _exit_with_help() to interact with the OptionParser's
+ help method.
+ - Updated the parse() method as necessary. Also changed the
+ raising of ValueErrors to calls to _exit_with_help().
+
+ * Scripts/webkitpy/style/optparser_unittest.py:
+ - Removed the CreateUsageTest class since the create_usage method
+ was replaced by a constant string.
+ - Added a _MockStdErr class to the ArgumentParserTest class.
+ - Updated the unit tests as necessary.
+
+
+2010-04-02 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ The master commit-queue process should take responsibility for checking that the builders are green
+ https://bugs.webkit.org/show_bug.cgi?id=37009
+
+ We had a failure where the child process noticed that the builders were
+ red. We've always had this race condition, but the new optimistic
+ design made it easier to trigger.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-04-02 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Tweak rollout changelog to pass ValidateReviewer check
+ https://bugs.webkit.org/show_bug.cgi?id=37019
+
+ We need to use the magic word "unreviewed" to make the commit-queue
+ happy when landing rollouts.
+
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ * Scripts/webkitpy/common/checkout/changelog_unittest.py:
+
+2010-04-02 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Unreviewed.
+
+ Removed duplicate ChangeLog entry.
+
+2010-04-02 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Rubber-stamped by Eric Seidel.
+
+ To the Python 2.4 error message, added a link to the wiki page
+ that contains instructions on how to upgrade.
+
+ * Scripts/test-webkitpy:
+ - Eliminated a use of the ternary operator in configure_logging()
+ to let the version warning display in case of Python 2.4.
+
+ * Scripts/webkitpy/python24/versioning.py:
+ - Added this link to the error text:
+ http://trac.webkit.org/wiki/PythonGuidelines
+
+ * Scripts/webkitpy/python24/versioning_unittest.py:
+ - Updated unit test text.
+
+2010-04-02 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Record the IRC nick of folks who request rollouts
+ https://bugs.webkit.org/show_bug.cgi?id=36999
+
+ * Scripts/webkitpy/common/net/irc/ircbot.py:
+ * Scripts/webkitpy/tool/bot/irc_command.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py:
+
+2010-04-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add cr-win-ews
+ https://bugs.webkit.org/show_bug.cgi?id=36974
+
+ Adds support for an Early Warning System for Chromium on Linux. The
+ interface to the Chromium port is the same on every platform, so we
+ don't need to create a new Port object for this queue.
+
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+
+2010-04-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Using a failure exit code when failing to load a required import
+ https://bugs.webkit.org/show_bug.cgi?id=37000
+
+ Well spotted by Mark Rowe.
+
+ * Scripts/webkitpy/common/system/user.py:
+
+2010-04-01 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Rewrote the revision (r56942) to disable the 79 character line
+ length limit Python/PEP8 style check.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33639#c39
+
+ This rewrite puts the disabling not in the PythonProcessor but
+ in the calling code's default filter rule configuration. This
+ allows the user to check line-length style from the command-line
+ if desired.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added "-pep8/E501" to the _BASE_FILTER_RULES configuration
+ variable to disable the line-length check.
+ - Added "-pep8/E501" to the list of recognized style categories
+ to permit the category to be checked from the command line.
+
+ * Scripts/webkitpy/style/processors/python.py:
+ - Reverted r56942: http://trac.webkit.org/changeset/56942
+
+2010-04-01 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Dmitry Titov.
+
+ Add FileThread for async file operation support in FileReader and FileWriter
+ https://bugs.webkit.org/show_bug.cgi?id=36896
+
+ Add options to enable FILE_READER and FILE_WRITER support.
+
+ * Scripts/build-webkit:
+
+2010-04-01 Kent Tamura <tkent@chromium.org>
+
+ Unreviewed. Add missing license header.
+
+ * DumpRenderTree/chromium/TestShellMac.mm:
+
+2010-04-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Improve the error handling in rollout a bit
+ https://bugs.webkit.org/show_bug.cgi?id=36995
+
+ This patch does a few things to make the error handling in rollout a
+ bit more robust.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ The old logic here was wrong. We don't want to resolve the
+ ChangeLogs (that would remove the old ChangeLog entry). Instead,
+ we want to revert the ChangeLogs so we can fill them with the new
+ message.
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ Update test expectations because we're using a different mock object.
+ * Scripts/webkitpy/tool/commands/download.py:
+ - Added an update command to make updating from the SheriffBot more
+ robust.
+ - Now that we have CommitInfo, we can automatically CC the
+ responsible parties on the bug we create.
+ - Re-ordered the steps in create-rollout. Our original thinking
+ was that we always wanted to create the bug, but that's not
+ really true given how things appear to be playing out. If we
+ fail to apply the reverse diff, we don't want to create the bug.
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ - Use the new, more robust update command.
+ * Scripts/webkitpy/tool/steps/createbug.py:
+ Allow commands to pre-load who they want to be CCed on a new bug.
+
+2010-04-01 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Add TestShell and WebViewHost class, main(), and so on
+ https://bugs.webkit.org/show_bug.cgi?id=36814
+
+ This change introduces:
+ - WebViewHost class
+ It's an implementation of some delegates required by Chromium
+ WebKit API, and manages painting of a WebView. It's base on
+ src/webkit/tools/test_shell/test_webview_delegate.{cc,h} of
+ Chromium rev.40492.
+ - TestShell class
+ The TestShell instance holds global states of DumpRenderTree process.
+ Unlike TestShell class of Chromium test_shell, TestShell instance is
+ created just once.
+ - DumpRenderTree.cpp
+ The program entry.
+
+ * DumpRenderTree/chromium/DumpRenderTree.cpp: Added.
+ * DumpRenderTree/chromium/TestShell.cpp: Added.
+ * DumpRenderTree/chromium/TestShell.h: Added.
+ * DumpRenderTree/chromium/TestShellMac.mm: Added.
+ * DumpRenderTree/chromium/WebViewHost.cpp: Added.
+ * DumpRenderTree/chromium/WebViewHost.h: Added.
+ * DumpRenderTree/chromium/config.h: Added.
+
+2010-04-01 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ sheriffbot rollout should verify that the svn revision is a number.
+ https://bugs.webkit.org/show_bug.cgi?id=37001
+
+ * Scripts/webkitpy/common/net/bugzilla.py: Allow for the message to be None.
+ * Scripts/webkitpy/tool/bot/sheriff.py: Did verification that svn revision
+ is a number. Fixed the imports (since the files uses ScriptError and log)
+ and a typo.
+ * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py: Added a test to verify
+ the behavior.
+
+2010-04-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Print an error message for readline bogosity in MacPorts
+ https://bugs.webkit.org/show_bug.cgi?id=36979
+
+ * Scripts/webkitpy/common/system/user.py:
+
+2010-04-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Don't pass --non-interactive to create-rollout
+ https://bugs.webkit.org/show_bug.cgi?id=36989
+
+ It turns out you can't pass --non-interactive to create-rollout. Also,
+ improve our error reporting slighly to catch the case where we error
+ out after creating the rollout bug.
+
+ * Scripts/webkitpy/tool/bot/irc_command.py:
+ * Scripts/webkitpy/tool/bot/sheriff.py:
+
+2010-04-01 Ojan Vafai <ojan@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch can incorrectly think the working directory is modified
+ https://bugs.webkit.org/show_bug.cgi?id=36985
+
+ If a file's modification time is modified, but the contents are not,
+ then diff-index will think the file has been modified unless you do
+ some crazy update-index call. Instead, call diff --name-only, which
+ has the index update builtin.
+
+ Tried to write a test, but could not reproduce this in a unittest.
+ To test manually:
+ touch file-in-repo
+ git diff-index HEAD
+ git diff HEAD --name-only
+
+ The diff-index call incorrectly shows file-in-repo as modified.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+
+2010-04-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add rollout command to sheriffbot
+ https://bugs.webkit.org/show_bug.cgi?id=36986
+
+ This IRC command creates a new bug an attaches a rollout patch. To
+ actually commit the rollout, a committer needs to mark the patch
+ commit-queue+ in bugs.webkit.org.
+
+ Also, factored out some of the logic from the queue into a separate
+ object for easier testing.
+
+ * Scripts/webkitpy/common/system/executive.py:
+ * Scripts/webkitpy/tool/bot/irc_command.py:
+ * Scripts/webkitpy/tool/bot/sheriff.py: Added.
+ * Scripts/webkitpy/tool/bot/sheriff_unittest.py: Added.
+ * Scripts/webkitpy/tool/bot/sheriffircbot.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+
+2010-04-01 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, only ignoring chatty style errors.
+
+ check-webkit-style: WebKit needs a python style checker
+ https://bugs.webkit.org/show_bug.cgi?id=33639
+
+ Remove the 79 char line limit by ignoring
+ pep8/E501. Because we have our own report_error
+ implementation we have to ignore E501 by hand
+ instead of passing --ignore=E501.
+
+ Right now over 1400 lines of our existing python
+ fail E501 so this rule just generates needless noise.
+ The rest of WebKit has no wrapping rule so it makes
+ little sense for our Python to differ here.
+
+ * Scripts/webkitpy/style/processors/python.py:
+
+2010-04-01 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Add cmarrin's IRC nickname.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-01 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ EWS spins hot when unable to build
+ https://bugs.webkit.org/show_bug.cgi?id=36981
+
+ The problem is that the queue engine things we have more work to do,
+ but the bot isn't actually able to do anything. After this change, we
+ back off the usual amount.
+
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/bot/queueengine_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+
+2010-04-01 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ Added layerTreeAsText function to DRT (for Mac)
+ https://bugs.webkit.org/show_bug.cgi?id=36782
+
+ This is the DRT side. It exposes the call to JavaScript
+ through the LayoutTestController.
+
+ * DumpRenderTree/LayoutTestController.cpp:Platform independent JavaScript shim
+ (layerTreeAsTextCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:Mac specific plumbing to WebKit
+ (LayoutTestController::layerTreeAsText):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:Windows specific plumbing to WebKit
+ (LayoutTestController::layerTreeAsText):
+
+2010-04-01 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after addition of JavaScriptCore/wtf/text directory.
+
+ * wx/build/settings.py:
+
+2010-04-01 Jian Li <jianli@chromium.org>
+
+ Rubber-stamped by David Levin.
+
+ Add myself to the reviewers list.
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-01 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Turns out the Chromium Windows bots don't have pdevenv installed.
+
+ * Scripts/webkitdirs.pm:
+
+2010-04-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Let Chromium Windows build with Visual Studio Express
+ https://bugs.webkit.org/show_bug.cgi?id=36919
+
+ This is horrible, horrible copy/paste code, but that seems to be the
+ way of webkitdirs.pm. :(
+
+ Someone needs to go through an cleanup this code, but I don't have the
+ heart to do it in this patch.
+
+ * Scripts/webkitdirs.pm:
+
+2010-04-01 Ilya Tikhonovsky <loislo@chromium.org>
+
+ Reviewed by Yury Semikhatsky.
+
+ Add myself to the committers list.
+ https://bugs.webkit.org/show_bug.cgi?id=36953
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-04-01 Eric Seidel <eric@webkit.org>
+
+ Rubber-stamped by Adam Barth.
+
+ Add Snow Leopard Release bot to the list of "core builders" (builders which stop the commit-queue when they turn red)
+ https://bugs.webkit.org/show_bug.cgi?id=33292
+
+ Just adding the "Build" builder for now.
+ We'll add the "Test" builders when the tests
+ are less flaky.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+
+2010-04-01 Yury Semikhatsky <yurys@chromium.org>
+
+ Reviewed by David Levin.
+
+ Add myself to the reviewers list.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36935
+
+ * Scripts/webkitpy/common/config/committers.py:
+
+2010-03-31 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Dave Levin.
+
+ Added Python style checking to check-webkit-style using
+ the third-party pep8 module (via autoinstall).
+
+ https://bugs.webkit.org/show_bug.cgi?id=33639
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added PYTHON to FileType.
+ - Updated ProcessorDispatcher to return a PythonProcessor
+ for *.py files.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated the ProcessorDispatcher unit tests for *.py files.
+
+ * Scripts/webkitpy/style/processors/python.py: Added.
+ - Added PythonProcessor class.
+
+ * Scripts/webkitpy/style/processors/python_unittest.py: Added.
+ - Added PythonProcessor unit tests.
+
+ * Scripts/webkitpy/style/processors/python_unittest_input.py: Added.
+ - Added a sample Python file to test the PythonProcessor.process()
+ code path (since pep8 accepts a file path).
+
+ * Scripts/webkitpy/style/unittests.py:
+ - Updated the style unit test file to import python_unittest.py.
+
+ * Scripts/webkitpy/style_references.py:
+ - Adjusted style references to import pep8.
+
+2010-03-31 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Dave Levin.
+
+ Rewrote autoinstall.py to support unzipping *.zip files after
+ download, unzipping and extracting *.tar.gz files after download,
+ and copying installed files to a given destination directory.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35163
+
+ These changes will let us autoinstall pep8.py from the web and put
+ our third-party autoinstalled code in an explicit directory like
+ webkitpy/thirdparty/autoinstalled. These changes should also speed
+ up the execution of autoinstalled *.zip packages slightly since
+ *.pyc files cannot be generated when importing from zipped
+ packages using the current autoinstall.
+
+ * Scripts/test-webkitpy:
+ - Addressed the FIXME to enable auto-install logging once
+ autoinstall was rewritten not to log as verbosely.
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ - Updated mechanize import statement.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ - Updated mechanize import statement.
+
+ * Scripts/webkitpy/common/net/irc/ircbot.py:
+ - Updated ircbot and irclib import statements.
+
+ * Scripts/webkitpy/common/net/networktransaction.py:
+ - Updated mechanize import statement.
+
+ * Scripts/webkitpy/common/net/networktransaction_unittest.py:
+ - Updated mechanize import statement.
+
+ * Scripts/webkitpy/common/net/statusserver.py:
+ - Updated mechanize import statement.
+
+ * Scripts/webkitpy/common/system/autoinstall.py: Added.
+ - Added AutoInstaller class.
+ - Added sample/testing usage to the __main__ block.
+
+ * Scripts/webkitpy/thirdparty/__init__.py:
+ - Updated the autoinstall lines to use the new autoinstall methods.
+ - Added pep8.py to the list of auto-installed packages.
+ - Added a README file to the target autoinstallation directory
+ so users know that the directory is safe to delete.
+
+ * Scripts/webkitpy/thirdparty/autoinstall.py: Removed.
+ - This is replaced by the rewritten autoinstall
+ webkitpy/common/system/autoinstall.py.
+
+ * Scripts/webkitpy/thirdparty/autoinstalled/__init__.py: Removed.
+ - The target autoinstallation directory is now auto-generated.
+
+2010-03-31 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Tweak webkitpy's logtesting.LogTesting class to get more mileage out
+ of our unit tests that test log messages.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36886
+
+ This patch adds to the LogTesting class's tearDown() method a line
+ asserting that the array of remaining log messages is empty. This
+ ensures that no extra log messages are getting logged that the caller
+ might not be aware of or may have forgotten to check for.
+
+ * Scripts/webkitpy/common/system/logtesting.py:
+ - Modified the tearDown() method as described above.
+ - Also modified the assertMessages() method to clear the array
+ of log messages after asserting.
+
+2010-03-31 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Added support for a --verbose-logging flag to test-webkitpy.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36429
+
+ Verbose logging is useful for debugging test-webkitpy code that
+ runs before the actual unit tests -- things like autoinstalling and
+ unit-test auto-detection logic. This is different from verbose
+ logging of the unit tests themselves (which corresponds to the
+ unittest module's --verbose flag).
+
+ * Scripts/test-webkitpy:
+ - In the configure_logging() method--
+ - Added an is_verbose_logging parameter that sets the logging
+ level to logging.DEBUG instead of logging.INFO.
+ - Changed the method to throttle the logging level on the
+ root logger's handler instead of directly on the root logger
+ itself.
+ - Enabled logging of the autoinstall module when the flag is set.
+
+ * Scripts/webkitpy/thirdparty/autoinstalled/__init__.py:
+ - Added a work-around for a bug in Python 2.6's logging module
+ that was discovered while working on this patch.
+
+2010-03-31 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Enabled Python's logging module for webkit-patch, and replaced
+ deprecated_logging with Python logging in networktransaction.py.
+ This eliminates some spurious output when running test-webkitpy.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36725
+
+ * Scripts/webkit-patch:
+ - Replaced the configure_logging() function with a call to
+ the new logutils.configure_logging() function.
+
+ * Scripts/webkitpy/common/net/networktransaction.py:
+ - Replaced the use of deprecated_logging with Python logging.
+
+ * Scripts/webkitpy/common/system/logutils.py:
+ - Added _default_handlers() which creates the default logging
+ handler for webkitpy.
+ - Added configure_logging() which configures default logging
+ for webkitpy.
+
+ * Scripts/webkitpy/common/system/logutils_unittest.py:
+ - Added unit tests for logutils.configure_logging().
+
+ * Scripts/webkitpy/style/checker.py:
+ - Refactored check-webkit-style's configure_logging() method
+ to call the new logutils.configure_logging().
+
+ * Scripts/webkitpy/style_references.py:
+ - Updated references as necessary.
+
+2010-03-31 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch land fails if not run from the root directory
+ https://bugs.webkit.org/show_bug.cgi?id=35822
+
+ The root of the problem was that ChangeLog.__init__ expects a path
+ relative to the current working directory, and SCM expects to
+ return paths relative to the SCM root. Fix it by converting from
+ SCM-relative to absolute paths in Checkout.modified_changelogs
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+
+2010-03-31 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add more tests for webkitpy.common.checkout
+ https://bugs.webkit.org/show_bug.cgi?id=36926
+
+ We don't have a great way of testing checkout, sadly.
+
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+
+2010-03-31 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ REGRESSION: EWS crashes on failure
+ https://bugs.webkit.org/show_bug.cgi?id=36924
+
+ Turns out we need to pass one more argument. My test is kind of lame,
+ but at least it's there.
+
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+
+2010-03-31 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Unreviewed.
+
+ Fixed typo in WebKitTools/ChangeLog: opsys -> ospath.
+
+2010-03-31 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Make the EWS go faster by being optimistic
+ https://bugs.webkit.org/show_bug.cgi?id=36916
+
+ Have the EWS be optimistic that a patch will correctly build. This
+ should speed up the common case by not requiring two builds for every
+ patch.
+
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-03-31 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add the ability to restart sheriffbot from IRC
+ https://bugs.webkit.org/show_bug.cgi?id=36909
+
+ * Scripts/webkitpy/tool/bot/irc_command.py:
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py:
+
+2010-03-31 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add win-ews to QueueStatusServer
+ https://bugs.webkit.org/show_bug.cgi?id=36876
+
+ The win-ews is still experimental, but it seems to be more or less
+ running. We should show its results to the people.
+
+ * QueueStatusServer/model/queues.py:
+ * QueueStatusServer/templates/dashboard.html:
+ * QueueStatusServer/templates/statusbubble.html:
+
+2010-03-30 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Update rebaseline tool to check the release image diff binary and
+ fallback to debug if the release version does not exist.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36245
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-03-31 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Teach buildbot.py how to parse builder activity from /one_box_per_builder
+ https://bugs.webkit.org/show_bug.cgi?id=36898
+
+ I also removed some obsolete FIXMEs and
+ refactored one_box_per_builder parsing into multiple
+ methods for easier reading.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/buildbot_unittest.py:
+
+2010-03-31 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix logging in new-run-webkit-tests so that we don't report IMAGE
+ expected failures as unexpected passes when we run with pixel tests
+ disabled.
+
+ This change splits some of the logic embedded into the TestExpectations
+ classes out into separate pure functions (result_was_expected,
+ remove_image_failures) to make them easier to test. This also adds
+ a parameter to matches_an_expected_result() to indicate whether or
+ not pixel test results should be included in the expectations.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36771
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_test.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-03-31 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ In webkitpy, refactored two calls to os.path.relpath() replacements
+ to use a common method.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36891
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ - Replaced the relpath implementation with a call to
+ webkitpy.common.system.ospath.relpath().
+
+ * Scripts/webkitpy/common/system/ospath.py: Added.
+ - Moved the relpath() implementation from style/main.py.
+
+ * Scripts/webkitpy/common/system/ospath_unittest.py: Added.
+ - Moved the relpath() unit tests from style/main_unittest.py.
+
+ * Scripts/webkitpy/style/main.py:
+ - Replaced the relpath implementation with a call to
+ webkitpy.common.system.ospath.relpath().
+
+ * Scripts/webkitpy/style/main_unittest.py:
+ - Moved the relpath unit tests to ospath_unittest.py.
+
+2010-03-31 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add a Builder.force_build method
+ https://bugs.webkit.org/show_bug.cgi?id=36875
+
+ We plan to eventually use this in SheriffBot to break deadlocks created
+ by flaky tests.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+
+2010-03-31 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch reads wrong bug url from unified diff context
+ https://bugs.webkit.org/show_bug.cgi?id=36477
+
+ Instead of trying to figure out the bug_id from the diff, we should
+ just get the information from the Checkout object, which understands
+ these concepts.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/commitinfo.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-03-31 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch commit-queue should land patches optimistically
+ https://bugs.webkit.org/show_bug.cgi?id=34187
+
+ This patch adds an optimistic path to commit-queue and a "fail twice"
+ requirement for rejecting patches. That means we'll land good patches
+ faster (via the optmistic first run) and we'll reject many fewer
+ patches due to flaky tests.
+
+ * Scripts/webkitpy/tool/commands/queues.py:
+
+2010-03-31 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Custom user agent for user agent switcher
+ https://bugs.webkit.org/show_bug.cgi?id=36757
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::showUserAgentDialog):
+
+2010-03-31 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ path to committers.py in commit-queue rejection message is wrong
+ https://bugs.webkit.org/show_bug.cgi?id=36865
+
+ This fix would have only been 3 lines long if we had
+ 1. Had access to an SCM object or tool to give us the checkout root
+ 2. Been able to depend on Python 2.6
+ Instead I've added a bunch of hack code, but at least now
+ we should never have to update this string again as the location
+ of committers.py is fully dynamically discovered. :p
+
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+
+2010-03-31 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Unreviewed test fix for r56809.
+
+ webkit-patch what-broke throws exception
+ https://bugs.webkit.org/show_bug.cgi?id=36852
+
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+
+2010-03-30 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Rubber stamped by Dave Levin.
+
+ Made check-webkit-style less chatty.
+
+ Examples include:
+ - https://bugs.webkit.org/show_bug.cgi?id=36866#c4
+ - https://bugs.webkit.org/show_bug.cgi?id=36472#c9
+
+ * Scripts/webkitpy/style/checker.py:
+ - Changed unrecognized file type log message from info to debug.
+
+2010-03-30 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after new method added.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::callShouldCloseOnWebView):
+
+2010-03-30 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch what-broke throws exception
+ https://bugs.webkit.org/show_bug.cgi?id=36852
+
+ * Scripts/webkitpy/common/checkout/api.py: Add missing import StringIO.
+ * Scripts/webkitpy/common/checkout/api_unittest.py: Test the function which previously threw and exception.
+
+2010-03-30 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36616
+ Dvorak-Qwerty keyboard layout gives unexpected results in javascript keydown
+
+ https://bugs.webkit.org/show_bug.cgi?id=36797
+ For non-Roman layouts, keydown Event.keyCode is always 0
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController keyDown:withModifiers:withLocation:]): Generate a correct keyCode
+ for keys used in tests (we used to always pass 0 for 'A').
+
+2010-03-30 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Implement win-ews
+ https://bugs.webkit.org/show_bug.cgi?id=36809
+
+ * Scripts/webkitpy/common/config/ports.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+
+2010-03-30 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Adjusted test-webkitpy to delete all orphaned *.pyc files
+ from webkitpy/ prior to importing any modules from webkitpy.
+ This ensures that no import statements in webkitpy falsely
+ succeed because of leftover *.pyc files.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36599
+
+ * Scripts/test-webkitpy:
+ - Added _clean_pyc_files() to delete orphaned *.pyc files
+ from a directory.
+ - Added _clean_webkitpy_with_test() to call and test
+ _clean_pyc_files().
+ - Moved the "import webkitpy.python24.versioning" statement
+ from the top of the module to the init() method -- immediately
+ after the call to _clean_webkitpy_with_test().
+
+2010-03-30 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ [Chromium-Win] subprocess.call should be called with stdin=open(os.devnull,'r')
+ https://bugs.webkit.org/show_bug.cgi?id=36811
+
+ subproess.Popen() on Python 2.4/Windows with stdout,stdout, but no stdin will fail, because it uses return value of GetStdHandle(STD_INPUT_HANDLE), but DuplicateHandle requires integer, not the handle.
+ We don't need stdin, so use devnull as stdin.
+ Same as https://bugs.webkit.org/show_bug.cgi?id=36586
+
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py: open os.devnull for stdin
+
+2010-03-29 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, build fix only.
+
+ * Scripts/webkitpy/tool/steps/validatereviewer.py: Add missing import.
+
+2010-03-29 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Remove '_flymake' suffix from base part of file name so that
+ check-webkit-style uses a correct header guard name when it is called from Emacs's flymake.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36573
+
+ * Scripts/webkitpy/style/processors/cpp.py:
+ * Scripts/webkitpy/style/processors/cpp_unittest.py:
+
+2010-03-29 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Get the following test-webkitpy unit test working again:
+ scm_unittest.SVNTest.test_svn_apply().
+
+ https://bugs.webkit.org/show_bug.cgi?id=36696
+
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ - Add leading spaces to the empty lines of the ChangeLog strings.
+ - Manually set the _reviewer attribute on the Attachment object
+ to get the tests to pass.
+
+2010-03-29 Martin Robinson <mrobinson@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [GTK] suppress (un)desired launcher output that can make layout test to fail with stderr
+ https://bugs.webkit.org/show_bug.cgi?id=36390
+
+ Suppress debugging messages sent to the GLib logger during DRT runs.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (logHandler): Added.
+ (main): Use logHandler as the default GLib log message handler.
+
+2010-03-29 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ sheriff-bot should comment on bugs when builders break
+ https://bugs.webkit.org/show_bug.cgi?id=36786
+
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ - Add a new _post_blame_comment_to_bug and all it from process_work_item
+ - Move commit-queue logic into _post_rollout_patch to make its api match the other _post commands.
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+ - Test the new _post_blame_comment_to_bug call
+
+2010-03-29 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ sheriff-bot fails to get information about certain builds
+ https://bugs.webkit.org/show_bug.cgi?id=36768
+
+ This seems to be caused by:
+ http://buildbot.net/trac/ticket/753
+ I have no work-around, but for now at least we're logging
+ the error better. I also added allow_none to our ServerProxy
+ creation in case that fixes things for other versions of python.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+
+2010-03-29 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Add sign in/out link to TestResults appengine
+
+ Add a link to main menu for sign in/out to this appengine.
+ People signed in with admin privilege could perform
+ actions that are only allowed to admins like deleting files.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36767
+
+ * TestResultServer/handlers/menu.py:
+ * TestResultServer/stylesheets/menu.css:
+ (.sign):
+ * TestResultServer/templates/menu.html:
+
+2010-03-29 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ ValidateReviewer step is draconian and un-tested
+ https://bugs.webkit.org/show_bug.cgi?id=36792
+
+ ValidateReviewer logic was commented out in
+ http://trac.webkit.org/changeset/56744
+ That was a symptom of the fact that validatereviewer.py
+ is too inflexible to be used when real humans are driving webkit-patch.
+ For now we just disable ValidateReviewer when humans are at the keyboard.
+
+ * Scripts/webkitpy/tool/steps/validatereviewer.py:
+ - Only run when in non-interactive mode.
+ * Scripts/webkitpy/tool/steps/validatereviewer_unittest.py: Added.
+ - Test our validation logic to make sure it's sane.
+
+2010-03-29 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Eliminate explicit slash characters from check-webkit-style's
+ _rel_path() method to make its implementation more platform
+ independent.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36759
+
+ * Scripts/webkitpy/style/main.py:
+ - Changed to use os.sep instead of slash_chars "/\\". This can
+ be done since os.path.abspath() converts slashes to os.sep.
+
+2010-03-29 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Change new-run-webkit-tests to not use more than four threads by
+ default on the mac port until
+ https://bugs.webkit.org/show_bug.cgi?id=36622 is fixed.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36687
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+
+2010-03-29 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Reformat port/mac.py to fit witin 80 columns for PEP-8 compliance.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36691
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+
+2010-03-29 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests fails java/lc3 on a clean checkout
+ https://bugs.webkit.org/show_bug.cgi?id=36078
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ - Build the java support files in check_build
+ - Unwrap a line which would still fit under 80col
+
+2010-02-26 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Fraser.
+
+ Add support for Widgets 1.0: View Mode Media Feature
+ https://bugs.webkit.org/show_bug.cgi?id=35446
+
+ Add hooks to the Qt DRT for testing the view mode media feature.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setViewModeMediaFeature):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-03-29 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Update expected results for unit tests.
+
+ * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+
+2010-03-29 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. I think Eric meant svn_revision.
+
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+
+2010-03-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch commit-queue should notice if it breaks builders (and roll out its own changes)
+ https://bugs.webkit.org/show_bug.cgi?id=29311
+
+ Now that we have sheriff-bot watching the tree, it can post
+ rollout patches on behalf of the commit queue.
+
+ * Scripts/webkitpy/common/checkout/commitinfo.py: add responsible_parties()
+ * Scripts/webkitpy/common/checkout/commitinfo_unittest.py: test responsible_parties()
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ - Break IRC logic out into _post_irc_warning for easier testing.
+ - Add _post_rollout_patch for posting rollout patches to bugzilla.
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+ - Test _rollout_reason
+ * Scripts/webkitpy/tool/grammar.py:
+ - Fix join_with_separators to not add Adam's "oxford comma" for two item lists.
+ * Scripts/webkitpy/tool/grammar_unittest.py:
+ - Test join_with_separators
+
+2010-03-29 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Sheriffbot should actually run commands
+ https://bugs.webkit.org/show_bug.cgi?id=36776
+
+ Some minor changes to Sheriffbot:
+
+ 1) We should actually run commands (by giving control back to the
+ command processing object.
+
+ 2) Use URLs instead of just numbers to represent SVN revisions (making
+ it easier to folks in IRC ot followup).
+
+ * Scripts/webkitpy/tool/bot/irc_command.py:
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+
+2010-03-26 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Antti Koivisto.
+
+ Renaming of frame flattening LayoutTestController method
+ to setFrameFlatteningEnabled(bool)
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setFrameFlatteningEnabledCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setFrameFlatteningEnabled):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setFrameFlatteningEnabled):
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setFrameFlatteningEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setFrameFlatteningEnabled):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setFrameFlatteningEnabled):
+
+2010-03-28 Gustavo Noronha Silva <gns@gnome.org>
+
+ No review, rolling out r56679.
+ http://trac.webkit.org/changeset/56679
+ https://bugs.webkit.org/show_bug.cgi?id=36454
+
+ Lots of tests broken.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (createWebView):
+
+2010-03-28 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Unreviewed.
+
+ Fixed typo in deprecated_logging_unittest.py, which is masking
+ sys.stderr while running test-webkitpy.
+
+ See also-- https://bugs.webkit.org/show_bug.cgi?id=36725#c3
+
+ * Scripts/webkitpy/common/system/deprecated_logging_unittest.py:
+
+2010-03-28 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Renamed check-webkit-style's --debug flag to --verbose to be more
+ in line with other WebKit scripts. Also renamed the current
+ --verbose flag to --min-confidence to allow the --debug rename.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36521
+
+ We also renamed the internal "verbose" variables to "confidence" or
+ "min_confidence," as appropriate, to avoid confusion with the
+ --verbose flag, and because the new names are more accurate.
+
+ * Scripts/check-webkit-style:
+ - Renamed is_debug to is_verbose.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Renamed _DEFAULT_VERBOSITY to _DEFAULT_CONFIDENCE.
+ - Renamed "verbosity" parameters to "min_confidence" throughout.
+ - Renamed configure_logging()'s is_debug parameter to is_verbose.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated the unit tests as necessary.
+
+ * Scripts/webkitpy/style/error_handlers.py:
+ - Updated the call to StyleCheckerConfiguration.write_style_error().
+
+ * Scripts/webkitpy/style/error_handlers_unittest.py:
+ - Updated the unit tests as necessary.
+
+ * Scripts/webkitpy/style/optparser.py:
+ - Updated the usage string with the new flag names.
+ - Renamed the verbosity parameter to min_confidence throughout.
+ - Renamed the is_debug parameter to is_verbose throughout.
+
+ * Scripts/webkitpy/style/optparser_unittest.py:
+ - Updated the unit tests as necessary.
+
+ * Scripts/webkitpy/style/processors/cpp.py:
+ - Renamed the verbosity parameter to min_confidence throughout.
+
+ * Scripts/webkitpy/style/processors/cpp_unittest.py:
+ - Updated the unit tests as necessary.
+
+2010-03-28 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Unreviewed.
+
+ Added back a line that accidentally got deleted in r56690.
+
+ * Scripts/check-webkit-style:
+
+2010-03-28 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Add to check-webkit-style support for checking directories.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35234
+
+ * Scripts/check-webkit-style:
+ - Replaced the call to check_file() with a call to check_paths().
+
+ * Scripts/webkitpy/style/checker.py:
+ - In the StyleChecker class:
+ - Added a check_paths() method that accepts a list of paths
+ to files and directories.
+ - Added a _check_directory() method that checks the files
+ in a directory.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Added a StyleCheckerCheckPathsTest to unit-test the new
+ check_paths() method.
+
+ * Scripts/webkitpy/style/optparser.py:
+ - Updated the usage string.
+
+2010-03-28 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Changed check-webkit-style to convert paths to paths relative to
+ the checkout root when invoking check-webkit-style with path
+ arguments. Also added warning messages where appropriate.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35498
+
+ Converting paths to paths relative to the checkout root ensures
+ that style checking will behave as expected (since path-specific
+ rules assume input paths are relative to a source root).
+
+ * Scripts/check-webkit-style:
+ - Added debug logging of whether the current directory was found
+ to be in a WebKit checkout.
+ - Added the found_checkout parameter to the call to parser.parse().
+ - Renamed the files variable to paths.
+ - Added a call to change_directory() prior to checking style.
+
+ * Scripts/webkitpy/style/checker.py:
+ - For StyleChecker.check_file():
+ - Updated the docstring.
+ - Added two log messages.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated a call to parser.parse() with the found_checkout parameter.
+
+ * Scripts/webkitpy/style/main.py: Added.
+ - Added a new file so the code in this patch could be unit-tested,
+ as opposed to adding new code to check-webkit-style.
+ - Added the method _rel_path() as a substitute for os.path.relpath(),
+ which is available only in Python 2.6.
+ - Added the method change_directory(), which contains most of the
+ new functionality in this patch.
+
+ * Scripts/webkitpy/style/main_unittest.py: Added.
+ - Added RelPathTest to test main._rel_path().
+ - Added ChangeDirectoryTest to test main.change_directory().
+
+ * Scripts/webkitpy/style/optparser.py:
+ - Updated check-webkit-style's usage string.
+ - For the ArgumentParser.parse() method:
+ - Added a found_checkout parameter.
+ - Renamed filenames to paths.
+ - Added logic so that an error is raised if no paths are passed
+ if found_checkout is False.
+
+ * Scripts/webkitpy/style/optparser_unittest.py:
+ - Updated the ArgumentParser.parse() unit tests to include
+ coverage for the new found_checkout parameter.
+
+ * Scripts/webkitpy/style/unittests.py:
+ - Added an import statement for main_unittest.
+
+ * Scripts/webkitpy/style_references.py:
+ - Renamed SimpleScm to WebKitCheckout.
+ - Added a detect_checkout() function to allow returning None
+ instead of a WebKitCheckout instance if no checkout is found.
+ - Renamed checkout_root to root_path.
+
+2010-03-27 Sergio Villar Senin <svillar@igalia.com>
+
+ Reviewed by Eric Seidel.
+
+ Print didHandleOnloadEventsForFrame in the callback of
+ onload-event signal comming from frame loader
+
+ [GTK] Improve reporting of frame loader callbacks in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=36454
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewOnloadEvent):
+ (createWebView): added connection to signal::onload-event and
+ signal callback
+
+2010-03-27 Sergio Villar Senin <svillar@igalia.com>
+
+ Reviewed by Eric Seidel.
+
+ Print didCommitLoadForFrame in the callback of signal::load-committed
+
+ [GTK] Improve reporting of frame loader callbacks in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=36454
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewLoadCommitted):
+ (createWebView): added connection to sinal::load-committed and
+ signal callback
+
+2010-03-27 Sergio Villar Senin <svillar@igalia.com>
+
+ Reviewed by Eric Seidel.
+
+ Print didStartProvisionalLoadForFrame in the callback of
+ notify::load-status property change notification
+
+ [GTK] Improve reporting of frame loader callbacks in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=36454
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webInspectorCloseWindow):
+ (webInspectorInspectWebView):
+ (createWebView): added connection to notify::load-status and
+ signal callback
+
+2010-03-27 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ In webkitpy/, deleted the /unittests.py files since test-webkitpy
+ now auto-detects all *_unittest.py files.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36712
+
+ * Scripts/webkitpy/common/net/irc/unittests.py: Removed.
+ * Scripts/webkitpy/common/system/unittests.py: Removed.
+ * Scripts/webkitpy/common/thread/unittests.py: Removed.
+ * Scripts/webkitpy/common/unittests.py: Removed.
+ * Scripts/webkitpy/python24/unittests.py: Removed.
+ * Scripts/webkitpy/style/unittests.py: Removed.
+ * Scripts/webkitpy/tool/unittests.py: Removed.
+ * Scripts/webkitpy/unittests.py: Removed.
+
+2010-03-27 Sergio Villar Senin <svillar@igalia.com>
+
+ Reviewed by Eric Seidel.
+
+ Add a CR after printing didFinishDocumentLoadForFrame
+
+ [GTK] Improve reporting of frame loader callbacks in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=36454
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewLoadFinished):
+
+2010-03-27 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Rubber-stamped by Adam Barth.
+
+ Fixed the name of a unit test file in webkitpy.
+
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittest.py: Copied from WebKitTools/Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittests.py.
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittests.py: Removed.
+
+2010-03-26 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ The test-webkitpy script now automatically detects all unit-test
+ files in webkitpy/. This lets us eliminate the need to have and
+ maintain all of the unittests.py files.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36591
+
+ * Scripts/test-webkitpy:
+ - Replaced the "from webkitpy.unittests import *" with a call
+ to webkitpy.test.main.Tester().run_tests().
+
+ * Scripts/webkitpy/test/__init__.py: Copied from WebKitTools/QueueStatusServer/filters/__init__.py.
+ - Required file for the new webkitpy/test/ directory.
+
+ * Scripts/webkitpy/test/main.py: Added.
+ - Added a Tester class that contains the following methods:
+ - _find_unittest_files() to detect all the unit-test files.
+ - _modules_from_paths() to convert the paths to the unit-test
+ files to fully-qualified module names.
+ - run_tests() which calls the above two methods and then passes
+ the module names to Python's unittest module.
+
+2010-03-27 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Simon Fraser.
+
+ [Qt/Win] Add support to unix and windows NS plugin for executing scripts on setWindow.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36701
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance): Add onSetWindow.
+ (webkit_test_plugin_destroy_instance): Add onSetWindow.
+ (webkit_test_plugin_set_window): Add onSetWindow.
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp:
+ (NPP_New): Add onSetWindow.
+ (NPP_Destroy): Add onSetWindow.
+ (NPP_SetWindow): Add onSetWindow.
+
+2010-03-26 Robert Hogan <robert@roberthogan.net>
+
+ Reviewed by Simon Hausmann.
+
+ Allow plugins implemented by the application, such as mimetype 'x-qt-plugin',
+ when pluginsEnabled is false.
+
+ Add support for LayoutTestController.WebKitPluginsEnabled
+
+ https://bugs.webkit.org/show_bug.cgi?id=32196
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (copyWebSettingKey):
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::overridePreference):
+
+2010-03-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add some basic IRC commands to sheriffbot
+ https://bugs.webkit.org/show_bug.cgi?id=36684
+
+ Adds support for sheriffbot to respond to a "hi" command and a
+ "last-green-revision" command. It's lame that we're rebuilding
+ MultiCommandTool, but as discussed in person we'll intergrate the two
+ once we see what the requirements are.
+
+ * Scripts/webkitpy/tool/bot/irc_command.py: Added.
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/bot/queueengine_unittest.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py: Added.
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/unittests.py:
+
+2010-03-26 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. More errors in the IRC module. I have no idea how to test
+ ircbot.py, which is too bad. Hopefully we've abstracted it away enough
+ that we don't have to touch it very much after this patch.
+
+ * Scripts/webkitpy/common/net/irc/ircbot.py:
+
+2010-03-26 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Add a missing "_".
+
+ * Scripts/webkitpy/common/net/irc/ircproxy.py:
+ * Scripts/webkitpy/common/net/irc/ircproxy_unittest.py: Added.
+ * Scripts/webkitpy/common/net/irc/unittests.py:
+
+2010-03-26 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Fix a the commit queue after my recent change.
+
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+
+2010-03-26 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed fix.
+
+ Fix the return value for port/base.diff_image (changed from 1/0 to
+ True/False in bug 34826.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+
+2010-03-26 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Change the Mac port of new-run-webkit-tests to look for a
+ test_expectations.txt file in addition to the Skipped files, so we
+ can track pixel failures.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36619
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+
+2010-03-26 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Implement pixel tests (image diff) properly on the Mac port.
+
+ This change introduces a new "ServerPocess" class that can be used
+ to manage processes that the run-webkit-tests harness forks off and
+ expects to stay up for longer than a single request/response session.
+ Both DumpRenderTree and ImageDiff use this style of communication,
+ although the current code forks off a new ImageDiff for each diff
+ (We need to restructure other parts of the code to be able to do this
+ safely in a multi-threaded environment).
+
+ Also, now that the ServerProcess abstraction exists, we can probably
+ clean up and simplify some of the thread management logic in
+ test_shell_thread as well.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34826
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/server_process.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+
+2010-03-26 Sergio Villar Senin <svillar@igalia.com>
+
+ Reviewed by Eric Seidel.
+
+ Print didFinishLoadForFrame outcome in DRT
+
+ [GTK] Improve reporting of frame loader callbacks in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=36454
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewLoadCommitted):
+
+2010-03-26 Eric Seidel <eric@webkit.org>
+
+ Unreviewed test fix.
+ My change conflicted with one of Adam's causing test-webkitpy to fail.
+
+ Move commit_message_for_this_commit from scm to checkout
+ https://bugs.webkit.org/show_bug.cgi?id=36629
+
+ * Scripts/webkitpy/common/checkout/api_unittest.py:
+ - modified_changelogs is now on Checkout instead of scm.
+
+2010-03-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Refactor IRCBot controller logic to allow for commands
+ https://bugs.webkit.org/show_bug.cgi?id=36676
+
+ We need to move the controller logic into the tool package so it can
+ know about commands. The changes to queueengine could go in a
+ different patch, but we're going to need it anyway.
+
+ * Scripts/webkitpy/common/config/irc.py: Added.
+ * Scripts/webkitpy/common/net/irc/ircbot.py:
+ * Scripts/webkitpy/common/net/irc/ircproxy.py:
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/bot/sheriffircbot.py: Added.
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+
+2010-03-26 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by Eric Seidel.
+
+ Move the threading code into its own module. (It has nothing to do with IRC.)
+
+ * Scripts/webkitpy/common/net/irc/ircbot.py:
+ * Scripts/webkitpy/common/net/irc/ircproxy.py:
+ * Scripts/webkitpy/common/net/irc/messagepump.py: Removed.
+ * Scripts/webkitpy/common/net/irc/messagepump_unittest.py: Removed.
+ * Scripts/webkitpy/common/net/irc/threadedmessagequeue.py: Removed.
+ * Scripts/webkitpy/common/net/irc/threadedmessagequeue_unittest.py: Removed.
+ * Scripts/webkitpy/common/net/irc/unittests.py:
+ * Scripts/webkitpy/common/thread: Added.
+ * Scripts/webkitpy/common/thread/__init__.py: Added.
+ * Scripts/webkitpy/common/thread/messagepump.py: Copied from Scripts/webkitpy/common/net/irc/messagepump.py.
+ * Scripts/webkitpy/common/thread/messagepump_unittest.py: Copied from Scripts/webkitpy/common/net/irc/messagepump_unittest.py.
+ * Scripts/webkitpy/common/thread/threadedmessagequeue.py: Copied from Scripts/webkitpy/common/net/irc/threadedmessagequeue.py.
+ * Scripts/webkitpy/common/thread/threadedmessagequeue_unittest.py: Copied from Scripts/webkitpy/common/net/irc/threadedmessagequeue_unittest.py.
+ * Scripts/webkitpy/common/thread/unittests.py: Added.
+ * Scripts/webkitpy/common/unittests.py:
+
+2010-03-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Move commit_message_for_this_commit from scm to checkout
+ https://bugs.webkit.org/show_bug.cgi?id=36629
+
+ Finally add some basic unit testing for Checkout.commit_message_for_this_commit
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/api_unittest.py: Added.
+ * Scripts/webkitpy/common/unittests.py:
+
+2010-03-26 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ [Qt] User Agent Switcher on QtLauncher
+ https://bugs.webkit.org/show_bug.cgi?id=36451
+
+ Patch by Diego Gonzalez <diego.gonzalez@openbossa.org> on 2010-03-26
+ Reviewed by Simon Hausmann.
+
+ Make possible to change the QtLauncher user agent via
+ a predefined list.
+
+ * QtLauncher/QtLauncher.pro:
+ * QtLauncher/QtLauncher.qrc: Added.
+ * QtLauncher/main.cpp:
+ (LauncherWindow::showUserAgentDialog):
+ (LauncherWindow::createChrome):
+ * QtLauncher/useragentlist.txt: Added.
+ * QtLauncher/webpage.cpp:
+ (WebPage::userAgentForUrl):
+ * QtLauncher/webpage.h:
+ (WebPage::setUserAgent):
+
+2010-03-26 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Host layout test flakiness dashboard in TestResultServer appengine.
+
+ Flakiness dashboard is a tool to monitor layout test status and
+ help layout test regression diagnostics.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36195
+
+ * TestResultServer/handlers/dashboardhandler.py: Added.
+ - New handler to handle dashboard request
+ * TestResultServer/handlers/menu.py:
+ - Add new dashboard links
+ * TestResultServer/handlers/testfilehandler.py:
+ - Request routes refactory
+ * TestResultServer/index.yaml:
+ * TestResultServer/main.py:
+ - Add new dashboard request routes and refactor test result file rountes.
+ * TestResultServer/model/dashboardfile.py: Added.
+ - Model to access datastore for dashboard files
+ * TestResultServer/model/testfile.py:
+ * TestResultServer/stylesheets/dashboardfile.css: Added.
+ * TestResultServer/templates/dashboardfilelist.html: Added.
+ * TestResultServer/templates/showfilelist.html:
+
+2010-03-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Remove some evil statics from CommitInfo
+ https://bugs.webkit.org/show_bug.cgi?id=36637
+
+ These methods should really be on checkout. You can tell because they
+ know about ChangeLogs and take an SCM as an argument. :)
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ * Scripts/webkitpy/common/checkout/commitinfo.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+
+2010-03-23 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Simon Hausmann.
+
+ Add an option to QtLauncher to enable/disable a QGLWidget as Viewport
+ of the QGraphicsView when the launcher is running on graphicsview mode.
+
+ [Qt] QtLauncher needs an option to Enable/Disable a QGLWidget as Viewport
+ https://bugs.webkit.org/show_bug.cgi?id=36270
+
+ * QtLauncher/QtLauncher.pro:
+ * QtLauncher/main.cpp:
+ (LauncherWindow::toggleQGLWidgetViewport):
+ (LauncherWindow::createChrome):
+
+2010-03-26 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ [Chromium-Win] websocket_server.py failed to start
+ https://bugs.webkit.org/show_bug.cgi?id=36586
+
+ subproess.Popen() on Python 2.4/Windows with stdout,stdout, but no stdin will fail, because it uses return value of GetStdHandle(STD_INPUT_HANDLE), but DuplicateHandle requires integer, not the handle.
+ We don't need stdin, so use devnull as stdin.
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py: open os.devnull for stdin
+
+2010-03-26 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Add TestNavigationController and TestWebWorker
+ https://bugs.webkit.org/show_bug.cgi?id=36520
+
+ Add LayoutTestController class, which is going to be used by
+ DumpRenderTree Chromium port. These files are based on:
+ - src/webkit/tools/test_shell/layout_test_controller.cc
+ - src/webkit/tools/test_shell/layout_test_controller.h
+ of Chromium rev.40492.
+
+ * DumpRenderTree/chromium/LayoutTestController.cpp: Added.
+ * DumpRenderTree/chromium/LayoutTestController.h: Added.
+
+2010-03-25 Charlie Reis <creis@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ onbeforeunload not called at window close + frame or iframe focused
+ https://bugs.webkit.org/show_bug.cgi?id=27481
+
+ Adds a callShouldCloseOnWebView method to LayoutTestController,
+ to allow automated testing for bug 27481.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (callShouldCloseOnWebViewCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::callShouldCloseOnWebView):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::callShouldCloseOnWebView):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::callShouldCloseOnWebView):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::callShouldCloseOnWebView):
+
+2010-03-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add webkit-patch lkgr for finding last known good revision
+ https://bugs.webkit.org/show_bug.cgi?id=36626
+
+ This is rather slow for now because the command
+ has to compute this information from the buildbot.
+ A better long-term solution would be to have a server
+ somewhere store a pre-computed LKGR and then any
+ script (like webkit-patch) could just fetch it.
+
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move modified_changelogs (and friends) from scm to checkout
+ https://bugs.webkit.org/show_bug.cgi?id=36636
+
+ These functions know about ChangeLogs, which is forbidden knowledge in
+ scm.py.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ * Scripts/webkitpy/tool/steps/preparechangelogforrevert.py:
+ * Scripts/webkitpy/tool/steps/revertrevision.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py:
+ * Scripts/webkitpy/tool/steps/validatereviewer.py:
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move apply_patch from scm to checkout
+ https://bugs.webkit.org/show_bug.cgi?id=36635
+
+ SCM shouldn't have any knowledge of WebKit scripts.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/applypatch.py:
+
+2010-03-25 Eric Seidel <eric@webkit.org>
+
+ Unreviewed build fix to un-break webkit-patch land.
+ Test-case coming in follow-up commit.
+
+ Move commit_message_for_this_commit from scm to checkout
+ https://bugs.webkit.org/show_bug.cgi?id=36629
+
+ * Scripts/webkitpy/common/checkout/api.py: import scm.CommitMessage
+
+2010-03-25 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Darin Adler.
+
+ <rdar://problem/7728903> Support color bitmap fonts
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj: Added ColorBits.ttf
+ and ColorBits-A.png.
+ * DumpRenderTree/fonts/ColorBits-A.png: Copied from WebCore/inspector/front-end/Images/successGreenDot.png.
+ * DumpRenderTree/fonts/ColorBits.ttf: Added.
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (activateFonts): Activate ColorBits.ttf.
+
+2010-03-25 Mark Rowe <mrowe@apple.com>
+
+ Remove a printf that was causing commit-log-editor to spew the name of the editor
+ to the terminal many times during a commit.
+
+ * Scripts/commit-log-editor:
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move commit_message_for_this_commit from scm to checkout
+ https://bugs.webkit.org/show_bug.cgi?id=36629
+
+ This function requires knowledge of ChangeLogs, but scm shouldn't know
+ about ChangeLogs.
+
+ * Scripts/webkitpy/common/checkout/api.py:
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/applypatchwithlocalcommit.py:
+ * Scripts/webkitpy/tool/steps/commit.py:
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ REGRESSION: webkit-patch land can't land "rubber-stamped" patches
+ https://bugs.webkit.org/show_bug.cgi?id=36582
+
+ Allow a "-" in rubber stamped.
+
+ * Scripts/webkitpy/tool/steps/validatereviewer.py:
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Fix some copyright lines to remove extraneous comma and
+ python directive.
+
+ * Scripts/webkitpy/tool/bot/patchcollection.py:
+ * Scripts/webkitpy/tool/bot/patchcollection_unittest.py:
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/bot/queueengine_unittest.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/comments.py:
+ * Scripts/webkitpy/tool/grammar.py:
+ * Scripts/webkitpy/tool/multicommandtool.py:
+ * Scripts/webkitpy/tool/multicommandtool_unittest.py:
+
+2010-03-25 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Darin Adler, Alexey Proskuryakov.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36631
+ Allow the test plugin to run scripts in response to NPP_SetWindow calls
+
+ Hook up the ability for the TestNetscapePlugIn to run JavaScript in
+ response to NPP_SetWindow.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+ (NPP_Destroy):
+ (NPP_SetWindow):
+
+2010-03-25 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Unreviewed, build fix.
+
+ [Qt] Fix QtLauncher guards.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::showFPS):
+ (LauncherWindow::updateFPS):
+
+2010-03-25 Yury Semikhatsky <yurys@chromium.org>
+
+ Reviewed by Pavel Feldman.
+
+ Allow running tests with enabled developer extras and closed Web Inspector. Tests that have inspector-enabled/ in their path/url will have developer extras enabled.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36610
+
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (shouldEnableDeveloperExtras):
+ (runTest):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setJavaScriptProfilingEnabled):
+ (LayoutTestController::setDeveloperExtrasEnabled):
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::closeWebInspector):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (shouldEnableDeveloperExtras):
+ (runTest):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setJavaScriptProfilingEnabled):
+ (LayoutTestController::setDeveloperExtrasEnabled):
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::closeWebInspector):
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::shouldEnableDeveloperExtras):
+ (WebCore::DumpRenderTree::open):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::closeWebInspector):
+ (LayoutTestController::setDeveloperExtrasEnabled):
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::setJavaScriptProfilingEnabled):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (shouldEnableDeveloperExtras):
+ (runTest):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setJavaScriptProfilingEnabled):
+ (LayoutTestController::setDeveloperExtrasEnabled):
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::closeWebInspector):
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by Eric Seidel.
+
+ Tweaks to sheriffbot to improve latency by keeping the working copy up
+ to date even when there's no build break. Also, officially move
+ sheriffbot to #webkit.
+
+ (Also teach ValidateReviewer to understand rubber stamps.)
+
+ * Scripts/webkitpy/common/net/irc/ircbot.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/steps/validatereviewer.py:
+
+2010-03-22 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Simon Hausmann.
+
+ Not displaying FPS info on the terminal. On S60 and Maemo the
+ Window title will be used and Status bar will used on desktop.
+
+ [Qt] QtLauncher's FPS info should not be displayed on the terminal
+ https://bugs.webkit.org/show_bug.cgi?id=36244
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::initializeView):
+ (LauncherWindow::showFPS):
+ (LauncherWindow::updateFPS):
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::setFrameRateMeasurementEnabled):
+ (WebViewGraphicsBased::updateFrameRate):
+ * QtLauncher/webview.h:
+ (WebViewGraphicsBased::frameRateMeasurementEnabled):
+
+2010-03-25 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ Added missing frame flattening activation on
+ fast/frames/flattening/frameset-flattening-grid.html;
+ removed unnecessary CONSOLE MESSAGE from the expected file;
+ reset the setFrameSetFlatteningEnabled for each test.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::resetSettings):
+
+2010-03-25 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Moved deprecated_logging unit test import statement from
+ webkitpy/unittests.py to webkitpy/common/system/unittests.py.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ This is part of the master bug to reorganize webkitpy.
+
+ * Scripts/webkitpy/common/system/unittests.py:
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-25 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Moved webkit_logging.py to common/system/deprecated_logging.py
+ inside webkitpy.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ This is part of the master bug to reorganize webkitpy.
+
+ * Scripts/validate-committer-lists:
+ * Scripts/webkitpy/common/checkout/changelog.py:
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/buildbot.py:
+ * Scripts/webkitpy/common/net/credentials.py:
+ * Scripts/webkitpy/common/net/irc/ircproxy.py:
+ * Scripts/webkitpy/common/net/networktransaction.py:
+ * Scripts/webkitpy/common/net/statusserver.py:
+ * Scripts/webkitpy/common/system/deprecated_logging.py: Copied from WebKitTools/Scripts/webkitpy/webkit_logging.py.
+ * Scripts/webkitpy/common/system/deprecated_logging_unittest.py: Copied from WebKitTools/Scripts/webkitpy/webkit_logging_unittest.py.
+ * Scripts/webkitpy/common/system/executive.py:
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py:
+ * Scripts/webkitpy/tool/commands/openbugs.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/commands/stepsequence.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/multicommandtool.py:
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ * Scripts/webkitpy/tool/steps/applypatch.py:
+ * Scripts/webkitpy/tool/steps/build.py:
+ * Scripts/webkitpy/tool/steps/checkstyle.py:
+ * Scripts/webkitpy/tool/steps/closebug.py:
+ * Scripts/webkitpy/tool/steps/closebugforlanddiff.py:
+ * Scripts/webkitpy/tool/steps/confirmdiff.py:
+ * Scripts/webkitpy/tool/steps/ensurebuildersaregreen.py:
+ * Scripts/webkitpy/tool/steps/ensurelocalcommitifneeded.py:
+ * Scripts/webkitpy/tool/steps/obsoletepatches.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+ * Scripts/webkitpy/tool/steps/reopenbugafterrollout.py:
+ * Scripts/webkitpy/tool/steps/runtests.py:
+ * Scripts/webkitpy/tool/steps/update.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py:
+ * Scripts/webkitpy/tool/steps/validatereviewer.py:
+ * Scripts/webkitpy/unittests.py:
+ * Scripts/webkitpy/webkit_logging.py: Removed.
+ * Scripts/webkitpy/webkit_logging_unittest.py: Removed.
+
+2010-03-25 Julien Chaffraix <jchaffraix@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ commit-log-editor can call itself in an infinite loop
+ https://bugs.webkit.org/show_bug.cgi?id=35291
+
+ if $editor ends up being commit-log-editor, the script will exec itself
+ in an infinite loop.
+
+ To avoid this, we now check that the $editor variable is not
+ commit-log-editor to avoid this case.
+
+ * Scripts/commit-log-editor: Added an isCommitLogEditor method and
+ reworked the $editor setting to add this check.
+
+2010-03-25 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Add a Toggle Frame Flattening option to QtLauncher.
+ It will be enabled by default on Maemo5 and S60 platforms.
+
+ [Qt] Add enable/disable Frame Flattening option to QtLauncher
+ https://bugs.webkit.org/show_bug.cgi?id=36558
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::applyPrefs):
+ (LauncherWindow::toggleFrameFlattening):
+ (LauncherWindow::createChrome):
+
+2010-03-25 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ svn-create-patch prints a warning for large patches
+ https://bugs.webkit.org/show_bug.cgi?id=32582
+
+ svn-create-patch prints a warning message for larger patches than 20k.
+
+ * Scripts/svn-create-patch:
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Renamed early_warning_system.py to earlywarningsystem.py.
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ * Scripts/webkitpy/tool/commands/early_warning_system.py: Removed.
+ * Scripts/webkitpy/tool/commands/early_warning_system_unittest.py: Removed.
+ * Scripts/webkitpy/tool/commands/earlywarningsystem.py: Copied from Scripts/webkitpy/tool/commands/early_warning_system.py.
+ * Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py: Copied from Scripts/webkitpy/tool/commands/early_warning_system_unittest.py.
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/unittests.py:
+
+2010-03-25 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ In webkitpy, pushed the unit test import statements in
+ webkitpy/unittests.py into appropriate unittests.py files in the
+ new root-level packages beneath webkitpy.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ This is part of the master bug to reorganize webkitpy.
+
+ * Scripts/webkitpy/common/system/unittests.py:
+ * Scripts/webkitpy/common/unittests.py: Added.
+ * Scripts/webkitpy/python24/unittests.py: Added.
+ * Scripts/webkitpy/tool/unittests.py: Added.
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Move WebKitCheckout into the webkitpy.common.checkout
+ package.
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ * Scripts/webkitpy/common/checkout/api.py: Copied from Scripts/webkitpy/webkitcheckout.py.
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/webkitcheckout.py: Removed.
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Move OutputCapture to webkitpy.common.system.
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py:
+ * Scripts/webkitpy/common/net/credentials_unittest.py:
+ * Scripts/webkitpy/common/system/outputcapture.py: Copied from Scripts/webkitpy/outputcapture.py.
+ * Scripts/webkitpy/outputcapture.py: Removed.
+ * Scripts/webkitpy/tool/commands/commandtest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ * Scripts/webkitpy/tool/multicommandtool_unittest.py:
+ * Scripts/webkitpy/tool/steps/closebugforlanddiff_unittest.py:
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittests.py:
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Move user.py to webkitpy.common.system.
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/net/bugzilla.py:
+ * Scripts/webkitpy/common/net/credentials.py:
+ * Scripts/webkitpy/common/system/user.py: Copied from Scripts/webkitpy/user.py.
+ * Scripts/webkitpy/common/system/user_unittest.py: Copied from Scripts/webkitpy/user_unittest.py.
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/unittests.py:
+ * Scripts/webkitpy/user.py: Removed.
+ * Scripts/webkitpy/user_unittest.py: Removed.
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Move executive.py to webkitpy.common.system.
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ * Scripts/webkitpy/common/checkout/scm.py:
+ * Scripts/webkitpy/common/checkout/scm_unittest.py:
+ * Scripts/webkitpy/common/config/ports.py:
+ * Scripts/webkitpy/common/config/ports_unittest.py:
+ * Scripts/webkitpy/common/net/credentials.py:
+ * Scripts/webkitpy/common/net/credentials_unittest.py:
+ * Scripts/webkitpy/common/system/executive.py: Copied from Scripts/webkitpy/executive.py.
+ * Scripts/webkitpy/common/system/executive_unittest.py: Copied from Scripts/webkitpy/executive_unittest.py.
+ * Scripts/webkitpy/executive.py: Removed.
+ * Scripts/webkitpy/executive_unittest.py: Removed.
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/bot/queueengine_unittest.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/early_warning_system.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/stepsequence.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/steps/checkstyle.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+ * Scripts/webkitpy/unittests.py:
+ * Scripts/webkitpy/webkit_logging_unittest.py:
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Move grammary.py into webkitpy.tool.
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ * Scripts/webkitpy/grammar.py: Removed.
+ * Scripts/webkitpy/grammar_unittest.py: Removed.
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/grammar.py: Copied from Scripts/webkitpy/grammar.py.
+ * Scripts/webkitpy/tool/grammar_unittest.py: Copied from Scripts/webkitpy/grammar_unittest.py.
+ * Scripts/webkitpy/tool/multicommandtool.py:
+ * Scripts/webkitpy/tool/steps/obsoletepatches.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py:
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-25 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ In webkitpy, moved init/ to common/system/.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ This is part of the master bug to reorganize webkitpy.
+
+ * Scripts/webkitpy/common/system: Copied from WebKitTools/Scripts/webkitpy/init.
+ * Scripts/webkitpy/common/system/logutils.py:
+ * Scripts/webkitpy/common/system/logutils_unittest.py:
+ * Scripts/webkitpy/init: Removed.
+ * Scripts/webkitpy/init/__init__.py: Removed.
+ * Scripts/webkitpy/init/logtesting.py: Removed.
+ * Scripts/webkitpy/init/logutils.py: Removed.
+ * Scripts/webkitpy/init/logutils_unittest.py: Removed.
+ * Scripts/webkitpy/init/unittests.py: Removed.
+ * Scripts/webkitpy/python24/versioning_unittest.py:
+ * Scripts/webkitpy/style_references.py:
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Move stepsequence to webkitpy.tool.commands.
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ * Scripts/webkitpy/stepsequence.py: Removed.
+ * Scripts/webkitpy/tool/commands/abstractsequencedcommand.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/stepsequence.py: Copied from Scripts/webkitpy/stepsequence.py.
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Create webkitpy.common.checkout as described in
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ * Scripts/webkitpy/changelogs.py: Removed.
+ * Scripts/webkitpy/changelogs_unittest.py: Removed.
+ * Scripts/webkitpy/commitinfo.py: Removed.
+ * Scripts/webkitpy/commitinfo_unittest.py: Removed.
+ * Scripts/webkitpy/common/checkout: Added.
+ * Scripts/webkitpy/common/checkout/__init__.py: Copied from Scripts/webkitpy/common/__init__.py.
+ * Scripts/webkitpy/common/checkout/changelog.py: Copied from Scripts/webkitpy/changelogs.py.
+ * Scripts/webkitpy/common/checkout/changelog_unittest.py: Copied from Scripts/webkitpy/changelogs_unittest.py.
+ * Scripts/webkitpy/common/checkout/commitinfo.py: Copied from Scripts/webkitpy/commitinfo.py.
+ * Scripts/webkitpy/common/checkout/commitinfo_unittest.py: Copied from Scripts/webkitpy/commitinfo_unittest.py.
+ * Scripts/webkitpy/common/checkout/diff_parser.py: Copied from Scripts/webkitpy/diff_parser.py.
+ * Scripts/webkitpy/common/checkout/diff_parser_unittest.py: Copied from Scripts/webkitpy/diff_parser_unittest.py.
+ * Scripts/webkitpy/common/checkout/scm.py: Copied from Scripts/webkitpy/scm.py.
+ * Scripts/webkitpy/common/checkout/scm_unittest.py: Copied from Scripts/webkitpy/scm_unittest.py.
+ * Scripts/webkitpy/common/net/credentials.py:
+ * Scripts/webkitpy/diff_parser.py: Removed.
+ * Scripts/webkitpy/diff_parser_unittest.py: Removed.
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/scm.py: Removed.
+ * Scripts/webkitpy/scm_unittest.py: Removed.
+ * Scripts/webkitpy/stepsequence.py:
+ * Scripts/webkitpy/style_references.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/comments.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/preparechangelogforrevert.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py:
+ * Scripts/webkitpy/tool/steps/validatereviewer.py:
+ * Scripts/webkitpy/unittests.py:
+ * Scripts/webkitpy/webkitcheckout.py:
+
+2010-03-25 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ In webkitpy, moved init/versioning.py to python24/.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ This is part of the master bug to reorganize webkitpy.
+
+ * Scripts/test-webkitpy:
+ * Scripts/webkit-patch:
+ * Scripts/webkitpy/init/unittests.py:
+ * Scripts/webkitpy/init/versioning.py: Removed.
+ * Scripts/webkitpy/init/versioning_unittest.py: Removed.
+ * Scripts/webkitpy/python24: Added.
+ * Scripts/webkitpy/python24/__init__.py: Copied from WebKitTools/Scripts/webkitpy/tool/__init__.py.
+ * Scripts/webkitpy/python24/versioning.py: Copied from WebKitTools/Scripts/webkitpy/init/versioning.py.
+ * Scripts/webkitpy/python24/versioning_unittest.py: Copied from WebKitTools/Scripts/webkitpy/init/versioning_unittest.py.
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Create webkitpy.common.net as described in
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ * Scripts/webkitpy/bugzilla.py: Removed.
+ * Scripts/webkitpy/bugzilla_unittest.py: Removed.
+ * Scripts/webkitpy/buildbot.py: Removed.
+ * Scripts/webkitpy/buildbot_unittest.py: Removed.
+ * Scripts/webkitpy/commitinfo.py:
+ * Scripts/webkitpy/common/net: Added.
+ * Scripts/webkitpy/common/net/__init__.py: Added.
+ * Scripts/webkitpy/common/net/bugzilla.py: Copied from Scripts/webkitpy/bugzilla.py.
+ * Scripts/webkitpy/common/net/bugzilla_unittest.py: Copied from Scripts/webkitpy/bugzilla_unittest.py.
+ * Scripts/webkitpy/common/net/buildbot.py: Copied from Scripts/webkitpy/buildbot.py.
+ * Scripts/webkitpy/common/net/buildbot_unittest.py: Copied from Scripts/webkitpy/buildbot_unittest.py.
+ * Scripts/webkitpy/common/net/credentials.py: Copied from Scripts/webkitpy/credentials.py.
+ * Scripts/webkitpy/common/net/credentials_unittest.py: Copied from Scripts/webkitpy/credentials_unittest.py.
+ * Scripts/webkitpy/common/net/irc: Copied from Scripts/webkitpy/irc.
+ * Scripts/webkitpy/common/net/irc/ircbot.py:
+ * Scripts/webkitpy/common/net/irc/ircproxy.py:
+ * Scripts/webkitpy/common/net/irc/messagepump_unittest.py:
+ * Scripts/webkitpy/common/net/irc/threadedmessagequeue_unittest.py:
+ * Scripts/webkitpy/common/net/irc/unittests.py:
+ * Scripts/webkitpy/common/net/networktransaction.py: Copied from Scripts/webkitpy/networktransaction.py.
+ * Scripts/webkitpy/common/net/networktransaction_unittest.py: Copied from Scripts/webkitpy/networktransaction_unittest.py.
+ * Scripts/webkitpy/common/net/statusserver.py: Copied from Scripts/webkitpy/statusserver.py.
+ * Scripts/webkitpy/credentials.py: Removed.
+ * Scripts/webkitpy/credentials_unittest.py: Removed.
+ * Scripts/webkitpy/irc: Removed.
+ * Scripts/webkitpy/irc/__init__.py: Removed.
+ * Scripts/webkitpy/irc/ircbot.py: Removed.
+ * Scripts/webkitpy/irc/ircproxy.py: Removed.
+ * Scripts/webkitpy/irc/messagepump.py: Removed.
+ * Scripts/webkitpy/irc/messagepump_unittest.py: Removed.
+ * Scripts/webkitpy/irc/threadedmessagequeue.py: Removed.
+ * Scripts/webkitpy/irc/threadedmessagequeue_unittest.py: Removed.
+ * Scripts/webkitpy/irc/unittests.py: Removed.
+ * Scripts/webkitpy/networktransaction.py: Removed.
+ * Scripts/webkitpy/networktransaction_unittest.py: Removed.
+ * Scripts/webkitpy/scm_unittest.py:
+ * Scripts/webkitpy/statusserver.py: Removed.
+ * Scripts/webkitpy/tool/bot/queueengine.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/queries_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/postdiffforrevert.py:
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-25 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ In webkitpy, renamed MockBugzillaTool to MockTool.
+
+ * Scripts/webkitpy/tool/commands/commandtest.py:
+ * Scripts/webkitpy/tool/commands/queries_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py:
+ * Scripts/webkitpy/tool/steps/closebugforlanddiff_unittest.py:
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittests.py:
+
+2010-03-25 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ In Scripts/webkitpy, moved webkitport.py and committers.py into
+ common/config/ (also creating common/config/).
+
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ This is part of the master bug to reorganize webkitpy.
+
+ * Scripts/validate-committer-lists:
+ * Scripts/webkitpy/bugzilla.py:
+ * Scripts/webkitpy/bugzilla_unittest.py:
+ * Scripts/webkitpy/changelogs.py:
+ * Scripts/webkitpy/commitinfo.py:
+ * Scripts/webkitpy/commitinfo_unittest.py:
+ * Scripts/webkitpy/committers.py: Removed.
+ * Scripts/webkitpy/committers_unittest.py: Removed.
+ * Scripts/webkitpy/common: Added.
+ * Scripts/webkitpy/common/__init__.py: Copied from WebKitTools/Scripts/webkitpy/style/__init__.py.
+ * Scripts/webkitpy/common/config: Added.
+ * Scripts/webkitpy/common/config/__init__.py: Copied from WebKitTools/Scripts/webkitpy/style/__init__.py.
+ * Scripts/webkitpy/common/config/committers.py: Copied from WebKitTools/Scripts/webkitpy/committers.py.
+ * Scripts/webkitpy/common/config/committers_unittest.py: Copied from WebKitTools/Scripts/webkitpy/committers_unittest.py.
+ * Scripts/webkitpy/common/config/ports.py: Copied from WebKitTools/Scripts/webkitpy/webkitport.py.
+ * Scripts/webkitpy/common/config/ports_unittest.py: Copied from WebKitTools/Scripts/webkitpy/webkitport_unittest.py.
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ * Scripts/webkitpy/tool/commands/early_warning_system.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/steps/abstractstep.py:
+ * Scripts/webkitpy/unittests.py:
+ * Scripts/webkitpy/webkitport.py: Removed.
+ * Scripts/webkitpy/webkitport_unittest.py: Removed.
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Move mock_bugzillatool.py to tool/mocktool.py.
+
+ * Scripts/webkitpy/mock_bugzillatool.py: Removed.
+ * Scripts/webkitpy/tool/commands/commandtest.py:
+ * Scripts/webkitpy/tool/commands/queries_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/mocktool.py: Copied from Scripts/webkitpy/mock_bugzillatool.py.
+ * Scripts/webkitpy/tool/steps/closebugforlanddiff_unittest.py:
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittests.py:
+
+2010-03-24 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Move comments.py and multicommandtool.py to their new
+ home.
+
+ * Scripts/webkitpy/comments.py: Removed.
+ * Scripts/webkitpy/multicommandtool.py: Removed.
+ * Scripts/webkitpy/multicommandtool_unittest.py: Removed.
+ * Scripts/webkitpy/tool/commands/abstractsequencedcommand.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/openbugs.py:
+ * Scripts/webkitpy/tool/commands/queries.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/comments.py: Copied from Scripts/webkitpy/comments.py.
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/tool/multicommandtool.py: Copied from Scripts/webkitpy/multicommandtool.py.
+ * Scripts/webkitpy/tool/multicommandtool_unittest.py: Copied from Scripts/webkitpy/multicommandtool_unittest.py.
+ * Scripts/webkitpy/tool/steps/closebugforlanddiff.py:
+ * Scripts/webkitpy/tool/steps/closepatch.py:
+ * Scripts/webkitpy/tool/steps/reopenbugafterrollout.py:
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-24 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Fixup one import statement I didn't find because the .pyc
+ masked the error.
+
+ * Scripts/webkitpy/stepsequence.py:
+
+2010-03-24 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Move queueengine.py to its new home.
+
+ * Scripts/webkitpy/queueengine.py: Removed.
+ * Scripts/webkitpy/queueengine_unittest.py: Removed.
+ * Scripts/webkitpy/tool/bot/queueengine.py: Copied from Scripts/webkitpy/queueengine.py.
+ * Scripts/webkitpy/tool/bot/queueengine_unittest.py: Copied from Scripts/webkitpy/queueengine_unittest.py.
+ * Scripts/webkitpy/tool/commands/early_warning_system.py:
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-24 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Move patchcollection.py to its new home.
+
+ * Scripts/webkitpy/patchcollection.py: Removed.
+ * Scripts/webkitpy/patchcollection_unittest.py: Removed.
+ * Scripts/webkitpy/tool/bot: Added.
+ * Scripts/webkitpy/tool/bot/__init__.py: Added.
+ * Scripts/webkitpy/tool/bot/patchcollection.py: Copied from WebKitTools/Scripts/webkitpy/patchcollection.py.
+ * Scripts/webkitpy/tool/bot/patchcollection_unittest.py: Copied from WebKitTools/Scripts/webkitpy/patchcollection_unittest.py.
+ * Scripts/webkitpy/tool/commands/queues.py:
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-24 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ In Scripts/webkitpy, moved steps_references.py and the steps
+ folder into webkitpy/patch.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36093
+
+ * Scripts/webkitpy/steps: Removed.
+ * Scripts/webkitpy/steps/__init__.py: Removed.
+ * Scripts/webkitpy/steps/abstractstep.py: Removed.
+ * Scripts/webkitpy/steps/applypatch.py: Removed.
+ * Scripts/webkitpy/steps/applypatchwithlocalcommit.py: Removed.
+ * Scripts/webkitpy/steps/build.py: Removed.
+ * Scripts/webkitpy/steps/checkstyle.py: Removed.
+ * Scripts/webkitpy/steps/cleanworkingdirectory.py: Removed.
+ * Scripts/webkitpy/steps/cleanworkingdirectorywithlocalcommits.py: Removed.
+ * Scripts/webkitpy/steps/closebug.py: Removed.
+ * Scripts/webkitpy/steps/closebugforlanddiff.py: Removed.
+ * Scripts/webkitpy/steps/closebugforlanddiff_unittest.py: Removed.
+ * Scripts/webkitpy/steps/closepatch.py: Removed.
+ * Scripts/webkitpy/steps/commit.py: Removed.
+ * Scripts/webkitpy/steps/confirmdiff.py: Removed.
+ * Scripts/webkitpy/steps/createbug.py: Removed.
+ * Scripts/webkitpy/steps/editchangelog.py: Removed.
+ * Scripts/webkitpy/steps/ensurebuildersaregreen.py: Removed.
+ * Scripts/webkitpy/steps/ensurelocalcommitifneeded.py: Removed.
+ * Scripts/webkitpy/steps/metastep.py: Removed.
+ * Scripts/webkitpy/steps/obsoletepatches.py: Removed.
+ * Scripts/webkitpy/steps/options.py: Removed.
+ * Scripts/webkitpy/steps/postdiff.py: Removed.
+ * Scripts/webkitpy/steps/postdiffforcommit.py: Removed.
+ * Scripts/webkitpy/steps/postdiffforrevert.py: Removed.
+ * Scripts/webkitpy/steps/preparechangelog.py: Removed.
+ * Scripts/webkitpy/steps/preparechangelogforrevert.py: Removed.
+ * Scripts/webkitpy/steps/promptforbugortitle.py: Removed.
+ * Scripts/webkitpy/steps/reopenbugafterrollout.py: Removed.
+ * Scripts/webkitpy/steps/revertrevision.py: Removed.
+ * Scripts/webkitpy/steps/runtests.py: Removed.
+ * Scripts/webkitpy/steps/steps_unittest.py: Removed.
+ * Scripts/webkitpy/steps/update.py: Removed.
+ * Scripts/webkitpy/steps/updatechangelogswithreview_unittests.py: Removed.
+ * Scripts/webkitpy/steps/updatechangelogswithreviewer.py: Removed.
+ * Scripts/webkitpy/steps/validatereviewer.py: Removed.
+ * Scripts/webkitpy/steps_references.py: Removed.
+ * Scripts/webkitpy/stepsequence.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/steps: Copied from WebKitTools/Scripts/webkitpy/steps.
+ * Scripts/webkitpy/tool/steps/__init__.py:
+ * Scripts/webkitpy/tool/steps/applypatch.py:
+ * Scripts/webkitpy/tool/steps/applypatchwithlocalcommit.py:
+ * Scripts/webkitpy/tool/steps/build.py:
+ * Scripts/webkitpy/tool/steps/checkstyle.py:
+ * Scripts/webkitpy/tool/steps/cleanworkingdirectory.py:
+ * Scripts/webkitpy/tool/steps/cleanworkingdirectorywithlocalcommits.py:
+ * Scripts/webkitpy/tool/steps/closebug.py:
+ * Scripts/webkitpy/tool/steps/closebugforlanddiff.py:
+ * Scripts/webkitpy/tool/steps/closebugforlanddiff_unittest.py:
+ * Scripts/webkitpy/tool/steps/closepatch.py:
+ * Scripts/webkitpy/tool/steps/commit.py:
+ * Scripts/webkitpy/tool/steps/confirmdiff.py:
+ * Scripts/webkitpy/tool/steps/createbug.py:
+ * Scripts/webkitpy/tool/steps/editchangelog.py:
+ * Scripts/webkitpy/tool/steps/ensurebuildersaregreen.py:
+ * Scripts/webkitpy/tool/steps/ensurelocalcommitifneeded.py:
+ * Scripts/webkitpy/tool/steps/metastep.py:
+ * Scripts/webkitpy/tool/steps/obsoletepatches.py:
+ * Scripts/webkitpy/tool/steps/postdiff.py:
+ * Scripts/webkitpy/tool/steps/postdiffforcommit.py:
+ * Scripts/webkitpy/tool/steps/postdiffforrevert.py:
+ * Scripts/webkitpy/tool/steps/preparechangelog.py:
+ * Scripts/webkitpy/tool/steps/preparechangelogforrevert.py:
+ * Scripts/webkitpy/tool/steps/promptforbugortitle.py:
+ * Scripts/webkitpy/tool/steps/reopenbugafterrollout.py:
+ * Scripts/webkitpy/tool/steps/revertrevision.py:
+ * Scripts/webkitpy/tool/steps/runtests.py:
+ * Scripts/webkitpy/tool/steps/steps_unittest.py:
+ * Scripts/webkitpy/tool/steps/update.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittests.py:
+ * Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py:
+ * Scripts/webkitpy/tool/steps/validatereviewer.py:
+ * Scripts/webkitpy/tool/steps_references.py: Copied from WebKitTools/Scripts/webkitpy/steps_references.py.
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-24 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, build fix only.
+
+ Abstract LayoutTestResults logic for easier reuse
+ https://bugs.webkit.org/show_bug.cgi?id=36579
+
+ * Scripts/webkitpy/buildbot_unittest.py: Add a missing import.
+
+2010-03-24 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Fix a stray comma to test landing an patch without review.
+
+ * Scripts/webkitpy/commitinfo.py:
+
+2010-03-24 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ In Scripts/webkitpy, moved commands_references.py and the commands
+ folder into webkitpy/patch.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36483
+
+ This is part of master bug 36093 to organize webkitpy.
+
+ * Scripts/webkitpy/commands: Removed.
+ * Scripts/webkitpy/commands/__init__.py: Removed.
+ * Scripts/webkitpy/commands/abstractsequencedcommand.py: Removed.
+ * Scripts/webkitpy/commands/commandtest.py: Removed.
+ * Scripts/webkitpy/commands/download.py: Removed.
+ * Scripts/webkitpy/commands/download_unittest.py: Removed.
+ * Scripts/webkitpy/commands/early_warning_system.py: Removed.
+ * Scripts/webkitpy/commands/early_warning_system_unittest.py: Removed.
+ * Scripts/webkitpy/commands/openbugs.py: Removed.
+ * Scripts/webkitpy/commands/openbugs_unittest.py: Removed.
+ * Scripts/webkitpy/commands/queries.py: Removed.
+ * Scripts/webkitpy/commands/queries_unittest.py: Removed.
+ * Scripts/webkitpy/commands/queues.py: Removed.
+ * Scripts/webkitpy/commands/queues_unittest.py: Removed.
+ * Scripts/webkitpy/commands/queuestest.py: Removed.
+ * Scripts/webkitpy/commands/sheriffbot.py: Removed.
+ * Scripts/webkitpy/commands/sheriffbot_unittest.py: Removed.
+ * Scripts/webkitpy/commands/upload.py: Removed.
+ * Scripts/webkitpy/commands/upload_unittest.py: Removed.
+ * Scripts/webkitpy/commands_references.py: Removed.
+ * Scripts/webkitpy/tool/commands: Copied from WebKitTools/Scripts/webkitpy/commands.
+ * Scripts/webkitpy/tool/commands/commandtest.py:
+ * Scripts/webkitpy/tool/commands/download.py:
+ * Scripts/webkitpy/tool/commands/download_unittest.py:
+ * Scripts/webkitpy/tool/commands/early_warning_system.py:
+ * Scripts/webkitpy/tool/commands/early_warning_system_unittest.py:
+ * Scripts/webkitpy/tool/commands/openbugs_unittest.py:
+ * Scripts/webkitpy/tool/commands/queries_unittest.py:
+ * Scripts/webkitpy/tool/commands/queues_unittest.py:
+ * Scripts/webkitpy/tool/commands/queuestest.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot.py:
+ * Scripts/webkitpy/tool/commands/sheriffbot_unittest.py:
+ * Scripts/webkitpy/tool/commands/upload.py:
+ * Scripts/webkitpy/tool/commands/upload_unittest.py:
+ * Scripts/webkitpy/tool/commands_references.py: Copied from WebKitTools/Scripts/webkitpy/commands_references.py.
+ * Scripts/webkitpy/tool/main.py:
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-24 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Rename webkitpy.patch to webkitpy.tool
+ https://bugs.webkit.org/show_bug.cgi?id=36580
+
+ This is in preparation for the great webkitpy naming cleanup.
+
+ * Scripts/webkit-patch:
+ * Scripts/webkitpy/patch: Removed.
+ * Scripts/webkitpy/patch/__init__.py: Removed.
+ * Scripts/webkitpy/patch/patcher.py: Removed.
+ * Scripts/webkitpy/tool: Copied from WebKitTools/Scripts/webkitpy/patch.
+ * Scripts/webkitpy/tool/main.py: Copied from WebKitTools/Scripts/webkitpy/patch/patcher.py.
+ * Scripts/webkitpy/tool/patcher.py: Removed.
+
+2010-03-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Abstract LayoutTestResults logic for easier reuse
+ https://bugs.webkit.org/show_bug.cgi?id=36579
+
+ * Scripts/webkitpy/buildbot.py:
+ - Split out logic into new LayoutTestResults class.
+ * Scripts/webkitpy/buildbot_unittest.py:
+ - Rename the testing class to match.
+ * Scripts/webkitpy/commands/queries.py:
+ - Use the new LayoutTestResults class.
+
+2010-03-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move Bugzilla.prompt_for_component to User.prompt_with_list for re-use
+ https://bugs.webkit.org/show_bug.cgi?id=36577
+
+ * Scripts/webkitpy/bugzilla.py:
+ - Move prompt_for_component to User
+ * Scripts/webkitpy/commands/queries.py:
+ - Add a missing argument_names declaration.
+ * Scripts/webkitpy/user.py:
+ - Add prompt_with_list
+ - Make staticmethods classmethods for easier mocking
+
+2010-03-24 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/36572> commit-log-editor: thinks mergeChangeLogs.pl is a ChangeLog file
+
+ Reviewed by Eric Seidel.
+
+ Fixes the following error when committing a file with
+ "ChangeLog" in the name that isn't a ChangeLog (like
+ mergeChangeLogs.pl from r56471 and r56472):
+
+ $ git commit .
+ Can't open WebKitTools/Scripts/webkitperl/VCSUtils_unittest/mergeChangeLog at commit-log-editor line 132.
+ error: There was a problem with the editor 'commit-log-editor'.
+ Please supply the message using either -m or -F option.
+
+ * Scripts/commit-log-editor: Added '$' to anchor "ChangeLog" to
+ the end of the file name when searching for ChangeLog files in a
+ commit.
+
+2010-03-24 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/36570> resolve-ChangeLogs: fall back to git-merge-file if ChangeLog can't be merged
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/resolve-ChangeLogs: Switched to exec git-merge-file if
+ the merge attempt fails.
+
+2010-03-24 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch or pre-commit hook should validate reviewer lines before committing
+ https://bugs.webkit.org/show_bug.cgi?id=26927
+
+ Validate that patches have valid reivewers listed in their ChangeLogs
+ before landing. For patches without reviewers can be landed if their
+ ChangeLogs state that they are unreviewed.
+
+ * Scripts/webkitpy/changelogs.py:
+ * Scripts/webkitpy/commands/download.py:
+ * Scripts/webkitpy/commitinfo.py:
+ * Scripts/webkitpy/commitinfo_unittest.py:
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ * Scripts/webkitpy/steps/__init__.py:
+ * Scripts/webkitpy/steps/validatereviewer.py: Added.
+
+2010-03-19 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by David Levin.
+
+ Undefined names reported by pyflakes in python scripts
+ https://bugs.webkit.org/show_bug.cgi?id=36403
+
+ Attempt to use names that exist or can exist in the lexical
+ scope instead of not being available at all.
+
+ * Scripts/webkitpy/changelogs.py: Use self._content.
+ * Scripts/webkitpy/layout_tests/port/base.py: Use os.stat
+ * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py: Use self._port
+ * Scripts/webkitpy/style/processors/cpp_unittest.py: Use expected_message_re
+
+2010-03-24 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/36560> resolve-ChangeLogs: git-rebase fails when resolve-ChangeLogs can't merge
+
+ Reviewed by Eric Seidel.
+
+ When resolve-ChangeLogs fails to merge a patch while running as
+ a git merge driver, it deletes the original file, which causes
+ an internal failure and stops git mid-merge:
+
+ fatal: Failed to execute internal merge
+
+ The fix is to use the --force switch with patch so that it will
+ always attempt to apply the patch. (The change in
+ mergeChangeLogs() for the previous commit also fixed this, but
+ adding --force also prevents any potential user interaction that
+ patch may want to display.)
+
+ * Scripts/VCSUtils.pm:
+ (mergeChangeLogs): Added --force switch to patch command. Also
+ changed to use the exit status from the patch command to
+ determine the return value for this method.
+ * Scripts/webkitperl/VCSUtils_unittest/mergeChangeLogs.pl: Added
+ test to cover this bug.
+
+2010-03-24 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/36560> resolve-ChangeLogs: move mergeChanges() into VCSUtils package
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/VCSUtils.pm:
+ (mergeChangeLogs): Copied from mergeChanges() in
+ resolve-ChangeLogs and renamed. Added method documentation.
+ Fixed bug found by new tests where the original file to be
+ patched was deleted when cleaning up after a traditinal rejected
+ patch failed to apply.
+ * Scripts/resolve-ChangeLogs: Switched to using
+ mergeChangeLogs().
+ (mergeChanges): Moved to VCSUtils.pm and renamed to
+ mergeChangeLogs().
+ * Scripts/webkitperl/VCSUtils_unittest/mergeChangeLogs.pl: Added.
+
+2010-03-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add support for qt's unassigned list to webkit-patch assign-to-committer
+ https://bugs.webkit.org/show_bug.cgi?id=36559
+
+ * Scripts/webkitpy/bugzilla.py:
+ - Move Bugzilla.unassigned_email into Bug and make it a set.
+ * Scripts/webkitpy/bugzilla_unittest.py:
+ - Test the new Bug.is_unassigned method
+ * Scripts/webkitpy/commands/upload.py:
+ - Use the new Bug.is_unassigned method instead of an explicit ==
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ - Bugzilla.unassigned_email no longer needs mocking
+
+2010-03-24 Kent Hansen <kent.hansen@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Rename QWebSettings::XSSAuditorEnabled to XSSAuditingEnabled
+ https://bugs.webkit.org/show_bug.cgi?id=36522
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setXSSAuditorEnabled): Use the new name.
+
+2010-03-24 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Added to check-webkit-style support for a --debug flag.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36100
+
+ The --debug flag adjusts the logging level to DEBUG and
+ includes the logger name and level in each log message.
+
+ * Scripts/check-webkit-style:
+ - Changed the code to check for the --debug flag and pass
+ the result to the configure_logging() method.
+ * Scripts/webkitpy/style/checker.py:
+ - Added an is_debug parameter to configure_logging().
+ - Refactored configure_logging() by adding calls to
+ the following two methods: _create_log_handlers() and
+ _create_debug_log_handlers().
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Added unit tests for configure_logging() with is_debug True
+ by splitting the ConfigureLoggingTest class into
+ ConfigureLoggingTest and ConfigureLoggingTestBase, and
+ adding ConfigureLoggingDebugTest.
+ * Scripts/webkitpy/style/optparser.py:
+ - Updated the usage string.
+ - Added an is_debug data attribute to the CommandOptionValues
+ class.
+ - Added support for the --debug flag to the ArgumentParser.parse()
+ method.
+ - Also added extra error information to the parse() method in
+ the case of an invalid flag.
+ * Scripts/webkitpy/style/optparser_unittest.py:
+ - Updated the unit tests as necessary.
+ - Also fixed an issue with the CommandOptionValuesTest.test_eq()
+ unit test.
+
+2010-03-23 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Add TestNavigationController and TestWebWorker
+ https://bugs.webkit.org/show_bug.cgi?id=36489
+
+ Add TestNavigationController and TestWebWorker classes, which are
+ going to be used by DumpRenderTree Chromium port. These files are
+ based on:
+ - src/webkit/tools/test_shell/test_navigation_controller.{cc,h}
+ - src/webkit/tools/test_shell/test_web_worker.h
+ of Chromium rev.40492.
+
+ TestNavigationController has non-style changes.
+ - Change ContentState type: binary string -> WebHistoryItem
+ - Remove TestShell dependency by introducing NavigationHost interface.
+
+ * DumpRenderTree/chromium/TestNavigationController.cpp: Added.
+ * DumpRenderTree/chromium/TestNavigationController.h: Added.
+ * DumpRenderTree/chromium/TestWebWorker.h: Added.
+
+2010-03-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add support for revision -> build lookup in buildbot.py and layout test result parsing
+ https://bugs.webkit.org/show_bug.cgi?id=36474
+
+ * Scripts/webkitpy/bugzilla_unittest.py: Added a FIXME about sharing code.
+ * Scripts/webkitpy/buildbot.py:
+ - Add support for looking up builds by revision number.
+ - Add support for fetching and parsing results.html files from buildbot.
+ - build_for_revision has an allow_failed_lookups option to work around the fact that
+ our buildbot's xmlrpc calls return failure on old revision numbers.
+ - Add parsing support for twisted directory listings.
+ * Scripts/webkitpy/buildbot_unittest.py:
+ - Unit test all the new code.
+ * Scripts/webkitpy/commands/queries.py:
+ - Add a new results-for command which prints all the results for a given revision (very slow due to slow revision lookup)
+
+2010-03-23 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Adam Roben.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36048
+
+ Detect if the Windows Platform SDK is missing when building with
+ Visual C++ Express Edition and inform the user to download it.
+
+ * Scripts/webkitdirs.pm:
+
+2010-03-23 Darin Adler <darin@apple.com>
+
+ Tell Subversion about more directories that expect to have .pyc files.
+
+ * Scripts/webkitpy: Modified property svn:ignore.
+ * Scripts/webkitpy/irc: Added property svn:ignore.
+
+2010-03-23 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Adam Barth.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36149
+
+ Import the GNU readline interface to modify the behavior
+ of raw_input so as to provide line editing support. In
+ particular this will prevent "delete" characters from
+ appearing in the returned value for function raw_input.
+
+ * Scripts/webkitpy/user.py:
+
+2010-03-23 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Remove support for Qt v4.4
+ https://bugs.webkit.org/show_bug.cgi?id=36389
+
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+ * QtLauncher/mainwindow.cpp:
+ (MainWindow::MainWindow):
+
+2010-03-22 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make build_webkit_command() pass MAKEFLAGS environment variable to make.
+ https://bugs.webkit.org/show_bug.cgi?id=36440
+
+ * Scripts/webkitpy/webkitport.py:
+ * Scripts/webkitpy/webkitport_unittest.py:
+
+2010-03-22 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Change baseline_path() to point to the upstream locations for the
+ Chromium ports. Also change the reabselining scripts to use the
+ correct functions to get the baseline directories, and fix the
+ script's sys.path to pull in simplejson correctly.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36417
+
+ * Scripts/rebaseline-chromium-webkit-tests:
+ - fix sys.path to pick up simplejson properly
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ - change baseline_path() to use webkit_baseline_path()
+ - error out correctly if we can't find the chromium base dir
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ - call baseline_path(), not chromium_baseline_path()
+
+2010-03-22 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Refactored the cpu_count() code in executive.py.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36437
+
+ * Scripts/webkitpy/executive.py:
+ - Moved the import of the multiprocessing module to the top
+ of the file rather than importing from within a function.
+
+2010-03-22 Antonio Gomes <tonikitoo@webkit.org>
+
+ Unreviewed.
+
+ Rolling out r56183: http://trac.webkit.org/changeset/56183
+
+ https://bugs.webkit.org/show_bug.cgi?id=36244
+
+ Need to roll out because this patch will be re-worked by the author
+ and other reviewers agreed on it.
+
+2010-03-22 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Created a function for getting a module-specific logging.logger
+ based on the __file__ value of the module.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35821
+
+ This function allows us to get the module-specific logger for
+ a module without having to hard-code the fully-qualified name
+ of the module in the module itself. The code can be the same
+ in every case: "_log = logutils.get_logger(__file__)".
+
+ * Scripts/webkitpy/init/logutils.py: Added.
+ - Added a module with a get_logger() function to return
+ a module-specific logger based on the module's __file__
+ variable.
+
+ * Scripts/webkitpy/init/logutils_unittest.py: Added.
+ - Added unit tests for logutils.py.
+
+ * Scripts/webkitpy/init/unittests.py:
+ - Added logutils_unittest to the list of imports.
+
+2010-03-22 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] REGRESSION (r56209): fast/media/print-restores-previous-mediatype.htm crashes
+ https://bugs.webkit.org/show_bug.cgi?id=36386
+
+ Fix the regression by implementing a null printer for Qt DRT.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::NullPrinter::NullPaintEngine::begin):
+ (WebCore::NullPrinter::NullPaintEngine::end):
+ (WebCore::NullPrinter::NullPaintEngine::type):
+ (WebCore::NullPrinter::NullPaintEngine::drawPixmap):
+ (WebCore::NullPrinter::NullPaintEngine::updateState):
+ (WebCore::NullPrinter::paintEngine):
+ (WebCore::DumpRenderTree::dryRunPrint):
+
+2010-03-20 Martin Robinson <mrobinson@webkit.org>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] eventSender.zoomPageOut() bug?
+ https://bugs.webkit.org/show_bug.cgi?id=30575
+
+ Make zoomPage{In/Out}Callback respect the 1.2f zoom factor that DRT should be using.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (zoomIn): Added.
+ (zoomOut): Added.
+ (textZoomInCallback): Use zoomIn helper function.
+ (textZoomOutCallback): Use zoomOut helper function.
+ (zoomPageInCallback): Use zoomIn helper function, which respects zoom factor.
+ (zoomPageOutCallback): Use zoomOut helper function, which respects zoom factor.
+
+2010-03-20 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after recent database API change.
+
+ * wx/browser/browser.cpp:
+ (MyApp::OnInit):
+
+2010-03-20 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Renamed UnitTestLogStream to TestLogStream in webkitpy.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36099
+
+ TestLogStream is more concise and more consistent with the name of
+ the module (logtesting rather than logunittesting) and its main
+ class (LogTesting rather than LogUnitTesting).
+
+ * Scripts/webkitpy/init/logtesting.py:
+ - Renamings.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Renamings.
+
+ * Scripts/webkitpy/style_references.py:
+ - Renamings.
+
+2010-03-20 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fixes for new method in LayoutTestController.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setSpatialNavigationEnabled):
+ * wx/build/settings.py:
+
+2010-03-20 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Unreviewed, tool fix.
+
+ Remove vestiges of downstream directory names to unbreak rebaselining tool.
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py: Changed paths to use WebKit repo.
+
+2010-03-20 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Re-enable the downstream test_expectations overrides file that was
+ disabled in bug 36396 / r56287.
+
+ https://bugs.chromium.org/show_bug.cgi?id=36401
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-03-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Disable the downstream override expectations temporarily to allow
+ us to test that we've upstreamed everything correctly. Also, stop
+ looking at the downstream baselines at all (now you will only be
+ able to update baselines upstream). In theory this should work, but
+ if we need to we can always add the downstream dirs back in.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36396
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+
+2010-03-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ fix typo in chromium test expectations overrides routine
+ https://bugs.webkit.org/show_bug.cgi?id=36397
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-03-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Flip the Chromium ports to look first for the test expectations
+ in LayoutTests/platform/chromium and only afterwards look in the
+ Chromium repo downstream for overrides.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36326
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-03-19 James Hawkins <jhawkins@chromium.org>
+
+ Unreviewed.
+
+ Add myself to the committers list.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-03-19 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Fix SheriffBot exception lock when we can't retrieve the first build
+ from buildbot. (I'll ask Eric to review this change after the fact,
+ but he's at lunch and I want to get the bot unlocked.)
+
+ * Scripts/webkitpy/buildbot.py:
+ * Scripts/webkitpy/buildbot_unittest.py:
+
+2010-03-19 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36380
+ websocket/tests/frame-lengths.html times out on Tiger bot
+
+ https://bugs.webkit.org/show_bug.cgi?id=35041
+ websocket/tests/frame-lengths.html / websocket/tests/simple-stress.html fail on Windows bot
+
+ Double the timeout (from 15 seconds to 30 seconds). We can increase it more, if necessary -
+ sampling the DRT process on Mac OS X takes much longer anyway, so it's better to avoid
+ timing out than to detect it early.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setWaitToDump):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::waitUntilDone):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ * Scripts/run-webkit-tests:
+
+2010-03-19 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Unreviewed.
+
+ Buildfix for Qt v4.5.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ (LauncherWindow::applyZoom):
+
+2010-03-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Operational tweaks to SheriffBot
+ https://bugs.webkit.org/show_bug.cgi?id=36385
+
+ These changes aren't pretty, but they're helpful to make SheriffBot
+ work operationally. I plan to iterate in these areas, but I wanted to
+ get this patch landed so I could be running the bot against TOT.
+
+ * Scripts/webkitpy/commands/sheriffbot.py:
+ * Scripts/webkitpy/irc/ircbot.py:
+ * Scripts/webkitpy/thirdparty/autoinstalled/__init__.py:
+
+2010-03-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Help sheriff-bot avoid warning about flaky tests (and add more unit testing)
+ https://bugs.webkit.org/show_bug.cgi?id=36354
+
+ * Scripts/webkitpy/buildbot.py:
+ - Make Build creation easier to Mock and test
+ * Scripts/webkitpy/buildbot_unittest.py:
+ - Test finding green to red transitions and suspect revisions
+ * Scripts/webkitpy/commands/queries.py:
+ - Make what-broke note when builders have only failed once.
+
+2010-03-19 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Fix the rebaselining tool, which was broken by r36324 when I
+ added the concept of overridding expectations.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36374
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+
+2010-03-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Misc bug fixes to make the SheriffBot actually work
+ https://bugs.webkit.org/show_bug.cgi?id=36355
+
+ With these changes, I can actually run the sheriff-bot from start to
+ finish.
+
+ * Scripts/webkitpy/irc/ircproxy.py:
+ * Scripts/webkitpy/patch/patcher.py:
+ * Scripts/webkitpy/statusserver.py:
+
+2010-03-19 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Actually import the sheriff-bot command so we can run it. Also, move
+ the bot to #webkit-test so it doesn't cause a ruckus while we test it.
+
+ * Scripts/webkitpy/patch/patcher.py:
+ * Scripts/webkitpy/irc/ircbot.py:
+
+2010-03-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Second cut at SheriffBot
+ https://bugs.webkit.org/show_bug.cgi?id=36353
+
+ This patch should contain a complete SheriffBot that's capable of
+ saying reasonable things on IRC. I had to refactor the use of
+ CommitInfo to make the SheriffBot testable, but I did the minimum
+ necessary. We should grow webkitcheckout over time to contain the
+ knowledge of ChangeLogs from scm.
+
+ * Scripts/webkitpy/commands/sheriffbot.py:
+ * Scripts/webkitpy/commands/sheriffbot_unittest.py:
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ * Scripts/webkitpy/patch/patcher.py:
+ * Scripts/webkitpy/webkitcheckout.py: Added.
+
+2010-03-19 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Fix Hyatt's IRC nickname.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-03-19 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Add IRC nicknames for the non-reviewer committers.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-03-19 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ More reviewer IRC nicknames.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-03-19 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Add a bunch of IRC nicknames for reviewers.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-03-19 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Oliver Hunt.
+
+ Added USE_SYSTEM_MALLOC flag to build-webkit
+ https://bugs.webkit.org/show_bug.cgi?id=21272
+
+ Add system-alloc flag to build-webkit. It makes easy to switch
+ between system allocator and TCmalloc.
+
+ * Scripts/build-webkit:
+
+2010-03-19 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix.
+
+ Of course, I caused a regression in the file that isn't tested. :(
+
+ * Scripts/webkitpy/statusserver.py:
+
+2010-03-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add basic "who-broke-it" command and revision -> broken builder association code
+ https://bugs.webkit.org/show_bug.cgi?id=36352
+
+ The "what-broke" command prints builders and what revisions we suspect
+ broke them. who-broke-it prints revisions and what builders we suspect
+ they broke. The sheriff-bot needs this revision to broken builder mapping
+ so this change adds it!
+
+ * Scripts/webkitpy/buildbot.py:
+ * Scripts/webkitpy/commands/queries.py:
+
+2010-03-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Simplify BuildBot core builder code for easier re-use
+ https://bugs.webkit.org/show_bug.cgi?id=36350
+
+ I simply couldn't see anything through all this Yak-hair.
+
+ * Scripts/webkitpy/buildbot.py:
+ * Scripts/webkitpy/commands/queries.py:
+
+2010-03-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ committers.py should know IRC nicknames
+ https://bugs.webkit.org/show_bug.cgi?id=36349
+
+ I'll add the actual nicknames in another patch.
+
+ * Scripts/webkitpy/committers.py:
+ * Scripts/webkitpy/committers_unittest.py:
+
+2010-03-18 Anders Bakken <agbakken@gmail.com>
+
+ Reviewed by Simon Hausmann.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36318
+
+ QtLauncher runs as a GuiClient by default in Qt Embedded which will
+ make it try to connect to an existing GuiServer. This patch makes it
+ run like a stand-alone app.
+
+ * QtLauncher/main.cpp:
+ (LauncherApplication::LauncherApplication):
+
+2010-03-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Move find_green_to_red_transition out of "what-broke" onto Builder for easier re-use
+ https://bugs.webkit.org/show_bug.cgi?id=36345
+
+ * Scripts/webkitpy/buildbot.py:
+ * Scripts/webkitpy/commands/queries.py:
+
+2010-03-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Actually pass the IRC password to the IRC object
+ https://bugs.webkit.org/show_bug.cgi?id=36346
+
+ I wanted to do this before, but both patches were in flight. This
+ patch finally closes the loop and makes the IRCProxy system complete.
+
+ * Scripts/webkitpy/patch/patcher.py:
+
+2010-03-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add a StatusServer front end to the SVNRevision table on QueueStatusServer
+ https://bugs.webkit.org/show_bug.cgi?id=36344
+
+ No test because Browser was too hard to mock. :( I couldn't figure
+ out how to make Mock be a dictionary as well as an object.
+
+ * Scripts/webkitpy/statusserver.py:
+
+2010-03-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Split out CommitInfo class and add unit tests
+ https://bugs.webkit.org/show_bug.cgi?id=36343
+
+ Move more logic out of "what-broke" into a shared CommitInfo
+ class so that it can be used by other commands and unit tested.
+
+ * Scripts/webkitpy/commands/queries.py:
+ * Scripts/webkitpy/commitinfo.py: Added.
+ * Scripts/webkitpy/commitinfo_unittest.py: Added.
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-18 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Fix LayoutTests/http/tests/appcache/max-size.html
+ https://bugs.webkit.org/show_bug.cgi?id=36207
+
+ Implement setAppCacheMaximumSize() for Qt.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setAppCacheMaximumSize):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-03-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ QueueStatusServer should be able to log broken bots
+ https://bugs.webkit.org/show_bug.cgi?id=36341
+
+ We need to add a new table to the QueueStatusServer to store persistent
+ information for the SheriffBot. The new table will keep track of which
+ bots each SVN revision broke.
+
+ * QueueStatusServer/handlers/__init__.py:
+ * QueueStatusServer/handlers/svnrevision.py: Added.
+ * QueueStatusServer/handlers/updatebase.py: Added.
+ * QueueStatusServer/handlers/updatestatus.py:
+ * QueueStatusServer/handlers/updatesvnrevision.py: Added.
+ * QueueStatusServer/index.yaml:
+ * QueueStatusServer/main.py:
+ * QueueStatusServer/model/__init__.py:
+ * QueueStatusServer/model/svnrevision.py: Added.
+ * QueueStatusServer/templates/updatesvnrevision.html: Added.
+
+2010-03-18 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Add a new method to the Qt LayoutTestController for
+ changing media type and make the DRT support dry-run printing.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::dryRunPrint):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setMediaType):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-03-18 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Add upstream LayoutTests/platform/chromium* directories to the
+ baseline search path for new-run-webkit-tests in preparation for
+ upstreaming all of the Chromium baselines. Note that this does
+ not actually create the directories themselves, but that's okay.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36324
+
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+
+2010-03-18 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Anders Carlsson.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36327
+ Test that a plug-in can override Node methods of its element
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (normalizeOverride):
+ (pluginInvoke):
+ Override "normalize", and call back to let a test know that the plug-in was called.
+
+2010-03-17 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Add the concept of an "overrides" file for expectations so that we
+ can store test_expectations both upstream and downstream for a port
+ that runs both in webkit.org and in a separate repository (like
+ Chromium). Also add some unit tests for the expectations module.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36249
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations_test.py: Added.
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-03-18 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Add an overlay QGraphicsTextItem to QtLauncher so we can display FPS info
+ on the launcher and not on the terminal anymore.
+
+ [Qt] QtLauncher's FPS info should be displayed on an overlay text item
+ https://bugs.webkit.org/show_bug.cgi?id=36244
+
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::WebViewGraphicsBased):
+ (WebViewGraphicsBased::setFrameRateMeasurementEnabled):
+ (WebViewGraphicsBased::updateFrameRate):
+ * QtLauncher/webview.h:
+
+2010-03-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ First cut at SheriffBot
+ https://bugs.webkit.org/show_bug.cgi?id=36253
+
+ This patch contains a first attempt at writing a sheriff bot.
+ Currently, we're missing the logic that actually finds the SVN revision
+ numbers to complain about, but once we have that, we'll have the rest
+ of the infrustructure to ping IRC and to file bugs.
+
+ There's a lot to fill in for the SheriffBot, but this patch give us the
+ framework in which to do it.
+
+ This patch required a bit of refactoring of AbstractQueue because
+ SheriffBot is the first bot that doesn't process patches (it processes
+ SVN revisions). Accordingly, I've factored out AbstractPatchQueue to
+ hold the parts of AbstractQueue that are specific to dealing with
+ patches. Some of the choices here might not be obvious yet, but we can
+ tweak them as our needs become clearer.
+
+ * Scripts/webkitpy/commands/queues.py:
+ * Scripts/webkitpy/commands/queues_unittest.py:
+ * Scripts/webkitpy/commands/sheriffbot.py: Added.
+ * Scripts/webkitpy/commands/sheriffbot_unittest.py: Added.
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ Added a MockIRC object to the mock tool.
+ * Scripts/webkitpy/multicommandtool.py:
+ Added a finalize method so the tool can disconnect from IRC
+ cleanly instead of just droping the socket.
+ * Scripts/webkitpy/multicommandtool_unittest.py:
+ * Scripts/webkitpy/patch/patcher.py:
+ Added support for talking to IRC.
+ * Scripts/webkitpy/unittests.py:
+ We should add a commands/unittests.py file at some point to make
+ the commands module more self-contained.
+
+2010-03-18 Antti Koivisto <koivisto@iki.fi>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36102
+ [Qt] Scaling control API for tiled backing store
+
+ Add animated smooth zooming to Qt launcher when in tiled mode.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ (LauncherWindow::zoomAnimationFinished):
+ (LauncherWindow::applyZoom):
+ (LauncherWindow::zoomIn):
+ (LauncherWindow::zoomOut):
+ * QtLauncher/webview.h:
+ (WebViewGraphicsBased::graphicsWebView):
+
+2010-03-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Support using IRC accounts with a password
+ https://bugs.webkit.org/show_bug.cgi?id=36287
+
+ Add a global option to specify an IRC password so we can use the
+ sheriffbot account (which needs a password).
+
+ * Scripts/webkitpy/irc/ircbot.py:
+ * Scripts/webkitpy/irc/ircproxy.py:
+ * Scripts/webkitpy/patch/patcher.py:
+
+2010-03-18 Eric Seidel <eric@webkit.org>
+
+ Just fixing missing parenthesis typo, no review.
+
+ * Scripts/webkitpy/commands/queries.py: '%' has higher precedence than 'or', use parentheses.
+
+2010-03-18 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Adam Roben and Anders Carlsson.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36210
+ plugins/resize-from-plugin.html fails on some platforms
+
+ Turns out that most platforms don't use "cross-platform" main.cpp. Copied code added for
+ the test to their versions of the file.
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_set_window):
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp:
+ (NPP_SetWindow):
+
+2010-03-18 Leandro Pereira <leandro@profusion.mobi>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Add support to run-launcher to open the EFL example browser.
+ http://webkit.org/b/36181
+
+ * Scripts/webkitdirs.pm:
+ * Scripts/run-launcher:
+
+2010-03-18 Sergio Villar Senin <svillar@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Failing tests http/tests/misc/image-blocked-src-change.html
+ & http/tests/misc/image-blocked-src-no-change.html
+ https://bugs.webkit.org/show_bug.cgi?id=36227
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewConsoleMessage): print only the file name instead of the
+ whole URI when printing messages with local URI's
+
+2010-03-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Teach what-broke how to look up reviewer and author Committer objects by name
+ https://bugs.webkit.org/show_bug.cgi?id=36264
+
+ * Scripts/webkitpy/commands/queries.py:
+ - Add committer_by_name lookups for both reviewer and author
+ - Improve printing in the cases where lookups fail.
+ * Scripts/webkitpy/committers.py:
+ - Add committer_by_name
+ * Scripts/webkitpy/committers_unittest.py:
+ - Test committer_by_name
+
+2010-03-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ create-rollout should actually fill out the description
+ https://bugs.webkit.org/show_bug.cgi?id=36261
+
+ * Scripts/webkitpy/commands/download.py:
+ The % operator was applied to the wrong string.
+ * Scripts/webkitpy/commands/download_unittest.py:
+ * Scripts/webkitpy/commands/upload_unittest.py:
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ Add support for seeing what we actually do with create_bug.
+
+2010-03-17 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Accelerated Compositing is now default on QtWebKit so the option
+ in QtLauncher must be true as default.
+
+ [Qt] QtLauncher's Accelerated Compositing option must be true as default
+ https://bugs.webkit.org/show_bug.cgi?id=36234
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::applyPrefs):
+ (LauncherWindow::toggleAcceleratedCompositing):
+ (LauncherApplication::handleUserOptions):
+
+2010-03-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Commit queue should ignore (probably red) builders when landing rollouts
+ https://bugs.webkit.org/show_bug.cgi?id=36169
+
+ When landing a rollout, the builders are probably red, so we need to
+ ignore them in the subprocess too. Also, we might as well update the
+ working copy because we haven't validated anything about the current
+ revision prior to trying to land.
+
+ This change is testable, but it requires changing the mock executive to
+ log its arguments. That will generate a lot of expectation changes, so
+ I'd like to do that in a separate patch.
+
+ * Scripts/webkitpy/commands/queues.py:
+
+2010-03-17 Chang Shu <chang.shu@nokia.com>
+
+ Reviewed by Laszlo Gombos.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36139
+ [Qt] Clean up cache each time DumpRenderTree starts. This behavior
+ matches other platforms, such as mac and gtk.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2010-03-17 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Turns out this needs to be a string.
+
+ * Scripts/webkitpy/bugzilla.py:
+
+2010-03-17 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add more infrastructure for sheriff-bot, including making what-broke more awesome
+ https://bugs.webkit.org/show_bug.cgi?id=36254
+
+ * Scripts/webkitpy/bugzilla.py:
+ - Made the various URL methods return None when passed None.
+ * Scripts/webkitpy/bugzilla_unittest.py:
+ - Test that the url methods work as expected.
+ * Scripts/webkitpy/buildbot.py:
+ - Add a static Build.build_url so that its possible to generate a build url without a Build object.
+ - Give users a URL in _fetch_xmlrpc_build_dictionary error message.
+ * Scripts/webkitpy/changelogs.py:
+ - Add a new ChangeLogEntry class to encapsulate entry-parsing logic.
+ - Add is_path_to_changelog to greatly simplify SCM.modified_changelogs code.
+ - Make ChangeLog.parse_latest_entry_from_file a public method.
+ * Scripts/webkitpy/changelogs_unittest.py:
+ - Add tests for new ChangeLog entry parsing.
+ * Scripts/webkitpy/commands/queries.py:
+ - Make "what-broke" not print "ok" builders, only failing ones.
+ - Print much more information on failing builders, including links and authorship/reviewer information.
+ * Scripts/webkitpy/commands/queues_unittest.py:
+ - Use a fake_checkout path since fixing the cwd (as part of fixing scm_unittests.py) was breaking tests.
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ - Move MockSCM away from using os.getcwd() as that was fragile (and wrong).
+ * Scripts/webkitpy/patch/patcher.py:
+ - Remove code which was broken now that this file has moved.
+ - Code was also redundant now that SCM.find_checkout_root() exists.
+ * Scripts/webkitpy/scm.py:
+ - Greatly simplify modified_changelogs now that I understand list comprehensions.
+ - Expect ChangeLogEntry objects instead of raw strings.
+ - Add changed_files_for_revision, committer_email_for_revision and contents_at_revision
+ - Add commit_with_message argument to all sites since someone half-added it before. :(
+ - Get rid of copy/paste code using _status_regexp()
+ * Scripts/webkitpy/scm_unittest.py:
+ - Fix these tests!
+ - Add new tests for new scm code.
+ - Fix spelling of "awsome" to "awesome".
+
+2010-03-17 Daniel Bates <dbates@rim.com>
+
+ Rubber-stamped by David Levin.
+
+ Add myself to the list of reviewers.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-03-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Change post-rollout to create-rollout and have it make a new bug
+ instead of posting the rollout to the old bug.
+ https://bugs.webkit.org/show_bug.cgi?id=36250
+
+ The new bug blocks the old bug instead of adding more complexity to the
+ old bug. One tricky question is whether to create the bug if we're
+ unable to create a rollout patch. In this patch, we do create the bug,
+ but we might revist this question in the future.
+
+ * Scripts/webkitpy/bugzilla.py:
+ * Scripts/webkitpy/commands/download.py:
+ * Scripts/webkitpy/commands/download_unittest.py:
+ * Scripts/webkitpy/steps/createbug.py:
+
+2010-03-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add a way for the bots to send messages to IRC
+ https://bugs.webkit.org/show_bug.cgi?id=36235
+
+ We'll use these classes to notify #webkit about bad SVN revisions.
+ This patch just has some skeleton code for us to play with.
+
+ * Scripts/webkitpy/irc/__init__.py: Added.
+ * Scripts/webkitpy/irc/ircbot.py: Added.
+ A bot that knows how to talk to IRC.
+ * Scripts/webkitpy/irc/ircproxy.py: Added.
+ We need to run the bot on its own thread because the irclib needs
+ its own mainloop. This class provides an abstraction of the
+ threading.
+ * Scripts/webkitpy/irc/messagepump.py: Added.
+ * Scripts/webkitpy/irc/messagepump_unittest.py: Added.
+ * Scripts/webkitpy/irc/threadedmessagequeue.py: Added.
+ A thread-safe message queue for sending messages from the main
+ thread to the IRC thread.
+ * Scripts/webkitpy/irc/threadedmessagequeue_unittest.py: Added.
+ * Scripts/webkitpy/irc/unittests.py: Added.
+ * Scripts/webkitpy/thirdparty/autoinstalled/__init__.py:
+ Autoinstall irclib
+ * Scripts/webkitpy/unittests.py:
+
+2010-03-17 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Fix image_diff syntax in webkitpy/port/base.py.
+ The syntax is wrong if diff_filename is specified.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36230
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+
+2010-03-16 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ Provide to QtLauncher a way to change the ViewportUpdateMode
+ when it's in graphics based mode.
+
+ [Qt] Make QtLaucher able to select the ViewportUpdateMode
+ https://bugs.webkit.org/show_bug.cgi?id=36175
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::selectViewportUpdateMode):
+ (LauncherWindow::createChrome):
+
+2010-03-17 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Ambiguous error message when building for unspecified platform
+ https://bugs.webkit.org/show_bug.cgi?id=30203
+
+ Add an extra line information to the error message.
+
+ * Scripts/webkitdirs.pm:
+
+2010-03-16 Adam Barth <abarth@webkit.org>
+
+ No review, rolling out r56044.
+ http://trac.webkit.org/changeset/56044
+ https://bugs.webkit.org/show_bug.cgi?id=36048
+
+ This patch broke Windows Debug (Tests)
+
+ * Scripts/webkitdirs.pm:
+
+2010-03-16 John Abd-El-Malek <jam@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ Give keyboard focus to PluginDocuments by default
+ https://bugs.webkit.org/show_bug.cgi?id=36147
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+ (NPP_SetWindow):
+ (handleEventCarbon):
+ (handleEventCocoa):
+
+2010-03-16 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Fix run-webkit-httpd on Windows.
+
+ * Scripts/webkitperl/httpd.pm:
+
+2010-03-16 Alexey Proskuryakov <ap@apple.com>
+
+ Tiger build fix.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp: (pluginGetProperty):
+ Added more type casts to shut down warnings.
+
+2010-03-16 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36184
+ YouTube video resizing doesn't work with OOP plug-ins
+
+ Added a resizeTo() method, which calls resizePlugin() in JS with the same arguments,
+ and a lastSetWindowArguments property, which returns a string describing the last NPWindow
+ passed to NPN_SetWindow.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginGetProperty):
+ (testResizeTo):
+ (pluginInvoke):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_SetWindow):
+
+2010-03-16 Joanmarie Diggs <joanmarie.diggs@gmail.com>
+
+ Reviewed by Xan Lopez.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35504
+ [Gtk] Evaluate and fix AtkTable for layout tables
+
+ Implements rowCount and columnCount for Gtk in DRT.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::rowCount):
+ (AccessibilityUIElement::columnCount):
+
+2010-03-15 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add "what-broke" command for debugging when the tree broke
+ https://bugs.webkit.org/show_bug.cgi?id=36157
+
+ This is another step towards automated sheriffing of the webkit tree.
+ With this logic our scripts are able to determine what revision broke the
+ tree. Buildbot should do this for us, but unfortunately buildbot doesn't
+ expose this kind of aggregate information.
+
+ * Scripts/webkitpy/buildbot.py:
+ - Add new Builder and Build classes (which will eventually replace the custom dictionaries previously used).
+ - Split out more network logic into _fetch methods which will eventually be their own class for mocking.
+ - Use XMLRPC to communicate with the buildbot master instead of scraping build pages.
+ * Scripts/webkitpy/buildbot_unittest.py:
+ - Test the newly added buildbot classes.
+ * Scripts/webkitpy/commands/queries.py:
+ - Add an experimental what-broke command.
+
+2010-03-15 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36048
+
+ Detect if the Windows Platform SDK is missing when building with
+ Visual C++ Express Edition and inform the user to download it.
+
+ * Scripts/webkitdirs.pm:
+
+2010-03-15 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Let commit-queue land rollout patches even when the tree is red
+ https://bugs.webkit.org/show_bug.cgi?id=36155
+
+ Now the commit-queue will land patches whose name begins with "ROLLOUT "
+ even if the tree is red. The patches still go through the usual build
+ and test process, but they can be landed while the tree is on fire.
+
+ * Scripts/webkitpy/bugzilla.py:
+ * Scripts/webkitpy/commands/queues.py:
+ * Scripts/webkitpy/commands/queues_unittest.py:
+ * Scripts/webkitpy/commands/queuestest.py:
+ * Scripts/webkitpy/mock_bugzillatool.py:
+
+2010-03-15 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add webkit-patch post-rollout to upload rollouts to bugs.webkit.org for easy committing
+ https://bugs.webkit.org/show_bug.cgi?id=36154
+
+ This new command is a mashup of prepare-rollout and post. This command
+ will be used by an experimental bot to post rollouts of patches that
+ break things to bugs.webkit.org where they can be landed with the
+ greatest of ease.
+
+ * Scripts/webkitpy/commands/download.py:
+ * Scripts/webkitpy/commands/download_unittest.py:
+ * Scripts/webkitpy/steps/__init__.py:
+ * Scripts/webkitpy/steps/postdiffforrevert.py: Added.
+
+2010-03-15 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch rollout should error out on conflicts
+ https://bugs.webkit.org/show_bug.cgi?id=36151
+
+ Instead of blindingly plowing ahead, we now throw an exception if there
+ are conflicts after applying a reverse diff.
+
+ * Scripts/webkitpy/scm.py:
+
+2010-03-15 Chris Fleizach <cfleizach@apple.com>
+
+ Unreviewed layout test fix.
+
+ VO not able to perform a VO-spacebar on facebook links
+ https://bugs.webkit.org/show_bug.cgi?id=36132
+
+ GTK needs to implement press for this test to work.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::press):
+
+2010-03-15 Chris Fleizach <cfleizach@apple.com>
+
+ Unreviewed layout test fix.
+
+ VO not able to perform a VO-spacebar on facebook links
+ https://bugs.webkit.org/show_bug.cgi?id=36132
+
+ Windows needs to implement press in DRT.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::press):
+
+2010-03-15 Chris Fleizach <cfleizach@apple.com>
+
+ Unreviewed. Fix break of layout tests on win and gtk.
+
+ VO not able to perform a VO-spacebar on facebook links
+ https://bugs.webkit.org/show_bug.cgi?id=36132
+
+ Attempting to implement press action for windows and gtk.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::press):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::press):
+
+2010-03-15 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ VO not able to perform a VO-spacebar on facebook links
+ https://bugs.webkit.org/show_bug.cgi?id=36132
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (pressCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::press):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::press):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::press):
+
+2010-03-15 Mark Rowe <mrowe@apple.com>
+
+ Add a new build slave to replace the existing SnowLeopard Leaks build slave which
+ appears to be suffering a slow and painful death at the hands of its graphics hardware.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2010-03-15 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Fix a minor case where we'd deference a null pointer if we tried
+ to run new-run-webkit-tests on an unsupported platform (e.g.
+ Cygwin's python version).
+
+ https://bugs.webkit.org/show_bug.cgi?id=36076
+
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+
+2010-03-15 Darin Adler <darin@apple.com>
+
+ Tell Subversion about more directories that expect to have .pyc files.
+
+ * Scripts/webkitpy/layout_tests: Added property svn:ignore.
+ * Scripts/webkitpy/layout_tests/port: Added property svn:ignore.
+
+2010-03-15 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Operational scripts from running the EWS
+ https://bugs.webkit.org/show_bug.cgi?id=36097
+
+ These are the scripts I use to manage the EWS on EC2. If someone other
+ than me wants to run the EWS, these scripts might be helpful.
+
+ * EWSTools/boot.sh: Added.
+ * EWSTools/create-webkit-git: Added.
+ * EWSTools/screen-config: Added.
+ * EWSTools/start-queue.sh: Added.
+
+2010-03-14 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ Fix the webkit-patch bots. Turns out they need the path of the main
+ script to run properly.
+
+ * Scripts/webkit-patch:
+ * Scripts/webkitpy/patch/patcher.py:
+
+2010-03-14 Darin Adler <darin@apple.com>
+
+ Tell Subversion about more directories that expect to have .pyc files.
+
+ * Scripts/webkitpy/init: Added property svn:ignore.
+ * Scripts/webkitpy/patch: Added property svn:ignore.
+ * Scripts/webkitpy/thirdparty: Added property svn:ignore.
+ * Scripts/webkitpy/thirdparty/autoinstalled: Added property svn:ignore.
+
+2010-03-14 Antti Koivisto <koivisto@iki.fi>
+
+ Reviewed by Simon Hausmann.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35146
+ Support tiled backing store
+
+ QtLauncher support and build flag in build-webkit.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::applyPrefs):
+ (LauncherWindow::toggleTiledBackingStore):
+ (LauncherWindow::toggleResizesToContents):
+ (LauncherWindow::createChrome):
+ (LauncherApplication::handleUserOptions):
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::WebViewGraphicsBased):
+ (WebViewGraphicsBased::setResizesToContents):
+ (WebViewGraphicsBased::resizeEvent):
+ * QtLauncher/webview.h:
+ * Scripts/build-webkit:
+
+2010-03-13 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ The webkit-patch script now displays a warning if run using
+ a version of Python less than 2.5. This will help users
+ understand why webkit-patch is erroring out if they are
+ using Python 2.4, for example.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31533
+
+ * Scripts/webkit-patch:
+ - Moved most of the file contents to webkitpy/patch/patcher.py
+ so the Python version can be checked before interpreting
+ any code that can cause the script to error out.
+ - Added a configure_logging() method to enable any version
+ warnings to show up.
+ - Added a main() method with calls to configure_logging(),
+ check_version(), and the main webkit patch method.
+
+ * Scripts/webkitpy/patch/__init__.py: Copied from WebKitTools/QueueStatusServer/filters/__init__.py.
+ - This file is required to make a folder a package.
+
+ * Scripts/webkitpy/patch/patcher.py: Added.
+ - Moved code from Scripts/webkit-patch.
+
+2010-03-13 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Changed test-webkitpy so that messages logged as a side-effect
+ of unit-testing code do not get displayed to the screen. These
+ messages clutter up the unit test results if not filtered out.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35835
+
+ * Scripts/test-webkitpy:
+ - Adjusted the configure_logging() method to filter out any
+ log messages from webkitpy.
+ - Also added an INFO message stating that most console logging
+ is getting suppressed.
+
+ * Scripts/webkitpy/init/versioning.py:
+ - Added a log parameter to the check_version() method.
+
+ * Scripts/webkitpy/init/versioning_unittest.py:
+ - Qualified a call to check_version() with the parameter names.
+
+2010-03-13 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ The test-webkitpy script now warns the user if the script is
+ being run using a Python version different from the minimum
+ version the webkitpy package was meant to support.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35788
+
+ Warning developers if their Python version is too low will help
+ them understand why test-webkitpy is failing. Secondly, warning
+ developers if their Python version is higher than the minimum will
+ help them understand that their changes may not be okay for the
+ minimum supported version, even if test-webkitpy is passing.
+
+ * Scripts/test-webkitpy:
+ - Moved the "from ..._unittest import *" lines to the new
+ file Scripts/webkitpy/unittests.py. This will allow the
+ version-check warning to be displayed even if an error occurs
+ while interpreting (i.e. importing) the unit test code.
+ - Added configure_logging() to configur logging for test-webkitpy.
+ - Added an init() method to configure logging and check the
+ current Python version.
+
+ * Scripts/webkitpy/init/unittests.py: Added.
+ - Added a file to import all unit test modules in the
+ webkitpy.init package.
+
+ * Scripts/webkitpy/init/versioning.py: Added.
+ - Added a _MINIMUM_SUPPORTED_PYTHON_VERSION variable and set
+ it equal to 2.5.
+ - Added a compare_version() method to compare the current Python
+ version against a target version.
+ - Added a check_version() method to check the current Python
+ version against the current minimum supported version, and to
+ log a warning message if the check fails.
+
+ * Scripts/webkitpy/init/versioning_unittest.py: Added.
+ - Added unit tests for the functions in versioning.py.
+
+ * Scripts/webkitpy/style/unittests.py:
+ - Fixed/updated a code comment.
+
+ * Scripts/webkitpy/unittests.py: Added.
+ - Moved the "from ..._unittest import *" lines from test-webkitpy.
+
+2010-03-13 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Moved all code in webkitpy/__init__.py to another location.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35828
+
+ Keeping webkitpy/__init__.py free of non-trivial code allows
+ calling code to import initialization code from webkitpy
+ before any errors or log messages occur due to code in
+ __init__.py. Such initialization code can include things like
+ version checking code and logging configuration code. This
+ also lets us move the autoinstall initialization code to a
+ location where it only executes if it is needed -- something
+ we have done in this patch.
+
+ * Scripts/webkitpy/__init__.py:
+ - Moved all executable code to the following location:
+ webkitpy/thirdparty/autoinstalled/__init__.py
+ - Added a code comment to keep this file free of non-trivial
+ code.
+
+ * Scripts/webkitpy/bugzilla.py:
+ - Updated mechanize import statement.
+
+ * Scripts/webkitpy/networktransaction.py:
+ - Updated mechanize import statement.
+
+ * Scripts/webkitpy/networktransaction_unittest.py:
+ - Updated mechanize import statement.
+
+ * Scripts/webkitpy/statusserver.py:
+ - Updated mechanize import statement.
+
+ * Scripts/webkitpy/thirdparty/autoinstalled/__init__.py: Added.
+ - Copied the code from webkitpy/__init__.py and updated it
+ as necessary.
+
+2010-03-13 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Moved webkitpy/mock.py into webkitpy/thirdparty since it is
+ third-party code.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35499
+
+ Updated the import statement in all of the below except where noted.
+
+ * Scripts/webkitpy/bugzilla_unittest.py:
+ * Scripts/webkitpy/commands/commandtest.py:
+ * Scripts/webkitpy/commands/download_unittest.py:
+ * Scripts/webkitpy/commands/early_warning_system_unittest.py:
+ * Scripts/webkitpy/commands/queries_unittest.py:
+ * Scripts/webkitpy/commands/queues_unittest.py:
+ * Scripts/webkitpy/commands/queuestest.py:
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/commands/upload_unittest.py:
+ * Scripts/webkitpy/commands_references.py: Added.
+ - Added a file containing an absolute import of Mock so that
+ the imports in the commands folder can import from this file
+ (similar to style_references.py). This helps limit the
+ number of affected files in future refactorings.
+
+ * Scripts/webkitpy/credentials_unittest.py:
+ * Scripts/webkitpy/mock.py: Removed.
+ - Moved to Scripts/webkitpy/thirdparty.
+
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ * Scripts/webkitpy/patchcollection_unittest.py:
+ * Scripts/webkitpy/steps/closebugforlanddiff_unittest.py:
+ * Scripts/webkitpy/steps/steps_unittest.py:
+ * Scripts/webkitpy/steps/updatechangelogswithreview_unittests.py:
+ * Scripts/webkitpy/steps_references.py: Added.
+ - Added a file containing an absolute import of Mock so that
+ the imports in the steps folder can import from this file
+ (similar to style_references.py). This helps limit the
+ number of affected files in future refactorings.
+
+ * Scripts/webkitpy/thirdparty/mock.py: Copied from WebKitTools/Scripts/webkitpy/mock.py.
+ - Also eliminated trailing white space and carriage returns.
+
+2010-03-12 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Amend incorrect typo patch for QtLauncher.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35877
+
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::setFrameRateMeasurementEnabled):
+
+2010-03-13 Victor Wang <victorw@chromium.org>
+
+ Add appengine app to host and serve webkit layout test results.
+
+ The app allows you post test result files (json) and serve them up.
+ Chromium flakiness dashboard will first use this app to host results.json
+ and expectations.json, but the files hosted by this app are not limited
+ to chromium results or json files. It can be used to host other files if needed.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35944
+
+ * TestResultServer: Added.
+ * TestResultServer/app.yaml: Added.
+ * TestResultServer/handlers: Added.
+ * TestResultServer/handlers/__init__.py: Added.
+ * TestResultServer/handlers/menu.py: Added.
+ * TestResultServer/handlers/testfilehandler.py: Added.
+ * TestResultServer/index.yaml: Added.
+ * TestResultServer/main.py: Added.
+ * TestResultServer/model: Added.
+ * TestResultServer/model/__init__.py: Added.
+ * TestResultServer/model/testfile.py: Added.
+ * TestResultServer/stylesheets: Added.
+ * TestResultServer/stylesheets/form.css: Added.
+ * TestResultServer/stylesheets/menu.css: Added.
+ * TestResultServer/stylesheets/testfile.css: Added.
+ * TestResultServer/templates: Added.
+ * TestResultServer/templates/menu.html: Added.
+ * TestResultServer/templates/showfilelist.html: Added.
+ * TestResultServer/templates/uploadform.html: Added.
+
+2010-03-13 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by David Levin.
+
+ new-run-webkit-tests fails with --debug option.
+ https://bugs.webkit.org/show_bug.cgi?id=36067
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+
+2010-03-13 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Add "Show FPS" menu option to QtLauncher.
+
+ [Qt] QtLauncher need a menu option to show/hide FPS
+ https://bugs.webkit.org/show_bug.cgi?id=35794
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::showFPS):
+ (LauncherWindow::createChrome):
+
+2010-03-13 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Add a "Toggle FullScreen" option to QtLauncher Menu.
+
+ [Qt] QtLauncher needs an option to toggle FullScreen Mode
+ https://bugs.webkit.org/show_bug.cgi?id=35755
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::init):
+ (LauncherWindow::eventFilter):
+ (LauncherWindow::initializeView):
+ (LauncherWindow::toggleFullScreenMode):
+ (LauncherWindow::createChrome):
+
+2010-03-12 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Fix typo in websocket_server (path_from_base instead of
+ path_from_chromium_base).
+
+ https://bugs.webkit.org/show_bug.cgi?id=36074
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+
+2010-03-12 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ new-run-webkit-tests --new-baseline doesn't work at all.
+
+ It attempts to call a method that isn't defined. To fix it, I
+ removed the unnecessary and unnecessarily confusing 'platform'
+ argument to the test_type constructor and use the Port object that
+ is passed in instead, since we are only ever generating a baseline
+ from the port that is currently executing.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36046
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+
+2010-03-12 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Fix new-run-webkit-tests --run-singly
+
+ This script option is currently broken - the script attempts to
+ dereference methods and variables that don't exist, which causes
+ the Chromium Linux valgrind bot to be quite unhappy. This has been
+ broken since r54449 when I renamed Port.start_test_driver to
+ Port.start_driver.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36042
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_shell_thread.py:
+
+2010-03-12 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Fix critical being printed to stderr on every test. This is
+ because the jar is only being created when soup hits the HTTP
+ path. We should reconsider the time of its creation.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2010-03-12 Adam Roben <aroben@apple.com>
+
+ Teach prepare-ChangeLog to find modified selectors in CSS files
+
+ Reviewed by Tim Hatcher.
+
+ Fixes <http://webkit.org/b/36064> prepare-ChangeLog should extract
+ modified selectors from CSS files
+
+ * Scripts/prepare-ChangeLog:
+ (get_function_line_ranges): Call get_selector_line_ranges_for_css for
+ .css files.
+ (get_selector_line_ranges_for_css): Added. Finds selectors and their
+ line ranges and returns them.
+
+2010-03-12 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Build fix (for EWS). Make sure the new code builds on older soup.
+
+ Thanks to Dan Winship.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setAlwaysAcceptCookies):
+
+2010-03-12 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Eric Carlson.
+
+ [GTK] DRT does not handle cookie policy setting
+ https://bugs.webkit.org/show_bug.cgi?id=36056
+
+ Implement cookie accept policy setting for GTK+'s LayoutTestController.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setAlwaysAcceptCookies):
+
+2010-03-12 Adam Langley <agl@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [chromium]: update Linux layout test scripts for RedHat like systems.
+
+ (Tested on Fedora 12.)
+
+ https://bugs.webkit.org/show_bug.cgi?id=35867
+
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+
+2010-03-12 Adam Roben <aroben@apple.com>
+
+ Make svn-create-patch's diffs of ObjC header files more readable
+
+ Fixes <http://webkit.org/b/36055>.
+
+ Reviewed by John Sullivan.
+
+ * Scripts/svn-create-patch:
+ (diffOptionsForFile): Added. Returns the options that should be passed
+ to diff for the given file. All the options are the same for all
+ files, except for the option to specify which lines should be used as
+ hunk headers.
+ (generateDiff): Use diffOptionsForFile to get the options to pass to
+ diff.
+ (hunkHeaderLineRegExForFile): Added. Returns the regular expression
+ that should be used by diff to identify lines that should be included
+ after the "@@" in the hunk header lines of the diff. For ObjC[++]
+ source files, we use any lines starting with -, +, or
+ @implementation/@interface/@protocol. For ObjC[++] header files (which
+ we assume to be any .h files in a mac/ or objc/ directory), we use any
+ lines starting with @implementation/@interface/@protocol.
+
+2010-03-12 Jochen Eisinger <jochen@chromium.org>
+
+ Reviewed by Jeremy Orlow.
+
+ Introduce setWillSendRequestClearHeader to LayoutTestController to selectively remove headers in willSendRequest. Used in http/tests/security/no-referrer.html
+ https://bugs.webkit.org/show_bug.cgi?id=35920
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setWillSendRequestClearHeaderCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::willSendRequestClearHeaders):
+ (LayoutTestController::setWillSendRequestClearHeader):
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:resource:willSendRequest:redirectResponse:fromDataSource:]):
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::willSendRequest):
+
+2010-03-11 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed.
+
+ Fix typo in websocket_server.py
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+
+2010-03-11 Garret Kelly <gdk@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Fixing minor typo in the commit queue status page.
+ https://bugs.webkit.org/show_bug.cgi?id=35979
+
+ * Scripts/webkitpy/commands/queues.py:
+
+2010-03-11 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed.
+
+ Fix for WebSocket layout test runner on chromium/win port.
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py: register_cygwin and set CYGWIN_PATH
+
+2010-03-11 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by David Kilzer.
+
+ <rdar://problem/7745082> Make it possible to build WebKit for older Mac OS X versions from the current Mac OS X version
+
+ Default to using the appropriate SDK if the target Mac OS X version is not the current Mac OS X version.
+
+ * DumpRenderTree/mac/Configurations/Base.xcconfig:
+
+2010-03-11 Victor Wang <victorw@chromium.org>
+
+ Reviewed by dglazkov@chromium.org.
+
+ rebaseline_chromium_webkit_tests can generate new baselines for
+ all platforms so it needs to know two ports in order to work correctly:
+ the port that the script is running on and the port that it generates
+ new baselines for. Update rebaselining tool to handle both port correctly.
+
+ https://bugs.webkit.org/show_bug.cgi?id=36032
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-03-11 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Tim Hatcher.
+
+ <rdar://problem/7745082> Make it possible to build WebKit for older Mac OS X versions from the current Mac OS X version
+
+ Introduce TARGET_MAC_OS_X_VERSION_MAJOR to represent the Mac OS X version that is being targeted. It defaults to the
+ current Mac OS X version unless otherwise specified.
+
+ Key off TARGET_MAC_OS_X_VERSION_MAJOR where we'd previously been keying off MAC_OS_X_VERSION_MAJOR.
+
+ Explicitly map from the target Mac OS X version to the preferred compiler since Xcode's default compiler choice
+ may not be usable when targetting a different Mac OS X version.
+
+ Key off TARGET_GCC_VERSION rather than MAC_OS_X_VERSION_MAJOR in locations where we'd previously been keying off
+ MAC_OS_X_VERSION_MAJOR but the decision is really related to the compiler version being used.
+
+ * DumpRenderTree/mac/Configurations/Base.xcconfig:
+ * DumpRenderTree/mac/Configurations/DebugRelease.xcconfig:
+ * DumpRenderTree/mac/DumpRenderTree.mm: Wrap the include of mach-o/getsect.h in 'extern "C"' as some versions of the
+ header in older SDKs do not do this inside the header.
+
+2010-03-11 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35965
+ <rdar://problem/7742771> Crash when passing an object returned from plug-in back to the plug-in
+
+ Made rememberedObject a member of PluginObject. A plug-in must not use its references
+ to browser NPObjects after being destroyed, but this wasn't the case with static variable.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginInvoke):
+ (pluginInvalidate):
+ (pluginAllocate):
+ (pluginDeallocate):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+
+2010-03-11 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35905
+ REGRESSION(55699?): media/video-no-autoplay.html times out on Leopard Commit Bot
+
+ Make sure we reset the WebGL preference, so that WebGL doesn't get left
+ on after being enabled via layoutTestController.overridePreference(),
+ which in turn causes accelerated compositing to be enabled on Leopard
+ when we don't want it to be.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+
+2010-03-10 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ rebaseline_chromium_webkit_tests doesn't handle other plaforms
+ correctly (e.g., if you run on the Mac platform and try to
+ rebaseline the WIN results, the result gets written into
+ platform/mac instead of platform/chromium-win). Also, this script
+ doesn't work on non-Chromium ports, so we need to fix that at some
+ point.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35982
+
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-03-10 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Simon Hausmann.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35840
+
+ Updates the subroutine builtDylibPathForName() so that it adds the "d" suffix to
+ the QtWebKit library name on Windows. This change makes run-launcher work again
+ under Windows. Moreover, this change corresponds to the change made in change-
+ set 53924 <http://trac.webkit.org/changeset/53924>.
+
+ * Scripts/webkitdirs.pm:
+
+2010-03-10 Adam Roben <aroben@apple.com>
+
+ Roll out the prepare-ChangeLog part of r55870
+
+ This change wasn't needed (prepare-ChangeLog calls svn-create-patch
+ when it's asked to print out diffs for the user) and was screwing up
+ its ability to find changed function names.
+
+ * Scripts/prepare-ChangeLog:
+ (diffCommand): Change the options we pass to svn-diff back to their
+ pre-r55870 form.
+
+2010-03-10 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Add Support for WebKitEnableCaretBrowsing to Qt DRT
+
+ Unskip test fast/events/multiline-link-arrow-navigation.html
+
+ https://bugs.webkit.org/show_bug.cgi?id=35593
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::overridePreference):
+ (LayoutTestController::setCaretBrowsingEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-03-10 Robert Hogan <robert@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ QtLauncher: Fix typo in conditional statement in
+ WebViewGraphicsBased::setFrameRateMeasurementEnabled.
+
+ '=' should be '=='!
+
+ https://bugs.webkit.org/show_bug.cgi?id=35877
+
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::setFrameRateMeasurementEnabled):
+
+2010-03-10 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Refactored and cleaned up the code for unit-testing logging.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35845
+
+ * Scripts/webkitpy/init/logtesting.py:
+ - Added more information to the module docstring.
+ - Added an assertMessages() method to the UnitTestLogStream
+ class. This simplifies the calling code.
+ - Renamed the UnitTestLog class to LogTesting, and reformulated
+ it as follows:
+ - Moved the logging configuration code from the __init__
+ method to a new static setUp() method.
+ - Documented the __init__ method to be private.
+ - Improved the code so that the root logger does not have
+ its logging level changed. Instead we set the handler's
+ level. This makes the unit testing more unintrusive.
+ - Updated the assertMessages() method to call the
+ UnitTestLogStream class's assertMessages() method.
+ - More fully documented the class.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added a logger parameter to the configure_logging() method.
+ This allows us to prevent test messages from being sent
+ to the root logger during unit testing, which may be
+ rendering to the screen, etc.
+ - Simplified the code by removing the _LevelLoggingFilter class.
+ - Replaced the _LevelLoggingFilter class with a one-line lambda
+ expression in configure_logging().
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Changed relative imports to absolute to comply more with PEP8.
+ - In the ConfigureLoggingTest class:
+ - Changed the setUp() method to prevent test messages from
+ being propagated to the root logger.
+ - Changed the _log() method to a data attribute.
+ - Updated to accommodate changes to logtesting.py.
+
+ * Scripts/webkitpy/style_references.py:
+ - Updated an import statement.
+
+2010-03-10 Evan Martin <evan@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Python code for GDB 7 to support native printing of some WebCore types.
+
+ * gdb/webcore.py: Added.
+
+2010-03-10 Adam Roben <aroben@apple.com>
+
+ Make svn-create-patch and prepare-ChangeLog show better section
+ headings for ObjC files
+
+ This makes the text at the end of each "@@" line in a diff actually
+ show the ObjC method or interface that contains the change, rather
+ than whatever the most-recently-defined C function was.
+
+ Fixes <http://webkit.org/b/35970>.
+
+ Reviewed by John Sullivan.
+
+ * Scripts/svn-create-patch: Pass -F'^[-+@]' to diff so that it will
+ treat any lines starting with -, +, or @ as section heading lines.
+ This works well for ObjC files, and shouldn't affect other types of
+ files.
+
+ * Scripts/prepare-ChangeLog: Changed the options passed to diff to
+ match those used in svn-create-patch.
+
+2010-03-10 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Link QtLauncher against the WebKit library using a relative rpath.
+
+ This makes the launcher and the lib relocatable.
+
+ * QtLauncher/QtLauncher.pro:
+
+2010-03-10 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Rubber-stamped by Simon Hausmann.
+
+ [iExploder] Add new CSS Properties and HTML Attributes
+
+ The update-iexploder-cssproperties script was used to update
+ the various input files. The autobuffer HTML Attribute was removed
+ from WebKit and I manually added it back to the htmlattrs.in like
+ we have done it for other attributes in the past.
+
+ * iExploder/htdocs/cssproperties.in:
+ * iExploder/htdocs/htmlattrs.in:
+ * iExploder/htdocs/htmltags.in:
+
+2010-03-09 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed.
+
+ Obvious fix for --cgi-paths of pywebsocket.
+
+ * Scripts/run-webkit-websocketserver:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+
+2010-03-09 Jakub Wieczorek <jwieczorek@webkit.org>
+
+ Unreviewed.
+
+ Adding myself to committers.py.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-03-09 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Nate Chapin.
+
+ Fix --clobber-old-results in new-run-webkit-tests.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35778
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-03-09 Andy Estes <aestes@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ Add the ability to dispatch scroll wheel events in DRT. This was
+ necessary in order to write a test for
+ https://bugs.webkit.org/show_bug.cgi?id=34700.
+
+ * DumpRenderTree/mac/EventSendingController.mm: Add support for two
+ new methods to EventSender: mouseScrollBy(x, y) and
+ continuousMouseScrollBy(x, y). The API to generate scroll events on
+ the mac was added in 10.5, so these methods are NOOPs on Tiger.
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ Regiester mouseScrollByX:andY: and continuousMouseScrollByX:andY:
+ (+[EventSendingController webScriptNameForSelector:]): Map JavaScript
+ method names to ObjC selectors.
+ (-[EventSendingController mouseScrollByX:andY:continuously:]): Generate
+ a scroll wheel event using CGEventCreateScrollWheelEvent() and dispatch
+ it to WebKit.
+ (-[EventSendingController continuousMouseScrollByX:andY:]): Generate a
+ continuous scrolling event by x and y pixels.
+ (-[EventSendingController mouseScrollByX:andY:]): Generate a notchy
+ scrolling event by x and y lines.
+
+2010-03-09 Chris Fleizach <cfleizach@apple.com>
+
+ DRT build fix for Tiger. No review.
+
+ AX: hit testing a list box doesn't work anymore
+ https://bugs.webkit.org/show_bug.cgi?id=35893
+
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::elementAtPoint):
+
+2010-03-09 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ AX: hit testing a list box doesn't work anymore
+ https://bugs.webkit.org/show_bug.cgi?id=35893
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (getElementAtPointCallback):
+ (AccessibilityController::getJSClass):
+ * DumpRenderTree/AccessibilityController.h:
+ * DumpRenderTree/gtk/AccessibilityControllerGtk.cpp:
+ (AccessibilityController::elementAtPoint):
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::elementAtPoint):
+ * DumpRenderTree/win/AccessibilityControllerWin.cpp:
+ (AccessibilityController::elementAtPoint):
+
+2010-03-03 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ pywebsocket should support html and cgi in the same directory.
+ https://bugs.webkit.org/show_bug.cgi?id=34879
+
+ Import pywebsocket 0.4.9.2
+ Specify --server-host 127.0.0.1, so that it only binds listening socket
+ to 127.0.0.1 to prevent access from non-localhost.
+ Change --cgi-paths from /websocket/tests/cookies to /websocket/tests,
+ because pywebsocket 0.4.9.2 supports html and cgi in the same directory
+ and only executable (httponly-cookies.pl) will be handled as cgi
+ script.
+
+ * Scripts/run-webkit-tests:
+ * Scripts/run-webkit-websocketserver:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ * Scripts/webkitpy/thirdparty/pywebsocket/README.webkit:
+ * Scripts/webkitpy/thirdparty/pywebsocket/example/echo_client.py:
+ * Scripts/webkitpy/thirdparty/pywebsocket/example/handler_map.txt: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/mod_pywebsocket/standalone.py:
+ * Scripts/webkitpy/thirdparty/pywebsocket/mod_pywebsocket/util.py:
+ * Scripts/webkitpy/thirdparty/pywebsocket/setup.py:
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/test_util.py:
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/testdata/README: Added.
+ * Scripts/webkitpy/thirdparty/pywebsocket/test/testdata/hello.pl: Added.
+
+2010-03-09 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Simplified check-webkit-style's argument parsing code by removing
+ support for the vestigial "extra flag values" parameter.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34677
+
+ The "extra flag values" parameter was needed before WebKit
+ forked check-webkit-style from Google. It was used to pass
+ through the option parser those command-line flags that WebKit
+ required but that Google's parser did not support (the --git-commit
+ flag in particular).
+ We can remove the parameter now because it is no longer
+ needed and unnecessarily clutters the argument-parsing code.
+
+ * Scripts/webkitpy/style/optparser.py:
+ - Removed the extra_flag_values parameter from the
+ CommandOptionValues class's constructor.
+ - Removed the extra_flags parameter from the ArgumentParser
+ class's parse() method.
+
+ * Scripts/webkitpy/style/optparser_unittest.py:
+ - Removed from the unit tests all references to the
+ extra_flag_values variable.
+
+2010-03-08 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Add EventSender
+ https://bugs.webkit.org/show_bug.cgi?id=35859
+
+ Add EventSender classes, which are going to be used by
+ DumpRenderTree Chromium port. These files are based on:
+ - src/webkit/tools/test_shell/event_sending_controller.cc
+ - src/webkit/tools/test_shell/event_sending_controller.h
+ of Chromium rev.40492.
+
+ * DumpRenderTree/chromium/EventSender.cpp: Added.
+ * DumpRenderTree/chromium/EventSender.h: Added.
+
+2010-03-08 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Add PlainTextController and TextInputController
+ https://bugs.webkit.org/show_bug.cgi?id=35852
+
+ Add PlainTextController and TextInputController classes, which are going
+ to be used by DumpRenderTree Chromium port. These files are based on:
+ - src/webkit/tools/test_shell/plain_text_controller.{cc,h} and
+ - src/webkit/tools/test_shell/text_input_controller.{cc,h}
+ of Chromium rev.40492.
+
+ * DumpRenderTree/chromium/PlainTextController.cpp: Added.
+ * DumpRenderTree/chromium/PlainTextController.h: Added.
+ * DumpRenderTree/chromium/TextInputController.cpp: Added.
+ * DumpRenderTree/chromium/TextInputController.h: Added.
+
+2010-03-08 Dumitru Daniliuc <dumi@chromium.org>
+
+ Unreviewed, Chromium build fix.
+
+ Reverting r55689.
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-03-08 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Fix webkit-patch post and land to work well with security bug
+ https://bugs.webkit.org/show_bug.cgi?id=35733
+
+ Bugzilla requires authentication to access security bug page,
+ so call authenticate() if it failed to fetch bug page.
+
+ * Scripts/webkitpy/bugzilla.py:
+
+2010-03-04 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitry Glazkov.
+
+ Fix --clobber-old-results in new-run-webkit-tests.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35778
+
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-03-08 Brady Eidson <beidson@apple.com>
+
+ Reviewed by NOBODY (but suggested by Steve Falkenburg and fixing a boneheaded mistake on my part last week)
+
+ Followup to https://bugs.webkit.org/show_bug.cgi?id=35532
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::apiTestGoToCurrentBackForwardItem): Can't pass in a null BOOL to WebKit APIs.
+
+2010-03-08 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Unreviewed.
+
+ Fixed incorrect import statement in validate-committer-lists:
+ webkitpy.BeautifulSoup -> webkitpy.thirdparty.BeautifulSoup.
+
+ * Scripts/validate-committer-lists:
+
+2010-03-08 Jian Li <jianli@chromium.org>
+
+ Reviewed by Dmitry Titov.
+
+ Blob.slice support.
+ https://bugs.webkit.org/show_bug.cgi?id=32993
+
+ Add ENABLE_BLOB_SLICE feature define and flag for build-webkit. It is
+ currently only turned on for Mac.
+
+ * Scripts/build-webkit:
+
+2010-03-08 Gustavo Noronha Silva <gns@gnome.org>
+
+ No review, rolling out r55662.
+ http://trac.webkit.org/changeset/55662
+ https://bugs.webkit.org/show_bug.cgi?id=35863
+
+ Need to be coordinated with bots setup
+
+ * Scripts/run-webkit-tests:
+
+2010-03-08 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Holger Freyther.
+
+ [GTK] Tests fail when running with ipv6 addresses available, on Debian systems
+ https://bugs.webkit.org/show_bug.cgi?id=35863
+
+ If running on a Debian-based system, also listen on the ipv6 address.
+
+ * Scripts/run-webkit-tests:
+
+2010-03-08 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Darin Adler.
+
+ [iexploder] Automatically update htmltags.in and htmlattrs.in too
+ https://bugs.webkit.org/show_bug.cgi?id=33755
+
+ Change the update-iexploder-cssproperites script to update
+ the htmlattrs.in and htmltags.in of WebKitTools/iExploder/htdocs
+ automatically as well.
+
+ Change the reading and writing code to work with parameters
+ and extend the method that is parsing the .in files to handle
+ the HTMLTagNames.in and the HTMLAttributeNames.in files.
+
+ Remove custom code to determine the revision of files with a
+ utility of VCUtils.pm to determine the revision of the directory
+ these files are located in. This will also work with git checkout.
+
+ * Scripts/update-iexploder-cssproperties:
+
+2010-03-07 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ check-webkit-style: false positive for empty loop
+ https://bugs.webkit.org/show_bug.cgi?id=35717
+
+ * Scripts/webkitpy/style/processors/cpp.py:
+ * Scripts/webkitpy/style/processors/cpp_unittest.py:
+
+2010-03-07 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Add AccessibilityController and AccessibilityUIElement
+ https://bugs.webkit.org/show_bug.cgi?id=35774
+
+ Add AccessibilityController and AccessibilityUIElement classes,
+ which are going to be used by DumpRenderTree Chromium port. These
+ files are based on:
+ - src/webkit/tools/test_shell/accessibility_controller.{cc,h} and
+ - src/webkit/tools/test_shell/accessibility_ui_element.{cc,h}
+ of Chromium rev.40492.
+
+ * DumpRenderTree/chromium/AccessibilityController.cpp: Added.
+ * DumpRenderTree/chromium/AccessibilityController.h: Added.
+ * DumpRenderTree/chromium/AccessibilityUIElement.cpp: Added.
+ * DumpRenderTree/chromium/AccessibilityUIElement.h: Added.
+
+2010-03-06 Hironori Bono <hbono@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [Chromium] Typing into Flash with wmode = opaque|transparent and
+ non-latin language active outputs as if US keyboard layout active
+
+ https://bugs.webkit.org/show_bug.cgi?id=34936
+
+ To test keyboard events on the test plugin, this change implements
+ NPCocoaEventKeyDown and NPCocoaEventKeyUp handlers so the plugin
+ can write log messages.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (handleEventCocoa): Implemented the event handlers for NPCocoaKeyDown
+ and NPCocoaEventKeyUp.
+
+2010-03-05 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix Print option on QtLauncher by calling print directly from QWebFrame.
+
+ [Qt] QtLauncher Print option is not working on QGraphicsView mode
+ https://bugs.webkit.org/show_bug.cgi?id=35769
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::print):
+
+2010-03-05 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Changed the logging code for new-run-webkit-tests to use
+ module-specific loggers rather than the root logger. This is
+ a standard practice that allows logging specific to a package
+ to be configured independently of other modules.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35194
+
+ Added a line of the form "_log = logging.getLogger(<module>)"
+ to each module below, where <module> is the fully-qualified
+ name of the module, and updated the log lines to use the new
+ _log logger.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_shell_thread.py:
+ * Scripts/webkitpy/layout_tests/port/apache_http_server.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/http_server.py:
+ * Scripts/webkitpy/layout_tests/port/http_server_base.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-03-05 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Siedel.
+
+ Split the command-line invocation of the Chromium/python LigHTTPd
+ server implementation out into its own top level script to make it
+ a more "public" interface and to resolve some awkward layering
+ issues. This script will be called directly by other test scripts in
+ the Chromium tree.
+
+ At some point this script should be made to work with Apache-based
+ implementations and on other ports. I have filed
+ https://bugs.webkit.org/show_bug.cgi?id=35820 for this.
+
+ Also fix a bug in port/factory where options.chromium could be
+ dereferenced even if it wasn't set, raising an exception.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35812
+
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/http_server.py:
+ * Scripts/new-run-webkit-httpd: Added
+
+2010-03-02 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Holger Freyther
+ Patch by Antonio Gomes <tonikitoo@webkit.org>
+
+ [Gtk] Implement setSpatialNavigationEnabled in DRT.
+ https://bugs.webkit.org/show_bug.cgi?id=35705
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setSpatialNavigationEnabled):
+
+2010-02-23 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Kenneth Christiansen.
+ Patch by Antonio Gomes <tonikitoo@webkit.org>
+
+ Add toggle on/off stub methods for Spatial Navigation in win, gtk and mac LayoutTestController class implementations.
+ https://bugs.webkit.org/show_bug.cgi?id=35699
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setSpatialNavigationEnabledCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setSpatialNavigationEnabled):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setSpatialNavigationEnabled):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setSpatialNavigationEnabled):
+
+2010-02-18 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Kenneth Christiansen.
+ Patch by Antonio Gomes <tonikitoo@webkit.org>
+
+ Add toggle on/off mechanism for Spatial Navigation in QtLauncher.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::toggleSpatialNavigation):
+ (LauncherWindow::setupUI):
+
+2010-03-02 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Simon Hausmann.
+ Patch by Antonio Gomes <tonikitoo@webkit.org>
+
+ [Qt] Add setSpatialNavigationEnabled method DRT
+ https://bugs.webkit.org/show_bug.cgi?id=33715
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setSpatialNavigationEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+ Unskipped fast/events/spatialnavigation/
+
+2010-03-04 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Alice Liu.
+
+ Find the framework relative to TARGET_BUILD_DIR as that has a more obvious value during production builds.
+
+ * Scripts/check-for-webkit-framework-include-consistency:
+
+2010-03-04 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [DRT/Chromium] Add CppVariant and CppBoundClass
+ https://bugs.webkit.org/show_bug.cgi?id=35634
+
+ Add CppVariant and CppBoundClass classes, which are going to be
+ used by DumpRenderTree Chromium port. These files are based on:
+ - src/webkit/glue/cpp_variant.{cc,h} and
+ - src/webkit/glue/cpp_bound_class.{cc,h}
+ of Chromium rev.40492.
+
+ * DumpRenderTree/chromium/CppBoundClass.cpp: Added.
+ * DumpRenderTree/chromium/CppBoundClass.h: Added.
+ * DumpRenderTree/chromium/CppVariant.cpp: Added.
+ * DumpRenderTree/chromium/CppVariant.h: Added.
+
+2010-03-04 Mark Rowe <mrowe@apple.com>
+
+ Build fix for older versions of Ruby.
+
+ * Scripts/check-for-webkit-framework-include-consistency:
+
+2010-03-04 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Add a script to verify that WebKit framework headers are internally consistent.
+
+ This script detects the following problematic situations:
+ * An exported WebKit header that includes a header from WebCore.
+ * An exported WebKit header that includes a header that does not exist in the WebKit framework.
+ * A public WebKit header that includes a private WebKit header.
+
+ * Scripts/check-for-webkit-framework-include-consistency: Added.
+
+2010-03-04 Dumitru Daniliuc <dumi@chromium.org>
+
+ Reviewed by Adam Roben.
+
+ Making sure that the correct path is set before invoking
+ DumpRenderTree on cygwin.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35768
+
+ * Scripts/run-webkit-tests:
+
+2010-03-04 Simon Fraser <simon.fraser@apple.com>
+
+ Revert the exceptions I just added, and make the error clearer.
+
+ * Scripts/check-for-global-initializers:
+
+2010-03-04 Simon Fraser <simon.fraser@apple.com>
+
+ Build fix: add exceptions to the check-for-global-initializers script
+ for FocusController and SpatialNavigation, and improve the script
+ to actually print out the globals found.
+
+ * Scripts/check-for-global-initializers:
+
+2010-03-04 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Fix dangling reference to "port" instead of "self._port_obj" that
+ was preventing the http_server from starting on Windows.
+
+ * Scripts/webkitpy/layout_tests/port/http_server.py:
+
+2010-03-04 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Simon Hausmann.
+
+ Make Qt DumpRenderTree EventSender able to send double click events
+
+ LayoutTests:
+ fast/events/dblclick-addEventListener.html
+
+ [Qt] DRT: Send double click event from EventSender
+ https://bugs.webkit.org/show_bug.cgi?id=35255
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::EventSender):
+ (EventSender::mouseDown):
+ * DumpRenderTree/qt/EventSenderQt.h:
+ (EventSender::resetClickCount):
+
+2010-03-04 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [Qt] Make the OUTPUT_DIR variable in qmake projects independent of build-webkit's logic.
+
+ This also allows shadow builds relying only on qmake to work properly.
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/ImageDiff.pro:
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+ * QtLauncher/QtLauncher.pro:
+
+2010-03-04 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Enable to use built-product-archive on Qt platform.
+
+ * BuildSlaveSupport/built-product-archive:
+
+2010-03-03 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Simon Hausmann.
+
+ Add a missing 'm_' to class variables names.
+
+ [Qt] QtLauncher is not respecting class variable names
+ https://bugs.webkit.org/show_bug.cgi?id=35542
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ (LauncherWindow::init):
+ (LauncherWindow::sendTouchEvent):
+ (LauncherWindow::eventFilter):
+ (LauncherWindow::zoomIn):
+ (LauncherWindow::zoomOut):
+ (LauncherWindow::resetZoom):
+ (LauncherWindow::setEditable):
+ (LauncherWindow::setTouchMocking):
+ (LauncherWindow::initializeView):
+ (LauncherWindow::createChrome):
+
+2010-03-03 Alexey Proskuryakov <ap@apple.com>
+
+ Rubber-stamped by Mark Rowe.
+
+ Exclude leaks in Java that build bot complains about.
+
+ * Scripts/run-webkit-tests:
+
+2010-03-03 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ Additional change to separate Accelerated Compositing test from 3D Rendering test
+ https://bugs.webkit.org/show_bug.cgi?id=35610
+
+ I am now using #if ENABLED(3D_RENDERING) to emit the 3DRendering string from
+ DRT or not. This allows these flags to set independently. I also improved
+ the code flow in run-webkit-tests a bit.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main):
+ * Scripts/run-webkit-tests:
+
+2010-03-03 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ Added ability to print supported features to console to DRT
+ https://bugs.webkit.org/show_bug.cgi?id=35610
+
+ This currently only prints whether or not Accelerated Compositing
+ and 3D Rendering are supported, which is the only way to tell if you
+ can run the compositing LayoutTests on Windows. But it can be expanded
+ to give more information as needed. Currently it prints that both
+ AcceleratedCompositing and 3DRendering are available if accelerated compositing
+ is enabled since both have to be turned on together. This allows me to maintain
+ separate checks for them.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:Added --print-supported-features flag
+ (main):
+ * Scripts/run-webkit-tests:Runs DRT and enabled compositing tests if HW comp is available on Windows
+
+2010-03-03 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Simon Hausmann.
+
+ Refactor QtLauncher so it respects command line arguments
+ and inherits settings when you clone or create a new window.
+
+ Implemented with help of Kenneth Rohde Christiansen.
+
+ [Qt] QtLauncher must be refactored to fix command line arguments usage
+ https://bugs.webkit.org/show_bug.cgi?id=35536
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ (LauncherWindow::init):
+ (LauncherWindow::isGraphicsBased):
+ (applySetting):
+ (LauncherWindow::applyPrefs):
+ (LauncherWindow::initializeView):
+ (LauncherWindow::newWindow):
+ (LauncherWindow::cloneWindow):
+ (LauncherWindow::createChrome):
+ (main):
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::WebViewGraphicsBased):
+ (WebViewGraphicsBased::setFrameRateMeasurementEnabled):
+ * QtLauncher/webview.h:
+ (WebViewGraphicsBased::itemCacheMode):
+ (WebViewGraphicsBased::frameRateMeasurementEnabled):
+
+2010-03-02 Arno Renevier <arno@renevier.net>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [Gtk] implements ChromeClient::requestGeolocationPermissionForFrame
+ https://bugs.webkit.org/show_bug.cgi?id=35210
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (geolocationPolicyDecisionRequested):
+ (createWebView):
+
+2010-03-02 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by David Levin.
+
+ Revert r55339 - the Chromium codebase downstream had a temporary
+ need for WebKitTools/pywebsocket to still exist after Chris Jerdonek
+ had moved it (scripts still referenced the old location). Those
+ scripts have been updated to the new location, so it should be safe
+ to delete this now.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35614
+
+ * pywebsocket/mod_pywebsocket/standalone.py: Removed.
+
+2010-03-02 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ new-run-webkit-tests on chromium-linux tests to see if
+ layout_test_helper exists, but we don't use layout_test_helper on
+ linux. The test derefences a None object, and we crash. This fixes
+ that.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35602
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+ 2010-03-02 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ r55388 (bug 35553) worked around a bug in Python's subprocess.Popen()
+ that was causing DRT to hang on exit in new-run-webkit-tests.
+ Unfortunately, that workaround doesn't work on chromium-win
+ (and the script fails completely). The good news is that the check
+ isn't actually necessary, and so this change makes it conditional.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35601
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-03-02 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 35576: WebKit should tell plug-in instances when private browsing state changes
+ <http://webkit.org/b/35576>
+
+ TestNetscapePlugin is another bit of plug-in code where copy-paste was heavily used
+ when porting. Update the Windows and UNIX implementations of NPP_New and NPP_SetValue
+ to provide the expected behavior related to NPNVprivateModeBool. Hopefully this code
+ duplication can be cleaned up in the future.
+
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance):
+ (webkit_test_plugin_set_value):
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp:
+ (NPP_New):
+ (NPP_SetValue):
+
+2010-03-02 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Test plugin still has issues with releasing objects, and variants
+ https://bugs.webkit.org/show_bug.cgi?id=35587
+
+ Fix the conditions for releasing the variants after calling
+ invoke, and avoid having a number of objects leak.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (testDocumentOpen):
+ (testWindowOpen):
+
+2010-03-02 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Refactored the StyleChecker class's file-processing method
+ _process_file(). This will make it easier to add new
+ file-processing capabilities to check-webkit-style.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35490
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added a _read_lines() method to the StyleChecker class
+ that extracts the lines from a file.
+ - Replaced part of _process_file() with a call to the new
+ _read_lines() method.
+ - Replaced another part of _process_file() with a call
+ to the new CarriageReturnProcessor.process() method.
+
+ * Scripts/webkitpy/style/processors/common.py:
+ - Replaced the check_no_carriage_return() function with a
+ new CarriageReturnProcessor class.
+
+ * Scripts/webkitpy/style/processors/common_unittest.py:
+ - Renamed the CarriageReturnTest class to
+ CarriageReturnProcessorTest and updated it as necessary.
+
+2010-03-02 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Started using the logging module in check-webkit-style.
+ This provides more options for debugging and a more flexible,
+ uniform way to report messages to the end-user.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35484
+
+ Also included classes in a central location to facilitate
+ the unit testing of logging code (setUp and tearDown of unit
+ test logging configurations, etc).
+
+ * Scripts/check-webkit-style:
+ - Added a call to configure_logging() in the beginning of main().
+ - Replaced two calls to sys.stderr.write() with appropriate
+ logging calls.
+
+ * Scripts/webkitpy/init/__init__.py: Copied from WebKitTools/QueueStatusServer/filters/__init__.py.
+
+ * Scripts/webkitpy/init/logtesting.py: Added.
+ - Added a UnitTestLogStream class to capture log output
+ during unit tests.
+ - Added a UnitTestLog class that provides convenience methods
+ for unit-testing logging code.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added a configure_logging() method.
+ - Added a _LevelLoggingFilter class to filter out log messages
+ above a certain logging level.
+ - Removed the _stderr_write() method from the StyleChecker class
+ and replaced its use with appropriate logging calls.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Added a ConfigureLoggingTest class to unit test the
+ configure_logging() method.
+ - Updated the StyleCheckerCheckFileTest class as necessary.
+
+ * Scripts/webkitpy/style_references.py:
+ - Added references to logtesting.UnitTestLog and
+ logtesting.UnitTestLogStream.
+
+2010-03-01 Chris Fleizach <cfleizach@apple.com>
+
+ Fixing broken DRT on Leopard/Tiger. Second try.
+
+ AX: changes to WAI-ARIA grid aren't perceived correctly by VoiceOver
+ https://bugs.webkit.org/show_bug.cgi?id=35514
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+
+2010-03-01 Chris Fleizach <cfleizach@apple.com>
+
+ Fixing broken DRT on Leopard/Tiger.
+
+ AX: changes to WAI-ARIA grid aren't perceived correctly by VoiceOver
+ https://bugs.webkit.org/show_bug.cgi?id=35514
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+
+2010-03-01 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Eric Seidel.
+
+ [GTK] plugins/setProperty.html fails on 64bit Release
+ https://bugs.webkit.org/show_bug.cgi?id=35425
+
+ Check invoke's return code before releasing the variant, since
+ there's a chance it won't be properly initialized, leading to
+ memory corruption, in some cases.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (testCallback):
+ (testEnumerate):
+ (testDocumentOpen):
+ (testWindowOpen):
+ (handleCallback):
+
+2010-03-01 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by nobody. Build bustage :(
+
+ Fix stupid typo that I committed even after David Levin pointed
+ it out to me :(
+
+ https://bugs.webkit.org/show_bug.cgi?id=35553
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+
+2010-03-01 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ AX: changes to WAI-ARIA grid aren't perceived correctly by VoiceOver
+ https://bugs.webkit.org/show_bug.cgi?id=35514
+
+ Add rowCount, columnCount for tables.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (rowCountCallback):
+ (columnCountCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::rowCount):
+ (AccessibilityUIElement::columnCount):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::rowCount):
+ (AccessibilityUIElement::columnCount):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::rowCount):
+ (AccessibilityUIElement::columnCount):
+
+2010-03-01 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Work around a bug in Python's subprocess.Popen() that keeps us from
+ cleaning up DumpRenderTree / test_shell properly when we finish the
+ tests in new-run-webkit-tests.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35553
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+
+2010-03-01 Arno Renevier <arno@renevier.net>
+
+ Reviewed by Xan Lopez.
+
+ webkit-build could pass unknown arguments to autogen.sh
+ https://bugs.webkit.org/show_bug.cgi?id=35454
+
+ * Scripts/build-webkit:
+
+2010-03-01 Dirk Pranke <dpranke@chromium.org>
+
+ Rubber-stamped by Dimitri Glazkov.
+
+ Fix breakage from r55372.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35549
+
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+
+2010-03-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ EWS can hang for five hours when compile output is too big
+ https://bugs.webkit.org/show_bug.cgi?id=35545
+
+ * Scripts/webkitpy/commands/queues.py: Limit uploads to 1MB instead of
+ 5MB. AppEngine seems to not like 5MB uploads. I'm not sure what the
+ limit is. Let's try 1MB for a while and see how it goes.
+ * Scripts/webkitpy/networktransaction.py: Tune the default parameters
+ to our exponential backoff. I'm not sure why I picked five hours as
+ the retry limit. That seems way too large.
+
+2010-03-01 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ REGRESSION: Telling a WebView to go to its current WebHistoryItem is broken.
+ <rdar://problem/7699371> and https://bugs.webkit.org/show_bug.cgi?id=35532
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (apiTestGoToCurrentBackForwardItemCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::apiTestGoToCurrentBackForwardItem):
+
+ Stubs for now:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::apiTestGoToCurrentBackForwardItem):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::apiTestGoToCurrentBackForwardItem):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::apiTestGoToCurrentBackForwardItem):
+
+2010-03-01 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by David Levin.
+
+ General cleanup of error handling in new-run-webkit-tests.
+
+ Add Port.check_build() call that is separate from Port.check_sys_deps()
+ (and add a --nocheck-build flag to skip). This breaks a circular
+ dependency where you would start the layout test helper before
+ checking sys deps, but checking sys deps was the thing that told
+ you if your binaries where there.
+
+ Also, made Port.check_sys_deps(), start_helper() and stop_helper()
+ optional by providing default implementations in the base class
+ rather than requiring ports to implement the routines regardless
+ of whether or not they were needed.
+
+ Lastly, tweak a bunch of log messages to be cleaner, including
+ changing messages in thirdparty/autoinstall.py to be silent at
+ the default log level.
+
+ http://bugs.webkit.org/show_bug.cgi?id=35416
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/passing.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+ * Scripts/webkitpy/thirdparty/autoinstall.py
+
+2010-03-01 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by David Levin.
+
+ new-chromium-webkit-tests --platform=mac-leopard diffs are backwards
+ https://bugs.webkit.org/show_bug.cgi?id=35265
+
+ Some parts of the code passed arguments as
+ "actual, expected" and some passed as "expected, actual".
+ As you might imagine, this lead to great confusion and wrongness.
+ Standardize on "expected, actual" as that's the order which is
+ passed to the underlying diff tool.
+
+ Based on a patch by Eric Siedel <eric@webkit.org>.
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py
+
+2010-03-01 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Unreviewed.
+
+ Rolling out: http://trac.webkit.org/changeset/55348
+
+ https://bugs.webkit.org/show_bug.cgi?id=35163
+
+ Rolling out since the changes to autoinstall do not work
+ with Python 2.4. In particular, ZipFile.extractall() was
+ added in Python 2.6.
+
+ * Scripts/webkitpy/__init__.py:
+ * Scripts/webkitpy/bugzilla.py:
+ * Scripts/webkitpy/init/__init__.py: Removed.
+ * Scripts/webkitpy/init/autoinstall.py: Removed.
+ * Scripts/webkitpy/networktransaction.py:
+ * Scripts/webkitpy/networktransaction_unittest.py:
+ * Scripts/webkitpy/statusserver.py:
+ * Scripts/webkitpy/thirdparty/autoinstall.py: Added.
+
+2010-03-01 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Unreviewed.
+
+ Rolling out r55350: http://trac.webkit.org/changeset/55350
+
+ https://bugs.webkit.org/show_bug.cgi?id=33639
+
+ Need to roll out because this patch (pep8) depends on the newly
+ rewritten autoinstall.py (r55348), which is breaking for people
+ with Python 2.4:
+
+ https://bugs.webkit.org/show_bug.cgi?id=35163#c21
+
+ That revision also needs to be rolled out and will be rolled out next.
+
+ * Scripts/webkitpy/style/checker.py:
+ * Scripts/webkitpy/style/checker_unittest.py:
+ * Scripts/webkitpy/style/processors/python.py: Removed.
+ * Scripts/webkitpy/style/processors/python_unittest.py: Removed.
+ * Scripts/webkitpy/style/processors/python_unittest_input.py: Removed.
+ * Scripts/webkitpy/style/unittests.py:
+ * Scripts/webkitpy/style_references.py:
+
+2010-02-28 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Exempted WebKitTools/Scripts/webkitpy/thirdparty from all
+ style checks except for the whitespace/carriage_return check
+ and the pep8 tab and trailing white space checks.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35497
+
+ * Scripts/webkitpy/style/checker.py:
+ - Adjusted the _PATH_RULES_SPECIFIER configuration as necessary.
+ - Added enough pep8 categories to _all_categories() for the
+ unit tests to pass.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated the test_path_rules_specifier() unit test.
+
+2010-02-27 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by David Levin.
+
+ Added Python style checking to check-webkit-style using
+ the third-party pep8 module (via autoinstall).
+
+ https://bugs.webkit.org/show_bug.cgi?id=33639
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added PYTHON to FileType.
+ - Updated ProcessorDispatcher to return a PythonProcessor
+ for *.py files.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated the ProcessorDispatcher unit tests for *.py files.
+
+ * Scripts/webkitpy/style/processors/python.py: Added.
+ - Added PythonProcessor class.
+
+ * Scripts/webkitpy/style/processors/python_unittest.py: Added.
+ - Added PythonProcessor unit tests.
+
+ * Scripts/webkitpy/style/processors/python_unittest_input.py: Added.
+ - Added a sample Python file to test the PythonProcessor.process()
+ code path (since pep8 accepts a file path).
+
+ * Scripts/webkitpy/style/unittests.py:
+ - Updated the style unit test file to import python_unittest.py.
+
+ * Scripts/webkitpy/style_references.py:
+ - Adjusted style references to import pep8.
+
+2010-02-26 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by David Levin.
+
+ Rewrote autoinstall.py to support unzipping *.zip files after
+ download, unzipping and extracting *.tar.gz files after download,
+ and copying installed files to a destination directory.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35163
+
+ These changes will allow us to autoinstall pep8.py from the web
+ and to put our third-party autoinstalled code in an explicit
+ directory like webkitpy/thirdparty/autoinstalled. They should
+ also speed up imports from autoinstalled *.zip packages slightly
+ since *.pyc files cannot be generated when importing from
+ zipped packages.
+
+ * Scripts/webkitpy/__init__.py:
+ - Updated the autoinstall lines to use the new autoinstall methods.
+ - Added pep8.py to the list of auto-installed packages.
+
+ * Scripts/webkitpy/bugzilla.py:
+ - Updated mechanize import path.
+
+ * Scripts/webkitpy/init/__init__.py: Copied from WebKitTools/QueueStatusServer/filters/__init__.py.
+
+ * Scripts/webkitpy/init/autoinstall.py: Added.
+ - Added AutoInstaller class.
+ - Added sample testing usage to __main__.
+
+ * Scripts/webkitpy/networktransaction.py:
+ - Updated mechanize import path.
+
+ * Scripts/webkitpy/networktransaction_unittest.py:
+ - Updated mechanize import path.
+
+ * Scripts/webkitpy/statusserver.py:
+ - Updated mechanize import path.
+
+ * Scripts/webkitpy/thirdparty/autoinstall.py: Removed.
+ - Replaced with rewritten autoinstall in init/autoinstall.py.
+
+2010-02-26 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Change the default port for new-run-webkit-tests when running on
+ a Mac from 'chromium-mac' to 'mac'. Add a '--chromium' switch to
+ pick up the default platform-specific version of chromium instead.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35462
+
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py:
+
+2010-02-26 Dirk Pranke <dpranke@chromium.org>
+
+ Unreviewed, build fix
+
+ third time's the charm getting this path right?
+
+ * pywebsocket/mod_pywebsocket/standalone.py:
+
+2010-02-26 Dumitru Daniliuc <dumi@chromium.org>
+
+ Unreviewed, build fix.
+
+ * pywebsocket/mod_pywebsocket/standalone.py:
+
+2010-02-26 Dumitru Daniliuc <dumi@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Moving the script to the right location.
+
+ * pywebsocket/mod_pywebsocket: Added.
+ * pywebsocket/mod_pywebsocket/standalone.py: Copied from WebKitTools/pywebsocket/standalone.py.
+ * pywebsocket/standalone.py: Removed.
+
+2010-02-26 Dumitru Daniliuc <dumi@chromium.org>
+
+ Unreviewed, fixing the license.
+
+ * pywebsocket/standalone.py:
+
+2010-02-26 Dumitru Daniliuc <dumi@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Adding pywebsocket/standalone.py back to fix the Chromium webkit
+ canaries. Once all layout tests pass, we can get in the patch that
+ moves this directorty to WebKitTools/Scripts, update all Chromium
+ scripts, and revert this patch.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35464
+
+ * pywebsocket: Added.
+ * pywebsocket/standalone.py: Added.
+
+2010-02-26 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Needs proper reporting of frame loader callbacks, in DRT
+ https://bugs.webkit.org/show_bug.cgi?id=32170
+
+ Fix reporting of unload handlers, so that it is emitted where
+ needed, not after it.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewLoadFinished):
+ (webViewDocumentLoadFinished):
+ (createWebView):
+
+2010-02-26 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Gustavo Noronha.
+ Patch by Antonio Gomes <tonikitoo@webkit.org>
+
+ [Gtk] Make DRT EventSender::keyDown to consider 'hardware_keycode' field when synthesizing an event.
+ https://bugs.webkit.org/show_bug.cgi?id=35432
+
+ When a directional key-press event (arrow keys, End, Home, PageUp,
+ PageDown, etc) is synthesized by DRT's EventSender and it targets
+ an editor (e.g. <input type=text>, <textare>, etc), event is processed
+ by WebCore::EventHandler. On the other hand, if event target is not
+ an editor, event is bubbled up to Gtk+ for processing. In such cases,
+ if 'hardware_keycode' is not provided at event synthesize time
+ its processing fails (at some point in gtk_bindings_activate_event),
+ and no scroll action is performed.
+
+ Unskip fast/events/node-event-anchor-lock.html
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (keyDownCallback):
+ * platform/gtk/Skipped:
+
+2010-02-26 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by David Levin.
+
+ new-webkit-run-tests: Extraneous parenthesis in websocket_server.py
+ https://bugs.webkit.org/show_bug.cgi?id=35436
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py: Removed extra paren.
+
+2010-02-26 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by David Levin.
+
+ Moved pywebsocket into the webkitpy/thirdparty directory and added
+ an associated README.webkit file to the pywebsocket directory.
+ This makes pywebsocket more consistent with the other third-party
+ Python code in our repository.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35198
+
+ * Scripts/run-webkit-tests:
+ - Updated paths to pywebsocket.
+
+ * Scripts/run-webkit-websocketserver:
+ - Updated paths to pywebsocket.
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ - Updated paths to pywebsocket.
+
+ * Scripts/webkitpy/thirdparty/pywebsocket: Copied from WebKitTools/pywebsocket.
+ * Scripts/webkitpy/thirdparty/pywebsocket/README.webkit: Added.
+ - Added a file containing information about the contents
+ of the pywebsocket directory. This will make it easier to
+ understand where the third-party code came from and what
+ local changes have been made.
+
+ * pywebsocket: Removed.
+ * pywebsocket/COPYING: Removed.
+ * pywebsocket/MANIFEST.in: Removed.
+ * pywebsocket/README: Removed.
+ * pywebsocket/example: Removed.
+ * pywebsocket/example/echo_client.py: Removed.
+ * pywebsocket/example/echo_wsh.py: Removed.
+ * pywebsocket/mod_pywebsocket: Removed.
+ * pywebsocket/mod_pywebsocket/__init__.py: Removed.
+ * pywebsocket/mod_pywebsocket/dispatch.py: Removed.
+ * pywebsocket/mod_pywebsocket/handshake.py: Removed.
+ * pywebsocket/mod_pywebsocket/headerparserhandler.py: Removed.
+ * pywebsocket/mod_pywebsocket/memorizingfile.py: Removed.
+ * pywebsocket/mod_pywebsocket/msgutil.py: Removed.
+ * pywebsocket/mod_pywebsocket/standalone.py: Removed.
+ * pywebsocket/mod_pywebsocket/util.py: Removed.
+ * pywebsocket/setup.py: Removed.
+ * pywebsocket/test: Removed.
+ * pywebsocket/test/config.py: Removed.
+ * pywebsocket/test/mock.py: Removed.
+ * pywebsocket/test/run_all.py: Removed.
+ * pywebsocket/test/test_dispatch.py: Removed.
+ * pywebsocket/test/test_handshake.py: Removed.
+ * pywebsocket/test/test_memorizingfile.py: Removed.
+ * pywebsocket/test/test_mock.py: Removed.
+ * pywebsocket/test/test_msgutil.py: Removed.
+ * pywebsocket/test/test_util.py: Removed.
+ * pywebsocket/test/testdata: Removed.
+ * pywebsocket/test/testdata/handlers: Removed.
+ * pywebsocket/test/testdata/handlers/blank_wsh.py: Removed.
+ * pywebsocket/test/testdata/handlers/origin_check_wsh.py: Removed.
+ * pywebsocket/test/testdata/handlers/sub: Removed.
+ * pywebsocket/test/testdata/handlers/sub/exception_in_transfer_wsh.py: Removed.
+ * pywebsocket/test/testdata/handlers/sub/no_wsh_at_the_end.py: Removed.
+ * pywebsocket/test/testdata/handlers/sub/non_callable_wsh.py: Removed.
+ * pywebsocket/test/testdata/handlers/sub/plain_wsh.py: Removed.
+ * pywebsocket/test/testdata/handlers/sub/wrong_handshake_sig_wsh.py: Removed.
+ * pywebsocket/test/testdata/handlers/sub/wrong_transfer_sig_wsh.py: Removed.
+
+2010-02-26 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Changed the diff_parser module to log to a module-specific
+ logging.logger rather than the root logger.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35391
+
+ * Scripts/webkitpy/diff_parser.py:
+
+2010-02-26 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] LayoutTestController.numberOfPages() should have default parameters
+ https://bugs.webkit.org/show_bug.cgi?id=35428
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp: maxViewWidth and maxViewHeight moved to
+ LayoutTestController to converge to platform independent implementation.
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp: Initialization of maxViewWidth and maxViewHeight added.
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ - Default parameters for LayoutTestController.numberOfPages() added.
+ - maxViewWidth and maxViewHeight members added.
+
+2010-02-26 Jamey Hicks <jamey.hicks@nokia.com>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] added QWebSettings::setInspectorUrl() and QWebSettings::inspectorUrl()
+
+ Enables the use of alternate Web Inspector frontends by changing
+ the location of the frontend. The location is specified by providing
+ -inspector-url url
+ as an argument to QtLauncher.
+
+ This is required so that the Web Inspector may be run from an
+ external process or an external tool such as Eclipse or Aptana may
+ be used instead of the in-process Web Inspector UI.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35340
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::init):
+ (LauncherApplication::handleUserOptions):
+
+2010-02-25 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Add a 'passing' port implementation to new-run-webkit-tests that
+ acts as a wrapper around an existing implementation but stubs out
+ the actual test invocations (instead, the expected results are echoed
+ back to the harness). This is useful for coverage and perf testing
+ of the harness (especially perf testing as it essentially provides
+ a lower bound on how fast the harness can run).
+
+ Also added a --nostart-helper flag to new-run-webkit-tests so that
+ you can skip starting the layout_test_helper and actually run the
+ harness even if you don't have a build of that port.
+
+ Also fix a bug in the 'test' port implementation to actually
+ create the results directory under /tmp instead of /.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35370
+
+ * Scripts/webkitpy/layout_tests/port/factory.py: Modified.
+ * Scripts/webkitpy/layout_tests/port/passing.py: Added.
+ * Scripts/webkitpy/layout_tests/port/test.py: Added.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py: Modified.
+
+2010-02-25 Eric Seidel <eric@webkit.org>
+
+ Fix typo in my last change. No review.
+
+ Rename run-chromium-webkit-tests to new-run-webkit-tests to stop confusion
+ https://bugs.webkit.org/show_bug.cgi?id=35408
+
+ * Scripts/new-run-webkit-tests:
+
+2010-02-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Rename run-chromium-webkit-tests to new-run-webkit-tests to stop confusion
+ https://bugs.webkit.org/show_bug.cgi?id=35408
+
+ * Scripts/new-run-webkit-tests: Added.
+ * Scripts/run-chromium-webkit-tests: Removed.
+ * Scripts/webkitpy/layout_tests/run_webkit_tests.py: Renamed from WebKitTools/Scripts/webkitpy/layout_tests/run_chromium_webkit_tests.py.
+
+2010-02-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by David Levin.
+
+ EWS leaks memory slowly
+ https://bugs.webkit.org/show_bug.cgi?id=35395
+
+ The EWS bots leak memory very slowly. If you run them for about a
+ month, each one will take up around 1 GB of virutal memory. If you run
+ several of them on one machine, you'll eventually exhaust all available
+ memory and grind the bots to a halt.
+
+ This patch introduces a --exit-after-iteration option to the queues so
+ that we run them for a finite amount of time. Once they exit and
+ restart, they'll reclaim the leaked memory. I'm not sure how many
+ iterations I'll end up running them for. I'll need to sort that out
+ operationally, but my initial guess is around 1000.
+
+ * Scripts/webkitpy/commands/queues.py:
+ * Scripts/webkitpy/commands/queues_unittest.py:
+
+2010-02-25 Jarkko Sakkinen <jarkko.sakkinen@tieto.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Qt WebGL support
+
+ Adds toggling of WebGL support to QtLauncher.
+ https://bugs.webkit.org/show_bug.cgi?id=35153
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::toggleWebGL):
+ (LauncherWindow::setupUI):
+
+2010-02-25 Ben Murdoch <benm@google.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ The target element of a Touch should be the target where that touch originated, not where it is now.
+ https://bugs.webkit.org/show_bug.cgi?id=34585
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::addTouchPoint): Fix a bug where touch points were not being given unique ids.
+
+2010-02-24 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] QtLauncher has a border when running on QGraphicsView mode
+ https://bugs.webkit.org/show_bug.cgi?id=35352
+
+ Fix 2-pixels frame on each border of QtLauncher when running on QGraphicsView mode.
+
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::WebViewGraphicsBased):
+
+2010-02-23 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by David Levin.
+
+ When the run-chromium-webkit-tests code was landed and the code was
+ refactored into the 'port' package, I accidentally broke using
+ http_server.py or websocket_server.py as command-line scripts
+ (the constructors needed a port object they weren't getting). This
+ change fixes them so that --server start|stop actually works.
+
+ As a part of this, the two files need to be able to call port.get(),
+ but doing that is awkward from a file inside the package, so I moved
+ get() into factory.py and imported that into __init__.py so that
+ http_server.py and websocket_server.py can just import factory.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35316
+
+ * Scripts/webkitpy/layout_tests/port/__init__.py:
+ * Scripts/webkitpy/layout_tests/port/factory.py:
+ * Scripts/webkitpy/layout_tests/port/http_server.py:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+
+2010-02-24 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by David Levin.
+
+ Fix the function signature for check_sys_deps on the mac port, and
+ fix the ordering of port_obj.check_sys_deps() and
+ port_obj.start_helper() (helper needs to be started before we check
+ the system configuration).
+
+ http://bugs.webkit.org/show_bug.cgi?id=35367
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/run_chromium_webkit_tests.py:
+
+2010-02-24 James Robinson <jamesr@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Provide default username parameter to SVN.commit_with_message().
+
+ * Scripts/webkitpy/scm.py:
+
+2010-02-24 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Siedel.
+
+ Check the proper directory for a WebKit SVN version (Chromium does
+ not check out the entire WebKit tree directly, but rather pulls
+ individual subdirectories. So, checking for the SVN version in
+ WebKit/WebCore rather than just in WebKit works more reliably across
+ different ports).
+
+ http://bugs.webkit.org/show_bug.cgi?id=35321
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+
+2010-02-24 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35357
+ Two editing tests fail after DumpRenderTree run loop changes
+
+ AppKit decided that it wanted to group all editing commands for some reason (and thus undo
+ reverted them all at once).
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dump): Reverted the change that made DumpRenderTree use -[NSApplication run].
+ (runTest): Ditto.
+ (-[DumpRenderTreeApplication isRunning]): Override isRunning with a function that always
+ returns YES. This is another way to make the Java plug-in work.
+
+2010-02-23 Adam Roben <aroben@apple.com>
+
+ Make commit-log-editor find just-added ChangeLog files
+
+ Fixes <http://webkit.org/b/35294> commit-log-editor doesn't find
+ just-added ChangeLog files
+
+ Reviewed by Dave Levin.
+
+ * Scripts/commit-log-editor:
+ (top level): Modified the regular expression that's used to find
+ modified ChangeLog files to also look for just-added ChangeLog files.
+
+2010-02-24 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ check-webkit-style false positive for WebCore forwarding header
+ https://bugs.webkit.org/show_bug.cgi?id=34604
+
+ * Scripts/webkitpy/style/checker.py:
+ * Scripts/webkitpy/style/checker_unittest.py:
+
+2010-02-23 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ https://bugs.webkit.org/show_bug.cgi?id=22602
+ Enable Java in DumpRenderTree (on Mac)
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (exitApplicationRunLoop):
+ (dump):
+ (runTest):
+ DumpRenderTree now runs an NSApplication, not just an event loop. This way, the Java plug-in
+ can start without freezing.
+
+ * Scripts/run-webkit-tests: Compile java sources in LayputTests/java.
+
+2010-02-23 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Need a final integration between QtLauncher and QGVLauncher
+ https://bugs.webkit.org/show_bug.cgi?id=35292
+
+ WebKit coding style fixes.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::resetZoom):
+
+2010-02-23 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Need a final integration between QtLauncher and QGVLauncher
+ https://bugs.webkit.org/show_bug.cgi?id=35292
+
+ Add cloneWindow feature to QtLauncher, when running on QGraphicsView mode.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ (LauncherWindow::~LauncherWindow):
+ (LauncherWindow::init):
+ (LauncherWindow::cloneWindow):
+ (LauncherWindow::setupUI):
+
+2010-02-23 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Fix handling of check_wdiff_install when wdiff isn't installed.
+
+ http://bugs.webkit.org/show_bug.cgi?id=35304
+
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+
+2010-02-23 Leandro Pereira <leandro@profusion.mobi>
+
+ Reviewed by NOBODY.
+
+ Fix false positives for 'delete *pointer' statements.
+ http://webkit.org/b/35235
+
+ * WebKitTools/Scripts/webkitpy/style/processors/cpp.py:
+
+2010-02-23 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [Gtk] Implement layoutTestController.numberOfPages
+ https://bugs.webkit.org/show_bug.cgi?id=35228
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::numberOfPages):
+
+2010-02-23 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] QtLauncher should not use internal JavaScriptCore and WebCore interfaces
+ https://bugs.webkit.org/show_bug.cgi?id=35248
+
+ * QtLauncher/QtLauncher.pro:
+ * QtLauncher/utils.h:
+
+2010-02-23 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34439
+
+ Prompts a person for their SVN username if not already cached (by Subversion).
+
+ Currently, webkit-patch is unable to commit to the SVN repo. unless the
+ WebKit SVN username is already cached (from of a prior commit by hand)
+ because "svn commit" (called by webkit-patch) defaults to using the system
+ login name unless the username is already cached or specified on the
+ command line.
+
+ * Scripts/webkitpy/scm.py: Added methods SVN.has_authorization_for_realm and
+ modified SVN.commit_with_message to call it. Added optional username parameter
+ to method SVN.commit_with_message.
+ * Scripts/webkitpy/scm_unittest.py: Added unit test methods: SVNTest.test_commit_with_username,
+ SVNTest.test_has_authorization_for_realm, and SVNTest.test_not_have_authorization_for_realm.
+
+2010-02-22 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Siedel.
+
+ Add more checking for missing binaries and packages to check_sys_deps()
+
+ https://bugs.webkit.org/show_bug.cgi?id=35062
+
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/run_chromium_webkit_tests.py:
+
+2010-02-22 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ [Gtk] check-webkit-style: GTK style should be allowed in WebKitTools/DumpRenderTree/gtk
+ https://bugs.webkit.org/show_bug.cgi?id=35229
+
+ * Scripts/webkitpy/style/checker.py:
+ * Scripts/webkitpy/style/checker_unittest.py:
+
+2010-02-22 James Robinson <jamesr@chromium.org>
+
+ Unreviewed. Adding myself to committers list.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-02-22 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Remove DRT hack that turns off hardware acceleration with older QuickTimes
+ https://bugs.webkit.org/show_bug.cgi?id=35275
+
+ Now that WebKit does a version check to avoid a QuickTime-related
+ crash (r55100), DumpRenderTree does not need to.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+
+2010-02-22 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Build the DRT in debug on Mac OS X
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+
+2010-02-22 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Add support for layout tests on Symbian
+ https://bugs.webkit.org/show_bug.cgi?id=31589
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2010-02-20 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Moved simplejson into webkitpy/thirdparty directory.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35196
+
+ * Scripts/run-chromium-webkit-tests:
+ - Added webkitpy/thirdparty to the script's search path.
+
+ * Scripts/webkitpy/thirdparty/simplejson: Copied from WebKitTools/simplejson.
+ - Copied simplejson directory.
+
+ * simplejson: Removed.
+ * simplejson/LICENSE.txt: Removed.
+ * simplejson/README.txt: Removed.
+ * simplejson/__init__.py: Removed.
+ * simplejson/_speedups.c: Removed.
+ * simplejson/decoder.py: Removed.
+ * simplejson/encoder.py: Removed.
+ * simplejson/jsonfilter.py: Removed.
+ * simplejson/scanner.py: Removed.
+
+2010-02-20 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Moved BeautifulSoup to webkitpy/thirdparty directory.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35195
+
+ * Scripts/webkitpy/BeautifulSoup.py: Removed.
+ - Moved to webkitpy/thirdparty.
+
+ * Scripts/webkitpy/bugzilla.py:
+ - Updated import statement.
+
+ * Scripts/webkitpy/bugzilla_unittest.py:
+ - Updated import statement.
+
+ * Scripts/webkitpy/buildbot.py:
+ - Updated import statement.
+
+ * Scripts/webkitpy/buildbot_unittest.py:
+ - Updated import statement.
+
+ * Scripts/webkitpy/statusserver.py:
+ - Updated import statement.
+
+ * Scripts/webkitpy/thirdparty/BeautifulSoup.py: Copied from WebKitTools/Scripts/webkitpy/BeautifulSoup.py.
+
+2010-02-20 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Created a directory for third-party Python code, and moved
+ autoinstall.py into it.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34540
+
+ * Scripts/webkitpy/__init__.py:
+ - Updated "import autoinstall" statement.
+
+ * Scripts/webkitpy/autoinstall.py: Removed.
+ - Moved to thirdparty/autoinstall.py.
+
+ * Scripts/webkitpy/thirdparty: Added.
+ * Scripts/webkitpy/thirdparty/__init__.py: Added.
+ * Scripts/webkitpy/thirdparty/autoinstall.py: Copied from WebKitTools/Scripts/webkitpy/autoinstall.py.
+
+2010-02-20 Gustavo Noronha Silva <gns@gnome.org>
+
+ Unreviewed, obvious fix for the python failure in our new buildbot
+ step:
+
+ http://build.webkit.org/builders/GTK Linux 32-bit Release/builds/9075/steps/API tests/logs/err.text
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2010-02-19 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by David Levin.
+
+ Add an ENABLE flag for sandboxed iframes to make it possible to disable it in releases
+ https://bugs.webkit.org/show_bug.cgi?id=35147
+
+ * Scripts/build-webkit: Handle new flag.
+
+2010-02-19 Leandro Pereira <leandro@profusion.mobi>
+
+ Reviewed by Shinichiro Hamaji.
+
+ [style-queue] should not complain about identifier names with underscores under WebKit/efl/ewk/
+ https://bugs.webkit.org/show_bug.cgi?id=35091
+
+ White list unix_hacker_style names in WebKit/efl/ewk because these
+ are used in the EFL API.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Filter out readability/naming on WebKit/efl/ewk.
+
+2010-02-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Split out "prepare-rollout" from "rollout" and make --complete-rollout default
+ https://bugs.webkit.org/show_bug.cgi?id=33745
+
+ * Scripts/webkitpy/commands/download.py:
+ - Add a new AbstractRolloutPrepCommand to share code between PrepareRollout and Rollout
+ - Add PrepareRollout
+ * Scripts/webkitpy/commands/download_unittest.py: Test PrepareRollout, remove CompleteRollout tests.
+ * Scripts/webkitpy/steps/__init__.py: include ReopenBugAfterRollout step.
+ * Scripts/webkitpy/steps/completerollout.py: Removed.
+ * Scripts/webkitpy/steps/options.py: remove complete_rollout
+ * Scripts/webkitpy/steps/reopenbugafterrollout.py: Added.
+
+2010-02-19 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Need a final integration between QtLauncher and QGVLauncher
+ https://bugs.webkit.org/show_bug.cgi?id=35161
+
+ Add animated flip support to QtLauncher when running on QGraphicsView mode.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::initializeView):
+ (LauncherWindow::setupUI):
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::WebViewGraphicsBased):
+ (WebViewGraphicsBased::animatedFlip):
+ (WebViewGraphicsBased::animatedYFlip):
+ * QtLauncher/webview.h:
+ (WebViewGraphicsBased::setYRotation):
+ (WebViewGraphicsBased::yRotation):
+
+2010-02-19 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Implement textZoomIn() and textZoomOut() in DRT's EventSender, add results
+ for passing new tests and unskip the passing ones from the Skipped list.
+ https://bugs.webkit.org/show_bug.cgi?id=35159
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::textZoomIn):
+ (EventSender::textZoomOut):
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2010-02-19 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] Clean-up the handling of HTML5 persistent data for LayoutTests
+ https://bugs.webkit.org/show_bug.cgi?id=35004
+
+ DumpRenderTreeQt.cpp calls QWebSettings::enablePersistentStorage which sets up
+ and enables all HTML5 persistent data. All the other calls for setting the
+ persistent path or enabling the persistent feature are redundant.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage): No need to enable AppCache again.
+ * DumpRenderTree/qt/main.cpp:
+ (main): No need to setup and enable HTML5 LocalStorage again.
+
+2010-02-19 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Send the context menu event from contextClick() of EventSender
+ and do not show context menu in DRT.
+
+ LayoutTests:
+ fast/events/contextmenu-scrolled-page-with-frame.html
+
+ [Qt] DRT: Send context menu event from EventSender
+ https://bugs.webkit.org/show_bug.cgi?id=35131
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::contextClick):
+
+2010-02-18 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Moved parsing-related code to a separate file. Also increased
+ the unit test coverage in some affected areas.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34675
+
+ This revision contains no new functionality.
+
+ * Scripts/check-webkit-style:
+ - Adjusted to call check_webkit_style_parser().
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added check_webkit_style_parser() to pass checker.py
+ configuration settings to optparser.py.
+ - Moved _create_usage() and the CommandOptionValues,
+ DefaultCommandOptionValues, ArgumentPrinter, and
+ ArgumentParser classes to optparser.py.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Moved the ProcessorOptionsTest, ArgumentPrinterTest, and
+ ArgumentParserTest classes to optparser.py.
+ - Added the CheckWebKitStyleFunctionTest class to check
+ the check_webkit_style_configuration() and
+ check_webkit_style_parser() code paths.
+
+ * Scripts/webkitpy/style/optparser.py: Added.
+ - From checker.py, added _create_usage() and the
+ CommandOptionValues, DefaultCommandOptionValues,
+ ArgumentPrinter, and ArgumentParser classes.
+ - In the ArgumentParser constructor--
+ - Added all_categories as a required parameter.
+ - Removed the default value from the default_options parameter.
+
+ * Scripts/webkitpy/style/optparser_unittest.py: Added.
+ - From checker_unittest.py, added the ProcessorOptionsTest,
+ ArgumentPrinterTest, and ArgumentParserTest classes.
+ - Added the CreateUsageTest class to test _create_usage().
+
+ * Scripts/webkitpy/style/unittests.py:
+ - Added optparser_unittest import.
+
+2010-02-18 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ https://bugs.webkit.org/show_bug.cgi?id=35134
+ <rdar://problem/7246280> Crash when a plugin calls NPN_SetStatus(0)
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (testSetStatus):
+ (pluginInvoke):
+ Added a setStatus() method.
+
+2010-02-18 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Particularly constructed WebFrames can try to access a null HistoryItem
+ <rdar://problem/7638892> and https://bugs.webkit.org/show_bug.cgi?id=35063
+
+ Add the specific ability to test this API pattern.
+
+ For now only on Mac, perhaps on the main Windows port later, probably not relevant for other ports.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (apiTestNewWindowDataLoadBaseURLCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (-[APITestDelegate initWithCompletionCondition:]):
+ (-[APITestDelegate webView:didFailLoadWithError:forFrame:]):
+ (-[APITestDelegate webView:didFailProvisionalLoadWithError:forFrame:]):
+ (-[APITestDelegate webView:didFinishLoadForFrame:]):
+ (LayoutTestController::apiTestNewWindowDataLoadBaseURL): Create a WebView, do a loadData: in its
+ mainFrame, and synchronously wait for main load completion.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::apiTestNewWindowDataLoadBaseURL):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::apiTestNewWindowDataLoadBaseURL):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::apiTestNewWindowDataLoadBaseURL):
+
+2010-02-18 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ Teach resolve-ChangeLogs to act as a merge-driver for Git
+
+ https://bugs.webkit.org/show_bug.cgi?id=28721
+
+ To enable automatic merging of ChangeLog files, use the following command:
+
+ git config merge.changelog.driver "resolve-ChangeLogs --merge-driver %O %A %B"
+
+ The driver always works in "downstream" merge mode, meaning
+ it will always put the user's changelog entries on top.
+
+ * Scripts/resolve-ChangeLogs:
+
+2009-12-05 Gustavo Noronha Silva <gns@gnome.org>
+
+ Reviewed by Eric Seidel.
+
+ Enable running of GTK+ API tests.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+ * Scripts/run-gtk-tests: Added.
+
+2010-02-18 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ debug-safari doesn't pass --debug option to gdb-safari on MacOSX
+ https://bugs.webkit.org/show_bug.cgi?id=34411
+
+ * Scripts/webkitdirs.pm:
+
+2010-02-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ run-chromium-webkit-tests --platform=mac-leopard needs to run build-dumprendertree
+ https://bugs.webkit.org/show_bug.cgi?id=35053
+
+ * Scripts/webkitpy/layout_tests/port/base.py: Add script_path() function for finding scripts.
+ * Scripts/webkitpy/layout_tests/port/chromium.py: Remove unused argument.
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ - Make sure that calling webkit-build-directory works even if Scripts/ is not in the user's path.
+ - Call build-dumprendertree (and make sure it succeeds) before running the tests.
+
+2010-02-16 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Refactored check-webkit-style's ProcessorOptions class into two
+ classes. This revision contains no new functionality.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34674
+
+ Divided the ProcessorOptions class into a CommandOptionValues
+ class (the result of parsing the command-line options) and
+ a StyleCheckerConfiguration class (which configures the main
+ StyleChecker).
+
+ * Scripts/check-webkit-style:
+ - Updated main() to convert the parsed command option values
+ to a StyleCheckConfiguration instance prior to constructing
+ a StyleChecker.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added check_webkit_style_configuration() to convert a
+ CommandOptionValues instance into a StyleCheckerConfiguration
+ instance.
+ - Renamed the ProcessorOptions class to CommandOptionValues.
+ - In the CommandOptionValues class--
+ - Replaced the filter_configuration attribute with the
+ simpler filter_rules attribute.
+ - Removed the max_reports_per_error attribute.
+ - Moved the is_reportable() method to the new
+ StyleCheckerConfiguration class.
+ - Removed the base_filter_rules attribute from the
+ DefaultCommandOptionValues class.
+ - In the ArgumentParser class--
+ - Added base_filter_rules to the constructor.
+ - Changed the parse() method to return a CommandOptionValues
+ instance instead of a ProcessorOptions instance.
+ - Created a StyleCheckerConfiguration class.
+ - Added the data attributes max_reports_per_category,
+ stderr_write, and verbosity.
+ - Added is_reportable() (moved from the ProcessorOptions
+ class) and write_style_error() (moved from the
+ DefaultStyleErrorHandler class).
+ - In the StyleChecker class--
+ - Replaced the ProcessorOptions options attribute with the
+ StyleCheckerConfiguration _configuration attribute.
+ - Removed the _stderr_write attribute.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated the existing unit test classes as necessary.
+ - Added a StyleCheckerConfigurationTest class.
+
+ * Scripts/webkitpy/style/error_handlers.py:
+ - Updated the DefaultStyleErrorHandler class to accept a
+ StyleCheckerConfiguration instance instead of a ProcessorOptions
+ instance and an stderr_write method.
+
+ * Scripts/webkitpy/style/error_handlers_unittest.py:
+ - Updated the unit test classes as necessary.
+
+ * Scripts/webkitpy/style/filter.py:
+ - Addressed the FIXME in the FilterConfiguration class to change
+ the user_rules attribute to _user_rules (since it is now
+ accessed only internally).
+
+ * Scripts/webkitpy/style/filter_unittest.py:
+ - Updated to reflect the change from user_rules to _user_rules.
+
+2010-02-17 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Share the DRT values maxViewWidth/Height among ports
+ https://bugs.webkit.org/show_bug.cgi?id=34474
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (pageNumberForElementByIdCallback):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::maxViewWidth):
+ (LayoutTestController::maxViewHeight):
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (runTest):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (createWebViewAndOffscreenWindow):
+ (sizeWebViewForCurrentTest):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dump):
+ (createWebViewAndOffscreenWindow):
+
+2010-02-17 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [Win] Implement test functions for printing
+ https://bugs.webkit.org/show_bug.cgi?id=34570
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::pageNumberForElementById):
+ (LayoutTestController::numberOfPages):
+
+2010-02-17 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ websocket/tests/cookies/httponly-cookie.pl fails every time under run-chromium-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=35001
+
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py: add -x flag to run pywebsocket.
+
+2010-02-17 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ check-webkit-style: Misses variables that contain underscores.
+ https://bugs.webkit.org/show_bug.cgi?id=33724
+
+ - Check identifiers whose types are unsigned.
+ - Check bitfields properly.
+
+ * Scripts/webkitpy/style/processors/cpp.py:
+ * Scripts/webkitpy/style/processors/cpp_unittest.py:
+
+2010-02-17 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ check-webkit-style should report the number of files checked
+ https://bugs.webkit.org/show_bug.cgi?id=34971
+
+ * Scripts/check-webkit-style:
+ * Scripts/webkitpy/style/checker.py:
+ * Scripts/webkitpy/style/checker_unittest.py:
+
+2010-02-17 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Ariya Hidayat.
+
+ Make possible Qt DRT to get total number of pages to be printed
+
+ LayoutTests:
+ printing/numberOfPages.html
+
+ [Qt] DRT: Get total number of pages to be printed
+ https://bugs.webkit.org/show_bug.cgi?id=34955
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::numberOfPages):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-02-17 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ Update to use new property name.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2010-02-17 Julien Chaffraix <jchaffraix@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ Remove some warnings seen when building Qt
+ https://bugs.webkit.org/show_bug.cgi?id=35017
+
+ Using a machine without the needed tools to build WebKit leads to
+ several errors and warnings.
+
+ * Scripts/webkitdirs.pm: Refactored the code testing the command's
+ presence into a commandExists routine. While doing so removed, stderr
+ output as it usually does not give anything more than our message. Also
+ added a Qt check for qmake that was missing.
+
+2010-02-17 Xan Lopez <xlopez@igalia.com>
+
+ Rubber-stamped by Gustavo Noronha.
+
+ Disable Java by default in DRT.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2010-02-15 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Some minor check-webkit-style code clean-ups. This revision
+ contains no new functionality.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34932
+
+ * Scripts/check-webkit-style:
+ - Replaced the call to webkit_argument_defaults() with a
+ default parameter in the ArgumentParser constructor.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Removed the WEBKIT prefix from the default global variables.
+ - Prefixed several of the global variables with an underscore
+ to reflect that they are used internally.
+ - Renamed _DEFAULT_FILTER_RULES to _BASE_FILTER_RULES.
+ - Addressed a FIXME by changing the _PATH_RULES_SPECIFIER
+ configuration from list-tuple pairs to list-list pairs.
+ - Renamed style_categories() to _all_categories().
+ - Renamed webkit_argument_defaults() to _check_webkit_style_defaults().
+ - Renamed the ArgumentDefaults class to DefaultCommandOptionValues.
+ - In the ArgumentParser class--
+ - Renamed the doc_print attribute to stderr_write.
+ - Other minor updates.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated the import statements and unit test classes as necessary.
+ - Added assertions to test _PATH_RULES_SPECIFIER more fully.
+
+ * Scripts/webkitpy/style/error_handlers_unittest.py:
+ - Updated the unit test classes as necessary.
+ - Changed StyleErrorHandlerTestBase to store a list of error
+ messages rather than just the last one.
+
+ * Scripts/webkitpy/style/filter.py:
+ - Altered FilterConfiguration._path_rules_from_path()
+ to convert the path_rules list to a tuple.
+
+ * Scripts/webkitpy/style/filter_unittest.py:
+ - Updated the unit tests to reflect the change from tuples to
+ lists in the _PATH_RULES_SPECIFIER configuration variable.
+
+2010-02-16 Mark Rowe <mrowe@apple.com>
+
+ Let's not check garbage in to common build scripts and hose the world now eh guys?
+
+ * Scripts/webkitdirs.pm:
+
+2010-02-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ re-factor Skipped list parsing code into multiple functions and unit test it
+ https://bugs.webkit.org/show_bug.cgi?id=34986
+
+ * Scripts/test-webkitpy: Add new unit test.
+ * Scripts/webkitpy/layout_tests/__init__.py: Copied from WebKitTools/QueueStatusServer/filters/__init__.py.
+ * Scripts/webkitpy/layout_tests/port/mac.py: Split parsing function into multiple functions for testing.
+ * Scripts/webkitpy/layout_tests/port/mac_unittest.py: Added.
+
+2010-02-16 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ Enable 'auto-resize-window' in our DRT.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2010-02-15 Martin Robinson <mrobinson@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ check-webkit-style should not complain about NULL sentinel in calls to g_strconcat and g_strjoin
+ https://bugs.webkit.org/show_bug.cgi?id=34834
+
+ * Scripts/webkitpy/style/processors/cpp.py:
+ * Scripts/webkitpy/style/processors/cpp_unittest.py:
+
+2010-02-12 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Kevin Decker.
+
+ <rdar://problem/7130641> Browser objects identity is not preserved by Safari
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginInvoke): Added methods for checking object identity (via refcount).
+
+2010-02-15 Robert Hogan <robert@roberthogan.net>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] DRT: Support evaluateInWebInspector(), setTimelineProfilingEnabled().
+
+ Support LayoutTestController.evaluateInWebInspector(), setTimelineProfilingEnabled() in Qt DRT.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33096
+
+ This allows the following tests to pass:
+
+ inspector/console-format-collections.html
+ inspector/styles-iframe.html
+ inspector/syntax-highlight-css.html
+ inspector/syntax-highlight-javascript.html
+ inspector/timeline-enum-stability.html
+ inspector/timeline-layout.html
+ inspector/timeline-mark-timeline.html
+ inspector/timeline-paint.html
+ inspector/timeline-parse-html.html
+ inspector/timeline-recalculate-styles.html
+ inspector/timeline-script-tag-1.html
+ inspector/timeline-script-tag-2.html
+ inspector/timeline-trivial.html
+ inspector/cookie-resource-match.html
+ inspector/elements-img-tooltip.html
+ inspector/elements-panel-selection-on-refresh.html
+ inspector/inspected-objects-not-overriden.html
+ inspector/timeline-event-dispatch.html
+ inspector/timeline-network-resource.html
+ inspector/elements-panel-rewrite-href.html
+ inspector/console-dir.html
+ inspector/console-dirxml.html
+ inspector/console-format.html
+ inspector/console-tests.html
+ inspector/elements-panel-structure.html
+ inspector/evaluate-in-frontend.html
+ inspector/console-clear.html
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ (WebCore::isWebInspectorTest):
+ (WebCore::DumpRenderTree::open):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ (WebCore::DumpRenderTree::display):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::closeWebInspector):
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::evaluateInWebInspector):
+ (LayoutTestController::setTimelineProfilingEnabled):
+ (LayoutTestController::display):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-02-14 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Update rebaseline-chromium-webkit-tests to work with the new code
+ structure (port objects instead of path_utils and platform_utils).
+
+ Added a path_to_test_expectations_file() to the Port interface.
+
+ Fixed a bug in the chromium_* platform implementations where the
+ 'target' option was assumed to be set.
+
+ * Scripts/rebaseline-chromium-webkit-tests:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/test.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+
+2010-02-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ webkit-build-directory misuses terms
+ https://bugs.webkit.org/show_bug.cgi?id=34822
+
+ * Scripts/webkit-build-directory:
+ - Add --top-level and --configuration options and make using one of them required.
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ - Use --top-level instead of --base.
+
+2010-02-14 Chang Shu <Chang.Shu@nokia.com>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] Enable appcache feature.
+ https://bugs.webkit.org/show_bug.cgi?id=34713
+
+ Re-land r54543 without the change in DumpRenderTree/qt/main.cpp.
+ Persistent storage for AppCache is already initialized in
+ DumpRenderTreeQt.cpp.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+
+2010-02-12 Chang Shu <Chang.Shu@nokia.com>
+
+ Not Reviewed.
+
+ Change case of my email address as a work-around for the following bug.
+ https://bugs.webkit.org/show_bug.cgi?id=34717
+
+ * Scripts/webkitpy/committers.py:
+
+2010-02-12 Darin Adler <darin@apple.com>
+
+ Ignore compiled Python in more of webkitpy.
+
+ * Scripts/webkitpy/style/processors: Added property svn:ignore.
+
+2010-02-12 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Qt DRT now dump the frame loader callbacks when LayoutTestController()
+ method is called.
+
+ LayoutTests:
+ http/tests/security/mixedContent/data-url-script-in-iframe.html
+ http/tests/security/mixedContent/empty-url-plugin-in-frame.html
+ http/tests/security/mixedContent/insecure-css-in-iframe.html
+ http/tests/security/mixedContent/insecure-iframe-in-iframe.html
+ http/tests/security/mixedContent/insecure-image-in-iframe.html
+ http/tests/security/mixedContent/insecure-plugin-in-iframe.html
+ http/tests/security/mixedContent/insecure-script-in-iframe.html
+ http/tests/security/mixedContent/redirect-http-to-https-script-in-iframe.html
+ http/tests/security/mixedContent/redirect-https-to-http-script-in-iframe.html
+
+ [Qt] Make possible Qt DRT dump frame load callbacks
+ https://bugs.webkit.org/show_bug.cgi?id=34702
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::dumpFrameLoadCallbacks):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-02-12 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Antti Koivisto.
+
+ Make QtLauncher somewhat useable on S60.
+
+ Show the window fullscreen to make scrollbars appear, resize
+ the toolbar buttons to 16x16 to give more screen space to
+ web content and moved the location lineedit into a separate
+ line.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ * QtLauncher/mainwindow.cpp:
+ (MainWindow::buildUI):
+
+2010-02-12 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Support frameset flattening
+ https://bugs.webkit.org/show_bug.cgi?id=32717
+
+ Add FrameSet Flattening support to Mac DRT.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setFrameSetFlatteningEnabled):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setXSSAuditorEnabled):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setFrameSetFlatteningEnabled):
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setFrameSetFlatteningEnabledCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setFrameSetFlatteningEnabled):
+
+2010-02-12 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix typos in driver_test.py
+
+ https://bugs.webkit.org/show_bug.cgi?id=34810
+
+ * Scripts/webkitpy/layout_tests/driver_test.py:
+
+2010-02-12 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Make it possible to toggle the use of QGraphicsView in QtLauncher at run-time
+ https://bugs.webkit.org/show_bug.cgi?id=34844
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ (LauncherWindow::initializeView):
+ (LauncherWindow::setupUI):
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::WebViewGraphicsBased):
+
+2010-02-11 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ WebSocket ignores HttpOnly cookies, but should use in Handshake.
+ https://bugs.webkit.org/show_bug.cgi?id=34289
+
+ Update pywebsocket to 0.4.8, which supports cgi directories.
+ run-webkit-tests and run-webkit-websocketserver will run
+ pywebsocket, specifying /websocket/test/cookies as cgi directory.
+
+ * Scripts/run-webkit-tests:
+ * Scripts/run-webkit-websocketserver:
+ * pywebsocket/mod_pywebsocket/standalone.py:
+ * pywebsocket/setup.py:
+
+2010-02-11 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Dan Bernstein.
+
+ [Mac] Duplicated setXSSAuditorEnabled preference at Mac DRT
+ https://bugs.webkit.org/show_bug.cgi?id=34798
+
+ Remove duplicated setXSSAuditorEnabled preference at Mac DRT
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+
+2010-02-11 Eric Seidel <eric@webkit.org>
+
+ No review, build fix only.
+
+ webkitdirs.pm has a crazy amount of duplicated feature detection code
+ https://bugs.webkit.org/show_bug.cgi?id=34869
+
+ * Scripts/build-webkit: Fix typo which broke bots.
+
+2010-02-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkitdirs.pm has a crazy amount of duplicated feature detection code
+ https://bugs.webkit.org/show_bug.cgi?id=34869
+
+ * Scripts/build-webkit: Use the new hotness.
+ * Scripts/run-webkit-tests: ditto
+ * Scripts/webkitdirs.pm: Remove a bunch of bad duplicate code.
+ * Scripts/webkitperl/features.pm: Added.
+ - Simplified the 10 methods in webkitdirs.pm into 2 exported methods in this new file.
+
+2010-02-11 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Adam Barth.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34830
+
+ Makes method User.prompt static and adds the parameter repeat
+ to prompt the user up to repeat times.
+
+ * Scripts/test-webkitpy:
+ * Scripts/webkitpy/bugzilla.py: Substituted method User.prompt for method raw_input.
+ * Scripts/webkitpy/commands/upload.py: Ditto
+ * Scripts/webkitpy/credentials.py: Ditto
+ * Scripts/mock_bugzillatool.py: Updated prototype of MockUser.prompt to match User.prompt.
+ * Scripts/webkitpy/user.py: Made method prompt static and added parameter repeat.
+ * Scripts/webkitpy/user_unittest.py: Added.
+
+2010-02-10 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Darin Adler.
+
+ Allow underscored identifiers in CSSParser.cpp
+
+ Flex (http://flex.sourceforge.net/) uses identifiers named as yy_*.
+ WebCore/css/CSSParser.cpp needs to handle some such identifiers.
+ We should relax the style rule for the file to allow underscored identifiers.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34787
+
+ * Scripts/webkitpy/style/checker.py:
+
+2010-02-11 Eric Seidel <eric@webkit.org>
+
+ Rubber-stamped by Adam Barth.
+
+ Remove DrawTest, the application I used when bringing up SVG support on the Mac.
+ The code hasn't been touched (or used) in years. No sense in keeping it in trunk.
+
+ * Scripts/build-drawtest: Removed.
+ * Scripts/run-drawtest: Removed.
+ * DrawTest: Removed.
+
+2010-02-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Need a command to clear r+ on obsolete patches in the pending-commit queue.
+ https://bugs.webkit.org/show_bug.cgi?id=34863
+
+ Unfortunately our http://webkit.org/pending-commit bugzilla query is not
+ smart enough to ignore obsolete patches, so bugs show up there which are
+ still open, but do not have patches ready for landing on them.
+ This new command "clean-pending-commit" will remove r+ from obsolete patches
+ in the pending-commit list.
+
+ * Scripts/test-webkitpy: Add grammar_unittest
+ * Scripts/webkitpy/commands/upload.py: Add clean-pending-commit and make assign-to-committer ignore cq+'d patches.
+ * Scripts/webkitpy/grammar.py: Add join_with_separators
+ * Scripts/webkitpy/grammar_unittest.py: Added.
+
+2010-02-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ run-chromium-webkit-tests fails random pixel tests on Mac
+ https://bugs.webkit.org/show_bug.cgi?id=34862
+
+ This is due to the fact that the Mac port has an
+ invalid path to the image diff tool. Currently it points
+ to image_diff even though ImageDiff would be correct. We
+ can't change it to the right path yet without causing the
+ script to hang. ImageDiff expects to be long-running and
+ be passed image data over stdin. image_diff (chromium's fork)
+ expects to be passed command line arguments.
+ This fix works around the random failures by disabling pixel
+ tests on mac and logging if the user was trying to run with pixel
+ tests enabled.
+
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+
+2010-02-11 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Reviewed by Adam Roben.
+ Try to fix build breakage from r54665.
+
+ * Scripts/check-for-global-initializers:
+
+2010-02-11 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Make it possible to toggle accelerated compositing from the menu
+ at run-time.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::toggleAcceleratedCompositing):
+ (LauncherWindow::setupUI):
+
+2010-02-08 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Cameron Zwarich.
+
+ Restore ENABLE_RUBY flag so vendors can ship with Ruby disabled if they choose.
+ https://bugs.webkit.org/show_bug.cgi?id=34698
+
+ * Scripts/build-webkit:
+
+2010-02-10 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix various minor bugs keeping run-chromium-webkit-tests from actually
+ working on the linux and win ports of Chromium.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34739
+
+ * Scripts/webkitpy/layout_tests/layout_package/test_shell_thread.py:
+ * Scripts/webkitpy/layout_tests/port/__init__.py:
+ * Scripts/webkitpy/layout_tests/port/base.py:
+ * Scripts/webkitpy/layout_tests/port/chromium.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/http_server.py:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+
+2010-02-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ run-chromium-webkit-tests --platform=mac-leopard crashes when using a custom build directory
+ https://bugs.webkit.org/show_bug.cgi?id=34817
+
+ This doesn't fix the root cause of us not
+ correctly failing when support binaries are missing.
+ This only causes the DumpRenderTree binary not to be
+ missing in the custom build directory case.
+ Later patches will make us correctly fail fast when
+ support binaries (like DumpRenderTree or ImageDiff) are missing.
+
+ * Scripts/webkit-build-directory: Added.
+ - Need a way to re-use the perl logic for finding build directories in non-perl scripts.
+ * Scripts/webkitpy/layout_tests/port/base.py: Add a FIXME.
+ * Scripts/webkitpy/layout_tests/port/mac.py:
+ - Call webkit-build-directory to find the build directory instead of assuming "WebKitBuild"
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: Add FIXMEs.
+
+2010-02-10 Kevin Watters <kevinwatters@gmail.com>
+
+ Reviewed by Kevin Ollivier.
+
+ [wx] Add Windows complex text support.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34759
+
+ * wx/build/settings.py:
+
+2010-02-10 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix. Add stub for new LayoutTestController method.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::numberOfPages):
+
+2010-02-10 Csaba Osztrogonác <ossy@webkit.org>
+
+ Unreviewed. Roll out r54626, because it broke GTK and Win build.
+ https://bugs.webkit.org/show_bug.cgi?id=32717
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+
+2010-02-10 Jesus Sanchez-Palencia <jesus.palencia@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Support frameset flattening
+ https://bugs.webkit.org/show_bug.cgi?id=32717
+
+ Add FrameSet Flattening support to Mac DRT.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setFrameSetFlatteningEnabledCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setFrameSetFlatteningEnabled):
+
+2010-02-08 Jon Honeycutt <jhoneycutt@apple.com>
+
+ <rdar://problem/7436875> Crash in Flash when visiting
+ http://www.cctv.com/default.shtml (WER ID 819298200) [watson 2502260]
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp:
+ (executeScript):
+ Moved to an earlier point in the file.
+ (NPP_New):
+ If the plug-in has an onDestroy attribute, store its value.
+ (NPP_Destroy):
+ If the plug-in has code to run on destruction, run it and free it.
+
+2010-02-10 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Implement pageNumberForElementById() method in Qt DRT LayoutTestController,
+ to make Qt DRT able to get page number.
+
+ LayoutTests:
+ printing/page-break-always.html
+ printing/pageNumerForElementById.html
+ printing/css2.1/page-break-before-000.html
+ printing/css2.1/page-break-after-000.html
+ printing/css2.1/page-break-after-004.html
+ printing/css2.1/page-break-before-001.html
+ printing/css2.1/page-break-after-001.html
+ printing/css2.1/page-break-after-002.html
+ printing/css2.1/page-break-before-002.html
+ printing/css2.1/page-break-inside-000.html
+
+ [Qt] Make possible Qt DRT get a page number for element by ID
+ https://bugs.webkit.org/show_bug.cgi?id=34777
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::pageNumberForElementById):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-02-10 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make run-iexploder-tests work on Linux.
+ https://bugs.webkit.org/show_bug.cgi?id=34748
+
+ Extract the platform dependant Apache configuration checking code in httpd.pm to a separate function
+ called getHTTPDConfigPathForTestDirectory and use run-launcher instead of run-safari if run on Linux.
+
+ * Scripts/run-iexploder-tests:
+ * Scripts/webkitperl/httpd.pm:
+
+2010-02-09 Csaba Osztrogonác <ossy@webkit.org>
+
+ [Qt] Unreviewed. Roll-out r54543, because layout tests crash in debug mode.
+ https://bugs.webkit.org/show_bug.cgi?id=34713
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2010-02-09 Alejandro G. Castro <alex@igalia.com>
+
+ Unreviewed; added myself to committers
+
+ * Scripts/webkitpy/committers.py:
+
+2010-02-09 Yael Aharon <yael.aharon@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Webkit in Qt does not have window.showModalDialog
+ https://bugs.webkit.org/show_bug.cgi?id=25585
+
+ Set the modality flag when createWindow is called with window type WebWindowDialog.
+
+ * QtLauncher/main.cpp:
+ (WebPage::createWindow):
+
+2010-02-09 Andras Becsi <abecsi@webkit.org>
+
+ Unreviewed trivial warning fix.
+
+ * Scripts/build-webkit:
+
+2010-02-09 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Add possibility of passing parameters to build-webkit by environment variable,
+ because the buildbot slaves can't control the arguments.
+
+ * Scripts/build-webkit:
+
+2010-02-09 Chang Shu <Chang.Shu@nokia.com>
+
+ Reviewed by Laszlo Gombos.
+
+ [Qt] Enable appcache feature.
+ https://bugs.webkit.org/show_bug.cgi?id=34713
+
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2010-02-09 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Provide a way to get total number of pages to be printed
+ https://bugs.webkit.org/show_bug.cgi?id=34699
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (parsePageParameters):
+ (pageNumberForElementByIdCallback):
+ (numberOfPagesCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::numberOfPages):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::numberOfPages):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::numberOfPages):
+
+2010-02-08 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34727
+ Assertion crashes and freezes when plug-in property access results in an exception
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginGetProperty): Raise an exception when accessing a particular property.
+ (pluginSetProperty): Ditto.
+ (pluginInvoke): Added methods to get and set host object properties.
+
+2010-02-08 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] Backport No'am Rosenthal's frame rate measurement
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ (LauncherApplication::handleUserOptions):
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::WebViewGraphicsBased):
+ (WebViewGraphicsBased::enableFrameRateMeasurement):
+ (WebViewGraphicsBased::updateFrameRate):
+ (WebViewGraphicsBased::paintEvent):
+ * QtLauncher/webview.h:
+
+2010-02-08 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [Qt] Make overridePreference complain when it does not
+ support the preference given.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::overridePreference):
+
+2010-02-08 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Set stdout/stderr to binary mode for DRT on Windows
+
+ This makes sure we don't end up with lots of CRLFs in the
+ DRT output, which breaks tons of results. Matches what
+ the Windows DRT does.
+
+ * DumpRenderTree/qt/main.cpp:
+
+2010-02-08 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Build fix for Qt on Windows.
+
+ Don't use noreturn directly since it's a gcc attribute.
+ Instead use the NO_RETURN macro from AlwaysInline.h
+
+ * QtLauncher/QtLauncher.pro:
+ * QtLauncher/utils.h:
+
+2010-02-05 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Suppressed check-webkit-style's underscore check in Qt's autotests.
+ Also made the path-specific filter check case-insensitive.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34574
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added a list element to _PATH_RULES_SPECIFIER for
+ directories that should be excluded from the
+ "readability/naming" category (the category that relates to
+ underscores in identifiers, for example).
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Added an "end-to-end" test for "WebKit/qt/tests/".
+
+ * Scripts/webkitpy/style/filter.py:
+ - Altered FilterConfiguration's should_check() method to
+ check for path substring matches case-insensitively.
+
+ * Scripts/webkitpy/style/filter_unittest.py:
+ - Added a test to check case-insensitive path substring matching.
+
+ * Scripts/webkitpy/style/processors/cpp.py:
+ - Removed the hard-coded "WebKit/gtk/webkit/" path reference
+ since this is now taken care of by the _PATH_RULES_SPECIFIER
+ configuration variable.
+
+ * Scripts/webkitpy/style/processors/cpp_unittest.py:
+ - Removed the unit test for the GTK directory since this
+ is now taken care of by the checker._PATH_RULES_SPECIFIER
+ end-to-end tests.
+
+2010-02-08 Leith Bade <leith@leithalweapon.geek.nz>
+
+ Reviewed by Darin Adler.
+
+ Fixes: https://bugs.webkit.org/show_bug.cgi?id=34637
+ Corrects the newline inserted into WebKitOutputDir, and WebKitLibrariesDir Windows
+ environemnt variables when there is a space in the user's /home path.
+
+ * Scripts/webkitdirs.pm:
+ - Added missing quotes around $sourceDir in argument list of cygpath in determineWindowsSourceDir().
+
+2010-02-05 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34670
+ TestNetscapePlugin should work with Firefox
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp: (NPP_New): Default to Carbon if
+ browser doesn't tell what it supports.
+
+2010-02-05 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [Gtk] Implement layoutTestController.pageNumberForElementById
+ https://bugs.webkit.org/show_bug.cgi?id=34572
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::pageNumberForElementById):
+
+2010-02-03 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Add a simple test implementation and the WebKit Mac implementation
+ for the layout_tests/port package. Also add a simple test driver of
+ that interface.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34511
+
+ * Scripts/webkitpy/layout_tests/driver_test.py: Added.
+ * Scripts/webkitpy/layout_tests/port/__init__.py:
+ * Scripts/webkitpy/layout_tests/port/mac.py: Added.
+ * Scripts/webkitpy/layout_tests/port/test.py: Added.
+
+2010-02-03 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Siedel.
+
+ Refactor the port package into an object-oriented style and merge
+ path_utils into it. We add a 'base' and a 'chromium' object to the
+ port package; this will allow us to easily add new ports (like
+ WebKit Mac).
+
+ https://bugs.webkit.org/show_bug.cgi?id=34511
+
+ * Scripts/rebaseline-chromium-webkit-tests:
+ * Scripts/run-chromium-webkit-tests:
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_files.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_shell_thread.py:
+ * Scripts/webkitpy/layout_tests/port/__init__.py:
+ * Scripts/webkitpy/layout_tests/port/apache_http_server.py:
+ * Scripts/webkitpy/layout_tests/port/base.py: Added.
+ * Scripts/webkitpy/layout_tests/port/chromium.py: Added.
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/http_server.py:
+ * Scripts/webkitpy/layout_tests/port/http_server_base.py:
+ * Scripts/webkitpy/layout_tests/port/path_utils.py: Removed.
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-01-19 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Dave Hyatt.
+
+ Implement flattening of framesets
+ https://bugs.webkit.org/show_bug.cgi?id=32717
+
+ Add support for testing frame flattening with the Qt DRT
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setFrameSetFlatteningEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-02-03 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Provided a way in check-webkit-style to specify filter rules
+ on a per file or folder basis, via a configuration variable.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33684
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added _PATH_RULES_SPECIFIER configuration variable.
+ - In ProcessorOptions class--
+ - Changed the CategoryFilter attribute to FilterConfiguration.
+ - Added path parameter to is_reportable().
+ - Renamed ArgumentDefaults filter_rules attribute to
+ base_filter_rules.
+ - Updated ArgumentPrinter class.
+ - Added filter rule validation to ArgumentParser (instead of
+ in CategoryFilter constructor).
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated unit tests as necessary.
+ - Added unit tests for PATH_RULES_SPECIFIER.
+
+ * Scripts/webkitpy/style/error_handlers.py:
+ - Updated DefaultStyleErrorHandler to use file path when
+ calling is_reportable().
+
+ * Scripts/webkitpy/style/error_handlers_unittest.py:
+ - Updated unit tests as necessary.
+
+ * Scripts/webkitpy/style/filter.py:
+ - Marked CategoryFilter internal with an underscore.
+ - Removed argument validation from CategoryFilter.
+ - Added FilterConfiguration class.
+
+ * Scripts/webkitpy/style/filter_unittest.py:
+ - Updated CategoryFilterTest class.
+ - Added FilterConfigurationTest unit tests.
+
+ * Scripts/webkitpy/style/processors/cpp.py:
+ - Removed _is_test_filename() code.
+ - Removed hard-coded path checks from check_include_line().
+
+ * Scripts/webkitpy/style/processors/cpp_unittest.py:
+ - Removed three unit tests related to exempted files.
+
+2010-02-05 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] Apply the command line options as settings to the
+ graphics system.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ (requiresGraphicsView):
+ (LauncherApplication::handleUserOptions):
+ * QtLauncher/webview.h:
+ (WebViewGraphicsBased::setItemCacheMode):
+
+2010-02-05 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Notify user that run-webkit-tests has to be run under Cygwin
+
+ The script will bail out if run under Windows shell or Msys.
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2010-02-05 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Generate convenience headers (QWebView, etc) using qmake
+
+ In Qt this is done using syncqt, but we use a pro-file instead
+ that generates makefile-rules for each of the extra headers.
+
+ These extra headers are installed alongside the normal headers.
+
+ * Scripts/webkitdirs.pm: Run qmake and make on new API-DerivedSources
+
+2010-02-05 Andras Becsi <abecsi@webkit.org>
+
+ Unreviewed typo fix.
+
+ Fix wrong whitespace alignment introduced in r54342.
+
+ * Scripts/run-webkit-tests:
+
+2010-02-04 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Timothy Hatcher.
+
+ Build fix. Remove a symbol corresponding to an inline function from the linker export
+ file to prevent a weak external failure.
+
+ * Scripts/check-for-weak-vtables-and-externals: Renamed from WebKitTools/Scripts/check-for-weak-vtables.
+ Teach the script how to detect weak external symbols so that these errors can be caught immediately
+ in the future.
+
+2010-02-04 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Oliver Hunt.
+
+ [Qt] Make it possible to choose whether the launcher should
+ use the traditional QWidget based QWebView or the newer
+ QGraphics based QGraphicsWebView on a QGraphicsView.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ (LauncherWindow::eventFilter):
+ (LauncherWindow::loadStarted):
+ (LauncherWindow::print):
+ (LauncherWindow::screenshot):
+ (LauncherWindow::setEditable):
+ (LauncherWindow::setupUI):
+ (main):
+ * QtLauncher/webview.cpp:
+ (WebViewGraphicsBased::WebViewGraphicsBased):
+ (WebViewGraphicsBased::resizeEvent):
+ (GraphicsWebView::mousePressEvent):
+ (GraphicsWebView::contextMenuEvent):
+ * QtLauncher/webview.h:
+ (WebViewTraditional::WebViewTraditional):
+ (GraphicsWebView::GraphicsWebView):
+ (WebViewGraphicsBased::setPage):
+
+2010-02-04 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Oliver Hunt.
+
+ [Qt] QtLauncher cleanup.
+
+ Refactor option handling out in utility functions and make the
+ arguments more Qt compatible.
+
+ * QtLauncher/main.cpp:
+ (requiresGraphicsView):
+ (LauncherApplication::handleUserOptions):
+ * QtLauncher/utils.cpp:
+ (takeOptionValue):
+ (formatKeys):
+ (enumToKeys):
+ (appQuit):
+ * QtLauncher/utils.h:
+
+2010-02-04 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Implement a locking and scheduling mechanism for http testing sessions to be able
+ to run multiple instances of run-webkit-tests parallel on the same machine.
+ If a test session wants to run http tests and this feature is enabled, the pending
+ sessions create lockfiles with sequential lock numbers. These locks are used to schedule
+ the running test sessions in first come first served order. An exclusive lock ensures
+ that the lock numbers are sequential to avoid deadlocks and starvation.
+ Because the buildbot master specifies the flags used by slaves we need an environment
+ variable too to be able to use the feature per-slave.
+ Exporting WEBKIT_WAIT_FOR_HTTPD=1 before testing or using the --wait-for-httpd
+ flag enables this feature, otherwise this patch has no effect on the testing whatsoever.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33153
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitperl/httpd.pm:
+
+2010-01-22 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Make run-webkit-tests work under Cygwin for the Qt port
+
+ setPathForRunningWebKitApp() is implemented for the Qt port
+ by using qmake to query for the location of the Qt libraries.
+
+ This requires the original environment (%ENV) to be untouched,
+ so launchWithCurrentEnv() was refactored to launchWithEnv(),
+ and the code in openDumpTool() to not use %ENV but a %CLEAN_ENV
+ instead. This has the added benefit of getting rid of the temp
+ variables used for storing the current env.
+
+ openDumpTool() is also refactored a bit into platform-spesific,
+ port-spesific, and generic environment variables.
+
+ Checks for undef was added a few places to fix Perl concat
+ warnings when run-webkit-tests is aborted.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33895
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2010-02-04 Yuzo Fujishima <yuzo@google.com>
+
+ Unreviewed.
+
+ Add Yuzo to the committers list.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-02-03 Dirk Pranke <dpranke@chromium.org>
+
+ Rubber-stamped by Eric Seidel.
+
+ Change "the Chromium name" to "the name of Google Inc." in the licenses
+
+ https://bugs.webkit.org/show_bug.cgi?id=34511
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/metered_stream.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_failures.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_files.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_shell_thread.py:
+ * Scripts/webkitpy/layout_tests/port/__init__.py:
+ * Scripts/webkitpy/layout_tests/port/apache_http_server.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py:
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py:
+ * Scripts/webkitpy/layout_tests/port/http_server.py:
+ * Scripts/webkitpy/layout_tests/port/http_server_base.py:
+ * Scripts/webkitpy/layout_tests/port/path_utils.py:
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-02-03 Dirk Pranke <dpranke@chromium.org>
+
+ Rubber-stamped by Eric Siedel.
+
+ Rename files as part of refactoring the layout_tests package. All
+ the platform_utils* module, the path_utils.py module, and
+ the http server and web socket server modules are moved into a new
+ port/ package.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34511
+
+ * Scripts/webkitpy/layout_tests/layout_package/apache_http_server.py: Removed.
+ * Scripts/webkitpy/layout_tests/layout_package/http_server.py: Removed.
+ * Scripts/webkitpy/layout_tests/layout_package/http_server_base.py: Removed.
+ * Scripts/webkitpy/layout_tests/layout_package/httpd2.pem: Removed.
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/lighttpd.conf: Removed.
+ * Scripts/webkitpy/layout_tests/layout_package/path_utils.py: Removed.
+ * Scripts/webkitpy/layout_tests/layout_package/platform_utils.py: Removed.
+ * Scripts/webkitpy/layout_tests/layout_package/platform_utils_linux.py: Removed.
+ * Scripts/webkitpy/layout_tests/layout_package/platform_utils_mac.py: Removed.
+ * Scripts/webkitpy/layout_tests/layout_package/platform_utils_win.py: Removed.
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_files.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_shell_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/websocket_server.py: Removed.
+ * Scripts/webkitpy/layout_tests/port: Added.
+ * Scripts/webkitpy/layout_tests/port/__init__.py: Copied from Scripts/webkitpy/layout_tests/layout_package/platform_utils.py.
+ * Scripts/webkitpy/layout_tests/port/apache_http_server.py: Copied from Scripts/webkitpy/layout_tests/layout_package/apache_http_server.py.
+ * Scripts/webkitpy/layout_tests/port/chromium_linux.py: Copied from Scripts/webkitpy/layout_tests/layout_package/platform_utils_linux.py.
+ * Scripts/webkitpy/layout_tests/port/chromium_mac.py: Copied from Scripts/webkitpy/layout_tests/layout_package/platform_utils_mac.py.
+ * Scripts/webkitpy/layout_tests/port/chromium_win.py: Copied from Scripts/webkitpy/layout_tests/layout_package/platform_utils_win.py.
+ * Scripts/webkitpy/layout_tests/port/http_server.py: Copied from Scripts/webkitpy/layout_tests/layout_package/http_server.py.
+ * Scripts/webkitpy/layout_tests/port/http_server_base.py: Copied from Scripts/webkitpy/layout_tests/layout_package/http_server_base.py.
+ * Scripts/webkitpy/layout_tests/port/httpd2.pem: Copied from Scripts/webkitpy/layout_tests/layout_package/httpd2.pem.
+ * Scripts/webkitpy/layout_tests/port/lighttpd.conf: Copied from Scripts/webkitpy/layout_tests/layout_package/lighttpd.conf.
+ * Scripts/webkitpy/layout_tests/port/path_utils.py: Copied from Scripts/webkitpy/layout_tests/layout_package/path_utils.py.
+ * Scripts/webkitpy/layout_tests/port/websocket_server.py: Copied from Scripts/webkitpy/layout_tests/layout_package/websocket_server.py.
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+
+2010-02-03 Csaba Osztrogonác <ossy@webkit.org>
+
+ Rubber-stamped by Eric Seidel.
+
+ Roll back r53559 and r54084 again, because roll out didn't solve flakeyness on the Windows Test bots
+ https://bugs.webkit.org/show_bug.cgi?id=34399
+
+ * Scripts/run-iexploder-tests:
+ * Scripts/run-webkit-httpd:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitperl/httpd.pm: Added.
+
+2010-02-03 Csaba Osztrogonác <ossy@webkit.org>
+
+ Rubber-stamped by Eric Seidel.
+
+ Roll out r53559 and r54084, because it might caused flakeyness on the Windows Test bots
+
+ * Scripts/run-iexploder-tests:
+ * Scripts/run-webkit-httpd:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitperl/httpd.pm: Removed.
+
+2010-02-03 Csaba Osztrogonác <ossy@webkit.org>
+
+ Rubber-stamped by Ariya Hidayat.
+
+ Roll back r53889 again, because roll out didn't solve flakeyness on the Windows Test bots
+ https://bugs.webkit.org/show_bug.cgi?id=34399
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (buildModifierFlags):
+ (mouseDownCallback):
+ (mouseUpCallback):
+ (keyDownCallback):
+
+2010-02-03 Eric Seidel <eric@webkit.org>
+
+ No review, just fixing copyrights.
+
+ Concerns were expressed about "The Chromium Authors" being
+ a valid legal entity for copyright assignment in the WebKit repository,
+ so this change removes all "The Chromium Authors".
+
+ I looked at the svn logs in src.chromium.org and failed to find any
+ non-google contributions to these files, so they are all now
+ marked as copyright "Google Inc" as all Google contributers assign
+ copyright to "Google Inc" as part of their employment agreement.
+
+ * Scripts/rebaseline-chromium-webkit-tests:
+ * Scripts/run-chromium-webkit-tests:
+ * Scripts/webkitpy/layout_tests/layout_package/apache_http_server.py:
+ * Scripts/webkitpy/layout_tests/layout_package/http_server.py:
+ * Scripts/webkitpy/layout_tests/layout_package/http_server_base.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py:
+ * Scripts/webkitpy/layout_tests/layout_package/metered_stream.py:
+ * Scripts/webkitpy/layout_tests/layout_package/path_utils.py:
+ * Scripts/webkitpy/layout_tests/layout_package/platform_utils.py:
+ * Scripts/webkitpy/layout_tests/layout_package/platform_utils_linux.py:
+ * Scripts/webkitpy/layout_tests/layout_package/platform_utils_mac.py:
+ * Scripts/webkitpy/layout_tests/layout_package/platform_utils_win.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_failures.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_files.py:
+ * Scripts/webkitpy/layout_tests/layout_package/test_shell_thread.py:
+ * Scripts/webkitpy/layout_tests/layout_package/websocket_server.py:
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/run_chromium_webkit_tests.py:
+ * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py:
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py:
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py:
+
+2010-02-03 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] QtLauncher, refactor argument handling in preparation of merge
+ with QGVLauncher
+
+ * QtLauncher/main.cpp:
+ (LauncherApplication::urls):
+ (LauncherApplication::isRobotized):
+ (LauncherApplication::applyDefaultSettings):
+ (LauncherApplication::LauncherApplication):
+ (LauncherApplication::formatKeys):
+ (LauncherApplication::enumToKeys):
+ (fail):
+ (LauncherApplication::handleUserOptions):
+ (main):
+
+2010-02-03 Csaba Osztrogonác <ossy@webkit.org>
+
+ Rubber-stamped by Ariya Hidayat.
+
+ Rolling out r53889, because it might caused flakeyness on the Windows Test bots
+ https://bugs.webkit.org/show_bug.cgi?id=34399
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (mouseDownCallback):
+ (mouseUpCallback):
+ (keyDownCallback):
+
+2010-02-03 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] Fix pixel tests support.
+ https://bugs.webkit.org/show_bug.cgi?id=27813
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::processLine):
+ - Hash processing mechanism moved from DumpRenderTree::open to DumpRenderTree::processLine.
+ (WebCore::DumpRenderTree::dump): Fixed and renamed variables.
+
+2010-02-03 Kevin Watters <kevinwatters@gmail.com>
+
+ Reviewed by Kevin Ollivier.
+
+ [wx] Enable JIT compilation for wx.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34536
+
+ * wx/build/settings.py:
+
+2010-02-02 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after introduction of pageNumberForElementById.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::pageNumberForElementById):
+
+2010-02-02 Shu Chang <Chang.Shu@nokia.com>
+
+ Unreviewed.
+
+ Add myself to list of committers.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-02-02 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Moved filter-related check-webkit-style code into a separate
+ filter module.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34408
+
+ This is preparatory refactoring for Bug 33684, which will allow
+ file and folder-specific filter rules.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Removed CategoryFilter class (moved to filter.py).
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Removed CategoryFilter unit tests (moved to filter_unittest.py).
+
+ * Scripts/webkitpy/style/filter.py: Added.
+ - Added CategoryFilter class (moved from checker.py).
+
+ * Scripts/webkitpy/style/filter_unittest.py: Added.
+ - Added CategoryFilter unit tests (moved from checker_unittest.py).
+
+ * Scripts/webkitpy/style/unittests.py:
+ - Added reference to filter_unittest.py.
+
+2010-02-01 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Addressed FIXME in check-webkit-style so that the carriage-return
+ check will work for patches.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34260
+
+ Also added support for limiting the number of errors reported
+ per category, per file.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added new "whitespace/carriage_return" category from common.py.
+ - Added MAX_REPORTS_PER_CATEGORY dictionary.
+ - Added max_reports_per_category attribute to ProcessorOptions class.
+ - Refactored StyleChecker._process_file().
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Updated ProcessorOptionsTest tests.
+ - Added test to check MAX_REPORTS_PER_CATEGORY.
+
+ * Scripts/webkitpy/style/error_handlers.py:
+ - Added support for suppressing the display of errors after
+ reaching a per-category maximum (from max_reports_per_category).
+
+ * Scripts/webkitpy/style/error_handlers_unittest.py:
+ - Added test for suppressing error display.
+
+ * Scripts/webkitpy/style/processors/common.py: Added.
+ - Moved carriage-return check to new file.
+
+ * Scripts/webkitpy/style/processors/common_unittest.py: Added.
+ - Added unit tests for carriage-return check.
+
+ * Scripts/webkitpy/style/unittests.py:
+ - Added reference to common_unittest.py.
+
+2010-02-01 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Provide a way to get page number with layoutTestController
+ https://bugs.webkit.org/show_bug.cgi?id=33840
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (pageNumberForElementByIdCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::pageNumberForElementById):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::pageNumberForElementById):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::pageNumberForElementById):
+
+2010-02-01 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Unreviewed fix for an invalid function call.
+
+ check-webkit-style: Remove filename parameter from all functions where no longer used
+ https://bugs.webkit.org/show_bug.cgi?id=34249
+
+ * Scripts/webkitpy/style/checker.py:
+
+2010-02-01 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] DRT Provide global flag ability
+ https://bugs.webkit.org/show_bug.cgi?id=34418
+
+ Add the globalFlag property to the Qt LayoutTestController to allow
+ cross-domain indications.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::globalFlag):
+ (LayoutTestController::setGlobalFlag):
+
+2010-02-01 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ Crash in Safari opening new tabs to "same page"
+ <rdar://problem/7593857> and https://bugs.webkit.org/show_bug.cgi?id=34444
+
+ Add a mode (Mac-only for now) that exercises the WebView SPI _loadBackForwardListFromOtherView:
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (setNewWindowsCopyBackForwardListCallback):
+ (LayoutTestController::staticFunctions):
+
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::newWindowsCopyBackForwardList):
+ (LayoutTestController::setNewWindowsCopyBackForwardList):
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:createWebViewWithRequest:]):
+
+2010-02-01 Carol Szabo <carol.szabo@nokia.com>
+
+ Unreviewed.
+
+ Add myself to list of committers.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-02-01 Nate Chapin <japhet@chromium.org>
+
+ Rubber-stamped by David Levin.
+
+ Add myself to reviewer list.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-01-31 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Moved style error handler code to their own classes, and
+ related refactoring. Increased unit test code coverage of
+ style error handling.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34379
+
+ * Scripts/check-webkit-style:
+ - Minor change: added error_count variable.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Renamed ProcessorOptions.should_report_error() to is_reportable().
+ - In the StyleChecker class--
+ - Removed _default_style_error_handler().
+ - Added _increment_error_count().
+ - Refactored to use DefaultStyleErrorHandler and
+ PatchStyleErrorHandler constructors.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - In the StyleStyleCheckerTest class--
+ - Removed write_sample_error().
+ - Removed test_default_style_error_handler().
+
+ * Scripts/webkitpy/style/error_handlers.py: Added.
+ - Added DefaultStyleErrorHandler class.
+ - Added PatchStyleErrorHandler class.
+
+ * Scripts/webkitpy/style/error_handlers_unittest.py: Added.
+ - Added unit tests for DefaultStyleErrorHandler and
+ PatchStyleErrorHandler.
+
+ * Scripts/webkitpy/style/unittests.py:
+ - Added error_handlers unit tests.
+
+2010-01-29 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Stephanie Lewis.
+
+ Fix run-leaks with newer versions of the leaks tool.
+
+ * Scripts/run-leaks:
+
+2010-01-29 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Siedel.
+
+ Top-level test drivers for running the Chromium port of run-webkit-tests
+ and being able to rebaseline test results from the test bots. The
+ files in the Scripts directory are simply wrappers around the files
+ in webkitpy/layout_tests for convenience.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31498
+
+ * Scripts/rebaseline-chromium-webkit-tests: Added.
+ * Scripts/run-chromium-webkit-tests: Added.
+ * Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py: Added.
+ * Scripts/webkitpy/layout_tests/run_chromium_webkit_tests.py: Added.
+
+2010-01-29 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Siedel.
+
+ Add in the second block of python code for the Chromium port
+ of run-webkit-tests. These files execute different diffs to classify
+ the various types of failures from a test.
+
+ * Scripts/webkitpy/layout_tests/test_types: Added.
+ * Scripts/webkitpy/layout_tests/test_types/__init__.py: Added.
+ * Scripts/webkitpy/layout_tests/test_types/fuzzy_image_diff.py: Added.
+ * Scripts/webkitpy/layout_tests/test_types/image_diff.py: Added.
+ * Scripts/webkitpy/layout_tests/test_types/test_type_base.py: Added.
+ * Scripts/webkitpy/layout_tests/test_types/text_diff.py: Added.
+
+2010-01-29 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Siedel.
+
+ Check in the first part of the Chromium Python port of the
+ run-webkit-tests test driver. The files under
+ layout_tests/layout_layout constitute most of the implementation;
+ they can be roughly divided into code that parses the
+ "test_expectations.txt" file that describes how we expect tests to
+ pass or fail, platform-specific hooks for the different Chromium
+ ports (in platform_utils*), code for parsing the output of the
+ tests and generating results files and HTML and JSON for the
+ dashboards, auxiliary scripts for starting and stopping HTTP and
+ Web Socket servers, and then one of the actual driver files
+ (test_shell_thread). Code for actually parsing test output for
+ failures and the top-level driver scripts will follow shortly.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31498
+
+ * Scripts/webkitpy/layout_tests: Added.
+ * Scripts/webkitpy/layout_tests/layout_package: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/__init__.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/apache_http_server.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/http_server.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/http_server_base.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/httpd2.pem: Added.
+ - scripts to start and stop apache. Note that the apache file
+ generates a conf file dynamically, and we should switch to
+ using the same static conf file that the regular run-webkit-tests
+ uses, and we can also use the same httpd2.pem file.
+
+ * Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py: Added.
+ - scripts to generate the JSON layout test dashboard and the
+ flakiness dashboard
+ * Scripts/webkitpy/layout_tests/layout_package/lighttpd.conf: Added.
+ - default configuration for LigHTTPd (used on Windows)
+ * Scripts/webkitpy/layout_tests/layout_package/metered_stream.py: Added.
+ - utility class that implements progress bars on the console to
+ be displayed while the tests are running
+ * Scripts/webkitpy/layout_tests/layout_package/path_utils.py: Added.
+ - various routines for manipulating paths and URIs
+ * Scripts/webkitpy/layout_tests/layout_package/platform_utils.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/platform_utils_linux.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/platform_utils_mac.py: Added.
+ * Scripts/webkitpy/layout_tests/layout_package/platform_utils_win.py: Added.
+ - platform-specific aspects of the drivers (binary names, paths,
+ process control, etc.)
+ * Scripts/webkitpy/layout_tests/layout_package/test_expectations.py: Added.
+ - code for parsing the 'test_expectations.txt' file to determine
+ which tests are expected to fail (and how) on which platforms
+ * Scripts/webkitpy/layout_tests/layout_package/test_failures.py: Added.
+ - code for handling different kinds of failures (generating output
+ in the results, etc.)
+ * Scripts/webkitpy/layout_tests/layout_package/test_files.py: Added.
+ - code to gather the lists of tests
+ * Scripts/webkitpy/layout_tests/layout_package/test_shell_thread.py: Added.
+ - code to actually execute tests via TestShell and process
+ the output
+ * Scripts/webkitpy/layout_tests/layout_package/websocket_server.py: Added.
+ - scripts to start and stop the pywebsocket server
+
+2010-01-29 Dirk Pranke <dpranke@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Check in a copy of the simplejson library; it will be used by
+ the Chromium port of run-webkit-tests.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31498
+
+ * simplejson: Added.
+ * simplejson/LICENSE.txt: Added.
+ * simplejson/README.txt: Added.
+ * simplejson/__init__.py: Added.
+ * simplejson/_speedups.c: Added.
+ (ascii_escape_char):
+ (ascii_escape_unicode):
+ (ascii_escape_str):
+ (py_encode_basestring_ascii):
+ (init_speedups):
+ * simplejson/decoder.py: Added.
+ * simplejson/encoder.py: Added.
+ * simplejson/jsonfilter.py: Added.
+ * simplejson/scanner.py: Added.
+
+2010-01-29 Dirk Pranke <dpranke@chromium.org>
+
+ No review
+
+ Add myself to the committers list
+
+ * Scripts/webkitpy/committers.py:
+
+2010-01-29 Jeremy Orlow <jorlow@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ A first step towards the Indexed Database API
+ https://bugs.webkit.org/show_bug.cgi?id=34342
+
+ Add indexed database API.
+
+ * Scripts/build-webkit:
+
+2010-01-29 Andras Becsi <abecsi@webkit.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Correct openHTTPD() to print requests to stdout if run-webkit-httpd is used.
+ This fixes a regression introduced in r53559.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34336
+
+ * Scripts/webkitperl/httpd.pm:
+
+2010-01-28 Jon Honeycutt <jhoneycutt@apple.com>
+
+ MSAA: Crash when posting a notification for a detached object
+
+ https://bugs.webkit.org/show_bug.cgi?id=34309
+ <rdar://problem/7409759>
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/AccessibilityController.h:
+ Declare new functions. Add new members to store the event hook and the
+ mapping of accessibility elements to their JS callbacks.
+
+ * DumpRenderTree/gtk/AccessibilityControllerGtk.cpp:
+ (AccessibilityController::notificationReceived):
+ Stubbed.
+ (AccessibilityController::addNotificationListener):
+ Stubbed.
+
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::notificationReceived):
+ Stubbed.
+ (AccessibilityController::addNotificationListener):
+ Stubbed.
+
+ * DumpRenderTree/win/AccessibilityControllerWin.cpp:
+ (AccessibilityController::AccessibilityController):
+ Initialize the event hook.
+ (AccessibilityController::~AccessibilityController):
+ Remove the event hook. Unprotect all of the JS functions that are stored
+ in the map.
+ (logEventProc):
+ Clean-up a variable.
+ (stringEvent):
+ Return a string description of the MSAA event code.
+ (notificationListenerProc):
+ Get the accessible object from the event, and query it for IAccessible.
+ Call the AccessibilityController's notificationReceived().
+ (comparableObject):
+ Use QueryService to obtain the IAccessibleComparable for the
+ IServiceProvider.
+ (AccessibilityController::notificationReceived):
+ Iterate the map of objects that have registered for notification
+ callbacks. Query each for IServiceProvider, then use comparableObject()
+ to get an IAccessibleComparable. If we find an object matching the
+ notified object, call its callback, passing the event that was received.
+ (AccessibilityController::addNotificationListener):
+ If we have not created the event hook, create it. Protect the JS
+ callback function object, and add the object and its callback to our
+ map.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::addNotificationListener):
+ Call through to the AccessibilityController's addNotificationListener().
+
+ * DumpRenderTree/win/DumpRenderTreeWin.h:
+ Add an extern declaration for the shared FrameLoadDelegate extern, so we
+ can access it from AccessibilityController.
+
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+ (FrameLoadDelegate::accessibilityController):
+ Return the AccessibilityController.
+
+2010-01-29 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ prepare-ChangeLog outputs useless messages for a nonexistent bug ID
+ https://bugs.webkit.org/show_bug.cgi?id=34313
+
+ * Scripts/prepare-ChangeLog:
+
+2010-01-29 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Simon Hausmann.
+
+ [Qt] Separate implementation from class definition.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::webView):
+ (LauncherWindow::LauncherWindow):
+ (LauncherWindow::~LauncherWindow):
+ (LauncherWindow::keyPressEvent):
+ (LauncherWindow::grabZoomKeys):
+ (LauncherWindow::sendTouchEvent):
+ (LauncherWindow::eventFilter):
+ (LauncherWindow::loadStarted):
+ (LauncherWindow::loadFinished):
+ (LauncherWindow::showLinkHover):
+ (LauncherWindow::zoomIn):
+ (LauncherWindow::zoomOut):
+ (LauncherWindow::resetZoom):
+ (LauncherWindow::toggleZoomTextOnly):
+ (LauncherWindow::print):
+ (LauncherWindow::screenshot):
+ (LauncherWindow::setEditable):
+ (LauncherWindow::dumpHtml):
+ (LauncherWindow::selectElements):
+ (LauncherWindow::setTouchMocking):
+ (LauncherWindow::newWindow):
+ (LauncherWindow::setupUI):
+
+2010-01-29 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] On Maemo5, a click/touch in the location bar (when unfocused)
+ should result in all text selected.
+
+ * QtLauncher/locationedit.cpp:
+ (LocationEdit::focusInEvent):
+ * QtLauncher/locationedit.h:
+
+2010-01-29 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] Show progress reaching 100% for loads.
+
+ * QtLauncher/locationedit.cpp:
+ (LocationEdit::LocationEdit):
+ (LocationEdit::setProgress):
+ (LocationEdit::reset):
+ (LocationEdit::paintEvent):
+ * QtLauncher/locationedit.h:
+
+2010-01-29 Andreas Kling <andreas.kling@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Disable the QtLauncher statusbar on Maemo
+
+ https://bugs.webkit.org/show_bug.cgi?id=34330
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::showLinkHover):
+ (LauncherWindow::selectElements):
+
+2010-01-29 Andreas Kling <andreas.kling@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Display page loading progress inside the QtLauncher location bar
+
+ https://bugs.webkit.org/show_bug.cgi?id=34210
+
+ * QtLauncher/QtLauncher.pro:
+ * QtLauncher/locationedit.cpp: Added.
+ (LocationEdit::LocationEdit):
+ (LocationEdit::setProgress):
+ (LocationEdit::paintEvent):
+ * QtLauncher/locationedit.h: Added.
+ * QtLauncher/mainwindow.cpp:
+ (MainWindow::buildUI):
+ * QtLauncher/mainwindow.h:
+
+2010-01-29 Andreas Kling <andreas.kling@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Add support for Maemo zoom keys in QtLauncher
+
+ https://bugs.webkit.org/show_bug.cgi?id=34160
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ (LauncherWindow::~LauncherWindow):
+ (LauncherWindow::keyPressEvent):
+ (LauncherWindow::grabZoomKeys):
+
+2010-01-29 Benjamin Poulain <benjamin.poulain@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Implement the display() method of the layout test controller
+ https://bugs.webkit.org/show_bug.cgi?id=34258
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::showPage):
+ (WebCore::DumpRenderTree::hidePage):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::display):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-01-28 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix for MSW, use ThreadingWin.cpp as the Windows pthreads implementation
+ implements pthread_t in a way that makes it impossible to check its validity,
+ which is needed by ThreadingPthreads.cpp.
+
+ * DumpRenderTree/wscript:
+ * wx/build/settings.py:
+
+2010-01-28 Andras Becsi <abecsi@webkit.org>
+
+ Adding myself to the committer list. No review needed.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-01-28 Hayato Ito <hayato@chromium.org>
+
+ Reviewed by David Levin.
+
+ Remove NULL char from input JS file because 'grep' fails if the file contains NULL char.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34252
+
+ * Scripts/make-script-test-wrappers:
+
+2010-01-28 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after removal of the zlib image decoder.
+
+ * wx/build/settings.py:
+
+2010-01-28 Csaba Osztrogonác <ossy@webkit.org>
+
+ [Qt] Unreviewed, roll out r54000.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::display):
+
+2010-01-28 Benjamin Poulain <benjamin.poulain@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Implement the display() method of the layout test controller
+ https://bugs.webkit.org/show_bug.cgi?id=34258
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::showPage):
+ (WebCore::DumpRenderTree::hidePage):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::display):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-01-28 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Eliminated the filename parameter from functions in
+ check-webkit-style's cpp.py where it is no longer used.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34249
+
+ * Scripts/webkitpy/style/processors/cpp.py:
+ - Reduced number of occurrences of "filename" variable from
+ approximately 200 to 120.
+
+ * Scripts/webkitpy/style/processors/cpp_unittest.py:
+ - Refactored unit tests as necessary to accommodate changes to cpp.py.
+ - Fixed bug in CppStyleTestBase.perform_include_what_you_use()
+ where the incorrect file extension was getting passed to
+ cpp_style.check_language().
+
+2010-01-28 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ In check-webkit-style, eliminated the dependency of
+ processors/cpp_unittest.py on checker.py.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34205
+
+ * Scripts/webkitpy/style/checker.py:
+ - Addressed FIXME by removing STYLE_CATEGORIES data.
+ - Added style_categories().
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Minor changes.
+
+ * Scripts/webkitpy/style/processors/cpp.py:
+ - Added categories attribute to CppProcessor class (data
+ was originally checker.STYLE_CATEGORIES).
+
+ * Scripts/webkitpy/style/processors/cpp_unittest.py:
+ - Addressed FIXME by eliminating "import" from checker.py.
+
+2010-01-28 Anton Muhin <antonm@chromium.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Improve treatment of conditions and rest of the line for if, else, switch and alikes
+ https://bugs.webkit.org/show_bug.cgi?id=34173
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+
+2010-01-28 Joe Mason <jmason@rim.com>
+
+ Reviewed by Adam Barth.
+
+ Limit login retries to 5
+ https://bugs.webkit.org/show_bug.cgi?id=34193
+
+ * Scripts/webkitpy/bugzilla.py:
+
+2010-01-27 Martin Robinson <mrobinson@webkit.org>
+
+ Adding myself to the committer list. No review necessary.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-01-27 George Wright <gwright@rim.com>
+
+ Reviewed by Adam Treat.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34216
+
+ Add missing include for wtf/Platform.h
+
+ * DumpRenderTree/AccessibilityController.h:
+
+2010-01-27 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] DRT Provide worker thread ability to track counters
+ https://bugs.webkit.org/show_bug.cgi?id=34221
+
+ Implement workerThreadCount() in LayoutTestController of Qt DRT
+
+ Tests:
+ fast/workers/dedicated-worker-lifecycle.html
+ fast/workers/shared-worker-frame-lifecycle.html
+ fast/workers/shared-worker-lifecycle.html
+ fast/workers/worker-lifecycle.html
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::workerThreadCount):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-01-27 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Simon Hausmann.
+
+ [Qt] QtLauncher refactoring:
+
+ Make the LauncherWindow depend less on the view, so that more
+ code can be shared in near future.
+
+ * QtLauncher/main.cpp:
+ (LauncherWindow::sendTouchEvent):
+ (LauncherWindow::loadFinished):
+ (LauncherWindow::zoomIn):
+ (LauncherWindow::zoomOut):
+ (LauncherWindow::resetZoom):
+ (LauncherWindow::toggleZoomTextOnly):
+ (LauncherWindow::dumpHtml):
+ (LauncherWindow::selectElements):
+ (LauncherWindow::setupUI):
+
+2010-01-27 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Correctly handle the KeyLocation argument that has been introduced
+ recently to test location-dependent key events in EventSender.keyDown.
+ http://bugs.webkit.org/show_bug.cgi?id=28247
+
+ Test: fast/events/keydown-numpad-keys.html
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (keyDownCallback):
+
+2010-01-27 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Simon Hausmann.
+
+ [Qt] QtLauncher refactoring:
+
+ Move out code from the MainWindow (renamed to LauncherWindow)
+ that is not depending on the view, and add it to a new class
+ called MainWindow.
+
+ * QtLauncher/QtLauncher.pro:
+ * QtLauncher/main.cpp:
+ (LauncherWindow::LauncherWindow):
+ (LauncherWindow::eventFilter):
+ (LauncherWindow::loadStarted):
+ (LauncherWindow::loadFinished):
+ (LauncherWindow::newWindow):
+ (LauncherWindow::setupUI):
+ (WebPage::createWindow):
+ (main):
+ * QtLauncher/mainwindow.cpp: Added.
+ (MainWindow::MainWindow):
+ (MainWindow::buildUI):
+ (MainWindow::page):
+ (MainWindow::setAddressUrl):
+ (MainWindow::addCompleterEntry):
+ (MainWindow::load):
+ (MainWindow::changeLocation):
+ (MainWindow::openFile):
+ * QtLauncher/mainwindow.h: Added.
+
+2010-01-27 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Simon Hausmann.
+
+ [Qt] QtLauncher, coding style fixes.
+
+ * QtLauncher/main.cpp:
+ (MainWindow::MainWindow):
+ (MainWindow::sendTouchEvent):
+ (MainWindow::eventFilter):
+ (MainWindow::loadURL):
+ (MainWindow::setupUI):
+ (WebPage::createPlugin):
+
+2010-01-27 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Simon Hausmann.
+
+ [Qt] QtLauncher refactoring, separating the webview and
+ adding a QGraphicsWebView based version.
+
+ * QtLauncher/QtLauncher.pro:
+ * QtLauncher/main.cpp:
+ (MainWindow::MainWindow):
+ * QtLauncher/webpage.h:
+ * QtLauncher/webview.cpp: Added.
+ (createContextMenu):
+ (WebViewGraphicsBased::mousePressEvent):
+ (WebViewTraditional::mousePressEvent):
+ (WebViewGraphicsBased::contextMenuEvent):
+ (WebViewTraditional::contextMenuEvent):
+ * QtLauncher/webview.h: Added.
+ (WebViewGraphicsBased::WebViewGraphicsBased):
+ (WebViewTraditional::WebViewTraditional):
+
+2010-01-27 Alexander Pavlov <apavlov@chromium.org>
+
+ Adding myself as committer. No review necessary.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-01-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ webkit-patch needs an open-bugs command
+ https://bugs.webkit.org/show_bug.cgi?id=30793
+
+ * Scripts/test-webkitpy: import OpenBugsTest
+ * Scripts/webkit-patch: import OpenBugs
+ * Scripts/webkitpy/commands/download_unittest.py: don't import unittest
+ * Scripts/webkitpy/commands/early_warning_system_unittest.py: ditto
+ * Scripts/webkitpy/commands/queries_unittest.py: ditto
+ * Scripts/webkitpy/commands/queues_unittest.py: ditto
+ * Scripts/webkitpy/commands/upload_unittest.py: ditto
+ * Scripts/webkitpy/mock_bugzillatool.py: log when user.open_url is called.
+
+2010-01-27 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Simon Hausmann
+
+ [Qt] QtLauncher refactoring, separating utility methods.
+
+ * QtLauncher/QtLauncher.pro:
+ * QtLauncher/main.cpp:
+ * QtLauncher/utils.cpp: Added.
+ (urlFromUserInput):
+ * QtLauncher/utils.h: Added.
+
+2010-01-27 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Simon Hausmann
+
+ [Qt] Refactor the code in the QtLauncher dealing with HTTP proxy.
+
+ * QtLauncher/main.cpp:
+ (MainWindow::MainWindow):
+ * QtLauncher/webpage.cpp:
+ (WebPage::WebPage):
+ (WebPage::applyProxy):
+ * QtLauncher/webpage.h:
+
+2010-01-26 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [Qt] Corrects debug build of DumpRenderTree on Windows.
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+
+2010-01-26 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34070
+
+ Moves the try/catch for OSError exceptions in Executive.run_command
+ to Credentials.read_credentials() so that the unit test
+ webkitpy.scm_unittest.SCMClassTests.test_error_handlers can
+ assert that Executive.run_command throws an OSError exception.
+
+ * Scripts/webkitpy/credentials.py:
+ * Scripts/webkitpy/executive.py: Moved try/catch for OSError to
+ method Credentials.read_credentials().
+ * Scripts/webkitpy/executive_unittest.py: Removed tests that no longer
+ apply: test_run_command_with_bad_command_check_return_code and
+ test_run_command_with_bad_command_check_calls_error_handler. Added new
+ test to assert that run_command throws OSError exceptions.
+
+2010-01-26 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] DRT WebHistory support
+ https://bugs.webkit.org/show_bug.cgi?id=34167
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::webHistoryItemCount):
+ (LayoutTestController::keepWebHistory):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-01-26 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [Win] Add modifiers parameter support to Windows DumpRenderTree
+ https://bugs.webkit.org/show_bug.cgi?id=34068
+
+ Add support for functional name modifiers; "addSelectionKey" and
+ "rangeSelectionKey", and modifiers parameter to eventSender.mouseDown()
+ and eventSender.mouseUp().
+ This change is similar to r53498 for Mac.
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (buildModifierFlags): New function to set MK_CONTROL or MK_SHIFT to WPARAM.
+ (mouseDownCallback): Call buidlModifiersFlags().
+ (mouseUpCallback): ditto.
+ (keyDownCallback): Add support for "addSelectionkey" and "rangeSelectionKey".
+
+2010-01-26 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ The Python autoinstall cache directory now only gets created
+ in the directory containing autoinstall.py.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33365
+
+ * Scripts/webkitpy/autoinstall.py:
+ - Also added a README file to the cache directory saying
+ where it came from.
+
+2010-01-26 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Moved the check-webkit-style processors into a new
+ webkitpy/style/processors directory.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34060
+
+ * Scripts/webkitpy/style/checker.py:
+ * Scripts/webkitpy/style/checker_unittest.py:
+ * Scripts/webkitpy/style/cpp_style.py: Removed.
+ * Scripts/webkitpy/style/cpp_style_unittest.py: Removed.
+ * Scripts/webkitpy/style/processors: Added.
+ * Scripts/webkitpy/style/processors/__init__.py: Added.
+ * Scripts/webkitpy/style/processors/cpp.py: Copied from WebKitTools/Scripts/webkitpy/style/cpp_style.py.
+ * Scripts/webkitpy/style/processors/cpp_unittest.py: Copied from WebKitTools/Scripts/webkitpy/style/cpp_style_unittest.py.
+ * Scripts/webkitpy/style/processors/text.py: Copied from WebKitTools/Scripts/webkitpy/style/text_style.py.
+ * Scripts/webkitpy/style/processors/text_unittest.py: Copied from WebKitTools/Scripts/webkitpy/style/text_style_unittest.py.
+ * Scripts/webkitpy/style/text_style.py: Removed.
+ * Scripts/webkitpy/style/text_style_unittest.py: Removed.
+ * Scripts/webkitpy/style/unittests.py:
+
+2010-01-26 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix, make sure stub function returns a value.
+
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::counterValueForElementById):
+
+2010-01-26 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Windows build references non-existent include paths
+ https://bugs.webkit.org/show_bug.cgi?id=34175
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+
+2010-01-26 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt] Separating out the UrlLoader from the QtLauncher in it's
+ own implementation and header file.
+
+ * QtLauncher/main.cpp:
+ (main):
+ * QtLauncher/urlloader.cpp: Added.
+ (UrlLoader::UrlLoader):
+ (UrlLoader::loadNext):
+ (UrlLoader::init):
+ (UrlLoader::getUrl):
+ * QtLauncher/urlloader.h: Added.
+
+2010-01-25 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Refactored check-webkit-style by removing the file path
+ parameter from the style error handler functions.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34031
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added _default_style_error_handler() to StyleChecker class.
+ - Moved handle_style_error() to inside _default_style_error_handler().
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Removed file path from calls to error handler.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ - Removed file path from calls to error handler.
+
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+ - Removed file path from calls to error handler.
+
+ * Scripts/webkitpy/style/text_style.py:
+ - Removed file path from calls to error handler.
+
+ * Scripts/webkitpy/style/text_style_unittest.py:
+ - Removed file path from calls to error handler.
+
+2010-01-25 Jeremy Orlow <jorlow@chromium.org>
+
+ Adding myself as reviewer. No review necessary.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-01-25 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Improved prepare-ChangeLog so that it preserves the relative
+ indentation of a git commit message.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34058
+
+ * Scripts/prepare-ChangeLog:
+ - Also adjusted the script so that it does not add white
+ space characters to empty lines.
+
+2010-01-24 Eric Seidel <eric@webkit.org>
+
+ No review, rolling out r53763.
+ http://trac.webkit.org/changeset/53763
+ https://bugs.webkit.org/show_bug.cgi?id=33895
+
+ Broke 20+ tests on Windows.
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2010-01-24 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by Eric Seidel.
+
+ More pep8 compliance.
+
+ * Scripts/webkitpy/mock_bugzillatool.py:
+
+2010-01-24 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by Eric Seidel.
+
+ More pep8 compliance.
+
+ * Scripts/webkitpy/executive.py:
+ * Scripts/webkitpy/grammar.py:
+
+2010-01-24 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by Eric Seidel.
+
+ More pep8 compliance.
+
+ * Scripts/webkitpy/comments.py:
+ * Scripts/webkitpy/committers.py:
+ * Scripts/webkitpy/credentials.py:
+
+2010-01-24 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by Eric Seidel.
+
+ Make changelogs.py pass pep8.
+
+ * Scripts/webkitpy/changelogs.py:
+
+2010-01-23 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ [Qt] Unreviewed build fix
+
+ * QtLauncher/QtLauncher.pro:
+ * QtLauncher/webinspector.h:
+
+2010-01-23 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Simon Hausmann.
+
+ [Qt] Move the WebInspector class to it's own header file.
+
+ * QtLauncher/main.cpp:
+ * QtLauncher/webinspector.h: Added.
+ (WebInspector::WebInspector):
+ (WebInspector::showEvent):
+ (WebInspector::hideEvent):
+
+2010-01-23 Robert Hogan <robert@roberthogan.net>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Qt DRT: respect window.close() and window.closed()
+
+ Qt DRT needs to maintain a correct count of open windows
+ for windowCount(). It also needs to delete windows that
+ have been closed by window.close().
+
+ This fixes the following tests:
+
+ plugins/destroy-during-npp-new.html
+ fast/dom/Document/early-document-access.html
+ fast/dom/Window/window-early-properties.html
+ fast/events/open-window-from-another-frame.html
+ fast/events/popup-blocking-click-in-iframe.html
+
+ https://bugs.webkit.org/show_bug.cgi?id=32953
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::createWindow):
+ (WebCore::DumpRenderTree::windowCloseRequested):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::maybeDump):
+
+2010-01-23 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Added a user default for specifying a fallback frameworks path in case
+ the bundle does not contain frameworks for the current Mac OS X version.
+
+ * WebKitLauncher/main.m:
+ (fallbackMacOSXVersion): Added. Looks up the fallback version in a dictionary
+ keyed by the FallbackSystemVersions user default and returns it.
+ (main): If a frameworks directory for the current system version is not found,
+ try the fallback.
+
+2010-01-22 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Make run-webkit-tests work under Cygwin for the Qt port
+
+ setPathForRunningWebKitApp() is implemented for the Qt port
+ by using qmake to query for the location of the Qt libraries.
+
+ This requires the original environment (%ENV) to be untouched,
+ so launchWithCurrentEnv() was refactored to launchWithEnv(),
+ and the code in openDumpTool() to not use %ENV but a %CLEAN_ENV
+ instead. This has the added benefit of getting rid of the temp
+ variables used for storing the current env.
+
+ openDumpTool() is also refactored a bit into platform-spesific,
+ port-spesific, and generic environment variables.
+
+ Checks for undef was added a few places to fix Perl concat
+ warnings when run-webkit-tests is aborted.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33895
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2010-01-22 Kevin Watters <kevinwatters@gmail.com>
+
+ Reviewed by Kevin Ollivier.
+
+ [wx] Remove the Bakefile build system, which is no longer being used.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34022
+
+ * DumpRenderTree/wx/DumpRenderTree.bkl: Removed.
+ * wx/browser/browser.bkl: Removed.
+ * wx/build-wxwebkit: Removed.
+
+2010-01-22 Gustavo Noronha Silva <gns@gnome.org>
+
+ Reviewed by Simon Fraser.
+
+ Reset zoom level to 1.0 when resetting view state. This is causing
+ many tests to fail after svg/custom/text-zoom.xhtml changes the
+ zoom level.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2010-01-22 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=34025
+ Enable client-based Geolocation abstraction for Mac, Windows AppleWebKit targets.
+
+ * Scripts/build-webkit:
+
+2010-01-22 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Arg. Someone renamed limit to output_limit on me.
+
+ * Scripts/webkitpy/commands/queues.py:
+
+2010-01-22 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by Eric Seidel.
+
+ Make __init__.py and buildbot.py pass pep8 style checker.
+
+ * Scripts/webkitpy/__init__.py:
+ * Scripts/webkitpy/buildbot.py:
+
+2010-01-21 Joe Mason <jmason@rim.com>
+
+ Reviewed by Adam Barth.
+
+ webkit-patch should retry on invalid password
+ https://bugs.webkit.org/show_bug.cgi?id=33955
+
+ Ask for bugs.webkit.org authentication in a loop.
+
+ * Scripts/webkitpy/bugzilla.py:
+
+2010-01-22 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Don't call seek on a NoneType.
+
+ * Scripts/webkitpy/statusserver.py:
+
+2010-01-22 Petri Latvala <petri.latvala@nomovok.com>
+
+ Reviewed by David Levin.
+
+ check-webkit-style breaks on files with unknown types
+ https://bugs.webkit.org/show_bug.cgi?id=34001
+
+ For files with type FileType.NONE, dispatch_processor returns None.
+
+ * Scripts/webkitpy/style/checker.py: Don't call process_file with a processor of value None.
+
+2010-01-22 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Make bugzilla.py and webkitport.py conform to pep8
+ https://bugs.webkit.org/show_bug.cgi?id=34015
+
+ This patch makes webkitport.py and bugzilla.py mostly conform to PEP8
+ style as enforced by pep8.py. I wasn't able to get rid of all the
+ errors because I'm not sure how to wrap some lines properly. Also,
+ there are a few deprication errors that I couldn't resolve easily.
+ However, this is a massive improvement in compliance.
+
+ * Scripts/webkitpy/bugzilla.py:
+ * Scripts/webkitpy/webkitport.py:
+
+2010-01-22 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Limit length of EWS results to 5MB
+ https://bugs.webkit.org/show_bug.cgi?id=34016
+
+ Hopefully this will fix the bug where the results link doesn't appear.
+ Our current theory is that the results blob is too big and the server
+ is rejecting the request with a 500 error. That causes us to re-try
+ the post, but when we re-try the StringIO buffer has its seek pointer
+ at the end.
+
+ * Scripts/webkitpy/commands/queues.py:
+ * Scripts/webkitpy/statusserver.py:
+
+2010-01-22 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Made check-webkit-style able to check patches when script not
+ run from source root. Also consolidated external references
+ to a single file.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33791
+
+ * Scripts/check-webkit-style:
+ - Changed to import style_references.py.
+
+ * Scripts/webkitpy/style/__init__.py:
+ - Removed __path__ hack that allowed searching Scripts/ directory.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Changed to import style_references.py.
+
+ * Scripts/webkitpy/style_references.py: Added.
+
+2010-01-22 Dmitry Titov <dimich@chromium.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Fix the leak of ThreadIdentifiers in threadMap across threads.
+ https://bugs.webkit.org/show_bug.cgi?id=32689
+
+ Add a new test to verify the ThreadIdentifiers are not reused across threads.
+ The test runs in the beginning of DumpRenderTree and spawns 2 non-WTF treads sequentially,
+ waiting for the previous thread to terminate before starting the next.
+ The treads use WTF::currentThread() in their thread function. Without a fix, this
+ causes both threads to have the same ThreadIdentifier which triggers ASSERT in thread function.
+ It also starts another thread using WTF. Without the fix, this finds pthread handle from previous
+ threads in the WTF threadMap and asserts in WTF::establishIdentifierForPthreadHandle().
+ The test practically does not affect the DRT run time because the threads end immediately.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (runThread): Test thread function.
+ (testThreadIdentifierMap):
+ (dumpRenderTree):
+
+2010-01-22 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Fix a bug that mouseDown:withModifiers: is never called.
+ https://bugs.webkit.org/show_bug.cgi?id=33989
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (+[EventSendingController webScriptNameForSelector:]):
+
+2010-01-22 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Antti Koivisto.
+
+ [Qt] Separate out the WebPage class into it's own
+ cpp/header files. Also, removed the assumption that
+ the view is a QWebView, in preparation of a merger
+ of the two Qt WebKit launchers.
+
+ * QtLauncher/QtLauncher.pro:
+ * QtLauncher/main.cpp:
+ (WebView::mousePressEvent):
+ * QtLauncher/webpage.cpp: Added.
+ (WebPage::supportsExtension):
+ (WebPage::extension):
+ (WebPage::acceptNavigationRequest):
+ (WebPage::openUrlInDefaultBrowser):
+ * QtLauncher/webpage.h: Added.
+ (WebPage::WebPage):
+
+2010-01-21 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Refactored to move file name and file-reading related code
+ from cpp_style.py and text_style.py to checker.py.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33775
+
+ * Scripts/check-webkit-style:
+ - Updates caused by changes to checker.py.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added SKIPPED_FILES_WITH_WARNING list.
+ - Added SKIPPED_FILES_WITHOUT_WARNING list.
+ - Added FileType class.
+ - Added ProcessorDispatcher class.
+ - In StyleChecker class:
+ - Renamed process_patch() to check_patch().
+ - Renamed process_file() to check_file().
+ - Added _process_file().
+ - Related refactoring.
+ - Addressed check_patch() FIXME to share code with process_file().
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Added ProcessorDispatcherSkipTest class.
+ - Added ProcessorDispatcherDispatchTest class.
+ - Added StyleCheckerCheckFileTest class.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ - Renamed process_file_data() to _process_lines.
+ - Removed process_file() (moved logic to checker.py).
+ - Removed can_handle() (moved logic to checker.py).
+ - Added CppProcessor class.
+ - Removed is_exempt() (moved logic to checker.py).
+ - Added process_file_data() back as a wrapper function.
+
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+ - Removed test_can_handle().
+ - Removed test_is_exempt().
+ - Added CppProcessorTest class.
+
+ * Scripts/webkitpy/style/text_style.py:
+ - Added TextProcessor class.
+ - Removed process_file().
+ - Removed can_handle().
+
+ * Scripts/webkitpy/style/text_style_unittest.py:
+ - Removed test_can_handle().
+ - Added TextProcessorTest class.
+
+2010-01-21 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ Create a unit-tested subroutine to parse patch files created
+ by svn-create-patch.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33475
+
+ * Scripts/VCSUtils.pm:
+ - Added parseDiff().
+ - Added parsePatch().
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl: Added.
+ - Added unit tests for parseDiff().
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl:
+ - Total number of tests now computed dynamically.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parsePatch.pl: Added.
+ - Added unit tests for parsePatch().
+
+2010-01-21 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix, add new directory to dir list.
+
+ * wx/build/settings.py:
+
+2010-01-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Make the EWS transactional
+ https://bugs.webkit.org/show_bug.cgi?id=33978
+
+ Now if the EWS gets interrupted in the middle of processing a patch,
+ the bots will re-process the patch.
+
+ * Scripts/test-webkitpy:
+ * Scripts/webkitpy/commands/queues.py:
+ * Scripts/webkitpy/commands/queues_unittest.py:
+ * Scripts/webkitpy/patchcollection.py:
+ * Scripts/webkitpy/patchcollection_unittest.py: Added.
+
+2010-01-21 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Add missing "ago" for style in the status bubble.
+
+ * QueueStatusServer/templates/statusbubble.html:
+
+2010-01-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by David Levin.
+
+ [style-queue] should not complain about identifier names with underscores under WebKit/gtk/webkit/
+ https://bugs.webkit.org/show_bug.cgi?id=33356
+
+ White list unix_hacker_style names in WebKit/gtk/webkit because these
+ are used in the GTK+ API.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+
+2010-01-21 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] add setDomainRelaxationForbiddenForURLScheme in Qt DRT
+ https://bugs.webkit.org/show_bug.cgi?id=33945
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setDomainRelaxationForbiddenForURLScheme):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-01-21 Simon Hausmann <simon.hausmann@nokia.com>
+
+ No review, rolling out 53615 as it causes two
+ crashes on the bot.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::createWindow):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::maybeDump):
+
+2010-01-21 Robert Hogan <robert@roberthogan.net>
+
+ Reviewed by Simon Hausmann.
+
+ Qt DRT: respect window.close() and window.closed()
+
+ Qt DRT needs to maintain a correct count of open windows
+ for windowCount(). It also needs to delete windows that
+ have been closed by window.close().
+
+ This fixes the following tests:
+
+ plugins/destroy-during-npp-new.html
+ fast/dom/Document/early-document-access.html
+ fast/dom/Window/window-early-properties.html
+ fast/events/open-window-from-another-frame.html
+ fast/events/popup-blocking-click-in-iframe.html
+
+ https://bugs.webkit.org/show_bug.cgi?id=32953
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::createWindow):
+ (WebCore::DumpRenderTree::windowCloseRequested):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::maybeDump):
+
+2010-01-20 Eric Seidel <eric@webkit.org>
+
+ No review, rolling out r53593.
+ http://trac.webkit.org/changeset/53593
+ https://bugs.webkit.org/show_bug.cgi?id=33496
+
+ Re-rollout this patch, the commit-queue should not have landed
+ it again, but it did due to land-diff and rollout both not
+ clearing flags.
+
+ * Scripts/webkitpy/commands/early_warning_system.py:
+ * Scripts/webkitpy/commands/queues.py:
+ * Scripts/webkitpy/queueengine.py:
+ * Scripts/webkitpy/scm.py:
+ * Scripts/webkitpy/scm_unittest.py:
+
+2010-01-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-commit-queue status page is confusing
+ https://bugs.webkit.org/show_bug.cgi?id=33496
+
+ This should improve the status page by removing more Fail messages.
+ To do this, I re-factored the CommitQueue and the AbstractReviewQueues
+ to behave more like one another. This meant moving where the failure reporting was done.
+ Previously the AbstractReviewQueue always used the parent process to report the error,
+ while CommitQueue used the subprocess when possible, and the parent only reported errors
+ that we didn't know how to handle (bugs in the commit-queue itself).
+ Now the AbstractReviewQueue follow's the commit-queue's model. This got rid of a try-block
+ in both implementations and required teaching handle_script_error in each to post Fail messages
+ to the status server instead of calling exit(1).
+
+ This will also make the style-queue share more bug posting logic with other queues:
+ https://bugs.webkit.org/show_bug.cgi?id=33871
+
+ * Scripts/webkitpy/commands/early_warning_system.py:
+ - Don't exit(1) as that will cause the calling queue to also report Fail to the status server.
+ Implementors of handle_script_error are expected to update the status server if needed, but only exit if the error could not be handled.
+ So we instead pass patch_has_failed_this_queue=True to _update_status_for_script_error in the case that this was a real failure.
+ _update_status_for_script_error knows how to post the Fail message to the status server.
+ - Teach _update_status_for_script_error how to post Fail messages to the status server.
+ * Scripts/webkitpy/commands/queues.py:
+ - Remove the try block from process_work_item since the caller already has one.
+ - Only CC watchers on failure to cut down on commit-queue generated mail.
+ - handle_unexpected_error needs to mark _did_fail now that the try block is gone from process_work_item.
+ - Abstract _format_script_error_output_for_bug to share code between all queues.
+ - The new _format_script_error_output_for_bug allows the style-queue to share the posting limit with other queues, as well as support linking to the full output.
+ - Rename _can_build_and_test to _current_checkout_builds_and_passes_tests to better explain what revision it's testing.
+ - Move logging out of _can_build_and_test and make the logs explain what revision we're testing.
+ - handle_script_error now posts Fail instead of the try block in process_work_item handling it.
+ * Scripts/webkitpy/queueengine.py:
+ - QueueEngine is no longer used just by the commit-queue, update the logging to say "processing" instead of landing.
+ * Scripts/webkitpy/scm.py:
+ - Add new checkout_revision function.
+ * Scripts/webkitpy/scm_unittest.py:
+ - Test our new checkout_revision function.
+
+2010-01-20 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ WebSocket: Missing Request-URI, when no tralling slash in host
+ https://bugs.webkit.org/show_bug.cgi?id=33689
+
+ Update pywebsocket to 0.4.7.1, which supports alias for resource
+ name, so that we could test for ws://127.0.0.1:8880
+
+ * Scripts/run-webkit-tests:
+ * Scripts/run-webkit-websocketserver:
+ * pywebsocket/mod_pywebsocket/dispatch.py:
+ * pywebsocket/mod_pywebsocket/handshake.py:
+ * pywebsocket/mod_pywebsocket/standalone.py:
+ * pywebsocket/setup.py:
+ * pywebsocket/test/test_dispatch.py:
+ * pywebsocket/test/test_handshake.py:
+
+2010-01-20 Eric Seidel <eric@webkit.org>
+
+ No review, rolling out r53537.
+ http://trac.webkit.org/changeset/53537
+ https://bugs.webkit.org/show_bug.cgi?id=33496
+
+ Added a failure condition to the commit-queue and looks to
+ have broken the EWS bots
+
+ * Scripts/webkitpy/commands/early_warning_system.py:
+ * Scripts/webkitpy/commands/queues.py:
+ * Scripts/webkitpy/queueengine.py:
+ * Scripts/webkitpy/scm.py:
+ * Scripts/webkitpy/scm_unittest.py:
+
+2010-01-20 Jon Honeycutt <jhoneycutt@apple.com>
+
+ MSAA: accSelect() is not implemented
+
+ https://bugs.webkit.org/show_bug.cgi?id=33918
+ <rdar://problem/7436861>
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (takeFocusCallback):
+ Call the object's takeFocus() function.
+ (takeSelectionCallback):
+ Call its takeSelection() function.
+ (addSelectionCallback):
+ Call its addSelection() function.
+ (removeSelectionCallback):
+ Call its removeSelection() function.
+ (AccessibilityUIElement::getJSClass):
+ Add new functions to the JS class definition.
+
+ * DumpRenderTree/AccessibilityUIElement.h:
+ Declare new functions.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::takeFocus):
+ Stubbed.
+ (AccessibilityUIElement::takeSelection):
+ Stubbed.
+ (AccessibilityUIElement::addSelection):
+ Stubbed.
+ (AccessibilityUIElement::removeSelection):
+ Stubbed.
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::takeFocus):
+ Stubbed.
+ (AccessibilityUIElement::takeSelection):
+ Stubbed.
+ (AccessibilityUIElement::addSelection):
+ Stubbed.
+ (AccessibilityUIElement::removeSelection):
+ Stubbed.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::takeFocus):
+ Call the object's accSelect() function, passing the appropriate flag.
+ (AccessibilityUIElement::takeSelection):
+ Ditto.
+ (AccessibilityUIElement::addSelection):
+ Ditto.
+ (AccessibilityUIElement::removeSelection):
+ Ditto.
+
+2010-01-20 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Extract Apache handling to httpd.pm module and use the provided functionality
+ in scripts where Apache is needed.
+ The module httpd.pm stores the PID of Apache in a variable and cleans up
+ the PID directory after Apache properly shut down. Catching INT and TERM
+ signals allows the scripts to close Apache and clean up its PID directory
+ even if the testing was interrupted.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33153
+
+ * Scripts/webkitperl/httpd.pm: Added.
+ * Scripts/run-iexploder-tests:
+ * Scripts/run-webkit-httpd:
+ * Scripts/run-webkit-tests:
+
+2010-01-20 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Make DumpRenderTree build on Windows
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/main.cpp:
+
+2010-01-20 Steve Block <steveblock@google.com>
+
+ Reviewed by Eric Seidel.
+
+ Fix commit bot to land patches in order of the bug last modification date.
+ https://bugs.webkit.org/show_bug.cgi?id=33395
+
+ * Scripts/webkitpy/bugzilla.py: Modified. Added 'order=Last+Changed' to bugzilla commit queue URL.
+
+2010-01-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Teach check-webkit-style about WebKit/gtk/tests
+ https://bugs.webkit.org/show_bug.cgi?id=33892
+
+ Removes false positives found in
+ https://bugs.webkit.org/show_bug.cgi?id=30883
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+
+2010-01-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Teach check-webkit-style about QGVLauncher
+ https://bugs.webkit.org/show_bug.cgi?id=33890
+
+ Remove false positives found in
+ https://bugs.webkit.org/show_bug.cgi?id=33708
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+
+2010-01-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ webkit-commit-queue status page is confusing
+ https://bugs.webkit.org/show_bug.cgi?id=33496
+
+ This should improve the status page by removing more Fail messages.
+ To do this, I re-factored the CommitQueue and the AbstractReviewQueues
+ to behave more like one another. This meant moving where the failure reporting was done.
+ Previously the AbstractReviewQueue always used the parent process to report the error,
+ while CommitQueue used the subprocess when possible, and the parent only reported errors
+ that we didn't know how to handle (bugs in the commit-queue itself).
+ Now the AbstractReviewQueue follow's the commit-queue's model. This got rid of a try-block
+ in both implementations and required teaching handle_script_error in each to post Fail messages
+ to the status server instead of calling exit(1).
+
+ This will also make the style-queue share more bug posting logic with other queues:
+ https://bugs.webkit.org/show_bug.cgi?id=33871
+
+ * Scripts/webkitpy/commands/early_warning_system.py:
+ - Don't exit(1) as that will cause the calling queue to also report Fail to the status server.
+ Implementors of handle_script_error are expected to update the status server if needed, but only exit if the error could not be handled.
+ So we instead pass patch_has_failed_this_queue=True to _update_status_for_script_error in the case that this was a real failure.
+ _update_status_for_script_error knows how to post the Fail message to the status server.
+ - Teach _update_status_for_script_error how to post Fail messages to the status server.
+ * Scripts/webkitpy/commands/queues.py:
+ - Remove the try block from process_work_item since the caller already has one.
+ - Only CC watchers on failure to cut down on commit-queue generated mail.
+ - handle_unexpected_error needs to mark _did_fail now that the try block is gone from process_work_item.
+ - Abstract _format_script_error_output_for_bug to share code between all queues.
+ - The new _format_script_error_output_for_bug allows the style-queue to share the posting limit with other queues, as well as support linking to the full output.
+ - Rename _can_build_and_test to _current_checkout_builds_and_passes_tests to better explain what revision it's testing.
+ - Move logging out of _can_build_and_test and make the logs explain what revision we're testing.
+ - handle_script_error now posts Fail instead of the try block in process_work_item handling it.
+ * Scripts/webkitpy/queueengine.py:
+ - QueueEngine is no longer used just by the commit-queue, update the logging to say "processing" instead of landing.
+ * Scripts/webkitpy/scm.py:
+ - Add new checkout_revision function.
+ * Scripts/webkitpy/scm_unittest.py:
+ - Test our new checkout_revision function.
+
+2010-01-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Exempt JavaScriptCore/qt/api from style checks
+ https://bugs.webkit.org/show_bug.cgi?id=33879
+
+ Apparently there is a JavaScriptCore API for Qt as well as a WebKit
+ API.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+
+2010-01-19 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Don't use QSocketNotifier in the DRT for reading stdin
+
+ QSocketNotifier is not available on Windows. Instead we read
+ stdin synchronously after each test using signals and slots.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/main.cpp:
+
+2010-01-19 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by Eric Seidel.
+
+ Move chromium-ews back to building release only to make the EWS faster.
+
+ * Scripts/webkitpy/commands/early_warning_system.py:
+
+2010-01-17 Jon Honeycutt <jhoneycutt@apple.com>
+
+ MSAA: The child <option> elements of a non-multiple <select> are not
+ exposed
+
+ https://bugs.webkit.org/show_bug.cgi?id=33773
+ <rdar://problem/7550556>
+
+ Reviewed by Alice Liu.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getIsVisibleCallback):
+ Call the object's isVisible() function.
+ (getIsOffScreenCallback):
+ Ditto, for isOffScreen().
+ (getIsCollapsedCallback):
+ Ditto, for isCollapsed().
+ (getHasPopupCallback):
+ Ditto, for hasPopup().
+ (AccessibilityUIElement::getJSClass):
+ Add isVisible and isOffScreen attributes.
+
+ * DumpRenderTree/AccessibilityUIElement.h:
+ Declare new functions.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::isVisible):
+ Stubbed.
+ (AccessibilityUIElement::isOffScreen):
+ Stubbed.
+ (AccessibilityUIElement::isCollapsed):
+ Stubbed.
+ (AccessibilityUIElement::hasPopup):
+ Stubbed.
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::isVisible):
+ Stubbed.
+ (AccessibilityUIElement::isOffScreen):
+ Stubbed.
+ (AccessibilityUIElement::isCollapsed):
+ Stubbed.
+ (AccessibilityUIElement::hasPopup):
+ Stubbed.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::showMenu):
+ Call the object's accDoDefaultAction() to show its popup menu.
+ (AccessibilityUIElement::isEnabled):
+ Check that the object does not have the "unavailable" state.
+ (AccessibilityUIElement::isVisible):
+ Check that the object does not have the "invisible" state.
+ (AccessibilityUIElement::isOffScreen):
+ Check whether the object has the "offscreen" state.
+ (AccessibilityUIElement::isCollapsed):
+ Check whether the object has the "collapsed" state.
+ (AccessibilityUIElement::hasPopup):
+ Check whether the object has the "has popup" state.
+
+2010-01-19 Victor Wang <victorw@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Correct committer name.
+ https://bugs.webkit.org/show_bug.cgi?id=33868
+
+ * Scripts/webkitpy/committers.py:
+
+2010-01-19 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ [DRT][Mac] Add modifiers parameter to eventSender.mouseDown() and eventSender.mouseUp()
+ https://bugs.webkit.org/show_bug.cgi?id=33783
+
+ Some listbox tests check selection behavior by click events with
+ "meta" or "shift" keys. Behaviors for such modifier keys are
+ platform-dependent. The new parameter of mouseDown() and mouseUp()
+ allows to specify not only concrete modifier keys such as
+ "shiftKey" "metaKey", but also functional names like
+ "addSelectionKey" "rangeSelectionKey".
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (+[EventSendingController webScriptNameForSelector:]):
+ (buildModifierFlags):
+ (-[EventSendingController mouseDown:withModifiers:]):
+ (-[EventSendingController mouseDown:]):
+ (-[EventSendingController mouseUp:withModifiers:]):
+ (-[EventSendingController mouseUp:]):
+ (-[EventSendingController keyDown:withModifiers:withLocation:]):
+
+2010-01-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Unbreak --request-commit
+ https://bugs.webkit.org/show_bug.cgi?id=33832
+
+ * Scripts/webkitpy/bugzilla.py:
+
+2010-01-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ validate-committer-lists throws exception and committers.py needs a refresh
+ https://bugs.webkit.org/show_bug.cgi?id=33831
+
+ * Scripts/validate-committer-lists: use webkit_logging
+ * Scripts/webkitpy/committers.py: Add recently minted committers. Fix Simon Hausmanns email address list to include his webkit-committers@lists address.
+
+2010-01-18 Adam Roben <aroben@apple.com>
+
+ Add LayoutTestController support for calling new WebKit SPI to
+ disallow setting document.domain
+
+ DRT part of fixing <http://webkit.org/b/33806>
+ <rdar://problem/7552837> Would like API to disallow setting of
+ document.domain for pages with certain URL schemes
+
+ Reviewed by Sam Weinig.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setDomainRelaxationForbiddenForURLSchemeCallback): Added. Calls
+ through to LayoutTestController.
+ (LayoutTestController::staticFunctions): Added
+ setDomainRelaxationForbiddenForURLScheme.
+
+ * DumpRenderTree/LayoutTestController.h: Added
+ setDomainRelaxationForbiddenForURLScheme.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setDomainRelaxationForbiddenForURLScheme):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setDomainRelaxationForbiddenForURLScheme):
+ Added. Calls through to WebKit.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setDomainRelaxationForbiddenForURLScheme):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setDomainRelaxationForbiddenForURLScheme):
+ Stubbed out.
+
+2010-01-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Rename patches-to-commit to patches-in-commit-queue
+ https://bugs.webkit.org/show_bug.cgi?id=33789
+
+ The command really lists the patches in the commit-queue not all the
+ patches that are pending-commit (as the FIXME commands).
+
+ * Scripts/webkitpy/commands/queries.py:
+ * Scripts/webkitpy/commands/queries_unittest.py:
+
+2010-01-18 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Force qmake to generate a single makefile for DerivedSources.pro
+
+ * Scripts/webkitdirs.pm:
+
+2010-01-18 Adam Roben <aroben@apple.com>
+
+ Clean up use of /useenv when invoking Visual C++
+
+ This change reverts things to their pre-r49485 state. That revision
+ (and, subsequently, r49664 and r51788) started passing /useenv to
+ Visual C++, even in cases where we don't want to do so (such as when
+ invoking Visual C++ Express), in the name of making the Chromium build
+ work. Now that Chromium isn't using buildVisualStudioProject or
+ pdevenv, we can put things back they way they were.
+
+ Fixes <http://webkit.org/b/33797> build-webkit fails with VC++ Express
+ (due to /useenv flag)
+
+ Reviewed by Sam Weinig.
+
+ * Scripts/pdevenv: Always pass /useenv. Chromium doesn't use this
+ script anymore.
+ * Scripts/webkitdirs.pm:
+ (buildVisualStudioProject): Never pass /useenv anymore. pdevenv takes
+ care of this itself, and we don't want to pass /useenv when not using
+ pdevenv (e.g., when using VC++ Express, because that will cause it to
+ ignore the Platform SDK).
+
+2010-01-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch land-safely should obsolete old patches
+ https://bugs.webkit.org/show_bug.cgi?id=33788
+
+ When posting a commit-queue+ patch with land-safely, we should
+ obsolete the old patches on the bug. They're really confusing
+ because the main use case is to address reviewer feedback on a
+ previous patch.
+
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/commands/upload_unittest.py:
+
+2010-01-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by David Levin.
+
+ webkit-patch should authenticate more often
+ https://bugs.webkit.org/show_bug.cgi?id=33701
+
+ This makes it easier to work with security patches.
+
+ * Scripts/webkitpy/bugzilla.py:
+
+2010-01-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ style checker needs to know about GObject-specific requirements
+ inside WebCore/bindings/gobject/
+ https://bugs.webkit.org/show_bug.cgi?id=33606
+
+ Add an exception to the underscore rule for certain
+ GObject-specific names.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+
+2010-01-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ [check-webkit-style] does understand ResourceHandleWin.h
+ https://bugs.webkit.org/show_bug.cgi?id=32975
+
+ I'm not 100% convinced this fix is correct, but without more examples,
+ it's hard to generalize. We can always generalize the fix in the
+ future.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+
+2010-01-18 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix.
+
+ * Scripts/webkitpy/bugzilla.py:
+
+2010-01-18 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Actually make land-safely mark commit-queue+ as
+ discussed with Eric.
+
+ * Scripts/webkitpy/bugzilla.py:
+ * Scripts/webkitpy/steps/postdiffforcommit.py:
+
+2010-01-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ style-queue complains about one-line macros that include multiple statements
+ https://bugs.webkit.org/show_bug.cgi?id=33173
+
+ Add an exception for multiple statements on a line that starts a macro.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+
+2010-01-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ [check-webkit-style] qt unit testing false positives
+ https://bugs.webkit.org/show_bug.cgi?id=32833
+
+ Exempt the Qt API and unit tests from the style checker.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+
+2010-01-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ style-check script reports loads of errors on gtk2drawing.c
+ https://bugs.webkit.org/show_bug.cgi?id=33771
+
+ Exempt WebCore/platform/gtk/gtk2drawing.c and
+ WebCore/platform/gtk/gtk2drawing.h from style checks.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+
+2010-01-17 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Finished eliminating _cpp_style_state global state variable from
+ check-webkit-style code and eliminating _CppStyleState class.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33764
+
+ * Scripts/webkitpy/style/checker.py:
+ - Minor updates caused by changes to cpp_style.py.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ - Removed _CppStyleState class.
+ - Removed verbose_level functions.
+ - Added verbosity as a parameter to _FunctionState constructor.
+ - Added verbosity as a parameter to process_file().
+ - Added verbosity as a parameter to process_file_data().
+
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+ - Added helper functions to set verbosity while running tests.
+
+2010-01-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Shinichiro Hamaji.
+
+ check-webkit-style underscore check should be disabled for Qt methods starting with qt_
+ https://bugs.webkit.org/show_bug.cgi?id=33663
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+
+2010-01-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ style-queue complains about missing #include of config.h for non-WebCore projects
+ https://bugs.webkit.org/show_bug.cgi?id=33170
+
+ WebKitAPITests are consumers of the WebKit API and therefore do not
+ need to follow the same include discipline as the rest of WebKit. This
+ patch exempts them from the include checks.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+
+2010-01-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ EWS (Early Warning Systems) should build both debug and release
+ https://bugs.webkit.org/show_bug.cgi?id=33681
+
+ Build both debug and release for chromium-ews.
+
+ * Scripts/webkitpy/commands/early_warning_system.py:
+
+2010-01-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ style-queue should include instructions for how to file bugs against check-webkit-style
+ https://bugs.webkit.org/show_bug.cgi?id=32345
+
+ Added some text to the error message asking folks to file bugs against
+ false positives.
+
+ * Scripts/webkitpy/commands/queues.py:
+
+2010-01-17 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Eliminated the error_count global variable and related
+ check-webkit-style refactoring.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33678
+
+ * Scripts/check-webkit-style:
+ - Updated to use webkit_argument_defaults().
+ - Renamed styleChecker to style_checker.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Prefixed the three default arguments with WEBKIT_DEFAULT.
+ - Added webkit_argument_defaults().
+ - Added default filter_rules parameter to CategoryFilter constructor.
+ - Added __ne__() to CategoryFilter class.
+ - Added __eq__() and __ne__() to ProcessorOptions class.
+ - Added error_count and _write_error attributes to StyleChecker class.
+ - Made StyleChecker._handle_error() increment the error count.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Improved CategoryFilterTest.test_eq().
+ - Added CategoryFilterTest.test_ne().
+ - Added test_eq() and test_ne() to ProcessorOptionsTest class.
+ - Updated unit tests to use webkit_argument_defaults().
+ - Added StyleCheckerTest class.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ - Removed references to global error_count.
+
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+ - Removed CppStyleStateTest class.
+
+2010-01-15 Jon Honeycutt <jhoneycutt@apple.com>
+
+ get_accParent should try to retrieve parent AccessibilityObject, before
+ calling upon window
+
+ https://bugs.webkit.org/show_bug.cgi?id=22893
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::parentElement):
+ Get the object's parent. Query it for IAccessible, and return it.
+
+2010-01-16 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ <rdar://problem/7529519> DumpRenderTree crashes in makeLargeMallocFailSilently()
+
+ * DumpRenderTree/mac/CheckedMalloc.cpp:
+ (makeLargeMallocFailSilently): Temporarily allow writing to the default
+ malloc zone structure while modifying it.
+
+2010-01-16 David Kilzer <ddkilzer@apple.com>
+
+ Added back removed properties to iExploder input files
+
+ While the update-iexploder-cssproperties script works great to
+ add new properties, it has the side-effect of removing old
+ properties that once were parsed.
+
+ * iExploder/htdocs/cssproperties.in: Added back removed
+ properties into their own section.
+ * iExploder/htdocs/htmlattrs.in: Ditto.
+
+2010-01-16 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by David Kilzer.
+
+ Update iExploder/htdocs/*.in by running update-iexploder-cssproperties
+ https://bugs.webkit.org/show_bug.cgi?id=33756
+
+ * iExploder/htdocs/cssproperties.in: New CSS attributes
+ * iExploder/htdocs/htmlattrs.in: New HTML attributes
+ * iExploder/htdocs/htmltags.in: New HTML tags
+
+2010-01-15 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by David Kilzer.
+
+ Altered parseDiffHeader() to skip unrecognized lines and
+ other minor clean-ups.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33476
+
+ * Scripts/VCSUtils.pm:
+ - Changed parseDiffHeader() as follows:
+ - Skips over unrecognized lines.
+ - Addressed FIXME to remove substitution for "diff" line.
+ - Renamed "version" header hash key to "sourceRevision".
+ - Eliminated "copiedFromVersion" header hash key.
+ - Included "sourceRevision" also for copied files.
+ - Checks that copy revision number matches "sourceRevision".
+ - No longer returns $foundHeaderEnding.
+ - Dies if header ending not found.
+ - Diff header dividing line now always added.
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl:
+ - Made necessary changes in parseDiffHeader() unit tests.
+ - Shortened the file paths in some test cases.
+
+2010-01-14 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Update pywebsocket to 0.4.6
+ https://bugs.webkit.org/show_bug.cgi?id=32299
+ The newer pywebsocket can handle more simultaneous connections.
+
+ * pywebsocket/mod_pywebsocket/handshake.py:
+ * pywebsocket/mod_pywebsocket/standalone.py:
+ * pywebsocket/setup.py:
+ * pywebsocket/test/test_handshake.py:
+
+2010-01-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ REGRESSION(53133): commit-queue no longer rejects patches with invalid committers, instead it hangs
+ https://bugs.webkit.org/show_bug.cgi?id=33638
+
+ * Scripts/webkitpy/bugzilla.py:
+ - Add Bug.id() to match Attachment.id()
+ - Give Bug.reviewed_patches and commit_queued_patches the option to return patches with invalid committers/reviewers.
+ - Add back a missing variable to _validate_setter_email found by the new unit tests!
+ * Scripts/webkitpy/commands/queries.py:
+ - Add FIXMEs about the commands being confusingly named.
+ * Scripts/webkitpy/commands/queries_unittest.py:
+ - Update results to reflect the newly restructured mock bug cache.
+ * Scripts/webkitpy/commands/queues.py:
+ - Add a new _validate_patches_in_commit_queue method (this is what fixes the regression).
+ - Add a FIXME about eventually sorting the patches into some order.
+ * Scripts/webkitpy/commands/queues_unittest.py:
+ - Update results now that with the newly restructure mock bug cache we're testing cq+'d patches with an invalid committer.
+ * Scripts/webkitpy/commands/upload_unittest.py:
+ - Update results to match the newly restructured mock bug cache.
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ - Restructure fetch_ methods to not use a manual list of ids, but rather use Bug and Attachment classes to make real queries from all of the Bugs.
+ - Add a few more attachments and bug dictionaries for use by the tests.
+
+2010-01-13 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ [Qt] DRT missing setUserStyleSheetLocation and setUserStyleSheetEnabled in LayoutTestController
+ https://bugs.webkit.org/show_bug.cgi?id=33617
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setUserStyleSheetLocation):
+ (LayoutTestController::setUserStyleSheetEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-01-14 Adam Roben <aroben@apple.com>
+
+ Add LayoutTestController API to force
+ -webView:resource:willSendRequest:: to return null
+
+ Enables tests for <rdar://problem/7533333> <http://webkit.org/b/33533>
+ window.onload never fires if page contains an <iframe> with a bad
+ scheme or whose load is cancelled by returning null from resource load
+ delegate's willSendRequest
+
+ Reviewed by Brady Eidson.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController): Initialize new member.
+ (setWillSendRequestReturnsNullCallback): Call through to
+ LayoutTestController.
+ (LayoutTestController::staticFunctions): Added new function.
+
+ * DumpRenderTree/LayoutTestController.h: Added
+ m_willSendRequestReturnsNull.
+ (LayoutTestController::willSendRequestReturnsNull):
+ (LayoutTestController::setWillSendRequestReturnsNull):
+ Added standard accessors.
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:resource:willSendRequest:redirectResponse:fromDataSource:]):
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::willSendRequest):
+ Return null if LayoutTestController says to.
+
+2010-01-14 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after removal of XBM support.
+
+ * wx/build/settings.py:
+
+2010-01-14 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Add support for partial building on Symbian.
+
+ The build happens in the source directory as out of source builds are
+ not supported by qmake for Symbian.
+
+ Also the actual build isn't started but it is left to the developer
+ to choose the architecture/configuration.
+
+ * Scripts/webkitdirs.pm:
+
+2010-01-14 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Add support for "detecting" Symbian environments by either
+ looking for the EPOCROOT environment variable or via --symbian
+ being passed on the commandline.
+
+ * Scripts/webkitdirs.pm:
+
+2010-01-14 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Unreviewed.
+
+ [Qt] Use a different Makefile names for sources generation and compilation.
+ This prevents Makefile overwriting when running build-webkit twice.
+
+ * Scripts/webkitdirs.pm:
+
+2010-01-14 Andreas Kling <andreas.kling@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Add an "alien_QLabel" classId for manual testing of alien widgets.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33373
+
+ * QtLauncher/main.cpp:
+ (WebPage::createPlugin):
+
+2010-01-14 Eric Seidel <eric@webkit.org>
+
+ No review, rolling out r53249.
+ http://trac.webkit.org/changeset/53249
+ https://bugs.webkit.org/show_bug.cgi?id=33617
+
+ This caused http/tests/security/local-user-CSS-from-
+ remote.html to fail on the Qt Release Build Bot.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::overridePreference):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-01-14 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Moved error() from cpp_style.py to checker.py.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33620
+
+ * Scripts/check-webkit-style:
+ - Addressed FIXME to not set global state.
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added argument validation to ProcessorOptions constructor.
+ - Added should_report_error() to ProcessorOptions class.
+ - Removed set_options().
+ - Added StyleChecker class.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Added unit test class for ProcessorOptions class.
+ - Added unit test to check that parse() strips white space.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ - Removed "filter" and "output_format" methods.
+ - Removed should_print_error() and error() functions.
+ - Removed default parameter value from process_file().
+
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+ - Removed call to cpp_style._should_print_error().
+ - Removed test_filter() and test_filter_appending().
+
+ * Scripts/webkitpy/style/text_style.py:
+ - Removed default parameter value from process_file().
+
+2010-01-14 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] DRT missing setUserStyleSheetLocation and setUserStyleSheetEnabled in LayoutTestController
+ https://bugs.webkit.org/show_bug.cgi?id=33617
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setUserStyleSheetLocation):
+ (LayoutTestController::setUserStyleSheetEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-01-13 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix CloseBugForLandDiff unittest to actually run
+ https://bugs.webkit.org/show_bug.cgi?id=33640
+
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ * Scripts/webkitpy/steps/closebugforlanddiff_unittest.py:
+
+2010-01-12 Jon Honeycutt <jhoneycutt@apple.com>
+
+ MSAA: selected, selectable, extended selectable, and multiple
+ selectable states are not reported
+
+ https://bugs.webkit.org/show_bug.cgi?id=33574
+ <rdar://problem/7536826>
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getIsSelectableCallback):
+ Return the result of calling isSelectable().
+ (getIsMultiSelectableCallback):
+ Return the result of calling isMultiSelectable().
+ (AccessibilityUIElement::getJSClass):
+ Add isSelected and isMultiSelectable properties to the JSClass
+ definition.
+
+ * DumpRenderTree/AccessibilityUIElement.h:
+ Declare isSelectable() and isMultiSelectable().
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::isSelectable):
+ Stubbed.
+ (AccessibilityUIElement::isMultiSelectable):
+ Stubbed.
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::isSelectable):
+ Stubbed.
+ (AccessibilityUIElement::isMultiSelectable):
+ Stubbed.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (accessibilityState):
+ Get the object's state, and return it.
+ (AccessibilityUIElement::isSelected):
+ Check the object's selected state.
+ (AccessibilityUIElement::isSelectable):
+ Check the object's selectable state.
+ (AccessibilityUIElement::isMultiSelectable):
+ Check the object's extended/multiple selectable state.
+
+2010-01-13 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Repeat the below for CloseBugForLandDiff.
+
+ * Scripts/test-webkitpy:
+ * Scripts/webkitpy/steps/closebugforlanddiff.py:
+ * Scripts/webkitpy/steps/closebugforlanddiff_unittest.py: Added.
+
+2010-01-13 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Turn the mac-ews status bubbles back on now that this bot
+ is running again.
+
+ * QueueStatusServer/templates/statusbubble.html:
+
+2010-01-13 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ REGRESSION(53133): webkit-patch land dies if it can't find a bug id.
+ https://bugs.webkit.org/show_bug.cgi?id=33634
+
+ Deal with the case of no bug patch object in the state.
+
+ * Scripts/webkitpy/steps/updatechangelogswithreview_unittests.py:
+ * Scripts/webkitpy/steps/updatechangelogswithreviewer.py:
+
+2010-01-13 Kenneth Russell <kbr@google.com>
+
+ Unreviewed; added myself to the committers list.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-01-13 Darin Adler <darin@apple.com>
+
+ Ignore compiled Python in more of webkitpy.
+
+ * Scripts/webkitpy/commands: Added property svn:ignore.
+ * Scripts/webkitpy/steps: Added property svn:ignore.
+ * Scripts/webkitpy/style: Added property svn:ignore.
+
+2010-01-13 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Fix build problem related to the pushd command
+
+ * Scripts/webkitdirs.pm:
+
+2010-01-13 Jocelyn Turcotte <jocelyn.turcotte@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Split the build process in two different .pro files.
+ This allows qmake to be run once all source files are available.
+
+ * Scripts/webkitdirs.pm: Add calls to make DerivedSources.pro in JSC and WC.
+
+2010-01-13 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Unreviewed tiny typo fix in docstrings.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+
+2010-01-13 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by Shinichiro Hamaji.
+
+ Created a CategoryFilter class to encapsulate the logic of
+ filter rules.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33454
+
+ * Scripts/webkitpy/style/checker.py:
+ - Added CategoryFilter class.
+
+ * Scripts/webkitpy/style/checker_unittest.py:
+ - Added CategoryFilter unit tests.
+
+ * Scripts/webkitpy/style/cpp_style.py:
+ - Updated filter methods to use CategoryFilter.
+
+ * Scripts/webkitpy/style/cpp_style_unittest.py:
+ - Updated references to filters.
+
+2010-01-12 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Unreviewed. Now I can review :)
+
+ * Scripts/webkitpy/committers.py:
+
+2010-01-12 Brent Fulgham <bfulgham@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Extend WinLauncher example with better printing features.
+
+ * WinLauncher/PrintWebUIDelegate.cpp:
+ (PrintWebUIDelegate::webViewPrintingMarginRect): Provide slightly
+ larger margins.
+ (PrintWebUIDelegate::webViewHeaderHeight): Compute header height based
+ on text metrics.
+ (PrintWebUIDelegate::webViewFooterHeight): Compute footer height based
+ on text metrics.
+ (PrintWebUIDelegate::drawHeaderInRect): Write useful header, along
+ with separating line.
+ (PrintWebUIDelegate::drawFooterInRect):
+ * WinLauncher/PrintWebUIDelegate.h: Remove stubs.
+ * WinLauncher/WinLauncher.cpp:
+ (PrintView): Correct loop used to print individual pages.
+ Previously it started at 0, which is a wild-card to print all
+ pages at once.
+
+2010-01-12 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33540
+ Make it possible to build in debug mode with assertions disabled
+
+ * DumpRenderTree/mac/ObjCController.m: (-[ObjCController accessStoredWebScriptObject]):
+
+2010-01-11 Darin Fisher <darin@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ [Chromium] "build-webkit --chromium" should run "make all" on Linux
+ https://bugs.webkit.org/show_bug.cgi?id=33500
+
+ * Scripts/webkitdirs.pm:
+
+2010-01-12 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ AssignToCommitter does not need to fetch bugs twice
+ https://bugs.webkit.org/show_bug.cgi?id=33530
+
+ This is a no-brainer patch now that we've added Bug.reviewed_patches
+
+ * Scripts/webkitpy/commands/upload.py:
+
+2010-01-12 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla.py should have an Attachment object instead of passing around dictionaries
+ https://bugs.webkit.org/show_bug.cgi?id=31594
+
+ * Scripts/webkitpy/bugzilla.py:
+ - Add a new Attachment class, with accessor methods for all the necessary properties.
+ - Update Bug to carry a pointer back to bugzilla (attachments need to access Bugzilla for committer validation and url())
+ - Move reviewed_patches and commit_queued_patches out of Bugzilla custom methods and onto Bug
+ - Move committer validation logic into its own class.
+ - Committer rejection is only used in one place. Make the new Bug reviewed_patches and commit_queued_patches
+ handle the common case (of returning "reviewer" or "committer" as None), and let CommitterValidation handle
+ the case where we want to reject patches in bugzilla.
+ - Simplify fetch_patches_from_commit_queue now that committer validation is simpler.
+ - Make all self.bugzilla.fetch_bug access go through BugzillaQueries._fetch_bug.
+ - Mark set_flag_on_attachment as non-private to denote that CommitterValidation depends on it.
+ - Move fetch_reviewed_patches_from_bug and fetch_commit_queue_patches_from_bug logic onto the Bug class.
+ * Scripts/webkitpy/bugzilla_unittest.py:
+ - Move test_flag_permission_rejection_message into a new CommitterValidationTest class.
+ * Scripts/webkitpy/commands/download.py:
+ - Store "bug_id" in state instead of making a fake patch object.
+ - Update to use Attachment and Bug objects.
+ * Scripts/webkitpy/commands/download_unittest.py:
+ - Update expected results now that our testing framework covers more code.
+ * Scripts/webkitpy/commands/early_warning_system.py: Update to use new Attachment class.
+ * Scripts/webkitpy/commands/queries.py: Remove unused ReviewedPatches class.
+ * Scripts/webkitpy/commands/queries_unittest.py: ditto.
+ * Scripts/webkitpy/commands/queues.py: Update to use new Attachment and CommitterValidator classes.
+ * Scripts/webkitpy/commands/queuestest.py: ditto.
+ * Scripts/webkitpy/commands/upload.py: ditto.
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ - Now that more logic has moved into Attachment and Bug, we have to actually
+ provide real reviewer emails as well as real reviewer flags.
+ - Update mock methods to return Attachment objects.
+ * Scripts/webkitpy/scm.py: Update to use Attachment class.
+ * Scripts/webkitpy/scm_unittest.py: Update to use Attachment class.
+ * Scripts/webkitpy/statusserver.py: ditto.
+ * Scripts/webkitpy/steps/applypatch.py: ditto.
+ * Scripts/webkitpy/steps/applypatchwithlocalcommit.py: ditto.
+ * Scripts/webkitpy/steps/closebug.py: ditto.
+ * Scripts/webkitpy/steps/closebugforlanddiff.py: Handle either state["bug_id"] or state["patch"].bug_id()
+ * Scripts/webkitpy/steps/closepatch.py: Update to use Attachment class.
+ * Scripts/webkitpy/steps/obsoletepatches.py: ditto.
+ * Scripts/webkitpy/steps/updatechangelogswithreviewer.py: ditto.
+
+2010-01-12 Adam Barth <abarth@webkit.org>
+
+ Unreviewed typo fix. :(
+
+ * Scripts/webkitpy/commands/early_warning_system.py:
+ * Scripts/webkitpy/commands/queues.py:
+
+2010-01-12 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Add "error" to the right part of the message.
+
+ * Scripts/webkitpy/commands/queues.py:
+
+2010-01-12 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ EWS should show purple when svn-apply fails
+ https://bugs.webkit.org/show_bug.cgi?id=33527
+
+ * Scripts/webkitpy/commands/early_warning_system.py:
+ * Scripts/webkitpy/commands/queues.py:
+
+2010-01-12 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Remove copy/paste code from subclasses of AbstractReviewQueue
+ https://bugs.webkit.org/show_bug.cgi?id=33525
+
+ * Scripts/webkitpy/commands/early_warning_system.py:
+ * Scripts/webkitpy/commands/queues.py:
+
+2010-01-12 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add Gustavo and Xan as gtk-ews watchers
+ https://bugs.webkit.org/show_bug.cgi?id=33519
+
+ * Scripts/webkitpy/commands/early_warning_system.py:
+
+2010-01-12 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch shouldn't waste my time for with a component prompt
+ https://bugs.webkit.org/show_bug.cgi?id=33521
+
+ The component field isn't very useful for bugs created with
+ webkit-patch because they're likely to be resolved quickly. Instead of
+ always prompting for a component, we should just default to the "New
+ Bugs" component. If the bug stays around for more than five minutes,
+ we can assign it a proper component.
+
+ * Scripts/webkitpy/bugzilla.py:
+
+2010-01-12 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add experimental "land-safely" command to webkit-patch
+ https://bugs.webkit.org/show_bug.cgi?id=33518
+
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/commands/upload_unittest.py:
+ * Scripts/webkitpy/steps/__init__.py:
+ * Scripts/webkitpy/steps/postdiffforcommit.py: Added.
+
+2010-01-11 Kevin Ollivier <kevino@theolliviers.com>
+
+ [wx] Build fix after introduction of JS_NO_EXPORT
+
+ * wx/build/settings.py:
+
+2010-01-11 Eric Seidel <eric@webkit.org>
+
+ No review, rolling out r53079.
+ http://trac.webkit.org/changeset/53079
+ https://bugs.webkit.org/show_bug.cgi?id=33197
+
+ Adam doens't think this actually works, and believe it caused
+ a regression https://bugs.webkit.org/show_bug.cgi?id=33488 so
+ rolling this out.
+
+ * Scripts/test-webkitpy:
+ * Scripts/webkitpy/commands/abstractdiffcommand.py: Removed.
+ * Scripts/webkitpy/commands/abstractdiffcommand_unittest.py: Removed.
+ * Scripts/webkitpy/commands/download.py:
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/mock_bugzillatool.py:
+
+2010-01-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ bugzilla-tool submit-patch mistakenly picks up bug URLs in non-ChangeLog files
+ https://bugs.webkit.org/show_bug.cgi?id=33197
+
+ We should just search for bug numbers in the ChangeLogs instead of in
+ the whole diff.
+
+ * Scripts/test-webkitpy:
+ * Scripts/webkitpy/commands/abstractdiffcommand.py: Added.
+ * Scripts/webkitpy/commands/abstractdiffcommand_unittest.py: Added.
+ * Scripts/webkitpy/commands/download.py:
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/mock_bugzillatool.py:
+
+2010-01-11 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by David Kilzer.
+
+ Created a unit-tested function to parse the header block of
+ a Git or SVN diff -- for future refactoring of svn-apply and
+ svn-unapply.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33447
+
+ * Scripts/VCSUtils.pm:
+ - Added parseDiffHeader().
+ - Removed irrelevant comment from gitdiff2svndiff().
+
+ * Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl: Added.
+ - Added 48 unit tests for parseDiffHeader().
+
+2010-01-10 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by David Kilzer.
+
+ bugzilla-tool submit-patch mistakenly picks up bug URLs in non-ChangeLog files
+ https://bugs.webkit.org/show_bug.cgi?id=33197
+
+ Fix a typo: Commmand -> Command.
+
+ * Scripts/webkitpy/commands/abstractsequencedcommand.py:
+ * Scripts/webkitpy/commands/download.py:
+ * Scripts/webkitpy/commands/queries.py:
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/multicommandtool.py:
+
+2010-01-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Let webkit-patch work with options in $EDITOR
+ https://bugs.webkit.org/show_bug.cgi?id=33414
+
+ The $EDITOR evironment variable might have command line options like
+ bbedit -w. This patch lets us run those $EDITORs.
+
+ * Scripts/webkitpy/user.py:
+
+2010-01-10 Robert Hogan <robert@roberthogan.net>
+
+ Reviewed by Adam Barth.
+
+ [Qt] Add enableXSSAuditor support to QWebSettings and DRT.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33419
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::resetSettings):
+ (WebCore::DumpRenderTree::createWindow):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setXSSAuditorEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-01-10 Adam Barth <abarth@webkit.org>
+
+ Unreviewed cosmetic change. Remove the status bubble for mac-ews
+ because we don't have hardware for it at the moment.
+
+ * QueueStatusServer/templates/statusbubble.html:
+
+2010-01-09 Daniel Bates <dbates@webkit.org>
+
+ No review, rolling out r53044.
+ http://trac.webkit.org/changeset/53044
+ https://bugs.webkit.org/show_bug.cgi?id=33419
+
+ We need to look into this some more because the Qt
+ bot is failing the XSSAuditor tests. See bug #33419
+ for more details.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-01-09 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33419
+
+ Adds support for the XSSAuditor to the Qt DRT.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setXSSAuditorEnabled):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2010-01-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Retry writes to QueueStatusServer when we get 500 errors
+ https://bugs.webkit.org/show_bug.cgi?id=33412
+
+ This prevents the queues from failing to mark a patch as "pass" or
+ "fail" when AppEngine throws 500 errors.
+
+ * Scripts/test-webkitpy:
+ * Scripts/webkitpy/networktransaction.py: Added.
+ * Scripts/webkitpy/networktransaction_unittest.py: Added.
+ * Scripts/webkitpy/statusserver.py:
+ * Scripts/webkitpy/steps/closebugformarkbugfixed.py: Added.
+ * Scripts/webkitpy/steps/closebugregardlessofpatches.py: Added.
+ * Scripts/webkitpy/steps/findbugidfromsvnrevision.py: Added.
+
+2010-01-09 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/33430> Fix rounded borders in queue status on older Firefox and Safari browsers
+
+ Reviewed by Eric Seidel.
+
+ * QueueStatusServer/templates/statusbubble.html: Added
+ -moz-border-radius and -webkit-border-radius to provide rounded
+ borders in older Firefox and Safari browsers.
+
+2010-01-09 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by David Kilzer.
+
+ Modified VCSUtils::gitdiff2svndiff() to accept strings that
+ end in vertical white space.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33415
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/webkitperl/VCSUtils_unittest/gitdiff2svndiff.pl:
+
+2010-01-08 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ run-javascriptcore-tests needs a --quiet flag
+ https://bugs.webkit.org/show_bug.cgi?id=33399
+
+ Until run-javascriptcore-tests has a --quiet flag, lets just stiffle the output in webkit-patch.
+
+ * Scripts/webkitpy/steps/runtests.py:
+
+2010-01-08 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Only run http and websocket tests as last if no argument is given to be able to explicitly control the test order.
+
+ To be able to run multiple instances of run-webkit-tests besides each other on the same machine we need to minimize
+ the time when Apache and WebSocketServer is locked by tests.
+ Because closeHTTPD() and closeWebSocketServer() is only called at the end of the testing,
+ we need to run http and websocket tests after all other tests.
+ If one however explicitly specifies the tests to run in the argument list of run-webkit-tests
+ we need to preserve the given order.
+
+ * Scripts/run-webkit-tests:
+
+2010-01-08 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Don't post style-queue pass messages to bugs
+ https://bugs.webkit.org/show_bug.cgi?id=33404
+
+ These messages aren't needed any more now that we have the status
+ bubble reporting pass events passively.
+
+ * Scripts/webkitpy/commands/queues.py:
+
+2010-01-08 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Optimize the number of CPUs used for building Qt and Gtk
+ https://bugs.webkit.org/show_bug.cgi?id=33394
+
+ Instead of hardcoding the number 8, we should read the number of CPUs
+ from the environment.
+
+ * Scripts/webkitpy/executive.py:
+ * Scripts/webkitpy/webkitport.py:
+ * Scripts/webkitpy/webkitport_unittest.py:
+
+2010-01-08 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Eric Seidel.
+
+ REGRESSION(52819?): AXLoadComplete and AXLayoutComplete causes 4 tests fail on Snow Leopard Debug bot
+ https://bugs.webkit.org/show_bug.cgi?id=33300
+
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::AccessibilityUIElement):
+ (AccessibilityUIElement::~AccessibilityUIElement):
+ (_accessibilityNotificationCallback):
+ (AccessibilityUIElement::addNotificationListener):
+
+2010-01-08 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ commit-queue should run run-javascriptcore-tests
+ https://bugs.webkit.org/show_bug.cgi?id=33376
+
+ I also made it run the python and perl unit tests.
+
+ * Scripts/webkitpy/steps/runtests.py:
+ * Scripts/webkitpy/webkitport.py:
+
+2010-01-07 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Reviewed by Darin Adler.
+
+ Run the http and websocket tests after all other tests.
+ https://bugs.webkit.org/show_bug.cgi?id=33153
+
+ * Scripts/run-webkit-tests:
+
+2010-01-07 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix some test-webkitpy expectations
+ https://bugs.webkit.org/show_bug.cgi?id=33345
+
+ I forgot to change these when I added the CheckStyle step.
+
+ * Scripts/webkitpy/commands/upload_unittest.py:
+
+2010-01-07 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ webkit-patch edit-changelogs (or upload) will open blank files if run outside the root
+ https://bugs.webkit.org/show_bug.cgi?id=33341
+
+ Fix this by moving to the root directory before editing ChangeLogs.
+ There is a related bug with CheckStyle.
+
+ * Scripts/webkitpy/steps/checkstyle.py:
+ * Scripts/webkitpy/steps/editchangelog.py:
+
+2010-01-07 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Nikolas Zimmermann.
+
+ media/unsupported-tracks.html is failing on Snow Leopard Release bot
+ https://bugs.webkit.org/show_bug.cgi?id=32339
+
+ This is a speculative fix. I do not have a Snow Leopard machine to test on
+ and I've not seen mention of someone being able to reproduce this locally.
+
+ Prevent watchdog timer from firing after a test completes but before
+ the next one starts, causing the error to appear in the next test.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dump): Stop the watchdog before printing #EOF for the test content.
+ We only need to care about the JavaScript of the test running too long
+ or some hang in WebCore. Any other failures will be covered by the calling
+ script's own watchdog timer.
+
+2010-01-07 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue is stuck spinning due to exception
+ https://bugs.webkit.org/show_bug.cgi?id=33358
+
+ * Scripts/webkitpy/commands/queues.py:
+ - Don't try to stringify the exception.
+
+2010-01-07 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Jon Honeycutt.
+
+ Don't leak a JSStringRef within _accessibilityNotificationCallback.
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (_accessibilityNotificationCallback): Have a JSRetainPtr adopt the JSStringRef so that it will be cleaned up
+ when it goes out of scope.
+
+2010-01-07 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Add proposed rename of HTMLPlugInImageElement to HTMLEmbeddedObjectElement.
+
+ * Scripts/do-webcore-rename:
+
+2010-01-07 Kim Grönholm <kim.gronholm@nomovok.com>
+
+ Reviewed by Antti Koivisto.
+
+ Wrong state and TouchLists in TouchEvents
+ https://bugs.webkit.org/show_bug.cgi?id=32878
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::touchStart):
+ (EventSender::touchEnd):
+ (EventSender::clearTouchPoints):
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2010-01-07 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by Adam Barth.
+
+ Created a module that runs the style package unit tests.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32973
+
+ * Scripts/test-webkitpy:
+ * Scripts/webkitpy/style/unittests.py: Added.
+
+2010-01-07 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Don't print a redundant message when confirming a diff
+ https://bugs.webkit.org/show_bug.cgi?id=33315
+
+ Instead of saying "ERROR: User declined" we should just exit because
+ the use knows they just declined!
+
+ * Scripts/webkitpy/steps/confirmdiff.py:
+
+2010-01-07 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Check style before uploading a patch
+ https://bugs.webkit.org/show_bug.cgi?id=33314
+
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/steps/checkstyle.py:
+ * Scripts/webkitpy/steps/options.py:
+
+2010-01-07 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Add prepare and post to webkit-patch main help
+ https://bugs.webkit.org/show_bug.cgi?id=33313
+
+ * Scripts/webkitpy/commands/upload.py:
+
+2010-01-07 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add Chromium bots to the list of "core builders" (builders which stop the commit-queue when they turn red)
+ https://bugs.webkit.org/show_bug.cgi?id=33290
+
+ Add the Chromium builders to our list of core builders and test that our regexps work.
+ I also updated our regexp testing to make sure we cover all known builders at build.webkit.org.
+
+ * Scripts/webkitpy/buildbot.py:
+ * Scripts/webkitpy/buildbot_unittest.py:
+
+2010-01-07 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ bugzilla-tool needs a new name
+ https://bugs.webkit.org/show_bug.cgi?id=28459
+
+ Rename bugzilla-tool to webkit-patch. Also, rename some commands to
+ make more sense with the new name.
+
+ * Scripts/bugzilla-tool: Removed.
+ * Scripts/webkit-patch: Added.
+ * Scripts/webkit-tools-completion.sh:
+ * Scripts/webkitpy/bugzilla_unittest.py:
+ * Scripts/webkitpy/commands/download.py:
+ * Scripts/webkitpy/commands/download_unittest.py:
+ * Scripts/webkitpy/commands/early_warning_system.py:
+ * Scripts/webkitpy/commands/queries.py:
+ * Scripts/webkitpy/commands/queues.py:
+ * Scripts/webkitpy/commands/queues_unittest.py:
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/commands/upload_unittest.py:
+ * Scripts/webkitpy/queueengine.py:
+ * Scripts/webkitpy/steps/completerollout.py:
+
+2010-01-07 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by Eric Seidel.
+
+ Moved style-related modules to webkitpy.style sub-package.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32971
+
+ * Scripts/check-webkit-style:
+ - Updated import statement.
+
+ * Scripts/test-webkitpy:
+ - Updated import statements.
+
+ * Scripts/webkitpy/cpp_style.py: Removed.
+ - Moved to webkitpy/style.
+
+ * Scripts/webkitpy/cpp_style_unittest.py: Removed.
+ - Moved to webkitpy/style.
+
+ * Scripts/webkitpy/style.py: Removed.
+ - Moved to webkitpy/style/checker.py.
+
+ * Scripts/webkitpy/style/__init__.py: Added.
+ - Added containing webkitpy directory to package search path.
+
+ * Scripts/webkitpy/style/checker.py: Copied from Scripts/webkitpy/style.py.
+ * Scripts/webkitpy/style/checker_unittest.py: Copied from Scripts/webkitpy/style_unittest.py.
+ - Updated import statement.
+
+ * Scripts/webkitpy/style/cpp_style.py: Copied from Scripts/webkitpy/cpp_style.py.
+ * Scripts/webkitpy/style/cpp_style_unittest.py: Copied from Scripts/webkitpy/cpp_style_unittest.py.
+ - Update import statement.
+
+ * Scripts/webkitpy/style/text_style.py: Copied from Scripts/webkitpy/text_style.py.
+ * Scripts/webkitpy/style/text_style_unittest.py: Copied from Scripts/webkitpy/text_style_unittest.py.
+ * Scripts/webkitpy/style_unittest.py: Removed.
+ - Moved to webkitpy/style/checker_unittest.py.
+
+ * Scripts/webkitpy/text_style.py: Removed.
+ - Moved to webkitpy/style.
+
+ * Scripts/webkitpy/text_style_unittest.py: Removed.
+ - Moved to webkitpy/style.
+
+2010-01-06 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] Support the 3rd argument of EventSender.keyDown that
+ has been recently added to report keyLocation
+ (see also: https://bugs.webkit.org/show_bug.cgi?id=28247).
+ https://bugs.webkit.org/show_bug.cgi?id=33250
+
+ Test: fast/events/keydown-numpad-keys.html
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::keyDown):
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2010-01-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add long_help for all common commands.
+ https://bugs.webkit.org/show_bug.cgi?id=33261
+
+ For now these long_helps are pretty basic.
+ These were all written to just explain the steps
+ that each command runs. This style long_help could
+ be made easier by using:
+ https://bugs.webkit.org/show_bug.cgi?id=33257
+
+ * Scripts/webkitpy/commands/download.py:
+ * Scripts/webkitpy/commands/queries.py:
+
+2010-01-06 Diego Gonzalez <diego.gonzalez@openbossa.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ [Qt] Add page zooming support to Qt DumpRenderTree
+ https://bugs.webkit.org/show_bug.cgi?id=32898
+
+ Patch by Kim Grönholm <kim.gronholm@nomovok.com>,
+ Diego Gonzalez <diego.gonzalez@openbossa.org> and
+ Afonso Costa <afonso.costa@openbossa.org>
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::zoomPageIn):
+ (EventSender::zoomPageOut):
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2010-01-06 Eric Seidel <eric@webkit.org>
+
+ No review, just adding Mike Belshe's new bugzilla email at his request.
+
+ * Scripts/webkitpy/committers.py:
+
+2010-01-06 Eric Seidel <eric@webkit.org>
+
+ Unreviewed. Rolling out r52869 and r52853 due to bot
+ and local run-webkit-test failures
+
+ REGRESSION(52854?) fast/workers/shared-worker-constructor.html failed on Leopard Build Bot
+ https://bugs.webkit.org/show_bug.cgi?id=33256
+
+ The original bug was https://bugs.webkit.org/show_bug.cgi?id=33153
+
+ * Scripts/run-webkit-tests:
+
+2010-01-06 Eric Seidel <eric@webkit.org>
+
+ Unreviewed "build" fix. Just adding missing include.
+
+ bugzilla-tool rollout --complete-rollout should make a nicer bug comment
+ https://bugs.webkit.org/show_bug.cgi?id=29212
+
+ * Scripts/webkitpy/steps/completerollout.py:
+
+2010-01-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool rollout --complete-rollout should make a nicer bug comment
+ https://bugs.webkit.org/show_bug.cgi?id=29212
+
+ * Scripts/webkitpy/bugzilla.py:
+ - Make reopen_bug robust against the bug already being open.
+ * Scripts/webkitpy/commands/download.py:
+ - Remove dead code from Rollout.
+ * Scripts/webkitpy/steps/completerollout.py:
+ - Improve the rollout comment.
+
+2010-01-06 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Reviewed by Darin Adler.
+
+ Set isHttpdOpen to 0 if pidfile does not exist for some reason.
+ Speculative fix for https://bugs.webkit.org/show_bug.cgi?id=33256.
+
+ * Scripts/run-webkit-tests:
+
+2010-01-06 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Reviewed by Darin Adler.
+
+ Change hardcoded /tmp in run-webkit-tests to File::Spec->tmpdir(),
+ and remove the httpd's pidfile directory if httpd terminated.
+
+ * Scripts/run-webkit-tests:
+
+2010-01-05 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by David Levin.
+
+ Refactored check-webkit-style's argument parser to not rely
+ on global state, and improved its error handling and unit
+ test coverage.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32966
+
+ * Scripts/check-webkit-style:
+ - Adjusted to use new argument parser.
+
+ * Scripts/webkitpy/cpp_style.py:
+ - Changed _CppStyleState to accept an array of filter rules
+ instead of a comma-delimited string.
+ - Eliminated cpp_style._DEFAULT_FILTER_RULES.
+ - Eliminated cpp_style._USAGE.
+
+ * Scripts/webkitpy/cpp_style_unittest.py:
+ - Updated test_filter() and test_default_filter().
+
+ * Scripts/webkitpy/style.py:
+ - Converted style._USAGE to create_usage().
+ - Corrected usage instructions by removing 0 as a valid
+ --verbose flag value.
+ - Removed use_webkit_styles().
+ - Added ProcessorOptions class.
+ - Added ArgumentDefaults class.
+ - Added ArgumentPrinter class.
+ - Removed parse_arguments and added ArgumentParser class.
+ - Moved exit_with_usage() and exit_with_categories() into
+ ArgumentParser.
+ - Refactored parse_arguments() as ArgumentParser.parse().
+ - Improved parser error handling.
+
+ * Scripts/webkitpy/style_unittest.py:
+ - Added DefaultArgumentsTest class.
+ - Addressed FIXME to check style.WEBKIT_FILTER_RULES
+ against style.STYLE_CATEGORIES.
+ - Added ArgumentPrinterTest class.
+ - Added ArgumentParserTest class and rewrote parser unit tests.
+
+2010-01-05 Adam Roben <aroben@apple.com>
+
+ Test that it's safe to call IWebView::close when
+ IWebView::initWithFrame hasn't been called
+
+ Part of <http://webkit.org/b/32827> Crash when calling
+ IWebView::close, then releasing the WebView, without calling
+ DestroyWindow
+
+ Reviewed by Steve Falkenburg.
+
+ * WebKitAPITest/tests/WebViewDestruction.cpp:
+ (WebKitAPITest::CloseWithoutInitWithFrame): Calls IWebView::close
+ without ever calling IWebView::initWithFrame and tests that we don't
+ crash or leak.
+
+2010-01-05 Adam Roben <aroben@apple.com>
+
+ Add more WebViewDestruction tests
+
+ Fixes <http://webkit.org/b/33216>.
+
+ Reviewed by Eric Seidel.
+
+ * WebKitAPITest/tests/WebViewDestruction.cpp:
+ (WebKitAPITest::NoInitWithFrame):
+ (WebKitAPITest::CloseThenDestroyViewWindow):
+ (WebKitAPITest::DestroyViewWindowThenClose):
+ (WebKitAPITest::DestroyHostWindow):
+ (WebKitAPITest::DestroyHostWindowThenClose):
+ (WebKitAPITest::CloseThenDestroyHostWindow):
+ Added these tests that exercise tearing down a WebView in various
+ ways, all of which we eventually want to have work. Some of them
+ currently crash or leak.
+
+2010-01-05 Robert Hogan <robert@roberthogan.net>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] fix DRT link failures on --no-svg builds when only making changes to DRT
+
+ If you're working from a --minimal or --no-svg build and make changes to the
+ DRT, then recompile, the build will fail.
+
+ This is because the current behavior at build time is to assume that the
+ previous Qt build supported SVG and consequently delete libQtWebKit.so.
+ Unfortunately, just deleting libQtWebKit.so will not cause the library to
+ re-link. Instead the build will see libQtWebKit.so.4 and co., pass over the
+ linking phase, and attempt to link the DRT with libQtWebKit.so absent. This
+ results in a link failure on the DRT.
+
+ Since re-linking libQtWebKit can take up to ten minutes and should be avoided
+ in cases where not actually required, remove the assumption that
+ the previous Qt build supported SVG, and amend the symbol detection to look for
+ a symbol name that is not present in SVG builds. Currently webkitdirs.pm looks
+ for 'SVGElement' but even non-SVG builds contain the symbol 'isSVGElement'.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32992
+
+ * Scripts/webkitdirs.pm:
+
+2010-01-05 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by David Kilzer.
+
+ Switched to generating list of Perl unit test files dynamically,
+ instead of explicitly.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33200
+
+ * Scripts/test-webkitperl:
+
+2010-01-05 Yael Aharon <yael.aharon@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Reimplement EventSender::leapForward
+ https://bugs.webkit.org/show_bug.cgi?id=33114
+
+ Follow Windows implementation of leapForward. When leapForward is called,
+ messages are queued and posted after the timeout. A new event loop is created to
+ handle those messages and the additional messages that are created as a result.
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::EventSender):
+ (EventSender::mouseDown):
+ (EventSender::mouseUp):
+ (EventSender::mouseMoveTo):
+ (EventSender::leapForward):
+ (EventSender::sendOrQueueEvent):
+ (EventSender::replaySavedEvents):
+ (EventSender::eventFilter):
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2010-01-05 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Fix obscure queue crash in queueengine
+ https://bugs.webkit.org/show_bug.cgi?id=33196
+
+ Sometimes we get an exception that can't be stringified. For example:
+
+ AttributeError: 'ParseError' object has no attribute 'msg'
+
+ In these cases, the whole queue dies because we're in the global
+ exception handler. Instead of dieing here, we should just print a less
+ informative message to the console. We're already printing the whole
+ backtrace anyway, so there's not much point to stringifying the
+ exception anyway.
+
+ * Scripts/webkitpy/queueengine.py:
+
+2010-01-05 Dominic Mazzoni <dmazzoni@google.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32571
+
+ For an object with an aria role of "checkbox" or "radiobutton",
+ use the "aria-checked" attribute to determine if it's checked.
+ These changes add an isChecked() method to AccessibilityUIElement
+ so that we can check for this property from a layout test.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getIsCheckedCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::isChecked):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::isChecked):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::isChecked):
+
+2010-01-05 David Levin <levin@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Having a comment for the #endif for a header guard is not required WebKit style.
+ https://bugs.webkit.org/show_bug.cgi?id=33214
+
+ * Scripts/webkitpy/cpp_style.py: removed the check and made the loop exit
+ early when it has all the needed information to continue.
+ * Scripts/webkitpy/cpp_style_unittest.py: removed the corresponding tests.
+
+2010-01-05 Adam Roben <aroben@apple.com>
+
+ Share more code in the WebViewDestruction tests
+
+ Part of <http://webkit.org/b/33212> Small fixes/improvements to
+ WebKitAPITest
+
+ Reviewed by Sam Weinig.
+
+ * WebKitAPITest/tests/WebViewDestruction.cpp:
+ (WebKitAPITest::createAndInitializeWebView): Renamed from
+ createWebView. Now initializes the HostWindow and returns the
+ WebView's HWND via an out-parameter.
+ (WebKitAPITest::finishWebViewDestructionTest): Added. Code came from
+ the CloseWithoutDestroyWindow test.
+ (WebKitAPITest::CloseWithoutDestroyViewWindow): Renamed from
+ CloseWithoutDestroyWindow and changed to use the new functions.
+ (WebKitAPITest::MainFrameAfterClose): Changed to use the new
+ functions.
+ (WebKitAPITest::NoCloseOrDestroyViewWindow): Renamed from
+ NoCloseOrDestroyWindow and changed to use the new functions.
+
+2010-01-05 Adam Roben <aroben@apple.com>
+
+ Don't show HostWindows by default
+
+ This was making WebKitAPITest very flashy as windows appeared and
+ disappeared.
+
+ Part of <http://webkit.org/b/33212> Small fixes/improvements to
+ WebKitAPITest
+
+ Reviewed by Sam Weinig.
+
+ * WebKitAPITest/HostWindow.cpp:
+ (WebKitAPITest::HostWindow::initialize): Removed the WS_VISIBLE style
+ from the window.
+
+2010-01-05 Adam Roben <aroben@apple.com>
+
+ Don't hang in WebKitAPITest if no messages have been posted
+
+ Part of <http://webkit.org/b/33212> Small fixes/improvements to
+ WebKitAPITest
+
+ Reviewed by Sam Weinig.
+
+ * WebKitAPITest/tests/WebViewDestruction.cpp:
+ (WebKitAPITest::runMessagePump): Use PeekMessage instead of GetMessage
+ to avoid hanging if no messages have been posted.
+
+2010-01-05 Adam Roben <aroben@apple.com>
+
+ Fix WebKitCreateInstance helper
+
+ Part of <http://webkit.org/b/33212> Small fixes/improvements to
+ WebKitAPITest
+
+ Reviewed by Sam Weinig.
+
+ * WebKitAPITest/tests/WebViewDestruction.cpp:
+ (WebKitAPITest::WebKitCreateInstance): Pass the pointer straight
+ through, instead of taking its address.
+
+2010-01-04 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Darin Fisher.
+
+ Reorganize, document and rename OS() platform macros.
+ https://bugs.webkit.org/show_bug.cgi?id=33198
+
+ Adapt to name changes.
+
+ * DumpRenderTree/DumpRenderTree.h:
+ * DumpRenderTree/config.h:
+
+2010-01-05 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by Eric Seidel.
+
+ Minor improvements to test-webkit-scripts, as suggested
+ by an earlier review.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33125
+
+ * Scripts/test-webkit-scripts:
+ - Used OptionParser class instead of getopt.getopt().
+ - Created main() method for __main__ block.
+ - Enclosed functions in a class.
+
+2010-01-05 Chris Fleizach <cfleizach@apple.com>
+
+ No review. Fix DRT breakage on Tiger/Leopard.
+
+ Add ARIA "Live Region" support
+ https://bugs.webkit.org/show_bug.cgi?id=33117
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+
+2010-01-04 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Add ARIA "Live Region" support
+ https://bugs.webkit.org/show_bug.cgi?id=33117
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (indexOfChildCallback):
+ (boolAttributeValueCallback):
+ (stringAttributeValueCallback):
+ (addNotificationListenerCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::indexOfChild):
+ (AccessibilityUIElement::stringAttributeValue):
+ (AccessibilityUIElement::boolAttributeValue):
+ (AccessibilityUIElement::addNotificationListener):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::indexOfChild):
+ (AccessibilityUIElement::stringAttributeValue):
+ (AccessibilityUIElement::boolAttributeValue):
+ (_accessibilityNotificationCallback):
+ (AccessibilityUIElement::addNotificationListener):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::indexOfChild):
+ (AccessibilityUIElement::stringAttributeValue):
+ (AccessibilityUIElement::boolAttributeValue):
+ (AccessibilityUIElement::addNotificationListener):
+
+2010-01-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool rollout should require a reason
+ https://bugs.webkit.org/show_bug.cgi?id=30810
+
+ * Scripts/webkitpy/changelogs.py: Add support for a reason, add auto-wrapping logic.
+ * Scripts/webkitpy/changelogs_unittest.py: Test reason support.
+ * Scripts/webkitpy/commands/download.py: rollout now requires a reason, remove unused BUGID argument
+ * Scripts/webkitpy/commands/download_unittest.py: pass required reason
+ * Scripts/webkitpy/steps/preparechangelogforrevert.py: pass reason to update_for_revert
+
+2010-01-04 Jon Honeycutt <jhoneycutt@apple.com>
+
+ MSAA: <select> elements should broadcast value change events
+
+ https://bugs.webkit.org/show_bug.cgi?id=33088
+
+ <rdar://problem/7332364>
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (logValueChangeEventsCallback):
+ Start logging value change events.
+ (AccessibilityController::getJSClass):
+ Add a "logValueChangeEvents" to the AccessibilityController's JS class
+ definition.
+ (AccessibilityController::resetToConsistentState):
+ Disable logging of value change events.
+
+ * DumpRenderTree/AccessibilityController.h:
+ Declare setLogValueChangeEvents(), and add a member variable for the
+ value change event hook.
+
+ * DumpRenderTree/gtk/AccessibilityControllerGtk.cpp:
+ (AccessibilityController::setLogValueChangeEvents):
+ Stubbed.
+
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::setLogValueChangeEvents):
+ Stubbed.
+
+ * DumpRenderTree/win/AccessibilityControllerWin.cpp:
+ (AccessibilityController::AccessibilityController):
+ Initialize new member var.
+ (AccessibilityController::~AccessibilityController):
+ Disable logging of value change events.
+ (logEventProc):
+ When we receive an EVENT_OBJECT_VALUECHANGE, log the name of the object
+ and its value.
+ (AccessibilityController::setLogValueChangeEvents):
+ If disabling logging, unhook the event, and clear the event hook
+ member var. Otherwise, query for the root element to enable
+ accessibility, and hook EVENT_OBJECT_VALUECHANGE.
+
+2010-01-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ long_help for submit-patch
+ https://bugs.webkit.org/show_bug.cgi?id=33184
+
+ * Scripts/webkitpy/commands/upload.py:
+
+2010-01-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ commit-queue can wrongly reject patches if the buildbots are behind
+ https://bugs.webkit.org/show_bug.cgi?id=30098
+
+ Check to make sure we can currently build and test before trying to
+ land a patch.
+
+ * Scripts/webkitpy/commands/queues.py:
+
+2010-01-04 Adam Roben <aroben@apple.com>
+
+ Add a test harness for the Windows WebKit API, and a few tests
+
+ We currently only have tests for a handful of bugs regarding WebView
+ destruction, but more tests can easily be added later. Eventually
+ we'll run these tests as part of run-webkit-tests.
+
+ Fixes <http://webkit.org/b/33167>.
+
+ Reviewed by Sam Weinig.
+
+ * WebKitAPITest/HostWindow.cpp: Added.
+ (WebKitAPITest::HostWindow::HostWindow): Initialize m_window.
+ (WebKitAPITest::HostWindow::~HostWindow): Destroy our window if
+ needed.
+ (WebKitAPITest::HostWindow::initialize): Create our window.
+ (WebKitAPITest::HostWindow::clientRect): Return our window's client
+ rect.
+ (WebKitAPITest::HostWindow::registerWindowClass): Does what it says.
+ (WebKitAPITest::HostWindow::wndProc): Just call through to
+ DefWindowProcW.
+
+ * WebKitAPITest/HostWindow.h: Added.
+ (WebKitAPITest::HostWindow::window): Simple getter.
+
+ * WebKitAPITest/Test.h: Added. This file defines some macros useful
+ for writing tests.
+
+ * WebKitAPITest/TestsController.cpp: Added.
+ (WebKitAPITest::TestsController::TestsController): Initialize our
+ members.
+ (WebKitAPITest::TestsController::shared): Return the shared instance.
+ (WebKitAPITest::TestsController::runAllTests): Run a message pump
+ until a WM_QUIT message is received, then return whether all tests
+ succeeded.
+ (WebKitAPITest::TestsController::addTest): Add the test to m_tests and
+ start running tests soon.
+ (WebKitAPITest::TestsController::testFailed): Record the failure and
+ print a message about it to stdout.
+ (WebKitAPITest::TestsController::runNextTest): If we don't have any
+ tests to run, post a WM_QUIT message to stop the message pump.
+ Otherwise, run the test and print whether it passed, then schedule the
+ next test.
+ (WebKitAPITest::TestsController::runNextTestSoon): Set a 0-delay timer
+ to run the next test.
+ (WebKitAPITest::TestsController::registerWindowClass): Does what it
+ says.
+ (WebKitAPITest::TestsController::wndProc): If the runNextTestTimer
+ fired, call runNextTest(). Pass everything else through to
+ DefWindowProcW.
+
+ * WebKitAPITest/TestsController.h: Added.
+
+ * WebKitAPITest/WebKitAPITest.vcproj: Added.
+
+ * WebKitAPITest/WebKitAPITestCommon.vsprops: Added.
+
+ * WebKitAPITest/main.cpp: Added.
+ (main): (Mostly) just calls TestsController::runAllTests.
+
+ * WebKitAPITest/tests/WebViewDestruction.cpp: Added.
+ (WebKitAPITest::WebKitCreateInstance): Helper function template to
+ call through to the real WebKitCreateInstance.
+ (WebKitAPITest::webViewCount): Helper function to call through to
+ IWebKitStatistics::webViewCount.
+ (WebKitAPITest::createWebView): Helper function to create a WebView
+ and put it inside a HostWindow.
+ (WebKitAPITest::runMessagePump): Helper function to run a message pump
+ for a specified number of milliseconds, or until a WM_QUIT message is
+ received.
+ (WebKitAPITest::CloseWithoutDestroyWindow): Test for
+ <http://webkit.org/b/32827>.
+ (WebKitAPITest::MainFrameAfterClose): Test for
+ <http://webkit.org/b/32868>.
+ (WebKitAPITest::NoCloseOrDestroyWindow): Test for
+ <http://webkit.org/b/33162>.
+
+2010-01-04 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by David Kilzer.
+
+ Add support for Git's "diff.mnemonicprefix" config option to WebKitTools
+
+ https://bugs.webkit.org/show_bug.cgi?id=32820
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/svn-apply:
+ * Scripts/svn-unapply:
+ * Scripts/test-webkitperl: Run gitdiff2svndiff test
+ * Scripts/webkitperl/VCSUtils_unittest/gitdiff2svndiff.pl: Added.
+ * Scripts/webkitpy/diff_parser.py:
+ * Scripts/webkitpy/diff_parser_unittest.py:
+
+2010-01-04 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by David Kilzer.
+
+ Divided the Perl unit tests into separate files and put
+ them in a separate directory, and renamed test-webkit-perl
+ to test-webkitperl.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33124
+
+ * Scripts/VCSUtils.pm:
+ - Renamed generateRunPatchCommand() to generatePatchCommand().
+
+ * Scripts/VCSUtils_unittest.pl: Removed.
+ - Divided into three files in Scripts/webkitperl/VCSUtils_unittest.
+
+ * Scripts/test-webkit-perl: Removed.
+ - Renamed to test-webkitperl.
+
+ * Scripts/test-webkit-scripts:
+ - Updated paths to test-webkitpy and test-webkitperl.
+
+ * Scripts/test-webkitperl: Copied from Scripts/test-webkit-perl.
+ - Added paths to new test files.
+
+ * Scripts/webkitperl: Added.
+ * Scripts/webkitperl/VCSUtils_unittest: Added.
+ * Scripts/webkitperl/VCSUtils_unittest/fixChangeLogPatch.pl: Added.
+ * Scripts/webkitperl/VCSUtils_unittest/generatePatchCommand.pl: Added.
+ * Scripts/webkitperl/VCSUtils_unittest/runPatchCommand.pl: Copied from Scripts/VCSUtils_unittest.pl.
+
+2010-01-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make bugzilla-tool rollout include a bug link in the ChangeLog entry
+ https://bugs.webkit.org/show_bug.cgi?id=33146
+
+ One more step towards better rollouts.
+
+ * Scripts/webkitpy/changelogs.py:
+ * Scripts/webkitpy/changelogs_unittest.py:
+ * Scripts/webkitpy/steps/preparechangelogforrevert.py:
+
+2010-01-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Sort the step options
+ https://bugs.webkit.org/show_bug.cgi?id=33144
+
+ * Scripts/webkitpy/steps/options.py:
+
+2010-01-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Need support for longer text in per-command help
+ https://bugs.webkit.org/show_bug.cgi?id=33143
+
+ Add some minimal additional help to land-diff and
+ pave the way for adding better help to all commands.
+
+ * Scripts/webkitpy/commands/download.py: Add small amount of additional help to land-diff
+ * Scripts/webkitpy/multicommandtool.py: support long_help
+ * Scripts/webkitpy/multicommandtool_unittest.py: test long_help
+
+2010-01-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add unit test for MarkBugFixed
+ https://bugs.webkit.org/show_bug.cgi?id=33142
+
+ MarkBugFixed is way behind in command technology, but it still needs a
+ unit test, as the FIXME commands.
+
+ Also, remove mark-bug-fixed and create-bug from main help since we have
+ more modern commands to replace them.
+
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/commands/upload_unittest.py:
+ * Scripts/webkitpy/mock_bugzillatool.py:
+
+2010-01-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add missing unit test for CommitMessageForCurrentDiff
+ https://bugs.webkit.org/show_bug.cgi?id=33141
+
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/commands/upload_unittest.py:
+
+2010-01-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Remove raw_input from queues in favor of user.prompt
+ https://bugs.webkit.org/show_bug.cgi?id=33140
+
+ This lets up properly mock out the user interaction instead of hacking
+ around it with the options.
+
+ * Scripts/webkitpy/commands/queues.py:
+ * Scripts/webkitpy/commands/queuestest.py:
+
+2010-01-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool should not require users to install mechanize
+ https://bugs.webkit.org/show_bug.cgi?id=32635
+
+ * Scripts/webkitpy/__init__.py: Add missing declaration for ClientForm (which mechanize requires).
+
+2010-01-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool should not require users to install mechanize
+ https://bugs.webkit.org/show_bug.cgi?id=32635
+
+ Use the nifty "autoinstall" module from Daniel Krech:
+ http://pypi.python.org/pypi/autoinstall/0.2
+ http://code.google.com/p/pyautoinstall/
+ It's available under a WebKit-compatible BSD license.
+
+ * Scripts/webkitpy/__init__.py:
+ - bind "mechanize" to an autoinstall importer which will
+ auto-download mechanize if necessary.
+ * Scripts/webkitpy/autoinstall.py: Added.
+ * Scripts/webkitpy/bugzilla.py: use "mechanize" instead of webkit_mechanize
+ * Scripts/webkitpy/statusbot.py: ditto.
+ * Scripts/webkitpy/webkit_mechanize.py: Removed.
+
+2010-01-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Move AbstractSequencedCommand to a more general location
+ https://bugs.webkit.org/show_bug.cgi?id=33137
+
+ I do what the FIXME tell me to do.
+
+ * Scripts/webkitpy/commands/abstractsequencedcommand.py: Added.
+ * Scripts/webkitpy/commands/download.py:
+ * Scripts/webkitpy/commands/upload.py:
+
+2010-01-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Rename StatusBot to StatusServer
+ https://bugs.webkit.org/show_bug.cgi?id=33139
+
+ It's not a bot. It's a server.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/webkitpy/bugzilla.py:
+ * Scripts/webkitpy/commands/early_warning_system.py:
+ * Scripts/webkitpy/commands/queues.py:
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ * Scripts/webkitpy/queueengine.py:
+ * Scripts/webkitpy/statusbot.py: Removed.
+
+2010-01-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] submit-pach should have a -o/--open option to open the bug after submit
+ https://bugs.webkit.org/show_bug.cgi?id=33136
+
+ Python makes this very easy.
+
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ * Scripts/webkitpy/steps/options.py:
+ * Scripts/webkitpy/steps/postdiff.py:
+ * Scripts/webkitpy/user.py:
+
+2010-01-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Move steps to a submodule
+ https://bugs.webkit.org/show_bug.cgi?id=33135
+
+ For great victory. This will probably introduce some regressions
+ because our test coverage isn't perfect, but I've tried to be careful.
+
+ * Scripts/test-webkitpy:
+ * Scripts/webkitpy/buildsteps.py: Removed.
+ * Scripts/webkitpy/buildsteps_unittest.py: Removed.
+ * Scripts/webkitpy/commands/download.py:
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/steps/__init__.py: Added.
+ * Scripts/webkitpy/steps/abstractstep.py: Added.
+ * Scripts/webkitpy/steps/applypatch.py: Added.
+ * Scripts/webkitpy/steps/applypatchwithlocalcommit.py: Added.
+ * Scripts/webkitpy/steps/build.py: Added.
+ * Scripts/webkitpy/steps/checkstyle.py: Added.
+ * Scripts/webkitpy/steps/cleanworkingdirectory.py: Added.
+ * Scripts/webkitpy/steps/cleanworkingdirectorywithlocalcommits.py: Added.
+ * Scripts/webkitpy/steps/closebug.py: Added.
+ * Scripts/webkitpy/steps/closebugforlanddiff.py: Added.
+ * Scripts/webkitpy/steps/closepatch.py: Added.
+ * Scripts/webkitpy/steps/commit.py: Added.
+ * Scripts/webkitpy/steps/completerollout.py: Added.
+ * Scripts/webkitpy/steps/confirmdiff.py: Added.
+ * Scripts/webkitpy/steps/createbug.py: Added.
+ * Scripts/webkitpy/steps/editchangelog.py: Added.
+ * Scripts/webkitpy/steps/ensurebuildersaregreen.py: Added.
+ * Scripts/webkitpy/steps/ensurelocalcommitifneeded.py: Added.
+ * Scripts/webkitpy/steps/metastep.py: Added.
+ * Scripts/webkitpy/steps/obsoletepatches.py: Added.
+ * Scripts/webkitpy/steps/options.py: Added.
+ * Scripts/webkitpy/steps/postdiff.py: Added.
+ * Scripts/webkitpy/steps/preparechangelog.py: Added.
+ * Scripts/webkitpy/steps/preparechangelogforrevert.py: Added.
+ * Scripts/webkitpy/steps/promptforbugortitle.py: Added.
+ * Scripts/webkitpy/steps/revertrevision.py: Added.
+ * Scripts/webkitpy/steps/runtests.py: Added.
+ * Scripts/webkitpy/steps/steps_unittest.py: Added.
+ * Scripts/webkitpy/steps/update.py: Added.
+ * Scripts/webkitpy/steps/updatechangelogswithreview_unittests.py: Added.
+ * Scripts/webkitpy/steps/updatechangelogswithreviewer.py: Added.
+ * Scripts/webkitpy/stepsequence.py:
+
+2010-01-04 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33097
+
+ Cleans up the File menu to better conform to the File menu in Safari
+ both in terms of options and keyboard shortcuts. Adds a "Quit" menu
+ options to close all open windows. Also, renames the Tools menu to
+ Develop.
+
+ * QtLauncher/main.cpp:
+ (MainWindow::setupUI):
+
+2010-01-04 Daniel Bates <dbates@webkit.org>
+
+ https://bugs.webkit.org/show_bug.cgi?id=33039
+
+ Unreviewed fix.
+
+ * Scripts/webkitpy/credentials.py:
+ * Scripts/webkitpy/credentials_unittest.py:
+
+2010-01-04 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33039
+
+ [bzt] Second attempt to fix an issue where bugzilla-tool dies
+ when the keychain lookup fails to find an entry for bugs.webkit.org.
+
+ * Scripts/webkitpy/credentials.py:
+ * Scripts/webkitpy/credentials_unittest.py:
+
+2010-01-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make Rollout an AbstractSequencedCommmand
+ https://bugs.webkit.org/show_bug.cgi?id=33133
+
+ As suggested by Adam in:
+ https://bugs.webkit.org/show_bug.cgi?id=33131#c2
+
+ * Scripts/webkitpy/commands/download.py:
+
+2010-01-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Make all commands AbstractDeclarativeCommmands instead of direct Command subclasses
+ https://bugs.webkit.org/show_bug.cgi?id=33131
+
+ Evenetually we'll probably roll AbstractDeclarativeCommmand directly into Command
+ but for now we just deploy it everywhere and don't try to fix up the few valid uses
+ of Command.
+
+ * Scripts/webkitpy/commands/download.py:
+ * Scripts/webkitpy/commands/queries.py:
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/multicommandtool.py:
+
+2010-01-03 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix. Need to import ScriptError.
+
+ * Scripts/webkitpy/buildsteps.py:
+
+2010-01-03 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Make it easier to run submit-patch when previous run cancelled
+ https://bugs.webkit.org/show_bug.cgi?id=33070
+
+ This patch renames create-review to submit-patch (as requested by
+ Maciej).
+
+ This patch makes it easier to run submit-patch after the user has
+ already cancelled a previous run of submit-patch by detecting when we
+ already have ChangeLogs and reading the bug number from them (and not
+ attempting to recreate them). Aside from performance and the extra
+ edit step, this command should not subsume post-dif.
+
+ Also, added a --email command line argument so that the output of
+ prepare-ChangeLog makes sense when it can't find the user's email
+ address.
+
+ * Scripts/webkitpy/bugzilla.py:
+ * Scripts/webkitpy/buildsteps.py:
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/commands/upload_unittest.py:
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ * Scripts/webkitpy/user.py:
+
+2010-01-03 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Rename Scripts/modules to Scripts/webkitpy
+ https://bugs.webkit.org/show_bug.cgi?id=33128
+
+ Just search-replace and svn mv commands.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/check-webkit-style:
+ * Scripts/modules: Removed.
+ * Scripts/modules/BeautifulSoup.py: Removed.
+ * Scripts/modules/__init__.py: Removed.
+ * Scripts/modules/bugzilla.py: Removed.
+ * Scripts/modules/bugzilla_unittest.py: Removed.
+ * Scripts/modules/buildbot.py: Removed.
+ * Scripts/modules/buildbot_unittest.py: Removed.
+ * Scripts/modules/buildsteps.py: Removed.
+ * Scripts/modules/buildsteps_unittest.py: Removed.
+ * Scripts/modules/changelogs.py: Removed.
+ * Scripts/modules/changelogs_unittest.py: Removed.
+ * Scripts/modules/commands: Removed.
+ * Scripts/modules/commands/__init__.py: Removed.
+ * Scripts/modules/commands/commandtest.py: Removed.
+ * Scripts/modules/commands/download.py: Removed.
+ * Scripts/modules/commands/download_unittest.py: Removed.
+ * Scripts/modules/commands/early_warning_system.py: Removed.
+ * Scripts/modules/commands/early_warning_system_unittest.py: Removed.
+ * Scripts/modules/commands/queries.py: Removed.
+ * Scripts/modules/commands/queries_unittest.py: Removed.
+ * Scripts/modules/commands/queues.py: Removed.
+ * Scripts/modules/commands/queues_unittest.py: Removed.
+ * Scripts/modules/commands/queuestest.py: Removed.
+ * Scripts/modules/commands/upload.py: Removed.
+ * Scripts/modules/commands/upload_unittest.py: Removed.
+ * Scripts/modules/comments.py: Removed.
+ * Scripts/modules/committers.py: Removed.
+ * Scripts/modules/committers_unittest.py: Removed.
+ * Scripts/modules/cpp_style.py: Removed.
+ * Scripts/modules/cpp_style_unittest.py: Removed.
+ * Scripts/modules/credentials.py: Removed.
+ * Scripts/modules/credentials_unittest.py: Removed.
+ * Scripts/modules/diff_parser.py: Removed.
+ * Scripts/modules/diff_parser_unittest.py: Removed.
+ * Scripts/modules/executive.py: Removed.
+ * Scripts/modules/executive_unittest.py: Removed.
+ * Scripts/modules/grammar.py: Removed.
+ * Scripts/modules/mock.py: Removed.
+ * Scripts/modules/mock_bugzillatool.py: Removed.
+ * Scripts/modules/multicommandtool.py: Removed.
+ * Scripts/modules/multicommandtool_unittest.py: Removed.
+ * Scripts/modules/outputcapture.py: Removed.
+ * Scripts/modules/patchcollection.py: Removed.
+ * Scripts/modules/queueengine.py: Removed.
+ * Scripts/modules/queueengine_unittest.py: Removed.
+ * Scripts/modules/scm.py: Removed.
+ * Scripts/modules/scm_unittest.py: Removed.
+ * Scripts/modules/statusbot.py: Removed.
+ * Scripts/modules/stepsequence.py: Removed.
+ * Scripts/modules/style: Removed.
+ * Scripts/modules/style.py: Removed.
+ * Scripts/modules/style_unittest.py: Removed.
+ * Scripts/modules/text_style.py: Removed.
+ * Scripts/modules/text_style_unittest.py: Removed.
+ * Scripts/modules/user.py: Removed.
+ * Scripts/modules/webkit_logging.py: Removed.
+ * Scripts/modules/webkit_logging_unittest.py: Removed.
+ * Scripts/modules/webkit_mechanize.py: Removed.
+ * Scripts/modules/webkitport.py: Removed.
+ * Scripts/modules/webkitport_unittest.py: Removed.
+ * Scripts/test-webkit-python: Removed.
+ * Scripts/test-webkitpy: Copied from WebKitTools/Scripts/test-webkit-python.
+ * Scripts/validate-committer-lists:
+ * Scripts/webkitpy: Copied from WebKitTools/Scripts/modules.
+ * Scripts/webkitpy/bugzilla.py:
+ * Scripts/webkitpy/bugzilla_unittest.py:
+ * Scripts/webkitpy/buildbot.py:
+ * Scripts/webkitpy/buildbot_unittest.py:
+ * Scripts/webkitpy/buildsteps.py:
+ * Scripts/webkitpy/buildsteps_unittest.py:
+ * Scripts/webkitpy/commands/commandtest.py:
+ * Scripts/webkitpy/commands/download.py:
+ * Scripts/webkitpy/commands/download_unittest.py:
+ * Scripts/webkitpy/commands/early_warning_system.py:
+ * Scripts/webkitpy/commands/early_warning_system_unittest.py:
+ * Scripts/webkitpy/commands/queries.py:
+ * Scripts/webkitpy/commands/queries_unittest.py:
+ * Scripts/webkitpy/commands/queues.py:
+ * Scripts/webkitpy/commands/queues_unittest.py:
+ * Scripts/webkitpy/commands/queuestest.py:
+ * Scripts/webkitpy/commands/upload.py:
+ * Scripts/webkitpy/commands/upload_unittest.py:
+ * Scripts/webkitpy/comments.py:
+ * Scripts/webkitpy/credentials.py:
+ * Scripts/webkitpy/credentials_unittest.py:
+ * Scripts/webkitpy/executive.py:
+ * Scripts/webkitpy/executive_unittest.py:
+ * Scripts/webkitpy/mock_bugzillatool.py:
+ * Scripts/webkitpy/multicommandtool.py:
+ * Scripts/webkitpy/multicommandtool_unittest.py:
+ * Scripts/webkitpy/queueengine.py:
+ * Scripts/webkitpy/queueengine_unittest.py:
+ * Scripts/webkitpy/scm.py:
+ * Scripts/webkitpy/scm_unittest.py:
+ * Scripts/webkitpy/statusbot.py:
+ * Scripts/webkitpy/stepsequence.py:
+ * Scripts/webkitpy/webkit_logging_unittest.py:
+ * Scripts/webkitpy/webkitport_unittest.py:
+
+2010-01-03 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by Eric Seidel.
+
+ Added script to test both Perl and Python, and renamed
+ run-webkit-unittests to test-webkit-python.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33045
+
+ * Scripts/VCSUtils_unittest.pl:
+ - Tweaked so it can be run from outside Scripts directory.
+
+ * Scripts/run-webkit-unittests: Removed.
+ - Renamed to test-webkit-python.
+
+ * Scripts/test-webkit-perl:
+ - Tweaked so it can be run from outside Scripts directory.
+
+ * Scripts/test-webkit-python: Copied from Scripts/run-webkit-unittests.
+
+ * Scripts/test-webkit-scripts: Added.
+ - Runs both test-webkit-perl and test-webkit-python.
+
+2010-01-03 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ commit-queue/bugzilla-tool should build both Debug and Release
+ https://bugs.webkit.org/show_bug.cgi?id=28450
+
+ Add a --build-style command that lets the master process tell the child
+ process to build both debug and release. Eventually we want to teach
+ the test step to understand this option too, but that's a patch for
+ another day.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/webkitport.py:
+ * Scripts/modules/webkitport_unittest.py:
+
+2010-01-03 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] EventSender: add support for Enter key events
+ https://bugs.webkit.org/show_bug.cgi?id=33064
+
+ Unskip 5 tests that are fixed now.
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::keyDown):
+
+2010-01-03 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Add test for previous typo fix
+ https://bugs.webkit.org/show_bug.cgi?id=33083
+
+ A trivial test for a trivial fix, as requested by Eric.
+
+ * Scripts/modules/bugzilla_unittest.py:
+
+2010-01-03 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Implement mac-ews
+ https://bugs.webkit.org/show_bug.cgi?id=33072
+
+ The mac-ews is slightly different than the other early warning systems
+ because we can't run Mac OS X inside a VM. For that reason, we only
+ process patches that were uploaded by committers. This isn't as much
+ coverage as the other EWS bots, but it's better than nothing.
+
+ * Scripts/modules/commands/early_warning_system.py:
+ * Scripts/modules/commands/early_warning_system_unittest.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/commands/queuestest.py:
+ * Scripts/modules/mock_bugzillatool.py:
+
+2010-01-03 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by David Kilzer.
+
+ Refactored svn-apply and svn-unapply to use a common "patch"
+ command method, and added unit tests for this new method.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33098
+
+ * Scripts/VCSUtils.pm:
+ - Added generateRunPatchCommand().
+ - Added runPatchCommand().
+ - Added exitStatus() from webkitdirs.pm to address FIXME.
+
+ * Scripts/VCSUtils_unittest.pl:
+ - Added 10 unit tests for generateRunPatchCommand().
+ - Added 4 unit tests for runPatchCommand().
+ - Added callSilently() method.
+
+ * Scripts/svn-apply:
+ - Refactored applyPatch().
+ - Removed $pathScriptWasRunFrom global variable.
+ - Addressed issue where "--force" option was getting added twice.
+
+ * Scripts/svn-unapply:
+ - Refactored applyPatch().
+ - Removed $pathScriptWasRunFrom global variable.
+ - Added support for --force option.
+ - Enhanced to return meaningful exit status.
+
+ * Scripts/webkitdirs.pm:
+ - Moved exitStatus() implementation to VCSUtils.pm.
+
+2009-12-31 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Implement build-and-test
+ https://bugs.webkit.org/show_bug.cgi?id=33073
+
+ Some of the early warning system bots want to use build-and-test so
+ they can cover LayoutTests in addition to just compilation.
+
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/download_unittest.py:
+
+2009-12-31 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Show mac-ews status on QueueStatusServer
+ https://bugs.webkit.org/show_bug.cgi?id=33076
+
+ Also make error status purple.
+
+ * QueueStatusServer/model/attachment.py:
+ * QueueStatusServer/model/queues.py:
+ * QueueStatusServer/templates/dashboard.html:
+ * QueueStatusServer/templates/statusbubble.html:
+
+2009-12-31 Adam Barth <abarth@webkit.org>
+
+ Unreviewed.
+
+ [bzt] REGRESSION: Bugzila is a typo
+ https://bugs.webkit.org/show_bug.cgi?id=33074
+
+ Eric should test his code before landing! :)
+
+ * Scripts/modules/bugzilla.py:
+
+2009-12-31 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Fix the unit tests!
+
+ * Scripts/run-webkit-unittests:
+
+2009-12-30 Kevin Watters <kevinwatters@gmail.com>
+
+ Reviewed by Kevin Ollivier.
+
+ [wx] Alter a couple of default settings in the test app.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32956
+
+ * wx/browser/browser.cpp:
+ (MyApp::OnInit):
+
+2009-12-30 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ logging.py should be renamed to webkit_logging.py and eventually die
+ https://bugs.webkit.org/show_bug.cgi?id=33058
+
+ Change all imports of "logging" to webkit_logging,
+ except the ones which came from Google's cpp_lint.py and diff_parser.py
+ which clearly are assuming python's logging.py.
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/buildbot.py:
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/queries.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/commands/upload.py:
+ * Scripts/modules/credentials.py:
+ * Scripts/modules/executive.py:
+ * Scripts/modules/multicommandtool.py:
+ * Scripts/modules/queueengine.py:
+ * Scripts/modules/scm.py:
+ * Scripts/modules/statusbot.py:
+ * Scripts/modules/stepsequence.py:
+ * Scripts/modules/webkit_logging.py: Renamed from WebKitTools/Scripts/modules/logging.py.
+ * Scripts/modules/webkit_logging_unittest.py: Renamed from WebKitTools/Scripts/modules/logging_unittest.py.
+
+2009-12-30 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] layoutTestController.pathToLocalResource() should return a path, not an URL
+ https://bugs.webkit.org/show_bug.cgi?id=33051
+
+ Moreover, its primary function is to normalize the path in regard of platform
+ specific directory separators. Therefore, it can simply make use of the
+ QDir::toNativeSeparators function.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::pathToLocalResource):
+
+2009-12-30 David D. Kilzer <ddkilzer@webkit.org>
+
+ Fix executable bits for r52646
+
+ * Scripts/VCSUtils_unittest.pl: Added property svn:executable.
+ * Scripts/test-webkit-perl: Ditto.
+
+2009-12-29 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by David Kilzer.
+
+ Fixed a bug in fixChangeLogPatch, made it work correctly in
+ more circumstances, and added unit tests.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32919
+
+ * Scripts/VCSUtils.pm:
+ Rewrote fixChangeLogPatch.
+
+ * Scripts/VCSUtils_unittest.pl: Added.
+ Added 7 unit tests for fixChangeLogPatch.
+
+ * Scripts/test-webkit-perl: Added.
+ Added test harness for unit tests of Perl code.
+
+2009-12-29 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Split out BugzillaQueries class from Bugzilla
+ https://bugs.webkit.org/show_bug.cgi?id=33042
+
+ * Scripts/modules/bugzilla.py:
+ - Split out BugzillaQueries from Bugzilla.
+ - Try to isolate self.bugzilla usage into helper functions whenever possible.
+ - Add a bunch of FIXMEs.
+ - Rename fetch_bug_ids_from_needs_commit_list to fetch_bug_ids_from_pending_commit_list
+ * Scripts/modules/bugzilla_unittest.py:
+ - Create a new BugzillaQueriesTest testcase and move logic there.
+ * Scripts/modules/buildsteps_unittest.py:
+ - Use Bug 75 instead of 1 since bug 1 doesn't actually exist.
+ * Scripts/modules/commands/queries.py:
+ - Update to use bugzilla.queries
+ * Scripts/modules/commands/queues.py:
+ - Ditto.
+ * Scripts/modules/commands/upload.py:
+ - Ditto.
+ * Scripts/modules/mock_bugzillatool.py:
+ - Add a MockBugzillaQueries.
+ - Make patches and bugs global privates.
+ - Let _id_to_object_dictionary take a variable argument list instead of an array.
+
+2009-12-29 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33041
+
+ Speed up the test method test_read_credentials_with_SVN by not actually
+ creating an SVN repository to test against (by default). Instead, it is
+ sufficient to create a temporary directory that does not contain a Git
+ repository.
+
+ Also, renamed method test_read_credentials_with_SVN to
+ test_read_credentials_without_git_repo, to better reflect what it is
+ testing.
+
+ * Scripts/modules/credentials_unittest.py:
+
+2009-12-29 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ https://bugs.webkit.org/show_bug.cgi?id=33039
+
+ [bzt] Fixes an issue where bugzilla-tool dies when the keychain lookup
+ fails to find an entry for bugs.webkit.org.
+
+ Under Mac OS X, bugzilla-tool tries to query the keychain and Security
+ framework (via /usr/sbin/security) for an internet-password entry for
+ bugs.webkit.org so that it can use it to login to bugs.webkit.org.
+ However, if no such entry exists then bugzilla-tool dies with an error.
+
+ * Scripts/modules/credentials.py: Modified method _parse_security_tool_output to return
+ [None, None] if /usr/sbin/security cannot find keychain entry for bugs.webkit.org.
+ * Scripts/modules/credentials_unittest.py: Added method test_security_output_parse_entry_not_found.
+
+2009-12-29 Eric Seidel <eric@webkit.org>
+
+ Rubber-stamped by Adam Barth.
+
+ Remove unused BugzillaException.
+
+ * Scripts/modules/bugzilla.py:
+
+2009-12-29 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Need a script to assign bugs with r+ patches to committers for landing
+ https://bugs.webkit.org/show_bug.cgi?id=33009
+
+ This is just one more small tool to help in the fight against our
+ ever-growing list of to-be-committed patches.
+
+ * Scripts/modules/bugzilla.py:
+ - Rename assign_to_email to assigned_to_email (typo).
+ - Add assigned_to_email() method on Bug.
+ - Add reassign_bug method.
+ - Add Bugzilla.unassigned_email, eventually should move to some webkit_config.py module.
+ * Scripts/modules/bugzilla_unittest.py:
+ - Update test after assigned_to_email rename.
+ * Scripts/modules/commands/commandtest.py:
+ - Call bind_to_tool to that self.tool works in Command testing.
+ * Scripts/modules/commands/download.py:
+ - Move AbstractDeclarativeCommmand multicommandtool.py, it should be part of Command.
+ * Scripts/modules/commands/queries_unittest.py:
+ - One of the test patches is now posted by "eric@webkit.org" which is a committer.
+ - Eventually we'll mock out CommitterList and be able to better control what's a committer and what's not.
+ * Scripts/modules/commands/upload.py:
+ - Add new assign-to-committer command.
+ * Scripts/modules/commands/upload_unittest.py:
+ - Add basic assign-to-committer test.
+ * Scripts/modules/committers.py:
+ - Add bugzilla_email() accessor.
+ * Scripts/modules/committers_unittest.py:
+ - Test our assumption that bugzilla_email is the first email.
+ * Scripts/modules/mock_bugzillatool.py:
+ - Add _id_to_object_dictionary for generating bug_cache from list of bugs.
+ - Remove unused fetch_attachments_from_bug.
+ - Add fetch_bug support and a bug_cache.
+ * Scripts/modules/multicommandtool.py:
+ - Move AbstractDeclarativeCommmand here from download.py
+
+2009-12-29 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Don't crash if user types a number during PromptForBugOrTitleStep
+ https://bugs.webkit.org/show_bug.cgi?id=33038
+
+ Simple fix with test.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/buildsteps_unittest.py:
+
+2009-12-29 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] post-diff requires reading to the end
+ https://bugs.webkit.org/show_bug.cgi?id=33036
+
+ Catch the IOError caused by not reading to the end of the diff. We
+ don't have a good way to test this currently.
+
+ * Scripts/modules/user.py:
+
+2009-12-29 Chang Shu <Chang.Shu@nokia.com>
+
+ Reviewed by Adam Barth.
+
+ [Qt] Move logic that handles Qt headers before primary headers
+ so that Qt headers won't be treated as primary headers by mistake.
+ https://bugs.webkit.org/show_bug.cgi?id=32991
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-12-29 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add the start of a Bug object for bugzilla.py
+ https://bugs.webkit.org/show_bug.cgi?id=32995
+
+ This allowed us to get rid of some duplicated "is_obsolete" checks.
+
+ * Scripts/modules/bugzilla.py:
+ - Add a new Bug class, and move patches/unreviewed_patches filtering logic there.
+ - Add _fetch_bug_page for possible future mocking.
+ (I did not try to test fetch_*_from_bug now due to difficulties with our current validate_reviewer logic.)
+ - Rename fetch_bug to fetch_bug_dictionary and add a new fetch_bug which returns a Bug object.
+ - Use fetch_bug and attachments(), patches(), etc. instead of custom fetch_*_from_bug methods.
+ - Reduce code in fetch_patches_from_pending_commit_list and fetch_patches_from_review_queue
+ using list comprehensions. Use a sum(list, []) trick to flatten a list of lists into a single list.
+ * Scripts/modules/bugzilla_unittest.py:
+ - Remove an unneeded unicode string marker.
+ * Scripts/modules/buildsteps.py:
+ - define __all__ to include just the BuildSteps
+ * Scripts/modules/commands/download.py:
+ - import * now that we have an __all__ defined.
+ * Scripts/modules/commands/upload.py:
+ - Use fetch_bug_dictionary instead of fetch_bug.
+
+2009-12-29 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32925
+
+ Adds an Open File dialog to make it convenient to open a file
+ to view in the browser.
+
+ Currently a person must either specify the path to a file as a
+ command-line argument or type a file URL. Instead, we should
+ have a file dialog to allow a person to open a file without
+ memorizing its path.
+
+ * QtLauncher/main.cpp:
+ (MainWindow::MainWindow): Changed urlEdit->setText(qurl.toEncoded())
+ to urlEdit->setText(qurl.toString()).
+ (MainWindow::openFile): Added.
+ (MainWindow::changeLocation): Moved code to load URL into method
+ MainWindow::loadURL.
+ (MainWindow::loadURL): Added.
+ (MainWindow::setupUI): Added menu item Open File.
+
+2009-12-29 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Holger Freyther.
+
+ [GTK] fails fast/harness/use-page-cache.html
+ https://bugs.webkit.org/show_bug.cgi?id=33013
+
+ Make sure settings are forwarded to child WebViews.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (createWebView):
+
+2009-12-29 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32778
+
+ Changes $diffPercentage to be a number to resolve Perl
+ warning about comparing a string to a number.
+
+ * Scripts/run-webkit-tests:
+
+2009-12-29 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] DRT: Frame loader callbacks differ from the Mac port
+ https://bugs.webkit.org/show_bug.cgi?id=32989
+
+ Remove messages from the callbacks that should not dump them to match
+ the expected results for the http/loading tests.
+
+ Unskip some http/loading tests which succeed now.
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::dump):
+
+2009-12-29 Robert Hogan <robert@roberthogan.net>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] fix fast/dom/Window/window-onFocus.html
+
+ Add support for layouttestcontroller.windowIsKey to Qt DRT and fix issue where
+ window.onblur was getting dispatched twice from QtWebKit.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32990
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::switchFocus):
+ * DumpRenderTree/qt/DumpRenderTreeQt.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setWindowIsKey):
+ (LayoutTestController::setMainFrameIsFirstResponder):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2009-12-28 Kinuko Yasuda <kinuko@chromium.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Extended EventSender.keyDown method to take another (3rd) argument
+ for indicating the keyLocation to make numeric pad key events testable.
+ Expected values for the argument is one of the KeyLocationCode
+ specified in DOM Level 3
+ (http://www.w3.org/TR/DOM-Level-3-Events/#events-keyboardevents).
+ https://bugs.webkit.org/show_bug.cgi?id=28247
+
+ Test: fast/events/keydown-numpad-keys.html
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (+[EventSendingController isSelectorExcludedFromWebScript:]):
+ (+[EventSendingController webScriptNameForSelector:]):
+ (-[EventSendingController keyDown:withModifiers:withLocation:]):
+
+2009-12-28 Ariya Hidayat <ariya.hidayat@gmail.com>
+
+ Unreviewed, update my email address.
+
+ * Scripts/modules/committers.py:
+
+2009-12-28 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Adam Barth.
+
+ [Qt] Fix build break for Qt 4.4
+ https://bugs.webkit.org/show_bug.cgi?id=30327
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp: Include QLocale
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp: Ditto.
+ * QtLauncher/main.cpp:
+ (MainWindow::MainWindow): Qt::WA_TranslucentBackground was
+ introduced in Qt version 4.5
+
+2009-12-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Add an edit-changelog command
+ https://bugs.webkit.org/show_bug.cgi?id=32986
+
+ This command makes it easier to edit ChangeLogs. It's similar to
+ prepare-ChangeLog -o, except it works with already existing ChangeLogs.
+
+ * Scripts/modules/commands/upload.py:
+ * Scripts/modules/commands/upload_unittest.py:
+
+2009-12-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Create an ASAD command for uploading a patch
+ https://bugs.webkit.org/show_bug.cgi?id=32979
+
+ The create-review command goes through the whole process of preparing a
+ code review, including creating a bug, editing the ChangeLogs, and
+ uploading the patch. It is indeed the All Sing, All Dance upload
+ command.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/upload.py:
+ * Scripts/modules/commands/upload_unittest.py:
+ * Scripts/modules/mock_bugzillatool.py:
+ * Scripts/modules/user.py:
+
+2009-12-28 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix (with test!).
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/bugzilla_unittest.py:
+
+2009-12-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add more awesome bug-parsing logic to bugzilla.py in preparation for assign-to-committer command
+ https://bugs.webkit.org/show_bug.cgi?id=32980
+
+ * Scripts/modules/bugzilla.py:
+ - Add a new _parse_bug_page function and use it in fetch_attachments_from_bug
+ - Replace fetch_title_from_bug with a new fetch_bug call instead.
+ - Use list comprehensions where possible to reduce code duplication.
+ * Scripts/modules/bugzilla_unittest.py:
+ - Add a minimal bug parsing test.
+ - Share code between bug parsing and attachment parsing tests with _assert_dictionaries_equal
+ * Scripts/modules/commands/upload.py:
+ - Use fetch_bug(bug_id)["title"] instead of fetch_title_from_bug
+
+2009-12-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Status bubble shouldn't be transparent for bots that haven't run yet
+ https://bugs.webkit.org/show_bug.cgi?id=32977
+
+ * QueueStatusServer/templates/statusbubble.html:
+
+2009-12-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [QueueStatusServer] Run gc cron job less often
+ https://bugs.webkit.org/show_bug.cgi?id=32958
+
+ Now that we've cleaned out the backlog of idle messages, we don't need
+ to run the gc job every half hour. We could also stop logging the idle
+ messages, but this seems easier for the time being.
+
+ * QueueStatusServer/cron.yaml:
+
+2009-12-27 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32896
+
+ Fixes an issue where bugzilla-tool tries to read the username and password from
+ Git regardless of whether Git is installed. In particular, if Git is not
+ installed then bugzilla-tool dies (with a trace) when it attempts to query Git
+ for the authentication credentials to log into bugs.webkit.org.
+
+ Moreover, modifies Executive.run_command to catch and pass OSError exceptions to
+ the specified error handler. For instance, the specified error handler will now
+ be called when the command does not exist (i.e. OSError errno 2).
+
+ * Scripts/modules/credentials.py: Added check for Git.
+ * Scripts/modules/credentials_unittest.py: Added test method
+ test_read_credentials_with_SVN.
+ * Scripts/modules/executive.py: Modified method run_command to catch
+ OSError exceptions (i.e [Errno 2] No such file or directory) and call
+ the specified error handler.
+ * Scripts/modules/executive_unittest.py: Added.
+ * Scripts/run-webkit-unittests: Added import executive_unittest.py.
+
+2009-12-27 Daniel Bates <dbates@webkit.org>
+
+ Unreviewed. Added missing file style_unittest.py that wasn't committed
+ in change set 52541 (http://trac.webkit.org/changeset/52541) as part of
+ the patch for bug #32592.
+
+ * Scripts/modules/style_unittest.py: Added.
+
+2009-12-27 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32964
+
+ [bzt] Updated the unit test based on the change made in bug #32951.
+
+ The change made in bug #32951 added the command-line argument:
+ --makeargs="-j8" to the build-webkit command. However, the associated
+ unit test was not updated.
+
+ * Scripts/modules/webkitport_unittest.py:
+
+2009-12-27 Yael Aharon <yael.aharon@nokia.com>
+
+ Reviewed by Darin Adler.
+
+ check-webkit-style should not mark moc files inclusion as errors
+ https://bugs.webkit.org/show_bug.cgi?id=32669
+
+ Add a new header type for moc files, and skip them when checking the order of header files.
+
+ * Scripts/modules/cpp_style.py:
+
+2009-12-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Make the qt build go fast
+ https://bugs.webkit.org/show_bug.cgi?id=32951
+
+ Make use of multiple cores, if available.
+
+ * Scripts/modules/webkitport.py:
+
+2009-12-25 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32682
+
+ Fixes an issue where checkFrameworks always dies with an error under Windows
+ since the clause "unless (-x $path)" is always satisfied because files under
+ Windows do not have an explict executable bit.
+
+ * Scripts/webkitdirs.pm:
+
+2009-12-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool should accept global options anywhere
+ https://bugs.webkit.org/show_bug.cgi?id=26912
+
+ * Scripts/bugzilla-tool:
+ - Use the new global_options class property.
+ - Add a handle_global_options callback to avoid needing callbacks for each global option.
+ * Scripts/modules/multicommandtool.py:
+ - Make the code use one combined option parser.
+ This allows us to accept global options anywhere and
+ individual command options before commands.
+ - Add a handle_global_options callback to avoid needing callbacks for each global option.
+ - Make the Command hold the option parser, but allow the tool to override it.
+ - The default option parser is used for help printing and when Commands are run stand alone,
+ but are otherwise not used.
+ - Add Command.main to codify the idea that Commands should support being run stand-alone.
+ - Change _split_args to _split_command_name_from_args now that args are unified.
+ * Scripts/modules/multicommandtool_unittest.py:
+ - Test that "tool" and "tool help" show the same help.
+ - Test that args are accepted before commands
+
+2009-12-20 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by David Levin.
+
+ Moved some sections of code in preparation to refactor
+ check-webkit-style's argument parser to avoid setting
+ global variables.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32592
+
+ * Scripts/check-webkit-style:
+ - Moved _USAGE string to style.py.
+ - Addressed FIXME by eliminating dependencies on cpp_style.py.
+
+ * Scripts/modules/cpp_style.py:
+ - Moved default arguments and style categories to style.py.
+ - Moved exit_with_usage(), exit_with_categories(), and
+ parse_arguments() to style.py.
+ - Removed references in _CppStyleState to the global
+ variables now in style.py.
+
+ * Scripts/modules/cpp_style_unittest.py:
+ - Moved parse_arguments() unit tests to style_unittest.py.
+
+ * Scripts/modules/style.py:
+ - Added _USAGE string from check-webkit-style.
+ - Added default arguments and style categories from cpp_style.py.
+ - Added exit_with_usage(), exit_with_categories(), and
+ parse_arguments() from cpp_sstyle.py.
+
+ * Scripts/modules/style_unittest.py: Added.
+ - Added parse_arguments() unit tests from cpp_style_unittest.py.
+
+ * Scripts/run-webkit-unittests:
+ - Added unit tests from style_unittest.py.
+
+2009-12-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue should mention bug 30084 when rejecting patches until it can be fixed
+ https://bugs.webkit.org/show_bug.cgi?id=32911
+
+ * Scripts/modules/bugzilla.py: Make the message even more fancy.
+ * Scripts/modules/bugzilla_unittest.py: Test our new fancy message.
+
+2009-12-23 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Not reviewed, adding myself to the reviewers list.
+
+ * Scripts/modules/committers.py:
+
+2009-12-23 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Create a prepare-diff command that creates a bug and a ChangeLog
+ https://bugs.webkit.org/show_bug.cgi?id=32895
+
+ The workflow Maciej and I discussed is as follows:
+
+ 1) Write code.
+ 2) bugzilla-tool prepare-diff
+ 3) Edit ChangeLogs
+ 4) bugzilla-tool post-diff
+
+ We might want to experimenting with combining 2-4 into a single
+ command, but that might be stressful to edit the ChangeLogs modally.
+
+ Removed submit-patch since it has the modal ChangeLog editing but none
+ oof the bug creating fun.
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/upload.py:
+ * Scripts/modules/commands/upload_unittest.py:
+
+2009-12-23 Gabor Loki <loki@webkit.org>
+
+ Unreviewed; added myself to the committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-12-22 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ [bzt] Don't call create-patch twice during post-diff
+ https://bugs.webkit.org/show_bug.cgi?id=32893
+
+ If we call create-patch to get the bug number, cache the diff in the
+ state so we don't need to call it again.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/upload.py:
+
+2009-12-22 Daniel Bates <dbates@rim.com>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32680
+
+ Fixes an issue in builtDylibPathForName so that it returns the correct
+ path to the built QtWebKit library on the Qt Windows port. Currently,
+ it returns the path to the file named QtWebKit.dll but this file does
+ not exist on the Qt Windows build. Instead, the file is named
+ QtWebKit4.dll.
+
+ * Scripts/webkitdirs.pm:
+
+2009-12-22 Marc-Antoine Ruel <maruel@chromium.org>
+
+ Reviewed by Adam Roben.
+
+ Remove the only dependency on perl-libwin32 in cygwin
+
+ * Scripts/num-cpus:
+
+2009-12-22 Darin Adler <darin@apple.com>
+
+ * pywebsocket/mod_pywebsocket: Added property svn:ignore to ignore
+ generated ".pyc" files.
+
+2009-12-22 Darin Adler <darin@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Turn off datagrid by default, at least for all platforms Apple ships.
+ The datagrid implementation isn't ready for general web use yet.
+
+ * Scripts/build-webkit: Turn off datagrid by default.
+
+2009-12-22 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ validate-committer-lists fails when run from an SVN checkout
+ https://bugs.webkit.org/show_bug.cgi?id=31974
+
+ * Scripts/validate-committer-lists:
+ - Make it print a warning message instead of throwing
+ an exception when running from an SVN checkout.
+
+2009-12-22 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by Adam Barth.
+
+ check-webkit-style should not warn about NULL usage in g_object_{get,set}
+ https://bugs.webkit.org/show_bug.cgi?id=32858
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-12-22 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Holger Freyther.
+
+ Moved QtLauncher from WebKit/qt.
+
+ * QtLauncher: Copied from WebKit/qt/QtLauncher.
+ * QtLauncher/QtLauncher.pro:
+
+2009-12-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Automate the process of calling prepare-ChangeLog
+ https://bugs.webkit.org/show_bug.cgi?id=32816
+
+ This patch automates the process of creating a bug and patch and
+ uploading it to bugzilla. The first cut just calls
+ prepare-ChangeLog.
+
+ This patch required some refactoring of upload.py to the Step
+ model, but that's worth doing anyway.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/upload.py:
+ * Scripts/modules/commands/upload_unittest.py:
+ * Scripts/modules/mock_bugzillatool.py:
+
+2009-12-21 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Did a rename, so checking in the
+ version of the script I used.
+
+2009-12-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Update status-bubble to show all the queues
+ https://bugs.webkit.org/show_bug.cgi?id=32838
+
+ Also, move statusbubble over to use memcache.
+
+ * QueueStatusServer/handlers/statusbubble.py:
+ * QueueStatusServer/templates/statusbubble.html:
+
+2009-12-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Delete the boring "Empty queue" status messages in QueueStatusServer
+ https://bugs.webkit.org/show_bug.cgi?id=32818
+
+ * QueueStatusServer/app.yaml:
+ * QueueStatusServer/cron.yaml:
+ * QueueStatusServer/handlers/gc.py:
+ * QueueStatusServer/main.py:
+
+2009-12-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Exception on queue status server
+ https://bugs.webkit.org/show_bug.cgi?id=32812
+
+ Turns out we need to pass the id to the filter.
+
+ * QueueStatusServer/filters/webkit_extras.py:
+ * QueueStatusServer/templates/patch.html:
+ * QueueStatusServer/templates/recentstatus.html:
+
+2009-12-20 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by Eric Seidel.
+
+ Created "style" folder for code supporting check-webkit-style.
+
+ * Scripts/modules/style: Added.
+
+2009-12-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ REGRESSION: error when running commit-queue
+ https://bugs.webkit.org/show_bug.cgi?id=32806
+
+ Fix typo and add test!
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/bugzilla_unittest.py:
+
+2009-12-20 Adam Barth <abarth@webkit.org>
+
+ [bzt] Optimize status updates for new dashboard
+ https://bugs.webkit.org/show_bug.cgi?id=32797
+
+ This patch makes the queues slightly more chatty with the web service.
+ Also, this patch introduces some testing for the queues!
+
+ * Scripts/modules/commands/early_warning_system.py:
+ * Scripts/modules/commands/early_warning_system_unittest.py: Added.
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/commands/queues_unittest.py:
+ * Scripts/modules/commands/queuestest.py: Added.
+ * Scripts/modules/mock_bugzillatool.py:
+ * Scripts/modules/patchcollection.py:
+ * Scripts/modules/queueengine.py:
+ * Scripts/run-webkit-unittests:
+
+2009-12-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Prepare QueueStatusServer for new status messages
+ https://bugs.webkit.org/show_bug.cgi?id=32805
+
+ * QueueStatusServer/handlers/recentstatus.py:
+ * QueueStatusServer/index.html: Removed.
+ * QueueStatusServer/model/attachment.py:
+ * QueueStatusServer/model/queues.py: Added.
+ * QueueStatusServer/templates/recentstatus.html: Added.
+
+2009-12-20 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ [check-webkit-style] static_cast is not misnamed!
+ https://bugs.webkit.org/show_bug.cgi?id=32796
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-12-20 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ [GTK] Failing test platform/gtk/editing/pasteboard/middle-button-paste.html
+ https://bugs.webkit.org/show_bug.cgi?id=32788
+
+ Do not increase the click count if we are using a different button.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+
+2009-12-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [QueueStatusServer] Add a per-patch details page
+ https://bugs.webkit.org/show_bug.cgi?id=32784
+
+ This is a first cut at a per-patch details page. I'm sure we'll have
+ to iterate.
+
+ * QueueStatusServer/filters/webkit_extras.py:
+ * QueueStatusServer/handlers/patch.py: Added.
+ * QueueStatusServer/index.yaml:
+ * QueueStatusServer/main.py:
+ * QueueStatusServer/model/attachment.py:
+ * QueueStatusServer/stylesheets/dashboard.css:
+ * QueueStatusServer/templates/dashboard.html:
+ * QueueStatusServer/templates/patch.html: Added.
+
+2009-12-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Use memcache to make dashboard to fast
+ https://bugs.webkit.org/show_bug.cgi?id=32780
+
+ * QueueStatusServer/app.yaml:
+ * QueueStatusServer/handlers/dashboard.py:
+ * QueueStatusServer/handlers/updatestatus.py:
+ * QueueStatusServer/model/attachment.py: Added.
+
+2009-12-19 Brent Fulgham <bfulgham@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Provide an example implementation for printing under Windows.
+ http://bugs.webkit.org/show_bug.cgi?id=32504.`
+
+ * WinLauncher/PrintWebUIDelegate.cpp: Added.
+ (PrintWebUIDelegate::QueryInterface):
+ (PrintWebUIDelegate::AddRef):
+ (PrintWebUIDelegate::Release):
+ (PrintWebUIDelegate::webViewPrintingMarginRect):
+ * WinLauncher/PrintWebUIDelegate.h: Added.
+ (PrintWebUIDelegate::PrintWebUIDelegate):
+ (PrintWebUIDelegate::createWebViewWithRequest):
+ (PrintWebUIDelegate::webViewShow):
+ (PrintWebUIDelegate::webViewClose):
+ (PrintWebUIDelegate::webViewFocus):
+ (PrintWebUIDelegate::webViewUnfocus):
+ (PrintWebUIDelegate::webViewFirstResponder):
+ (PrintWebUIDelegate::makeFirstResponder):
+ (PrintWebUIDelegate::setStatusText):
+ (PrintWebUIDelegate::webViewStatusText):
+ (PrintWebUIDelegate::webViewAreToolbarsVisible):
+ (PrintWebUIDelegate::setToolbarsVisible):
+ (PrintWebUIDelegate::webViewIsStatusBarVisible):
+ (PrintWebUIDelegate::setStatusBarVisible):
+ (PrintWebUIDelegate::webViewIsResizable):
+ (PrintWebUIDelegate::setResizable):
+ (PrintWebUIDelegate::setFrame):
+ (PrintWebUIDelegate::webViewFrame):
+ (PrintWebUIDelegate::setContentRect):
+ (PrintWebUIDelegate::webViewContentRect):
+ (PrintWebUIDelegate::runJavaScriptAlertPanelWithMessage):
+ (PrintWebUIDelegate::runJavaScriptConfirmPanelWithMessage):
+ (PrintWebUIDelegate::runJavaScriptTextInputPanelWithPrompt):
+ (PrintWebUIDelegate::runBeforeUnloadConfirmPanelWithMessage):
+ (PrintWebUIDelegate::runOpenPanelForFileButtonWithResultListener):
+ (PrintWebUIDelegate::mouseDidMoveOverElement):
+ (PrintWebUIDelegate::contextMenuItemsForElement):
+ (PrintWebUIDelegate::validateUserInterfaceItem):
+ (PrintWebUIDelegate::shouldPerformAction):
+ (PrintWebUIDelegate::dragDestinationActionMaskForDraggingInfo):
+ (PrintWebUIDelegate::willPerformDragDestinationAction):
+ (PrintWebUIDelegate::dragSourceActionMaskForPoint):
+ (PrintWebUIDelegate::willPerformDragSourceAction):
+ (PrintWebUIDelegate::contextMenuItemSelected):
+ (PrintWebUIDelegate::hasCustomMenuImplementation):
+ (PrintWebUIDelegate::trackCustomPopupMenu):
+ (PrintWebUIDelegate::measureCustomMenuItem):
+ (PrintWebUIDelegate::drawCustomMenuItem):
+ (PrintWebUIDelegate::addCustomMenuDrawingData):
+ (PrintWebUIDelegate::cleanUpCustomMenuDrawingData):
+ (PrintWebUIDelegate::canTakeFocus):
+ (PrintWebUIDelegate::takeFocus):
+ (PrintWebUIDelegate::registerUndoWithTarget):
+ (PrintWebUIDelegate::removeAllActionsWithTarget):
+ (PrintWebUIDelegate::setActionTitle):
+ (PrintWebUIDelegate::undo):
+ (PrintWebUIDelegate::redo):
+ (PrintWebUIDelegate::canUndo):
+ (PrintWebUIDelegate::canRedo):
+ (PrintWebUIDelegate::printFrame):
+ (PrintWebUIDelegate::ftpDirectoryTemplatePath):
+ (PrintWebUIDelegate::webViewHeaderHeight):
+ (PrintWebUIDelegate::webViewFooterHeight):
+ (PrintWebUIDelegate::drawHeaderInRect):
+ (PrintWebUIDelegate::drawFooterInRect):
+ (PrintWebUIDelegate::canRunModal):
+ (PrintWebUIDelegate::createModalDialog):
+ (PrintWebUIDelegate::runModal):
+ (PrintWebUIDelegate::isMenuBarVisible):
+ (PrintWebUIDelegate::setMenuBarVisible):
+ (PrintWebUIDelegate::runDatabaseSizeLimitPrompt):
+ (PrintWebUIDelegate::paintCustomScrollbar):
+ (PrintWebUIDelegate::paintCustomScrollCorner):
+ * WinLauncher/WinLauncher.cpp: Add new UI delegate for print support.
+ (WinLauncherWebHost::updateAddressBar): check-webkit-style fixes.
+ (WinLauncherWebHost::QueryInterface): check-webkit-style fixes.
+ (WinLauncherWebHost::AddRef): check-webkit-style fixes.
+ (WinLauncherWebHost::Release): check-webkit-style fixes.
+ (resizeSubViews): check-webkit-style fixes.
+ (_tWinMain): check-webkit-style fixes.
+ (MyRegisterClass): check-webkit-style fixes.
+ (InitInstance): check-webkit-style fixes.
+ (AbortProc): New print support function.
+ (getPrinterDC): New print support function.
+ (initDocStruct): New print support function.
+ (PrintView): New printing implementation.
+ (WndProc): Add support for printing.
+ (MyEditProc): check-webkit-style fixes.
+ (About): check-webkit-style fixes.
+ (loadURL): check-webkit-style fixes.
+ * WinLauncher/WinLauncher.h:
+ (WinLauncherWebHost::WinLauncherWebHost):
+ (WinLauncherWebHost::didStartProvisionalLoadForFrame):
+ (WinLauncherWebHost::didReceiveServerRedirectForProvisionalLoadForFrame):
+ (WinLauncherWebHost::didFailProvisionalLoadWithError):
+ (WinLauncherWebHost::didCommitLoadForFrame):
+ (WinLauncherWebHost::didReceiveTitle):
+ (WinLauncherWebHost::didReceiveIcon):
+ (WinLauncherWebHost::didFinishLoadForFrame):
+ (WinLauncherWebHost::didFailLoadWithError):
+ (WinLauncherWebHost::didChangeLocationWithinPageForFrame):
+ (WinLauncherWebHost::willPerformClientRedirectToURL):
+ (WinLauncherWebHost::didCancelClientRedirectForFrame):
+ (WinLauncherWebHost::willCloseFrame):
+ (WinLauncherWebHost::windowScriptObjectAvailable):
+ * WinLauncher/WinLauncher.rc: Add menu entry for printing.
+ * WinLauncher/WinLauncher.vcproj: Add new files.
+ * WinLauncher/resource.h: Add menu entry for printing.
+
+2009-12-19 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Tweak the CSS to make the dashboard prettier.
+
+ * QueueStatusServer/stylesheets/dashboard.css:
+ * QueueStatusServer/templates/dashboard.html:
+
+2009-12-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ QueueStatusServer needs a human readable dashboard
+ https://bugs.webkit.org/show_bug.cgi?id=32769
+
+ Here is a first cut at the dashboard. There's a lot left to do.
+
+ * QueueStatusServer/filters/webkit_extras.py:
+ * QueueStatusServer/handlers/dashboard.py: Added.
+ * QueueStatusServer/handlers/patchstatus.py:
+ * QueueStatusServer/handlers/recentstatus.py:
+ * QueueStatusServer/handlers/showresults.py:
+ * QueueStatusServer/handlers/statusbubble.py:
+ * QueueStatusServer/handlers/updatestatus.py:
+ * QueueStatusServer/main.py:
+ * QueueStatusServer/model/__init__.py: Copied from WebKitTools/QueueStatusServer/filters/__init__.py.
+ * QueueStatusServer/model/queuestatus.py: Renamed from WebKitTools/QueueStatusServer/model.py.
+ * QueueStatusServer/stylesheets/dashboard.css: Added.
+ * QueueStatusServer/templates/dashboard.html: Added.
+ * QueueStatusServer/templates/statusbubble.html: Renamed from WebKitTools/QueueStatusServer/status_bubble.html.
+ * QueueStatusServer/templates/updatestatus.html: Renamed from WebKitTools/QueueStatusServer/update_status.html.
+
+2009-12-19 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Timothy Hatcher.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32462
+
+ Added --inspector-frontend flag to build-webkit to copy any changes
+ to the inspector front-end files to the built WebCore framework. This
+ will make inspector development more consistent with the rest of
+ WebKit development.
+
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2009-12-19 Adam Barth <abarth@webkit.org>
+
+ Unreviewed fixes for me being terrible at python.
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/run-webkit-unittests:
+
+2009-12-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Split QueueStatus server into modules
+ https://bugs.webkit.org/show_bug.cgi?id=32768
+
+ One monolithic file is no good.
+
+ * QueueStatusServer/app.yaml:
+ * QueueStatusServer/handlers/__init__.py: Copied from WebKitTools/QueueStatusServer/filters/__init__.py.
+ * QueueStatusServer/handlers/patchstatus.py: Added.
+ * QueueStatusServer/handlers/recentstatus.py: Added.
+ * QueueStatusServer/handlers/showresults.py: Added.
+ * QueueStatusServer/handlers/statusbubble.py: Added.
+ * QueueStatusServer/handlers/updatestatus.py: Added.
+ * QueueStatusServer/main.py: Added.
+ * QueueStatusServer/model.py: Added.
+ * QueueStatusServer/queue_status.py: Removed.
+
+2009-12-18 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by Eric Seidel.
+
+ Renamed WorkQueue to QueueEngine. WorkQueue is not a queue.
+
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/queueengine.py: Added.
+ * Scripts/modules/queueengine_unittest.py: Added.
+ * Scripts/modules/stepsequence.py:
+ * Scripts/modules/workqueue.py: Removed.
+ * Scripts/modules/workqueue_unittest.py: Removed.
+
+2009-12-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add watches for EWS
+ https://bugs.webkit.org/show_bug.cgi?id=32767
+
+ dglazkov wanted to be added.
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/commands/early_warning_system.py:
+ * Scripts/modules/commands/queues.py:
+
+2009-12-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ move bugzilla.py off of urllib2
+ https://bugs.webkit.org/show_bug.cgi?id=32729
+
+ * Scripts/modules/bugzilla.py: use mechanize for all url fetching.
+
+2009-12-18 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Rubber-stamped by Xan Lopez.
+
+ [GTK] New events (pageshow and pagehide) tests failing
+ https://bugs.webkit.org/show_bug.cgi?id=28823
+
+ Original patch by Jan Michael Alonzo.
+
+ Disable page cache for tests.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (copyWebSettingKey):
+ (LayoutTestController::overridePreference):
+
+2009-12-18 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by David Levin.
+
+ Check one space before end of line comments.
+ https://bugs.webkit.org/show_bug.cgi?id=32597
+
+ Fix to check one space before end of line comments in whitespace and build/header_guard.
+ Also fix build/header_guard to use WebKit header guard defines.
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-12-17 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Add BUILDING_ON_SNOW_LEOPARD #define.
+
+ * DumpRenderTree/mac/DumpRenderTreeMac.h:
+
+2009-12-17 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Update pywebsocket to 0.4.5 and make handshake checking stricter
+ https://bugs.webkit.org/show_bug.cgi?id=32249
+
+ * Scripts/run-webkit-tests:
+ * pywebsocket/mod_pywebsocket/handshake.py:
+ * pywebsocket/mod_pywebsocket/memorizingfile.py: Added.
+ * pywebsocket/mod_pywebsocket/standalone.py:
+ * pywebsocket/setup.py:
+ * pywebsocket/test/test_handshake.py:
+ * pywebsocket/test/test_memorizingfile.py: Added.
+
+2009-12-17 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Command.show_in_main_help should default to False
+ https://bugs.webkit.org/show_bug.cgi?id=32686
+
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/queries.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/commands/upload.py:
+ * Scripts/modules/multicommandtool.py:
+
+2009-12-17 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Eric Seidel.
+
+ Added the key WebKitEnableCaretBrowsing to the
+ layoutTestController.overridePreference in order to activate caret
+ browsing.
+ https://bugs.webkit.org/show_bug.cgi?id=32612
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp: Added the reset value of
+ the setting.
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: Inserted the new
+ key in the keytable.
+
+2009-12-17 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by David Kilzer.
+
+ AX: DRT needs to support URL for accessibility
+ https://bugs.webkit.org/show_bug.cgi?id=32666
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getURLCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::url):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::url):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::url):
+
+2009-12-17 Philippe Normand <pnormand@igalia.com>
+
+ Unreviewed; added myself to committers
+
+ * Scripts/modules/committers.py:
+
+2009-12-17 Benjamin Otte <otte@gnome.org>
+
+ Unreviewed; added myself to committers
+
+ * Scripts/modules/committers.py:
+
+2009-12-17 Adam Barth <abarth@webkit.org>
+
+ Rubber stamp by Seidel.
+
+ Clean up exception handling in WorkQueue. Basically, a bunch of the
+ delegate messages can throw exceptions because of network errors. We
+ want the queues to keep on ticking instead of erroring out. That means
+ we want to catch generic exceptions and continue looping.
+
+ Also, cleaned up the exception handling in the EWS to properly log
+ failures.
+
+ * Scripts/modules/commands/early_warning_system.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/workqueue.py:
+
+2009-12-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Make UpdateStep quiet
+ https://bugs.webkit.org/show_bug.cgi?id=32599
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/buildsteps_unittest.py:
+
+2009-12-16 Evan Martin <evan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Add Gtk to the early warning system WebKit port list.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32629
+
+ * Scripts/modules/commands/early_warning_system.py:
+ * Scripts/modules/webkitport.py:
+ * Scripts/modules/webkitport_unittest.py:
+
+2009-12-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ post-diff is failing with exception under guess_reviewer_from_bug
+ https://bugs.webkit.org/show_bug.cgi?id=32642
+
+ Also refactor output capturing code into
+ OutputCapture.assert_outputs to share more code between tests.
+
+ * Scripts/modules/buildsteps.py:
+ - Add the missing include.
+ - Give guess_reviewer_from_bug a private underscore.
+ * Scripts/modules/buildsteps_unittest.py: Added.
+ - Test to make sure _guess_reviewer_from_bug works as expected.
+ * Scripts/modules/commands/commandtest.py:
+ - Custom code is now obsoleted by OutputCapture.assert_outputs
+ * Scripts/modules/commands/queues_unittest.py:
+ - ditto
+ * Scripts/modules/credentials_unittest.py:
+ - ditto
+ * Scripts/modules/mock_bugzillatool.py:
+ - fetch_reviewed_patches_from_bug can never return None
+ * Scripts/modules/multicommandtool_unittest.py:
+ - Custom code is now obsoleted by OutputCapture.assert_outputs
+ * Scripts/modules/outputcapture.py:
+ - Add assert_outputs to share more code between tests.
+ * Scripts/run-webkit-unittests:
+ - Add buildsteps_unittest.py
+
+2009-12-16 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Added a default argument to _update_status so that callers
+ don't have to explictly pass None when they don't have a patch object.
+
+ * Scripts/modules/commands/queues.py:
+
+2009-12-16 Kent Tamura <tkent@chromium.org>
+
+ Reviewed by David Levin.
+
+ check-webkit-style supports for TAB check against text files.
+ https://bugs.webkit.org/show_bug.cgi?id=32538
+
+ * Scripts/check-webkit-style:
+ Move process_patch() to style.py.
+ * Scripts/modules/cpp_style.py:
+ Add can_handle().
+ * Scripts/modules/cpp_style_unittest.py:
+ Add tests for can_handle().
+ * Scripts/modules/style.py:
+ Added. This is a front-end of cpp_style and text_style. It dispatches
+ files to an appropriate linter.
+ * Scripts/modules/text_style.py:
+ Added. This is a linter module for generic text files. It supports
+ only for TAB checking at this moment.
+ * Scripts/modules/text_style_unittest.py:
+ Added. Tests for text_style.py.
+ * Scripts/run-webkit-unittests:
+ Add text_style_unittest.
+
+2009-12-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ bugzilla-tool should not require users to install mechanize
+ https://bugs.webkit.org/show_bug.cgi?id=32635
+
+ Centralize our import logic.
+
+ * Scripts/modules/bugzilla.py: use webkit_mechanize
+ * Scripts/modules/statusbot.py: use webkit_mechanize
+ * Scripts/modules/webkit_mechanize.py: Added.
+
+2009-12-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Generalize commit-queue recent status page for all queues
+ https://bugs.webkit.org/show_bug.cgi?id=32633
+
+ * QueueStatusServer/index.html:
+ - Generalize to support other queues.
+ * QueueStatusServer/queue_status.py:
+ - Generalize MainPage to support other queues.
+
+2009-12-16 Evan Martin <evan@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Early warning system server should display output as UTF-8.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32625
+
+ * QueueStatusServer/queue_status.py:
+
+2009-12-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Add error handling to the early warning system
+ https://bugs.webkit.org/show_bug.cgi?id=32594
+
+ This should be the last step in making the EWS operational. When we
+ have a build error, we post the log to QueueStatusServer and add a link
+ to the bug.
+
+ * Scripts/modules/commands/early_warning_system.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/executive.py:
+
+2009-12-16 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Holger Freyther.
+
+ Fix crash with tests that use custom font faces.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32600
+
+ In the DRT we call QApplication::removeAllApplicationFonts(), to make sure
+ that custom font faces between tests don't influence each other. Calling this
+ function in Qt however also invalidates all existing handles with QFontDatabase.
+
+ In order to make sure that WebCore also drops these handles we call QWebSettings::clearMemoryCaches(),
+ which implies a call to WebCore::FontCache::fontCache()->invalidate().
+
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp:
+ (WebCore::DumpRenderTree::open):
+
+2009-12-16 Andreas Kling <andreas.kling@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Maintain button state between mouse events.
+
+ This allows eventSender to generate drag events.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32601
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::mouseDown):
+ (EventSender::mouseUp):
+ (EventSender::mouseMoveTo):
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2009-12-15 Chris Jerdonek <chris.jerdonek@gmail.com>
+
+ Reviewed by David Levin.
+
+ Code clean-up in check-webkit-style as described below.
+ The only functional changes are minor improvements to the
+ script's help output.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32487
+
+ * Scripts/check-webkit-style:
+ - Added the module docstring from cpp_style.py.
+ - Improved wording of the --help output and added some of the
+ default values as substitution strings.
+ - Called cpp_style.exit_with_usage instead of sys.stderr.write
+ in main function.
+ - Made changes caused by changes to cpp_style.py.
+
+ * Scripts/modules/cpp_style.py:
+ - Removed module docstring, as well as redundant _USAGE string
+ and main() function obsoleted by check-webkit-style.
+ - Moved specification of default script values from within a
+ function definition to global variables.
+ - Moved the default webkit filter rules to be near the other
+ global variables.
+ - Renamed "FILTER" global variables to "FILTER_RULES" to
+ establish unambiguous terminology.
+ - Renamed _ERROR_CATEGORIES to _STYLE_CATEGORIES.
+ - Changed _STYLE_CATEGORIES from a string to a list.
+ - Added default webkit filter rules to --filter= output.
+ - Renamed "print_" methods to "exit_with_" since they exist
+ and added a temporary display_help parameter.
+ - Added a temporary display_help parameter to parse_arguments.
+
+ * Scripts/modules/cpp_style_unittest.py:
+ - Made changes caused by changes to cpp_style.py.
+ - Lower-cased ErrorCollector's ERROR_CATEGORIES instance
+ variables since they are not global.
+
+2009-12-15 Adam Barth <abarth@webkit.org>
+
+ Unreviewed fix for the style-queue.
+ Typo: _updates_status -> _update_status
+
+ We need to improve our testing infrastructure for the queues.
+
+ * Scripts/modules/commands/queues.py:
+
+2009-12-15 Adam Barth <abarth@webkit.org>
+
+ Unreviewed fix for the style-queue. I suspect this is a recent
+ regression from Eric's change below.
+
+ * Scripts/modules/commands/queues.py:
+
+2009-12-15 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ update-webkit-chromium to auto-install gclient
+
+ https://bugs.webkit.org/show_bug.cgi?id=32587
+
+ * Scripts/update-webkit-chromium:
+
+2009-12-15 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool / commit-queue should add results links to bugs when more results are available on the status bot
+ https://bugs.webkit.org/show_bug.cgi?id=32546
+
+ You can see an example of this working in:
+ https://bugs.webkit.org/show_bug.cgi?id=32585#c3
+
+ * QueueStatusServer/queue_status.py:
+ - Output the id of the newly created status.
+ * Scripts/modules/commands/queues.py:
+ - Tweak the commit-queue logging to include a full status link.
+ * Scripts/modules/statusbot.py:
+ - update_status should return the newly created status id.
+
+2009-12-15 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [Qt] Rename Qt DRT components to match other ports' naming convention and to be more understandable.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp: Removed.
+ * DumpRenderTree/qt/DumpRenderTree.h: Removed.
+ * DumpRenderTree/qt/DumpRenderTree.pro: Updated.
+ * DumpRenderTree/qt/DumpRenderTreeQt.cpp: Copied from WebKitTools/DumpRenderTree/qt/DumpRenderTree.cpp.
+ * DumpRenderTree/qt/DumpRenderTreeQt.h: Copied from WebKitTools/DumpRenderTree/qt/DumpRenderTree.h.
+ * DumpRenderTree/qt/GCControllerQt.cpp: Copied from WebKitTools/DumpRenderTree/qt/jsobjects.cpp.
+ (GCController::GCController):
+ * DumpRenderTree/qt/GCControllerQt.h: Copied from WebKitTools/DumpRenderTree/qt/jsobjects.h.
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ * DumpRenderTree/qt/WorkQueueItem.h: Removed.
+ * DumpRenderTree/qt/WorkQueueItemQt.cpp: Updated includes.
+ * DumpRenderTree/qt/WorkQueueItemQt.h: Copied from WebKitTools/DumpRenderTree/qt/WorkQueueItem.h.
+ * DumpRenderTree/qt/jsobjects.cpp: Removed.
+ * DumpRenderTree/qt/jsobjects.h: Removed.
+ * DumpRenderTree/qt/main.cpp: Updated includes.
+
+2009-12-15 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ We have two mark-fixed commands
+ https://bugs.webkit.org/show_bug.cgi?id=32073
+
+ * Scripts/mark-bug-fixed: Removed.
+ * Scripts/modules/commands/upload.py:
+ * Scripts/modules/commands/upload_unittest.py:
+
+2009-12-15 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool/commit-queue needs to upload failure logs when patches are rejected
+ https://bugs.webkit.org/show_bug.cgi?id=28286
+
+ * QueueStatusServer/index.html:
+ - Show [results] links if a results log was uploaded.
+ * QueueStatusServer/queue_status.py:
+ - Empty file uploads appear as u"" and Blob does not handle unicode, so convert to str().
+ * Scripts/modules/commands/queues.py:
+ - Post to the status bot when a patch fails and include the failure log as a results file.
+
+2009-12-15 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ queue sub-commands need --status-host so they can report status
+ https://bugs.webkit.org/show_bug.cgi?id=32313
+
+ Make --status-bot a global option and make
+ run_bugzilla_tool pass --status-bot to sub-commands.
+
+ * Scripts/bugzilla-tool:
+ - Rename _status to status_bot and make it non-lazy.
+ * Scripts/modules/commands/queues.py:
+ - Move status updates out of WorkQueue and into individual queues.
+ * Scripts/modules/commands/queues_unittest.py:
+ - Test that --status-host is passed to bugzilla-tool when run as subcommand.
+ * Scripts/modules/mock_bugzillatool.py:
+ - Add a MockStatusBot
+ * Scripts/modules/workqueue.py:
+ - Remove status_host and work_work_logs_directory callbacks.
+ - Add new work_item_log_path callback so that WorkQueue doesn't need to know about patches!
+ * Scripts/modules/workqueue_unittest.py:
+ - Update unit tests to reflect new callbacks.
+
+2009-12-15 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ scm_unittest.py is too slow
+ https://bugs.webkit.org/show_bug.cgi?id=31818
+
+ Now we don't run the SCM unit tests unless we get the --all flag on the
+ command line. Eric and I were commenting out this test because it was
+ too painful to run.
+
+ * Scripts/run-webkit-unittests:
+
+2009-12-14 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Fix failing unittest.
+
+ * Scripts/modules/bugzilla_unittest.py:
+
+2009-12-14 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Move Credential handling out into a separate module
+ https://bugs.webkit.org/show_bug.cgi?id=32531
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/credentials.py: Added.
+ * Scripts/modules/credentials_unittest.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-12-14 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Kill _create_step_sequence
+ https://bugs.webkit.org/show_bug.cgi?id=32539
+
+ It's cleaner to represent not having these sequences as an empty
+ sequence instead of None.
+
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/stepsequence.py:
+
+2009-12-14 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Address reviewer comments from an earlier patch. I didn't
+ do this earlier because I was worried about conflicts in dependent
+ patches.
+
+ * Scripts/modules/commands/download.py:
+
+2009-12-14 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Make download commands declarative
+ https://bugs.webkit.org/show_bug.cgi?id=32469
+
+ This patch "properly" factors most of the download commands. These
+ commands are now largely declarative, which is the final step of this
+ grand refactoring.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+
+2009-12-14 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Add AbstractPatchSequencingCommand to remove redundant code
+ https://bugs.webkit.org/show_bug.cgi?id=32468
+
+ Redundant code is bad. This patch moves us towards more declarative
+ commands.
+
+ * Scripts/modules/commands/download.py:
+
+2009-12-14 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitApplyingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=32467
+
+ Ah! I've been wanting to do this for a long time. This patch brings
+ the applying commands into the patch processing fold.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/download_unittest.py:
+ * Scripts/modules/mock_bugzillatool.py:
+
+2009-12-14 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Convert rollout to StepSequence
+ https://bugs.webkit.org/show_bug.cgi?id=32406
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/download_unittest.py:
+ * Scripts/modules/mock_bugzillatool.py:
+
+2009-12-14 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill LandingSequence
+ https://bugs.webkit.org/show_bug.cgi?id=32464
+
+ Removes LandingSequence in favor of StepSequence. This required
+ changing the Step API slightly to carry a general notion of state
+ instead of carrying patches specifically.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/landingsequence.py: Removed.
+ * Scripts/modules/stepsequence.py:
+
+2009-12-14 Robert Hogan <robert@roberthogan.net>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] Fix https://bugs.webkit.org/show_bug.cgi?id=32437
+
+ Amend the behaviour of DRT::notifyDone to dump only when
+ the page has finished loading.
+
+ This fix permits removal of the following tests from the Qt skipped list:
+ fast/forms/textarea-linewrap-dynamic.html
+ fast/forms/textarea-setvalue-submit.html
+ fast/forms/textarea-hard-linewrap-empty.html
+ fast/forms/submit-to-url-fragment.html
+ http/tests/misc/percent-sign-in-form-field-name.html
+ http/tests/security/escape-form-data-field-names.html
+
+ However it also requires the following two to be added to the skipped list:
+
+ http/tests/xmlhttprequest/access-control-basic-denied-preflight-cache.html
+ svg/custom/use-instanceRoot-as-event-target.xhtml
+
+ It appears the behaviour of notifyDone was masking problems with these two
+ tests.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::processWork):
+ (LayoutTestController::maybeDump):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::provisionalLoad):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::resetLoadFinished):
+
+2009-12-14 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Qt] Add support for keyboard modifiers to Qt DRT's EventSender for touch events
+
+ https://bugs.webkit.org/show_bug.cgi?id=32482
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::setTouchModifier):
+ (EventSender::clearTouchPoints):
+ (EventSender::sendTouchEvent):
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2009-12-13 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Gavin Barraclaugh.
+
+ Fix minor problem in sunspider-compare-results which left it broken.
+
+ * Scripts/sunspider-compare-results: Declare $parseonly
+
+2009-12-12 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Give command-line sunspider the ability to handle multiple suites and versions
+ https://bugs.webkit.org/show_bug.cgi?id=32477
+
+ * Scripts/run-sunspider: Updated for changes to command-line parameters.
+ * Scripts/sunspider-compare-results: ditto
+
+2009-12-12 Maciej Stachowiak <mjs@apple.com>
+
+ Not reviewed, fixing previous comment.
+
+ Remove accidental change to sunspider-compare-results
+
+ * Scripts/sunspider-compare-results:
+
+2009-12-11 Yael Aharon <yael.aharon@nokia.com>
+
+ Unreviewed build fix for Qt versions < 4.6.
+ Guard every slot individually with #ifdef.
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::addTouchPoint):
+ (EventSender::updateTouchPoint):
+ (EventSender::touchStart):
+ (EventSender::touchMove):
+ (EventSender::touchEnd):
+ (EventSender::clearTouchPoints):
+ (EventSender::releaseTouchPoint):
+ (EventSender::sendTouchEvent):
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2009-12-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ CommandsTest.assert_execute_outputs doesn't check stderr
+ https://bugs.webkit.org/show_bug.cgi?id=32352
+
+ Fix assert_execute_outputs to check stderr
+ and then fix all the unit tests which needed to
+ pass stderr output.
+
+ * Scripts/modules/commands/commandtest.py:
+ * Scripts/modules/commands/download_unittest.py:
+ * Scripts/modules/commands/upload_unittest.py:
+
+2009-12-11 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [check-webkit-style] False positive for tst_QWebFrame
+ https://bugs.webkit.org/show_bug.cgi?id=32436
+
+ Add an exception for function names that start with "tst_". These are
+ used by the Qt unit testing framework.
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-12-11 Simon Hausmann <hausmann@webkit.org>, Kim Grönholm <kim.gronholm@nomovok.com>
+
+ Reviewed by Antti Koivisto.
+
+ Added support for creating synthetic touch events with EventSender
+ in Qt's DumpRenderTree.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32114
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::addTouchPoint):
+ (EventSender::updateTouchPoint):
+ (EventSender::touchStart):
+ (EventSender::touchMove):
+ (EventSender::touchEnd):
+ (EventSender::clearTouchPoints):
+ (EventSender::releaseTouchPoint):
+ (EventSender::sendTouchEvent):
+ * DumpRenderTree/qt/EventSenderQt.h:
+
+2009-12-11 Benjamin Poulain <benjamin.poulain@nokia.com>
+
+ Reviewed by Darin Adler.
+
+ The values of RuntimeArray are not enumerable
+ https://bugs.webkit.org/show_bug.cgi?id=29005
+
+ * DumpRenderTree/mac/ObjCController.m:
+ (+[ObjCController isSelectorExcludedFromWebScript:]):
+ (+[ObjCController webScriptNameForSelector:]):
+ (-[ObjCController arrayOfString]):
+
+2009-12-10 Eric Seidel <eric@webkit.org>
+
+ No review, just updating unit tests to match recent checkins.
+
+ * Scripts/modules/mock_bugzillatool.py:
+ - Add missing red_core_builders_names method causing exception.
+ * Scripts/modules/workqueue_unittest.py:
+ - processutils is dead, use executive.py instead.
+
+2009-12-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Move run_command onto Executive to make code which uses run_command testable
+ https://bugs.webkit.org/show_bug.cgi?id=32396
+
+ * Scripts/modules/executive.py:
+ - Move run_command and error handlers onto Executive.
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+
+2009-12-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool needs a command to list patches needing cq+
+ https://bugs.webkit.org/show_bug.cgi?id=32351
+
+ * Scripts/modules/bugzilla.py:
+ - Parse attacher_email from attachment xml.
+ * Scripts/modules/bugzilla_unittest.py:
+ - Test new attacher_email parsing.
+ * Scripts/modules/commands/queries.py:
+ - Add PatchesToCommitQueue
+ * Scripts/modules/commands/queries_unittest.py:
+ - Tests for PatchesToCommitQueue
+ * Scripts/modules/mock_bugzillatool.py:
+ - Add necessary mock methods for running PatchesToCommitQueue
+
+2009-12-10 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Turns out every StepSequence command needs a --quiet
+ option.
+
+ * Scripts/modules/stepsequence.py:
+
+2009-12-10 Eric Z. Ayers <zundel@google.com>
+
+ Reviewed by Pavel Feldman.
+
+ Implements displayWebView() to force an invalidation and repaint.
+ This fixes a problem running the timeline-paint.html unit test.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31729
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (displayWebView):
+
+2009-12-10 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Convert more commands to StepSequences
+ https://bugs.webkit.org/show_bug.cgi?id=32362
+
+ We should eventually convert all the commands, but I'm starting with
+ the easy ones.
+
+ * Scripts/modules/commands/download.py:
+
+2009-12-10 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Jan Alonzo.
+
+ [GTK] editing/selection/shrink-selection-after-shift-pagedown.html failing
+ https://bugs.webkit.org/show_bug.cgi?id=31103
+
+ Give focus to the webviews when we create them, since some tests expect this.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (main):
+
+2009-12-10 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool "builders are red" error should tell you which builders
+ https://bugs.webkit.org/show_bug.cgi?id=32211
+
+ * Scripts/modules/buildsteps.py:
+
+2009-12-09 Marwan Al Jubeh <marwan.aljubeh@gmail.com>
+
+ Reviewed by Adam Roben.
+
+ Fixes: https://bugs.webkit.org/show_bug.cgi?id=31228
+ Set the WebKitOutputDir, WebKitLibrariesDir and Cygwin environment variables automatically
+ in Windows as part of running update_webkit.
+
+ * Scripts/update-webkit:
+ - Run setupAppleWinEnv() on Apple's Windows port.
+ * Scripts/webkitdirs.pm:
+ - Added functions that return the source directory, libraries directory and default build directory on Windows.
+ - Added isWindowsNT() which tests if the current Windows version is from the Windows NT family.
+ - Implemented setupAppleWinEnv() which sets the environment variables WebKitOutputDir, WebKitLibrariesDir
+ and Cygwin to their desired values.
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ exception thrown when running apply-patches
+ https://bugs.webkit.org/show_bug.cgi?id=32344
+
+ The update step now takes a port option. Once we finish the Steps
+ refactoring, we won't have to worry about this kind of bug again.
+
+ * Scripts/modules/commands/download.py:
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Fix ScriptError includes. I don't understand why these
+ didn't throw during unit testing...
+
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/logging_unittest.py:
+ * Scripts/modules/workqueue.py:
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Remove unused PatchCollection class
+ https://bugs.webkit.org/show_bug.cgi?id=32312
+
+ It's dead code.
+
+ * Scripts/modules/patchcollection.py:
+ * Scripts/modules/patchcollection_unittest.py: Removed.
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix. CheckStyle needs a --no-upate option.
+
+ * Scripts/modules/commands/download.py:
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Convert Build to use Sequence
+ https://bugs.webkit.org/show_bug.cgi?id=32310
+
+ So much prettier.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/stepsequence.py: Added.
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Add missing file.
+
+ * Scripts/modules/executive.py: Added.
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix.
+
+ * Scripts/modules/landingsequence.py:
+
+2009-12-09 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Implement abstract Steps
+ https://bugs.webkit.org/show_bug.cgi?id=32212
+
+ This is a fairly disruptive change that refactors how we build
+ commands. Instead of using a landing sequence, we can now assemble a
+ sequence of steps directly. We still use the landing sequence in the
+ interim, but this will be removed soon.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/early_warning_system.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/commands/queues_unittest.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/mock_bugzillatool.py:
+ * Scripts/modules/processutils.py: Removed.
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+ * Scripts/modules/webkitport.py:
+
+2009-12-08 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ run_command and ScriptError should move into processutils.py
+ https://bugs.webkit.org/show_bug.cgi?id=32305
+
+ Turns out there are a zillion callers to run_command.
+
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/early_warning_system.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/logging_unittest.py:
+ * Scripts/modules/processutils.py:
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+ * Scripts/modules/workqueue.py:
+ * Scripts/modules/workqueue_unittest.py:
+
+2009-12-08 Kevin Watters <kevinwatters@gmail.com>
+
+ Reviewed by Kevin Ollivier.
+
+ [wx] Mac plugins support.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32236
+
+ * wx/browser/wscript:
+
+2009-12-08 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ [check-webkit-style] False positive for DEFINE_OPCODE(op_jtrue) {
+ https://bugs.webkit.org/show_bug.cgi?id=32193
+
+ * Scripts/modules/cpp_style.py: For the function { rule, if there is space
+ at the beginning of line, ignore lines which then have a macro.
+ * Scripts/modules/cpp_style_unittest.py: Add tests to verify the
+ new behavior.
+
+2009-12-08 Dmitry Titov <dimich@chromium.org>
+
+ Rubber-stamped by David Levin.
+
+ Revert and reopen "Add asserts to RefCounted to make sure ref/deref happens on the right thread."
+ It may have caused massive increase of reported leaks on the bots.
+ https://bugs.webkit.org/show_bug.cgi?id=31639
+
+ * DumpRenderTree/ForwardingHeaders/wtf/ThreadVerifier.h: Removed.
+
+2009-12-08 Dmitry Titov <dimich@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Add asserts to RefCounted to make sure ref/deref happens on the right thread.
+ https://bugs.webkit.org/show_bug.cgi?id=31639
+
+ * DumpRenderTree/ForwardingHeaders/wtf/ThreadVerifier.h: Added.
+
+2009-12-08 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ [check-webkit-style] False positive for camel case of JSC op codes
+ https://bugs.webkit.org/show_bug.cgi?id=32192
+
+ * Scripts/modules/cpp_style.py: Added an exception for the JSC op
+ code functions and const_iterator as well since I noticed a false
+ positive there when testing the fix.
+ * Scripts/modules/cpp_style_unittest.py: Added tests for these
+ changes.
+
+2009-12-08 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Turn on (SVG) Filters for Win.
+ https://bugs.webkit.org/show_bug.cgi?id=32224
+
+ * Scripts/webkitdirs.pm:
+
+2009-12-08 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Turn on (SVG) Filters for Gtk.
+ https://bugs.webkit.org/show_bug.cgi?id=32224
+
+ * Scripts/build-webkit:
+
+2009-12-07 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ [check-webkit-style] S_OK is a fine identifier
+ https://bugs.webkit.org/show_bug.cgi?id=32225
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-12-07 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Turn on (SVG) Filters for Qt.
+ https://bugs.webkit.org/show_bug.cgi?id=32224
+
+ * Scripts/build-webkit:
+
+2009-12-07 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Make run-webkit-websocketserver log to stderr rather than to a file.
+ https://bugs.webkit.org/show_bug.cgi?id=32234
+
+ * Scripts/run-webkit-websocketserver:
+
+2009-12-07 Dmitry Titov <dimich@chromium.org>
+
+ Rubber-stamped by Darin Adler.
+
+ Remove ENABLE_SHARED_SCRIPT flags
+ https://bugs.webkit.org/show_bug.cgi?id=32245
+ This patch was obtained by "git revert" command and then un-reverting of ChangeLog files.
+
+ * Scripts/build-webkit:
+
+2009-12-07 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Darin Adler.
+
+ <rdar://problem/7450481> One compositing test keeps DRT in "compositing mode", breaks repaint tests
+
+ The counter that WebView used to keep track of the number of enclosed WebHTMLViews using
+ accelerated compositing was hard to manage, and maintained incorrectly in a number of cases.
+ This caused one compositing test make DumpRenderTree think that all subsequent tests
+ were compositing too.
+
+ Replace this counter with notifications, which are only fired if a client (DRT) requests them. The
+ notification informs the client that a WebHTMLView entered compositing mode (or an already-
+ compositing WebHTML was added); it does not say when a view becomes uncomposited, or all
+ compositing subviews were removed, since this is tricky to get right.
+
+ DumpRenderTreeWindow listens for this notification, and uses it to turn on window
+ autodisplay, which is necessary to kick-start Core Animation rendering and animations.
+ We ensure that window autodisplay is turned off before every test.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (createWebViewAndOffscreenWindow):
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/mac/DumpRenderTreeWindow.h:
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ (-[DumpRenderTreeWindow close]):
+ (-[DumpRenderTreeWindow startListeningForAcceleratedCompositingChanges]):
+ (-[DumpRenderTreeWindow webViewStartedAcceleratedCompositing:]):
+
+2009-12-07 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Reviewed by Holger Hans Peter Freyther.
+
+ Turn on (SVG) Filters support, by default.
+ https://bugs.webkit.org/show_bug.cgi?id=32224
+
+ For now only enable FILTERS build flag on WebKit/mac. Other platforms will follow soon.
+
+ * Scripts/build-webkit:
+
+2009-12-07 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ Chromium buildbots are not red when they fail
+ https://bugs.webkit.org/show_bug.cgi?id=32235
+
+ * Scripts/build-webkit:
+
+2009-12-07 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ Typo in chromium linux builder
+ https://bugs.webkit.org/show_bug.cgi?id=32238
+
+ * Scripts/webkitdirs.pm:
+
+2009-12-07 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Darin Fisher.
+
+ fixes to build-webkit --chromium
+ https://bugs.webkit.org/show_bug.cgi?id=32179
+
+ * Scripts/webkitdirs.pm:
+
+2009-12-07 Eric Seidel <eric@webkit.org>
+
+ No review, just adding two recently approved committers.
+
+ * Scripts/modules/committers.py:
+
+2009-12-07 Alexey Proskuryakov <ap@apple.com>
+
+ * Scripts/run-webkit-websocketserver: Added property svn:executable.
+
+2009-12-07 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Add run-webkit-websocketserver
+
+ https://bugs.webkit.org/show_bug.cgi?id=31390
+
+ * Scripts/run-webkit-websocketserver: Added.
+
+2009-12-07 Steve Falkenburg <sfalken@apple.com>
+
+ Build fix. Be flexible about which version of ICU is used on Windows.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Add optional xcopy commands to copy ICU 4.2.
+
+2009-12-07 Dirk Schulze <krit@webkit.org>
+
+ Not reviewed, adding myself to the reviewers list.
+
+ * Scripts/modules/committers.py:
+
+2009-12-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add an API for uploading results files to StatusBot
+ https://bugs.webkit.org/show_bug.cgi?id=32210
+
+ Add Content-Type: plain/text which was forgotten
+ from the previous commit when I landed with land-patches
+ instead of land-diff.
+
+ * QueueStatusServer/queue_status.py:
+
+2009-12-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Status Server needs a way to handle uploaded results
+ https://bugs.webkit.org/show_bug.cgi?id=32209
+
+ * QueueStatusServer/queue_status.py: Add a ShowResults (results/*) command
+ * QueueStatusServer/update_status.html: Add file upload.
+
+2009-12-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Add an API for uploading results files to StatusBot
+ https://bugs.webkit.org/show_bug.cgi?id=32210
+
+ * Scripts/modules/statusbot.py:
+
+2009-12-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Status Server needs a way to handle uploaded results
+ https://bugs.webkit.org/show_bug.cgi?id=32209
+
+ * QueueStatusServer/queue_status.py: Add a ShowResults (results/*) command
+ * QueueStatusServer/update_status.html: Add file upload.
+
+2009-12-06 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] BuildAttachment should not check the builders
+ https://bugs.webkit.org/show_bug.cgi?id=32207
+
+ This is code that got copied here by accident when the class was created.
+
+ * Scripts/modules/commands/download.py:
+
+2009-12-06 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Make LandingSequence.update aware of ports
+ https://bugs.webkit.org/show_bug.cgi?id=32208
+
+ This is required to make build work on the Chromium port because
+ Chromium has a custom update-webkit.
+
+ * Scripts/modules/landingsequence.py:
+
+2009-12-06 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add early warning system commands to bugzilla-tool.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitport.py:
+
+2009-12-06 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Implement Qt EarlyWarningSystem and Chromium EarlyWarningSystem
+ https://bugs.webkit.org/show_bug.cgi?id=32205
+
+ * Scripts/modules/commands/early_warning_system.py: Added.
+ * Scripts/modules/commands/queues.py:
+
+2009-12-06 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ REGRESSION (r51728): update-webkit fails when the current directory is
+ not inside a Subversion working copy
+ https://bugs.webkit.org/show_bug.cgi?id=32204
+
+ * Scripts/update-webkit: Invoke isSVN() in the correct working
+ directory.
+
+2009-12-06 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Rename AbstractTryQueue to AbstractReviewQueue
+ https://bugs.webkit.org/show_bug.cgi?id=32202
+
+ * Scripts/modules/commands/queues.py:
+
+2009-12-05 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Implement ChromiumPort
+ https://bugs.webkit.org/show_bug.cgi?id=32182
+
+ * Scripts/modules/webkitport.py:
+ * Scripts/modules/webkitport_unittest.py:
+
+2009-12-05 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move update-webkit into BuildSteps
+ https://bugs.webkit.org/show_bug.cgi?id=32181
+
+ We need to move update-webkit out of SCM.py because SCM isn't supposed to know
+ that WebKit exists. The proper place for the knowledge of the existence of
+ update-webkit is in WebKitPort because some ports have specialized update
+ scripts (analogous to build-webkit).
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/scm.py:
+ * Scripts/modules/webkitport.py:
+
+2009-12-05 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ update-webkit should call git svn rebase and resolve-ChangeLogs -f
+ https://bugs.webkit.org/show_bug.cgi?id=27162
+
+ Teach update-webkit about Git. I didn't add the call to
+ resolve-ChangeLogs -f because sometimes that script goes bananas. We
+ can iterate from here, however.
+
+ * Scripts/update-webkit:
+
+2009-12-04 Yael Aharon <yael.aharon@nokia.com>
+
+ Unreviewed build fix.
+
+ [Qt] build fix after r51634 removed unused QBoxLayout include which included limits.h.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+
+2009-12-04 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Adam Treat.
+
+ Add some missing methods for showing and hiding the
+ Web Inspector.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::~WebPage):
+ (WebCore::WebPage::webInspector):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::hideWebInspector):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2009-12-04 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Adam Treat.
+
+ Implement the setAllowUniversalAccessFromFileURLs method
+ for the Qt LayoutTestController.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2009-12-04 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ REGRESSION: AX: buttons now extremely repetitive
+ https://bugs.webkit.org/show_bug.cgi?id=32164
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (isAttributeSupportedCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::isAttributeSupported):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::isAttributeSupported):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::isAttributeSupported):
+
+2009-12-03 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ check-webkit-style should check for camelCase variable names
+ https://bugs.webkit.org/show_bug.cgi?id=32051
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-12-03 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Eric Seidel.
+
+ AX: VO just says "term" on many web sites
+ https://bugs.webkit.org/show_bug.cgi?id=32139
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getRoleDescriptionCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::roleDescription):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::roleDescription):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::roleDescription):
+
+2009-12-03 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Implement WAI-ARIA scrollbar role and related property aria-orientation
+ https://bugs.webkit.org/show_bug.cgi?id=32126
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getOrientationCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::orientation):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::orientation):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::orientation):
+
+2009-12-03 Eric Carlson <eric.carlson@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Minor correction to r51663.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (addQTDirToPATH):
+ GetEnvironmentVariable -> GetEnvironmentVariableW.
+
+2009-12-03 Eric Carlson <eric.carlson@apple.com>
+
+ Reviewed by Adam Roben.
+
+ ~96 regression tests fail when using QuickTime 7.6 (they pass with QuickTime 7.3)
+ https://bugs.webkit.org/show_bug.cgi?id=30256
+
+ Add the QuickTime dll directory to the PATH environment variable so
+ inialization can succeed.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (addQTDirToPATH):
+ (initialize):
+
+2009-12-03 Shu Chang <Chang.Shu@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] After revision 32643, sender() is of type QWebPage instead of QWebFrame.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::maybeDump):
+
+2009-12-03 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Eric Seidel.
+
+ Update pywebsocket to 0.4.3
+ This version logs friendlier and higher-level messages in WARN level, which is used for LayoutTests.
+ Stack trace is logged now in INFO level.
+ https://bugs.webkit.org/show_bug.cgi?id=32097
+
+ * pywebsocket/mod_pywebsocket/dispatch.py:
+ * pywebsocket/mod_pywebsocket/msgutil.py:
+ * pywebsocket/mod_pywebsocket/standalone.py:
+ * pywebsocket/mod_pywebsocket/util.py:
+ * pywebsocket/setup.py:
+ * pywebsocket/test/test_dispatch.py:
+ * pywebsocket/test/test_util.py:
+
+2009-12-03 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Gavin Barraclough.
+
+ Fix JSClassRef leak.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (AccessibilityController::makeWindowObject):
+ * DumpRenderTree/GCController.cpp:
+ (GCController::makeWindowObject):
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::makeWindowObject):
+
+2009-12-03 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/7214236> and http://webkit.org/b/32052 - Implement HTML5 state object history API
+
+ Keep DRT-win building...
+
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+ (FrameLoadDelegate::didPushStateWithinPageForFrame):
+ (FrameLoadDelegate::didReplaceStateWithinPageForFrame):
+ (FrameLoadDelegate::didPopStateWithinPageForFrame):
+
+2009-12-03 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Unreviewed build fix.
+
+ [Qt] ARM-Linux build fix after r51634 removed unused QBoxLayout include which included limits.h on ARM.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+
+2009-12-03 Andras Becsi <abecsi@inf.u-szeged.hu>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Refactor DRT to not crash on tests which open child windows from javascript.
+ Prevent DRT from showing the main view if these childs get deleted.
+ This fixes https://bugs.webkit.org/show_bug.cgi?id=31591.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::~DumpRenderTree):
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::closeRemainingWindows):
+ (WebCore::DumpRenderTree::createWindow):
+ (WebCore::DumpRenderTree::windowCount):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+
+2009-12-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ REGRESSION(51595): commit-queue is throwing exceptions
+ https://bugs.webkit.org/show_bug.cgi?id=32083
+
+ * Scripts/modules/commands/queues.py:
+ - Don't use default value of [] as it ends up getting shared.
+ - Make log_progress accept arrays of ints as well as strings.
+ - Return an exit code from execute()
+ * Scripts/modules/commands/queues_unittest.py: Added.
+ - Test to make sure log_progress will accept ints.
+ - Test to make sure run_bugzilla_tool will accept ints.
+ * Scripts/modules/workqueue.py:
+ - Print the stack trace on unexpected exceptions for easier debugging.
+ * Scripts/run-webkit-unittests:
+ - Add queues_unittest.
+
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/commands/queues_unittest.py: Copied from WebKitTools/Scripts/modules/commands/commandtest.py.
+ * Scripts/modules/mock_bugzillatool.py:
+ * Scripts/modules/workqueue.py:
+ * Scripts/run-webkit-unittests:
+
+2009-12-02 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ check-webkit-style is too noisy about namespace indenting issues.
+ https://bugs.webkit.org/show_bug.cgi?id=32096
+
+ * Scripts/modules/cpp_style.py:
+ Added a _FileState object to be able to track file level information. In this
+ case, it simply tracks whether the error has already been given, so that it isn't
+ done again.
+ * Scripts/modules/cpp_style_unittest.py:
+ Modified test cases to pass in the _FileState object and fix a test that expected
+ to see the namespace error twice (now it only occurs once). No new tests because
+ existing tests cover the change in functionality.
+
+2009-12-01 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Eric Seidel.
+
+ [wx] Get DumpRenderTree building after waf switch.
+
+ https://bugs.webkit.org/show_bug.cgi?id=32041
+
+ * DumpRenderTree/wscript: Added.
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setTimelineProfilingEnabled):
+ (LayoutTestController::evaluateScriptInIsolatedWorld):
+ (LayoutTestController::disableImageLoading):
+ (LayoutTestController::whiteListAccessFromOrigin):
+ (LayoutTestController::counterValueForElementById):
+ * Scripts/build-webkit:
+
+2009-12-02 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] build-attachment shouldn't check whether the builders are red
+ https://bugs.webkit.org/show_bug.cgi?id=32062
+
+ build-attachment doesn't touch the remote repository, so there isn't a
+ need to hold off when the builders are red.
+
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/landingsequence.py:
+
+2009-12-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ REGRESSION(51590): style-queue and build-queue think their empty when they are not
+ https://bugs.webkit.org/show_bug.cgi?id=32061
+
+ * Scripts/modules/bugzilla.py: make all id lookups return ints instead of strings.
+ * Scripts/modules/bugzilla_unittest.py: Add and update unit tests to use ints.
+
+2009-12-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ build-queue is throwing exceptions and complaining about
+ lack of --no-update on build-attachment. Make it stop.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+
+2009-12-02 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix. Forgot to declare my variables. :(
+
+ * QueueStatusServer/queue_status.py:
+
+2009-12-02 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Implement status bubble view
+ https://bugs.webkit.org/show_bug.cgi?id=32057
+
+ The status bubble is a compact representation of the queue status for a
+ given patch. This will eventually help us reduce the comment spam from
+ the queues.
+
+ * QueueStatusServer/index.html: Added HTML5 doctype for sanity.
+ * QueueStatusServer/queue_status.py:
+ * QueueStatusServer/status_bubble.html: Added.
+
+2009-12-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ trim commands/*.py includes now that commands are unit tested
+ https://bugs.webkit.org/show_bug.cgi?id=32056
+
+ In the course of ensuring that the unit tests still
+ passed after this change, I had to actually make them
+ pass in the first place.
+
+ * Scripts/modules/bugzilla.py:
+ - Fix _parse_attachment_ids_request_query to return ints instead of strings.
+ * Scripts/modules/commands/download.py: Remove unneeded imports.
+ * Scripts/modules/commands/queries.py: Ditto.
+ * Scripts/modules/commands/queues.py: Ditto.
+ * Scripts/modules/commands/upload.py: Ditto.
+ * Scripts/modules/scm_unittest.py:
+ - Fix to expect the \n after the path since echo adds an \n.
+
+2009-12-01 Yaar Schnitman <yaar@chromium.org>
+
+ build-webkit: Remove flex,bison,gperf check for chromium
+ https://bugs.webkit.org/show_bug.cgi?id=32043
+
+ * Scripts/webkitdirs.pm:
+
+2009-12-01 Chris Fleizach <cfleizach@apple.com>
+
+ Build fixage for Windows/GTK for DumpRenderTree.
+
+ WAI-ARIA: implement support for ARIA drag and drop
+ https://bugs.webkit.org/show_bug.cgi?id=32007
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::ariaIsGrabbed):
+ (AccessibilityUIElement::ariaDropEffects):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::ariaIsGrabbed):
+ (AccessibilityUIElement::ariaDropEffects):
+
+2009-12-01 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ WAI-ARIA: implement support for ARIA drag and drop
+ https://bugs.webkit.org/show_bug.cgi?id=32007
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getARIADropEffectsCallback):
+ (getARIAIsGrabbedCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::ariaIsGrabbed):
+ (AccessibilityUIElement::ariaDropEffects):
+
+2009-12-01 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Not reviewed. GTK DRT try 2.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+
+2009-12-01 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Not reviewed. Try to fix gtk DRT build.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+
+2009-12-01 David Levin <levin@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ check-webkit-style does not understand (Prefix)Foo(Custom|Gtk|CG|Mac).cpp including Foo.h
+ https://bugs.webkit.org/show_bug.cgi?id=32033
+
+ * Scripts/modules/cpp_style.py: Changed check for a possible primary header to use find
+ instead of startswith.
+ * Scripts/modules/cpp_style_unittest.py: Added a unit test for the new behavior.
+
+2009-12-01 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Not reviewed. Qt build almost fixed, DumpRenderTree should compile now as well.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.h: Update old function signature.
+
+2009-12-01 Nikolas Zimmermann <nzimmermann@rim.com>
+
+ Reviewed by Simon Fraser.
+
+ Add SVG animation test framework with 'snapshot' functionality
+ https://bugs.webkit.org/show_bug.cgi?id=31897
+
+ Add new 'sampleSVGAnimationForElementAtTime' DRT method,
+ used by the new SVG animation testing framework, implemented
+ for qt/gtk/win/mac.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (sampleSVGAnimationForElementAtTimeCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::sampleSVGAnimationForElementAtTime):
+
+2009-12-01 Adam Roben <aroben@apple.com>
+
+ Remove user content before running each test on Windows
+
+ Fixes <http://webkit.org/b/31479> Make websocket tests work on Windows
+
+ Reviewed by Alexey Proskuryakov.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting): Remove all user content
+ before each test, which matches Mac.
+
+2009-12-01 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Make pywebsocket log errors to a file
+ https://bugs.webkit.org/show_bug.cgi?id=31604
+
+ * Scripts/run-webkit-tests: Log output to a pywebsocket_log.txt file in results directory
+ (by passing the path to the server via a recently added -l option).
+
+2009-12-01 Adam Roben <aroben@apple.com>
+
+ Fix tests that use the TestNetscapePlugin in Debug_Internal builds
+
+ Reviewed by Ada Chan.
+
+ Fixes <http://webkit.org/b/32027> REGRESSION (r49705): Tests that use
+ TestNetscapePlugin fail in Debug_Internal builds
+
+ * DumpRenderTree/win/DumpRenderTree.cpp: Use the "_Debug" plugin
+ directory in Debug and Debug_All builds, but not in Debug_Internal
+ builds.
+
+2009-12-01 Adam Roben <aroben@apple.com>
+
+ Re-enable DRT's watchdog timer on Windows
+
+ It was accidentally disabled in r50907.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setWaitToDump): Remove a "false &&" that snuck
+ into an if condition.
+
+2009-12-01 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ check-webkit-style complains about #imports with / in them
+ https://bugs.webkit.org/show_bug.cgi?id=32022
+
+ We need to exclude #import directives in addition to #include from the
+ binary operator whitespace checks.
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-11-30 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ check-webkit-style is slightly too verbose
+ https://bugs.webkit.org/show_bug.cgi?id=32010
+
+ check-webkit-style prints out a bunch of "done" lines that seem redundant,
+ especially for the style-queue.
+
+ * Scripts/modules/cpp_style.py:
+
+2009-11-30 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Eric Seidel.
+
+ [GTK] Moved the functions that are closing the result log of the
+ tests to the last line of the runTest function, this avoids
+ reporting crashes in the wrong test if there is a problem when
+ reseting the state after the test.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump):
+ (runTest):
+
+2009-11-30 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Geoffrey Garen.
+
+ Fix for https://bugs.webkit.org/show_bug.cgi?id=31286
+ fast/js/date-proto-generic-invocation breaks another test
+
+ Don't cache JSClassRefs, a change to the prototype chain will
+ last between tests.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (AccessibilityController::getJSClass):
+ * DumpRenderTree/GCController.cpp:
+ (GCController::getJSClass):
+ * DumpRenderTree/GCController.h:
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::getJSClass):
+
+2009-11-30 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Update pywebsocket to 0.4.2.1.
+ This is to fix a bug that some messages are logged to stderr even when the log file is specified.
+ https://bugs.webkit.org/show_bug.cgi?id=31976
+
+ * pywebsocket/mod_pywebsocket/standalone.py:
+ * pywebsocket/setup.py:
+
+2009-11-30 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Generate pass messages for style-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31995
+
+ With this change, the style-queue posts "pass" messages to bugs as
+ well. Also, added more information to the state store w.r.t. passing
+ and failing.
+
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/patchcollection.py:
+
+2009-11-30 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Simon Fraser.
+
+ Check for WEBKIT_TESTFONTS environment variable in
+ run-webkit-tests, for GTK+, to have a more prominent error
+ message.
+
+ * Scripts/run-webkit-tests:
+
+2009-11-30 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ update-webkit --chromium forces gclient sync
+
+ https://bugs.webkit.org/show_bug.cgi?id=31967
+
+ * Scripts/update-webkit-chromium:
+
+2009-11-29 Eric Seidel <eric@webkit.org>
+
+ Add Erik Arvidsson to committers.py since by r51326 he clear has commit rights.
+
+ * Scripts/modules/committers.py:
+
+2009-11-29 Eric Seidel <eric@webkit.org>
+
+ No review, just adding missing svn property.
+
+ Set svn:executable property on new scripts.
+ These were added by commit-queue commits, but the executable
+ property was lost due to a bug in svn-apply:
+ https://bugs.webkit.org/show_bug.cgi?id=27204
+
+ * Scripts/update-webkit-chromium: Added property svn:executable.
+ * Scripts/validate-committer-lists: Added property svn:executable.
+
+2009-11-29 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Need a way to validate that committers.py includes all committers/reviewers
+ https://bugs.webkit.org/show_bug.cgi?id=30970
+
+ Add a script which knows how to compare our public committer/reviewer
+ lists and show discrepancies between them.
+
+ Validates mailing lists vs. committers.py:
+ - committers.py committers missing from webkit-committers@lists
+ - webkit-committers@lists members missing from committers.py
+ - committers.py reviewers missing from webkit-reviewers@lists
+ - webkit-reviewers@lists members missing from committers.py
+ - webkit-reviewers@lists members missing from committers.py reviewer list
+
+ Validates committers.py vs. trunk/ SVN history:
+ - committers who have not committed in over a year
+ - SVN committers missing from committers.py
+ - committers.py members who have no record in SVN.
+
+ All of these lists still show "false positives" until a few more committers.py updates are made, like:
+ https://bugs.webkit.org/show_bug.cgi?id=31366
+
+ * Scripts/validate-committer-lists: Added.
+
+2009-11-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] style-queue sends ~100 requests to QueueStatusServer every 5 minutes
+ https://bugs.webkit.org/show_bug.cgi?id=31950
+
+ Now we cache the last status that we get back from QueueStatusServer.
+ Eventually we'll have to do something more fancy if we want to support
+ a "try again" button on QueueStatusServer, but we can cross that bridge
+ when we come to it.
+
+ * Scripts/modules/patchcollection.py:
+
+2009-11-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ StyleQueue scans ~100 bug pages every 5 minutes
+ https://bugs.webkit.org/show_bug.cgi?id=31947
+
+ Instead of getting the pending-review attachment ids by scanning each
+ bug (which results in a network request), we should just get them all
+ from webkit.org/pending-review in one shot.
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/bugzilla_unittest.py:
+ * Scripts/modules/commands/queries.py:
+ * Scripts/modules/commands/queries_unittest.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/mock_bugzillatool.py:
+ * Scripts/modules/patchcollection.py:
+
+2009-11-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] CC webkit-bot-watchers whenever the bots touch bugs
+ https://bugs.webkit.org/show_bug.cgi?id=31952
+
+ The mailing list is open for anyone to subscribe.
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/commands/queues.py:
+
+2009-11-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] style-queue should report style errors to bugzilla
+ https://bugs.webkit.org/show_bug.cgi?id=31945
+
+ Currently, we're just logging the style errors locally. With this
+ patch we'll actually log the errors to bugzilla. Note: I plan to run
+ with the "local-only" logging during development.
+
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/scm.py:
+
+2009-11-28 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] style-queue shouldn't reject patches from the commit-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31944
+
+ Currently the style-queue subprocess gets confused and thinks its the
+ commit-queue. If the patch has an error, it rejects it from the
+ commit-queue. Instead, we should have style-queue specific logic.
+ This patch doesn't add that logic, but it gives us a callback we can
+ use to add that logic.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/landingsequence.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by Eric Seidel.
+
+ Rename CommitQueueStatus to QueueStatusServer to allow for more queues.
+
+ * CommitQueueStatus: Removed.
+ * CommitQueueStatus/app.yaml: Removed.
+ * CommitQueueStatus/filters: Removed.
+ * CommitQueueStatus/filters/__init__.py: Removed.
+ * CommitQueueStatus/filters/webkit_extras.py: Removed.
+ * CommitQueueStatus/index.html: Removed.
+ * CommitQueueStatus/index.yaml: Removed.
+ * CommitQueueStatus/queue_status.py: Removed.
+ * CommitQueueStatus/stylesheets: Removed.
+ * CommitQueueStatus/stylesheets/main.css: Removed.
+ * CommitQueueStatus/update_status.html: Removed.
+ * QueueStatusServer: Copied from WebKitTools/CommitQueueStatus.
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ style-queue should only process each patch once
+ https://bugs.webkit.org/show_bug.cgi?id=31939
+
+ Actually address reviewer comments!
+
+ * Scripts/bugzilla-tool:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] style-queue fails to apply a bunch of patches for no reason
+ https://bugs.webkit.org/show_bug.cgi?id=31942
+
+ By passing --non-interactive to check-style, we convince check-style
+ to pass --force to svn-apply, which lets it apply more patches.
+
+ * Scripts/modules/commands/queues.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Support --status-host in style-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31941
+
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/statusbot.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ style-queue should only process each patch once
+ https://bugs.webkit.org/show_bug.cgi?id=31939
+
+ Before processing a patch, the try-queues now ask the web service
+ whether they have already processed the patch. This is an initial cut
+ of this functionality. I expect we're make it richer over time.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/commands/queues.py:
+ * Scripts/modules/patchcollection.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ PatchStatus does not return status
+ https://bugs.webkit.org/show_bug.cgi?id=31938
+
+ We need to parse attachment_id as an int. Otherwise, we can't find
+ anything in the datastore.
+
+ * CommitQueueStatus/queue_status.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Make commit-queue status not throw an exception where there is not
+ status
+ https://bugs.webkit.org/show_bug.cgi?id=31936
+
+ We need to actually fetch the results of the query to see what's in the
+ datastore.
+
+ * CommitQueueStatus/queue_status.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] unit test ApplyPatches and ApplyAttachment
+ https://bugs.webkit.org/show_bug.cgi?id=31935
+
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/download_unittest.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Unit test download commands
+ https://bugs.webkit.org/show_bug.cgi?id=31923
+
+ Adds download_unittest and fixes a bug found while testing.
+
+ * Scripts/modules/commands/commandtest.py:
+ * Scripts/modules/commands/download.py:
+ Fixed a bug where we'd throw an error because [].append returns
+ None.
+ * Scripts/modules/commands/download_unittest.py: Added.
+ * Scripts/modules/mock_bugzillatool.py:
+ * Scripts/run-webkit-unittests:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix found while writing unit tests.
+
+ * Scripts/modules/commands/download.py:
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitLandingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=31904
+
+ Step 6: Kill the rest.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/commands/queries.py:
+ * Scripts/modules/commands/upload.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/scm.py:
+ * Scripts/modules/webkitlandingscripts.py: Removed.
+
+2009-11-27 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Unit test upload commands
+ https://bugs.webkit.org/show_bug.cgi?id=31903
+
+ Adds unit tests for all but two of the upload commands. The two
+ remaining ones are more difficult. I'll return to them later. The
+ goal of these tests is just to run the commands. We can test more
+ detailed behavior later.
+
+ * Scripts/modules/commands/commandtest.py:
+ * Scripts/modules/commands/upload.py:
+ * Scripts/modules/commands/upload_unittest.py:
+ * Scripts/modules/mock.py: Added.
+ * Scripts/modules/mock_bugzillatool.py:
+
+2009-11-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitLandingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=31904
+
+ Step 5: Kill run_and_throw_if_fail.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/processutils.py: Added.
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitLandingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=31904
+
+ Step 4: Kill run_webkit_script.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitLandingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=31904
+
+ Step 3: Kill build_webkit.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitLandingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=31904
+
+ Step 2: Kill ensure_builders_are_green.
+
+ * Scripts/modules/buildsteps.py:
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [bzt] Kill WebKitLandingScripts
+ https://bugs.webkit.org/show_bug.cgi?id=31904
+
+ Step 1: Kill prepare_clean_working_directory and run_webkit_tests.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/buildsteps.py: Added.
+ * Scripts/modules/commands/download.py:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-26 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Remove directory prefixes from linux commands
+
+ SCM unittests can cause errors on some systems if we use absolute reference to
+ the commands, so directory prefixes have been removed.
+
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-21 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Link DumpRenderTree to the Qt Ui Tools
+ https://bugs.webkit.org/show_bug.cgi?id=31203
+
+ Implement QWebPage::createPlugin using the Qt Ui Tools
+ to be able to create classes like QProgressBar from within
+ the <object></object> tags This is required for the
+ new automatic test of Qt Plugins.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::createPlugin):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+
+2009-11-25 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Eric Seidel.
+
+ Update pywebsocket to 0.4.2
+
+ Update pywebsocket to 0.4.2
+ https://bugs.webkit.org/show_bug.cgi?id=31861
+
+ * pywebsocket/example/echo_client.py:
+ * pywebsocket/example/echo_wsh.py:
+ * pywebsocket/mod_pywebsocket/__init__.py:
+ * pywebsocket/mod_pywebsocket/dispatch.py:
+ * pywebsocket/mod_pywebsocket/msgutil.py:
+ * pywebsocket/mod_pywebsocket/standalone.py:
+ * pywebsocket/setup.py:
+ * pywebsocket/test/test_dispatch.py:
+ * pywebsocket/test/test_msgutil.py:
+
+2009-11-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Add unit test for mark-fixed
+ https://bugs.webkit.org/show_bug.cgi?id=31896
+
+ * Scripts/modules/commands/commandtest.py: Added.
+ * Scripts/modules/commands/queries_unittest.py:
+ * Scripts/modules/commands/upload_unittest.py: Added.
+ * Scripts/modules/mock_bugzillatool.py:
+ * Scripts/run-webkit-unittests:
+
+2009-11-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ bugzilla-tool should have a mark-fixed command
+ https://bugs.webkit.org/show_bug.cgi?id=31853
+
+ Pretty simple stuff.
+
+ * Scripts/modules/commands/upload.py:
+
+2009-11-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ 'bugzilla-tool help' should only show common commands like how 'git help' does
+ https://bugs.webkit.org/show_bug.cgi?id=31772
+
+ I also took this opportunity to make 'help' a real Command.
+ Making 'help' a real command required adding Command.tool (which we've wanted to do for a while).
+
+ * Scripts/bugzilla-tool:
+ - change should_show_command_help to should_show_in_main_help
+ * Scripts/modules/commands/download.py:
+ - Mark commands as being shown in main help or not.
+ - show_in_main_help = False is not required (default is false),
+ but it seemed to make the commands more self-documenting.
+ * Scripts/modules/commands/queries.py: ditto
+ * Scripts/modules/commands/queues.py: ditto
+ * Scripts/modules/commands/upload.py: ditto
+ * Scripts/modules/multicommandtool.py:
+ - Make Command hold a pointer to tool in self.tool. Most Command
+ subclasses do not take advantage of this yet, but it was required
+ for HelpCommand to be able to reach the tool from _help_epilog().
+ - Move MultiCommandTool._standalone_help_for_command to Command.standalone_help
+ - Move MultiCommandTool._help_epilog to Command._help_epilog
+ - Move "help" logic into HelpCommand.execute()
+ - Change should_show_command_help to should_show_in_main_help and add a default implementation.
+ * Scripts/modules/multicommandtool_unittest.py:
+ - Test hiding of Commands in --help, and that all commands are shown in 'help --all-commands'
+
+2009-11-25 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Patch by Mark Rowe.
+
+ The buildbots are failing on Windows because when they were upgraded
+ to 4.0.4, Apple Application Support was not in their path. Add it to
+ the path to fix the buildots.
+
+ * Scripts/webkitdirs.pm:
+
+2009-11-25 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ run-webkit-tests doesn't accept directories/files with --skipped=only parameter
+ https://bugs.webkit.org/show_bug.cgi?id=31799
+
+ * Scripts/run-webkit-tests: Fixed.
+
+2009-11-25 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Change run_command to give back stderr by default
+ https://bugs.webkit.org/show_bug.cgi?id=31734
+
+ Change run_command to give back stderr by default.
+ Set run_commands's 'svn-create-patch' calling to put only the stdout into the patches.
+ Change the related unittest call.
+
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Centralize required argument parsing in Command
+ https://bugs.webkit.org/show_bug.cgi?id=31872
+
+ * Scripts/modules/commands/download.py: remove custom required arg message.
+ * Scripts/modules/commands/upload.py: ditto.
+ * Scripts/modules/multicommandtool.py:
+ - Add _parse_required_arguments.
+ - Pass program name off to OptionParser.
+ - Add name() for access to tool name.
+ - Add check_arguments_and_execute and make it return a return code.
+ - Replace a couple uses of + with %.
+ * Scripts/modules/multicommandtool_unittest.py: test _parse_required_arguments
+
+2009-11-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Abstract out capturing stdout/stderr into a new OutputCapture class for re-use among the various unit tests.
+ https://bugs.webkit.org/show_bug.cgi?id=31870
+
+ * Scripts/modules/commands/queries_unittest.py: Use the new class.
+ * Scripts/modules/multicommandtool_unittest.py: Ditto.
+ * Scripts/modules/outputcapture.py: Added.
+
+2009-11-24 Dmitry Titov <dimich@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Add ENABLE_SHARED_SCRIPT feature define and flag for build-webkit
+ https://bugs.webkit.org/show_bug.cgi?id=31444
+
+ * Scripts/build-webkit:
+
+2009-11-24 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ Changes the way 3D_RENDERING and ACCELERATED_COMPOSITING related tests are excluded
+ https://bugs.webkit.org/show_bug.cgi?id=27314
+
+ Now the script allows the directories with these tests to be included on all
+ platforms but Mac, where they behave the same as always. For all other platforms
+ the tests need to be excluded using the Skipped files, which is currently done
+ for all platforms (including win since we're not turned on yet)
+
+ * Scripts/webkitdirs.pm:
+
+2009-11-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ queries_unittest.py should test command output
+ https://bugs.webkit.org/show_bug.cgi?id=31845
+
+ * Scripts/modules/commands/queries_unittest.py:
+ - Capture stdout and stderr and compare with expected strings.
+
+2009-11-24 Simon Fraser <simon.fraser@apple.com>
+
+ No Review.
+
+ Fix spelling error ("depenedencies").
+
+ * Scripts/build-webkit:
+
+2009-11-24 Mark Rowe <mrowe@apple.com>
+
+ Land the configuration that includes the two debug GTK Linux builders.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2009-11-24 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/31840> bisect-builds broke after r50080
+
+ Reviewed by Dan Bernstein.
+
+ * Scripts/bisect-builds:
+ (mountAndRunNightly): Switched back to using backticks to run
+ the hdiutil command since exec() will terminate the existing
+ script, which is not what we want. Store the output of
+ File::Spec->devnull() in a variable for use in the hdiutil
+ detach commands.
+
+2009-11-23 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Include "config.h" to meet Coding Style Guidelines
+ https://bugs.webkit.org/show_bug.cgi?id=31792
+
+ * DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp:
+ * DumpRenderTree/qt/jsobjects.cpp:
+ * DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp:
+
+2009-11-23 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Oliver Hunt.
+
+ Implement new required function to pass test we used to pass. This
+ change is required since r51294.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+
+2009-11-23 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] DRT: dumpBackForwardList() does not work properly with non-file URLs.
+ https://bugs.webkit.org/show_bug.cgi?id=31775
+
+ LayoutTestController::dumpBackForwardList() should work with local URLs
+ as well as with normal URLs (in http tests for instance).
+ Currently it does not output the latter properly.
+
+ Unskip a bunch of passing http/navigation tests.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::dumpHistoryItem):
+
+2009-11-22 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ ARIA: support aria-flowto
+ https://bugs.webkit.org/show_bug.cgi?id=31762
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (ariaFlowToElementAtIndexCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::ariaFlowToElementAtIndex):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::ariaFlowToElementAtIndex):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::ariaFlowToElementAtIndex):
+
+2009-11-22 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ [Qt] fast/history/back-forward-reset-after-error-handling.html failing due to WorkQueue not being un-frozen
+ https://bugs.webkit.org/show_bug.cgi?id=31638
+
+ Unfreeze WorkQueue after each test execution.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2009-11-22 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Adam Barth.
+
+ [Qt] DumpRenderTree should explicitly ignore any SSL certificate errors
+ for localhost and 127.0.0.1.
+ https://bugs.webkit.org/show_bug.cgi?id=31783
+
+ Unskip the http/tests/ssl/verify-ssl-enabled.php test, which is passing now.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::NetworkAccessManager::NetworkAccessManager):
+ (WebCore::NetworkAccessManager::sslErrorsEncountered):
+ (WebCore::WebPage::WebPage):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+
+2009-11-22 Chris Evans <cevans@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Disable access to file:/// directory listings
+ https://bugs.webkit.org/show_bug.cgi?id=31329
+
+ Implemented setAllowUniversalAccessFromFileURLs to support testing of
+ file URL security.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setAllowUniversalAccessFromFileURLsCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setAllowUniversalAccessFromFileURLs):
+
+2009-11-22 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Fix the timeout of fast/frames/frame-navigation.html
+ https://bugs.webkit.org/show_bug.cgi?id=31638
+
+ The test is timeouting, because it uses the WorkQueue to load a document in one
+ of the child frames and once the loading is finished, the DRT does not dump the
+ tree. This is because it waits for the QWebFrame::loadFinished() signal from
+ the main frame, while it should connect to QWebPage::loadFinished().
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2009-11-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool --help spews way too much text
+ https://bugs.webkit.org/show_bug.cgi?id=31771
+
+ * Scripts/bugzilla-tool:
+ - Remove self.cached_scm initialization hack.
+ * Scripts/modules/buildbot.py:
+ - Make default_host accessible to callers.
+ * Scripts/modules/commands/download.py:
+ - Phrase help for all commands consistently and remove spurious help text punctuation.
+ * Scripts/modules/commands/queries.py: Ditto.
+ * Scripts/modules/commands/queues.py: Ditto.
+ * Scripts/modules/commands/upload.py: Ditto.
+ * Scripts/modules/multicommandtool.py:
+ - Add HelpPrintingOptionParser.format_epilog to replace
+ NonWrappingEpilogIndentedHelpFormatter and allow us to lazily initialize
+ per-command help (thus removing the need for the cached_scm hack in BugzillaTool).
+ - Make --help only show a list of commands like "svn help" and "git help" do --
+ previously --help was listing all commands and options.
+ - Sort list of commands alphabetically.
+
+2009-11-21 Eric Seidel <eric@webkit.org>
+
+ No review. Fixing a typo from the previous patch for bug 31767.
+
+ AbstractQueue.run_bugzilla_tool throws an exception
+ https://bugs.webkit.org/show_bug.cgi?id=31769
+
+ * Scripts/modules/commands/queues.py:
+
+2009-11-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue fails to run with "permissions error" due to bad bugzilla-tool path
+ https://bugs.webkit.org/show_bug.cgi?id=31767
+
+ What we really want to test is BugzillaTool.path() instead of TrivialTool.path().
+ Since we don't have a good way to test BugzillaTool pieces, I've
+ left out a test for now.
+
+ * Scripts/bugzilla-tool:
+ - Add a path() implementation to expose bugzilla-tool's __file__ path to commit-queue.
+ * Scripts/modules/commands/queues.py:
+ - Use tool.path() instead of __file__.
+ * Scripts/modules/multicommandtool.py:
+ - Add a new path() method to MultiComandTool.
+ * Scripts/modules/multicommandtool_unittest.py:
+ - Provide a path() method. Little point in testing this mock implementation.
+
+2009-11-21 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix. Turns out I was testing the wrong copy of
+ WebKitTools.
+
+ * Scripts/modules/commands/download.py:
+
+2009-11-21 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Convert check-style to use LandingSequence
+ https://bugs.webkit.org/show_bug.cgi?id=31763
+
+ Instead of manipulating the working copy by hand, we should use the
+ LandingSequence in CheckStyle. This will make this code eaiser to
+ test.
+
+ * Scripts/modules/commands/download.py:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Unit test query commands
+ https://bugs.webkit.org/show_bug.cgi?id=31755
+
+ These tests are pretty rough, but hopefully they'll grow.
+
+ * Scripts/modules/commands/queries_unittest.py: Added.
+ * Scripts/modules/mock_bugzillatool.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-11-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Fix a bunch of unit test regressions from our recent bugzilla-toll hacking
+ https://bugs.webkit.org/show_bug.cgi?id=31758
+
+ * Scripts/modules/multicommandtool.py:
+ - Allow passing of explicit commands to MultiCommandTool.__init__
+ * Scripts/modules/multicommandtool_unittest.py:
+ - Use new Command.name naming system.
+ - Test Command auto-discovery.
+ * Scripts/modules/workqueue.py:
+ - bug_id no longer exists, use patch['bug_id'] instead.
+ * Scripts/modules/workqueue_unittest.py:
+ - WorkQueues require names now.
+ - should_proceed_with_work_item must return a patch object.
+
+2009-11-20 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ WAI-ARIA: add support for aria-owns
+ https://bugs.webkit.org/show_bug.cgi?id=31702
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (ariaOwnsElementAtIndexCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::ariaOwnsElementAtIndex):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::ariaOwnsElementAtIndex):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::ariaOwnsElementAtIndex):
+
+2009-11-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Fix exception thrown when running the commit-queue.
+
+ * Scripts/modules/statusbot.py: patch is optional.
+ * Scripts/modules/workqueue.py: WorkQUeue requires a name.
+
+2009-11-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Teach the StatusBot how to support more than just the commit-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31754
+
+ * Scripts/modules/workqueue.py: Another typo.
+
+2009-11-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Teach the StatusBot how to support more than just the commit-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31754
+
+ * Scripts/modules/commands/queues.py: Fix silly typo.
+
+2009-11-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Teach the StatusBot how to support more than just the commit-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31754
+
+ * CommitQueueStatus/index.yaml:
+ - Add indices required for the new queries.
+ * CommitQueueStatus/queue_status.py:
+ - Add a patch-status page and move update_status to update-status.
+ - Only display "commit-queue" status records for the commit-queue.
+ - Add support for a queue_name property on status records.
+ - Fix _int_from_request to actually work.
+ * CommitQueueStatus/update_status.html:
+ - Add support for a queue_name on status records.
+ - Remove unused list of bug ids.
+ * Scripts/modules/commands/queues.py
+ - Make the queues pass the patch instead of the bug_id to StatusBot.
+ * Scripts/modules/statusbot.py:
+ - Support passing the queue_name to the status updates.
+ - Support fetching patch status with patch_status().
+ * Scripts/modules/workqueue.py:
+ - Pass the patch to the StatusBot instead of the bug_id.
+ - Let WorkQueues have a name.
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move bugzilla-tool commands into their own file
+ https://bugs.webkit.org/show_bug.cgi?id=31752
+
+ This will let us write unit tests.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/commands/__init__.py: Added.
+ * Scripts/modules/commands/download.py: Added.
+ * Scripts/modules/commands/queries.py: Added.
+ * Scripts/modules/commands/queues.py: Added.
+ * Scripts/modules/commands/upload.py: Added.
+ * Scripts/modules/grammar.py: Added.
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ BuildQueue should check if the tree is currently buildable
+ https://bugs.webkit.org/show_bug.cgi?id=31744
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move prepare_clean_working_directory into the LandingSequence
+ https://bugs.webkit.org/show_bug.cgi?id=31743
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/landingsequence.py:
+
+2009-11-20 Yael Aharon <yael.aharon@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ NPN_ReloadPlugins does not reload the page even if reloadPages is true.
+ https://bugs.webkit.org/show_bug.cgi?id=30460
+
+ Added code for calling NPN_ReloadPlugins with reloadPages true and false.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginInvoke):
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Pass the port information to the child process
+ https://bugs.webkit.org/show_bug.cgi?id=31736
+
+ We need to do this so the child process knows what to build!
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitport.py:
+ * Scripts/modules/webkitport_unittest.py:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Support Qt port in build-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31733
+
+ * Scripts/bugzilla-tool:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Implement a build-queue
+ https://bugs.webkit.org/show_bug.cgi?id=31725
+
+ Currently this just builds the first 10 patches in the review queue.
+ We'll want to do something smarter soon.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Make commit-queue and style-queue show up in help
+ https://bugs.webkit.org/show_bug.cgi?id=31724
+
+ We need to store their names on their class to make these commands
+ properly register themselves with MultiCommandTool.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Implement bugzilla-tool build-attachment
+ https://bugs.webkit.org/show_bug.cgi?id=31722
+
+ This command builds an attachment from bugzilla. It leaves the built
+ patch in the working copy.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/landingsequence.py:
+ * Scripts/modules/webkitlandingscripts.py:
+
+2009-11-20 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] DRT release event does not create the state correctly
+ https://bugs.webkit.org/show_bug.cgi?id=31717
+
+ * WebKitTools/DumpRenderTree/gtk/EventSender.cpp:
+
+2009-11-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ MultiCommandTool should find Command objects automatically instead of with a manual list
+ https://bugs.webkit.org/show_bug.cgi?id=31710
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/multicommandtool.py:
+ - Use some wild python-fu to crawl all the known subclasses of Command.
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix. Added missing import.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Unreviewed "build" fix. I failed to update LandingSequence.test
+ properly.
+
+ * Scripts/modules/landingsequence.py:
+
+2009-11-20 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Create LandingSequence as the all-sing, all-dance landing class
+ https://bugs.webkit.org/show_bug.cgi?id=31709
+
+ Client can inherit from this class to carefully control exactly which
+ steps they wish to have happen in the landing sequence.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/landingsequence.py: Added.
+ * Scripts/modules/webkitlandingscripts.py: Added.
+
+2009-11-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Abstract AbstractPatchProcessingCommand from AbstractPatchLandingCommand
+ https://bugs.webkit.org/show_bug.cgi?id=31707
+
+ This is to help when we implement build-attachment.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Support Qt port in bugzilla-tool
+ https://bugs.webkit.org/show_bug.cgi?id=31701
+
+ Now we support building with Qt!
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/webkitport.py: Added.
+ * Scripts/modules/webkitport_unittest.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-11-19 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Remove inserting stderr into patch in bugzilla-tool
+ https://bugs.webkit.org/show_bug.cgi?id=29914
+
+ Modify SCM python module's run_command function to avoid return of stderr
+ by default, so stderr won't be inserted into the patches.
+ Modify the related unit test.
+
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool needs per-command help
+ https://bugs.webkit.org/show_bug.cgi?id=31697
+
+ Added support for "bugzilla-tool help command-name"
+ and a unit test to make sure it works.
+
+ * Scripts/modules/multicommandtool.py:
+ * Scripts/modules/multicommandtool_unittest.py:
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Move MultiCommandTool and Command into a separate file and add some basic unit tests
+ https://bugs.webkit.org/show_bug.cgi?id=31695
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/multicommandtool.py: Added.
+ * Scripts/modules/multicommandtool_unittest.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ No review, just adding a FIXME.
+
+ Split out command parsing and help printing from BugzillaTool
+ https://bugs.webkit.org/show_bug.cgi?id=31688
+
+ * Scripts/bugzilla-tool: Add an extra comment about current design failures.
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Split out command parsing and help printing from BugzillaTool
+ https://bugs.webkit.org/show_bug.cgi?id=31688
+
+ * Scripts/bugzilla-tool:
+ - Add new MultiCommandTool class to contain option parsing and help printing logic.
+ - Rename private methods to use _ pattern.
+ - MultiCommandTool has two abstract methods should_show_command_help and should_execute_command.
+ -
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Re-factor help printing to use modern python idioms
+ https://bugs.webkit.org/show_bug.cgi?id=31685
+
+ * Scripts/bugzilla-tool:
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ commit-queue empty queue logs twice
+ https://bugs.webkit.org/show_bug.cgi?id=31679
+
+ * Scripts/bugzilla-tool:
+
+2009-11-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ bugzilla-tool's reviewer/committer rejection message should be clearer
+ https://bugs.webkit.org/show_bug.cgi?id=31126
+
+ Add more explanatory prose to bugzilla-tool's flag permission rejection message.
+
+ * Scripts/modules/bugzilla.py:
+
+2009-11-19 Eric Z. Ayers <zundel@google.com>
+
+ Reviewed by Pavel Feldman.
+
+ Forces a WM_PAINT event on calling layoutTestController.display()
+ in order to enable the timeline-paint.html test on Windows.
+ ::UpdateWindow() does not force an event becaue the window is
+ not visible.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31402
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (displayWebView):
+
+2009-11-19 Michelangelo De Simone <michelangelo@webkit.org>
+
+ No review needed.
+
+ Added myself to committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-11-19 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Bugzilla-tool command classes should match command names
+ https://bugs.webkit.org/show_bug.cgi?id=31666
+
+ I renamed all the commands except CommitMessageForCurrentDiff because
+ the new name would conflict with an existing class.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-19 Pavel Feldman <pfeldman@chromium.org>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ Web Inspector: Implement "show inspector" in WebKit GTK
+ API and enable console tests.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31669
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::showWebInspector):
+
+2009-11-19 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Minor refactoring + more documentation.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::clearHistory):
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2009-11-19 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Ignore websocket tests when --no-http is specified.
+ https://bugs.webkit.org/show_bug.cgi?id=31662
+
+ * Scripts/run-webkit-tests:
+
+2009-11-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Normalize ' and " in bugzilla-tool
+ https://bugs.webkit.org/show_bug.cgi?id=31655
+
+ We decided " is better than ' and we should be consistent.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-18 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Remove support for Qt v4.3 or older versions
+ https://bugs.webkit.org/show_bug.cgi?id=29469
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/ImageDiff.pro:
+
+2009-11-18 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ GitTest.test_create_binary_patch fails if /tmp is symlink
+ https://bugs.webkit.org/show_bug.cgi?id=31536
+
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-18 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Configuration for Chromium Build Slaves.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31442
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2009-11-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ workqueue.py results in totally broken commit-queue UI
+ https://bugs.webkit.org/show_bug.cgi?id=31645
+
+ * Scripts/bugzilla-tool:
+ - Remove unneeded use of PatchCollection.
+ - Grab a new copy of the cq'd patches every run of the queue.
+
+2009-11-18 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Anders Carlsson.
+
+ Make the Mac Geolocation API async.
+
+ Update DRT to use the new async Mac Geolocation API.
+
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:decidePolicyForGeolocationRequestFromOrigin:frame:listener:]):
+
+2009-11-18 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ Add and option to toggle HTML5 datalist support to build-webkit
+ https://bugs.webkit.org/show_bug.cgi?id=31599
+
+ * Scripts/build-webkit:
+
+2009-11-18 Kevin Watters <kevinwatters@gmail.com>
+
+ Reviewed by Kevin Ollivier.
+
+ Enable wx plugin support using the Windows implementation as a base.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31636
+
+ * wx/build/settings.py:
+
+2009-11-18 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Change the initialization order so that the controllers
+ will be created before exporting them to the JS DOM window.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2009-11-18 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Fix a code copy and paste error. m_page should be page.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::createWindow):
+
+2009-11-17 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ <http://webkit.org/b/31603> WebSocket server is confused if WebKit tests run from within /tmp on Mac OS X
+
+ * pywebsocket/mod_pywebsocket/dispatch.py: Use os.path.realpath as it returns the canonical path of a file.
+ This prevents symlinks from confusing the descendant check.
+
+2009-11-17 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ <http://webkit.org/b/31602> Failing to start the WebSocket server shouldn’t terminate entire test run
+
+ If the WebSocket server fails to start have DRT load an error page in place of tests that require the
+ server to be up rather than having run-webkit-tests abort immediately.
+
+ * Scripts/run-webkit-tests:
+
+2009-11-17 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ commit-queue is failing to set reviewer in ChangeLogs
+ https://bugs.webkit.org/show_bug.cgi?id=31592
+
+ * Scripts/bugzilla-tool: Clarify the "applying" log message.
+ * Scripts/modules/bugzilla.py:
+ - Add a new _validate_committer_and_reviewer function as a
+ temporary solution until we can make a real Attachment object
+ which knows how to fill in its committer/reviewer fields automatically.
+
+2009-11-17 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Unreviewed buildbot fix.
+
+ Revert part of earlier patch and add comment, as it
+ was causing timeouts on the buildbot.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::notifyDone):
+
+2009-11-17 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Oliver Hunt.
+
+ Make the timeout 15 sec as for the other DRT's and make
+ it print out the same output when a test timeout.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::waitUntilDone):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::timerEvent):
+
+2009-11-17 Joseph Pecoraro <joepeck@webkit.org>
+
+ Reviewed by Timothy Hatcher.
+
+ Fixed typos in comments.
+
+ * Scripts/modules/committers.py:
+
+2009-11-17 Pavel Feldman <pfeldman@chromium.org>
+
+ Reviewed by Timothy Hatcher.
+
+ Web Inspector: Make DRT show web inspector for tests in inspector/ folder.
+ - Updated DRT to show/close inspector for all tests under /inspector
+ - Introduced LayoutTestController::setTimelineProfilingEnabled and
+ WebInspector::setTimelineProfilingEnabled beside setJavaScriptProfilingEnabled
+ - Removed reload on each inspector test
+ - Renamed fast/inspector to fast/inspector-support in order not to trigger
+ inspector for those.
+ - Reimplemented timeline tests in order to get rid of reload there.
+ - Moved tests that don't require harness into the fast group.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31472
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setTimelineProfilingEnabledCallback):
+ (closeWebInspectorCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (shouldOpenWebInspector):
+ (runTest):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setTimelineProfilingEnabled):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (shouldOpenWebInspector):
+ (runTest):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setTimelineProfilingEnabled):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (shouldOpenWebInspector):
+ (runTest):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setTimelineProfilingEnabled):
+
+2009-11-17 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Incorrect use of JavaScriptCore API in DumpRenderTree
+ https://bugs.webkit.org/show_bug.cgi?id=31577
+
+ Return undefined rather than a literal null.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (setSelectedTextRangeCallback):
+ (incrementCallback):
+ (decrementCallback):
+ (showMenuCallback):
+
+2009-11-16 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ AX: aria-labelledby duplicates some of its WAI-ARIA label
+ https://bugs.webkit.org/show_bug.cgi?id=31565
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (titleUIElementCallback):
+ (getIsValidCallback):
+ (AccessibilityUIElement::getJSClass):
+
+2009-11-16 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ r50942 broke output from created windows. Make the
+ m_enableTextOutput a member of the DRT and not the
+ WebPage.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::javaScriptAlert):
+ (WebCore::WebPage::javaScriptConsoleMessage):
+ (WebCore::WebPage::javaScriptConfirm):
+ (WebCore::WebPage::javaScriptPrompt):
+ (WebCore::WebPage::acceptNavigationRequest):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::createWindow):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ (WebCore::DumpRenderTree::setTextOutputEnabled):
+ (WebCore::DumpRenderTree::isTextOutputEnabled):
+ (WebCore::WebPage::shouldInterruptJavaScript):
+ (WebCore::WebPage::isTextOutputEnabled):
+ (WebCore::WebPage::setViewGeometry):
+
+2009-11-16 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ Moved DumpRenderTree/gtk/TestNetscapePlugin to DumpRenderTree/unix/TestNetscapePlugin
+ as the implementation is being used by at least Qt and Gtk+.
+
+ Update buildsystems as well.
+
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+ * DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h:
+ * DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h:
+ * DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h:
+ * DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ * GNUmakefile.am:
+
+2009-11-16 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Disable wss until all platforms support pyOpenSSL
+
+ https://bugs.webkit.org/show_bug.cgi?id=31479
+
+ * Scripts/run-webkit-tests:
+
+2009-11-14 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Kenneth Christiansen.
+
+ [Qt] Implement load error pages support for Qt's DRT.
+ https://bugs.webkit.org/show_bug.cgi?id=31509
+
+ For now, it will not be a default feature, and layout tests
+ that want to make use of this have to explicitily call
+ 'handleErrorPages();' for the test source.
+
+ Any of the other DumpRenderTree's (mac, win and gtk)
+ support handling error pages. Qt's will be the first.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::supportsExtension):
+ (WebCore::WebPage::extension):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::reset):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ (LayoutTestController::shouldHandleErrorPages):
+ (LayoutTestController::handleErrorPages):
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Rename the --commit-queue flag on land-* now that the commit-queue needs no special treatment
+ https://bugs.webkit.org/show_bug.cgi?id=31549
+
+ Renamed --commit-queue to --non-interactive in most places
+ and remove the code in land-patches which is no longer needed.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ The commit-queue should use land-attachment
+ https://bugs.webkit.org/show_bug.cgi?id=31548
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Convert CommitQueue over to PatchCollection
+ https://bugs.webkit.org/show_bug.cgi?id=31547
+
+ Also fixes a bug in workqueue and adds a test!
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/workqueue.py:
+ * Scripts/modules/workqueue_unittest.py:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move StyleQueue over to using PatchCollection
+ https://bugs.webkit.org/show_bug.cgi?id=31544
+
+ That's what the class it's for.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/patchcollection.py:
+ * Scripts/modules/patchcollection_unittest.py:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool needs a land-attachment command
+ https://bugs.webkit.org/show_bug.cgi?id=31546
+
+ * Scripts/bugzilla-tool:
+ - Move all the logic into AbstractLandingCommand and
+ add a new LandAttachment command subclass.
+ - Split out _collect_patches_by_bug logging from _fetch_list_of_patches_to_land.
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Move more patch-landing code into WebKitLandingScripts in preparation for land-attachment
+ https://bugs.webkit.org/show_bug.cgi?id=31543
+
+ Just moving code and updating the one caller to use WebKitLandingScripts instead of 'self'.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Disable the style queue from posting to the commit queue status page.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Implement PatchCollection
+ https://bugs.webkit.org/show_bug.cgi?id=31541
+
+ This class holds a set of patches and lets clients iterate through
+ them. Optionally, clients can install a filter.
+
+ * Scripts/modules/patchcollection.py: Added.
+ * Scripts/modules/patchcollection_unittest.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool land-patches will close bugs with patches r=?
+ https://bugs.webkit.org/show_bug.cgi?id=28230
+
+ The commit-queue shouldn't close patches with outstanding reviews on them,
+ even if many reviewers seem to be against multi-patch bugs.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool check-style should work with attachment ids instead of bug ids
+ https://bugs.webkit.org/show_bug.cgi?id=31540
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ WorkQueue is the only place that should know about special exit codes
+ https://bugs.webkit.org/show_bug.cgi?id=31534
+
+ Move LandPatchesFromBugs.handled_error to WorkQueue.exit_after_handled_error
+ and add tests for handling exit codes.
+ I also cleaned up workqueue_unittest.py more.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/workqueue.py:
+ * Scripts/modules/workqueue_unittest.py:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Re-factor workqueue_unittest to allow for more than one test.
+ https://bugs.webkit.org/show_bug.cgi?id=31535
+
+ * Scripts/modules/workqueue_unittest.py:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ land-patches needs to be re-factored into smaller chunks
+ https://bugs.webkit.org/show_bug.cgi?id=31532
+
+ * Scripts/bugzilla-tool: fix a couple obvious typos.
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ land-patches needs to be re-factored into smaller chunks
+ https://bugs.webkit.org/show_bug.cgi?id=31532
+
+ The next patch will move these methods into WebKitLandingScripts.
+
+ * Scripts/bugzilla-tool:
+ - Split out _land_patch and _close_bug_if_no_active_patches.
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Fix silly copy-and-paste code. I am a terrible coder.
+
+ * Scripts/modules/bugzilla.py:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Implement a StyleQueue
+ https://bugs.webkit.org/show_bug.cgi?id=31537
+
+ The first iteration of the style queue only produces output locally.
+ There is also a limit of 10 patches because it's not that useful to
+ iterate through the entire review queue at this point. We can remove
+ the limit later.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/bugzilla.py:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Unit test WorkQueue
+ https://bugs.webkit.org/show_bug.cgi?id=31531
+
+ Adds basic unit testing for WorkQueue. Just runs through one cycle.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/statusbot.py:
+ * Scripts/modules/workqueue.py:
+ * Scripts/modules/workqueue_unittest.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool land-diff should know how to parse bug ids out of ChangeLogs
+ https://bugs.webkit.org/show_bug.cgi?id=31530
+
+ * Scripts/bugzilla-tool:
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool needs apply-attachment
+ https://bugs.webkit.org/show_bug.cgi?id=31528
+
+ * Scripts/bugzilla-tool:
+ - Add ApplyAttachment command.
+ - Abstract applying code into WebKitApplyingScripts.
+ - Rename setup_for_landing to prepare_clean_working_directory and make local_commit checking optional.
+ * Scripts/modules/bugzilla.py:
+ - Add fetch_attachment and bug_id_for_attachment_id.
+ * Scripts/modules/bugzilla_unittest.py:
+ - Add test for new parsing.
+ - Fix previous parsing test which broke with Adam's check-style patch (bug 31515).
+
+2009-11-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Document check-style's use of force_clean.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/scm.py:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move WorkQueue to its own file
+ https://bugs.webkit.org/show_bug.cgi?id=31529
+
+ WorkQueue and WorkQueueDelegate are separate concerns from
+ bugzilla-tool. Also added a missing include to logging.py.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/logging.py:
+ * Scripts/modules/workqueue.py:
+
+2009-11-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move OutputTee to logging.py.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/logging.py:
+
+2009-11-15 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Refactor bugzilla-tool to allow for multiple queues
+ https://bugs.webkit.org/show_bug.cgi?id=31513
+
+ Divide the commit queue class into three class to make creating
+ additional queues easier.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-15 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ svn-apply may not handle git patches created by bugzilla-tool
+ https://bugs.webkit.org/show_bug.cgi?id=31457
+
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-15 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ bugzilla-tool should post git binary diff
+ https://bugs.webkit.org/show_bug.cgi?id=31458
+
+ Add --binary option to Git.create_patch.
+
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-15 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Add bugzilla-tool check-style
+ https://bugs.webkit.org/show_bug.cgi?id=31515
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/bugzilla.py:
+
+2009-11-13 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Make the Qt Linux only --valgrind feature, suppress errors
+ defined in the SuppressedValgrindErrors file.
+
+ * Scripts/run-webkit-tests:
+
+2009-11-13 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Set the locale to C and not to the current one in use on the system.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2009-11-13 Adam Roben <aroben@apple.com>
+
+ Add support for
+ http/tests/security/isolatedWorld/didClearWindowObject.html
+
+ Fixes <http://webkit.org/b/31124> Tell the WebFrameLoadDelegate when
+ window objects in isolated worlds are cleared
+
+ Reviewed by Dave Hyatt.
+
+ * DumpRenderTree/mac/DumpRenderTreeMac.h: Declared worldIDForWorld.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate didClearWindowObjectInStandardWorldForFrame:]):
+ Added. Moved code here from -webView:didClearWindowObject:forFrame:.
+ (-[FrameLoadDelegate didClearWindowObjectForFrame:inIsolatedWorld:]):
+ Added. Sets a __worldID property on the global object whose value is
+ the ID of this world.
+ (-[FrameLoadDelegate webView:didClearWindowObjectForFrame:inScriptWorld:]):
+ Respond to this new delegate callback by calling through to one of the
+ above new methods.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (worldMap): Added. Returns a HashMap containing all the worlds we've
+ created.
+ (worldIDForWorld): Added. Returns the ID for this world, or 0 if we
+ haven't kept track of this world.
+ (LayoutTestController::evaluateScriptInIsolatedWorld): Use worldMap()
+ instead of declaring our own.
+
+ * DumpRenderTree/win/DumpRenderTreeWin.h: Declared worldIDForWorld.
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::didClearWindowObject): Moved code from hear to
+ didClearWindowObjectForFrameInStandardWorld.
+ (FrameLoadDelegate::didClearWindowObjectForFrameInScriptWorld):
+ Respond to this new delegate callback by calling through to one of the
+ below new methods.
+ (FrameLoadDelegate::didClearWindowObjectForFrameInIsolatedWorld):
+ Added. Sets a __worldID property on the gobal object whose value is
+ the ID of this world.
+ (FrameLoadDelegate::didClearWindowObjectForFrameInStandardWorld):
+ Added. Moved code here from didClearWindowObject.
+
+ * DumpRenderTree/win/FrameLoadDelegate.h: Added the
+ didClearWindowObjectForFrame* functions.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (worldMap): Added. Returns a HashMap containing all the worlds we've
+ created.
+ (worldIDForWorld): Added. Returns the ID of this world, or 0 if we
+ haven't kept track of this world.
+ (LayoutTestController::evaluateScriptInIsolatedWorld): Use worldMap()
+ instead of declaring our own.
+
+2009-11-13 Adam Roben <aroben@apple.com>
+
+ Finish replacing worldIDs with world objects
+
+ The only remaining use of worldIDs was in a method only used by DRT
+ for the isolated worlds tests.
+
+ Fixes <http://webkit.org/b/31414> Replace worldIDs with world objects
+
+ Reviewed by Mark Rowe.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::evaluateScriptInIsolatedWorld):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::evaluateScriptInIsolatedWorld):
+ Updated for changes to WebFrame. Now holds the map of worldID -> world
+ at this level instead of making WebKit do it.
+
+2009-11-13 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Ensure the DRT does not output anything until first test is run
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ * DumpRenderTree/qt/DumpRenderTree.h:
+
+2009-11-13 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Clear the undo stack in before each new test run.
+
+ Locally fixes 3 incorrect layouts, 9 timeouts and 7 crashes.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2009-11-13 Andras Becsi <becsi.andras@stud.u-szeged.hu>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Add WebKitUsesPageCachePreferenceKey overriding support to DRT's LayoutTestController.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::resetSettings):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::overridePreference):
+
+2009-11-13 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ Update committers.py based on svn records
+ https://bugs.webkit.org/show_bug.cgi?id=31366
+
+ This list was generated using validate-committer-lists from
+ https://bugs.webkit.org/show_bug.cgi?id=30970
+ and makes committers.py current for committers who have
+ committed in the last 3 years.
+
+ * Scripts/modules/committers.py:
+
+2009-11-12 Anantanarayanan G Iyengar <ananta@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ The document-open.html test was flaky at times. The test invokes the layout test plugin
+ which in its destroy stream handler opens a new document. This basically tears down the
+ stream and the associated plugin instance. The pluginLog function in the layout test
+ plugin attempts to retrieve the window script object on a torn down plugin instance
+ which crashed consistently on windows in the debugger. The functions which issue
+ these logs already have a valid window script object. We now have variants of the pluginLog
+ function which take in a window script object with and without variable arguments.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31067
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginLogWithWindowObject):
+ (pluginLogWithWindowObjectVariableArgs):
+ (pluginLog):
+ (notifyTestCompletion):
+ (testDocumentOpen):
+ (testWindowOpen):
+
+2009-11-12 Joanmarie Diggs <joanmarie.diggs@gmail.com>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30997
+ [Gtk] Implemment AtkDocument
+
+ Added testing support.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ * DumpRenderTree/AccessibilityUIElement.h:
+ (getDocumentEncodingCallback):
+ (getDocumentURICallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::documentEncoding):
+ (AccessibilityUIElement::documentURI):
+
+2009-11-12 Adam Roben <aroben@apple.com>
+
+ Replace worldIDs with world objects
+
+ Part of <http://webkit.org/b/31414> Implement new SPI for dealing with
+ user scripts/stylesheets and isolated worlds
+
+ Reviewed by Sam Weinig.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::addUserScript):
+ (LayoutTestController::addUserStyleSheet):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::addUserScript):
+ (LayoutTestController::addUserStyleSheet):
+ Changed these functions to create a new WebJSWorld each time they're
+ called and to pass that world to WebKit.
+
+2009-11-11 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ need to implement aria tree roles
+ https://bugs.webkit.org/show_bug.cgi?id=31284
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (disclosedRowAtIndexCallback):
+ (selectedRowAtIndexCallback):
+ (isEqualCallback):
+ (isAttributeSettableCallback):
+ (isActionSupportedCallback):
+ (disclosedByRowCallback):
+ (hierarchicalLevelCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ (AccessibilityUIElement::isEqual):
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::hierarchicalLevel):
+ (AccessibilityUIElement::disclosedRowAtIndex):
+ (AccessibilityUIElement::selectedRowAtIndex):
+ (AccessibilityUIElement::disclosedByRow):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::getChildAtIndex):
+ (AccessibilityUIElement::disclosedRowAtIndex):
+ (AccessibilityUIElement::selectedRowAtIndex):
+ (AccessibilityUIElement::titleUIElement):
+ (AccessibilityUIElement::parentElement):
+ (AccessibilityUIElement::disclosedByRow):
+ (AccessibilityUIElement::hierarchicalLevel):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::hierarchicalLevel):
+ (AccessibilityUIElement::disclosedRowAtIndex):
+ (AccessibilityUIElement::selectedRowAtIndex):
+ (AccessibilityUIElement::disclosedByRow):
+
+2009-11-11 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ svn-apply can not handle git binary diffs
+ https://bugs.webkit.org/show_bug.cgi?id=26830
+
+ Support "literal" type git binary diffs.
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/modules/scm_unittest.py:
+ * Scripts/svn-apply:
+
+2009-11-11 Dmitry Titov <dimich@chromium.org>
+
+ Not reviewed, removing duplicate entry for myself in committers.py.
+
+ * Scripts/modules/committers.py:
+
+2009-11-11 Alexey Proskuryakov <ap@apple.com>
+
+ Reviewed by Darin Adler and Mark Rowe.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31200
+ Tests in http/tests/security/mixedContent start to fail when new tests are added
+
+ * DumpRenderTree/mac/DumpRenderTree.mm: (dumpRenderTree): Added a workaround for Tiger bug.
+
+2009-11-11 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Jan Alonzo.
+
+ Create, and display a window for the inspector, for inspector
+ tests.
+
+ Need to also show/hide the inspector window to avoid having
+ problems with code assuming it is realized
+ https://bugs.webkit.org/show_bug.cgi?id=31347
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webInspectorShowWindow):
+ (webInspectorCloseWindow):
+ (webInspectorInspectWebView):
+ (createWebView):
+
+2009-11-11 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Unreviewed Qt buildbot fix.
+
+ My previous fix was wrong, so revert that change and fix it by
+ returning when the document of the frame has no document element.
+ Idea is borrowed from mac and win DRT.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::dumpFramesAsText):
+
+2009-11-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed byg Kenneth Rohde Christiansen.
+
+ Update Kenneth's committer record to include the email he
+ uses on lists.webkit.org.
+
+ * Scripts/modules/committers.py:
+
+2009-11-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Gustavo Noronha Silva.
+
+ Several committers use separate email addresses for bugzilla and svn.webkit.org
+ https://bugs.webkit.org/show_bug.cgi?id=31364
+
+ Update records for existing committers to include email addresses
+ used in svn.webkit.org and lists.webkit.org.
+ Most committers use the same email address in all 3 places, but some use
+ separate addresses. committers.py needs record of each of these addresses.
+
+ * Scripts/modules/committers.py:
+
+2009-11-11 Eric Seidel <eric@webkit.org>
+
+ No review, adding second email address for an existing committer.
+
+ Add Yong Li's second bugzilla account to his committer record.
+ See: https://bugs.webkit.org/show_bug.cgi?id=27371#c27
+
+ * Scripts/modules/committers.py:
+
+2009-11-11 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ If the frame has no innerText don't append it, and
+ do not add a newline which breaks some cross platform
+ results.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::dumpFramesAsText):
+
+2009-11-11 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Implement missing functionality in the Gtk/Qt TestNetscapePlugin.
+
+ * DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance):
+ (webkit_test_plugin_destroy_instance):
+ (webkit_test_plugin_destroy_stream):
+
+2009-11-11 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Implement the functionality needed by plugins/window-open.html
+
+ * DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance):
+ (webkit_test_plugin_set_window):
+
+2009-11-11 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Force -graphicssystem raster and -style windows when running DRT
+
+ * DumpRenderTree/qt/main.cpp:
+ * Scripts/run-webkit-tests:
+
+2009-11-11 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Compute correct library paths for Qt
+
+ * Scripts/webkitdirs.pm:
+
+2009-11-10 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <http://webkit.org/b/31200> Tests in http/tests/security/mixedContent start to fail when new tests are added
+
+ The first request to an HTTPS URL results in didFailProvisionalLoadWithError being called with an error
+ about the validity of the self-signed certificates used in the regression tests. We would then add the
+ host to the ignore list for SSL certificate errors and retry the request. If this happened during a test
+ that had enabled frame load delegate logging this would result in extra log messages being generated,
+ causing the test to fail.
+
+ We address this by explicitly ignoring SSL certificate errors for localhost and 127.0.0.1 before running any
+ tests.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpRenderTree):
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate webView:didFailProvisionalLoadWithError:forFrame:]):
+
+2009-11-10 Andras Becsi <becsi.andras@stud.u-szeged.hu>
+
+ Reviewed by Kenneth Rohde Christiansen.
+
+ [Qt] Remove obsolete scrollbar policy settings from DRT constructor.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2009-11-10 Philippe Normand <pnormand@igalia.com>
+
+ Reviewed by Jan Alonzo.
+
+ [GTK] Remove WebSocket configuration from WebKitWebSettings
+ https://bugs.webkit.org/show_bug.cgi?id=31244
+
+ Follow-up of r50724. Don't set the enable-web-socket property
+ anymore.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2009-11-10 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Rename 3D Canvas related classes to use WebGL prefix
+ https://bugs.webkit.org/show_bug.cgi?id=29095
+
+ Checkin new version of do-webcore-rename used to do the WebGL type rename,
+ and upate webkitdirs script to new method of testing for WebGL.
+
+ * Scripts/do-webcore-rename:
+ * Scripts/webkitdirs.pm:
+
+2009-11-09 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ Make do-webcore-rename work with git.
+
+ * Scripts/do-webcore-rename:
+
+2009-11-09 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Adding Kenneth to the reviewers list.
+
+ * Scripts/modules/committers.py:
+
+2009-11-09 Martin Robinson <martin.james.robinson@gmail.com>
+
+ Reviewed by Jan Alonzo.
+
+ [GTK] Expose Page::tabKeyCyclesThroughElements in the API
+ https://bugs.webkit.org/show_bug.cgi?id=30482
+
+ LayoutTestControllerGtk now uses the exposed
+ Page::tabKeyCyclesThroughElements API
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setTabKeyCyclesThroughElements):
+
+2009-11-08 Shu Chang <Chang.Shu@nokia.com>
+
+ Reviewed by Holger Freyther.
+
+ [Qt] Added support for key code 8 (backspace) in EventSenderQt.
+ This helps to pass the test case below. Also replaced hardcoded
+ code numbers with defined constants.
+ https://bugs.webkit.org/show_bug.cgi?id=31185
+
+ Test: editing/undo/undo-deleteWord.html
+
+ * DumpRenderTree/qt/EventSenderQt.cpp:
+ (EventSender::keyDown):
+
+2009-11-07 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Qt] [DRT] Fix wrong logic in LayoutTestController processWork
+ https://bugs.webkit.org/show_bug.cgi?id=31164
+
+ Fixed wrong logic to assume WorkQueue is done in QT's DRT.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::processWork):
+
+2009-11-05 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Qt][DRT] Replace queueScript by queueNonLoadingScript and queueLoadingScript method
+ https://bugs.webkit.org/show_bug.cgi?id=31158
+
+ By invoking a script queue'd by queueScript(), 'true' was beeing returned
+ always, which from WorkQueue prospective means that a load has been started
+ and the queue processing should stop and wait for the load to finish.
+ Spinning it off into a loading and a non-loading variants was the solution
+ adopted by Mac's DRT to work around this problem. The former keeps returning
+ 'true' while the later executes the script synchronously and returns 'false'
+ making it possible to the WorkQueue to proceed right away.
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::processWork):
+ (LayoutTestController::queueLoadingScript):
+ (LayoutTestController::queueNonLoadingScript):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+ * DumpRenderTree/qt/WorkQueueItem.h:
+ (LoadingScriptItem::LoadingScriptItem):
+ (LoadingScriptItem::invoke):
+ (NonLoadingScriptItem::NonLoadingScriptItem):
+ (NonLoadingScriptItem::invoke):
+
+2009-11-07 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Cameron Zwarich.
+
+ Invoke prepare-ChangeLog via an absolute path rather than assuming it can be found in PATH.
+
+ * Scripts/commit-log-editor:
+
+2009-11-07 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Fix <https://bugs.webkit.org/show_bug.cgi?id=28168>.
+ commit-log-editor does not support all the email address configurations that prepare-Changelog supports
+
+ Move logic for determining the name and email address to use in a ChangeLog entry from
+ prepare-ChangeLog to VCSUtils so that commit-log-editor can use it. It wants to check
+ whether the author of the patch matches committer, and therefore needs access to the
+ email address that would be used in a ChangeLog entry.
+
+ Based on a patch by Pierre d'Herbemont.
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/commit-log-editor:
+ * Scripts/prepare-ChangeLog:
+ * Scripts/webkitdirs.pm:
+
+2009-11-06 Anantanarayanan G Iyengar <ananta@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Added functionality to the layout test plugin to invoke document.open and
+ window.open with default arguments. The associated webkit bug is
+ https://bugs.webkit.org/show_bug.cgi?id=31067, which affects Chromium. Basically
+ window.open and document.open calls issued by NPAPI plugins via NPN_Invoke don't
+ work in Chromium (V8) if there is no calling javascript context. To achieve this
+ effect we invoke these functions in the layout test plugin in the NPP_SetWindow
+ for the window.open test case and in NPP_DestroyStream for the document.open test case.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (testDocumentOpen):
+ (testWindowOpen):
+ (pluginAllocate):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+ (NPP_SetWindow):
+ (NPP_DestroyStream):
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp:
+ (NPP_New):
+ (NPP_SetWindow):
+ (NPP_NewStream):
+ (NPP_DestroyStream):
+
+2009-11-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool crashed with exception
+ https://bugs.webkit.org/show_bug.cgi?id=31092
+
+ * Scripts/modules/bugzilla.py: Change a ',' to a '%' to fix the error.
+
+2009-11-04 Eric Seidel <eric@webkit.org>
+
+ No review, just add a line which got left out of the patch uploaded for commit.
+
+ commit-queue is crashing when trying to reject patches after unknown failures
+ https://bugs.webkit.org/show_bug.cgi?id=31091
+
+ * Scripts/bugzilla-tool: Set bug_log = None after closing to we don't re-close and crash.
+
+2009-11-04 Adam Roben <aroben@apple.com>
+
+ Remove bogus else clause in bugzilla-tool
+
+ Fixes <http://webkit.org/b/31125> REGRESSION (r47121): bugzilla-tool
+ create-bug raises exception after entering bug description
+
+ Reviewed by David Kilzer.
+
+ * Scripts/bugzilla-tool:
+ (CreateBug): else clauses are only hit if no exception is raised, so
+ it makes no sense to try to re-raise the exception in an else clause.
+ The exception will automatically be re-raised if it doesn't match any
+ of the except clauses, so we don't have to do anything special here at
+ all to get the desired behavior.
+
+2009-11-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ svn-apply's fixChangeLogPatch function seems broken
+ https://bugs.webkit.org/show_bug.cgi?id=30683
+
+ Update fixChangeLogPatch to be able to handle patches which
+ don't start at line 1.
+ Add unit tests for svn-apply to scm_unittest.py.
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/modules/scm_unittest.py:
+
+2009-11-04 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Need to implement ARIA role="combobox"
+ https://bugs.webkit.org/show_bug.cgi?id=31096
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (showMenuCallback):
+ (getIsExpandedCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::isExpanded):
+ (AccessibilityUIElement::showMenu):
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::isExpanded):
+ (AccessibilityUIElement::showMenu):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::isSelected):
+ (AccessibilityUIElement::isExpanded):
+ (AccessibilityUIElement::showMenu):
+
+2009-11-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue is crashing when trying to reject patches after unknown failures
+ https://bugs.webkit.org/show_bug.cgi?id=31091
+
+ * Scripts/bugzilla-tool:
+ - patch['id'] was a copy/paste mistake. This code has no 'patch' variable
+ so we have to find out what the current patch is by asking bugzilla again.
+ - Discovered that this code was also leaking file descriptors, so fixed that.
+
+2009-11-04 Adam Roben <aroben@apple.com>
+
+ Make run-webkit-tests work for the Debug_Internal Windows
+ configuration
+
+ In Debug_Internal, DumpRenderTree.exe and ImageDiff.exe have no _debug
+ suffix.
+
+ Fixes <http://webkit.org/b/31123>.
+
+ Reviewed by Sam Weinig.
+
+ * Scripts/run-webkit-tests: Don't add the _debug suffix in
+ Debug_Internal, either.
+
+2009-11-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ committers.py needs a way to store non-bugzilla email addresses
+ https://bugs.webkit.org/show_bug.cgi?id=31037
+
+ Make Committer and Reviewer constructors take a single email or a list of emails.
+ Change committer_by_bugzilla_email functions to committer_by_email to support lookup by any email.
+ Expose reviewers(), used by validate-committer-lists on bug 30970.
+
+ * Scripts/modules/committers.py:
+ * Scripts/modules/committers_unittest.py: Added tests for the new code.
+
+2009-11-03 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by David Levin.
+
+ Start/Stop Web Socket and Web Socket Secure servers for layout tests.
+ https://bugs.webkit.org/show_bug.cgi?id=27491
+
+ The test path determination logic is changed to handle websocket and websocket/ssl cases.
+ The logic for non-http (and now also non-websocket) tests is moved toward the end of the if-elsif statement.
+
+ Functions to start or stop Web Socket servers are added.
+
+ * Scripts/run-webkit-tests:
+
+2009-11-03 Eric Seidel <eric@webkit.org>
+
+ No review, just changing wording of log message.
+
+ Change log string to say "failed" instead of "rejected"
+ when a commit fails due to an out of date checkout.
+ This makes grepping the commit-queue log for rejected patches easier.
+
+ * Scripts/bugzilla-tool:
+
+2009-11-03 Eric Seidel <eric@webkit.org>
+
+ No review, adding commonly known committers missing from the file.
+
+ * Scripts/modules/committers.py: Add committers found by looking at SVN records.
+
+2009-11-03 Eric Seidel <eric@webkit.org>
+
+ No review, just sort-order cleanup.
+
+ * Scripts/modules/committers.py: Sort committers/reviewers alphabetically.
+
+2009-11-03 Stephen White <senorblanco@chromium.org>
+
+ (Unreviewed).
+
+ Add myself to committers.py.
+
+ * Scripts/modules/committers.py:
+
+2009-11-03 Robin Dunn <robin@alldunn.com>
+
+ Reviewed by Kevin Ollviier.
+
+ Add packaging scripts for Debian-based Linux distros.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31075
+
+ * wx/packaging/build-debian-installer.py: Added.
+ * wx/packaging/debian: Added.
+
+2009-11-03 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Anders Carlsson and Beth Dakin.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31070
+
+ Added an 'ondestroy' parameter to the test plug-in. When the plug-in is
+ destroyed, it executes the value of the 'ondestroy' parameter as a
+ script.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginAllocate): Initialize onDestroy.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h: Define
+ onDestroy.
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New): Set onDestroy to the value of the 'ondestroy' parameter, if
+ specified.
+ (NPP_Destroy): Execute the value of 'ondestroy' as a script.
+
+2009-11-02 Joanmarie Diggs <joanmarie.diggs@gmail.com>
+
+ Reviewed by Xan Lopez.
+
+ https://bugs.webkit.org/show_bug.cgi?id=31035
+ [GTK] some accessibility tests hitting assertion in debug builds
+
+ Get the correct Gtk+ object before attempting to turn it into an AtkObject.
+
+ * DumpRenderTree/gtk/AccessibilityControllerGtk.cpp:
+ (AccessibilityController::rootElement):
+
+2009-11-02 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Support ARIA "tab" roles
+ https://bugs.webkit.org/show_bug.cgi?id=30842
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+
+2009-11-01 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ buildbots should use --exit-after-N-failures
+ https://bugs.webkit.org/show_bug.cgi?id=30809
+
+ Make the bots exit after 20 failures to prevent never-ending
+ test runs where every test spends a minute crashing.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2009-11-01 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ Turn on warnings for QtWebKit for gcc
+ https://bugs.webkit.org/show_bug.cgi?id=30958
+
+ * DumpRenderTree/qt/main.cpp:
+ (crashHandler): Mark function NO_RETURN
+
+2009-11-01 Jessie Berlin <jberlin@webkit.org>
+
+ Adding myself to the committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-10-30 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Fix an issue that Adam noticed in DRT.
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::role):
+ Get the length of the role text, and create a buffer dynamically.
+
+2009-10-30 Eric Seidel <eric@webkit.org>
+
+ No review, rolling out r50105.
+ http://trac.webkit.org/changeset/50105
+
+ This commit was causing:
+ https://bugs.webkit.org/show_bug.cgi?id=30869
+ We'll re-implement the feature a different way.
+
+ * Scripts/bugzilla-tool:
+
+2009-10-29 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Test for MSAA: Accessibility of headings is not correct
+
+ https://bugs.webkit.org/show_bug.cgi?id=30937
+
+ Reviewed by Adam Roben.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::role):
+ Allow the role returned to be a BSTR.
+ (AccessibilityUIElement::description):
+ Fix a copy/paste error.
+
+2009-10-29 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Test for MSAA: Accessibility of links is wrong
+
+ https://bugs.webkit.org/show_bug.cgi?id=30928
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getAccessibilityValueCallback):
+ Return the accessibility value.
+ (AccessibilityUIElement::getJSClass):
+ Added "accessibilityValue" value.
+
+ * DumpRenderTree/AccessibilityUIElement.h:
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::accessibilityValue):
+ Stubbed.
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::accessibilityValue):
+ Stubbed.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::accessibilityValue):
+ Get the object's value, and return it as a JS string.
+
+2009-10-30 Kevin Ollivier <kevino@theolliviers.com>
+
+ Fix typo in command name used by wx build system.
+
+ * wx/build/build_utils.py:
+
+2009-10-30 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Patch v1 is a dumb default name for patches
+ https://bugs.webkit.org/show_bug.cgi?id=30952
+
+ Let's use "Patch" instead.
+
+ * Scripts/bugzilla-tool:
+
+2009-10-30 Andras Becsi <becsi.andras@stud.u-szeged.hu>
+
+ Unreviewed trivial buildfix.
+
+ [Qt] Buildfix for r50333.
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+
+2009-10-30 Antonio Gomes <tonikitoo@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ [Qt] Remove qt/WorkQueue.cpp|h in favor of platform independent WorkQueue
+ https://bugs.webkit.org/show_bug.cgi?id=30953
+
+ DumpRenderTree/WorkQueue and DumpRenderTree/qt/WorkQueue share mostly the
+ same implementation. Some Q_ASSERTs differ from ASSERTs basically. Patch
+ makes qt DRT to share this implementation (as gtk and mac ports do).
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/WorkQueue.cpp: Removed.
+ * DumpRenderTree/qt/WorkQueue.h: Removed.
+
+2009-10-30 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Unreviewed potential buildbot fix.
+
+ Second try: Reset page history before running each test.
+
+ Apparently the QWebHistory::clear() keeps the current page
+ in history which is not what we want, so we not additionally
+ sets the history capacity to 0 (forces removing everything)
+ and then sets it back to its original value.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2009-10-30 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Unreviewed potential buildbot fix.
+
+ Reset page history before running each test.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+
+2009-10-30 Roland Steiner <rolandsteiner@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Remove ENABLE_RUBY guards as discussed with Dave Hyatt and Maciej Stachowiak.
+
+ Bug 28420 - Implement HTML5 <ruby> rendering
+ (https://bugs.webkit.org/show_bug.cgi?id=28420)
+
+ No new tests (no functional change).
+
+ * Scripts/build-webkit:
+
+2009-10-29 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Fix “Undefined subroutine†errors in svn-*apply by moving the removeEOL subroutine
+ from the two scripts that define it but don’t use it to the script that uses it but doesn’t
+ define it.
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/svn-apply:
+ * Scripts/svn-unapply:
+
+2009-10-29 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ Use the GTK+ main loop instead of rolling our own mini-version of
+ it.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dump):
+ (runTest):
+ (webViewLoadFinished):
+
+2009-10-29 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Oliver Hunt.
+
+ Implement the Qt version of DRT dumpBackForwardList().
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::dumpHistoryItem):
+ (WebCore::DumpRenderTree::dumpBackForwardList):
+
+2009-10-29 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Implement DRT functionality for Qt introduced in
+ r28690 and r28705.
+
+ - Implemented pathToLocalResource which exposes the functionality of
+ converting a given unix path to the correct location on Windows.
+ - Implemented a way to remove machine-dependent information from paths
+ in layout test results.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::urlSuitableForTestResult):
+ (WebCore::WebPage::javaScriptConsoleMessage):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::pathToLocalResource):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2009-10-28 Roland Steiner <rolandsteiner@chromium.org>
+
+ Adding myself to the committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-10-28 Chris Fleizach <cfleizach@apple.com>
+
+ Adding myself to the committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-10-28 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Jan Alonzo.
+
+ [GTK] API to start inspector for a WebView
+ https://bugs.webkit.org/show_bug.cgi?id=22551
+
+ Use the new inspector API to implement the LayoutTestController
+ interfaces used to test the inspector.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webInspectorInspectWebView):
+ (createWebView):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::closeWebInspector):
+ (LayoutTestController::evaluateInWebInspector):
+
+2009-10-28 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] WebFrame::counterValueForElementById must not be exposed
+ https://bugs.webkit.org/show_bug.cgi?id=30882
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::counterValueForElementById):
+
+2009-10-28 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Oliver Hunt.
+
+ Fix the warning:
+
+ "warning: ignoring return value of 'char* getcwd(char*, size_t)',
+ declared with attribute warn_unused_result".
+
+ by actually checking the result. In the case it is null, an
+ error has occoured, so treat it as the other fatal errors.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::initializeFonts):
+
+2009-10-27 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Provide a way to get counter values with layoutTestContoller
+ https://bugs.webkit.org/show_bug.cgi?id=30555
+
+ Define layoutTestContoller.counterValueForElementById.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (counterValueForElementByIdCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::counterValueForElementById):
+
+2009-10-27 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Oliver Hunt.
+
+ Change two methods to be internal for DRT use only.
+
+ Part of [Qt] Review all new API in Qt 4.6
+ https://bugs.webkit.org/show_bug.cgi?id=29843#c11
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::whiteListAccessFromOrigin):
+
+2009-10-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ REGRESSION: svn-apply exits(1) when applying a patch with a file add
+ https://bugs.webkit.org/show_bug.cgi?id=30826
+
+ * Scripts/svn-apply:
+ - Add () around all system() calls.
+ - Use the correct system() == 0 or die instead of system() or die
+ - Add descriptive messages to all die statements.
+
+2009-10-27 Steve Block <steveblock@google.com>
+
+ Reviewed by NOBODY.
+
+ Adds steveblock@google.com to list of committers.
+
+ * Scripts/modules/committers.py: Adds steveblock@google.com to list of committers.
+
+2009-10-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ svn-apply can exit(0) even on patch failure
+ https://bugs.webkit.org/show_bug.cgi?id=29622
+
+ * Scripts/svn-apply:
+ - Add a bunch of "or die" statements, hopefully catching all
+ possible cases where failure could still exit(0).
+
+2009-10-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ svn-* scripts should share code through VCSUtils.pm
+ https://bugs.webkit.org/show_bug.cgi?id=30791
+
+ Just moving code into a shared location.
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/prepare-ChangeLog:
+ * Scripts/resolve-ChangeLogs:
+ * Scripts/svn-apply:
+ * Scripts/svn-create-patch:
+ * Scripts/svn-unapply:
+ * Scripts/update-webkit:
+
+2009-10-27 Vadim Zeitlin <vadim@wxwidgets.org>
+
+ Suppress a huge number of MSVC warnings when building wxWebKit.
+
+ * wx/build/settings.py:
+
+2009-10-26 Eric Seidel <eric@webkit.org>
+
+ No review, just adding Mike Belshe to the committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-10-26 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Darin Adler.
+
+ Make .rc files compile on Windows without depending on MFC headers
+ https://bugs.webkit.org/show_bug.cgi?id=30750
+
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.rc: Use
+ windows.h instead of afxres.h because it exists even when MFC is not
+ installed, and is all that's needed here.
+
+ * FindSafari/FindSafari.rc: Ditto
+
+2009-10-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool post-diff should know how to mark commit-queue=?
+ https://bugs.webkit.org/show_bug.cgi?id=29202
+
+ * Scripts/bugzilla-tool:
+ - Add --commit-queue option to post-diff, post-commits and create-bug.
+ * Scripts/modules/bugzilla.py:
+ - Added support for --commit-queue to add_patch_to_bug and create_bug_with_patch.
+ - Added _fill_attachment_form to share code between add_patch_to_bug and create_bug_with_patch.
+
+2009-10-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool commit-queue does not notice modifications to committers.py
+ https://bugs.webkit.org/show_bug.cgi?id=30084
+
+ * Scripts/bugzilla-tool:
+ - Make commit-queue re-exec itself instead of using while(1).
+ - Add a --is-relaunch parameter to commit-queue to bypass initialization on re-launch.
+ - Add a _next_patch() method which calls exec() (and could eventually call update-webkit too).
+
+2009-10-22 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue will get stuck on patches if land-patches terminates unexpectedly
+ https://bugs.webkit.org/show_bug.cgi?id=30634
+
+ * Scripts/bugzilla-tool:
+ - Add a way for land-patches to exit(2) to indicate an error, but one it has handled.
+ - Make commit-queue auto cq- any patch where land-patches exited anything other than '0' or '2'.
+
+2009-10-26 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by Eric Seidel.
+
+ Upgrade pywebsocket to 0.4.1. This will make reusing LayoutTests/fast/js/resources easier, for example.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30763
+
+ * pywebsocket/mod_pywebsocket/__init__.py:
+ * pywebsocket/mod_pywebsocket/dispatch.py:
+ * pywebsocket/mod_pywebsocket/headerparserhandler.py:
+ * pywebsocket/mod_pywebsocket/standalone.py:
+ * pywebsocket/setup.py:
+ * pywebsocket/test/test_dispatch.py:
+
+2009-10-26 Carol Szabo <carol.szabo@nokia.com>
+
+ Reviewed by David Levin.
+
+ REGRESSION: 2 failures in run-webkit-unittests
+ https://bugs.webkit.org/show_bug.cgi?id=30645
+
+ * Scripts/modules/cpp_style_unittest.py:
+ Fixed a few test scenarios which apparently lost some spaces from
+ text literals.
+
+2009-10-26 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Make sure isQt() doesn't return true if --wx was passed to build-webkit.
+
+ * Scripts/webkitdirs.pm:
+
+2009-10-26 Csaba Osztrogonác <ossy@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Unification of using null device in perl scripts.
+ https://bugs.webkit.org/show_bug.cgi?id=30572
+
+ * Scripts/VCSUtils.pm:
+ * Scripts/bisect-builds:
+ * Scripts/resolve-ChangeLogs:
+ * Scripts/run-iexploder-tests:
+ * Scripts/run-jsc:
+ * Scripts/run-mangleme-tests:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+ Using File::Spec->devnull() instead of hard coded /dev/null.
+
+2009-10-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ Reviewers are missing from committers.py
+ https://bugs.webkit.org/show_bug.cgi?id=30733
+
+ * Scripts/modules/committers.py:
+
+2009-10-23 Eric Seidel <eric@webkit.org>
+
+ No review, only adding Alice to the list of reviewers.
+
+ * Scripts/modules/committers.py:
+
+2009-10-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Eric Carlson.
+
+ fast/media/mq-transform-02.html failed on Leopard Commit Bot
+ https://bugs.webkit.org/show_bug.cgi?id=30700
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues): Update QuickTime version check.
+
+2009-10-23 Kevin Ollivier <kevino@theolliviers.com>
+
+ wxMac 10.4 build fix, needs to link against WebKitSystemInterfaceTiger to get
+ character measurement APIs that are private on Tiger.
+
+ * wx/build/settings.py:
+
+2009-10-22 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by NOBODY (build fix).
+ Build fix following bug #30696.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::evaluateScriptInIsolatedWorld):
+
+2009-10-22 Gavin Barraclough <barraclough@apple.com>
+
+ Reviewed by Sam Weinig & Geoff Garen.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30696
+ Enable isolated-worlds tests on mac.
+
+ Add private interface for DRT to invoke execution in a given world.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (evaluateScriptInIsolatedWorldCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::evaluateScriptInIsolatedWorld):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::evaluateScriptInIsolatedWorld):
+
+2009-10-21 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool's "patch failed to download an apply" error should give more information
+ https://bugs.webkit.org/show_bug.cgi?id=30632
+
+ * Scripts/modules/scm.py:
+ - Use the common run_command method instead of custom POpen code.
+ - Make run_command know how to take pipes as input.
+ * Scripts/modules/scm_unittest.py:
+ - Add new tests to cover change.
+ - Also move test_error_handlers into new SCMClassTests so we don't run it 3 times.
+
+2009-10-21 Kent Tamura <tkent@chromium.org>
+
+ Unreviewed. Adding myself to the committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-10-21 Robin Dunn <robin@alldunn.com>
+
+ Reviewed by Kevin Ollivier.
+
+ Update the Windows installer builder to work with Vista / Win 7 and with git.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30649
+
+ * wx/build/build_utils.py:
+ * wx/packaging/build-mac-installer.py:
+ * wx/packaging/build-win-installer.py:
+ * wx/packaging/wxWebKitInstaller.iss.in:
+
+2009-10-21 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ [GTK] Added conditional code to avoid using
+ gdk_window_get_root_coords if we do not have a gtk+ release newer
+ than 2.17.3.
+ https://bugs.webkit.org/show_bug.cgi?id=30636
+
+ * WebKitTools/DumpRenderTree/gtk/EventSender.cpp:
+
+2009-10-21 Shu Chang <Chang.Shu@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] Added dummy implementation for keepWebHistory()
+ https://bugs.webkit.org/show_bug.cgi?id=30592
+
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::keepWebHistory):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2009-10-21 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Fixed the double click condition, it is not double click if
+ we move in just in one direction.
+ https://bugs.webkit.org/show_bug.cgi?id=30636
+
+ * WebKitTools/DumpRenderTree/gtk/EventSender.cpp:
+
+2009-10-21 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Initialize the events completly before emitting them.
+ https://bugs.webkit.org/show_bug.cgi?id=30633
+
+ * WebKitTools/DumpRenderTree/gtk/EventSender.cpp:
+
+2009-10-21 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Fix for when linking using --as-needed with gcc.
+
+ * wx/browser/wscript:
+
+2009-10-21 Kevin Ollivier <kevino@theolliviers.com>
+
+ wxMac 10.4 build fix. Build and link against a version of libcurl new enough
+ to support all the features used by CURL backend.
+
+ * wx/build/settings.py:
+ * wx/install-unix-extras:
+
+2009-10-20 Anton Muhin <antonm@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Add {ager,antonm,yurys}@chromium.org into committers.py
+ https://bugs.webkit.org/show_bug.cgi?id=30560
+
+ * Scripts/modules/committers.py:
+
+2009-10-20 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Make the Netscape Test plugin available to the Qt launcher.
+
+ * Scripts/run-launcher:
+
+2009-10-20 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by David Levin.
+
+ Removed WebSocket runtime settings.
+ https://bugs.webkit.org/show_bug.cgi?id=29896
+
+ WebSocket runtime configuration is supported by chromium/v8 only.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2009-10-19 Nate Chapin <japhet@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Add testFail() to test plugin so we can test our handling of a
+ plugin invoke call returning false.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30239
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp: Add testFail().
+ (pluginInvoke):
+ (testIdentifierToString): Always return true, since returning false will now cause an exception to be thrown.
+
+2009-10-19 Zan Dobersek <zandobersek@gmail.com>
+
+ Reviewed by Gustavo Noronha.
+
+ Enable DOM pasting when running layout tests.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2009-10-18 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Use the setPreferredContentsSize method instead
+ of setFixedContentsSize, as the method has been renamed.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::open):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setFixedContentsSize):
+
+2009-10-16 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30456
+ Fixes for new Debug_All Windows build configuration.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (sharedCFURLCache): Use new DEBUG_ALL preprocessor define for library naming.
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Remove unused DEBUG_WEBKIT_HAS_SUFFIX.
+
+2009-10-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue status bot should list which buildbot is blocking the queue
+ https://bugs.webkit.org/show_bug.cgi?id=30452
+
+ Add new methods and testing.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/buildbot.py:
+ * Scripts/modules/buildbot_unittest.py:
+
+2009-10-16 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ run-webkit-tests fails when CWD is not inside a WebKit checkout
+ https://bugs.webkit.org/show_bug.cgi?id=30451
+
+ * Scripts/modules/scm.py: in_working_directory shouldn't throw exceptions on failure.
+ * Scripts/modules/scm_unittest.py:
+ - Remove use of original_path (we don't need to restore the CWD).
+ - Don't use '.' to find the webkit checkout, use __file__ instead.
+
+2009-10-16 Steve Falkenburg <sfalken@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Add a Debug_All configuration to build entire stack as debug.
+ Change Debug_Internal to:
+ - stop using _debug suffix for all WebKit/Safari binaries
+ - not use _debug as a DLL naming suffix
+ - use non-debug C runtime lib.
+
+ * DumpRenderTree/DumpRenderTree.sln: Add Debug_All configuration.
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Add Debug_All configuration.
+ * DumpRenderTree/win/ImageDiff.vcproj: Add Debug_All configuration.
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+ Add missing debug.vsprops inherited property sheet.
+ Add Debug_All configuration.
+ * FindSafari/FindSafari.vcproj: Renamed single configuration from "Release" to "all".
+ * WinLauncher/WinLauncher.vcproj:
+ Removed extraneous definitions inherited from vsprops.
+ Add Debug_All configuration.
+
+2009-10-16 Carol Szabo <carol.szabo@nokia.com>
+
+ Reviewed by David Levin.
+
+ check-webkit-style is wrong about indent checking in namespaces
+ in header files and a few other things
+ https://bugs.webkit.org/show_bug.cgi?id=30362
+
+ The few other things include:
+ + check-webkit-style does not require spaces around the equal sign
+ inside 'if' statements and around binary operators that take
+ numeric literals.
+ + check-webkit-style reports false errors for the / operator
+ when part of a filename in the #include directive.
+
+ * Scripts/modules/cpp_style.py:
+ Improved indentation checking and space checking around
+ binary operators. While the checks are still not perfect,
+ they are clearly better than before.
+ * Scripts/modules/cpp_style_unittest.py:
+ Added test cases for the newly supported checks and modified old
+ test cases to match the new guidelines
+
+2009-10-16 Kevin Ollivier <kevino@theolliviers.com>
+
+ wxMSW build fix. Link to MSW library needed by PluginPackageWin.cpp.
+
+ * wx/build/settings.py:
+
+2009-10-15 Yuzo Fujishima <yuzo@google.com>
+
+ Reviewed by David Levin.
+
+ Add mod_pywebsocket to test Web Sockets.
+ http://code.google.com/p/pywebsocket/
+ https://bugs.webkit.org/show_bug.cgi?id=27490
+
+ * pywebsocket/COPYING: Added.
+ * pywebsocket/MANIFEST.in: Added.
+ * pywebsocket/README: Added.
+ * pywebsocket/example/echo_client.py: Added.
+ * pywebsocket/example/echo_wsh.py: Added.
+ * pywebsocket/mod_pywebsocket/__init__.py: Added.
+ * pywebsocket/mod_pywebsocket/dispatch.py: Added.
+ * pywebsocket/mod_pywebsocket/handshake.py: Added.
+ * pywebsocket/mod_pywebsocket/headerparserhandler.py: Added.
+ * pywebsocket/mod_pywebsocket/msgutil.py: Added.
+ * pywebsocket/mod_pywebsocket/standalone.py: Added.
+ * pywebsocket/mod_pywebsocket/util.py: Added.
+ * pywebsocket/setup.py: Added.
+ * pywebsocket/test/config.py: Added.
+ * pywebsocket/test/mock.py: Added.
+ * pywebsocket/test/run_all.py: Added.
+ * pywebsocket/test/test_dispatch.py: Added.
+ * pywebsocket/test/test_handshake.py: Added.
+ * pywebsocket/test/test_mock.py: Added.
+ * pywebsocket/test/test_msgutil.py: Added.
+ * pywebsocket/test/test_util.py: Added.
+ * pywebsocket/test/testdata/handlers/blank_wsh.py: Added.
+ * pywebsocket/test/testdata/handlers/origin_check_wsh.py: Added.
+ * pywebsocket/test/testdata/handlers/sub/exception_in_transfer_wsh.py: Added.
+ * pywebsocket/test/testdata/handlers/sub/no_wsh_at_the_end.py: Added.
+ * pywebsocket/test/testdata/handlers/sub/non_callable_wsh.py: Added.
+ * pywebsocket/test/testdata/handlers/sub/plain_wsh.py: Added.
+ * pywebsocket/test/testdata/handlers/sub/wrong_handshake_sig_wsh.py: Added.
+ * pywebsocket/test/testdata/handlers/sub/wrong_transfer_sig_wsh.py: Added.
+
+2009-10-15 James Robinson <jamesr@google.com>
+
+ Reviewed by David Levin.
+
+ Updates check-webkit-style to reflect that code inside a namespace should not be indented, even in a header file.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30426
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-10-15 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Fixes <http://webkit.org/b/30411>.
+ REGRESSION(49485): pdevenv doesn't compile in parallel for non-chromium builds on Windows.
+
+ Added a check for isChromium() in pdevenv, and pass /useenv if we are not
+ building Chromium.
+
+ * Scripts/pdevenv:
+
+2009-10-15 Robin Dunn <robin@alldunn.com>
+
+ Reviewed by Kevin Ollivier.
+
+ Add Mac package building scripts for wx.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30405
+
+ * wx/build/build_utils.py:
+ * wx/build/settings.py:
+ * wx/packaging/build-mac-installer.py: Added.
+
+2009-10-15 Zan Dobersek <zandobersek@gmail.com>
+
+ Reviewed by Gustavo Noronha.
+
+ Enable Web Sockets support when running layout tests.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2009-10-15 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ Need to initialize event.button.button, since in most cases a
+ button number is not passed as an argument.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (mouseDownCallback):
+ (mouseUpCallback):
+
+2009-10-15 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. More SDK fixes for Mac, make sure we use the SDK corresponding to
+ the OS if none was explicitly set.
+
+ * wx/build/settings.py:
+
+2009-10-14 Pavel Feldman <pfeldman@chromium.org>
+
+ Reviewed by Timothy Hatcher.
+
+ Web Inspector: enable developers extras within inspector layout tests.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30014
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::closeWebInspector):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::closeWebInspector):
+
+2009-10-14 José Millán Soto <jmillan@igalia.com>
+
+ Reviewed by Jan Alonzo.
+
+ GtkLauncher is using a deprecated signal
+ https://bugs.webkit.org/show_bug.cgi?id=30364
+
+ Modified GtkLauncher to use notify::title signal instead of
+ deprecated title-changed signal
+
+ * GtkLauncher/main.c:
+ (notify_title_cb):
+ (create_browser):
+
+2009-10-14 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Don't set the history delegate on new windows that are opened during a test, as the history delegate:
+ 1 - Disables WebHistory
+ 2 - Doesn't make sense in that context anyway.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (createWebViewAndOffscreenWindow):
+
+2009-10-14 Kevin Ollivier <kevino@theolliviers.com>
+
+ wxMac build fix. Ensure 10.4 compatibility for deps, and allow the user to specify
+ the SDK to use since Python overrides any user-set value of MACOSX_DEPLOYMENT_TARGET.
+
+ * wx/build/settings.py:
+ * wx/install-unix-extras:
+
+2009-10-14 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ WebKit Win API should provide a delegate interface for global history.
+ https://bugs.webkit.org/show_bug.cgi?id=29905
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::dumpHistoryDelegateCallbacks):
+ (LayoutTestController::setDumpHistoryDelegateCallbacks):
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (shouldLogHistoryDelegates):
+ (runTest):
+ (createWebViewAndOffscreenWindow):
+ (main):
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+
+ Add the IWebHistoryDelegate to DRT Windows:
+ * DumpRenderTree/win/HistoryDelegate.cpp: Added.
+ (wstringFromBSTR):
+ (HistoryDelegate::HistoryDelegate):
+ (HistoryDelegate::~HistoryDelegate):
+ (HistoryDelegate::QueryInterface):
+ (HistoryDelegate::AddRef):
+ (HistoryDelegate::Release):
+ (HistoryDelegate::didNavigateWithNavigationData):
+ (HistoryDelegate::didPerformClientRedirectFromURL):
+ (HistoryDelegate::didPerformServerRedirectFromURL):
+ (HistoryDelegate::updateHistoryTitle):
+ (HistoryDelegate::populateVisitedLinksForWebView):
+ * DumpRenderTree/win/HistoryDelegate.h: Added.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::removeAllVisitedLinks):
+
+2009-10-14 Shu Chang <Chang.Shu@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Implement support for setPOSIXLocale on Qt.
+ https://bugs.webkit.org/show_bug.cgi?id=30268
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp:
+ (LayoutTestController::setPOSIXLocale):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h:
+
+2009-10-13 Stephanie Lewis <slewis@apple.com>
+
+ Unreviewed, adding myself to reviewers list.
+
+ * Scripts/modules/committers.py:
+
+2009-10-13 Stephanie Lewis <slewis@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Fix null assignment so root tests work again.
+
+ * Scripts/webkitdirs.pm:
+
+2009-10-13 Andras Becsi <becsi.andras@stud.u-szeged.hu>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Refactor LayoutTestController, EventSender, TextInputController and WorkQueueItem classes
+ out of jsobjects into separate files to get a more structured DumpRenderTree implementation.
+ This is done in preparation of implementing missing features in DRT.
+ No functionality changes made yet.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/EventSenderQt.cpp: Added.
+ (EventSender::EventSender):
+ (EventSender::mouseDown):
+ (EventSender::mouseUp):
+ (EventSender::mouseMoveTo):
+ (EventSender::leapForward):
+ (EventSender::keyDown):
+ (EventSender::contextClick):
+ (EventSender::scheduleAsynchronousClick):
+ (EventSender::frameUnderMouse):
+ * DumpRenderTree/qt/EventSenderQt.h: Added.
+ (EventSender::clearKillRing):
+ * DumpRenderTree/qt/LayoutTestControllerQt.cpp: Added.
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::reset):
+ (LayoutTestController::processWork):
+ (LayoutTestController::maybeDump):
+ (LayoutTestController::waitUntilDone):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::windowCount):
+ (LayoutTestController::clearBackForwardList):
+ (LayoutTestController::dumpEditingCallbacks):
+ (LayoutTestController::dumpResourceLoadCallbacks):
+ (LayoutTestController::queueBackNavigation):
+ (LayoutTestController::queueForwardNavigation):
+ (LayoutTestController::queueLoad):
+ (LayoutTestController::queueReload):
+ (LayoutTestController::queueScript):
+ (LayoutTestController::provisionalLoad):
+ (LayoutTestController::timerEvent):
+ (LayoutTestController::encodeHostName):
+ (LayoutTestController::decodeHostName):
+ (LayoutTestController::setJavaScriptProfilingEnabled):
+ (LayoutTestController::setFixedContentsSize):
+ (LayoutTestController::setPrivateBrowsingEnabled):
+ (LayoutTestController::setPopupBlockingEnabled):
+ (LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+ (LayoutTestController::numberOfActiveAnimations):
+ (LayoutTestController::disableImageLoading):
+ (LayoutTestController::dispatchPendingLoadRequests):
+ (LayoutTestController::setDatabaseQuota):
+ (LayoutTestController::clearAllDatabases):
+ (LayoutTestController::whiteListAccessFromOrigin):
+ (LayoutTestController::waitForPolicyDelegate):
+ (LayoutTestController::overridePreference):
+ * DumpRenderTree/qt/LayoutTestControllerQt.h: Added.
+ (LayoutTestController::isLoading):
+ (LayoutTestController::setLoading):
+ (LayoutTestController::shouldDumpAsText):
+ (LayoutTestController::shouldDumpBackForwardList):
+ (LayoutTestController::shouldDumpChildrenAsText):
+ (LayoutTestController::shouldDumpDatabaseCallbacks):
+ (LayoutTestController::shouldDumpStatusCallbacks):
+ (LayoutTestController::shouldWaitUntilDone):
+ (LayoutTestController::canOpenWindows):
+ (LayoutTestController::shouldDumpTitleChanges):
+ (LayoutTestController::waitForPolicy):
+ (LayoutTestController::dumpAsText):
+ (LayoutTestController::dumpChildFramesAsText):
+ (LayoutTestController::dumpDatabaseCallbacks):
+ (LayoutTestController::dumpStatusCallbacks):
+ (LayoutTestController::setCanOpenWindows):
+ (LayoutTestController::dumpBackForwardList):
+ (LayoutTestController::setCloseRemainingWindowsWhenComplete):
+ (LayoutTestController::display):
+ (LayoutTestController::dumpTitleChanges):
+ (LayoutTestController::dumpSelectionRect):
+ * DumpRenderTree/qt/TextInputControllerQt.cpp: Added.
+ (TextInputController::TextInputController):
+ (TextInputController::doCommand):
+ * DumpRenderTree/qt/TextInputControllerQt.h: Added.
+ * DumpRenderTree/qt/WorkQueue.cpp:
+ * DumpRenderTree/qt/WorkQueue.h:
+ * DumpRenderTree/qt/WorkQueueItem.h:
+ * DumpRenderTree/qt/WorkQueueItemQt.cpp: Added.
+ (findFrameNamed):
+ (LoadItem::invoke):
+ (ReloadItem::invoke):
+ (ScriptItem::invoke):
+ (BackForwardItem::invoke):
+ * DumpRenderTree/qt/jsobjects.cpp: Move all the above classes into separate files
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-10-13 Dmitry Titov <dimich@chromium.org>
+
+ Not reviewed, adding myself to the list of reviewers.
+
+ * Scripts/modules/committers.py:
+
+2009-10-13 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ <rdar://problem/6660507> Add "privacy mode" to Netscape Plug-in API
+
+ Make the private browsing mode testable by the test plug-in.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginGetProperty):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+ (NPP_SetValue):
+
+2009-10-13 Pavel Feldman <pfeldman@chromium.org>
+
+ No review, just adding self to the list of reviewers.
+
+ * Scripts/modules/committers.py:
+
+2009-10-12 Pavel Feldman <pfeldman@chromium.org>
+
+ Reviewed by Adam Roben.
+
+ Web Inspector: Use proper web view in inspector layout
+ tests for windows.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30298
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::closeWebInspector):
+ (LayoutTestController::evaluateInWebInspector):
+
+2009-10-12 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Sam Weinig.
+
+ Enable experimentalWebSocket in DumpRenderTree for LayoutTest.
+ https://bugs.webkit.org/show_bug.cgi?id=29841
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2009-10-12 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ Chromium Port - Windows
+ https://bugs.webkit.org/show_bug.cgi?id=29969
+
+ * Scripts/pdevenv: removed msvc's /useenv for chromium builds
+ * Scripts/webkitdirs.pm:
+
+2009-10-12 Csaba Osztrogonac <ossy@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ jsc scripts cleanup and Qt/GTK fix
+ https://bugs.webkit.org/show_bug.cgi?id=30288
+
+ Duplicated jscPath() moved to webkitdirs.pm.
+ New jscProductDir() added to webkitdirs.pm instead of duplicated codes.
+ Configuration added (release/debug) to path for Qt-port on Windows.
+
+ * Scripts/run-javascriptcore-tests:
+ * Scripts/run-jsc:
+ * Scripts/run-sunspider:
+ * Scripts/sunspider-compare-results:
+ * Scripts/webkitdirs.pm:
+
+2009-10-11 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Add Collin to committers.py.
+
+ * Scripts/modules/committers.py:
+
+2009-10-11 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix, add bindings to source/include dirs now that there are sources there.
+
+ * wx/build/settings.py:
+
+2009-10-09 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Brady Eidson.
+
+ Enable plug-in halting in DumpRenderTree.
+
+ We drop the plug-in halting delay to 1 second and opt in the delegate method to never halt plug-ins.
+ This is sufficient to ensure that the crash covered by <rdar://problem/7290671> no longer occurs.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/mac/UIDelegate.mm:
+ (-[UIDelegate webView:shouldHaltPlugin:]):
+
+2009-10-08 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Ask the History Delegate to populate the visited links hash.
+ <rdar://problem/7285293> and https://webkit.org/b/29904
+
+ Add the ability for LayoutTestController to clear all visited links.
+ Also lets the History Delegate dump visited links, but only if this test specifically cleared them.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (removeAllVisitedLinksCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::removeAllVisitedLinks):
+
+ * DumpRenderTree/mac/HistoryDelegate.mm:
+ (-[HistoryDelegate populateVisitedLinksForWebView:]):
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::removeAllVisitedLinks):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::removeAllVisitedLinks):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::removeAllVisitedLinks):
+
+
+2009-10-08 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30175
+
+ The Windows DRT equivalent of DoDragDrop (i.e. UIDelegate::doDragDrop) does not return
+ the OLE drag-and-drop return value like the function it emulates. Currently,
+ UIDelegate::doDragDrop returns a hard-coded S_OK. Hence, the caller cannot determine
+ whether the drag-and-drop operation was successful or was cancelled.
+
+ This patch fixes this issue by having UIDelegate::doDragDrop return the OLE drag-and-drop
+ return value according to whether the drop operation was successful or not.
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (doMouseUp): Added parameter oleDragAndDropReturnValue.
+ (replaySavedEvents): Ditto.
+ * DumpRenderTree/win/EventSender.h:
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::doDragDrop): Modified to return OLE drag-and-drop return value.
+
+2009-10-08 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Added support for a parameter setting the button that was
+ pressed in the mouseDown function.
+ https://bugs.webkit.org/show_bug.cgi?id=30220
+
+ * WebKitTools/DumpRenderTree/gtk/EventSender.cpp:
+
+2009-10-08 Alejandro G. Castro <alex@igalia.com>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] Added a line to the bottom of the expected result to match
+ the output of the test.
+ https://bugs.webkit.org/show_bug.cgi?id=30220
+
+ * LayoutTests/platform/gtk/editing/pasteboard/middle-click-onpaste-
+ expected.txt:
+
+2009-10-08 Adam Roben <aroben@apple.com>
+
+ Use QueryInterface to get IWebInspectorPrivate
+
+ Fixes <http://webkit.org/b/30215> Make IWebInspectorPrivate be
+ accessed in a more standard way
+
+ Reviewed by John Sullivan and Tim Hatcher.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::evaluateInWebInspector): Get the IWebInspector
+ by calling IWebViewPrivate::inspector, then use QueryInterface to get
+ to the IWebInspectorPrivate interface.
+
+2009-10-07 Adam Roben <aroben@apple.com>
+
+ Implement DRT support for origin whitelisting
+
+ Fixes <http://webkit.org/b/30185>.
+
+ Reviewed by Eric Seidel.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting): Reset any origin
+ whitelist, to match Mac DRT.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::whiteListAccessFromOrigin): Call through to
+ IWebViewPrivate::whiteListAccessFromOrigin.
+
+2009-10-07 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Send title changes to the global history delegate.
+ <rdar://problem/7285293> and https://webkit.org/b/29904
+
+ * DumpRenderTree/mac/HistoryDelegate.mm:
+ (-[HistoryDelegate webView:updateHistoryTitle:forURL:]):
+
+2009-10-07 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Remove some folks from committers.py who were listed on
+ the WebKit Team wiki page but who weren't actually listed as commit+.
+ At some point, we should coorelate this list with the committers
+ mailing list.
+
+ * Scripts/modules/committers.py:
+
+2009-10-07 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Import a bunch of committers from the WebKit Team page on
+ the wiki into committers.py.
+
+ * Scripts/modules/committers.py:
+
+2009-10-07 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Added Aaron Boodman to committers.py.
+
+ * Scripts/modules/committers.py:
+
+2009-10-07 Evan Martin <evan@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Add API to LayoutTestController for re/setting the system locale.
+ https://bugs.webkit.org/show_bug.cgi?id=18994
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setLocaleCallback):
+ (LayoutTestController::staticFunctions):
+ (LayoutTestController::setLocale):
+ * DumpRenderTree/LayoutTestController.h:
+
+2009-10-06 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Jan Alonzo.
+
+ [Layout tests] [Gtk] Gtk DumpRenderTree should use WebKit test fonts
+ https://bugs.webkit.org/show_bug.cgi?id=29689
+
+ Build fix by adding -lfontconfig for DumpRenderTree.
+
+ * GNUmakefile.am:
+
+2009-10-07 Csaba Osztrogonac <oszi@inf.u-szeged.hu>
+
+ Reviewed by Simon Hausmann.
+
+ Re-enable use-remote-links-to-tests for Qt. Disabled in r46416.
+
+ * Scripts/run-webkit-tests:
+
+2009-10-07 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ "delete" in EventSender is the backspace key, not the delete one.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (keyDownCallback):
+
+2009-10-07 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ getChildrenWithRange expects as last parameter the end index, not
+ the length of the range. Correct this and clarify the variable
+ names to reflect how the code works.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::getChildrenWithRange):
+ (AccessibilityUIElement::getChildAtIndex):
+
+2009-10-06 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ <http://webkit.org/b/30138> update-webkit-localizable-strings assumes that WebKitTools/Scripts is in the PATH
+
+ * Scripts/update-webkit-localizable-strings: Use an explicit path to extract-localizable-strings based on the
+ the fact we have already changed the working directory to the top of the open source tree.
+
+2009-10-06 Julie Parent <jparent@chromium.org>
+
+ Unreviewed. Fixing the entry for myself in committers.py to use my bugzilla email,
+ rather than my committer email.
+
+ * Scripts/modules/committers.py:
+
+2009-10-06 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Eric Seidel.
+
+ [Qt] LayoutTestController: Reset m_dumpStatusCallbacks to false in reset().
+
+ r49189 added support for the 'dumpStatusCallbacks' setting but didn't reset
+ it after each layout test as it should do, making the DRT dump additional output
+ for all of the subsequent layout tests.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::reset):
+
+2009-10-06 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Implement layoutTestController.dumpStatusCallbacks() and unskip the
+ fast/dom/assign-to-window-status.html test, which is passing as a result.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30127
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::statusBarMessage):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/jsobjects.h:
+ (LayoutTestController::shouldDumpStatusCallbacks):
+ (LayoutTestController::dumpStatusCallbacks):
+
+2009-10-06 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] The implementation of EventSender::mouseUp() and EventSender::mouseDown()
+ ignores the argument indicating which mouse button to trigger.
+ https://bugs.webkit.org/show_bug.cgi?id=30048
+
+ This affects the fast/events/mouse-click-events.html layout test.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (EventSender::mouseDown):
+ (EventSender::mouseUp):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-10-06 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Fix the EventSender::keyDown() implementation
+ https://bugs.webkit.org/show_bug.cgi?id=30043
+
+ It should post both a key press event and a key release event,
+ just like other ports do.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (EventSender::keyDown):
+
+2009-10-05 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Add jpeg to the list of libs to link against.
+
+ * wx/build/settings.py:
+
+2009-10-05 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] EventSender::keyDown() cannot send function-key events.
+ https://bugs.webkit.org/show_bug.cgi?id=30044
+
+ This affects the fast/events/keydown-function-keys.html layout test.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (EventSender::keyDown):
+
+2009-10-05 Vadim Zeitlin <vadim@wxwidgets.org>
+
+ Added --wx-compiler-prefix waf option to allow building wxWebKit with
+ wxWidgets built using "nmake COMPILER_PREFIX=something-non-default".
+
+ * wx/build/settings.py:
+ * wx/build/wxpresets.py:
+
+2009-10-05 Pavel Feldman <pfeldman@chromium.org>
+
+ Reviewed by Timothy Hatcher.
+
+ Web Inspector: add testing harness for Web Inspector.
+
+ https://bugs.webkit.org/show_bug.cgi?id=30010
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (showWebInspectorCallback):
+ (closeWebInspectorCallback):
+ (evaluateInWebInspectorCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::closeWebInspector):
+ (LayoutTestController::evaluateInWebInspector):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::closeWebInspector):
+ (LayoutTestController::evaluateInWebInspector):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::closeWebInspector):
+ (LayoutTestController::evaluateInWebInspector):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::showWebInspector):
+ (LayoutTestController::closeWebInspector):
+ (LayoutTestController::evaluateInWebInspector):
+
+2009-10-05 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Ariyha Hidayat.
+
+ Pass arguments to system() as a string instead of array
+
+ When passed as an array entries with a space fail to translate
+ to two arguments to the child process, so instead of manually
+ splitting all the entries in @buildArgs we pass the whole thing
+ as a string instead.
+
+ * Scripts/webkitdirs.pm:
+
+2009-10-04 Carol Szabo <carol.szabo@nokia.com>
+
+ Reviewed by David Levin.
+
+ check-webkit-style misses whitespace errors for operators:
+ <<, >>, <<=, >>=, &=, |=, +=, -=, *=, /=, /, |, &&, ||.
+ https://bugs.webkit.org/show_bug.cgi?id=30021
+
+ * Scripts/modules/cpp_style.py:
+ Added the operators mentioned above to the same list as == and !=.
+
+2009-10-02 Julie Parent <jparent@chromium.org>
+
+ Unreviewed.
+
+ Adding myself and Ojan Vafai as committers, because we are committers.
+
+ * Scripts/modules/committers.py:
+
+2009-10-02 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Adam Roben.
+
+ svn-create-patch should have an --ignore-changelogs to not add ChangeLogs to the diff,
+ this will help the patch merging process when TryBots are used.
+
+ * Scripts/svn-create-patch:
+
+2009-10-02 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Implement layoutTestController.overridePreference().
+ https://bugs.webkit.org/show_bug.cgi?id=29970
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::WebPage::resetSettings):
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::setPrivateBrowsingEnabled):
+ (LayoutTestController::setPopupBlockingEnabled):
+ (LayoutTestController::overridePreference):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-10-01 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Turn on ENABLE_3D_CANVAS in TOT
+ https://bugs.webkit.org/show_bug.cgi?id=29906
+
+ * Scripts/build-webkit:
+
+2009-10-01 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Rubberstamped by Simon Hausmann.
+
+ Enable HTTP tests for Qt
+
+ * Scripts/run-webkit-tests:
+
+2009-10-01 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by Dimitri Glazkov.
+
+ build-webkit --chromium now also works on cygwin.
+
+ https://bugs.webkit.org/show_bug.cgi?id=29973
+
+ * Scripts/webkitdirs.pm:
+
+2009-10-01 Zoltan Horvath <zoltan@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Don't use TCmalloc in DumpRenderTree
+ https://bugs.webkit.org/show_bug.cgi?id=27029
+
+ Add USE_SYSTEM_MALLOC macro to the DRT's profile to avoid using TCmalloc in Qt's DRT.
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+
+2009-10-01 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Implement eventSender.scheduleAsynchronousClick().
+
+ https://bugs.webkit.org/show_bug.cgi?id=29931
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (EventSender::scheduleAsynchronousClick):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-10-01 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Implement setPopupBlockingEnabled() in the LayoutTestController and remove
+ fast/events/open-window-from-another-frame.html from the Skipped list.
+
+ https://bugs.webkit.org/show_bug.cgi?id=29930
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::setPopupBlockingEnabled):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-09-30 Cameron McCormack <cam@mcc.id.au>
+
+ Unreviewed.
+
+ Added myself to the list of committers.
+
+ * Scripts/modules/committers.py:
+
+2009-09-30 Eric Seidel <eric@webkit.org>
+
+ No review, just adding Geoff to the list of reviewers.
+
+ * Scripts/modules/committers.py:
+
+2009-09-30 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Added the WebKit Layout Tests fonts that are referenced in
+ LayoutTests/platform/win/css2.1/resources/Mac-compatible-font-fallback.css
+
+ * DumpRenderTree/fonts/WebKit Layout Tests 2.ttf: Added.
+ * DumpRenderTree/fonts/WebKit Layout Tests.ttf: Added.
+
+2009-09-30 Csaba Osztrogonac <oszi@inf.u-szeged.hu>
+
+ Reviewed by David Kilzer.
+
+ Make sunspider scripts work on Windows platform.
+ https://bugs.webkit.org/show_bug.cgi?id=29656
+
+ * Scripts/run-sunspider: Perl scripts invoked with same Perl interpreter.
+ * Scripts/sunspider-compare-results: Perl scripts invoked with same Perl interpreter.
+ * Scripts/webkitdirs.pm: currentPerlPath() added.
+
+2009-09-29 Brady Eidson <beidson@apple.com>
+
+ Rubberstamped by Dan Bernstein.
+
+ Fix license and some sorting in new files.
+
+ * DumpRenderTree/mac/HistoryDelegate.h:
+ * DumpRenderTree/mac/HistoryDelegate.mm:
+
+2009-09-29 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by David Kilzer.
+
+ Fixed how error codes are handled.
+ https://bugs.webkit.org/show_bug.cgi?id=29898
+
+ * Scripts/update-webkit:
+ * Scripts/update-webkit-chromium:
+
+2009-09-29 Brady Eidson <beidson@apple.com>
+
+ Reviewed by John Sullivan.
+
+ Updated way-out-of-date sorting throughout the dump methods/flags.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (dumpAsPDFCallback):
+ (dumpAsTextCallback):
+ (dumpFrameLoadCallbacksCallback):
+ (dumpResourceLoadCallbacksCallback):
+ (LayoutTestController::staticFunctions):
+
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::dumpAsText):
+ (LayoutTestController::setDumpAsText):
+ (LayoutTestController::dumpFrameLoadCallbacks):
+ (LayoutTestController::setDumpFrameLoadCallbacks):
+ (LayoutTestController::dumpSelectionRect):
+ (LayoutTestController::setDumpSelectionRect):
+ (LayoutTestController::dumpSourceAsWebArchive):
+ (LayoutTestController::setDumpSourceAsWebArchive):
+ (LayoutTestController::dumpStatusCallbacks):
+ (LayoutTestController::setDumpStatusCallbacks):
+ (LayoutTestController::dumpTitleChanges):
+ (LayoutTestController::setDumpTitleChanges):
+ (LayoutTestController::dumpWillCacheResponse):
+ (LayoutTestController::setDumpWillCacheResponse):
+
+2009-09-29 Brady Eidson <beidson@apple.com>
+
+ Reviewed by John Sullivan.
+
+ WebKit Mac API should provide a delegate interface for global history.
+ <rdar://problem/7042773> and https://webkit.org/b/29904
+
+ Adding the dumping of global history delegate callbacks.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+
+ Automatically dump history delegate callbacks for tests with "globalhistory/" in their URL:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (createWebViewAndOffscreenWindow):
+ (allocateGlobalControllers):
+ (shouldLogFrameLoadDelegates):
+ (shouldLogHistoryDelegates):
+ (runTest):
+
+ Dump history delegate callbacks:
+ * DumpRenderTree/mac/HistoryDelegate.h: Added.
+ * DumpRenderTree/mac/HistoryDelegate.mm: Added.
+ (-[HistoryDelegate webView:didNavigateWithNavigationData:inFrame:]):
+ (-[HistoryDelegate webView:didPerformClientRedirectFromURL:toURL:inFrame:]):
+ (-[HistoryDelegate webView:didPerformServerRedirectFromURL:toURL:inFrame:]):
+
+2009-09-29 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ https://bugs.webkit.org/show_bug.cgi?id=28902
+
+ Fixes an issue where the drop effect returned by Window Dump Render Tree
+ was always DROPEFFECT_NONE (since it was hard coded to do so).
+
+ This patch corrects this issue by determining the actual drop effect
+ performed by the corresponding drag-and-drop operation so that we can
+ return it.
+
+ * DumpRenderTree/win/DraggingInfo.h: Added field m_dropEffect to store performed drop effect.
+ (DraggingInfo::DraggingInfo):
+ (DraggingInfo::performedDropEffect): Added method.
+ (DraggingInfo::setPerformedDropEffect): Added method.
+ * DumpRenderTree/win/EventSender.cpp:
+ (doMouseUp): Calls method DraggingInfo::setPerformedDropEffect with performed drop effect.
+ Moved delete draggingInfo to UIDelegate::doDragDrop.
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::doDragDrop): Sets performedDropEffect to DraggingInfo::performedDropEffect().
+
+2009-09-29 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Adam Roben.
+
+ Remove copying of unnecessary or nonexistent files from the ImageDiff
+ post-build event.
+
+ * DumpRenderTree/win/ImageDiff.vcproj:
+
+2009-09-29 Csaba Osztrogonac <oszi@inf.u-szeged.hu>
+
+ Reviewed by David Kilzer.
+
+ [Qt] Make build-webkit script work on Windows
+ https://bugs.webkit.org/show_bug.cgi?id=29802
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+ - Removed unnecessary -p switch for mkdir on Windows.
+ - Use canonical path, which uses slashes or backslashes depends on platform.
+ - isWindows() only test for Windows and not for Cyqwin.
+
+2009-09-29 Andras Becsi <becsi.andras@stud.u-szeged.hu>
+
+ Reviewed by Simon Hausmann.
+
+ Fix time measurement in build-webkit after refactoring done in r48853.
+
+ * Scripts/build-webkit:
+
+2009-09-29 Andras Becsi <becsi.andras@stud.u-szeged.hu>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [Qt] Default font size reconciliation to 16px/13px to match other platform's de-facto standard.
+ This fixes https://bugs.webkit.org/show_bug.cgi?id=19674.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+
+2009-09-29 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Implement eventSender.contextClick().
+ https://bugs.webkit.org/show_bug.cgi?id=29821
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (EventSender::contextClick):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-09-28 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ Add experimentalWebSocketsEnabled in WebPreferences.
+ https://bugs.webkit.org/show_bug.cgi?id=28941
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2009-09-28 Yaar Schnitman <yaar@chromium.org>
+
+ Reviewed by David Kilzer.
+
+ Integrated chromium port building into webkit tools update-webkit and
+ build-webkit.
+
+ https://bugs.webkit.org/show_bug.cgi?id=29749
+
+ * Scripts/build-webkit: When --chromium is specified, will build
+ the chromium port (currently only Mac is supported).
+ * Scripts/update-webkit: When --chromium is specified, delegates to
+ update-webkit-chromium.
+ * Scripts/webkitdirs.pm: Added chromium specific defs.
+ * Scripts/update-webkit-chromium: Uses gclient and gyp to fetch
+ chromium port's dependencies and update its project files.
+
+2009-09-28 Fumitoshi Ukai <ukai@chromium.org>
+
+ Unreviewed.
+
+ Add myself to list of committers.
+
+ * Scripts/modules/committers.py:
+
+2009-09-27 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ run-webkit-tests: Do not strip the metrics when there is no expected result for a test.
+ https://bugs.webkit.org/show_bug.cgi?id=29771
+
+ * Scripts/run-webkit-tests:
+
+2009-09-27 Jakub Wieczorek <faw217@gmail.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Implement layoutTestController.waitForPolicyDelegate.
+ https://bugs.webkit.org/show_bug.cgi?id=25037
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::acceptNavigationRequest):
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::waitForPolicyDelegate):
+ * DumpRenderTree/qt/jsobjects.h:
+ (LayoutTestController::waitForPolicy):
+
+2009-09-26 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/29764> mark-bug-fixed: add -o|--open switch
+
+ Reviewed by Eric Seidel.
+
+ The -o|--open switch uses the open(1) command on Mac OS X to
+ open the bug URL in the default web browser. If there are
+ similar mechanisms on other platforms, they may be added later.
+
+ * Scripts/mark-bug-fixed:
+ (MarkBugFixed.__init__): Added -o|--open switch to list of parse
+ options.
+ (MarkBugFixed._determine_bug_id_and_svn_revision): Moved logging
+ code into main() and extracted prompting code into
+ _prompt_user_for_correctness().
+ (MarkBugFixed._open_bug_in_web_browser): Added.
+ (MarkBugFixed._prompt_user_for_correctness): Added.
+ (MarkBugFixed.main): Added logging code from
+ _determine_bug_id_and_svn_revision(). Added code to call
+ _open_bug_in_web_browser() if the switch is set. Added code to
+ call _prompt_user_for_correctness() when needed.
+ * Scripts/modules/bugzilla.py:
+ (Bugzilla.short_bug_url_for_bug_id): Added.
+
+2009-09-26 David Kilzer <ddkilzer@apple.com>
+
+ svn-unapply and svn-apply don't work when used outside multiple svn working directories
+
+ <http://webkit.org/b/29744>
+ <rdar://problem/7252905>
+
+ Reviewed by Eric Seidel.
+
+ Some users have a workflow where svn-create-patch, svn-apply and
+ svn-unapply are used outside of multiple svn working
+ directories. Instead of aborting the scripts in these cases,
+ print a warning and assume that Subversion is being used.
+
+ * Scripts/VCSUtils.pm:
+ (determineVCSRoot): Call warn() instead of die() if both isGit()
+ and isSVN() initially return false. Set $VCSUtils::isSVN to 1
+ to enforce the assumption about Subversion, then return
+ determineSVNRoot().
+ * Scripts/svn-apply: Switch to using isGit() and isSVN() from
+ VCSUtils.pm. They both already cache their values and checking
+ here is redundant since determineVCSRoot() is called later.
+
+2009-09-26 Zan Dobersek <zandobersek@gmail.com>
+
+ Reviewed by Gustavo Noronha.
+
+ [Layout tests] [Gtk] Gtk DumpRenderTree should use WebKit test fonts
+ https://bugs.webkit.org/show_bug.cgi?id=29689
+
+ Load test fonts through FontConfig before each test.
+ This ensures a more proper rendering of the tests.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (initializeFonts):
+ (runTest):
+ (main):
+ * DumpRenderTree/gtk/fonts.conf: Copied from WebKitTools/DumpRenderTree/qt/fonts.conf.
+ * GNUmakefile.am:
+
+2009-09-25 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/29718> mark-bug-fixed: add -u|--update-only switch
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/mark-bug-fixed:
+ (MarkBugFixed.__init__): Added -u|--update-only switch to list
+ of parse options.
+ (MarkBugFixed.main): When -u|--update-only is specified, add a
+ comment to the bug without marking it Resolved/Fixed.
+
+2009-09-25 Darin Adler <darin@apple.com>
+
+ Reviewed by Geoffrey Garen.
+
+ * Scripts/prepare-ChangeLog: Leave files from the script-tests directory
+ out, just as we do for the resources directory.
+
+2009-09-25 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. Added Tony to committers.py because he's a
+ committer now.
+
+ * Scripts/modules/committers.py:
+
+2009-09-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Simon Fraser.
+
+ REGRESSION: media/video-pause-empty-events.html is occasionally timing out on bots
+ https://bugs.webkit.org/show_bug.cgi?id=28624
+
+ Disable hardware compositing on Leopard for versions of QuickTime 7.6.4 and older.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+
+2009-09-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue should auto-retry patches which fail to commit due to out of date files
+ https://bugs.webkit.org/show_bug.cgi?id=28316
+
+ * Scripts/bugzilla-tool:
+ - Handle new CheckoutNeedsUpdate exception.
+ * Scripts/modules/logging_unittest.py:
+ - Call the ScriptError constructor correctly (this test had regressed).
+ * Scripts/modules/scm.py:
+ - Added the ability to define custom error handlers for run_command
+ and added a commit_error_handler which throws CheckoutNeedsUpdate
+ instead of ScriptError.
+ - Re-ordered ScriptError constructor arguments to make ScriptError("message text") usage possible.
+ * Scripts/modules/scm_unittest.py:
+ - Added tests of new error handlers.
+
+2009-09-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue should give better feedback when failing a patch
+ https://bugs.webkit.org/show_bug.cgi?id=29316
+
+ * Scripts/bugzilla-tool:
+ - Update ScriptError uses to the new constructor format.
+ - Move CommitQueue._run_command to WebKitLandingScripts.run_command_with_teed_output
+ so that we can print to both stdout as well as an output buffer for error reporting.
+ - Update run_and_throw_if_fail to use teed output so that it can report the "output" as part of ScriptError.
+ - Use e.message_with_output() when failing a patch (this is the real fix here).
+ I also removed use of "This patch will require manual commit." as that's not always true.
+ - Add missing word "bug" from log message.
+ * Scripts/modules/scm.py:
+ - Make ScriptError save a bunch more data so that error messages can be nicer.
+ - Update ScriptError callers.
+
+2009-09-24 John Gregg <johnnyg@google.com>
+
+ Reviewed by Eric Seidel.
+
+ Enable switch for notifications (experimental) in Page Settings
+ https://bugs.webkit.org/show_bug.cgi?id=28930
+
+ Now that desktop notifications are controlled by run-time switch,
+ set that switch to true for DumpRenderTree.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::QueryInterface):
+
+2009-09-24 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. SnowLeopard fixes for Mac dependencies.
+
+ * wx/build/build_utils.py:
+ * wx/build/settings.py:
+ * wx/install-unix-extras:
+
+2009-09-24 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Oliver Hunt.
+
+ Add support for DRT to send mouse wheel events.
+
+ https://bugs.webkit.org/show_bug.cgi?id=29348
+ [Gtk] Scrollwheel on horizontal scrollbars should slide horizontally
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (mouseWheelToCallback):
+
+2009-09-17 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ commit-queue needs web-based status reporting
+ https://bugs.webkit.org/show_bug.cgi?id=29307
+
+ Add a first-pass web-based status for the commit-queue.
+ The bot is currently reachable at:
+ http://webkit-commit-queue.appspot.com/
+
+ * CommitQueueStatus/app.yaml: Added.
+ - Application description file required by App Engine.
+ * CommitQueueStatus/filters/__init__.py: Added.
+ - Required by python to treat 'filters' as a module.
+ * CommitQueueStatus/filters/webkit_extras.py: Added.
+ - Support for turning 'bug 123' and 'patch 123' into links.
+ This lets us use plain text strings in our logs yet display nice HTML (help prevent XSS attacks on the page).
+ * CommitQueueStatus/index.html: Added.
+ * CommitQueueStatus/index.yaml: Added.
+ - Some auto-generated file from app engine.
+ * CommitQueueStatus/queue_status.py: Added.
+ - The core logic of this bot. We could eventually split this file out into pieces.
+ * CommitQueueStatus/stylesheets/main.css: Added.
+ - Some basic lame-o CSS to make the page look less awful.
+ * CommitQueueStatus/update_status.html: Added.
+ - The form that the commit-queue (or a human) can use to update the status.
+ * Scripts/bugzilla-tool:
+ - Add some very basic update_status calls.
+ * Scripts/modules/statusbot.py: Added.
+ - Knows how to post to the CommitQueueStatus web application.
+
+2009-09-24 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/29712> mark-bug-fixed: add -m|--comment switch
+
+ Reviewed by Adam Roben.
+
+ * Scripts/mark-bug-fixed:
+ (MarkBugFixed.__init__): Added -m|--comment switch to list of
+ parse options.
+ (MarkBugFixed.main): When specified, prepend comment from
+ -m|--comment command-line switch to the bug comment.
+
+2009-09-24 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Jan Alonzo.
+
+ [GTK] DRT must display window instead of just realizing, to enable synthesizing events correctly
+ https://bugs.webkit.org/show_bug.cgi?id=29693
+
+ Show the window, to be able to synthesize events correctly.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (runTest):
+ (main):
+
+2009-09-24 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by NOBODY(rollout)
+
+ Roll out r48712 as it is incorrect.
+
+ * DumpRenderTree/mac/ObjCController.m:
+ (+[ObjCController isSelectorExcludedFromWebScript:]):
+ (+[ObjCController webScriptNameForSelector:]):
+
+2009-09-24 Benjamin Poulain <benjamin.poulain@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=29005
+ The indices of RuntimeArray should be enumerated like for a regular array.
+
+ * DumpRenderTree/mac/ObjCController.m:
+ (+[ObjCController isSelectorExcludedFromWebScript:]):
+ (+[ObjCController webScriptNameForSelector:]):
+ (-[ObjCController arrayOfString]):
+
+2009-09-23 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/28910> Move bugzilla-tool mark-fixed to standalone mark-bug-fixed tool
+
+ Reviewed by Darin Adler.
+
+ Also fixed a bug where specifying a revision on the command-line
+ as 'r12345' would fail. See <http://webkit.org/b/29699>.
+
+ * Scripts/bugzilla-tool: Updated module import statements.
+ (parse_bug_id): Removed. Moved to bugzilla.py.
+ (bug_comment_from_svn_revision): Removed. Moved to comments.py.
+ (bug_comment_from_commit_text): Removed. Moved to comments.py.
+ (MarkBugFixed): Removed. Code moved to mark-bug-fixed.
+ (BugzillaTool.__init__): Removed mark-fixed subcommand.
+ * Scripts/mark-bug-fixed: Added.
+ * Scripts/modules/bugzilla.py:
+ (parse_bug_id): Added. Moved from bugzilla-tool.
+ * Scripts/modules/comments.py: Added.
+ (bug_comment_from_svn_revision): Added. Moved from bugzilla-tool.
+ (bug_comment_from_commit_text): Added. Moved from bugzilla-tool.
+
+2009-09-23 Marshall Culpepper <mculpepper@appcelerator.com>
+
+ Reviewed by Eric Seidel.
+
+ jpeg.lib is now libjpeg.lib in DRT Cairo dependencies. return
+ "false" in non-implemented stub for setAlwaysAcceptCookies.
+ https://bugs.webkit.org/show_bug.cgi?id=29661
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+
+2009-09-23 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Reviewed by Xan Lopez.
+
+ [GTK] need to dump number of pending unload handlers
+ https://bugs.webkit.org/show_bug.cgi?id=29685
+
+ Implement dumping of the number of pending unload handlers.
+
+ The following tests will pass:
+
+ fast/loader/unload-form-about-blank.html
+ fast/loader/unload-form-post-about-blank.html
+ fast/loader/unload-form-post.html
+ fast/loader/unload-form.html
+ fast/loader/unload-hyperlink.html
+ fast/loader/unload-javascript-url.html
+ fast/loader/unload-reload.html
+ fast/loader/unload-window-location.html
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (getFrameNameSuitableForTestResult):
+ (webViewLoadFinished):
+
+2009-09-22 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ js tests should move into jstests subdirectory instead of resources/
+ https://bugs.webkit.org/show_bug.cgi?id=25880
+
+ Remove support of resources directory.
+
+ * Scripts/make-script-test-wrappers:
+
+2009-09-22 Eric Seidel <eric@webkit.org>
+
+ No review, only fixing typo (missing space character).
+
+ Fix typo from https://bugs.webkit.org/show_bug.cgi?id=29220
+
+ * Scripts/run-webkit-tests:
+
+2009-09-22 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ run-webkit-tests needs a --repeat-each=N option (AAABBBCCC instead of ABCABCABC)
+ https://bugs.webkit.org/show_bug.cgi?id=29220
+
+ * Scripts/run-webkit-tests:
+
+2009-09-22 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ svn-apply can't handle single-line binary file additions
+ https://bugs.webkit.org/show_bug.cgi?id=29100
+
+ Fixed the regexp and added a unit test.
+
+ * Scripts/modules/scm_unittest.py:
+ * Scripts/svn-apply:
+
+2009-09-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ post-diff and post-commits should be able to find bug urls in ChangeLogs.
+ https://bugs.webkit.org/show_bug.cgi?id=29206
+
+ * Scripts/bugzilla-tool:
+ - Share common options by adding a PostDiffAsPatchToBug.posting_options() method.
+ - Rename --no-comment to --add-log-as-comment and reverse behavior.
+ Comments tend to just be noise. I'll eventually remove this argument if no one uses it.
+ - Split out code into helper functions to try and make execute() more legible.
+ - Make post-diff find the bug url in the ChangeLogs if not passed as an argument.
+ - Fallback to bug urls in commit diffs, instead of just in commit messages,
+ meaning post-commits will now find bug urls in ChangeLogs.
+
+2009-09-21 Csaba Osztrogonac <oszi@inf.u-szeged.hu>
+
+ Reviewed by Maciej Stachowiak.
+
+ --parse-only parameter wasn't passed to SunSpider/sunspider script.
+ https://bugs.webkit.org/show_bug.cgi?id=29611
+
+ * Scripts/run-sunspider: Missing parameter passing added.
+
+2009-09-20 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/29521> run-webkit-tests: use require instead eval to load DumpRenderTreeSupport module
+
+ Reviewed by Mark Rowe.
+
+ The require statement is like the use statement, except that it
+ is run during script execution instead of during the 'BEGIN'
+ phase. This makes it possible to change @INC before the require
+ statement is run. See 'require' and 'use' in the perlfunc(1)
+ manpage and 'BEGIN' in perlmod(1) manpage.
+
+ * Scripts/run-webkit-tests: Replace eval statement with require
+ statement.
+
+2009-09-18 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fixes. Fix the config name under git and allow users to specify
+ their own waf install for experimenting with new versions.
+
+ * Scripts/webkitdirs.pm:
+ * wx/build/settings.py:
+
+2009-09-18 Alex Milowski <alex@milowski.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Added checkWebCoreMathMLSupport and hasMathMLSupport to support
+ checking for whether MathML tests should be run
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2009-08-28 Darin Adler <darin@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Break more of run-webkit-tests into separate functions
+ https://bugs.webkit.org/show_bug.cgi?id=29497
+
+ Some small steps toward improving run-webkit-tests. My goal is to
+ refactor much more of the script into functions. Later we can add
+ parallel test running to the tool. But better structure may help
+ even if someone decides to translate this into another scripting
+ language instead.
+
+ * Scripts/run-webkit-tests: Break more pieces of the script into
+ seprate functions. Added readSkippedFiles, findTestsToRun, and
+ printResults functions. Removed custom code to skip results.html
+ and instead just put it into the ignoredFiles hash. Fixed some
+ indentation. Sorted function declarations, global variables,
+ and options at the top of the file alphabetically so they're not
+ in a semi-random order.
+
+2009-09-17 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix, add missing dependency.
+
+ * wx/browser/wscript:
+
+2009-09-16 Mark Rowe <mrowe@apple.com>
+
+ Split the SnowLeopard build across a few machines.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2009-09-16 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix to support monolithic builds on Windows.
+
+ * wx/build/wxpresets.py:
+
+2009-09-16 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix, improve debug support and 2.9 support on MSW.
+
+ * wx/build/settings.py:
+ * wx/build/wxpresets.py:
+
+2009-09-16 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Blind try at fixing new test failure on Windows.
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::didReceiveTitle):
+
+2009-09-15 Alex Milowski <alex@milowski.com>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Added mathml toggle
+
+ * Scripts/build-webkit:
+
+2009-09-15 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Allow waf build to support Python < 2.6.
+
+ * wx/build/waf_extensions.py:
+
+2009-09-14 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Add LayoutTests infrastructure to enable and disable webgl tests.
+ https://bugs.webkit.org/show_bug.cgi?id=29254
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2009-09-14 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Add --iterations option to run-webkit-tests to repeat the tests N times
+ https://bugs.webkit.org/show_bug.cgi?id=29263
+
+ When run with --iterations N, run-webkit-tests will repeat the tests N times.
+
+ * Scripts/run-webkit-tests:
+
+2009-09-14 Brady Eidson <beidson@apple.com>
+
+ Not reviewed, maybe should've been:
+
+ Cleaning up more Windows-specific fallout from the fix for:
+ <rdar://problem/7174050> and https://bugs.webkit.org/show_bug.cgi?id=29160
+
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::didReceiveAuthenticationChallenge): Correct printf() formatter,
+ and call the correct method to get the Sender.
+
+2009-09-14 Jon Honeycutt <jhoneycutt@apple.com>
+
+ GTK build fix.
+
+ Unreviewed.
+
+ * DumpRenderTree/gtk/AccessibilityControllerGtk.cpp:
+ (AccessibilityController::setLogScrollingStartEvents):
+
+2009-09-11 Jon Honeycutt <jhoneycutt@apple.com>
+
+ DRT/test part of
+ <rdar://problem/7197644> WebKit should broadcast an MSAA event when
+ jumping to a named anchor
+
+ https://bugs.webkit.org/show_bug.cgi?id=28899
+
+ Reviewed by Adam Roben.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (logScrollingStartEventsCallback):
+ Turn on logging of scrolling start events.
+ (AccessibilityController::getJSClass):
+ Add a "logScrollingStartEvents" to the AccessibilityController's JS
+ class definition.
+ (AccessibilityController::resetToConsistentState):
+ Turn off logging of scrolling start events.
+
+ * DumpRenderTree/AccessibilityController.h:
+ Declare setLogScrollingStartEvents(). Add a member for the scrolling
+ start event hook.
+
+ * DumpRenderTree/mac/AccessibilityControllerMac.cpp:
+ (AccessibilityController::setLogScrollingStartEvents):
+ Stubbed.
+
+ * DumpRenderTree/win/AccessibilityControllerWin.cpp:
+ (AccessibilityController::AccessibilityController):
+ Initialize the handle to 0.
+ (logEventProc):
+ Renamed from logFocusEventProc; now logs scrolling start events, too.
+ Removed the assertion that the event is a focus event. Added a switch
+ to print a message for focus, scrolling start, and other, unknown
+ events.
+ (AccessibilityController::setLogFocusEvents):
+ Changed to use logEventProc.
+ (AccessibilityController::setLogScrollingStartEvents):
+ If turning logging off, unhook the scrolling start event hook, and clear
+ the member holding the handle. If turning on, query for the root
+ accessible, so that accessibility is enabled for the WebView, and call
+ SetWinEventHook to setup an event hook using logEventProc as the
+ callback function.
+
+2009-09-14 Brady Eidson <beidson@apple.com>
+
+ Windows build fix.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setAuthenticationPasswordCallback):
+ (setAuthenticationUsernameCallback):
+
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::didReceiveAuthenticationChallenge):
+
+2009-09-14 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Safari 4 cannot be used to update firmware on Linksys routers.
+ <rdar://problem/7174050> and https://bugs.webkit.org/show_bug.cgi?id=29160
+
+ Add the ability for DRT to handle authentication challenges.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setAuthenticationPasswordCallback):
+ (setAuthenticationUsernameCallback):
+ (setHandlesAuthenticationChallengesCallback):
+ (LayoutTestController::staticFunctions):
+
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::handlesAuthenticationChallenges):
+ (LayoutTestController::setHandlesAuthenticationChallenges):
+ (LayoutTestController::authenticationUsername):
+ (LayoutTestController::setAuthenticationUsername):
+ (LayoutTestController::authenticationPassword):
+ (LayoutTestController::setAuthenticationPassword):
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:resource:didReceiveAuthenticationChallenge:fromDataSource:]):
+
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::didReceiveAuthenticationChallenge):
+ * DumpRenderTree/win/ResourceLoadDelegate.h:
+
+2009-09-12 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Test for <rdar://problem/6954546> and <rdar://problem/7090444>.
+
+ Add a flag on the test plug-in that asks it to clear the document during the call to NPP_New.
+ This is the trigger for both <rdar://problem/6954546> and <rdar://problem/7090444>.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+
+2009-09-14 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix for non-wxPython builds and a fix for errors when updating swig.py.
+
+ * wx/build/build_utils.py:
+ * wx/build/settings.py:
+
+2009-09-14 Csaba Osztrogonac <oszi@inf.u-szeged.hu>
+
+ Reviewed by Tor Arne Vestbø.
+
+ [Qt] Build fix for windows build.
+
+ * Scripts/bisect-builds: Add missing paranthesis for tmpdir function.
+
+2009-09-13 Kevin Ollivier <kevino@theolliviers.com>
+
+ Fix typo accidently landed in last commit.
+
+ * wx/build/settings.py:
+
+2009-09-13 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix, error out if using the wrong Python.
+
+ * wx/build/settings.py:
+
+2009-09-13 Xan Lopez <xlopez@igalia.com>
+
+ Build fix for GTK+ < 2.14.
+
+ Do not use gtk_widget_get_window, access the window directly
+ through the struct.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (contextClickCallback):
+ (mouseDownCallback):
+ (mouseUpCallback):
+ (mouseMoveToCallback):
+ (keyDownCallback):
+
+2009-09-13 Martin Robinson <martin.james.robinson@gmail.com>
+
+ Reviewed by Xan Lopez and Jan Alonzo.
+
+ [GTK] EventSender does not set 'window' property on synthesized GDK events
+ https://bugs.webkit.org/show_bug.cgi?id=29169
+
+ Set the window property on synthesized GDK events in the GTK+ EventSender.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (contextClickCallback):
+ (mouseDownCallback):
+ (mouseUpCallback):
+ (mouseMoveToCallback):
+ (keyDownCallback):
+
+2009-09-12 Drew Wilson <atwilson@google.com>
+
+ Reviewed by Mark Rowe.
+
+ run-webkit-tests has a timeout value that is too low
+ https://bugs.webkit.org/show_bug.cgi?id=29223
+
+ * Scripts/run-webkit-tests:
+ Changed timeout value to 20 seconds to avoid timing out too early.
+
+2009-09-11 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Mark dependencies as mandatory and declare which MSVC versions and
+ architectures are supported for building wxWebKit.
+
+ * wx/build/settings.py:
+
+2009-09-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ bugzilla-tool rollout threw exception under svn
+ https://bugs.webkit.org/show_bug.cgi?id=29211
+
+ * Scripts/modules/scm.py: add missing return, and convert number arguments to strings.
+ * Scripts/modules/scm_unittest.py: add testing for this fix.
+
+2009-09-11 Brian Weinstein <bweinstein@apple.com>
+
+ Add myself to the committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-09-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool land-patches should only fail-fast in --commit-queue mode
+ https://bugs.webkit.org/show_bug.cgi?id=29201
+
+ * Scripts/bugzilla-tool:
+
+2009-09-11 Adam Roben <aroben@apple.com>
+
+ Make commit-log-editor move common prefixes to the top of the log
+
+ Fies <http://webkit.org/b/29190> commit-log-editor should move common
+ prefixes to the top of the commit log
+
+ Reviewed by Darin Adler.
+
+ * Scripts/commit-log-editor: Find and remove the longest common prefix
+ ending in a double newline from each ChangeLog entry, then put that
+ common prefix at the top of the commit log.
+ (removeLongestCommonPrefixEndingInDoubleNewline): Added. Finds,
+ removes, and returns the longest common prefix ending in a double
+ newline from a hash of strings
+
+2009-09-11 Eric Seidel <eric@webkit.org>
+
+ Fix obvious typo in previous commit, no review.
+
+ bugzilla-tool should automate rollouts
+ https://bugs.webkit.org/show_bug.cgi?id=26715
+
+ * Scripts/bugzilla-tool: add back missing "scm" argument.
+
+2009-09-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool should automate rollouts
+ https://bugs.webkit.org/show_bug.cgi?id=26715
+
+ bugzilla-tool rollout will do the rollout locally and leave the diff for you to verify and commit.
+ The --complete-rollout option will automatically land and update the bug.
+ Eventually --complete-rollout will be default, but that will require more testing.
+
+ This first pass is good enough for others to try and file bugs about.
+
+ * Scripts/bugzilla-tool:
+ - Move modified_changelogs into scm.py.
+ - Move svn_revision_from_commit_text logic into scm.py.
+ - Add RolloutCommit command.
+ * Scripts/modules/bugzilla.py:
+ - Add reopen_bug command used by RolloutCommit.
+ * Scripts/modules/scm.py:
+ - Add functions to support RolloutCommit.
+ - Abstract find_uuid into value_from_svn_info so it can be re-used for _repository_url (needed by svn merge).
+ - Add a str() call so that svn_commit_log can take a numeric argument.
+ - Remove a bunch of very slow code from last_svn_commit_log and used the built-in 'BASE' alias instead.
+ - Made dry_run commits return something that svn_revision_from_commit_text can parse.
+ * Scripts/modules/scm_unittest.py:
+ - Add read_from_path for easy file reading.
+ - Put test4 on a new line to make reverts work w/o conflict.
+ - Add an "svn update" call so that the checkout revision matches the server revision.
+ - Add tests for svn_revision_from_commit_text.
+ - Add a simple test for apply_reverse_diff.
+ - Add a new self.scm member and use it in the new tests (eventually other tests can use it too).
+ - Add test for svn_commit_log to make sure my 'BASE' change above worked as expected.
+
+2009-09-11 Adam Roben <aroben@apple.com>
+
+ Get user script/stylesheet tests running on Windows
+
+ Fixes <http://webkit.org/b/29181> User script/stylesheet tests are
+ skipped on Windows
+
+ Reviewed by John Sullivan.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Link all configurations
+ against comsuppw.lib so we can use _bstr_t.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp: Fixed #include
+ order, added #include of comutil.h for _bstr_t.
+
+ (bstrT): Helper function to convert a JSStringRef to a _bstr_t.
+ (LayoutTestController::addUserScript):
+ (LayoutTestController::addUserStyleSheet):
+ Implemented. Implementations were based on those in
+ LayoutTestControllerMac.mm.
+
+2009-09-10 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/29147> run-webkit-tests: make -h show help
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/run-webkit-tests: Updated to make -h switch show help.
+
+2009-09-10 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ Add WebCore/websockets directory in wx build system.
+ https://bugs.webkit.org/show_bug.cgi?id=28038
+
+ * wx/build/settings.py:
+
+2009-09-10 Martin Robinson <martin.james.robinson@gmail.com>
+
+ [GTK] EventSender does not properly convert some keyDown strings
+ https://bugs.webkit.org/show_bug.cgi?id=29119
+
+ Add more keyDown string to character code conversions for GTK+ EventSender.
+
+ * DumpRenderTree/gtk/EventSender.cpp:
+ (keyDownCallback):
+
+2009-09-09 Steve Block <steveblock@google.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Geolocation Coordinates::toString() prints bogus values for unspecified properties.
+ https://bugs.webkit.org/show_bug.cgi?id=29080
+
+ * Scripts/make-script-test-wrappers: Modified. Adds asynchronous Geolocation tests to exclusion list.
+
+2009-09-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Eric Carlson.
+
+ reviewer/committer lookups are backwards
+ https://bugs.webkit.org/show_bug.cgi?id=29113
+
+ I also moved Eric Carlson from the committer list to the reviewer list now that he is one.
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/committers.py:
+
+2009-09-09 Cameron McCormack <cam@mcc.id.au>
+
+ Reviewed by Eric Seidel.
+
+ svn-unapply doesn't revert directories correctly
+ https://bugs.webkit.org/show_bug.cgi?id=29065
+
+ * Scripts/svn-unapply: Make svnStatus consistently return status
+ lines including a newline.
+ * Scripts/svn-apply: Keep svnStatus in sync with the one in
+ svn-unapply, in lieu of moving it to a common file.
+
+2009-09-09 Cameron McCormack <cam@mcc.id.au>
+
+ Reviewed by Eric Seidel.
+
+ svn-apply doesn't handle changes to files copied to new directories properly
+ https://bugs.webkit.org/show_bug.cgi?id=29059
+
+ * Scripts/svn-apply: Don't treat "--- revision 0" patches as being
+ additions if we know that we've just copied a file to this name.
+
+2009-09-09 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ commit-queue hangs if a builder has never built
+ https://bugs.webkit.org/show_bug.cgi?id=29091
+
+ * Scripts/modules/buildbot.py:
+ * Scripts/modules/buildbot_unittest.py:
+
+2009-09-09 Zan Dobersek <zandobersek@gmail.com>
+
+ Reviewed by Gustavo Noronha.
+
+ [GTK] DumpRenderTree needs eventSender object and implementation
+ https://bugs.webkit.org/show_bug.cgi?id=25990
+
+ Implements most of the EventSender object's functionality for
+ the DumpRenderTree tool. Implementation still lacks support
+ for drag and drop tests and forward leaps.
+
+ Based on work by Holger Hans Peter Freyther.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (runTest): Focus on the view before loading a new test.
+ (webViewWindowObjectCleared):
+ * DumpRenderTree/gtk/EventSender.cpp: Added.
+ (getDragModeCallback):
+ (setDragModeCallback):
+ (leapForwardCallback):
+ (contextClickCallback):
+ (updateClickCount):
+ (mouseDownCallback):
+ (mouseUpCallback):
+ (mouseMoveToCallback):
+ (beginDragWithFilesCallback):
+ (replaySavedEvents):
+ (keyDownCallback):
+ (textZoomInCallback):
+ (textZoomOutCallback):
+ (zoomPageInCallback):
+ (zoomPageOutCallback):
+ (getClass):
+ (makeEventSender):
+ * DumpRenderTree/gtk/EventSender.h: Added.
+ * GNUmakefile.am: Add build rules for EventSender.
+
+2009-09-09 Daniel Bates <dbates@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ https://bugs.webkit.org/show_bug.cgi?id=28953
+
+ Added pre- and post- build events so that on build failure, the file
+ buildfailed is written to the directory $(WebKitOutputDir).
+
+ * WinLauncher/WinLauncher.vcproj:
+
+2009-09-09 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Unreviewed.
+
+ Add myself to list of committers.
+
+ * Scripts/modules/committers.py:
+
+2009-09-08 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ commit-queue gets stuck if a non-committer sets commit-queue+ or review+
+ https://bugs.webkit.org/show_bug.cgi?id=28605
+ https://bugs.webkit.org/show_bug.cgi?id=28916
+
+ * Scripts/bugzilla-tool:
+ - Fix comment and adjust reject_patch_from_commit_queue call to pass "manual commit"
+ comment now that it's used for rejecting patches for invalid committers too.
+ - Pass reject_invalid_patches=True for commit-queue calls, normally we just ignore patches with invalid reviewers, the commit-queue rejects them.
+ - Make the commit queue print patches count instead of bugs count, this also fixes https://bugs.webkit.org/show_bug.cgi?id=28916.
+ * Scripts/modules/bugzilla.py:
+ - Make _parse_attachment_element not validate reviewer/committer.
+ - Share flag parsing code in _parse_attachment_flag.
+ - Add _validate* methods for validating reviewers and committers and updating bugs when validation fails.
+ - Add reject_invalid_patches argument so the commit-queue can update bugs on failed validation and other "read only" commands will not.
+ - Add reject_patch_from_review_queue using a new _set_flag_on_attachment abstraction.
+ * Scripts/modules/bugzilla_unittest.py:
+ - Update this test to no longer expect committer/reviewer validation.
+ * Scripts/modules/committers.py:
+ - Return None on failed lookups instead of raising Exceptions.
+ * Scripts/modules/committers_unittest.py:
+ - Update tests to expect None returns instead of exceptions.
+
+2009-09-09 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/29061> Fix obvious copy-paste error in AccessibilityUIElement::clickPointY()
+
+ Reviewed by Mark Rowe.
+
+ No change to layout test results.
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::clickPointY): Changed to return y value
+ instead of x value.
+
+2009-09-08 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by Mark Rowe.
+
+ Reduce dglazkov's boboiness by properly concatenating revision value.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: Used substitution
+ rather than "+".
+
+2009-09-08 Kevin Ollivier <kevino@theolliviers.com>
+
+ wxWebKit Python extension build fix - get swig.py if it doesn't exist.
+
+ * wx/build/build_utils.py:
+
+2009-09-08 Mark Rowe <mrowe@apple.com>
+
+ Fix an incorrect variable name in UpdateChromiumSource.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2009-09-08 Mark Rowe <mrowe@apple.com>
+
+ Don't check for leaks on the release SnowLeopard builder.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2009-09-08 Mark Rowe <mrowe@apple.com>
+
+ Add a SnowLeopard release builder.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2009-09-08 David Levin <levin@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Remove end of line whitespace check from check-webkit-style.
+ https://bugs.webkit.org/show_bug.cgi?id=29053
+
+ * Scripts/modules/cpp_style.py:
+
+2009-09-08 Cameron McCormack <cam@mcc.id.au>
+
+ Reviewed by Darin Adler.
+
+ Fix DumpRenderTree build from clean tree on Tiger
+ https://bugs.webkit.org/show_bug.cgi?id=28927
+
+ * DumpRenderTree/mac/PerlSupport/Makefile: Ensure the
+ DerivedSources/DumpRenderTree directory exists when
+ building on Tiger.
+
+2009-09-08 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix after introduction of platform/mock directory.
+
+ * wx/build/settings.py:
+
+2009-09-08 Yael Aharon <yael.aharon@nokia.com>
+
+ Unreviewed.
+
+ Add myself to list of committers.
+
+ * Scripts/modules/committers.py:
+
+2009-09-08 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Unreviewed.
+
+ Add myself to list of committers.
+
+ * Scripts/modules/committers.py:
+
+2009-09-08 Cameron McCormack <cam@mcc.id.au>
+
+ Reviewed by Darin Adler.
+
+ prepare-ChangeLog too chatty on file additions
+ https://bugs.webkit.org/show_bug.cgi?id=29019
+
+ * Scripts/prepare-ChangeLog: Omit description of added properties
+ on newly added files.
+
+2009-09-08 Steve Block <steveblock@google.com>
+
+ Reviewed by Adam Barth.
+
+ Adds a LayoutTestController method to set the permission state for Geolocation.
+ This is required to use the mock Geolocation service for testing.
+ https://bugs.webkit.org/show_bug.cgi?id=29027
+
+ * DumpRenderTree/LayoutTestController.cpp: Modified.
+ (setDatabaseQuotaCallback): Modified. Style fix.
+ (setGeolocationPermissionCallback): Added. Sets the Geolocation permission state.
+ (LayoutTestController::staticFunctions): Modified. Registers the above function on the LayoutTestController.
+ * DumpRenderTree/LayoutTestController.h: Modified.
+ (LayoutTestController::setGeolocationPermission): Added. Sets the Geolocation permission state.
+ (LayoutTestController::isGeolocationPermissionSet): Added. Returns whether the Geolocation permission has been set.
+ (LayoutTestController::geolocationPermission): Added. Returns the Geolocation permission state.
+ * DumpRenderTree/mac/UIDelegate.mm: Modified.
+ (-[UIDelegate webView:frame:requestGeolocationPermission:securityOrigin:]): Added. Implement chrome method to respond to request for Geolocation permission state. Response is made using above methods to access permission state.
+
+2009-09-08 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] QtWebKit single API to enable persistency
+ https://bugs.webkit.org/show_bug.cgi?id=28682
+
+ Use the new enablePersistentStorage API instead
+ of enabling all persistent features one-by-one.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2009-09-07 Andras Becsi <becsi.andras@stud.u-szeged.hu>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Refactor --strict switch to --ignore-metrics and correct the
+ implementation to make the feature usable on all platforms.
+ https://bugs.webkit.org/show_bug.cgi?id=28907
+
+ run-webkit-tests --ignore-metrics strips the font related metrics from
+ the actual and expected data before comparing them.
+ In this way the render trees can be checked for obvious differences but
+ a successful test implies by no means that the layout is actually correct.
+
+ * Scripts/run-webkit-tests:
+
+2009-09-07 Steve Block <steveblock@google.com>
+
+ Reviewed by Adam Barth.
+
+ Adds a mock Geolocation service. This will be used to provide predictable behavior of the
+ Geolocation API for use in LayoutTests. Later changes will integrate the the mock
+ Geolocation service with DumpRenderTree.
+ https://bugs.webkit.org/show_bug.cgi?id=28264
+
+ * DumpRenderTree/LayoutTestController.cpp: Modified.
+ (setMockGeolocationPositionCallback): Added. Configures the mock Geolocation service.
+ (setMockGeolocationErrorCallback): Added. Configures the mock Geolocation service.
+ (LayoutTestController::staticFunctions): Added. Registers the above functions on the LayoutTestController.
+ * DumpRenderTree/LayoutTestController.h: Modified.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm: Modified.
+ (LayoutTestController::setMockGeolocationPosition): Added. Configures the mock Geolocation service.
+ (LayoutTestController::setMockGeolocationError): Added. Configures the mock Geolocation service.
+
+2009-09-07 Drew Wilson <atwilson@google.com>
+
+ Reviewed by David Levin.
+
+ Enable SHARED_WORKERS by default
+ https://bugs.webkit.org/show_bug.cgi?id=28959
+
+ * Scripts/build-webkit:
+
+2009-09-07 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fixes for wx SVN trunk.
+
+ * wx/build/settings.py:
+
+2009-09-04 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx build fix. Switch USE_ defines over to the compiler so that they can be
+ checked by files not including config.h (like WebCorePrefix.h).
+
+ * wx/build/settings.py:
+
+2009-09-04 Adam Barth <abarth@webkit.org>
+
+ Unreviewed build fix.
+
+ Update declaration of FrameLoadDelegate to reflect that
+ IWebFrameLoadDelegatePrivate2 inherits from
+ IWebFrameLoadDelegatePrivate.
+
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+
+2009-09-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=24696
+
+ Add testing instrumentation for mixed content.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate webView:]):
+ (-[FrameLoadDelegate webView:didRunInsecureContent:]):
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (descriptionSuitableForTestResult):
+ (FrameLoadDelegate::QueryInterface):
+ (FrameLoadDelegate::didDisplayInsecureContent):
+ (FrameLoadDelegate::didRunInsecureContent):
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+
+2009-09-03 Kevin Watters <kevinwatters@gmail.com>
+
+ Reviewed by Kevin Ollivier.
+
+ [wx] Frames support
+ https://bugs.webkit.org/show_bug.cgi?id=19041
+
+ * wx/build-wxwebkit:
+
+2009-09-02 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/28880> svn-apply --force doesn't actually work
+
+ Reviewed by Eric Seidel.
+
+ This fixes "svn-apply --force" and adds unit tests for the
+ scm.apply_patch() method which uses this script.
+
+ * Scripts/svn-apply: Created $globalExitCode variable that
+ defaults to 0. Exit with a value of $globalExitCode when the
+ script is finished.
+ (applyPatch): Ignore a non-zero $exitCode if $force is true, but
+ set $globalExitCode to $exitCode so that svn-apply exits with a
+ non-zero status if any patches did not apply cleanly. Also
+ print out the actual patch command if $force was not true.
+
+ * Scripts/modules/scm.py:
+ (scripts_directory): Added. Extracted from script_path().
+ (script_path): Extracted scripts_directory().
+ * Scripts/modules/scm_unittest.py: Import urllib.
+ (SVNTestRepository.setup): Save the original working directory
+ in test_object since this represents the WebKit repository from
+ where the unit tests are run.
+ (SCMTest): Created new super class to hold utility methods.
+ (SCMTest._create_patch): Creates a patch file on disk and a
+ dictionary for use with scm.svn_apply().
+ (SCMTest._setup_webkittools_scripts_symlink): Sets up a symlink
+ back to WebKitTools/Scripts in the test repository so that
+ scm.apply_patch() is able to find the svn-apply script.
+ (SVNTest): Inherit from SCMTest instead of unittest.TestCase.
+ (SVNTest.tearDown): Make sure to change directories back to the
+ original_path before the next test.
+ (SVNTest.test_apply_svn_patch): New test case for applying an
+ svn patch with scm.apply_patch().
+ (SVNTest.test_apply_svn_patch_force): New test case for applying
+ an svn patch with scm.apply_patch() that conflicts.
+ (GitTest): Inherit from SCMTest instead of unittest.TestCase.
+ (GitTest.tearDown): Make sure to change directories back to the
+ original_path before the next test.
+ (GitTest.test_apply_git_patch): New test case for applying a git
+ patch with scm.apply_patch().
+ (GitTest.test_apply_git_patch_force): New test case for applying
+ a git patch with scm.apply_patch() that conflicts.
+
+2009-09-02 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Mark Rowe.
+
+ [Qt] Add support for platform-spesific layout-test results
+
+ For the Qt port we use the qt-[mac|linux|win] directories and then fall
+ back to the generic qt directory for both test results and skipped list.
+
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2009-09-02 Laurent Cerveau <lcerveau@me.com>
+
+ Reviewed by David Kilzer.
+
+ <http://webkit.org/b/25517> build-webkit script should print build time at end
+
+ * Scripts/build-webkit:
+ Added startTime and endTime variable so that the build time is computed and printed as
+ part of the build message; display formatting has been separated in a dedicated subroutine.
+
+2009-09-02 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/28881> svn-create-patch should check if the repo path is the same when trying to find the root
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/VCSUtils.pm:
+ (determineSvnRoot): Added back check for repository root that
+ was removed in r46134 when this code lived in svn-create-patch.
+ It's necessary to check both the repository root and the
+ repository UUID in case two different working directories are
+ checked out from the same repository.
+
+2009-09-02 Timothy Hatcher <timothy@apple.com>
+
+ Use new 512x512 icons for nightly builds.
+
+ Rubber-stamped by Mark Rowe.
+
+ * WebKitLauncher/webkit.icns:
+
+2009-09-02 Kevin Ollivier <kevino@theolliviers.com>
+
+ waf build fix. Remove local variable shadowing global.
+
+ * wx/build/settings.py:
+
+2009-09-02 Zan Dobersek <zandobersek@gmail.com>
+
+ Reviewed by David Kilzer.
+
+ Calls exitStatus function from the main package where it is also defined.
+
+ * Scripts/VCSUtils.pm:
+
+2009-09-02 Kevin Ollivier <kevino@theolliviers.com>
+
+ waf build fixes for Windows/MSVC and Mac/Snow Leopard.
+
+ * wx/browser/wscript:
+ * wx/build/build_utils.py:
+ * wx/build/settings.py:
+
+2009-08-10 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Eric Seidel.
+
+ Changes needed for build-webkit to support the waf build system for the wx port.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27619
+
+ * Scripts/build-webkit:
+ * Scripts/run-launcher:
+ * Scripts/webkitdirs.pm:
+
+2009-09-02 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/27168> With Subversion 1.6, update-webkit prompts on conflicts
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/update-webkit: Added "--accept postpone" to
+ @svnOptions when running with svn-1.6 or newer.
+
+2009-09-02 David Kilzer <ddkilzer@apple.com>
+
+ Moved svn 1.6 version check into VCSUtils::isSVNVersion16OrNewer()
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/VCSUtils.pm:
+ (@EXPORT): Added &isSVNVersion16OrNewer.
+ (svnVersion): Added. Internal method that gets the SVN version
+ and caches it.
+ (isSVNVersion16OrNewer): Added. Method that does the SVN 1.6
+ version check.
+ * Scripts/prepare-ChangeLog: Switched to use new
+ isSVNVersion16OrNewer() method.
+ * Scripts/resolve-ChangeLogs: Ditto.
+ * Scripts/svn-create-patch: Ditto.
+
+2009-09-02 David Kilzer <ddkilzer@apple.com>
+
+ Clean up VCSUtils.pm
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/VCSUtils.pm: Added proper package statement. Fixed
+ indentation of BEGIN block. Listed each exported method on a
+ line by itself. Added methods to the export list after adding
+ the package statement. Sorted module variables. Moved
+ definiton of $gitRoot next to other module variables.
+
+2009-09-01 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Rubber-stamped by Simon Hausmann.
+
+ [Qt] Fix layout-test plugins/plugin-javascript-access.html
+
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+
+2009-09-02 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ js tests should move into jstests subdirectory instead of resources/
+ https://bugs.webkit.org/show_bug.cgi?id=25880
+
+ make-script-wrappers supports both resources and script-tests directories.
+ run-webkit-tests ignores files in script-tests.
+ Move script tests of animations to check the new script is working.
+
+ * Scripts/make-script-test-wrappers:
+ * Scripts/run-webkit-tests:
+
+2009-09-02 Szabo Carol <carol.szabo@nokia.com>
+
+ Reviewed by David Levin.
+
+ check-webkit-style uses python from /usr/bin instead of the PATH
+ https://bugs.webkit.org/show_bug.cgi?id=28225
+
+ * Scripts/bugzilla-tool:
+ * Scripts/check-webkit-style:
+ * Scripts/run-webkit-unittests:
+ * Scripts/update-sources-list.py:
+ Changed the first line from
+ #!/usr/bin/python
+ to
+ #!/usr/bin/env python
+ which causes python to be invoked from the path location returned
+ by "which python" when any of these scripts are launched.
+ these are currently all the python scripts in WebKitTools/Scripts.
+
+2009-09-01 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/28601> bugzilla-tool post-commits posts commits backwards
+
+ Reviewed by Adam Barth.
+
+ * Scripts/modules/scm.py:
+ (Git.commit_ids_from_commitish_arguments): Reverse the list of
+ commits returned from git-rev-list since we always want to post
+ the oldest patches first to bugs.webkit.org.
+ * Scripts/modules/scm_unittest.py:
+ (run): Added return statement to return the output now that we
+ want it sometimes.
+ (SVNTestRepository._setup_test_commits): Added a fourth commit
+ so the GitTest.test_commitish_order() test has more commits to
+ work with.
+ (GitTest.test_commitish_order): Added unit test for change to
+ Git.commit_ids_from_commitish_arguments() in scm.py.
+
+2009-09-01 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/28877> Implement bugzilla-tool mark-fixed
+
+ Reviewed by David Levin.
+
+ The mark-fixed subcommand is for those times when you don't use
+ bugzilla-tool to commit a patch, but you want to use it to close
+ the bug with a committed-revision message.
+
+ * Scripts/bugzilla-tool:
+ (bug_comment_from_svn_revision): Added. Extracted from
+ bug_comment_from_commit_text().
+ (bug_comment_from_commit_text): Extracted
+ bug_comment_from_svn_revision() from this method.
+ (MarkBugFixed.__init__): Added.
+ (MarkBugFixed._fetch_commit_log): Added. Retrieves the commit
+ log from the last commit if no svn revision is specified, else
+ the commit log for the specified svn revision.
+ (MarkBugFixed._determine_bug_id_and_svn_revision): Added.
+ Attempts to determine the bug id and svn revision if one or both
+ were not defined on the command line.
+ (MarkBugFixed.execute): Added. Adds a comment about the
+ revision that fixed the bug and closes the bug.
+ (BugzillaTool.__init__): Added mark-fixed subcommand.
+ * Scripts/modules/bugzilla.py:
+ (Bugzilla.fetch_title_from_bug): Added. Returns the title of a
+ bug given a bug id.
+ * Scripts/modules/scm.py:
+ (SCM.strip_r_from_svn_revision): Added. Utility method to strip
+ the leading 'r' from an svn revision.
+ (SCM.svn_commit_log): Added. Subclasses must override.
+ (SCM.last_svn_commit_log): Added. Subclasses must override.
+ (SVN.svn_commit_log): Added. Returns svn log for a given
+ revision.
+ (SVN.last_svn_commit_log): Added. Uses svnversion to find the
+ last commit in an svn working directory and then runs svn log.
+ (Git.svn_commit_log): Added. Returns svn log for a given
+ revision.
+ (Git.last_svn_commit_log): Added. Runs git-svn-log with a limit
+ of one log message.
+
+2009-09-01 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/28880> svn-apply --force doesn't actually work
+
+ Reviewed by Brady Eidson.
+
+ * Scripts/svn-apply:
+ (applyPatch): Add "--force" to $options arrayref if $force is
+ set.
+
+2009-09-01 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/28725> resolve-ChangeLogs: determineVCSRoot() returns incorrect repository root during git filter-branch
+
+ Reviewed by Adam Roben.
+
+ When git-filter-branch has been invoked to rewrite ChangeLog
+ files on series of git commits, it changes directories into
+ .git-rewrite/t before re-running resolve-ChangeLogs. This
+ causes determineVCSRoot() in VCSUtils.pm to return
+ ".git-rewrite/t", which causes that path to be prepended to all
+ ChangeLog paths, which results in an error like this:
+
+ error: pathspec '.git-rewrite/t/ChangeLog' did not match any file(s) known to git.
+ Died at WebKitTools/Scripts/resolve-ChangeLogs line 376.
+
+ The correct way to fix this is not to try to find the repository
+ root when invoked by git-filter-branch.
+
+ * Scripts/resolve-ChangeLogs: If isInGitFilterBranch() is true,
+ set $relativePath to '.' instead of calling
+ chdirReturningRelativePath(determineVCSRoot()).
+ (isInGitFilterBranch): Added. Checks for the existence of the
+ MAPPED_PREVIOUS_COMMIT environment variable.
+
+2009-09-01 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ Add support for Fedora distros in the http tests
+ https://bugs.webkit.org/show_bug.cgi?id=28263
+
+ Add detection code for Fedora distribution, and use the proper
+ httpd conf file when needed.
+
+ * Scripts/run-webkit-httpd:
+ * Scripts/run-webkit-tests:
+ * Scripts/webkitdirs.pm:
+
+2009-09-01 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [Gtk] DRT needs implementation of overridePreference
+ https://bugs.webkit.org/show_bug.cgi?id=28830
+
+ Implement overridePreference.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+ (setDefaultsToConsistentStateValuesForTesting):
+ (runTest):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (toWebSettingKey):
+ (LayoutTestController::overridePreference):
+
+2009-09-01 Joseph Pecoraro <joepeck@webkit.org>
+
+ <http://webkit.org/b/28623> svn-[un]apply should change directories to the repository root before [un]applying
+
+ Reviewed by Eric Seidel.
+
+ Jump back and forth between the repository root directory (to apply) and the
+ directory the script was run from (to find the patch).
+
+ * Scripts/svn-apply:
+ * Scripts/svn-unapply:
+
+2009-08-31 Adam Roben <aroben@apple.com>
+
+ Fall back to a Release version of Safari if a Debug one doesn't exist
+
+ <http://webkit.org/b/28849>
+
+ Reviewed by Sam Weinig.
+
+ * Scripts/webkitdirs.pm:
+ (safariPath): If the user is working with a Debug build, but there's
+ no Debug version of Safari present, fall back to using a Release
+ version of Safari.
+
+2009-08-31 Adam Roben <aroben@apple.com>
+
+ Make safariPath() work for Debug builds of Safari on Windows
+
+ <http://webkit.org/b/28849>
+
+ Reviewed by Sam Weinig.
+
+ * Scripts/webkitdirs.pm:
+ (safariPath): If the user is working with a Debug build, add the
+ _debug suffix to Safari.exe.
+
+2009-08-28 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue needs a master process
+ https://bugs.webkit.org/show_bug.cgi?id=28040
+
+ Add a bugzilla-tool commit-queue command
+ Keeps per-bug logs, but doesn't yet upload them anywhere.
+
+ * Scripts/bugzilla-tool: Add LandPatchesFromCommitQueue to handle 'commit-queue'
+ * Scripts/modules/buildbot.py: remove noisy log message
+ * Scripts/modules/logging.py: add a 'tee()' call for splitting outputs in python
+
+2009-08-28 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Gustavo Noronha.
+
+ [GTK] Geolocation needs permission API before being enabled by default
+
+ Build the Gtk port with geolocation enabled. This option is only
+ enabled for the buildbot. The autotools option will be enabled by
+ default once the permissions API is implemented.
+
+ * Scripts/build-webkit:
+
+2009-08-26 Cameron McCormack <cam@mcc.id.au>
+
+ Reviewed by David Kilzer.
+
+ Make prepare-ChangeLog notice property changes
+ https://bugs.webkit.org/show_bug.cgi?id=28675
+
+ Make the generated ChangeLog entry include a short description of
+ property changes if there were such changes. Also make
+ prepare-ChangeLog not bail if the only changes are property changes.
+
+ * Scripts/prepare-ChangeLog:
+
+2009-08-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Oliver Hunt.
+
+ Don't let local files access web URLs
+ https://bugs.webkit.org/show_bug.cgi?id=28480
+
+ A bunch of our LayoutTests rely on our old behavior, so we explicitly
+ grant local files universal access during testing. Mainly, these tests
+ involve making XMLHttpRequests for data URLs.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2009-08-26 John Gregg <johnnyg@google.com>
+
+ Reviewed by David Levin.
+
+ Minor style correction and include fix for notifications
+ https://bugs.webkit.org/show_bug.cgi?id=28745
+
+ * DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp:
+ change to correct EnumStyle
+ (DRTDesktopNotificationPresenter::checkNotificationPermission):
+
+2009-08-26 David Levin <levin@chromium.org>
+
+ Reviewed by Alexey Proskuryakov.
+
+ XMLHttpRequest.withCredentials=false shouldn't save cookies.
+ https://bugs.webkit.org/show_bug.cgi?id=28743
+
+ Added the support to the layout test controller on OSX and
+ Windows (for CFNETWORK) to allow for changing the accept cookie
+ policy.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController): Added a bool
+ to track the state of accepting cookies.
+ (setAlwaysAcceptCookiesCallback): Standard wrapper method
+ to go from js to a C++ method.
+ (LayoutTestController::staticFunctions): Added the
+ setAlwaysAcceptCookies method to the js layoutTestController.
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::alwaysAcceptCookies): Returns the value.
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setAlwaysAcceptCookies): Stub out method.
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues): Reset the accept cookie to
+ its default.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setAlwaysAcceptCookies): Does the work for
+ OSX to change the cookie accept policy.
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (setAlwaysAcceptCookies): Method to handle all the calls necessary
+ to change the accept cookie policy on Windows.
+ (resetDefaultsToConsistentValues): Reset the accept cookie to
+ its default.
+ * DumpRenderTree/win/DumpRenderTreeWin.h:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setAlwaysAcceptCookies): Stub out method.
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setAlwaysAcceptCookies): Stub out method.
+
+2009-08-26 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Unreviewed.
+
+ Remove accidentally left in clobber option.
+ https://bugs.webkit.org/show_bug.cgi?id=28400
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: Removed clobber option.
+
+2009-08-26 Dimitri Glazkov <dglazkov@chromium.org>
+
+ Reviewed by Mark Rowe.
+
+ Add canary-style Chromium WebKit build slave to the waterfall.
+ https://bugs.webkit.org/show_bug.cgi?id=28400
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json: Added one Chromium/Windows slave
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg: Added support for Chromium slave commands.
+
+2009-08-25 Cameron McCormack <cam@mcc.id.au>
+
+ Reviewed by Darin Adler.
+
+ make-script-test-wrappers should be executable
+ https://bugs.webkit.org/show_bug.cgi?id=28669
+
+ Make make-script-test-wrappers and update-sources-list.py both be
+ executable.
+
+ * Scripts/update-sources-list.py:
+ * Scripts/make-script-test-wrappers:
+
+2009-08-25 Brent Fulgham <bfulgham@webkit.org>
+
+ Build fix
+
+ Revise Debug_Cairo targets to point inherit from the
+ debug_wincairo.vsprops property sheet so that they link
+ against the proper libraries in Debug build.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+ * WinLauncher/WinLauncher.vcproj:
+
+2009-08-25 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Roben.
+
+ PLATFORM(CFNETWORK) should be USE(CFNETWORK).
+ https://bugs.webkit.org/show_bug.cgi?id=28713
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main):
+
+2009-08-25 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Ariya Hidayat.
+
+ [Qt/Mac] Use CONFIG+=build_all only when building libraries
+
+ If no configuration is specified when building WebKit we pass the
+ debug_and_release option to QMake which results in Makefiles for
+ both configurations being generated.
+
+ Previously we built both of these configurations by default, for
+ all targets (both the QtWebKit framework/dyldlib and the various
+ executables such as QtLauncher and tests). This makes sense for
+ the libraries, which get the _debug suffix and can be loaded on
+ demand by setting the DYLD_IMAGE_SUFFIX, but for executables we
+ ended up building the same executable twice.
+
+ We now only build one instance of each executable, and since this
+ is a developer build we build the debug-version. Passing either
+ --debug or --release to build-webkit will override this, and
+ even in the default case the release version can still be built
+ by running 'make release' in the the build directory of each
+ target.
+
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+ * Scripts/webkitdirs.pm:
+
+2009-08-24 Hironori Bono <hbono@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Fix Bug 27827 "[Chromium] Functions Keys don't work in google spreadsheet".
+ <https://bugs.webkit.org/show_bug.cgi?id=27827>.
+
+ Because of the lack of mappings from GDK key-codes to WebKit key-codes,
+ Chromium cannot send valid key-codes to JavaScript when a user types
+ function keys. This change just copies the mappings from 'KeyEventGtk.cpp'.
+
+ To write layout tests for this issue, added mappings from function-key
+ names to platform-specific key-codes to EventSendingController objects
+ so that eventSender.keyDown() can send function-key events without using
+ platform-specific key codes. (Unfortunately, this eventSender.keyDown() change
+ is only for Mac. So this change adds this new test to Skipped tests for other
+ platforms to prevent this change from crashing the build trees.)
+
+ * DumpRenderTree/mac/EventSendingController.mm:
+ (-[EventSendingController keyDown:withModifiers:]):
+
+2009-08-23 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Xan Lopez.
+
+ [Gtk] API for disabling local file access to web URLs
+ https://bugs.webkit.org/show_bug.cgi?id=28663
+
+ Enable this setting for DRT.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+
+2009-08-22 Adam Barth <abarth@webkit.org>
+
+ Revert 47684. We're going to do this later once clients have had a
+ chance to opt into the setting they like.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2009-08-22 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Don't let local files access web URLs
+ https://bugs.webkit.org/show_bug.cgi?id=28480
+
+ A bunch of our LayoutTests rely on our old behavior, so we explicitly
+ grant local files universal access during testing. Mainly, these tests
+ involve making XMLHttpRequests for data URLs.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetDefaultsToConsistentValues):
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues):
+
+2009-08-22 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Anders Carlsson.
+
+ Bring signed updates to the Mac nightly builds.
+
+ * WebKitLauncher/Info.plist:
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj:
+ * WebKitLauncher/WebKitNightlyEnablerSparkle.m:
+ (initializeSparkle):
+ * WebKitLauncher/nightly.webkit.org.public.pem: Added.
+
+2009-08-21 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Rubberstamped by Simon Fraser.
+
+ Remove GNOME keyring support in build-webkit. This dependency's
+ already been removed in the Gtk port.
+
+ * Scripts/build-webkit:
+
+2009-08-20 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Adam Roben.
+ Based on original patch by Stephanie Lewis.
+
+ Added support of the Windows malloc history format to parse-malloc history, so we can
+ read and parse it.
+
+ * Scripts/parse-malloc-history:
+
+2009-08-20 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Enable various "grouping" ARIA roles
+ https://bugs.webkit.org/show_bug.cgi?id=28486
+
+ Expose the ability to retrieve the subrole through accessibility for DRT.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+
+2009-08-20 Joseph Pecoraro <joepeck@webkit.org>
+
+ Unreviewed.
+
+ Added myself as a committer.
+
+ * Scripts/modules/committers.py:
+
+2009-08-20 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ Fix memory leaks.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::whiteListAccessFromOrigin):
+ (LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+
+2009-08-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool post-diff can post partial diffs from SVN checkouts.
+ https://bugs.webkit.org/show_bug.cgi?id=28445
+
+ Pass the checkout root as the cwd. Also wrote a test to ensure this.
+
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+
+2009-08-20 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Adele Peterson.
+
+ Don't leak the JSStringRef returned by AccessibilityUIElement::attributeValue.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (attributeValueCallback):
+
+2009-08-20 Ariya Hidayat <ariya.hidayat@nokia.com>
+
+ Unreviewed, build fix.
+
+ [Qt] The template-based qMax() compares two qreals.
+
+ * DumpRenderTree/qt/ImageDiff.cpp:
+ (main):
+
+2009-08-20 David Levin <levin@chromium.org>
+
+ Reviewed by David Kilzer.
+
+ bugzilla-tool patch retrieval should handle 302 redirects.
+ https://bugs.webkit.org/show_bug.cgi?id=28485
+
+ * Scripts/modules/scm.py: Pass the --location parameter to curl
+ so that 302's are followed.
+
+2009-08-20 Aaron Boodman <aa@chromium.org>
+
+ One more speculative build for gtk.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+
+2009-08-20 Aaron Boodman <aa@chromium.org>
+
+ Speculative build for gtk.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::whiteListAccessFromOrigin):
+
+2009-08-20 Mark Rowe <mrowe@apple.com>
+
+ Ignore some leaks that are known to originate from ImageIO.
+
+ * Scripts/run-webkit-tests:
+
+2009-08-20 Aaron Boodman <aa@chromium.org>
+
+ With David Levin.
+
+ Speculative build fix for qt.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::whiteListAccessFromOrigin):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-08-19 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Fix <http://webkit.org/b/28484> Plug-in-related leaks seen on the build bot
+
+ Update check-for-global-initializers to accommodate the new uses of RefCountedLeakCounter in WebKit.
+
+ * Scripts/check-for-global-initializers:
+
+2009-08-19 Aaron Boodman <aa@chromium.org>
+
+ Reviewed by David Levin.
+
+ https://bugs.webkit.org/show_bug.cgi?id=24853: Provide a way for WebKit clients to
+ specify a more granular policy for cross-origin XHR access.
+
+ * DumpRenderTree/LayoutTestController.cpp: Expose whiteListAccessFromOrigin() to layout tests.
+ (whiteListAccessFromOriginCallback): Ditto.
+ (LayoutTestController::staticFunctions): Ditto.
+ * DumpRenderTree/LayoutTestController.h: Ditto.
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp: Ditto.
+ (LayoutTestController::whiteListAccessToOrigin): Ditto.
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm: Ditto.
+ (LayoutTestController::whiteListAccessFromOrigin): Ditto.
+ * DumpRenderTree/qt/jsobjects.cpp: Ditto.
+ (LayoutTestController::whiteListAccessFromOrigin): Ditto.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp: Stub out whiteListAccessFromOrigin().
+ (LayoutTestController::whiteListAccessFromOrigin): Ditto.
+ * DumpRenderTree/gtk/DumpRenderTree.cpp: Reset origin access lists before each test.
+ (resetWebViewToConsistentStateBeforeTesting): Ditto.
+ * DumpRenderTree/mac/DumpRenderTree.mm: Ditto.
+ (resetWebViewToConsistentStateBeforeTesting): Ditto.
+ * DumpRenderTree/qt/DumpRenderTree.cpp: Ditto.
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting): Ditto.
+
+2009-08-19 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Dan Bernstein.
+
+ Ignore some leaks that are known to originate from QTKit.
+
+ * Scripts/run-webkit-tests:
+
+2009-08-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ commit-queue/bugzilla-tool can get wedged if git is mid-rebase
+ https://bugs.webkit.org/show_bug.cgi?id=28436
+
+ Make clean_working_directory cancel rebases too (even though that's a bit of a hack).
+ This code will only ever be run when --force-clean is passed.
+
+ I also added a new unit test to make sure this code actually works. :)
+
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py:
+
+2009-08-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ WebKit needs a changelogs.py to hold changelog-related code
+ https://bugs.webkit.org/show_bug.cgi?id=28477
+
+ This is moving code and adding tests. There was only one functional
+ change (which was removing a trailing newline from the last_entry() result).
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/changelogs.py: Added.
+ * Scripts/modules/changelogs_unittest.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-08-20 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool needs a way to ask build.webkit.org if the bots are passing
+ https://bugs.webkit.org/show_bug.cgi?id=28222
+
+ Basic support for now. This has been in testing for 24 hours now and worked great!
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/buildbot.py: Added.
+ * Scripts/modules/buildbot_unittest.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-08-19 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Gustavo Noronha.
+
+ [Gtk] Bump waitToDumpWatchdog interval to 15 seconds to match the
+ default timeout used by run-webkit-tests. Mac and Win ports were
+ recently bumped in http://trac.webkit.org/changeset/r47465.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setWaitToDump):
+
+2009-08-19 David D. Kilzer <ddkilzer@webkit.org>
+
+ DumpRenderTreeSupport.pm: provide pre-generated swig source for Tiger
+
+ Reviewed by Mark Rowe.
+
+ Provide pre-generated swig source files for Tiger so it may
+ benefit from the faster run-webkit-tests.
+
+ * DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportTiger.pm:
+ Generated by swig.
+ * DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport_wrapTiger.c: Added.
+ Generated by swig.
+ (swig_type_info::SWIG_TypeNameComp):
+ (swig_type_info::SWIG_TypeEquiv):
+ (swig_type_info::SWIG_TypeRegisterTL):
+ (swig_type_info::SWIG_TypeCheck):
+ (swig_type_info::SWIG_TypeCast):
+ (swig_type_info::SWIG_TypeDynamicCast):
+ (swig_type_info::SWIG_TypeName):
+ (swig_type_info::SWIG_TypePrettyName):
+ (swig_type_info::SWIG_TypeQueryTL):
+ (swig_type_info::SWIG_TypeClientDataTL):
+ (swig_type_info::SWIG_PackData):
+ (swig_type_info::SWIG_UnpackData):
+ (swig_type_info::SWIG_PropagateClientDataTL):
+ (swig_type_info::SWIG_PackVoidPtr):
+ (swig_type_info::SWIG_UnpackVoidPtr):
+ (swig_type_info::SWIG_PackDataName):
+ (swig_type_info::SWIG_UnpackDataName):
+ * DumpRenderTree/mac/PerlSupport/Makefile: Updated to build on
+ Tiger using pre-generated files.
+
+2009-08-18 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Kilzer.
+
+ run-webkit-tests hangs when WebCore tries to log too much
+ https://bugs.webkit.org/show_bug.cgi?id=15743
+
+ Read stdout and stderr in parallel.
+
+ * Scripts/run-webkit-tests:
+
+2009-08-18 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Oliver Hunt.
+
+ Add a new build configuration that checks for leaks during the layout tests,
+ and hook a new machine up to it.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2009-08-18 Aaron Boodman <aa@chromium.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ https://bugs.webkit.org/show_bug.cgi?id=28412: Leak of WebCore::XMLHttpRequest object during layout tests.
+
+ No new tests: Already covered by existing tests.
+
+ * Scripts/check-for-global-initializers: Allow global initialization of WTF::RefCountedLeakCounter for XMLHttpRequest.
+
+2009-08-18 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Geoff Garen.
+
+ Bump waitToDumpWatchdogInterval to 15 seconds to match the time-out used by run-webkit-tests.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+
+2009-08-18 Brian Weinstein <bweinstein@apple.com>
+
+ Rubber-stamped by Adam Roben.
+
+ Changed use of CComBSTR in exceededDatabaseQuota to BSTRs, and free them,
+ and removed include to fix building on VC++ Express.
+
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::exceededDatabaseQuota):
+
+2009-08-18 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Fix of <https://bugs.webkit.org/show_bug.cgi?id=28326> DRT on Windows doesn't support
+ LayoutTestController::setQuota or print a callback on UIDelegate::exceededDatabaseQuota.
+
+ Implemenent setDatabaseQuota and added a new function to the IWebDatabaseManager interface.
+ Also added a console output on UIDelegate::exceededDatabaseQuota to match the mac.
+
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setDatabaseQuota):
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::exceededDatabaseQuota):
+
+2009-08-18 Peter Kasting <pkasting@google.com>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=28415
+ Set svn:eol-style CRLF on all .sln and .vcproj files that don't already
+ have it.
+
+ * record-memory-win/record-memory-win.vcproj:
+ * WinLauncher/WinLauncher.vcproj:
+ * WebKitLauncherWin/WebKitLauncherWin.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * FindSafari/FindSafari.vcproj:
+
+2009-08-18 Drew Wilson <atwilson@google.com>
+
+ Reviewed by Eric Seidel.
+
+ Need to extend DumpRenderTree to expose number of worker threads
+ https://bugs.webkit.org/show_bug.cgi?id=28292
+
+ Added layoutTestController.workerThreadCount, and implementations on various platforms that call into WebKit.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (getWorkerThreadCountCallback):
+ (LayoutTestController::staticValues):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::workerThreadCount):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::workerThreadCount):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::workerThreadCount):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::workerThreadCount):
+
+2009-08-18 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Jan Alonzo.
+
+ Initialize x and y in the GtkAllocation structure to shut up
+ valgrind.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (runTest):
+
+2009-08-17 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Some HTMLs are modified by make-script-test-wrappers
+ https://bugs.webkit.org/show_bug.cgi?id=28213
+
+ Add fast/js/const.js and fast/canvas/canvas-2d-imageData-create-nonfinite.js into
+ the exclude list, modified fast/dom/Geolocation/resources/TEMPLATE.html, and
+ re-generated wml/* and Geolocation/* .
+
+ * Scripts/make-script-test-wrappers:
+
+2009-08-17 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ -webkit-box-orient:horizontal doesn't work on <button> tag
+ https://bugs.webkit.org/show_bug.cgi?id=34445
+
+ Make a flexible button's anonymous child flexible and pass the
+ parent's box-orient to the anonymous child.
+
+ Also, added a renderName for anonymous flexible boxes.
+
+ * Scripts/make-script-test-wrappers:
+
+2009-08-17 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Can no longer --reset-results of a layout test directory
+ https://bugs.webkit.org/show_bug.cgi?id=28336
+
+ --reset-results and --exit-after-n-failures are incompatible.
+
+ * Scripts/run-webkit-tests:
+
+2009-08-17 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/26920> bugzilla-tool dumps too much junk the the commit comment from git
+
+ Reviewed by Adam Roben.
+
+ New commit message:
+ Committed r12345: <http://trac.webkit.org/changeset/12345>
+
+ * Scripts/bugzilla-tool:
+ (bug_comment_from_commit_text): Print out a compact,
+ standardized commit message for both git and svn.
+
+2009-08-17 Peter Kasting <pkasting@google.com>
+
+ Reviewed by Steve Falkenburg.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Only add Cygwin to the path when it isn't already there. This avoids
+ causing problems for people who purposefully have non-Cygwin versions of
+ executables like svn in front of the Cygwin ones in their paths.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+
+2009-08-17 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/28393> check-webkit-style: add check for use of std::max()/std::min() instead of MAX()/MIN()
+
+ Reviewed by David Levin.
+
+ * Scripts/modules/cpp_style.py:
+ (_ERROR_CATEGORIES): Added 'runtime/max_min_macros'.
+ (check_max_min_macros): Added. Returns level 4 error when MAX()
+ and MIN() macros are used in header files and C++ source files.
+ (check_style): Added call to check_max_min_macros().
+ * Scripts/modules/cpp_style_unittest.py: Added unit tests.
+ (test_max_macro): Added.
+ (test_min_macro): Added.
+
+2009-08-13 Mike Fenton <mike.fenton@torchmobile.com>
+
+ Reviewed by Eric Seidel.
+
+ Move adjustLineToPixelBoundaries overlapping function to GraphicsContext.cpp
+ and remove from GraphicsContextCairo.cpp and GraphicsContextQt.cpp.
+
+ https://bugs.webkit.org/show_bug.cgi?id=28268
+
+ * platform/graphics/GraphicsContext.cpp:
+ (WebCore::GraphicsContext::adjustLineToPixelBoundaries):
+ * platform/graphics/GraphicsContext.h:
+ * platform/graphics/cairo/GraphicsContextCairo.cpp:
+ * platform/graphics/qt/GraphicsContextQt.cpp:
+
+2009-08-10 Mike Fenton <mike.fenton@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Style fixes for DumpRenderTree/qt/jsobjects.cpp based on cpp_style.py and
+ WebKit style guide.
+
+ https://bugs.webkit.org/show_bug.cgi?id=28161
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (findFrameNamed):
+ (LoadItem::invoke):
+ (LayoutTestController::provisionalLoad):
+ (LayoutTestController::timerEvent):
+ (LayoutTestController::pauseAnimationAtTimeOnElementWithId):
+ (LayoutTestController::pauseTransitionAtTimeOnElementWithId):
+ (LayoutTestController::numberOfActiveAnimations):
+ (EventSender::keyDown):
+ (EventSender::frameUnderMouse):
+ (TextInputController::doCommand):
+
+2009-08-16 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/28370> check-webkit-style: add check for 'using std::foo;' statements
+
+ Reviewed by David Levin.
+
+ In <http://webkit.org/b/28355#c1>, it was noted that new source
+ files use 'using namespace std;' instead of individual
+ 'using std::foo;' statements. This adds a level 4 check for
+ such statements.
+
+ * Scripts/modules/cpp_style.py:
+ (_ERROR_CATEGORIES): Added 'build/using_std'.
+ (check_using_std): Added.
+ (check_style): Added call to check_using_std().
+ * Scripts/modules/cpp_style_unittest.py:
+ (WebKitStyleTest.test_using_std): Added unit test.
+
+2009-08-16 David Kilzer <ddkilzer@apple.com>
+
+ Backed out r47343 which was mistakenly committed
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/scm.py:
+
+2009-08-16 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/28367> bugzilla.py: replace ScriptError class with BugzillaError class
+
+ Reviewed by David Levin.
+
+ The ScriptError class doesn't exist in bugzilla.py, so any
+ errors print error messages about ScriptError instead of the
+ actual error:
+
+ NameError: global name 'ScriptError' is not defined
+
+ * Scripts/modules/bugzilla.py:
+ (BugzillaError): Added class. Modeled after ScriptError class
+ in scm.py.
+ (Bugzilla.authenticate): Changed to use BugzillaError instead of
+ ScriptError.
+ (Bugzilla._check_create_bug_response): Ditto.
+
+2009-08-14 Adam Bergkvist <adam.bergkvist@ericsson.com>
+
+ Reviewed by Sam Weinig.
+
+ Added EventSource to the build script (default on).
+ https://bugs.webkit.org/show_bug.cgi?id=14997
+
+ * Scripts/build-webkit:
+
+2009-08-15 Ryosuke Niwa <rniwa@webkit.org>
+
+ Unreviewed.
+
+ Add myself to list of committers.
+
+ * Scripts/modules/committers.py:
+
+2009-08-15 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Fix layout test failures after r47312.
+
+ Reviewed by Cameron Zwarich.
+
+ * DumpRenderTree/AccessibilityController.h:
+ Replaced logFocusEvents() with setLogFocusEvents(), which takes a
+ boolean argument to turn logging of focus events on or off.
+ Added a function to reset the AccessibilityController to a consistent
+ state.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (logFocusEventsCallback):
+ Call setLogFocusEvents() to enable logging.
+ (AccessibilityController::resetToConsistentState):
+ Call setLogFocusEvents() to disable logging.
+
+ * DumpRenderTree/gtk/AccessibilityControllerGtk.cpp:
+ (AccessibilityController::setLogFocusEvents):
+ Update stub.
+
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::setLogFocusEvents):
+ Update stub.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting):
+ Call the FrameLoadDelegate's resetToConsistentState method.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.h:
+ Declare the resetToConsistentState method.
+
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ (-[FrameLoadDelegate resetToConsistentState]):
+ Call the AccessibilityController's resetToConsistentState() function.
+
+ * DumpRenderTree/win/AccessibilityControllerWin.cpp:
+ (AccessibilityController::~AccessibilityController):
+ Turn off focus event logging when the controller is destroyed.
+ (AccessibilityController::setLogFocusEvents):
+ If the caller passes false, unhook the focus event, and clear
+ m_focusEventHook.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+ Call the FrameLoadDelegate's resetToConsistentState function.
+
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+ Declare the resetToConsistentState() function.
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ (FrameLoadDelegate::resetToConsistentState):
+ Call the AccessibilityController's resetToConsistentState() function.
+
+
+2009-08-14 Jon Honeycutt <jhoneycutt@apple.com>
+
+ Add a mechanism for logging MSAA focus events.
+
+ Part of <rdar://problem/6218721> No MSAA focus events fired for Webkit
+ nightly (20866)
+
+ https://bugs.webkit.org/show_bug.cgi?id=20866
+
+ Reviewed by Oliver Hunt.
+
+ * DumpRenderTree/AccessibilityController.cpp:
+ (logFocusEventsCallback):
+ Call the AccessibilityController's logFocusEvents() function.
+ (AccessibilityController::getJSClass):
+ Add a "logFocusEvents" function to the AccessibilityController's JS
+ class definition.
+
+ * DumpRenderTree/AccessibilityController.h:
+ On Windows, include windows.h, and add a member variable to hold the
+ handle to the event hook for focus events. Add a declaration for a
+ function that enables logging of focus events.
+
+ * DumpRenderTree/gtk/AccessibilityControllerGtk.cpp:
+ (AccessibilityController::logFocusEvents):
+ Stubbed.
+
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ (AccessibilityController::logFocusEvents):
+ Stubbed.
+
+ * DumpRenderTree/win/AccessibilityControllerWin.cpp:
+ (AccessibilityController::AccessibilityController):
+ (AccessibilityController::~AccessibilityController):
+ If we hooked the focus event, unhook it.
+ (logFocusEventProc):
+ When we receive a focus event, get the accessible object for the event,
+ and log its name to stdout.
+ (AccessibilityController::logFocusEvents):
+ Setup the focus event hook to listen for events in the current process.
+
+2009-08-14 Eric Seidel <eric@webkit.org>
+
+ No review. Fix 5-space indent to be 4-spaces.
+
+ * Scripts/bugzilla-tool:
+
+2009-08-14 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] Public API to configure the storage path for HTML5 localStorage
+ https://bugs.webkit.org/show_bug.cgi?id=28036
+
+ Turn on LocalStorage support for Qt DumpRenderTree since
+ LocalStorage is now disabled by defult for QtWebkit.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+
+2009-08-14 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Jan Alonzo.
+
+ Do not unref the main webview, it's owned by its parent
+ container. Instead destroy the container, which should take care
+ of everything (not terribly important since we exit right after
+ that, but still).
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (main):
+
+2009-08-13 Eric Seidel <eric@webkit.org>
+
+ No review, correcting obvious python error seen in the commit queue.
+
+ args can be a string or an array. Assuming args is always an array results in
+ double-spaced text in error logs.
+
+ * Scripts/bugzilla-tool:
+
+2009-08-13 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk>
+
+ Unreviewed build fix. Include stdio.h for using stdout, stderr,
+ and fprintf.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+
+2009-08-13 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Eric Seidel.
+
+ rename make-js-test-wrappers to make-script-test-wrappers
+ https://bugs.webkit.org/show_bug.cgi?id=28212
+
+ * Scripts/make-script-test-wrappers: Renamed from WebKitTools/Scripts/make-js-test-wrappers.
+
+2009-08-13 Drew Wilson <atwilson@chromium.org>
+
+ Unreviewed.
+
+ Add myself to list of committers.
+
+ * Scripts/modules/committers.py:
+
+2009-08-13 John Sullivan <sullivan@apple.com>
+
+ Unreviewed.
+
+ Add myself to list of committers.
+
+ * Scripts/modules/committers.py:
+
+2009-08-13 Eric Seidel <eric@webkit.org>
+
+ Correct spelling error in file name. No review.
+
+ * Scripts/modules/committers_unittest.py: Renamed from WebKitTools/Scripts/modules/commiters_unittest.py.
+ * Scripts/run-webkit-unittests:
+
+2009-08-13 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Simon Fraser.
+
+ REGRESSION(r47175): error running run-webkit-tests
+ https://bugs.webkit.org/show_bug.cgi?id=28261
+
+ Fix "Use of uninitialized value in concatenation (.) or string at
+ WebKitTools/Scripts/run-webkit-tests line 191." by setting
+ $testsPerDumpTool to 1000 by default.
+
+ * Scripts/run-webkit-tests:
+
+2009-08-13 Nate Chapin <japhet@chromium.org>
+
+ Unreviewed.
+
+ Add myself to list of committers.
+
+ * Scripts/modules/committers.py:
+
+2009-08-13 Brent Fulgham <bfulgham@webkit.org>
+
+ Unreviewed.
+
+ Add 'Brent Fulgham' to the committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-08-13 Adam Langley <agl@chromium.org>
+
+ Review not required.
+
+ * Scripts/modules/committers.py:
+ Adding myself to this list because Eric told me to.
+
+2009-08-13 Greg Bolsinga <bolsinga@apple.com>
+
+ Unreviewed.
+
+ Add 'Greg Bolsinga' to the committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-08-13 Adam Roben <aroben@apple.com>
+
+ Fix off-by-one result comparisons in media tests on Windows Debug
+ builds
+
+ media/video-played.html seems always to time out in Windows Debug
+ builds. A race condition between media/video-test.js's "hang" timer and
+ DumpRenderTree's built-in "watchdog" timer was causing results for
+ media/video-played.html to be printed twice, causing all future media
+ tests to be compared to the previous test's results.
+
+ The fix is to make the watchdog timer got through the same code path
+ as calling notifyDone manually, so that the results will only get
+ printed once. A subsequent patch will remove video-test.js's hang
+ timer entirely, since it is redundant.
+
+ Fixes <http://webkit.org/b/28265>.
+
+ Reviewed by Mark Rowe.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::waitToDumpWatchdogTimerFired): Added. Code came
+ from Gtk/Mac/Win's watchdog timer handlers, but we now call
+ notifyDone() instead of dump() so that a subsequent call to
+ notifyDone() won't print the results out again.
+
+ * DumpRenderTree/LayoutTestController.h: Added
+ waitToDumpWatchdogTimerFired.
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (waitToDumpWatchdogFired):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (waitUntilDoneWatchdogFired):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (waitUntilDoneWatchdogFired):
+ Changed to call waitToDumpWatchdogTimerFired.
+
+2009-08-13 Eric Carlson <eric.carlson@apple.com>
+
+ Unreviewed.
+
+ Added 'Eric Carlson' to the committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-08-13 Dirk Schulze <krit@webkit.org>
+
+ Unreviewed.
+ Added 'Dirk Schulze' to the committers list.
+
+ * Scripts/modules/committers.py:
+
+2009-08-13 Adam Roben <aroben@apple.com>
+
+ Enable running testapi in run-javascriptcore-tests on Windows
+
+ Fixes <http://webkit.org/b/24856> run-javascriptcore-tests should run
+ testapi on Windows
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/run-javascriptcore-tests: Allow testapi to run if we're in
+ the AppleWinWebKit configuration.
+
+2009-08-13 Adam Roben <aroben@apple.com>
+
+ Re-enable testapi in run-javascriptcore-tests on Mac
+
+ This seems to have been mistakenly disabled in r47089.
+
+ Rubber-stamped by Mark Rowe.
+
+ * Scripts/run-javascriptcore-tests: Removed comment markers that were
+ preventing running testapi.
+
+2009-08-12 George Staikos <george.staikos@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Enable WCSS and XHTML-MP flags for build-webkit.
+
+ * Scripts/build-webkit:
+
+2009-08-12 David Kilzer <ddkilzer@apple.com>
+
+ run-webkit-tests: document --nthly flag in help message
+
+ Reviewed by Simon Fraser.
+
+ * Scripts/run-webkit-tests: Added --nthly flag to $usage string.
+ Also noted that -1|--singly implies --nthly 1.
+
+2009-08-12 Eric Seidel <eric@webkit.org>
+
+ No review, just fixing mismerged ChangeLogs.
+
+2009-08-12 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ run-webkit-tests needs a --exit-after-failures=N option
+ https://bugs.webkit.org/show_bug.cgi?id=28192
+
+ Added the option and deployed it to bugzilla-tool.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/run-webkit-tests:
+
+2009-08-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ bugzilla-tool : various improvements for running the commit-queue
+ https://bugs.webkit.org/show_bug.cgi?id=28199
+
+ Make run_and_throw_if_fail silence STDERR as well as STDIN.
+ I also changed run_and_throw_if_fail to use the /dev/null trick instead of .communicate() to avoid ever buffering the output (per abarth's suggestion).
+ Change a few "print" statements to "log" so they appear in the output.
+ Changed all string + uses to use string formatting instead (this is less error prone as it will automatically convert non-string objects).
+ Added a little more logging so that --quiet mode is easier to understand.
+ Changed clear_attachment_review_flag to clear_attachment_flags and made it clear the commit-queue flag as well.
+ Added the ability for bugzilla-tool to reject patches from the commit-queue when they fail to compile/apply/etc.
+ Added _find_select_element_for_flag to make the code for finding flag <select> elements clearer.
+ Made curl call (downloading patch files) quieter.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/scm.py:
+
+2009-08-12 Peter Kasting <pkasting@google.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Change pattern that strips all trailing whitespace to just remove EOL
+ chars (\r, \n), to make it clear that varying EOL chars is the primary
+ problem being solved.
+
+ * Scripts/prepare-ChangeLog:
+ * Scripts/resolve-ChangeLogs:
+ * Scripts/svn-create-patch:
+ * Scripts/update-webkit:
+
+2009-08-12 Kevin Ollivier <kevino@theolliviers.com>
+
+ wx waf build fix, add new directories to the build.
+
+ * wx/build/settings.py:
+
+2009-08-11 Adam Roben <aroben@apple.com>
+
+ Update DumpRenderTree for IWebUIDelegatePrivate changes
+
+ Reviewed by Dave Hyatt.
+
+ * DumpRenderTree/win/UIDelegate.h: Updated to match
+ IWebUIDelegatePrivate.
+
+2009-08-12 Adam Roben <aroben@apple.com>
+
+ Don't try to seek to the end of stdin on Cygwin
+
+ Doing so seems to always cause an exception (for unknown reasons).
+
+ Fixes <http://webkit.org/b/28159> create-bug throws an exception in
+ Cygwin
+
+ Reviewed by Dave Kilzer.
+
+ * Scripts/bugzilla-tool:
+ (CreateBug.prompt_for_bug_title_and_comments): Ignore IOErrors
+ generated by calling sys.stdin.seek, since these seem to be generated
+ for no good reason on Cygwin.
+
+2009-08-12 Adam Roben <aroben@apple.com>
+
+ Don't raise an exception when --cc is not passed to create-bug
+
+ Fixes <http://webkit.org/b/28158> create-bug throws an exception if
+ --cc is not specified
+
+ Reviewed by Dave Kilzer.
+
+ * Scripts/modules/bugzilla.py:
+ (Bugzilla.create_bug_with_patch): Only set the "cc" field if a CC
+ string was specified. Otherwise we'll generate an exception about the
+ "cc" variable not being a string.
+
+2009-08-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool : various improvements for running the commit-queue
+ https://bugs.webkit.org/show_bug.cgi?id=28199
+
+ Make run_and_throw_if_fail silence STDERR as well as STDIN.
+ I also changed run_and_throw_if_fail to use the /dev/null trick instead of .communicate() to avoid ever buffering the out
+ Change a few "print" statements to "log" so they appear in the output.
+ Changed all string + uses to use string formatting instead (this is less error prone as it will automatically convert non
+ Added a little more logging so that --quiet mode is easier to understand.
+ Changed clear_attachment_review_flag to clear_attachment_flags and made it clear the commit-queue flag as well.
+ Added the ability for bugzilla-tool to reject patches from the commit-queue when they fail to compile/apply/etc.
+ Added _find_select_element_for_flag to make the code for finding flag <select> elements clearer.
+ Made curl call (downloading patch files) quieter.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/scm.py:
+
+2009-08-11 Eric Seidel <eric@webkit.org>
+
+ No review, script regression fix only.
+
+ run-webkit-tests --quiet hangs
+ https://bugs.webkit.org/show_bug.cgi?id=28202
+
+ Do a huge dance to get open3 to pipe to /dev/null w/o blocking.
+ This was what I came up with after discussions in #perl.
+
+ * Scripts/run-webkit-tests:
+
+2009-08-11 John Gregg <johnnyg@google.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Switch DumpRenderTree to contain a WebUIDelegate2, which extends
+ WebUIDelegate, so that the notifications tests will still work.
+ https://bugs.webkit.org/show_bug.cgi?id=28198
+
+ * DumpRenderTree/win/UIDelegate.h:
+
+2009-08-11 Darin Adler <darin@apple.com>
+
+ Try to fix GTK build.
+
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp:
+ (AccessibilityUIElement::stringForRange): Added.
+
+2009-08-10 Mike Fenton <mike.fenton@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Add processing for string constants used by the tests to trigger
+ common actions like up, down, left, right, etc. for the Qt
+ implementation of DumpRenderTree.
+
+ Note this allows fast/forms/textarea-arrow-navigation.html to pass
+ correctly.
+
+ https://bugs.webkit.org/show_bug.cgi?id=28161
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (EventSender::keyDown):
+
+2009-08-11 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 28200 - ListMarker should be included as part of the text value to parse
+ https://bugs.webkit.org/show_bug.cgi?id=28200
+
+ Add the ability to retrieve a string given a plain NSRange.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (stringForRangeCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::valueDescription):
+ (AccessibilityUIElement::stringForRange):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::stringForRange):
+
+2009-08-11 Dmitry Titov <dimich@chromium.org>
+
+ Reviewed by NOBODY (Speculative fix for the layout test failure).
+
+ Fix fast/dom/prototype-inheritance.html
+ and fast/dom/prototype-inheritance-2.html
+ broken on Windows by http://trac.webkit.org/changeset/47018
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues): enable app cache in Windows DRT.
+
+2009-08-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool: Re-factor shared landing logic into helper class to share more code
+ https://bugs.webkit.org/show_bug.cgi?id=28193
+
+ Added new WebKitLandingScripts class to hold this shared logic.
+ Also added a view_source_url function to move more webkit-specific urls out of bugzilla-tool core.
+
+ * Scripts/bugzilla-tool:
+
+2009-08-11 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Adam Treat.
+
+ Fix the current failures on the buildbot.
+
+ As Qt hooks up the maybeDump to loadFinished, we need to make
+ sure that calling dump() will not call maybeDump on loadFinished.
+
+ As dump is called my emitting done() which calls dump() and then
+ setting m_isLoading to false. So in the case m_isLoading is false,
+ do not dump again.
+
+ The current code is confusing, and should be made more clear
+ in another commit.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::maybeDump):
+ (LayoutTestController::notifyDone):
+
+2009-08-11 John Gregg <johnnyg@google.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ Add support for desktop notifications API to DumpRenderTree,
+ and support for ENABLE_NOTIFICATIONS flag to build-webkit.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (grantDesktopNotificationPermissionCallback):
+ (LayoutTestController::staticFunctions):
+ (LayoutTestController::grantDesktopNotificationPermission):
+ (LayoutTestController::checkDesktopNotificationPermission):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/win/DRTDesktopNotificationPresenter.cpp: Added.
+ (DRTDesktopNotificationPresenter::DRTDesktopNotificationPresenter):
+ (DRTDesktopNotificationPresenter::QueryInterface):
+ (DRTDesktopNotificationPresenter::AddRef):
+ (DRTDesktopNotificationPresenter::Release):
+ (DRTDesktopNotificationPresenter::showDesktopNotification):
+ (DRTDesktopNotificationPresenter::cancelDesktopNotification):
+ (DRTDesktopNotificationPresenter::notificationDestroyed):
+ (DRTDesktopNotificationPresenter::checkNotificationPermission):
+ (DRTDesktopNotificationPresenter::requestNotificationPermission):
+ * DumpRenderTree/win/DRTDesktopNotificationPresenter.h: Added.
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/UIDelegate.cpp:
+ (UIDelegate::UIDelegate):
+ (UIDelegate::desktopNotificationsDelegate):
+ * DumpRenderTree/win/UIDelegate.h:
+ * Scripts/build-webkit:
+
+2009-08-11 Peter Kasting <pkasting@google.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Handle arbitrary line endings when manufacturing patches for additions
+ with history.
+
+ * Scripts/svn-create-patch:
+
+2009-08-11 Peter Kasting <pkasting@google.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=28183
+ Support VS2008 as well as VS2005 in a few scripts.
+
+ * Scripts/pdevenv: Check both $VS80COMNTOOLS and $VS90COMNTOOLS.
+ * Scripts/webkitdirs.pm: Use $VSINSTALLDIR if available instead of hardcoding the VS2005 dir.
+
+2009-08-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ run-webkit-tests --quiet should not output build-dumprendertree output
+ https://bugs.webkit.org/show_bug.cgi?id=28189
+
+ * Scripts/run-webkit-tests:
+
+2009-08-11 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Exception in land-patches
+ https://bugs.webkit.org/show_bug.cgi?id=27962
+
+ Use ("%s" % object) instead of ("" + object).
+ Added unit tests for logging.py.
+
+ * Scripts/modules/logging.py:
+ * Scripts/modules/logging_unittest.py: Added.
+ * Scripts/run-webkit-unittests:
+
+2009-08-11 Dmitry Titov <dimich@chromium.org>
+
+ Reviewed by NOBODY (Windows layout tests fix).
+
+ Fix for layout tests failures. Need to initialize some preferences early
+ because WebView on Windows uses them during create time.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main):
+
+2009-08-11 Dmitry Titov <dimich@chromium.org>
+
+ Reviewed by Adam Roben.
+
+ Originally implemented by Glenn Wilson <gwilson@chromium.org>.
+
+ Added support for overriding default preferences per-test.
+ See https://bugs.webkit.org/show_bug.cgi?id=20534
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (overridePreferenceCallback): add wiring for layoutTestController.overridePreference.
+ (LayoutTestController::staticFunctions): same.
+ * DumpRenderTree/LayoutTestController.h: same.
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::overridePreference): added empty overridePreference method.
+ * DumpRenderTree/mac/DumpRenderTree.mm: implemented preference override.
+ (resetDefaultsToConsistentValues): new method, resets preferences to same set of value before every test.
+ (setDefaultsToConsistentValuesForTesting): new method, sets other details of testing environment, every time DRT starts.
+ (resetWebViewToConsistentStateBeforeTesting): move some preference setting from here to new resetDefaultsToConsistentValues().
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::overridePreference):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetDefaultsToConsistentValues): new method, resets preferences to same set of value before every test.
+ (resetWebViewToConsistentStateBeforeTesting): move some preference setting from here to new resetDefaultsToConsistentValues().
+ (createWebViewAndOffscreenWindow): same.
+ (main): same.
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::overridePreference):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::overridePreference):
+
+2009-08-11 Brian Weinstein <bweinstein@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Added support for DRT to support arguments for eventSender.mouseDown and eventSender.mouseUp for Windows.
+ https://bugs.webkit.org/show_bug.cgi?id=28166.
+
+ This is a step towards fixing fast/events/mouse-click-events.html on Windows.
+
+ * DumpRenderTree/win/EventSender.cpp:
+ (mouseDownCallback):
+ (mouseUpCallback):
+ (replaySavedEvents):
+
+2009-08-11 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Build the TestNetscapePlugin on Qt/Mac
+
+ * DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro:
+
+2009-08-11 Dmitry Titov <dimich@chromium.org>
+
+ Reviewed by NOBODY (build fix).
+
+ Attempt to fix the Windows test bot. Reverted r47015 caused one of the Windows
+ bots that runs Layout Tests to save "JS disabled" and "default font 24pt"
+ preferences permanently. Since these preferences are not initialized explicitly in DRT,
+ almost all Layout tests are failing. Attempt to fix by explicit
+ initialization of these into defaults (enabled, 16pt) at the beginning of the DRT.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main): see above.
+
+2009-08-10 Steve Falkenburg <sfalken@apple.com>
+
+ Windows nightly fix.
+
+ Reviewed by Ada Chan.
+
+ * FindSafari/FindSafari.cpp:
+ (_tmain): Copy Safari.dll if it exists.
+
+2009-08-10 David Levin <levin@chromium.org>
+
+ Reviewed by David Kilzer.
+
+ check-webkit-style doesn't catch braces around single line statements when followed by else.
+ https://bugs.webkit.org/show_bug.cgi?id=28164
+
+ * Scripts/modules/cpp_style.py: Added else to the regex that finds ending }'s when
+ checking the no braces for "single lines" rule.
+ * Scripts/modules/cpp_style_unittest.py: Added test case.
+
+2009-08-10 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/28163> bugzilla-tool: scm module should not import bugzilla module
+
+ Reviewed by David Levin.
+
+ * Scripts/bugzilla-tool:
+ (parse_bug_id): Added. Moved from CommitMessage.parse_bug_id()
+ in scm module.
+ * Scripts/modules/scm.py: Removed import of bugzilla module.
+ (CommitMessage.parse_bug_id): Deleted.
+
+2009-08-10 Peter Kasting <pkasting@google.com>
+
+ Reviewed by David Kilzer.
+
+ https://bugs.webkit.org/show_bug.cgi?id=18599
+ Work around apparent bug in abs2rel() with symlinked directories.
+
+ * Scripts/resolve-ChangeLogs:
+
+2009-08-10 Dan Bernstein <mitz@apple.com>
+
+ Build fix
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+
+2009-08-10 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Fix a bunch of build warnings in TestNetscapePlugin
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/TestObject.cpp:
+ * DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp:
+
+2009-08-10 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Adam Roben.
+
+ Allow TestNetscapePlugIn to fall back to the Carbon event model
+
+ Previously the plugin would fail, even though the Carbon event
+ model was available. The only way to get the Carbon event model
+ was to pass the "forcecarbon" argument in the test markup, but no
+ tests were using this.
+
+ Now the plugin uses carbon either if it's forced, or if the Cocoa
+ event model is not supported.
+
+ This helps us run most of the plugin tests on Qt/Mac, which still
+ does not support the Cocoa event model.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+
+2009-08-08 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ bugzilla-tool needs a --quiet option
+ https://bugs.webkit.org/show_bug.cgi?id=28060
+
+ A first pass at a --quiet option. This doesn't do all the excting
+ things we might want, but it addresses 80% of the use case.
+
+ * Scripts/bugzilla-tool:
+
+2009-08-08 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Xan Lopez.
+
+ [Gtk] Enable accessibility in Gtk DRT
+ https://bugs.webkit.org/show_bug.cgi?id=25989
+
+ Add Accessibility support to the GTK DRT.
+
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/gtk/AccessibilityControllerGtk.cpp: Added.
+ (AccessibilityController::AccessibilityController):
+ (AccessibilityController::~AccessibilityController):
+ (AccessibilityController::focusedElement):
+ (AccessibilityController::rootElement):
+ * DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp: Added.
+ (AccessibilityUIElement::AccessibilityUIElement):
+ (AccessibilityUIElement::~AccessibilityUIElement):
+ (AccessibilityUIElement::getLinkedUIElements):
+ (AccessibilityUIElement::getDocumentLinks):
+ (AccessibilityUIElement::getChildren):
+ (AccessibilityUIElement::getChildrenWithRange):
+ (AccessibilityUIElement::childrenCount):
+ (AccessibilityUIElement::elementAtPoint):
+ (AccessibilityUIElement::getChildAtIndex):
+ (AccessibilityUIElement::allAttributes):
+ (AccessibilityUIElement::attributesOfLinkedUIElements):
+ (AccessibilityUIElement::attributesOfDocumentLinks):
+ (AccessibilityUIElement::titleUIElement):
+ (AccessibilityUIElement::parentElement):
+ (AccessibilityUIElement::attributesOfChildren):
+ (AccessibilityUIElement::parameterizedAttributeNames):
+ (AccessibilityUIElement::role):
+ (AccessibilityUIElement::title):
+ (AccessibilityUIElement::description):
+ (AccessibilityUIElement::language):
+ (AccessibilityUIElement::x):
+ (AccessibilityUIElement::y):
+ (AccessibilityUIElement::width):
+ (AccessibilityUIElement::height):
+ (AccessibilityUIElement::clickPointX):
+ (AccessibilityUIElement::clickPointY):
+ (AccessibilityUIElement::intValue):
+ (AccessibilityUIElement::minValue):
+ (AccessibilityUIElement::maxValue):
+ (AccessibilityUIElement::valueDescription):
+ (AccessibilityUIElement::isEnabled):
+ (AccessibilityUIElement::insertionPointLineNumber):
+ (AccessibilityUIElement::isActionSupported):
+ (AccessibilityUIElement::isRequired):
+ (AccessibilityUIElement::attributesOfColumnHeaders):
+ (AccessibilityUIElement::attributesOfRowHeaders):
+ (AccessibilityUIElement::attributesOfColumns):
+ (AccessibilityUIElement::attributesOfRows):
+ (AccessibilityUIElement::attributesOfVisibleCells):
+ (AccessibilityUIElement::attributesOfHeader):
+ (AccessibilityUIElement::indexInTable):
+ (AccessibilityUIElement::rowIndexRange):
+ (AccessibilityUIElement::columnIndexRange):
+ (AccessibilityUIElement::lineForIndex):
+ (AccessibilityUIElement::boundsForRange):
+ (AccessibilityUIElement::cellForColumnAndRow):
+ (AccessibilityUIElement::selectedTextRange):
+ (AccessibilityUIElement::setSelectedTextRange):
+ (AccessibilityUIElement::attributeValue):
+ (AccessibilityUIElement::isAttributeSettable):
+ (AccessibilityUIElement::increment):
+ (AccessibilityUIElement::decrement):
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewWindowObjectCleared):
+ (main):
+ * GNUmakefile.am:
+
+2009-08-07 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Unreviewed Gtk build fix.
+
+ DRT needs internal WTF symbols so we link to libJavaScriptCore.la
+ too. Also don't force Gtk to use USE_SYSTEM_MALLOC.
+
+ * GNUmakefile.am:
+
+2009-08-07 Darin Adler <darin@apple.com>
+
+ * Scripts/commit-log-editor: Fix unchecked access to environment
+ variable that may not be there.
+
+2009-08-07 Mark Rowe <mrowe@apple.com>
+
+ Handle the case where only a single test is missing results.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2009-08-07 George Wright <george.wright@torchmobile.com>
+
+ Reviewed by Adam Treat
+
+ Fix DumpRenderTree for the Qt port to always dump the PNG data unless
+ the expected and actual hashes match.
+
+ https://bugs.webkit.org/show_bug.cgi?id=28077
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::dump):
+
+2009-08-07 Pierre d'Herbemont <pdherbemont@apple.com>
+
+ Reviewed by Eric Seidel.
+
+ commit-log-editor does not produce a git commit log that is git friendly.
+ https://bugs.webkit.org/show_bug.cgi?id=27754
+
+ We make sure we end up with:
+ - A first paragraph describing the bug. It is eventually prefixed by
+ "WebKit: <line>" or "WebCore: <line>". This used to be
+ "WebCore:\n\n<line>".
+ - The Reviewed By line.
+ - An eventual Patch By line if author and committer doesn't match.
+ - The rest of the commit.
+
+ * Scripts/commit-log-editor:
+
+2009-08-07 Adam Barth <abarth@webkit.org>
+
+ Unreviewed. (Darin Adler indicated he'd prefer if we landed these
+ kinds of changes unreviewed, like editing the WebKit Team wiki page.)
+
+ Added Pierre d'Herbemont to list of committers.
+
+ * Scripts/modules/committers.py:
+
+2009-08-07 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Adele Peterson.
+
+ Cannot scroll for box-reflect:right
+ https://bugs.webkit.org/show_bug.cgi?id=27979
+
+ Update m_overflowLeft an m_overflowWidth for reflection just like
+ m_overflowTop and m_overflowHeight.
+
+ * Scripts/make-js-test-wrappers: Added regexp to skip box-shadow-overflo
+w-scroll.js
+
+2009-08-06 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ box-shadow's spread is ignored with <table>
+ https://bugs.webkit.org/show_bug.cgi?id=28017
+
+ Use RenderStyle::getBoxShadowExtent just like RenderBlock.
+
+ * Scripts/make-js-test-wrappers: Added regexp to skip box-shadow-overflow-scroll.js
+
+2009-08-06 Eric Seidel <eric@webkit.org>
+
+ No review, only changing make-js-test-wrappers.
+
+ Fix make-js-test-wrappers to ignore a few more js tests
+ with custom templates.
+
+ * Scripts/make-js-test-wrappers:
+
+2009-08-06 Chris Marrin <cmarrin@apple.com>
+
+ Reviewed by David Hyatt.
+
+ Added ENABLE_3D_CANVAS flag to build, default to off
+
+ * Scripts/build-webkit:
+
+2009-08-05 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Win DRT's resource load delegate is missing didReceiveResponse
+ https://bugs.webkit.org/show_bug.cgi?id=28033
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ Added:
+ (FrameLoadDelegate::didReceiveServerRedirectForProvisionalLoadForFrame):
+ (FrameLoadDelegate::willPerformClientRedirectToURL):
+ (FrameLoadDelegate::didCancelClientRedirectForFrame):
+
+ Minor style cleanup:
+ (FrameLoadDelegate::didStartProvisionalLoadForFrame):
+ (FrameLoadDelegate::didReceiveTitle):
+ (FrameLoadDelegate::didFinishLoadForFrame):
+ (FrameLoadDelegate::willCloseFrame):
+ (FrameLoadDelegate::didClearWindowObject):
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+
+2009-08-05 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Win DRT's resource load delegate is missing didReceiveResponse
+ https://bugs.webkit.org/show_bug.cgi?id=28033
+
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::didReceiveResponse):
+ * DumpRenderTree/win/ResourceLoadDelegate.h:
+
+2009-08-05 Darin Fisher <darin@chromium.org>
+
+ Reviewed by Darin Adler.
+
+ Add layoutTestController.dumpWillCacheResponse
+ https://bugs.webkit.org/show_bug.cgi?id=28010
+
+ willCacheResponse is only interesting for embedders of mainline WebKit on Mac.
+ Splitting off a new dumpWillCacheResponse allows a number of existings tests
+ to run across platforms.
+
+ The test that was specifically verifying willCacheResponse now calls
+ dumpWillCacheResponse.
+
+ * DumpRenderTree/LayoutTestController.cpp: Add dumpWillCacheResponse
+ (LayoutTestController::LayoutTestController):
+ (dumpWillCacheResponseCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::dumpWillCacheResponse):
+ (LayoutTestController::setDumpWillCacheResponse):
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm: Inspect dumpWillCacheResponse
+ instead of dumpResourceLoadCallbacks.
+ (-[ResourceLoadDelegate webView:resource:willCacheResponse:fromDataSource:]):
+
+2009-08-05 Jeremy Orlow <jorlow@chromium.org>
+
+ Reviewed by Adam Barth.
+
+ Add my name to committers.py
+ https://bugs.webkit.org/show_bug.cgi?id=28013
+
+ Add my name to committers.py.
+
+ * Scripts/modules/committers.py:
+
+2009-08-05 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ A minor refactoring of the Qt DRT to be a bit more similar to
+ the other DRTs, as well as more understandable.
+
+ Splitting up resetJSObjects into a LayoutTestController->reset()
+ plus a new closeRemainingWindows() method.
+
+ Added a resetToConsistentStateBeforeTesting() method to keep
+ the code in one place, making it easier to verify that we are
+ doing things properly.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::resetToConsistentStateBeforeTesting):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::closeRemainingWindows):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+
+2009-08-05 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Make the Qt DRT WorkQueue work similarily to the cross platform
+ one. This means that all items return true if they started
+ loading.
+
+ This change paves the way for unforking the WorkQueue, if we [Qt]
+ would like that.
+
+ * DumpRenderTree/qt/WorkQueue.cpp:
+ (WorkQueue::processWork):
+ * DumpRenderTree/qt/WorkQueue.h:
+ * DumpRenderTree/qt/WorkQueueItem.h:
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LoadItem::invoke):
+ (ReloadItem::invoke):
+ (ScriptItem::invoke):
+ (BackForwardItem::invoke):
+ (LayoutTestController::processWork):
+ (LayoutTestController::maybeDump):
+
+2009-08-04 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ If load of a test fails, don't dump as it will be dumped
+ in the preceding test, resulting in a invalid incorrect layout.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::maybeDump):
+
+2009-08-04 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Make the Qt DumpRenderTree more similar to the mac one.
+
+ Changes include:
+ 1) Reset zoom factor before each test
+ 2) Only dump the backforward list when we got other dump result
+ 3) When we dump the render tree, and got zero result print out:
+ [mainFrame renderTreeAsExternalRepresentation]
+ and not:
+ [frame renderTreeAsExternalRepresentation]
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::open):
+ (WebCore::methodNameStringForFailedTest):
+ (WebCore::DumpRenderTree::dump):
+
+2009-08-05 chris fleizach <cfleizach@apple.com>
+
+ Fix Tiger build breakage.
+
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+
+2009-08-04 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 27994 - WAI-ARIA: aria-valuetext needs to be implemented
+ https://bugs.webkit.org/show_bug.cgi?id=27994
+
+ Expose valueDescription for accessibility.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getValueDescriptionCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::valueDescription):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::valueDescription):
+
+2009-08-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ REGRESSION: run-webkit-tests crashes if you have non-system perl in PATH
+ https://bugs.webkit.org/show_bug.cgi?id=28006
+
+ Hard-code perl to /usr/bin/perl and swig to /usr/bin/swig
+
+ * DumpRenderTree/mac/PerlSupport/Makefile:
+
+2009-08-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ Add pkasting to bugzilla-tool as a committer
+ https://bugs.webkit.org/show_bug.cgi?id=28002
+
+ * Scripts/modules/committers.py:
+
+2009-08-04 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Bug 27993 - AXSliders are missing required attributes and actions
+ https://bugs.webkit.org/show_bug.cgi?id=27993
+
+ Add ability to check if any arbitrary action is supported.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (isActionSupportedCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::isActionSupported):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::isActionSupported):
+
+2009-08-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ bugzilla-tool unit tests need a test harness
+ https://bugs.webkit.org/show_bug.cgi?id=27977
+
+ * Scripts/run-webkit-unittests: Added.
+
+2009-08-04 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Gavin "Gavvy" Barraclough.
+
+ Ensure that DumpRenderTreeSupport is regenerated when switching between OS versions
+ by listing the DumpRenderTree binary as a dependency. Xcode has the smarts to rebuild
+ DumpRenderTree itself when switching OS versions so this dependency removes the need
+ for any smarts in the Makefile.
+
+ * DumpRenderTree/mac/PerlSupport/Makefile:
+
+2009-08-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool needs unit tests
+ https://bugs.webkit.org/show_bug.cgi?id=26916
+
+ Add some basic unit testing for scm.py.
+
+ * Scripts/modules/scm.py:
+ * Scripts/modules/scm_unittest.py: Added.
+
+2009-08-04 Mike Fenton <mike.fenton@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Fix --skipped=only mode to honor flags such as --no-http and platform ignored directories by checking
+ to make sure the Skipped entries are not in the $ignoredDirectories array. Directories commonly included
+ are (http, media, compositing, wml, wcss).
+
+ https://bugs.webkit.org/show_bug.cgi?id=27893
+
+ * Scripts/run-webkit-tests:
+
+2009-08-03 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Jon Honeycutt.
+
+ Bug 27958 - WAI-ARIA: Implement 'aria-required' attribute.
+ https://bugs.webkit.org/show_bug.cgi?id=27958
+
+ Exposed isRequired to DumpRenderTree for accessibility.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getIsRequiredCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::isRequired):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::isRequired):
+
+2009-08-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ bugzilla-tool --commit-queue should validate commit-queue setter is a committer
+ https://bugs.webkit.org/show_bug.cgi?id=27974
+
+ With a test!
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/bugzilla_unittest.py:
+
+2009-08-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ REGRESSION(r46700): bugzilla-tool land-diff double-spaces ChangeLogs
+ https://bugs.webkit.org/show_bug.cgi?id=27973
+
+ The trailing comma (suppresses newlines) was lost in r46700.
+
+ * Scripts/bugzilla-tool:
+
+2009-08-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ bugzilla-tool has too many fatal errors
+ https://bugs.webkit.org/show_bug.cgi?id=27969
+
+ Replace several fatal errors with ScriptError exceptions.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/scm.py:
+
+2009-08-04 Eric Seidel <eric@webkit.org>
+
+ No review, ChangeLog fix only.
+
+ Fix a ChangeLog line-spacing disaster caused by:
+ https://bugs.webkit.org/show_bug.cgi?id=27973
+
+ Still unsure what the fix for bugzilla-tool will be.
+
+2009-08-04 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ bugzilla-tool --commit-queue should only land commit-queue+ patches
+ https://bugs.webkit.org/show_bug.cgi?id=27970
+
+ commit-queue mode for bugzilla-tool
+ https://bugs.webkit.org/show_bug.cgi?id=27918
+
+ Make bugzilla tool smart enough to find the commit-queue+ flags and
+ land those patches.
+ When we call land-patches with --commit-queue, we should filter the
+ patches we land to only those that have the commit-queue+ flag set.
+ That way, when we call bugzilla-tool from a main commit queue process,
+ we won't land the wrong patches.
+
+ * Scripts/bugzilla-tool:
+
+2009-08-04 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ committer logic should be split out of bugzilla.py into its own module
+
+ https://bugs.webkit.org/show_bug.cgi?id=27972
+
+ I also added unit tests for the functionality I added.
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/bugzilla_unittest.py: Added.
+ * Scripts/modules/commiters_unittest.py: Added.
+ * Scripts/modules/committers.py: Added.
+
+2009-08-03 Peter Kasting <pkasting@google.com>
+
+ Reviewed by David Kilzer.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Handle any kind of line endings in svn-apply and svn-unapply, instead
+ of assuming LF.
+
+ * Scripts/svn-apply:
+ * Scripts/svn-unapply:
+
+2009-08-03 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ bugzilla-tool land-patches needs --queue mode
+ https://bugs.webkit.org/show_bug.cgi?id=27961
+
+ Add a --commit-queue command line option to suppress user interaction.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/scm.py:
+
+2009-08-03 Mark Rowe <mrowe@apple.com>
+
+ Build fix. Add installsrc, installhdrs and install targets.
+
+ * DumpRenderTree/mac/PerlSupport/Makefile:
+
+2009-08-03 Eric Carlson <eric.carlson@apple.com>
+
+ Reviewed by Eric Seidel.
+
+ HTMLInputElement is not controllable by assistive technologies
+ https://bugs.webkit.org/show_bug.cgi?id=27941
+
+ Accessibility control of a slider required adding increment() and decrement()
+ methods to AccessibilityObject, so expose thos methods on AccessibilityUIElement.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (incrementCallback): New, call UI element increment method.
+ (decrementCallback): New, call UI element decrement method.
+ (AccessibilityUIElement::getJSClass): Expose increment and decrement methods.
+
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::increment): New, send NSAccessibilityIncrementAction to Mac wrapper.
+ (AccessibilityUIElement::decrement): New, send NSAccessibilityDecrementAction to Mac wrapper.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::increment): New, do nothing.
+ (AccessibilityUIElement::decrement): New, do nothing.
+
+2009-08-02 David D. Kilzer <ddkilzer@webkit.org>
+
+ <http://webkit.org/b/27930> bugzilla-tool hates Tor Arne Vestbø
+
+ Reviewed by Tor Arne Vestbø.
+
+ * Scripts/bugzilla-tool:
+ (set_reviewer_in_changelog): Made sure reviewer is properly
+ encoded when calling replace().
+
+2009-08-02 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by David Levin.
+
+ Script for building the wxBrowser sample app for wx.
+ https://bugs.webkit.org/show_bug.cgi?id=27619
+
+ * wx/browser/wscript: Added.
+
+2009-08-02 Kevin Ollivier <kevino@theolliviers.com>
+
+ Reviewed by Jan Alonzo.
+
+ Scripts needed for the waf build.
+ https://bugs.webkit.org/show_bug.cgi?id=27619
+
+ * wx/build: Added.
+ * wx/build/build_utils.py: Added.
+ * wx/build/settings.py: Added.
+ * wx/build/waf_extensions.py: Added.
+ * wx/build/wxpresets.py: Added.
+
+2009-08-01 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Make pixel test results more consistent across Mac OS X versions
+
+ * DumpRenderTree/cg/ImageDiffCG.cpp:
+ (createDifferenceImage): Avoid color correction when rendering the
+ images into graphics contexts, so that the actual color values are
+ compared, regardless of how the images are tagged.
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (createWebViewAndOffscreenWindow): Set the window’s color space to the
+ main screen’s color space, even though the window is off-screen.
+
+2009-08-01 Mark Rowe <mrowe@apple.com>
+
+ Try again to make the Qt build bot happy.
+
+ * BuildSlaveSupport/test-result-archive: Create a placeholder file inside the newly-created
+ directory to prevent 'zip' from failing due to the directory containing no files.
+
+2009-08-01 Mark Rowe <mrowe@apple.com>
+
+ Try and make the Qt build bot happy.
+
+ * BuildSlaveSupport/test-result-archive: Handle the case where run-webkit-tests generates
+ no output files at all and thus does not create the layout-test-results directory.
+
+2009-08-01 Mark Rowe <mrowe@apple.com>
+
+ Move the include of DumpRenderTreeSupport to after DumpRenderTree has been built.
+
+ * Scripts/run-webkit-tests:
+
+2009-08-01 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig and David D. Kilzer.
+
+ Fix <https://bugs.webkit.org/show_bug.cgi?id=27923>.
+ Bug 27923: run-webkit-tests should not invoke "ps" repeatedly on Mac OS X
+
+ run-webkit-tests invokes "ps" after each test on Mac OS X to determine whether DumpRenderTree is
+ in the process of crashing. We can do the same test more efficiently with a simple call to sysctl.
+ I couldn't find any built-in way of doing this directly from perl, so we do it from a simple C module
+ instead. This speeds up run-webkit-tests by around 8%.
+
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupport.c: Added.
+ (processIsCrashing):
+ * DumpRenderTree/mac/PerlSupport/DumpRenderTreeSupportTiger.pm: Added. Tiger does not have the SWIG tool
+ that is used to generate the Perl binding to the C code, so we fall back to the old implementation on Tiger.
+ * DumpRenderTree/mac/PerlSupport/Makefile: Added.
+ * Scripts/run-webkit-tests:
+
+2009-08-01 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by David D. Kilzer.
+
+ Display the reminder once rather than once per ChangeLog.
+
+ * Scripts/prepare-ChangeLog:
+
+2009-08-01 David Kilzer <ddkilzer@apple.com>
+
+ resolve-ChangeLogs: add error checking to git ls-files command on close()
+
+ Reviewed by Eric Seidel.
+
+ Item 2 of <https://bugs.webkit.org/show_bug.cgi?id=18599#c0>.
+
+ * Scripts/resolve-ChangeLogs: Added error checking to close()
+ after running git ls-files. Added error checking to all
+ system() calls by checking for a non-zero WEXITSTATUS($?).
+ Changed "|| die;" expressions to "or die $!;".
+
+2009-08-01 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/18599> resolve-ChangeLogs doesn't work with relative paths
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/resolve-ChangeLogs: Used chdirReturningRelativePath()
+ and determineVCSRoot() to change directories to the root of the
+ project before running the command and to provide a path for
+ removeChangeLogArguments() to make sure any ChangeLog arguments
+ on the command line are still found.
+ (canonicalRelativePath): Added. Returns a canonical path (e.g.,
+ stripping 'dir/../' from the path) relative to the current
+ directory.
+ (removeChangeLogArguments): Added argument which contains a
+ relative path that must be prepended to any ChangeLog arguments.
+ Used canonicalRelativePath() and File::Spec->catfile() to
+ construct a normalized, relative path to each file.
+
+2009-08-01 David Kilzer <ddkilzer@apple.com>
+
+ Implement VCSUtils::chdirReturningRelativePath()
+
+ Reviewed by Eric Seidel.
+
+ Step 2 to fix:
+ <http://webkit.org/b/18599> resolve-ChangeLogs doesn't work with relative paths
+
+ * Scripts/VCSUtils.pm:
+ (VCSUtils::chdirReturningRelativePath): Moved here from
+ chdirAndGetDifference() in svn-create-patch.
+ * Scripts/svn-create-patch: Switched to use
+ chdirReturningRelativePath() instead of chdirAndGetDifference().
+ (chdirAndGetDifference): Removed.
+
+2009-08-01 David Kilzer <ddkilzer@apple.com>
+
+ Implement VCSUtils::determineVCSRoot()
+
+ Reviewed by Eric Seidel.
+
+ Step 1 to fix:
+ <http://webkit.org/b/18599> resolve-ChangeLogs doesn't work with relative paths
+
+ * Scripts/VCSUtils.pm: Removed reference to webkitdirs module.
+ (VCSUtils::EXPORT): Added &determineVCSRoot. Realphabetized.
+ (VCSUtils::determineGitRoot): Added. Based on code in
+ commit-log-editor.
+ (VCSUtils::determineVCSRoot): Implemented using
+ determineGitRoot() and determineSVNRoot().
+ * Scripts/commit-log-editor: Replaced use of
+ topLevelSourceDirectory() with determineVCSRoot(). Resorted
+ use statements.
+ (topLevelSourceDirectory): Removed.
+
+2009-07-31 Daniel Bates <dbates@intudata.com>
+
+ Reviewed by Eric Seidel.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27757
+
+ Resolves Perl redefinition warnings about functions tmpfile and tmpnam which are
+ defined in both File::Temp and POSIX.
+
+ This stops the warnings by preventing the "import" method of File::Temp from being called,
+ which would otherwise add these functions into the primary namespace. Note, "use POSIX"
+ will import these functions into the primary namespace anyway. We only need one instance
+ of these functions in our namespace (or we get redefinition warnings), so lets use the
+ one's in the POSIX package.
+
+ * Scripts/update-webkit-auxiliary-libs: Changed "use File::Temp" to "use File::Temp ()".
+ * Scripts/update-webkit-support-libs: ditto
+
+2009-07-31 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ Add a top level build option to control datagrid support
+ https://bugs.webkit.org/show_bug.cgi?id=27915
+
+ * Scripts/build-webkit:
+
+2009-07-31 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Treat.
+
+ check-webkit-style --git-commit has bugs if you select a commit in the past
+ https://bugs.webkit.org/show_bug.cgi?id=27908
+
+ * Scripts/check-webkit-style:
+ (main): Made the git-commit command only select the first commit
+ if a range is given (and print a warning).
+ * Scripts/modules/scm.py:
+ (SCM::create_patch_from_local_commit):
+ (SCM::create_patch_since_local_commit):
+ (SCM::commit_locally_with_message):
+ (SCM::discard_local_commits):
+ Added an error messages in case these aren't overriden.
+
+ (Git::create_patch_since_local_commit):
+ Added this command to allow doing a diff of everything after a given commit.
+
+2009-07-31 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Speculative Qt build fix. Not reviewed.
+
+ Add LayoutTestController::disableImageLoading() in jsobjects.h.
+
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-07-31 Brady Eidson <beidson@apple.com>
+
+ Reviewed by John Sullivan.
+
+ <rdar://problem/6973106> and https://bugs.webkit.org/show_bug.cgi?id=27896
+ Favicons are still loaded when automatic image loading is disabled.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (disableImageLoadingCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::disableImageLoading):
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::disableImageLoading):
+
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::disableImageLoading): Stubbed for now.
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::disableImageLoading): Ditto.
+
+2009-07-30 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ bugzilla-tool post-commits trunk..head errors out
+ https://bugs.webkit.org/show_bug.cgi?id=27847
+
+ Rename commit_ids_from_range_arguments to commit_ids_from_commitish_arguments
+ and make it handle the new arguments format proposed in the bug.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/scm.py:
+
+2009-07-30 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ clean up build-webkit to use less copy/paste code and remove unneeded SVG warning
+ https://bugs.webkit.org/show_bug.cgi?id=27857
+
+ * Scripts/build-webkit:
+
+2009-07-31 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/27894> bugzilla-tool: Bugzilla.clear_attachment_review_flag() fails with ClientForm-0.2.10 and python-2.5
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/modules/bugzilla.py:
+ (Bugzilla.clear_attachment_review_flag): Specify which 'comment'
+ form field to use when setting its value.
+
+2009-07-31 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Kilzer.
+
+ bugzilla-tool post-commits obsoletes its own work :(
+ https://bugs.webkit.org/show_bug.cgi?id=27849
+
+ Simple fix. Use .add() instead of .update()
+
+ * Scripts/bugzilla-tool:
+
+2009-07-31 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Anders Carlsson.
+
+ Improve platform-detection in run-webkit-tests
+
+ This prevents miss-detection of mac-* over Qt/Mac.
+
+ * Scripts/run-webkit-tests:
+
+2009-07-30 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Cameron Zwarich.
+
+ Teach buildbot to detect test cases that are missing results.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+
+2009-07-30 Mark Rowe <mrowe@apple.com>
+
+ Things work better when you create the correct directories.
+
+ * Scripts/run-webkit-tests:
+
+2009-07-30 Mark Rowe <mrowe@apple.com>
+
+ Include some information about the error when we die.
+
+ * Scripts/run-webkit-tests:
+
+2009-07-30 Mark Rowe <mrowe@apple.com>
+
+ Ensure that the path exists before writing results to it.
+ Hopefully this will make the Windows build bot happy.
+
+ * Scripts/run-webkit-tests:
+
+2009-07-30 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Adam Treat and Jon Honeycutt.
+
+ Teach run-webkit-tests to always store the actual results in the results directory for new tests.
+ This allows us to give a working link to the results from the result summary page, even if we're
+ not generating new results in to the tree.
+
+ * Scripts/run-webkit-tests:
+
+2009-07-30 Mark Rowe <mrowe@apple.com>
+
+ Add a Qt Linux build bot.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2009-07-30 Jakob Petsovits <jakob.petsovits@torchmobile.com>
+
+ Reviewed by Adam Roben.
+
+ Add --minimal option to webkit-build.
+ https://bugs.webkit.org/show_bug.cgi?id=27852
+
+ This option disables all optional build features unless
+ they are explicitly enabled.
+
+ * Scripts/build-webkit:
+
+2009-07-30 Jakub Wieczorek <faw217@gmail.com>
+
+ [Qt] Fix build with GCC 4.4.
+
+ * DumpRenderTree/qt/ImageDiff.cpp:
+
+2009-07-29 Ariya Hidayat <ariya.hidayat@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27813
+
+ [Qt] Support pixel tests in DumpRenderTree for the Qt port.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::open):
+ (WebCore::DumpRenderTree::setDumpPixels):
+ (WebCore::DumpRenderTree::dump):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2009-07-29 Ariya Hidayat <ariya.hidayat@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27813
+
+ [Qt] Implement ImageDiff.
+
+ * DumpRenderTree/qt/ImageDiff.cpp: Added.
+ * DumpRenderTree/qt/ImageDiff.pro: Added.
+
+2009-07-30 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Eric Seidel.
+
+ build-webkit: Reorder logic for determining the baseProductDir
+
+ https://bugs.webkit.org/show_bug.cgi?id=27699
+
+ We now do port-spesific probing for the product dir first, and then
+ fall back to either the generic WEBKITOUTPUTDIR (which now also works
+ on Mac), or WebKitBuild.
+
+ Then we add the git branch if the git branch build option is enabled.
+
+ Finally we massage the product dir based on the port. For example the
+ Mac port will now always set the SYMROOT and OBJROOT configuration for
+ XCode.
+
+ Note that isAppleWinWebkit() and isCygwin() is not mutually exclusive,
+ hence the normal if and not elsif in the last two blocks.
+
+ * Scripts/webkitdirs.pm:
+
+2009-07-29 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/27082> bugzilla-tool: Add --no-close switch to land-patches
+
+ Reviewed by David Levin.
+
+ * Scripts/bugzilla-tool:
+ (LandPatchesFromBugs.__init__): Added --no-close switch.
+ (LandPatchesFromBugs.land_patches): Don't close the bug if the
+ --no-close switch was used. Always clear the review+ flag on
+ every landed patch using the commit_text message when cleared.
+ This prevents patches from showing up in the commit queue if
+ reopened and provides consistency with all landed patches.
+ * Scripts/modules/bugzilla.py:
+ (Bugzilla.clear_attachment_review_flag): Added.
+
+2009-07-29 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/27815> bugzilla-tool: add -m/--description to post-commits command
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/bugzilla-tool:
+ (PostDiffAsPatchToBug.execute): Changed default patch name from
+ "patch" to "Patch v1".
+ (PostCommitsAsPatchesToBug.__init__): Added -m/--description
+ switch.
+ (PostCommitsAsPatchesToBug.execute): Use description provided by
+ -m/--description switch first, else fall back to the commit
+ message.
+
+2009-07-29 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Dave Levin.
+
+ Make check-webkit-style support files as arguments.
+ https://bugs.webkit.org/show_bug.cgi?id=27549
+
+ * Scripts/check-webkit-style:
+ Support files as argument. Change documentation and use basename
+ on the binary name when used in the documentation. Also do not
+ die when printing something containing non-ASCII characters.
+
+2009-08-06 Mike Fenton <mike.fenton@torchmobile.com>
+
+ Reviewed by David Levin.
+
+ Add validation for pointer and reference declaration as defined by webkit style guidelines to cpp_style.py.
+ Add unit tests for validation and update existing c style cast test to be run explicitly as c validation.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27984
+
+ * Scripts/modules/cpp_style.py:
+ * Scripts/modules/cpp_style_unittest.py:
+
+2009-07-29 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/27119> bugzilla-tool: Add create-bug command
+
+ Reviewed by David Levin.
+
+ Implement "create-bug" command for bugzilla-tool.
+
+ * Scripts/bugzilla-tool: Added CreateBug class.
+ (CreateBug.__init__): Added.
+ (CreateBug.create_bug_from_commit): Added.
+ (CreateBug.create_bug_from_patch): Added.
+ (CreateBug.prompt_for_bug_title_and_comment): Added.
+ (CreateBug.execute): Added.
+ (BugzillaTool.__init__): Added create-bug command.
+ * Scripts/modules/bugzilla.py:
+ (Bugzilla.prompt_for_component): Added.
+ (Bugzilla.check_create_bug_response_returning_bug_id_on_success): Added.
+ (Bugzilla.create_bug_with_patch): Added.
+
+2009-07-29 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Eric Seidel and Xan Lopez.
+
+ [Gtk] Enable http/tests/appcache tests
+ https://bugs.webkit.org/show_bug.cgi?id=27674
+
+ Add support for testing http/tests/appcache tests.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setAppCacheMaximumSize):
+
+2009-07-28 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Prevent nightly builds of WebKit from launching against old Safari versions that we no longer work with.
+
+ * WebKitLauncher/main.m:
+ (checkSafariVersion): Add a minimum required Safari version of 4.0. This matches the requirement on Windows.
+ (main): If the minimum version requirement is not met, display an alert and bail out.
+
+2009-07-28 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Treat.
+
+ cpplint* should be named cpp_style*
+ https://bugs.webkit.org/show_bug.cgi?id=27752
+
+ The files were renamed. A few renames were done:
+ CppLint -> CppStyle
+ cpplint -> cpp_style
+
+ * Scripts/check-webkit-style:
+ * Scripts/modules/cpp_style.py: Copied from cpplint.py and
+ did name fix ups.
+ * Scripts/modules/cpp_style_unittest.py: Copied from cpplint_unittest.py and
+ did name fix ups.
+ * Scripts/modules/cpplint.py: Removed.
+ * Scripts/modules/cpplint_unittest.py: Removed.
+
+2009-07-28 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Rubber-stamped by Holger Freyther.
+
+ Add Steve Falkenburg to bugzilla-tools' reviewers list
+
+ * Scripts/modules/bugzilla.py:
+
+2009-07-28 Zoltan Horvath <hzoltan@inf.u-szeged.hu>
+
+ Reviewed by Simon Hausmann.
+
+ Implement test result archive support for the Qt port.
+
+ * BuildSlaveSupport/test-result-archive:
+
+2009-07-27 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27755
+ Layout tests that dump resource load delegate calls should dump the request method and the response status code.
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[NSURLResponse _drt_descriptionSuitableForTestResult]):
+ (-[NSURLRequest _drt_descriptionSuitableForTestResult]):
+
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (descriptionSuitableForTestResult):
+
+2009-07-27 Pierre d'Herbemont <pdherbemont@apple.com>
+
+ Reviewed by David Levin.
+
+ "bugzilla-tool post-commit head" doesn't work because it can't find the bug id from the commit load.
+ https://bugs.webkit.org/show_bug.cgi?id=27747
+
+ modules.bugzilla is not found because not included.
+
+ * Scripts/modules/scm.py: Properly import modules.bugzilla.
+
+2009-07-24 Pierre d'Herbemont <pdherbemont@apple.com>
+
+ Reviewed by David Kilzer.
+
+ commit-log-editor should allow git commit --amend to regenerate the commit log based on the modifed ChangeLog
+ https://bugs.webkit.org/show_bug.cgi?id=27664
+
+ * Scripts/commit-log-editor: Add --regenerate-log option.
+ The user is asked if he wants to suppress previous ChangeLog and regenerate it,
+ if this option is enabled.
+
+2009-07-27 Gabor Rapcsanyi <rapcsanyi.gabor@stud.u-szeged.hu>
+
+ Reviewed by Simon Hausmann.
+
+ Generating remote links causes a lot of unnecessary spew on Qt build bot too
+
+ * Scripts/run-webkit-tests:
+
+2009-07-25 Kwang Yul Seo <skyul@company100.net>
+
+ Reviewed by Darin Adler.
+
+ Windows build break due to warning C4819
+ https://bugs.webkit.org/show_bug.cgi?id=27416
+
+ Disable C4819 warning to fix build.
+
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+
+2009-07-24 Nikolas Zimmermann <nikolas.zimmermann@torchmobile.com>
+
+ Not reviewed. Add Kevin McCullough as reviewer in bugzilla.py
+
+ * Scripts/modules/bugzilla.py:
+
+2009-07-24 Eli Fidler <eli.fidler@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Improve git workflow by populating commit messages with ChangeLog entries.
+ https://bugs.webkit.org/show_bug.cgi?id=27605
+
+ If the user doesn't manually modify the ChangeLog files, use
+ prepare-ChangeLog to populate the git commit message. This behaviour
+ can be disabled by the 'webkitGenerateCommitMessage' git configuration option.
+
+ * Scripts/commit-log-editor:
+
+2009-07-24 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Treat.
+
+ cpplint crash when there is a duplicate header followed by another header.
+ https://bugs.webkit.org/show_bug.cgi?id=27625
+
+ * Scripts/modules/cpplint.py: Ensure that include_state.header_types is updated even
+ there is a duplicate header, which resulted in some code rearrangement. Also,
+ changed some if's in this function to return early. This avoids having nearly the
+ whole function content being indented.
+ * Scripts/modules/cpplint_unittest.py: Added a test which would have exposed the crash.
+
+2009-07-24 Jakob Petsovits <jakob.petsovits@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Filetype support changes for cpplint and check_webkit_style
+ https://bugs.webkit.org/show_bug.cgi?id=27653
+
+ Introduce .c support for check_webkit_style, and remove support for
+ .cc files in favor of .cpp.
+
+ * Scripts/check-webkit-style:
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-24 Eli Fidler <eli.fidler@torchmobile.com>
+
+ Reviewed by David Levin.
+
+ Improve git workflow by populating commit messages with ChangeLog entries.
+ https://bugs.webkit.org/show_bug.cgi?id=27605
+
+ add --[no-]write prepare-ChangeLog options to bash completion
+
+ * Scripts/webkit-tools-completion.sh:
+
+2009-07-24 Andrei Popescu <andreip@google.com>
+
+ Reviewed by Anders Carlsson.
+
+ ApplicationCache should have size limit
+ https://bugs.webkit.org/show_bug.cgi?id=22700
+
+ Adds a new method on the LayoutTestController that
+ allows a JS unit test to configure the maximum size
+ of the Application Cache.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setAppCacheMaximumSizeCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setAppCacheMaximumSize):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setAppCacheMaximumSize):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setAppCacheMaximumSize):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setAppCacheMaximumSize):
+
+2009-07-24 Adam Barth <abarth@webkit.org>
+
+ Rubber stamped by Eric Seidel.
+
+ Added andersca to list of reviewers.
+
+ * Scripts/modules/bugzilla.py:
+
+2009-07-24 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Xan Lopez.
+
+ Fix dozens of "Deallocation of a pointer not malloced" messages seen while running
+ layout tests on the build bot.
+
+ Memory allocated via FastMalloc was being deleted via the system memory allocator
+ due to an inconsistent including of FastMalloc.h. We address this by including it
+ from config.h and including config.h from every implementation file, as in our other
+ projects.
+
+ * DumpRenderTree/ForwardingHeaders/wtf/FastMalloc.h: Copied from JavaScriptGlue/ForwardingHeaders/wtf/FastMalloc.h.
+ * DumpRenderTree/config.h:
+ * DumpRenderTree/mac/AccessibilityControllerMac.mm:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ * DumpRenderTree/mac/AppleScriptController.m:
+ * DumpRenderTree/mac/CheckedMalloc.cpp:
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ * DumpRenderTree/mac/DumpRenderTreeDraggingInfo.mm:
+ * DumpRenderTree/mac/DumpRenderTreePasteboard.m:
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ * DumpRenderTree/mac/EditingDelegate.mm:
+ * DumpRenderTree/mac/EventSendingController.mm:
+ * DumpRenderTree/mac/FrameLoadDelegate.mm:
+ * DumpRenderTree/mac/GCControllerMac.mm:
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ * DumpRenderTree/mac/NavigationController.m:
+ * DumpRenderTree/mac/ObjCController.m:
+ * DumpRenderTree/mac/ObjCPlugin.m:
+ * DumpRenderTree/mac/ObjCPluginFunction.m:
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ * DumpRenderTree/mac/PlainTextController.mm:
+ * DumpRenderTree/mac/PolicyDelegate.mm:
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ * DumpRenderTree/mac/TextInputController.m:
+ * DumpRenderTree/mac/UIDelegate.mm:
+ * DumpRenderTree/mac/WorkQueueItemMac.mm:
+
+2009-07-24 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Simon Hausmann.
+
+ Add a command line option to run-javascriptcore-tests to explicitly opt out of attempting to rebuild JavaScriptCore.
+ This is primarily useful to speed up the build bots where one machine builds JavaScriptCore and a second runs the tests,
+ leading to situations where the build system unnecessarily feels that the need to recompile.
+
+ * BuildSlaveSupport/build.webkit.org-config/master.cfg:
+ * Scripts/run-javascriptcore-tests:
+
+2009-07-23 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ [Gtk] Add implementation of GCController for DRT
+ https://bugs.webkit.org/show_bug.cgi?id=27636
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (webViewWindowObjectCleared):
+ (main):
+ * DumpRenderTree/gtk/GCControllerGtk.cpp:
+ (GCController::collect):
+ (GCController::collectOnAlternateThread):
+ (GCController::getJSObjectCount):
+
+2009-07-23 Mark Rowe <mrowe@apple.com>
+
+ Update build.webkit.org config for new machine.
+
+ * BuildSlaveSupport/build.webkit.org-config/config.json:
+
+2009-07-23 Brady Eidson <beidson@apple.com>
+
+ Remove accidentally checked in code.
+
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (waitUntilDoneWatchdogFired):
+ (LayoutTestController::setWaitToDump):
+
+2009-07-23 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Geoff Garen.
+
+ WebCore has a few places that don't gracefully handle a null request returned from willSendRequest.
+ https://bugs.webkit.org/show_bug.cgi?id=27595
+
+ Add the ability to tell the LayoutTestController to return a null request for willSendRequest
+ redirect callbacks.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (setWillSendRequestReturnsNullOnRedirectCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::willSendRequestReturnsNullOnRedirect):
+ (LayoutTestController::setWillSendRequestReturnsNullOnRedirect):
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:resource:willSendRequest:redirectResponse:fromDataSource:]):
+ * DumpRenderTree/win/ResourceLoadDelegate.cpp:
+ (ResourceLoadDelegate::willSendRequest):
+
+2009-07-23 Mark Rowe <mrowe@apple.com>
+
+ Reviewed Oliver Hunt.
+
+ Fix DumpRenderTree to not fail an assertion on launch on a new machine.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (setDefaultsToConsistentValuesForTesting): Disable the XSS auditor. It being enabled
+ breaks all of the JavaScript tests within testStringByEvaluatingJavaScriptFromString,
+ which causes us to exit due to an assertion failure. It's not clear why the XSS auditor
+ decides to interfere with these tests.
+
+2009-07-23 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Update default state of the XSS auditor in GTK DumpRenderTree to match Mac and Windows
+ in hopes of fixing some layout test failures seen on the build bot.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+
+2009-07-23 Jakob Petsovits <jakob.petsovits@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Fix false positives for switch statement indentation check in cpplint.
+ https://bugs.webkit.org/show_bug.cgi?id=27615
+
+ Makes one-line case statements (e.g. "case foo: bar();") work.
+ Also a few general improvements to the robustness and readability of
+ the check, and more test cases.
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-23 Jakob Petsovits <jakob.petsovits@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Add check for line-breaking rule #3 to cpplint.
+ https://bugs.webkit.org/show_bug.cgi?id=27610
+
+ "An else if statement should be written as an if statement when
+ the prior if concludes with a return statement."
+
+ Implemented by a multi-line (kind of back-tracking) algorithm.
+ Comes with loads of unit tests. Fixes the check for label indentation
+ to be not so overzealous, as it didn't allow for completely unindented
+ goto labels (at the very start of a line).
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-23 Eli Fidler <eli.fidler@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Improve git workflow by populating commit messages with ChangeLog entries.
+ https://bugs.webkit.org/show_bug.cgi?id=27605
+
+ add --[no-]write option to optionally output new ChangeLog entries to
+ stdout instead of modifying ChangeLog files
+
+ fix Torch Mobile copyright
+
+ * Scripts/prepare-ChangeLog:
+
+2009-07-23 Jakob Petsovits <jakob.petsovits@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Enable cpplint for .c files.
+ https://bugs.webkit.org/show_bug.cgi?id=27604
+
+ Also make sure that the check for NULL does not apply to .c files.
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-22 Steve Falkenburg <sfalken@apple.com>
+
+ Checkpoint new Windows nightly launcher.
+
+ Reviewed by Mark Rowe.
+
+ * WebKitLauncherWin: Added.
+ * WebKitLauncherWin/Resource.h: Added.
+ * WebKitLauncherWin/WebKitLauncherWin.cpp: Added.
+ (getStringValue): Retrieve a string registry value.
+ (applePathFromRegistry): Get an Apple-related path out of the registry.
+ (copyEnvironmentVariable): Copy an environment variable.
+ (safariInstallDir): Helper function to get the install directory for Safari.
+ (safariBrowserExe): Helper function to get the full path of the Safari executable.
+ (_tWinMain): Locate Safari and launch it after setting up an environment variable.
+ * WebKitLauncherWin/WebKitLauncherWin.h: Added.
+ * WebKitLauncherWin/WebKitLauncherWin.rc: Added.
+ * WebKitLauncherWin/WebKitLauncherWin.vcproj: Added.
+ * WebKitLauncherWin/webkit.ico: Added.
+
+2009-07-22 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Treat.
+
+ run-webkit-lint should be named check-webkit-style
+ https://bugs.webkit.org/show_bug.cgi?id=27568
+
+ This name better reflects the fact that it is about checking the style of files.
+
+ * Scripts/check-webkit-style: Renamed from WebKitTools/Scripts/run-webkit-lint.
+
+2009-07-22 Takeshi Yoshino <tyoshino@google.com>
+
+ Reviewed by Darin Adler.
+
+ VC++ 2005 Express failed to build WebKit due to raw UTF-8 string in WebKit/win/WebCoreLocalizedStrings.cpp
+ https://bugs.webkit.org/show_bug.cgi?id=26375
+
+ Make it able to use hexadecimal escape sequences in .*UI_STRING(_KEY)? macros. Now,
+ the extract-localizable-strings script unescapes hexadecimal escape sequences in string literals
+ in the macros before writing out them into the file to update.
+
+ By this fix, we can eliminate raw UTF-8 strings in source code while using raw UTF-16 big endian
+ strings in the Localizable.strings file.
+
+ Bonus: There's no longer extract-webkit-localizable-strings script. Fix usage message to guide
+ users to update-webkit-localizable-strings.
+
+ * Scripts/extract-localizable-strings:
+
+2009-07-22 Shinichiro Hamaji <hamaji@google.com>
+
+ Reviewed by David Levin.
+
+ Tiny typo fixes for cpplint.py
+ https://bugs.webkit.org/show_bug.cgi?id=27530
+
+ * Scripts/modules/cpplint.py:
+
+2009-07-22 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ run-webkit-lint checks code which are not changed
+ https://bugs.webkit.org/show_bug.cgi?id=27529
+
+ Add check if the line is newly added.
+
+ * Scripts/run-webkit-lint:
+
+2009-07-22 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ run-webkit-lint should have --git-commit option
+ https://bugs.webkit.org/show_bug.cgi?id=27528
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/run-webkit-lint:
+
+2009-07-22 Peter Kasting <pkasting@google.com>
+
+ Reviewed by David Kilzer.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Factor svn-create-patch's "determineSvnRoot()" into a function in
+ VCSUtils.pm so commit-log-editor can use it too.
+
+ * Scripts/VCSUtils.pm: Add determineSVNRoot().
+ * Scripts/commit-log-editor: Use determineSVNRoot() instead of old
+ code (which didn't work as well).
+ * Scripts/svn-create-patch: Remove determineSvnRoot() (moved).
+
+2009-07-22 Jakob Petsovits <jakob.petsovits@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Fix false positives in namespace indentation checks.
+ https://bugs.webkit.org/show_bug.cgi?id=27567
+
+ The regular expression detecting goto labels (in order
+ to skip those) was too permissive, which caused other
+ code like "Foo::Bar()" to be treated as a label too,
+ thereby not stopping the processing loop as expected.
+
+ Now comes with a stricter regexp, and more demanding
+ test cases to check for these issues.
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-22 Jakob Petsovits <jakob.petsovits@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Fix cpplint generating false positives for
+ "primary" includes in headers.
+ https://bugs.webkit.org/show_bug.cgi?id=27553
+
+ Doing so by only flagging includes in header files
+ as primary when the include filename exactly matches
+ the header filename.
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-22 Jakob Petsovits <jakob.petsovits@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ cpplint generates false positives for primary includes
+ https://bugs.webkit.org/show_bug.cgi?id=27544
+
+ Fix false positives for instances when cpplint would
+ normally classify multiple includes as primary: After
+ the first primary include, classify subsequent ones as
+ "other" includes even if they look like primary ones.
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-22 Gabor Rapcsanyi <rapcsanyi.gabor@stud.u-szeged.hu>
+
+ Reviewed by Simon Hausmann.
+
+ Pass XAUTHORITY environment variable to $dumpTool as well.
+
+ * Scripts/run-webkit-tests:
+
+2009-07-21 Jakob Petsovits <jakob.petsovits@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ Add check for correct wtf includes to cpplint.
+ https://bugs.webkit.org/show_bug.cgi?id=27524
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-21 Jakob Petsovits <jakob.petsovits@torchmobile.com>
+
+ Reviewed by David Levin.
+
+ Add checks for multi-line boolean operator placement.
+ https://bugs.webkit.org/show_bug.cgi?id=27496
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-21 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by David Levin.
+
+ We can't match implementation file and primary header exactly
+ since we have so many files in WebKit where the port suffix
+ is appended to the filename.
+
+ Example: FooQt.cpp and the primary header is Foo.h.
+
+ * Scripts/modules/cpplint.py:
+
+2009-07-21 Jakob Petsovits <jakob.petsovits@torchmobile.com>
+
+ Reviewed by David Levin.
+
+ Add checks for switch statement indentation to cpplint.
+ https://bugs.webkit.org/show_bug.cgi?id=27508
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-21 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by Adam Treat.
+
+ Feature request: cpplint should check for braces - rule 2
+ https://bugs.webkit.org/show_bug.cgi?id=27497
+
+ Add the requested feature: Make sure { is on the same line
+ as the foreach "keyword".
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-20 Jakob Petsovits <jakob.petsovits@torchmobile.com>
+
+ Reviewed by David Levin.
+
+ Add checks for namespace indentation to cpplint.
+ https://bugs.webkit.org/show_bug.cgi?id=27461
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-20 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by David Levin.
+
+ Add cpplint check for proper include order
+ https://bugs.webkit.org/show_bug.cgi?id=27462
+
+ Add a new check to cpplint to flag cases where the include section of a file
+ does not match the mandated include order and style of the Webkit coding style
+ guidelines.
+
+ Add associated tests.
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-21 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ Support lint for patches
+ https://bugs.webkit.org/show_bug.cgi?id=27291
+
+ Add run-webkit-lint script, which lints recent changes in local
+ repository. Also, modified cpplint.py so that we don't need to
+ specify verbose level for process_file().
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/run-webkit-lint: Added.
+
+2009-07-21 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ diff_parser should accept lines without trailing \n
+ https://bugs.webkit.org/show_bug.cgi?id=27483
+
+ Normalize the input lines by removing a trailing newline.
+ Also, add a case for unittest for newly added files.
+
+ * Scripts/modules/diff_parser.py:
+ * Scripts/modules/diff_parser_unittest.py:
+
+2009-07-21 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ cpplint.py's process_file() should accept customized error function
+ https://bugs.webkit.org/show_bug.cgi?id=27487
+
+ * Scripts/modules/cpplint.py:
+
+2009-07-21 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ cpplint.py should have an interface to get global error count
+ https://bugs.webkit.org/show_bug.cgi?id=27486
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-21 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ cpplint's parse_argument should not exit even if no files are specified
+ https://bugs.webkit.org/show_bug.cgi?id=27489
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-21 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ diff_parser: s/add_deleted_line/add_old_line/g
+ https://bugs.webkit.org/show_bug.cgi?id=27484
+
+ * Scripts/modules/diff_parser.py:
+
+2009-07-21 Roland Steiner <rolandsteiner@google.com>
+
+ Reviewed by David Levin.
+
+ Add ENABLE_RUBY to list of build options
+ https://bugs.webkit.org/show_bug.cgi?id=27324
+
+ * Scripts/build-webkit: Added flag ENABLE_RUBY.
+
+2009-07-20 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by David D. Kilzer.
+
+ Fix <https://bugs.webkit.org/show_bug.cgi?id=27482>.
+ Bug 27482: svn-apply cannot apply patch generated by Windows SVN
+
+ A regexp in svn-apply was treating everything prior to a \n as part of the
+ file name. The native Windows SVN client uses \r\n for line endings which
+ meant that the \r was being included in the file name. This defeated the
+ special-case logic for ChangeLogs to apply them with an increased fuzz factor,
+ meaning that the ChangeLog portions of such patches would fail to apply.
+
+ Also updated two other regexps that look like they would hit similar problems
+ with line-endings so that they will correctly handle patches from Windows SVN.
+
+ * Scripts/svn-apply:
+
+2009-07-20 Peter Kasting <pkasting@google.com>
+
+ Reviewed by Mark Rowe.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27468
+ Back out r46060, which caused problems for some Apple developers.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+
+2009-07-20 Peter Kasting <pkasting@google.com>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Use shorter, more correct code for determining the current directory,
+ which works better with symbolic links on some systems. Also switch
+ from checking repository root to checking UUID, to match scm.py.
+
+ * Scripts/svn-create-patch:
+
+2009-07-20 Mark Rowe <mrowe@apple.com>
+
+ Rubber-stamped by Dan Bernstein.
+
+ Work around <rdar://problem/7075373> by ensuring that the URL is absolute before handing it off to CoreText.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (activateFonts):
+
+2009-07-20 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Treat.
+
+ Enable filename completion for run-webkit-test (added "-o default").
+
+ * Scripts/webkit-tools-completion.sh:
+
+2009-07-20 Simon Hausmann <simon.hausmann@nokia.com>
+
+ No review, just adding Gavin Barraclough as reviewer.
+
+ * Scripts/modules/bugzilla.py:
+
+2009-07-20 Kenneth Rohde Christiansen <kenneth@webkit.org>
+
+ Reviewed by David Levin.
+
+ Add support for Qt's foreach to cpplint
+ https://bugs.webkit.org/show_bug.cgi?id=27386
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-18 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ https://bugs.webkit.org/show_bug.cgi?id=27145
+ [Gtk][REGRESSION] subframe-navigate-during-main-frame-load.html fails after r45615
+
+ Reviewed by Gustavo Noronha.
+
+ Normalize file URLs.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dumpHistoryItem):
+
+2009-07-17 Peter Kasting <pkasting@google.com>
+
+ Reviewed by David Kilzer.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Further improve non-Cygwin SVN support.
+
+ * Scripts/prepare-ChangeLog: Harmless change to be consistent with other
+ places that consume whitespace at the end of svn output.
+ * Scripts/resolve-ChangeLogs: Add support for SVN 1.6. Slightly
+ optimize svn info parsing based on technique in svn-create-patch.
+ Normalize paths and consume whitespace in the same way as
+ prepare-ChangeLog, for Windows systems with a non-Cygwin SVN. Force
+ diff and patch to run in binary mode so that they won't
+ "intelligently" screw up line endings.
+
+2009-07-18 Simon Fraser <simon.fraser@apple.com>
+
+ Fix Tiger DRT build.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (createWebViewAndOffscreenWindow):
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+
+2009-07-17 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ DRT doesn't reliably snapshot composited layers
+ https://bugs.webkit.org/show_bug.cgi?id=27399
+
+ If we're doing an "onscreen" pixel capture, it means that we're snapshotting a view
+ with composited content. In that case we need to force the view to display so that
+ the composited layers are rendered to the screen.
+
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (createBitmapContextFromWebView):
+
+2009-07-17 Adam Barth <abarth@webkit.org>
+
+ Reviewed by David Levin.
+
+ bugzilla-tool does not understand nested SVN repos
+ https://bugs.webkit.org/show_bug.cgi?id=27404
+
+ Determine the root of the working copy by looking at SVN's UUIDs.
+
+ * Scripts/modules/scm.py:
+
+2009-07-17 David Levin <levin@chromium.org>
+
+ Reviewed by Mark Rowe.
+
+ webkit-tools-completion.sh has two typos and sorting issues.
+ https://bugs.webkit.org/show_bug.cgi?id=27401
+
+ * Scripts/webkit-tools-completion.sh: Fix two typos "--dif" and "-clean".
+ Also, sort all lists including items in the case statement and flags for
+ the commands.
+
+2009-07-17 Peter Kasting <pkasting@google.com>
+
+ Reviewed by David Kilzer.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Tweak some regexes for correctness.
+
+ * Scripts/prepare-ChangeLog: Allow 1-character filenames (my previous
+ change here didn't quite get things right).
+ * Scripts/update-webkit: Detect conflicting ChangeLogs correctly by not
+ including any trailing whitespace in the name "ChangeLog", and by
+ normalizing paths before calling basename() to avoid confusing it.
+ (normalizePath() copied from prepare-ChangeLog.)
+
+2009-07-17 Peter Kasting <pkasting@google.com>
+
+ Reviewed by Steve Falkenburg.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Only add Cygwin to the path when it isn't already there. This avoids
+ causing problems for people who purposefully have non-Cygwin versions of
+ executables like svn in front of the Cygwin ones in their paths.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+
+2009-07-17 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Treat.
+
+ WebKit should have a bash completion script to aid with common commands.
+ https://bugs.webkit.org/show_bug.cgi?id=27374
+
+ * Scripts/webkit-tools-completion.sh: The script which enables option completion
+ for several WebKit command line scripts.
+
+2009-07-17 Peter Kasting <pkasting@google.com>
+
+ Reviewed by David Kilzer.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Avoid error spew on Macs, and fix a few other tiny details.
+
+ * Scripts/svn-create-patch:
+
+2009-07-17 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by Dave Levin.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27377
+ This makes cpplint complain about this for instance:
+
+ if (true)
+ {
+ int foo;
+ }
+
+ Add the appropriate unit tests.
+
+ * Scripts/modules/cpplint.py:
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-17 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by Dave Levin.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27377
+ Don't filter whitespace at the end of the line. This is not
+ explicitly a rule of webkit coding style, but there is no reason
+ not to warn of this common style problem.
+
+ Don't filter whitespace newline. Now, cpplint will complain
+ about the following situation:
+
+ if (true) {
+ doSomething();
+ doSomethingAgain();
+ }
+ else
+ doSomething();
+
+ Which is a webkit coding style rule violation.
+
+ * Scripts/modules/cpplint.py:
+
+2009-07-17 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by Dave Levin.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27377
+ Move this comment to where it belongs.
+
+ * Scripts/modules/cpplint_unittest.py:
+
+2009-07-17 Brent Fulgham <bfulgham@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Correct crash in WinLauncher due to improper mixing of BSTR
+ and TCHAR types.
+ https://bugs.webkit.org/show_bug.cgi?id=27381
+
+ * WinLauncher/WinLauncher.cpp:
+ (loadURL): Perform SysReAllocString to update the BSTR with
+ the contents of the TCHAR string.
+
+2009-07-17 David Levin <levin@chromium.org>
+
+ Reviewed by Adam Treat.
+
+ cpplint should flag usages of NULL.
+ https://bugs.webkit.org/show_bug.cgi?id=27341
+
+ * Scripts/modules/cpplint.py: Add the check for NULL test and call it.
+ Make the collapse_strings method public.
+ * Scripts/modules/cpplint_unittest.py: Add several tests to verify
+ the check for NULL behavior. Adjust existing tests due to the
+ new NULL check:
+ 1. Several had NULL removed (or were just removed completely).
+ 2. Two tests now do an assert that allows the caller to check
+ that a particular error is one of several that was returned.
+
+2009-07-17 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ Add a parser of patches for linter.
+ https://bugs.webkit.org/show_bug.cgi?id=27363
+
+ Adds a simple parser for unified diff format.
+
+ * Scripts/modules/diff_parser.py: Added.
+ * Scripts/modules/diff_parser_unittest.py: Added.
+
+2009-06-30 Holger Hans Peter Freyther <zecke@selfish.org>
+
+ Reviewed by Simon Hausmann.
+
+ [GTK+] Remove check to be loadable in firefox
+ https://bugs.webkit.org/show_bug.cgi?id=27345
+
+ if (aMozillaVTable->size < sizeof (NPNetscapeFuncs))
+ fails in firefox but no other example in the mozilla tree is
+ doing that check. Remove and be happy.
+
+ * DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (NP_Initialize):
+
+2009-07-17 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by Simon Hausmann.
+
+ Something about having a single TAB in a style checking tool like this
+ is equivalent to nails on a chalk board to me...
+
+ * Scripts/modules/cpplint.py:
+
+2009-07-17 Kenneth Rohde Christiansen <kenneth.christiansen@openbossa.org>
+
+ Reviewed by Simon Hausmann.
+
+ Overwrite the plugin directories for the DRT.
+ Part of https://bugs.webkit.org/show_bug.cgi?id=27215
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+
+2009-07-16 Fumitoshi Ukai <ukai@chromium.org>
+
+ Reviewed by David Levin.
+
+ Add --web-sockets flag and ENABLE_WEB_SOCKETS define.
+ https://bugs.webkit.org/show_bug.cgi?id=27206
+
+ Add --web-sockets flag.
+
+ * Scripts/build-webkit: add --web-sockets flag.
+
+2009-07-16 Adam Treat <adam.treat@torchmobile.com>
+
+ Reviewed by Dave Levin.
+
+ cpplint should check for one line control clauses that are surrounded
+ by braces
+ https://bugs.webkit.org/show_bug.cgi?id=27354
+
+ * Scripts/modules/cpplint.py: Added the new lint check.
+ * Scripts/modules/cpplint_unittest.py: Add tests for the new lint check
+ and fix the other tests as they were not passing this new lint check.
+
+2009-07-16 Peter Kasting <pkasting@google.com>
+
+ Reviewed by David Kilzer.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Improve support for WebKit checkouts hosted inside other checkouts
+ (possible for some ports, e.g. Chromium).
+
+ * Scripts/svn-create-patch: Determine SVN root by looking for Repository
+ Root string and aborting when it's missing or different than what
+ we've already seen.
+
+2009-07-16 Peter Kasting <pkasting@google.com>
+
+ Reviewed by Adam Roben.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Improve support for non-Cygwin SVNs on Windows.
+
+ * Scripts/commit-log-editor: Modify regex so that trailing whitespace
+ (e.g. \r) isn't included in filenames.
+ * Scripts/prepare-ChangeLog: Fix a case of adding "\n" to the ChangeLog
+ without normalizing. Normalize file paths early instead of late so
+ all stages of the script work. Modify regexes so that trailing
+ whitespace (e.g. \r) isn't included in filenames.
+ * Scripts/svn-create-patch: Use a regex instead of chomp so we cut off
+ line endings even if they don't match Perl's.
+
+2009-07-16 Joseph Pecoraro <joepeck02@gmail.com>
+
+ Reviewed by Darin Adler.
+
+ WebKitTools/Scripts/svn-create-patch is broken
+ https://bugs.webkit.org/show_bug.cgi?id=27328
+
+ * Scripts/svn-create-patch: one line fix for unusual perl behavior
+
+2009-07-16 David Levin <levin@chromium.org>
+
+ Reviewed by David Kilzer.
+
+ cpplint should check for equality comparisons to 0/true/false
+ https://bugs.webkit.org/show_bug.cgi?id=27333
+
+ * Scripts/modules/cpplint.py: Added the new lint check.
+ * Scripts/modules/cpplint_unittest.py: Add tests for the new lint check
+ and fix a regex that in another unit test that caused it to fail when
+ you have a directory with a number in it (like WebKit-2)
+
+2009-07-16 David D. Kilzer <ddkilzer@webkit.org>
+
+ <http://webkit.org/b/27241> bugzilla-tool post-commits silently fails with bad args
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/bugzilla-tool:
+ (PostCommitsAsPatchesToBug.execute): Added more error checking
+ when consuming arguments.
+
+2009-07-16 David D. Kilzer <ddkilzer@webkit.org>
+
+ TOOL FIX: scm.py: CommitMessage.message is ambiguous
+
+ Fixes this error when running bugzilla-tool apply-patches
+ --local-commit:
+
+ File "bugzilla-tool", line 188, in apply_patches
+ scm.commit_locally_with_message(commit_message.message() or patch['name'])
+ TypeError: 'list' object is not callable
+
+ * Scripts/modules/scm.py: After r45940 (and r45971), rename
+ CommitMessage.message attribute to CommitMessage.message_lines.
+ (CommitMessage.__init__):
+ (CommitMessage.body):
+ (CommitMessage.description):
+ (CommitMessage.message):
+ (CommitMessage.parse_bug_id):
+
+2009-07-16 David D. Kilzer <ddkilzer@webkit.org>
+
+ TOOL FIX: bugzilla-tool: import CommitMessage class
+
+ * Scripts/bugzilla-tool: After r45940, the CommitMessage class
+ needs to be imported for commit_message_for_this_commit().
+
+2009-07-16 David Levin <levin@chromium.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ prepare-ChangeLog should display the --bug option in its help text.
+ https://bugs.webkit.org/show_bug.cgi?id=27334
+
+ * Scripts/prepare-ChangeLog: Added the help text.
+
+2009-07-15 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: Check in the version used to
+ rename parseURL to deprecatedParseURL.
+
+2009-07-10 David Kilzer <ddkilzer@apple.com>
+
+ bugzilla-tool: create CommitMessage class
+
+ Reviewed by Eric Seidel.
+
+ Create a CommitMessage class to encapsulate related code.
+
+ * Scripts/bugzilla-tool:
+ (bug_id_from_commit_message): Moved to
+ CommitMessage.parse_bug_id().
+ (commit_message_for_this_commit): Return a CommitMessage.
+ (ApplyPatchesFromBug.apply_patches): Use CommitMessage.message().
+ (LandPatchesFromBugs.build_and_commit): Ditto.
+ (CommitMessageForCurrentDiff.execute): Ditto.
+ (PostCommitsAsPatchesToBug.execute): Switched from
+ Git.commit_message_for_commit() to
+ Git.commit_message_for_local_commit(). Switched from
+ bug_id_from_commit_message() to CommitMessage.parse_bug_id().
+
+ * Scripts/modules/scm.py:
+ (first_non_empty_line_after_index): Added.
+ (CommitMessage.__init__): Added.
+ (CommitMessage.body): Added.
+ (CommitMessage.description): Added.
+ (CommitMessage.message): Added.
+ (CommitMessage.parse_bug_id): Added. Moved from
+ bug_id_from_commit_message() in bugzilla-tool.
+ (Git.commit_message_for_local_commit): Renamed from
+ commit_message_for_commit(). Return a CommitMessage.
+
+2009-07-15 Joseph Pecoraro <joepeck02@gmail.com>
+
+ Reviewed by David Kilzer.
+
+ bugzilla-tool/svn-apply can't handle patches made from a non-root directory
+ https://bugs.webkit.org/show_bug.cgi?id=26999
+
+ * Scripts/svn-create-patch:
+
+2009-07-15 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ Move cpplint.py to module directory
+ https://bugs.webkit.org/show_bug.cgi?id=27302
+
+ * Scripts/modules/cpplint.py: Renamed from WebKitTools/Scripts/cpplint.py.
+ * Scripts/modules/cpplint_unittest.py: Renamed from WebKitTools/Scripts/cpplint_unittest.py.
+
+2009-07-15 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Adam Treat.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27295
+
+ Re-implement QWebPage::shouldInterruptJavaScript to disable
+ js interruption and avoid showing a messagebox during Qt DRT
+ runs when script execution takes a bit longer.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::shouldInterruptJavaScript): Return false
+ in re-implemented slot.
+
+2009-07-15 Zoltan Horvath <hzoltan@inf.u-szeged.hu>
+
+ Reviewed by Jan Alonzo.
+
+ Fix the DumpRenderTree GTK+ build
+ https://bugs.webkit.org/show_bug.cgi?id=27290
+
+ Set USE_SYSTEM_MALLOC macro for the DumpRenderTree build to
+ disable using TCmalloc in DumpRenderTree.
+
+ * GNUmakefile.am:
+
+2009-07-14 Steve Falkenburg <sfalken@apple.com>
+
+ Reorganize JavaScriptCore headers into:
+ API: include/JavaScriptCore/
+ Private: include/private/JavaScriptCore/
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+
+2009-07-14 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by David Levin.
+
+ WebKit needs a style linting tool
+ https://bugs.webkit.org/show_bug.cgi?id=25884
+
+ Modifies cpplint (http://google-styleguide.googlecode.com/svn/trunk/cpplint/)
+ based on WebKit's style guide.
+
+ * Scripts/cpplint.py: Added.
+ * Scripts/cpplint_unittest.py: Added.
+
+2009-07-14 Laszlo Gombos <laszlo.1.gombos@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ [Qt] DumpRenderTree no longer builds with Qt4.4
+ https://bugs.webkit.org/show_bug.cgi?id=27257
+
+ Flag Qt 4.5 dependency to allow building with Qt 4.4.
+
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2009-07-13 Brent Fulgham <bfulgham@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Add new configuration flag for redistributable Windows build.
+ https://bugs.webkit.org/show_bug.cgi=27087
+
+ * DumpRenderTree/config.h: Check for presence of WIN_CAIRO and
+ select appropriate configuration. Defaults to standard Apple build.
+ * DumpRenderTree/win/DumpRenderTree.vcproj: Add new WinCairo.vsprops
+ to Debug_Cairo and Release_Cairo targets.
+
+2009-07-13 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Ariya Hidayat.
+
+ Always run the Qt DRT with the raster graphicssystem on X11, for
+ increased stability in the image based tests, in particular canvas.
+
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2009-07-13 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Reviewed by Ariya Hidayat.
+
+ Fix test netscape plugin usage with the Qt DRT.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage): Enable plugins in the settings.
+ * Scripts/run-webkit-tests: Set the QT_WEBKIT_PLUGIN path to the correct build
+ directory to make Qt DRT find the test netscape plugin.
+
+2009-07-13 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ Make sure to disable the fixed contents size when resetting the page/view
+ state between test runs, to avoid side-effects.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::open): Call setFixedContentsSize() with an invalid
+ QSize to disable the fixed layout.
+
+2009-07-13 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ When creating new windows, don't forget to connect the new
+ page's main frame. This ensures that for example the layoutTestController
+ is also available there.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::createWindow):
+
+2009-07-13 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ Added support for LayoutTestController.setPrivateBrowsingEnabled.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::setPrivateBrowsingEnabled):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-07-13 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ Added support for database callbacks, storage quota setting,
+ and clearing of all databases.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree):
+ (WebCore::DumpRenderTree::dumpDatabaseQuota):
+ * DumpRenderTree/qt/DumpRenderTree.h:
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::reset):
+ (LayoutTestController::setDatabaseQuota):
+ (LayoutTestController::clearAllDatabases):
+ * DumpRenderTree/qt/jsobjects.h:
+ (LayoutTestController::shouldDumpDatabaseCallbacks):
+ (LayoutTestController::dumpDatabaseCallbacks):
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2009-07-13 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ Setup the path in the Qt DRT for HTML 5 Databases, to enable some of
+ the storage layout tests.
+
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2009-07-13 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ Make the test output more robust by dumping only when the main
+ frame finishes loading, instead of when _any_ frame finishes.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree): Connect to the
+ main frame's loadFinished() signal instead of the page's one.
+
+2009-07-13 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ Implement the GCController DRT interface.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree): Allocate the GCController.
+ (WebCore::DumpRenderTree::initJSObjects): Register the interface with the JS engine.
+ * DumpRenderTree/qt/DumpRenderTree.h: Declare m_gcController.
+ * DumpRenderTree/qt/jsobjects.cpp: Implement GCController.
+ (GCController::GCController):
+ (GCController::collect):
+ (GCController::collectOnAlternateThread):
+ (GCController::getJSObjectCount):
+ * DumpRenderTree/qt/jsobjects.h: Declare GCController.
+
+2009-07-13 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Ariya Hidayat.
+
+ Implement the GCController DRT interface in the Qt DRT.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::DumpRenderTree): Allocate the GCController.
+ (WebCore::DumpRenderTree::initJSObjects): Register the interface with the JS engine.
+ * DumpRenderTree/qt/DumpRenderTree.h: Declare m_gcController.
+ * DumpRenderTree/qt/jsobjects.cpp: Implement GCController.
+ (GCController::GCController):
+ (GCController::collect):
+ (GCController::collectOnAlternateThread):
+ (GCController::getJSObjectCount):
+ * DumpRenderTree/qt/jsobjects.h: Declare GCController.
+
+2009-07-13 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ https://bugs.webkit.org/show_bug.cgi?id=26718 [Gtk] Add support for javascript windows for DRT
+
+ Reviewed by Gustavo Noronha and Xan Lopez.
+
+ Support running of tests that open and close JS windows automatically.
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (dumpFramesAsText):
+ (dumpBackForwardListForAllWebViews):
+ (resetWebViewToConsistentStateBeforeTesting):
+ (dump):
+ (runTest):
+ (webViewClose):
+ (createWebView):
+ (webViewCreate):
+ (main):
+ * DumpRenderTree/gtk/DumpRenderTreeGtk.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::windowCount):
+ (LayoutTestController::setPopupBlockingEnabled):
+
+2009-07-13 Shinichiro Hamaji <hamaji@chromium.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ prepare-ChangeLog should decode HTML entities in short description
+ https://bugs.webkit.org/show_bug.cgi?id=27122
+
+ Decode the short description by adding a function which decodes HTML
+ entities. It can decode &, <, >, ", and ' . They may be sufficient
+ as the description seems to be encoded by xml_quote in
+ http://mxr.mozilla.org/bugzilla/source/Bugzilla/Util.pm
+
+ * Scripts/prepare-ChangeLog:
+
+2009-07-13 Drew Wilson <atwilson@google.com>
+
+ Reviewed by David Levin.
+
+ Add ENABLE(SHARED_WORKERS) flag and define SharedWorker APIs
+ https://bugs.webkit.org/show_bug.cgi?id=26932
+
+ Added support for --shared-workers (turned off by default)
+
+ * Scripts/build-webkit:
+
+2009-07-12 Dan Bernstein <mitz@apple.com>
+
+ Reviewed by Maciej Stachowiak.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27196
+ Update check-for-global-initializers for the renaming for bidi.cpp to
+ RenderBlockLineLayout.cpp
+
+ * Scripts/check-for-global-initializers:
+
+2009-07-11 Simon Fraser <simon.fraser@apple.com>
+
+ Enable support for accelerated compositing and 3d transforms on Leopard.
+ <https://bugs.webkit.org/show_bug.cgi?id=20166>
+ <rdar://problem/6120614>
+
+ Reviewed by Oliver Hunt.
+
+ * Configurations/FeatureDefines.xcconfig:
+ * wtf/Platform.h:
+
+2009-07-10 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/27173> svn-apply: Fix typo in git command used to find deleted files
+
+ Reviewed by Eric Seidel.
+
+ * Scripts/svn-apply:
+ (scmWillDeleteFile): Changed 'head' to 'HEAD'.
+
+2009-07-10 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/27167> bugzilla-tool: hide help for unsupported commands
+
+ Reviewed by Eric Seidel.
+
+ When bugzilla-tool -h|--help is invoked in an svn working
+ directory, don't print help for commands that are only supported
+ on git working directories.
+
+ * Scripts/bugzilla-tool:
+ (Command.__init__): Added requires_local_commits argument with a
+ default of False. Set self.requires_local_commits attribute.
+ (PostCommitsAsPatchesToBug.execute): Removed
+ SCM.supports_local_commits() check since this is now handled by
+ BugzillaTool.main().
+ (PostCommitsAsPatchesToBug.__init__): Added
+ requires_local_commits=True argument to Command.__init__().
+ (BugzillaTool.commands_usage): Don't print help for commands if
+ they require local commits and the current SCM doesn't support
+ them.
+ (BugzillaTool.main): If command_object requires local commits
+ and the current SCM doesn't, exit with an error message.
+
+2009-07-10 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/27117> bugzilla-tool: use Mac OS X keychain for authentication
+
+ Reviewed by Eric Seidel.
+
+ Try reading credentials from git config first, then keychain if
+ running on Mac OS X, else prompt at the command-line.
+
+ * Scripts/modules/bugzilla.py: Added "import platform".
+ (credentials_from_git): Added.
+ (credentials_from_keychain): Added.
+ (is_mac_os_x): Added.
+ (read_credentials): Added.
+ (Bugzilla.__init__): Moved instance attribute bug_server to a
+ static attribute named bug-server_url.
+ (Bugzilla.bug_server_host): Added. Extracted host name from
+ bug_server_url.
+ (Bugzilla.bug_server_regex): Updated to be created using
+ bug_server_host.
+ (Bugzilla.bug_server_url): Renamed from bug_server.
+ (Bugzilla.bug_url_for_bug_id): Updated for renaming of
+ bug_server to bug_server_url.
+ (Bugzilla.attachment_url_for_id): Ditto.
+ (Bugzilla.fetch_bug_ids_from_commit_queue): Ditto.
+ (Bugzilla.authenticate): Ditto. Updated to use
+ read_credentials().
+ (Bugzilla.add_patch_to_bug): Ditto.
+
+2009-07-10 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/27115> bugzilla-tool: extract duplicate logging methods into a module
+
+ Reviewed by Adam Roben.
+
+ * Scripts/bugzilla-tool: Removed error() and log() methods and
+ added import of new logging module.
+ * Scripts/modules/bugzilla.py: Ditto. Removed "import sys".
+ * Scripts/modules/scm.py: Ditto.
+
+ * Scripts/modules/logging.py: Added.
+ (log): Added.
+ (error): Added. Prefix error messages with "ERROR: ".
+
+2009-07-10 Adam Roben <aroben@apple.com>
+
+ Sort all our Xcode projects
+
+ Accomplished using sort-Xcode-project-file.
+
+ Requested by Dave Kilzer.
+
+ * DrawTest/DrawTest.xcodeproj/project.pbxproj:
+ * DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj:
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj:
+
+2009-07-10 Adam Roben <aroben@apple.com>
+
+ Print prepare-ChangeLog's reminders to STDERR so they don't end up in
+ the diff output
+
+ Fixes REGRESSION (r45647): prepare-ChangeLog -d puts non-diff lines
+ into the diff
+ <https://bugs.webkit.org/show_bug.cgi?id=27150>
+
+ Reviewed by Maciej Stachowiak.
+
+ * Scripts/prepare-ChangeLog:
+
+2009-07-08 Adam Roben <aroben@apple.com>
+
+ Use case-insensitive comparisons when sorting Xcode project files
+
+ This matches the sorting used in Xcode's files list.
+
+ Fixes Bug 27079: sort-Xcode-project-file should sort
+ case-insensitively, to match Xcode's files list
+ <https://bugs.webkit.org/show_bug.cgi?id=27079>
+
+ Reviewed by Dave Kilzer.
+
+ * Scripts/sort-Xcode-project-file:
+ (sortChildrenByFileName):
+ (sortFilesByFileName):
+ Lowercase the strings before comparing them so that the comparison
+ will be case-insensitive.
+
+2009-07-08 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27109
+
+ Fix side-effects in the Qt DRT with tests using application fonts.
+
+ Detect if a test used application fonts and re-initialize the fontconfig
+ application fontset accordingly.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::open): call initializeFonts and remove all application fonts
+ after running a testcase.
+ (WebCore::DumpRenderTree::initializeFonts): Moved fontconfig initialization code
+ here from main.
+ * DumpRenderTree/qt/DumpRenderTree.h: Declare initializeFonts.
+ * DumpRenderTree/qt/main.cpp:
+ (main): Moved fontconfig initialization code to DRT::initializeFonts.
+
+2009-07-10 Antonio Gomes <antonio.gomes@openbossa.org>
+
+ Reviewed by Simon Hausmann.
+
+ [QT] [ARM] Add pkg-config entry for FontConfig on DRT.pro
+ https://bugs.webkit.org/show_bug.cgi?id=26990
+
+ Missing pkg-config entry for FontConfig in DRT.pro causes some compilers to
+ not link fine against FontConfig bits.
+
+ * DumpRenderTree/qt/DumpRenderTree.pro:
+
+2009-07-09 Drew Wilson <atwilson@google.com>
+
+ Reviewed by Alexey Proskuryakov.
+
+ https://bugs.webkit.org/show_bug.cgi?id=26903
+
+ Turned on CHANNEL_MESSAGING by default because the MessageChannel API
+ can now be implemented for Web Workers and is reasonably stable.
+
+ * Scripts/build-webkit:
+
+2009-07-09 David Kilzer <ddkilzer@apple.com>
+
+ <http://webkit.org/b/27114> bugzilla-tool: Parse short bug URL from commit log messages
+
+ Reviewed by Adam Roben.
+
+ * Scripts/bugzilla-tool:
+ (bug_id_from_commit_message): Check for the short bug URL before
+ checking for the longer bugs.webkit.org URL.
+
+2009-07-08 David Kilzer <ddkilzer@apple.com>
+
+ Bug 27062: bugzilla-tool: post-commits should read bug id from commit log and actually work
+
+ <https://bugs.webkit.org/show_bug.cgi?id=27062>
+
+ Reviewed by Eric Seidel.
+
+ Removed the required BUGID argument from the "post-commits"
+ command and replaced it with a -b|--bug-id switch or parsing the
+ commit log message for the bug URL. Fixed a bug in the
+ "post-commits" that would ignore the COMMITISH used and post a
+ patch of local changes against HEAD. Added --no-commit switch
+ to disable using the bulk of the ChangeLog entry as the comment
+ for the new patch.
+
+ * Scripts/bugzilla-tool:
+ (bug_id_from_commit_message): Added. Returns a bug id from the
+ commit log message, thus enforcing the need for a bug URL in the
+ message.
+ (PostCommitsAsPatchesToBug.__init__): Updated help description
+ to match new behavior of pulling bug ids from commit log
+ messages instead of from the command line. Added -b|--bug-id
+ switch and --no-comment switch.
+ (PostCommitsAsPatchesToBug.execute): Updated to use
+ bug_id_from_commit_message() to pull bug ids from commit log
+ messages. Also switched from SCM.create_patch() to use
+ SCM.create_patch_from_local_commit() to fix a bug where local
+ repository changes were posted as a patch instead of the
+ specific COMMITISH. Fall back to -b|--bug-id if no URL is found
+ in the commit log message. Don't specify a comment for the
+ patch if --no-comment is used. Set cherry_pick argument to True
+ for Git.commit_ids_from_range_arguments() since we don't want
+ implicit commit range behavior for this command.
+
+ * Scripts/modules/bugzilla.py: Import datetime module.
+ (timestamp): Added. Returns a timestamp in the form of
+ "YYYYMMDDhhmmss".
+ (Bugzilla.bug_server_regex): Added static attribute.
+ (Bugzilla.add_patch_to_bug): Construct a more meaningful patch
+ file name using the bug_id and timestamp().
+
+ * Scripts/modules/scm.py:
+ (SCM.create_patch_from_local_commit): Added.
+ (Git.create_patch_from_local_commit): Added. Runs "git diff" to
+ return a patch for the given commit_id.
+
+2009-07-08 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ Make prepare-ChangeLog less shouty
+ https://bugs.webkit.org/show_bug.cgi?id=27098
+
+ * Scripts/prepare-ChangeLog:
+
+2009-07-08 David Kilzer <ddkilzer@apple.com>
+
+ Bug 27083: bugzilla.py: Clean up bug_server use
+
+ <https://bugs.webkit.org/show_bug.cgi?id=27083>
+
+ Reviewed by Darin Adler.
+
+ * Scripts/modules/bugzilla.py:
+ (Bugzilla.fetch_bug_ids_from_commit_queue): Use bug_server
+ instead of hard-coding the URL.
+ (Bugzilla.authenticate): Remove extra '/' before URL path.
+ (Bugzilla.add_patch_to_bug): Ditto.
+
+2009-07-08 Brent Fulgham <bfulgham@webkit.org>
+
+ Build fix for Windows Cairo.
+
+ Cairo build was incorrectly #including the PixelDumpSupportCG.h
+ instead of PixelDumpSupportCairo.h
+
+ * DumpRenderTree/win/PixelDumpSupportWin.cpp: Correct #include
+
+2009-07-08 David Faure <faure@kde.org>
+
+ Reviewed by Ariya Hidayat.
+
+ Small documentation improvement for build-webkit --help
+
+ * Scripts/build-webkit: mention --debug option
+
+2009-07-07 Brady Eidson <beidson@apple.com>
+
+ Tiger build fix, work around missing NSString API.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpHistoryItem):
+
+2009-07-07 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27049 - In dumpBackForwardList() mode, DRT should normalize file urls.
+
+ Make the dump of a history item agnostic to the layout of filesystem on the testing machine.
+
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (dumpHistoryItem):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (dumpHistoryItem):
+
+2009-07-07 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Rubber-stamped by Simon Hausmann.
+
+ Correct git url of the Qt test-fonts.
+
+ * DumpRenderTree/qt/main.cpp:
+ (main):
+
+2009-07-07 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ Clear the main frame's name between loading pages, like in r36652. This
+ reduces the side-effects between test cases.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::open):
+
+2009-07-06 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Holger Freyther.
+
+ Fix various layout tests with Qt's DRT.
+
+ Remember to set the focus on the web page before
+ loading.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::DumpRenderTree::open):
+
+2009-07-07 Simon Hausmann <hausmann@webkit.org>
+
+ Reviewed by Tor Arne Vestbø and Holger Freyther.
+
+ Fix timeout timer handling in Qt DRT.
+
+ Use QBasicTimer instead of startTimer/killTimer, to fix the
+ problem that starting the timeout timer did not stop a
+ previously started timer, causing multiple emissions of timeout.
+ The timerEvent() implementation now also checks the timer id, to
+ protect against double timeouts.
+
+ * DumpRenderTree/qt/jsobjects.cpp:
+ (LayoutTestController::LayoutTestController):
+ (LayoutTestController::reset):
+ (LayoutTestController::waitUntilDone):
+ (LayoutTestController::notifyDone):
+ (LayoutTestController::timerEvent):
+ * DumpRenderTree/qt/jsobjects.h:
+
+2009-07-06 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ bugzilla-tool fails to close bugs with bugzilla 3.0
+ https://bugs.webkit.org/show_bug.cgi?id=27008
+
+ Update bugzilla.py to match changes in the bug page "changeform"
+ Update scm.py to add bug_ids to attachments to make error reporting nicer.
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/scm.py:
+
+2009-07-03 Maciej Stachowiak <mjs@apple.com>
+
+ Reviewed by Eric Seidel.
+
+ bugzilla-tool forgot how to obsolete patches
+ https://bugs.webkit.org/show_bug.cgi?id=26951
+
+ * Scripts/modules/bugzilla.py:
+
+2009-07-02 Brent Fulgham <bfulgham@webkit.org>
+
+ Unreviewed build fix (Cairo this time) for DumpRenderTree.
+ Put Cairo code back in, but use original include order
+ for the CG stuff to avoid compile issues.
+
+ * DumpRenderTree/win/PixelDumpSupportWin.cpp:
+ (createBitmapContextFromWebView):
+
+2009-07-02 Eric Seidel <eric@webkit.org>
+
+ Correct blatant typo (missing []), no review.
+
+ * Scripts/modules/scm.py:
+
+2009-07-02 Brent Fulgham <bfulgham@webkit.org>
+
+ Windows build fix, no review.
+
+
+ Reverting PixelDumpSupportWin.cpp change to avoid strange
+ error on the build-bot.
+
+ * DumpRenderTree/win/PixelDumpSupportWin.cpp:
+ (createBitmapContextFromWebView):
+
+2009-07-02 Brent Fulgham <bfulgham@webkit.org>
+
+ Build fix, no review.
+
+ * DumpRenderTree/config.h:
+
+2009-07-02 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ bugzilla-tool needs to handle login failure
+ https://bugs.webkit.org/show_bug.cgi?id=26913
+
+ We now exit(1) on login failure.
+
+ * Scripts/modules/bugzilla.py:
+
+2009-06-30 Brent Fulgham <bfulgham@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ Add build support for a Windows Cairo version of
+ DumpRenderTree. Share as much logic between the
+ CG and Cairo builds as possible.
+ https://bugs.webkit.org/show_bug.cgi?id=26457
+
+ * DumpRenderTree/PixelDumpSupport.cpp: Added.
+ (dumpWebViewAsPixelsAndCompareWithExpected): Moved common logic
+ from CG-specific file.
+ (printPNG): Moved common logic from CG-specific file.
+ * DumpRenderTree/PixelDumpSupport.h: Add declaration for new
+ common printPNG function.
+ * DumpRenderTree/cairo: Added.
+ * DumpRenderTree/cairo/PixelDumpSupportCairo.cpp: Added.
+ Implement cairo-specific logic for dealing with Cairo surfaces.
+ (writeFunction):
+ (printPNG): Cairo-specific PNG handling logic.
+ (computeMD5HashStringForBitmapContext): New Cairo routine using
+ the generic BitmapContext signature.
+ (dumpBitmap): New function containing Cairo-specific portions of
+ the dumping routine.
+ * DumpRenderTree/cairo/PixelDumpSupportCairo.h: Added.
+ Provide Cairo version of the BitmapContext structure so that
+ dumping routines can work on an abstract type.
+ (BitmapContext::createByAdoptingBitmapAndContext):
+ (BitmapContext::~BitmapContext):
+ (BitmapContext::cairoContext):
+ (BitmapContext::BitmapContext):
+ * DumpRenderTree/cg/PixelDumpSupportCG.cpp:
+ (printPNG): CG-specific PNG handling logic.
+ (computeMD5HashStringForBitmapContext): Revised to use generic
+ BitmapContext signature.
+ (dumpBitmap): New function containing CG-specific portions of
+ the dumping routine.
+ * DumpRenderTree/cg/PixelDumpSupportCG.h: Add new signatures.
+ * DumpRenderTree/win/DumpRenderTree.cpp: Disable CFNetwork logic
+ when building the non-CFNetwork version.
+ (main):
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/PixelDumpSupportWin.cpp:
+ (createBitmapContextFromWebView): Provide parallel Cairo implementation
+ of CG bitmap/context setup.
+
+2009-07-02 Eric Seidel <eric@webkit.org>
+
+ No review, just adding Antti as a reviewer.
+
+ * Scripts/modules/bugzilla.py:
+
+2009-07-02 Antonio Gomes <antonio.gomes@openbossa.org>
+
+ Reviewed by Simon Hausmann.
+
+ https://bugs.webkit.org/show_bug.cgi?id=26896
+
+ [Qt] Set DRT's default fontsize to 13.
+
+ * DumpRenderTree/qt/DumpRenderTree.cpp:
+ (WebCore::WebPage::WebPage):
+
+2009-07-01 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Barth.
+
+ bugzilla-tool fails for SVN users
+ https://bugs.webkit.org/show_bug.cgi?id=26914
+
+ To fix this I moved svn from -F - to using -m
+ In order for -m to work I had to move us off of shell=True
+ To move off of shell=True all call sites for run_command
+ which take args, need to pass their args as an list instead of a string.
+
+ In order for the final bug update to work correctly, I had to
+ abstract the way that we parse out revision numbers from the commit text.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/scm.py:
+
+2009-07-01 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ prepare-ChangeLog should have a --bug= argument and use it for url autofill
+ https://bugs.webkit.org/show_bug.cgi?id=26383
+
+ prepare-ChangeLog now knows how to grab the bug title from bugs.webkit.org
+ I also added a bit more template text in an effort to get better ChangeLogs
+ from casual contributers.
+
+ * Scripts/prepare-ChangeLog:
+
+2009-07-01 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Adam Roben.
+
+ prepare-ChangeLog should fail when EMAIL_ADDRESS or REAL_NAME are missing:
+ https://bugs.webkit.org/show_bug.cgi?id=26692
+
+ I also made prepare-ChangeLog sanity-check names and email addresses a little.
+ Names must contain a space, and email addresses must contain '@'
+
+ Also "fixed" $email_address to $emailAddress. This script uses mixed variable name styles.
+
+ * Scripts/prepare-ChangeLog:
+
+2009-07-01 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Beth Dakin.
+
+ Bug 26900: AX: Manual spell check with Command-; does not bring up suggestions
+ https://bugs.webkit.org/show_bug.cgi?id=26900
+
+ Expose the ability to get the click point of an element through accessibility.
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getClickPointXCallback):
+ (getClickPointYCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::clickPointX):
+ (AccessibilityUIElement::clickPointY):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::clickPointX):
+ (AccessibilityUIElement::clickPointY):
+
+2009-07-01 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ Change how WebKitNightlyEnabler.dylib lies about Safari's identity to LaunchServices.
+ This makes WebKit.app behave as expected when set as the default web browser on a wider
+ range of OS versions.
+
+ * WebKitLauncher/WebKitNightlyEnabler.m:
+ (poseAsWebKitApp):
+ (enableWebKitNightlyBehaviour):
+
+2009-07-01 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Simon Fraser.
+
+ Shuffle some code around in preparation for a change to how poseAsWebKitApp works.
+
+ * WebKitLauncher/WebKitNightlyEnabler.m:
+ (systemVersion):
+ (webKitLauncherBundle):
+ (insideSafari4OnTigerTrampoline):
+
+2009-06-30 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Jan Alonzo.
+
+ https://bugs.webkit.org/show_bug.cgi?id=26877
+ [GTK] DRT fixes to pass new plugin test
+
+ Silence compiler warnings.
+
+ Newer GCC don't like using or returning a static string where a
+ 'char*' is expected. Ideally we'd change the function signatures
+ to return or take 'const char*' I suppose, but since we can't do
+ that just cast the strings to 'char*'.
+
+ * DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_get_value):
+
+2009-06-30 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Jan Alonzo.
+
+ https://bugs.webkit.org/show_bug.cgi?id=26877
+ [GTK] DRT fixes to pass new plugin test
+
+ Use the common pluginLog function instead of a local copy.
+
+ * DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance):
+ (webkit_test_plugin_destroy_instance):
+ (webkit_test_plugin_set_window):
+ (webkit_test_plugin_handle_event):
+
+2009-06-30 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Jan Alonzo.
+
+ https://bugs.webkit.org/show_bug.cgi?id=26877
+ [GTK] DRT fixes to pass new plugin test
+
+ Modify our DRT as done in bug #15457 to log logSrc as src in order
+ to pass test plugins/netscape-plugin-map-data-to-src.html.
+
+ * DumpRenderTree/gtk/TestNetscapePlugin/TestNetscapePlugin.cpp:
+ (webkit_test_plugin_new_instance):
+
+2009-06-30 Adrien Nader <camaradetux@gmail.com>
+
+ Reviewed by Jan Alonzo.
+
+ [GTK] GtkLauncher depends on gtk+2-2.15 because of gtk_orientable_set_orientation()
+ https://bugs.webkit.org/show_bug.cgi?id=26835
+
+ * GtkLauncher/main.c:
+ (create_toolbar):
+
+2009-06-30 Eric Seidel <eric@webkit.org>
+
+ Typo fix only, no review.
+
+ Fix typo causing failure during land-diff
+
+ * Scripts/bugzilla-tool:
+
+2009-06-30 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Dan Bernstein.
+
+ Fix drawing of view background in pixel snapshots when using compositing.
+ We still need to call -displayIfNeeded to ensure that the NSView drawing
+ has happened.
+
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (createBitmapContextFromWebView):
+
+2009-06-30 Simon Fraser <simon.fraser@apple.com>
+
+ Reviewed by Mark Rowe.
+
+ createBitmapContextFromWebView() incorrectly used #ifdef BUILDING_ON_LEOPARD,
+ and thus failed on SnowLeopard.
+
+ * DumpRenderTree/mac/PixelDumpSupportMac.mm:
+ (createBitmapContextFromWebView):
+
+2009-06-30 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Nikolas Zimmermann.
+
+ Make bugzilla tool print a message explaining how to get help on failure:
+ https://bugs.webkit.org/show_bug.cgi?id=26861
+
+ % bugzilla-tool
+ Usage: bugzilla-tool [options] command [command-options] [command-arguments]
+
+ bugzilla-tool: error: No command specified
+
+ Type 'bugzilla-tool --help' to see usage.
+
+ * Scripts/bugzilla-tool:
+
+2009-06-30 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Include a built copy of BeautifulSoup 3.1.0.1 so that
+ bugzilla-tool users do not need to install it manually.
+ https://bugs.webkit.org/show_bug.cgi?id=26833
+
+ BeautifulSoup is BSD-licensed (thus WebKit compatible) and available from:
+ http://www.crummy.com/software/BeautifulSoup
+
+ * Scripts/bugzilla-tool: fixed a typo in a log message.
+ * Scripts/modules/BeautifulSoup.py: Added.
+ * Scripts/modules/bugzilla.py:
+
+2009-06-30 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Simon Hausmann.
+
+ Fix our create_patch handling to not
+ hang when creating large patches.
+ https://bugs.webkit.org/show_bug.cgi?id=26834
+
+ We're now using StringIO to make an in-memory buffer for the patch
+ instead of piping from the patch command directly to the upload.
+ The previous hang was caused by calling wait() when the process had already
+ filed the stdout buffer.
+
+ * Scripts/modules/scm.py:
+
+2009-06-29 Sam Weinig <sam@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Remove more unused scons support.
+
+ * Scripts/build-jsc:
+ * Scripts/build-webkit:
+ * Scripts/webkitdirs.pm:
+
+2009-06-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by David Levin.
+
+ Rename land-and-update to land-diff and make it awesome.
+ https://bugs.webkit.org/show_bug.cgi?id=26734
+
+ Renamed land-and-update to land-diff
+ Made the BUGID argument optional.
+ Added optional support for building and testing before landing.
+
+ land-diff [options] [BUGID] Lands the current working directory diff and updates the bug if provided.
+ Options:
+ -r REVIEWER, --reviewer=REVIEWER
+ Update ChangeLogs to say Reviewed by REVIEWER.
+ --no-close Leave bug open after landing.
+ --no-build Commit without building first, implies --no-test.
+ --no-test Commit without running run-webkit-tests.
+
+ * Scripts/bugzilla-tool:
+
+2009-06-28 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Gtk build fix - include stdarg.h for va_start/va_end.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+
+2009-06-28 John Abd-El-Malek <jam@chromium.org>
+
+ https://bugs.webkit.org/show_bug.cgi?id=15457
+
+ Modify NPAPI test plugin to verify that "src" paramater is added when
+ it's missing but "data" is present.
+
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.cpp:
+ (pluginLog):
+ * DumpRenderTree/TestNetscapePlugIn.subproj/PluginObject.h:
+ * DumpRenderTree/TestNetscapePlugIn.subproj/main.cpp:
+ (NPP_New):
+ (NPP_Destroy):
+ (NPP_SetWindow):
+ (handleEventCarbon):
+ (handleEventCocoa):
+ * DumpRenderTree/win/TestNetscapePlugin/main.cpp:
+ (NPP_New):
+
+2009-06-27 Emilio Pozuelo Monfort <pochu27@gmail.com>
+
+ Reviewed by Jan Alonzo.
+
+ [GTK] Don't use deprecated GTK+ symbols.
+ https://bugs.webkit.org/show_bug.cgi?id=26583
+
+ * GtkLauncher/main.c:
+ (create_toolbar):
+
+2009-06-26 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Make SVN work (again?).
+
+ * Scripts/modules/scm.py:
+
+2009-06-26 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Add ability to query isEnabled
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getIsEnabledCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::isEnabled):
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::isEnabled):
+
+2009-06-26 Brady Eidson <beidson@apple.com>
+
+ Reviewed by Sam Weinig
+
+ <rdar://problem/6961578> REGRESSION (r43511): Opening .fdf files from Acrobat Professional fails
+
+ Add a dumpResourceResponseMIMETypes() mode so the ResourceLoadDelegate will dump the mime type from
+ the NSURLResponse. Needed for the test for this bug fix.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (LayoutTestController::LayoutTestController):
+ (dumpResourceResponseMIMETypesCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ (LayoutTestController::dumpResourceResponseMIMETypes):
+ (LayoutTestController::setDumpResourceResponseMIMETypes):
+
+ * DumpRenderTree/mac/ResourceLoadDelegate.mm:
+ (-[ResourceLoadDelegate webView:resource:didReceiveResponse:fromDataSource:]):
+
+2009-06-26 David Kilzer <ddkilzer@apple.com>
+
+ Update build-dumprendertree to use buildXCodeProject()
+
+ Reviewed by Adam Roben.
+
+ * Scripts/build-dumprendertree: Updated to use
+ buildXCodeProject() when building for isAppleMacWebKit(). This
+ provides additional command-line switch parsing for free. Also
+ added --clean and --help switches. Updated copyright.
+
+2009-06-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Remove non-sense --update option to land-patches
+ and make land-patches update before every patch application.
+ This makes it slightly less likely that multi-patch landings will fail.
+
+ Also updated git diff command to include staged modifications.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/scm.py:
+
+2009-06-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Jan Alonzo.
+
+ Fix obsolete_attachment to work when passed a comment.
+ https://bugs.webkit.org/show_bug.cgi?id=26745
+
+ * Scripts/modules/bugzilla.py:
+
+2009-06-25 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ bugzilla-tool apply-patch throws exception in Linux
+ https://bugs.webkit.org/show_bug.cgi?id=26738
+
+ HEAD is case-sensitive in Linux. Convert uses of head to HEAD in
+ the scm module.
+
+ * Scripts/modules/scm.py:
+
+2009-06-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Jan Alonzo.
+
+ bugzilla-tool post-diff needs to obsolete old patches before posting
+ https://bugs.webkit.org/show_bug.cgi?id=26740
+
+ I've also added a --no-obsolete to disable this behavior.
+
+ I also finally updated the bug page parsing to use XML. So much less code!
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/bugzilla.py:
+
+2009-06-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ Call WebKitTools/Scripts scripts by their absolute paths
+ https://bugs.webkit.org/show_bug.cgi?id=26704
+
+ bugzilla-tool used to use whatever build-webkit was in your path.
+ That could end up building the wrong copy of WebKit.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/scm.py:
+
+2009-06-25 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Dave Levin.
+
+ Use unicode() instead of str when reading from bugzilla.
+ Also add Simon Fraser as a reviewer.
+ https://bugs.webkit.org/show_bug.cgi?id=26719
+
+ * Scripts/modules/bugzilla.py:
+
+2009-06-25 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Simon Hausmann.
+
+ Use Q_ASSERT in Qt's DumpRenderTree instead of JSC's ASSERT
+
+ The WTFReportAssertionFailure function in JSC is not exported when
+ building QtWebKit in both debug and release on Mac, so DRT fails to
+ link.
+
+ We can revert this patch once the Qt port builds JSC as a separate
+ library, and we add the proper export macros to Assertions.cpp
+
+ * DumpRenderTree/qt/WorkQueue.cpp:
+ (WorkQueue::queue):
+ (WorkQueue::dequeue):
+
+2009-06-25 Tor Arne Vestbø <tor.arne.vestbo@nokia.com>
+
+ Reviewed by Jan Alonzo.
+
+ bugzilla-tool: Add Simon Hausmann as reviewer
+
+ * Scripts/modules/bugzilla.py:
+
+2009-06-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Dave Levin.
+
+ Support local commits during apply-patches
+ and let land-patches take multiple bug ids.
+ https://bugs.webkit.org/show_bug.cgi?id=26703
+
+ I also restructured parts of land-patches into
+ class methods and static methods in preparation
+ for future code sharing with other commands.
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/scm.py:
+
+2009-06-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Make svn-apply work with Git too
+ https://bugs.webkit.org/show_bug.cgi?id=26299
+
+ Add an --force option to svn-apply and otherwise make svn-apply
+ exit non-zero when patch application fails.
+ https://bugs.webkit.org/show_bug.cgi?id=26300
+
+ I did not update svn-unapply, because it makes no sense in a Git world.
+ You don't roll in and out patch files. You make commits and deal with those.
+ Git users can just git reset --hard to get the same functionality.
+
+ * Scripts/svn-apply:
+
+2009-06-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Remove use of os.system to fix reviewers with unicode chars in their names
+ https://bugs.webkit.org/show_bug.cgi?id=26713
+
+ Also change to latin1 encoding of ø to make python happy.
+
+ * Scripts/modules/bugzilla.py:
+ * Scripts/modules/scm.py:
+
+2009-06-25 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Add Adam Roben and Tor Arne Vestbø to the reviewers list.
+
+ * Scripts/modules/bugzilla.py:
+
+2009-06-24 Chris Fleizach <cfleizach@apple.com>
+
+ Windows build fix.
+
+ * DumpRenderTree/win/AccessibilityUIElementWin.cpp:
+ (AccessibilityUIElement::language):
+
+2009-06-24 Chris Fleizach <cfleizach@apple.com>
+
+ Reviewed by Oliver Hunt.
+
+ Bug 26668: AX: need a way to retrieve the language for an element
+ Support ability to retrieve AXLanguage for testing
+
+ * DumpRenderTree/AccessibilityUIElement.cpp:
+ (getLanguageCallback):
+ (AccessibilityUIElement::getJSClass):
+ * DumpRenderTree/AccessibilityUIElement.h:
+ * DumpRenderTree/mac/AccessibilityUIElementMac.mm:
+ (AccessibilityUIElement::language):
+
+2009-06-24 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Maciej Stachowiak.
+
+ Spell Maciej's name right and add Brady Eidson.
+
+ * Scripts/modules/bugzilla.py:
+
+2009-06-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Dave Levin.
+
+ Fix missing comment message during land-patches and SVN.commit_with_message respecting --dry-run
+ https://bugs.webkit.org/show_bug.cgi?id=26669
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/scm.py:
+
+2009-06-23 Takeshi Yoshino <tyoshino@google.com>
+
+ Reviewed by Mark Rowe.
+
+ Bug 26537: Builds from command-line fail if custom build product directory is set and ~/Library/Preferences/xcodebuild.plist exists
+ https://bugs.webkit.org/show_bug.cgi?id=26537
+
+ Let determineBaseProductDir subroutine remove
+ ~/Library/Preferences/xcodebuild.plist. It can prevent xcodebuild from
+ respecting global settings such as a custom build products directory
+ (<rdar://problem/5585899>).
+
+ * Scripts/webkitdirs.pm:
+
+2009-06-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Dave Levin.
+
+ Make SCM.run_command smarter, and make all previous
+ os.system and subprocess.popen use SCM.run_command instead.
+ https://bugs.webkit.org/show_bug.cgi?id=26666
+
+ This makes it easier to handle errors in a standard way throughout all the code.
+ Since this new code raises by default when the exit_code != 0,
+ we should prevent future problems of bugzilla-tool continuing after
+ a git or svn command failed.
+
+ * Scripts/modules/scm.py:
+
+2009-06-23 Joe Mason <joe.mason@torchmobile.com>
+
+ Reviewed by Adam Treat.
+
+ https://bugs.webkit.org/show_bug.cgi?id=26664
+ * Scripts/prepare-ChangeLog: Added --git-index mode to list only the
+ changes which are already staged in the index. Useful to create an
+ entry for what you're about to commit while ignoring unstaged changes.
+
+2009-06-23 Anders Carlsson <andersca@apple.com>
+
+ Reviewed by Darin Adler.
+
+ Update for WebKit changes.
+
+ * DumpRenderTree/win/UIDelegate.h:
+ (UIDelegate::willPerformDragSourceAction):
+
+2009-06-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/modules/scm.py: Fix commit_with_message to return the commit output.
+
+2009-06-23 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Mark Rowe.
+
+ * Scripts/modules/scm.py: Fix error seen when commiting r44979.
+
+2009-06-18 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Dave Levin.
+
+ WebKit needs a script to interact with bugzilla and automate
+ parts of the patch posting and commit processes.
+ https://bugs.webkit.org/show_bug.cgi?id=26283
+
+ This is really a first-draft tool.
+ It's to the point where it's useful to more people than just me now though.
+ Git support works. SVN support is written, but mostly untested.
+
+ This tool requires BeautifulSoup and mechanize python modules to run:
+ sudo easy_install BeautifulSoup
+ sudo easy_install mechanize
+
+ More important than the tool itself are the Bugzilla, Git and SVN class abstractions
+ which I hope will allow easy writing of future tools.
+
+ The tool currently implements 10 commands, described below.
+
+ Helpers for scripting dealing with the commit queue:
+ bugs-to-commit Bugs in the commit queue
+ patches-to-commit Patches attached to bugs in the commit queue
+
+ Dealing with bugzilla:
+ reviewed-patches BUGID r+'d patches on a bug
+ apply-patches BUGID Applies all patches on a bug to the local working directory without committing.
+ land-and-update BUGID Lands the current working directory diff and updates the bug.
+ land-patches [options] BUGID Lands all patches on a bug optionally testing them first
+ obsolete-attachments BUGID Marks all attachments on a bug as obsolete.
+ commit-message Prints a commit message suitable for the uncommitted changes.
+
+ These effectively replace git-send-bugzilla:
+ post-diff BUGID Attaches the current working directory diff to a bug as a patch file.
+ post-commits BUGID COMMITISH Attaches a range of local commits to a bug as patch files.
+
+ post-diff works for SVN and Git, post-commits only works for SCMs with local-commit support (like Git)
+
+ land-* commands in a Git environment only work with simple patches due to svn-apply bugs:
+ https://bugs.webkit.org/show_bug.cgi?id=26299
+ https://bugs.webkit.org/show_bug.cgi?id=26300
+
+ This script follows python style (similar to how for Obj-C we follow AppKit style)
+ http://www.python.org/doc/essays/styleguide.html
+ The Python community has a strong style culture and the WebKit style guide is silent re: Python.
+
+ I've filed a bug to update the WebKit style guide to mention python:
+ https://bugs.webkit.org/show_bug.cgi?id=26524
+
+ * Scripts/bugzilla-tool: Added.
+
+2009-06-22 Steve Falkenburg <sfalken@apple.com>
+
+ Remove errant line of code mistakenly checked in.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main):
+
+2009-06-22 Steve Falkenburg <sfalken@apple.com>
+
+ Pass correct value to setShouldPaintNativeControls.
+
+ Rubber stamped by Mark Rowe.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main):
+
+2009-06-22 Steve Falkenburg <sfalken@apple.com>
+
+ Fix last DumpRenderTree change to correctly set preferences flag without crashing.
+
+ Reviewed by Mark Rowe.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main):
+
+2009-06-21 Steve Falkenburg <sfalken@apple.com>
+
+ Set up global native controls flag before creating the first WebView.
+
+ Reviewed by Darin Adler.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (main):
+
+2009-06-21 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Set a sensible user agent string for the HTTP requests that Sparkle makes (checking for and downloading updates).
+
+ * WebKitLauncher/WebKitNightlyEnablerSparkle.m:
+ (userAgentStringForSparkle):
+ (initializeSparkle):
+
+2009-06-21 Mark Rowe <mrowe@apple.com>
+
+ Reviewed by Sam Weinig.
+
+ Add a hook to the WebKit launcher application to allow a link on the nightly build start page to
+ trigger an update via the built-in software update mechanism.
+
+ * WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj:
+ * WebKitLauncher/WebKitLauncherURLProtocol.h: Added.
+ * WebKitLauncher/WebKitLauncherURLProtocol.m: Added.
+ (+[WebKitLauncherURLProtocol load]):
+ (+[WebKitLauncherURLProtocol canInitWithRequest:]): Only allow use of the x-webkit-launcher scheme from .webkit.org subdomains.
+ (+[WebKitLauncherURLProtocol canonicalRequestForRequest:]):
+ (-[WebKitLauncherURLProtocol startLoading]):
+ (-[WebKitLauncherURLProtocol stopLoading]):
+ (-[WebKitLauncherURLProtocol handleIsWebKitLauncherAvailableJS]): Return a brief JavaScript snippet that can be used to programatically
+ determine whether the x-webkit-launcher is available and working.
+ (-[WebKitLauncherURLProtocol handleCheckForUpdates]): Trigger a software update on the main thread.
+ (-[WebKitLauncherURLProtocol resourceNotFound]): Fail with a generic "File does not exist" error.
+
+2009-06-20 Jan Michael Alonzo <jmalonzo@webkit.org>
+
+ Reviewed by Gustavo Noronha and Xan Lopez.
+
+ [Gtk] Implement DRT XSS auditor support
+ https://bugs.webkit.org/show_bug.cgi?id=26571
+
+ * DumpRenderTree/gtk/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setXSSAuditorEnabled):
+
+2009-06-19 Darin Adler <darin@apple.com>
+
+ * Scripts/do-webcore-rename: More renaming ideas.
+
+2009-06-15 Andre Pedralho <andre.pedralho@openbossa.org>
+
+ Reviewed by Tor Arne Vestbø.
+
+ Only pass --makeargs along if an argument is given.
+
+ * Scripts/build-webkit:
+
+2009-06-19 Adam Barth <abarth@webkit.org>
+
+ Unreviewed attempt to fix Windows build.
+
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setXSSAuditorEnabled):
+
+2009-06-18 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Sam Weinig.
+
+ https://bugs.webkit.org/show_bug.cgi?id=26199
+
+ Add support for testing the XSSAuditor.
+
+ * DumpRenderTree/LayoutTestController.cpp:
+ (setXSSAuditorEnabledCallback):
+ (LayoutTestController::staticFunctions):
+ * DumpRenderTree/LayoutTestController.h:
+ * DumpRenderTree/gtk/LayoutTestControllerGtk.cpp:
+ (LayoutTestController::setXSSAuditorEnabled):
+ * DumpRenderTree/mac/DumpRenderTree.mm:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/mac/LayoutTestControllerMac.mm:
+ (LayoutTestController::setXSSAuditorEnabled):
+ * DumpRenderTree/win/DumpRenderTree.cpp:
+ (resetWebViewToConsistentStateBeforeTesting):
+ * DumpRenderTree/win/LayoutTestControllerWin.cpp:
+ (LayoutTestController::setXSSAuditorEnabled):
+ (LayoutTestController::setPopupBlockingEnabled):
+ * DumpRenderTree/wx/LayoutTestControllerWx.cpp:
+ (LayoutTestController::setXSSAuditorEnabled):
+
+2009-06-18 Darin Adler <darin@apple.com>
+
+ Rubber stamped by Mark Rowe.
+
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ (-[DumpRenderTreeWindow close]): Resolved crashes seen during regression
+ tests. The close method can be called on a window that's already closed
+ so we can't assert here.
+
+2009-06-17 Steve Falkenburg <sfalken@apple.com>
+
+ Updated for consolidated WebKit COM interfaces.
+
+ Reviewed by Adam Roben.
+
+ * DumpRenderTree/win/FrameLoadDelegate.cpp:
+ * DumpRenderTree/win/FrameLoadDelegate.h:
+ * DumpRenderTree/win/UIDelegate.cpp:
+ * DumpRenderTree/win/UIDelegate.h:
+ * WinLauncher/WinLauncher.h:
+
+2009-06-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=26437
+
+ Make the commit-log-editor match the ambient line endings in commit
+ messages.
+
+ * Scripts/commit-log-editor:
+
+2009-06-16 Xan Lopez <xlopez@igalia.com>
+
+ Reviewed by Gustavo Noronha.
+
+ Update GtkLauncher to recent API changes in the progress property,
+ which now goes from 0.0 to 1.0.
+
+ * GtkLauncher/main.c:
+
+2009-06-16 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Darin Adler.
+
+ https://bugs.webkit.org/show_bug.cgi?id=26000
+
+ Teach prepare-ChangeLog to match the line ends that are already present
+ in ChangeLog files. This helps folks whose use cygwin perl with CR LF
+ line endings on Windows.
+
+ Also, teach prepare-ChangeLog to normalize backslashes in paths. This
+ helps folks who use Windows SVN prepare correct ChangeLogs.
+
+ * Scripts/prepare-ChangeLog:
+
+== Rolled over to ChangeLog-2009-06-16 ==
diff --git a/Tools/CodeCoverage/README b/Tools/CodeCoverage/README
new file mode 100644
index 0000000..7a85527
--- /dev/null
+++ b/Tools/CodeCoverage/README
@@ -0,0 +1,22 @@
+Generate coverage on Mac
+
+call Tools/Script/generate-coverage-data
+
+or by hand
+
+
+# delete
+find . -name '*.gcda' -delete
+
+# build, -framework CoreFoundation might suffice as well
+Tools/Scripts/build-webkit GCC_GENERATE_TEST_COVERAGE_FILES=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES EXTRA_LINK=" -ftest-coverage -fprofile-arcs" OTHER_CFLAGS=" -MD " OTHER_LDFLAGS=" -ftest-coverage -fprofile-arcs -framework AppKit"
+Tools/Scripts/run-webkit-tests
+Tools/Scripts/run-javascriptcore-tests GCC_GENERATE_TEST_COVERAGE_FILES=YES GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES EXTRA_LINK=" -ftest-coverage -fprofile-arcs" OTHER_CFLAGS=" -MD " OTHER_LDFLAGS=" -ftest-coverage -fprofile-arcs -framework AppKit"
+
+
+# Collect files
+Tools/CodeCoverage/run-generate-coverage-data <RUN_ID> ../coverage-results/
+
+
+# Generate graph
+Tools/CodeCoverage/regenerate-coverage-display ../coverage-results/ ../coverage-results/html
diff --git a/Tools/CodeCoverage/amber.png b/Tools/CodeCoverage/amber.png
new file mode 100644
index 0000000..ee5d920
--- /dev/null
+++ b/Tools/CodeCoverage/amber.png
Binary files differ
diff --git a/Tools/CodeCoverage/cov.py b/Tools/CodeCoverage/cov.py
new file mode 100644
index 0000000..443e601
--- /dev/null
+++ b/Tools/CodeCoverage/cov.py
@@ -0,0 +1,201 @@
+# Copyright (C) 2004, 2005, 2006 Nathaniel Smith
+# Copyright (C) 2006, 2007 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.
+
+import csv
+import time
+import os.path
+import shutil
+
+def analyze_coverage(possible_gcov_files, source_files, runid, data_dir, base):
+
+ if not os.path.exists(data_dir):
+ os.makedirs(data_dir)
+
+ output = open(os.path.join(data_dir, runid + ".csv"), "w")
+ w = csv.writer(output)
+ # First row: id and time
+ w.writerow([runid, time.time()])
+
+ results = scan_gcov_files(possible_gcov_files, source_files)
+ annotated_dir = os.path.join(data_dir, runid + ".annotated")
+ if os.path.exists(annotated_dir):
+ shutil.rmtree(annotated_dir)
+
+ keys = results.keys()
+ keys.sort()
+ for path in keys:
+ (total, covered, annotated_data) = results[path]
+ path = path[path.find(base)+len(base):]
+ # Rest of the rows: filename, total_lines, covered_lines
+ w.writerow([path, total, covered])
+
+ if path[:1] == "/":
+ path = path[1:]
+ annotated_path = os.path.join(annotated_dir, path)
+ try:
+ os.makedirs(os.path.dirname(annotated_path))
+ except OSError:
+ pass
+ a = open(annotated_path, "w")
+ a.write(annotated_data)
+ a.close()
+
+
+# zecke's rewrite
+STATE_NOT_CODE = -1
+STATE_NOT_SEEN = -2
+STATE_TEST_CODE = -3
+
+def find_gcov(f, possible_gcovs):
+ """
+ Find .gcov files that could be of interest for us
+ """
+ try:
+ return possible_gcovs[f]
+ except:
+ return []
+
+
+def parse_source_file(file):
+ """
+ Parse one source file and return a list of lines
+ """
+ f_source_list = []
+ init_state = STATE_NOT_SEEN
+ in_test_code = False
+ nesting = 0
+
+ for line in open(file, "r"):
+ code = line.split(":", 2)[-1]
+ if not in_test_code and code.startswith("#ifdef BUILD_UNIT_TESTS"):
+ in_test_code = 1
+ if in_test_code and code.startswith("#if"):
+ nesting += 1
+ if in_test_code and code.startswith("#endif"):
+ nesting -= 1
+ if not nesting:
+ in_test_code = True
+ if in_test_code:
+ init_state = STATE_TEST_CODE
+ else:
+ init_state = STATE_NOT_SEEN
+ f_source_list.append([init_state, line.split(":", 1)[1]])
+
+ return f_source_list
+
+# Runner-up, 3rd annual "write Python that looks like Perl" competition,
+# Well, not really. It doesn't even use regexps.
+# He is right so I'm cleaning it up (zecke)
+def scan_gcov_files(possible_gcov_files, source_files):
+ """Takes a list of gcov filenames and a list of source filenames.
+
+ The gcov files should have names of the form foo.o##foo.cc.gcov, as
+ created by 'gcov -l'.
+
+ Returns a dict mapping source filenames to tuples
+ (total_lines, tested_lines, gcov_annotated_source)
+ which are a number, a number, and a very long string, respectively.
+
+ The fun bit is that we merge .gcov output generated by different object
+ files; this way we can provide accurate information for header files and
+ for monotone's current unit test system."""
+ results = {}
+ for f in source_files:
+ possible_gcovs = find_gcov(f, possible_gcov_files)
+ base_name = os.path.splitext(os.path.basename(f))[0]
+ if len(possible_gcovs) == 0:
+ print "No gcov files found for: '%s' but it was compiled" % f
+ continue
+
+ (garbage,extension) = os.path.splitext(f)
+ if extension in [".cc", ".c", ".moc", ".cpp", ".cxx", ".m", ".mm"]:
+ lines = open(f, "r").readlines()
+ results[f] = (len(lines), 0, "".join(lines))
+ continue
+ elif len(possible_gcovs) > 1:
+ print "More than one gcov file for %s %d" % (f,len(possible_gcovs))
+ base_gcov_lines = parse_source_file(possible_gcovs[0])
+
+ # Now we will try hard to merge the results with others
+ # Our requirement is that we have the same amount of lines as
+ # as the original file
+ for cov_file in possible_gcovs:
+ lines = open(cov_file, "r").readlines()
+
+ # e.g. with phonon we have visualisation.h and we can not know
+ # which header file (foldername) it is refering to. This is a gcov
+ # limitation and i have no workaround yet. We just hope we will pick
+ # the right header file...
+ if len(lines) != len(base_gcov_lines):
+ print "Error Base: %s and Target: %s have different amount of lines" % (possible_gcovs[0],cov_file)
+ continue
+
+ # now do the merging of the file. If it has the same basename
+ # and the same number of lines things might work out
+ # In the future take a look at the header of the file
+ i = 0
+ for line in lines:
+ accumulator = base_gcov_lines[i]
+ if accumulator[0] != STATE_TEST_CODE:
+ info = line.split(":", 1)[0]
+ if info.endswith("-"):
+ if accumulator[0] == STATE_NOT_SEEN:
+ accumulator[0] = STATE_NOT_CODE
+ else:
+ if info.endswith("#"):
+ num = 0
+ else:
+ num = int(info)
+ if accumulator[0] in (STATE_NOT_SEEN, STATE_NOT_CODE):
+ accumulator[0] = 0
+ accumulator[0] += num
+ i += 1
+
+ # post processing of ths file
+ (total_lines, total_covered) = (0, 0)
+ annotated_lines = []
+ for state, line in base_gcov_lines:
+ if state == STATE_NOT_SEEN:
+ desc = "?????"
+ elif state == STATE_TEST_CODE:
+ desc = "+"
+ elif state == STATE_NOT_CODE:
+ desc = "-"
+ elif state == 0:
+ desc = "#####"
+ total_lines += 1
+ else:
+ desc = str(state)
+ total_lines += 1
+ total_covered += 1
+ annotated_lines.append(":".join([desc.rjust(9), line]))
+ results[f] = (total_lines, total_covered, "".join(annotated_lines))
+ return results
+
+
+
+ return results
diff --git a/Tools/CodeCoverage/emerald.png b/Tools/CodeCoverage/emerald.png
new file mode 100644
index 0000000..0e60294
--- /dev/null
+++ b/Tools/CodeCoverage/emerald.png
Binary files differ
diff --git a/Tools/CodeCoverage/gcov.css b/Tools/CodeCoverage/gcov.css
new file mode 100644
index 0000000..71ca080
--- /dev/null
+++ b/Tools/CodeCoverage/gcov.css
@@ -0,0 +1,116 @@
+body {
+ color: black; background-color: white;
+ font-family: Helvetica,Arial,sans-serif;
+ margin: 0; padding: 0em;
+ text-align: center;
+}
+
+.title {
+ text-align:center;
+ font-weight:bold;
+ font-style:italic;
+ font-size:1.8em;
+ padding:10px;
+}
+
+.ruler {
+ height:3px;
+ background-color:#638AD6;
+ margin-left:10px;
+ margin-right:10px;
+}
+
+.headerItem {
+ text-align:right;
+ font-weight:bold;
+}
+
+.headerValue {
+ text-align:left;
+ font-weight:bold;
+ color:#638AD6;
+}
+
+.tableHead {
+ text-align:center;
+ font-weight:bold;
+ background-color:#638AD6;
+ color:white;
+
+}
+
+.coverFile {
+ font-family: Courier;
+ background-color:#DEE7FF;
+ padding:3px;
+ width:70%;
+}
+
+.coverBar {
+ background-color:#DEE7FF;
+ padding:3px;
+ width:5%;
+}
+
+.coverBarOutline {
+}
+
+.coverPerHi {
+ font-family: Times;
+ text-align:center;
+ font-weight:bold;
+ background-color:lightgreen;
+ padding:3px;
+ width:5%;
+}
+
+.coverNumHi {
+ font-family: Times;
+ text-align:right;
+ background-color:lightgreen;
+ padding:3px;
+ width:25%;
+}
+
+.coverPerMed {
+ font-family: Times;
+ text-align:center;
+ font-weight:bold;
+ background-color:yellow;
+ padding:3px;
+}
+
+.coverNumMed {
+ font-family: Times;
+ text-align:right;
+ background-color:yellow;
+ padding:3px;
+}
+
+.coverPerLo {
+ font-family: Times;
+ text-align:center;
+ font-weight:bold;
+ background-color:red;
+ padding:3px;
+}
+
+.coverNumLo {
+ font-family: Times;
+ text-align:right;
+ background-color:red;
+ padding:3px;
+}
+
+.lineNum {
+ background-color:#EFE384;
+}
+
+.lineCov {
+ background-color:#CED7FF;
+}
+
+.lineNoCov {
+ background-color:#FF6131;
+}
+
diff --git a/Tools/CodeCoverage/glass.png b/Tools/CodeCoverage/glass.png
new file mode 100644
index 0000000..a4ba373
--- /dev/null
+++ b/Tools/CodeCoverage/glass.png
Binary files differ
diff --git a/Tools/CodeCoverage/regenerate-coverage-display b/Tools/CodeCoverage/regenerate-coverage-display
new file mode 100755
index 0000000..c25b412
--- /dev/null
+++ b/Tools/CodeCoverage/regenerate-coverage-display
@@ -0,0 +1,382 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2004, 2005, 2006 Nathaniel Smith
+# Copyright (C) 2007 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.
+
+#
+# HTML output inspired by the output of lcov as found on the GStreamer
+# site. I assume this is not copyrightable.
+#
+
+
+#
+# Read all CSV files and
+# Create an overview file
+#
+#
+
+
+import sys
+import csv
+import glob
+import time
+import os
+import os.path
+import datetime
+import shutil
+
+os.environ["TTFPATH"] = ":".join(["/usr/share/fonts/truetype/" + d
+ for d in "ttf-bitstream-vera",
+ "freefont",
+ "msttcorefonts"])
+
+level_LOW = 10
+level_MEDIUM = 70
+
+def copy_files(dest_dir):
+ """
+ Copy the CSS and the png's to the destination directory
+ """
+ images = ["amber.png", "emerald.png", "glass.png", "ruby.png", "snow.png"]
+ css = "gcov.css"
+ (base_path, name) = os.path.split(__file__)
+ base_path = os.path.abspath(base_path)
+
+ shutil.copyfile(os.path.join(base_path,css), os.path.join(dest_dir,css))
+ map(lambda x: shutil.copyfile(os.path.join(base_path,x), os.path.join(dest_dir,x)), images)
+
+def sumcov(cov):
+ return "%.2f%% (%s/%s)" % (cov[1] * 100.0 / (cov[0] or 1), cov[1], cov[0])
+
+def create_page(dest_dir, name):
+ index = open(os.path.join(dest_dir, name), "w")
+ index.write("""<HTML>
+ <HEAD>
+ <TITLE>WebKit test coverage information</TITLE>
+ <link rel="stylesheet" type="text/css" href="gcov.css">
+ </HEAD>
+ <BODY>
+ """)
+ return index
+
+def generate_header(file, last_time, total_lines, total_executed, path, image):
+ product = "WebKit"
+ date = time.strftime("%Y-%m-%d %H:%M:%S", time.gmtime(last_time))
+ covered_lines = sumcov((total_lines, total_executed))
+
+ file.write("""<table width="100%%" border=0 cellspacing=0 cellpadding=0>
+ <tr><td class="title">GCOV code coverage report</td></tr>
+ <tr><td class="ruler"><img src="glass.png" width=3 height=3 alt=""></td></tr>
+
+ <tr>
+ <td width="100%%">
+ <table cellpadding=1 border=0 width="100%%">
+ <tr>
+ <td class="headerItem" width="20%%">Current&nbsp;view:</td>
+ <td class="headerValue" width="80%%" colspan=4>%(path)s</td>
+ </tr>
+ <tr>
+ <td class="headerItem" width="20%%">Test:</td>
+ <td class="headerValue" width="80%%" colspan=4>%(product)s</td>
+ </tr>
+ <tr>
+ <td class="headerItem" width="20%%">Date:</td>
+ <td class="headerValue" width="20%%">%(date)s</td>
+ <td width="20%%"></td>
+ <td class="headerItem" width="20%%">Instrumented&nbsp;lines:</td>
+ <td class="headerValue" width="20%%">%(total_lines)s</td>
+ </tr>
+ <tr>
+ <td class="headerItem" width="20%%">Code&nbsp;covered:</td>
+ <td class="headerValue" width="20%%">%(covered_lines)s</td>
+ <td width="20%%"></td>
+ <td class="headerItem" width="20%%">Executed&nbsp;lines:</td>
+ <td class="headerValue" width="20%%">%(total_executed)s</td>
+ </tr>
+ </table>
+ </td>
+ </tr>
+ <tr><td class="ruler"><img src="glass.png" width=3 height=3 alt=""></td></tr>
+ </table>""" % vars())
+ # disabled for now <tr><td><img src="%(image)s"></td></tr>
+
+def generate_table_item(file, name, total_lines, covered_lines):
+ covered_precise = (covered_lines*100.0)/(total_lines or 1.0)
+ covered = int(round(covered_precise))
+ remainder = 100-covered
+ (image,perClass,numClass) = coverage_icon(covered_precise)
+ site = "%s.html" % name.replace(os.path.sep,'__')
+ file.write("""
+ <tr>
+ <td class="coverFile"><a href="%(site)s">%(name)s</a></td>
+ <td class="coverBar" align="center">
+ <table border=0 cellspacing=0 cellpadding=1><tr><td class="coverBarOutline"><img src="%(image)s" width=%(covered)s height=10 alt="%(covered_precise).2f"><img src="snow.png" width=%(remainder)s height=10 alt="%(covered_precise).2f"></td></tr></table>
+ </td>
+ <td class="%(perClass)s">%(covered_precise).2f&nbsp;%%</td>
+ <td class="%(numClass)s">%(covered_lines)s&nbsp;/&nbsp;%(total_lines)s&nbsp;lines</td>
+ </tr>
+ """ % vars())
+
+def generate_table_header_start(file):
+ file.write("""<center>
+ <table width="80%%" cellpadding=2 cellspacing=1 border=0>
+
+ <tr>
+ <td width="50%%"><br></td>
+ <td width="15%%"></td>
+ <td width="15%%"></td>
+ <td width="20%%"></td>
+ </tr>
+
+ <tr>
+ <td class="tableHead">Directory&nbsp;name</td>
+ <td class="tableHead" colspan=3>Coverage</td>
+ </tr>
+ """)
+
+def coverage_icon(percent):
+ if percent < level_LOW:
+ return ("ruby.png", "coverPerLo", "coverNumLo")
+ elif percent < level_MEDIUM:
+ return ("amber.png", "coverPerMed", "coverNumMed")
+ else:
+ return ("emerald.png", "coverPerHi", "coverNumHi")
+
+def replace(text, *pairs):
+ """
+ From pydoc... almost identical at least
+ """
+ from string import split, join
+ while pairs:
+ (a,b) = pairs[0]
+ text = join(split(text, a), b)
+ pairs = pairs[1:]
+ return text
+
+def escape(text):
+ """
+ Escape string to be conform HTML
+ """
+ return replace(text,
+ ('&', '&amp;'),
+ ('<', '&lt;' ),
+ ('>', '&gt;' ) )
+
+def generate_table_header_end(file):
+ file.write("""</table>
+ </center>""")
+
+def write_title_page(dest_dir, last_time, last_tot_lines, last_tot_covered, dir_series):
+ """
+ Write the index.html with a overview of each directory
+ """
+ index= create_page(dest_dir, "index.html")
+ generate_header(index, last_time, last_tot_lines, last_tot_covered, "directory", "images/Total.png")
+ # Create the directory overview
+ generate_table_header_start(index)
+ dirs = dir_series.keys()
+ dirs.sort()
+ for dir in dirs:
+ (dir_files, total_lines, covered_lines,_) = dir_series[dir][-1]
+ generate_table_item(index, dir, total_lines, covered_lines)
+ generate_table_header_end(index)
+
+ index.write("""</BODY></HTML>""")
+ index.close()
+
+def write_directory_site(dest_dir, dir_name, last_time, dir_series, file_series):
+ escaped_dir = dir_name.replace(os.path.sep,'__')
+ site = create_page(dest_dir, "%s.html" % escaped_dir)
+ (_,tot_lines,tot_covered,files) = dir_series[dir_name][-1]
+ generate_header(site, last_time, tot_lines, tot_covered, "directory - %s" % dir_name, "images/%s.png" % escaped_dir)
+
+ files.sort()
+
+ generate_table_header_start(site)
+ for file in files:
+ (lines,covered) = file_series[file][-1]
+ generate_table_item(site, file, lines, covered)
+
+ generate_table_header_end(site)
+ site.write("""</BODY></HTML>""")
+ site.close()
+
+def write_file_site(dest_dir, file_name, last_time, data_dir, last_id, file_series):
+ escaped_name = file_name.replace(os.path.sep,'__')
+ site = create_page(dest_dir, "%s.html" % escaped_name)
+ (tot_lines,tot_covered) = file_series[file_name][-1]
+ generate_header(site, last_time, tot_lines, tot_covered, "file - %s" % file_name, "images/%s.png" % escaped_name)
+
+ path = "%s/%s.annotated%s" % (data_dir,last_id,file_name)
+
+ # In contrast to the lcov we want to show files that have been compiled
+ # but have not been tested at all. This means we have sourcefiles with 0
+ # lines covered in the path but they are not lcov files.
+ # To identify them we check the first line now. If we see that we can
+ # continue
+ # -: 0:Source:
+ try:
+ file = open(path, "r")
+ except:
+ return
+ all_lines = file.read().split("\n")
+
+ # Convert the gcov file to HTML if we have a chanche to do so
+ # Scan each line and see if it was covered or not and escape the
+ # text
+ if len(all_lines) == 0 or not "-: 0:Source:" in all_lines[0]:
+ site.write("<p>The file was not excercised</p>")
+ else:
+ site.write("""</br><table cellpadding=0 cellspacing=0 border=0>
+ <tr>
+ <td><br></td>
+ </tr>
+ <tr>
+ <td><pre class="source">
+ """)
+ for line in all_lines:
+ split_line = line.split(':',2)
+ # e.g. at the EOF
+ if len(split_line) == 1:
+ continue
+ line_number = split_line[1].strip()
+ if line_number == "0":
+ continue
+ covered = 15*" "
+ end = ""
+ if "#####" in split_line[0]:
+ covered = '<span class="lineNoCov">%15s' % "0"
+ end = "</span>"
+ elif split_line[0].strip() != "-":
+ covered = '<span class="lineCov">%15s' % split_line[0].strip()
+ end = "</span>"
+
+ escaped_line = escape(split_line[2])
+ str = '<span class="lineNum">%(line_number)10s </span>%(covered)s: %(escaped_line)s%(end)s\n' % vars()
+ site.write(str)
+ site.write("</pre></td></tr></table>")
+ site.write("</BODY></HTML>")
+ site.close()
+
+def main(progname, args):
+ if len(args) != 2:
+ sys.exit("Usage: %s DATADIR OUTDIR" % progname)
+
+ branch = "WebKit from trunk"
+ datadir, outdir = args
+
+ # First, load in all data from the data directory.
+ data = []
+ for datapath in glob.glob(os.path.join(datadir, "*.csv")):
+ data.append(read_csv(datapath))
+ # Sort by time
+ data.sort()
+
+ # Calculate time series for each file.
+ times = [sample[0] for sample in data]
+ times = [datetime.datetime.utcfromtimestamp(t) for t in times]
+
+ all_files = {}
+ all_dirs = {}
+ for sample in data:
+ t, i, tot_line, tot_cover, per_file, per_dir = sample
+ all_files.update(per_file)
+ all_dirs.update(per_dir)
+ total_series = []
+ file_serieses = dict([[k, [(0, 0)] * len(times)] for k in all_files.keys()])
+ dir_serieses = dict([[k, [(0, 0, 0, [])] * len(times)] for k in all_dirs.keys()])
+ data_idx = 0
+ for sample in data:
+ t, i, tot_line, tot_cover, per_file, per_dir = sample
+ total_series.append([tot_line, tot_cover])
+ for f, covinfo in per_file.items():
+ file_serieses[f][data_idx] = covinfo
+ for f, covinfo in per_dir.items():
+ dir_serieses[f][data_idx] = covinfo
+ data_idx += 1
+
+
+ # Okay, ready to start outputting. First make sure our directories
+ # exist.
+ if not os.path.exists(outdir):
+ os.makedirs(outdir)
+ rel_imgdir = "images"
+ imgdir = os.path.join(outdir, rel_imgdir)
+ if not os.path.exists(imgdir):
+ os.makedirs(imgdir)
+
+
+ # And look up the latest revision id, and coverage information
+ last_time, last_id, last_tot_lines, last_tot_covered = data[-1][:4]
+
+ # Now start generating our html file
+ copy_files(outdir)
+ write_title_page(outdir, last_time, last_tot_lines, last_tot_covered, dir_serieses)
+
+ dir_keys = dir_serieses.keys()
+ dir_keys.sort()
+ for dir_name in dir_keys:
+ write_directory_site(outdir, dir_name, last_time, dir_serieses, file_serieses)
+
+ file_keys = file_serieses.keys()
+ for file_name in file_keys:
+ write_file_site(outdir, file_name, last_time, datadir, last_id, file_serieses)
+
+def read_csv(path):
+ r = csv.reader(open(path, "r"))
+ # First line is id, time
+ for row in r:
+ id, time_str = row
+ break
+ time = int(float(time_str))
+ # Rest of lines are path, total_lines, covered_lines
+ per_file = {}
+ per_dir = {}
+ grand_total_lines, grand_covered_lines = 0, 0
+ for row in r:
+ path, total_lines_str, covered_lines_str = row
+ total_lines = int(total_lines_str)
+ covered_lines = int(covered_lines_str)
+ grand_total_lines += total_lines
+ grand_covered_lines += covered_lines
+ per_file[path] = [total_lines, covered_lines]
+
+ # Update dir statistics
+ dirname = os.path.dirname(path)
+ if not dirname in per_dir:
+ per_dir[dirname] = (0,0,0,[])
+ (dir_files,dir_total_lines,dir_covered_lines, files) = per_dir[dirname]
+ dir_files += 1
+ dir_total_lines += total_lines
+ dir_covered_lines += covered_lines
+ files.append(path)
+ per_dir[dirname] = (dir_files,dir_total_lines,dir_covered_lines,files)
+ return [time, id, grand_total_lines, grand_covered_lines, per_file, per_dir]
+
+if __name__ == "__main__":
+ import sys
+ main(sys.argv[0], sys.argv[1:])
diff --git a/Tools/CodeCoverage/ruby.png b/Tools/CodeCoverage/ruby.png
new file mode 100644
index 0000000..a582d35
--- /dev/null
+++ b/Tools/CodeCoverage/ruby.png
Binary files differ
diff --git a/Tools/CodeCoverage/run-generate-coverage-data b/Tools/CodeCoverage/run-generate-coverage-data
new file mode 100755
index 0000000..a87da1d
--- /dev/null
+++ b/Tools/CodeCoverage/run-generate-coverage-data
@@ -0,0 +1,240 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2004, 2005, 2006 Nathaniel Smith
+# Copyright (C) 2007 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.
+
+import os, sys
+
+# from BitBake
+def mkdirhier(dir):
+ """Create a directory like 'mkdir -p', but does not complain if
+ directory already exists like os.makedirs
+ """
+ try:
+ os.makedirs(dir)
+ except OSError, e:
+ if e.errno != 17: raise e
+
+def collect_base(src,match_array):
+ """
+ Collect all files that match the match_array.
+ """
+
+ sources = []
+ for root, dirs, files in os.walk(src):
+ if ".svn" in root:
+ continue
+
+ for file in files:
+ base,ext = os.path.splitext(file)
+ if ext in match_array:
+ sources.append( os.path.join(root, file) )
+
+ return sources
+
+def collect_depends(src):
+ return collect_base(src, [".d"])
+
+def parse_dependency_file(src, base_dir, black_list):
+ """
+ Parse the .d files of the gcc
+
+ Wow, the first time os.path.join is doing the right thing. We might
+ have a relative path in the depends using os.path.join(dirname of .d, dep)
+ we will end up in
+ """
+ file = open(src)
+ file = file.read()
+ file = file.replace('\\', '').replace('\n', '')
+
+ # We now have object: dependencies splitted
+ ar = file.split(':', 1)
+ obj = ar[0].strip()
+ dir = os.path.dirname(obj)
+ deps = ar[1].split(' ')
+
+ # Remove files outside WebKit, make path absolute
+ deps = filter(lambda x: base_dir in x, deps)
+ deps = map(lambda x: os.path.abspath(os.path.join(dir, x)), deps)
+ return (obj, dir, deps)
+
+def collect_cov(base_path,targets):
+ """
+ Collect gcov files, collect_sources is not used as it also creates
+ dirs and needs to do substituting.
+ Actually we will build a mapping from source file to gcov files of
+ interest. This is because we could have bytestream.h in many different
+ subdirectories. And we would endup with bla.cpp##bytestream.h and we
+ do not know which bytestream file was tested
+ """
+ def find_source_file(root,cov_file):
+ """ Find a Source line or crash
+
+ '#Users#ich#projekte#src#threadmessage.cpp###space#dports#include#qt3#qstring.h.gcov'
+ '#Users#ich#projekte#src#threadmessage.cpp##..#^#src#threadmessage.cpp.gcov'
+
+ ### is absolute path
+ ##..#^# is relative path... well a gcov bug as well
+ ## normal split file in the same directory
+ """
+ if '###' in cov_file:
+ split = cov_file.split('###')
+ if not len(split) == 2:
+ raise "Unexpected split result"
+ filepath = split[1][:-5].replace('#',os.path.sep)
+ return os.path.join(os.path.sep,filepath)
+ elif '##..#^#' in cov_file:
+ split = cov_file.split('##..#^#')
+ if not len(split) == 2:
+ raise "Unexpected split result"
+ filepath = split[1][:-5].replace('#',os.path.sep)
+ return os.path.abspath(os.path.join(root,os.path.pardir,os.path.pardir,filepath))
+ elif '##' in cov_file:
+ split = cov_file.split('##')
+ if not len(split) == 2:
+ raise "Unexpected split result"
+ filepath = split[1][:-5].replace('#',os.path.sep)
+ return os.path.abspath(os.path.join(root,filepath))
+ elif '#' in cov_file:
+ # wow a not broken gcov on OSX
+ basename=os.path.basename(cov_file).replace('#',os.path.sep)[:-5]
+ return os.path.abspath(os.path.join(root,basename))
+
+ else:
+ raise "No source found %s" % cov_file
+
+ def sanitize_path(path):
+ """
+ Well fix up paths once again /usr/lib/gcc/i486-linux-gnu/4.1.2/^/^/^/^/include/c++/4.1.2/bits/stl_pair.h
+ according to gcov '^' is a relative path, we will now build one from this one. Somehow it depends
+ on the gcov version if .. really gets replaced to ^....
+ """
+ import os
+ split = path.split(os.path.sep)
+ str = ""
+ for part in split:
+ if part == '':
+ str = os.path.sep
+ elif part == '^':
+ str = "%s..%s" % (str,os.path.sep)
+ else:
+ str = "%s%s%s" % (str,part,os.path.sep)
+ return os.path.abspath(str)
+
+
+ gcov = {}
+ for root, dirs, files in os.walk(base_path):
+ if ".svn" in root:
+ continue
+ for file in files:
+ base,ext = os.path.splitext(file)
+ if ext in [".gcov"]:
+ try:
+ cov = os.path.join(root, file)
+ src = find_source_file( root, cov )
+ src = sanitize_path( src )
+
+ if not src in gcov:
+ gcov[src] = []
+ gcov[src].append( cov )
+ except Exception,e:
+ print "Exception on ", e
+ #import sys
+ #sys.exit(0)
+ pass
+
+ #print gcov
+ return gcov
+
+def generate_covs(candidates):
+ """
+ Generate gcov files in the right directory
+
+ candidtaes contains the directories we have used when
+ building. Each directory contains a set of files we will
+ try to generate gcov files for.
+ """
+ print candidates.keys()
+ for dir in candidates.keys():
+ print "Trying in %s" % (dir)
+ for dep in candidates[dir].keys():
+ cmd = "cd %s; gcov -p -l %s" % (dir, dep)
+ os.system("%s > /dev/null 2>&1 " % cmd)
+
+
+def analyze_coverage(sources,data,dirs,runid,base):
+ """
+ sources actual source files relative to src_dir e.g kdelibs/kdecore/klibloader.cpp
+ data Where to put the stuff
+ dirs Where to take a look for gcov files
+ base The base directory for files. All files not inside base will be ignored
+ """
+ import cov
+ print base
+ gcov = collect_cov(base,dirs)
+ result = cov.analyze_coverage(gcov, sources, runid, data, base)
+ print result
+
+if __name__ == "__main__":
+ #global targets
+ if not len(sys.argv) == 3:
+ print "This script needs three parameters"
+ print "Call it with generate_cov RUNID ResultsDir"
+ sys.exit(-1)
+ runid = sys.argv[1]
+ results = sys.argv[2]
+
+ # create directories for out result
+ mkdirhier(results)
+
+ print "Collection Sources and preparing data tree"
+ base_dir = os.path.abspath(os.path.curdir)
+ depends = collect_depends(base_dir)
+ candidates = map(lambda x: parse_dependency_file(x,base_dir,[]), depends)
+
+ # Build a number of sources from the candidates. This is a Set for the poor
+ # Two level dict. One for
+ dirs = {}
+ files = {}
+ for (_,dir,deps) in candidates:
+ if not dir in dirs:
+ dirs[dir] = {}
+ for dep in deps:
+ if not dep in dirs[dir]:
+ dirs[dir][dep] = dep
+ if not dep in files:
+ files[dep] = dep
+
+ sources = files.keys()
+
+ print "Found %d candidates" % (len(sources))
+ print "Will run inefficient generation of gcov files now"
+ generate_covs(dirs)
+
+ print "Analyzing Gcov"
+ analyze_coverage(sources, results, dirs.keys(), runid, base_dir)
+ print "Done"
diff --git a/Tools/CodeCoverage/snow.png b/Tools/CodeCoverage/snow.png
new file mode 100644
index 0000000..a4ba373
--- /dev/null
+++ b/Tools/CodeCoverage/snow.png
Binary files differ
diff --git a/Tools/CygwinDownloader/cygwin-downloader.py b/Tools/CygwinDownloader/cygwin-downloader.py
new file mode 100644
index 0000000..d87e0da
--- /dev/null
+++ b/Tools/CygwinDownloader/cygwin-downloader.py
@@ -0,0 +1,157 @@
+#!/usr/bin/env python
+
+import os, random, sys, time, urllib
+
+#
+# Options
+#
+
+dry_run = len(sys.argv) > 1 and "--dry-run" in set(sys.argv[1:])
+quiet = len(sys.argv) > 1 and "--quiet" in set(sys.argv[1:])
+
+#
+# Functions and constants
+#
+
+def download_progress_hook(block_count, block_size, total_blocks):
+ if quiet or random.random() > 0.5:
+ return
+ sys.stdout.write(".")
+ sys.stdout.flush()
+
+def download_url_to_file(url, file, message):
+ if not quiet:
+ print message + " ",
+ if not dry_run:
+ dir = os.path.dirname(file)
+ if len(dir) and not os.path.exists(dir):
+ os.makedirs(dir)
+ urllib.urlretrieve(url, file, download_progress_hook)
+ if not quiet:
+ print
+
+# This is mostly just the list of North America http mirrors from http://cygwin.com/mirrors.html,
+# but a few have been removed that seemed unresponsive from Cupertino.
+mirror_servers = ["http://cygwin.elite-systems.org/",
+ "http://mirror.mcs.anl.gov/cygwin/",
+ "http://cygwin.osuosl.org/",
+ "http://mirrors.kernel.org/sourceware/cygwin/",
+ "http://mirrors.xmission.com/cygwin/",
+ "http://sourceware.mirrors.tds.net/pub/sourceware.org/cygwin/"]
+
+package_mirror_url = mirror_servers[random.choice(range(len(mirror_servers)))]
+
+def download_package(package, message):
+ download_url_to_file(package_mirror_url + package["path"], package["path"], message)
+
+required_packages = frozenset(["apache",
+ "bc",
+ "bison",
+ "curl",
+ "diffutils",
+ "e2fsprogs",
+ "emacs",
+ "flex",
+ "gcc",
+ "gperf",
+ "keychain",
+ "make",
+ "nano",
+ "openssh",
+ "patch",
+ "perl",
+ "perl-libwin32",
+ "python",
+ "rebase",
+ "rsync",
+ "ruby",
+ "subversion",
+ "unzip",
+ "vim",
+ "zip"])
+
+#
+# Main
+#
+
+print "Using Cygwin mirror server " + package_mirror_url + " to download setup.ini..."
+
+urllib.urlretrieve(package_mirror_url + "setup.ini", "setup.ini.orig")
+
+downloaded_packages_file_path = "setup.ini.orig"
+downloaded_packages_file = file(downloaded_packages_file_path, "r")
+if not dry_run:
+ modified_packages_file = file("setup.ini", "w")
+
+packages = {}
+current_package = ''
+for line in downloaded_packages_file.readlines():
+ if line[0] == "@":
+ current_package = line[2:-1]
+ packages[current_package] = {"name": current_package, "needs_download": False, "requires": [], "path": ""}
+ elif line[:10] == "category: ":
+ if current_package in required_packages:
+ line = "category: Base\n"
+ if "Base" in set(line[10:-1].split()):
+ packages[current_package]["needs_download"] = True
+ elif line[:10] == "requires: ":
+ packages[current_package]["requires"] = line[10:].split()
+ packages[current_package]["requires"].sort()
+ elif line[:9] == "install: " and not len(packages[current_package]["path"]):
+ end_of_path = line.find(" ", 9)
+ if end_of_path != -1:
+ packages[current_package]["path"] = line[9:end_of_path]
+ if not dry_run:
+ modified_packages_file.write(line)
+
+downloaded_packages_file.close()
+os.remove(downloaded_packages_file_path)
+if not dry_run:
+ modified_packages_file.close()
+
+names_to_download = set()
+package_names = packages.keys()
+package_names.sort()
+
+def add_package_and_dependencies(name):
+ if name in names_to_download:
+ return
+ if not name in packages:
+ return
+ packages[name]["needs_download"] = True
+ names_to_download.add(name)
+ for dep in packages[name]["requires"]:
+ add_package_and_dependencies(dep)
+
+for name in package_names:
+ if packages[name]["needs_download"]:
+ add_package_and_dependencies(name)
+
+downloaded_so_far = 0
+for name in package_names:
+ if packages[name]["needs_download"]:
+ downloaded_so_far += 1
+ download_package(packages[name], "Downloading package %3d of %3d (%s)" % (downloaded_so_far, len(names_to_download), name))
+
+download_url_to_file("http://cygwin.com/setup.exe", "setup.exe", "Downloading setup.exe")
+
+seconds_to_sleep = 10
+
+print """
+Finished downloading Cygwin. In %d seconds,
+I will run setup.exe. Select the "Install
+from Local Directory" option and browse to
+"%s"
+when asked for the "Local Package Directory".
+""" % (seconds_to_sleep, os.getcwd())
+
+
+while seconds_to_sleep > 0:
+ print "%d..." % seconds_to_sleep,
+ sys.stdout.flush()
+ time.sleep(1)
+ seconds_to_sleep -= 1
+print
+
+if not dry_run:
+ os.execl("setup.exe")
diff --git a/Tools/CygwinDownloader/cygwin-downloader.zip b/Tools/CygwinDownloader/cygwin-downloader.zip
new file mode 100644
index 0000000..9b9c0f0
--- /dev/null
+++ b/Tools/CygwinDownloader/cygwin-downloader.zip
Binary files differ
diff --git a/Tools/CygwinDownloader/make-zip.sh b/Tools/CygwinDownloader/make-zip.sh
new file mode 100755
index 0000000..4a389a9
--- /dev/null
+++ b/Tools/CygwinDownloader/make-zip.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+
+PYTHONEXE=$(cygpath -u "${SYSTEMDRIVE}\\Python25\\python.exe")
+ZIPNAME="cygwin-downloader.zip"
+
+if [[ ! -f "${PYTHONEXE}" ]]; then
+ echo "Couldn't find python.exe at ${PYTHONEXE}" 1>&2
+ exit 1
+fi
+
+"${PYTHONEXE}" setup.py py2exe || {
+ echo "Failed executing setup.py" 1>&2
+ exit 1
+}
+
+rm -f "${ZIPNAME}"
+
+cd dist
+
+zip -r ../"${ZIPNAME}" * || {
+ echo "Failed to create cygwin-downloader" 1>&2
+ exit 1
+}
+
+cd ..
+
+rm -rf build dist || {
+ echo "Failed to cleanup cygwin-downloader and build directories" 1>&2
+ exit 1
+}
diff --git a/Tools/CygwinDownloader/setup.py b/Tools/CygwinDownloader/setup.py
new file mode 100644
index 0000000..c3171d9
--- /dev/null
+++ b/Tools/CygwinDownloader/setup.py
@@ -0,0 +1,4 @@
+from distutils.core import setup
+import py2exe
+
+setup(console=['cygwin-downloader.py'])
diff --git a/Tools/DumpRenderTree/AccessibilityController.cpp b/Tools/DumpRenderTree/AccessibilityController.cpp
new file mode 100644
index 0000000..798389f
--- /dev/null
+++ b/Tools/DumpRenderTree/AccessibilityController.cpp
@@ -0,0 +1,122 @@
+/*
+ * 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 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));
+}
+
+JSClassRef AccessibilityController::getJSClass()
+{
+ static JSStaticFunction staticFunctions[] = {
+ { "logFocusEvents", logFocusEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "logValueChangeEvents", logValueChangeEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "logScrollingStartEvents", logScrollingStartEventsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "elementAtPoint", getElementAtPointCallback, 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);
+}
diff --git a/Tools/DumpRenderTree/AccessibilityController.h b/Tools/DumpRenderTree/AccessibilityController.h
new file mode 100644
index 0000000..5a6ca13
--- /dev/null
+++ b/Tools/DumpRenderTree/AccessibilityController.h
@@ -0,0 +1,72 @@
+/*
+ * 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 resetToConsistentState();
+
+ void addNotificationListener(PlatformUIElement, JSObjectRef functionCallback);
+ void notificationReceived(PlatformUIElement, const std::string& eventName);
+
+private:
+ static JSClassRef getJSClass();
+
+#if PLATFORM(WIN)
+ HWINEVENTHOOK m_focusEventHook;
+ HWINEVENTHOOK m_valueChangeEventHook;
+ HWINEVENTHOOK m_scrollingStartEventHook;
+
+ HWINEVENTHOOK m_allEventsHook;
+ HashMap<PlatformUIElement, JSObjectRef> m_notificationListeners;
+#endif
+};
+
+#endif // AccessibilityController_h
diff --git a/Tools/DumpRenderTree/AccessibilityTextMarker.cpp b/Tools/DumpRenderTree/AccessibilityTextMarker.cpp
new file mode 100644
index 0000000..d84ee80
--- /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>
+
+#pragma 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;
+}
+
+#pragma 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 0000000..aeb078d
--- /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 0000000..57b4e54
--- /dev/null
+++ b/Tools/DumpRenderTree/AccessibilityUIElement.cpp
@@ -0,0 +1,983 @@
+/*
+ * 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 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 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 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 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 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 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; }
+#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;
+}
+
+#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 },
+ { "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 },
+ { 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 },
+ { "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 },
+ { "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 },
+ { "textMarkerRangeForMarkers", textMarkerRangeForMarkersCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "startTextMarkerForTextMarkerRange", startTextMarkerForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "endTextMarkerForTextMarkerRange", endTextMarkerForTextMarkerRangeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "accessibilityElementForTextMarker", accessibilityElementForTextMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "textMarkerRangeLength", textMarkerRangeLengthCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "textMarkerForPoint", textMarkerForPointCallback, 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 0000000..d321b4f
--- /dev/null
+++ b/Tools/DumpRenderTree/AccessibilityUIElement.h
@@ -0,0 +1,224 @@
+/*
+ * 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);
+ 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;
+ 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);
+
+ // Table-specific
+ AccessibilityUIElement cellForColumnAndRow(unsigned column, unsigned row);
+
+ // Text markers.
+ AccessibilityTextMarkerRange textMarkerRangeForElement(AccessibilityUIElement*);
+ AccessibilityTextMarkerRange textMarkerRangeForMarkers(AccessibilityTextMarker* startMarker, AccessibilityTextMarker* endMarker);
+ AccessibilityTextMarker startTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*);
+ AccessibilityTextMarker endTextMarkerForTextMarkerRange(AccessibilityTextMarkerRange*);
+ AccessibilityTextMarker textMarkerForPoint(int x, int y);
+ AccessibilityUIElement accessibilityElementForTextMarker(AccessibilityTextMarker*);
+ int textMarkerRangeLength(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/DumpRenderTree.gypi b/Tools/DumpRenderTree/DumpRenderTree.gypi
new file mode 100644
index 0000000..04caee7
--- /dev/null
+++ b/Tools/DumpRenderTree/DumpRenderTree.gypi
@@ -0,0 +1,72 @@
+{
+ '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/DRTDevToolsCallArgs.cpp',
+ 'chromium/DRTDevToolsCallArgs.h',
+ 'chromium/DRTDevToolsClient.cpp',
+ 'chromium/DRTDevToolsClient.h',
+ 'chromium/DumpRenderTree.cpp',
+ 'chromium/EventSender.cpp',
+ 'chromium/EventSender.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/TestShellGtk.cpp',
+ 'chromium/TestShellMac.mm',
+ 'chromium/TestShellWin.cpp',
+ 'chromium/TextInputController.cpp',
+ 'chromium/TextInputController.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/NPRuntimeObjectFromDestroyedPlugin.cpp',
+ 'TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp',
+ 'TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp',
+ 'TestNetscapePlugIn/main.cpp',
+ ],
+ 'conditions': [
+ ['OS=="win"', {
+ 'drt_files': [
+ 'chromium/WebThemeControlDRTWin.cpp',
+ 'chromium/WebThemeControlDRTWin.h',
+ 'chromium/WebThemeEngineDRTWin.cpp',
+ 'chromium/WebThemeEngineDRTWin.h',
+ ],
+ }],
+ ],
+ }
+}
diff --git a/Tools/DumpRenderTree/DumpRenderTree.h b/Tools/DumpRenderTree/DumpRenderTree.h
new file mode 100644
index 0000000..7a862f7
--- /dev/null
+++ b/Tools/DumpRenderTree/DumpRenderTree.h
@@ -0,0 +1,64 @@
+/*
+ * 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"
+#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 0000000..1f7d803
--- /dev/null
+++ b/Tools/DumpRenderTree/DumpRenderTree.sln
@@ -0,0 +1,83 @@
+
+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
+ {59CC0547-70AC-499C-9B19-EC01C6F61137} = {59CC0547-70AC-499C-9B19-EC01C6F61137}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FindSafari", "..\FindSafari\FindSafari.vcproj", "{DA31DA52-6675-48D4-89E0-333A7144397C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImageDiff", "win\ImageDiff.vcproj", "{59CC0547-70AC-499C-9B19-EC01C6F61137}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA31DA52-6675-48D4-89E0-333A7144397C} = {DA31DA52-6675-48D4-89E0-333A7144397C}
+ EndProjectSection
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug_All|Win32 = Debug_All|Win32
+ Debug_Cairo_CFLite|Win32 = Debug_Cairo_CFLite|Win32
+ Debug|Win32 = Debug|Win32
+ Release_Cairo_CFLite|Win32 = Release_Cairo_CFLite|Win32
+ Release_LTCG|Win32 = Release_LTCG|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}.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_LTCG|Win32.ActiveCfg = Release_LTCG|Win32
+ {6567DFD4-D6DE-4CD5-825D-17E353D160E1}.Release_LTCG|Win32.Build.0 = Release_LTCG|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}.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_LTCG|Win32.ActiveCfg = Release_LTCG|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release_LTCG|Win32.Build.0 = Release_LTCG|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release|Win32.ActiveCfg = Release|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release|Win32.Build.0 = Release|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug_All|Win32.Build.0 = Debug_All|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug|Win32.Build.0 = Debug|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_LTCG|Win32.ActiveCfg = Release_LTCG|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_LTCG|Win32.Build.0 = Release_LTCG|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release|Win32.ActiveCfg = Release|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.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}.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_LTCG|Win32.ActiveCfg = Release_LTCG|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release_LTCG|Win32.Build.0 = Release_LTCG|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release|Win32.ActiveCfg = Release|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.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 0000000..34ff710
--- /dev/null
+++ b/Tools/DumpRenderTree/DumpRenderTree.xcodeproj/project.pbxproj
@@ -0,0 +1,1071 @@
+// !$*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 */; };
+ 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 */; };
+ 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 */; };
+ 1AD4CB2212A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AD4CB2012A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp */; };
+ 1AD9D2FE12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1AD9D2FD12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.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 */; };
+ 3713EDE2115BE19300705720 /* ColorBits-A.png in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 3713EDDF115BE16F00705720 /* ColorBits-A.png */; };
+ 3713EDE3115BE19300705720 /* ColorBits.ttf in Copy Font Files */ = {isa = PBXBuildFile; fileRef = 3713EDE0115BE16F00705720 /* ColorBits.ttf */; };
+ 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 */; };
+ 5185F6B210714E07007AA393 /* HistoryDelegate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5185F69F10714A57007AA393 /* HistoryDelegate.mm */; };
+ 5185F6B310714E12007AA393 /* HistoryDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5185F69E10714A57007AA393 /* HistoryDelegate.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 */; };
+ 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 */; };
+ 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 */,
+ 3713EDE2115BE19300705720 /* ColorBits-A.png in Copy Font Files */,
+ 3713EDE3115BE19300705720 /* ColorBits.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>"; };
+ 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>"; };
+ 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>"; };
+ 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>"; };
+ 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>"; };
+ 3713EDDF115BE16F00705720 /* ColorBits-A.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = "ColorBits-A.png"; path = "fonts/ColorBits-A.png"; sourceTree = "<group>"; };
+ 3713EDE0115BE16F00705720 /* ColorBits.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = ColorBits.ttf; path = fonts/ColorBits.ttf; 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>"; };
+ 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>"; };
+ 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>"; };
+ 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>"; };
+ 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>"; };
+ 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 = (
+ 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 */,
+ 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 = (
+ 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 */,
+ );
+ name = Delegates;
+ sourceTree = "<group>";
+ };
+ 1A215A6E11F25FF1008AD0F5 /* Tests */ = {
+ isa = PBXGroup;
+ children = (
+ 1A215A7511F26072008AD0F5 /* DocumentOpenInDestroyStream.cpp */,
+ C0E720741281C828004EF533 /* EvaluateJSAfterRemovingPluginElement.cpp */,
+ 1AD4CB2012A6D1350027A7AF /* GetUserAgentWithNullNPPFromNPPNew.cpp */,
+ 1A24BAA8120734EE00FBB059 /* NPRuntimeObjectFromDestroyedPlugin.cpp */,
+ 1AC77DCE120605B6005C19EF /* NPRuntimeRemoveProperty.cpp */,
+ C0EC3C9B12787F0500939164 /* NullNPPGetValuePointer.cpp */,
+ C06F9ABB1267A7060058E1F6 /* PassDifferentNPPStruct.cpp */,
+ 1AD9D2FD12028409001A70D1 /* PluginScriptableNPObjectInvokeDefault.cpp */,
+ );
+ path = Tests;
+ sourceTree = "<group>";
+ };
+ 9340995508540CAF007F3BC8 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 9340995408540CAF007F3BC8 /* DumpRenderTree */,
+ B5A7526708AF4A4A00138E45 /* ImageDiff */,
+ 141BF233096A44CF00E0753C /* TestNetscapePlugIn.plugin */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 9345229B0BD12B2C0086EDA0 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 3713EDDF115BE16F00705720 /* ColorBits-A.png */,
+ 3713EDE0115BE16F00705720 /* ColorBits.ttf */,
+ 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 = (
+ 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 */,
+ BCB282F40CFA7450007E533E /* DebugRelease.xcconfig */,
+ BCB281F00CFA713D007E533E /* DumpRenderTree.xcconfig */,
+ BCB283D80CFA7AFD007E533E /* ImageDiff.xcconfig */,
+ BCB283DE0CFA7C20007E533E /* TestNetscapePlugIn.xcconfig */,
+ );
+ name = Configurations;
+ sourceTree = "<group>";
+ };
+ BCB284870CFA81ED007E533E /* PixelDump */ = {
+ isa = PBXGroup;
+ children = (
+ 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 */,
+ 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 */,
+ );
+ 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 */,
+ );
+ 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 */,
+ 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 */,
+ );
+ 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 0000000..e2f45d6
--- /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 0000000..449d918
--- /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 0000000..1344754
--- /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/wtf/ASCIICType.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ASCIICType.h
new file mode 100644
index 0000000..f2258d2
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ASCIICType.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/ASCIICType.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Assertions.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Assertions.h
new file mode 100644
index 0000000..2144410
--- /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 0000000..37b1892
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Atomics.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/Atomics.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/CurrentTime.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/CurrentTime.h
new file mode 100644
index 0000000..a31a23d
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/CurrentTime.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/CurrentTime.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastMalloc.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/FastMalloc.h
new file mode 100644
index 0000000..1701231
--- /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 0000000..9f262e2
--- /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 0000000..cfe2d80
--- /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 100755
index 0000000..412fa98
--- /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 0000000..75b0acd
--- /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 0000000..ff75971
--- /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 0000000..2955786
--- /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 0000000..f8484d2
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Noncopyable.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/Noncopyable.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtr.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/OwnPtr.h
new file mode 100644
index 0000000..9211d38
--- /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 0000000..6064e88
--- /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 0000000..6064e88
--- /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 0000000..aafd1a2
--- /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 0000000..3b22955
--- /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 0000000..628a63b
--- /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 0000000..0ff6213
--- /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 0000000..65fc27b
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/RetainPtr.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/RetainPtr.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/StringExtras.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/StringExtras.h
new file mode 100644
index 0000000..063d500
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/StringExtras.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/StringExtras.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadSafeShared.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadSafeShared.h
new file mode 100644
index 0000000..4a7a77f
--- /dev/null
+++ b/Tools/DumpRenderTree/ForwardingHeaders/wtf/ThreadSafeShared.h
@@ -0,0 +1 @@
+#include <JavaScriptCore/ThreadSafeShared.h>
diff --git a/Tools/DumpRenderTree/ForwardingHeaders/wtf/Threading.h b/Tools/DumpRenderTree/ForwardingHeaders/wtf/Threading.h
new file mode 100644
index 0000000..17359e5
--- /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 0000000..a7ee117
--- /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 0000000..c6d15fd
--- /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 0000000..06a04fb
--- /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 0000000..afc1de0
--- /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 0000000..43795a1
--- /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 0000000..16a3149
--- /dev/null
+++ b/Tools/DumpRenderTree/LayoutTestController.cpp
@@ -0,0 +1,2144 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 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 <stdio.h>
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/RefPtr.h>
+
+LayoutTestController::LayoutTestController(const std::string& testPathOrURL, const std::string& expectedPixelHash)
+ : m_dumpApplicationCacheDelegateCallbacks(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_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_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 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 availableWidth = JSValueToNumber(context, arguments[0], exception);
+ ASSERT(!*exception);
+ double availableHeight = JSValueToNumber(context, arguments[1], exception);
+ ASSERT(!*exception);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->dumpConfigurationForViewport(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 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 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 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 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 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 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 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 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));
+ 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 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 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 setTimelineProfilingEnabledCallback(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->setTimelineProfilingEnabled(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 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());
+ char* headerBuffer = new char[maxLength + 1];
+ JSStringGetUTF8CString(header.get(), headerBuffer, maxLength + 1);
+
+ LayoutTestController* controller = static_cast<LayoutTestController*>(JSObjectGetPrivate(thisObject));
+ controller->setWillSendRequestClearHeader(headerBuffer);
+
+ 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 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->setTimelineProfilingEnabled(false);
+ 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 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 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 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());
+}
+
+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 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 },
+ { 0, 0, 0, 0 }
+ };
+ return staticValues;
+}
+
+JSStaticFunction* LayoutTestController::staticFunctions()
+{
+ static JSStaticFunction staticFunctions[] = {
+ { "abortModal", abortModalCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addDisallowedURL", addDisallowedURLCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addUserScript", addUserScriptCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addUserStyleSheet", addUserStyleSheetCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "apiTestNewWindowDataLoadBaseURL", apiTestNewWindowDataLoadBaseURLCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "apiTestGoToCurrentBackForwardItem", apiTestGoToCurrentBackForwardItemCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "callShouldCloseOnWebView", callShouldCloseOnWebViewCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "clearAllApplicationCaches", clearAllApplicationCachesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "clearAllDatabases", clearAllDatabasesCallback, 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 },
+ { "dispatchPendingLoadRequests", dispatchPendingLoadRequestsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "display", displayCallback, 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 },
+ { "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 },
+ { "grantDesktopNotificationPermission", grantDesktopNotificationPermissionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "hasSpellingMarker", hasSpellingMarkerCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isCommandEnabled", isCommandEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "isPageBoxVisible", isPageBoxVisibleCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "keepWebHistory", keepWebHistoryCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "layerTreeAsText", layerTreeAsTextCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "numberOfPages", numberOfPagesCallback, 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 },
+ { "setAcceptsEditing", setAcceptsEditingCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAllowUniversalAccessFromFileURLs", setAllowUniversalAccessFromFileURLsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAllowFileAccessFromFileURLs", setAllowFileAccessFromFileURLsCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAlwaysAcceptCookies", setAlwaysAcceptCookiesCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAppCacheMaximumSize", setAppCacheMaximumSizeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setApplicationCacheOriginQuota", setApplicationCacheOriginQuotaCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAuthenticationPassword", setAuthenticationPasswordCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAuthenticationUsername", setAuthenticationUsernameCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setAuthorAndUserStylesEnabled", setAuthorAndUserStylesEnabledCallback, 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 },
+ { "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 },
+ { "setMockDeviceOrientation", setMockDeviceOrientationCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setMockGeolocationError", setMockGeolocationErrorCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setMockGeolocationPosition", setMockGeolocationPositionCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "addMockSpeechInputResult", addMockSpeechInputResultCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setNewWindowsCopyBackForwardList", setNewWindowsCopyBackForwardListCallback, 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 },
+ { "setTimelineProfilingEnabled", setTimelineProfilingEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setUseDashboardCompatibilityMode", setUseDashboardCompatibilityModeCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setUserStyleSheetEnabled", setUserStyleSheetEnabledCallback, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
+ { "setUserStyleSheetLocation", setUserStyleSheetLocationCallback, 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 },
+ { "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 },
+ { 0, 0, 0 }
+ };
+
+ return staticFunctions;
+}
+
+void LayoutTestController::queueLoadHTMLString(JSStringRef content, JSStringRef baseURL)
+{
+ WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL));
+}
+
+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::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);
+}
+
+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 0000000..026de13
--- /dev/null
+++ b/Tools/DumpRenderTree/LayoutTestController.h
@@ -0,0 +1,370 @@
+/*
+ * 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 <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 clearAllApplicationCaches();
+ void clearAllDatabases();
+ 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 execCommand(JSStringRef name, JSStringRef value);
+ bool findString(JSContextRef, JSStringRef, JSObjectRef optionsArray);
+ 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);
+ 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 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 setCacheModel(int);
+ void setCustomPolicyDelegate(bool setDelegate, bool permissive);
+ void setDatabaseQuota(unsigned long long quota);
+ void setDomainRelaxationForbiddenForURLScheme(bool forbidden, JSStringRef scheme);
+ 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 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 waitForPolicyDelegate();
+ size_t webHistoryItemCount();
+ unsigned workerThreadCount() const;
+ int windowCount();
+
+ void grantDesktopNotificationPermission(JSStringRef origin);
+ bool checkDesktopNotificationPermission(JSStringRef origin);
+
+ bool elementDoesAutoCompleteForElementWithId(JSStringRef id);
+
+ 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 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 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; }
+
+ 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 setTimelineProfilingEnabled(bool enabled);
+ void evaluateInWebInspector(long callId, JSStringRef script);
+ void evaluateScriptInIsolatedWorld(unsigned worldId, JSObjectRef globalObject, JSStringRef script);
+
+ void setPOSIXLocale(JSStringRef locale);
+
+ void setWebViewEditable(bool);
+
+ void abortModal();
+
+ bool hasSpellingMarker(int from, int length);
+
+ void dumpConfigurationForViewport(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;
+
+ static const unsigned maxViewWidth;
+ static const unsigned maxViewHeight;
+
+private:
+ LayoutTestController(const std::string& testPathOrURL, const std::string& expectedPixelHash);
+
+ void setGeolocationPermissionCommon(bool allow);
+
+ bool m_dumpApplicationCacheDelegateCallbacks;
+ 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_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;
+
+ 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;
+
+ // origins which have been granted desktop notification access
+ std::vector<JSStringRef> m_desktopNotificationAllowedOrigins;
+
+ 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 0000000..1f1dbbc
--- /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 0000000..352eaaa
--- /dev/null
+++ b/Tools/DumpRenderTree/PixelDumpSupport.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 "DumpRenderTree.h"
+#include "LayoutTestController.h"
+#include <cstdio>
+#include <wtf/Assertions.h>
+#include <wtf/RefPtr.h>
+
+#if PLATFORM(CG)
+#include "PixelDumpSupportCG.h"
+#elif PLATFORM(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);
+
+ // 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());
+
+ if (expectedHash == actualHash) // FIXME: do case insensitive compare
+ dumpImage = false;
+ }
+
+ if (dumpImage)
+ dumpBitmap(context.get());
+}
+
+void printPNG(const unsigned char* data, const size_t dataLength)
+{
+ printf("Content-Type: %s\n", "image/png");
+ printf("Content-Length: %lu\n", static_cast<unsigned long>(dataLength));
+
+ const size_t bytesToWriteInOneChunk = 1 << 15;
+ size_t dataRemainingToWrite = dataLength;
+ 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 0000000..e172a83
--- /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*);
+void dumpWebViewAsPixelsAndCompareWithExpected(const std::string& expectedHash);
+void printPNG(const unsigned char* data, const size_t dataLength);
+
+#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/TestNetscapePlugIn/PluginObject.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp
new file mode 100644
index 0000000..45e5ddb
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp
@@ -0,0 +1,1245 @@
+/*
+ * 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);
+}
+
+// Helper function to log to the console object.
+void pluginLog(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);
+
+ 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);
+}
+
+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_PRIVATE_BROWSING_ENABLED,
+ ID_PROPERTY_CACHED_PRIVATE_BROWSING_ENABLED,
+ 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",
+ "privateBrowsingEnabled",
+ "cachedPrivateBrowsingEnabled",
+ "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,
+ 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"
+};
+
+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_PRIVATE_BROWSING_ENABLED]) {
+ NPBool privateBrowsingEnabled = FALSE;
+ browser->getvalue(plugin->npp, NPNVprivateModeBool, &privateBrowsingEnabled);
+ BOOLEAN_TO_NPVARIANT(privateBrowsingEnabled, *result);
+ return true;
+ }
+ if (name == pluginPropertyIdentifiers[ID_PROPERTY_CACHED_PRIVATE_BROWSING_ENABLED]) {
+ BOOLEAN_TO_NPVARIANT(plugin->cachedPrivateBrowsingMode, *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 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);
+
+ 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 0000000..c264e49
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h
@@ -0,0 +1,97 @@
+/*
+ * 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>
+
+#if defined(XP_MACOSX)
+#if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
+#define BUILDING_ON_TIGER 1
+#elif !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;
+ NPBool cachedPrivateBrowsingMode;
+ 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
+#if defined(XP_MACOSX) && !defined(BUILDING_ON_TIGER)
+ 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 bool testDocumentOpen(NPP npp);
+extern bool testWindowOpen(NPP npp);
+
+#if defined(XP_MACOSX) && !defined(BUILDING_ON_TIGER)
+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 0000000..3aff46d
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginObjectMac.mm
@@ -0,0 +1,102 @@
+/*
+ * 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"
+
+#if !defined(BUILDING_ON_TIGER)
+
+#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;
+}
+
+#endif // !defined(BUILDING_ON_TIGER)
+
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp
new file mode 100644
index 0000000..703d9d5
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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 <assert.h>
+#include <string.h>
+
+using namespace std;
+extern NPNetscapeFuncs *browser;
+
+PluginTest* PluginTest::create(NPP npp, const string& identifier)
+{
+ CreateTestFunction createTestFunction = createTestFunctions()[identifier];
+ if (createTestFunction)
+ return createTestFunction(npp, identifier);
+
+ return new PluginTest(npp, identifier);
+}
+
+PluginTest::PluginTest(NPP npp, const string& identifier)
+ : m_npp(npp)
+ , m_identifier(identifier)
+{
+}
+
+PluginTest::~PluginTest()
+{
+}
+
+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_DestroyStream(NPStream *stream, NPReason reason)
+{
+ return NPERR_NO_ERROR;
+}
+
+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_SetWindow(NPP, NPWindow*)
+{
+ return NPERR_NO_ERROR;
+}
+
+void PluginTest::NPN_InvalidateRect(NPRect* invalidRect)
+{
+ browser->invalidaterect(m_npp, invalidRect);
+}
+
+NPIdentifier PluginTest::NPN_GetStringIdentifier(const NPUTF8 *name)
+{
+ return browser->getstringidentifier(name);
+}
+
+NPIdentifier PluginTest::NPN_GetIntIdentifier(int32_t intid)
+{
+ return browser->getintidentifier(intid);
+}
+
+NPError PluginTest::NPN_GetValue(NPNVariable variable, void* value)
+{
+ return browser->getvalue(m_npp, variable, value);
+}
+
+NPObject* PluginTest::NPN_CreateObject(NPClass* npClass)
+{
+ return browser->createobject(m_npp, npClass);
+}
+
+bool PluginTest::NPN_RemoveProperty(NPObject* npObject, NPIdentifier propertyName)
+{
+ return browser->removeproperty(m_npp, npObject, propertyName);
+}
+
+void PluginTest::executeScript(const char* script)
+{
+ NPObject* windowScriptObject;
+ browser->getvalue(m_npp, NPNVWindowNPObject, &windowScriptObject);
+
+ NPString npScript;
+ npScript.UTF8Characters = script;
+ npScript.UTF8Length = strlen(script);
+
+ NPVariant browserResult;
+ browser->evaluate(m_npp, windowScriptObject, &npScript, &browserResult);
+ browser->releasevariantvalue(&browserResult);
+}
+
+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 0000000..2c06079
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h
@@ -0,0 +1,222 @@
+/*
+ * 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));
+
+class PluginTest {
+public:
+ static PluginTest* create(NPP, const std::string& identifier);
+ virtual ~PluginTest();
+
+ // 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_DestroyStream(NPStream* stream, NPReason reason);
+ virtual NPError NPP_GetValue(NPPVariable, void* value);
+ virtual NPError NPP_SetWindow(NPP, NPWindow*);
+
+ // NPN functions.
+ void NPN_InvalidateRect(NPRect* invalidRect);
+ NPIdentifier NPN_GetStringIdentifier(const NPUTF8* name);
+ NPIdentifier NPN_GetIntIdentifier(int32_t intid);
+ NPError NPN_GetValue(NPNVariable, void* value);
+ NPObject* NPN_CreateObject(NPClass*);
+ bool NPN_RemoveProperty(NPObject*, NPIdentifier propertyName);
+
+ void executeScript(const char*);
+
+ 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;
+ }
+
+ 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 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
+ 0, // NPClass::removeProperty
+ 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 0000000..9e65f11
--- /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 0000000..73748e0
--- /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 0000000..69e706e
--- /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 0000000..4b5d3e0
--- /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/GetUserAgentWithNullNPPFromNPPNew.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp
new file mode 100644
index 0000000..322d3fe
--- /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/NPRuntimeObjectFromDestroyedPlugin.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp
new file mode 100644
index 0000000..38236e3
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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.
+ 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_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 0000000..4d417d1
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp
@@ -0,0 +1,89 @@
+/*
+ * 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 NPRuntimeRemoveProperty : public PluginTest {
+public:
+ NPRuntimeRemoveProperty(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ {
+ }
+
+private:
+ struct TestObject : Object<TestObject> {
+ public:
+ bool hasMethod(NPIdentifier methodName)
+ {
+ return methodName == pluginTest()->NPN_GetStringIdentifier("testRemoveProperty");
+ }
+
+ bool invoke(NPIdentifier methodName, const NPVariant* arguments, uint32_t argumentCount, NPVariant* result)
+ {
+ assert(methodName == pluginTest()->NPN_GetStringIdentifier("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 = arguments[1].value.doubleValue;
+ propertyName = pluginTest()->NPN_GetIntIdentifier(number);
+ }
+
+ pluginTest()->NPN_RemoveProperty(NPVARIANT_TO_OBJECT(arguments[0]), propertyName);
+
+ VOID_TO_NPVARIANT(*result);
+ return true;
+ }
+ };
+
+ virtual NPError NPP_GetValue(NPPVariable variable, void *value)
+ {
+ if (variable != NPPVpluginScriptableNPObject)
+ return NPERR_GENERIC_ERROR;
+
+ *(NPObject**)value = TestObject::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 0000000..9e4e976
--- /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 0000000..e464996
--- /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(NPP instance, 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) {
+ pluginLog(instance, "NPN_GetValue(NPNVprivateModeBool) with a different NPP struct failed with error %d", error);
+ return NPERR_GENERIC_ERROR;
+ }
+ pluginLog(instance, "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 0000000..959e182
--- /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/win/DrawsGradient.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/DrawsGradient.cpp
new file mode 100644
index 0000000..2b06198
--- /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/GetValueNetscapeWindow.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/GetValueNetscapeWindow.cpp
new file mode 100644
index 0000000..32fd99b
--- /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 0000000..e598c49
--- /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 = ::GetAncestor(window(), GA_ROOT);
+ 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 0000000..8054497
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowGeometryInitializedBeforeSetWindow.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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;
+ }
+
+ HWND parent = ::GetParent(hwnd);
+ if (!parent) {
+ pluginLog(instance, "::GetParent failed");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ // MSDN says that calling ::MapWindowPoints this way will tell it we're passing a RECT rather than two POINTs.
+ if (!::MapWindowPoints(hwnd, parent, reinterpret_cast<POINT*>(&rect), 2)) {
+ pluginLog(instance, "::MapWindowPoints failed");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if (rect.left != window->x || rect.top != window->y || (rect.right - rect.left) != window->width || (rect.bottom - rect.top) != window->height) {
+ pluginLog(instance, "HWND's rect and NPWindow's rect are not equal");
+ return NPERR_GENERIC_ERROR;
+ }
+
+ pluginLog(instance, "Plugin's HWND has been sized and positioned 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 0000000..975a598
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/Tests/win/WindowRegionIsSetToClipRect.cpp
@@ -0,0 +1,114 @@
+/*
+ * 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;
+
+// The plugin's window's window region should be set to the plugin's clip rect.
+
+class WindowRegionIsSetToClipRect : public PluginTest {
+public:
+ WindowRegionIsSetToClipRect(NPP, const string& identifier);
+
+private:
+ virtual NPError NPP_SetWindow(NPP, NPWindow*);
+
+ bool m_didReceiveInitialSetWindowCall;
+};
+
+static PluginTest::Register<WindowRegionIsSetToClipRect> registrar("window-region-is-set-to-clip-rect");
+
+WindowRegionIsSetToClipRect::WindowRegionIsSetToClipRect(NPP npp, const string& identifier)
+ : PluginTest(npp, identifier)
+ , m_didReceiveInitialSetWindowCall(false)
+{
+}
+
+NPError WindowRegionIsSetToClipRect::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 regionRect;
+ if (::GetWindowRgnBox(hwnd, &regionRect) == ERROR) {
+ pluginLog(instance, "::GetWindowRgnBox failed with error %u", ::GetLastError());
+ return NPERR_GENERIC_ERROR;
+ }
+
+ // 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)) {
+ pluginLog(instance, "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 NPERR_GENERIC_ERROR;
+ }
+
+ pluginLog(instance, "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(hwnd, className, _countof(className))) {
+ pluginLog(instance, "::GetClassName failed with error %u", ::GetLastError());
+ return NPERR_GENERIC_ERROR;
+ }
+
+#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) {
+ pluginLog(instance, "::GetModuleHandleW failed with error %u", ::GetLastError());
+ return NPERR_GENERIC_ERROR;
+ }
+
+ WNDCLASSW wndClass;
+ if (!::GetClassInfoW(webKitModule, className, &wndClass)) {
+ pluginLog(instance, "::GetClassInfoW failed with error %u", ::GetLastError());
+ return NPERR_GENERIC_ERROR;
+ }
+
+ if (wndClass.style & CS_PARENTDC)
+ pluginLog(instance, "FAIL: Plugin's window's class has the CS_PARENTDC style, which will defeat clipping");
+ else
+ pluginLog(instance, "PASS: Plugin's window's class does not have the CS_PARENTDC style");
+
+ return NPERR_NO_ERROR;
+}
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/mac/Info.plist b/Tools/DumpRenderTree/TestNetscapePlugIn/mac/Info.plist
new file mode 100644
index 0000000..7444b84
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/mac/Info.plist
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//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>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 0000000..b4b7fa3
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/main.cpp
@@ -0,0 +1,762 @@
+/*
+ * 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 <string>
+
+#ifdef XP_UNIX
+#include <X11/Xlib.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)
+{
+}
+
+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)
+{
+ bool forceCarbon = false;
+
+#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 && !forceCarbon) {
+ 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;
+#if !defined(BUILDING_ON_TIGER)
+ obj->coreAnimationLayer = 0;
+#endif
+#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], "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], "forcecarbon") == 0)
+ forceCarbon = true;
+ 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) {
+#if defined(XP_MACOSX) && !defined(BUILDING_ON_TIGER)
+ 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;
+ }
+ }
+
+#ifdef XP_MACOSX
+ browser->setvalue(instance, NPPVpluginDrawingModel, (void *)drawingModelToUse);
+#if !defined(BUILDING_ON_TIGER)
+ if (drawingModelToUse == NPDrawingModelCoreAnimation)
+ obj->coreAnimationLayer = createCoreAnimationLayer();
+#endif
+#endif
+
+ browser->getvalue(instance, NPNVprivateModeBool, (void *)&obj->cachedPrivateBrowsingMode);
+
+ obj->pluginTest = PluginTest::create(instance, testIdentifier);
+
+#ifdef XP_UNIX
+ // On Unix, plugins only get events if they are windowless.
+ browser->setvalue(instance, NPPVpluginWindowBool, 0);
+#endif
+
+ 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");
+
+#if defined(XP_MACOSX) && !defined(BUILDING_ON_TIGER)
+ if (obj->coreAnimationLayer)
+ CFRelease(obj->coreAnimationLayer);
+#endif
+
+ 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(instance, 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 NPERR_NO_ERROR;
+}
+
+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)
+{
+ return 4096;
+}
+
+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 len;
+}
+
+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 int16_t handleEventX11(NPP instance, PluginObject* obj, XEvent* event)
+{
+ XButtonPressedEvent* buttonPressEvent = reinterpret_cast<XButtonPressedEvent*>(event);
+ XButtonReleasedEvent* buttonReleaseEvent = reinterpret_cast<XButtonReleasedEvent*>(event);
+ switch (event->type) {
+ case ButtonPress:
+ if (obj->eventLogging)
+ pluginLog(instance, "mouseDown at (%d, %d)", buttonPressEvent->x, buttonPressEvent->y);
+ if (obj->evaluateScriptOnMouseDownOrKeyDown && obj->mouseDownForEvaluateScript)
+ executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
+ break;
+ case ButtonRelease:
+ if (obj->eventLogging)
+ pluginLog(instance, "mouseUp at (%d, %d)", buttonReleaseEvent->x, buttonReleaseEvent->y);
+ break;
+ case KeyPress:
+ // FIXME: extract key code
+ if (obj->eventLogging)
+ pluginLog(instance, "NOTIMPLEMENTED: keyDown '%c'", ' ');
+ if (obj->evaluateScriptOnMouseDownOrKeyDown && !obj->mouseDownForEvaluateScript)
+ executeScript(obj, obj->evaluateScriptOnMouseDownOrKeyDown);
+ break;
+ case KeyRelease:
+ // FIXME: extract key code
+ if (obj->eventLogging)
+ pluginLog(instance, "NOTIMPLEMENTED: keyUp '%c'", ' ');
+ break;
+ case GraphicsExpose:
+ if (obj->eventLogging)
+ pluginLog(instance, "updateEvt");
+ 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:
+ if (obj->eventLogging)
+ pluginLog(instance, "adjustCursorEvent");
+ break;
+ default:
+ if (obj->eventLogging)
+ pluginLog(instance, "event %d", event->type);
+ }
+
+ fflush(stdout);
+ return 0;
+}
+#endif // XP_UNIX
+
+int16_t NPP_HandleEvent(NPP instance, void *event)
+{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+
+#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));
+#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->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;
+ }
+#endif
+
+ 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;
+ }
+
+#if defined(XP_MACOSX) && !defined(BUILDING_ON_TIGER)
+ 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);
+
+ switch (variable) {
+ case NPNVprivateModeBool:
+ obj->cachedPrivateBrowsingMode = *(NPBool*)value;
+ return NPERR_NO_ERROR;
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+}
+
+#ifdef XP_UNIX
+extern "C"
+const char* NP_GetMIMEDescription(void)
+{
+ return "application/x-webkit-test-netscape:testnetscape:test netscape content";
+}
+
+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/TestNetscapePlugin.def b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.def
new file mode 100644
index 0000000..ac41e7e
--- /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 0000000..a8fbbcd
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.rc
@@ -0,0 +1,101 @@
+// 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", "TestNetscapePlugIn"
+ VALUE "FileOpenName", "test netscape content"
+ VALUE "LegalCopyright", "Copyright Apple Inc. 2007-2009"
+ VALUE "MIMEType", "application/x-webkit-test-netscape"
+ VALUE "OriginalFilename", "npTestNetscapePlugin.dll"
+ VALUE "ProductName", "TestNetscapePlugIn"
+ 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 0000000..11c9723
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin.vcproj
@@ -0,0 +1,508 @@
+<?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="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\TestNetscapePluginCommon.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="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\TestNetscapePluginCommon.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="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;.\TestNetscapePluginCommon.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="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\TestNetscapePluginCommon.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_LTCG|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\TestNetscapePluginCommon.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="$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;.\TestNetscapePluginCommon.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="..\Tests\DocumentOpenInDestroyStream.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\EvaluateJSAfterRemovingPluginElement.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\GetUserAgentWithNullNPPFromNPPNew.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>
+ <Filter
+ Name="win"
+ >
+ <File
+ RelativePath="..\Tests\win\DrawsGradient.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\WindowRegionIsSetToClipRect.cpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="win"
+ >
+ <File
+ RelativePath=".\WindowedPluginTest.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\WindowedPluginTest.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 0000000..922ae52
--- /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;$(WebKitOutputDir)\Include&quot;;&quot;$(WebKitOutputDir)\Include\JavaScriptCore&quot;;&quot;$(WebKitOutputDir)\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/TestNetscapePluginPostBuild.cmd b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPostBuild.cmd
new file mode 100644
index 0000000..f011495
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPostBuild.cmd
@@ -0,0 +1 @@
+if exist "%WEBKITOUTPUTDIR%\buildfailed" del "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPreBuild.cmd b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePluginPreBuild.cmd
new file mode 100644
index 0000000..3a84c26
--- /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 "%WEBKITOUTPUTDIR%\buildfailed" grep XX%PROJECTNAME%XX "%WEBKITOUTPUTDIR%\buildfailed"
+if errorlevel 1 exit 1
+echo XX%PROJECTNAME%XX > "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin_debug.def b/Tools/DumpRenderTree/TestNetscapePlugIn/win/TestNetscapePlugin_debug.def
new file mode 100644
index 0000000..158fb7c
--- /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/WindowedPluginTest.cpp b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp
new file mode 100644
index 0000000..96b51f8
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.cpp
@@ -0,0 +1,71 @@
+/*
+ * 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)
+{
+}
+
+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 0000000..7abc734
--- /dev/null
+++ b/Tools/DumpRenderTree/TestNetscapePlugIn/win/WindowedPluginTest.h
@@ -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.
+ */
+
+#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; }
+
+ // 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 0000000..b0ce340
--- /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 0000000..0106fba
--- /dev/null
+++ b/Tools/DumpRenderTree/WorkQueue.cpp
@@ -0,0 +1,104 @@
+/*
+ * 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"
+
+#include "WorkQueueItem.h"
+#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 0000000..649c6c1
--- /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 0000000..34276c8
--- /dev/null
+++ b/Tools/DumpRenderTree/WorkQueueItem.h
@@ -0,0 +1,141 @@
+/*
+ * 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)
+ {
+ }
+
+private:
+ virtual bool invoke() const;
+
+ JSRetainPtr<JSStringRef> m_content;
+ JSRetainPtr<JSStringRef> m_baseURL;
+};
+
+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/android/get_layout_tests_dir_contents.php b/Tools/DumpRenderTree/android/get_layout_tests_dir_contents.php
new file mode 100644
index 0000000..28a1a8a
--- /dev/null
+++ b/Tools/DumpRenderTree/android/get_layout_tests_dir_contents.php
@@ -0,0 +1,110 @@
+<?php
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+###############################################################################
+
+# Lists the content of the LayoutTests directory
+#
+# Usage:
+# get_layout_tests_dir_contents.php?path=PATH&recurse=RECURSE&separator=SEPARATOR&mode=MODE
+# where
+# PATH - relative path in the LayoutTests dir
+# RECURSE = [true|false] (defaults to true)
+# SEPARATOR = a string separating paths in result (defaults to \n)
+# MODE = [folders|files] (defaults to files) - if 'folders' then lists only folders,
+# if 'files' then only files
+
+ # The server document root is LayoutTests/http/tests. See run_apache2.py.
+ $rootDir = realpath($_SERVER['DOCUMENT_ROOT'] . '..' . DIRECTORY_SEPARATOR . '..');
+
+ function getAbsolutePath($relPath) {
+ global $rootDir;
+ return $rootDir . DIRECTORY_SEPARATOR . $relPath;
+ }
+
+ function getFilesAsArray($relPath) {
+ return array_slice(scandir(getAbsolutePath($relPath)), 2);
+ }
+
+ function isIgnored($basename) {
+ return substr($basename, 0, 1) == '.';
+ }
+
+ function getAllFilesUnderAsArray($relPath, $recurse, $mode) {
+ $files = getFilesAsArray($relPath);
+ $result = array();
+
+ foreach($files as $i => $value) {
+ if (isIgnored($value)) {
+ continue;
+ }
+ if ($relPath == '') {
+ $filePath = $value;
+ } else {
+ $filePath = $relPath . DIRECTORY_SEPARATOR . $value;
+ }
+
+ if (is_dir(getAbsolutePath($filePath))) {
+ if ($mode == 'folders') {
+ $result = array_merge($result, (array)$filePath);
+ }
+ if ($recurse) {
+ $result = array_merge($result, getAllFilesUnderAsArray($filePath, $recurse, $mode));
+ }
+ } else if ($mode == 'files') {
+ $result = array_merge($result, (array)$filePath);
+ }
+ }
+
+ return $result;
+ }
+
+ function main() {
+ global $rootDir;
+
+ $path = getAbsolutePath($_GET['path']);
+
+ if (!isset($_GET['separator'])) {
+ $separator = "\n";
+ } else {
+ $separator = $_GET['separator'];
+ }
+
+ $recurse = (strtolower($_GET['recurse']) != 'false');
+
+ if (strtolower($_GET['mode']) == 'folders') {
+ $mode = 'folders';
+ } else {
+ $mode = 'files';
+ }
+
+ # Very primitive check if path tries to go above DOCUMENT_ROOT or is absolute
+ if (strpos($_GET['path'], "..") !== False ||
+ substr($_GET['path'], 0, 1) == DIRECTORY_SEPARATOR) {
+ return;
+ }
+
+ # If we don't want realpath to append any prefixes we need to pass it an absolute path
+ $path = realpath(getAbsolutePath($_GET['path']));
+ $relPath = substr($path, strlen($rootDir) + 1);
+
+ # If there is an error of some sort it will be output as a part of the answer!
+ foreach (getAllFilesUnderAsArray($relPath, $recurse, $mode) as $i => $value) {
+ echo "$value$separator";
+ }
+ }
+
+ main();
+?>
diff --git a/Tools/DumpRenderTree/android/view_source.php b/Tools/DumpRenderTree/android/view_source.php
new file mode 100644
index 0000000..fc9ae31
--- /dev/null
+++ b/Tools/DumpRenderTree/android/view_source.php
@@ -0,0 +1,53 @@
+<?php
+# Copyright (C) 2010 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+###############################################################################
+
+# Show the source of the test.
+#
+# Usage:
+# view_source.php?src=PATH
+# where
+# PATH - relative path in the LayoutTests dir
+
+ # Global variables
+ # The server document root is LayoutTests/http/tests. See run_apache2.py.
+ $rootDir = realpath($_SERVER['DOCUMENT_ROOT'] . '..' . DIRECTORY_SEPARATOR . '..');
+
+ function getAbsolutePath($relPath) {
+ global $rootDir;
+ return $rootDir . DIRECTORY_SEPARATOR . $relPath;
+ }
+
+ function main() {
+ global $rootDir;
+
+ # Very primitive check if path tries to go above DOCUMENT_ROOT or is absolute
+ if (strpos($_GET['src'], "..") !== False ||
+ substr($_GET['src'], 0, 1) == DIRECTORY_SEPARATOR) {
+ return;
+ }
+
+ # If we don't want realpath to append any prefixes we need to pass it an absolute path
+ $src = realpath(getAbsolutePath($_GET['src']));
+
+ echo "<html><body>";
+ # TODO: Add link following and syntax highlighting for html and js.
+ highlight_string(file_get_contents($src));
+ echo "</body></html>";
+ }
+
+ main();
+?>
diff --git a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp
new file mode 100644
index 0000000..7de019d
--- /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)
+{
+ 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);
+}
+
+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)
+{
+ cairo_surface_t* surface = cairo_get_target(context->cairoContext());
+ printPNG(surface);
+}
diff --git a/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h b/Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h
new file mode 100644
index 0000000..fa1f48b
--- /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)
+#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 0000000..4d77454
--- /dev/null
+++ b/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.cpp
@@ -0,0 +1,229 @@
+/*
+ * 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.
+ */
+
+#import "WebArchiveDumpSupport.h"
+
+#import <CoreFoundation/CoreFoundation.h>
+#import <CFNetwork/CFNetwork.h>
+#import <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;
+
+#if defined(BUILDING_ON_TIGER) || defined(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;
+
+#if defined(BUILDING_ON_TIGER) || defined(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.releaseRef();
+}
diff --git a/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.h b/Tools/DumpRenderTree/cf/WebArchiveDumpSupport.h
new file mode 100644
index 0000000..08d9c45
--- /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);
+
+#pragma mark -
+#pragma 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 0000000..593ba64
--- /dev/null
+++ b/Tools/DumpRenderTree/cg/ImageDiffCG.cpp
@@ -0,0 +1,250 @@
+/*
+ * 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
+
+#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", stdout);
+ }
+
+ 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 0000000..5cf32f1
--- /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)
+{
+ 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));
+}
+
+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)
+{
+ RetainPtr<CGImageRef> image(AdoptCF, CGBitmapContextCreateImage(context->cgContext()));
+ printPNG(image.get());
+}
diff --git a/Tools/DumpRenderTree/cg/PixelDumpSupportCG.h b/Tools/DumpRenderTree/cg/PixelDumpSupportCG.h
new file mode 100644
index 0000000..f0c9746
--- /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 0000000..5601d9d
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/AccessibilityController.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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 "WebAccessibilityCache.h"
+#include "WebAccessibilityObject.h"
+#include "WebFrame.h"
+#include "WebString.h"
+#include "WebView.h"
+
+using namespace WebKit;
+
+AccessibilityController::AccessibilityController(TestShell* shell)
+ : m_shell(shell)
+{
+
+ bindMethod("dumpAccessibilityNotifications", &AccessibilityController::dumpAccessibilityNotifications);
+ bindMethod("logFocusEvents", &AccessibilityController::logFocusEventsCallback);
+ bindMethod("logScrollingStartEvents", &AccessibilityController::logScrollingStartEventsCallback);
+
+ bindProperty("focusedElement", &AccessibilityController::focusedElementGetterCallback);
+ bindProperty("rootElement", &AccessibilityController::rootElementGetterCallback);
+
+ bindFallbackMethod(&AccessibilityController::fallbackCallback);
+}
+
+void AccessibilityController::bindToJavascript(WebFrame* frame, const WebString& classname)
+{
+ WebAccessibilityCache::enableAccessibility();
+ CppBoundClass::bindToJavascript(frame, classname);
+}
+
+void AccessibilityController::reset()
+{
+ m_rootElement = WebAccessibilityObject();
+ m_focusedElement = WebAccessibilityObject();
+ m_elements.clear();
+
+ m_dumpAccessibilityNotifications = 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.create(m_focusedElement);
+}
+
+AccessibilityUIElement* AccessibilityController::getRootElement()
+{
+ if (m_rootElement.isNull())
+ m_rootElement = m_shell->webView()->accessibilityObject();
+ return m_elements.createRoot(m_rootElement);
+}
+
+void AccessibilityController::dumpAccessibilityNotifications(const CppArgumentList&, CppVariant* result)
+{
+ m_dumpAccessibilityNotifications = true;
+ result->setNull();
+}
+
+void AccessibilityController::logFocusEventsCallback(const CppArgumentList&, CppVariant* result)
+{
+ // As of r49031, this is not being used upstream.
+ result->setNull();
+}
+
+void AccessibilityController::logScrollingStartEventsCallback(const CppArgumentList&, CppVariant* result)
+{
+ // As of r49031, this is not being used upstream.
+ 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 0000000..0817ec3
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/AccessibilityController.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 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();
+
+ // This function sets a flag that tells the test_shell to dump all
+ // accessibility notifications.
+ void dumpAccessibilityNotifications(const CppArgumentList&, CppVariant*);
+
+public:
+ // The following methods are not exposed to JavaScript.
+ bool shouldDumpAccessibilityNotifications() { return m_dumpAccessibilityNotifications; }
+
+private:
+ // If true, the test_shell will dump all accessibility notifications.
+ bool m_dumpAccessibilityNotifications;
+
+ // Bound methods and properties
+ void logFocusEventsCallback(const CppArgumentList&, CppVariant*);
+ void logScrollingStartEventsCallback(const CppArgumentList&, CppVariant*);
+ void fallbackCallback(const CppArgumentList&, CppVariant*);
+
+ void focusedElementGetterCallback(CppVariant*);
+ void rootElementGetterCallback(CppVariant*);
+
+ WebKit::WebAccessibilityObject m_focusedElement;
+ WebKit::WebAccessibilityObject m_rootElement;
+
+ AccessibilityUIElementList m_elements;
+
+ 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 0000000..dbd025a
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/AccessibilityUIElement.cpp
@@ -0,0 +1,585 @@
+/*
+ * 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 "WebCString.h"
+#include "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 getRole(const WebAccessibilityObject& object)
+{
+ return roleToString(object.roleValue());
+}
+
+string getTitle(const WebAccessibilityObject& object)
+{
+ string title = object.title().utf8();
+ return title.insert(0, "AXTitle: ");
+}
+
+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);
+
+ bindMethod("allAttributes", &AccessibilityUIElement::allAttributesCallback);
+ bindMethod("attributesOfLinkedUIElements",
+ &AccessibilityUIElement::attributesOfLinkedUIElementsCallback);
+ bindMethod("attributesOfDocumentLinks",
+ &AccessibilityUIElement::attributesOfDocumentLinksCallback);
+ bindMethod("attributesOfChildren",
+ &AccessibilityUIElement::attributesOfChildrenCallback);
+ bindMethod("parameterizedAttributeNames",
+ &AccessibilityUIElement::parametrizedAttributeNamesCallback);
+ 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);
+
+ bindProperty("role", &AccessibilityUIElement::roleGetterCallback);
+ bindProperty("subrole", &m_subrole);
+ bindProperty("title", &AccessibilityUIElement::titleGetterCallback);
+ bindProperty("description",
+ &AccessibilityUIElement::descriptionGetterCallback);
+ bindProperty("language", &m_language);
+ bindProperty("x", &m_x);
+ bindProperty("y", &m_y);
+ bindProperty("width", &m_width);
+ bindProperty("height", &m_height);
+ bindProperty("clickPointX", &m_clickPointX);
+ bindProperty("clickPointY", &m_clickPointY);
+ bindProperty("intValue", &m_intValue);
+ bindProperty("minValue", &m_minValue);
+ bindProperty("maxValue", &m_maxValue);
+ bindProperty("childrenCount",
+ &AccessibilityUIElement::childrenCountGetterCallback);
+ bindProperty("insertionPointLineNumber", &m_insertionPointLineNumber);
+ bindProperty("selectedTextRange", &m_selectedTextRange);
+ bindProperty("isEnabled", &AccessibilityUIElement::isEnabledGetterCallback);
+ bindProperty("isRequired", &m_isRequired);
+ bindProperty("isSelected", &AccessibilityUIElement::isSelectedGetterCallback);
+ bindProperty("valueDescription", &m_valueDescription);
+
+ bindFallbackMethod(&AccessibilityUIElement::fallbackCallback);
+}
+
+AccessibilityUIElement* AccessibilityUIElement::getChildAtIndex(unsigned index)
+{
+ return m_factory->create(accessibilityObject().childAt(index));
+}
+
+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::fallbackCallback(const CppArgumentList &, CppVariant* result)
+{
+ // FIXME: Implement this.
+ result->setNull();
+}
+
+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::descriptionGetterCallback(CppVariant* result)
+{
+ result->set(getDescription(accessibilityObject()));
+}
+
+void AccessibilityUIElement::isEnabledGetterCallback(CppVariant* result)
+{
+ result->set(accessibilityObject().isEnabled());
+}
+
+void AccessibilityUIElement::isSelectedGetterCallback(CppVariant* result)
+{
+ result->setNull();
+}
+
+void AccessibilityUIElement::roleGetterCallback(CppVariant* result)
+{
+ result->set(getRole(accessibilityObject()));
+}
+
+void AccessibilityUIElement::titleGetterCallback(CppVariant* result)
+{
+ result->set(getTitle(accessibilityObject()));
+}
+
+
+RootAccessibilityUIElement::RootAccessibilityUIElement(const WebAccessibilityObject &object, Factory *factory)
+ : AccessibilityUIElement(object, factory) { }
+
+AccessibilityUIElement* RootAccessibilityUIElement::getChildAtIndex(unsigned index)
+{
+ if (index)
+ return 0;
+
+ return factory()->create(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::create(const WebAccessibilityObject& object)
+{
+ if (object.isNull())
+ return 0;
+
+ 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 0000000..366ed42
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/AccessibilityUIElement.h
@@ -0,0 +1,142 @@
+/*
+ * 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 <wtf/Vector.h>
+
+class AccessibilityUIElement : public CppBoundClass {
+public:
+ class Factory {
+ public:
+ virtual ~Factory() { }
+ virtual AccessibilityUIElement* create(const WebKit::WebAccessibilityObject&) = 0;
+ };
+
+ AccessibilityUIElement(const WebKit::WebAccessibilityObject&, Factory*);
+
+ virtual AccessibilityUIElement* getChildAtIndex(unsigned);
+ virtual bool isRoot() const { return false; }
+
+protected:
+ const WebKit::WebAccessibilityObject& accessibilityObject() const { return m_accessibilityObject; }
+ Factory* factory() const { return m_factory; }
+
+private:
+ // Bound methods and properties.
+ 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 fallbackCallback(const CppArgumentList&, CppVariant*);
+
+ void childrenCountGetterCallback(CppVariant*);
+ void descriptionGetterCallback(CppVariant*);
+ void isEnabledGetterCallback(CppVariant*);
+ void isSelectedGetterCallback(CppVariant*);
+ void roleGetterCallback(CppVariant*);
+ void titleGetterCallback(CppVariant*);
+
+ CppVariant m_subrole;
+ CppVariant m_language;
+ CppVariant m_x;
+ CppVariant m_y;
+ CppVariant m_width;
+ CppVariant m_height;
+ CppVariant m_clickPointX;
+ CppVariant m_clickPointY;
+ CppVariant m_intValue;
+ CppVariant m_minValue;
+ CppVariant m_maxValue;
+ CppVariant m_childrenCount;
+ CppVariant m_insertionPointLineNumber;
+ CppVariant m_selectedTextRange;
+ CppVariant m_isRequired;
+ CppVariant m_valueDescription;
+
+ WebKit::WebAccessibilityObject m_accessibilityObject;
+ Factory* m_factory;
+};
+
+
+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* create(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 0000000..1348bbf
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/CppBoundClass.cpp
@@ -0,0 +1,350 @@
+/*
+ * 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 "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(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, 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 0000000..6cb638e
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/CppBoundClass.h
@@ -0,0 +1,241 @@
+/*
+ * 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/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 : public Noncopyable {
+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 name |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, |method|
+ // 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&, GetterCallback*);
+
+ // A wrapper for BindGetterCallback, to simplify the common case of binding a
+ // property on the current object. Though not verified here, |method|
+ // must be a method of this CppBoundClass subclass.
+ template<class T>
+ void bindProperty(const std::string& name, void (T::*method)(CppVariant*))
+ {
+ GetterCallback* callback = new MemberGetterCallback<T>(static_cast<T*>(this), method);
+ bindGetterCallback(name, callback);
+ }
+
+ // 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(Callback* fallbackCallback)
+ {
+ m_fallbackCallback.set(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) {
+ Callback* callback = new MemberCallback<T>(static_cast<T*>(this), method);
+ bindFallbackCallback(callback);
+ } else
+ bindFallbackCallback(0);
+ }
+
+ // 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 0000000..22e0013
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/CppVariant.cpp
@@ -0,0 +1,310 @@
+/*
+ * 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;
+}
diff --git a/Tools/DumpRenderTree/chromium/CppVariant.h b/Tools/DumpRenderTree/chromium/CppVariant.h
new file mode 100644
index 0000000..3032310
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/CppVariant.h
@@ -0,0 +1,133 @@
+/*
+ * 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;
+};
+
+#endif // CppVariant_h
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp
new file mode 100644
index 0000000..78c86e7
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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 "DRTDevToolsCallArgs.h"
+#include "DRTDevToolsClient.h"
+
+#include "WebCString.h"
+#include "WebDevToolsAgent.h"
+#include "WebString.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;
+ if (m_routingID == 1)
+ WebDevToolsAgent::setMessageLoopDispatchHandler(&DRTDevToolsAgent::dispatchMessageLoop);
+}
+
+void DRTDevToolsAgent::reset()
+{
+ m_taskList.revokeAll();
+}
+
+void DRTDevToolsAgent::setWebView(WebView* webView)
+{
+ m_webView = webView;
+}
+
+void DRTDevToolsAgent::sendMessageToInspectorFrontend(const WebKit::WebString& data)
+{
+ if (m_drtDevToolsClient)
+ m_drtDevToolsClient->asyncCall(DRTDevToolsCallArgs(data));
+}
+
+void DRTDevToolsAgent::runtimePropertyChanged(const WebKit::WebString& name, const WebKit::WebString& value)
+{
+ // FIXME: Implement.
+}
+
+WebCString DRTDevToolsAgent::debuggerScriptSource()
+{
+ return webkit_support::GetDevToolsDebuggerScriptSource();
+}
+
+WebDevToolsAgentClient::WebKitClientMessageLoop* DRTDevToolsAgent::createClientMessageLoop()
+{
+ return webkit_support::CreateDevToolsMessageLoop();
+}
+
+void DRTDevToolsAgent::asyncCall(const DRTDevToolsCallArgs& args)
+{
+ postTask(new AsyncCallTask(this, args));
+}
+
+void DRTDevToolsAgent::call(const DRTDevToolsCallArgs &args)
+{
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (agent)
+ agent->dispatchOnInspectorBackend(args.m_data);
+ if (DRTDevToolsCallArgs::callsCount() == 1 && m_drtDevToolsClient)
+ m_drtDevToolsClient->allMessagesProcessed();
+}
+
+void DRTDevToolsAgent::delayedFrontendLoaded()
+{
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (agent)
+ agent->frontendLoaded();
+}
+
+
+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;
+}
+
+void DRTDevToolsAgent::frontendLoaded()
+{
+ postTask(new DelayedFrontendLoadedTask(this));
+}
+
+bool DRTDevToolsAgent::setTimelineProfilingEnabled(bool enabled)
+{
+ WebDevToolsAgent* agent = webDevToolsAgent();
+ if (!agent)
+ return false;
+ agent->setTimelineProfilingEnabled(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;
+}
+
+// static method
+void DRTDevToolsAgent::dispatchMessageLoop()
+{
+ webkit_support::DispatchMessageLoop();
+}
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h
new file mode 100644
index 0000000..e1478d0
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsAgent.h
@@ -0,0 +1,105 @@
+/*
+ * 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 "DRTDevToolsCallArgs.h"
+#include "Task.h"
+#include "WebDevToolsAgentClient.h"
+#include <wtf/HashMap.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebKit {
+
+class WebCString;
+class WebDevToolsAgent;
+class WebString;
+class WebView;
+struct WebDevToolsMessageData;
+
+} // namespace WebKit
+
+class DRTDevToolsClient;
+
+class DRTDevToolsAgent : public WebKit::WebDevToolsAgentClient
+ , public Noncopyable {
+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 WebKit::WebCString debuggerScriptSource();
+ virtual WebKitClientMessageLoop* createClientMessageLoop();
+
+ void asyncCall(const DRTDevToolsCallArgs&);
+
+ void attach(DRTDevToolsClient*);
+ void detach();
+ void frontendLoaded();
+
+ bool evaluateInWebInspector(long callID, const std::string& script);
+ bool setTimelineProfilingEnabled(bool enable);
+ TaskList* taskList() { return &m_taskList; }
+
+private:
+ void call(const DRTDevToolsCallArgs&);
+ void delayedFrontendLoaded();
+ static void dispatchMessageLoop();
+ WebKit::WebDevToolsAgent* webDevToolsAgent();
+
+ class AsyncCallTask: public MethodTask<DRTDevToolsAgent> {
+ public:
+ AsyncCallTask(DRTDevToolsAgent* object, const DRTDevToolsCallArgs& args)
+ : MethodTask<DRTDevToolsAgent>(object), m_args(args) {}
+ virtual void runIfValid() { m_object->call(m_args); }
+ private:
+ DRTDevToolsCallArgs m_args;
+ };
+
+ struct DelayedFrontendLoadedTask: public MethodTask<DRTDevToolsAgent> {
+ DelayedFrontendLoadedTask(DRTDevToolsAgent* object) : MethodTask<DRTDevToolsAgent>(object) {}
+ virtual void runIfValid() { m_object->delayedFrontendLoaded(); }
+ };
+
+ 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/DRTDevToolsCallArgs.cpp b/Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.cpp
new file mode 100644
index 0000000..dacd6f7
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 "DRTDevToolsCallArgs.h"
+
+// static
+int DRTDevToolsCallArgs::m_callsCount = 0;
+
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.h b/Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.h
new file mode 100644
index 0000000..a548159
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsCallArgs.h
@@ -0,0 +1,65 @@
+/*
+ * 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 DRTDevToolsCallArgs_h
+#define DRTDevToolsCallArgs_h
+
+#include "WebString.h"
+#include <wtf/Assertions.h>
+
+class DRTDevToolsCallArgs {
+public:
+ DRTDevToolsCallArgs(const WebKit::WebString& data)
+ : m_data(data)
+ {
+ ++m_callsCount;
+ }
+
+ DRTDevToolsCallArgs(const DRTDevToolsCallArgs& args)
+ : m_data(args.m_data)
+ {
+ ++m_callsCount;
+ }
+
+ ~DRTDevToolsCallArgs()
+ {
+ --m_callsCount;
+ ASSERT(m_callsCount >= 0);
+ }
+
+ static int callsCount() { return m_callsCount; }
+
+ WebKit::WebString m_data;
+
+private:
+ static int m_callsCount;
+};
+
+#endif // DRTDevToolsCallArgs_h
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp
new file mode 100644
index 0000000..acccf18
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.cpp
@@ -0,0 +1,124 @@
+/*
+ * 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 "DRTDevToolsCallArgs.h"
+
+#include "WebDevToolsAgent.h"
+#include "WebDevToolsFrontend.h"
+#include "WebFrame.h"
+#include "WebScriptSource.h"
+#include "WebString.h"
+#include "WebView.h"
+#include "webkit/support/webkit_support.h"
+
+using namespace WebKit;
+
+DRTDevToolsClient::DRTDevToolsClient(DRTDevToolsAgent* agent, WebView* webView)
+ : m_webView(webView)
+ , m_drtDevToolsAgent(agent)
+{
+ m_webDevToolsFrontend.set(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::sendFrontendLoaded() {
+ if (m_drtDevToolsAgent)
+ m_drtDevToolsAgent->frontendLoaded();
+}
+
+void DRTDevToolsClient::sendMessageToBackend(const WebString& data)
+{
+ if (m_drtDevToolsAgent)
+ m_drtDevToolsAgent->asyncCall(DRTDevToolsCallArgs(data));
+}
+
+void DRTDevToolsClient::sendDebuggerCommandToAgent(const WebString& command)
+{
+ WebDevToolsAgent::executeDebuggerCommand(command, 1);
+}
+
+void DRTDevToolsClient::activateWindow()
+{
+ // Not implemented.
+}
+
+void DRTDevToolsClient::closeWindow()
+{
+ // Not implemented.
+}
+
+void DRTDevToolsClient::dockWindow()
+{
+ // Not implemented.
+}
+
+void DRTDevToolsClient::undockWindow()
+{
+ // Not implemented.
+}
+
+void DRTDevToolsClient::asyncCall(const DRTDevToolsCallArgs& args)
+{
+ postTask(new AsyncCallTask(this, args));
+}
+
+void DRTDevToolsClient::call(const DRTDevToolsCallArgs& args)
+{
+ m_webDevToolsFrontend->dispatchOnInspectorFrontend(args.m_data);
+ if (DRTDevToolsCallArgs::callsCount() == 1)
+ allMessagesProcessed();
+}
+
+void DRTDevToolsClient::allMessagesProcessed()
+{
+ m_webView->mainFrame()->executeScript(
+ WebKit::WebScriptSource(WebString::fromUTF8(
+ "if (window.WebInspector && WebInspector.queuesAreEmpty) WebInspector.queuesAreEmpty();")));
+}
diff --git a/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h
new file mode 100644
index 0000000..9ca1402
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DRTDevToolsClient.h
@@ -0,0 +1,90 @@
+/*
+ * 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 "DRTDevToolsCallArgs.h"
+#include "Task.h"
+#include "WebDevToolsFrontendClient.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebKit {
+
+class WebDevToolsFrontend;
+struct WebDevToolsMessageData;
+class WebString;
+class WebView;
+
+} // namespace WebKit
+
+class DRTDevToolsAgent;
+
+class DRTDevToolsClient : public WebKit::WebDevToolsFrontendClient
+ , public Noncopyable {
+public:
+ DRTDevToolsClient(DRTDevToolsAgent*, WebKit::WebView*);
+ virtual ~DRTDevToolsClient();
+ void reset();
+
+ // WebDevToolsFrontendClient implementation
+ virtual void sendFrontendLoaded();
+ virtual void sendMessageToBackend(const WebKit::WebString&);
+ virtual void sendDebuggerCommandToAgent(const WebKit::WebString& command);
+
+ virtual void activateWindow();
+ virtual void closeWindow();
+ virtual void dockWindow();
+ virtual void undockWindow();
+
+ void asyncCall(const DRTDevToolsCallArgs&);
+
+ void allMessagesProcessed();
+ TaskList* taskList() { return &m_taskList; }
+
+ private:
+ void call(const DRTDevToolsCallArgs&);
+ class AsyncCallTask: public MethodTask<DRTDevToolsClient> {
+ public:
+ AsyncCallTask(DRTDevToolsClient* object, const DRTDevToolsCallArgs& args)
+ : MethodTask<DRTDevToolsClient>(object), m_args(args) {}
+ virtual void runIfValid() { m_object->call(m_args); }
+ private:
+ DRTDevToolsCallArgs 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 0000000..3bbba98
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/DumpRenderTree.cpp
@@ -0,0 +1,214 @@
+/*
+ * 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 <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 optionTree[] = "--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 optionEnableAcceleratedCompositing[] = "--enable-accelerated-compositing";
+static const char optionEnableAccelerated2DCanvas[] = "--enable-accelerated-2d-canvas";
+
+static const char optionMultipleLoads[] = "--multiple-loads=";
+static const char optionJavaScriptFlags[] = "--js-flags=";
+
+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);
+ for (int i = 0; i < shell.loadCount(); i++) {
+ string javaScriptFlags = shell.javaScriptFlagsForLoad(i);
+ v8::V8::SetFlagsFromString(javaScriptFlags.data(), static_cast<int>(javaScriptFlags.size()));
+ bool isLastLoad = (i == (shell.loadCount() - 1));
+ shell.setDumpWhenFinished(isLastLoad);
+ shell.resetTestController();
+ shell.runFileTest(params);
+ }
+ shell.setLayoutTestTimeout(oldTimeoutMsec);
+}
+
+int main(int argc, char* argv[])
+{
+ webkit_support::SetUpTestEnvironment();
+ platformInit(&argc, &argv);
+
+ TestParams params;
+ Vector<string> tests;
+ bool serverMode = false;
+ bool testShellMode = false;
+ bool allowExternalPages = false;
+ bool startupDialog = false;
+ bool acceleratedCompositingEnabled = false;
+ bool accelerated2DCanvasEnabled = false;
+ int loadCount = 1;
+ string javaScriptFlags;
+ 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 == optionTestShell) {
+ testShellMode = true;
+ serverMode = true;
+ } else if (argument == optionAllowExternalPages)
+ allowExternalPages = true;
+ else if (argument == optionStartupDialog)
+ startupDialog = true;
+ else if (argument == optionCheckLayoutTestSystemDeps)
+ exit(checkLayoutTestSystemDependencies() ? EXIT_SUCCESS : EXIT_FAILURE);
+ else if (argument == optionEnableAcceleratedCompositing)
+ acceleratedCompositingEnabled = true;
+ else if (argument == optionEnableAccelerated2DCanvas)
+ accelerated2DCanvasEnabled = true;
+ else if (!argument.find(optionMultipleLoads)) {
+ string multipleLoadsStr = argument.substr(strlen(optionMultipleLoads));
+ loadCount = atoi(multipleLoadsStr.c_str());
+ } else if (!argument.find(optionJavaScriptFlags)) {
+ javaScriptFlags = argument.substr(strlen(optionJavaScriptFlags));
+ } 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 (loadCount < 1) {
+ fprintf(stderr, "--multiple-loads requires a positive numeric argument.\n");
+ return EXIT_FAILURE;
+ }
+
+ // The test runner might send a quoted string which needs to be unquoted before further processing.
+ if (javaScriptFlags.length() > 1 && javaScriptFlags[0] == '"' && javaScriptFlags[javaScriptFlags.length() - 1] == '"')
+ javaScriptFlags = javaScriptFlags.substr(1, javaScriptFlags.length() - 2);
+ // Split the JavaScript flags into a list.
+ Vector<string> flagsList;
+ size_t start = 0;
+ while (true) {
+ size_t commaPos = javaScriptFlags.find_first_of(',', start);
+ string flags;
+ if (commaPos == string::npos)
+ flags = javaScriptFlags.substr(start, javaScriptFlags.length() - start);
+ else {
+ flags = javaScriptFlags.substr(start, commaPos - start);
+ start = commaPos + 1;
+ }
+ flagsList.append(flags);
+ if (commaPos == string::npos)
+ break;
+ }
+
+ if (startupDialog)
+ openStartupDialog();
+
+ { // Explicit scope for the TestShell instance.
+ TestShell shell(testShellMode);
+ shell.setAllowExternalPages(allowExternalPages);
+ shell.setAcceleratedCompositingEnabled(acceleratedCompositingEnabled);
+ shell.setAccelerated2dCanvasEnabled(accelerated2DCanvasEnabled);
+ shell.setLoadCount(loadCount);
+ shell.setJavaScriptFlags(flagsList);
+ if (serverMode && !tests.size()) {
+ 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;
+ runTest(shell, params, testString, testShellMode);
+ }
+ } else if (!tests.size())
+ printf("#EOF\n");
+ 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();
+ }
+
+ webkit_support::TearDownTestEnvironment();
+ return EXIT_SUCCESS;
+}
diff --git a/Tools/DumpRenderTree/chromium/EventSender.cpp b/Tools/DumpRenderTree/chromium/EventSender.cpp
new file mode 100644
index 0000000..6104a90
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/EventSender.cpp
@@ -0,0 +1,1008 @@
+/*
+ * 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 "WebDragData.h"
+#include "WebDragOperation.h"
+#include "WebPoint.h"
+#include "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 gfx::Point& 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("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("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("zoomPageIn", &EventSender::zoomPageIn);
+ bindMethod("zoomPageOut", &EventSender::zoomPageOut);
+
+ // 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();
+}
+
+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, 0, clientPoint, screenPoint, currentDragEffectsAllowed);
+
+ // Finish processing events.
+ replaySavedEvents();
+}
+
+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)
+{
+ 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 {
+ // 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 WebKit/WebKitTools/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 (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/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
+ // WebKit/WebKitTools/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::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));
+}
+
+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, 0, 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;
+ touchPoint.id = touchPoints.size();
+ 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::touchPointsLengthCap) > touchPoints.size());
+ webview()->layout();
+
+ WebTouchEvent touchEvent;
+ touchEvent.type = type;
+ touchEvent.modifiers = touchModifiers;
+ touchEvent.timeStampSeconds = getCurrentEventTimeSec();
+ touchEvent.touchPointsLength = touchPoints.size();
+ for (unsigned i = 0; i < touchPoints.size(); ++i)
+ touchEvent.touchPoints[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();
+
+ 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;
+ 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);
+}
+
+//
+// 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 0000000..118509b
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/EventSender.h
@@ -0,0 +1,163 @@
+/*
+ * 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 "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);
+
+ // 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*);
+ void textZoomIn(const CppArgumentList&, CppVariant*);
+ void textZoomOut(const CppArgumentList&, CppVariant*);
+ void zoomPageIn(const CppArgumentList&, CppVariant*);
+ void zoomPageOut(const CppArgumentList&, CppVariant*);
+ void mouseScrollBy(const CppArgumentList&, CppVariant*);
+ void continuousMouseScrollBy(const CppArgumentList&, CppVariant*);
+ void scheduleAsynchronousClick(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*);
+
+ // 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 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/ImageDiff.cpp b/Tools/DumpRenderTree/chromium/ImageDiff.cpp
new file mode 100644
index 0000000..f2875dd
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/ImageDiff.cpp
@@ -0,0 +1,408 @@
+/*
+ * 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 <stdio.h>
+#include <string.h>
+#include <vector>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/Vector.h>
+
+#if OS(WINDOWS)
+#include <windows.h>
+#define PATH_MAX MAX_PATH
+#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";
+
+// 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 uint32_t rgbaRed = 0x000000ff;
+static const uint32_t 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 craeteFromStdin(size_t byteLength)
+ {
+ if (!byteLength)
+ return false;
+
+ OwnArrayPtr<unsigned char> source(new unsigned char[byteLength]);
+ if (fread(source.get(), 1, byteLength, stdin) != byteLength)
+ return false;
+
+ if (!webkit_support::DecodePNG(source.get(), byteLength, &m_data, &m_width, &m_height)) {
+ clear();
+ return false;
+ }
+ 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 uint32_t pixelAt(int x, int y) const
+ {
+ ASSERT(x >= 0 && x < m_width);
+ ASSERT(y >= 0 && y < m_height);
+ return *reinterpret_cast<const uint32_t*>(&(m_data[(y * m_width + x) * 4]));
+ }
+
+ void setPixelAt(int x, int y, uint32_t 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<uint32_t*>(addr) = color;
+ }
+
+private:
+ // pixel dimensions of the image
+ int m_width, m_height;
+
+ vector<unsigned char> m_data;
+};
+
+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;
+}
+
+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");
+ /* 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)
+{
+ 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 = percentageDifferent(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()
+{
+ 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.craeteFromStdin(imageSize)) {
+ fputs("Error, input image can't be decoded.\n", stderr);
+ return 1;
+ }
+ } else if (imageSize > 0 && !baselineImage.hasImage()) {
+ if (!baselineImage.craeteFromStdin(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 = percentageDifferent(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++) {
+ uint32_t 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.
+ uint32_t alpha = basePixel & rgbaAlpha;
+ uint32_t 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)
+{
+ 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;
+ return statusDifferent;
+}
+
+int main(int argc, const char* argv[])
+{
+ Vector<const char*> values;
+ bool pollStdin = false;
+ bool generateDiff = false;
+ for (int i = 1; i < argc; ++i) {
+ if (!strcmp(argv[i], optionPollStdin))
+ pollStdin = true;
+ else if (!strcmp(argv[i], optionGenerateDiff))
+ generateDiff = true;
+ else
+ values.append(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) == 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]);
+ } else if (values.size() == 2)
+ return compareImages(argv[1], argv[2]);
+
+ printHelp();
+ return statusError;
+}
diff --git a/Tools/DumpRenderTree/chromium/LayoutTestController.cpp b/Tools/DumpRenderTree/chromium/LayoutTestController.cpp
new file mode 100644
index 0000000..e3af738
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/LayoutTestController.cpp
@@ -0,0 +1,1590 @@
+/*
+ * 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 "WebData.h"
+#include "WebDeviceOrientation.h"
+#include "WebDeviceOrientationClientMock.h"
+#include "WebDocument.h"
+#include "WebElement.h"
+#include "WebFrame.h"
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+#include "WebGeolocationClientMock.h"
+#else
+#include "WebGeolocationServiceMock.h"
+#endif
+#include "WebInputElement.h"
+#include "WebKit.h"
+#include "WebNotificationPresenter.h"
+#include "WebScriptSource.h"
+#include "WebSecurityPolicy.h"
+#include "WebSettings.h"
+#include "WebSize.h"
+#include "WebSpeechInputControllerMock.h"
+#include "WebURL.h"
+#include "WebView.h"
+#include "WebViewHost.h"
+#include "webkit/support/webkit_support.h"
+#include <algorithm>
+#include <cstdlib>
+#include <limits>
+#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_workQueue(this)
+{
+
+ // 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("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("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("dumpUserGestureInFrameLoadCallbacks", &LayoutTestController::dumpUserGestureInFrameLoadCallbacks);
+ bindMethod("dumpResourceLoadCallbacks", &LayoutTestController::dumpResourceLoadCallbacks);
+ bindMethod("dumpResourceResponseMIMETypes", &LayoutTestController::dumpResourceResponseMIMETypes);
+ bindMethod("dumpSelectionRect", &LayoutTestController::dumpSelectionRect);
+ bindMethod("dumpStatusCallbacks", &LayoutTestController::dumpWindowStatusChanges);
+ bindMethod("dumpTitleChanges", &LayoutTestController::dumpTitleChanges);
+ bindMethod("elementDoesAutoCompleteForElementWithId", &LayoutTestController::elementDoesAutoCompleteForElementWithId);
+ bindMethod("evaluateInWebInspector", &LayoutTestController::evaluateInWebInspector);
+ bindMethod("evaluateScriptInIsolatedWorld", &LayoutTestController::evaluateScriptInIsolatedWorld);
+ bindMethod("execCommand", &LayoutTestController::execCommand);
+ bindMethod("forceRedSelectionColors", &LayoutTestController::forceRedSelectionColors);
+ bindMethod("grantDesktopNotificationPermission", &LayoutTestController::grantDesktopNotificationPermission);
+ bindMethod("isCommandEnabled", &LayoutTestController::isCommandEnabled);
+ bindMethod("layerTreeAsText", &LayoutTestController::layerTreeAsText);
+ bindMethod("markerTextForListItem", &LayoutTestController::markerTextForListItem);
+ bindMethod("hasSpellingMarker", &LayoutTestController::hasSpellingMarker);
+ bindMethod("notifyDone", &LayoutTestController::notifyDone);
+ bindMethod("numberOfActiveAnimations", &LayoutTestController::numberOfActiveAnimations);
+ bindMethod("numberOfPages", &LayoutTestController::numberOfPages);
+ bindMethod("objCIdentityIsEqual", &LayoutTestController::objCIdentityIsEqual);
+ bindMethod("overridePreference", &LayoutTestController::overridePreference);
+ bindMethod("pageNumberForElementById", &LayoutTestController::pageNumberForElementById);
+ 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("resumeAnimations", &LayoutTestController::resumeAnimations);
+ bindMethod("sampleSVGAnimationForElementAtTime", &LayoutTestController::sampleSVGAnimationForElementAtTime);
+ bindMethod("setAcceptsEditing", &LayoutTestController::setAcceptsEditing);
+ bindMethod("setAllowFileAccessFromFileURLs", &LayoutTestController::setAllowFileAccessFromFileURLs);
+ bindMethod("setAllowUniversalAccessFromFileURLs", &LayoutTestController::setAllowUniversalAccessFromFileURLs);
+ bindMethod("setAlwaysAcceptCookies", &LayoutTestController::setAlwaysAcceptCookies);
+ bindMethod("setAuthorAndUserStylesEnabled", &LayoutTestController::setAuthorAndUserStylesEnabled);
+ 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("setGeolocationPermission", &LayoutTestController::setGeolocationPermission);
+ bindMethod("setIconDatabaseEnabled", &LayoutTestController::setIconDatabaseEnabled);
+ bindMethod("setJavaScriptCanAccessClipboard", &LayoutTestController::setJavaScriptCanAccessClipboard);
+ bindMethod("setMockDeviceOrientation", &LayoutTestController::setMockDeviceOrientation);
+ bindMethod("setMockGeolocationError", &LayoutTestController::setMockGeolocationError);
+ bindMethod("setMockGeolocationPosition", &LayoutTestController::setMockGeolocationPosition);
+ bindMethod("addMockSpeechInputResult", &LayoutTestController::addMockSpeechInputResult);
+ bindMethod("setPopupBlockingEnabled", &LayoutTestController::setPopupBlockingEnabled);
+ bindMethod("setPOSIXLocale", &LayoutTestController::setPOSIXLocale);
+ bindMethod("setScrollbarPolicy", &LayoutTestController::setScrollbarPolicy);
+ bindMethod("setSelectTrailingWhitespaceEnabled", &LayoutTestController::setSelectTrailingWhitespaceEnabled);
+ bindMethod("setSmartInsertDeleteEnabled", &LayoutTestController::setSmartInsertDeleteEnabled);
+ bindMethod("setStopProvisionalFrameLoads", &LayoutTestController::setStopProvisionalFrameLoads);
+ bindMethod("setTabKeyCyclesThroughElements", &LayoutTestController::setTabKeyCyclesThroughElements);
+ bindMethod("setTimelineProfilingEnabled", &LayoutTestController::setTimelineProfilingEnabled);
+ bindMethod("setUserStyleSheetEnabled", &LayoutTestController::setUserStyleSheetEnabled);
+ bindMethod("setUserStyleSheetLocation", &LayoutTestController::setUserStyleSheetLocation);
+ 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("suspendAnimations", &LayoutTestController::suspendAnimations);
+ bindMethod("testRepaint", &LayoutTestController::testRepaint);
+ bindMethod("waitForPolicyDelegate", &LayoutTestController::waitForPolicyDelegate);
+ bindMethod("waitUntilDone", &LayoutTestController::waitUntilDone);
+ bindMethod("windowCount", &LayoutTestController::windowCount);
+
+ // The following are stubs.
+ bindMethod("abortModal", &LayoutTestController::abortModal);
+ bindMethod("accessStoredWebScriptObject", &LayoutTestController::accessStoredWebScriptObject);
+ bindMethod("addDisallowedURL", &LayoutTestController::addDisallowedURL);
+ bindMethod("callShouldCloseOnWebView", &LayoutTestController::callShouldCloseOnWebView);
+ bindMethod("clearAllApplicationCaches", &LayoutTestController::clearAllApplicationCaches);
+ 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);
+
+ // 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);
+}
+
+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::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::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()->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) {}
+ bool run(TestShell* shell)
+ {
+ shell->webView()->mainFrame()->loadHTMLString(
+ WebKit::WebData(m_html.data(), m_html.length()), m_baseURL);
+ return true;
+ }
+private:
+ std::string m_html;
+ WebURL m_baseURL;
+};
+
+void LayoutTestController::queueLoadHTMLString(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() > 0 && arguments[0].isString()) {
+ string html = arguments[0].toString();
+ WebURL baseURL;
+ if (arguments.size() > 1 && arguments[1].isString())
+ baseURL = WebURL(GURL(arguments[1].toString()));
+ 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_dumpEditingCallbacks = false;
+ m_dumpFrameLoadCallbacks = 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_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_userStyleSheetLocation = WebURL();
+
+ 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();
+}
+
+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&, CppVariant*)
+{
+ // FIXME: Implement this.
+}
+
+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::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::setApplicationCacheOriginQuota(const CppArgumentList&, CppVariant* result)
+{
+ // FIXME: implement to support Application Cache Quotas.
+ 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(new WCHAR[bufferSize]);
+ DWORD tempLength = ::GetTempPathW(bufferSize, tempPath.get());
+ if (tempLength + url.length() - tempPrefixLength + 1 > bufferSize) {
+ bufferSize = tempLength + url.length() - tempPrefixLength + 1;
+ tempPath.set(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;
+ }
+ m_shell->notificationPresenter()->grantPermission(cppVariantToWebString(arguments[0]));
+ result->set(true);
+}
+
+void LayoutTestController::simulateDesktopNotificationClick(const CppArgumentList& arguments, CppVariant* result)
+{
+ if (arguments.size() != 1 || !arguments[0].isString()) {
+ result->set(false);
+ return;
+ }
+ if (m_shell->notificationPresenter()->simulateClick(cppVariantToWebString(arguments[0])))
+ result->set(true);
+ else
+ 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::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::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::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();
+}
+
+// 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());
+}
+
+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 == "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 == "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 {
+ 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());
+}
+
+static bool parsePageSizeParameters(const CppArgumentList& arguments,
+ int argOffset,
+ float* pageWidthInPixels,
+ float* pageHeightInPixels)
+{
+ // WebKit is using the window width/height of DumpRenderTree as the
+ // default value of the page size.
+ // FIXME: share these values with other ports.
+ *pageWidthInPixels = 800;
+ *pageHeightInPixels = 600;
+ switch (arguments.size() - argOffset) {
+ case 2:
+ if (!arguments[argOffset].isNumber() || !arguments[1 + argOffset].isNumber())
+ return false;
+ *pageWidthInPixels = static_cast<float>(arguments[argOffset].toInt32());
+ *pageHeightInPixels = static_cast<float>(arguments[1 + argOffset].toInt32());
+ // fall through.
+ case 0:
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+void LayoutTestController::pageNumberForElementById(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ float pageWidthInPixels = 0;
+ float 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]),
+ pageWidthInPixels, pageHeightInPixels));
+}
+
+void LayoutTestController::numberOfPages(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ float pageWidthInPixels = 0;
+ float 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::logErrorToConsole(const std::string& text)
+{
+ m_shell->webViewHost()->didAddMessageToConsole(
+ WebConsoleMessage(WebConsoleMessage::LevelError, WebString::fromUTF8(text)),
+ WebString(), 0);
+}
+
+void LayoutTestController::setTimelineProfilingEnabled(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isBool())
+ return;
+ m_shell->drtDevToolsAgent()->setTimelineProfilingEnabled(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);
+}
+
+void LayoutTestController::setGeolocationPermission(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 1 || !arguments[0].isBool())
+ return;
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ m_shell->webViewHost()->geolocationClientMock()->setPermission(arguments[0].toBoolean());
+#else
+ WebGeolocationServiceMock::setMockGeolocationPermission(arguments[0].toBoolean());
+#endif
+}
+
+void LayoutTestController::setMockGeolocationPosition(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 3 || !arguments[0].isNumber() || !arguments[1].isNumber() || !arguments[2].isNumber())
+ return;
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ m_shell->webViewHost()->geolocationClientMock()->setPosition(arguments[0].toDouble(), arguments[1].toDouble(), arguments[2].toDouble());
+#else
+ WebGeolocationServiceMock::setMockGeolocationPosition(arguments[0].toDouble(), arguments[1].toDouble(), arguments[2].toDouble());
+#endif
+}
+
+void LayoutTestController::setMockGeolocationError(const CppArgumentList& arguments, CppVariant* result)
+{
+ result->setNull();
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isString())
+ return;
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ m_shell->webViewHost()->geolocationClientMock()->setError(arguments[0].toInt32(), cppVariantToWebString(arguments[1]));
+#else
+ WebGeolocationServiceMock::setMockGeolocationError(arguments[0].toInt32(), cppVariantToWebString(arguments[1]));
+#endif
+}
+
+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;
+
+ m_shell->webViewHost()->speechInputControllerMock()->addMockRecognitionResult(cppVariantToWebString(arguments[0]), arguments[1].toDouble(), cppVariantToWebString(arguments[2]));
+}
+
+void LayoutTestController::layerTreeAsText(const CppArgumentList& args, CppVariant* result)
+{
+ result->set(m_shell->webView()->mainFrame()->layerTreeAsText().utf8());
+}
+
+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()));
+}
diff --git a/Tools/DumpRenderTree/chromium/LayoutTestController.h b/Tools/DumpRenderTree/chromium/LayoutTestController.h
new file mode 100644
index 0000000..13d1447
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/LayoutTestController.h
@@ -0,0 +1,551 @@
+/*
+ * 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 "WebString.h"
+#include "WebURL.h"
+#include <wtf/Deque.h>
+#include <wtf/OwnPtr.h>
+
+namespace WebKit {
+class WebGeolocationClientMock;
+class WebSpeechInputController;
+class WebSpeechInputControllerMock;
+class WebSpeechInputListener;
+}
+
+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
+ // 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*);
+
+ // 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*);
+
+ // The following are only stubs. TODO(pamg): 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 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 evaluateScriptInIsolatedWorld(const CppArgumentList&, CppVariant*);
+ void overridePreference(const CppArgumentList&, CppVariant*);
+ void setAllowUniversalAccessFromFileURLs(const CppArgumentList&, CppVariant*);
+ void setAllowFileAccessFromFileURLs(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*);
+ // Sets the Application Quota for the localhost origin.
+ void setApplicationCacheOriginQuota(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*);
+
+ // Gets the number of page where the specified element will be put.
+ void pageNumberForElementById(const CppArgumentList&, CppVariant*);
+
+ // Gets the number of pages to be printed.
+ void numberOfPages(const CppArgumentList&, CppVariant*);
+
+
+ // Allows layout tests to start Timeline profiling.
+ void setTimelineProfilingEnabled(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 layerTreeAsText(const CppArgumentList& args, CppVariant* result);
+
+ void markerTextForListItem(const CppArgumentList&, CppVariant*);
+ void hasSpellingMarker(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 shouldDumpAsText() { return m_dumpAsText; }
+ bool shouldDumpEditingCallbacks() { return m_dumpEditingCallbacks; }
+ bool shouldDumpFrameLoadCallbacks() { return m_dumpFrameLoadCallbacks; }
+ void setShouldDumpFrameLoadCallbacks(bool value) { m_dumpFrameLoadCallbacks = 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 shouldDumpChildFrameScrollPositions() { return m_dumpChildFrameScrollPositions; }
+ bool shouldDumpChildFramesAsText() { return m_dumpChildFramesAsText; }
+ bool shouldGeneratePixelResults() { return m_generatePixelResults; }
+ 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; }
+
+ 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* shell) = 0;
+ };
+
+ TaskList* taskList() { return &m_taskList; }
+
+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* work);
+
+ 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&);
+
+ 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 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 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, the test_shell will generate pixel results in dumpAsText mode
+ bool m_generatePixelResults;
+
+ // 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;
+
+ WorkQueue m_workQueue;
+
+ CppVariant m_globalFlag;
+
+ // Bound variable counting the number of top URLs visited.
+ CppVariant m_webHistoryItemCount;
+
+ WebKit::WebURL m_userStyleSheetLocation;
+
+ OwnPtr<WebKit::WebSpeechInputControllerMock> m_speechInputControllerMock;
+};
+
+#endif // LayoutTestController_h
diff --git a/Tools/DumpRenderTree/chromium/LayoutTestHelper.mm b/Tools/DumpRenderTree/chromium/LayoutTestHelper.mm
new file mode 100644
index 0000000..e34cf5f
--- /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 0000000..25efdcd
--- /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 0000000..7243152
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/MockSpellCheck.cpp
@@ -0,0 +1,156 @@
+/*
+ * 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 "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().
+ const WTF::String stringText(text.data(), text.length());
+
+ // 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 ? 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))
+ return true;
+
+ *misspelledOffset = wordOffset;
+ *misspelledLength = 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 0000000..dcd37f3
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/MockSpellCheck.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 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 0000000..7e7053b
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/NotificationPresenter.cpp
@@ -0,0 +1,148 @@
+/*
+ * 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"
+
+#include "WebKit.h"
+#include "WebKitClient.h"
+#include "WebNotification.h"
+#include "WebNotificationPermissionCallback.h"
+#include "WebSecurityOrigin.h"
+#include "WebString.h"
+#include "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;
+}
+
+void NotificationPresenter::grantPermission(const WebString& origin)
+{
+ // Make sure it's in the form of an origin.
+ GURL url(origin);
+ m_allowedOrigins.add(WTF::String(url.GetOrigin().spec().c_str()));
+}
+
+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.dir() == "rtl" ? "(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);
+
+ webKitClient()->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 WebURL& url)
+{
+ // Check with the layout test controller
+ WTF::String origin = WTF::String(static_cast<GURL>(url).GetOrigin().spec().c_str());
+ bool allowed = m_allowedOrigins.find(origin) != 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();
+}
diff --git a/Tools/DumpRenderTree/chromium/NotificationPresenter.h b/Tools/DumpRenderTree/chromium/NotificationPresenter.h
new file mode 100644
index 0000000..689a908
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/NotificationPresenter.h
@@ -0,0 +1,77 @@
+/*
+ * 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) {}
+
+ // 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::WebURL&);
+ 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 0000000..c8bdabd
--- /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 "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 0000000..3d3a04c
--- /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 0000000..007a479
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/Task.cpp
@@ -0,0 +1,75 @@
+/*
+ * 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 "WebKitClient.h"
+#include "webkit/support/webkit_support.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::webKitClient()->callOnMainThread(invokeTask, static_cast<void*>(task));
+}
+
+void postDelayedTask(WebTask* task, int64_t ms)
+{
+ webkit_support::PostDelayedTask(invokeTask, static_cast<void*>(task), ms);
+}
+
+
diff --git a/Tools/DumpRenderTree/chromium/Task.h b/Tools/DumpRenderTree/chromium/Task.h
new file mode 100644
index 0000000..f29dc7d
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/Task.h
@@ -0,0 +1,88 @@
+/*
+ * 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 <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:
+ 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();
+protected:
+ TaskList* m_taskList;
+};
+
+class TaskList {
+public:
+ TaskList() {}
+ ~TaskList() { revokeAll(); }
+ void registerTask(WebTask* task) { m_tasks.append(task); }
+ void unregisterTask(WebTask* task);
+ 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* task);
+void postDelayedTask(WebTask* task, 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 0000000..2130534
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestEventPrinter.cpp
@@ -0,0 +1,168 @@
+/*
+ * 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 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 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::createDRTPrinter()
+{
+ return new DRTPrinter;
+}
+
+TestEventPrinter* TestEventPrinter::createTestShellPrinter()
+{
+ return 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::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::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 0000000..fdbfd02
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestEventPrinter.h
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+class TestEventPrinter {
+public:
+ static TestEventPrinter* createDRTPrinter();
+ static TestEventPrinter* createTestShellPrinter();
+
+ 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 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;
+};
diff --git a/Tools/DumpRenderTree/chromium/TestNavigationController.cpp b/Tools/DumpRenderTree/chromium/TestNavigationController.cpp
new file mode 100644
index 0000000..9653c07
--- /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. TODO(darin): 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 0000000..b671489
--- /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 "WebString.h"
+#include "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: public Noncopyable {
+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 0000000..9fa3fff
--- /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 0000000..59ae666
--- /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 0000000..597d4ad
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/ForwardingHeaders/WebKit/npruntime.h
@@ -0,0 +1 @@
+#include "bindings/npruntime.h"
diff --git a/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/Info.plist b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/Info.plist
new file mode 100644
index 0000000..663f058
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestNetscapePlugIn/Info.plist
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//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>WebKitTestNetscapePlugIn</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>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/chromium/TestShell.cpp b/Tools/DumpRenderTree/chromium/TestShell.cpp
new file mode 100644
index 0000000..21f4208
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShell.cpp
@@ -0,0 +1,621 @@
+/*
+ * 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 "WebDataSource.h"
+#include "WebDocument.h"
+#include "WebElement.h"
+#include "WebFrame.h"
+#include "WebHistoryItem.h"
+#include "WebKit.h"
+#include "WebRuntimeFeatures.h"
+#include "WebScriptController.h"
+#include "WebSettings.h"
+#include "WebSize.h"
+#include "WebSpeechInputControllerMock.h"
+#include "WebString.h"
+#include "WebURLRequest.h"
+#include "WebURLResponse.h"
+#include "WebView.h"
+#include "WebViewHost.h"
+#include "skia/ext/bitmap_platform_device.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;
+
+TestShell::TestShell(bool testShellMode)
+ : m_testIsPending(false)
+ , m_testIsPreparing(false)
+ , m_focusedWidget(0)
+ , m_testShellMode(testShellMode)
+ , m_devTools(0)
+ , m_allowExternalPages(false)
+ , m_acceleratedCompositingEnabled(false)
+ , m_accelerated2dCanvasEnabled(false)
+ , m_loadCount(1)
+ , m_dumpWhenFinished(true)
+{
+ WebRuntimeFeatures::enableGeolocation(true);
+ WebRuntimeFeatures::enableIndexedDatabase(true);
+ WebRuntimeFeatures::enableFileSystem(true);
+ m_accessibilityController.set(new AccessibilityController(this));
+ m_layoutTestController.set(new LayoutTestController(this));
+ m_eventSender.set(new EventSender(this));
+ m_plainTextController.set(new PlainTextController());
+ m_textInputController.set(new TextInputController(this));
+ m_notificationPresenter.set(new NotificationPresenter(this));
+ m_printer.set(m_testShellMode ? TestEventPrinter::createTestShellPrinter() : TestEventPrinter::createDRTPrinter());
+
+ // 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;
+
+ m_drtDevToolsAgent.set(new DRTDevToolsAgent);
+ m_webViewHost = createWebView();
+ 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);
+}
+
+void TestShell::createDRTDevToolsClient(DRTDevToolsAgent* agent)
+{
+ m_drtDevToolsClient.set(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);
+ ASSERT(m_devTools);
+ createDRTDevToolsClient(m_drtDevToolsAgent.get());
+ }
+ m_devTools->show(WebKit::WebNavigationPolicyNewWindow);
+}
+
+void TestShell::closeDevTools()
+{
+ if (m_devTools) {
+ m_drtDevToolsAgent->reset();
+ m_drtDevToolsClient.clear();
+ closeWindow(m_devTools);
+ m_devTools = 0;
+ }
+}
+
+void TestShell::resetWebSettings(WebView& webView)
+{
+ m_prefs.reset();
+ m_prefs.acceleratedCompositingEnabled = m_acceleratedCompositingEnabled;
+ m_prefs.accelerated2dCanvasEnabled = m_accelerated2dCanvasEnabled;
+ 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();
+
+ bool inspectorTestMode = testUrl.find("/inspector/") != string::npos
+ || testUrl.find("\\inspector\\") != string::npos;
+ m_prefs.developerExtrasEnabled = inspectorTestMode;
+ applyPreferences();
+
+ if (testUrl.find("loading/") != string::npos
+ || testUrl.find("loading\\") != string::npos)
+ m_layoutTestController->setShouldDumpFrameLoadCallbacks(true);
+
+ if (inspectorTestMode)
+ showDevTools();
+
+ 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_accessibilityController->reset();
+ m_layoutTestController->reset();
+ m_eventSender->reset();
+ m_webViewHost->reset();
+ m_notificationPresenter->reset();
+ m_drtDevToolsAgent->reset();
+ if (m_drtDevToolsClient)
+ m_drtDevToolsClient->reset();
+}
+
+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 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 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 = item.urlString().utf8();
+ size_t pos;
+ if (!url.find(fileUrlPattern) && ((pos = url.find(layoutTestsPattern)) != string::npos)) {
+ // adjust file URLs to match upstream results.
+ url.replace(0, pos + layoutTestsPatternSize, fileTestPrefix);
+ } else if (!url.find(dataUrlPattern)) {
+ // URL-escape data URLs to match results upstream.
+ string path = webkit_support::EscapePath(url.substr(dataUrlPatternSize));
+ url.replace(dataUrlPatternSize, url.length(), path);
+ }
+
+ 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 shouldGeneratePixelResults = m_layoutTestController->shouldGeneratePixelResults();
+ bool dumpedAnything = false;
+ 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 = dumpFramesAsText(frame, recursive);
+ if (fwrite(dataUtf8.c_str(), 1, dataUtf8.size(), stdout) != dataUtf8.size())
+ FATAL("Short write to stdout, disk full?\n");
+ } else {
+ printf("%s", frame->renderTreeAsText().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
+ 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(skia::PlatformCanvas* canvas) const
+{
+ skia::BitmapPlatformDevice& device =
+ static_cast<skia::BitmapPlatformDevice&>(canvas->getTopPlatformDevice());
+ const SkBitmap& sourceBitmap = device.accessBitmap(false);
+
+ SkAutoLockPixels sourceBitmapLock(sourceBitmap);
+
+ // 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;
+ device.makeOpaque(0, 0, sourceBitmap.width(), sourceBitmap.height());
+#endif
+
+ // 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::EncodeBGRAPNG(
+ reinterpret_cast<const unsigned char*>(sourceBitmap.getPixels()),
+ sourceBitmap.width(), sourceBitmap.height(),
+ static_cast<int>(sourceBitmap.rowBytes()), discardTransparency, &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)
+{
+ m_accessibilityController->bindToJavascript(frame, WebString::fromUTF8("accessibilityController"));
+ 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::createWebView()
+{
+ return createNewWindow(WebURL());
+}
+
+WebViewHost* TestShell::createNewWindow(const WebURL& url)
+{
+ WebViewHost* host = new WebViewHost(this);
+ WebView* view = WebView::create(host, m_drtDevToolsAgent.get());
+ 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();
+}
diff --git a/Tools/DumpRenderTree/chromium/TestShell.h b/Tools/DumpRenderTree/chromium/TestShell.h
new file mode 100644
index 0000000..1da4e17
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShell.h
@@ -0,0 +1,221 @@
+/*
+ * 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 "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 WebView;
+class WebURL;
+}
+namespace skia {
+class PlatformCanvas;
+}
+
+class DRTDevToolsAgent;
+class DRTDevToolsCallArgs;
+class DRTDevToolsClient;
+
+struct TestParams {
+ bool dumpTree;
+ bool dumpPixels;
+ 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)
+ , 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; }
+ LayoutTestController* layoutTestController() const { return m_layoutTestController.get(); }
+ EventSender* eventSender() const { return m_eventSender.get(); }
+ AccessibilityController* accessibilityController() const { return m_accessibilityController.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); }
+
+ void bindJSObjectsToWindow(WebKit::WebFrame*);
+ void runFileTest(const TestParams&);
+ void callJSGC();
+ void resetTestController();
+ void waitTestFinished();
+
+ // Operations to the main window.
+ void loadURL(const WebKit::WebURL& url);
+ 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 setAcceleratedCompositingEnabled(bool enabled) { m_acceleratedCompositingEnabled = enabled; }
+ void setAccelerated2dCanvasEnabled(bool enabled) { m_accelerated2dCanvasEnabled = 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; }
+
+ // Number of times to load each URL.
+ int loadCount() { return m_loadCount; }
+ void setLoadCount(int loadCount) { m_loadCount = loadCount; }
+
+ // The JavaScript flags are specified as a vector of strings. Each element of the vector is full flags string
+ // which can contain multiple flags (e.g. "--xxx --yyy"). With multiple load testing it is possible to specify
+ // separate sets of flags to each load.
+ std::string javaScriptFlagsForLoad(size_t load) { return (load < m_javaScriptFlags.size()) ? m_javaScriptFlags[load] : ""; }
+ void setJavaScriptFlags(Vector<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* createWebView();
+ 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;
+
+private:
+ void createDRTDevToolsClient(DRTDevToolsAgent*);
+
+ void resetWebSettings(WebKit::WebView&);
+ void dump();
+ std::string dumpAllBackForwardLists();
+ void dumpImage(skia::PlatformCanvas*) const;
+
+ bool m_testIsPending;
+ bool m_testIsPreparing;
+ bool m_isLoading;
+ WebKit::WebView* m_webView;
+ WebKit::WebWidget* m_focusedWidget;
+ bool m_testShellMode;
+ WebViewHost* m_webViewHost;
+ WebViewHost* m_devTools;
+ OwnPtr<DRTDevToolsAgent> m_drtDevToolsAgent;
+ OwnPtr<DRTDevToolsClient> m_drtDevToolsClient;
+ OwnPtr<AccessibilityController> m_accessibilityController;
+ OwnPtr<EventSender> m_eventSender;
+ OwnPtr<LayoutTestController> m_layoutTestController;
+ OwnPtr<PlainTextController> m_plainTextController;
+ OwnPtr<TextInputController> m_textInputController;
+ OwnPtr<NotificationPresenter> m_notificationPresenter;
+ OwnPtr<TestEventPrinter> m_printer;
+ TestParams m_params;
+ int m_timeout; // timeout value in millisecond
+ bool m_allowExternalPages;
+ bool m_acceleratedCompositingEnabled;
+ bool m_accelerated2dCanvasEnabled;
+ WebPreferences m_prefs;
+ int m_loadCount;
+ Vector<std::string> m_javaScriptFlags;
+ bool m_dumpWhenFinished;
+
+
+ // List of all windows in this process.
+ // The main window should be put into windowList[0].
+ typedef Vector<WebViewHost*> WindowList;
+ 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 0000000..1cf7c56
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShellGtk.cpp
@@ -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.
+ */
+
+#include "config.h"
+#include "TestShell.h"
+
+#include "webkit/support/webkit_support.h"
+#include <fontconfig/fontconfig.h>
+#include <gtk/gtk.h>
+#include <signal.h>
+
+static void AlarmHandler(int signatl)
+{
+ // 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);
+}
+
+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",
+ // 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_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 installing msttcorefonts. Also see "
+ "http://code.google.com/p/chromium/wiki/LinuxBuildInstructions",
+ 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-lucida/LucidaSansRegular.ttf",
+ "/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/LinuxBuildInstructionsPrerequisites "
+ "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);
+ }
+}
+
+void TestShell::waitTestFinished()
+{
+ ASSERT(!m_testIsPending);
+
+ m_testIsPending = true;
+
+ // Install an alarm signal handler that will kill us if we time out.
+ signal(SIGALRM, AlarmHandler);
+ 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);
+ signal(SIGALRM, SIG_DFL);
+}
+
+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#
+ gtk_init(argc, argv);
+
+ setupFontconfig();
+}
+
+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/TestShellMac.mm b/Tools/DumpRenderTree/chromium/TestShellMac.mm
new file mode 100644
index 0000000..53ede56
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShellMac.mm
@@ -0,0 +1,145 @@
+/*
+ * 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"
+#import <AppKit/AppKit.h>
+
+// 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***)
+{
+}
+
+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/TestShellWin.cpp b/Tools/DumpRenderTree/chromium/TestShellWin.cpp
new file mode 100644
index 0000000..3b3ddd9
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TestShellWin.cpp
@@ -0,0 +1,244 @@
+/*
+ * 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()
+{
+ std::list<std::string> errors;
+
+ OSVERSIONINFOEX versionInfo;
+ ::ZeroMemory(&versionInfo, sizeof(OSVERSIONINFOEX));
+ versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
+ ::GetVersionEx(reinterpret_cast<OSVERSIONINFO*>(&versionInfo));
+
+ // Default to XP metrics, override if on Vista or win 7.
+ int requiredVScrollSize = 17;
+ int requiredFontSize = -11; // 8 pt
+ const wchar_t* requiredFont = L"Tahoma";
+ bool isVista = false;
+ bool isWin7 = false;
+ const DWORD major = versionInfo.dwMajorVersion;
+ const DWORD minor = versionInfo.dwMinorVersion;
+ const WORD type = versionInfo.wProductType;
+ if (major == 6 && minor == 1 && type == VER_NT_WORKSTATION) {
+ requiredFont = L"Segoe UI";
+ requiredFontSize = -12;
+ isWin7 = true;
+ } else if (major == 6 && !minor && type == VER_NT_WORKSTATION) {
+ requiredFont = L"Segoe UI";
+ requiredFontSize = -12; // 9 pt
+ isVista = true;
+ } else if (!(major == 5 && minor == 1 && type == VER_NT_WORKSTATION)) {
+ // The above check is for XP, so that means ...
+ errors.push_back("Unsupported Operating System version "
+ "(must use XP, Vista, or Windows 7).");
+ }
+
+ // This metric will be 17 when font size is "Normal".
+ // The size of drop-down menus depends on it.
+ int verticalScrollSize = ::GetSystemMetrics(SM_CXVSCROLL);
+ 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
+ NONCLIENTMETRICS metrics;
+ // Checks Vista or later.
+ metrics.cbSize = major >= 6 ? 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};
+
+ for (size_t i = 0; i < arraysize(systemFonts); ++i) {
+ if (systemFonts[i]->lfHeight != requiredFontSize || wcscmp(requiredFont, systemFonts[i]->lfFaceName)) {
+ if (isVista || isWin7)
+ errors.push_back("Must use either the Aero or Basic theme.");
+ else
+ errors.push_back("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/TestWebWorker.h b/Tools/DumpRenderTree/chromium/TestWebWorker.h
new file mode 100644
index 0000000..89e19af
--- /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 "WebWorker.h"
+#include "WebWorkerClient.h"
+#include <wtf/RefCounted.h>
+
+namespace WebKit {
+class WebNotificationPresenter;
+class WebString;
+class WebURL;
+}
+
+class TestWebWorker : public WebKit::WebWorker,
+ public WebKit::WebWorkerClient,
+ 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::WebWorkerClient*) { 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 0000000..3603840
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/TextInputController.cpp
@@ -0,0 +1,262 @@
+/*
+ * 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 "WebString.h"
+#include "WebVector.h"
+#include "WebView.h"
+#include <wtf/StringExtras.h>
+#include <string>
+
+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();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+ if (arguments.size() < 1 || !arguments[0].isString())
+ return;
+
+ if (mainFrame->hasMarkedText()) {
+ mainFrame->unmarkText();
+ mainFrame->replaceSelection(WebString());
+ }
+ mainFrame->insertText(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();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ if (arguments.size() >= 3 && arguments[0].isString()
+ && arguments[1].isNumber() && arguments[2].isNumber()) {
+ mainFrame->setMarkedText(WebString::fromUTF8(arguments[0].toString()),
+ arguments[1].toInt32(),
+ arguments[2].toInt32());
+ }
+}
+
+void TextInputController::unmarkText(const CppArgumentList&, CppVariant* result)
+{
+ result->setNull();
+
+ WebFrame* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ mainFrame->unmarkText();
+}
+
+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* mainFrame = getMainFrame();
+ if (!mainFrame)
+ return;
+
+ if (arguments.size() < 2 || !arguments[0].isNumber() || !arguments[1].isNumber())
+ return;
+
+ WebRect rect;
+ if (!mainFrame->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 0000000..3a3907f
--- /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/WebPreferences.cpp b/Tools/DumpRenderTree/chromium/WebPreferences.cpp
new file mode 100644
index 0000000..7c274c3
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebPreferences.cpp
@@ -0,0 +1,166 @@
+/*
+ * 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;
+
+ DOMPasteAllowed = true;
+ XSSAuditorEnabled = false;
+ allowFileAccessFromFileURLs = true;
+ authorAndUserStylesEnabled = true;
+ defaultTextEncodingName = WebString::fromUTF8("ISO-8859-1");
+ developerExtrasEnabled = false;
+ 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;
+ 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;
+ acceleratedCompositingEnabled = false;
+ accelerated2dCanvasEnabled = false;
+}
+
+void WebPreferences::applyTo(WebView* webView)
+{
+ WebSettings* settings = webView->settings();
+ settings->setCursiveFontFamily(cursiveFontFamily);
+ settings->setFantasyFontFamily(fantasyFontFamily);
+ settings->setSerifFontFamily(serifFontFamily);
+ settings->setStandardFontFamily(standardFontFamily);
+ settings->setFixedFontFamily(fixedFontFamily);
+ settings->setSansSerifFontFamily(sansSerifFontFamily);
+
+ settings->setDefaultFontSize(defaultFontSize);
+ settings->setDefaultFixedFontSize(defaultFixedFontSize);
+ settings->setMinimumFontSize(minimumFontSize);
+ settings->setMinimumLogicalFontSize(minimumLogicalFontSize);
+
+ settings->setDOMPasteAllowed(DOMPasteAllowed);
+ settings->setXSSAuditorEnabled(XSSAuditorEnabled);
+ settings->setAllowFileAccessFromFileURLs(allowFileAccessFromFileURLs);
+ 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->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);
+
+ // Fixed values.
+ settings->setShouldPaintCustomScrollbars(true);
+ settings->setTextDirectionSubmenuInclusionBehaviorNeverIncluded();
+ settings->setDownloadableBinaryFontsEnabled(true);
+ settings->setAllowScriptsToCloseWindows(false);
+ settings->setNeedsSiteSpecificQuirks(true);
+ settings->setEditableLinkBehaviorNeverLive();
+ settings->setFontRenderingModeNormal();
+ settings->setTextDirectionSubmenuInclusionBehaviorNeverIncluded();
+ settings->setUsesEncodingDetector(false);
+ settings->setImagesEnabled(true);
+ settings->setAcceleratedCompositingEnabled(acceleratedCompositingEnabled);
+ settings->setAccelerated2dCanvasEnabled(accelerated2dCanvasEnabled);
+}
+
diff --git a/Tools/DumpRenderTree/chromium/WebPreferences.h b/Tools/DumpRenderTree/chromium/WebPreferences.h
new file mode 100644
index 0000000..46877c0
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebPreferences.h
@@ -0,0 +1,88 @@
+/*
+ * 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 WebPerferences_h
+
+#include "WebSettings.h"
+#include "WebString.h"
+#include "WebURL.h"
+
+namespace WebKit {
+class WebView;
+}
+
+struct WebPreferences {
+ WebKit::WebString cursiveFontFamily;
+ WebKit::WebString fantasyFontFamily;
+ WebKit::WebString serifFontFamily;
+ WebKit::WebString standardFontFamily;
+ WebKit::WebString fixedFontFamily;
+ WebKit::WebString sansSerifFontFamily;
+
+ int defaultFontSize;
+ int defaultFixedFontSize;
+ int minimumFontSize;
+ int minimumLogicalFontSize;
+
+ bool DOMPasteAllowed;
+ bool XSSAuditorEnabled;
+ bool allowFileAccessFromFileURLs;
+ 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 webSecurityEnabled;
+ bool allowUniversalAccessFromFileURLs;
+ WebKit::WebSettings::EditingBehavior editingBehavior;
+ bool tabsToLinks;
+ bool hyperlinkAuditingEnabled;
+ bool caretBrowsingEnabled;
+ bool acceleratedCompositingEnabled;
+ bool accelerated2dCanvasEnabled;
+
+ 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 0000000..b1d9fa1
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.cpp
@@ -0,0 +1,523 @@
+/*
+ * 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/platform_canvas.h"
+#include "skia/ext/skia_utils_win.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;
+using namespace skia;
+
+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(PlatformCanvas* 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;
+
+ m_canvas->beginPlatformPaint();
+
+ 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:
+ // 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 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();
+ m_canvas->endPlatformPaint();
+}
+
+// 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;
+
+ m_canvas->beginPlatformPaint();
+ 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();
+ m_canvas->endPlatformPaint();
+}
+
+void WebThemeControlDRTWin::drawProgressBar(const SkIRect& fillRect)
+{
+ SkPaint paint;
+
+ m_canvas->beginPlatformPaint();
+ 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();
+ m_canvas->endPlatformPaint();
+}
+
diff --git a/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h b/Tools/DumpRenderTree/chromium/WebThemeControlDRTWin.h
new file mode 100644
index 0000000..4e22461
--- /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 "skia/ext/platform_canvas.h"
+#include "third_party/skia/include/core/SkColor.h"
+#include <wtf/Noncopyable.h>
+
+// Skia forward declarations
+struct SkIRect;
+
+class WebThemeControlDRTWin : public Noncopyable {
+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,
+ DropDownButtonType,
+ ProgressBarType
+ };
+
+ // canvas is the canvas to draw onto, and rect gives the size of the
+ // control. ctype and cstate specify the type and state of the control.
+ WebThemeControlDRTWin(skia::PlatformCanvas* canvas,
+ const SkIRect& rect,
+ Type ctype,
+ State cstate);
+ ~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 color);
+
+ // 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 color);
+
+
+ // 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 color);
+
+ // 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 color);
+
+ // 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 color);
+
+ // 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 color);
+
+ // 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 color);
+
+ // 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();
+
+ skia::PlatformCanvas* 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/WebThemeEngineDRTWin.cpp b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp
new file mode 100755
index 0000000..103b295
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.cpp
@@ -0,0 +1,758 @@
+/*
+ * 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 "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_TRACK == part) {
+ ctype = WebThemeControlDRTWin::HorizontalSliderTrackType;
+ ASSERT(part == TUS_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 0000000..2e15cf8
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebThemeEngineDRTWin.h
@@ -0,0 +1,97 @@
+/*
+ * 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 "win/WebThemeEngine.h"
+#include <wtf/Noncopyable.h>
+
+class WebThemeEngineDRTWin : public WebKit::WebThemeEngine, public Noncopyable {
+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 0000000..e3c8c28
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebViewHost.cpp
@@ -0,0 +1,1519 @@
+/*
+ * 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 "WebViewHost.h"
+
+#include "LayoutTestController.h"
+#include "TestNavigationController.h"
+#include "TestShell.h"
+#include "TestWebWorker.h"
+#include "WebCString.h"
+#include "WebConsoleMessage.h"
+#include "WebContextMenuData.h"
+#include "WebDataSource.h"
+#include "WebDeviceOrientationClientMock.h"
+#include "WebDragData.h"
+#include "WebElement.h"
+#include "WebFrame.h"
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+#include "WebGeolocationClientMock.h"
+#else
+#include "WebGeolocationServiceMock.h"
+#endif
+#include "WebHistoryItem.h"
+#include "WebNode.h"
+#include "WebRange.h"
+#include "WebRect.h"
+#include "WebScreenInfo.h"
+#include "WebSize.h"
+#include "WebSpeechInputControllerMock.h"
+#include "WebStorageNamespace.h"
+#include "WebURLRequest.h"
+#include "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>
+
+using namespace WebCore;
+using namespace WebKit;
+using namespace skia;
+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 |data_object| (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 WebWindowFeatures&, const WebString&)
+{
+ if (!layoutTestController()->canOpenWindows())
+ return 0;
+ return m_shell->createWebView()->webView();
+}
+
+WebWidget* WebViewHost::createPopupMenu(WebPopupType)
+{
+ return 0;
+}
+
+WebWidget* WebViewHost::createPopupMenu(const WebPopupMenuInfo&)
+{
+ 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.
+ 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()
+{
+ 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)
+{
+ // Check the spelling of the given text.
+#if OS(MAC_OS_X)
+ // FIXME: rebaseline layout-test results of Windows and Linux so we
+ // can enable this mock spellchecker on them.
+ m_spellcheck.spellCheckWord(text, &misspelledOffset, &misspelledLength);
+#endif
+}
+
+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&)
+{
+ return true; // Allow window closure.
+}
+
+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::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);
+
+ if (m_shell->accessibilityController()->shouldDumpAccessibilityNotifications()) {
+ printf("AccessibilityNotification - ");
+
+ switch (notification) {
+ case WebAccessibilityNotificationActiveDescendantChanged:
+ printf("ActiveDescendantChanged");
+ break;
+ case WebAccessibilityNotificationCheckedStateChanged:
+ printf("CheckedStateChanged");
+ break;
+ case WebAccessibilityNotificationChildrenChanged:
+ printf("ChildrenChanged");
+ break;
+ case WebAccessibilityNotificationFocusedUIElementChanged:
+ printf("FocusedUIElementChanged");
+ break;
+ case WebAccessibilityNotificationLayoutComplete:
+ printf("LayoutComplete");
+ break;
+ case WebAccessibilityNotificationLoadComplete:
+ printf("LoadComplete");
+ break;
+ case WebAccessibilityNotificationSelectedChildrenChanged:
+ printf("SelectedChildrenChanged");
+ break;
+ case WebAccessibilityNotificationSelectedTextChanged:
+ printf("SelectedTextChanged");
+ break;
+ case WebAccessibilityNotificationValueChanged:
+ printf("ValueChanged");
+ break;
+ case WebAccessibilityNotificationScrolledToAnchor:
+ printf("ScrolledToAnchor");
+ break;
+ case WebAccessibilityNotificationLiveRegionChanged:
+ printf("LiveRegionChanged");
+ break;
+ case WebAccessibilityNotificationMenuListValueChanged:
+ printf("MenuListValueChanged");
+ break;
+ case WebAccessibilityNotificationRowCountChanged:
+ printf("RowCountChanged");
+ break;
+ case WebAccessibilityNotificationRowCollapsed:
+ printf("RowCollapsed");
+ break;
+ case WebAccessibilityNotificationRowExpanded:
+ printf("RowExpanded");
+ break;
+ default:
+ break;
+ }
+
+ 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();
+}
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+WebKit::WebGeolocationClient* WebViewHost::geolocationClient()
+{
+ return geolocationClientMock();
+}
+
+WebKit::WebGeolocationClientMock* WebViewHost::geolocationClientMock()
+{
+ if (!m_geolocationClientMock)
+ m_geolocationClientMock.set(WebGeolocationClientMock::create());
+ return m_geolocationClientMock.get();
+}
+#else
+WebKit::WebGeolocationService* WebViewHost::geolocationService()
+{
+ if (!m_geolocationServiceMock)
+ m_geolocationServiceMock.set(WebGeolocationServiceMock::createWebGeolocationServiceMock());
+ return m_geolocationServiceMock.get();
+}
+#endif
+
+WebSpeechInputController* WebViewHost::speechInputController(WebKit::WebSpeechInputListener* listener)
+{
+ if (!m_speechInputControllerMock)
+ m_speechInputControllerMock.set(WebSpeechInputControllerMock::create(listener));
+ return m_speechInputControllerMock.get();
+}
+
+WebDeviceOrientationClientMock* WebViewHost::deviceOrientationClientMock()
+{
+ if (!m_deviceOrientationClientMock.get())
+ m_deviceOrientationClientMock.set(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);
+}
+
+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.
+}
+
+static void invokeCloseWidget(void* context)
+{
+ WebViewHost* wvh = static_cast<WebViewHost*>(context);
+ wvh->closeWidget();
+}
+
+void WebViewHost::closeWidgetSoon()
+{
+ webkit_support::PostDelayedTask(invokeCloseWidget, static_cast<void*>(this), 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);
+}
+
+// WebFrameClient ------------------------------------------------------------
+
+WebPlugin* WebViewHost::createPlugin(WebFrame* frame, const WebPluginParams& params)
+{
+ return webkit_support::CreateWebPlugin(frame, params);
+}
+
+WebWorker* WebViewHost::createWorker(WebFrame*, WebWorkerClient*)
+{
+ 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);
+}
+
+bool WebViewHost::allowPlugins(WebFrame* frame, bool enabledPerSettings)
+{
+ return enabledPerSettings;
+}
+
+bool WebViewHost::allowImages(WebFrame* frame, bool enabledPerSettings)
+{
+ return enabledPerSettings;
+}
+
+void WebViewHost::loadURLExternally(WebFrame*, const WebURLRequest& request, WebNavigationPolicy policy)
+{
+ 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())
+ return;
+ printFrameDescription(frame);
+ printf(" - willPerformClientRedirectToURL: %s \n", to.spec().data());
+}
+
+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->shouldDumpUserGestureInFrameLoadCallbacks())
+ printFrameUserGestureStatus(frame, " - in didStartProvisionalLoadForFrame\n");
+ if (m_shell->shouldDumpFrameLoadCallbacks()) {
+ printFrameDescription(frame);
+ fputs(" - didStartProvisionalLoadForFrame\n", stdout);
+ }
+
+ 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)
+{
+ 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);
+}
+
+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)
+{
+ if (m_shell->shouldDumpFrameLoadCallbacks())
+ fputs("didRunInsecureContent\n", stdout);
+}
+
+bool WebViewHost::allowScript(WebFrame*, bool enabledPerSettings)
+{
+ return enabledPerSettings;
+}
+
+void WebViewHost::openFileSystem(WebFrame* frame, WebFileSystem::Type type, long long size, bool create, WebFileSystemCallbacks* callbacks)
+{
+ webkit_support::OpenFileSystem(frame, type, size, create, callbacks);
+}
+
+// Public functions -----------------------------------------------------------
+
+WebViewHost::WebViewHost(TestShell* shell)
+ : m_shell(shell)
+ , m_webWidget(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());
+ }
+
+ // Call GC twice to clean up garbage.
+ m_shell->callJSGC();
+ m_shell->callJSGC();
+
+ webWidget()->close();
+
+ if (m_inModalLoop)
+ webkit_support::QuitMessageLoop();
+}
+
+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;
+#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.set(new TestNavigationController(this));
+
+ m_pendingExtraData.clear();
+ m_resourceIdentifierMap.clear();
+ m_clearHeaders.clear();
+ m_editCommandName.clear();
+ m_editCommandValue.clear();
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ if (m_geolocationClientMock.get())
+ m_geolocationClientMock->resetMock();
+#else
+ m_geolocationServiceMock.clear();
+#endif
+
+ if (m_speechInputControllerMock.get())
+ m_speechInputControllerMock->clearResults();
+
+ m_currentCursor = WebCursorInfo();
+ m_windowRect = WebRect();
+ m_paintRect = WebRect();
+
+ if (m_webWidget)
+ webView()->mainFrame()->setName(WebString());
+}
+
+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::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(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(0);
+
+ // 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(TestShellExtraData* extraData)
+{
+ m_pendingExtraData.set(extraData);
+}
+
+void WebViewHost::setPageTitle(const WebString&)
+{
+ // Nothing to do in layout test.
+}
+
+void WebViewHost::setAddressBarURL(const WebURL&)
+{
+ // Nothing to do in layout test.
+}
+
+// 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 PLATFORM(CG)
+ webWidget()->paint(canvas()->getTopPlatformDevice().GetBitmapContext(), rect);
+#else
+ webWidget()->paint(canvas(), rect);
+#endif
+ m_isPainting = false;
+}
+
+void WebViewHost::paintInvalidatedRegion()
+{
+ 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());
+}
+
+PlatformCanvas* WebViewHost::canvas()
+{
+ if (m_canvas)
+ return m_canvas.get();
+ WebSize widgetSize = webWidget()->size();
+ resetScrollRect();
+ m_canvas.set(new PlatformCanvas(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 0000000..20b29c0
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/WebViewHost.h
@@ -0,0 +1,332 @@
+/*
+ * 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 "TestNavigationController.h"
+#include "WebAccessibilityNotification.h"
+#include "WebCursorInfo.h"
+#include "WebFrameClient.h"
+#include "WebViewClient.h"
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+#include <wtf/text/WTFString.h>
+
+class LayoutTestController;
+class TestShell;
+namespace WebKit {
+class WebFrame;
+class WebDeviceOrientationClient;
+class WebDeviceOrientationClientMock;
+class WebGeolocationClient;
+class WebGeolocationClientMock;
+class WebGeolocationServiceMock;
+class WebSpeechInputController;
+class WebSpeechInputControllerMock;
+class WebSpeechInputListener;
+class WebURL;
+struct WebRect;
+struct WebURLError;
+struct WebWindowFeatures;
+}
+namespace skia {
+class PlatformCanvas;
+}
+
+class WebViewHost : public WebKit::WebViewClient, public WebKit::WebFrameClient, public NavigationHost {
+ public:
+ WebViewHost(TestShell* shell);
+ ~WebViewHost();
+ void setWebWidget(WebKit::WebWidget* widget) { m_webWidget = widget; }
+ WebKit::WebView* webView() const;
+ WebKit::WebWidget* webWidget() const;
+ void reset();
+ void setSelectTrailingWhitespaceEnabled(bool);
+ void setSmartInsertDeleteEnabled(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(TestShellExtraData*);
+
+ void paintRect(const WebKit::WebRect&);
+ void updatePaintRect(const WebKit::WebRect&);
+ void paintInvalidatedRegion();
+ skia::PlatformCanvas* 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::WebViewClient
+ virtual WebKit::WebView* createView(WebKit::WebFrame*, 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 spellCheck(const WebKit::WebString&, int& offset, int& length);
+ virtual WebKit::WebString autoCorrectWord(const WebKit::WebString&);
+ 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 navigateBackForwardSoon(int offset);
+ virtual int historyBackListCount();
+ virtual int historyForwardListCount();
+ virtual void postAccessibilityNotification(const WebKit::WebAccessibilityObject&, WebKit::WebAccessibilityNotification);
+ virtual WebKit::WebNotificationPresenter* notificationPresenter();
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ virtual WebKit::WebGeolocationClient* geolocationClient();
+#else
+ virtual WebKit::WebGeolocationService* geolocationService();
+#endif
+ 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();
+ virtual void didFocus();
+ virtual void didBlur();
+ virtual void didChangeCursor(const WebKit::WebCursorInfo&);
+ virtual void closeWidgetSoon();
+ virtual void show(WebKit::WebNavigationPolicy);
+ virtual void runModal();
+ 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::WebWorkerClient*);
+ virtual WebKit::WebMediaPlayer* createMediaPlayer(WebKit::WebFrame*, WebKit::WebMediaPlayerClient*);
+ virtual WebKit::WebApplicationCacheHost* createApplicationCacheHost(WebKit::WebFrame*, WebKit::WebApplicationCacheHostClient*);
+ virtual bool allowPlugins(WebKit::WebFrame*, bool enabledPerSettings);
+ virtual bool allowImages(WebKit::WebFrame*, bool enabledPerSettings);
+ virtual void loadURLExternally(WebKit::WebFrame*, const WebKit::WebURLRequest&, WebKit::WebNavigationPolicy);
+ 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&);
+ 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&);
+ virtual bool allowScript(WebKit::WebFrame*, bool enabledPerSettings);
+ virtual void openFileSystem(WebKit::WebFrame*, WebKit::WebFileSystem::Type, long long size, bool create, WebKit::WebFileSystemCallbacks*);
+
+ WebKit::WebDeviceOrientationClientMock* deviceOrientationClientMock();
+ MockSpellCheck* mockSpellCheck();
+
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ // Geolocation client mocks for LayoutTestController
+ WebKit::WebGeolocationClientMock* geolocationClientMock();
+#endif
+
+private:
+ 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&);
+
+ // 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;
+
+ // 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<skia::PlatformCanvas> m_canvas;
+ WebKit::WebRect m_paintRect;
+ bool m_isPainting;
+
+ OwnPtr<WebKit::WebContextMenuData> m_lastContextMenuData;
+
+ // Geolocation
+#if ENABLE(CLIENT_BASED_GEOLOCATION)
+ OwnPtr<WebKit::WebGeolocationClientMock> m_geolocationClientMock;
+#else
+ OwnPtr<WebKit::WebGeolocationServiceMock> m_geolocationServiceMock;
+#endif
+
+ OwnPtr<WebKit::WebDeviceOrientationClientMock> m_deviceOrientationClientMock;
+ OwnPtr<WebKit::WebSpeechInputControllerMock> m_speechInputControllerMock;
+
+ OwnPtr<TestNavigationController*> m_navigationController;
+};
+
+#endif // WebViewHost_h
diff --git a/Tools/DumpRenderTree/chromium/config.h b/Tools/DumpRenderTree/chromium/config.h
new file mode 100644
index 0000000..7dfda18
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/config.h
@@ -0,0 +1,56 @@
+/*
+ * 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>
+
+#if OS(WINDOWS) && !COMPILER(GCC)
+// Allow 'this' to be used in base member initializer list.
+#pragma warning(disable : 4355)
+// JS_EXPORTDATA is needed to inlucde wtf/WTFString.h.
+#define JS_EXPORTDATA __declspec(dllimport)
+#else
+#define JS_EXPORTDATA
+#endif
+
+#endif // config_h
diff --git a/Tools/DumpRenderTree/chromium/fonts.conf b/Tools/DumpRenderTree/chromium/fonts.conf
new file mode 100644
index 0000000..be214c6
--- /dev/null
+++ b/Tools/DumpRenderTree/chromium/fonts.conf
@@ -0,0 +1,155 @@
+<?xml version="1.0"?>
+<!DOCTYPE fontconfig SYSTEM "fonts.dtd">
+<!-- /etc/fonts/fonts.conf file to configure system font access -->
+<fontconfig>
+ <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>
+</fontconfig>
diff --git a/Tools/DumpRenderTree/config.h b/Tools/DumpRenderTree/config.h
new file mode 100644
index 0000000..55e2dc1
--- /dev/null
+++ b/Tools/DumpRenderTree/config.h
@@ -0,0 +1,80 @@
+/*
+ * 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
+#include "autotoolsconfig.h"
+#endif
+
+#include <wtf/Platform.h>
+
+#ifdef __cplusplus
+#undef new
+#undef delete
+#include <wtf/FastMalloc.h>
+#endif
+
+#if OS(WINDOWS) && !COMPILER(GCC)
+#define JS_EXPORTDATA __declspec(dllimport)
+#define WEBKIT_EXPORTDATA __declspec(dllimport)
+#else
+#define JS_EXPORTDATA
+#define WEBKIT_EXPORTDATA
+#endif
+
+#if PLATFORM(MAC)
+#define WTF_PLATFORM_CF 1
+
+#if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_5
+#define BUILDING_ON_TIGER 1
+#elif !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 PLATFORM(WIN)
+#define WTF_PLATFORM_CF 1
+#if defined(WIN_CAIRO)
+#define WTF_PLATFORM_CAIRO 1
+#define WTF_USE_CURL 1
+#else
+#define WTF_PLATFORM_CG 1
+#define WTF_USE_CFNETWORK 1
+#endif
+
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+
+#undef WINVER
+#define WINVER 0x0500
+
+// 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
+
+#undef _WINSOCKAPI_
+#define _WINSOCKAPI_ // Prevent inclusion of winsock.h in windows.h
+#endif // PLATFORM(WIN)
diff --git a/Tools/DumpRenderTree/fonts/ColorBits-A.png b/Tools/DumpRenderTree/fonts/ColorBits-A.png
new file mode 100644
index 0000000..8b9319c
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/ColorBits-A.png
Binary files differ
diff --git a/Tools/DumpRenderTree/fonts/ColorBits.ttf b/Tools/DumpRenderTree/fonts/ColorBits.ttf
new file mode 100644
index 0000000..cd919e8
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/ColorBits.ttf
Binary files differ
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 0000000..e732fbc
--- /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 0000000..f9f997e
--- /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 0000000..22b00de
--- /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 0000000..1ccadba
--- /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 0000000..ab5563d
--- /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 0000000..56d279e
--- /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 0000000..d827d7d
--- /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 0000000..9141596
--- /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 0000000..a2d0505
--- /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 0000000..d0f354b
--- /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 0000000..6b895ca
--- /dev/null
+++ b/Tools/DumpRenderTree/fonts/WebKitWeightWatcher900.ttf
Binary files differ
diff --git a/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp b/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
new file mode 100644
index 0000000..589e53c
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 "AccessibilityUIElement.h"
+#include "DumpRenderTree.h"
+#include "WebCoreSupport/DumpRenderTreeSupportGtk.h"
+
+#include <atk/atk.h>
+#include <gtk/gtk.h>
+#include <webkit/webkit.h>
+
+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()
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+
+ // The presumed, desired rootElement is the parent of the web view.
+ GtkWidget* webViewParent = gtk_widget_get_parent(GTK_WIDGET(view));
+ AtkObject* axObject = gtk_widget_get_accessible(webViewParent);
+
+ return AccessibilityUIElement(axObject);
+}
+
+void AccessibilityController::setLogFocusEvents(bool)
+{
+}
+
+void AccessibilityController::setLogScrollingStartEvents(bool)
+{
+}
+
+void AccessibilityController::setLogValueChangeEvents(bool)
+{
+}
+
+void AccessibilityController::addNotificationListener(PlatformUIElement, JSObjectRef)
+{
+}
+
+void AccessibilityController::notificationReceived(PlatformUIElement, const std::string&)
+{
+}
diff --git a/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp b/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp
new file mode 100644
index 0000000..7e1a9c2
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp
@@ -0,0 +1,739 @@
+/*
+ * 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 <JavaScriptCore/JSStringRef.h>
+#include <wtf/Assertions.h>
+
+#include <atk/atk.h>
+#include <gtk/gtk.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;
+
+ PlatformRefPtr<AtkStateSet> stateSet = adoptPlatformRef(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;
+
+ PlatformRefPtr<AtkStateSet> stateSet = adoptPlatformRef(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
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isChecked() const
+{
+ return intValue();
+}
+
+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;
+}
+
+JSStringRef AccessibilityUIElement::rowIndexRange()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+JSStringRef AccessibilityUIElement::columnIndexRange()
+{
+ // FIXME: implement
+ return JSStringCreateWithCharacters(0, 0);
+}
+
+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::cellForColumnAndRow(unsigned column, unsigned row)
+{
+ // FIXME: implement
+ return 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);
+}
+
+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()
+{
+ // FIXME: implement
+}
+
+void AccessibilityUIElement::decrement()
+{
+ // FIXME: implement
+}
+
+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;
+
+ PlatformRefPtr<AtkStateSet> stateSet = adoptPlatformRef(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::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 0000000..32a41c3
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/DumpRenderTree.cpp
@@ -0,0 +1,1112 @@
+/*
+ * 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 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 "WebCoreSupport/DumpRenderTreeSupportGtk.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>
+
+#if PLATFORM(X11)
+#include <fontconfig/fontconfig.h>
+#endif
+
+
+using namespace std;
+
+extern "C" {
+// This API is not yet public.
+extern G_CONST_RETURN 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 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-antialias", 1,
+ "gtk-xft-hinting", 0,
+ "gtk-font-name", "Liberation Sans 16", NULL);
+
+ // 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);
+}
+
+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());
+
+ static const char *const fontPaths[][2] = {
+ { "/usr/share/fonts/truetype/ttf-liberation/LiberationMono-BoldItalic.ttf",
+ "/usr/share/fonts/liberation/LiberationMono-BoldItalic.ttf", },
+ { "/usr/share/fonts/truetype/ttf-liberation/LiberationMono-Bold.ttf",
+ "/usr/share/fonts/liberation/LiberationMono-Bold.ttf", },
+ { "/usr/share/fonts/truetype/ttf-liberation/LiberationMono-Italic.ttf",
+ "/usr/share/fonts/liberation/LiberationMono-Italic.ttf", },
+ { "/usr/share/fonts/truetype/ttf-liberation/LiberationMono-Regular.ttf",
+ "/usr/share/fonts/liberation/LiberationMono-Regular.ttf", },
+ { "/usr/share/fonts/truetype/ttf-liberation/LiberationSans-BoldItalic.ttf",
+ "/usr/share/fonts/liberation/LiberationSans-BoldItalic.ttf", },
+ { "/usr/share/fonts/truetype/ttf-liberation/LiberationSans-Bold.ttf",
+ "/usr/share/fonts/liberation/LiberationSans-Bold.ttf", },
+ { "/usr/share/fonts/truetype/ttf-liberation/LiberationSans-Italic.ttf",
+ "/usr/share/fonts/liberation/LiberationSans-Italic.ttf", },
+ { "/usr/share/fonts/truetype/ttf-liberation/LiberationSans-Regular.ttf",
+ "/usr/share/fonts/liberation/LiberationSans-Regular.ttf", },
+ { "/usr/share/fonts/truetype/ttf-liberation/LiberationSerif-BoldItalic.ttf",
+ "/usr/share/fonts/liberation/LiberationSerif-BoldItalic.ttf", },
+ { "/usr/share/fonts/truetype/ttf-liberation/LiberationSerif-Bold.ttf",
+ "/usr/share/fonts/liberation/LiberationSerif-Bold.ttf", },
+ { "/usr/share/fonts/truetype/ttf-liberation/LiberationSerif-Italic.ttf",
+ "/usr/share/fonts/liberation/LiberationSerif-Italic.ttf", },
+ { "/usr/share/fonts/truetype/ttf-liberation/LiberationSerif-Regular.ttf",
+ "/usr/share/fonts/liberation/LiberationSerif-Regular.ttf", },
+ { "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf",
+ "/usr/share/fonts/dejavu/DejaVuSans.ttf", },
+ { "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSerif.ttf",
+ "/usr/share/fonts/dejavu/DejaVuSerif.ttf", },
+
+ // MathML tests require the STIX fonts.
+ { "/usr/share/fonts/opentype/stix/STIXGeneral.otf",
+ "/usr/share/fonts/stix/STIXGeneral.otf" },
+ { "/usr/share/fonts/opentype/stix/STIXGeneralBolIta.otf",
+ "/usr/share/fonts/stix/STIXGeneralBolIta.otf" },
+ { "/usr/share/fonts/opentype/stix/STIXGeneralBol.otf",
+ "/usr/share/fonts/stix/STIXGeneralBol.otf" },
+ { "/usr/share/fonts/opentype/stix/STIXGeneralItalic.otf",
+ "/usr/share/fonts/stix/STIXGeneralItalic.otf" }
+ };
+
+ // TODO: Some tests use Lucida. We should load these as well, once it becomes
+ // clear how to install these fonts easily on Fedora.
+ for (size_t font = 0; font < G_N_ELEMENTS(fontPaths); font++) {
+ bool found = false;
+ for (size_t path = 0; path < 2; path++) {
+
+ if (g_file_test(fontPaths[font][path], G_FILE_TEST_EXISTS)) {
+ found = true;
+ if (!FcConfigAppFontAddFile(config, reinterpret_cast<const FcChar8*>(fontPaths[font][path])))
+ g_error("Could not load font at %s!", fontPaths[font][path]);
+ else
+ break;
+ }
+ }
+
+ if (!found)
+ g_error("Could not find font at %s. Either install this font or file a bug "
+ "at http://bugs.webkit.org if it is installed in another location.",
+ fontPaths[font][0]);
+ }
+
+ // 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());
+
+ // 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)
+{
+ return g_ascii_strcasecmp(webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item1)),
+ webkit_web_history_item_get_target(WEBKIT_WEB_HISTORY_ITEM(item2)));
+}
+
+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');
+ GList* kids = webkit_web_history_item_get_children(item);
+ if (kids) {
+ // must sort to eliminate arbitrary result ordering which defeats reproducible testing
+ kids = g_list_sort(kids, (GCompareFunc) compareHistoryItems);
+ for (unsigned i = 0; i < g_list_length(kids); i++)
+ dumpHistoryItem(WEBKIT_WEB_HISTORY_ITEM(g_list_nth_data(kids, i)), indent+4, FALSE);
+ }
+ 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_append(itemsToPrint, item);
+ }
+
+ WebKitWebHistoryItem* currentItem = webkit_web_back_forward_list_get_current_item(bfList);
+
+ g_object_ref(currentItem);
+ itemsToPrint = g_list_append(itemsToPrint, currentItem);
+
+ gint currentItemIndex = g_list_length(itemsToPrint) - 1;
+ 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_append(itemsToPrint, item);
+ }
+
+ for (int i = g_list_length(itemsToPrint) - 1; i >= 0; i--) {
+ WebKitWebHistoryItem* item = WEBKIT_WEB_HISTORY_ITEM(g_list_nth_data(itemsToPrint, i));
+ dumpHistoryItem(item, historyItemIndent, i == currentItemIndex);
+ 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.
+ GSList* viewList = g_slist_reverse(webViewList);
+ for (unsigned i = 0; i < g_slist_length(viewList); ++i)
+ dumpBackForwardListForWebView(WEBKIT_WEB_VIEW(g_slist_nth_data(viewList, i)));
+}
+
+static void invalidateAnyPreviousWaitToDumpWatchdog()
+{
+ if (waitToDumpWatchdog) {
+ g_source_remove(waitToDumpWatchdog);
+ waitToDumpWatchdog = 0;
+ }
+
+ waitForPolicy = false;
+}
+
+static void resetDefaultsToConsistentValues()
+{
+ WebKitWebSettings* settings = webkit_web_view_get_settings(webView);
+ 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,
+ "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", 16,
+ "default-monospace-font-size", 13,
+ "minimum-font-size", 1,
+ "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);
+
+ DumpRenderTreeSupportGtk::clearMainFrameName(mainFrame);
+
+ 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::resetOriginAccessWhiteLists();
+
+ WebKitWebBackForwardList* list = webkit_web_view_get_back_forward_list(webView);
+ webkit_web_back_forward_list_clear(list);
+
+#ifdef HAVE_LIBSOUP_2_29_90
+ 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);
+#endif
+
+ setlocale(LC_ALL, "");
+
+ DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(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()
+{
+ gdk_screen_set_resolution(gdk_screen_get_default(), 72.0);
+
+ 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);
+}
+
+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();
+ }
+
+ 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;
+ }
+
+ // 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*)
+{
+ if (frame != topLoadingFrame)
+ return;
+
+ 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 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 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);
+
+ JSStringRef eventSenderStr = JSStringCreateWithUTF8CString("eventSender");
+ JSValueRef eventSender = makeEventSender(context, !webkit_web_frame_get_parent(frame));
+ JSObjectSetProperty(context, windowObject, eventSenderStr, eventSender, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, 0);
+ JSStringRelease(eventSenderStr);
+}
+
+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()) {
+ if (message && strcmp(message, ""))
+ 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 = webkit_web_view_new();
+ gtk_container_add(GTK_CONTAINER(webInspectorWindow),
+ webView);
+
+ return WEBKIT_WEB_VIEW(webView);
+}
+
+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 (frame != topLoadingFrame || !done)
+ printf("%s - didFinishLoadForFrame\n", frameName.get());
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+static void frameCreatedCallback(WebKitWebView* webView, WebKitWebFrame* webFrame, gpointer user_data)
+{
+ g_signal_connect(webFrame, "notify::load-status", G_CALLBACK(webFrameLoadStatusNotified), NULL);
+}
+
+static WebKitWebView* createWebView()
+{
+ WebKitWebView* view = WEBKIT_WEB_VIEW(webkit_web_view_new());
+
+ DumpRenderTreeSupportGtk::setDumpRenderTreeModeEnabled(true);
+
+ g_object_connect(G_OBJECT(view),
+ "signal::load-started", webViewLoadStarted, 0,
+ "signal::load-finished", webViewLoadFinished, 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,
+
+ 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[])
+{
+ g_thread_init(NULL);
+ 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);
+ container = GTK_WIDGET(gtk_scrolled_window_new(NULL, NULL));
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(container), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_container_add(GTK_CONTAINER(window), container);
+ gtk_widget_show_all(window);
+
+ webView = createWebView();
+ gtk_container_add(GTK_CONTAINER(container), GTK_WIDGET(webView));
+ gtk_widget_realize(GTK_WIDGET(webView));
+ gtk_widget_show_all(container);
+ gtk_widget_grab_focus(GTK_WIDGET(webView));
+ 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 0000000..7a5a4cf
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h
@@ -0,0 +1,45 @@
+/*
+ * 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>
+
+extern WebKitWebFrame* mainFrame;
+extern WebKitWebFrame* topLoadingFrame;
+extern guint waitToDumpWatchdog;
+extern bool waitForPolicy;
+extern GSList* webViewList;
+
+gchar* JSStringCopyUTF8CString(JSStringRef jsString);
+
+#endif // DumpRenderTreeGtk_h
diff --git a/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp b/Tools/DumpRenderTree/gtk/EditingCallbacks.cpp
new file mode 100644
index 0000000..2586611
--- /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 0000000..7a95149
--- /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 0000000..b844558
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/EventSender.cpp
@@ -0,0 +1,764 @@
+/*
+ * 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 <GtkVersioning.h>
+#include <JavaScriptCore/JSObjectRef.h>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JSStringRef.h>
+#include <webkit/webkitwebframe.h>
+#include <webkit/webkitwebview.h>
+#include <wtf/ASCIICType.h>
+#include <wtf/Platform.h>
+#include <wtf/text/CString.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkkeysyms.h>
+#include <string.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 int 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 void updateClickCount(int button)
+{
+ if (lastClickPositionX != lastMousePositionX
+ || lastClickPositionY != lastMousePositionY
+ || lastClickButton != button
+ || timeOffset - lastClickTimeOffset >= 1)
+ clickCount = 1;
+ else
+ clickCount++;
+}
+
+static guint gdkModifersFromJSValue(JSContextRef context, const JSValueRef 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) {
+ JSValueRef value = JSObjectGetPropertyAtIndex(context, modifiersArray, i, 0);
+ JSStringRef string = JSValueToStringCopy(context, value, 0);
+ if (JSStringIsEqualToUTF8CString(string, "ctrlKey")
+ || JSStringIsEqualToUTF8CString(string, "addSelectionKey"))
+ gdkModifiers |= GDK_CONTROL_MASK;
+ else if (JSStringIsEqualToUTF8CString(string, "shiftKey")
+ || JSStringIsEqualToUTF8CString(string, "rangeSelectionKey"))
+ gdkModifiers |= GDK_SHIFT_MASK;
+ else if (JSStringIsEqualToUTF8CString(string, "altKey"))
+ gdkModifiers |= GDK_MOD1_MASK;
+
+ // Currently the metaKey as defined in WebCore/platform/gtk/MouseEventGtk.cpp
+ // is GDK_MOD2_MASK. This code must be kept in sync with that file.
+ else if (JSStringIsEqualToUTF8CString(string, "metaKey"))
+ gdkModifiers |= GDK_MOD2_MASK;
+
+ JSStringRelease(string);
+ }
+ 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);
+
+ 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);
+ event->motion.state = 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 JSValueRef beginDragWithFilesCallback(JSContextRef context, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ if (argumentCount < 1)
+ return JSValueMakeUndefined(context);
+
+ // FIXME: Implement this completely once WebCore has complete drag and drop support
+ 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, "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 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 },
+ { 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 0000000..f440f0d
--- /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 0000000..4eb5d6e
--- /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/ImageDiff.cpp b/Tools/DumpRenderTree/gtk/ImageDiff.cpp
new file mode 100644
index 0000000..7e2744a
--- /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 0000000..1527811
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp
@@ -0,0 +1,842 @@
+/*
+ * 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 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_application_cache_set_maximum_size(unsigned long long size);
+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();
+}
+
+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)
+{
+ 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)
+{
+#ifdef HAVE_LIBSOUP_2_29_90
+ 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);
+#endif
+}
+
+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::setTimelineProfilingEnabled(bool flag)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(view);
+
+ WebKitWebInspector* inspector = webkit_web_view_get_inspector(view);
+ g_object_set(G_OBJECT(inspector), "timeline-profiling-enabled", flag, 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::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)
+{
+ // FIXME: implement
+}
+
+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::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)
+{
+ // 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);
+}
+
+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::setIconDatabaseEnabled(bool flag)
+{
+ // FIXME: implement
+}
+
+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)
+{
+ // FIXME: implement
+}
+
+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)
+{
+ // FIXME: Implement
+}
+
+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 */)
+{
+ // FIXME: Implement
+ return false;
+}
+
+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)
+{
+ if (!cacheModel) // WebCacheModelDocumentViewer
+ webkit_set_cache_model(WEBKIT_CACHE_MODEL_DOCUMENT_VIEWER);
+ else
+ webkit_set_cache_model(WEBKIT_CACHE_MODEL_WEB_BROWSER);
+}
+
+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::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);
+}
+
+void LayoutTestController::setDomainRelaxationForbiddenForURLScheme(bool, JSStringRef)
+{
+ // FIXME: implement
+}
+
+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(), "WebKitTabToLinksPreferenceKey")) {
+ DumpRenderTreeSupportGtk::setLinksIncludedInFocusChain(!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()
+{
+ // FIXME: Implement for testing fix for https://bugs.webkit.org/show_bug.cgi?id=27481
+ return false;
+}
+
+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);
+}
+
+void LayoutTestController::dumpConfigurationForViewport(int availableWidth, int availableHeight)
+{
+ WebKitWebView* webView = webkit_web_frame_get_web_view(mainFrame);
+ ASSERT(webView);
+ DumpRenderTreeSupportGtk::dumpConfigurationForViewport(webView, availableWidth, availableHeight);
+}
+
+void LayoutTestController::setSerializeHTTPLoads(bool)
+{
+ // FIXME: Implement if needed for https://bugs.webkit.org/show_bug.cgi?id=50758.
+}
diff --git a/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp
new file mode 100644
index 0000000..4073403
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp
@@ -0,0 +1,59 @@
+/*
+ * 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 "PixelDumpSupportCairo.h"
+#include <webkit/webkit.h>
+
+PassRefPtr<BitmapContext> createBitmapContextFromWebView(bool, bool, bool, bool)
+{
+ WebKitWebView* view = webkit_web_frame_get_web_view(mainFrame);
+ gint width, height;
+#ifdef GTK_API_VERSION_2
+ GdkPixmap* pixmap = gtk_widget_get_snapshot(GTK_WIDGET(view), 0);
+ gdk_drawable_get_size(GDK_DRAWABLE(pixmap), &width, &height);
+#else
+ width = gtk_widget_get_allocated_width(GTK_WIDGET(view));
+ height = gtk_widget_get_allocated_height(GTK_WIDGET(view));
+#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(GTK_WIDGET(view), context);
+#endif
+
+ return BitmapContext::createByAdoptingBitmapAndContext(0, context);
+}
diff --git a/Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp b/Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp
new file mode 100644
index 0000000..0f44f54
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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()));
+ 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 0000000..ac81cb0
--- /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 0000000..8fff7d9
--- /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 0000000..81c2e4a
--- /dev/null
+++ b/Tools/DumpRenderTree/gtk/fonts/fonts.conf
@@ -0,0 +1,405 @@
+<?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>
+
+ <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 0000000..9d7edef
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/AccessibilityControllerMac.mm
@@ -0,0 +1,81 @@
+/*
+ * 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 "AccessibilityUIElement.h"
+#import <Foundation/Foundation.h>
+#import <WebKit/WebFrame.h>
+#import <WebKit/WebHTMLView.h>
+
+AccessibilityController::AccessibilityController()
+{
+}
+
+AccessibilityController::~AccessibilityController()
+{
+}
+
+AccessibilityUIElement AccessibilityController::elementAtPoint(int x, int y)
+{
+ id accessibilityObject = [[[mainFrame frameView] documentView] accessibilityHitTest:NSMakePoint(x, y)];
+ return AccessibilityUIElement(accessibilityObject);
+}
+
+AccessibilityUIElement AccessibilityController::focusedElement()
+{
+ // FIXME: we could do some caching here.
+ id accessibilityObject = [[[mainFrame frameView] documentView] accessibilityFocusedUIElement];
+ return AccessibilityUIElement(accessibilityObject);
+}
+
+AccessibilityUIElement AccessibilityController::rootElement()
+{
+ // FIXME: we could do some caching here.
+ id accessibilityObject = [[mainFrame frameView] documentView];
+ return AccessibilityUIElement(accessibilityObject);
+}
+
+void AccessibilityController::setLogFocusEvents(bool)
+{
+}
+
+void AccessibilityController::setLogScrollingStartEvents(bool)
+{
+}
+
+void AccessibilityController::setLogValueChangeEvents(bool)
+{
+}
+
+void AccessibilityController::addNotificationListener(PlatformUIElement, JSObjectRef)
+{
+}
+
+void AccessibilityController::notificationReceived(PlatformUIElement, const std::string&)
+{
+}
diff --git a/Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm b/Tools/DumpRenderTree/mac/AccessibilityTextMarkerMac.mm
new file mode 100644
index 0000000..9170ab6
--- /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"
+
+#pragma 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();
+}
+
+#pragma 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 0000000..e2f0597
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/AccessibilityUIElementMac.mm
@@ -0,0 +1,1341 @@
+/*
+ * 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 "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>
+
+#ifdef BUILDING_ON_TIGER
+#define NSAccessibilityValueDescriptionAttribute @"AXValueDescription"
+#endif
+
+#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;
+- (void)accessibilitySetShouldRepostNotifications:(BOOL)repost;
+- (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
+
+@interface AccessibilityNotificationHandler : NSObject
+{
+ id m_platformElement;
+ JSObjectRef m_notificationFunctionCallback;
+}
+
+@end
+
+@implementation AccessibilityNotificationHandler
+
+- (id)initWithPlatformElement:(id)platformElement
+{
+ self = [super init];
+
+ m_platformElement = platformElement;
+
+ // Once an object starts 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 just listen when they want to.
+ [m_platformElement accessibilitySetShouldRepostNotifications:YES];
+ [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_notificationReceived:) name:@"AXDRTNotification" object:nil];
+
+ return self;
+}
+
+- (void)dealloc
+{
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+ JSValueUnprotect([mainFrame globalContext], m_notificationFunctionCallback);
+ m_notificationFunctionCallback = 0;
+
+ [super dealloc];
+}
+
+- (void)_notificationReceived:(NSNotification *)notification
+{
+ NSString *notificationName = [[notification userInfo] objectForKey:@"notificationName"];
+ if (!notificationName)
+ return;
+
+ JSRetainPtr<JSStringRef> jsNotification(Adopt, [notificationName createJSStringRef]);
+ JSValueRef argument = JSValueMakeString([mainFrame globalContext], jsNotification.get());
+ JSObjectCallAsFunction([mainFrame globalContext], m_notificationFunctionCallback, 0, 1, &argument, 0);
+}
+
+- (void)setCallback:(JSObjectRef)callback
+{
+ if (!callback)
+ return;
+
+ // Release the old callback.
+ if (m_notificationFunctionCallback)
+ JSValueUnprotect([mainFrame globalContext], m_notificationFunctionCallback);
+
+ m_notificationFunctionCallback = callback;
+ JSValueProtect([mainFrame globalContext], m_notificationFunctionCallback);
+}
+
+@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;
+}
+
+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;
+}
+
+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;
+}
+
+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] initWithPlatformElement:platformUIElement()];
+ [m_notificationHandler setCallback:functionCallback];
+
+ 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
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isSelectable() const
+{
+ // FIXME: implement
+ return false;
+}
+
+bool AccessibilityUIElement::isMultiSelectable() 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;
+}
+
+
+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 0000000..c29789c
--- /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 0000000..2eab827
--- /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 0000000..faef760
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/CheckedMalloc.cpp
@@ -0,0 +1,72 @@
+/*
+ * 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 <malloc/malloc.h>
+#import <sys/mman.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);
+}
+
+void makeLargeMallocFailSilently()
+{
+ malloc_zone_t* zone = malloc_default_zone();
+
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ vm_address_t pageStart = reinterpret_cast<vm_address_t>(zone) & static_cast<vm_size_t>(~(getpagesize() - 1));
+ vm_size_t len = reinterpret_cast<vm_address_t>(zone) - pageStart + sizeof(malloc_zone_t);
+ mprotect(reinterpret_cast<void*>(pageStart), len, PROT_READ | PROT_WRITE);
+#endif
+
+ savedMalloc = zone->malloc;
+ savedRealloc = zone->realloc;
+ zone->malloc = checkedMalloc;
+ zone->realloc = checkedRealloc;
+
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
+ mprotect(reinterpret_cast<void*>(pageStart), len, PROT_READ);
+#endif
+}
diff --git a/Tools/DumpRenderTree/mac/CheckedMalloc.h b/Tools/DumpRenderTree/mac/CheckedMalloc.h
new file mode 100644
index 0000000..c03bd20
--- /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 0000000..28a0518
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/Configurations/Base.xcconfig
@@ -0,0 +1,69 @@
+// 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.
+
+HEADER_SEARCH_PATHS = ForwardingHeaders mac/InternalHeaders;
+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;
+
+
+TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR);
+
+
+// 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_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+TARGET_GCC_VERSION_ = $(TARGET_GCC_VERSION_1040);
+TARGET_GCC_VERSION_1040 = GCC_40;
+TARGET_GCC_VERSION_1050 = $(TARGET_GCC_VERSION_1050_$(XCODE_VERSION_MINOR));
+TARGET_GCC_VERSION_1050_ = $(TARGET_GCC_VERSION_1050_$(XCODE_VERSION_ACTUAL));
+TARGET_GCC_VERSION_1050_0310 = GCC_42;
+TARGET_GCC_VERSION_1050_0320 = GCC_42;
+TARGET_GCC_VERSION_1060 = GCC_42;
+TARGET_GCC_VERSION_1070 = LLVM_GCC_42;
+
+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;
+
+// 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_1050_1040 = macosx10.4;
+SDKROOT_1060_1040 = macosx10.4;
+SDKROOT_1060_1050 = macosx10.5;
+SDKROOT_1070_1040 = macosx10.4;
+SDKROOT_1070_1050 = macosx10.5;
+SDKROOT_1070_1060 = macosx10.6;
diff --git a/Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig b/Tools/DumpRenderTree/mac/Configurations/DebugRelease.xcconfig
new file mode 100644
index 0000000..ab3278e
--- /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_ = $(ARCHS_1040);
+ARCHS_1040 = $(NATIVE_ARCH);
+ARCHS_1050 = $(NATIVE_ARCH);
+ARCHS_1060 = $(ARCHS_STANDARD_32_64_BIT);
+ARCHS_1070 = $(ARCHS_STANDARD_32_64_BIT);
+
+ONLY_ACTIVE_ARCH = YES;
+
+MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(TARGET_MAC_OS_X_VERSION_MAJOR))
+MACOSX_DEPLOYMENT_TARGET_ = 10.4;
+MACOSX_DEPLOYMENT_TARGET_1040 = 10.4;
+MACOSX_DEPLOYMENT_TARGET_1050 = 10.5;
+MACOSX_DEPLOYMENT_TARGET_1060 = 10.6;
+MACOSX_DEPLOYMENT_TARGET_1070 = 10.7;
diff --git a/Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig b/Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig
new file mode 100644
index 0000000..35a0720
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/Configurations/DumpRenderTree.xcconfig
@@ -0,0 +1,27 @@
+// 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
+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 0000000..35968af
--- /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 0000000..22ea4c2
--- /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 0000000..ed09cf6
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/DumpRenderTree.mm
@@ -0,0 +1,1188 @@
+/*
+ * 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 "UIDelegate.h"
+#import "WebArchiveDumpSupport.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/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;
+
+static int dumpPixels;
+static int threaded;
+static int dumpTree = YES;
+static int forceComplexText;
+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 void activateFonts()
+{
+#if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_TIGER)
+ static const char* fontSectionNames[] = {
+ "Ahem",
+ "WeightWatcher100",
+ "WeightWatcher200",
+ "WeightWatcher300",
+ "WeightWatcher400",
+ "WeightWatcher500",
+ "WeightWatcher600",
+ "WeightWatcher700",
+ "WeightWatcher800",
+ "WeightWatcher900",
+ 0
+ };
+
+ for (unsigned i = 0; fontSectionNames[i]; ++i) {
+ unsigned long fontDataLength;
+ char* fontData = getsectdata("__DATA", fontSectionNames[i], &fontDataLength);
+ if (!fontData) {
+ fprintf(stderr, "Failed to locate the %s font.\n", fontSectionNames[i]);
+ exit(1);
+ }
+
+ ATSFontContainerRef fontContainer;
+ OSStatus status = ATSFontActivateFromMemory(fontData, fontDataLength, kATSFontContextLocal, kATSFontFormatUnspecified, NULL, kATSOptionFlagsDefault, &fontContainer);
+
+ if (status != noErr) {
+ fprintf(stderr, "Failed to activate the %s font.\n", fontSectionNames[i]);
+ exit(1);
+ }
+ }
+#else
+
+ // 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",
+ "ColorBits.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);
+ }
+#endif
+}
+
+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];
+
+ // 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 screens] objectAtIndex:0] frame].size.height - rect.size.height + 10000);
+ DumpRenderTreeWindow *window = [[DumpRenderTreeWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
+
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ [window setColorSpace:[[NSScreen mainScreen] colorSpace]];
+#endif
+
+ [[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;
+}
+
+void testStringByEvaluatingJavaScriptFromString()
+{
+ // maps expected result <= JavaScript expression
+ NSDictionary *expressions = [NSDictionary dictionaryWithObjectsAndKeys:
+ @"0", @"0",
+ @"0", @"'0'",
+ @"", @"",
+ @"", @"''",
+ @"", @"new String()",
+ @"", @"new String('0')",
+ @"", @"throw 1",
+ @"", @"{ }",
+ @"", @"[ ]",
+ @"", @"//",
+ @"", @"a.b.c",
+ @"", @"(function() { throw 'error'; })()",
+ @"", @"null",
+ @"", @"undefined",
+ @"true", @"true",
+ @"false", @"false",
+ nil
+ ];
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ WebView *webView = [[WebView alloc] initWithFrame:NSZeroRect frameName:@"" groupName:@""];
+
+ NSEnumerator *enumerator = [expressions keyEnumerator];
+ id expression;
+ while ((expression = [enumerator nextObject])) {
+ NSString *expectedResult = [expressions objectForKey:expression];
+ NSString *result = [webView stringByEvaluatingJavaScriptFromString:expression];
+ assert([result isEqualToString:expectedResult]);
+ }
+
+ [webView close];
+ [webView release];
+ [pool release];
+}
+
+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()
+{
+ // Give some clear to undocumented defaults values
+ 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"];
+
+ if (initialValue)
+ CFPreferencesSetValue(CFSTR("AppleScrollBarVariant"), initialValue.get(), kCFPreferencesAnyApplication, kCFPreferencesCurrentUser, kCFPreferencesAnyHost);
+
+ NSString *path = libraryPathForDumpRenderTree();
+ [defaults setObject:[path stringByAppendingPathComponent:@"Databases"] forKey:WebDatabaseDirectoryDefaultsKey];
+ [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 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 setPluginAllowedRunTime:1];
+ [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 setFrameFlatteningEnabled: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];
+ [preferences setWebGLEnabled:NO];
+ [preferences setUsePreHTML5ParserQuirks:NO];
+ [preferences setAsynchronousSpellCheckingEnabled:NO];
+
+ [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy: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];
+
+}
+
+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];
+}
+
+// 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);
+}
+
+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},
+ {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();
+ activateFonts();
+
+ 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.
+#if BUILDING_ON_TIGER
+ // Initialize internal NSURLRequest data for setAllowsAnyHTTPSCertificate:forHost: to work properly.
+ [[[[NSURLRequest alloc] init] autorelease] HTTPMethod];
+#endif
+ [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"localhost"];
+ [NSURLRequest setAllowsAnyHTTPSCertificate:YES forHost:@"127.0.0.1"];
+
+ // <rdar://problem/5222911>
+ testStringByEvaluatingJavaScriptFromString();
+
+ // 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 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)
+{
+ NSPoint scrollPosition = [[[[f frameView] documentView] superview] bounds].origin;
+ 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->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 (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 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 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];
+
+ resetDefaultsToConsistentValues();
+
+ [[mainFrame webView] setSmartInsertDeleteEnabled:YES];
+ [[[mainFrame webView] inspector] setJavaScriptProfilingEnabled:NO];
+
+ [WebView _setUsesTestModeFocusRingColor:YES];
+ [WebView _resetOriginAccessWhitelists];
+
+ [[MockGeolocationProvider shared] stopTimer];
+
+ // Clear the contents of the general pasteboard
+ [[NSPasteboard generalPasteboard] declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:nil];
+}
+
+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 ([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];
+}
+
+void displayWebView()
+{
+ NSView *webView = [mainFrame webView];
+ [webView display];
+ [webView lockFocus];
+ [[[NSColor blackColor] colorWithAlphaComponent:0.66] set];
+ NSRectFillUsingOperation([webView frame], NSCompositeSourceOver);
+ [webView unlockFocus];
+}
+
+@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 0000000..249809c
--- /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 0000000..8eded66
--- /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_TIGER) && !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_TIGER) && !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 0000000..36c5eac
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/DumpRenderTreeMac.h
@@ -0,0 +1,68 @@
+/*
+ * 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 WebFrame;
+@class WebScriptWorld;
+@class WebView;
+#else
+class DumpRenderTreeDraggingInfo;
+class NavigationController;
+class PolicyDelegate;
+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 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 0000000..ba2754b
--- /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 0000000..b1b3b86
--- /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 0000000..a229d20
--- /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 0000000..e0cdc6b
--- /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 0000000..b5563c8
--- /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 0000000..02e931c
--- /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 0000000..9440575
--- /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 0000000..9031c63
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/EventSendingController.mm
@@ -0,0 +1,868 @@
+/*
+ * 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(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";
+ 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)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
+{
+ // CGEventCreateScrollWheelEvent() was introduced in 10.5
+#if !defined(BUILDING_ON_TIGER)
+ 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];
+#endif
+}
+
+- (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 0000000..390a881
--- /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 0000000..a36982c
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/FrameLoadDelegate.mm
@@ -0,0 +1,400 @@
+/*
+ * 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 "GCController.h"
+#import "LayoutTestController.h"
+#import "NavigationController.h"
+#import "ObjCController.h"
+#import "ObjCPlugin.h"
+#import "ObjCPluginFunction.h"
+#import "PlainTextController.h"
+#import "TextInputController.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;
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ 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);
+
+ // 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]);
+ }
+}
+
+- (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");
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/GCControllerMac.mm b/Tools/DumpRenderTree/mac/GCControllerMac.mm
new file mode 100644
index 0000000..de8a61e
--- /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 0000000..c56d203
--- /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 0000000..cbc4093
--- /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 0000000..58049c2
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/InternalHeaders/WebKit/WebTypesInternal.h
@@ -0,0 +1 @@
+#include "../../../../WebKit/mac/Misc/WebTypesInternal.h"
diff --git a/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm b/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm
new file mode 100644
index 0000000..a691951
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/LayoutTestControllerMac.mm
@@ -0,0 +1,1005 @@
+/*
+ * 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 "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/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];
+}
+
+void LayoutTestController::clearAllDatabases()
+{
+ [[WebDatabaseManager sharedWebDatabaseManager] deleteAllDatabases];
+}
+
+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];
+}
+
+size_t LayoutTestController::webHistoryItemCount()
+{
+ return [[[WebHistory optionalSharedHistory] allItems] count];
+}
+
+unsigned LayoutTestController::workerThreadCount() const
+{
+ return [WebWorkersPrivate workerThreadCount];
+}
+
+void LayoutTestController::notifyDone()
+{
+ if (m_waitToDump && !topLoadingFrame && !WorkQueue::shared()->count())
+ dump();
+ m_waitToDump = false;
+}
+
+JSStringRef LayoutTestController::pathToLocalResource(JSContextRef context, JSStringRef url)
+{
+ return JSStringRetain(url); // Do nothing on mac.
+}
+
+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;
+ [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy: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::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::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::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::setTimelineProfilingEnabled(bool enabled)
+{
+ [[[mainFrame webView] inspector] setTimelineProfilingEnabled:enabled];
+}
+
+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::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];
+}
+
+@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];
+}
+
+#ifndef BUILDING_ON_TIGER
+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) {
+ NSURLCredential *credential = [[NSURLCredential alloc] initWithUser:m_username password:m_password persistence:NSURLCredentialPersistenceForSession];
+ [[challenge sender] useCredential:credential 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
+#endif
+
+void LayoutTestController::authenticateSession(JSStringRef url, JSStringRef username, JSStringRef password)
+{
+ // See <rdar://problem/7880699>.
+#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
+ RetainPtr<CFStringRef> urlStringCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, url));
+ RetainPtr<CFStringRef> usernameCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, username));
+ RetainPtr<CFStringRef> passwordCF(AdoptCF, JSStringCopyCFString(kCFAllocatorDefault, password));
+
+ NSURLRequest *request = [[NSURLRequest alloc] initWithURL:[NSURL URLWithString:(NSString *)urlStringCF.get()]];
+
+ [SynchronousLoader makeRequest:request 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];
+}
+void LayoutTestController::dumpConfigurationForViewport(int /*availableWidth*/, int /*availableHeight*/)
+{
+
+}
+
+void LayoutTestController::setSerializeHTTPLoads(bool serialize)
+{
+ [WebView _setLoadResourcesSerially:serialize];
+}
diff --git a/Tools/DumpRenderTree/mac/MockGeolocationProvider.h b/Tools/DumpRenderTree/mac/MockGeolocationProvider.h
new file mode 100644
index 0000000..311d1e9
--- /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 0000000..e03cae2
--- /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 0000000..8ee3432
--- /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 0000000..8c01d50
--- /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 0000000..d1d001c
--- /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 0000000..f1d1c10
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/ObjCController.m
@@ -0,0 +1,285 @@
+/*
+ * 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(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(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;
+}
+
+- (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;
+}
+
+#pragma mark -
+#pragma 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 0000000..a6d3e50
--- /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 0000000..023eae1
--- /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 0000000..1e81b21
--- /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 0000000..5bf3617
--- /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 0000000..35f051c
--- /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 0000000..7b4ea34
--- /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 0000000..f734989
--- /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 0000000..16a9e51
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/PerlSupport/Makefile
@@ -0,0 +1,74 @@
+# 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)" "4"
+GENERATE_WRAPPER = NO
+endif
+ifeq "$(OSX_VERSION)" "7"
+GENERATE_WRAPPER = NO
+endif
+
+ifneq "$(GENERATE_WRAPPER)" "NO"
+
+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 -eldopts` $^
+
+clean:
+ rm -f $(WRAPPER) $(PERL_MODULE) $(DYLIB)
+
+installhdrs installsrc install:
diff --git a/Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm b/Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm
new file mode 100644
index 0000000..3967186
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/PixelDumpSupportMac.mm
@@ -0,0 +1,279 @@
+/*
+ * 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>
+
+#if defined(BUILDING_ON_TIGER)
+#include <OpenGL/OpenGL.h>
+#include <OpenGL/CGLMacro.h>
+#endif
+
+// 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)", 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)", 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)", 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);
+}
+
+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;
+
+ NSSize webViewSize = [view frame].size;
+ size_t pixelsWide = static_cast<size_t>(webViewSize.width);
+ size_t pixelsHigh = static_cast<size_t>(webViewSize.height);
+ size_t rowBytes = 0;
+ void* buffer = 0;
+ RefPtr<BitmapContext> bitmapContext = createBitmapContext(pixelsWide, pixelsHigh, rowBytes, buffer);
+ if (!bitmapContext)
+ return 0;
+ CGContextRef context = bitmapContext->cgContext();
+
+ 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 (onscreen) {
+#if !defined(BUILDING_ON_TIGER)
+ // 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);
+#else
+ // On 10.4 and earlier, we have to move the window temporarily "onscreen" and read directly from the display framebuffer using OpenGL
+ // In this code path, we need to ensure the window is above any other window or captured result will be corrupted
+
+ NSWindow *window = [view window];
+ int oldLevel = [window level];
+ NSRect oldFrame = [window frame];
+
+ NSRect newFrame = [[[NSScreen screens] objectAtIndex:0] frame];
+ newFrame = NSMakeRect(newFrame.origin.x + (newFrame.size.width - oldFrame.size.width) / 2, newFrame.origin.y + (newFrame.size.height - oldFrame.size.height) / 2, oldFrame.size.width, oldFrame.size.height);
+ [window setLevel:NSScreenSaverWindowLevel];
+ [window setFrame:newFrame display:NO animate:NO];
+
+ CGRect rect = CGRectMake(newFrame.origin.x, newFrame.origin.y, webViewSize.width, webViewSize.height);
+ CGDirectDisplayID displayID;
+ CGDisplayCount count;
+ if (CGGetDisplaysWithRect(rect, 1, &displayID, &count) == kCGErrorSuccess) {
+ CGRect bounds = CGDisplayBounds(displayID);
+ rect.origin.x -= bounds.origin.x;
+ rect.origin.y -= bounds.origin.y;
+
+ CGLPixelFormatAttribute attributes[] = {kCGLPFAAccelerated, kCGLPFANoRecovery, kCGLPFAFullScreen, kCGLPFADisplayMask, (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(displayID), (CGLPixelFormatAttribute)0};
+ CGLPixelFormatObj pixelFormat;
+ GLint num;
+ if (CGLChoosePixelFormat(attributes, &pixelFormat, &num) == kCGLNoError) {
+ CGLContextObj cgl_ctx;
+ if (CGLCreateContext(pixelFormat, 0, &cgl_ctx) == kCGLNoError) {
+ if (CGLSetFullScreen(cgl_ctx) == kCGLNoError) {
+ void *flipBuffer = calloc(pixelsHigh, rowBytes);
+ if (flipBuffer) {
+ glPixelStorei(GL_PACK_ROW_LENGTH, rowBytes / 4);
+ glPixelStorei(GL_PACK_ALIGNMENT, 4);
+#if __BIG_ENDIAN__
+ glReadPixels(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, flipBuffer);
+#else
+ glReadPixels(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, flipBuffer);
+#endif
+ if (!glGetError()) {
+ for(size_t i = 0; i < pixelsHigh; ++i)
+ bcopy((char*)flipBuffer + rowBytes * i, (char*)buffer + rowBytes * (pixelsHigh - i - 1), pixelsWide * 4);
+ }
+
+ free(flipBuffer);
+ }
+ }
+ CGLDestroyContext(cgl_ctx);
+ }
+ CGLDestroyPixelFormat(pixelFormat);
+ }
+ }
+
+ [window setFrame:oldFrame display:NO animate:NO];
+ [window setLevel:oldLevel];
+#endif
+ } 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];
+ [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 0000000..1488f2f
--- /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 0000000..eb89bce
--- /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 0000000..3b95455
--- /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 0000000..6935ea7
--- /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 0000000..0c4618e
--- /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 0000000..0855b83
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/ResourceLoadDelegate.mm
@@ -0,0 +1,245 @@
+/*
+ * 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 "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];
+
+ return [[self path] substringFromIndex:[basePath length] + 1];
+}
+
+@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
+
+- 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];
+ }
+
+ 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;
+}
+
+@end
diff --git a/Tools/DumpRenderTree/mac/TextInputController.h b/Tools/DumpRenderTree/mac/TextInputController.h
new file mode 100644
index 0000000..767e72f
--- /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 0000000..f780794
--- /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 0000000..a8017ad
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/UIDelegate.h
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+@end
diff --git a/Tools/DumpRenderTree/mac/UIDelegate.mm b/Tools/DumpRenderTree/mac/UIDelegate.mm
new file mode 100644
index 0000000..6194c26
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/UIDelegate.mm
@@ -0,0 +1,263 @@
+/*
+ * 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
+{
+ 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 YES;
+}
+
+
+- (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
+{
+ if (!done && gLayoutTestController->dumpApplicationCacheDelegateCallbacks()) {
+ printf("UI DELEGATE APPLICATION CACHE CALLBACK: exceededApplicationCacheOriginQuotaForSecurityOrigin:{%s, %s, %i}\n",
+ [[origin protocol] UTF8String], [[origin host] UTF8String], [origin port]);
+ }
+
+ 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];
+}
+
+- (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
+{
+ 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 0000000..c273087
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/WebArchiveDumpSupportMac.mm
@@ -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 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 "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 0000000..797afb7
--- /dev/null
+++ b/Tools/DumpRenderTree/mac/WorkQueueItemMac.mm
@@ -0,0 +1,91 @@
+/*
+ * 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()));
+
+ [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 0000000..5a48b27
--- /dev/null
+++ b/Tools/DumpRenderTree/pthreads/JavaScriptThreadingPthreads.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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 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;
+}
+
+// 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 (1) {
+ JSGlobalContextRef ctx = JSGlobalContextCreate(0);
+ JSStringRef scriptRef = JSStringCreateWithUTF8CString(script);
+
+ JSValueRef exception = 0;
+ JSEvaluateScript(ctx, scriptRef, 0, 0, 1, &exception);
+ ASSERT(!exception);
+
+ JSGarbageCollect(ctx);
+ JSGlobalContextRelease(ctx);
+ JSStringRelease(scriptRef);
+
+ JSGarbageCollect(0);
+
+ pthread_mutex_lock(&javaScriptThreadsMutex);
+
+ // Check for cancellation.
+ if (javaScriptThreadsShouldTerminate) {
+ javaScriptThreads()->remove(pthread_self());
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+ return 0;
+ }
+
+ // Respawn probabilistically.
+ if (random() % 5 == 0) {
+ pthread_t pthread;
+ pthread_create(&pthread, 0, &runJavaScriptThread, 0);
+ pthread_detach(pthread);
+
+ javaScriptThreads()->remove(pthread_self());
+ javaScriptThreads()->add(pthread);
+
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+ return 0;
+ }
+
+ pthread_mutex_unlock(&javaScriptThreadsMutex);
+ }
+}
+
+void startJavaScriptThreads()
+{
+ 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;
+
+ ASSERT(javaScriptThreads()->size() == javaScriptThreadsCount);
+
+ 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 0000000..e8831a3
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/DumpRenderTree.pro
@@ -0,0 +1,53 @@
+TARGET = DumpRenderTree
+CONFIG -= app_bundle
+CONFIG += uitools
+
+BASEDIR = $$PWD/../
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
+
+include(../../../WebKit.pri)
+INCLUDEPATH += ../../..
+INCLUDEPATH += ../../../JavaScriptCore
+INCLUDEPATH += ../../../JavaScriptCore/ForwardingHeaders
+INCLUDEPATH += $$BASEDIR
+DESTDIR = ../../../bin
+
+unix:!mac:!symbian {
+ CONFIG += link_pkgconfig
+ PKGCONFIG += fontconfig
+}
+
+QT = core gui network testlib
+macx: QT += xml
+
+HEADERS = $$BASEDIR/WorkQueue.h \
+ DumpRenderTreeQt.h \
+ EventSenderQt.h \
+ TextInputControllerQt.h \
+ WorkQueueItemQt.h \
+ LayoutTestControllerQt.h \
+ GCControllerQt.h \
+ PlainTextControllerQt.h \
+ testplugin.h
+SOURCES = ../../../JavaScriptCore/wtf/Assertions.cpp \
+ $$BASEDIR/WorkQueue.cpp \
+ DumpRenderTreeQt.cpp \
+ EventSenderQt.cpp \
+ TextInputControllerQt.cpp \
+ PlainTextControllerQt.cpp \
+ WorkQueueItemQt.cpp \
+ LayoutTestControllerQt.cpp \
+ GCControllerQt.cpp \
+ testplugin.cpp \
+ main.cpp
+
+unix:!mac {
+ QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR
+}
+
+wince*: {
+ INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/ce-compat $$WCECOMPAT/include
+ LIBS += $$WCECOMPAT/lib/wcecompat.lib
+}
+
+DEFINES+=USE_SYSTEM_MALLOC
diff --git a/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
new file mode 100644
index 0000000..935a307
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.cpp
@@ -0,0 +1,1151 @@
+/*
+ * 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 "../../../WebKit/qt/WebCoreSupport/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
+
+#ifdef Q_WS_X11
+#include <fontconfig/fontconfig.h>
+#endif
+
+#include <limits.h>
+#include <locale.h>
+
+#ifndef Q_OS_WIN
+#include <unistd.h>
+#endif
+
+#include <qdebug.h>
+
+namespace WebCore {
+
+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::PluginsEnabled);
+ settings()->resetAttribute(QWebSettings::JavascriptCanAccessClipboard);
+ settings()->resetAttribute(QWebSettings::AutoLoadImages);
+
+ m_drt->layoutTestController()->setCaretBrowsingEnabled(false);
+ m_drt->layoutTestController()->setFrameFlatteningEnabled(false);
+ m_drt->layoutTestController()->setSmartInsertDeleteEnabled(true);
+ m_drt->layoutTestController()->setSelectTrailingWhitespaceEnabled(false);
+
+ // globalSettings must be reset explicitly.
+ m_drt->layoutTestController()->setXSSAuditorEnabled(false);
+
+ QWebSettings::setMaximumPagesInCache(0); // reset to default
+ settings()->setUserStyleSheetUrl(QUrl()); // reset to default
+
+ 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()) {
+ QString url = QString::fromUtf8(request.url().toEncoded());
+ QString typeDescription;
+
+ switch (type) {
+ case NavigationTypeLinkClicked:
+ typeDescription = "link clicked";
+ break;
+ case NavigationTypeFormSubmitted:
+ typeDescription = "form submitted";
+ break;
+ case NavigationTypeBackOrForward:
+ typeDescription = "back/forward";
+ break;
+ case NavigationTypeReload:
+ typeDescription = "reload";
+ break;
+ case NavigationTypeFormResubmitted:
+ typeDescription = "form resubmitted";
+ break;
+ case NavigationTypeOther:
+ typeDescription = "other";
+ break;
+ default:
+ typeDescription = "illegal value";
+ }
+
+ if (isTextOutputEnabled())
+ fprintf(stdout, "Policy delegate: attempt to load %s with navigation type '%s'\n",
+ url.toUtf8().constData(), typeDescription.toUtf8().constData());
+
+ 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::overwritePluginDirectories();
+ DumpRenderTreeSupportQt::activeMockDeviceOrientationClient(true);
+ 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)),
+ this, SLOT(dumpApplicationCacheQuota(QWebSecurityOrigin *, 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);
+ QFocusEvent event(QEvent::FocusIn, Qt::ActiveWindowFocusReason);
+ QApplication::sendEvent(m_mainView, &event);
+}
+
+DumpRenderTree::~DumpRenderTree()
+{
+ delete m_mainView;
+ delete m_stdin;
+ DumpRenderTreeSupportQt::removeMockDeviceOrientation();
+}
+
+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()
+{
+ // 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);
+
+ // 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();
+
+ m_page->resetSettings();
+ m_page->undoStack()->clear();
+ m_page->mainFrame()->setZoomFactor(1.0);
+ clearHistory(m_page);
+ DumpRenderTreeSupportQt::clearFrameName(m_page->mainFrame());
+
+ m_page->mainFrame()->setScrollBarPolicy(Qt::Vertical, Qt::ScrollBarAsNeeded);
+ m_page->mainFrame()->setScrollBarPolicy(Qt::Horizontal, Qt::ScrollBarAsNeeded);
+
+ WorkQueue::shared()->clear();
+ WorkQueue::shared()->setFrozen(false);
+
+ DumpRenderTreeSupportQt::resetOriginAccessWhiteLists();
+
+ // Qt defaults to Windows editing behavior.
+ DumpRenderTreeSupportQt::setEditingBehavior(m_page, "win");
+
+ QLocale::setDefault(QLocale::c());
+
+#ifndef Q_OS_WINCE
+ setlocale(LC_ALL, "");
+#endif
+}
+
+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 shouldEnableDeveloperExtras(const QUrl& url)
+{
+ return true;
+}
+
+void DumpRenderTree::open(const QUrl& url)
+{
+ DumpRenderTreeSupportQt::dumpResourceLoadCallbacksPath(QFileInfo(url.toString()).path());
+ resetToConsistentStateBeforeTesting();
+
+ if (shouldEnableDeveloperExtras(m_page->mainFrame()->url())) {
+ layoutTestController()->closeWebInspector();
+ layoutTestController()->setDeveloperExtrasEnabled(false);
+ }
+
+ if (shouldEnableDeveloperExtras(url)) {
+ layoutTestController()->setDeveloperExtrasEnabled(true);
+ if (isWebInspectorTest(url))
+ layoutTestController()->showWebInspector();
+ }
+
+ 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 !(defined(Q_OS_SYMBIAN) && QT_VERSION <= QT_VERSION_CHECK(4, 6, 2))
+ QFontDatabase::removeAllApplicationFonts();
+#endif
+#if defined(Q_WS_X11)
+ initializeFonts();
+#endif
+
+ 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);
+
+ for (int i = 1; i < args.size(); ++i)
+ if (!args.at(i).startsWith('-'))
+ m_standAloneModeTestList.append(args[i]);
+
+ 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]);
+ }
+
+ processLine(m_standAloneModeTestList.first());
+ m_standAloneModeTestList.removeFirst();
+
+ connect(this, SIGNAL(ready()), this, SLOT(loadNextTestInStandAloneMode()));
+}
+
+void DumpRenderTree::loadNextTestInStandAloneMode()
+{
+ if (m_standAloneModeTestList.isEmpty()) {
+ emit quit();
+ return;
+ }
+
+ processLine(m_standAloneModeTestList.first());
+ m_standAloneModeTestList.removeFirst();
+}
+
+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);
+}
+
+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().toEncoded();
+ 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());
+ }
+
+ // 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) {
+ 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(5 * 1024 * 1024);
+}
+
+void DumpRenderTree::dumpApplicationCacheQuota(QWebSecurityOrigin* origin, quint64 defaultOriginQuota)
+{
+ if (!m_controller->shouldDumpApplicationCacheDelegateCallbacks())
+ return;
+
+ printf("UI DELEGATE APPLICATION CACHE CALLBACK: exceededApplicationCacheOriginQuotaForSecurityOrigin:{%s, %s, %i}\n",
+ origin->scheme().toUtf8().data(),
+ origin->host().toUtf8().data(),
+ origin->port()
+ );
+ 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);
+ // Our use of container->deleteLater() means we need to remove closed pages
+ // from the org.webkit.qt.DumpRenderTree group explicitly.
+ DumpRenderTreeSupportQt::webPageSetGroupName(page, "");
+ 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);
+ }
+
+}
+
+#if defined(Q_WS_X11)
+void DumpRenderTree::initializeFonts()
+{
+ static int numFonts = -1;
+
+ // 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 0000000..ef95bfc
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/DumpRenderTreeQt.h
@@ -0,0 +1,232 @@
+/*
+ * 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 "../../../WebKit/qt/WebCoreSupport/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();
+
+ 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; }
+
+#if defined(Q_WS_X11)
+ static void initializeFonts();
+#endif
+ void processArgsLine(const QStringList&);
+
+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);
+ 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;
+};
+
+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 0000000..6fb75a5
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/EventSenderQt.cpp
@@ -0,0 +1,653 @@
+/*
+ * 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);
+}
+
+void EventSender::mouseDown(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;
+ }
+
+ // 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, Qt::NoModifier);
+ } else {
+ event = new QMouseEvent((m_clickCount == 2) ? QEvent::MouseButtonDblClick :
+ QEvent::MouseButtonPress, m_mousePos, m_mousePos,
+ mouseButton, m_mouseButtons, Qt::NoModifier);
+ }
+
+ 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 = 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;
+ }
+ 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;
+ }
+ }
+ QKeyEvent event(QEvent::KeyPress, code, modifs, s);
+ sendEvent(m_page, &event);
+ QKeyEvent event2(QEvent::KeyRelease, code, modifs, s);
+ sendEvent(m_page, &event2);
+}
+
+void 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);
+ }
+}
+
+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)
+{
+ // Use index to refer to the position in the vector that this touch
+ // is stored. We then create a unique id for the touch that will be
+ // passed into WebCore.
+ int index = m_touchPoints.count();
+ int id = m_touchPoints.isEmpty() ? 0 : m_touchPoints.last().id() + 1;
+ QTouchEvent::TouchPoint point(id);
+ m_touchPoints.append(point);
+ updateTouchPoint(index, x, y);
+ m_touchPoints[index].setState(Qt::TouchPointPressed);
+}
+
+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)
+{
+ QTouchEvent event(type, QTouchEvent::TouchScreen, m_touchModifiers);
+ 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);
+}
+
+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 0000000..4ba8382
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/EventSenderQt.h
@@ -0,0 +1,112 @@
+/*
+ * 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);
+ 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() {}
+ void 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 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 0000000..3aa507f
--- /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 "../../../WebKit/qt/WebCoreSupport/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 0000000..d3c83b9
--- /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 0000000..9282e2f
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/ImageDiff.cpp
@@ -0,0 +1,149 @@
+/*
+ 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 (!count) {
+ 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);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/Tools/DumpRenderTree/qt/ImageDiff.pro b/Tools/DumpRenderTree/qt/ImageDiff.pro
new file mode 100644
index 0000000..74fabf8
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/ImageDiff.pro
@@ -0,0 +1,16 @@
+TARGET = ImageDiff
+CONFIG -= app_bundle
+
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
+include(../../../WebKit.pri)
+INCLUDEPATH += ../../../JavaScriptCore
+DESTDIR = $$OUTPUT_DIR/bin
+
+QT = core gui
+
+SOURCES = ImageDiff.cpp
+
+unix:!mac {
+ QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR
+}
+
diff --git a/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
new file mode 100644
index 0000000..b8cc9be
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.cpp
@@ -0,0 +1,834 @@
+/*
+ * 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 "../../../WebKit/qt/WebCoreSupport/DumpRenderTreeSupportQt.h"
+
+#include "DumpRenderTreeQt.h"
+#include "WorkQueue.h"
+#include "WorkQueueItemQt.h"
+#include <QDir>
+#include <QLocale>
+#include <qwebsettings.h>
+
+LayoutTestController::LayoutTestController(WebCore::DumpRenderTree* drt)
+ : QObject()
+ , m_drt(drt)
+{
+ qRegisterMetaType<QWebElement>("QWebElement");
+ 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_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::dumpUserGestureInFrameLoader(false);
+ DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(false);
+ DumpRenderTreeSupportQt::dumpResourceResponseMIMETypes(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);
+ setIconDatabaseEnabled(false);
+
+ 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()) {
+ if (success)
+ 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::clearBackForwardList()
+{
+ m_drt->webPage()->history()->clear();
+}
+
+QString LayoutTestController::pathToLocalResource(const QString& url)
+{
+ // Function introduced in r28690.
+ return QDir::toNativeSeparators(url);
+}
+
+void LayoutTestController::dumpConfigurationForViewport(int availableWidth, int availableHeight)
+{
+ QString res = DumpRenderTreeSupportQt::viewportAsText(m_drt->webPage(), QSize(availableWidth, availableHeight));
+ fputs(qPrintable(res), stdout);
+}
+
+void LayoutTestController::dumpEditingCallbacks()
+{
+ qDebug() << ">>>dumpEditingCallbacks";
+ DumpRenderTreeSupportQt::dumpEditingCallbacks(true);
+}
+
+void LayoutTestController::dumpFrameLoadCallbacks()
+{
+ DumpRenderTreeSupportQt::dumpFrameLoader(true);
+}
+
+void LayoutTestController::dumpUserGestureInFrameLoadCallbacks()
+{
+ DumpRenderTreeSupportQt::dumpUserGestureInFrameLoader(true);
+}
+
+void LayoutTestController::dumpResourceLoadCallbacks()
+{
+ DumpRenderTreeSupportQt::dumpResourceLoadCallbacks(true);
+}
+
+void LayoutTestController::dumpResourceResponseMIMETypes()
+{
+ DumpRenderTreeSupportQt::dumpResourceResponseMIMETypes(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)
+{
+ WorkQueue::shared()->queue(new LoadHTMLStringItem(content, baseURL, 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::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::setJavaScriptProfilingEnabled(bool enable)
+{
+ setDeveloperExtrasEnabled(enable);
+ DumpRenderTreeSupportQt::setJavaScriptProfilingEnabled(m_topLoadingFrame, enable);
+}
+
+void LayoutTestController::setTimelineProfilingEnabled(bool enable)
+{
+ DumpRenderTreeSupportQt::setTimelineProfilingEnabled(m_drt->webPage(), enable);
+}
+
+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::setApplicationCacheOriginQuota(unsigned long long quota)
+{
+ if (!m_topLoadingFrame)
+ return;
+ m_topLoadingFrame->securityOrigin().setApplicationCacheQuota(quota);
+}
+
+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()
+{
+ 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
+ printf("ERROR: LayoutTestController::overridePreference() does not support the '%s' preference\n",
+ name.toLatin1().data());
+}
+
+void LayoutTestController::setUserStyleSheetLocation(const QString& url)
+{
+ m_userStyleSheetLocation = QUrl(url);
+
+ if (m_userStyleSheetEnabled)
+ setUserStyleSheetEnabled(true);
+}
+
+void LayoutTestController::setCaretBrowsingEnabled(bool value)
+{
+ DumpRenderTreeSupportQt::setCaretBrowsingEnabled(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)
+{
+ DumpRenderTreeSupportQt::setMockDeviceOrientation(canProvideAlpha, alpha, canProvideBeta, beta, canProvideGamma, gamma);
+}
+
+void LayoutTestController::setGeolocationPermission(bool allow)
+{
+ setGeolocationPermissionCommon(allow);
+ emit geolocationPermissionSet();
+}
+
+void LayoutTestController::setGeolocationPermissionCommon(bool allow)
+{
+ m_isGeolocationPermissionSet = true;
+ m_geolocationPermission = allow;
+}
+
+void LayoutTestController::setMockGeolocationError(int code, const QString& message)
+{
+ DumpRenderTreeSupportQt::setMockGeolocationError(code, message);
+}
+
+void LayoutTestController::setMockGeolocationPosition(double latitude, double longitude, double accuracy)
+{
+ DumpRenderTreeSupportQt::setMockGeolocationPosition(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::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);
+}
+
+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 0000000..0048a7e
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/LayoutTestControllerQt.h
@@ -0,0 +1,289 @@
+/*
+ * 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 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 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 dumpUserGestureInFrameLoadCallbacks();
+ void dumpResourceLoadCallbacks();
+ void dumpResourceResponseMIMETypes();
+ void dumpHistoryCallbacks();
+ void dumpConfigurationForViewport(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());
+ 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 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 setJavaScriptProfilingEnabled(bool enable);
+ void setTimelineProfilingEnabled(bool enable);
+ 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 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 setApplicationCacheOriginQuota(unsigned long long quota);
+
+ void setDatabaseQuota(int size);
+ void clearAllDatabases();
+ void setIconDatabaseEnabled(bool enable);
+
+ void setCustomPolicyDelegate(bool enabled, bool permissive = true);
+ 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);
+ bool isGeolocationPermissionSet() const { return m_isGeolocationPermissionSet; }
+ bool geolocationPermission() const { return m_geolocationPermission; }
+
+ void addMockSpeechInputResult(const QString& result, double confidence, const QString& language);
+
+ // 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);
+
+ /*
+ 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);
+
+private slots:
+ void processWork();
+
+private:
+ void setGeolocationPermissionCommon(bool allow);
+
+private:
+ bool m_hasDumped;
+ bool m_textDump;
+ 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 0000000..441a37c
--- /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 "../../../WebKit/qt/WebCoreSupport/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 0000000..e78e110
--- /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 0000000..de3cf6a
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/TestNetscapePlugin/TestNetscapePlugin.pro
@@ -0,0 +1,46 @@
+TEMPLATE = lib
+TARGET = TestNetscapePlugIn
+
+VPATH = ../../unix/TestNetscapePlugin ../../TestNetscapePlugIn
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+include(../../../../WebKit.pri)
+
+DESTDIR = $$OUTPUT_DIR/lib/plugins
+
+mac {
+ CONFIG += plugin
+ 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
+ debug_and_release:TARGET = $$qtLibraryTarget($$TARGET)
+}
+
+INCLUDEPATH += ../../../../JavaScriptCore \
+ ../../unix/TestNetscapePlugin/ForwardingHeaders \
+ ../../unix/TestNetscapePlugin/ForwardingHeaders/WebKit \
+ ../../../../WebCore \
+ ../../../../WebCore/bridge \
+ ../../TestNetscapePlugIn
+
+SOURCES = PluginObject.cpp \
+ PluginTest.cpp \
+ TestObject.cpp \
+ Tests/DocumentOpenInDestroyStream.cpp \
+ Tests/EvaluateJSAfterRemovingPluginElement.cpp \
+ Tests/GetUserAgentWithNullNPPFromNPPNew.cpp \
+ Tests/NPRuntimeObjectFromDestroyedPlugin.cpp \
+ Tests/NPRuntimeRemoveProperty.cpp \
+ Tests/NullNPPGetValuePointer.cpp \
+ Tests/PassDifferentNPPStruct.cpp \
+ Tests/PluginScriptableNPObjectInvokeDefault.cpp
+
+mac {
+ SOURCES += ../../TestNetscapePlugIn/main.cpp
+ OBJECTIVE_SOURCES += PluginObjectMac.mm
+ LIBS += -framework Carbon -framework Cocoa -framework QuartzCore
+} else {
+ SOURCES += ../../unix/TestNetscapePlugin/TestNetscapePlugin.cpp
+}
diff --git a/Tools/DumpRenderTree/qt/TextInputControllerQt.cpp b/Tools/DumpRenderTree/qt/TextInputControllerQt.cpp
new file mode 100644
index 0000000..08d8850
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/TextInputControllerQt.cpp
@@ -0,0 +1,158 @@
+/*
+ * 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 "../../../WebKit/qt/WebCoreSupport/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);
+}
diff --git a/Tools/DumpRenderTree/qt/TextInputControllerQt.h b/Tools/DumpRenderTree/qt/TextInputControllerQt.h
new file mode 100644
index 0000000..0210984
--- /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 0000000..d1baf08
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/WorkQueueItemQt.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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"
+
+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 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 0000000..97c9b04
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/WorkQueueItemQt.h
@@ -0,0 +1,159 @@
+/*
+ * 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 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 0000000..3540c47
--- /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 0000000..ac81cb0
--- /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 0000000..8349d73
--- /dev/null
+++ b/Tools/DumpRenderTree/qt/main.cpp
@@ -0,0 +1,173 @@
+/*
+ * 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>
+#include <fontconfig/fontconfig.h>
+#endif
+
+#ifdef Q_OS_WIN
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#include <limits.h>
+#include <signal.h>
+
+#if defined(__GLIBC__)
+#include <execinfo.h>
+#endif
+
+void messageHandler(QtMsgType type, const char *message)
+{
+ if (type == QtCriticalMsg) {
+ fprintf(stderr, "%s\n", message);
+ return;
+ }
+ // do nothing
+}
+
+QString get_backtrace() {
+ QString s;
+
+#if defined(__GLIBC__)
+ 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
+
+#ifdef Q_WS_X11
+ FcInit();
+ WebCore::DumpRenderTree::initializeFonts();
+#endif
+
+ QApplication::setGraphicsSystem("raster");
+ QApplication::setStyle(new QWindowsStyle);
+
+ QFont f("Sans Serif");
+ f.setPointSize(9);
+ f.setWeight(QFont::Normal);
+ f.setStyle(QFont::StyleNormal);
+ QApplication::setFont(f);
+
+ QApplication app(argc, argv);
+#ifdef Q_WS_X11
+ QX11Info::setAppDpiY(0, 96);
+ QX11Info::setAppDpiX(0, 96);
+#endif
+
+#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() < 2) {
+ qDebug() << "Usage: DumpRenderTree [-v|--pixel-tests] filename [filename2..n]";
+ qDebug() << "Or folder containing test files: DumpRenderTree [-v|--pixel-tests] dirpath";
+ exit(0);
+ }
+
+ // Suppress debug output from Qt if not started with -v
+ if (!args.contains(QLatin1String("-v")))
+ qInstallMsgHandler(messageHandler);
+
+ WebCore::DumpRenderTree dumper;
+
+ if (args.contains(QLatin1String("--pixel-tests")))
+ dumper.setDumpPixels(true);
+
+ QWebDatabase::removeAllDatabases();
+
+ if (args.contains(QLatin1String("-"))) {
+ QObject::connect(&dumper, SIGNAL(ready()), &dumper, SLOT(readLine()), Qt::QueuedConnection);
+ QTimer::singleShot(0, &dumper, SLOT(readLine()));
+ } else
+ dumper.processArgsLine(args);
+
+ return app.exec();
+
+#ifdef Q_WS_X11
+ FcConfigSetCurrent(0);
+#endif
+}
diff --git a/Tools/DumpRenderTree/qt/testplugin.cpp b/Tools/DumpRenderTree/qt/testplugin.cpp
new file mode 100644
index 0000000..d5b8bc7
--- /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 0000000..3d8a28c
--- /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 0000000..08706f7
--- /dev/null
+++ b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h
@@ -0,0 +1 @@
+#include <bridge/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 0000000..54a603d
--- /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 0000000..00bbc18
--- /dev/null
+++ b/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h
@@ -0,0 +1 @@
+#include <bridge/npruntime.h>
diff --git a/Tools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp b/Tools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp
new file mode 100644
index 0000000..2f7288a
--- /dev/null
+++ b/Tools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp
@@ -0,0 +1,434 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Zan Dobersek <zandobersek@gmail.com>
+ * 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.
+ *
+ * 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 "PluginObject.h"
+#include "PluginTest.h"
+
+#include "npapi.h"
+#include "npruntime.h"
+#include "npfunctions.h"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <string>
+
+using namespace std;
+
+extern "C" {
+ NPError NP_Initialize (NPNetscapeFuncs *aMozillaVTable, NPPluginFuncs *aPluginVTable);
+ NPError NP_Shutdown(void);
+ NPError NP_GetValue(void *future, NPPVariable variable, void *value);
+ char* NP_GetMIMEDescription(void);
+}
+
+static void executeScript(const PluginObject* obj, const char* script);
+
+static NPError
+webkit_test_plugin_new_instance(NPMIMEType mimetype,
+ NPP instance,
+ uint16_t mode,
+ int16_t argc,
+ char *argn[],
+ char *argv[],
+ NPSavedData* savedData)
+{
+ if (browser->version >= 14) {
+ PluginObject* obj = (PluginObject*)browser->createobject(instance, getPluginClass());
+ instance->pdata = obj;
+
+ string testIdentifier;
+
+ for (int i = 0; i < argc; i++) {
+ if (strcasecmp(argn[i], "test") == 0)
+ testIdentifier = argv[i];
+ else 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], "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], "onSetWindow") == 0 && !obj->onSetWindow)
+ obj->onSetWindow = strdup(argv[i]);
+ }
+
+ browser->getvalue(instance, NPNVprivateModeBool, (void *)&obj->cachedPrivateBrowsingMode);
+
+ obj->pluginTest = PluginTest::create(instance, testIdentifier);
+
+ return obj->pluginTest->NPP_New(mimetype, mode, argc, argn, argv, savedData);
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+static NPError
+webkit_test_plugin_destroy_instance(NPP instance, NPSavedData** save)
+{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ if (obj) {
+ 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->logDestroy)
+ pluginLog(instance, "NPP_Destroy");
+
+ if (obj->onSetWindow)
+ free(obj->onSetWindow);
+
+ obj->pluginTest->NPP_Destroy(save);
+
+ browser->releaseobject(&obj->header);
+ }
+
+ return NPERR_NO_ERROR;
+}
+
+static NPError
+webkit_test_plugin_set_window(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;
+ }
+
+ }
+
+ return obj->pluginTest->NPP_SetWindow(instance, 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);
+}
+
+static NPError
+webkit_test_plugin_new_stream(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 NPERR_NO_ERROR;
+}
+
+static NPError
+webkit_test_plugin_destroy_stream(NPP instance, NPStream* stream, NPError 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);
+}
+
+static void
+webkit_test_plugin_stream_as_file(NPP /*instance*/, NPStream* /*stream*/, const char* /*fname*/)
+{
+}
+
+static int32_t
+webkit_test_plugin_write_ready(NPP /*instance*/, NPStream* /*stream*/)
+{
+ return 4096;
+}
+
+static int32_t
+webkit_test_plugin_write(NPP instance,
+ NPStream* /*stream*/,
+ int32_t /*offset*/,
+ int32_t len,
+ void* /*buffer*/)
+{
+ PluginObject* obj = (PluginObject*)instance->pdata;
+
+ if (obj->returnNegativeOneFromWrite)
+ return -1;
+
+ return len;
+}
+
+static void
+webkit_test_plugin_print(NPP /*instance*/, NPPrint* /*platformPrint*/)
+{
+}
+
+static char keyEventToChar(XKeyEvent* event)
+{
+ char c = ' ';
+ XLookupString(event, &c, sizeof(c), 0, 0);
+ return c;
+}
+
+static int16_t
+webkit_test_plugin_handle_event(NPP instance, void* event)
+{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+ if (!obj->eventLogging)
+ return 0;
+
+ XEvent* evt = static_cast<XEvent*>(event);
+
+ switch (evt->type) {
+ case ButtonRelease:
+ pluginLog(instance, "mouseUp at (%d, %d)", evt->xbutton.x, evt->xbutton.y);
+ break;
+ case ButtonPress:
+ pluginLog(instance, "mouseDown at (%d, %d)", evt->xbutton.x, evt->xbutton.y);
+ break;
+ case KeyRelease:
+ pluginLog(instance, "keyUp '%c'", keyEventToChar(&evt->xkey));
+ break;
+ case KeyPress:
+ pluginLog(instance, "keyDown '%c'", keyEventToChar(&evt->xkey));
+ break;
+ case MotionNotify:
+ case EnterNotify:
+ case LeaveNotify:
+ break;
+ case FocusIn:
+ pluginLog(instance, "getFocusEvent");
+ break;
+ case FocusOut:
+ pluginLog(instance, "loseFocusEvent");
+ break;
+ default:
+ pluginLog(instance, "event %d", evt->type);
+ }
+
+ return 0;
+}
+
+static void
+webkit_test_plugin_url_notify(NPP instance, const char* url, NPReason reason, void* notifyData)
+{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+
+ if (obj->onURLNotify)
+ executeScript(obj, obj->onURLNotify);
+
+ handleCallback(obj, url, reason, notifyData);
+}
+
+static NPError
+webkit_test_plugin_get_value(NPP instance, NPPVariable variable, void *value)
+{
+ PluginObject* obj = 0;
+ if (instance)
+ obj = static_cast<PluginObject*>(instance->pdata);
+
+ // First, check if the PluginTest object supports getting this value.
+ if (obj && obj->pluginTest->NPP_GetValue(variable, value) == NPERR_NO_ERROR)
+ return NPERR_NO_ERROR;
+
+ NPError err = NPERR_NO_ERROR;
+
+ switch (variable) {
+ case NPPVpluginNameString:
+ *((char **)value) = const_cast<char*>("WebKit Test PlugIn");
+ break;
+ case NPPVpluginDescriptionString:
+ *((char **)value) = const_cast<char*>("Simple Netscape plug-in that handles test content for WebKit");
+ break;
+ case NPPVpluginNeedsXEmbed:
+ *((NPBool *)value) = TRUE;
+ break;
+ case NPPVpluginScriptableIID:
+ case NPPVpluginScriptableInstance:
+ case NPPVpluginScriptableNPObject:
+ err = NPERR_GENERIC_ERROR;
+ break;
+ default:
+ err = NPERR_GENERIC_ERROR;
+ break;
+ }
+
+ if (variable == NPPVpluginScriptableNPObject) {
+ void **v = (void **)value;
+ browser->retainobject((NPObject *)obj);
+ *v = obj;
+ err = NPERR_NO_ERROR;
+ }
+
+ return err;
+}
+
+static NPError
+webkit_test_plugin_set_value(NPP instance, NPNVariable variable, void* value)
+{
+ PluginObject* obj = static_cast<PluginObject*>(instance->pdata);
+
+ switch (variable) {
+ case NPNVprivateModeBool:
+ obj->cachedPrivateBrowsingMode = *(NPBool*)value;
+ return NPERR_NO_ERROR;
+ default:
+ return NPERR_GENERIC_ERROR;
+ }
+}
+
+char *
+NP_GetMIMEDescription(void)
+{
+ // We sentence-case the mime-type here to ensure that ports are not
+ // case-sensitive when loading plugins. See https://webkit.org/b/36815
+ return const_cast<char*>("application/x-Webkit-Test-Netscape:testnetscape:test netscape content");
+}
+
+NPError
+NP_Initialize (NPNetscapeFuncs *aMozillaVTable, NPPluginFuncs *aPluginVTable)
+{
+ if (aMozillaVTable == NULL || aPluginVTable == NULL)
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+
+ if ((aMozillaVTable->version >> 8) > NP_VERSION_MAJOR)
+ return NPERR_INCOMPATIBLE_VERSION_ERROR;
+
+ if (aPluginVTable->size < sizeof (NPPluginFuncs))
+ return NPERR_INVALID_FUNCTABLE_ERROR;
+
+ browser = aMozillaVTable;
+ pluginFunctions = aPluginVTable;
+
+ aPluginVTable->size = sizeof (NPPluginFuncs);
+ aPluginVTable->version = (NP_VERSION_MAJOR << 8) + NP_VERSION_MINOR;
+ aPluginVTable->newp = webkit_test_plugin_new_instance;
+ aPluginVTable->destroy = webkit_test_plugin_destroy_instance;
+ aPluginVTable->setwindow = webkit_test_plugin_set_window;
+ aPluginVTable->newstream = webkit_test_plugin_new_stream;
+ aPluginVTable->destroystream = webkit_test_plugin_destroy_stream;
+ aPluginVTable->asfile = webkit_test_plugin_stream_as_file;
+ aPluginVTable->writeready = webkit_test_plugin_write_ready;
+ aPluginVTable->write = webkit_test_plugin_write;
+ aPluginVTable->print = webkit_test_plugin_print;
+ aPluginVTable->event = webkit_test_plugin_handle_event;
+ aPluginVTable->urlnotify = webkit_test_plugin_url_notify;
+ aPluginVTable->javaClass = NULL;
+ aPluginVTable->getvalue = webkit_test_plugin_get_value;
+ aPluginVTable->setvalue = webkit_test_plugin_set_value;
+
+ return NPERR_NO_ERROR;
+}
+
+NPError
+NP_Shutdown(void)
+{
+ return NPERR_NO_ERROR;
+}
+
+NPError
+NP_GetValue(void* /*future*/, NPPVariable variable, void *value)
+{
+ return webkit_test_plugin_get_value(NULL, variable, value);
+}
diff --git a/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp b/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp
new file mode 100644
index 0000000..f03c102
--- /dev/null
+++ b/Tools/DumpRenderTree/win/AccessibilityControllerWin.cpp
@@ -0,0 +1,295 @@
+/*
+ * 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)
+{
+}
+
+AccessibilityController::~AccessibilityController()
+{
+ setLogFocusEvents(false);
+ setLogValueChangeEvents(false);
+
+ if (m_allEventsHook)
+ UnhookWinEvent(m_allEventsHook);
+
+ 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_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);
+}
+
+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()->notificationReceived(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;
+}
+
+void AccessibilityController::notificationReceived(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::addNotificationListener(PlatformUIElement element, JSObjectRef functionCallback)
+{
+ if (!m_allEventsHook)
+ m_allEventsHook = 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 0000000..47ce7dc
--- /dev/null
+++ b/Tools/DumpRenderTree/win/AccessibilityUIElementWin.cpp
@@ -0,0 +1,681 @@
+/*
+ * 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::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);
+}
+
+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()->addNotificationListener(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::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 0000000..1bc4678
--- /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 0000000..5679845
--- /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 0000000..98982bc
--- /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 0000000..a8028c5
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTree.cpp
@@ -0,0 +1,1392 @@
+/*
+ * 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 <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
+}
+
+wstring urlSuitableForTestResult(const wstring& url)
+{
+ if (url.find(L"file://") == wstring::npos)
+ return url;
+
+ return lastPathComponent(url);
+}
+
+wstring lastPathComponent(const wstring& url)
+{
+ if (url.empty())
+ return url;
+
+ return PathFindFileNameW(url.c_str());
+}
+
+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());
+}
+
+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 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"));
+#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"));
+#endif
+
+ preferences->setStandardFontFamily(standardFamily);
+ preferences->setFixedFontFamily(fixedFamily);
+ preferences->setSerifFontFamily(standardFamily);
+ preferences->setSansSerifFontFamily(sansSerifFamily);
+ preferences->setCursiveFontFamily(cursiveFamily);
+ preferences->setFantasyFontFamily(fantasyFamily);
+
+ 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);
+ }
+ 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;
+
+ 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();
+}
+
+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();
+ }
+
+ 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;
+}
+
+int main(int argc, char* argv[])
+{
+ ::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 0000000..ca26cb8
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTree.vcproj
@@ -0,0 +1,720 @@
+<?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="1"
+ 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"
+ 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="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeApple.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="$(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\cURL.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeCairo.vsprops;.\DumpRenderTreeCFLite.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="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefinesCairo.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.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"
+ 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="$(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"
+ 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_LTCG|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\FeatureDefines.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\DumpRenderTreeCommon.vsprops;.\DumpRenderTreeApple.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=".\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="Release_LTCG|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="Release_LTCG|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 0000000..f126689
--- /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 0000000..209b3ea
--- /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 0000000..a3af01a
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeCairo.vsprops
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="DumpRenderTreeCairo"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)\..\cairo&quot;;"
+ PreprocessorDefinitions="WIN_CAIRO=1"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreeCommon.vsprops b/Tools/DumpRenderTree/win/DumpRenderTreeCommon.vsprops
new file mode 100644
index 0000000..71d261b
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeCommon.vsprops
@@ -0,0 +1,20 @@
+<?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;$(WebKitOutputDir)\Include&quot;;&quot;$(WebKitOutputDir)\Include\private&quot;;&quot;$(WebKitOutputDir)\Include\DumpRenderTree\ForwardingHeaders&quot;;&quot;$(WebKitOutputDir)\Include\JavaScriptCore&quot;;&quot;$(WebKitOutputDir)\Include\private\JavaScriptCore&quot;;&quot;$(WebKitLibrariesDir)\Include&quot;;&quot;$(WebKitLibrariesDir)\Include\private&quot;;&quot;$(WebKitLibrariesDir)\include\pthreads&quot;;&quot;$(WebKitOutputDir)\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 pthreadVC2$(LibraryConfigSuffix).lib gdi32.lib ole32.lib oleaut32.lib user32.lib shlwapi.lib oleacc.lib comsuppw.lib"
+ SubSystem="1"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreePostBuild.cmd b/Tools/DumpRenderTree/win/DumpRenderTreePostBuild.cmd
new file mode 100644
index 0000000..fc8c778
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreePostBuild.cmd
@@ -0,0 +1,40 @@
+if exist "%WEBKITOUTPUTDIR%\buildfailed" del "%WEBKITOUTPUTDIR%\buildfailed"
+
+if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)
+
+mkdir 2>NUL "%WEBKITOUTPUTDIR%\bin"
+
+if not exist "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.dll" exit /b
+
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreVideo%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreVideo%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFNetwork%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFNetwork%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CFNetwork.resources" "%WEBKITOUTPUTDIR%\bin\CFNetwork.resources"
+xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CoreFoundation.resources" "%WEBKITOUTPUTDIR%\bin\CoreFoundation.resources"
+xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CharacterSets" "%WEBKITOUTPUTDIR%\bin\CharacterSets"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreGraphics%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreGraphics%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\dnssd.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icudt40.dll" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt40.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icudt40%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt40%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icudt42.dll" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt42.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icudt42%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt42%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxml2%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxslt%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
diff --git a/Tools/DumpRenderTree/win/DumpRenderTreePreBuild.cmd b/Tools/DumpRenderTree/win/DumpRenderTreePreBuild.cmd
new file mode 100644
index 0000000..1d3fa8b
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreePreBuild.cmd
@@ -0,0 +1,18 @@
+%SystemDrive%\cygwin\bin\which.exe bash
+if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
+cmd /c
+if exist "%WEBKITOUTPUTDIR%\buildfailed" grep XX%PROJECTNAME%XX "%WEBKITOUTPUTDIR%\buildfailed"
+if errorlevel 1 exit 1
+echo XX%PROJECTNAME%XX > "%WEBKITOUTPUTDIR%\buildfailed"
+
+mkdir 2>NUL "%WEBKITOUTPUTDIR%\include\DumpRenderTree"
+mkdir 2>NUL "%WEBKITOUTPUTDIR%\include\DumpRenderTree\ForwardingHeaders"
+mkdir 2>NUL "%WEBKITOUTPUTDIR%\include\DumpRenderTree\ForwardingHeaders\wtf"
+
+xcopy /y /d "%PROJECTDIR%\..\ForwardingHeaders\wtf\*.h" "%WEBKITOUTPUTDIR%\include\DumpRenderTree\ForwardingHeaders\wtf"
+
+if "%CONFIGURATIONNAME%"=="Debug_Cairo_CFLite" xcopy /y /d "%WEBKITOUTPUTDIR%\include\WebCore\ForwardingHeaders\wtf\MD5.h" "%WEBKITOUTPUTDIR%\include\DumpRenderTree\ForwardingHeaders\wtf"
+if "%CONFIGURATIONNAME%"=="Release_Cairo_CFLite" xcopy /y /d "%WEBKITOUTPUTDIR%\include\WebCore\ForwardingHeaders\wtf\MD5.h" "%WEBKITOUTPUTDIR%\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/DumpRenderTreeWin.h b/Tools/DumpRenderTree/win/DumpRenderTreeWin.h
new file mode 100644
index 0000000..27edaa6
--- /dev/null
+++ b/Tools/DumpRenderTree/win/DumpRenderTreeWin.h
@@ -0,0 +1,69 @@
+/*
+ * 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&);
+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 0000000..71859cb
--- /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 && !isalpha(*cursor))
+ ++cursor;
+ return *cursor ? (cursor - text) : -1;
+};
+
+static int wordLength(const TCHAR* text)
+{
+ const TCHAR* cursor = text;
+ while (*cursor && isalpha(*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 0000000..7b7f418
--- /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 0000000..94f0945
--- /dev/null
+++ b/Tools/DumpRenderTree/win/EventSender.cpp
@@ -0,0 +1,691 @@
+/*
+ * 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 {
+ 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 0000000..a0add85
--- /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 0000000..a84e0f3
--- /dev/null
+++ b/Tools/DumpRenderTree/win/FrameLoadDelegate.cpp
@@ -0,0 +1,420 @@
+/*
+ * 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 "WorkQueueItem.h"
+#include "WorkQueue.h"
+#include <WebCore/COMPtr.h>
+#include <JavaScriptCore/Assertions.h>
+#include <JavaScriptCore/JavaScriptCore.h>
+#include <WebKit/WebKit.h>
+#include <wtf/Vector.h>
+#include <stdio.h>
+#include <string>
+
+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(new GCController)
+ , m_accessibilityController(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();
+}
+
+static void CALLBACK processWorkTimer(HWND, UINT, UINT_PTR id, DWORD)
+{
+ ::KillTimer(0, id);
+ FrameLoadDelegate* d = g_delegateWaitingOnTimer;
+ g_delegateWaitingOnTimer = 0;
+ d->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()) {
+ ASSERT(!g_delegateWaitingOnTimer);
+ g_delegateWaitingOnTimer = this;
+ ::SetTimer(0, 0, 0, processWorkTimer);
+ 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);
+}
+
+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 0000000..4cd5e11
--- /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 0000000..b867250
--- /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 0000000..8a41fac
--- /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 0000000..41be670
--- /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 0000000..f48af25
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiff.vcproj
@@ -0,0 +1,395 @@
+<?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="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\ImageDiffCommon.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="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\ImageDiffCommon.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="1"
+ 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"
+ 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"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;.\ImageDiffCommon.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_LTCG|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\ImageDiffCommon.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="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;.\ImageDiffCommon.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="..\cg\ImageDiffCG.cpp"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops b/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops
new file mode 100644
index 0000000..e93d262
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffCommon.vsprops
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="ImageDiffCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(WebKitOutputDir)\include&quot;;&quot;$(WebKitOutputDir)\include\private&quot;;&quot;$(WebKitOutputDir)\include\WebCore\ForwardingHeaders&quot;;&quot;$(WebKitLibrariesDir)\include&quot;;&quot;$(WebKitLibrariesDir)\include\private&quot;"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/NXCOMPAT"
+ AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib CoreGraphics$(LibraryConfigSuffix).lib CoreFoundation$(LibraryConfigSuffix).lib"
+ SubSystem="1"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/DumpRenderTree/win/ImageDiffPostBuild.cmd b/Tools/DumpRenderTree/win/ImageDiffPostBuild.cmd
new file mode 100644
index 0000000..f011495
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ImageDiffPostBuild.cmd
@@ -0,0 +1 @@
+if exist "%WEBKITOUTPUTDIR%\buildfailed" del "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/DumpRenderTree/win/ImageDiffPreBuild.cmd b/Tools/DumpRenderTree/win/ImageDiffPreBuild.cmd
new file mode 100644
index 0000000..3a84c26
--- /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 "%WEBKITOUTPUTDIR%\buildfailed" grep XX%PROJECTNAME%XX "%WEBKITOUTPUTDIR%\buildfailed"
+if errorlevel 1 exit 1
+echo XX%PROJECTNAME%XX > "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp b/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp
new file mode 100644
index 0000000..1dabf03
--- /dev/null
+++ b/Tools/DumpRenderTree/win/LayoutTestControllerWin.cpp
@@ -0,0 +1,1432 @@
+/*
+ * 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;
+}
+
+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::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);
+}
+
+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::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::setTimelineProfilingEnabled(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;
+
+ inspector->setTimelineProfilingEnabled(flag);
+}
+
+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;
+}
+
+static 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());
+}
+
+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::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::setApplicationCacheOriginQuota(unsigned long long quota)
+{
+ // FIXME: implement to support Application Cache quotas.
+}
+
+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::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;
+}
+
+void LayoutTestController::dumpConfigurationForViewport(int /*availableWidth*/, int /*availableHeight*/)
+{
+ // FIXME: Implement this.
+}
+
+void LayoutTestController::setSerializeHTTPLoads(bool)
+{
+ // FIXME: Implement.
+}
diff --git a/Tools/DumpRenderTree/win/MD5.cpp b/Tools/DumpRenderTree/win/MD5.cpp
new file mode 100644
index 0000000..1bfc9c7
--- /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 0000000..326e21d
--- /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 0000000..752cc39
--- /dev/null
+++ b/Tools/DumpRenderTree/win/PixelDumpSupportWin.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 PLATFORM(CG)
+#include "PixelDumpSupportCG.h"
+#elif PLATFORM(CAIRO)
+#include "PixelDumpSupportCairo.h"
+#endif
+
+#include "DumpRenderTree.h"
+
+#if PLATFORM(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>
+
+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);
+
+#if PLATFORM(CG)
+ RetainPtr<CGColorSpaceRef> colorSpace(AdoptCF, CGColorSpaceCreateDeviceRGB());
+ CGContextRef context = CGBitmapContextCreate(info.bmBits, info.bmWidth, info.bmHeight, 8,
+ info.bmWidthBytes, colorSpace.get(), kCGBitmapByteOrder32Host | kCGImageAlphaPremultipliedFirst);
+#elif PLATFORM(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 0000000..7d87c45
--- /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 0000000..c808dc9
--- /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 0000000..09b07d6
--- /dev/null
+++ b/Tools/DumpRenderTree/win/ResourceLoadDelegate.cpp
@@ -0,0 +1,379 @@
+/*
+ * 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();
+
+ wstring failingURL;
+
+ // If the error doesn't have a failing URL, we fake one by using the URL the resource had
+ // at creation time. This seems to work fine for now.
+ // See <rdar://problem/5064234> CFErrors should have failingURL key.
+ if (failingURLSTR)
+ failingURL = wstringFromBSTR(failingURLSTR);
+ else
+ failingURL = descriptionSuitableForTestResult(identifier);
+
+ ::SysFreeString(failingURLSTR);
+
+ result += L", failing URL \"" + urlSuitableForTestResult(failingURL) + 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 0000000..3f20f47
--- /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 100755
index 0000000..1e7669f
--- /dev/null
+++ b/Tools/DumpRenderTree/win/UIDelegate.cpp
@@ -0,0 +1,662 @@
+/*
+ * 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/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(new DRTUndoStack)
+ , m_undoStack(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(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.set(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;
+ *result = TRUE;
+ return E_NOTIMPL;
+}
+
+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) + urlSuitableForTestResult(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 100755
index 0000000..0c9fdaf
--- /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 0000000..a24ca37
--- /dev/null
+++ b/Tools/DumpRenderTree/win/WorkQueueItemWin.cpp
@@ -0,0 +1,158 @@
+/*
+ * 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());
+
+ 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 0000000..4aaedb4
--- /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, 'JavaScriptCore'),
+ os.path.join(wk_root, 'WebCore'),
+ os.path.join(wk_root, 'WebCore', 'bindings', 'wx'),
+ os.path.join(wk_root, '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 0000000..7142af2
--- /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"));
+ 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 0000000..99092b8
--- /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 0000000..bddf62f
--- /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 0000000..32b5f7e
--- /dev/null
+++ b/Tools/DumpRenderTree/wx/LayoutTestControllerWx.cpp
@@ -0,0 +1,546 @@
+/*
+ * 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::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::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::setApplicationCacheOriginQuota(unsigned long long quota)
+{
+ // FIXME: implement to support Application Cache quotas.
+}
+
+void LayoutTestController::clearAllDatabases()
+{
+ // FIXME: implement
+}
+
+void LayoutTestController::setDatabaseQuota(unsigned long long quota)
+{
+ // FIXME: implement
+}
+
+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);
+}
+
+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::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::setTimelineProfilingEnabled(bool enabled)
+{
+
+}
+
+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;
+}
+
+void LayoutTestController::dumpConfigurationForViewport(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;
+}
diff --git a/Tools/DumpRenderTree/wx/WorkQueueItemWx.cpp b/Tools/DumpRenderTree/wx/WorkQueueItemWx.cpp
new file mode 100644
index 0000000..e6ecb75
--- /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;
+}
diff --git a/Tools/EWSTools/boot.sh b/Tools/EWSTools/boot.sh
new file mode 100644
index 0000000..733441e
--- /dev/null
+++ b/Tools/EWSTools/boot.sh
@@ -0,0 +1,30 @@
+#!/bin/sh
+# 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.
+
+screen -c ~/tools/screen-config
diff --git a/Tools/EWSTools/create-webkit-git b/Tools/EWSTools/create-webkit-git
new file mode 100755
index 0000000..cbf8ce4
--- /dev/null
+++ b/Tools/EWSTools/create-webkit-git
@@ -0,0 +1,42 @@
+#/bin/bash
+# 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.
+
+# These are meant to match the instructions from:
+# http://trac.webkit.org/wiki/UsingGitWithWebKit
+cd /mnt/git
+git clone git://git.webkit.org/WebKit.git webkit
+cd webkit
+
+git svn init -T trunk http://svn.webkit.org/repository/webkit
+git update-ref refs/remotes/trunk origin/master
+# It's possible that this "config" step can get merged into an earlier setup step.
+git config --replace-all svn-remote.svn.fetch trunk:refs/remotes/origin/master
+
+git fetch
+git svn rebase
diff --git a/Tools/EWSTools/screen-config b/Tools/EWSTools/screen-config
new file mode 100644
index 0000000..5c003df
--- /dev/null
+++ b/Tools/EWSTools/screen-config
@@ -0,0 +1,4 @@
+screen -t style ./start-queue.sh style-queue
+screen -t qt ./start-queue.sh qt-ews
+screen -t kr ./start-queue.sh chromium-ews
+screen -t gtk ./start-queue.sh gtk-ews
diff --git a/Tools/EWSTools/start-queue.sh b/Tools/EWSTools/start-queue.sh
new file mode 100755
index 0000000..b511c11
--- /dev/null
+++ b/Tools/EWSTools/start-queue.sh
@@ -0,0 +1,55 @@
+#!/bin/sh
+# 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.
+
+if [[ $# -ne 2 ]];then
+echo "Usage: start-queue.sh QUEUE_NAME BOT_ID"
+echo
+echo "QUEUE_NAME will be passed as a command to webkit-patch"
+echo "QUEUE_NAME will also be used as the path to the queue: /mnt/git/webkit-QUEUE_NAME"
+echo "BOT_ID may not have spaces. It will appear as the bots name on queues.webkit.org"
+echo
+echo "For example, to run the mac-ews on a machine we're calling 'eseidel-cq-sf' run:"
+echo "start-queue.sh mac-ews eseidel-cq-sf"
+exit 1
+fi
+
+cd /mnt/git/webkit-$1
+while :
+do
+ git reset --hard trunk
+ git clean -f
+ git rebase --abort
+ git fetch
+ git svn rebase
+ # test-webkitpy has code to remove orphaned .pyc files, so we
+ # run it before running webkit-patch to avoid stale .pyc files
+ # preventing webkit-patch from launching.
+ ./Tools/Scripts/test-webkitpy
+ ./Tools/Scripts/webkit-patch $1 --bot-id=$2 --no-confirm --exit-after-iteration 10
+done
diff --git a/Tools/EWSTools/ubuntu-ews-packages b/Tools/EWSTools/ubuntu-ews-packages
new file mode 100644
index 0000000..a7917a0
--- /dev/null
+++ b/Tools/EWSTools/ubuntu-ews-packages
@@ -0,0 +1,61 @@
+subversion
+git-core
+git-svn
+binutils-gold
+python-mechanize
+libqt4-dev
+gperf
+bison
+fakeroot
+flex
+g++
+g++-multilib
+gperf
+autoconf
+automake
+libapache2-mod-php5
+libasound2-dev
+libbz2-dev
+libicu-dev
+libphonon-dev
+libsqlite3-dev
+libcairo2-dev
+libdbus-glib-1-dev
+libgconf2-dev
+libgl1-mesa-dev
+libglu1-mesa-dev
+libglib2.0-dev
+libjpeg62-dev
+libnspr4-dev
+libnss3-dev
+libpam0g-dev
+libtool
+libgtk2.0-dev
+libpango1.0-dev
+libicu-dev
+libxslt-dev
+libxslt1-dev
+libxss-dev
+libsoup2.4-dev
+libsqlite3-dev
+mesa-common-dev
+patch
+perl
+pkg-config
+python
+libcupsys2-dev
+libgnome-keyring-dev
+libcurl4-gnutls-dev
+libcupsys2-dev
+gperf
+bison
+flex
+libjpeg62-dev
+libpng12-dev
+libxt-dev
+autotools-dev
+libgstreamer-plugins-base0.10-dev
+libenchant-dev
+libgail-dev
+gtk-doc-tools
+libgeoclue-dev
diff --git a/Tools/EWebLauncher/main.c b/Tools/EWebLauncher/main.c
new file mode 100644
index 0000000..5f417d0
--- /dev/null
+++ b/Tools/EWebLauncher/main.c
@@ -0,0 +1,903 @@
+/*
+ * Copyright (C) 2008 INdT - Instituto Nokia de Tecnologia
+ * Copyright (C) 2009, 2010 ProFUSION embedded systems
+ * Copyright (C) 2009, 2010 Samsung Electronics
+ *
+ * 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 "EWebKit.h"
+
+#include <ctype.h>
+#include <Ecore.h>
+#include <Ecore_Evas.h>
+#include <Ecore_File.h>
+#include <Ecore_Getopt.h>
+#include <Ecore_X.h>
+#include <Edje.h>
+#include <Evas.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#define DEFAULT_WIDTH 800
+#define DEFAULT_HEIGHT 600
+#define DEFAULT_ZOOM_INIT 1.0
+
+#define info(format, args...) \
+ do { \
+ if (verbose) \
+ printf(format, ##args); \
+ } while (0)
+
+#define MIN_ZOOM_LEVEL 0
+#define DEFAULT_ZOOM_LEVEL 5
+#define MAX_ZOOM_LEVEL 13
+
+static int currentZoomLevel = DEFAULT_ZOOM_LEVEL;
+static float currentZoom = 1.0;
+
+// the zoom values are chosen to be like in Mozilla Firefox 3
+static int zoomLevels[] = {30, 50, 67, 80, 90,
+ 100,
+ 110, 120, 133, 150, 170, 200, 240, 300};
+
+static int verbose = 0;
+
+static Eina_List *windows = NULL;
+
+static char *themePath = NULL;
+
+static const char *backingStores[] = {
+ "tiled",
+ "single",
+ NULL
+};
+
+typedef struct _Window_Properties {
+ Eina_Bool toolbarsVisible:1;
+ Eina_Bool statusbarVisible:1;
+ Eina_Bool scrollbarsVisible:1;
+ Eina_Bool menubarVisible:1;
+} Window_Properties;
+
+Window_Properties windowProperties = { /* Pretend we have them and they are initially visible */
+ EINA_TRUE,
+ EINA_TRUE,
+ EINA_TRUE,
+ EINA_TRUE
+};
+
+static const Ecore_Getopt options = {
+ "EWebLauncher",
+ "%prog [options] [url]",
+ "0.0.1",
+ "(C)2008 INdT (The Nokia Technology Institute)\n"
+ "(C)2009, 2010 ProFUSION embedded systems\n"
+ "(C)2009, 2010 Samsung Electronics",
+ "GPL",
+ "Test Web Browser using the Enlightenment Foundation Libraries of WebKit",
+ EINA_TRUE, {
+ ECORE_GETOPT_STORE_STR
+ ('e', "engine", "ecore-evas engine to use."),
+ ECORE_GETOPT_CALLBACK_NOARGS
+ ('E', "list-engines", "list ecore-evas engines.",
+ ecore_getopt_callback_ecore_evas_list_engines, NULL),
+ ECORE_GETOPT_CHOICE
+ ('b', "backing-store", "choose backing store to use.", backingStores),
+ ECORE_GETOPT_STORE_DEF_BOOL
+ ('F', "fullscreen", "fullscreen mode.", 0),
+ ECORE_GETOPT_CALLBACK_ARGS
+ ('g', "geometry", "geometry to use in x:y:w:h form.", "X:Y:W:H",
+ ecore_getopt_callback_geometry_parse, NULL),
+ ECORE_GETOPT_STORE_STR
+ ('t', "theme", "path to read the theme file from."),
+ ECORE_GETOPT_STORE_STR
+ ('U', "user-agent", "custom user agent string to use."),
+ ECORE_GETOPT_STORE_DEF_BOOL
+ ('S', "sudo-workaround", "Workaround mode for making Flash work with sudo.", 0),
+ ECORE_GETOPT_COUNT
+ ('v', "verbose", "be more verbose."),
+ ECORE_GETOPT_VERSION
+ ('V', "version"),
+ ECORE_GETOPT_COPYRIGHT
+ ('R', "copyright"),
+ ECORE_GETOPT_LICENSE
+ ('L', "license"),
+ ECORE_GETOPT_HELP
+ ('h', "help"),
+ ECORE_GETOPT_SENTINEL
+ }
+};
+
+typedef struct _Viewport {
+ int w;
+ int h;
+ float initScale;
+ float minScale;
+ float maxScale;
+ float devicePixelRatio;
+ Eina_Bool userScalable;
+} Viewport;
+
+typedef struct _ELauncher {
+ Ecore_Evas *ee;
+ Evas *evas;
+ Evas_Object *bg;
+ Evas_Object *browser;
+ const char *theme;
+ const char *userAgent;
+ const char *backingStore;
+ Viewport viewport;
+} ELauncher;
+
+static void browserDestroy(Ecore_Evas *ee);
+static void closeWindow(Ecore_Evas *ee);
+static int browserCreate(const char *url, const char *theme, const char *userAgent, Eina_Rectangle geometry, const char *engine, const char *backingStore, unsigned char isFullscreen, const char *databasePath);
+
+static void
+print_history(Eina_List *list)
+{
+ Eina_List *l;
+ void *d;
+
+ if (!verbose)
+ return;
+
+ printf("Session history contains:\n");
+
+ EINA_LIST_FOREACH(list, l, d) {
+ Ewk_History_Item *item = (Ewk_History_Item*)d;
+ cairo_surface_t *cs = ewk_history_item_icon_surface_get(item);
+ char buf[PATH_MAX];
+ int s = snprintf(buf, sizeof(buf), "/tmp/favicon-%s.png", ewk_history_item_uri_original_get(item));
+ for (s--; s >= (int)sizeof("/tmp/favicon-"); s--) {
+ if (!isalnum(buf[s]) && buf[s] != '.')
+ buf[s] = '_';
+ }
+ cs = ewk_history_item_icon_surface_get(item);
+
+ if (cs && cairo_surface_status(cs) == CAIRO_STATUS_SUCCESS)
+ cairo_surface_write_to_png(cs, buf);
+ else
+ buf[0] = '\0';
+
+ printf("* '%s' title='%s' icon='%s'\n",
+ ewk_history_item_uri_original_get(item),
+ ewk_history_item_title_get(item), buf);
+ }
+}
+
+static int
+nearest_zoom_level_get(float factor)
+{
+ int i, intFactor = (int)(factor * 100.0);
+ for (i = 0; zoomLevels[i] <= intFactor; i++) { }
+ printf("factor=%f, intFactor=%d, zoomLevels[%d]=%d, zoomLevels[%d]=%d\n",
+ factor, intFactor, i-1, zoomLevels[i-1], i, zoomLevels[i]);
+ if (intFactor - zoomLevels[i-1] < zoomLevels[i] - intFactor)
+ return i - 1;
+ return i;
+}
+
+static Eina_Bool
+zoom_level_set(Evas_Object *webview, int level)
+{
+ float factor = ((float) zoomLevels[level]) / 100.0;
+ Evas_Coord ox, oy, mx, my, cx, cy;
+ evas_pointer_canvas_xy_get(evas_object_evas_get(webview), &mx, &my);
+ evas_object_geometry_get(webview, &ox, &oy, NULL, NULL);
+ cx = mx - ox;
+ cy = my - oy;
+ return ewk_view_zoom_animated_set(webview, factor, 0.5, cx, cy);
+}
+
+static void
+on_ecore_evas_resize(Ecore_Evas *ee)
+{
+ Evas_Object *webview;
+ Evas_Object *bg;
+ int w, h;
+
+ ecore_evas_geometry_get(ee, NULL, NULL, &w, &h);
+
+ bg = evas_object_name_find(ecore_evas_get(ee), "bg");
+ evas_object_move(bg, 0, 0);
+ evas_object_resize(bg, w, h);
+
+ webview = evas_object_name_find(ecore_evas_get(ee), "browser");
+ evas_object_move(webview, 10, 10);
+ evas_object_resize(webview, w - 20, h - 20);
+}
+
+static void
+title_set(Ecore_Evas *ee, const char *title, int progress)
+{
+ const char *appname = "EFL Test Launcher";
+ const char *separator = " - ";
+ char label[4096];
+ int size;
+
+ if (!title || !strcmp(title, "")) {
+ ecore_evas_title_set(ee, appname);
+ return;
+ }
+
+ if (progress < 100)
+ size = snprintf(label, sizeof(label), "%s (%d%%)%s%s", title, progress, separator, appname);
+ else
+ size = snprintf(label, sizeof(label), "%s %s%s", title, separator, appname);
+
+ if (size >= (int)sizeof(label))
+ return;
+
+ ecore_evas_title_set(ee, label);
+}
+
+/**
+ * This is en example function to adjust viewport via viewport tag's arguments.
+ * Application can invoke this function in order to adjust viewport tag when it is required.
+ */
+static void
+viewport_set()
+{
+ ELauncher *app;
+ app = (ELauncher*) eina_list_data_get(windows);
+
+ ewk_view_fixed_layout_size_set(app->browser, app->viewport.w, app->viewport.h);
+ ewk_view_zoom_set(app->browser, app->viewport.initScale, 0, 0);
+ if (!ewk_view_zoom_range_set(app->browser, app->viewport.minScale, app->viewport.maxScale))
+ info(" Fail to set zoom range. minScale = %f, maxScale = %f\n", app->viewport.minScale, app->viewport.maxScale);
+ ewk_view_user_scalable_set(app->browser, app->viewport.userScalable);
+}
+
+static void
+on_title_changed(void *user_data, Evas_Object *webview, void *event_info)
+{
+ ELauncher *app = (ELauncher *)user_data;
+ const char *title = (const char *)event_info;
+
+ title_set(app->ee, title, 100);
+}
+
+static void
+on_progress(void *user_data, Evas_Object *webview, void *event_info)
+{
+ ELauncher *app = (ELauncher *)user_data;
+ double *progress = (double *)event_info;
+
+ title_set(app->ee, ewk_view_title_get(app->browser), *progress * 100);
+}
+
+static void
+on_load_finished(void *user_data, Evas_Object *webview, void *event_info)
+{
+ const Ewk_Frame_Load_Error *err = (const Ewk_Frame_Load_Error *)event_info;
+
+ if (!err)
+ info("Succeeded loading page.\n");
+ else if (err->is_cancellation)
+ info("Load was cancelled.\n");
+ else
+ info("Failed loading page: %d %s \"%s\", url=%s\n",
+ err->code, err->domain, err->description, err->failing_url);
+
+ currentZoom = ewk_view_zoom_get(webview);
+ currentZoomLevel = nearest_zoom_level_get(currentZoom);
+ info("WebCore Zoom=%f, currentZoomLevel=%d\n", currentZoom, currentZoomLevel);
+}
+
+static void
+on_toolbars_visible_set(void* user_data, Evas_Object* webview, void* event_info)
+{
+ Eina_Bool *visible = (Eina_Bool *)event_info;
+ if (*visible) {
+ info("Toolbars visible changed: show");
+ windowProperties.toolbarsVisible = EINA_TRUE;
+ } else {
+ info("Toolbars visible changed: hide");
+ windowProperties.toolbarsVisible = EINA_FALSE;
+ }
+}
+
+static void
+on_toolbars_visible_get(void* user_data, Evas_Object* webview, void* event_info)
+{
+ Eina_Bool *visible = (Eina_Bool *)event_info;
+ *visible = windowProperties.toolbarsVisible;
+}
+
+static void
+on_statusbar_visible_set(void* user_data, Evas_Object* webview, void* event_info)
+{
+ Eina_Bool *visible = (Eina_Bool *)event_info;
+ if (*visible) {
+ info("Statusbar visible changed: show");
+ windowProperties.statusbarVisible = EINA_TRUE;
+ } else {
+ info("Statusbar visible changed: hide");
+ windowProperties.statusbarVisible = EINA_FALSE;
+ }
+}
+
+static void
+on_statusbar_visible_get(void* user_data, Evas_Object* webview, void* event_info)
+{
+ Eina_Bool *visible = (Eina_Bool *)event_info;
+ *visible = windowProperties.statusbarVisible;
+}
+
+static void
+on_scrollbars_visible_set(void* user_data, Evas_Object* webview, void* event_info)
+{
+ Eina_Bool *visible = (Eina_Bool *)event_info;
+ if (*visible) {
+ info("Scrollbars visible changed: show");
+ windowProperties.scrollbarsVisible = EINA_TRUE;
+ } else {
+ info("Scrollbars visible changed: hide");
+ windowProperties.scrollbarsVisible = EINA_FALSE;
+ }
+}
+
+static void
+on_scrollbars_visible_get(void* user_data, Evas_Object* webview, void* event_info)
+{
+ Eina_Bool *visible = (Eina_Bool *)event_info;
+ *visible = windowProperties.scrollbarsVisible;
+}
+
+static void
+on_menubar_visible_set(void* user_data, Evas_Object* webview, void* event_info)
+{
+ Eina_Bool *visible = (Eina_Bool *)event_info;
+ if (*visible) {
+ info("Menubar visible changed: show");
+ windowProperties.menubarVisible = EINA_TRUE;
+ } else {
+ info("Menubar visible changed: hide");
+ windowProperties.menubarVisible = EINA_FALSE;
+ }
+}
+
+static void
+on_menubar_visible_get(void* user_data, Evas_Object* webview, void* event_info)
+{
+ Eina_Bool *visible = (Eina_Bool *)event_info;
+ *visible = windowProperties.menubarVisible;
+}
+
+static void
+on_tooltip_text_set(void* user_data, Evas_Object* webview, void* event_info)
+{
+ const char *text = (const char *)event_info;
+ if (text && *text != '\0')
+ info("%s\n", text);
+}
+
+static void
+on_inputmethod_changed(void* user_data, Evas_Object* webview, void* event_info)
+{
+ Eina_Bool active = (Eina_Bool)(long)event_info;
+ unsigned int imh;
+ info("Keyboard changed: %d\n", active);
+
+ if (!active)
+ return;
+
+ imh = ewk_view_imh_get(webview);
+ info(" Keyboard flags: %#.2x\n", imh);
+
+}
+
+/**
+ * "viewport,changed" signal will be always emitted regardless of the viewport existence.
+ *
+ * If you don't want to process the viewport tag, you can either do nothing in this callback
+ * or simply ignore the signal in your application.
+ *
+ * More information about this can be found at http://developer.apple.com/safari/library/docum
+ * entation/appleapplications/reference/safariwebcontent/usingtheviewport/usingtheviewport.html
+ */
+static void
+on_viewport_changed(void* user_data, Evas_Object* webview, void* event_info)
+{
+ ELauncher *app = (ELauncher *)user_data;
+
+ float w, h, initScale, minScale, maxScale, devicePixelRatio;
+ Eina_Bool userScalable;
+
+ ewk_view_viewport_attributes_get(webview, &w, &h, &initScale, &maxScale, &minScale, &devicePixelRatio, &userScalable);
+
+ /**
+ * If there is no argument in viewport tag, argument's value is -1.
+ */
+ if ((int)w == -1)
+ w = DEFAULT_WIDTH;
+ if ((int)h == -1)
+ h = DEFAULT_HEIGHT;
+ if ((int)initScale == -1)
+ initScale = DEFAULT_ZOOM_INIT; // There's no scale separated from zooming in webkit-efl.
+ if ((int)minScale == -1)
+ minScale = ewk_view_zoom_range_min_get(webview);
+ if ((int)maxScale == -1)
+ maxScale = ewk_view_zoom_range_max_get(webview);
+ if ((int)devicePixelRatio == -1)
+ devicePixelRatio = ewk_view_device_pixel_ratio_get(webview);
+ if ((int)userScalable == -1)
+ userScalable = EINA_TRUE;
+
+ app->viewport.w = (int)w;
+ app->viewport.h = (int)h;
+ app->viewport.initScale = initScale;
+ app->viewport.minScale = minScale;
+ app->viewport.maxScale = maxScale;
+ app->viewport.devicePixelRatio = devicePixelRatio;
+ app->viewport.userScalable = userScalable;
+ viewport_set();
+}
+
+static void
+on_mouse_down(void* data, Evas* e, Evas_Object* webview, void* event_info)
+{
+ Evas_Event_Mouse_Down *ev = (Evas_Event_Mouse_Down*) event_info;
+ if (ev->button == 2)
+ evas_object_focus_set(webview, !evas_object_focus_get(webview));
+}
+
+static void
+on_focus_out(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ info("the webview lost keyboard focus\n");
+}
+
+static void
+on_focus_in(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ info("the webview gained keyboard focus\n");
+}
+
+static void
+on_resized(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ Evas_Coord w, h;
+ evas_object_geometry_get(obj, NULL, NULL, &w, &h);
+ ewk_view_fixed_layout_size_set(obj, w, h);
+}
+
+static void
+on_key_down(void *data, Evas *e, Evas_Object *obj, void *event_info)
+{
+ Evas_Event_Key_Down *ev = (Evas_Event_Key_Down*) event_info;
+ ELauncher *app = data;
+ static const char *encodings[] = {
+ "ISO-8859-1",
+ "UTF-8",
+ NULL
+ };
+ static int currentEncoding = -1;
+
+ if (!strcmp(ev->key, "Escape")) {
+ closeWindow(app->ee);
+ } else if (!strcmp(ev->key, "F1")) {
+ info("Back (F1) was pressed\n");
+ if (ewk_view_back_possible(obj)) {
+ Ewk_History *history = ewk_view_history_get(obj);
+ Eina_List *list = ewk_history_back_list_get(history);
+ print_history(list);
+ ewk_history_item_list_free(list);
+ ewk_view_back(obj);
+ } else
+ info("Back ignored: No back history\n");
+ } else if (!strcmp(ev->key, "F2")) {
+ info("Forward (F2) was pressed\n");
+ if (ewk_view_forward_possible(obj)) {
+ Ewk_History *history = ewk_view_history_get(obj);
+ Eina_List *list = ewk_history_forward_list_get(history);
+ print_history(list);
+ ewk_history_item_list_free(list);
+ ewk_view_forward(obj);
+ } else
+ info("Forward ignored: No forward history\n");
+ } else if (!strcmp(ev->key, "F3")) {
+ currentEncoding++;
+ currentEncoding %= (sizeof(encodings) / sizeof(encodings[0]));
+ info("Set encoding (F3) pressed. New encoding to %s", encodings[currentEncoding]);
+ ewk_view_setting_encoding_custom_set(obj, encodings[currentEncoding]);
+ } else if (!strcmp(ev->key, "F4")) {
+ Evas_Object *frame = ewk_view_frame_main_get(obj);
+ Evas_Coord x, y;
+ Ewk_Hit_Test *ht;
+
+ evas_pointer_canvas_xy_get(evas_object_evas_get(obj), &x, &y);
+ ht = ewk_frame_hit_test_new(frame, x, y);
+ if (!ht)
+ printf("No hit test returned for point %d,%d\n", x, y);
+ else {
+ printf("Hit test for point %d,%d\n"
+ " pos=%3d,%3d\n"
+ " bounding_box=%d,%d + %dx%d\n"
+ " title='%s'\n"
+ " alternate_text='%s'\n"
+ " frame=%p (%s)\n"
+ " link {\n"
+ " text='%s'\n"
+ " url='%s'\n"
+ " title='%s'\n"
+ " target frame=%p (%s)\n"
+ " }\n"
+ " flags {\n"
+ " editable=%hhu\n"
+ " selected=%hhu\n"
+ " }\n",
+ x, y,
+ ht->x, ht->y,
+ ht->bounding_box.x, ht->bounding_box.y, ht->bounding_box.w, ht->bounding_box.h,
+ ht->title,
+ ht->alternate_text,
+ ht->frame, evas_object_name_get(ht->frame),
+ ht->link.text,
+ ht->link.url,
+ ht->link.title,
+ ht->link.target_frame, evas_object_name_get(ht->link.target_frame),
+ ht->flags.editable,
+ ht->flags.selected);
+ ewk_frame_hit_test_free(ht);
+ }
+
+ } else if (!strcmp(ev->key, "F5")) {
+ info("Reload (F5) was pressed, reloading.\n");
+ ewk_view_reload(obj);
+ } else if (!strcmp(ev->key, "F6")) {
+ info("Stop (F6) was pressed, stop loading.\n");
+ ewk_view_stop(obj);
+ /* } FIXME: uncomment code below after Bug 18662 lands upstream.
+ else if (!strcmp(ev->key, "F12")) {
+ bool status = ewk_webframe_object_keyboard_navigation_get(page);
+ ewk_webframe_object_keyboard_navigation_set(page, !status);
+ info("Command::keyboard navigation toggle\n");*/
+ } else if (!strcmp(ev->key, "F7")) {
+ info("Zoom out (F7) was pressed.\n");
+ if (currentZoomLevel > MIN_ZOOM_LEVEL && zoom_level_set(obj, currentZoomLevel - 1))
+ currentZoomLevel--;
+ } else if (!strcmp(ev->key, "F8")) {
+ info("Zoom in (F8) was pressed.\n");
+ if (currentZoomLevel < MAX_ZOOM_LEVEL && zoom_level_set(obj, currentZoomLevel + 1))
+ currentZoomLevel++;
+ } else if (!strcmp(ev->key, "F9")) {
+ info("Create new window (F9) was pressed.\n");
+ Eina_Rectangle geometry = {0, 0, 0, 0};
+ browserCreate("http://www.google.com",
+ app->theme, app->userAgent, geometry, app-> backingStore,
+ NULL, 0, NULL);
+ } else if (!strcmp(ev->key, "F10")) {
+ Evas_Coord x, y, w, h;
+ Evas_Object *frame = ewk_view_frame_main_get(obj);
+ float zoom = zoomLevels[currentZoomLevel] / 100.0;
+
+ ewk_frame_visible_content_geometry_get(frame, EINA_FALSE, &x, &y, &w, &h);
+ x -= w;
+ y -= h;
+ w *= 4;
+ h *= 4;
+ info("Pre-render %d,%d + %dx%d\n", x, y, w, h);
+ ewk_view_pre_render_region(obj, x, y, w, h, zoom);
+ } else if (!strcmp(ev->key, "F11")) {
+ info("Pre-render 1 extra column/row with current zoom");
+ ewk_view_pre_render_relative_radius(obj, 1);
+ } else if (!strcmp(ev->key, "d")) {
+ info("Render suspended");
+ ewk_view_disable_render(obj);
+ } else if (!strcmp(ev->key, "e")) {
+ info("Render resumed");
+ ewk_view_enable_render(obj);
+ }
+}
+
+static void
+on_browser_del(void *data, Evas *evas, Evas_Object *browser, void *event)
+{
+ ELauncher *app = (ELauncher*) data;
+
+ evas_object_event_callback_del(app->browser, EVAS_CALLBACK_KEY_DOWN, on_key_down);
+ evas_object_event_callback_del(app->browser, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down);
+ evas_object_event_callback_del(app->browser, EVAS_CALLBACK_FOCUS_IN, on_focus_in);
+ evas_object_event_callback_del(app->browser, EVAS_CALLBACK_FOCUS_OUT, on_focus_out);
+ evas_object_event_callback_del(app->browser, EVAS_CALLBACK_DEL, on_browser_del);
+}
+
+static void
+on_closeWindow(Ecore_Evas *ee)
+{
+ browserDestroy(ee);
+}
+
+static int
+quit(Eina_Bool success, const char *msg)
+{
+ edje_shutdown();
+ ecore_evas_shutdown();
+
+ if (msg)
+ fputs(msg, (success) ? stdout : stderr);
+
+ if (themePath) {
+ free(themePath);
+ themePath = NULL;
+ }
+
+ if (!success)
+ return EXIT_FAILURE;
+
+ return EXIT_SUCCESS;
+}
+
+static int
+browserCreate(const char *url, const char *theme, const char *userAgent, Eina_Rectangle geometry, const char *engine, const char *backingStore, unsigned char isFullscreen, const char *databasePath)
+{
+ if ((geometry.w <= 0) && (geometry.h <= 0)) {
+ geometry.w = DEFAULT_WIDTH;
+ geometry.h = DEFAULT_HEIGHT;
+ }
+
+ ELauncher *app = (ELauncher*) malloc(sizeof(ELauncher));
+ if (!app)
+ return quit(EINA_FALSE, "ERROR: could not create EWebLauncher window\n");
+
+ app->ee = ecore_evas_new(engine, 0, 0, geometry.w, geometry.h, NULL);
+
+ if (!app->ee)
+ return quit(EINA_FALSE, "ERROR: could not construct evas-ecore\n");
+
+ if (isFullscreen)
+ ecore_evas_fullscreen_set(app->ee, EINA_TRUE);
+
+ ecore_evas_title_set(app->ee, "EFL Test Launcher");
+ ecore_evas_callback_resize_set(app->ee, on_ecore_evas_resize);
+ ecore_evas_callback_delete_request_set(app->ee, closeWindow);
+
+ app->evas = ecore_evas_get(app->ee);
+
+ if (!app->evas)
+ return quit(EINA_FALSE, "ERROR: could not get evas from evas-ecore\n");
+
+ app->theme = theme;
+ app->userAgent = userAgent;
+ app->backingStore = backingStore;
+
+ app->bg = evas_object_rectangle_add(app->evas);
+ evas_object_name_set(app->bg, "bg");
+ evas_object_color_set(app->bg, 255, 0, 255, 255);
+ evas_object_move(app->bg, 0, 0);
+ evas_object_resize(app->bg, geometry.w, geometry.h);
+ evas_object_layer_set(app->bg, EVAS_LAYER_MIN);
+ evas_object_show(app->bg);
+
+ if (backingStore && !strcasecmp(backingStore, "single")) {
+ app->browser = ewk_view_single_add(app->evas);
+ info("backing store: single\n");
+ } else {
+ app->browser = ewk_view_tiled_add(app->evas);
+ info("backing store: tiled\n");
+ }
+ ewk_view_theme_set(app->browser, theme);
+ if (userAgent)
+ ewk_view_setting_user_agent_set(app->browser, userAgent);
+ ewk_view_setting_local_storage_database_path_set(app->browser, databasePath);
+
+ evas_object_name_set(app->browser, "browser");
+
+ evas_object_smart_callback_add(app->browser, "title,changed", on_title_changed, app);
+ evas_object_smart_callback_add(app->browser, "load,progress", on_progress, app);
+ evas_object_smart_callback_add(app->browser, "load,finished", on_load_finished, app);
+ evas_object_smart_callback_add(app->browser, "viewport,changed", on_viewport_changed, app);
+
+ evas_object_smart_callback_add(app->browser, "toolbars,visible,set", on_toolbars_visible_set, app);
+ evas_object_smart_callback_add(app->browser, "toolbars,visible,get", on_toolbars_visible_get, app);
+ evas_object_smart_callback_add(app->browser, "statusbar,visible,set", on_statusbar_visible_set, app);
+ evas_object_smart_callback_add(app->browser, "statusbar,visible,get", on_statusbar_visible_get, app);
+ evas_object_smart_callback_add(app->browser, "scrollbars,visible,set", on_scrollbars_visible_set, app);
+ evas_object_smart_callback_add(app->browser, "scrollbars,visible,get", on_scrollbars_visible_get, app);
+ evas_object_smart_callback_add(app->browser, "menubar,visible,set", on_menubar_visible_set, app);
+ evas_object_smart_callback_add(app->browser, "menubar,visible,get", on_menubar_visible_get, app);
+ evas_object_smart_callback_add(app->browser, "tooltip,text,set", on_tooltip_text_set, app);
+ evas_object_smart_callback_add(app->browser, "inputmethod,changed", on_inputmethod_changed, app);
+
+/* ewk_callback_resize_requested_add(app->browser, on_resize_requested, app->ee); */
+
+ evas_object_event_callback_add(app->browser, EVAS_CALLBACK_RESIZE, on_resized, app);
+ evas_object_event_callback_add(app->browser, EVAS_CALLBACK_KEY_DOWN, on_key_down, app);
+ evas_object_event_callback_add(app->browser, EVAS_CALLBACK_MOUSE_DOWN, on_mouse_down, app);
+ evas_object_event_callback_add(app->browser, EVAS_CALLBACK_FOCUS_IN, on_focus_in, app);
+ evas_object_event_callback_add(app->browser, EVAS_CALLBACK_FOCUS_OUT, on_focus_out, app);
+ evas_object_event_callback_add(app->browser, EVAS_CALLBACK_DEL, on_browser_del, app);
+
+ evas_object_move(app->browser, 10, 10);
+ evas_object_resize(app->browser, geometry.w - 20, geometry.h - 20);
+
+ if (url && (url[0] != '\0'))
+ ewk_view_uri_set(app->browser, url);
+
+ evas_object_show(app->browser);
+ ecore_evas_show(app->ee);
+
+ evas_object_focus_set(app->browser, EINA_TRUE);
+
+ windows = eina_list_append(windows, app);
+
+ return 1;
+}
+
+static void
+browserDestroy(Ecore_Evas *ee)
+{
+ ecore_evas_free(ee);
+ if (!eina_list_count(windows))
+ ecore_main_loop_quit();
+}
+
+static void
+closeWindow(Ecore_Evas *ee)
+{
+ Eina_List *l;
+ void *app;
+ EINA_LIST_FOREACH(windows, l, app)
+ {
+ if (((ELauncher*) app)->ee == ee)
+ break;
+ }
+ windows = eina_list_remove(windows, app);
+ browserDestroy(ee);
+ free(app);
+}
+
+static Eina_Bool
+main_signal_exit(void *data, int ev_type, void *ev)
+{
+ ELauncher *app;
+ while (windows) {
+ app = (ELauncher*) eina_list_data_get(windows);
+ ecore_evas_free(app->ee);
+ windows = eina_list_remove(windows, app);
+ }
+ if (!eina_list_count(windows))
+ ecore_main_loop_quit();
+ return EINA_TRUE;
+}
+
+static char *
+findThemePath(const char *theme)
+{
+ const char *defaultTheme = DATA_DIR"/default.edj";
+ char *rpath;
+ struct stat st;
+
+ if (!theme)
+ theme = defaultTheme;
+
+ rpath = realpath(theme, NULL);
+ if (!rpath)
+ return NULL;
+
+ if (stat(rpath, &st)) {
+ free(rpath);
+ return NULL;
+ }
+
+ return rpath;
+}
+
+int
+main(int argc, char *argv[])
+{
+ const char *default_url = "http://www.google.com/";
+
+ Eina_Rectangle geometry = {0, 0, 0, 0};
+ char *url = NULL;
+ char *userAgent = NULL;
+ const char *tmp;
+ const char *proxyUri;
+ char path[PATH_MAX];
+
+ char *engine = NULL;
+ char *theme = NULL;
+ char *backingStore = (char *)backingStores[0];
+
+ unsigned char quitOption = 0;
+ unsigned char isFullscreen = 0;
+ unsigned char sudoWorkaround = 0;
+ int args;
+
+ Ecore_Getopt_Value values[] = {
+ ECORE_GETOPT_VALUE_STR(engine),
+ ECORE_GETOPT_VALUE_BOOL(quitOption),
+ ECORE_GETOPT_VALUE_STR(backingStore),
+ ECORE_GETOPT_VALUE_BOOL(isFullscreen),
+ ECORE_GETOPT_VALUE_PTR_CAST(geometry),
+ ECORE_GETOPT_VALUE_STR(theme),
+ ECORE_GETOPT_VALUE_STR(userAgent),
+ ECORE_GETOPT_VALUE_BOOL(sudoWorkaround),
+ ECORE_GETOPT_VALUE_INT(verbose),
+ ECORE_GETOPT_VALUE_BOOL(quitOption),
+ ECORE_GETOPT_VALUE_BOOL(quitOption),
+ ECORE_GETOPT_VALUE_BOOL(quitOption),
+ ECORE_GETOPT_VALUE_BOOL(quitOption),
+ ECORE_GETOPT_VALUE_NONE
+ };
+
+ if (!ecore_evas_init())
+ return EXIT_FAILURE;
+
+ if (!edje_init()) {
+ ecore_evas_shutdown();
+ return EXIT_FAILURE;
+ }
+
+ ecore_app_args_set(argc, (const char**) argv);
+ args = ecore_getopt_parse(&options, values, argc, argv);
+
+ if (args < 0)
+ return quit(EINA_FALSE, "ERROR: could not parse options.\n");
+
+ if (quitOption)
+ return quit(EINA_TRUE, NULL);
+
+ if (args < argc)
+ url = argv[args];
+ else
+ url = (char*) default_url;
+
+ if (sudoWorkaround)
+ strcat(getenv("HOME"), "blah");
+
+ themePath = findThemePath(theme);
+ if (!themePath)
+ return quit(EINA_FALSE, "ERROR: could not find theme.\n");
+
+ ewk_init();
+ tmp = getenv("TMPDIR");
+ if (!tmp)
+ tmp = "/tmp";
+ snprintf(path, sizeof(path), "%s/.ewebkit-%u", tmp, getuid());
+ ecore_file_mkpath(path);
+ ewk_settings_icon_database_path_set(path);
+ ewk_settings_web_database_path_set(path);
+
+ proxyUri = getenv("http_proxy");
+ if (proxyUri)
+ ewk_settings_proxy_uri_set(proxyUri);
+
+ browserCreate(url, themePath, userAgent, geometry, engine, backingStore, isFullscreen, path);
+ ecore_event_handler_add(ECORE_EVENT_SIGNAL_EXIT, main_signal_exit, &windows);
+
+ ecore_main_loop_begin();
+
+ ewk_shutdown();
+
+ return quit(EINA_TRUE, NULL);
+}
diff --git a/Tools/FindSafari/FindSafari.cpp b/Tools/FindSafari/FindSafari.cpp
new file mode 100644
index 0000000..c3d149f
--- /dev/null
+++ b/Tools/FindSafari/FindSafari.cpp
@@ -0,0 +1,169 @@
+/*
+ * 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 "resource.h"
+
+#include <shlwapi.h>
+#include <stdio.h>
+#include <tchar.h>
+#include <windows.h>
+
+#define LOG(header, ...) \
+ do { \
+ _ftprintf(stderr, header); \
+ _ftprintf(stderr, __VA_ARGS__); \
+ } while (0)
+#define LOG_WARNING(...) LOG(TEXT("WARNING: "), __VA_ARGS__)
+#define LOG_ERROR(...) LOG(TEXT("ERROR: "), __VA_ARGS__)
+
+static TCHAR* getStringValue(HKEY key, LPCTSTR valueName)
+{
+ DWORD type = 0;
+ DWORD bufferSize = 0;
+ if (RegQueryValueEx(key, valueName, 0, &type, 0, &bufferSize) != ERROR_SUCCESS || type != REG_SZ)
+ return 0;
+
+ TCHAR* buffer = (TCHAR*)malloc(bufferSize);
+ if (RegQueryValueEx(key, valueName, 0, &type, reinterpret_cast<LPBYTE>(buffer), &bufferSize) != ERROR_SUCCESS) {
+ free(buffer);
+ return 0;
+ }
+
+ return buffer;
+}
+
+static TCHAR* getInstalledWebKitDirectory()
+{
+ LPCTSTR installPathKeyString = TEXT("SOFTWARE\\Apple Computer, Inc.\\Safari");
+ LPCTSTR installPathWin64KeyString = TEXT("SOFTWARE\\Wow6432Node\\Apple Computer, Inc.\\Safari");
+ HKEY installPathKey = 0;
+ LONG error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, installPathKeyString, 0, KEY_READ, &installPathKey);
+ if (error != ERROR_SUCCESS)
+ error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, installPathWin64KeyString, 0, KEY_READ, &installPathKey);
+ if (error != ERROR_SUCCESS) {
+ LOG_WARNING(TEXT("Failed to open registry key %s\n"), installPathKeyString);
+ return 0;
+ }
+ LPTSTR webKitPath = getStringValue(installPathKey, TEXT("InstallDir"));
+ RegCloseKey(installPathKey);
+ if (!webKitPath) {
+ LOG_WARNING(TEXT("Couldn't retrieve value for registry key %s\n"), installPathKeyString);
+ return 0;
+ }
+ return webKitPath;
+}
+
+int _tmain(int argc, TCHAR* argv[])
+{
+ TCHAR* path = getInstalledWebKitDirectory();
+ if (!path) {
+ LOG_ERROR(TEXT("Couldn't determine installed Safari path\n"));
+ return 1;
+ }
+
+ bool printLauncher = false;
+ bool printEnvironment = false;
+ bool debugger = false;
+
+ for (int i = 1; i < argc; ++i) {
+ if (!_tcscmp(argv[i], TEXT("/printSafariLauncher"))) {
+ printLauncher = true;
+ continue;
+ }
+ if (!_tcscmp(argv[i], TEXT("/printSafariEnvironment"))) {
+ printEnvironment = true;
+ continue;
+ }
+ if (!_tcscmp(argv[i], TEXT("/debugger"))) {
+ debugger = true;
+ continue;
+ }
+ }
+
+ // printLauncher is inclusive of printEnvironment, so do not
+ // leave both enabled:
+ if (printLauncher && printEnvironment)
+ printEnvironment = false;
+
+ if (!printLauncher && !printEnvironment) {
+ _tprintf(TEXT("%s\n"), path);
+ free(path);
+ return 0;
+ }
+
+ LPCTSTR lines[] = {
+ TEXT("@echo off"),
+ TEXT("del /s /q \"%%TMP%%\\WebKitNightly\""),
+ TEXT("mkdir 2>NUL \"%%TMP%%\\WebKitNightly\\Safari.resources\""),
+ TEXT("mkdir 2>NUL \"%%TMP%%\\WebKitNightly\\WebKit.resources\""),
+ TEXT("mkdir 2>NUL \"%%TMP%%\\WebKitNightly\\JavaScriptCore.resources\""),
+ TEXT("xcopy /y /i /d \"%sSafari.exe\" \"%%TMP%%\\WebKitNightly\""),
+ TEXT("if exist \"%sSafari.dll\" xcopy /y /i /d \"%sSafari.dll\" \"%%TMP%%\\WebKitNightly\""),
+ TEXT("xcopy /y /i /d /e \"%sSafari.resources\" \"%%TMP%%\\WebKitNightly\\Safari.resources\""),
+ TEXT("xcopy /y /i /d /e \"%splugins\" \"%%TMP%%\\WebKitNightly\\plugins\""),
+ TEXT("xcopy /y /i /d WebKit.dll \"%%TMP%%\\WebKitNightly\""),
+ TEXT("xcopy /y /i /d WebKit.pdb \"%%TMP%%\\WebKitNightly\""),
+ TEXT("xcopy /y /i /d /e WebKit.resources \"%%TMP%%\\WebKitNightly\\WebKit.resources\""),
+ TEXT("xcopy /y /i /d JavaScriptCore.dll \"%%TMP%%\\WebKitNightly\""),
+ TEXT("xcopy /y /i /d JavaScriptCore.pdb \"%%TMP%%\\WebKitNightly\""),
+ TEXT("xcopy /y /i /d /e JavaScriptCore.resources \"%%TMP%%\\WebKitNightly\\JavaScriptCore.resources\""),
+ TEXT("set PATH=%%CD%%;%s;%%PATH%%"),
+ };
+
+ LPCTSTR command = TEXT("\"%TMP%\\WebKitNightly\\Safari.exe\"");
+
+ LPCTSTR launchLines[] = {
+ TEXT("%s"),
+ };
+
+ LPCTSTR debuggerLines[] = {
+ TEXT("if exist \"%%DevEnvDir%%\\VCExpress.exe\" ("),
+ TEXT("\"%%DevEnvDir%%\\VCExpress.exe\" /debugExe %s"),
+ TEXT(") else ("),
+ TEXT("\"%%DevEnvDir%%\\devenv.exe\" /debugExe %s"),
+ TEXT(")"),
+ };
+
+ for (int i = 0; i < ARRAYSIZE(lines); ++i) {
+ _tprintf(lines[i], path, path);
+ _tprintf(TEXT("\n"));
+ }
+
+ LPCTSTR* endLines = debugger ? debuggerLines : launchLines;
+
+ // Don't print launch command if we just want the environment set up...
+ if (!printEnvironment) {
+ for (unsigned i = 0; i < (debugger ? ARRAYSIZE(debuggerLines) : ARRAYSIZE(launchLines)); ++i) {
+ _tprintf(endLines[i], command);
+ _tprintf(TEXT("\n"));
+ }
+ }
+
+ free(path);
+ return 0;
+}
diff --git a/Tools/FindSafari/FindSafari.rc b/Tools/FindSafari/FindSafari.rc
new file mode 100644
index 0000000..7d4abac
--- /dev/null
+++ b/Tools/FindSafari/FindSafari.rc
@@ -0,0 +1,70 @@
+// 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
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// RT_MANIFEST
+//
+
+IDR_SAFARI_MANIFEST RT_MANIFEST "Safari.exe.manifest"
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Tools/FindSafari/FindSafari.vcproj b/Tools/FindSafari/FindSafari.vcproj
new file mode 100644
index 0000000..c91bb1c
--- /dev/null
+++ b/Tools/FindSafari/FindSafari.vcproj
@@ -0,0 +1,420 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="FindSafari"
+ ProjectGUID="{DA31DA52-6675-48D4-89E0-333A7144397C}"
+ RootNamespace="FindSafari"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\FindSafariCommon.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\FindSafariCommon.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\FindSafariCommon.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_LTCG|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\FindSafariCommon.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="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;.\FindSafariCommon.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;.\FindSafariCommon.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="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\FindSafari.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\resource.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\FindSafari.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/FindSafari/FindSafariCommon.vsprops b/Tools/FindSafari/FindSafariCommon.vsprops
new file mode 100644
index 0000000..cbbc8e6
--- /dev/null
+++ b/Tools/FindSafari/FindSafariCommon.vsprops
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="FindSafariCommon"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="shlwapi.lib advapi32.lib ole32.lib"
+ OutputFile="$(OutDir)\$(ProjectName).exe"
+ SubSystem="1"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/FindSafari/Safari.exe.manifest b/Tools/FindSafari/Safari.exe.manifest
new file mode 100644
index 0000000..08c85cf
--- /dev/null
+++ b/Tools/FindSafari/Safari.exe.manifest
@@ -0,0 +1,129 @@
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="win32" name="Microsoft.VC80.CRT" version="8.0.50727.762" processorArchitecture="x86" publicKeyToken="1fc8b3b9a1e18e3b"></assemblyIdentity>
+ </dependentAssembly>
+ </dependency>
+ <dependency>
+ <dependentAssembly>
+ <assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="x86" publicKeyToken="6595b64144ccf1df" language="*"></assemblyIdentity>
+ </dependentAssembly>
+ </dependency>
+ <file name="WebKit" hashalg="SHA1">
+ <comClass progid="OpenSourceWebKit.WebView" clsid="{D6BCA079-F61C-4E1E-B453-32A0477D02E3}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebIconDatabase" clsid="{66827EC1-3AEF-4241-BAC5-F776B44F030F}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebMutableURLRequest" clsid="{A062ECC3-BB1B-4694-A569-F59E0AD6BE0C}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebNotificationCenter" clsid="{BA590766-0A6F-46C7-B96E-743490D94CB7}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebHistory" clsid="{A4B9B45D-949F-4C8C-9B92-6FBFCC1CAAA2}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.CFDictionaryPropertyBag" clsid="{DD653964-4D37-4FB2-9CB6-6A9A97719332}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebHistoryItem" clsid="{6BE190E9-1725-4E4A-88DB-6A9FE242C9E5}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebCache" clsid="{F71071FD-A51B-4B69-9EB6-44374405E80C}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebJavaScriptCollector" clsid="{1820D883-42FE-4B78-88C8-5456BB19D224}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebPreferences" clsid="{67B89F90-F778-438B-ABBF-34D1ACBF8651}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebKitStatistics" clsid="{E93AA8D7-F362-4A4A-A95D-325906BEB5F0}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebError" clsid="{6C6AF3F9-36B4-4BF7-8BDE-74DCD4AD75A4}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebURLCredential" clsid="{7433F53B-7FE9-484A-9432-72909457A646}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebDownload" clsid="{C0F98BD9-3B1C-413D-904A-E2D1453EAF1F}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebURLRequest" clsid="{2FB5499A-BB5D-4469-8517-789FEC8FD9BA}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebURLProtectionSpace" clsid="{F366A6E8-E43C-4FD4-AAB0-8E6E79C73E6E}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebScrollBar" clsid="{24A53AD5-AA9F-44E6-AA22-2C7C250B661A}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebScriptDebugServer" clsid="{715636C4-59E7-4B85-BBC5-B555888787D7}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebURLResponse" clsid="{AB201196-8DD2-4D45-AEBD-029B6A37AA27}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebTextRenderer" clsid="{24040CD6-AFF4-4A51-9C8B-71539580EE76}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebDatabaseManager" clsid="{C2A1BFC2-1E7C-49FE-8592-D0C7FB440BC0}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebArchive" clsid="{1B63D781-9BC4-4A04-899F-C4B05BBD3BE5}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebCoreStatistics" clsid="{96B93356-9D61-4B3F-A6CF-A78283AC9649}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <comClass progid="OpenSourceWebKit.WebCookieManager" clsid="{3F35F332-BB2B-49B3-AEDD-27B317687E07}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}"></comClass>
+ <typelib tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" version="528.0" helpdir="" flags="HASDISKIMAGE"></typelib>
+ </file>
+ <comInterfaceExternalProxyStub name="IWebView" iid="{174BBEFD-058E-49C7-91DF-6F110AA4AC28}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebUIDelegate" iid="{2452A889-A74A-4FBC-9617-326A0A953630}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebURLRequest" iid="{F4B85F1D-F3B2-493D-B786-0930E804A3BA}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebFrame" iid="{B4B22EF7-DD43-4D01-A992-99C4A8B1F845}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebFrameView" iid="{E23E1B15-78F6-4E89-AD2E-49992A040A35}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebDocumentView" iid="{0A6397A7-90FE-49A0-B9C1-44693DD779F7}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebDataSource" iid="{5221A975-AE09-4A7B-A4DF-E3B1B5F38A21}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebDocumentRepresentation" iid="{3C9F6251-CFD8-447A-B429-6B6AE627436C}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebError" iid="{89E3B189-0B60-4D6B-A87A-3F1172CB5538}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebMutableURLRequest" iid="{C4042773-371F-427E-AFA9-9D4B358A0D93}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebURLResponse" iid="{9814930B-E037-4477-8DF1-4D898B648995}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebArchive" iid="{F07D5252-F66E-4A4D-B9DC-33BD11DCC138}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebResource" iid="{09567E0E-7859-494A-B0E4-92C13CFE5574}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMNode" iid="{3EEA3E20-72DA-4BE7-954F-79B5A14AD726}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMObject" iid="{A27FA225-F34E-425D-88EB-A35BD105A527}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebScriptObject" iid="{7022340A-649C-43FC-9214-85CA7D3BE3C7}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMNodeList" iid="{10A05A96-CBD9-4493-83AD-FAFB952615CE}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMNamedNodeMap" iid="{E6CBF396-C9F9-431B-A8D6-BCB525067E9F}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMDocument" iid="{A83C2C44-0BAC-45C7-8E17-6A49975D5CCA}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMDocumentType" iid="{17FCE6EA-4164-4BD4-9DBF-0395FBF37FD3}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMImplementation" iid="{6E48C25D-E542-4D1A-BC73-ACDC21E39C56}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMElement" iid="{E053A35B-7775-4859-80EA-C35D02D145A2}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMAttr" iid="{B587E098-8206-4B5A-A7DB-422F218571A0}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMDocumentFragment" iid="{09D35665-8396-4868-949E-8AA2407A6E10}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMText" iid="{74638F45-1AA0-4DB5-958C-82066E00BD2B}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMCharacterData" iid="{F4DED047-FE61-461A-BDBD-BB87F79DB713}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMComment" iid="{118002E8-847F-4B1A-968C-B25A6AC7B128}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMCDATASection" iid="{31B506C1-45A3-4D72-815A-311B0A897E58}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMProcessingInstruction" iid="{D99D2F48-ABF3-426A-9339-54681E1AFCA9}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMEntityReference" iid="{0593CE45-15B2-44AF-BBD0-5A1654F8240E}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMHTMLElement" iid="{EBD5F41D-FF65-41D8-97C9-FCE3A3D4CC3E}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebOpenPanelResultListener" iid="{634198C7-9DFC-4ABA-9E8C-90AEEA7A4144}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebUndoTarget" iid="{BF7F516E-E75D-4E3A-83E2-8F694D83C72D}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebResourceLoadDelegate" iid="{AF3289AA-90DB-4CA4-A112-A1E5F0517953}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebURLAuthenticationChallenge" iid="{5382DABA-C3C3-40C5-AA40-04079F11A844}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebURLAuthenticationChallengeSender" iid="{9360D6FB-186C-4FF7-AE57-D1B973DA0D1C}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebURLCredential" iid="{A1E9D765-FACE-4189-BBE3-AED7EBF65EBD}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebURLProtectionSpace" iid="{71D2622A-3FF2-404B-BD45-C60659C901AF}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebDownloadDelegate" iid="{16A32AE6-C862-40CD-9225-2CAF823F40F9}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebDownload" iid="{65EFE83B-A9E4-4516-8F3B-BAA25DA90FFD}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebFrameLoadDelegate" iid="{4CD809C2-73A5-44EE-B0D7-D1863DFE9F57}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebPolicyDelegate" iid="{9B0BAE6C-A496-4000-9E22-2E89F0747401}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebPolicyDecisionListener" iid="{DFCDE523-FD96-4F95-958B-151540FE122A}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebBackForwardList" iid="{C278A16D-B502-4131-B551-DCE3F4ED2B36}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebHistoryItem" iid="{1E2970AE-72B7-4500-A7A0-12B0FFEB91FC}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebPreferences" iid="{0930D594-A5A3-46E1-858E-AB17A13CD28E}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebIBActions" iid="{8F0E3A30-B924-44F8-990A-1AE61ED6C632}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebViewCSS" iid="{ADF68A8C-336F-405C-A053-3D11A9D5B092}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMCSSStyleDeclaration" iid="{DBBE9A6B-D505-4647-B4AB-40A7CF3EE63E}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMCSSValue" iid="{51D29553-2AF7-4F52-AFE6-3C59196A8BAA}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMCSSRule" iid="{05947A31-9E1C-4C98-8608-6688959D6542}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMCSSStyleSheet" iid="{14B1C213-1458-48A1-AD8F-54BFE64F9ECF}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMCSSRuleList" iid="{D45DA43D-5EDB-4315-A097-3ED3FA089193}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebViewEditing" iid="{07BDAC9A-19A1-4086-864D-BAD9E0F00D5C}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMRange" iid="{2F33E42C-0B39-48B3-B7B6-E910CDB325AD}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebUndoManager" iid="{D25D748C-6C1E-478D-9832-FDA26E8F7EE4}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebInvocation" iid="{67B067BE-4DE6-45C2-AD39-A91DFA84FF4E}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebMethodSignature" iid="{431DD6B2-56BF-4F48-943B-78CCEAC418E4}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebEditingDelegate" iid="{2C75A1E3-EE9D-45C8-A385-19DE68AC5675}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebNotification" iid="{93598207-3E34-49EC-97EC-EFA9A1E16335}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IEnumWebGrammarDetails" iid="{FABCC69A-5917-4242-A19A-42E8B62227A7}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebGrammarDetail" iid="{8B95C1B3-E1B3-4F97-80D6-2240417E3E0C}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IEnumSpellingGuesses" iid="{B0F960E7-FB81-447F-A958-E02DA02ADBB7}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebViewUndoableEditing" iid="{639E7121-13C8-4A12-BC18-6E1F3D68F3C3}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebViewEditingActions" iid="{7E066C42-8E81-4778-888D-D6CC93E27D4C}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebNotificationObserver" iid="{1BA491C4-58A7-4091-9F56-9AED118DB4C1}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebViewPrivate" iid="{44914369-DEB5-4FCF-A6A3-30C02E73154F}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebFormDelegate" iid="{4CBEC1BD-ABC3-4BDB-8E5E-4D3BCF9E8C1E}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMHTMLInputElement" iid="{80C40AC5-1755-4894-812F-479269C262A2}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IDOMHTMLTextAreaElement" iid="{298B02B7-3EB5-4BA4-AD3F-7FA53241AADE}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebFormSubmissionListener" iid="{1911D650-035E-4204-8746-ABECF77A4C9B}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebFrameLoadDelegatePrivate" iid="{32DC2531-948D-400E-A82F-FE6668B61A0B}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IEnumTextMatches" iid="{C0CDE63A-5ED1-453F-B937-93B1A61AD3B3}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebInspector" iid="{68159FF1-9037-45EC-9992-B2E455CF39F3}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebIconDatabase" iid="{E93F2616-2560-47D9-BD4D-6E2F1E1D3174}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebNotificationCenter" iid="{1E411ABE-DAA0-4A83-BCCA-D94E0704F193}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebHistory" iid="{F34E4B1A-361D-4B9F-9A3F-D869DCD97F9A}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebCache" iid="{0673E6F5-AE63-4871-AAC6-6A1E0E6A99AB}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebJavaScriptCollector" iid="{E6A1D169-F44A-4D11-B55B-F0A406F47612}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebKitStatistics" iid="{955C1042-BCF7-4F51-8AE7-66C2D0D47C44}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebScrollBarPrivate" iid="{6C585B08-2E4F-4594-9B90-0425E3A33FD0}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebScrollBarDelegatePrivate" iid="{2E8D56AF-3BF5-4E17-BDA6-01692ACBE3D5}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebScriptDebugServer" iid="{E24111D6-3668-4C8B-B921-D644524945F8}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebScriptDebugListener" iid="{09612B56-BE17-4867-A441-1C5C4E0F5302}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebScriptCallFrame" iid="{029D0676-162A-4140-8917-9574E09F66EB}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebTextRenderer" iid="{5B26ABBB-C27A-4527-A313-CB733E2CD257}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebDatabaseManager" iid="{5724F010-A77B-4A42-8F89-A5095B61D469}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebSecurityOrigin" iid="{304D4462-A921-4E85-BC11-BCE1462B159D}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebCoreStatistics" iid="{9607001D-6EEF-4C2C-AD22-94E9DA587973}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+ <comInterfaceExternalProxyStub name="IWebCookieManager" iid="{7053FE94-3623-444F-A298-209A90879A8C}" tlbid="{2A748656-625D-4207-B29F-40C95BFEB3A9}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
+</assembly> \ No newline at end of file
diff --git a/Tools/FindSafari/resource.h b/Tools/FindSafari/resource.h
new file mode 100644
index 0000000..91d1053
--- /dev/null
+++ b/Tools/FindSafari/resource.h
@@ -0,0 +1,16 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by FindSafari.rc
+//
+#define IDR_SAFARI_MANIFEST 100
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 103
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1001
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/Tools/GNUmakefile.am b/Tools/GNUmakefile.am
new file mode 100644
index 0000000..bf21418
--- /dev/null
+++ b/Tools/GNUmakefile.am
@@ -0,0 +1,192 @@
+noinst_PROGRAMS += \
+ Programs/DumpRenderTree \
+ Programs/GtkLauncher \
+ Programs/ImageDiff
+
+# GtkLauncher
+Programs_GtkLauncher_CPPFLAGS = \
+ -I$(srcdir)/WebKit/gtk \
+ -I$(srcdir)/WebCore/platform/network/soup/cache/ \
+ -I$(top_builddir)/WebKit/gtk \
+ -I$(top_builddir)/DerivedSources \
+ $(global_cppflags) \
+ $(javascriptcore_cppflags)
+
+Programs_GtkLauncher_SOURCES = \
+ Tools/GtkLauncher/main.c
+
+Programs_GtkLauncher_CFLAGS = \
+ -ansi \
+ -fno-strict-aliasing \
+ $(global_cflags) \
+ $(GTK_CFLAGS) \
+ $(LIBSOUP_CFLAGS)
+
+Programs_GtkLauncher_LDADD = \
+ libwebkitgtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
+ $(GTK_LIBS) \
+ $(GLIB_LIBS) \
+ $(WINMM_LIBS)
+
+Programs_GtkLauncher_LDFLAGS = \
+ -no-fast-install \
+ -no-install
+
+# DumpRenderTree
+dumprendertree_cppflags := \
+ -I$(srcdir)/Tools/DumpRenderTree \
+ -I$(srcdir)/Tools/DumpRenderTree/cairo \
+ -I$(srcdir)/Tools/DumpRenderTree/gtk \
+ -I$(srcdir)/WebKit/gtk \
+ -I$(srcdir)/WebCore/platform/gtk \
+ -I$(srcdir)/WebCore/platform/network/soup/cache/ \
+ -I$(top_builddir)/WebKit/gtk \
+ -I$(top_builddir)/DerivedSources \
+ $(global_cppflags) \
+ $(javascriptcore_cppflags)
+
+Programs_DumpRenderTree_CPPFLAGS = $(dumprendertree_cppflags)
+
+Programs_DumpRenderTree_SOURCES = \
+ Tools/DumpRenderTree/DumpRenderTree.h \
+ Tools/DumpRenderTree/DumpRenderTreePrefix.h \
+ Tools/DumpRenderTree/AccessibilityController.cpp \
+ Tools/DumpRenderTree/AccessibilityController.h \
+ Tools/DumpRenderTree/AccessibilityTextMarker.cpp \
+ Tools/DumpRenderTree/AccessibilityTextMarker.h \
+ Tools/DumpRenderTree/AccessibilityUIElement.cpp \
+ Tools/DumpRenderTree/AccessibilityUIElement.h \
+ Tools/DumpRenderTree/GCController.cpp \
+ Tools/DumpRenderTree/GCController.h \
+ Tools/DumpRenderTree/JavaScriptThreading.h \
+ Tools/DumpRenderTree/LayoutTestController.cpp \
+ Tools/DumpRenderTree/LayoutTestController.h \
+ Tools/DumpRenderTree/PixelDumpSupport.cpp \
+ Tools/DumpRenderTree/PixelDumpSupport.h \
+ Tools/DumpRenderTree/WorkQueue.cpp \
+ Tools/DumpRenderTree/WorkQueue.h \
+ Tools/DumpRenderTree/WorkQueueItem.h \
+ Tools/DumpRenderTree/config.h \
+ Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.cpp \
+ Tools/DumpRenderTree/cairo/PixelDumpSupportCairo.h \
+ Tools/DumpRenderTree/gtk/AccessibilityControllerGtk.cpp \
+ Tools/DumpRenderTree/gtk/AccessibilityUIElementGtk.cpp \
+ Tools/DumpRenderTree/gtk/DumpRenderTree.cpp \
+ Tools/DumpRenderTree/gtk/DumpRenderTreeGtk.h \
+ Tools/DumpRenderTree/gtk/EditingCallbacks.h \
+ Tools/DumpRenderTree/gtk/EditingCallbacks.cpp \
+ Tools/DumpRenderTree/gtk/EventSender.h \
+ Tools/DumpRenderTree/gtk/EventSender.cpp \
+ Tools/DumpRenderTree/gtk/GCControllerGtk.cpp \
+ Tools/DumpRenderTree/gtk/LayoutTestControllerGtk.cpp \
+ Tools/DumpRenderTree/gtk/PixelDumpSupportGtk.cpp \
+ Tools/DumpRenderTree/gtk/WorkQueueItemGtk.cpp \
+ WebCore/platform/gtk/GtkVersioning.c
+
+Programs_DumpRenderTree_CXXFLAGS = \
+ $(global_cxxflags) \
+ $(dumprendertree_cppflags) \
+ $(Programs_DumpRenderTree_CFLAGS)
+
+Programs_DumpRenderTree_CFLAGS = \
+ -fno-strict-aliasing \
+ $(dumprendertree_cppflags) \
+ $(global_cflags) \
+ $(GLOBALDEPS_CFLAGS) \
+ $(CAIRO_CFLAGS) \
+ $(GTK_CFLAGS) \
+ $(LIBSOUP_CFLAGS)
+
+Programs_DumpRenderTree_LDADD = \
+ libwebkitgtk-@WEBKITGTK_API_MAJOR_VERSION@.@WEBKITGTK_API_MINOR_VERSION@.la \
+ $(GLOBALDEPS_LIBS) \
+ $(CAIRO_LIBS) \
+ $(GTK_LIBS) \
+ $(GLIB_LIBS) \
+ $(LIBSOUP_LIBS) \
+ $(FREETYPE_LIBS) \
+ $(WINMM_LIBS)
+
+Programs_DumpRenderTree_LDFLAGS = \
+ -no-fast-install \
+ -no-install
+
+# 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
+
+# clean target
+CLEANFILES += \
+ Programs/DumpRenderTree \
+ Programs/GtkLauncher \
+ Programs/ImageDiff
+
+if TARGET_X11
+
+# Build TestNetscapePlugin only for X11
+# since we don't support plugins for non-X11 builds at the moment.
+noinst_LTLIBRARIES += \
+ TestNetscapePlugin/libtestnetscapeplugin.la
+
+dumprendertree_cppflags += \
+ -DTEST_PLUGIN_DIR=\"${shell pwd}/${top_builddir}/TestNetscapePlugin/.libs\" \
+ -DFONTS_CONF_DIR=\"${shell pwd}/${srcdir}/Tools/DumpRenderTree/gtk/fonts\"
+
+TestNetscapePlugin_libtestnetscapeplugin_la_CPPFLAGS = \
+ -I$(srcdir)/Tools/DumpRenderTree \
+ -I$(srcdir)/Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders \
+ -I$(srcdir)/WebCore \
+ -I$(srcdir)/WebCore/bridge \
+ -I$(srcdir)/WebCore/plugins \
+ -I$(srcdir)/Tools/DumpRenderTree/TestNetscapePlugIn \
+ $(global_cppflags) \
+ $(javascriptcore_cppflags)
+
+TestNetscapePlugin_libtestnetscapeplugin_la_SOURCES = \
+ Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npapi.h \
+ Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npfunctions.h \
+ Tools/DumpRenderTree/unix/TestNetscapePlugin/ForwardingHeaders/WebKit/npruntime.h \
+ Tools/DumpRenderTree/unix/TestNetscapePlugin/TestNetscapePlugin.cpp \
+ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/DocumentOpenInDestroyStream.cpp \
+ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/EvaluateJSAfterRemovingPluginElement.cpp \
+ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/GetUserAgentWithNullNPPFromNPPNew.cpp \
+ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeObjectFromDestroyedPlugin.cpp \
+ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NPRuntimeRemoveProperty.cpp \
+ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/NullNPPGetValuePointer.cpp \
+ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PassDifferentNPPStruct.cpp \
+ Tools/DumpRenderTree/TestNetscapePlugIn/Tests/PluginScriptableNPObjectInvokeDefault.cpp \
+ Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.cpp \
+ Tools/DumpRenderTree/TestNetscapePlugIn/PluginTest.h \
+ Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.cpp \
+ Tools/DumpRenderTree/TestNetscapePlugIn/PluginObject.h \
+ Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.cpp \
+ Tools/DumpRenderTree/TestNetscapePlugIn/TestObject.h
+
+TestNetscapePlugin_libtestnetscapeplugin_la_LDFLAGS = \
+ -rpath ${shell pwd}/$(top_builddir)/../unix/TestNetscapePlugin/.libs \
+ $(no_undefined) \
+ -avoid-version \
+ -module
+
+CLEANFILES += TestNetscapePlugin/libtestnetscapeplugin.la
+endif
diff --git a/Tools/GtkLauncher/main.c b/Tools/GtkLauncher/main.c
new file mode 100644
index 0000000..a1baf05
--- /dev/null
+++ b/Tools/GtkLauncher/main.c
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc.
+ * Copyright (C) 2007 Alp Toker <alp@atoker.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 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 <gtk/gtk.h>
+#include <webkit/webkit.h>
+
+static gint windowCount = 0;
+
+static GtkWidget* createWindow(WebKitWebView** outWebView);
+
+static void activateUriEntryCb(GtkWidget* entry, gpointer data)
+{
+ WebKitWebView *webView = g_object_get_data(G_OBJECT(entry), "web-view");
+ const gchar* uri = gtk_entry_get_text(GTK_ENTRY(entry));
+ g_assert(uri);
+ webkit_web_view_load_uri(webView, uri);
+}
+
+static void updateTitle(GtkWindow* window, WebKitWebView* webView)
+{
+ GString *string = g_string_new(webkit_web_view_get_title(webView));
+ gdouble loadProgress = webkit_web_view_get_progress(webView) * 100;
+ g_string_append(string, " - WebKit Launcher");
+ if (loadProgress < 100)
+ g_string_append_printf(string, " (%f%%)", loadProgress);
+ gchar *title = g_string_free(string, FALSE);
+ gtk_window_set_title(window, title);
+ g_free(title);
+}
+
+static void linkHoverCb(WebKitWebView* page, const gchar* title, const gchar* link, GtkStatusbar* statusbar)
+{
+ guint statusContextId =
+ GPOINTER_TO_UINT(g_object_get_data(G_OBJECT(statusbar), "link-hover-context"));
+ /* underflow is allowed */
+ gtk_statusbar_pop(statusbar, statusContextId);
+ if (link)
+ gtk_statusbar_push(statusbar, statusContextId, link);
+}
+
+static void notifyTitleCb(WebKitWebView* webView, GParamSpec* pspec, GtkWidget* window)
+{
+ updateTitle(GTK_WINDOW(window), webView);
+}
+
+static void notifyLoadStatusCb(WebKitWebView* webView, GParamSpec* pspec, GtkWidget* uriEntry)
+{
+ if (webkit_web_view_get_load_status(webView) == WEBKIT_LOAD_COMMITTED) {
+ WebKitWebFrame *frame = webkit_web_view_get_main_frame(webView);
+ const gchar *uri = webkit_web_frame_get_uri(frame);
+ if (uri)
+ gtk_entry_set_text(GTK_ENTRY(uriEntry), uri);
+ }
+}
+
+static void notifyProgressCb(WebKitWebView* webView, GParamSpec* pspec, GtkWidget* window)
+{
+ updateTitle(GTK_WINDOW(window), webView);
+}
+
+static void destroyCb(GtkWidget* widget, GtkWidget* window)
+{
+ if (g_atomic_int_dec_and_test(&windowCount))
+ gtk_main_quit();
+}
+
+static void goBackCb(GtkWidget* widget, WebKitWebView* webView)
+{
+ webkit_web_view_go_back(webView);
+}
+
+static void goForwardCb(GtkWidget* widget, WebKitWebView* webView)
+{
+ webkit_web_view_go_forward(webView);
+}
+
+static WebKitWebView*
+createWebViewCb(WebKitWebView* webView, WebKitWebFrame* web_frame, GtkWidget* window)
+{
+ WebKitWebView *newWebView;
+ createWindow(&newWebView);
+ return newWebView;
+}
+
+static gboolean webViewReadyCb(WebKitWebView* webView, GtkWidget* window)
+{
+ gtk_widget_grab_focus(GTK_WIDGET(webView));
+ gtk_widget_show_all(window);
+ return FALSE;
+}
+
+static gboolean closeWebViewCb(WebKitWebView* webView, GtkWidget* window)
+{
+ gtk_widget_destroy(window);
+ return TRUE;
+}
+
+static GtkWidget* createBrowser(GtkWidget* window, GtkWidget* uriEntry, GtkWidget* statusbar, WebKitWebView* webView)
+{
+ GtkWidget *scrolledWindow = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolledWindow), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+
+ gtk_container_add(GTK_CONTAINER(scrolledWindow), GTK_WIDGET(webView));
+
+ g_signal_connect(webView, "notify::title", G_CALLBACK(notifyTitleCb), window);
+ g_signal_connect(webView, "notify::load-status", G_CALLBACK(notifyLoadStatusCb), uriEntry);
+ g_signal_connect(webView, "notify::progress", G_CALLBACK(notifyProgressCb), window);
+ g_signal_connect(webView, "hovering-over-link", G_CALLBACK(linkHoverCb), statusbar);
+ g_signal_connect(webView, "create-web-view", G_CALLBACK(createWebViewCb), window);
+ g_signal_connect(webView, "web-view-ready", G_CALLBACK(webViewReadyCb), window);
+ g_signal_connect(webView, "close-web-view", G_CALLBACK(closeWebViewCb), window);
+
+ return scrolledWindow;
+}
+
+static GtkWidget* createStatusbar()
+{
+ GtkStatusbar *statusbar = GTK_STATUSBAR(gtk_statusbar_new());
+ guint statusContextId = gtk_statusbar_get_context_id(statusbar, "Link Hover");
+ g_object_set_data(G_OBJECT(statusbar), "link-hover-context",
+ GUINT_TO_POINTER(statusContextId));
+
+ return GTK_WIDGET(statusbar);
+}
+
+static GtkWidget* createToolbar(GtkWidget* uriEntry, WebKitWebView* webView)
+{
+ GtkWidget *toolbar = gtk_toolbar_new();
+
+#if GTK_CHECK_VERSION(2, 15, 0)
+ gtk_orientable_set_orientation(GTK_ORIENTABLE(toolbar), GTK_ORIENTATION_HORIZONTAL);
+#else
+ gtk_toolbar_set_orientation(GTK_TOOLBAR(toolbar), GTK_ORIENTATION_HORIZONTAL);
+#endif
+ gtk_toolbar_set_style(GTK_TOOLBAR(toolbar), GTK_TOOLBAR_BOTH_HORIZ);
+
+ GtkToolItem *item;
+
+ /* the back button */
+ item = gtk_tool_button_new_from_stock(GTK_STOCK_GO_BACK);
+ g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(goBackCb), webView);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+
+ /* The forward button */
+ item = gtk_tool_button_new_from_stock(GTK_STOCK_GO_FORWARD);
+ g_signal_connect(G_OBJECT(item), "clicked", G_CALLBACK(goForwardCb), webView);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+
+ /* The URL entry */
+ item = gtk_tool_item_new();
+ gtk_tool_item_set_expand(item, TRUE);
+ gtk_container_add(GTK_CONTAINER(item), uriEntry);
+ g_signal_connect(G_OBJECT(uriEntry), "activate", G_CALLBACK(activateUriEntryCb), NULL);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+
+ /* The go button */
+ g_object_set_data(G_OBJECT(uriEntry), "web-view", webView);
+ item = gtk_tool_button_new_from_stock(GTK_STOCK_OK);
+ g_signal_connect_swapped(G_OBJECT(item), "clicked", G_CALLBACK(activateUriEntryCb), (gpointer)uriEntry);
+ gtk_toolbar_insert(GTK_TOOLBAR(toolbar), item, -1);
+
+ return toolbar;
+}
+
+static GtkWidget* createWindow(WebKitWebView** outWebView)
+{
+ WebKitWebView *webView;
+ GtkWidget *vbox;
+ GtkWidget *window;
+ GtkWidget *uriEntry;
+ GtkWidget *statusbar;
+
+ g_atomic_int_inc(&windowCount);
+
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_default_size(GTK_WINDOW(window), 800, 600);
+ gtk_widget_set_name(window, "GtkLauncher");
+
+ webView = WEBKIT_WEB_VIEW(webkit_web_view_new());
+ uriEntry = gtk_entry_new();
+
+ vbox = gtk_vbox_new(FALSE, 0);
+ statusbar = createStatusbar(webView);
+ gtk_box_pack_start(GTK_BOX(vbox), createToolbar(uriEntry, webView), FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), createBrowser(window, uriEntry, statusbar, webView), TRUE, TRUE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), statusbar, FALSE, FALSE, 0);
+
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+
+ g_signal_connect(window, "destroy", G_CALLBACK(destroyCb), NULL);
+
+ if (outWebView)
+ *outWebView = webView;
+
+ return window;
+}
+
+static gchar* filenameToURL(const char* filename)
+{
+ if (!g_file_test(filename, G_FILE_TEST_EXISTS))
+ return 0;
+
+ GFile *gfile = g_file_new_for_path(filename);
+ gchar *fileURL = g_file_get_uri(gfile);
+ g_object_unref(gfile);
+
+ return fileURL;
+}
+
+int main(int argc, char* argv[])
+{
+ WebKitWebView *webView;
+ GtkWidget *main_window;
+
+ gtk_init(&argc, &argv);
+ if (!g_thread_supported())
+ g_thread_init(NULL);
+
+ main_window = createWindow(&webView);
+
+ gchar *uri =(gchar*)(argc > 1 ? argv[1] : "http://www.google.com/");
+ gchar *fileURL = filenameToURL(uri);
+
+ webkit_web_view_load_uri(webView, fileURL ? fileURL : uri);
+ g_free(fileURL);
+
+ gtk_widget_grab_focus(GTK_WIDGET(webView));
+ gtk_widget_show_all(main_window);
+ gtk_main();
+
+ return 0;
+}
diff --git a/Tools/GtkLauncher/simple.svg b/Tools/GtkLauncher/simple.svg
new file mode 100644
index 0000000..30b13ac
--- /dev/null
+++ b/Tools/GtkLauncher/simple.svg
@@ -0,0 +1,15 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+"http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg width="5cm" height="4cm"
+xmlns="http://www.w3.org/2000/svg">
+<desc>Four separate rectangles
+</desc>
+<rect x="0.5cm" y="0.5cm" width="2cm" height="1cm"/>
+<rect x="0.5cm" y="2cm" width="1cm" height="1.5cm"/>
+<rect x="3cm" y="0.5cm" width="1.5cm" height="2cm"/>
+<rect x="3.5cm" y="3cm" width="1cm" height="0.5cm"/>
+<!-- Show outline of canvas using 'rect' element -->
+<rect x=".01cm" y=".01cm" width="4.98cm" height="3.98cm"
+fill="none" stroke="blue" stroke-width=".02cm" />
+</svg>
diff --git a/Tools/GtkLauncher/text.html b/Tools/GtkLauncher/text.html
new file mode 100644
index 0000000..607df72
--- /dev/null
+++ b/Tools/GtkLauncher/text.html
@@ -0,0 +1,9 @@
+<html>
+<head>
+<title>Hello World</title>
+<body bgcolor=#00ffff text=#000000>
+<p>
+Hello world
+</p>
+</body>
+</html>
diff --git a/Tools/MIDLWrapper/MIDLWrapper.cpp b/Tools/MIDLWrapper/MIDLWrapper.cpp
new file mode 100644
index 0000000..8cb077a
--- /dev/null
+++ b/Tools/MIDLWrapper/MIDLWrapper.cpp
@@ -0,0 +1,86 @@
+// MIDLWrapper.cpp : Just calls the built-in midl.exe with the given arguments.
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#include <process.h>
+#include <stdio.h>
+#include <string>
+#include <windows.h>
+
+using namespace std;
+
+int wmain(int argc, wchar_t* argv[], wchar_t* envp[])
+{
+#ifndef NDEBUG
+ fwprintf(stderr, L"######### im in ur IDE, compiling ur c0des ########\n");
+#endif
+
+ int pathIndex = -1;
+ for (int i = 0; envp[i]; ++i)
+ if (!wcsncmp(envp[i], L"PATH=", 5)) {
+ pathIndex = i;
+ break;
+ }
+
+ if (pathIndex == -1) {
+ fwprintf(stderr, L"Couldn't find PATH environment variable!\n");
+ return -1;
+ }
+
+ wchar_t* vcbin = wcsstr(envp[pathIndex], L"Tools\\vcbin");
+ if (!vcbin) {
+ fwprintf(stderr, L"Couldn't find Tools\\vcbin in PATH!\n");
+ return -1;
+ }
+
+ wchar_t saved = *vcbin;
+ *vcbin = 0;
+
+ wchar_t* afterLeadingSemiColon = wcsrchr(envp[pathIndex], ';');
+ if (!afterLeadingSemiColon)
+ afterLeadingSemiColon = envp[pathIndex] + 5; // +5 for the length of "PATH="
+ else
+ afterLeadingSemiColon++;
+
+ *vcbin = saved;
+
+ size_t pathLength = wcslen(envp[pathIndex]);
+
+ wchar_t* trailingSemiColon = wcschr(vcbin, ';');
+ if (!trailingSemiColon)
+ trailingSemiColon = envp[pathIndex] + pathLength;
+
+ int vcbinLength = trailingSemiColon - afterLeadingSemiColon;
+
+ size_t newPathLength = pathLength - vcbinLength;
+
+ wchar_t* newPath = new wchar_t[newPathLength + 1];
+
+ // Copy everything before the vcbin path...
+ wchar_t* d = newPath;
+ wchar_t* s = envp[pathIndex];
+ while (s < afterLeadingSemiColon)
+ *d++ = *s++;
+
+ // Copy everything after the vcbin path...
+ s = trailingSemiColon;
+ while (*d++ = *s++);
+
+ envp[pathIndex] = newPath;
+
+#ifndef NDEBUG
+ fwprintf(stderr, L"New path: %s\n", envp[pathIndex]);
+#endif
+
+ wchar_t** newArgv = new wchar_t*[argc + 1];
+ for (int i = 0; i < argc; ++i) {
+ size_t length = wcslen(argv[i]);
+ newArgv[i] = new wchar_t[length + 3];
+ *newArgv[i] = '\"';
+ wcscpy_s(newArgv[i] + 1, length + 2, argv[i]);
+ *(newArgv[i] + 1 + length) = '\"';
+ *(newArgv[i] + 2 + length) = 0;
+ }
+ newArgv[argc] = 0;
+
+ return _wspawnvpe(_P_WAIT, L"midl", newArgv, envp);
+}
diff --git a/Tools/MIDLWrapper/MIDLWrapper.sln b/Tools/MIDLWrapper/MIDLWrapper.sln
new file mode 100644
index 0000000..e0eb2e9
--- /dev/null
+++ b/Tools/MIDLWrapper/MIDLWrapper.sln
@@ -0,0 +1,20 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "MIDLWrapper", "MIDLWrapper.vcproj", "{CBE6BA0B-1A76-4936-BF54-7EB84E1B0F21}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {CBE6BA0B-1A76-4936-BF54-7EB84E1B0F21}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CBE6BA0B-1A76-4936-BF54-7EB84E1B0F21}.Debug|Win32.Build.0 = Debug|Win32
+ {CBE6BA0B-1A76-4936-BF54-7EB84E1B0F21}.Release|Win32.ActiveCfg = Release|Win32
+ {CBE6BA0B-1A76-4936-BF54-7EB84E1B0F21}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Tools/MIDLWrapper/MIDLWrapper.vcproj b/Tools/MIDLWrapper/MIDLWrapper.vcproj
new file mode 100644
index 0000000..d9ab9f9
--- /dev/null
+++ b/Tools/MIDLWrapper/MIDLWrapper.vcproj
@@ -0,0 +1,199 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="MIDLWrapper"
+ ProjectGUID="{CBE6BA0B-1A76-4936-BF54-7EB84E1B0F21}"
+ RootNamespace="MIDLWrapper"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="..\vcbin"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE"
+ MinimalRebuild="true"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="4"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)\midl.exe"
+ LinkIncremental="2"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ TargetMachine="1"
+ />
+ <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"
+ OutputDirectory="..\vcbin"
+ IntermediateDirectory="$(ConfigurationName)"
+ ConfigurationType="1"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE"
+ RuntimeLibrary="2"
+ UsePrecompiledHeader="0"
+ WarningLevel="3"
+ Detect64BitPortabilityProblems="true"
+ DebugInformationFormat="3"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ OutputFile="$(OutDir)\midl.exe"
+ LinkIncremental="1"
+ GenerateDebugInformation="true"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"
+ />
+ <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="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\MIDLWrapper.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/Makefile b/Tools/Makefile
new file mode 100644
index 0000000..51ac703
--- /dev/null
+++ b/Tools/Makefile
@@ -0,0 +1,17 @@
+MODULES = DumpRenderTree WebKitTestRunner MiniBrowser TestWebKitAPI
+
+all:
+ @for dir in $(MODULES); do ${MAKE} $@ -C $$dir; exit_status=$$?; \
+ if [ $$exit_status -ne 0 ]; then exit $$exit_status; fi; done
+
+debug d development dev develop:
+ @for dir in $(MODULES); do ${MAKE} $@ -C $$dir; exit_status=$$?; \
+ if [ $$exit_status -ne 0 ]; then exit $$exit_status; fi; done
+
+release r deployment dep deploy:
+ @for dir in $(MODULES); do ${MAKE} $@ -C $$dir; exit_status=$$?; \
+ if [ $$exit_status -ne 0 ]; then exit $$exit_status; fi; done
+
+clean:
+ @for dir in $(MODULES); do ${MAKE} $@ -C $$dir; exit_status=$$?; \
+ if [ $$exit_status -ne 0 ]; then exit $$exit_status; fi; done
diff --git a/Tools/MiniBrowser/Configurations/Base.xcconfig b/Tools/MiniBrowser/Configurations/Base.xcconfig
new file mode 100644
index 0000000..abe65dd
--- /dev/null
+++ b/Tools/MiniBrowser/Configurations/Base.xcconfig
@@ -0,0 +1,66 @@
+// 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.
+
+DEBUG_INFORMATION_FORMAT = dwarf
+PREBINDING = NO
+GCC_C_LANGUAGE_STANDARD = gnu99
+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;
+VALID_ARCHS = i386 x86_64;
+
+
+TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR);
+
+
+// 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_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+TARGET_GCC_VERSION_ = $(TARGET_GCC_VERSION_1040);
+TARGET_GCC_VERSION_1040 = GCC_40;
+TARGET_GCC_VERSION_1050 = $(TARGET_GCC_VERSION_1050_$(XCODE_VERSION_MINOR));
+TARGET_GCC_VERSION_1050_ = $(TARGET_GCC_VERSION_1050_$(XCODE_VERSION_ACTUAL));
+TARGET_GCC_VERSION_1050_0310 = GCC_42;
+TARGET_GCC_VERSION_1050_0320 = GCC_42;
+TARGET_GCC_VERSION_1060 = GCC_42;
+TARGET_GCC_VERSION_1070 = LLVM_GCC_42;
+
+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;
+
+// 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_1050_1040 = macosx10.4;
+SDKROOT_1060_1040 = macosx10.4;
+SDKROOT_1060_1050 = macosx10.5;
+SDKROOT_1070_1040 = macosx10.4;
+SDKROOT_1070_1050 = macosx10.5;
+SDKROOT_1070_1060 = macosx10.6;
diff --git a/Tools/MiniBrowser/Configurations/DebugRelease.xcconfig b/Tools/MiniBrowser/Configurations/DebugRelease.xcconfig
new file mode 100644
index 0000000..8b156e8
--- /dev/null
+++ b/Tools/MiniBrowser/Configurations/DebugRelease.xcconfig
@@ -0,0 +1,40 @@
+// 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 "Base.xcconfig"
+
+ARCHS = $(ARCHS_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+ARCHS_ = $(ARCHS_1040);
+ARCHS_1040 = $(NATIVE_ARCH);
+ARCHS_1050 = $(NATIVE_ARCH);
+ARCHS_1060 = $(ARCHS_STANDARD_32_64_BIT);
+ARCHS_1070 = $(ARCHS_STANDARD_32_64_BIT);
+
+ONLY_ACTIVE_ARCH = YES;
+
+MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(TARGET_MAC_OS_X_VERSION_MAJOR))
+MACOSX_DEPLOYMENT_TARGET_ = 10.4;
+MACOSX_DEPLOYMENT_TARGET_1040 = 10.4;
+MACOSX_DEPLOYMENT_TARGET_1050 = 10.5;
+MACOSX_DEPLOYMENT_TARGET_1060 = 10.6;
+MACOSX_DEPLOYMENT_TARGET_1070 = 10.7;
diff --git a/Tools/MiniBrowser/Configurations/MiniBrowser.xcconfig b/Tools/MiniBrowser/Configurations/MiniBrowser.xcconfig
new file mode 100644
index 0000000..cf5ad84
--- /dev/null
+++ b/Tools/MiniBrowser/Configurations/MiniBrowser.xcconfig
@@ -0,0 +1,26 @@
+// 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.
+
+PRODUCT_NAME = MiniBrowser
+GCC_PREFIX_HEADER = mac/MiniBrowser_Prefix.pch
+INFOPLIST_FILE = mac/Info.plist
diff --git a/Tools/MiniBrowser/Configurations/MiniBrowserCFLite.vsprops b/Tools/MiniBrowser/Configurations/MiniBrowserCFLite.vsprops
new file mode 100644
index 0000000..be2d869
--- /dev/null
+++ b/Tools/MiniBrowser/Configurations/MiniBrowserCFLite.vsprops
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="MiniBrowserCFLite"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="shlwapi.lib WebKit$(WebKitDLLConfigSuffix).lib CFLite$(LibraryConfigSuffix).lib"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/MiniBrowser/Configurations/MiniBrowserCommon.vsprops b/Tools/MiniBrowser/Configurations/MiniBrowserCommon.vsprops
new file mode 100644
index 0000000..f971837
--- /dev/null
+++ b/Tools/MiniBrowser/Configurations/MiniBrowserCommon.vsprops
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="MiniBrowserCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(WebKitOutputDir)\Include&quot;;&quot;$(WebKitLibrariesDir)\Include&quot;"
+ UsePrecompiledHeader="2"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/MiniBrowser/Configurations/MiniBrowserCoreFoundation.vsprops b/Tools/MiniBrowser/Configurations/MiniBrowserCoreFoundation.vsprops
new file mode 100644
index 0000000..6d5105b
--- /dev/null
+++ b/Tools/MiniBrowser/Configurations/MiniBrowserCoreFoundation.vsprops
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="MiniBrowserCoreFoundation"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="shlwapi.lib WebKit$(WebKitDLLConfigSuffix).lib CoreFoundation$(LibraryConfigSuffix).lib CFNetwork$(LibraryConfigSuffix).lib"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/MiniBrowser/Configurations/WebBundle.xcconfig b/Tools/MiniBrowser/Configurations/WebBundle.xcconfig
new file mode 100644
index 0000000..253fdf7
--- /dev/null
+++ b/Tools/MiniBrowser/Configurations/WebBundle.xcconfig
@@ -0,0 +1,26 @@
+// 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.
+
+PRODUCT_NAME = WebBundle
+GCC_PREFIX_HEADER = mac/MiniBrowser_Prefix.pch
+INFOPLIST_FILE = mac/WebBundle/Info.plist
diff --git a/Tools/MiniBrowser/DerivedSources.pro b/Tools/MiniBrowser/DerivedSources.pro
new file mode 100644
index 0000000..3ca89ad
--- /dev/null
+++ b/Tools/MiniBrowser/DerivedSources.pro
@@ -0,0 +1,32 @@
+# DerivedSources - qmake build info
+
+CONFIG -= debug_and_release
+
+TEMPLATE = lib
+TARGET = dummy
+
+QMAKE_EXTRA_TARGETS += generated_files
+
+SRC_ROOT_DIR = $$replace(PWD, "/Tools/MiniBrowser", "")
+
+!exists($$OUTPUT_DIR/Tools/MiniBrowser/qt):system($$QMAKE_MKDIR $$OUTPUT_DIR/Tools/MiniBrowser/qt)
+
+ualist_copier.input = $$SRC_ROOT_DIR/Tools/QtTestBrowser/useragentlist.txt
+ualist_copier.output = $$OUTPUT_DIR/Tools/MiniBrowser/qt/useragentlist.txt
+ualist_copier.tempNames = $$ualist_copier.input $$ualist_copier.output
+ualist_copier.commands = $$QMAKE_COPY $$replace(ualist_copier.tempNames, "/", $$QMAKE_DIR_SEP)
+ualist_copier.depends = $$ualist_copier.input
+generated_files.depends += ualist_copier
+QMAKE_EXTRA_TARGETS += ualist_copier
+
+# We have to copy the resource file to the build directory
+# to use the useragentlist.txt file of QtTestBrowser without
+# polluting the source tree.
+
+qrc_copier.input = $$SRC_ROOT_DIR/Tools/MiniBrowser/MiniBrowser.qrc
+qrc_copier.output = $$OUTPUT_DIR/Tools/MiniBrowser/qt/MiniBrowser.qrc
+qrc_copier.tempNames = $$qrc_copier.input $$qrc_copier.output
+qrc_copier.commands = $$QMAKE_COPY $$replace(qrc_copier.tempNames, "/", $$QMAKE_DIR_SEP)
+qrc_copier.depends = ualist_copier $$qrc_copier.input
+generated_files.depends += qrc_copier
+QMAKE_EXTRA_TARGETS += qrc_copier
diff --git a/Tools/MiniBrowser/MBToolbarItem.h b/Tools/MiniBrowser/MBToolbarItem.h
new file mode 100644
index 0000000..cc5a4b4
--- /dev/null
+++ b/Tools/MiniBrowser/MBToolbarItem.h
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+@interface MBToolbarItem : NSToolbarItem
+{ }
+@end
diff --git a/Tools/MiniBrowser/MBToolbarItem.m b/Tools/MiniBrowser/MBToolbarItem.m
new file mode 100644
index 0000000..56f7778
--- /dev/null
+++ b/Tools/MiniBrowser/MBToolbarItem.m
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+#import "MBToolbarItem.h"
+
+@implementation MBToolbarItem
+
+- (void)validate
+{
+ [self setEnabled:[[self target] validateUserInterfaceItem:self]];
+}
+
+@end
diff --git a/Tools/MiniBrowser/Makefile b/Tools/MiniBrowser/Makefile
new file mode 100644
index 0000000..61cd475
--- /dev/null
+++ b/Tools/MiniBrowser/Makefile
@@ -0,0 +1,21 @@
+# Build MiniBrowser only on SnowLeopard and later.
+
+OSX_VERSION ?= $(shell sw_vers -productVersion | cut -d. -f 2)
+BUILD_MINIBROWSER = $(shell (( $(OSX_VERSION) >= 6 )) && echo "YES" )
+
+ifeq "$(BUILD_MINIBROWSER)" "YES"
+
+SCRIPTS_PATH = ../Scripts
+include ../../Makefile.shared
+
+else
+
+all: ;
+
+debug d development dev develop: ;
+
+release r deployment dep deploy: ;
+
+clean: ;
+
+endif
diff --git a/Tools/MiniBrowser/MiniBrowser.qrc b/Tools/MiniBrowser/MiniBrowser.qrc
new file mode 100644
index 0000000..ffe77b0
--- /dev/null
+++ b/Tools/MiniBrowser/MiniBrowser.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>useragentlist.txt</file>
+ </qresource>
+</RCC>
diff --git a/Tools/MiniBrowser/MiniBrowser.vcproj b/Tools/MiniBrowser/MiniBrowser.vcproj
new file mode 100644
index 0000000..3d94dbc
--- /dev/null
+++ b/Tools/MiniBrowser/MiniBrowser.vcproj
@@ -0,0 +1,508 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="MiniBrowser"
+ ProjectGUID="{1480CF5F-4160-47B5-A0E6-96AEC8258FB5}"
+ RootNamespace="MiniBrowser"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\Configurations\MiniBrowserCoreFoundation.vsprops;.\Configurations\MiniBrowserCommon.vsprops"
+ UseOfATL="1"
+ 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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\Configurations\MiniBrowserCoreFoundation.vsprops;.\Configurations\MiniBrowserCommon.vsprops"
+ UseOfATL="1"
+ 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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\Configurations\MiniBrowserCoreFoundation.vsprops;.\Configurations\MiniBrowserCommon.vsprops"
+ UseOfATL="1"
+ 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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;.\Configurations\MiniBrowserCFLite.vsprops;.\Configurations\MiniBrowserCommon.vsprops"
+ UseOfATL="1"
+ 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="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;.\Configurations\MiniBrowserCFLite.vsprops;.\Configurations\MiniBrowserCommon.vsprops"
+ UseOfATL="1"
+ 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_LTCG|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\Configurations\MiniBrowserCoreFoundation.vsprops;.\Configurations\MiniBrowserCommon.vsprops"
+ UseOfATL="1"
+ 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="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\win\BrowserView.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\win\BrowserWindow.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\win\main.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\win\MiniBrowser.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\win\stdafx.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_LTCG|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\win\BrowserView.h"
+ >
+ </File>
+ <File
+ RelativePath=".\win\BrowserWindow.h"
+ >
+ </File>
+ <File
+ RelativePath=".\win\MiniBrowser.h"
+ >
+ </File>
+ <File
+ RelativePath=".\win\Resource.h"
+ >
+ </File>
+ <File
+ RelativePath=".\win\stdafx.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\win\MiniBrowser.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj b/Tools/MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..1a7ccbb
--- /dev/null
+++ b/Tools/MiniBrowser/MiniBrowser.xcodeproj/project.pbxproj
@@ -0,0 +1,421 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 256AC3DA0F4B6AC300CF3369 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 256AC3D90F4B6AC300CF3369 /* AppDelegate.m */; };
+ 51E244FA11EFCE07008228D1 /* MBToolbarItem.m in Sources */ = {isa = PBXBuildFile; fileRef = 51E244F911EFCE07008228D1 /* MBToolbarItem.m */; };
+ 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
+ BC20545E11C96C92008F3375 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
+ BC329487116A92E2008635D0 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = BC329486116A92E2008635D0 /* main.m */; };
+ BC329498116A941B008635D0 /* BrowserWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = BC329497116A941B008635D0 /* BrowserWindowController.m */; };
+ BC72B89511E57E07001EB4EA /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58150DA1D0A300B32029 /* MainMenu.xib */; };
+ BC72B89611E57E0F001EB4EA /* BrowserWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = BC3294A2116A9852008635D0 /* BrowserWindow.xib */; };
+ BC8FB5A8116AA1FE0080D413 /* WebKit2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC8FB5A7116AA1FE0080D413 /* WebKit2.framework */; };
+ BCBD384011B08A6800E01E54 /* WebBundleMain.m in Sources */ = {isa = PBXBuildFile; fileRef = BCBD383D11B08A3100E01E54 /* WebBundleMain.m */; };
+ BCBD384411B08AAD00E01E54 /* WebKit2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC8FB5A7116AA1FE0080D413 /* WebKit2.framework */; };
+ BCBD38D011B08C0200E01E54 /* WebBundle.bundle in Copy WebBundle */ = {isa = PBXBuildFile; fileRef = BCBD381D11B0898200E01E54 /* WebBundle.bundle */; };
+ BCE625EE117FC80E00572433 /* BrowserStatisticsWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = BCE625ED117FC80E00572433 /* BrowserStatisticsWindow.xib */; };
+ BCE625F1117FC82700572433 /* BrowserStatisticsWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = BCE625F0117FC82700572433 /* BrowserStatisticsWindowController.m */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ BCBD38C511B08BA400E01E54 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BCBD381C11B0898200E01E54;
+ remoteInfo = WebBundle;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ BCBD38CF11B08C0100E01E54 /* Copy WebBundle */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = Contents;
+ dstSubfolderSpec = 1;
+ files = (
+ BCBD38D011B08C0200E01E54 /* WebBundle.bundle in Copy WebBundle */,
+ );
+ name = "Copy WebBundle";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+ 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = "<absolute>"; };
+ 1DDD58150DA1D0A300B32029 /* MainMenu.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = MainMenu.xib; path = mac/MainMenu.xib; sourceTree = "<group>"; };
+ 256AC3D80F4B6AC300CF3369 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = mac/AppDelegate.h; sourceTree = "<group>"; };
+ 256AC3D90F4B6AC300CF3369 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = mac/AppDelegate.m; sourceTree = "<group>"; };
+ 256AC3F00F4B6AF500CF3369 /* MiniBrowser_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = MiniBrowser_Prefix.pch; path = mac/MiniBrowser_Prefix.pch; sourceTree = "<group>"; };
+ 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = "<absolute>"; };
+ 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = "<absolute>"; };
+ 51E244F811EFCE07008228D1 /* MBToolbarItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MBToolbarItem.h; sourceTree = "<group>"; };
+ 51E244F911EFCE07008228D1 /* MBToolbarItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MBToolbarItem.m; sourceTree = "<group>"; };
+ 8D1107320486CEB800E47090 /* MiniBrowser.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MiniBrowser.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC1770121188DF19007D9E9A /* make-launchable.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; name = "make-launchable.sh"; path = "mac/make-launchable.sh"; sourceTree = "<group>"; };
+ BC329486116A92E2008635D0 /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = main.m; path = mac/main.m; sourceTree = "<group>"; };
+ BC329496116A941B008635D0 /* BrowserWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BrowserWindowController.h; path = mac/BrowserWindowController.h; sourceTree = "<group>"; };
+ BC329497116A941B008635D0 /* BrowserWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BrowserWindowController.m; path = mac/BrowserWindowController.m; sourceTree = "<group>"; };
+ BC3294A2116A9852008635D0 /* BrowserWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = BrowserWindow.xib; path = mac/BrowserWindow.xib; sourceTree = "<group>"; };
+ BC72B89711E57E6E001EB4EA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+ BC72B89A11E57E8A001EB4EA /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = mac/Info.plist; sourceTree = "<group>"; };
+ BC8FB5A7116AA1FE0080D413 /* WebKit2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = WebKit2.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ BCA8CBDD11E578A000812FB7 /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; };
+ BCA8CBDE11E578A000812FB7 /* DebugRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugRelease.xcconfig; sourceTree = "<group>"; };
+ BCA8CBDF11E578A000812FB7 /* MiniBrowser.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = MiniBrowser.xcconfig; sourceTree = "<group>"; };
+ BCA8CBE011E578A000812FB7 /* WebBundle.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = WebBundle.xcconfig; sourceTree = "<group>"; };
+ BCBD381D11B0898200E01E54 /* WebBundle.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WebBundle.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+ BCBD383D11B08A3100E01E54 /* WebBundleMain.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebBundleMain.m; sourceTree = "<group>"; };
+ BCE625ED117FC80E00572433 /* BrowserStatisticsWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = BrowserStatisticsWindow.xib; path = mac/BrowserStatisticsWindow.xib; sourceTree = "<group>"; };
+ BCE625EF117FC82700572433 /* BrowserStatisticsWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BrowserStatisticsWindowController.h; path = mac/BrowserStatisticsWindowController.h; sourceTree = "<group>"; };
+ BCE625F0117FC82700572433 /* BrowserStatisticsWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BrowserStatisticsWindowController.m; path = mac/BrowserStatisticsWindowController.m; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8D11072E0486CEB800E47090 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
+ BC8FB5A8116AA1FE0080D413 /* WebKit2.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BCBD381B11B0898200E01E54 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BC20545E11C96C92008F3375 /* Cocoa.framework in Frameworks */,
+ BCBD384411B08AAD00E01E54 /* WebKit2.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 080E96DDFE201D6D7F000001 /* MiniBrowser */ = {
+ isa = PBXGroup;
+ children = (
+ BC72B89A11E57E8A001EB4EA /* Info.plist */,
+ BC329486116A92E2008635D0 /* main.m */,
+ 256AC3D80F4B6AC300CF3369 /* AppDelegate.h */,
+ 256AC3D90F4B6AC300CF3369 /* AppDelegate.m */,
+ BC329496116A941B008635D0 /* BrowserWindowController.h */,
+ BC329497116A941B008635D0 /* BrowserWindowController.m */,
+ BCE625EF117FC82700572433 /* BrowserStatisticsWindowController.h */,
+ BCE625F0117FC82700572433 /* BrowserStatisticsWindowController.m */,
+ 51E244F811EFCE07008228D1 /* MBToolbarItem.h */,
+ 51E244F911EFCE07008228D1 /* MBToolbarItem.m */,
+ );
+ name = MiniBrowser;
+ sourceTree = "<group>";
+ };
+ 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
+ BC8FB5A7116AA1FE0080D413 /* WebKit2.framework */,
+ );
+ name = "Linked Frameworks";
+ sourceTree = "<group>";
+ };
+ 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 29B97324FDCFA39411CA2CEA /* AppKit.framework */,
+ 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */,
+ 29B97325FDCFA39411CA2CEA /* Foundation.framework */,
+ );
+ name = "Other Frameworks";
+ sourceTree = "<group>";
+ };
+ 19C28FACFE9D520D11CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8D1107320486CEB800E47090 /* MiniBrowser.app */,
+ BCBD381D11B0898200E01E54 /* WebBundle.bundle */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 29B97314FDCFA39411CA2CEA /* MiniBrowser */ = {
+ isa = PBXGroup;
+ children = (
+ 256AC3F00F4B6AF500CF3369 /* MiniBrowser_Prefix.pch */,
+ 080E96DDFE201D6D7F000001 /* MiniBrowser */,
+ BCBD382B11B089F700E01E54 /* WebBundle */,
+ 29B97317FDCFA39411CA2CEA /* Resources */,
+ BCA8CBDA11E5787800812FB7 /* Configurations */,
+ BC1770481188EB05007D9E9A /* Scripts */,
+ 29B97323FDCFA39411CA2CEA /* Frameworks */,
+ 19C28FACFE9D520D11CA2CBB /* Products */,
+ );
+ name = MiniBrowser;
+ sourceTree = "<group>";
+ };
+ 29B97317FDCFA39411CA2CEA /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ BC3294A2116A9852008635D0 /* BrowserWindow.xib */,
+ 1DDD58150DA1D0A300B32029 /* MainMenu.xib */,
+ BCE625ED117FC80E00572433 /* BrowserStatisticsWindow.xib */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
+ 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ BC1770481188EB05007D9E9A /* Scripts */ = {
+ isa = PBXGroup;
+ children = (
+ BC1770121188DF19007D9E9A /* make-launchable.sh */,
+ );
+ name = Scripts;
+ sourceTree = "<group>";
+ };
+ BCA8CBDA11E5787800812FB7 /* Configurations */ = {
+ isa = PBXGroup;
+ children = (
+ BCA8CBDD11E578A000812FB7 /* Base.xcconfig */,
+ BCA8CBDE11E578A000812FB7 /* DebugRelease.xcconfig */,
+ BCA8CBDF11E578A000812FB7 /* MiniBrowser.xcconfig */,
+ BCA8CBE011E578A000812FB7 /* WebBundle.xcconfig */,
+ );
+ path = Configurations;
+ sourceTree = "<group>";
+ };
+ BCBD382B11B089F700E01E54 /* WebBundle */ = {
+ isa = PBXGroup;
+ children = (
+ BC72B89711E57E6E001EB4EA /* Info.plist */,
+ BCBD383D11B08A3100E01E54 /* WebBundleMain.m */,
+ );
+ name = WebBundle;
+ path = mac/WebBundle;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 8D1107260486CEB800E47090 /* MiniBrowser */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "MiniBrowser" */;
+ buildPhases = (
+ 8D1107290486CEB800E47090 /* Resources */,
+ BCBD38CF11B08C0100E01E54 /* Copy WebBundle */,
+ 8D11072C0486CEB800E47090 /* Sources */,
+ 8D11072E0486CEB800E47090 /* Frameworks */,
+ BC17701E1188DFB4007D9E9A /* Make Launchable */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ BCBD38C611B08BA400E01E54 /* PBXTargetDependency */,
+ );
+ name = MiniBrowser;
+ productInstallPath = "$(HOME)/Applications";
+ productName = MiniBrowser;
+ productReference = 8D1107320486CEB800E47090 /* MiniBrowser.app */;
+ productType = "com.apple.product-type.application";
+ };
+ BCBD381C11B0898200E01E54 /* WebBundle */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BCBD382111B0898300E01E54 /* Build configuration list for PBXNativeTarget "WebBundle" */;
+ buildPhases = (
+ BCBD381911B0898200E01E54 /* Resources */,
+ BCBD381A11B0898200E01E54 /* Sources */,
+ BCBD381B11B0898200E01E54 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = WebBundle;
+ productName = WebBundle;
+ productReference = BCBD381D11B0898200E01E54 /* WebBundle.bundle */;
+ productType = "com.apple.product-type.bundle";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 29B97313FDCFA39411CA2CEA /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "MiniBrowser" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 29B97314FDCFA39411CA2CEA /* MiniBrowser */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8D1107260486CEB800E47090 /* MiniBrowser */,
+ BCBD381C11B0898200E01E54 /* WebBundle */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8D1107290486CEB800E47090 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BC72B89511E57E07001EB4EA /* MainMenu.xib in Resources */,
+ BC72B89611E57E0F001EB4EA /* BrowserWindow.xib in Resources */,
+ BCE625EE117FC80E00572433 /* BrowserStatisticsWindow.xib in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BCBD381911B0898200E01E54 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ BC17701E1188DFB4007D9E9A /* Make Launchable */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Make Launchable";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "mac/make-launchable.sh\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8D11072C0486CEB800E47090 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 256AC3DA0F4B6AC300CF3369 /* AppDelegate.m in Sources */,
+ BC329487116A92E2008635D0 /* main.m in Sources */,
+ BC329498116A941B008635D0 /* BrowserWindowController.m in Sources */,
+ BCE625F1117FC82700572433 /* BrowserStatisticsWindowController.m in Sources */,
+ 51E244FA11EFCE07008228D1 /* MBToolbarItem.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BCBD381A11B0898200E01E54 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BCBD384011B08A6800E01E54 /* WebBundleMain.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ BCBD38C611B08BA400E01E54 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BCBD381C11B0898200E01E54 /* WebBundle */;
+ targetProxy = BCBD38C511B08BA400E01E54 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ BCBD381F11B0898300E01E54 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCA8CBE011E578A000812FB7 /* WebBundle.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ BCBD382011B0898300E01E54 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCA8CBE011E578A000812FB7 /* WebBundle.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ C01FCF4B08A954540054247B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCA8CBDF11E578A000812FB7 /* MiniBrowser.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ C01FCF4C08A954540054247B /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCA8CBDF11E578A000812FB7 /* MiniBrowser.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ C01FCF4F08A954540054247B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCA8CBDE11E578A000812FB7 /* DebugRelease.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ C01FCF5008A954540054247B /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BCA8CBDE11E578A000812FB7 /* DebugRelease.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ BCBD382111B0898300E01E54 /* Build configuration list for PBXNativeTarget "WebBundle" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BCBD381F11B0898300E01E54 /* Debug */,
+ BCBD382011B0898300E01E54 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "MiniBrowser" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C01FCF4B08A954540054247B /* Debug */,
+ C01FCF4C08A954540054247B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C01FCF4E08A954540054247B /* Build configuration list for PBXProject "MiniBrowser" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C01FCF4F08A954540054247B /* Debug */,
+ C01FCF5008A954540054247B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
+}
diff --git a/Tools/MiniBrowser/MiniBrowserPostBuild.cmd b/Tools/MiniBrowser/MiniBrowserPostBuild.cmd
new file mode 100644
index 0000000..5445453
--- /dev/null
+++ b/Tools/MiniBrowser/MiniBrowserPostBuild.cmd
@@ -0,0 +1,33 @@
+mkdir 2>NUL "%WEBKITOUTPUTDIR%\bin"
+
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFNetwork%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFNetwork%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CFNetwork.resources" "%WEBKITOUTPUTDIR%\bin\CFNetwork.resources"
+xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CoreFoundation.resources" "%WEBKITOUTPUTDIR%\bin\CoreFoundation.resources"
+xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CharacterSets" "%WEBKITOUTPUTDIR%\bin\CharacterSets"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreGraphics%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreGraphics%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\dnssd.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt40.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt40%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxml2%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxslt%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\objc%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\objc%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+
+if exist "%WEBKITLIBRARIESDIR%\bin\QuartzCore%LIBRARYCONFIGSUFFIX%.dll" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\QuartzCore%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\QuartzCore%LIBRARYCONFIGSUFFIX%.pdb" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\QuartzCore%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+
+if exist "%WEBKITOUTPUTDIR%\buildfailed" del "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/MiniBrowser/MiniBrowserPreBuild.cmd b/Tools/MiniBrowser/MiniBrowserPreBuild.cmd
new file mode 100644
index 0000000..ff212e4
--- /dev/null
+++ b/Tools/MiniBrowser/MiniBrowserPreBuild.cmd
@@ -0,0 +1,5 @@
+set PATH=%SystemDrive%\cygwin\bin;%PATH%
+
+if exist "%WEBKITOUTPUTDIR%\buildfailed" grep XX%PROJECTNAME%XX "%WEBKITOUTPUTDIR%\buildfailed"
+if errorlevel 1 exit 1
+echo XX%PROJECTNAME%XX > "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/MiniBrowser/mac/AppDelegate.h b/Tools/MiniBrowser/mac/AppDelegate.h
new file mode 100644
index 0000000..bf79656
--- /dev/null
+++ b/Tools/MiniBrowser/mac/AppDelegate.h
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+enum ProcessModel {
+ kProcessModelSharedSecondaryThread,
+ kProcessModelSharedSecondaryProcess
+};
+typedef unsigned long ProcessModel;
+
+@interface BrowserAppDelegate : NSObject <NSApplicationDelegate> {
+ ProcessModel _currentProcessModel;
+ WKContextRef _threadContext;
+ WKContextRef _processContext;
+}
+
+- (WKContextRef)getCurrentContext;
+
+- (IBAction)setSharedProcessProcessModel:(id)sender;
+- (IBAction)setSharedThreadProcessModel:(id)sender;
+- (IBAction)showStatisticsWindow:(id)sender;
+
+@end
diff --git a/Tools/MiniBrowser/mac/AppDelegate.m b/Tools/MiniBrowser/mac/AppDelegate.m
new file mode 100644
index 0000000..a02193b
--- /dev/null
+++ b/Tools/MiniBrowser/mac/AppDelegate.m
@@ -0,0 +1,266 @@
+/*
+ * 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.
+ */
+
+#import "AppDelegate.h"
+
+#import "BrowserWindowController.h"
+#import "BrowserStatisticsWindowController.h"
+
+#import <WebKit2/WKContextPrivate.h>
+#import <WebKit2/WKStringCF.h>
+#import <WebKit2/WKURLCF.h>
+
+static NSString *defaultURL = @"http://www.webkit.org/";
+
+@implementation BrowserAppDelegate
+
+void didRecieveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void *clientInfo)
+{
+ CFStringRef cfMessageName = WKStringCopyCFString(0, messageName);
+
+ WKTypeID typeID = WKGetTypeID(messageBody);
+ if (typeID == WKStringGetTypeID()) {
+ CFStringRef cfMessageBody = WKStringCopyCFString(0, (WKStringRef)messageBody);
+ LOG(@"ContextInjectedBundleClient - didRecieveMessage - MessageName: %@ MessageBody %@", cfMessageName, cfMessageBody);
+ CFRelease(cfMessageBody);
+ } else {
+ LOG(@"ContextInjectedBundleClient - didRecieveMessage - MessageName: %@ (MessageBody Unhandeled)\n", cfMessageName);
+ }
+
+ CFRelease(cfMessageName);
+
+ WKStringRef newMessageName = WKStringCreateWithCFString(CFSTR("Response"));
+ WKStringRef newMessageBody = WKStringCreateWithCFString(CFSTR("Roger that!"));
+
+ WKContextPostMessageToInjectedBundle(context, newMessageName, newMessageBody);
+
+ WKRelease(newMessageName);
+ WKRelease(newMessageBody);
+}
+
+#pragma mark History Client Callbacks
+
+static void didNavigateWithNavigationData(WKContextRef context, WKPageRef page, WKNavigationDataRef navigationData, WKFrameRef frame, const void *clientInfo)
+{
+ WKStringRef wkTitle = WKNavigationDataCopyTitle(navigationData);
+ CFStringRef title = WKStringCopyCFString(0, wkTitle);
+ WKRelease(wkTitle);
+
+ WKURLRef wkURL = WKNavigationDataCopyURL(navigationData);
+ CFURLRef url = WKURLCopyCFURL(0, wkURL);
+ WKRelease(wkURL);
+
+ LOG(@"HistoryClient - didNavigateWithNavigationData - title: %@ - url: %@", title, url);
+ CFRelease(title);
+ CFRelease(url);
+}
+
+static void didPerformClientRedirect(WKContextRef context, WKPageRef page, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void *clientInfo)
+{
+ CFURLRef cfSourceURL = WKURLCopyCFURL(0, sourceURL);
+ CFURLRef cfDestinationURL = WKURLCopyCFURL(0, destinationURL);
+ LOG(@"HistoryClient - didPerformClientRedirect - sourceURL: %@ - destinationURL: %@", cfSourceURL, cfDestinationURL);
+ CFRelease(cfSourceURL);
+ CFRelease(cfDestinationURL);
+}
+
+static void didPerformServerRedirect(WKContextRef context, WKPageRef page, WKURLRef sourceURL, WKURLRef destinationURL, WKFrameRef frame, const void *clientInfo)
+{
+ CFURLRef cfSourceURL = WKURLCopyCFURL(0, sourceURL);
+ CFURLRef cfDestinationURL = WKURLCopyCFURL(0, destinationURL);
+ LOG(@"HistoryClient - didPerformServerRedirect - sourceURL: %@ - destinationURL: %@", cfSourceURL, cfDestinationURL);
+ CFRelease(cfSourceURL);
+ CFRelease(cfDestinationURL);
+}
+
+static void didUpdateHistoryTitle(WKContextRef context, WKPageRef page, WKStringRef title, WKURLRef URL, WKFrameRef frame, const void *clientInfo)
+{
+ CFStringRef cfTitle = WKStringCopyCFString(0, title);
+ CFURLRef cfURL = WKURLCopyCFURL(0, URL);
+ LOG(@"HistoryClient - didUpdateHistoryTitle - title: %@ - URL: %@", cfTitle, cfURL);
+ CFRelease(cfTitle);
+ CFRelease(cfURL);
+}
+
+static void populateVisitedLinks(WKContextRef context, const void *clientInfo)
+{
+ LOG(@"HistoryClient - populateVisitedLinks");
+}
+
+- (id)init
+{
+ self = [super init];
+ if (self) {
+ if ([NSEvent modifierFlags] & NSShiftKeyMask)
+ _currentProcessModel = kProcessModelSharedSecondaryThread;
+ else
+ _currentProcessModel = kProcessModelSharedSecondaryProcess;
+
+ WKContextHistoryClient historyClient = {
+ 0,
+ self,
+ didNavigateWithNavigationData,
+ didPerformClientRedirect,
+ didPerformServerRedirect,
+ didUpdateHistoryTitle,
+ populateVisitedLinks
+ };
+
+ _threadContext = WKContextGetSharedThreadContext();
+ WKContextSetHistoryClient(_threadContext, &historyClient);
+ WKContextSetCacheModel(_threadContext, kWKCacheModelPrimaryWebBrowser);
+
+ CFStringRef bundlePathCF = (CFStringRef)[[NSBundle mainBundle] pathForAuxiliaryExecutable:@"WebBundle.bundle"];
+ WKStringRef bundlePath = WKStringCreateWithCFString(bundlePathCF);
+
+ _processContext = WKContextCreateWithInjectedBundlePath(bundlePath);
+
+ WKContextInjectedBundleClient bundleClient = {
+ 0, /* version */
+ 0, /* clientInfo */
+ didRecieveMessageFromInjectedBundle,
+ 0
+ };
+ WKContextSetInjectedBundleClient(_processContext, &bundleClient);
+ WKContextSetHistoryClient(_processContext, &historyClient);
+ WKContextSetCacheModel(_processContext, kWKCacheModelPrimaryWebBrowser);
+
+ WKRelease(bundlePath);
+ }
+
+ return self;
+}
+
+- (IBAction)newWindow:(id)sender
+{
+ BrowserWindowController *controller = [[BrowserWindowController alloc] initWithContext:[self getCurrentContext]];
+ [[controller window] makeKeyAndOrderFront:sender];
+
+ [controller loadURLString:defaultURL];
+}
+
+- (WKContextRef)getCurrentContext
+{
+ return (_currentProcessModel == kProcessModelSharedSecondaryThread) ? _threadContext : _processContext;
+}
+
+- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
+{
+ if ([menuItem action] == @selector(setSharedProcessProcessModel:))
+ [menuItem setState:_currentProcessModel == kProcessModelSharedSecondaryProcess ? NSOnState : NSOffState];
+ else if ([menuItem action] == @selector(setSharedThreadProcessModel:))
+ [menuItem setState:_currentProcessModel == kProcessModelSharedSecondaryThread ? NSOnState : NSOffState];
+ return YES;
+}
+
+- (void)_setProcessModel:(ProcessModel)processModel
+{
+ if (processModel == _currentProcessModel)
+ return;
+
+ _currentProcessModel = processModel;
+}
+
+- (IBAction)setSharedProcessProcessModel:(id)sender
+{
+ [self _setProcessModel:kProcessModelSharedSecondaryProcess];
+}
+
+- (IBAction)setSharedThreadProcessModel:(id)sender
+{
+ [self _setProcessModel:kProcessModelSharedSecondaryThread];
+}
+
+- (IBAction)showStatisticsWindow:(id)sender
+{
+ static BrowserStatisticsWindowController* windowController;
+ if (!windowController)
+ windowController = [[BrowserStatisticsWindowController alloc] initWithThreadedWKContextRef:_threadContext
+ processWKContextRef:_processContext];
+
+ [[windowController window] makeKeyAndOrderFront:self];
+}
+
+- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
+{
+ [self newWindow:self];
+}
+
+- (void)applicationWillTerminate:(NSNotification *)notification
+{
+ NSArray* windows = [NSApp windows];
+ for (NSWindow* window in windows) {
+ id delegate = [window delegate];
+ if ([delegate isKindOfClass:[BrowserWindowController class]]) {
+ BrowserWindowController *controller = (BrowserWindowController *)delegate;
+ [controller applicationTerminating];
+ }
+ }
+
+ WKRelease(_processContext);
+ _processContext = 0;
+}
+
+- (BrowserWindowController *)frontmostBrowserWindowController
+{
+ NSArray* windows = [NSApp windows];
+ for (NSWindow* window in windows) {
+ id delegate = [window delegate];
+ if ([delegate isKindOfClass:[BrowserWindowController class]])
+ return (BrowserWindowController *)delegate;
+ }
+
+ return 0;
+}
+
+- (IBAction)openDocument:(id)sender
+{
+ NSOpenPanel *openPanel = [[NSOpenPanel openPanel] retain];
+ [openPanel beginForDirectory:nil
+ file:nil
+ types:nil
+ modelessDelegate:self
+ didEndSelector:@selector(openPanelDidEnd:returnCode:contextInfo:)
+ contextInfo:0];
+}
+
+- (void)openPanelDidEnd:(NSOpenPanel *)sheet returnCode:(int)returnCode contextInfo:(void *)contextInfo
+{
+ [sheet autorelease];
+ if (returnCode != NSOKButton || ![[sheet filenames] count])
+ return;
+
+ NSString* filePath = [[sheet filenames] objectAtIndex:0];
+
+ BrowserWindowController *controller = [self frontmostBrowserWindowController];
+ if (!controller) {
+ controller = [[BrowserWindowController alloc] initWithContext:[self getCurrentContext]];
+ [[controller window] makeKeyAndOrderFront:self];
+ }
+
+ [controller loadURLString:[[NSURL fileURLWithPath:filePath] absoluteString]];
+}
+
+@end
diff --git a/Tools/MiniBrowser/mac/BrowserStatisticsWindow.xib b/Tools/MiniBrowser/mac/BrowserStatisticsWindow.xib
new file mode 100644
index 0000000..ae2b5f8
--- /dev/null
+++ b/Tools/MiniBrowser/mac/BrowserStatisticsWindow.xib
@@ -0,0 +1,974 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
+ <data>
+ <int key="IBDocument.SystemTarget">1060</int>
+ <string key="IBDocument.SystemVersion">10D573</string>
+ <string key="IBDocument.InterfaceBuilderVersion">762</string>
+ <string key="IBDocument.AppKitVersion">1038.29</string>
+ <string key="IBDocument.HIToolboxVersion">460.00</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="NS.object.0">762</string>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="2"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys" id="0">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSCustomObject" id="1001">
+ <string key="NSClassName">BrowserStatisticsWindowController</string>
+ </object>
+ <object class="NSCustomObject" id="1003">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="1004">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSWindowTemplate" id="1005">
+ <int key="NSWindowStyleMask">15</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{196, 352}, {398, 158}}</string>
+ <int key="NSWTFlags">544735232</int>
+ <string key="NSWindowTitle">Window</string>
+ <string key="NSWindowClass">NSWindow</string>
+ <nil key="NSViewClass"/>
+ <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
+ <object class="NSView" key="NSWindowView" id="1006">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSBox" id="349928848">
+ <reference key="NSNextResponder" ref="1006"/>
+ <int key="NSvFlags">45</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSView" id="737205069">
+ <reference key="NSNextResponder" ref="349928848"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMatrix" id="840724334">
+ <reference key="NSNextResponder" ref="737205069"/>
+ <int key="NSvFlags">256</int>
+ <string key="NSFrame">{{18, 14}, {318, 42}}</string>
+ <reference key="NSSuperview" ref="737205069"/>
+ <bool key="NSEnabled">YES</bool>
+ <int key="NSNumRows">3</int>
+ <int key="NSNumCols">3</int>
+ <object class="NSMutableArray" key="NSCells">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSTextFieldCell" id="66669903">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">71435264</int>
+ <string key="NSContents"/>
+ <object class="NSFont" key="NSSupport" id="57559">
+ <string key="NSName">LucidaGrande-Bold</string>
+ <double key="NSSize">11</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <reference key="NSControlView" ref="840724334"/>
+ <object class="NSColor" key="NSBackgroundColor" id="159766406">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MC42NjY2NjY2NjY3AA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor" id="822671316">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlTextColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
+ </object>
+ </object>
+ <object class="NSTextFieldCell" id="792638244">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">71435264</int>
+ <string key="NSContents">Shared Process</string>
+ <reference key="NSSupport" ref="57559"/>
+ <reference key="NSControlView" ref="840724334"/>
+ <int key="NSTag">1</int>
+ <reference key="NSBackgroundColor" ref="159766406"/>
+ <reference key="NSTextColor" ref="822671316"/>
+ </object>
+ <object class="NSTextFieldCell" id="220500282">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">71435264</int>
+ <string key="NSContents">Shared Thread</string>
+ <reference key="NSSupport" ref="57559"/>
+ <reference key="NSControlView" ref="840724334"/>
+ <reference key="NSBackgroundColor" ref="159766406"/>
+ <reference key="NSTextColor" ref="822671316"/>
+ </object>
+ <object class="NSTextFieldCell" id="822378002">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">71435264</int>
+ <string key="NSContents">Pages</string>
+ <reference key="NSSupport" ref="57559"/>
+ <reference key="NSControlView" ref="840724334"/>
+ <reference key="NSBackgroundColor" ref="159766406"/>
+ <reference key="NSTextColor" ref="822671316"/>
+ </object>
+ <object class="NSTextFieldCell" id="665973187">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">71435264</int>
+ <string key="NSContents">-100</string>
+ <object class="NSFont" key="NSSupport" id="422232155">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">11</double>
+ <int key="NSfFlags">16</int>
+ </object>
+ <reference key="NSControlView" ref="840724334"/>
+ <int key="NSTag">11</int>
+ <reference key="NSBackgroundColor" ref="159766406"/>
+ <reference key="NSTextColor" ref="822671316"/>
+ </object>
+ <object class="NSTextFieldCell" id="534624797">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">71435264</int>
+ <string key="NSContents">-100</string>
+ <reference key="NSSupport" ref="422232155"/>
+ <reference key="NSControlView" ref="840724334"/>
+ <int key="NSTag">21</int>
+ <reference key="NSBackgroundColor" ref="159766406"/>
+ <reference key="NSTextColor" ref="822671316"/>
+ </object>
+ <object class="NSTextFieldCell" id="576107244">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">71435264</int>
+ <string key="NSContents">Frames</string>
+ <reference key="NSSupport" ref="57559"/>
+ <reference key="NSControlView" ref="840724334"/>
+ <reference key="NSBackgroundColor" ref="159766406"/>
+ <reference key="NSTextColor" ref="822671316"/>
+ </object>
+ <object class="NSTextFieldCell" id="775125133">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">71435264</int>
+ <string key="NSContents">-100</string>
+ <reference key="NSSupport" ref="422232155"/>
+ <reference key="NSControlView" ref="840724334"/>
+ <int key="NSTag">12</int>
+ <reference key="NSBackgroundColor" ref="159766406"/>
+ <reference key="NSTextColor" ref="822671316"/>
+ </object>
+ <object class="NSTextFieldCell" id="1058484862">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">71435264</int>
+ <string key="NSContents">-100</string>
+ <reference key="NSSupport" ref="422232155"/>
+ <reference key="NSControlView" ref="840724334"/>
+ <int key="NSTag">22</int>
+ <reference key="NSBackgroundColor" ref="159766406"/>
+ <reference key="NSTextColor" ref="822671316"/>
+ </object>
+ </object>
+ <string key="NSCellSize">{106, 14}</string>
+ <string key="NSIntercellSpacing">{0, 0}</string>
+ <int key="NSMatrixFlags">-2080374784</int>
+ <nil key="NSCellClass"/>
+ <object class="NSTextFieldCell" key="NSProtoCell" id="609012621">
+ <int key="NSCellFlags">68288064</int>
+ <int key="NSCellFlags2">71435264</int>
+ <string key="NSContents">Page Namespaces</string>
+ <reference key="NSSupport" ref="57559"/>
+ <reference key="NSBackgroundColor" ref="159766406"/>
+ <reference key="NSTextColor" ref="822671316"/>
+ </object>
+ <int key="NSSelectedRow">-1</int>
+ <int key="NSSelectedCol">-1</int>
+ <reference key="NSBackgroundColor" ref="159766406"/>
+ <reference key="NSCellBackgroundColor" ref="159766406"/>
+ </object>
+ </object>
+ <string key="NSFrame">{{1, 1}, {354, 66}}</string>
+ <reference key="NSSuperview" ref="349928848"/>
+ </object>
+ </object>
+ <string key="NSFrame">{{25, 56}, {356, 82}}</string>
+ <reference key="NSSuperview" ref="1006"/>
+ <string key="NSOffsets">{0, 0}</string>
+ <object class="NSTextFieldCell" key="NSTitleCell">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents">Statistics</string>
+ <object class="NSFont" key="NSSupport">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">11</double>
+ <int key="NSfFlags">3100</int>
+ </object>
+ <object class="NSColor" key="NSBackgroundColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">textBackgroundColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MCAwLjgwMDAwMDAxMTkAA</bytes>
+ </object>
+ </object>
+ <reference key="NSContentView" ref="737205069"/>
+ <int key="NSBorderType">1</int>
+ <int key="NSBoxType">0</int>
+ <int key="NSTitlePosition">2</int>
+ <bool key="NSTransparent">NO</bool>
+ </object>
+ <object class="NSButton" id="913385411">
+ <reference key="NSNextResponder" ref="1006"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{288, 12}, {96, 32}}</string>
+ <reference key="NSSuperview" ref="1006"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="465163606">
+ <int key="NSCellFlags">67239424</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents">Refresh</string>
+ <object class="NSFont" key="NSSupport">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">13</double>
+ <int key="NSfFlags">1044</int>
+ </object>
+ <reference key="NSControlView" ref="913385411"/>
+ <int key="NSButtonFlags">-2038284033</int>
+ <int key="NSButtonFlags2">129</int>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">200</int>
+ <int key="NSPeriodicInterval">25</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{398, 158}</string>
+ <reference key="NSSuperview"/>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {1680, 1028}}</string>
+ <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">window</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="1005"/>
+ </object>
+ <int key="connectionID">3</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="1005"/>
+ <reference key="destination" ref="1001"/>
+ </object>
+ <int key="connectionID">4</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">refreshStatistics:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="913385411"/>
+ </object>
+ <int key="connectionID">83</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">_basicStatsMatrix</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="840724334"/>
+ </object>
+ <int key="connectionID">84</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <reference key="object" ref="0"/>
+ <reference key="children" ref="1000"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="1001"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">File's Owner</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="1003"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="1004"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">1</int>
+ <reference key="object" ref="1005"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1006"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">2</int>
+ <reference key="object" ref="1006"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="349928848"/>
+ <reference ref="913385411"/>
+ </object>
+ <reference key="parent" ref="1005"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">5</int>
+ <reference key="object" ref="349928848"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="840724334"/>
+ </object>
+ <reference key="parent" ref="1006"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">37</int>
+ <reference key="object" ref="913385411"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="465163606"/>
+ </object>
+ <reference key="parent" ref="1006"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">38</int>
+ <reference key="object" ref="465163606"/>
+ <reference key="parent" ref="913385411"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">75</int>
+ <reference key="object" ref="840724334"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1058484862"/>
+ <reference ref="534624797"/>
+ <reference ref="220500282"/>
+ <reference ref="792638244"/>
+ <reference ref="66669903"/>
+ <reference ref="665973187"/>
+ <reference ref="822378002"/>
+ <reference ref="775125133"/>
+ <reference ref="576107244"/>
+ <reference ref="609012621"/>
+ </object>
+ <reference key="parent" ref="349928848"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">87</int>
+ <reference key="object" ref="1058484862"/>
+ <reference key="parent" ref="840724334"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">86</int>
+ <reference key="object" ref="534624797"/>
+ <reference key="parent" ref="840724334"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">85</int>
+ <reference key="object" ref="220500282"/>
+ <reference key="parent" ref="840724334"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">48</int>
+ <reference key="object" ref="792638244"/>
+ <reference key="parent" ref="840724334"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">42</int>
+ <reference key="object" ref="66669903"/>
+ <reference key="parent" ref="840724334"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">46</int>
+ <reference key="object" ref="665973187"/>
+ <reference key="parent" ref="840724334"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">43</int>
+ <reference key="object" ref="822378002"/>
+ <reference key="parent" ref="840724334"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">47</int>
+ <reference key="object" ref="775125133"/>
+ <reference key="parent" ref="840724334"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">44</int>
+ <reference key="object" ref="576107244"/>
+ <reference key="parent" ref="840724334"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">82</int>
+ <reference key="object" ref="609012621"/>
+ <reference key="parent" ref="840724334"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>1.IBEditorWindowLastContentRect</string>
+ <string>1.IBPluginDependency</string>
+ <string>1.IBWindowTemplateEditedContentRect</string>
+ <string>1.NSWindowTemplate.visibleAtLaunch</string>
+ <string>1.WindowOrigin</string>
+ <string>1.editorWindowContentRectSynchronizationRect</string>
+ <string>2.IBPluginDependency</string>
+ <string>37.IBPluginDependency</string>
+ <string>38.IBPluginDependency</string>
+ <string>5.IBPluginDependency</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>{{362, 638}, {398, 158}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{362, 638}, {398, 158}}</string>
+ <integer value="1"/>
+ <string>{196, 240}</string>
+ <string>{{202, 428}, {480, 270}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">88</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">BrowserStatisticsWindowController</string>
+ <string key="superclassName">NSWindowController</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">refreshStatistics:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <string key="NS.key.0">_basicStatsMatrix</string>
+ <string key="NS.object.0">NSMatrix</string>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">mac/BrowserStatisticsWindowController.h</string>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSActionCell</string>
+ <string key="superclassName">NSCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSActionCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <string key="superclassName">NSResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="580408357">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSApplication.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="153722584">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSApplicationScripting.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="814670282">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSColorPanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSHelpManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSPageLayout.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSUserInterfaceItemSearching.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSBox</string>
+ <string key="superclassName">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSBox.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSButton</string>
+ <string key="superclassName">NSControl</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSButton.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSButtonCell</string>
+ <string key="superclassName">NSActionCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSButtonCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSCell</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSControl</string>
+ <string key="superclassName">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="423015697">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSControl.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSFormatter</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSFormatter.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSMatrix</string>
+ <string key="superclassName">NSControl</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSMatrix.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSMenu</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="571428989">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSMenu.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSAccessibility.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="580408357"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="153722584"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="814670282"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="423015697"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDictionaryController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDragging.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSFontManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSFontPanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSKeyValueBinding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="571428989"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSNibLoading.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSPasteboard.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSSavePanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSTableView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSToolbarItem.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="214998123">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSArchiver.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSClassDescription.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSError.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSObject.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSObjectScripting.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSPortCoder.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptClassDescription.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptKeyValueCoding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptObjectSpecifiers.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptWhoseTests.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSThread.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURL.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURLDownload.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSInterfaceStyle.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSResponder</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSResponder.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSTextFieldCell</string>
+ <string key="superclassName">NSActionCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSTextFieldCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSClipView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSMenuItem.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSRulerView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <string key="superclassName">NSResponder</string>
+ <reference key="sourceIdentifier" ref="214998123"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDrawer.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
+ <string key="superclassName">NSResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSWindow.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSWindowScripting.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindowController</string>
+ <string key="superclassName">NSResponder</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">showWindow:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSWindowController.h</string>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDependencyDefaults">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.macosx</string>
+ <integer value="1060" key="NS.object.0"/>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
+ <integer value="3000" key="NS.object.0"/>
+ </object>
+ <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+ <string key="IBDocument.LastKnownRelativeProjectPath">../MiniBrowser.xcodeproj</string>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ </data>
+</archive>
diff --git a/Tools/MiniBrowser/mac/BrowserStatisticsWindowController.h b/Tools/MiniBrowser/mac/BrowserStatisticsWindowController.h
new file mode 100644
index 0000000..6b4438f
--- /dev/null
+++ b/Tools/MiniBrowser/mac/BrowserStatisticsWindowController.h
@@ -0,0 +1,20 @@
+//
+// BrowserStatisticsWindowController.h
+// MiniBrowser
+//
+// Created by Sam Weinig on 4/21/10.
+// Copyright 2010 Apple Inc. All rights reserved.
+//
+
+@interface BrowserStatisticsWindowController : NSWindowController {
+ IBOutlet NSMatrix *_basicStatsMatrix;
+
+ WKContextRef _threadContext;
+ WKContextRef _processContext;
+}
+
+- (id)initWithThreadedWKContextRef:(WKContextRef)threadContext processWKContextRef:(WKContextRef)processContext;
+
+- (IBAction)refreshStatistics:(id)sender;
+
+@end
diff --git a/Tools/MiniBrowser/mac/BrowserStatisticsWindowController.m b/Tools/MiniBrowser/mac/BrowserStatisticsWindowController.m
new file mode 100644
index 0000000..878821a
--- /dev/null
+++ b/Tools/MiniBrowser/mac/BrowserStatisticsWindowController.m
@@ -0,0 +1,47 @@
+//
+// BrowserStatisticsWindowController.m
+// MiniBrowser
+//
+// Created by Sam Weinig on 4/21/10.
+// Copyright 2010 Apple Inc. All rights reserved.
+//
+
+#import "BrowserStatisticsWindowController.h"
+
+#import <WebKit2/WKContextPrivate.h>
+
+@implementation BrowserStatisticsWindowController
+
+- (id)initWithThreadedWKContextRef:(WKContextRef)threadContext processWKContextRef:(WKContextRef)processContext
+{
+ if ((self = [super initWithWindowNibName:@"BrowserStatisticsWindow"])) {
+ _threadContext = WKRetain(threadContext);
+ _processContext = WKRetain(processContext);
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ WKRelease(_threadContext);
+ _threadContext = 0;
+
+ WKRelease(_processContext);
+ _processContext = 0;
+
+ [super dealloc];
+}
+
+- (void)windowDidLoad
+{
+ [super windowDidLoad];
+ [self refreshStatistics:nil];
+}
+
+- (IBAction)refreshStatistics:(id)sender
+{
+ // FIXME: (Re-)implement.
+}
+
+@end
diff --git a/Tools/MiniBrowser/mac/BrowserWindow.xib b/Tools/MiniBrowser/mac/BrowserWindow.xib
new file mode 100644
index 0000000..5984fe5
--- /dev/null
+++ b/Tools/MiniBrowser/mac/BrowserWindow.xib
@@ -0,0 +1,1558 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
+ <data>
+ <int key="IBDocument.SystemTarget">1060</int>
+ <string key="IBDocument.SystemVersion">10H545</string>
+ <string key="IBDocument.InterfaceBuilderVersion">820</string>
+ <string key="IBDocument.AppKitVersion">1038.35</string>
+ <string key="IBDocument.HIToolboxVersion">461.00</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="NS.object.0">820</string>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="9"/>
+ <integer value="71"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys" id="0">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1000">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSCustomObject" id="1001">
+ <string key="NSClassName">BrowserWindowController</string>
+ </object>
+ <object class="NSCustomObject" id="1003">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="1004">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSWindowTemplate" id="1005">
+ <int key="NSWindowStyleMask">4111</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{517, 330}, {776, 608}}</string>
+ <int key="NSWTFlags">544735232</int>
+ <string key="NSWindowTitle">Window</string>
+ <string key="NSWindowClass">NSWindow</string>
+ <object class="NSToolbar" key="NSViewClass" id="726585754">
+ <object class="NSMutableString" key="NSToolbarIdentifier">
+ <characters key="NS.bytes">994A0CB1-7575-4F39-A65B-7165AB1E8015</characters>
+ </object>
+ <nil key="NSToolbarDelegate"/>
+ <bool key="NSToolbarPrefersToBeShown">YES</bool>
+ <bool key="NSToolbarShowsBaselineSeparator">YES</bool>
+ <bool key="NSToolbarAllowsUserCustomization">YES</bool>
+ <bool key="NSToolbarAutosavesConfiguration">NO</bool>
+ <int key="NSToolbarDisplayMode">2</int>
+ <int key="NSToolbarSizeMode">1</int>
+ <object class="NSMutableDictionary" key="NSToolbarIBIdentifiedItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>255D29F2-C9AA-4B4B-BB43-B38FCD6A0BBB</string>
+ <string>6BDC61B7-F1A8-425A-A212-9CAC59C56385</string>
+ <string>73DE9F4B-73E2-4036-A134-2D9E029DA980</string>
+ <string>88C16109-D40F-4682-BCE4-CBEE2EDE32D2</string>
+ <string>E1A9D32A-59E3-467B-9ABA-A95780416E69</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSToolbarItem" id="16289946">
+ <object class="NSMutableString" key="NSToolbarItemIdentifier">
+ <characters key="NS.bytes">255D29F2-C9AA-4B4B-BB43-B38FCD6A0BBB</characters>
+ </object>
+ <string key="NSToolbarItemLabel">Location</string>
+ <string key="NSToolbarItemPaletteLabel">Location</string>
+ <nil key="NSToolbarItemToolTip"/>
+ <object class="NSTextField" key="NSToolbarItemView" id="690456651">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">266</int>
+ <string key="NSFrame">{{0, 14}, {565, 22}}</string>
+ <int key="NSViewLayerContentsRedrawPolicy">2</int>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSTextFieldCell" key="NSCell" id="1023147716">
+ <int key="NSCellFlags">-1804468671</int>
+ <int key="NSCellFlags2">268436480</int>
+ <string key="NSContents"/>
+ <object class="NSFont" key="NSSupport" id="1064395332">
+ <string key="NSName">LucidaGrande</string>
+ <double key="NSSize">13</double>
+ <int key="NSfFlags">1044</int>
+ </object>
+ <reference key="NSControlView" ref="690456651"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <object class="NSColor" key="NSBackgroundColor" id="1032961300">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">textBackgroundColor</string>
+ <object class="NSColor" key="NSColor">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MQA</bytes>
+ </object>
+ </object>
+ <object class="NSColor" key="NSTextColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">textColor</string>
+ <object class="NSColor" key="NSColor" id="365730878">
+ <int key="NSColorSpace">3</int>
+ <bytes key="NSWhite">MAA</bytes>
+ </object>
+ </object>
+ </object>
+ </object>
+ <nil key="NSToolbarItemImage"/>
+ <nil key="NSToolbarItemTarget"/>
+ <nil key="NSToolbarItemAction"/>
+ <string key="NSToolbarItemMinSize">{200, 22}</string>
+ <string key="NSToolbarItemMaxSize">{800, 22}</string>
+ <bool key="NSToolbarItemEnabled">YES</bool>
+ <bool key="NSToolbarItemAutovalidates">YES</bool>
+ <int key="NSToolbarItemTag">0</int>
+ <bool key="NSToolbarIsUserRemovable">YES</bool>
+ <int key="NSToolbarItemVisibilityPriority">0</int>
+ </object>
+ <object class="NSToolbarItem" id="457655522">
+ <object class="NSMutableString" key="NSToolbarItemIdentifier">
+ <characters key="NS.bytes">6BDC61B7-F1A8-425A-A212-9CAC59C56385</characters>
+ </object>
+ <string key="NSToolbarItemLabel">Progress</string>
+ <string key="NSToolbarItemPaletteLabel">Progress</string>
+ <nil key="NSToolbarItemToolTip"/>
+ <object class="NSProgressIndicator" key="NSToolbarItemView" id="128750774">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">1289</int>
+ <object class="NSPSMatrix" key="NSDrawMatrix"/>
+ <string key="NSFrame">{{19, 14}, {16, 16}}</string>
+ <int key="NSpiFlags">28936</int>
+ <double key="NSMaxValue">1</double>
+ </object>
+ <nil key="NSToolbarItemImage"/>
+ <nil key="NSToolbarItemTarget"/>
+ <nil key="NSToolbarItemAction"/>
+ <string key="NSToolbarItemMinSize">{16, 16}</string>
+ <string key="NSToolbarItemMaxSize">{16, 16}</string>
+ <bool key="NSToolbarItemEnabled">YES</bool>
+ <bool key="NSToolbarItemAutovalidates">YES</bool>
+ <int key="NSToolbarItemTag">-1</int>
+ <bool key="NSToolbarIsUserRemovable">YES</bool>
+ <int key="NSToolbarItemVisibilityPriority">0</int>
+ </object>
+ <object class="NSToolbarItem" id="332491395">
+ <object class="NSMutableString" key="NSToolbarItemIdentifier">
+ <characters key="NS.bytes">73DE9F4B-73E2-4036-A134-2D9E029DA980</characters>
+ </object>
+ <string key="NSToolbarItemLabel">Go Back</string>
+ <string key="NSToolbarItemPaletteLabel">Go Back</string>
+ <nil key="NSToolbarItemToolTip"/>
+ <object class="NSButton" key="NSToolbarItemView" id="777930419">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{9, 14}, {32, 25}}</string>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="663899880">
+ <int key="NSCellFlags">-2080244224</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="1064395332"/>
+ <reference key="NSControlView" ref="777930419"/>
+ <int key="NSButtonFlags">-2033434369</int>
+ <int key="NSButtonFlags2">163</int>
+ <object class="NSCustomResource" key="NSNormalImage" id="206098440">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSGoLeftTemplate</string>
+ </object>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ <reference key="NSToolbarItemImage" ref="206098440"/>
+ <nil key="NSToolbarItemTarget"/>
+ <nil key="NSToolbarItemAction"/>
+ <string key="NSToolbarItemMinSize">{32, 25}</string>
+ <string key="NSToolbarItemMaxSize">{32, 25}</string>
+ <bool key="NSToolbarItemEnabled">YES</bool>
+ <bool key="NSToolbarItemAutovalidates">YES</bool>
+ <int key="NSToolbarItemTag">0</int>
+ <bool key="NSToolbarIsUserRemovable">YES</bool>
+ <int key="NSToolbarItemVisibilityPriority">0</int>
+ </object>
+ <object class="NSToolbarItem" id="818723416">
+ <object class="NSMutableString" key="NSToolbarItemIdentifier">
+ <characters key="NS.bytes">88C16109-D40F-4682-BCE4-CBEE2EDE32D2</characters>
+ </object>
+ <string key="NSToolbarItemLabel">Refresh</string>
+ <string key="NSToolbarItemPaletteLabel">Refresh</string>
+ <nil key="NSToolbarItemToolTip"/>
+ <object class="NSButton" key="NSToolbarItemView" id="35464578">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{10, 14}, {29, 25}}</string>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="366486485">
+ <int key="NSCellFlags">-2080244224</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="1064395332"/>
+ <reference key="NSControlView" ref="35464578"/>
+ <int key="NSButtonFlags">-2033434369</int>
+ <int key="NSButtonFlags2">163</int>
+ <object class="NSCustomResource" key="NSNormalImage" id="443763357">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSRefreshTemplate</string>
+ </object>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ <reference key="NSToolbarItemImage" ref="443763357"/>
+ <nil key="NSToolbarItemTarget"/>
+ <nil key="NSToolbarItemAction"/>
+ <string key="NSToolbarItemMinSize">{29, 25}</string>
+ <string key="NSToolbarItemMaxSize">{29, 25}</string>
+ <bool key="NSToolbarItemEnabled">YES</bool>
+ <bool key="NSToolbarItemAutovalidates">YES</bool>
+ <int key="NSToolbarItemTag">0</int>
+ <bool key="NSToolbarIsUserRemovable">YES</bool>
+ <int key="NSToolbarItemVisibilityPriority">0</int>
+ </object>
+ <object class="NSToolbarItem" id="928383107">
+ <object class="NSMutableString" key="NSToolbarItemIdentifier">
+ <characters key="NS.bytes">E1A9D32A-59E3-467B-9ABA-A95780416E69</characters>
+ </object>
+ <string key="NSToolbarItemLabel">Go Forward</string>
+ <string key="NSToolbarItemPaletteLabel">Go Forward</string>
+ <nil key="NSToolbarItemToolTip"/>
+ <object class="NSButton" key="NSToolbarItemView" id="95415629">
+ <nil key="NSNextResponder"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{19, 14}, {32, 25}}</string>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSButtonCell" key="NSCell" id="767612038">
+ <int key="NSCellFlags">-2080244224</int>
+ <int key="NSCellFlags2">134217728</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="1064395332"/>
+ <reference key="NSControlView" ref="95415629"/>
+ <int key="NSButtonFlags">-2033434369</int>
+ <int key="NSButtonFlags2">163</int>
+ <object class="NSCustomResource" key="NSNormalImage" id="163672266">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSGoRightTemplate</string>
+ </object>
+ <string key="NSAlternateContents"/>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ </object>
+ <reference key="NSToolbarItemImage" ref="163672266"/>
+ <nil key="NSToolbarItemTarget"/>
+ <nil key="NSToolbarItemAction"/>
+ <string key="NSToolbarItemMinSize">{32, 25}</string>
+ <string key="NSToolbarItemMaxSize">{32, 25}</string>
+ <bool key="NSToolbarItemEnabled">YES</bool>
+ <bool key="NSToolbarItemAutovalidates">YES</bool>
+ <int key="NSToolbarItemTag">0</int>
+ <bool key="NSToolbarIsUserRemovable">YES</bool>
+ <int key="NSToolbarItemVisibilityPriority">0</int>
+ </object>
+ </object>
+ </object>
+ <object class="NSArray" key="NSToolbarIBAllowedItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="332491395"/>
+ <reference ref="928383107"/>
+ <reference ref="818723416"/>
+ <reference ref="457655522"/>
+ <reference ref="16289946"/>
+ </object>
+ <object class="NSMutableArray" key="NSToolbarIBDefaultItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="332491395"/>
+ <reference ref="928383107"/>
+ <reference ref="818723416"/>
+ <reference ref="16289946"/>
+ <reference ref="457655522"/>
+ </object>
+ <object class="NSMutableArray" key="NSToolbarIBSelectableItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
+ <object class="NSView" key="NSWindowView" id="1006">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSCustomView" id="877383975">
+ <reference key="NSNextResponder" ref="1006"/>
+ <int key="NSvFlags">274</int>
+ <string key="NSFrameSize">{776, 608}</string>
+ <reference key="NSSuperview" ref="1006"/>
+ <int key="NSViewLayerContentsRedrawPolicy">2</int>
+ <string key="NSClassName">NSView</string>
+ </object>
+ </object>
+ <string key="NSFrameSize">{776, 608}</string>
+ <reference key="NSSuperview"/>
+ <int key="NSViewLayerContentsRedrawPolicy">2</int>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
+ <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
+ <string key="NSFrameAutosaveName">Main Window</string>
+ </object>
+ <object class="NSWindowTemplate" id="833876351">
+ <int key="NSWindowStyleMask">147</int>
+ <int key="NSWindowBacking">2</int>
+ <string key="NSWindowRect">{{230, 479}, {452, 62}}</string>
+ <int key="NSWTFlags">-461897728</int>
+ <string key="NSWindowTitle">Find</string>
+ <string key="NSWindowClass">NSPanel</string>
+ <nil key="NSViewClass"/>
+ <string key="NSWindowContentMaxSize">{1.79769e+308, 1.79769e+308}</string>
+ <object class="NSView" key="NSWindowView" id="585866018">
+ <reference key="NSNextResponder"/>
+ <int key="NSvFlags">256</int>
+ <object class="NSMutableArray" key="NSSubviews">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSSearchField" id="841639270">
+ <reference key="NSNextResponder" ref="585866018"/>
+ <int key="NSvFlags">268</int>
+ <string key="NSFrame">{{20, 20}, {412, 22}}</string>
+ <reference key="NSSuperview" ref="585866018"/>
+ <bool key="NSEnabled">YES</bool>
+ <object class="NSSearchFieldCell" key="NSCell" id="41426839">
+ <int key="NSCellFlags">343014976</int>
+ <int key="NSCellFlags2">268436544</int>
+ <string key="NSContents"/>
+ <reference key="NSSupport" ref="1064395332"/>
+ <reference key="NSControlView" ref="841639270"/>
+ <bool key="NSDrawsBackground">YES</bool>
+ <int key="NSTextBezelStyle">1</int>
+ <reference key="NSBackgroundColor" ref="1032961300"/>
+ <object class="NSColor" key="NSTextColor">
+ <int key="NSColorSpace">6</int>
+ <string key="NSCatalogName">System</string>
+ <string key="NSColorName">controlTextColor</string>
+ <reference key="NSColor" ref="365730878"/>
+ </object>
+ <object class="NSButtonCell" key="NSSearchButtonCell">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents">search</string>
+ <reference key="NSControlView" ref="841639270"/>
+ <string key="NSAction">_searchFieldSearch:</string>
+ <reference key="NSTarget" ref="41426839"/>
+ <int key="NSButtonFlags">138690815</int>
+ <int key="NSButtonFlags2">0</int>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ <object class="NSButtonCell" key="NSCancelButtonCell">
+ <int key="NSCellFlags">130560</int>
+ <int key="NSCellFlags2">0</int>
+ <string key="NSContents">clear</string>
+ <object class="NSMutableArray" key="NSAccessibilityOverriddenAttributes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMutableDictionary">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>AXDescription</string>
+ <string>NSAccessibilityEncodedAttributesValueType</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>cancel</string>
+ <integer value="1"/>
+ </object>
+ </object>
+ </object>
+ <reference key="NSControlView" ref="841639270"/>
+ <string key="NSAction">_searchFieldCancel:</string>
+ <reference key="NSTarget" ref="41426839"/>
+ <int key="NSButtonFlags">138690815</int>
+ <int key="NSButtonFlags2">0</int>
+ <string key="NSKeyEquivalent"/>
+ <int key="NSPeriodicDelay">400</int>
+ <int key="NSPeriodicInterval">75</int>
+ </object>
+ <int key="NSMaximumRecents">255</int>
+ </object>
+ </object>
+ </object>
+ <string key="NSFrameSize">{452, 62}</string>
+ <reference key="NSSuperview"/>
+ </object>
+ <string key="NSScreenRect">{{0, 0}, {1920, 1178}}</string>
+ <string key="NSMaxSize">{1.79769e+308, 1.79769e+308}</string>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">window</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="1005"/>
+ </object>
+ <int key="connectionID">3</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="1005"/>
+ <reference key="destination" ref="1001"/>
+ </object>
+ <int key="connectionID">4</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">urlText</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="690456651"/>
+ </object>
+ <int key="connectionID">32</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">progressIndicator</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="128750774"/>
+ </object>
+ <int key="connectionID">33</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">reloadButton</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="35464578"/>
+ </object>
+ <int key="connectionID">34</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">reload:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="35464578"/>
+ </object>
+ <int key="connectionID">35</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">fetch:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="690456651"/>
+ </object>
+ <int key="connectionID">36</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">containerView</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="877383975"/>
+ </object>
+ <int key="connectionID">37</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">backButton</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="777930419"/>
+ </object>
+ <int key="connectionID">46</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">forwardButton</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="95415629"/>
+ </object>
+ <int key="connectionID">47</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">goBack:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="332491395"/>
+ </object>
+ <int key="connectionID">61</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">goForward:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="928383107"/>
+ </object>
+ <int key="connectionID">62</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">toolbar</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="726585754"/>
+ </object>
+ <int key="connectionID">67</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">find:</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="841639270"/>
+ </object>
+ <int key="connectionID">76</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">findPanelWindow</string>
+ <reference key="source" ref="1001"/>
+ <reference key="destination" ref="833876351"/>
+ </object>
+ <int key="connectionID">77</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <reference key="object" ref="0"/>
+ <reference key="children" ref="1000"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="1001"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">File's Owner</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="1003"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="1004"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">1</int>
+ <reference key="object" ref="1005"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1006"/>
+ <reference ref="726585754"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">2</int>
+ <reference key="object" ref="1006"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="877383975"/>
+ </object>
+ <reference key="parent" ref="1005"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">9</int>
+ <reference key="object" ref="877383975"/>
+ <reference key="parent" ref="1006"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">48</int>
+ <reference key="object" ref="726585754"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="332491395"/>
+ <reference ref="928383107"/>
+ <reference ref="818723416"/>
+ <reference ref="16289946"/>
+ <reference ref="457655522"/>
+ </object>
+ <reference key="parent" ref="1005"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">56</int>
+ <reference key="object" ref="332491395"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="777930419"/>
+ </object>
+ <reference key="parent" ref="726585754"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">40</int>
+ <reference key="object" ref="777930419"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="663899880"/>
+ </object>
+ <reference key="parent" ref="332491395"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">41</int>
+ <reference key="object" ref="663899880"/>
+ <reference key="parent" ref="777930419"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">57</int>
+ <reference key="object" ref="928383107"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="95415629"/>
+ </object>
+ <reference key="parent" ref="726585754"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">42</int>
+ <reference key="object" ref="95415629"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="767612038"/>
+ </object>
+ <reference key="parent" ref="928383107"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">43</int>
+ <reference key="object" ref="767612038"/>
+ <reference key="parent" ref="95415629"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">58</int>
+ <reference key="object" ref="818723416"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="35464578"/>
+ </object>
+ <reference key="parent" ref="726585754"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">23</int>
+ <reference key="object" ref="35464578"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="366486485"/>
+ </object>
+ <reference key="parent" ref="818723416"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">24</int>
+ <reference key="object" ref="366486485"/>
+ <reference key="parent" ref="35464578"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">59</int>
+ <reference key="object" ref="16289946"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="690456651"/>
+ </object>
+ <reference key="parent" ref="726585754"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">10</int>
+ <reference key="object" ref="690456651"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1023147716"/>
+ </object>
+ <reference key="parent" ref="16289946"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">11</int>
+ <reference key="object" ref="1023147716"/>
+ <reference key="parent" ref="690456651"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">60</int>
+ <reference key="object" ref="457655522"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="128750774"/>
+ </object>
+ <reference key="parent" ref="726585754"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">21</int>
+ <reference key="object" ref="128750774"/>
+ <reference key="parent" ref="457655522"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">70</int>
+ <reference key="object" ref="833876351"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="585866018"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">71</int>
+ <reference key="object" ref="585866018"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="841639270"/>
+ </object>
+ <reference key="parent" ref="833876351"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">74</int>
+ <reference key="object" ref="841639270"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="41426839"/>
+ </object>
+ <reference key="parent" ref="585866018"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">75</int>
+ <reference key="object" ref="41426839"/>
+ <reference key="parent" ref="841639270"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>1.IBEditorWindowLastContentRect</string>
+ <string>1.IBPluginDependency</string>
+ <string>1.IBWindowTemplateEditedContentRect</string>
+ <string>1.NSWindowTemplate.visibleAtLaunch</string>
+ <string>1.WindowOrigin</string>
+ <string>1.editorWindowContentRectSynchronizationRect</string>
+ <string>10.IBPluginDependency</string>
+ <string>11.IBPluginDependency</string>
+ <string>2.IBPluginDependency</string>
+ <string>21.IBPluginDependency</string>
+ <string>21.IBViewIntegration.shadowBlurRadius</string>
+ <string>21.IBViewIntegration.shadowColor</string>
+ <string>21.IBViewIntegration.shadowOffsetHeight</string>
+ <string>21.IBViewIntegration.shadowOffsetWidth</string>
+ <string>23.IBPluginDependency</string>
+ <string>24.IBPluginDependency</string>
+ <string>40.IBPluginDependency</string>
+ <string>41.IBPluginDependency</string>
+ <string>42.IBPluginDependency</string>
+ <string>43.IBPluginDependency</string>
+ <string>48.IBEditorWindowLastContentRect</string>
+ <string>48.IBPluginDependency</string>
+ <string>56.CustomClassName</string>
+ <string>57.CustomClassName</string>
+ <string>58.CustomClassName</string>
+ <string>70.IBEditorWindowLastContentRect</string>
+ <string>70.IBPluginDependency</string>
+ <string>70.IBWindowTemplateEditedContentRect</string>
+ <string>70.NSWindowTemplate.visibleAtLaunch</string>
+ <string>71.IBPluginDependency</string>
+ <string>74.IBPluginDependency</string>
+ <string>75.IBPluginDependency</string>
+ <string>9.IBPluginDependency</string>
+ <string>9.IBViewBoundsToFrameTransform</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>{{404, 157}, {776, 608}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{404, 157}, {776, 608}}</string>
+ <integer value="1"/>
+ <string>{196, 240}</string>
+ <string>{{202, 428}, {480, 270}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <real value="0.0"/>
+ <reference ref="365730878"/>
+ <real value="0.0"/>
+ <real value="0.0"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{422, 781}, {616, 0}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>MBToolbarItem</string>
+ <string>MBToolbarItem</string>
+ <string>MBToolbarItem</string>
+ <string>{{558, 468}, {452, 62}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{558, 468}, {452, 62}}</string>
+ <boolean value="NO"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <object class="NSAffineTransform"/>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">77</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">BrowserWindowController</string>
+ <string key="superclassName">NSWindowController</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>dumpSourceToConsole:</string>
+ <string>fetch:</string>
+ <string>find:</string>
+ <string>forceRepaint:</string>
+ <string>goBack:</string>
+ <string>goForward:</string>
+ <string>reload:</string>
+ <string>removeReinsertWebView:</string>
+ <string>resetZoom:</string>
+ <string>showHideWebView:</string>
+ <string>toggleZoomMode:</string>
+ <string>zoomIn:</string>
+ <string>zoomOut:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>dumpSourceToConsole:</string>
+ <string>fetch:</string>
+ <string>find:</string>
+ <string>forceRepaint:</string>
+ <string>goBack:</string>
+ <string>goForward:</string>
+ <string>reload:</string>
+ <string>removeReinsertWebView:</string>
+ <string>resetZoom:</string>
+ <string>showHideWebView:</string>
+ <string>toggleZoomMode:</string>
+ <string>zoomIn:</string>
+ <string>zoomOut:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBActionInfo">
+ <string key="name">dumpSourceToConsole:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">fetch:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">find:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">forceRepaint:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">goBack:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">goForward:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">reload:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">removeReinsertWebView:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">resetZoom:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">showHideWebView:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">toggleZoomMode:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">zoomIn:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">zoomOut:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>backButton</string>
+ <string>containerView</string>
+ <string>findPanelWindow</string>
+ <string>forwardButton</string>
+ <string>progressIndicator</string>
+ <string>reloadButton</string>
+ <string>toolbar</string>
+ <string>urlText</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSButton</string>
+ <string>NSView</string>
+ <string>NSWindow</string>
+ <string>NSButton</string>
+ <string>NSProgressIndicator</string>
+ <string>NSButton</string>
+ <string>NSToolbar</string>
+ <string>NSTextField</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>backButton</string>
+ <string>containerView</string>
+ <string>findPanelWindow</string>
+ <string>forwardButton</string>
+ <string>progressIndicator</string>
+ <string>reloadButton</string>
+ <string>toolbar</string>
+ <string>urlText</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBToOneOutletInfo">
+ <string key="name">backButton</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">containerView</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">findPanelWindow</string>
+ <string key="candidateClassName">NSWindow</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">forwardButton</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">progressIndicator</string>
+ <string key="candidateClassName">NSProgressIndicator</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">reloadButton</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">toolbar</string>
+ <string key="candidateClassName">NSToolbar</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">urlText</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">mac/BrowserWindowController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">BrowserWindowController</string>
+ <string key="superclassName">NSWindowController</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">MBToolbarItem</string>
+ <string key="superclassName">NSToolbarItem</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">MBToolbarItem.h</string>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSActionCell</string>
+ <string key="superclassName">NSCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSActionCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <string key="superclassName">NSResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="558771426">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSApplication.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="344596456">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSApplicationScripting.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="428409299">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSColorPanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSHelpManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSPageLayout.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSUserInterfaceItemSearching.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSButton</string>
+ <string key="superclassName">NSControl</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSButton.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSButtonCell</string>
+ <string key="superclassName">NSActionCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSButtonCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSCell</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSControl</string>
+ <string key="superclassName">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="297186634">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSControl.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSFormatter</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSFormatter.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSMenu</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="808053469">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSMenu.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSAccessibility.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="558771426"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="344596456"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="428409299"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="297186634"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDictionaryController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDragging.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSFontManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSFontPanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSKeyValueBinding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="808053469"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSNibLoading.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSPasteboard.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSSavePanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSTableView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="335804019">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSToolbarItem.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="555757547">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSArchiver.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSClassDescription.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSError.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSObject.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSObjectScripting.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSPortCoder.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptClassDescription.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptKeyValueCoding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptObjectSpecifiers.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptWhoseTests.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSThread.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURL.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURLDownload.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSPanel</string>
+ <string key="superclassName">NSWindow</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSPanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSProgressIndicator</string>
+ <string key="superclassName">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSProgressIndicator.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSInterfaceStyle.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSResponder</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSResponder.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSSearchField</string>
+ <string key="superclassName">NSTextField</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSSearchField.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSSearchFieldCell</string>
+ <string key="superclassName">NSTextFieldCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSSearchFieldCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSTextField</string>
+ <string key="superclassName">NSControl</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSTextField.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSTextFieldCell</string>
+ <string key="superclassName">NSActionCell</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSTextFieldCell.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSToolbar</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSToolbar.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSToolbarItem</string>
+ <string key="superclassName">NSObject</string>
+ <reference key="sourceIdentifier" ref="335804019"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSClipView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSMenuItem.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSRulerView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <string key="superclassName">NSResponder</string>
+ <reference key="sourceIdentifier" ref="555757547"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDrawer.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
+ <string key="superclassName">NSResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSWindow.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSWindowScripting.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindowController</string>
+ <string key="superclassName">NSResponder</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">showWindow:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <string key="NS.key.0">showWindow:</string>
+ <object class="IBActionInfo" key="NS.object.0">
+ <string key="name">showWindow:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSWindowController.h</string>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
+ <integer value="3000" key="NS.object.0"/>
+ </object>
+ <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+ <string key="IBDocument.LastKnownRelativeProjectPath">../MiniBrowser.xcodeproj</string>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ <object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSGoLeftTemplate</string>
+ <string>NSGoRightTemplate</string>
+ <string>NSRefreshTemplate</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>{9, 9}</string>
+ <string>{9, 9}</string>
+ <string>{10, 12}</string>
+ </object>
+ </object>
+ </data>
+</archive>
diff --git a/Tools/MiniBrowser/mac/BrowserWindowController.h b/Tools/MiniBrowser/mac/BrowserWindowController.h
new file mode 100644
index 0000000..d132802
--- /dev/null
+++ b/Tools/MiniBrowser/mac/BrowserWindowController.h
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+@interface BrowserWindowController : NSWindowController {
+ IBOutlet NSProgressIndicator *progressIndicator;
+ IBOutlet NSButton *reloadButton;
+ IBOutlet NSButton *backButton;
+ IBOutlet NSButton *forwardButton;
+ IBOutlet NSToolbar *toolbar;
+ IBOutlet NSTextField *urlText;
+ IBOutlet NSView *containerView;
+
+ IBOutlet NSWindow *findPanelWindow;
+
+ WKContextRef _context;
+ WKView *_webView;
+ BOOL _zoomTextOnly;
+}
+- (IBAction)fetch:(id)sender;
+- (IBAction)reload:(id)sender;
+- (IBAction)forceRepaint:(id)sender;
+- (IBAction)goBack:(id)sender;
+- (IBAction)goForward:(id)sender;
+
+- (IBAction)showHideWebView:(id)sender;
+- (IBAction)removeReinsertWebView:(id)sender;
+
+- (id)initWithContext:(WKContextRef)context;
+- (void)loadURLString:(NSString *)urlString;
+- (void)applicationTerminating;
+
+- (IBAction)zoomIn:(id)sender;
+- (IBAction)zoomOut:(id)sender;
+- (IBAction)resetZoom:(id)sender;
+- (BOOL)canZoomIn;
+- (BOOL)canZoomOut;
+- (BOOL)canResetZoom;
+
+- (IBAction)toggleZoomMode:(id)sender;
+
+- (IBAction)dumpSourceToConsole:(id)sender;
+
+- (IBAction)find:(id)sender;
+
+@end
diff --git a/Tools/MiniBrowser/mac/BrowserWindowController.m b/Tools/MiniBrowser/mac/BrowserWindowController.m
new file mode 100644
index 0000000..0fa4755
--- /dev/null
+++ b/Tools/MiniBrowser/mac/BrowserWindowController.m
@@ -0,0 +1,740 @@
+/*
+ * 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.
+ */
+
+#import "BrowserWindowController.h"
+
+#import <WebKit2/WKPagePrivate.h>
+#import <WebKit2/WKStringCF.h>
+#import <WebKit2/WKURLCF.h>
+
+@interface BrowserWindowController ()
+- (void)didStartProgress;
+- (void)didChangeProgress:(double)value;
+- (void)didFinishProgress;
+- (void)didStartProvisionalLoadForFrame:(WKFrameRef)frame;
+- (void)didCommitLoadForFrame:(WKFrameRef)frame;
+- (void)didReceiveServerRedirectForProvisionalLoadForFrame:(WKFrameRef)frame;
+- (void)didFailProvisionalLoadWithErrorForFrame:(WKFrameRef)frame;
+- (void)didFailLoadWithErrorForFrame:(WKFrameRef)frame;
+- (void)didSameDocumentNavigationForFrame:(WKFrameRef)frame;
+@end
+
+@implementation BrowserWindowController
+
+- (id)initWithContext:(WKContextRef)context
+{
+ if ((self = [super initWithWindowNibName:@"BrowserWindow"])) {
+ _context = WKRetain(context);
+ _zoomTextOnly = NO;
+ }
+
+ return self;
+}
+
+- (void)dealloc
+{
+ assert(!_context);
+ [super dealloc];
+}
+
+- (IBAction)fetch:(id)sender
+{
+ CFURLRef cfURL = CFURLCreateWithString(0, (CFStringRef)[urlText stringValue], 0);
+ if (!cfURL)
+ return;
+
+ WKURLRef url = WKURLCreateWithCFURL(cfURL);
+ CFRelease(cfURL);
+
+ WKPageLoadURL(_webView.pageRef, url);
+ WKRelease(url);
+}
+
+- (IBAction)showHideWebView:(id)sender
+{
+ BOOL hidden = ![_webView isHidden];
+
+ [_webView setHidden:hidden];
+}
+
+- (IBAction)removeReinsertWebView:(id)sender
+{
+ if ([_webView window]) {
+ [_webView retain];
+ [_webView removeFromSuperview];
+ } else {
+ [containerView addSubview:_webView];
+ [_webView release];
+ }
+}
+
+- (BOOL)validateMenuItem:(NSMenuItem *)menuItem
+{
+ SEL action = [menuItem action];
+
+ if (action == @selector(zoomIn:))
+ return [self canZoomIn];
+ if (action == @selector(zoomOut:))
+ return [self canZoomOut];
+ if (action == @selector(resetZoom:))
+ return [self canResetZoom];
+
+ if (action == @selector(showHideWebView:))
+ [menuItem setTitle:[_webView isHidden] ? @"Show Web View" : @"Hide Web View"];
+ else if (action == @selector(removeReinsertWebView:))
+ [menuItem setTitle:[_webView window] ? @"Remove Web View" : @"Insert Web View"];
+ else if (action == @selector(toggleZoomMode:))
+ [menuItem setState:_zoomTextOnly ? NSOnState : NSOffState];
+ return YES;
+}
+
+- (IBAction)reload:(id)sender
+{
+ WKPageReload(_webView.pageRef);
+}
+
+- (IBAction)forceRepaint:(id)sender
+{
+ [_webView setNeedsDisplay:YES];
+}
+
+- (IBAction)goBack:(id)sender
+{
+ WKPageGoBack(_webView.pageRef);
+}
+
+- (IBAction)goForward:(id)sender
+{
+ WKPageGoForward(_webView.pageRef);
+}
+
+- (BOOL)validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)item
+{
+ SEL action = [item action];
+
+ if (action == @selector(goBack:))
+ return _webView && WKPageCanGoBack(_webView.pageRef);
+
+ if (action == @selector(goForward:))
+ return _webView && WKPageCanGoForward(_webView.pageRef);
+
+ return YES;
+}
+
+- (void)validateToolbar
+{
+ [toolbar validateVisibleItems];
+}
+
+- (BOOL)windowShouldClose:(id)sender
+{
+ LOG(@"windowShouldClose");
+ BOOL canCloseImmediately = WKPageTryClose(_webView.pageRef);
+ return canCloseImmediately;
+}
+
+- (void)windowWillClose:(NSNotification *)notification
+{
+ WKRelease(_context);
+ _context = 0;
+}
+
+- (void)applicationTerminating
+{
+ WKPageClose(_webView.pageRef);
+ WKRelease(_webView.pageRef);
+}
+
+#define DefaultMinimumZoomFactor (.5)
+#define DefaultMaximumZoomFactor (3.0)
+#define DefaultZoomFactorRatio (1.2)
+
+- (double)currentZoomFactor
+{
+ return _zoomTextOnly ? WKPageGetTextZoomFactor(_webView.pageRef) : WKPageGetPageZoomFactor(_webView.pageRef);
+}
+
+- (void)setCurrentZoomFactor:(double)factor
+{
+ _zoomTextOnly ? WKPageSetTextZoomFactor(_webView.pageRef, factor) : WKPageSetPageZoomFactor(_webView.pageRef, factor);
+}
+
+- (BOOL)canZoomIn
+{
+ return [self currentZoomFactor] * DefaultZoomFactorRatio < DefaultMaximumZoomFactor;
+}
+
+- (void)zoomIn:(id)sender
+{
+ if (![self canZoomIn])
+ return;
+
+ double factor = [self currentZoomFactor] * DefaultZoomFactorRatio;
+ [self setCurrentZoomFactor:factor];
+}
+
+- (BOOL)canZoomOut
+{
+ return [self currentZoomFactor] / DefaultZoomFactorRatio > DefaultMinimumZoomFactor;
+}
+
+- (void)zoomOut:(id)sender
+{
+ if (![self canZoomIn])
+ return;
+
+ double factor = [self currentZoomFactor] / DefaultZoomFactorRatio;
+ [self setCurrentZoomFactor:factor];
+}
+
+- (BOOL)canResetZoom
+{
+ return _zoomTextOnly ? (WKPageGetTextZoomFactor(_webView.pageRef) != 1) : (WKPageGetPageZoomFactor(_webView.pageRef) != 1);
+}
+
+- (void)resetZoom:(id)sender
+{
+ if (![self canResetZoom])
+ return;
+
+ if (_zoomTextOnly)
+ WKPageSetTextZoomFactor(_webView.pageRef, 1);
+ else
+ WKPageSetPageZoomFactor(_webView.pageRef, 1);
+}
+
+- (IBAction)toggleZoomMode:(id)sender
+{
+ if (_zoomTextOnly) {
+ _zoomTextOnly = NO;
+ double currentTextZoom = WKPageGetTextZoomFactor(_webView.pageRef);
+ WKPageSetPageAndTextZoomFactors(_webView.pageRef, currentTextZoom, 1);
+ } else {
+ _zoomTextOnly = YES;
+ double currentPageZoom = WKPageGetPageZoomFactor(_webView.pageRef);
+ WKPageSetPageAndTextZoomFactors(_webView.pageRef, 1, currentPageZoom);
+ }
+}
+
+- (IBAction)dumpSourceToConsole:(id)sender
+{
+ WKPageGetSourceForFrame_b(_webView.pageRef, WKPageGetMainFrame(_webView.pageRef), ^(WKStringRef result, WKErrorRef error) {
+ CFStringRef cfResult = WKStringCopyCFString(0, result);
+ LOG(@"Main frame source\n \"%@\"", (NSString *)cfResult);
+ CFRelease(cfResult);
+ });
+}
+
+#pragma mark Loader Client Callbacks
+
+static void didStartProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void *clientInfo)
+{
+ [(BrowserWindowController *)clientInfo didStartProvisionalLoadForFrame:frame];
+}
+
+static void didReceiveServerRedirectForProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void *clientInfo)
+{
+ [(BrowserWindowController *)clientInfo didReceiveServerRedirectForProvisionalLoadForFrame:frame];
+}
+
+static void didFailProvisionalLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, WKErrorRef error, WKTypeRef userData, const void *clientInfo)
+{
+ [(BrowserWindowController *)clientInfo didFailProvisionalLoadWithErrorForFrame:frame];
+}
+
+static void didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void *clientInfo)
+{
+ [(BrowserWindowController *)clientInfo didCommitLoadForFrame:frame];
+}
+
+static void didFinishDocumentLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void *clientInfo)
+{
+ LOG(@"didFinishDocumentLoadForFrame");
+}
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void *clientInfo)
+{
+ LOG(@"didFinishLoadForFrame");
+}
+
+static void didFailLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, WKErrorRef error, WKTypeRef userData, const void *clientInfo)
+{
+ [(BrowserWindowController *)clientInfo didFailLoadWithErrorForFrame:frame];
+}
+
+static void didSameDocumentNavigationForFrame(WKPageRef page, WKFrameRef frame, WKSameDocumentNavigationType type, WKTypeRef userData, const void *clientInfo)
+{
+ [(BrowserWindowController *)clientInfo didSameDocumentNavigationForFrame:frame];
+}
+
+static void didReceiveTitleForFrame(WKPageRef page, WKStringRef title, WKFrameRef frame, WKTypeRef userData, const void *clientInfo)
+{
+ CFStringRef cfTitle = WKStringCopyCFString(0, title);
+ LOG(@"didReceiveTitleForFrame \"%@\"", (NSString *)cfTitle);
+ CFRelease(cfTitle);
+}
+
+static void didFirstLayoutForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void *clientInfo)
+{
+ LOG(@"didFirstLayoutForFrame");
+}
+
+static void didFirstVisuallyNonEmptyLayoutForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void *clientInfo)
+{
+ LOG(@"didFirstVisuallyNonEmptyLayoutForFrame");
+}
+
+static void didRemoveFrameFromHierarchy(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void *clientInfo)
+{
+ LOG(@"didRemoveFrameFromHierarchy");
+}
+
+static void didDisplayInsecureContentForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void *clientInfo)
+{
+ LOG(@"didDisplayInsecureContentForFrame");
+}
+
+static void didRunInsecureContentForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void *clientInfo)
+{
+ LOG(@"didRunInsecureContentForFrame");
+}
+
+static void didStartProgress(WKPageRef page, const void *clientInfo)
+{
+ [(BrowserWindowController *)clientInfo didStartProgress];
+}
+
+static void didChangeProgress(WKPageRef page, const void *clientInfo)
+{
+ [(BrowserWindowController *)clientInfo didChangeProgress:WKPageGetEstimatedProgress(page)];
+}
+
+static void didFinishProgress(WKPageRef page, const void *clientInfo)
+{
+ [(BrowserWindowController *)clientInfo didFinishProgress];
+}
+
+static void didBecomeUnresponsive(WKPageRef page, const void *clientInfo)
+{
+ LOG(@"didBecomeUnresponsive");
+}
+
+static void didBecomeResponsive(WKPageRef page, const void *clientInfo)
+{
+ LOG(@"didBecomeResponsive");
+}
+
+static void processDidExit(WKPageRef page, const void *clientInfo)
+{
+ LOG(@"processDidExit");
+}
+
+static void didChangeBackForwardList(WKPageRef page, const void *clientInfo)
+{
+ [(BrowserWindowController *)clientInfo validateToolbar];
+}
+
+#pragma mark Policy Client Callbacks
+
+static void decidePolicyForNavigationAction(WKPageRef page, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void *clientInfo)
+{
+ LOG(@"decidePolicyForNavigationAction");
+ WKFramePolicyListenerUse(listener);
+}
+
+static void decidePolicyForNewWindowAction(WKPageRef page, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void *clientInfo)
+{
+ LOG(@"decidePolicyForNewWindowAction");
+ WKFramePolicyListenerUse(listener);
+}
+
+static void decidePolicyForMIMEType(WKPageRef page, WKStringRef MIMEType, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void *clientInfo)
+{
+ WKFramePolicyListenerUse(listener);
+}
+
+#pragma mark UI Client Callbacks
+
+static WKPageRef createNewPage(WKPageRef page, WKDictionaryRef features, WKEventModifiers modifiers, WKEventMouseButton button, const void* clientInfo)
+{
+ LOG(@"createNewPage");
+ BrowserWindowController *controller = [[BrowserWindowController alloc] initWithContext:WKPageGetContext(page)];
+ [controller loadWindow];
+
+ return controller->_webView.pageRef;
+}
+
+static void showPage(WKPageRef page, const void *clientInfo)
+{
+ LOG(@"showPage");
+ [[(BrowserWindowController *)clientInfo window] orderFront:nil];
+}
+
+static void closePage(WKPageRef page, const void *clientInfo)
+{
+ LOG(@"closePage");
+ WKPageClose(page);
+ [[(BrowserWindowController *)clientInfo window] close];
+ WKRelease(page);
+}
+
+static void runJavaScriptAlert(WKPageRef page, WKStringRef message, WKFrameRef frame, const void* clientInfo)
+{
+ NSAlert* alert = [[NSAlert alloc] init];
+
+ WKURLRef wkURL = WKFrameCopyURL(frame);
+ CFURLRef cfURL = WKURLCopyCFURL(0, wkURL);
+ WKRelease(wkURL);
+
+ [alert setMessageText:[NSString stringWithFormat:@"JavaScript alert dialog from %@.", [(NSURL *)cfURL absoluteString]]];
+ CFRelease(cfURL);
+
+ CFStringRef cfMessage = WKStringCopyCFString(0, message);
+ [alert setInformativeText:(NSString *)cfMessage];
+ CFRelease(cfMessage);
+
+ [alert addButtonWithTitle:@"OK"];
+
+ [alert runModal];
+ [alert release];
+}
+
+static bool runJavaScriptConfirm(WKPageRef page, WKStringRef message, WKFrameRef frame, const void* clientInfo)
+{
+ NSAlert* alert = [[NSAlert alloc] init];
+
+ WKURLRef wkURL = WKFrameCopyURL(frame);
+ CFURLRef cfURL = WKURLCopyCFURL(0, wkURL);
+ WKRelease(wkURL);
+
+ [alert setMessageText:[NSString stringWithFormat:@"JavaScript confirm dialog from %@.", [(NSURL *)cfURL absoluteString]]];
+ CFRelease(cfURL);
+
+ CFStringRef cfMessage = WKStringCopyCFString(0, message);
+ [alert setInformativeText:(NSString *)cfMessage];
+ CFRelease(cfMessage);
+
+ [alert addButtonWithTitle:@"OK"];
+ [alert addButtonWithTitle:@"Cancel"];
+
+ NSInteger button = [alert runModal];
+ [alert release];
+
+ return button == NSAlertFirstButtonReturn;
+}
+
+static WKStringRef runJavaScriptPrompt(WKPageRef page, WKStringRef message, WKStringRef defaultValue, WKFrameRef frame, const void* clientInfo)
+{
+ NSAlert* alert = [[NSAlert alloc] init];
+
+ WKURLRef wkURL = WKFrameCopyURL(frame);
+ CFURLRef cfURL = WKURLCopyCFURL(0, wkURL);
+ WKRelease(wkURL);
+
+ [alert setMessageText:[NSString stringWithFormat:@"JavaScript prompt dialog from %@.", [(NSURL *)cfURL absoluteString]]];
+ CFRelease(cfURL);
+
+ CFStringRef cfMessage = WKStringCopyCFString(0, message);
+ [alert setInformativeText:(NSString *)cfMessage];
+ CFRelease(cfMessage);
+
+ [alert addButtonWithTitle:@"OK"];
+ [alert addButtonWithTitle:@"Cancel"];
+
+ NSTextField* input = [[NSTextField alloc] initWithFrame:NSMakeRect(0, 0, 200, 24)];
+ CFStringRef cfDefaultValue = WKStringCopyCFString(0, defaultValue);
+ [input setStringValue:(NSString *)cfDefaultValue];
+ CFRelease(cfDefaultValue);
+
+ [alert setAccessoryView:input];
+
+ NSInteger button = [alert runModal];
+
+ NSString* result = nil;
+ if (button == NSAlertFirstButtonReturn) {
+ [input validateEditing];
+ result = [input stringValue];
+ }
+
+ [alert release];
+
+ if (!result)
+ return 0;
+ return WKStringCreateWithCFString((CFStringRef)result);
+}
+
+static void setStatusText(WKPageRef page, WKStringRef text, const void* clientInfo)
+{
+ LOG(@"setStatusText");
+}
+
+static void mouseDidMoveOverElement(WKPageRef page, WKEventModifiers modifiers, WKTypeRef userData, const void *clientInfo)
+{
+ LOG(@"mouseDidMoveOverElement");
+}
+
+static WKRect getWindowFrame(WKPageRef page, const void* clientInfo)
+{
+ NSRect rect = [[(BrowserWindowController *)clientInfo window] frame];
+ WKRect wkRect;
+ wkRect.origin.x = rect.origin.x;
+ wkRect.origin.y = rect.origin.y;
+ wkRect.size.width = rect.size.width;
+ wkRect.size.height = rect.size.height;
+ return wkRect;
+}
+
+static void setWindowFrame(WKPageRef page, WKRect rect, const void* clientInfo)
+{
+ [[(BrowserWindowController *)clientInfo window] setFrame:NSMakeRect(rect.origin.x, rect.origin.y, rect.size.width, rect.size.height) display:YES];
+}
+
+static bool runBeforeUnloadConfirmPanel(WKPageRef page, WKStringRef message, WKFrameRef frame, const void* clientInfo)
+{
+ NSAlert *alert = [[NSAlert alloc] init];
+
+ WKURLRef wkURL = WKFrameCopyURL(frame);
+ CFURLRef cfURL = WKURLCopyCFURL(0, wkURL);
+ WKRelease(wkURL);
+
+ [alert setMessageText:[NSString stringWithFormat:@"BeforeUnload confirm dialog from %@.", [(NSURL *)cfURL absoluteString]]];
+ CFRelease(cfURL);
+
+ CFStringRef cfMessage = WKStringCopyCFString(0, message);
+ [alert setInformativeText:(NSString *)cfMessage];
+ CFRelease(cfMessage);
+
+ [alert addButtonWithTitle:@"OK"];
+ [alert addButtonWithTitle:@"Cancel"];
+
+ NSInteger button = [alert runModal];
+ [alert release];
+
+ return button == NSAlertFirstButtonReturn;
+}
+
+static void runOpenPanel(WKPageRef page, WKFrameRef frame, WKOpenPanelParametersRef parameters, WKOpenPanelResultListenerRef listener, const void* clientInfo)
+{
+ NSOpenPanel *openPanel = [NSOpenPanel openPanel];
+ [openPanel setAllowsMultipleSelection:WKOpenPanelParametersGetAllowsMultipleFiles(parameters)];
+
+ WKRetain(listener);
+
+ [openPanel beginSheetModalForWindow:[(BrowserWindowController *)clientInfo window] completionHandler:^(NSInteger result) {
+ if (result == NSFileHandlingPanelOKButton) {
+ WKMutableArrayRef fileURLs = WKMutableArrayCreate();
+
+ NSURL *nsURL;
+ for (nsURL in [openPanel URLs]) {
+ WKURLRef wkURL = WKURLCreateWithCFURL((CFURLRef)nsURL);
+ WKArrayAppendItem(fileURLs, wkURL);
+ WKRelease(wkURL);
+ }
+
+ WKOpenPanelResultListenerChooseFiles(listener, fileURLs);
+
+ WKRelease(fileURLs);
+ } else
+ WKOpenPanelResultListenerCancel(listener);
+
+ WKRelease(listener);
+ }];
+}
+
+- (void)awakeFromNib
+{
+ _webView = [[WKView alloc] initWithFrame:[containerView frame] contextRef:_context];
+
+ [containerView addSubview:_webView];
+ [_webView setFrame:[containerView frame]];
+
+ [_webView setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)];
+
+ WKPageLoaderClient loadClient = {
+ 0, /* version */
+ self, /* clientInfo */
+ didStartProvisionalLoadForFrame,
+ didReceiveServerRedirectForProvisionalLoadForFrame,
+ didFailProvisionalLoadWithErrorForFrame,
+ didCommitLoadForFrame,
+ didFinishDocumentLoadForFrame,
+ didFinishLoadForFrame,
+ didFailLoadWithErrorForFrame,
+ didSameDocumentNavigationForFrame,
+ didReceiveTitleForFrame,
+ didFirstLayoutForFrame,
+ didFirstVisuallyNonEmptyLayoutForFrame,
+ didRemoveFrameFromHierarchy,
+ didDisplayInsecureContentForFrame,
+ didRunInsecureContentForFrame,
+ 0, // canAuthenticateAgainstProtectionSpaceInFrame
+ 0, // didReceiveAuthenticationChallengeInFrame
+ didStartProgress,
+ didChangeProgress,
+ didFinishProgress,
+ didBecomeUnresponsive,
+ didBecomeResponsive,
+ processDidExit,
+ didChangeBackForwardList
+ };
+ WKPageSetPageLoaderClient(_webView.pageRef, &loadClient);
+
+ WKPagePolicyClient policyClient = {
+ 0, /* version */
+ self, /* clientInfo */
+ decidePolicyForNavigationAction,
+ decidePolicyForNewWindowAction,
+ decidePolicyForMIMEType
+ };
+ WKPageSetPagePolicyClient(_webView.pageRef, &policyClient);
+
+ WKPageUIClient uiClient = {
+ 0, /* version */
+ self, /* clientInfo */
+ createNewPage,
+ showPage,
+ closePage,
+ runJavaScriptAlert,
+ runJavaScriptConfirm,
+ runJavaScriptPrompt,
+ setStatusText,
+ mouseDidMoveOverElement,
+ 0, /* missingPluginButtonClicked */
+ 0, /* didNotHandleKeyEvent */
+ 0, /* toolbarsAreVisible */
+ 0, /* setToolbarsAreVisible */
+ 0, /* menuBarIsVisible */
+ 0, /* setMenuBarIsVisible */
+ 0, /* statusBarIsVisible */
+ 0, /* setStatusBarIsVisible */
+ 0, /* isResizable */
+ 0, /* setIsResizable */
+ getWindowFrame,
+ setWindowFrame,
+ runBeforeUnloadConfirmPanel,
+ 0, /* didDraw */
+ 0, /* pageDidScroll */
+ 0, /* exceededDatabaseQuota */
+ runOpenPanel
+ };
+ WKPageSetPageUIClient(_webView.pageRef, &uiClient);
+}
+
+- (void)didStartProgress
+{
+ [progressIndicator setDoubleValue:0.0];
+ [progressIndicator setHidden:NO];
+}
+
+- (void)didChangeProgress:(double)value
+{
+ [progressIndicator setDoubleValue:value];
+}
+
+- (void)didFinishProgress
+{
+ [progressIndicator setHidden:YES];
+ [progressIndicator setDoubleValue:1.0];
+}
+
+- (void)updateProvisionalURLForFrame:(WKFrameRef)frame
+{
+ static WKURLRef emptyURL = 0;
+ if (!emptyURL)
+ emptyURL = WKURLCreateWithUTF8CString("");
+
+ WKURLRef url = WKFrameCopyProvisionalURL(frame);
+ if (WKURLIsEqual(url, emptyURL)) {
+ WKRelease(url);
+ return;
+ }
+
+ CFURLRef cfSourceURL = WKURLCopyCFURL(0, url);
+ WKRelease(url);
+
+ [urlText setStringValue:(NSString*)CFURLGetString(cfSourceURL)];
+ CFRelease(cfSourceURL);
+}
+
+- (void)didStartProvisionalLoadForFrame:(WKFrameRef)frame
+{
+ if (!WKFrameIsMainFrame(frame))
+ return;
+
+ [self updateProvisionalURLForFrame:frame];
+}
+
+- (void)didReceiveServerRedirectForProvisionalLoadForFrame:(WKFrameRef)frame
+{
+ if (!WKFrameIsMainFrame(frame))
+ return;
+
+ [self updateProvisionalURLForFrame:frame];
+}
+
+- (void)didFailProvisionalLoadWithErrorForFrame:(WKFrameRef)frame
+{
+ if (!WKFrameIsMainFrame(frame))
+ return;
+
+ [self updateProvisionalURLForFrame:frame];
+}
+
+- (void)didFailLoadWithErrorForFrame:(WKFrameRef)frame
+{
+ if (!WKFrameIsMainFrame(frame))
+ return;
+
+ [self updateProvisionalURLForFrame:frame];
+}
+
+- (void)didSameDocumentNavigationForFrame:(WKFrameRef)frame
+{
+}
+
+- (void)didCommitLoadForFrame:(WKFrameRef)frame
+{
+}
+
+- (void)loadURLString:(NSString *)urlString
+{
+ // FIXME: We shouldn't have to set the url text here.
+ [urlText setStringValue:urlString];
+ [self fetch:nil];
+}
+
+- (IBAction)performFindPanelAction:(id)sender
+{
+ [findPanelWindow makeKeyAndOrderFront:sender];
+}
+
+- (IBAction)find:(id)sender
+{
+ WKStringRef string = WKStringCreateWithCFString((CFStringRef)[sender stringValue]);
+
+ WKPageFindString(_webView.pageRef, string, kWKFindOptionsCaseInsensitive | kWKFindOptionsWrapAround | kWKFindOptionsShowFindIndicator | kWKFindOptionsShowOverlay, 100);
+}
+
+@end
diff --git a/Tools/MiniBrowser/mac/Info.plist b/Tools/MiniBrowser/mac/Info.plist
new file mode 100644
index 0000000..7564a7e
--- /dev/null
+++ b/Tools/MiniBrowser/mac/Info.plist
@@ -0,0 +1,32 @@
+<?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>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIconFile</key>
+ <string>MiniBrowser</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>LSMinimumSystemVersion</key>
+ <string>${MACOSX_DEPLOYMENT_TARGET}</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+ <key>NSMainNibFile</key>
+ <string>MainMenu</string>
+ <key>NSPrincipalClass</key>
+ <string>NSApplication</string>
+</dict>
+</plist>
diff --git a/Tools/MiniBrowser/mac/MainMenu.xib b/Tools/MiniBrowser/mac/MainMenu.xib
new file mode 100644
index 0000000..634f615
--- /dev/null
+++ b/Tools/MiniBrowser/mac/MainMenu.xib
@@ -0,0 +1,3623 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<archive type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="7.10">
+ <data>
+ <int key="IBDocument.SystemTarget">1060</int>
+ <string key="IBDocument.SystemVersion">10F569</string>
+ <string key="IBDocument.InterfaceBuilderVersion">788</string>
+ <string key="IBDocument.AppKitVersion">1038.29</string>
+ <string key="IBDocument.HIToolboxVersion">461.00</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginVersions">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string key="NS.object.0">788</string>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <integer value="535"/>
+ </object>
+ <object class="NSArray" key="IBDocument.PluginDependencies">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ </object>
+ <object class="NSMutableDictionary" key="IBDocument.Metadata">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys" id="0">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="IBDocument.RootObjects" id="1048">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSCustomObject" id="1021">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSCustomObject" id="1014">
+ <string key="NSClassName">FirstResponder</string>
+ </object>
+ <object class="NSCustomObject" id="1050">
+ <string key="NSClassName">NSApplication</string>
+ </object>
+ <object class="NSMenu" id="649796088">
+ <string key="NSTitle">AMainMenu</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="694149608">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">MiniBrowser</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <object class="NSCustomResource" key="NSOnImage" id="35465992">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSMenuCheckmark</string>
+ </object>
+ <object class="NSCustomResource" key="NSMixedImage" id="502551668">
+ <string key="NSClassName">NSImage</string>
+ <string key="NSResourceName">NSMenuMixedState</string>
+ </object>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="110575045">
+ <string key="NSTitle">MiniBrowser</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="238522557">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">About MiniBrowser</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="304266470">
+ <reference key="NSMenu" ref="110575045"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="609285721">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Preferences…</string>
+ <string key="NSKeyEquiv">,</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="481834944">
+ <reference key="NSMenu" ref="110575045"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1046388886">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Services</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="752062318">
+ <string key="NSTitle">Services</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <string key="NSName">_NSServicesMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="646227648">
+ <reference key="NSMenu" ref="110575045"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="755159360">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Hide MiniBrowser</string>
+ <string key="NSKeyEquiv">h</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="342932134">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Hide Others</string>
+ <string key="NSKeyEquiv">h</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="908899353">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Show All</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1056857174">
+ <reference key="NSMenu" ref="110575045"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="632727374">
+ <reference key="NSMenu" ref="110575045"/>
+ <string key="NSTitle">Quit MiniBrowser</string>
+ <string key="NSKeyEquiv">q</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ <string key="NSName">_NSAppleMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="379814623">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">File</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="720053764">
+ <string key="NSTitle">File</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="705341025">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">New Window</string>
+ <string key="NSKeyEquiv">n</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="722745758">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Open…</string>
+ <string key="NSKeyEquiv">o</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1025936716">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Open Recent</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="1065607017">
+ <string key="NSTitle">Open Recent</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="759406840">
+ <reference key="NSMenu" ref="1065607017"/>
+ <string key="NSTitle">Clear Menu</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ <string key="NSName">_NSRecentDocumentsMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="425164168">
+ <reference key="NSMenu" ref="720053764"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="776162233">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Close</string>
+ <string key="NSKeyEquiv">w</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1023925487">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Save</string>
+ <string key="NSKeyEquiv">s</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="117038363">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Save As…</string>
+ <string key="NSKeyEquiv">S</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="579971712">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Revert to Saved</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1010469920">
+ <reference key="NSMenu" ref="720053764"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="294629803">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Page Setup...</string>
+ <string key="NSKeyEquiv">P</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSToolTip"/>
+ </object>
+ <object class="NSMenuItem" id="49223823">
+ <reference key="NSMenu" ref="720053764"/>
+ <string key="NSTitle">Print…</string>
+ <string key="NSKeyEquiv">p</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="952259628">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Edit</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="789758025">
+ <string key="NSTitle">Edit</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="1058277027">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Undo</string>
+ <string key="NSKeyEquiv">z</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="790794224">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Redo</string>
+ <string key="NSKeyEquiv">Z</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1040322652">
+ <reference key="NSMenu" ref="789758025"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="296257095">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Cut</string>
+ <string key="NSKeyEquiv">x</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="860595796">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Copy</string>
+ <string key="NSKeyEquiv">c</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="29853731">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Paste</string>
+ <string key="NSKeyEquiv">v</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="82994268">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Paste and Match Style</string>
+ <string key="NSKeyEquiv">V</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="437104165">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Delete</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="583158037">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Select All</string>
+ <string key="NSKeyEquiv">a</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="212016141">
+ <reference key="NSMenu" ref="789758025"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="892235320">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Find</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="963351320">
+ <string key="NSTitle">Find</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="447796847">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Find…</string>
+ <string key="NSKeyEquiv">f</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">1</int>
+ </object>
+ <object class="NSMenuItem" id="326711663">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Find Next</string>
+ <string key="NSKeyEquiv">g</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">2</int>
+ </object>
+ <object class="NSMenuItem" id="270902937">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Find Previous</string>
+ <string key="NSKeyEquiv">G</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">3</int>
+ </object>
+ <object class="NSMenuItem" id="159080638">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Use Selection for Find</string>
+ <string key="NSKeyEquiv">e</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">7</int>
+ </object>
+ <object class="NSMenuItem" id="88285865">
+ <reference key="NSMenu" ref="963351320"/>
+ <string key="NSTitle">Jump to Selection</string>
+ <string key="NSKeyEquiv">j</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="972420730">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Spelling and Grammar</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="769623530">
+ <string key="NSTitle">Spelling and Grammar</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="679648819">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Show Spelling and Grammar</string>
+ <string key="NSKeyEquiv">:</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="96193923">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Check Document Now</string>
+ <string key="NSKeyEquiv">;</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="859480356">
+ <reference key="NSMenu" ref="769623530"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="948374510">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Check Spelling While Typing</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="967646866">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Check Grammar With Spelling</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="795346622">
+ <reference key="NSMenu" ref="769623530"/>
+ <string key="NSTitle">Correct Spelling Automatically</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="507821607">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Substitutions</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="698887838">
+ <string key="NSTitle">Substitutions</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="65139061">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Show Substitutions</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="19036812">
+ <reference key="NSMenu" ref="698887838"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="605118523">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Smart Copy/Paste</string>
+ <string key="NSKeyEquiv">f</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">1</int>
+ </object>
+ <object class="NSMenuItem" id="197661976">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Smart Quotes</string>
+ <string key="NSKeyEquiv">g</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">2</int>
+ </object>
+ <object class="NSMenuItem" id="672708820">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Smart Dashes</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="708854459">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Smart Links</string>
+ <string key="NSKeyEquiv">G</string>
+ <int key="NSKeyEquivModMask">1179648</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <int key="NSTag">3</int>
+ </object>
+ <object class="NSMenuItem" id="537092702">
+ <reference key="NSMenu" ref="698887838"/>
+ <string key="NSTitle">Text Replacement</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="288088188">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Transformations</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="579392910">
+ <string key="NSTitle">Transformations</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="1060694897">
+ <reference key="NSMenu" ref="579392910"/>
+ <string key="NSTitle">Make Upper Case</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="879586729">
+ <reference key="NSMenu" ref="579392910"/>
+ <string key="NSTitle">Make Lower Case</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="56570060">
+ <reference key="NSMenu" ref="579392910"/>
+ <string key="NSTitle">Capitalize</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="676164635">
+ <reference key="NSMenu" ref="789758025"/>
+ <string key="NSTitle">Speech</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="785027613">
+ <string key="NSTitle">Speech</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="731782645">
+ <reference key="NSMenu" ref="785027613"/>
+ <string key="NSTitle">Start Speaking</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="680220178">
+ <reference key="NSMenu" ref="785027613"/>
+ <string key="NSTitle">Stop Speaking</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="586577488">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">View</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="466310130">
+ <string key="NSTitle">View</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="102151532">
+ <reference key="NSMenu" ref="466310130"/>
+ <string key="NSTitle">Show Toolbar</string>
+ <string key="NSKeyEquiv">t</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="237841660">
+ <reference key="NSMenu" ref="466310130"/>
+ <string key="NSTitle">Customize Toolbar…</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1025359947">
+ <reference key="NSMenu" ref="466310130"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="694544109">
+ <reference key="NSMenu" ref="466310130"/>
+ <string key="NSTitle">Zoom In</string>
+ <string key="NSKeyEquiv">+</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="943694335">
+ <reference key="NSMenu" ref="466310130"/>
+ <string key="NSTitle">Zoom Out</string>
+ <string key="NSKeyEquiv">-</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="863984465">
+ <reference key="NSMenu" ref="466310130"/>
+ <string key="NSTitle">Reset Zoom</string>
+ <string key="NSKeyEquiv">0</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="138443116">
+ <reference key="NSMenu" ref="466310130"/>
+ <string key="NSTitle">Zoom Text Only</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="713487014">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Window</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="835318025">
+ <string key="NSTitle">Window</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="1011231497">
+ <reference key="NSMenu" ref="835318025"/>
+ <string key="NSTitle">Minimize</string>
+ <string key="NSKeyEquiv">m</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="575023229">
+ <reference key="NSMenu" ref="835318025"/>
+ <string key="NSTitle">Zoom</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="299356726">
+ <reference key="NSMenu" ref="835318025"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="625202149">
+ <reference key="NSMenu" ref="835318025"/>
+ <string key="NSTitle">Bring All to Front</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ <string key="NSName">_NSWindowsMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="448692316">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Help</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="992780483">
+ <string key="NSTitle">Help</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="105068016">
+ <reference key="NSMenu" ref="992780483"/>
+ <string key="NSTitle">MiniBrowser Help</string>
+ <string key="NSKeyEquiv">?</string>
+ <int key="NSKeyEquivModMask">1048576</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ <string key="NSName">_NSHelpMenu</string>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="816668511">
+ <reference key="NSMenu" ref="649796088"/>
+ <string key="NSTitle">Debug</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="865232259">
+ <string key="NSTitle">Debug</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="878165919">
+ <reference key="NSMenu" ref="865232259"/>
+ <string key="NSTitle">Force Repaint</string>
+ <string key="NSKeyEquiv">r</string>
+ <int key="NSKeyEquivModMask">1572864</int>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="137933275">
+ <reference key="NSMenu" ref="865232259"/>
+ <string key="NSTitle">Hide Web View</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="1027125810">
+ <reference key="NSMenu" ref="865232259"/>
+ <string key="NSTitle">Remove Web View</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="864702084">
+ <reference key="NSMenu" ref="865232259"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="208343368">
+ <reference key="NSMenu" ref="865232259"/>
+ <string key="NSTitle">Show Statistics Window</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="162978490">
+ <reference key="NSMenu" ref="865232259"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="340689355">
+ <reference key="NSMenu" ref="865232259"/>
+ <string key="NSTitle">Process Model</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ <string key="NSAction">submenuAction:</string>
+ <object class="NSMenu" key="NSSubmenu" id="935112943">
+ <string key="NSTitle">Process Model</string>
+ <object class="NSMutableArray" key="NSMenuItems">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSMenuItem" id="993856752">
+ <reference key="NSMenu" ref="935112943"/>
+ <string key="NSTitle">Shared Process</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="516840223">
+ <reference key="NSMenu" ref="935112943"/>
+ <string key="NSTitle">Shared Thread</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ <object class="NSMenuItem" id="377902755">
+ <reference key="NSMenu" ref="865232259"/>
+ <bool key="NSIsDisabled">YES</bool>
+ <bool key="NSIsSeparator">YES</bool>
+ <string key="NSTitle"/>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ <object class="NSMenuItem" id="191469404">
+ <reference key="NSMenu" ref="865232259"/>
+ <string key="NSTitle">Dump Source To Console</string>
+ <string key="NSKeyEquiv"/>
+ <int key="NSMnemonicLoc">2147483647</int>
+ <reference key="NSOnImage" ref="35465992"/>
+ <reference key="NSMixedImage" ref="502551668"/>
+ </object>
+ </object>
+ </object>
+ </object>
+ </object>
+ <string key="NSName">_NSMainMenu</string>
+ </object>
+ <object class="NSCustomObject" id="976324537">
+ <string key="NSClassName">BrowserAppDelegate</string>
+ </object>
+ <object class="NSCustomObject" id="755631768">
+ <string key="NSClassName">NSFontManager</string>
+ </object>
+ </object>
+ <object class="IBObjectContainer" key="IBDocument.Objects">
+ <object class="NSMutableArray" key="connectionRecords">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performMiniaturize:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1011231497"/>
+ </object>
+ <int key="connectionID">37</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">arrangeInFront:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="625202149"/>
+ </object>
+ <int key="connectionID">39</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">print:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="49223823"/>
+ </object>
+ <int key="connectionID">86</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">runPageLayout:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="294629803"/>
+ </object>
+ <int key="connectionID">87</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">clearRecentDocuments:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="759406840"/>
+ </object>
+ <int key="connectionID">127</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">orderFrontStandardAboutPanel:</string>
+ <reference key="source" ref="1021"/>
+ <reference key="destination" ref="238522557"/>
+ </object>
+ <int key="connectionID">142</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performClose:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="776162233"/>
+ </object>
+ <int key="connectionID">193</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleContinuousSpellChecking:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="948374510"/>
+ </object>
+ <int key="connectionID">222</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">undo:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1058277027"/>
+ </object>
+ <int key="connectionID">223</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">copy:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="860595796"/>
+ </object>
+ <int key="connectionID">224</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">checkSpelling:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="96193923"/>
+ </object>
+ <int key="connectionID">225</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">paste:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="29853731"/>
+ </object>
+ <int key="connectionID">226</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">stopSpeaking:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="680220178"/>
+ </object>
+ <int key="connectionID">227</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">cut:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="296257095"/>
+ </object>
+ <int key="connectionID">228</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">showGuessPanel:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="679648819"/>
+ </object>
+ <int key="connectionID">230</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">redo:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="790794224"/>
+ </object>
+ <int key="connectionID">231</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">selectAll:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="583158037"/>
+ </object>
+ <int key="connectionID">232</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">startSpeaking:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="731782645"/>
+ </object>
+ <int key="connectionID">233</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">delete:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="437104165"/>
+ </object>
+ <int key="connectionID">235</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performZoom:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="575023229"/>
+ </object>
+ <int key="connectionID">240</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="447796847"/>
+ </object>
+ <int key="connectionID">241</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">centerSelectionInVisibleArea:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="88285865"/>
+ </object>
+ <int key="connectionID">245</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleGrammarChecking:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="967646866"/>
+ </object>
+ <int key="connectionID">347</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleSmartInsertDelete:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="605118523"/>
+ </object>
+ <int key="connectionID">355</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticQuoteSubstitution:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="197661976"/>
+ </object>
+ <int key="connectionID">356</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticLinkDetection:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="708854459"/>
+ </object>
+ <int key="connectionID">357</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">saveDocument:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1023925487"/>
+ </object>
+ <int key="connectionID">362</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">saveDocumentAs:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="117038363"/>
+ </object>
+ <int key="connectionID">363</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">revertDocumentToSaved:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="579971712"/>
+ </object>
+ <int key="connectionID">364</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">runToolbarCustomizationPalette:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="237841660"/>
+ </object>
+ <int key="connectionID">365</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleToolbarShown:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="102151532"/>
+ </object>
+ <int key="connectionID">366</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">hide:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="755159360"/>
+ </object>
+ <int key="connectionID">367</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">hideOtherApplications:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="342932134"/>
+ </object>
+ <int key="connectionID">368</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">unhideAllApplications:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="908899353"/>
+ </object>
+ <int key="connectionID">370</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">openDocument:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="722745758"/>
+ </object>
+ <int key="connectionID">374</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">terminate:</string>
+ <reference key="source" ref="1050"/>
+ <reference key="destination" ref="632727374"/>
+ </object>
+ <int key="connectionID">449</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticSpellingCorrection:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="795346622"/>
+ </object>
+ <int key="connectionID">456</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">orderFrontSubstitutionsPanel:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="65139061"/>
+ </object>
+ <int key="connectionID">458</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticDashSubstitution:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="672708820"/>
+ </object>
+ <int key="connectionID">461</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleAutomaticTextReplacement:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="537092702"/>
+ </object>
+ <int key="connectionID">463</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">uppercaseWord:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1060694897"/>
+ </object>
+ <int key="connectionID">464</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">capitalizeWord:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="56570060"/>
+ </object>
+ <int key="connectionID">467</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">lowercaseWord:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="879586729"/>
+ </object>
+ <int key="connectionID">468</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">pasteAsPlainText:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="82994268"/>
+ </object>
+ <int key="connectionID">486</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="326711663"/>
+ </object>
+ <int key="connectionID">487</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="270902937"/>
+ </object>
+ <int key="connectionID">488</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">performFindPanelAction:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="159080638"/>
+ </object>
+ <int key="connectionID">489</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">showHelp:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="105068016"/>
+ </object>
+ <int key="connectionID">493</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBOutletConnection" key="connection">
+ <string key="label">delegate</string>
+ <reference key="source" ref="1021"/>
+ <reference key="destination" ref="976324537"/>
+ </object>
+ <int key="connectionID">495</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">newWindow:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="705341025"/>
+ </object>
+ <int key="connectionID">533</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">setSharedProcessProcessModel:</string>
+ <reference key="source" ref="976324537"/>
+ <reference key="destination" ref="993856752"/>
+ </object>
+ <int key="connectionID">543</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">setSharedThreadProcessModel:</string>
+ <reference key="source" ref="976324537"/>
+ <reference key="destination" ref="516840223"/>
+ </object>
+ <int key="connectionID">544</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">forceRepaint:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="878165919"/>
+ </object>
+ <int key="connectionID">547</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">showHideWebView:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="137933275"/>
+ </object>
+ <int key="connectionID">549</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">removeReinsertWebView:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="1027125810"/>
+ </object>
+ <int key="connectionID">551</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">showStatisticsWindow:</string>
+ <reference key="source" ref="976324537"/>
+ <reference key="destination" ref="208343368"/>
+ </object>
+ <int key="connectionID">554</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">zoomIn:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="694544109"/>
+ </object>
+ <int key="connectionID">559</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">zoomOut:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="943694335"/>
+ </object>
+ <int key="connectionID">560</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">resetZoom:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="863984465"/>
+ </object>
+ <int key="connectionID">561</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">toggleZoomMode:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="138443116"/>
+ </object>
+ <int key="connectionID">564</int>
+ </object>
+ <object class="IBConnectionRecord">
+ <object class="IBActionConnection" key="connection">
+ <string key="label">dumpSourceToConsole:</string>
+ <reference key="source" ref="1014"/>
+ <reference key="destination" ref="191469404"/>
+ </object>
+ <int key="connectionID">567</int>
+ </object>
+ </object>
+ <object class="IBMutableOrderedSet" key="objectRecords">
+ <object class="NSArray" key="orderedObjects">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBObjectRecord">
+ <int key="objectID">0</int>
+ <reference key="object" ref="0"/>
+ <reference key="children" ref="1048"/>
+ <nil key="parent"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-2</int>
+ <reference key="object" ref="1021"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">File's Owner</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-1</int>
+ <reference key="object" ref="1014"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">First Responder</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">-3</int>
+ <reference key="object" ref="1050"/>
+ <reference key="parent" ref="0"/>
+ <string key="objectName">Application</string>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">29</int>
+ <reference key="object" ref="649796088"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="713487014"/>
+ <reference ref="694149608"/>
+ <reference ref="952259628"/>
+ <reference ref="379814623"/>
+ <reference ref="586577488"/>
+ <reference ref="448692316"/>
+ <reference ref="816668511"/>
+ </object>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">19</int>
+ <reference key="object" ref="713487014"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="835318025"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">56</int>
+ <reference key="object" ref="694149608"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="110575045"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">217</int>
+ <reference key="object" ref="952259628"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="789758025"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">83</int>
+ <reference key="object" ref="379814623"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="720053764"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">81</int>
+ <reference key="object" ref="720053764"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1023925487"/>
+ <reference ref="117038363"/>
+ <reference ref="49223823"/>
+ <reference ref="722745758"/>
+ <reference ref="705341025"/>
+ <reference ref="1025936716"/>
+ <reference ref="294629803"/>
+ <reference ref="776162233"/>
+ <reference ref="425164168"/>
+ <reference ref="579971712"/>
+ <reference ref="1010469920"/>
+ </object>
+ <reference key="parent" ref="379814623"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">75</int>
+ <reference key="object" ref="1023925487"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">80</int>
+ <reference key="object" ref="117038363"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">78</int>
+ <reference key="object" ref="49223823"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">72</int>
+ <reference key="object" ref="722745758"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">82</int>
+ <reference key="object" ref="705341025"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">124</int>
+ <reference key="object" ref="1025936716"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1065607017"/>
+ </object>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">77</int>
+ <reference key="object" ref="294629803"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">73</int>
+ <reference key="object" ref="776162233"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">79</int>
+ <reference key="object" ref="425164168"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">112</int>
+ <reference key="object" ref="579971712"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">74</int>
+ <reference key="object" ref="1010469920"/>
+ <reference key="parent" ref="720053764"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">125</int>
+ <reference key="object" ref="1065607017"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="759406840"/>
+ </object>
+ <reference key="parent" ref="1025936716"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">126</int>
+ <reference key="object" ref="759406840"/>
+ <reference key="parent" ref="1065607017"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">205</int>
+ <reference key="object" ref="789758025"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="437104165"/>
+ <reference ref="583158037"/>
+ <reference ref="1058277027"/>
+ <reference ref="212016141"/>
+ <reference ref="296257095"/>
+ <reference ref="29853731"/>
+ <reference ref="860595796"/>
+ <reference ref="1040322652"/>
+ <reference ref="790794224"/>
+ <reference ref="892235320"/>
+ <reference ref="972420730"/>
+ <reference ref="676164635"/>
+ <reference ref="507821607"/>
+ <reference ref="288088188"/>
+ <reference ref="82994268"/>
+ </object>
+ <reference key="parent" ref="952259628"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">202</int>
+ <reference key="object" ref="437104165"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">198</int>
+ <reference key="object" ref="583158037"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">207</int>
+ <reference key="object" ref="1058277027"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">214</int>
+ <reference key="object" ref="212016141"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">199</int>
+ <reference key="object" ref="296257095"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">203</int>
+ <reference key="object" ref="29853731"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">197</int>
+ <reference key="object" ref="860595796"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">206</int>
+ <reference key="object" ref="1040322652"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">215</int>
+ <reference key="object" ref="790794224"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">218</int>
+ <reference key="object" ref="892235320"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="963351320"/>
+ </object>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">216</int>
+ <reference key="object" ref="972420730"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="769623530"/>
+ </object>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">200</int>
+ <reference key="object" ref="769623530"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="948374510"/>
+ <reference ref="96193923"/>
+ <reference ref="679648819"/>
+ <reference ref="967646866"/>
+ <reference ref="859480356"/>
+ <reference ref="795346622"/>
+ </object>
+ <reference key="parent" ref="972420730"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">219</int>
+ <reference key="object" ref="948374510"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">201</int>
+ <reference key="object" ref="96193923"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">204</int>
+ <reference key="object" ref="679648819"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">220</int>
+ <reference key="object" ref="963351320"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="270902937"/>
+ <reference ref="88285865"/>
+ <reference ref="159080638"/>
+ <reference ref="326711663"/>
+ <reference ref="447796847"/>
+ </object>
+ <reference key="parent" ref="892235320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">213</int>
+ <reference key="object" ref="270902937"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">210</int>
+ <reference key="object" ref="88285865"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">221</int>
+ <reference key="object" ref="159080638"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">208</int>
+ <reference key="object" ref="326711663"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">209</int>
+ <reference key="object" ref="447796847"/>
+ <reference key="parent" ref="963351320"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">57</int>
+ <reference key="object" ref="110575045"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="238522557"/>
+ <reference ref="755159360"/>
+ <reference ref="908899353"/>
+ <reference ref="632727374"/>
+ <reference ref="646227648"/>
+ <reference ref="609285721"/>
+ <reference ref="481834944"/>
+ <reference ref="304266470"/>
+ <reference ref="1046388886"/>
+ <reference ref="1056857174"/>
+ <reference ref="342932134"/>
+ </object>
+ <reference key="parent" ref="694149608"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">58</int>
+ <reference key="object" ref="238522557"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">134</int>
+ <reference key="object" ref="755159360"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">150</int>
+ <reference key="object" ref="908899353"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">136</int>
+ <reference key="object" ref="632727374"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">144</int>
+ <reference key="object" ref="646227648"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">129</int>
+ <reference key="object" ref="609285721"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">143</int>
+ <reference key="object" ref="481834944"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">236</int>
+ <reference key="object" ref="304266470"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">131</int>
+ <reference key="object" ref="1046388886"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="752062318"/>
+ </object>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">149</int>
+ <reference key="object" ref="1056857174"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">145</int>
+ <reference key="object" ref="342932134"/>
+ <reference key="parent" ref="110575045"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">130</int>
+ <reference key="object" ref="752062318"/>
+ <reference key="parent" ref="1046388886"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">24</int>
+ <reference key="object" ref="835318025"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="299356726"/>
+ <reference ref="625202149"/>
+ <reference ref="575023229"/>
+ <reference ref="1011231497"/>
+ </object>
+ <reference key="parent" ref="713487014"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">92</int>
+ <reference key="object" ref="299356726"/>
+ <reference key="parent" ref="835318025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">5</int>
+ <reference key="object" ref="625202149"/>
+ <reference key="parent" ref="835318025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">239</int>
+ <reference key="object" ref="575023229"/>
+ <reference key="parent" ref="835318025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">23</int>
+ <reference key="object" ref="1011231497"/>
+ <reference key="parent" ref="835318025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">295</int>
+ <reference key="object" ref="586577488"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="466310130"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">296</int>
+ <reference key="object" ref="466310130"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="102151532"/>
+ <reference ref="237841660"/>
+ <reference ref="694544109"/>
+ <reference ref="1025359947"/>
+ <reference ref="943694335"/>
+ <reference ref="863984465"/>
+ <reference ref="138443116"/>
+ </object>
+ <reference key="parent" ref="586577488"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">297</int>
+ <reference key="object" ref="102151532"/>
+ <reference key="parent" ref="466310130"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">298</int>
+ <reference key="object" ref="237841660"/>
+ <reference key="parent" ref="466310130"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">211</int>
+ <reference key="object" ref="676164635"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="785027613"/>
+ </object>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">212</int>
+ <reference key="object" ref="785027613"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="680220178"/>
+ <reference ref="731782645"/>
+ </object>
+ <reference key="parent" ref="676164635"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">195</int>
+ <reference key="object" ref="680220178"/>
+ <reference key="parent" ref="785027613"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">196</int>
+ <reference key="object" ref="731782645"/>
+ <reference key="parent" ref="785027613"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">346</int>
+ <reference key="object" ref="967646866"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">348</int>
+ <reference key="object" ref="507821607"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="698887838"/>
+ </object>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">349</int>
+ <reference key="object" ref="698887838"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="605118523"/>
+ <reference ref="197661976"/>
+ <reference ref="708854459"/>
+ <reference ref="65139061"/>
+ <reference ref="19036812"/>
+ <reference ref="672708820"/>
+ <reference ref="537092702"/>
+ </object>
+ <reference key="parent" ref="507821607"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">350</int>
+ <reference key="object" ref="605118523"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">351</int>
+ <reference key="object" ref="197661976"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">354</int>
+ <reference key="object" ref="708854459"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">420</int>
+ <reference key="object" ref="755631768"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">450</int>
+ <reference key="object" ref="288088188"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="579392910"/>
+ </object>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">451</int>
+ <reference key="object" ref="579392910"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="1060694897"/>
+ <reference ref="879586729"/>
+ <reference ref="56570060"/>
+ </object>
+ <reference key="parent" ref="288088188"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">452</int>
+ <reference key="object" ref="1060694897"/>
+ <reference key="parent" ref="579392910"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">453</int>
+ <reference key="object" ref="859480356"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">454</int>
+ <reference key="object" ref="795346622"/>
+ <reference key="parent" ref="769623530"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">457</int>
+ <reference key="object" ref="65139061"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">459</int>
+ <reference key="object" ref="19036812"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">460</int>
+ <reference key="object" ref="672708820"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">462</int>
+ <reference key="object" ref="537092702"/>
+ <reference key="parent" ref="698887838"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">465</int>
+ <reference key="object" ref="879586729"/>
+ <reference key="parent" ref="579392910"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">466</int>
+ <reference key="object" ref="56570060"/>
+ <reference key="parent" ref="579392910"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">485</int>
+ <reference key="object" ref="82994268"/>
+ <reference key="parent" ref="789758025"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">490</int>
+ <reference key="object" ref="448692316"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="992780483"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">491</int>
+ <reference key="object" ref="992780483"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="105068016"/>
+ </object>
+ <reference key="parent" ref="448692316"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">492</int>
+ <reference key="object" ref="105068016"/>
+ <reference key="parent" ref="992780483"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">494</int>
+ <reference key="object" ref="976324537"/>
+ <reference key="parent" ref="0"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">534</int>
+ <reference key="object" ref="816668511"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="865232259"/>
+ </object>
+ <reference key="parent" ref="649796088"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">535</int>
+ <reference key="object" ref="865232259"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="340689355"/>
+ <reference ref="878165919"/>
+ <reference ref="162978490"/>
+ <reference ref="137933275"/>
+ <reference ref="1027125810"/>
+ <reference ref="864702084"/>
+ <reference ref="208343368"/>
+ <reference ref="377902755"/>
+ <reference ref="191469404"/>
+ </object>
+ <reference key="parent" ref="816668511"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">537</int>
+ <reference key="object" ref="340689355"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="935112943"/>
+ </object>
+ <reference key="parent" ref="865232259"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">538</int>
+ <reference key="object" ref="935112943"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference ref="993856752"/>
+ <reference ref="516840223"/>
+ </object>
+ <reference key="parent" ref="340689355"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">539</int>
+ <reference key="object" ref="993856752"/>
+ <reference key="parent" ref="935112943"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">540</int>
+ <reference key="object" ref="516840223"/>
+ <object class="NSMutableArray" key="children">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ <reference key="parent" ref="935112943"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">545</int>
+ <reference key="object" ref="878165919"/>
+ <reference key="parent" ref="865232259"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">546</int>
+ <reference key="object" ref="162978490"/>
+ <reference key="parent" ref="865232259"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">548</int>
+ <reference key="object" ref="137933275"/>
+ <reference key="parent" ref="865232259"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">550</int>
+ <reference key="object" ref="1027125810"/>
+ <reference key="parent" ref="865232259"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">552</int>
+ <reference key="object" ref="208343368"/>
+ <reference key="parent" ref="865232259"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">553</int>
+ <reference key="object" ref="864702084"/>
+ <reference key="parent" ref="865232259"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">555</int>
+ <reference key="object" ref="694544109"/>
+ <reference key="parent" ref="466310130"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">556</int>
+ <reference key="object" ref="1025359947"/>
+ <reference key="parent" ref="466310130"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">557</int>
+ <reference key="object" ref="943694335"/>
+ <reference key="parent" ref="466310130"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">558</int>
+ <reference key="object" ref="863984465"/>
+ <reference key="parent" ref="466310130"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">562</int>
+ <reference key="object" ref="138443116"/>
+ <reference key="parent" ref="466310130"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">565</int>
+ <reference key="object" ref="377902755"/>
+ <reference key="parent" ref="865232259"/>
+ </object>
+ <object class="IBObjectRecord">
+ <int key="objectID">566</int>
+ <reference key="object" ref="191469404"/>
+ <reference key="parent" ref="865232259"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="flattenedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>-3.IBPluginDependency</string>
+ <string>112.IBPluginDependency</string>
+ <string>112.ImportedFromIB2</string>
+ <string>124.IBPluginDependency</string>
+ <string>124.ImportedFromIB2</string>
+ <string>125.IBPluginDependency</string>
+ <string>125.ImportedFromIB2</string>
+ <string>125.editorWindowContentRectSynchronizationRect</string>
+ <string>126.IBPluginDependency</string>
+ <string>126.ImportedFromIB2</string>
+ <string>129.IBPluginDependency</string>
+ <string>129.ImportedFromIB2</string>
+ <string>130.IBPluginDependency</string>
+ <string>130.ImportedFromIB2</string>
+ <string>130.editorWindowContentRectSynchronizationRect</string>
+ <string>131.IBPluginDependency</string>
+ <string>131.ImportedFromIB2</string>
+ <string>134.IBPluginDependency</string>
+ <string>134.ImportedFromIB2</string>
+ <string>136.IBPluginDependency</string>
+ <string>136.ImportedFromIB2</string>
+ <string>143.IBPluginDependency</string>
+ <string>143.ImportedFromIB2</string>
+ <string>144.IBPluginDependency</string>
+ <string>144.ImportedFromIB2</string>
+ <string>145.IBPluginDependency</string>
+ <string>145.ImportedFromIB2</string>
+ <string>149.IBPluginDependency</string>
+ <string>149.ImportedFromIB2</string>
+ <string>150.IBPluginDependency</string>
+ <string>150.ImportedFromIB2</string>
+ <string>19.IBPluginDependency</string>
+ <string>19.ImportedFromIB2</string>
+ <string>195.IBPluginDependency</string>
+ <string>195.ImportedFromIB2</string>
+ <string>196.IBPluginDependency</string>
+ <string>196.ImportedFromIB2</string>
+ <string>197.IBPluginDependency</string>
+ <string>197.ImportedFromIB2</string>
+ <string>198.IBPluginDependency</string>
+ <string>198.ImportedFromIB2</string>
+ <string>199.IBPluginDependency</string>
+ <string>199.ImportedFromIB2</string>
+ <string>200.IBEditorWindowLastContentRect</string>
+ <string>200.IBPluginDependency</string>
+ <string>200.ImportedFromIB2</string>
+ <string>200.editorWindowContentRectSynchronizationRect</string>
+ <string>201.IBPluginDependency</string>
+ <string>201.ImportedFromIB2</string>
+ <string>202.IBPluginDependency</string>
+ <string>202.ImportedFromIB2</string>
+ <string>203.IBPluginDependency</string>
+ <string>203.ImportedFromIB2</string>
+ <string>204.IBPluginDependency</string>
+ <string>204.ImportedFromIB2</string>
+ <string>205.IBEditorWindowLastContentRect</string>
+ <string>205.IBPluginDependency</string>
+ <string>205.ImportedFromIB2</string>
+ <string>205.editorWindowContentRectSynchronizationRect</string>
+ <string>206.IBPluginDependency</string>
+ <string>206.ImportedFromIB2</string>
+ <string>207.IBPluginDependency</string>
+ <string>207.ImportedFromIB2</string>
+ <string>208.IBPluginDependency</string>
+ <string>208.ImportedFromIB2</string>
+ <string>209.IBPluginDependency</string>
+ <string>209.ImportedFromIB2</string>
+ <string>210.IBPluginDependency</string>
+ <string>210.ImportedFromIB2</string>
+ <string>211.IBPluginDependency</string>
+ <string>211.ImportedFromIB2</string>
+ <string>212.IBPluginDependency</string>
+ <string>212.ImportedFromIB2</string>
+ <string>212.editorWindowContentRectSynchronizationRect</string>
+ <string>213.IBPluginDependency</string>
+ <string>213.ImportedFromIB2</string>
+ <string>214.IBPluginDependency</string>
+ <string>214.ImportedFromIB2</string>
+ <string>215.IBPluginDependency</string>
+ <string>215.ImportedFromIB2</string>
+ <string>216.IBPluginDependency</string>
+ <string>216.ImportedFromIB2</string>
+ <string>217.IBPluginDependency</string>
+ <string>217.ImportedFromIB2</string>
+ <string>218.IBPluginDependency</string>
+ <string>218.ImportedFromIB2</string>
+ <string>219.IBPluginDependency</string>
+ <string>219.ImportedFromIB2</string>
+ <string>220.IBEditorWindowLastContentRect</string>
+ <string>220.IBPluginDependency</string>
+ <string>220.ImportedFromIB2</string>
+ <string>220.editorWindowContentRectSynchronizationRect</string>
+ <string>221.IBPluginDependency</string>
+ <string>221.ImportedFromIB2</string>
+ <string>23.IBPluginDependency</string>
+ <string>23.ImportedFromIB2</string>
+ <string>236.IBPluginDependency</string>
+ <string>236.ImportedFromIB2</string>
+ <string>239.IBPluginDependency</string>
+ <string>239.ImportedFromIB2</string>
+ <string>24.IBEditorWindowLastContentRect</string>
+ <string>24.IBPluginDependency</string>
+ <string>24.ImportedFromIB2</string>
+ <string>24.editorWindowContentRectSynchronizationRect</string>
+ <string>29.IBEditorWindowLastContentRect</string>
+ <string>29.IBPluginDependency</string>
+ <string>29.ImportedFromIB2</string>
+ <string>29.WindowOrigin</string>
+ <string>29.editorWindowContentRectSynchronizationRect</string>
+ <string>295.IBPluginDependency</string>
+ <string>296.IBEditorWindowLastContentRect</string>
+ <string>296.IBPluginDependency</string>
+ <string>296.editorWindowContentRectSynchronizationRect</string>
+ <string>297.IBPluginDependency</string>
+ <string>298.IBPluginDependency</string>
+ <string>346.IBPluginDependency</string>
+ <string>346.ImportedFromIB2</string>
+ <string>348.IBPluginDependency</string>
+ <string>348.ImportedFromIB2</string>
+ <string>349.IBEditorWindowLastContentRect</string>
+ <string>349.IBPluginDependency</string>
+ <string>349.ImportedFromIB2</string>
+ <string>349.editorWindowContentRectSynchronizationRect</string>
+ <string>350.IBPluginDependency</string>
+ <string>350.ImportedFromIB2</string>
+ <string>351.IBPluginDependency</string>
+ <string>351.ImportedFromIB2</string>
+ <string>354.IBPluginDependency</string>
+ <string>354.ImportedFromIB2</string>
+ <string>450.IBPluginDependency</string>
+ <string>451.IBEditorWindowLastContentRect</string>
+ <string>451.IBPluginDependency</string>
+ <string>452.IBPluginDependency</string>
+ <string>453.IBPluginDependency</string>
+ <string>454.IBPluginDependency</string>
+ <string>457.IBPluginDependency</string>
+ <string>459.IBPluginDependency</string>
+ <string>460.IBPluginDependency</string>
+ <string>462.IBPluginDependency</string>
+ <string>465.IBPluginDependency</string>
+ <string>466.IBPluginDependency</string>
+ <string>485.IBPluginDependency</string>
+ <string>490.IBPluginDependency</string>
+ <string>491.IBEditorWindowLastContentRect</string>
+ <string>491.IBPluginDependency</string>
+ <string>492.IBPluginDependency</string>
+ <string>5.IBPluginDependency</string>
+ <string>5.ImportedFromIB2</string>
+ <string>534.IBPluginDependency</string>
+ <string>535.IBEditorWindowLastContentRect</string>
+ <string>535.IBPluginDependency</string>
+ <string>537.IBPluginDependency</string>
+ <string>538.IBEditorWindowLastContentRect</string>
+ <string>538.IBPluginDependency</string>
+ <string>539.IBPluginDependency</string>
+ <string>540.IBPluginDependency</string>
+ <string>545.IBPluginDependency</string>
+ <string>546.IBPluginDependency</string>
+ <string>548.IBPluginDependency</string>
+ <string>550.IBPluginDependency</string>
+ <string>552.IBPluginDependency</string>
+ <string>553.IBPluginDependency</string>
+ <string>555.IBPluginDependency</string>
+ <string>556.IBPluginDependency</string>
+ <string>557.IBPluginDependency</string>
+ <string>558.IBPluginDependency</string>
+ <string>56.IBPluginDependency</string>
+ <string>56.ImportedFromIB2</string>
+ <string>562.IBPluginDependency</string>
+ <string>565.IBPluginDependency</string>
+ <string>566.IBPluginDependency</string>
+ <string>57.IBEditorWindowLastContentRect</string>
+ <string>57.IBPluginDependency</string>
+ <string>57.ImportedFromIB2</string>
+ <string>57.editorWindowContentRectSynchronizationRect</string>
+ <string>58.IBPluginDependency</string>
+ <string>58.ImportedFromIB2</string>
+ <string>72.IBPluginDependency</string>
+ <string>72.ImportedFromIB2</string>
+ <string>73.IBPluginDependency</string>
+ <string>73.ImportedFromIB2</string>
+ <string>74.IBPluginDependency</string>
+ <string>74.ImportedFromIB2</string>
+ <string>75.IBPluginDependency</string>
+ <string>75.ImportedFromIB2</string>
+ <string>77.IBPluginDependency</string>
+ <string>77.ImportedFromIB2</string>
+ <string>78.IBPluginDependency</string>
+ <string>78.ImportedFromIB2</string>
+ <string>79.IBPluginDependency</string>
+ <string>79.ImportedFromIB2</string>
+ <string>80.IBPluginDependency</string>
+ <string>80.ImportedFromIB2</string>
+ <string>81.IBEditorWindowLastContentRect</string>
+ <string>81.IBPluginDependency</string>
+ <string>81.ImportedFromIB2</string>
+ <string>81.editorWindowContentRectSynchronizationRect</string>
+ <string>82.IBPluginDependency</string>
+ <string>82.ImportedFromIB2</string>
+ <string>83.IBPluginDependency</string>
+ <string>83.ImportedFromIB2</string>
+ <string>92.IBPluginDependency</string>
+ <string>92.ImportedFromIB2</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{522, 812}, {146, 23}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{436, 809}, {64, 6}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{753, 187}, {275, 113}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{608, 612}, {275, 83}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{650, 538}, {254, 283}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{187, 434}, {243, 243}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{608, 612}, {167, 43}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{753, 217}, {238, 103}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{608, 612}, {241, 103}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{744, 748}, {194, 73}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{525, 802}, {197, 73}}</string>
+ <string>{{488, 821}, {451, 20}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{74, 862}</string>
+ <string>{{6, 978}, {478, 20}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{694, 688}, {234, 133}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{475, 832}, {234, 43}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{746, 287}, {220, 133}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{608, 612}, {215, 63}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{753, 197}, {170, 63}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{881, 798}, {189, 23}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{864, 668}, {260, 153}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{1110, 678}, {154, 43}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <string>{{286, 129}, {275, 183}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{23, 794}, {245, 183}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{608, 618}, {196, 203}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>{{145, 474}, {199, 203}}</string>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ <string>com.apple.InterfaceBuilder.CocoaPlugin</string>
+ <integer value="1"/>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="unlocalizedProperties">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="activeLocalization"/>
+ <object class="NSMutableDictionary" key="localizations">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <reference key="dict.sortedKeys" ref="0"/>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ </object>
+ </object>
+ <nil key="sourceID"/>
+ <int key="maxID">567</int>
+ </object>
+ <object class="IBClassDescriber" key="IBDocument.Classes">
+ <object class="NSMutableArray" key="referencedPartialClassDescriptions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">BrowserAppDelegate</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>setSharedProcessProcessModel:</string>
+ <string>setSharedThreadProcessModel:</string>
+ <string>showStatisticsWindow:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>setSharedProcessProcessModel:</string>
+ <string>setSharedThreadProcessModel:</string>
+ <string>showStatisticsWindow:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBActionInfo">
+ <string key="name">setSharedProcessProcessModel:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">setSharedThreadProcessModel:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">showStatisticsWindow:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">mac/AppDelegate.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">BrowserAppDelegate</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="outlets">
+ <string key="NS.key.0">window</string>
+ <string key="NS.object.0">NSWindow</string>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <string key="NS.key.0">window</string>
+ <object class="IBToOneOutletInfo" key="NS.object.0">
+ <string key="name">window</string>
+ <string key="candidateClassName">NSWindow</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">BrowserWindowController</string>
+ <string key="superclassName">NSWindowController</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>dumpSourceToConsole:</string>
+ <string>fetch:</string>
+ <string>forceRepaint:</string>
+ <string>goBack:</string>
+ <string>goForward:</string>
+ <string>reload:</string>
+ <string>removeReinsertWebView:</string>
+ <string>resetZoom:</string>
+ <string>showHideWebView:</string>
+ <string>toggleZoomMode:</string>
+ <string>zoomIn:</string>
+ <string>zoomOut:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>dumpSourceToConsole:</string>
+ <string>fetch:</string>
+ <string>forceRepaint:</string>
+ <string>goBack:</string>
+ <string>goForward:</string>
+ <string>reload:</string>
+ <string>removeReinsertWebView:</string>
+ <string>resetZoom:</string>
+ <string>showHideWebView:</string>
+ <string>toggleZoomMode:</string>
+ <string>zoomIn:</string>
+ <string>zoomOut:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBActionInfo">
+ <string key="name">dumpSourceToConsole:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">fetch:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">forceRepaint:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">goBack:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">goForward:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">reload:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">removeReinsertWebView:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">resetZoom:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">showHideWebView:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">toggleZoomMode:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">zoomIn:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">zoomOut:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="outlets">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>backButton</string>
+ <string>containerView</string>
+ <string>forwardButton</string>
+ <string>progressIndicator</string>
+ <string>reloadButton</string>
+ <string>toolbar</string>
+ <string>urlText</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSButton</string>
+ <string>NSView</string>
+ <string>NSButton</string>
+ <string>NSProgressIndicator</string>
+ <string>NSButton</string>
+ <string>NSToolbar</string>
+ <string>NSTextField</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="toOneOutletInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>backButton</string>
+ <string>containerView</string>
+ <string>forwardButton</string>
+ <string>progressIndicator</string>
+ <string>reloadButton</string>
+ <string>toolbar</string>
+ <string>urlText</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBToOneOutletInfo">
+ <string key="name">backButton</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">containerView</string>
+ <string key="candidateClassName">NSView</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">forwardButton</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">progressIndicator</string>
+ <string key="candidateClassName">NSProgressIndicator</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">reloadButton</string>
+ <string key="candidateClassName">NSButton</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">toolbar</string>
+ <string key="candidateClassName">NSToolbar</string>
+ </object>
+ <object class="IBToOneOutletInfo">
+ <string key="name">urlText</string>
+ <string key="candidateClassName">NSTextField</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBProjectSource</string>
+ <string key="minorKey">mac/BrowserWindowController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">FirstResponder</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>forceRepaint:</string>
+ <string>newWindow:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <string>id</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>forceRepaint:</string>
+ <string>newWindow:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBActionInfo">
+ <string key="name">forceRepaint:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">newWindow:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBUserSource</string>
+ <string key="minorKey"/>
+ </object>
+ </object>
+ </object>
+ <object class="NSMutableArray" key="referencedPartialClassDescriptionsV3.2+">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <string key="superclassName">NSResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="822405504">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSApplication.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="850738725">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSApplicationScripting.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="624831158">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSColorPanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSHelpManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSPageLayout.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSApplication</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSUserInterfaceItemSearching.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSBrowser</string>
+ <string key="superclassName">NSControl</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSBrowser.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSButton</string>
+ <string key="superclassName">NSControl</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSButton.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSControl</string>
+ <string key="superclassName">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="310914472">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSControl.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSDocument</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>printDocument:</string>
+ <string>revertDocumentToSaved:</string>
+ <string>runPageLayout:</string>
+ <string>saveDocument:</string>
+ <string>saveDocumentAs:</string>
+ <string>saveDocumentTo:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>printDocument:</string>
+ <string>revertDocumentToSaved:</string>
+ <string>runPageLayout:</string>
+ <string>saveDocument:</string>
+ <string>saveDocumentAs:</string>
+ <string>saveDocumentTo:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBActionInfo">
+ <string key="name">printDocument:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">revertDocumentToSaved:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">runPageLayout:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">saveDocument:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">saveDocumentAs:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">saveDocumentTo:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDocument.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSDocument</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDocumentScripting.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSDocumentController</string>
+ <string key="superclassName">NSObject</string>
+ <object class="NSMutableDictionary" key="actions">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>clearRecentDocuments:</string>
+ <string>newDocument:</string>
+ <string>openDocument:</string>
+ <string>saveAllDocuments:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ <string>id</string>
+ </object>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>clearRecentDocuments:</string>
+ <string>newDocument:</string>
+ <string>openDocument:</string>
+ <string>saveAllDocuments:</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="IBActionInfo">
+ <string key="name">clearRecentDocuments:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">newDocument:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">openDocument:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ <object class="IBActionInfo">
+ <string key="name">saveAllDocuments:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDocumentController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSFontManager</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="946436764">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSFontManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSFormatter</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSFormatter.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSMatrix</string>
+ <string key="superclassName">NSControl</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSMatrix.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSMenu</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="1056362899">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSMenu.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSMenuItem</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="472958451">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSMenuItem.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSMovieView</string>
+ <string key="superclassName">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSMovieView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSAccessibility.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="822405504"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="850738725"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="624831158"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="310914472"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDictionaryController.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDragging.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="946436764"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSFontPanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSKeyValueBinding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <reference key="sourceIdentifier" ref="1056362899"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSNibLoading.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSOutlineView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSPasteboard.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSSavePanel.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="809545482">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSTableView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSToolbarItem.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier" id="260078765">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSArchiver.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSClassDescription.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSError.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSFileManager.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyValueCoding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyValueObserving.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSKeyedArchiver.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSObject.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSObjectScripting.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSPortCoder.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSRunLoop.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptClassDescription.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptKeyValueCoding.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptObjectSpecifiers.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSScriptWhoseTests.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSThread.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURL.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURLConnection.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">Foundation.framework/Headers/NSURLDownload.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSProgressIndicator</string>
+ <string key="superclassName">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSProgressIndicator.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSInterfaceStyle.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSResponder</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSResponder.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSTableView</string>
+ <string key="superclassName">NSControl</string>
+ <reference key="sourceIdentifier" ref="809545482"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSText</string>
+ <string key="superclassName">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSText.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSTextField</string>
+ <string key="superclassName">NSControl</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSTextField.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSTextView</string>
+ <string key="superclassName">NSText</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSTextView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSToolbar</string>
+ <string key="superclassName">NSObject</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSToolbar.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSClipView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <reference key="sourceIdentifier" ref="472958451"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSRulerView.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSView</string>
+ <string key="superclassName">NSResponder</string>
+ <reference key="sourceIdentifier" ref="260078765"/>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSDrawer.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
+ <string key="superclassName">NSResponder</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSWindow.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindow</string>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSWindowScripting.h</string>
+ </object>
+ </object>
+ <object class="IBPartialClassDescription">
+ <string key="className">NSWindowController</string>
+ <string key="superclassName">NSResponder</string>
+ <object class="NSMutableDictionary" key="actions">
+ <string key="NS.key.0">showWindow:</string>
+ <string key="NS.object.0">id</string>
+ </object>
+ <object class="NSMutableDictionary" key="actionInfosByName">
+ <string key="NS.key.0">showWindow:</string>
+ <object class="IBActionInfo" key="NS.object.0">
+ <string key="name">showWindow:</string>
+ <string key="candidateClassName">id</string>
+ </object>
+ </object>
+ <object class="IBClassDescriptionSource" key="sourceIdentifier">
+ <string key="majorKey">IBFrameworkSource</string>
+ <string key="minorKey">AppKit.framework/Headers/NSWindowController.h</string>
+ </object>
+ </object>
+ </object>
+ </object>
+ <int key="IBDocument.localizationMode">0</int>
+ <string key="IBDocument.TargetRuntimeIdentifier">IBCocoaFramework</string>
+ <object class="NSMutableDictionary" key="IBDocument.PluginDeclaredDevelopmentDependencies">
+ <string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3</string>
+ <integer value="3000" key="NS.object.0"/>
+ </object>
+ <bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
+ <string key="IBDocument.LastKnownRelativeProjectPath">../MiniBrowser.xcodeproj</string>
+ <int key="IBDocument.defaultPropertyAccessControl">3</int>
+ <object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <object class="NSArray" key="dict.sortedKeys">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>NSMenuCheckmark</string>
+ <string>NSMenuMixedState</string>
+ </object>
+ <object class="NSMutableArray" key="dict.values">
+ <bool key="EncodedWithXMLCoder">YES</bool>
+ <string>{9, 8}</string>
+ <string>{7, 2}</string>
+ </object>
+ </object>
+ </data>
+</archive>
diff --git a/Tools/MiniBrowser/mac/MiniBrowser_Prefix.pch b/Tools/MiniBrowser/mac/MiniBrowser_Prefix.pch
new file mode 100644
index 0000000..a4e648e
--- /dev/null
+++ b/Tools/MiniBrowser/mac/MiniBrowser_Prefix.pch
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+#ifdef __OBJC__
+ #import <Cocoa/Cocoa.h>
+#endif
+
+#import <WebKit2/WebKit2.h>
+
+#define ENABLE_LOGGING 0
+
+#if ENABLE_LOGGING
+#define LOG NSLog
+#else
+#define LOG(...) ((void)0)
+#endif
diff --git a/Tools/MiniBrowser/mac/WebBundle/Info.plist b/Tools/MiniBrowser/mac/WebBundle/Info.plist
new file mode 100644
index 0000000..c285a47
--- /dev/null
+++ b/Tools/MiniBrowser/mac/WebBundle/Info.plist
@@ -0,0 +1,22 @@
+<?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>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>
diff --git a/Tools/MiniBrowser/mac/WebBundle/WebBundleMain.m b/Tools/MiniBrowser/mac/WebBundle/WebBundleMain.m
new file mode 100644
index 0000000..90db033
--- /dev/null
+++ b/Tools/MiniBrowser/mac/WebBundle/WebBundleMain.m
@@ -0,0 +1,104 @@
+/*
+ * 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 <Cocoa/Cocoa.h>
+#include <WebKit2/WKBundle.h>
+#include <WebKit2/WKBundleFrame.h>
+#include <WebKit2/WKBundleInitialize.h>
+#include <WebKit2/WKBundlePage.h>
+#include <WebKit2/WKString.h>
+#include <WebKit2/WKStringCF.h>
+#include <WebKit2/WKURLCF.h>
+#include <stdio.h>
+
+static WKBundleRef globalBundle;
+
+// WKBundlePageClient functions
+
+void didClearWindowObjectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleScriptWorldRef world, const void *clientInfo)
+{
+ WKURLRef wkURL = WKBundleFrameCopyURL(WKBundlePageGetMainFrame(page));
+ CFURLRef cfURL = WKURLCopyCFURL(0, wkURL);
+ WKRelease(wkURL);
+
+ LOG(@"WKBundlePageClient - didClearWindowForFrame %@", [(NSURL *)cfURL absoluteString]);
+ CFRelease(cfURL);
+
+ WKStringRef messageName = WKStringCreateWithCFString(CFSTR("Callback"));
+ WKStringRef messageBody = WKStringCreateWithCFString(CFSTR("Window was cleared"));
+ WKBundlePostMessage(globalBundle, messageName, messageBody);
+ WKRelease(messageName);
+ WKRelease(messageBody);
+}
+
+
+// WKBundleClient
+
+void didCreatePage(WKBundleRef bundle, WKBundlePageRef page, const void* clientInfo)
+{
+ LOG(@"WKBundleClient - didCreatePage\n");
+
+ WKBundlePageLoaderClient client;
+ memset(&client, 0, sizeof(client));
+ client.didClearWindowObjectForFrame = didClearWindowObjectForFrame;
+
+ WKBundlePageSetLoaderClient(page, &client);
+}
+
+void willDestroyPage(WKBundleRef bundle, WKBundlePageRef page, const void* clientInfo)
+{
+ LOG(@"WKBundleClient - willDestroyPage\n");
+}
+
+void didRecieveMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef messageBody, const void *clientInfo)
+{
+ CFStringRef cfMessageName = WKStringCopyCFString(0, messageName);
+
+ WKTypeID typeID = WKGetTypeID(messageBody);
+ if (typeID == WKStringGetTypeID()) {
+ CFStringRef cfMessageBody = WKStringCopyCFString(0, (WKStringRef)messageBody);
+ LOG(@"WKBundleClient - didRecieveMessage - MessageName: %@ MessageBody %@", cfMessageName, cfMessageBody);
+ CFRelease(cfMessageBody);
+ } else {
+ LOG(@"WKBundleClient - didRecieveMessage - MessageName: %@ (MessageBody Unhandeled)\n", cfMessageName);
+ }
+
+ CFRelease(cfMessageName);
+}
+
+void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData)
+{
+ globalBundle = bundle;
+
+ WKBundleClient client = {
+ 0,
+ 0,
+ didCreatePage,
+ willDestroyPage,
+ 0, // didInitializePageGroup
+ didRecieveMessage
+ };
+ WKBundleSetClient(bundle, &client);
+}
diff --git a/Tools/MiniBrowser/mac/main.m b/Tools/MiniBrowser/mac/main.m
new file mode 100644
index 0000000..7f56737
--- /dev/null
+++ b/Tools/MiniBrowser/mac/main.m
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+int main(int argc, char *argv[])
+{
+ return NSApplicationMain(argc, (const char **) argv);
+}
diff --git a/Tools/MiniBrowser/mac/make-launchable.sh b/Tools/MiniBrowser/mac/make-launchable.sh
new file mode 100755
index 0000000..7fba058
--- /dev/null
+++ b/Tools/MiniBrowser/mac/make-launchable.sh
@@ -0,0 +1,27 @@
+#!/bin/sh
+
+# 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.
+
+echo "Making app bundle launchable";
+defaults write "${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH%.plist}" LSEnvironment -dict DYLD_FRAMEWORK_PATH "${BUILT_PRODUCTS_DIR}"
diff --git a/Tools/MiniBrowser/qt/BrowserView.cpp b/Tools/MiniBrowser/qt/BrowserView.cpp
new file mode 100644
index 0000000..e6548ab
--- /dev/null
+++ b/Tools/MiniBrowser/qt/BrowserView.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010 University of Szeged
+ *
+ * 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 "BrowserView.h"
+
+#include <QGraphicsScene>
+
+static QWKPage* createNewPage(QWKPage* page)
+{
+ return page;
+}
+
+BrowserView::BrowserView(QGraphicsWKView::BackingStoreType backingStoreType, QWidget* parent)
+ : QGraphicsView(parent)
+ , m_item(0)
+ , m_context(new QWKContext(this))
+{
+ m_item = new QGraphicsWKView(m_context, backingStoreType, 0);
+ setScene(new QGraphicsScene(this));
+ scene()->addItem(m_item);
+
+ setFrameShape(QFrame::NoFrame);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ connect(m_item, SIGNAL(titleChanged(QString)), this, SLOT(setWindowTitle(QString)));
+ m_item->page()->setCreateNewPageFunction(createNewPage);
+}
+
+void BrowserView::resizeEvent(QResizeEvent* event)
+{
+ QGraphicsView::resizeEvent(event);
+ QRectF rect(QPoint(0, 0), event->size());
+ m_item->setGeometry(rect);
+ scene()->setSceneRect(rect);
+}
+
+void BrowserView::load(const QString& url)
+{
+ return m_item->load(QUrl::fromUserInput(url));
+}
+
+QGraphicsWKView* BrowserView::view() const
+{
+ return m_item;
+}
diff --git a/Tools/MiniBrowser/qt/BrowserView.h b/Tools/MiniBrowser/qt/BrowserView.h
new file mode 100644
index 0000000..7680aa7
--- /dev/null
+++ b/Tools/MiniBrowser/qt/BrowserView.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010 University of Szeged
+ *
+ * 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 BrowserView_h
+#define BrowserView_h
+
+#include <QGraphicsView>
+#include "qgraphicswkview.h"
+#include "qwkcontext.h"
+
+class BrowserView : public QGraphicsView {
+ Q_OBJECT
+
+public:
+ BrowserView(QGraphicsWKView::BackingStoreType, QWidget* parent = 0);
+ virtual ~BrowserView() { delete m_item; }
+
+ void load(const QString&);
+ QGraphicsWKView* view() const;
+
+protected:
+ virtual void resizeEvent(QResizeEvent*);
+
+private:
+ QGraphicsWKView* m_item;
+ QWKContext* m_context;
+};
+
+#endif
diff --git a/Tools/MiniBrowser/qt/BrowserWindow.cpp b/Tools/MiniBrowser/qt/BrowserWindow.cpp
new file mode 100644
index 0000000..743c91a
--- /dev/null
+++ b/Tools/MiniBrowser/qt/BrowserWindow.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010 University of Szeged
+ *
+ * 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 "BrowserWindow.h"
+
+BrowserWindow::BrowserWindow(QGraphicsWKView::BackingStoreType type)
+ : m_backingStoreType(type)
+{
+ setAttribute(Qt::WA_DeleteOnClose);
+
+ m_menu = new QMenuBar();
+ m_browser = new BrowserView(m_backingStoreType);
+ m_addressBar = new QLineEdit();
+
+ m_menu->addAction("New Window", this, SLOT(newWindow()));
+ m_menu->addAction("Change User Agent", this, SLOT(showUserAgentDialog()));
+
+ m_menu->addSeparator();
+ m_menu->addAction("Quit", this, SLOT(close()));
+
+ m_browser->setFocus(Qt::OtherFocusReason);
+
+ connect(m_addressBar, SIGNAL(returnPressed()), SLOT(changeLocation()));
+ connect(m_browser->view(), SIGNAL(loadProgress(int)), SLOT(loadProgress(int)));
+ connect(m_browser->view(), SIGNAL(titleChanged(const QString&)), SLOT(titleChanged(const QString&)));
+ connect(m_browser->view(), SIGNAL(urlChanged(const QUrl&)), SLOT(urlChanged(const QUrl&)));
+
+ QToolBar* bar = addToolBar("Navigation");
+ bar->addAction(m_browser->view()->page()->action(QWKPage::Back));
+ bar->addAction(m_browser->view()->page()->action(QWKPage::Forward));
+ bar->addAction(m_browser->view()->page()->action(QWKPage::Reload));
+ bar->addAction(m_browser->view()->page()->action(QWKPage::Stop));
+ bar->addWidget(m_addressBar);
+
+ this->setMenuBar(m_menu);
+ this->setCentralWidget(m_browser);
+
+ m_browser->setFocus(Qt::OtherFocusReason);
+
+ QShortcut* selectAddressBar = new QShortcut(Qt::CTRL | Qt::Key_L, this);
+ connect(selectAddressBar, SIGNAL(activated()), this, SLOT(openLocation()));
+
+ resize(960, 640);
+ show();
+}
+
+void BrowserWindow::load(const QString& url)
+{
+ m_addressBar->setText(url);
+ m_browser->load(url);
+}
+
+BrowserWindow* BrowserWindow::newWindow(const QString& url)
+{
+ BrowserWindow* window = new BrowserWindow(m_backingStoreType);
+ window->load(url);
+ return window;
+}
+
+void BrowserWindow::openLocation()
+{
+ m_addressBar->selectAll();
+ m_addressBar->setFocus();
+}
+
+void BrowserWindow::changeLocation()
+{
+ QString string = m_addressBar->text();
+ m_browser->load(string);
+}
+
+void BrowserWindow::loadProgress(int progress)
+{
+ QColor backgroundColor = QApplication::palette().color(QPalette::Base);
+ QColor progressColor = QColor(120, 180, 240);
+ QPalette pallete = m_addressBar->palette();
+
+ if (progress <= 0 || progress >= 100)
+ pallete.setBrush(QPalette::Base, backgroundColor);
+ else {
+ QLinearGradient gradient(0, 0, width(), 0);
+ gradient.setColorAt(0, progressColor);
+ gradient.setColorAt(((double) progress) / 100, progressColor);
+ if (progress != 100)
+ gradient.setColorAt((double) progress / 100 + 0.001, backgroundColor);
+ pallete.setBrush(QPalette::Base, gradient);
+ }
+ m_addressBar->setPalette(pallete);
+}
+
+void BrowserWindow::titleChanged(const QString& title)
+{
+ setWindowTitle(title);
+}
+
+void BrowserWindow::urlChanged(const QUrl& url)
+{
+ m_addressBar->setText(url.toString());
+}
+
+void BrowserWindow::updateUserAgentList()
+{
+ QWKPage* page = m_browser->view()->page();
+
+ QFile file(":/useragentlist.txt");
+
+ if (file.open(QIODevice::ReadOnly)) {
+ while (!file.atEnd()) {
+ QString agent = file.readLine().trimmed();
+ if (!m_userAgentList.contains(agent))
+ m_userAgentList << agent;
+ }
+ file.close();
+ }
+
+ Q_ASSERT(!m_userAgentList.isEmpty());
+
+ if (!(page->customUserAgent().isEmpty() || m_userAgentList.contains(page->customUserAgent())))
+ m_userAgentList << page->customUserAgent();
+}
+
+void BrowserWindow::showUserAgentDialog()
+{
+ updateUserAgentList();
+
+ QDialog dialog(this);
+ dialog.setWindowTitle("Change User Agent");
+ dialog.resize(size().width() * 0.7, dialog.size().height());
+ QVBoxLayout* layout = new QVBoxLayout(&dialog);
+ dialog.setLayout(layout);
+
+ QComboBox* combo = new QComboBox(&dialog);
+ combo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
+ combo->setEditable(true);
+ combo->insertItems(0, m_userAgentList);
+ layout->addWidget(combo);
+
+ int index = combo->findText(m_browser->view()->page()->customUserAgent());
+ combo->setCurrentIndex(index);
+
+ QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel
+ , Qt::Horizontal, &dialog);
+ connect(buttonBox, SIGNAL(accepted()), &dialog, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), &dialog, SLOT(reject()));
+ layout->addWidget(buttonBox);
+
+ if (dialog.exec() && !combo->currentText().isEmpty())
+ m_browser->view()->page()->setCustomUserAgent(combo->currentText());
+}
+
+BrowserWindow::~BrowserWindow()
+{
+ delete m_addressBar;
+ delete m_browser;
+ delete m_menu;
+}
diff --git a/Tools/MiniBrowser/qt/BrowserWindow.h b/Tools/MiniBrowser/qt/BrowserWindow.h
new file mode 100644
index 0000000..fe94d6b
--- /dev/null
+++ b/Tools/MiniBrowser/qt/BrowserWindow.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010 University of Szeged
+ *
+ * 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 BrowserWindow_h
+#define BrowserWindow_h
+
+#include "BrowserView.h"
+#include <QStringList>
+#include <QtGui>
+#include <qgraphicswkview.h>
+
+class BrowserWindow : public QMainWindow {
+ Q_OBJECT
+
+public:
+ BrowserWindow(QGraphicsWKView::BackingStoreType);
+ ~BrowserWindow();
+ void load(const QString& url);
+
+public slots:
+ BrowserWindow* newWindow(const QString& url = "about:blank");
+ void openLocation();
+
+protected slots:
+ void changeLocation();
+ void loadProgress(int progress);
+ void titleChanged(const QString&);
+ void urlChanged(const QUrl&);
+ void showUserAgentDialog();
+
+private:
+ void updateUserAgentList();
+
+ BrowserView* m_browser;
+ QMenuBar* m_menu;
+ QLineEdit* m_addressBar;
+ QStringList m_userAgentList;
+ QGraphicsWKView::BackingStoreType m_backingStoreType;
+};
+
+#endif
diff --git a/Tools/MiniBrowser/qt/MiniBrowser.pro b/Tools/MiniBrowser/qt/MiniBrowser.pro
new file mode 100644
index 0000000..2cdd3b5
--- /dev/null
+++ b/Tools/MiniBrowser/qt/MiniBrowser.pro
@@ -0,0 +1,58 @@
+TEMPLATE = app
+TARGET = MiniBrowser
+
+SOURCES += \
+ main.cpp \
+ BrowserView.cpp \
+ BrowserWindow.cpp \
+
+HEADERS += \
+ BrowserView.h \
+ BrowserWindow.h \
+
+CONFIG += uitools
+
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
+include(../../../WebKit.pri)
+
+INCLUDEPATH += \
+ $$PWD/../../../WebKit2/ \
+ $$PWD/../../../WebKit2/UIProcess/API/cpp \
+ $$PWD/../../../WebKit2/UIProcess/API/C \
+ $$PWD/../../../WebKit2/UIProcess/API/qt \
+ $$OUTPUT_DIR/include
+
+
+DESTDIR = $$OUTPUT_DIR/bin
+!CONFIG(standalone_package): CONFIG -= app_bundle
+
+QT += network
+macx:QT+=xml
+
+linux-* {
+ # From Creator's src/rpath.pri:
+ # Do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR
+ # this expands to $ORIGIN (after qmake and make), it does NOT read a qmake var.
+ QMAKE_RPATHDIR = \$\$ORIGIN/../lib $$QMAKE_RPATHDIR
+ MY_RPATH = $$join(QMAKE_RPATHDIR, ":")
+
+ QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${MY_RPATH}\'
+ QMAKE_RPATHDIR =
+} else {
+ QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR
+}
+
+symbian {
+ TARGET.UID3 = 0xA000E543
+ TARGET.CAPABILITY = ReadUserData WriteUserData NetworkServices
+}
+
+contains(QT_CONFIG, opengl) {
+ QT += opengl
+ DEFINES += QT_CONFIGURED_WITH_OPENGL
+}
+
+# We copy the resource file to the build directory.
+# The copier is defined in Tools/MiniBrowser/DerivedSources.pro.
+RESOURCES += \
+ $$OUTPUT_DIR/Tools/MiniBrowser/qt/MiniBrowser.qrc
diff --git a/Tools/MiniBrowser/qt/main.cpp b/Tools/MiniBrowser/qt/main.cpp
new file mode 100644
index 0000000..20f4ff5
--- /dev/null
+++ b/Tools/MiniBrowser/qt/main.cpp
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2010 University of Szeged
+ *
+ * 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 "BrowserWindow.h"
+#include <QLatin1String>
+#include <QRegExp>
+#include <qgraphicswkview.h>
+#include <QtGui>
+
+int main(int argc, char** argv) {
+ QApplication app(argc, argv);
+
+ QStringList args = QApplication::arguments();
+ args.removeAt(0);
+
+ QGraphicsWKView::BackingStoreType backingStoreTypeToUse = QGraphicsWKView::Simple;
+ int indexOfTiledOption;
+ if ((indexOfTiledOption = args.indexOf(QRegExp(QLatin1String("-tiled")))) != -1) {
+ backingStoreTypeToUse = QGraphicsWKView::Tiled;
+ args.removeAt(indexOfTiledOption);
+ }
+
+ if (args.isEmpty()) {
+ QString defaultUrl = QString("file://%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html"));
+ if (QDir(defaultUrl).exists())
+ args.append(defaultUrl);
+ else
+ args.append("http://www.google.com");
+ }
+
+ BrowserWindow* window = new BrowserWindow(backingStoreTypeToUse);
+ window->load(args[0]);
+
+ for (int i = 1; i < args.size(); ++i)
+ window->newWindow(args[i]);
+
+ app.exec();
+
+ return 0;
+}
diff --git a/Tools/MiniBrowser/win/BrowserView.cpp b/Tools/MiniBrowser/win/BrowserView.cpp
new file mode 100644
index 0000000..a93ca96
--- /dev/null
+++ b/Tools/MiniBrowser/win/BrowserView.cpp
@@ -0,0 +1,145 @@
+/*
+ * 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 "StdAfx.h"
+#include "BrowserView.h"
+
+#include "BrowserWindow.h"
+#include <WebKit2/WKContextPrivate.h>
+#include <WebKit2/WKURLCF.h>
+
+static const unsigned short HIGH_BIT_MASK_SHORT = 0x8000;
+
+BrowserView::BrowserView()
+ : m_webView(0)
+{
+}
+
+// UI Client Callbacks
+
+static WKPageRef createNewPage(WKPageRef page, WKDictionaryRef features, WKEventModifiers modifiers, WKEventMouseButton mouseButton, const void* clientInfo)
+{
+ BrowserWindow* browserWindow = BrowserWindow::create();
+ browserWindow->createWindow(0, 0, 800, 600);
+
+ return WKViewGetPage(browserWindow->view().webView());
+}
+
+static void showPage(WKPageRef page, const void *clientInfo)
+{
+ static_cast<BrowserWindow*>(const_cast<void*>(clientInfo))->showWindow();
+}
+
+static void closePage(WKPageRef page, const void *clientInfo)
+{
+}
+
+static void runJavaScriptAlert(WKPageRef page, WKStringRef alertText, WKFrameRef frame, const void* clientInfo)
+{
+}
+
+static bool runJavaScriptConfirm(WKPageRef page, WKStringRef message, WKFrameRef frame, const void* clientInfo)
+{
+ return false;
+}
+
+static WKStringRef runJavaScriptPrompt(WKPageRef page, WKStringRef message, WKStringRef defaultValue, WKFrameRef frame, const void* clientInfo)
+{
+ return 0;
+}
+
+static void setStatusText(WKPageRef page, WKStringRef text, const void* clientInfo)
+{
+}
+
+static void mouseDidMoveOverElement(WKPageRef page, WKEventModifiers modifiers, WKTypeRef userData, const void *clientInfo)
+{
+}
+
+void BrowserView::create(RECT webViewRect, BrowserWindow* parentWindow)
+{
+ assert(!m_webView);
+
+ bool isShiftKeyDown = ::GetKeyState(VK_SHIFT) & HIGH_BIT_MASK_SHORT;
+
+ WKContextRef context;
+ if (isShiftKeyDown)
+ context = WKContextGetSharedThreadContext();
+ else
+ context = WKContextGetSharedProcessContext();
+
+ m_webView = WKViewCreate(webViewRect, context, 0, parentWindow->window());
+
+ WKPageUIClient uiClient = {
+ 0, /* version */
+ parentWindow, /* clientInfo */
+ createNewPage,
+ showPage,
+ closePage,
+ runJavaScriptAlert,
+ runJavaScriptConfirm,
+ runJavaScriptPrompt,
+ setStatusText,
+ mouseDidMoveOverElement,
+ 0, /* didNotHandleKeyEvent */
+ 0, /* toolbarsAreVisible */
+ 0, /* setToolbarsAreVisible */
+ 0, /* menuBarIsVisible */
+ 0, /* setMenuBarIsVisible */
+ 0, /* statusBarIsVisible */
+ 0, /* setStatusBarIsVisible */
+ 0, /* isResizable */
+ 0, /* setIsResizable */
+ 0, /* getWindowFrame */
+ 0, /* setWindowFrame */
+ 0, /* runBeforeUnloadConfirmPanel */
+ 0, /* didDraw */
+ 0, /* pageDidScroll */
+ 0, /* exceededDatabaseQuota */
+ 0 /* runOpenPanel */
+ };
+
+ WKPageSetPageUIClient(WKViewGetPage(m_webView), &uiClient);
+}
+
+void BrowserView::setFrame(RECT rect)
+{
+ HWND webViewWindow = WKViewGetWindow(m_webView);
+ ::SetWindowPos(webViewWindow, 0, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS);
+}
+
+void BrowserView::goToURL(const std::wstring& urlString)
+{
+ CFStringRef string = CFStringCreateWithCharacters(0, (const UniChar*)urlString.data(), urlString.size());
+ CFURLRef cfURL = CFURLCreateWithString(0, string, 0);
+ CFRelease(string);
+
+ WKURLRef url = WKURLCreateWithCFURL(cfURL);
+ CFRelease(cfURL);
+
+ WKPageRef page = WKViewGetPage(m_webView);
+ WKPageLoadURL(page, url);
+ WKRelease(url);
+}
diff --git a/Tools/MiniBrowser/win/BrowserView.h b/Tools/MiniBrowser/win/BrowserView.h
new file mode 100644
index 0000000..08c5e4a
--- /dev/null
+++ b/Tools/MiniBrowser/win/BrowserView.h
@@ -0,0 +1,49 @@
+/*
+ * 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 BrowserView_h
+#define BrowserView_h
+
+#include <WebKit2/WebKit2.h>
+#include <string>
+
+class BrowserWindow;
+
+class BrowserView {
+public:
+ BrowserView();
+
+ void goToURL(const std::wstring& url);
+
+ void create(RECT, BrowserWindow* parentWindow);
+ void setFrame(RECT);
+
+ WKViewRef webView() const { return m_webView; }
+
+private:
+ WKViewRef m_webView;
+};
+
+#endif // BrowserView_h
diff --git a/Tools/MiniBrowser/win/BrowserWindow.cpp b/Tools/MiniBrowser/win/BrowserWindow.cpp
new file mode 100644
index 0000000..dc43a68
--- /dev/null
+++ b/Tools/MiniBrowser/win/BrowserWindow.cpp
@@ -0,0 +1,261 @@
+/*
+ * 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 "StdAfx.h"
+#include "BrowserWindow.h"
+#include "MiniBrowser.h"
+#include "Resource.h"
+
+#include <assert.h>
+#include <commctrl.h>
+#include <shlwapi.h>
+#include <vector>
+#include <wininet.h>
+
+using namespace std;
+
+BrowserWindow::BrowserWindow()
+ : m_window(0)
+ , m_rebarWindow(0)
+ , m_comboBoxWindow(0)
+{
+}
+
+LRESULT CALLBACK BrowserWindow::BrowserWindowWndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LONG_PTR longPtr = ::GetWindowLongPtr(window, 0);
+
+ if (BrowserWindow* browserView = reinterpret_cast<BrowserWindow*>(longPtr))
+ return browserView->wndProc(window, message, wParam, lParam);
+
+ if (message == WM_CREATE) {
+ LPCREATESTRUCT createStruct = reinterpret_cast<LPCREATESTRUCT>(lParam);
+ BrowserWindow* browserWindow = static_cast<BrowserWindow*>(createStruct->lpCreateParams);
+ browserWindow->m_window = window;
+
+ ::SetWindowLongPtr(window, 0, (LONG_PTR)browserWindow);
+
+ browserWindow->onCreate(createStruct);
+ return 0;
+ }
+
+ return ::DefWindowProc(window, message, wParam, lParam);
+}
+
+LRESULT BrowserWindow::wndProc(HWND window, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT lResult = 0;
+ bool handled = true;
+
+ switch (message) {
+ case WM_ERASEBKGND:
+ lResult = 1;
+ break;
+
+ case WM_COMMAND:
+ lResult = onCommand(LOWORD(wParam), handled);
+ break;
+
+ case WM_SIZE:
+ onSize(LOWORD(lParam), HIWORD(lParam));
+ break;
+
+ case WM_DESTROY:
+ onDestroy();
+ break;
+
+ case WM_NCDESTROY:
+ onNCDestroy();
+ break;
+
+ default:
+ handled = false;
+ }
+
+ if (!handled)
+ lResult = ::DefWindowProc(window, message, wParam, lParam);
+
+ return lResult;
+}
+
+void BrowserWindow::createWindow(int x, int y, int width, int height)
+{
+ assert(!m_window);
+
+ // Register the class.
+ WNDCLASSEX windowClass = { 0 };
+ windowClass.cbSize = sizeof(windowClass);
+ windowClass.style = 0;
+ windowClass.lpfnWndProc = BrowserWindowWndProc;
+ windowClass.cbClsExtra = 0;
+ windowClass.cbWndExtra = sizeof(this);
+ windowClass.hInstance = MiniBrowser::shared().instance();
+ windowClass.hIcon = 0;
+ windowClass.hCursor = ::LoadCursor(0, IDC_ARROW);
+ windowClass.hbrBackground = (HBRUSH)::GetStockObject(WHITE_BRUSH);
+ windowClass.lpszMenuName = MAKEINTRESOURCE(IDR_MAINFRAME);
+ windowClass.lpszClassName = L"MiniBrowser";
+ windowClass.hIconSm = 0;
+
+ ::RegisterClassEx(&windowClass);
+
+ ::CreateWindowW(L"MiniBrowser", L"MiniBrowser", WS_OVERLAPPEDWINDOW, x, y, width, height, 0, 0, MiniBrowser::shared().instance(), this);
+}
+
+void BrowserWindow::showWindow()
+{
+ assert(m_window);
+
+ ::ShowWindow(m_window, SW_SHOWNORMAL);
+}
+
+void BrowserWindow::goToURL(const std::wstring& url)
+{
+ m_browserView.goToURL(url);
+}
+
+void BrowserWindow::onCreate(LPCREATESTRUCT createStruct)
+{
+ // Register our window.
+ MiniBrowser::shared().registerWindow(this);
+
+ // Create the rebar control.
+ m_rebarWindow = ::CreateWindowEx(0, REBARCLASSNAME, 0, WS_VISIBLE | WS_BORDER | WS_CHILD | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CCS_NODIVIDER | CCS_NOPARENTALIGN | RBS_VARHEIGHT | RBS_BANDBORDERS,
+ 0, 0, 0, 0, m_window, 0, createStruct->hInstance, 0);
+ REBARINFO rebarInfo = { 0 };
+ rebarInfo.cbSize = sizeof(rebarInfo);
+ rebarInfo.fMask = 0;
+ ::SendMessage(m_rebarWindow, RB_SETBARINFO, 0, (LPARAM)&rebarInfo);
+
+ // Create the combo box control.
+ m_comboBoxWindow = ::CreateWindowEx(0, L"combobox", 0, WS_VISIBLE | WS_CHILD | WS_TABSTOP | WS_VSCROLL | WS_CLIPCHILDREN | WS_CLIPSIBLINGS | CBS_AUTOHSCROLL | CBS_DROPDOWN,
+ 0, 0, 0, 0, m_rebarWindow, 0, createStruct->hInstance, 0);
+ SendMessage(m_comboBoxWindow, WM_SETFONT, (WPARAM)GetStockObject(DEFAULT_GUI_FONT), MAKELPARAM(TRUE, 0));
+
+ REBARBANDINFO bandInfo;
+ bandInfo.cbSize = sizeof(bandInfo);
+ bandInfo.fMask = RBBIM_STYLE | RBBIM_TEXT | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE;
+ bandInfo.fStyle = RBBS_CHILDEDGE | RBBS_GRIPPERALWAYS;
+ bandInfo.lpText = L"Address";
+ bandInfo.hwndChild = m_comboBoxWindow;
+
+ RECT comboBoxRect;
+ ::GetWindowRect(m_comboBoxWindow, &comboBoxRect);
+ bandInfo.cx = 100;
+ bandInfo.cxMinChild = comboBoxRect.right - comboBoxRect.left;
+ bandInfo.cyMinChild = comboBoxRect.bottom - comboBoxRect.top;
+
+ // Add the band to the rebar.
+ int result = ::SendMessage(m_rebarWindow, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&bandInfo);
+
+ // Create the browser view.
+ RECT webViewRect = { 0, 0, 0, 0};
+ m_browserView.create(webViewRect, this);
+}
+
+void BrowserWindow::onDestroy()
+{
+ MiniBrowser::shared().unregisterWindow(this);
+
+ // FIXME: Should we close the browser view here?
+}
+
+void BrowserWindow::onNCDestroy()
+{
+ delete this;
+}
+
+void BrowserWindow::onSize(int width, int height)
+{
+ RECT rebarRect;
+ ::GetClientRect(m_rebarWindow, &rebarRect);
+
+ // Resize the rebar.
+ ::MoveWindow(m_rebarWindow, 0, 0, width, rebarRect.bottom - rebarRect.top, true);
+
+ RECT webViewRect;
+ webViewRect.top = rebarRect.bottom;
+ webViewRect.left = 0;
+ webViewRect.right = width;
+ webViewRect.bottom = height;
+ m_browserView.setFrame(webViewRect);
+}
+
+LRESULT BrowserWindow::onCommand(int commandID, bool& handled)
+{
+ switch (commandID) {
+ case ID_FILE_NEW_WINDOW:
+ MiniBrowser::shared().createNewWindow();
+ break;
+ case ID_FILE_CLOSE:
+ ::PostMessage(m_window, WM_CLOSE, 0, 0);
+ break;
+ case ID_DEBUG_SHOW_WEB_VIEW: {
+ HMENU menu = ::GetMenu(m_window);
+ bool shouldHide = ::GetMenuState(menu, ID_DEBUG_SHOW_WEB_VIEW, MF_BYCOMMAND) & MF_CHECKED;
+
+ ::CheckMenuItem(menu, ID_DEBUG_SHOW_WEB_VIEW, MF_BYCOMMAND | (shouldHide ? MF_UNCHECKED : MF_CHECKED));
+
+ // Show or hide the web view.
+ HWND webViewWindow = WKViewGetWindow(m_browserView.webView());
+ ::ShowWindow(webViewWindow, shouldHide ? SW_HIDE : SW_SHOW);
+ break;
+ }
+ default:
+ handled = false;
+ }
+
+ return 0;
+}
+
+bool BrowserWindow::handleMessage(const MSG* message)
+{
+ if (message->hwnd != m_comboBoxWindow && !::IsChild(m_comboBoxWindow, message->hwnd))
+ return false;
+
+ // Look for a WM_KEYDOWN message.
+ if (message->message != WM_KEYDOWN)
+ return false;
+
+ // Look for the VK_RETURN key.
+ if (message->wParam != VK_RETURN)
+ return false;
+
+ std::vector<WCHAR> buffer;
+ int textLength = ::GetWindowTextLength(m_comboBoxWindow);
+
+ buffer.resize(textLength + 1);
+ ::GetWindowText(m_comboBoxWindow, &buffer[0], buffer.size());
+
+ std::wstring url(&buffer[0], buffer.size() - 1);
+
+ if (url.find(L"http://"))
+ url = L"http://" + url;
+
+ m_browserView.goToURL(url);
+
+ // We handled this message.
+ return true;
+}
diff --git a/Tools/MiniBrowser/win/BrowserWindow.h b/Tools/MiniBrowser/win/BrowserWindow.h
new file mode 100644
index 0000000..1cf7350
--- /dev/null
+++ b/Tools/MiniBrowser/win/BrowserWindow.h
@@ -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.
+ */
+
+#ifndef BrowserWindow_h
+#define BrowserWindow_h
+
+#include "BrowserView.h"
+#include <string>
+
+class BrowserWindow {
+public:
+ static BrowserWindow* create()
+ {
+ return new BrowserWindow;
+ }
+
+ void createWindow(int x, int y, int width, int height);
+ void showWindow();
+
+ void goToURL(const std::wstring& url);
+
+ bool handleMessage(const MSG*);
+
+ const BrowserView& view() const { return m_browserView; }
+ HWND window() const { return m_window; }
+
+private:
+ BrowserWindow();
+
+ static LRESULT CALLBACK BrowserWindowWndProc(HWND, UINT, WPARAM, LPARAM);
+
+ // Message handlers.
+ LRESULT wndProc(HWND, UINT, WPARAM, LPARAM);
+ void onCreate(LPCREATESTRUCT);
+ void onDestroy();
+ void onNCDestroy();
+
+ void onSize(int width, int height);
+ LRESULT onCommand(int commandID, bool& handled);
+
+ HWND m_window;
+
+ HWND m_rebarWindow;
+ HWND m_comboBoxWindow;
+ BrowserView m_browserView;
+};
+
+#endif // BrowserWindow_h
diff --git a/Tools/MiniBrowser/win/MiniBrowser.cpp b/Tools/MiniBrowser/win/MiniBrowser.cpp
new file mode 100644
index 0000000..7e3d488
--- /dev/null
+++ b/Tools/MiniBrowser/win/MiniBrowser.cpp
@@ -0,0 +1,84 @@
+/*
+ * 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 "stdafx.h"
+
+#include "BrowserWindow.h"
+#include "MiniBrowser.h"
+#include <assert.h>
+
+MiniBrowser::MiniBrowser()
+ : m_instance(0)
+{
+}
+
+MiniBrowser& MiniBrowser::shared()
+{
+ static MiniBrowser miniBrowser;
+
+ return miniBrowser;
+}
+
+void MiniBrowser::initialize(HINSTANCE instance)
+{
+ assert(!m_instance);
+
+ m_instance = instance;
+}
+
+void MiniBrowser::createNewWindow()
+{
+ static const wchar_t* kDefaultURLString = L"http://webkit.org/";
+
+ BrowserWindow* browserWindow = BrowserWindow::create();
+ browserWindow->createWindow(0, 0, 800, 600);
+ browserWindow->showWindow();
+ browserWindow->goToURL(kDefaultURLString);
+}
+
+void MiniBrowser::registerWindow(BrowserWindow* window)
+{
+ m_browserWindows.insert(window);
+}
+
+void MiniBrowser::unregisterWindow(BrowserWindow* window)
+{
+ m_browserWindows.erase(window);
+
+ if (m_browserWindows.empty())
+ ::PostQuitMessage(0);
+}
+
+bool MiniBrowser::handleMessage(const MSG* message)
+{
+ for (std::set<BrowserWindow*>::const_iterator it = m_browserWindows.begin(), end = m_browserWindows.end(); it != end; ++it) {
+ BrowserWindow* browserWindow = *it;
+
+ if (browserWindow->handleMessage(message))
+ return true;
+ }
+
+ return false;
+}
diff --git a/Tools/MiniBrowser/win/MiniBrowser.h b/Tools/MiniBrowser/win/MiniBrowser.h
new file mode 100644
index 0000000..c7b5177
--- /dev/null
+++ b/Tools/MiniBrowser/win/MiniBrowser.h
@@ -0,0 +1,55 @@
+/*
+ * 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 MiniBrowser_h
+#define MiniBrowser_h
+
+#include <set>
+
+class BrowserWindow;
+
+class MiniBrowser {
+public:
+ static MiniBrowser& shared();
+
+ void initialize(HINSTANCE);
+
+ void createNewWindow();
+
+ void registerWindow(BrowserWindow*);
+ void unregisterWindow(BrowserWindow*);
+
+ bool handleMessage(const MSG*);
+
+ HINSTANCE instance() const { return m_instance; }
+
+private:
+ MiniBrowser();
+
+ HINSTANCE m_instance;
+ std::set<BrowserWindow*> m_browserWindows;
+};
+
+#endif // MiniBrowser_h
diff --git a/Tools/MiniBrowser/win/MiniBrowser.rc b/Tools/MiniBrowser/win/MiniBrowser.rc
new file mode 100644
index 0000000..0ff88b0
--- /dev/null
+++ b/Tools/MiniBrowser/win/MiniBrowser.rc
@@ -0,0 +1,79 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+#include "winresrc.h"
+
+/////////////////////////////////////////////////////////////////////////////
+// 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
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDR_MAINFRAME MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&New Window\tCtrl+N", ID_FILE_NEW_WINDOW
+ MENUITEM SEPARATOR
+ MENUITEM "&Close", ID_FILE_CLOSE
+ END
+ POPUP "&Debug"
+ BEGIN
+ MENUITEM "&Show WebView", ID_DEBUG_SHOW_WEB_VIEW, CHECKED
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDR_MAINFRAME_ACCEL ACCELERATORS
+BEGIN
+ "N", ID_FILE_NEW_WINDOW, VIRTKEY, CONTROL, NOINVERT
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.\0"
+END
+
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Tools/MiniBrowser/win/main.cpp b/Tools/MiniBrowser/win/main.cpp
new file mode 100644
index 0000000..0c125ba
--- /dev/null
+++ b/Tools/MiniBrowser/win/main.cpp
@@ -0,0 +1,62 @@
+/*
+ * 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 "stdafx.h"
+
+#include "BrowserWindow.h"
+#include "MiniBrowser.h"
+#include <string>
+
+#if defined _M_IX86
+#define PROCESSORARCHITECTURE "x86"
+#elif defined _M_IA64
+#define PROCESSORARCHITECTURE "ia64"
+#elif defined _M_X64
+#define PROCESSORARCHITECTURE "amd64"
+#else
+#define PROCESSORARCHITECTURE "*"
+#endif
+
+#pragma comment(linker, "/manifestdependency:\"type='win32' name='Microsoft.Windows.Common-Controls' version='6.0.0.0' processorArchitecture='" PROCESSORARCHITECTURE "' publicKeyToken='6595b64144ccf1df' language='*'\"")
+
+int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpstrCmdLine, int nCmdShow)
+{
+ MiniBrowser::shared().initialize(hInstance);
+
+ // Create and show our initial window.
+ MiniBrowser::shared().createNewWindow();
+
+ MSG message;
+ while (BOOL result = ::GetMessage(&message, 0, 0, 0)) {
+ if (result == -1)
+ break;
+ ::TranslateMessage(&message);
+
+ if (!MiniBrowser::shared().handleMessage(&message))
+ ::DispatchMessage(&message);
+ }
+
+ return 0;
+}
diff --git a/Tools/MiniBrowser/win/resource.h b/Tools/MiniBrowser/win/resource.h
new file mode 100644
index 0000000..b12b906
--- /dev/null
+++ b/Tools/MiniBrowser/win/resource.h
@@ -0,0 +1,23 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by MiniBrowser.rc
+//
+
+#define ID_FILE_NEW_WINDOW 32770
+#define ID_FILE_OPEN 32771
+#define ID_FILE_CLOSE 32772
+#define ID_DEBUG_SHOW_WEB_VIEW 32773
+
+#define IDR_MAINFRAME 128
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 132
+#define _APS_NEXT_COMMAND_VALUE 32775
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
diff --git a/Tools/MiniBrowser/win/stdafx.cpp b/Tools/MiniBrowser/win/stdafx.cpp
new file mode 100644
index 0000000..c664e32
--- /dev/null
+++ b/Tools/MiniBrowser/win/stdafx.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+// stdafx.cpp : source file that includes just the standard includes
+// MiniBrowser.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/Tools/MiniBrowser/win/stdafx.h b/Tools/MiniBrowser/win/stdafx.h
new file mode 100644
index 0000000..2f531bb
--- /dev/null
+++ b/Tools/MiniBrowser/win/stdafx.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#define STRICT
+#define WIN32_LEAN_AND_MEAN
+
+#include <tchar.h>
+#include <windows.h>
+
+
+
diff --git a/Tools/QtTestBrowser/QtTestBrowser.pro b/Tools/QtTestBrowser/QtTestBrowser.pro
new file mode 100644
index 0000000..62d2c02
--- /dev/null
+++ b/Tools/QtTestBrowser/QtTestBrowser.pro
@@ -0,0 +1,61 @@
+TEMPLATE = app
+
+SOURCES += \
+ locationedit.cpp \
+ launcherwindow.cpp \
+ main.cpp \
+ mainwindow.cpp \
+ urlloader.cpp \
+ utils.cpp \
+ webpage.cpp \
+ webview.cpp \
+ fpstimer.cpp \
+
+HEADERS += \
+ locationedit.h \
+ launcherwindow.h \
+ mainwindow.h \
+ urlloader.h \
+ utils.h \
+ webinspector.h \
+ webpage.h \
+ webview.h \
+ fpstimer.h \
+
+CONFIG += uitools
+
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../..
+include(../../WebKit.pri)
+
+DESTDIR = $$OUTPUT_DIR/bin
+!CONFIG(standalone_package): CONFIG -= app_bundle
+
+QT += network
+macx:QT+=xml
+
+linux-* {
+ # From Creator's src/rpath.pri:
+ # Do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR
+ # this expands to $ORIGIN (after qmake and make), it does NOT read a qmake var.
+ QMAKE_RPATHDIR = \$\$ORIGIN/../lib $$QMAKE_RPATHDIR
+ MY_RPATH = $$join(QMAKE_RPATHDIR, ":")
+
+ QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${MY_RPATH}\'
+ QMAKE_RPATHDIR =
+} else {
+ QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR
+}
+
+symbian {
+ TARGET.UID3 = 0xA000E543
+ TARGET.CAPABILITY = ReadUserData WriteUserData NetworkServices Location
+ MMP_RULES *= pageddata
+}
+
+contains(QT_CONFIG, opengl) {
+ QT += opengl
+ DEFINES += QT_CONFIGURED_WITH_OPENGL
+}
+
+RESOURCES += \
+ QtTestBrowser.qrc
diff --git a/Tools/QtTestBrowser/QtTestBrowser.qrc b/Tools/QtTestBrowser/QtTestBrowser.qrc
new file mode 100644
index 0000000..ffe77b0
--- /dev/null
+++ b/Tools/QtTestBrowser/QtTestBrowser.qrc
@@ -0,0 +1,5 @@
+<RCC>
+ <qresource prefix="/">
+ <file>useragentlist.txt</file>
+ </qresource>
+</RCC>
diff --git a/Tools/QtTestBrowser/fpstimer.cpp b/Tools/QtTestBrowser/fpstimer.cpp
new file mode 100644
index 0000000..eae3d9c
--- /dev/null
+++ b/Tools/QtTestBrowser/fpstimer.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 "fpstimer.h"
+
+#include <QDateTime>
+#include <QTimerEvent>
+
+// We save a maximum of 10000 frames, and purge 2000 at a time
+#define MAX_FRAMES_SAVED 10000
+#define FRAMES_TO_PURGE_WHEN_FULL 2000
+// 60 FPS
+#define FPS_MEASURE_INTERVAL 1000 / 60
+
+FpsTimer::FpsTimer(QObject* parent)
+ : QObject(parent)
+ , m_timer(0)
+{
+}
+
+int FpsTimer::numFrames(int spanMillis) const
+{
+ const QTime now = QTime::currentTime();
+
+ int count = 0;
+ for (int i = m_frames.length() - 1; i >= 0; --i, ++count) {
+ int msecs = m_frames[i].msecsTo(now);
+ if (msecs < 0)
+ msecs += 24 * 60 * 60 * 1000;
+ if (msecs > spanMillis)
+ break;
+ }
+ return count;
+}
+
+void FpsTimer::start()
+{
+ m_timer = startTimer(FPS_MEASURE_INTERVAL);
+}
+
+void FpsTimer::stop()
+{
+ if (!m_timer)
+ return;
+ killTimer(m_timer);
+ m_frames.clear();
+}
+
+void FpsTimer::timerEvent(QTimerEvent* event)
+{
+ if (event->timerId() != m_timer)
+ return;
+ m_frames.append(QTime::currentTime());
+ if (m_frames.length() > MAX_FRAMES_SAVED)
+ m_frames.erase(m_frames.begin(), m_frames.begin() + FRAMES_TO_PURGE_WHEN_FULL);
+}
diff --git a/Tools/QtTestBrowser/fpstimer.h b/Tools/QtTestBrowser/fpstimer.h
new file mode 100644
index 0000000..eed1198
--- /dev/null
+++ b/Tools/QtTestBrowser/fpstimer.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 fpstimer_h
+#define fpstimer_h
+
+#include <QObject>
+#include <QSet>
+#include <QTime>
+
+class FpsTimer : public QObject {
+ Q_OBJECT
+
+public:
+ FpsTimer(QObject* parent = 0);
+ int numFrames(int spanMillis = 1000) const;
+
+public Q_SLOTS:
+ void start();
+ void stop();
+
+protected slots:
+ virtual void timerEvent(QTimerEvent*);
+
+private:
+ int m_timer;
+ QList<QTime> m_frames;
+};
+
+#endif // FPSMEASURE_H
diff --git a/Tools/QtTestBrowser/launcherwindow.cpp b/Tools/QtTestBrowser/launcherwindow.cpp
new file mode 100644
index 0000000..1a4d28f
--- /dev/null
+++ b/Tools/QtTestBrowser/launcherwindow.cpp
@@ -0,0 +1,872 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.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:
+ * 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 "launcherwindow.h"
+
+const int gExitClickArea = 80;
+QVector<int> LauncherWindow::m_zoomLevels;
+
+LauncherWindow::LauncherWindow(WindowOptions* data, QGraphicsScene* sharedScene)
+ : MainWindow()
+ , m_currentZoom(100)
+ , m_view(0)
+ , m_inspector(0)
+ , m_formatMenuAction(0)
+ , m_zoomAnimation(0)
+{
+ if (data)
+ m_windowOptions = *data;
+
+ init();
+ if (sharedScene && data->useGraphicsView)
+ static_cast<QGraphicsView*>(m_view)->setScene(sharedScene);
+
+ createChrome();
+}
+
+LauncherWindow::~LauncherWindow()
+{
+ grabZoomKeys(false);
+}
+
+void LauncherWindow::init()
+{
+ QSplitter* splitter = new QSplitter(Qt::Vertical, this);
+ setCentralWidget(splitter);
+
+#if defined(Q_OS_SYMBIAN)
+ setWindowState(Qt::WindowMaximized);
+#else
+ setWindowState(Qt::WindowNoState);
+ resize(800, 600);
+#endif
+
+ m_inspector = new WebInspector;
+#ifndef QT_NO_PROPERTIES
+ if (!m_windowOptions.inspectorUrl.isEmpty())
+ m_inspector->setProperty("_q_inspectorUrl", m_windowOptions.inspectorUrl);
+#endif
+ connect(this, SIGNAL(destroyed()), m_inspector, SLOT(deleteLater()));
+
+ // the zoom values are chosen to be like in Mozilla Firefox 3
+ if (!m_zoomLevels.count()) {
+ m_zoomLevels << 30 << 50 << 67 << 80 << 90;
+ m_zoomLevels << 100;
+ m_zoomLevels << 110 << 120 << 133 << 150 << 170 << 200 << 240 << 300;
+ }
+
+ grabZoomKeys(true);
+
+ initializeView();
+}
+
+void LauncherWindow::initializeView()
+{
+ delete m_view;
+
+ QUrl url = page()->mainFrame()->url();
+ setPage(new WebPage(this));
+ page()->setQnamThreaded(m_windowOptions.useThreadedQnam);
+
+ QSplitter* splitter = static_cast<QSplitter*>(centralWidget());
+
+ if (!m_windowOptions.useGraphicsView) {
+ WebViewTraditional* view = new WebViewTraditional(splitter);
+ view->setPage(page());
+
+ view->installEventFilter(this);
+
+ m_view = view;
+ } else {
+ WebViewGraphicsBased* view = new WebViewGraphicsBased(splitter);
+ view->setPage(page());
+
+ connect(view, SIGNAL(currentFPSUpdated(int)), this, SLOT(updateFPS(int)));
+
+ view->installEventFilter(this);
+ // The implementation of QAbstractScrollArea::eventFilter makes us need
+ // to install the event filter also on the viewport of a QGraphicsView.
+ view->viewport()->installEventFilter(this);
+
+ m_view = view;
+ }
+
+ m_touchMocking = false;
+
+ connect(page(), SIGNAL(loadStarted()), this, SLOT(loadStarted()));
+ connect(page(), SIGNAL(loadFinished(bool)), this, SLOT(loadFinished()));
+ connect(page(), SIGNAL(linkHovered(const QString&, const QString&, const QString&)),
+ this, SLOT(showLinkHover(const QString&, const QString&)));
+ connect(this, SIGNAL(enteredFullScreenMode(bool)), this, SLOT(toggleFullScreenMode(bool)));
+
+ applyPrefs();
+
+ splitter->addWidget(m_inspector);
+ m_inspector->setPage(page());
+ m_inspector->hide();
+
+ if (m_windowOptions.remoteInspectorPort)
+ page()->setProperty("_q_webInspectorServerPort", m_windowOptions.remoteInspectorPort);
+
+ if (url.isValid())
+ page()->mainFrame()->load(url);
+}
+
+void LauncherWindow::applyPrefs()
+{
+ QWebSettings* settings = page()->settings();
+ settings->setAttribute(QWebSettings::AcceleratedCompositingEnabled, m_windowOptions.useCompositing);
+ settings->setAttribute(QWebSettings::TiledBackingStoreEnabled, m_windowOptions.useTiledBackingStore);
+ settings->setAttribute(QWebSettings::FrameFlatteningEnabled, m_windowOptions.useFrameFlattening);
+ settings->setAttribute(QWebSettings::WebGLEnabled, m_windowOptions.useWebGL);
+
+ if (!isGraphicsBased())
+ return;
+
+ WebViewGraphicsBased* view = static_cast<WebViewGraphicsBased*>(m_view);
+ view->setViewportUpdateMode(m_windowOptions.viewportUpdateMode);
+ view->setFrameRateMeasurementEnabled(m_windowOptions.showFrameRate);
+ view->setItemCacheMode(m_windowOptions.cacheWebView ? QGraphicsItem::DeviceCoordinateCache : QGraphicsItem::NoCache);
+
+ if (m_windowOptions.resizesToContents)
+ toggleResizesToContents(m_windowOptions.resizesToContents);
+}
+
+void LauncherWindow::createChrome()
+{
+ QMenu* fileMenu = menuBar()->addMenu("&File");
+ fileMenu->addAction("New Window", this, SLOT(newWindow()), QKeySequence::New);
+ fileMenu->addAction(tr("Open File..."), this, SLOT(openFile()), QKeySequence::Open);
+ fileMenu->addAction(tr("Open Location..."), this, SLOT(openLocation()), QKeySequence(Qt::CTRL | Qt::Key_L));
+ fileMenu->addAction("Close Window", this, SLOT(close()), QKeySequence::Close);
+ fileMenu->addSeparator();
+ fileMenu->addAction("Take Screen Shot...", this, SLOT(screenshot()));
+ fileMenu->addAction(tr("Print..."), this, SLOT(print()), QKeySequence::Print);
+ fileMenu->addSeparator();
+ fileMenu->addAction("Quit", QApplication::instance(), SLOT(closeAllWindows()), QKeySequence(Qt::CTRL | Qt::Key_Q));
+
+ QMenu* editMenu = menuBar()->addMenu("&Edit");
+ editMenu->addAction(page()->action(QWebPage::Undo));
+ editMenu->addAction(page()->action(QWebPage::Redo));
+ editMenu->addSeparator();
+ editMenu->addAction(page()->action(QWebPage::Cut));
+ editMenu->addAction(page()->action(QWebPage::Copy));
+ editMenu->addAction(page()->action(QWebPage::Paste));
+ editMenu->addSeparator();
+ QAction* setEditable = editMenu->addAction("Set Editable", this, SLOT(setEditable(bool)));
+ setEditable->setCheckable(true);
+
+ QMenu* viewMenu = menuBar()->addMenu("&View");
+ viewMenu->addAction(page()->action(QWebPage::Stop));
+ viewMenu->addAction(page()->action(QWebPage::Reload));
+ viewMenu->addSeparator();
+ QAction* zoomIn = viewMenu->addAction("Zoom &In", this, SLOT(zoomIn()));
+ QAction* zoomOut = viewMenu->addAction("Zoom &Out", this, SLOT(zoomOut()));
+ QAction* resetZoom = viewMenu->addAction("Reset Zoom", this, SLOT(resetZoom()));
+ QAction* zoomTextOnly = viewMenu->addAction("Zoom Text Only", this, SLOT(toggleZoomTextOnly(bool)));
+ zoomTextOnly->setCheckable(true);
+ zoomTextOnly->setChecked(false);
+ viewMenu->addSeparator();
+ viewMenu->addAction("Dump HTML", this, SLOT(dumpHtml()));
+ // viewMenu->addAction("Dump plugins", this, SLOT(dumpPlugins()));
+
+ zoomIn->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Plus));
+ zoomOut->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Minus));
+ resetZoom->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_0));
+
+ QMenu* formatMenu = new QMenu("F&ormat", this);
+ m_formatMenuAction = menuBar()->addMenu(formatMenu);
+ m_formatMenuAction->setVisible(false);
+ formatMenu->addAction(page()->action(QWebPage::ToggleBold));
+ formatMenu->addAction(page()->action(QWebPage::ToggleItalic));
+ formatMenu->addAction(page()->action(QWebPage::ToggleUnderline));
+ QMenu* writingMenu = formatMenu->addMenu(tr("Writing Direction"));
+ writingMenu->addAction(page()->action(QWebPage::SetTextDirectionDefault));
+ writingMenu->addAction(page()->action(QWebPage::SetTextDirectionLeftToRight));
+ writingMenu->addAction(page()->action(QWebPage::SetTextDirectionRightToLeft));
+
+ QMenu* windowMenu = menuBar()->addMenu("&Window");
+ QAction* toggleFullScreen = windowMenu->addAction("Toggle FullScreen", this, SIGNAL(enteredFullScreenMode(bool)));
+ toggleFullScreen->setShortcut(Qt::Key_F11);
+ toggleFullScreen->setCheckable(true);
+ toggleFullScreen->setChecked(false);
+ // When exit fullscreen mode by clicking on the exit area (bottom right corner) we must
+ // uncheck the Toggle FullScreen action.
+ toggleFullScreen->connect(this, SIGNAL(enteredFullScreenMode(bool)), SLOT(setChecked(bool)));
+
+ QWebSettings* settings = page()->settings();
+
+ QMenu* toolsMenu = menuBar()->addMenu("&Develop");
+ QMenu* graphicsViewMenu = toolsMenu->addMenu("QGraphicsView");
+ QAction* toggleGraphicsView = graphicsViewMenu->addAction("Toggle use of QGraphicsView", this, SLOT(toggleWebView(bool)));
+ toggleGraphicsView->setCheckable(true);
+ toggleGraphicsView->setChecked(isGraphicsBased());
+
+ QAction* toggleWebGL = toolsMenu->addAction("Toggle WebGL", this, SLOT(toggleWebGL(bool)));
+ toggleWebGL->setCheckable(true);
+ toggleWebGL->setChecked(settings->testAttribute(QWebSettings::WebGLEnabled));
+
+ QAction* toggleThreadedQnam = toolsMenu->addAction("Toggle threaded network", this, SLOT(toggleThreadedQnam(bool)));
+ toggleThreadedQnam->setCheckable(true);
+ toggleThreadedQnam->setChecked(m_windowOptions.useThreadedQnam);
+
+ QAction* spatialNavigationAction = toolsMenu->addAction("Toggle Spatial Navigation", this, SLOT(toggleSpatialNavigation(bool)));
+ spatialNavigationAction->setCheckable(true);
+ spatialNavigationAction->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_S));
+
+ QAction* toggleFrameFlattening = toolsMenu->addAction("Toggle Frame Flattening", this, SLOT(toggleFrameFlattening(bool)));
+ toggleFrameFlattening->setCheckable(true);
+ toggleFrameFlattening->setChecked(settings->testAttribute(QWebSettings::FrameFlatteningEnabled));
+
+ QAction* touchMockAction = toolsMenu->addAction("Toggle touch mocking", this, SLOT(setTouchMocking(bool)));
+ touchMockAction->setCheckable(true);
+ touchMockAction->setShortcut(QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_T));
+
+ toolsMenu->addSeparator();
+
+ QAction* toggleInterruptingJavaScripteEnabled = toolsMenu->addAction("Enable interrupting js scripts", this, SLOT(toggleInterruptingJavaScriptEnabled(bool)));
+ toggleInterruptingJavaScripteEnabled->setCheckable(true);
+ toggleInterruptingJavaScripteEnabled->setChecked(false);
+
+ QAction* toggleJavascriptCanOpenWindows = toolsMenu->addAction("Enable js popup windows", this, SLOT(toggleJavascriptCanOpenWindows(bool)));
+ toggleJavascriptCanOpenWindows->setCheckable(true);
+ toggleJavascriptCanOpenWindows->setChecked(false);
+
+ toolsMenu->addSeparator();
+
+ QAction* userAgentAction = toolsMenu->addAction("Change User Agent", this, SLOT(showUserAgentDialog()));
+ userAgentAction->setShortcut(QKeySequence(Qt::CTRL | Qt::SHIFT | Qt::Key_U));
+
+ toolsMenu->addAction("Select Elements...", this, SLOT(selectElements()));
+
+ QAction* showInspectorAction = toolsMenu->addAction("Show Web Inspector", m_inspector, SLOT(setVisible(bool)), QKeySequence(Qt::CTRL | Qt::ALT | Qt::Key_I));
+ showInspectorAction->setCheckable(true);
+ showInspectorAction->connect(m_inspector, SIGNAL(visibleChanged(bool)), SLOT(setChecked(bool)));
+
+ // GraphicsView sub menu.
+ QAction* toggleAcceleratedCompositing = graphicsViewMenu->addAction("Toggle Accelerated Compositing", this, SLOT(toggleAcceleratedCompositing(bool)));
+ toggleAcceleratedCompositing->setCheckable(true);
+ toggleAcceleratedCompositing->setChecked(settings->testAttribute(QWebSettings::AcceleratedCompositingEnabled));
+ toggleAcceleratedCompositing->setEnabled(isGraphicsBased());
+ toggleAcceleratedCompositing->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
+
+ QAction* toggleResizesToContents = graphicsViewMenu->addAction("Toggle Resizes To Contents Mode", this, SLOT(toggleResizesToContents(bool)));
+ toggleResizesToContents->setCheckable(true);
+ toggleResizesToContents->setChecked(m_windowOptions.resizesToContents);
+ toggleResizesToContents->setEnabled(isGraphicsBased());
+ toggleResizesToContents->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
+
+ QAction* toggleTiledBackingStore = graphicsViewMenu->addAction("Toggle Tiled Backing Store", this, SLOT(toggleTiledBackingStore(bool)));
+ toggleTiledBackingStore->setCheckable(true);
+ toggleTiledBackingStore->setChecked(m_windowOptions.useTiledBackingStore);
+ toggleTiledBackingStore->setEnabled(isGraphicsBased());
+ toggleTiledBackingStore->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
+
+#if defined(QT_CONFIGURED_WITH_OPENGL)
+ QAction* toggleQGLWidgetViewport = graphicsViewMenu->addAction("Toggle use of QGLWidget Viewport", this, SLOT(toggleQGLWidgetViewport(bool)));
+ toggleQGLWidgetViewport->setCheckable(true);
+ toggleQGLWidgetViewport->setChecked(m_windowOptions.useQGLWidgetViewport);
+ toggleQGLWidgetViewport->setEnabled(isGraphicsBased());
+ toggleQGLWidgetViewport->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
+#endif
+
+ QMenu* viewportUpdateMenu = graphicsViewMenu->addMenu("Change Viewport Update Mode");
+ viewportUpdateMenu->setEnabled(isGraphicsBased());
+ viewportUpdateMenu->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
+
+ QAction* fullUpdate = viewportUpdateMenu->addAction("FullViewportUpdate");
+ fullUpdate->setCheckable(true);
+ fullUpdate->setChecked((m_windowOptions.viewportUpdateMode == QGraphicsView::FullViewportUpdate) ? true : false);
+
+ QAction* minimalUpdate = viewportUpdateMenu->addAction("MinimalViewportUpdate");
+ minimalUpdate->setCheckable(true);
+ minimalUpdate->setChecked((m_windowOptions.viewportUpdateMode == QGraphicsView::MinimalViewportUpdate) ? true : false);
+
+ QAction* smartUpdate = viewportUpdateMenu->addAction("SmartViewportUpdate");
+ smartUpdate->setCheckable(true);
+ smartUpdate->setChecked((m_windowOptions.viewportUpdateMode == QGraphicsView::SmartViewportUpdate) ? true : false);
+
+ QAction* boundingRectUpdate = viewportUpdateMenu->addAction("BoundingRectViewportUpdate");
+ boundingRectUpdate->setCheckable(true);
+ boundingRectUpdate->setChecked((m_windowOptions.viewportUpdateMode == QGraphicsView::BoundingRectViewportUpdate) ? true : false);
+
+ QAction* noUpdate = viewportUpdateMenu->addAction("NoViewportUpdate");
+ noUpdate->setCheckable(true);
+ noUpdate->setChecked((m_windowOptions.viewportUpdateMode == QGraphicsView::NoViewportUpdate) ? true : false);
+
+ QSignalMapper* signalMapper = new QSignalMapper(viewportUpdateMenu);
+ signalMapper->setMapping(fullUpdate, QGraphicsView::FullViewportUpdate);
+ signalMapper->setMapping(minimalUpdate, QGraphicsView::MinimalViewportUpdate);
+ signalMapper->setMapping(smartUpdate, QGraphicsView::SmartViewportUpdate);
+ signalMapper->setMapping(boundingRectUpdate, QGraphicsView::BoundingRectViewportUpdate);
+ signalMapper->setMapping(noUpdate, QGraphicsView::NoViewportUpdate);
+
+ connect(fullUpdate, SIGNAL(triggered()), signalMapper, SLOT(map()));
+ connect(minimalUpdate, SIGNAL(triggered()), signalMapper, SLOT(map()));
+ connect(smartUpdate, SIGNAL(triggered()), signalMapper, SLOT(map()));
+ connect(boundingRectUpdate, SIGNAL(triggered()), signalMapper, SLOT(map()));
+ connect(noUpdate, SIGNAL(triggered()), signalMapper, SLOT(map()));
+
+ connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(changeViewportUpdateMode(int)));
+
+ QActionGroup* viewportUpdateModeActions = new QActionGroup(viewportUpdateMenu);
+ viewportUpdateModeActions->addAction(fullUpdate);
+ viewportUpdateModeActions->addAction(minimalUpdate);
+ viewportUpdateModeActions->addAction(smartUpdate);
+ viewportUpdateModeActions->addAction(boundingRectUpdate);
+ viewportUpdateModeActions->addAction(noUpdate);
+
+ graphicsViewMenu->addSeparator();
+
+ QAction* flipAnimated = graphicsViewMenu->addAction("Animated Flip");
+ flipAnimated->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
+ flipAnimated->setEnabled(isGraphicsBased());
+ connect(flipAnimated, SIGNAL(triggered()), SLOT(animatedFlip()));
+
+ QAction* flipYAnimated = graphicsViewMenu->addAction("Animated Y-Flip");
+ flipYAnimated->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
+ flipYAnimated->setEnabled(isGraphicsBased());
+ connect(flipYAnimated, SIGNAL(triggered()), SLOT(animatedYFlip()));
+
+ QAction* cloneWindow = graphicsViewMenu->addAction("Clone Window", this, SLOT(cloneWindow()));
+ cloneWindow->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
+ cloneWindow->setEnabled(isGraphicsBased());
+
+ graphicsViewMenu->addSeparator();
+
+ QAction* showFPS = graphicsViewMenu->addAction("Show FPS", this, SLOT(showFPS(bool)));
+ showFPS->setCheckable(true);
+ showFPS->setEnabled(isGraphicsBased());
+ showFPS->connect(toggleGraphicsView, SIGNAL(toggled(bool)), SLOT(setEnabled(bool)));
+ showFPS->setChecked(m_windowOptions.showFrameRate);
+}
+
+bool LauncherWindow::isGraphicsBased() const
+{
+ return bool(qobject_cast<QGraphicsView*>(m_view));
+}
+
+void LauncherWindow::keyPressEvent(QKeyEvent* event)
+{
+#ifdef Q_WS_MAEMO_5
+ switch (event->key()) {
+ case Qt::Key_F7:
+ zoomIn();
+ event->accept();
+ break;
+ case Qt::Key_F8:
+ zoomOut();
+ event->accept();
+ break;
+ }
+#endif
+ MainWindow::keyPressEvent(event);
+}
+
+void LauncherWindow::grabZoomKeys(bool grab)
+{
+#ifdef Q_WS_MAEMO_5
+ if (!winId()) {
+ qWarning("Can't grab keys unless we have a window id");
+ return;
+ }
+
+ Atom atom = XInternAtom(QX11Info::display(), "_HILDON_ZOOM_KEY_ATOM", False);
+ if (!atom) {
+ qWarning("Unable to obtain _HILDON_ZOOM_KEY_ATOM");
+ return;
+ }
+
+ unsigned long val = (grab) ? 1 : 0;
+ XChangeProperty(QX11Info::display(), winId(), atom, XA_INTEGER, 32, PropModeReplace, reinterpret_cast<unsigned char*>(&val), 1);
+#endif
+}
+
+void LauncherWindow::sendTouchEvent()
+{
+ if (m_touchPoints.isEmpty())
+ return;
+
+ QEvent::Type type = QEvent::TouchUpdate;
+ if (m_touchPoints.size() == 1) {
+ if (m_touchPoints[0].state() == Qt::TouchPointReleased)
+ type = QEvent::TouchEnd;
+ else if (m_touchPoints[0].state() == Qt::TouchPointPressed)
+ type = QEvent::TouchBegin;
+ }
+
+ QTouchEvent touchEv(type);
+ touchEv.setTouchPoints(m_touchPoints);
+ QCoreApplication::sendEvent(page(), &touchEv);
+
+ // After sending the event, remove all touchpoints that were released
+ if (m_touchPoints[0].state() == Qt::TouchPointReleased)
+ m_touchPoints.removeAt(0);
+ if (m_touchPoints.size() > 1 && m_touchPoints[1].state() == Qt::TouchPointReleased)
+ m_touchPoints.removeAt(1);
+}
+
+bool LauncherWindow::eventFilter(QObject* obj, QEvent* event)
+{
+ // If click pos is the bottom right corner (square with size defined by gExitClickArea)
+ // and the window is on FullScreen, the window must return to its original state.
+ if (event->type() == QEvent::MouseButtonRelease) {
+ QMouseEvent* ev = static_cast<QMouseEvent*>(event);
+ if (windowState() == Qt::WindowFullScreen
+ && ev->pos().x() > (width() - gExitClickArea)
+ && ev->pos().y() > (height() - gExitClickArea)) {
+
+ emit enteredFullScreenMode(false);
+ }
+ }
+
+ if (!m_touchMocking)
+ return QObject::eventFilter(obj, event);
+
+ if (event->type() == QEvent::MouseButtonPress
+ || event->type() == QEvent::MouseButtonRelease
+ || event->type() == QEvent::MouseButtonDblClick
+ || event->type() == QEvent::MouseMove) {
+
+ QMouseEvent* ev = static_cast<QMouseEvent*>(event);
+ if (ev->type() == QEvent::MouseMove
+ && !(ev->buttons() & Qt::LeftButton))
+ return false;
+
+ QTouchEvent::TouchPoint touchPoint;
+ touchPoint.setState(Qt::TouchPointMoved);
+ if ((ev->type() == QEvent::MouseButtonPress
+ || ev->type() == QEvent::MouseButtonDblClick))
+ touchPoint.setState(Qt::TouchPointPressed);
+ else if (ev->type() == QEvent::MouseButtonRelease)
+ touchPoint.setState(Qt::TouchPointReleased);
+
+ touchPoint.setId(0);
+ touchPoint.setScreenPos(ev->globalPos());
+ touchPoint.setPos(ev->pos());
+ touchPoint.setPressure(1);
+
+ // If the point already exists, update it. Otherwise create it.
+ if (m_touchPoints.size() > 0 && !m_touchPoints[0].id())
+ m_touchPoints[0] = touchPoint;
+ else if (m_touchPoints.size() > 1 && !m_touchPoints[1].id())
+ m_touchPoints[1] = touchPoint;
+ else
+ m_touchPoints.append(touchPoint);
+
+ sendTouchEvent();
+ } else if (event->type() == QEvent::KeyPress
+ && static_cast<QKeyEvent*>(event)->key() == Qt::Key_F
+ && static_cast<QKeyEvent*>(event)->modifiers() == Qt::ControlModifier) {
+
+ // If the keyboard point is already pressed, release it.
+ // Otherwise create it and append to m_touchPoints.
+ if (m_touchPoints.size() > 0 && m_touchPoints[0].id() == 1) {
+ m_touchPoints[0].setState(Qt::TouchPointReleased);
+ sendTouchEvent();
+ } else if (m_touchPoints.size() > 1 && m_touchPoints[1].id() == 1) {
+ m_touchPoints[1].setState(Qt::TouchPointReleased);
+ sendTouchEvent();
+ } else {
+ QTouchEvent::TouchPoint touchPoint;
+ touchPoint.setState(Qt::TouchPointPressed);
+ touchPoint.setId(1);
+ touchPoint.setScreenPos(QCursor::pos());
+ touchPoint.setPos(m_view->mapFromGlobal(QCursor::pos()));
+ touchPoint.setPressure(1);
+ m_touchPoints.append(touchPoint);
+ sendTouchEvent();
+
+ // After sending the event, change the touchpoint state to stationary
+ m_touchPoints.last().setState(Qt::TouchPointStationary);
+ }
+ }
+
+ return false;
+}
+
+void LauncherWindow::loadStarted()
+{
+ m_view->setFocus(Qt::OtherFocusReason);
+}
+
+void LauncherWindow::loadFinished()
+{
+ QUrl url = page()->mainFrame()->url();
+ setAddressUrl(url.toString(QUrl::RemoveUserInfo));
+ addCompleterEntry(url);
+}
+
+void LauncherWindow::showLinkHover(const QString &link, const QString &toolTip)
+{
+#ifndef Q_WS_MAEMO_5
+ statusBar()->showMessage(link);
+#endif
+#ifndef QT_NO_TOOLTIP
+ if (!toolTip.isEmpty())
+ QToolTip::showText(QCursor::pos(), toolTip);
+#endif
+}
+
+void LauncherWindow::zoomAnimationFinished()
+{
+ if (!isGraphicsBased())
+ return;
+ QGraphicsWebView* view = static_cast<WebViewGraphicsBased*>(m_view)->graphicsWebView();
+ view->setTiledBackingStoreFrozen(false);
+}
+
+void LauncherWindow::applyZoom()
+{
+ if (isGraphicsBased() && page()->settings()->testAttribute(QWebSettings::TiledBackingStoreEnabled)) {
+ QGraphicsWebView* view = static_cast<WebViewGraphicsBased*>(m_view)->graphicsWebView();
+ view->setTiledBackingStoreFrozen(true);
+ if (!m_zoomAnimation) {
+ m_zoomAnimation = new QPropertyAnimation(view, "scale");
+ m_zoomAnimation->setStartValue(view->scale());
+ connect(m_zoomAnimation, SIGNAL(finished()), this, SLOT(zoomAnimationFinished()));
+ } else {
+ m_zoomAnimation->stop();
+ m_zoomAnimation->setStartValue(m_zoomAnimation->currentValue());
+ }
+
+ m_zoomAnimation->setDuration(300);
+ m_zoomAnimation->setEndValue(qreal(m_currentZoom) / 100.);
+ m_zoomAnimation->start();
+ return;
+ }
+ page()->mainFrame()->setZoomFactor(qreal(m_currentZoom) / 100.0);
+}
+
+void LauncherWindow::zoomIn()
+{
+ int i = m_zoomLevels.indexOf(m_currentZoom);
+ Q_ASSERT(i >= 0);
+ if (i < m_zoomLevels.count() - 1)
+ m_currentZoom = m_zoomLevels[i + 1];
+
+ applyZoom();
+}
+
+void LauncherWindow::zoomOut()
+{
+ int i = m_zoomLevels.indexOf(m_currentZoom);
+ Q_ASSERT(i >= 0);
+ if (i > 0)
+ m_currentZoom = m_zoomLevels[i - 1];
+
+ applyZoom();
+}
+
+void LauncherWindow::resetZoom()
+{
+ m_currentZoom = 100;
+ applyZoom();
+}
+
+void LauncherWindow::toggleZoomTextOnly(bool b)
+{
+ page()->settings()->setAttribute(QWebSettings::ZoomTextOnly, b);
+}
+
+void LauncherWindow::print()
+{
+#if !defined(QT_NO_PRINTER)
+ QPrintPreviewDialog dlg(this);
+ connect(&dlg, SIGNAL(paintRequested(QPrinter*)),
+ page()->mainFrame(), SLOT(print(QPrinter*)));
+ dlg.exec();
+#endif
+}
+
+void LauncherWindow::screenshot()
+{
+ QPixmap pixmap = QPixmap::grabWidget(m_view);
+ QLabel* label = 0;
+#if !defined(Q_OS_SYMBIAN)
+ label = new QLabel;
+ label->setAttribute(Qt::WA_DeleteOnClose);
+ label->setWindowTitle("Screenshot - Preview");
+ label->setPixmap(pixmap);
+ label->show();
+#endif
+
+ QString fileName = QFileDialog::getSaveFileName(label, "Screenshot");
+ if (!fileName.isEmpty()) {
+ pixmap.save(fileName, "png");
+ if (label)
+ label->setWindowTitle(QString("Screenshot - Saved at %1").arg(fileName));
+ }
+
+#if defined(QT_CONFIGURED_WITH_OPENGL)
+ toggleQGLWidgetViewport(m_windowOptions.useQGLWidgetViewport);
+#endif
+}
+
+void LauncherWindow::setEditable(bool on)
+{
+ page()->setContentEditable(on);
+ m_formatMenuAction->setVisible(on);
+}
+
+/*
+void LauncherWindow::dumpPlugins() {
+ QList<QWebPluginInfo> plugins = QWebSettings::pluginDatabase()->plugins();
+ foreach (const QWebPluginInfo plugin, plugins) {
+ qDebug() << "Plugin:" << plugin.name();
+ foreach (const QWebPluginInfo::MimeType mime, plugin.mimeTypes()) {
+ qDebug() << " " << mime.name;
+ }
+ }
+}
+*/
+
+void LauncherWindow::dumpHtml()
+{
+ qDebug() << "HTML: " << page()->mainFrame()->toHtml();
+}
+
+void LauncherWindow::selectElements()
+{
+ bool ok;
+ QString str = QInputDialog::getText(this, "Select elements", "Choose elements",
+ QLineEdit::Normal, "a", &ok);
+
+ if (ok && !str.isEmpty()) {
+ QWebElementCollection result = page()->mainFrame()->findAllElements(str);
+ foreach (QWebElement e, result)
+ e.setStyleProperty("background-color", "yellow");
+#ifndef Q_WS_MAEMO_5
+ statusBar()->showMessage(QString("%1 element(s) selected").arg(result.count()), 5000);
+#endif
+ }
+}
+
+void LauncherWindow::setTouchMocking(bool on)
+{
+ m_touchMocking = on;
+}
+
+void LauncherWindow::toggleWebView(bool graphicsBased)
+{
+ m_windowOptions.useGraphicsView = graphicsBased;
+ initializeView();
+ menuBar()->clear();
+ createChrome();
+}
+
+void LauncherWindow::toggleAcceleratedCompositing(bool toggle)
+{
+ m_windowOptions.useCompositing = toggle;
+ page()->settings()->setAttribute(QWebSettings::AcceleratedCompositingEnabled, toggle);
+}
+
+void LauncherWindow::toggleTiledBackingStore(bool toggle)
+{
+ page()->settings()->setAttribute(QWebSettings::TiledBackingStoreEnabled, toggle);
+}
+
+void LauncherWindow::toggleResizesToContents(bool toggle)
+{
+ m_windowOptions.resizesToContents = toggle;
+ static_cast<WebViewGraphicsBased*>(m_view)->setResizesToContents(toggle);
+}
+
+void LauncherWindow::toggleWebGL(bool toggle)
+{
+ m_windowOptions.useWebGL = toggle;
+ page()->settings()->setAttribute(QWebSettings::WebGLEnabled, toggle);
+}
+
+void LauncherWindow::toggleThreadedQnam(bool toggle)
+{
+ m_windowOptions.useThreadedQnam = toggle;
+ page()->setQnamThreaded(toggle);
+}
+
+void LauncherWindow::animatedFlip()
+{
+ qobject_cast<WebViewGraphicsBased*>(m_view)->animatedFlip();
+}
+
+void LauncherWindow::animatedYFlip()
+{
+ qobject_cast<WebViewGraphicsBased*>(m_view)->animatedYFlip();
+}
+void LauncherWindow::toggleSpatialNavigation(bool b)
+{
+ page()->settings()->setAttribute(QWebSettings::SpatialNavigationEnabled, b);
+}
+
+void LauncherWindow::toggleFullScreenMode(bool enable)
+{
+ if (enable)
+ setWindowState(Qt::WindowFullScreen);
+ else {
+#if defined(Q_OS_SYMBIAN)
+ setWindowState(Qt::WindowMaximized);
+#else
+ setWindowState(Qt::WindowNoState);
+#endif
+ }
+}
+
+void LauncherWindow::toggleFrameFlattening(bool toggle)
+{
+ m_windowOptions.useFrameFlattening = toggle;
+ page()->settings()->setAttribute(QWebSettings::FrameFlatteningEnabled, toggle);
+}
+
+void LauncherWindow::toggleInterruptingJavaScriptEnabled(bool enable)
+{
+ page()->setInterruptingJavaScriptEnabled(enable);
+}
+
+void LauncherWindow::toggleJavascriptCanOpenWindows(bool enable)
+{
+ page()->settings()->setAttribute(QWebSettings::JavascriptCanOpenWindows, enable);
+}
+
+#if defined(QT_CONFIGURED_WITH_OPENGL)
+void LauncherWindow::toggleQGLWidgetViewport(bool enable)
+{
+ if (!isGraphicsBased())
+ return;
+
+ m_windowOptions.useQGLWidgetViewport = enable;
+ WebViewGraphicsBased* view = static_cast<WebViewGraphicsBased*>(m_view);
+
+ view->setViewport(enable ? new QGLWidget() : 0);
+}
+#endif
+
+void LauncherWindow::changeViewportUpdateMode(int mode)
+{
+ m_windowOptions.viewportUpdateMode = QGraphicsView::ViewportUpdateMode(mode);
+
+ if (!isGraphicsBased())
+ return;
+
+ WebViewGraphicsBased* view = static_cast<WebViewGraphicsBased*>(m_view);
+ view->setViewportUpdateMode(m_windowOptions.viewportUpdateMode);
+}
+
+void LauncherWindow::showFPS(bool enable)
+{
+ if (!isGraphicsBased())
+ return;
+
+ m_windowOptions.showFrameRate = enable;
+ WebViewGraphicsBased* view = static_cast<WebViewGraphicsBased*>(m_view);
+ view->setFrameRateMeasurementEnabled(enable);
+
+ if (!enable) {
+#if defined(Q_WS_MAEMO_5) && defined(Q_OS_SYMBIAN)
+ setWindowTitle("");
+#else
+ statusBar()->clearMessage();
+#endif
+ }
+}
+
+void LauncherWindow::showUserAgentDialog()
+{
+ QStringList items;
+ QFile file(":/useragentlist.txt");
+ if (file.open(QIODevice::ReadOnly)) {
+ while (!file.atEnd())
+ items << file.readLine().trimmed();
+ file.close();
+ }
+
+ QSettings settings;
+ QString customUserAgent = settings.value("CustomUserAgent").toString();
+ if (!items.contains(customUserAgent) && !customUserAgent.isEmpty())
+ items << customUserAgent;
+
+ QDialog* dialog = new QDialog(this);
+ dialog->resize(size().width() * 0.7, dialog->size().height());
+ dialog->setMaximumHeight(dialog->size().height());
+ dialog->setWindowTitle("Change User Agent");
+
+ QVBoxLayout* layout = new QVBoxLayout(dialog);
+ dialog->setLayout(layout);
+
+ QComboBox* combo = new QComboBox(dialog);
+ combo->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
+ combo->setEditable(true);
+ combo->insertItems(0, items);
+ layout->addWidget(combo);
+
+ int index = combo->findText(page()->userAgentForUrl(QUrl()));
+ combo->setCurrentIndex(index);
+
+ QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
+ | QDialogButtonBox::Cancel, Qt::Horizontal, dialog);
+ connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
+ layout->addWidget(buttonBox);
+
+ if (dialog->exec() && !combo->currentText().isEmpty()) {
+ page()->setUserAgent(combo->currentText());
+ if (!items.contains(combo->currentText()))
+ settings.setValue("CustomUserAgent", combo->currentText());
+ }
+
+ delete dialog;
+}
+
+void LauncherWindow::updateFPS(int fps)
+{
+ QString fpsStatusText = QString("Current FPS: %1").arg(fps);
+
+#if defined(Q_WS_MAEMO_5) && defined(Q_OS_SYMBIAN)
+ setWindowTitle(fpsStatusText);
+#else
+ statusBar()->showMessage(fpsStatusText);
+#endif
+}
+
+LauncherWindow* LauncherWindow::newWindow()
+{
+ LauncherWindow* mw = new LauncherWindow(&m_windowOptions);
+ mw->show();
+ return mw;
+}
+
+LauncherWindow* LauncherWindow::cloneWindow()
+{
+ LauncherWindow* mw = new LauncherWindow(&m_windowOptions, qobject_cast<QGraphicsView*>(m_view)->scene());
+ mw->show();
+ return mw;
+}
+
diff --git a/Tools/QtTestBrowser/launcherwindow.h b/Tools/QtTestBrowser/launcherwindow.h
new file mode 100644
index 0000000..e35e7fd
--- /dev/null
+++ b/Tools/QtTestBrowser/launcherwindow.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.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:
+ * 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 launcherwindow_h
+#define launcherwindow_h
+
+#include <QtGui>
+#include <QtNetwork/QNetworkRequest>
+
+#if defined(QT_CONFIGURED_WITH_OPENGL)
+#include <QtOpenGL/QGLWidget>
+#endif
+
+#if !defined(QT_NO_PRINTER)
+#include <QPrintPreviewDialog>
+#endif
+
+#ifndef QT_NO_UITOOLS
+#include <QtUiTools/QUiLoader>
+#endif
+
+#include <QDebug>
+
+#include <cstdio>
+#include <qevent.h>
+#include <qwebelement.h>
+#include <qwebframe.h>
+#include <qwebinspector.h>
+#include <qwebsettings.h>
+
+#ifdef Q_WS_MAEMO_5
+#include <qx11info_x11.h>
+#endif
+
+#include "mainwindow.h"
+#include "urlloader.h"
+#include "utils.h"
+#include "webinspector.h"
+#include "webpage.h"
+#include "webview.h"
+#include "../../WebKit/qt/WebCoreSupport/DumpRenderTreeSupportQt.h"
+
+#ifdef Q_WS_MAEMO_5
+#include <X11/Xatom.h>
+#include <X11/Xlib.h>
+#undef KeyPress
+#endif
+
+class WindowOptions {
+public:
+ WindowOptions()
+ : useGraphicsView(false)
+ , useCompositing(true)
+ , useTiledBackingStore(false)
+ , useWebGL(false)
+#if defined(Q_WS_MAEMO_5) || defined(Q_OS_SYMBIAN)
+ , useFrameFlattening(true)
+#else
+ , useFrameFlattening(false)
+#endif
+ , useThreadedQnam(true)
+ , cacheWebView(false)
+ , showFrameRate(false)
+ , resizesToContents(false)
+ , viewportUpdateMode(QGraphicsView::MinimalViewportUpdate)
+#if defined(QT_CONFIGURED_WITH_OPENGL)
+ , useQGLWidgetViewport(false)
+#endif
+ {
+ }
+
+ bool useGraphicsView;
+ bool useCompositing;
+ bool useTiledBackingStore;
+ bool useWebGL;
+ bool useFrameFlattening;
+ bool useThreadedQnam;
+ bool cacheWebView;
+ bool showFrameRate;
+ bool resizesToContents;
+ QGraphicsView::ViewportUpdateMode viewportUpdateMode;
+#if defined(QT_CONFIGURED_WITH_OPENGL)
+ bool useQGLWidgetViewport;
+#endif
+ QUrl inspectorUrl;
+ quint16 remoteInspectorPort;
+};
+
+class LauncherWindow : public MainWindow {
+ Q_OBJECT
+
+public:
+ LauncherWindow(WindowOptions* data = 0, QGraphicsScene* sharedScene = 0);
+ virtual ~LauncherWindow();
+
+ virtual void keyPressEvent(QKeyEvent* event);
+ void grabZoomKeys(bool grab);
+
+ void sendTouchEvent();
+
+ bool eventFilter(QObject* obj, QEvent* event);
+
+protected slots:
+ void loadStarted();
+ void loadFinished();
+
+ void showLinkHover(const QString &link, const QString &toolTip);
+
+ void zoomIn();
+ void zoomOut();
+ void resetZoom();
+ void toggleZoomTextOnly(bool on);
+ void zoomAnimationFinished();
+
+ void print();
+ void screenshot();
+
+ void setEditable(bool on);
+
+ /* void dumpPlugins() */
+ void dumpHtml();
+
+ void setTouchMocking(bool on);
+ void toggleWebView(bool graphicsBased);
+ void toggleAcceleratedCompositing(bool toggle);
+ void toggleTiledBackingStore(bool toggle);
+ void toggleResizesToContents(bool toggle);
+ void toggleWebGL(bool toggle);
+ void toggleThreadedQnam(bool toggle);
+ void toggleSpatialNavigation(bool b);
+ void toggleFullScreenMode(bool enable);
+ void toggleFrameFlattening(bool toggle);
+ void toggleInterruptingJavaScriptEnabled(bool enable);
+ void toggleJavascriptCanOpenWindows(bool enable);
+
+#if defined(QT_CONFIGURED_WITH_OPENGL)
+ void toggleQGLWidgetViewport(bool enable);
+#endif
+
+ void changeViewportUpdateMode(int mode);
+ void animatedFlip();
+ void animatedYFlip();
+ void selectElements();
+ void showFPS(bool enable);
+ void showUserAgentDialog();
+
+public slots:
+ LauncherWindow* newWindow();
+ LauncherWindow* cloneWindow();
+ void updateFPS(int fps);
+
+signals:
+ void enteredFullScreenMode(bool on);
+
+private:
+ void init();
+ void initializeView();
+ void createChrome();
+ void applyPrefs();
+ void applyZoom();
+
+ bool isGraphicsBased() const;
+
+private:
+ static QVector<int> m_zoomLevels;
+ int m_currentZoom;
+
+ QWidget* m_view;
+ WebInspector* m_inspector;
+
+ WindowOptions m_windowOptions;
+
+ QAction* m_formatMenuAction;
+
+ QPropertyAnimation* m_zoomAnimation;
+ QList<QTouchEvent::TouchPoint> m_touchPoints;
+ bool m_touchMocking;
+};
+
+#endif
diff --git a/Tools/QtTestBrowser/locationedit.cpp b/Tools/QtTestBrowser/locationedit.cpp
new file mode 100644
index 0000000..a97f148
--- /dev/null
+++ b/Tools/QtTestBrowser/locationedit.cpp
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 "locationedit.h"
+
+LocationEdit::LocationEdit(QWidget* parent)
+ : QLineEdit(parent)
+ , m_progress(0)
+{
+ m_clearTimer.setSingleShot(true);
+ connect(&m_clearTimer, SIGNAL(timeout()), this, SLOT(reset()));
+}
+
+void LocationEdit::setProgress(int progress)
+{
+ m_clearTimer.stop();
+ m_progress = progress;
+ update();
+}
+
+void LocationEdit::reset()
+{
+ setProgress(0);
+}
+
+void LocationEdit::paintEvent(QPaintEvent* ev)
+{
+ QColor backgroundColor = QApplication::palette().color(QPalette::Base);
+ QColor progressColor = QColor(120, 180, 240);
+ QPalette p = palette();
+
+ if (!m_progress)
+ p.setBrush(QPalette::Base, backgroundColor);
+ else {
+ QLinearGradient gradient(0, 0, width(), 0);
+ gradient.setColorAt(0, progressColor);
+ gradient.setColorAt(((double) m_progress) / 100, progressColor);
+ if (m_progress != 100)
+ gradient.setColorAt((double) m_progress / 100 + 0.001, backgroundColor);
+ p.setBrush(QPalette::Base, gradient);
+ }
+ setPalette(p);
+
+ QLineEdit::paintEvent(ev);
+
+ if (m_progress == 100)
+ m_clearTimer.start(100);
+}
+
+void LocationEdit::focusInEvent(QFocusEvent* ev)
+{
+ QLineEdit::focusInEvent(ev);
+#ifdef Q_WS_MAEMO_5
+ QTimer::singleShot(0, this, SLOT(selectAll()));
+#endif
+}
diff --git a/Tools/QtTestBrowser/locationedit.h b/Tools/QtTestBrowser/locationedit.h
new file mode 100644
index 0000000..e82920c
--- /dev/null
+++ b/Tools/QtTestBrowser/locationedit.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 locationedit_h
+#define locationedit_h
+
+#include <QtGui>
+
+class LocationEdit : public QLineEdit {
+ Q_OBJECT
+
+public:
+ LocationEdit(QWidget* parent = 0);
+
+public slots:
+ void setProgress(int progress);
+
+private slots:
+ void reset();
+
+protected:
+ virtual void paintEvent(QPaintEvent*);
+ virtual void focusInEvent(QFocusEvent*);
+
+private:
+ int m_progress;
+ QTimer m_clearTimer;
+};
+
+#endif
diff --git a/Tools/QtTestBrowser/main.cpp b/Tools/QtTestBrowser/main.cpp
new file mode 100644
index 0000000..41471fa
--- /dev/null
+++ b/Tools/QtTestBrowser/main.cpp
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.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:
+ * 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 "launcherwindow.h"
+#include "urlloader.h"
+
+WindowOptions windowOptions;
+
+int launcherMain(const QApplication& app)
+{
+#ifndef NDEBUG
+ int retVal = app.exec();
+ DumpRenderTreeSupportQt::garbageCollectorCollect();
+ QWebSettings::clearMemoryCaches();
+ return retVal;
+#else
+ return app.exec();
+#endif
+}
+
+class LauncherApplication : public QApplication {
+ Q_OBJECT
+
+public:
+ LauncherApplication(int& argc, char** argv);
+ QStringList urls() const { return m_urls; }
+ bool isRobotized() const { return m_isRobotized; }
+ int robotTimeout() const { return m_robotTimeoutSeconds; }
+ int robotExtraTime() const { return m_robotExtraTimeSeconds; }
+
+private:
+ void handleUserOptions();
+ void applyDefaultSettings();
+
+private:
+ bool m_isRobotized;
+ int m_robotTimeoutSeconds;
+ int m_robotExtraTimeSeconds;
+ QStringList m_urls;
+};
+
+void LauncherApplication::applyDefaultSettings()
+{
+ QWebSettings::setMaximumPagesInCache(4);
+
+ QWebSettings::setObjectCacheCapacities((16*1024*1024) / 8, (16*1024*1024) / 8, 16*1024*1024);
+
+ QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true);
+ QWebSettings::globalSettings()->setAttribute(QWebSettings::DeveloperExtrasEnabled, true);
+ QWebSettings::enablePersistentStorage();
+}
+
+LauncherApplication::LauncherApplication(int& argc, char** argv)
+ : QApplication(argc, argv, QApplication::GuiServer)
+ , m_isRobotized(false)
+ , m_robotTimeoutSeconds(0)
+ , m_robotExtraTimeSeconds(0)
+{
+ // To allow QWebInspector's configuration persistence
+ setOrganizationName("Nokia");
+ setApplicationName("QtTestBrowser");
+ setApplicationVersion("0.1");
+
+ applyDefaultSettings();
+
+ handleUserOptions();
+}
+
+static void requiresGraphicsView(const QString& option)
+{
+ if (windowOptions.useGraphicsView)
+ return;
+ appQuit(1, QString("%1 only works in combination with the -graphicsbased option").arg(option));
+}
+
+void LauncherApplication::handleUserOptions()
+{
+ QStringList args = arguments();
+ QFileInfo program(args.at(0));
+ QString programName("QtTestBrowser");
+ if (program.exists())
+ programName = program.baseName();
+
+ QList<QString> updateModes(enumToKeys(QGraphicsView::staticMetaObject,
+ "ViewportUpdateMode", "ViewportUpdate"));
+
+ if (args.contains("-help")) {
+ qDebug() << "Usage:" << programName.toLatin1().data()
+ << "[-graphicsbased]"
+ << "[-no-compositing]"
+ << QString("[-viewport-update-mode %1]").arg(formatKeys(updateModes)).toLatin1().data()
+ << "[-cache-webview]"
+ << "[-show-fps]"
+ << "[-r list]"
+ << "[-robot-timeout seconds]"
+ << "[-robot-extra-time seconds]"
+ << "[-inspector-url location]"
+ << "[-tiled-backing-store]"
+ << "[-resizes-to-contents]"
+ << "URLs";
+ appQuit(0);
+ }
+
+ const bool defaultForAnimations = args.contains("-default-animations");
+ if (args.contains("-graphicsbased") || defaultForAnimations)
+ windowOptions.useGraphicsView = true;
+
+ if (args.contains("-no-compositing")) {
+ requiresGraphicsView("-no-compositing");
+ windowOptions.useCompositing = false;
+ }
+
+ if (args.contains("-show-fps")) {
+ requiresGraphicsView("-show-fps");
+ windowOptions.showFrameRate = true;
+ }
+
+ if (args.contains("-cache-webview") || defaultForAnimations) {
+ requiresGraphicsView("-cache-webview");
+ windowOptions.cacheWebView = true;
+ }
+
+ if (args.contains("-tiled-backing-store")) {
+ requiresGraphicsView("-tiled-backing-store");
+ windowOptions.useTiledBackingStore = true;
+ }
+
+ if (args.contains("-resizes-to-contents")) {
+ requiresGraphicsView("-resizes-to-contents");
+ windowOptions.resizesToContents = true;
+ }
+
+ if (defaultForAnimations)
+ windowOptions.viewportUpdateMode = QGraphicsView::BoundingRectViewportUpdate;
+
+ QString arg1("-viewport-update-mode");
+ int modeIndex = args.indexOf(arg1);
+ if (modeIndex != -1) {
+ requiresGraphicsView(arg1);
+
+ QString mode = takeOptionValue(&args, modeIndex);
+ if (mode.isEmpty())
+ appQuit(1, QString("%1 needs a value of one of [%2]").arg(arg1).arg(formatKeys(updateModes)));
+ int idx = updateModes.indexOf(mode);
+ if (idx == -1)
+ appQuit(1, QString("%1 value has to be one of [%2]").arg(arg1).arg(formatKeys(updateModes)));
+
+ windowOptions.viewportUpdateMode = static_cast<QGraphicsView::ViewportUpdateMode>(idx);
+ }
+#ifdef QT_CONFIGURED_WITH_OPENGL
+ if (args.contains("-gl-viewport") || defaultForAnimations) {
+ requiresGraphicsView("-gl-viewport");
+ windowOptions.useQGLWidgetViewport = true;
+ }
+#endif
+
+ QString inspectorUrlArg("-inspector-url");
+ int inspectorUrlIndex = args.indexOf(inspectorUrlArg);
+ if (inspectorUrlIndex != -1)
+ windowOptions.inspectorUrl = takeOptionValue(&args, inspectorUrlIndex);
+
+ QString remoteInspectorPortArg("-remote-inspector-port");
+ int remoteInspectorPortIndex = args.indexOf(remoteInspectorPortArg);
+ if (remoteInspectorPortIndex != -1)
+ windowOptions.remoteInspectorPort = takeOptionValue(&args, remoteInspectorPortIndex).toInt();
+
+ int robotIndex = args.indexOf("-r");
+ if (robotIndex != -1) {
+ QString listFile = takeOptionValue(&args, robotIndex);
+ if (listFile.isEmpty())
+ appQuit(1, "-r needs a list file to start in robotized mode");
+ if (!QFile::exists(listFile))
+ appQuit(1, "The list file supplied to -r does not exist.");
+
+ m_isRobotized = true;
+ m_urls = QStringList(listFile);
+ } else {
+ int lastArg = args.lastIndexOf(QRegExp("^-.*"));
+ m_urls = (lastArg != -1) ? args.mid(++lastArg) : args.mid(1);
+ }
+
+ int robotTimeoutIndex = args.indexOf("-robot-timeout");
+ if (robotTimeoutIndex != -1)
+ m_robotTimeoutSeconds = takeOptionValue(&args, robotTimeoutIndex).toInt();
+
+ int robotExtraTimeIndex = args.indexOf("-robot-extra-time");
+ if (robotExtraTimeIndex != -1)
+ m_robotExtraTimeSeconds = takeOptionValue(&args, robotExtraTimeIndex).toInt();
+}
+
+
+int main(int argc, char **argv)
+{
+ LauncherApplication app(argc, argv);
+
+ if (app.isRobotized()) {
+ LauncherWindow* window = new LauncherWindow();
+ UrlLoader loader(window->page()->mainFrame(), app.urls().at(0), app.robotTimeout(), app.robotExtraTime());
+ loader.loadNext();
+ window->show();
+ return launcherMain(app);
+ }
+
+ QStringList urls = app.urls();
+
+ if (urls.isEmpty()) {
+ QString defaultIndexFile = QString("%1/%2").arg(QDir::homePath()).arg(QLatin1String("index.html"));
+ if (QFile(defaultIndexFile).exists())
+ urls.append(QString("file://") + defaultIndexFile);
+ else
+ urls.append("");
+ }
+
+ LauncherWindow* window = 0;
+ foreach (QString url, urls) {
+ LauncherWindow* newWindow;
+ if (!window)
+ newWindow = window = new LauncherWindow(&windowOptions);
+ else
+ newWindow = window->newWindow();
+
+ newWindow->load(url);
+ }
+
+ window->show();
+ return launcherMain(app);
+}
+
+#include "main.moc"
diff --git a/Tools/QtTestBrowser/mainwindow.cpp b/Tools/QtTestBrowser/mainwindow.cpp
new file mode 100644
index 0000000..f361fa8
--- /dev/null
+++ b/Tools/QtTestBrowser/mainwindow.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.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:
+ * 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 "mainwindow.h"
+
+#include "locationedit.h"
+#include "utils.h"
+
+MainWindow::MainWindow()
+ : m_page(new WebPage(this))
+ , m_toolBar(0)
+ , urlEdit(0)
+{
+ setAttribute(Qt::WA_DeleteOnClose);
+ if (qgetenv("QTTESTBROWSER_USE_ARGB_VISUALS").toInt() == 1)
+ setAttribute(Qt::WA_TranslucentBackground);
+
+ buildUI();
+}
+
+void MainWindow::buildUI()
+{
+#if defined(Q_OS_SYMBIAN)
+ delete urlEdit;
+#endif
+ delete m_toolBar;
+
+ m_toolBar = addToolBar("Navigation");
+#if defined(Q_OS_SYMBIAN)
+ m_toolBar->setIconSize(QSize(16, 16));
+#endif
+ QAction* reloadAction = page()->action(QWebPage::Reload);
+ connect(reloadAction, SIGNAL(triggered()), this, SLOT(changeLocation()));
+
+ m_toolBar->addAction(page()->action(QWebPage::Back));
+ m_toolBar->addAction(page()->action(QWebPage::Forward));
+ m_toolBar->addAction(reloadAction);
+ m_toolBar->addAction(page()->action(QWebPage::Stop));
+
+ urlEdit = new LocationEdit(m_toolBar);
+ urlEdit->setSizePolicy(QSizePolicy::Expanding, urlEdit->sizePolicy().verticalPolicy());
+ connect(urlEdit, SIGNAL(returnPressed()), SLOT(changeLocation()));
+ QCompleter* completer = new QCompleter(m_toolBar);
+ urlEdit->setCompleter(completer);
+ completer->setModel(&urlModel);
+#if defined(Q_OS_SYMBIAN)
+ addToolBarBreak();
+ addToolBar("Location")->addWidget(urlEdit);
+#else
+ m_toolBar->addWidget(urlEdit);
+#endif
+
+ connect(page()->mainFrame(), SIGNAL(titleChanged(const QString&)),
+ this, SLOT(setWindowTitle(const QString&)));
+ connect(page()->mainFrame(), SIGNAL(urlChanged(QUrl)), this, SLOT(setAddressUrl(QUrl)));
+ connect(page(), SIGNAL(loadProgress(int)), urlEdit, SLOT(setProgress(int)));
+ connect(page(), SIGNAL(windowCloseRequested()), this, SLOT(close()));
+
+ // short-cuts
+ page()->action(QWebPage::Back)->setShortcut(QKeySequence::Back);
+ page()->action(QWebPage::Stop)->setShortcut(Qt::Key_Escape);
+ page()->action(QWebPage::Forward)->setShortcut(QKeySequence::Forward);
+ page()->action(QWebPage::Reload)->setShortcut(QKeySequence::Refresh);
+ page()->action(QWebPage::Undo)->setShortcut(QKeySequence::Undo);
+ page()->action(QWebPage::Redo)->setShortcut(QKeySequence::Redo);
+ page()->action(QWebPage::Cut)->setShortcut(QKeySequence::Cut);
+ page()->action(QWebPage::Copy)->setShortcut(QKeySequence::Copy);
+ page()->action(QWebPage::Paste)->setShortcut(QKeySequence::Paste);
+
+ page()->action(QWebPage::ToggleBold)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_B));
+ page()->action(QWebPage::ToggleItalic)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_I));
+ page()->action(QWebPage::ToggleUnderline)->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_U));
+}
+
+void MainWindow::setPage(WebPage* page)
+{
+ if (page && m_page)
+ page->setUserAgent(m_page->userAgentForUrl(QUrl()));
+
+ delete m_page;
+ m_page = page;
+
+ buildUI();
+}
+
+WebPage* MainWindow::page() const
+{
+ return m_page;
+}
+
+void MainWindow::setAddressUrl(const QUrl& url)
+{
+ setAddressUrl(url.toString(QUrl::RemoveUserInfo));
+}
+
+void MainWindow::setAddressUrl(const QString& url)
+{
+ if (!url.contains("about:"))
+ urlEdit->setText(url);
+}
+
+void MainWindow::addCompleterEntry(const QUrl& url)
+{
+ QUrl::FormattingOptions opts;
+ opts |= QUrl::RemoveScheme;
+ opts |= QUrl::RemoveUserInfo;
+ opts |= QUrl::StripTrailingSlash;
+ QString s = url.toString(opts);
+ s = s.mid(2);
+ if (s.isEmpty())
+ return;
+
+ if (!urlList.contains(s))
+ urlList += s;
+ urlModel.setStringList(urlList);
+}
+
+void MainWindow::load(const QString& url)
+{
+ QUrl qurl = urlFromUserInput(url);
+ if (qurl.scheme().isEmpty())
+ qurl = QUrl("http://" + url + "/");
+ load(qurl);
+}
+
+void MainWindow::load(const QUrl& url)
+{
+ if (!url.isValid())
+ return;
+
+ setAddressUrl(url.toString());
+ page()->mainFrame()->load(url);
+}
+
+void MainWindow::changeLocation()
+{
+ QString string = urlEdit->text();
+ QUrl mainFrameURL = page()->mainFrame()->url();
+
+ if (mainFrameURL.isValid() && string == mainFrameURL.toString()) {
+ page()->triggerAction(QWebPage::Reload);
+ return;
+ }
+
+ load(string);
+}
+
+void MainWindow::openFile()
+{
+ static const QString filter("HTML Files (*.htm *.html);;Text Files (*.txt);;Image Files (*.gif *.jpg *.png);;All Files (*)");
+
+ QFileDialog fileDialog(this, tr("Open"), QString(), filter);
+ fileDialog.setAcceptMode(QFileDialog::AcceptOpen);
+ fileDialog.setFileMode(QFileDialog::ExistingFile);
+ fileDialog.setOptions(QFileDialog::ReadOnly);
+
+ if (fileDialog.exec()) {
+ QString selectedFile = fileDialog.selectedFiles()[0];
+ if (!selectedFile.isEmpty())
+ load(QUrl::fromLocalFile(selectedFile));
+ }
+}
+
+void MainWindow::openLocation()
+{
+ urlEdit->selectAll();
+ urlEdit->setFocus();
+}
diff --git a/Tools/QtTestBrowser/mainwindow.h b/Tools/QtTestBrowser/mainwindow.h
new file mode 100644
index 0000000..3a39d57
--- /dev/null
+++ b/Tools/QtTestBrowser/mainwindow.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.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:
+ * 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 mainwindow_h
+#define mainwindow_h
+
+#include <QtGui>
+#include "webpage.h"
+
+class LocationEdit;
+
+class MainWindow : public QMainWindow {
+ Q_OBJECT
+
+public:
+ MainWindow();
+
+ void addCompleterEntry(const QUrl& url);
+
+ void load(const QString& url);
+ void load(const QUrl& url);
+
+ WebPage* page() const;
+ void setPage(WebPage*);
+
+protected slots:
+ void setAddressUrl(const QString& url);
+ void setAddressUrl(const QUrl& url);
+ void openFile();
+ void openLocation();
+ void changeLocation();
+
+private:
+ void buildUI();
+
+ WebPage* m_page;
+ QToolBar* m_toolBar;
+ QStringListModel urlModel;
+ QStringList urlList;
+ LocationEdit* urlEdit;
+};
+
+#endif
diff --git a/Tools/QtTestBrowser/urlloader.cpp b/Tools/QtTestBrowser/urlloader.cpp
new file mode 100644
index 0000000..2ae722b
--- /dev/null
+++ b/Tools/QtTestBrowser/urlloader.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 University of Szeged
+ *
+ * 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 "urlloader.h"
+
+#include <QFile>
+#include <QDebug>
+#include <QWebPage>
+
+UrlLoader::UrlLoader(QWebFrame* frame, const QString& inputFileName, int timeoutSeconds, int extraTimeSeconds)
+ : m_frame(frame)
+ , m_stdOut(stdout)
+ , m_loaded(0)
+ , m_numFramesLoading(0)
+{
+ m_checkIfFinishedTimer.setInterval(200);
+ m_checkIfFinishedTimer.setSingleShot(true);
+ connect(&m_checkIfFinishedTimer, SIGNAL(timeout()), this, SLOT(checkIfFinished()));
+ // loadStarted and loadFinished on QWebPage is emitted for each frame/sub-frame
+ connect(m_frame->page(), SIGNAL(loadStarted()), this, SLOT(frameLoadStarted()));
+ connect(m_frame->page(), SIGNAL(loadFinished(bool)), this, SLOT(frameLoadFinished()));
+
+ if (timeoutSeconds) {
+ m_timeoutTimer.setInterval(timeoutSeconds * 1000);
+ m_timeoutTimer.setSingleShot(true);
+ connect(frame, SIGNAL(loadStarted()), &m_timeoutTimer, SLOT(start()));
+ connect(&m_timeoutTimer, SIGNAL(timeout()), this, SLOT(loadNext()));
+ }
+ if (extraTimeSeconds) {
+ m_extraTimeTimer.setInterval(extraTimeSeconds * 1000);
+ m_extraTimeTimer.setSingleShot(true);
+ connect(this, SIGNAL(pageLoadFinished()), &m_extraTimeTimer, SLOT(start()));
+ connect(&m_extraTimeTimer, SIGNAL(timeout()), this, SLOT(loadNext()));
+ } else
+ connect(this, SIGNAL(pageLoadFinished()), this, SLOT(loadNext()));
+ loadUrlList(inputFileName);
+}
+
+void UrlLoader::loadNext()
+{
+ m_timeoutTimer.stop();
+ m_extraTimeTimer.stop();
+ m_checkIfFinishedTimer.stop();
+ m_numFramesLoading = 0;
+ QString qstr;
+ if (getUrl(qstr)) {
+ QUrl url(qstr, QUrl::StrictMode);
+ if (url.isValid()) {
+ m_stdOut << "Loading " << qstr << " ......" << ++m_loaded << endl;
+ m_frame->load(url);
+ } else
+ loadNext();
+ } else
+ disconnect(m_frame, 0, this, 0);
+}
+
+void UrlLoader::checkIfFinished()
+{
+ if (!m_numFramesLoading)
+ emit pageLoadFinished();
+}
+
+void UrlLoader::frameLoadStarted()
+{
+ ++m_numFramesLoading;
+ m_checkIfFinishedTimer.stop();
+}
+
+void UrlLoader::frameLoadFinished()
+{
+ Q_ASSERT(m_numFramesLoading > 0);
+ --m_numFramesLoading;
+ // Once our frame has finished loading, wait a moment to call loadNext for cases
+ // where a sub-frame starts loading or another frame is loaded through JavaScript.
+ m_checkIfFinishedTimer.start();
+}
+
+void UrlLoader::loadUrlList(const QString& inputFileName)
+{
+ QFile inputFile(inputFileName);
+ if (inputFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
+ QTextStream stream(&inputFile);
+ QString line;
+ while (true) {
+ line = stream.readLine();
+ if (line.isNull())
+ break;
+ m_urls.append(line);
+ }
+ } else {
+ qDebug() << "Can't open list file";
+ exit(0);
+ }
+ m_index = 0;
+ inputFile.close();
+}
+
+bool UrlLoader::getUrl(QString& qstr)
+{
+ if (m_index == m_urls.size())
+ return false;
+
+ qstr = m_urls[m_index++];
+ return true;
+}
diff --git a/Tools/QtTestBrowser/urlloader.h b/Tools/QtTestBrowser/urlloader.h
new file mode 100644
index 0000000..8ce24c0
--- /dev/null
+++ b/Tools/QtTestBrowser/urlloader.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 University of Szeged
+ *
+ * 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 urlloader_h
+#define urlloader_h
+
+#include "qwebframe.h"
+
+#include <QTextStream>
+#include <QTimer>
+#include <QVector>
+
+class UrlLoader : public QObject {
+ Q_OBJECT
+
+public:
+ UrlLoader(QWebFrame* frame, const QString& inputFileName, int timeoutSeconds, int extraTimeSeconds);
+
+public slots:
+ void loadNext();
+
+private slots:
+ void checkIfFinished();
+ void frameLoadStarted();
+ void frameLoadFinished();
+
+signals:
+ void pageLoadFinished();
+
+private:
+ void loadUrlList(const QString& inputFileName);
+ bool getUrl(QString& qstr);
+
+private:
+ QVector<QString> m_urls;
+ int m_index;
+ QWebFrame* m_frame;
+ QTextStream m_stdOut;
+ int m_loaded;
+ QTimer m_timeoutTimer;
+ QTimer m_extraTimeTimer;
+ QTimer m_checkIfFinishedTimer;
+ int m_numFramesLoading;
+};
+
+#endif
diff --git a/Tools/QtTestBrowser/useragentlist.txt b/Tools/QtTestBrowser/useragentlist.txt
new file mode 100644
index 0000000..1c424d9
--- /dev/null
+++ b/Tools/QtTestBrowser/useragentlist.txt
@@ -0,0 +1,10 @@
+Mozilla/5.0 (X11; U; Linux; en-US) AppleWebKit/533.3 (KHTML, like Gecko) QtTestBrowser/0.1 Safari/533.3
+Mozilla/5.0 (SymbianOS/9.4; U; Series60/5.0; en-GB) AppleWebKit/533.3 (KHTML, like Gecko) QtTestBrowser/0.1 Mobile Safari/533.3
+Mozilla/5.0 (Macintosh; U; PPC Mac OS X; en) AppleWebKit/125.2 (KHTML, like Gecko) Safari/125.8
+Mozilla/5.0 (Linux; U; Android 1.1; en-gb; dream) AppleWebKit/525.10+ (KHTML, like Gecko) Version/3.0.4 Mobile Safari/523.12.2
+Mozilla/5.0 (iPhone; U; CPU OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B334b Safari/531.21.10
+Mozilla/5.0 (iPhone; U; CPU iPhone OS 4_0 like Mac OS X; en-us) AppleWebKit/532.9 (KHTML, like Gecko) Version/4.0.5 Mobile/8A293 Safari/6531.22.7
+Mozilla/5.0(iPad; U; CPU iPhone OS 3_2 like Mac OS X; en-us) AppleWebKit/531.21.10 (KHTML, like Gecko) Version/4.0.4 Mobile/7B314 Safari/531.21.10
+Opera/9.25 (Windows NT 6.0; U; en)
+Mozilla/5.0 (SymbianOS/9.4; U; Series60/5.0 Nokia5800d-1b/20.2.014; Profile/MIDP-2.1 Configuration/CLDC-1.1 ) AppleWebKit/413 (KHTML, like Gecko) Safari/413
+Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 6.2; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0)
diff --git a/Tools/QtTestBrowser/utils.cpp b/Tools/QtTestBrowser/utils.cpp
new file mode 100644
index 0000000..567c989
--- /dev/null
+++ b/Tools/QtTestBrowser/utils.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 "utils.h"
+
+
+QString takeOptionValue(QStringList* arguments, int index)
+{
+ QString result;
+
+ if (++index < arguments->count() && !arguments->at(index).startsWith("-"))
+ result = arguments->takeAt(index);
+
+ return result;
+}
+
+QString formatKeys(QList<QString> keys)
+{
+ QString result;
+ for (int i = 0; i < keys.count() - 1; i++)
+ result.append(keys.at(i) + "|");
+ result.append(keys.last());
+ return result;
+}
+
+QList<QString> enumToKeys(const QMetaObject o, const QString& name, const QString& strip)
+{
+ QList<QString> list;
+
+ int enumIndex = o.indexOfEnumerator(name.toLatin1().data());
+ QMetaEnum enumerator = o.enumerator(enumIndex);
+
+ if (enumerator.isValid()) {
+ for (int i = 0; i < enumerator.keyCount(); i++) {
+ QString key(enumerator.valueToKey(i));
+ list.append(key.remove(strip));
+ }
+ }
+
+ return list;
+}
+
+void appQuit(int exitCode, const QString& msg)
+{
+ if (!msg.isEmpty()) {
+ if (exitCode > 0)
+ qDebug("ERROR: %s", msg.toLatin1().data());
+ else
+ qDebug() << msg;
+ }
+ exit(exitCode);
+}
+
+QUrl urlFromUserInput(const QString& string)
+{
+ QString input(string);
+ QFileInfo fi(input);
+ if (fi.exists() && fi.isRelative())
+ input = fi.absoluteFilePath();
+
+ return QUrl::fromUserInput(input);
+}
+
+
diff --git a/Tools/QtTestBrowser/utils.h b/Tools/QtTestBrowser/utils.h
new file mode 100644
index 0000000..b67351e
--- /dev/null
+++ b/Tools/QtTestBrowser/utils.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 utils_h
+#define utils_h
+
+#include <QtCore>
+
+#ifndef NO_RETURN
+#if defined(__CC_ARM) || defined(__ARMCC__)
+#define NO_RETURN __declspec(noreturn)
+#elif defined(__GNUC__)
+#define NO_RETURN __attribute((__noreturn__))
+#else
+#define NO_RETURN
+#endif
+#endif
+
+// options handling
+QString takeOptionValue(QStringList* arguments, int index);
+QString formatKeys(QList<QString> keys);
+QList<QString> enumToKeys(const QMetaObject o, const QString& name, const QString& strip);
+
+NO_RETURN void appQuit(int status, const QString& msg = QString());
+
+QUrl urlFromUserInput(const QString& input);
+
+#endif
diff --git a/Tools/QtTestBrowser/webinspector.h b/Tools/QtTestBrowser/webinspector.h
new file mode 100644
index 0000000..5cc7f8a
--- /dev/null
+++ b/Tools/QtTestBrowser/webinspector.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies)
+ *
+ * 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 webinspector_h
+#define webinspector_h
+
+#include <QtGui>
+#include "qwebinspector.h"
+
+class WebInspector : public QWebInspector {
+ Q_OBJECT
+
+public:
+ WebInspector(QWidget* parent = 0) : QWebInspector(parent) {}
+
+signals:
+ void visibleChanged(bool nowVisible);
+
+protected:
+ void showEvent(QShowEvent* event)
+ {
+ QWebInspector::showEvent(event);
+ emit visibleChanged(true);
+ }
+ void hideEvent(QHideEvent* event)
+ {
+ QWebInspector::hideEvent(event);
+ emit visibleChanged(false);
+ }
+};
+
+#endif
diff --git a/Tools/QtTestBrowser/webpage.cpp b/Tools/QtTestBrowser/webpage.cpp
new file mode 100644
index 0000000..15f6db0
--- /dev/null
+++ b/Tools/QtTestBrowser/webpage.cpp
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 2009-2010 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.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:
+ * 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 "webpage.h"
+
+#include "launcherwindow.h"
+
+#include <QAuthenticator>
+#include <QDesktopServices>
+#include <QtGui>
+#include <QtNetwork/QNetworkReply>
+#include <QtNetwork/QNetworkRequest>
+#include <QtNetwork/QNetworkProxy>
+
+WebPage::WebPage(QObject* parent)
+ : QWebPage(parent)
+ , m_userAgent()
+ , m_interruptingJavaScriptEnabled(false)
+{
+ applyProxy();
+
+ connect(this, SIGNAL(featurePermissionRequested(QWebFrame*, QWebPage::Feature)), this, SLOT(requestPermission(QWebFrame*, QWebPage::Feature)));
+ connect(this, SIGNAL(featurePermissionRequestCanceled(QWebFrame*, QWebPage::Feature)), this, SLOT(featurePermissionRequestCanceled(QWebFrame*, QWebPage::Feature)));
+}
+
+void WebPage::applyProxy()
+{
+ QUrl proxyUrl(qgetenv("http_proxy"));
+
+ if (proxyUrl.isValid() && !proxyUrl.host().isEmpty()) {
+ int proxyPort = (proxyUrl.port() > 0) ? proxyUrl.port() : 8080;
+ networkAccessManager()->setProxy(QNetworkProxy(QNetworkProxy::HttpProxy, proxyUrl.host(), proxyPort));
+ }
+}
+
+bool WebPage::supportsExtension(QWebPage::Extension extension) const
+{
+ if (extension == QWebPage::ErrorPageExtension)
+ return true;
+ return false;
+}
+
+bool WebPage::extension(Extension extension, const ExtensionOption* option, ExtensionReturn* output)
+{
+ const QWebPage::ErrorPageExtensionOption* info = static_cast<const QWebPage::ErrorPageExtensionOption*>(option);
+ QWebPage::ErrorPageExtensionReturn* errorPage = static_cast<QWebPage::ErrorPageExtensionReturn*>(output);
+
+ errorPage->content = QString("<html><head><title>Failed loading page</title></head><body>%1</body></html>")
+ .arg(info->errorString).toUtf8();
+
+ return true;
+}
+
+bool WebPage::acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type)
+{
+ QObject* view = parent();
+
+ QVariant value = view->property("keyboardModifiers");
+
+ if (!value.isNull()) {
+ Qt::KeyboardModifiers modifiers = Qt::KeyboardModifiers(value.toInt());
+
+ if (modifiers & Qt::ShiftModifier) {
+ QWebPage* page = createWindow(QWebPage::WebBrowserWindow);
+ page->mainFrame()->load(request);
+ return false;
+ }
+
+ if (modifiers & Qt::AltModifier) {
+ openUrlInDefaultBrowser(request.url());
+ return false;
+ }
+ }
+
+ return QWebPage::acceptNavigationRequest(frame, request, type);
+}
+
+void WebPage::openUrlInDefaultBrowser(const QUrl& url)
+{
+ if (QAction* action = qobject_cast<QAction*>(sender()))
+ QDesktopServices::openUrl(action->data().toUrl());
+ else
+ QDesktopServices::openUrl(url);
+}
+
+QString WebPage::userAgentForUrl(const QUrl& url) const
+{
+ if (!m_userAgent.isEmpty())
+ return m_userAgent;
+ return QWebPage::userAgentForUrl(url);
+}
+
+void WebPage::setQnamThreaded(bool threaded)
+{
+ bool alreadyThreaded = networkAccessManager()->thread() != thread();
+ if (threaded == alreadyThreaded)
+ return;
+
+ if (threaded) {
+ m_qnamThread.reset(new QtNAMThread);
+ m_qnamThread->start();
+ setNetworkAccessManager(m_qnamThread->networkAccessManager());
+ } else {
+ setNetworkAccessManager(0);
+ m_qnamThread.reset();
+ }
+
+ Qt::ConnectionType connectionType = threaded ? Qt::BlockingQueuedConnection : Qt::DirectConnection;
+ connect(networkAccessManager(), SIGNAL(authenticationRequired(QNetworkReply*, QAuthenticator*)),
+ this, SLOT(authenticationRequired(QNetworkReply*, QAuthenticator*)),
+ connectionType);
+ applyProxy();
+}
+
+bool WebPage::shouldInterruptJavaScript()
+{
+ if (!m_interruptingJavaScriptEnabled)
+ return false;
+ return QWebPage::shouldInterruptJavaScript();
+}
+
+void WebPage::authenticationRequired(QNetworkReply* reply, QAuthenticator* authenticator)
+{
+ QDialog* dialog = new QDialog(QApplication::activeWindow());
+ dialog->setWindowTitle("HTTP Authentication");
+
+ QGridLayout* layout = new QGridLayout(dialog);
+ dialog->setLayout(layout);
+
+ QLabel* messageLabel = new QLabel(dialog);
+ messageLabel->setWordWrap(true);
+ QString messageStr = QString("Enter with username and password for: %1");
+ messageLabel->setText(messageStr.arg(reply->url().toString()));
+ layout->addWidget(messageLabel, 0, 1);
+
+ QLabel* userLabel = new QLabel("Username:", dialog);
+ layout->addWidget(userLabel, 1, 0);
+ QLineEdit* userInput = new QLineEdit(dialog);
+ layout->addWidget(userInput, 1, 1);
+
+ QLabel* passLabel = new QLabel("Password:", dialog);
+ layout->addWidget(passLabel, 2, 0);
+ QLineEdit* passInput = new QLineEdit(dialog);
+ passInput->setEchoMode(QLineEdit::Password);
+ layout->addWidget(passInput, 2, 1);
+
+ QDialogButtonBox* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok
+ | QDialogButtonBox::Cancel, Qt::Horizontal, dialog);
+ connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
+ layout->addWidget(buttonBox, 3, 1);
+
+ if (dialog->exec() == QDialog::Accepted) {
+ authenticator->setUser(userInput->text());
+ authenticator->setPassword(passInput->text());
+ }
+
+ delete dialog;
+}
+
+void WebPage::requestPermission(QWebFrame* frame, QWebPage::Feature feature)
+{
+ setFeaturePermission(frame, feature, PermissionGrantedByUser);
+}
+
+void WebPage::featurePermissionRequestCanceled(QWebFrame*, QWebPage::Feature)
+{
+}
+
+QWebPage* WebPage::createWindow(QWebPage::WebWindowType type)
+{
+ LauncherWindow* mw = new LauncherWindow;
+ if (type == WebModalDialog)
+ mw->setWindowModality(Qt::ApplicationModal);
+ mw->show();
+ return mw->page();
+}
+
+QObject* WebPage::createPlugin(const QString &classId, const QUrl&, const QStringList&, const QStringList&)
+{
+ if (classId == "alien_QLabel") {
+ QLabel* l = new QLabel;
+ l->winId();
+ return l;
+ }
+
+#ifndef QT_NO_UITOOLS
+ QUiLoader loader;
+ return loader.createWidget(classId, view());
+#else
+ Q_UNUSED(classId);
+ return 0;
+#endif
+}
+
diff --git a/Tools/QtTestBrowser/webpage.h b/Tools/QtTestBrowser/webpage.h
new file mode 100644
index 0000000..e62402b
--- /dev/null
+++ b/Tools/QtTestBrowser/webpage.h
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.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:
+ * 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 webpage_h
+#define webpage_h
+
+#include <QFuture>
+#include <QScopedPointer>
+#include <QThread>
+#include <qwebframe.h>
+#include <qwebpage.h>
+
+class QtNAMThread;
+
+class WebPage : public QWebPage {
+ Q_OBJECT
+
+public:
+ WebPage(QObject* parent = 0);
+
+ virtual QWebPage* createWindow(QWebPage::WebWindowType);
+ virtual QObject* createPlugin(const QString&, const QUrl&, const QStringList&, const QStringList&);
+ virtual bool supportsExtension(QWebPage::Extension extension) const;
+ virtual bool extension(Extension extension, const ExtensionOption* option, ExtensionReturn* output);
+
+ virtual bool acceptNavigationRequest(QWebFrame* frame, const QNetworkRequest& request, NavigationType type);
+
+ QString userAgentForUrl(const QUrl& url) const;
+ void setInterruptingJavaScriptEnabled(bool enabled) { m_interruptingJavaScriptEnabled = enabled; }
+ void setQnamThreaded(bool threaded);
+
+public slots:
+ void openUrlInDefaultBrowser(const QUrl& url = QUrl());
+ void setUserAgent(const QString& ua) { m_userAgent = ua; }
+ bool shouldInterruptJavaScript();
+ void authenticationRequired(QNetworkReply*, QAuthenticator*);
+ void requestPermission(QWebFrame* frame, QWebPage::Feature feature);
+ void featurePermissionRequestCanceled(QWebFrame* frame, QWebPage::Feature feature);
+
+private:
+ void applyProxy();
+ QString m_userAgent;
+ bool m_interruptingJavaScriptEnabled;
+ QScopedPointer<QtNAMThread> m_qnamThread;
+};
+
+
+class QtNAMThread : public QThread {
+public:
+ QtNAMThread()
+ {
+ m_qnamFuture.reportStarted();
+ }
+ ~QtNAMThread()
+ {
+ quit();
+ wait();
+ }
+
+ QFuture<QNetworkAccessManager*> networkAccessManager()
+ {
+ return m_qnamFuture.future();
+ }
+protected:
+ void run()
+ {
+ QNetworkAccessManager qnam;
+ m_qnamFuture.reportResult(&qnam);
+ m_qnamFuture.reportFinished();
+ exec();
+ }
+private:
+ QFutureInterface<QNetworkAccessManager*> m_qnamFuture;
+};
+
+#endif
diff --git a/Tools/QtTestBrowser/webview.cpp b/Tools/QtTestBrowser/webview.cpp
new file mode 100644
index 0000000..2a541fb
--- /dev/null
+++ b/Tools/QtTestBrowser/webview.cpp
@@ -0,0 +1,273 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.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:
+ * 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 "webview.h"
+
+#include <QtGui>
+#include <QGraphicsScene>
+
+WebViewGraphicsBased::WebViewGraphicsBased(QWidget* parent)
+ : QGraphicsView(parent)
+ , m_item(new GraphicsWebView)
+ , m_numPaintsTotal(0)
+ , m_numPaintsSinceLastMeasure(0)
+ , m_measureFps(false)
+ , m_resizesToContents(false)
+ , m_machine(0)
+{
+ setScene(new QGraphicsScene(this));
+ scene()->addItem(m_item);
+ scene()->setFocusItem(m_item);
+
+ setFrameShape(QFrame::NoFrame);
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+
+ m_updateTimer = new QTimer(this);
+ m_updateTimer->setInterval(1000);
+ connect(m_updateTimer, SIGNAL(timeout()), this, SLOT(updateFrameRate()));
+}
+
+void WebViewGraphicsBased::setPage(QWebPage* page)
+{
+ connect(page->mainFrame(), SIGNAL(contentsSizeChanged(const QSize&)), SLOT(contentsSizeChanged(const QSize&)));
+ connect(page, SIGNAL(scrollRequested(int, int, const QRect&)), SLOT(scrollRequested(int, int)));
+ graphicsWebView()->setPage(page);
+}
+
+void WebViewGraphicsBased::scrollRequested(int x, int y)
+{
+ if (!m_resizesToContents)
+ return;
+
+ // Turn off interactive mode while scrolling, or QGraphicsView will replay the
+ // last mouse event which may cause WebKit to initiate a drag operation.
+ bool interactive = isInteractive();
+ setInteractive(false);
+
+ verticalScrollBar()->setValue(-y);
+ horizontalScrollBar()->setValue(-x);
+
+ setInteractive(interactive);
+}
+
+void WebViewGraphicsBased::contentsSizeChanged(const QSize& size)
+{
+ if (m_resizesToContents)
+ scene()->setSceneRect(0, 0, size.width(), size.height());
+}
+
+void WebViewGraphicsBased::setResizesToContents(bool b)
+{
+ if (b == m_resizesToContents)
+ return;
+
+ m_resizesToContents = b;
+ graphicsWebView()->setResizesToContents(m_resizesToContents);
+
+ // When setting resizesToContents ON, our web view widget will always size as big as the
+ // web content being displayed, and so will the QWebPage's viewport. It implies that internally
+ // WebCore will work as if there was no content rendered offscreen, and then no scrollbars need
+ // drawing. In order to keep scrolling working, we:
+ //
+ // 1) Set QGraphicsView's scrollbars policy back to 'auto'.
+ // 2) Set scene's boundaries rect to an invalid size, which automatically makes it to be as big
+ // as it needs to enclose all items onto it. We do that because QGraphicsView also calculates
+ // the size of its scrollable area according to the amount of content in scene that is rendered
+ // offscreen.
+ // 3) Set QWebPage's preferredContentsSize according to the size of QGraphicsView's viewport,
+ // so WebCore properly lays pages out.
+ //
+ // On the other hand, when toggling resizesToContents OFF, we set back the default values, as
+ // opposite as described above.
+ if (m_resizesToContents) {
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
+ graphicsWebView()->page()->setPreferredContentsSize(size());
+ QRectF itemRect(graphicsWebView()->geometry().topLeft(), graphicsWebView()->page()->mainFrame()->contentsSize());
+ graphicsWebView()->setGeometry(itemRect);
+ scene()->setSceneRect(itemRect);
+ } else {
+ setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ graphicsWebView()->page()->setPreferredContentsSize(QSize());
+ QRect viewportRect(QPoint(0, 0), size());
+ graphicsWebView()->setGeometry(viewportRect);
+ scene()->setSceneRect(viewportRect);
+ }
+}
+
+void WebViewGraphicsBased::resizeEvent(QResizeEvent* event)
+{
+ QGraphicsView::resizeEvent(event);
+
+ QSize size(event->size());
+
+ if (m_resizesToContents) {
+ graphicsWebView()->page()->setPreferredContentsSize(size);
+ return;
+ }
+
+ QRectF rect(QPoint(0, 0), size);
+ graphicsWebView()->setGeometry(rect);
+ scene()->setSceneRect(rect);
+}
+
+void WebViewGraphicsBased::setFrameRateMeasurementEnabled(bool enabled)
+{
+ m_measureFps = enabled;
+ if (m_measureFps) {
+ m_lastConsultTime = m_startTime = QTime::currentTime();
+ m_fpsTimer.start();
+ m_updateTimer->start();
+ } else {
+ m_fpsTimer.stop();
+ m_updateTimer->stop();
+ }
+}
+
+void WebViewGraphicsBased::updateFrameRate()
+{
+ const QTime now = QTime::currentTime();
+ int interval = m_lastConsultTime.msecsTo(now);
+ int frames = m_fpsTimer.numFrames(interval);
+ int current = interval ? frames * 1000 / interval : 0;
+
+ emit currentFPSUpdated(current);
+
+ m_lastConsultTime = now;
+}
+
+void WebViewGraphicsBased::animatedFlip()
+{
+ QSizeF center = graphicsWebView()->boundingRect().size() / 2;
+ QPointF centerPoint = QPointF(center.width(), center.height());
+ graphicsWebView()->setTransformOriginPoint(centerPoint);
+
+ QPropertyAnimation* animation = new QPropertyAnimation(graphicsWebView(), "rotation", this);
+ animation->setDuration(1000);
+
+ int rotation = int(graphicsWebView()->rotation());
+
+ animation->setStartValue(rotation);
+ animation->setEndValue(rotation + 180 - (rotation % 180));
+
+ animation->start(QAbstractAnimation::DeleteWhenStopped);
+}
+
+void WebViewGraphicsBased::animatedYFlip()
+{
+ if (!m_machine) {
+ m_machine = new QStateMachine(this);
+
+ QState* s0 = new QState(m_machine);
+ s0->assignProperty(this, "yRotation", 0);
+
+ QState* s1 = new QState(m_machine);
+ s1->assignProperty(this, "yRotation", 90);
+
+ QAbstractTransition* t1 = s0->addTransition(s1);
+ QPropertyAnimation* yRotationAnim = new QPropertyAnimation(this, "yRotation", this);
+ t1->addAnimation(yRotationAnim);
+
+ QState* s2 = new QState(m_machine);
+ s2->assignProperty(this, "yRotation", -90);
+ s1->addTransition(s1, SIGNAL(propertiesAssigned()), s2);
+
+ QState* s3 = new QState(m_machine);
+ s3->assignProperty(this, "yRotation", 0);
+
+ QAbstractTransition* t2 = s2->addTransition(s3);
+ t2->addAnimation(yRotationAnim);
+
+ QFinalState* final = new QFinalState(m_machine);
+ s3->addTransition(s3, SIGNAL(propertiesAssigned()), final);
+
+ m_machine->setInitialState(s0);
+ yRotationAnim->setDuration(1000);
+ }
+
+ m_machine->start();
+}
+
+void WebViewGraphicsBased::paintEvent(QPaintEvent* event)
+{
+ QGraphicsView::paintEvent(event);
+ if (!m_measureFps)
+ return;
+}
+
+static QMenu* createContextMenu(QWebPage* page, QPoint position)
+{
+ QMenu* menu = page->createStandardContextMenu();
+
+ QWebHitTestResult r = page->mainFrame()->hitTestContent(position);
+
+ if (!r.linkUrl().isEmpty()) {
+ WebPage* webPage = qobject_cast<WebPage*>(page);
+ QAction* newTabAction = menu->addAction("Open in Default &Browser", webPage, SLOT(openUrlInDefaultBrowser()));
+ newTabAction->setData(r.linkUrl());
+ menu->insertAction(menu->actions().at(2), newTabAction);
+ }
+ return menu;
+}
+
+void GraphicsWebView::mousePressEvent(QGraphicsSceneMouseEvent* event)
+{
+ setProperty("mouseButtons", QVariant::fromValue(int(event->buttons())));
+ setProperty("keyboardModifiers", QVariant::fromValue(int(event->modifiers())));
+
+ QGraphicsWebView::mousePressEvent(event);
+}
+
+void WebViewTraditional::mousePressEvent(QMouseEvent* event)
+{
+ setProperty("mouseButtons", QVariant::fromValue(int(event->buttons())));
+ setProperty("keyboardModifiers", QVariant::fromValue(int(event->modifiers())));
+
+ QWebView::mousePressEvent(event);
+}
+
+void GraphicsWebView::contextMenuEvent(QGraphicsSceneContextMenuEvent* event)
+{
+ QMenu* menu = createContextMenu(page(), event->pos().toPoint());
+ menu->exec(event->screenPos());
+ delete menu;
+}
+
+void WebViewTraditional::contextMenuEvent(QContextMenuEvent* event)
+{
+ QMenu* menu = createContextMenu(page(), event->pos());
+ menu->exec(event->globalPos());
+ delete menu;
+}
+
diff --git a/Tools/QtTestBrowser/webview.h b/Tools/QtTestBrowser/webview.h
new file mode 100644
index 0000000..240ea89
--- /dev/null
+++ b/Tools/QtTestBrowser/webview.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies)
+ * Copyright (C) 2009 Girish Ramakrishnan <girish@forwardbias.in>
+ * Copyright (C) 2006 George Staikos <staikos@kde.org>
+ * Copyright (C) 2006 Dirk Mueller <mueller@kde.org>
+ * Copyright (C) 2006 Zack Rusin <zack@kde.org>
+ * Copyright (C) 2006 Simon Hausmann <hausmann@kde.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:
+ * 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 webview_h
+#define webview_h
+
+#include "fpstimer.h"
+#include "webpage.h"
+#include <qwebview.h>
+#include <qgraphicswebview.h>
+#include <QGraphicsView>
+#include <QGraphicsWidget>
+#include <QTime>
+
+class QStateMachine;
+
+class WebViewTraditional : public QWebView {
+ Q_OBJECT
+
+public:
+ WebViewTraditional(QWidget* parent) : QWebView(parent) {}
+
+protected:
+ virtual void contextMenuEvent(QContextMenuEvent*);
+ virtual void mousePressEvent(QMouseEvent*);
+};
+
+
+class GraphicsWebView : public QGraphicsWebView {
+ Q_OBJECT
+
+public:
+ GraphicsWebView(QGraphicsItem* parent = 0) : QGraphicsWebView(parent) {};
+
+protected:
+ virtual void contextMenuEvent(QGraphicsSceneContextMenuEvent*);
+ virtual void mousePressEvent(QGraphicsSceneMouseEvent*);
+};
+
+
+class WebViewGraphicsBased : public QGraphicsView {
+ Q_OBJECT
+ Q_PROPERTY(qreal yRotation READ yRotation WRITE setYRotation)
+
+public:
+ WebViewGraphicsBased(QWidget* parent);
+ void setPage(QWebPage* page);
+
+ void setItemCacheMode(QGraphicsItem::CacheMode mode) { graphicsWebView()->setCacheMode(mode); }
+ QGraphicsItem::CacheMode itemCacheMode() { return graphicsWebView()->cacheMode(); }
+
+ void setFrameRateMeasurementEnabled(bool enabled);
+ bool frameRateMeasurementEnabled() const { return m_measureFps; }
+
+ virtual void resizeEvent(QResizeEvent*);
+ virtual void paintEvent(QPaintEvent* event);
+
+ void setResizesToContents(bool b);
+ bool resizesToContents() const { return m_resizesToContents; }
+
+ void setYRotation(qreal angle);
+ qreal yRotation() const { return m_yRotation; }
+
+ GraphicsWebView* graphicsWebView() const { return m_item; }
+
+public slots:
+ void updateFrameRate();
+ void animatedFlip();
+ void animatedYFlip();
+ void contentsSizeChanged(const QSize&);
+ void scrollRequested(int, int);
+
+signals:
+ void currentFPSUpdated(int fps);
+
+private:
+ GraphicsWebView* m_item;
+ int m_numPaintsTotal;
+ int m_numPaintsSinceLastMeasure;
+ QTime m_startTime;
+ QTime m_lastConsultTime;
+ QTimer* m_updateTimer;
+ bool m_measureFps;
+ qreal m_yRotation;
+ bool m_resizesToContents;
+ QStateMachine* m_machine;
+ FpsTimer m_fpsTimer;
+};
+
+inline void WebViewGraphicsBased::setYRotation(qreal angle)
+{
+ QRectF r = graphicsWebView()->boundingRect();
+ graphicsWebView()->setTransform(QTransform()
+ .translate(r.width() / 2, r.height() / 2)
+ .rotate(angle, Qt::YAxis)
+ .translate(-r.width() / 2, -r.height() / 2));
+ m_yRotation = angle;
+}
+
+#endif
diff --git a/Tools/QueueStatusServer/__init__.py b/Tools/QueueStatusServer/__init__.py
new file mode 100644
index 0000000..2346c23
--- /dev/null
+++ b/Tools/QueueStatusServer/__init__.py
@@ -0,0 +1,29 @@
+# Required for Python to search this directory for module files
+
+# This __init__.py makes unit testing easier by allowing us to treat the entire server as one big module.
+# This file is only accessed when not on AppEngine itself.
+
+# Make sure that this module will load in that case by including paths to
+# the default Google AppEngine install.
+
+
+def fix_sys_path():
+ import sys
+ import os
+
+ # AppEngine imports a bunch of google-specific modules. Thankfully the dev_appserver
+ # knows how to do the same. Re-use the dev_appserver fix_sys_path logic to import
+ # all the google.appengine.* stuff so we can run under test-webkitpy
+ sys.path.append("/usr/local/google_appengine")
+ import dev_appserver
+ dev_appserver.fix_sys_path()
+
+ # test-webkitpy adds $WEBKIT/WebKitTools to the sys.path and imports
+ # QueueStatusServer to run all the tests. However, when AppEngine runs
+ # our code QueueStatusServer is the root (and thus in the path).
+ # Emulate that here for test-webkitpy so that we can import "model."
+ # not "QueueStatusServer.model.", etc.
+ sys.path.append(os.path.dirname(__file__))
+
+
+fix_sys_path()
diff --git a/Tools/QueueStatusServer/app.yaml b/Tools/QueueStatusServer/app.yaml
new file mode 100644
index 0000000..e320eb0
--- /dev/null
+++ b/Tools/QueueStatusServer/app.yaml
@@ -0,0 +1,15 @@
+application: webkit-commit-queue
+version: 1
+runtime: python
+api_version: 1
+
+builtins:
+- datastore_admin: on
+- remote_api: on
+
+handlers:
+- url: /stylesheets
+ static_dir: stylesheets
+
+- url: /.*
+ script: main.py
diff --git a/Tools/QueueStatusServer/cron.yaml b/Tools/QueueStatusServer/cron.yaml
new file mode 100644
index 0000000..09b9945
--- /dev/null
+++ b/Tools/QueueStatusServer/cron.yaml
@@ -0,0 +1,4 @@
+cron:
+- description: collect the garbage
+ url: /gc
+ schedule: every 4 hours
diff --git a/Tools/QueueStatusServer/filters/__init__.py b/Tools/QueueStatusServer/filters/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/QueueStatusServer/filters/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/QueueStatusServer/filters/webkit_extras.py b/Tools/QueueStatusServer/filters/webkit_extras.py
new file mode 100644
index 0000000..b645f78
--- /dev/null
+++ b/Tools/QueueStatusServer/filters/webkit_extras.py
@@ -0,0 +1,59 @@
+# 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 re
+
+from django.template.defaultfilters import stringfilter
+from google.appengine.ext import webapp
+
+register = webapp.template.create_template_register()
+
+bug_regexp = re.compile(r"bug (?P<bug_id>\d+)")
+patch_regexp = re.compile(r"patch (?P<patch_id>\d+)")
+
+@register.filter
+@stringfilter
+def webkit_linkify(value):
+ value = bug_regexp.sub(r'<a href="http://webkit.org/b/\g<bug_id>">bug \g<bug_id></a>', value)
+ value = patch_regexp.sub(r'<a href="https://bugs.webkit.org/attachment.cgi?id=\g<patch_id>&action=prettypatch">patch \g<patch_id></a>', value)
+ return value
+
+@register.filter
+@stringfilter
+def webkit_bug_id(value):
+ return '<a href="http://webkit.org/b/%s">%s</a>' % (value, value)
+
+@register.filter
+@stringfilter
+def webkit_attachment_id(value):
+ return '<a href="https://bugs.webkit.org/attachment.cgi?id=%s&action=prettypatch">%s</a>' % (value, value)
+
+@register.filter
+@stringfilter
+def results_link(status_id):
+ return '<a href="/results/%s">results</a>' % status_id
diff --git a/Tools/QueueStatusServer/handlers/__init__.py b/Tools/QueueStatusServer/handlers/__init__.py
new file mode 100644
index 0000000..296e173
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/__init__.py
@@ -0,0 +1,3 @@
+# Required for Python to search this directory for module files
+
+from handlers.updatebase import UpdateBase
diff --git a/Tools/QueueStatusServer/handlers/dashboard.py b/Tools/QueueStatusServer/handlers/dashboard.py
new file mode 100644
index 0000000..660c595
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/dashboard.py
@@ -0,0 +1,64 @@
+# 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 operator
+
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+from model.attachment import Attachment
+from model.queues import Queue
+
+
+class Dashboard(webapp.RequestHandler):
+ # We may want to sort these?
+ _ordered_queues = Queue.all()
+ _header_names = [queue.short_name() for queue in _ordered_queues]
+
+ def _build_bubble(self, attachment, queue):
+ queue_status = attachment.status_for_queue(queue)
+ bubble = {
+ "status_class": attachment.state_from_queue_status(queue_status) if queue_status else "none",
+ "status_date": queue_status.date if queue_status else None,
+ }
+ return bubble
+
+ def _build_row(self, attachment):
+ row = {
+ "bug_id": attachment.bug_id(),
+ "attachment_id": attachment.id,
+ "bubbles": [self._build_bubble(attachment, queue) for queue in self._ordered_queues],
+ }
+ return row
+
+ def get(self):
+ template_values = {
+ "headers": self._header_names,
+ "rows": [self._build_row(attachment) for attachment in Attachment.recent(limit=25)],
+ }
+ self.response.out.write(template.render("templates/dashboard.html", template_values))
diff --git a/Tools/QueueStatusServer/handlers/gc.py b/Tools/QueueStatusServer/handlers/gc.py
new file mode 100644
index 0000000..d04ee4d
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/gc.py
@@ -0,0 +1,44 @@
+# 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.
+
+from google.appengine.ext import webapp
+
+from model.queuestatus import QueueStatus
+
+
+class GC(webapp.RequestHandler):
+ def get(self):
+ statuses = QueueStatus.all().order("-date")
+ seen_queues = set()
+ for status in statuses:
+ if status.active_patch_id or status.active_bug_id:
+ continue
+ if status.queue_name in seen_queues:
+ status.delete()
+ seen_queues.add(status.queue_name)
+ self.response.out.write("Done!")
diff --git a/Tools/QueueStatusServer/handlers/nextpatch.py b/Tools/QueueStatusServer/handlers/nextpatch.py
new file mode 100644
index 0000000..5f6d71d
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/nextpatch.py
@@ -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:
+#
+# * 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.
+
+from datetime import datetime
+
+from google.appengine.ext import db
+from google.appengine.ext import webapp
+
+from model.queues import Queue
+
+
+class NextPatch(webapp.RequestHandler):
+ # FIXME: This should probably be a post, or an explict lock_patch
+ # since GET requests shouldn't really modify the datastore.
+ def get(self, queue_name):
+ queue = Queue.queue_with_name(queue_name)
+ if not queue:
+ self.error(404)
+ return
+ # FIXME: Patch assignment should probably move into Queue.
+ patch_id = db.run_in_transaction(self._assign_patch, queue.active_work_items().key(), queue.work_items().item_ids)
+ if not patch_id:
+ self.error(404)
+ return
+ self.response.out.write(patch_id)
+
+ @staticmethod
+ def _assign_patch(key, work_item_ids):
+ now = datetime.now()
+ active_work_items = db.get(key)
+ active_work_items.deactivate_expired(now)
+ next_item = active_work_items.next_item(work_item_ids, now)
+ active_work_items.put()
+ return next_item
diff --git a/Tools/QueueStatusServer/handlers/patch.py b/Tools/QueueStatusServer/handlers/patch.py
new file mode 100644
index 0000000..3219212
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/patch.py
@@ -0,0 +1,53 @@
+# 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.
+
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+from model.queuestatus import QueueStatus
+
+
+class Patch(webapp.RequestHandler):
+ def get(self, attachment_id_string):
+ attachment_id = int(attachment_id_string)
+ statuses = QueueStatus.all().filter("active_patch_id =", attachment_id).order("-date")
+
+ bug_id = None
+ queue_status = {}
+ for status in statuses:
+ bug_id = status.active_bug_id # Should be the same for every status.
+ per_queue_statuses = queue_status.get(status.queue_name, [])
+ per_queue_statuses.append(status)
+ queue_status[status.queue_name] = per_queue_statuses
+
+ template_values = {
+ "attachment_id" : attachment_id,
+ "bug_id" : bug_id,
+ "queue_status" : queue_status,
+ }
+ self.response.out.write(template.render("templates/patch.html", template_values))
diff --git a/Tools/QueueStatusServer/handlers/patchstatus.py b/Tools/QueueStatusServer/handlers/patchstatus.py
new file mode 100644
index 0000000..1a5422e
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/patchstatus.py
@@ -0,0 +1,40 @@
+# 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.
+
+from google.appengine.ext import webapp
+
+from model.queuestatus import QueueStatus
+
+
+class PatchStatus(webapp.RequestHandler):
+ def get(self, queue_name, attachment_id):
+ statuses = QueueStatus.all().filter('queue_name =', queue_name).filter('active_patch_id =', int(attachment_id)).order('-date').fetch(1)
+ if not statuses:
+ self.error(404)
+ return
+ self.response.out.write(statuses[0].message)
diff --git a/Tools/QueueStatusServer/handlers/queuestatus.py b/Tools/QueueStatusServer/handlers/queuestatus.py
new file mode 100644
index 0000000..54c0fdd
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/queuestatus.py
@@ -0,0 +1,72 @@
+# 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 itertools
+
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+from model.queues import Queue
+from model import queuestatus
+
+
+class QueueStatus(webapp.RequestHandler):
+ def _rows_for_work_items(self, queue):
+ queued_items = queue.work_items()
+ active_items = queue.active_work_items()
+ if not queued_items:
+ return []
+ rows = []
+ for item_id in queued_items.item_ids:
+ rows.append({
+ "attachment_id": item_id,
+ "bug_id": 1,
+ "lock_time": active_items and active_items.time_for_item(item_id),
+ })
+ return rows
+
+ def _grouping_key_for_status(self, status):
+ return "%s-%s" % (status.active_patch_id, status.bot_id)
+
+ def _build_status_groups(self, statuses):
+ return [list(group) for key, group in itertools.groupby(statuses, self._grouping_key_for_status)]
+
+ def get(self, queue_name):
+ queue_name = queue_name.lower()
+ queue = Queue.queue_with_name(queue_name)
+ if not queue:
+ self.error(404)
+ return
+
+ statuses = queuestatus.QueueStatus.all().filter("queue_name =", queue.name()).order("-date").fetch(15)
+ template_values = {
+ "display_queue_name": queue.display_name(),
+ "work_item_rows": self._rows_for_work_items(queue),
+ "status_groups": self._build_status_groups(statuses),
+ }
+ self.response.out.write(template.render("templates/queuestatus.html", template_values))
diff --git a/Tools/QueueStatusServer/handlers/queuestatus_unittest.py b/Tools/QueueStatusServer/handlers/queuestatus_unittest.py
new file mode 100644
index 0000000..a5ae844
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/queuestatus_unittest.py
@@ -0,0 +1,62 @@
+# 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 Research in Motion Ltd. 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 unittest
+
+from handlers.queuestatus import QueueStatus
+from model.queues import Queue
+
+
+class MockStatus(object):
+ def __init__(self, patch_id, bot_id):
+ self.active_patch_id = patch_id
+ self.bot_id = bot_id
+
+
+class QueueStatusTest(unittest.TestCase):
+ def test_build_status_groups(self):
+ queue_status = QueueStatus()
+ statuses = [
+ MockStatus(1, "foo"),
+ MockStatus(1, "foo"),
+ MockStatus(2, "foo"),
+ MockStatus(1, "foo"),
+ MockStatus(1, "bar"),
+ MockStatus(1, "foo"),
+ ]
+ groups = queue_status._build_status_groups(statuses)
+ self.assertEqual(len(groups), 5)
+ self.assertEqual(groups[0], statuses[0:2])
+ self.assertEqual(groups[1], statuses[2:3])
+ self.assertEqual(groups[2], statuses[3:4])
+ self.assertEqual(groups[3], statuses[4:5])
+ self.assertEqual(groups[4], statuses[5:6])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/QueueStatusServer/handlers/recentstatus.py b/Tools/QueueStatusServer/handlers/recentstatus.py
new file mode 100644
index 0000000..fddc93a
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/recentstatus.py
@@ -0,0 +1,94 @@
+# 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 datetime
+
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+from model.queues import Queue
+from model.queuestatus import QueueStatus
+from model.workitems import WorkItems
+
+
+class QueueBubble(object):
+ """View support class for recentstatus.html"""
+ def __init__(self, queue):
+ self._queue = queue
+ self._work_items = queue.work_items()
+ self._last_status = QueueStatus.all().filter("queue_name =", queue.name()).order("-date").get()
+
+ # FIXME: name and display_name should be replaced by a .queue() accessor.
+ def name(self):
+ return self._queue.name()
+
+ def display_name(self):
+ return self._queue.display_name()
+
+ def _last_status_date(self):
+ if not self._last_status:
+ return None
+ return self._last_status.date
+
+ def last_heard_from(self):
+ if not self._work_items:
+ return self._last_status_date()
+ return max(self._last_status_date(), self._work_items.date)
+
+ def is_alive(self):
+ if not self.last_heard_from():
+ return False
+ return self.last_heard_from() > (datetime.datetime.now() - datetime.timedelta(minutes=30))
+
+ def status_class(self):
+ if not self.is_alive():
+ return "dead"
+ if self.pending_items_count() > 1:
+ return "behind"
+ return "alive"
+
+ def status_text(self):
+ if not self._work_items:
+ return "Offline"
+ if not self._work_items.item_ids:
+ return "Idle"
+ return self._last_status.message
+
+ def pending_items_count(self):
+ if not self._work_items:
+ return 0
+ return len(self._work_items.item_ids)
+
+
+class QueuesOverview(webapp.RequestHandler):
+
+ def get(self):
+ template_values = {
+ "queues": [QueueBubble(queue) for queue in Queue.all()],
+ }
+ self.response.out.write(template.render("templates/recentstatus.html", template_values))
diff --git a/Tools/QueueStatusServer/handlers/releasepatch.py b/Tools/QueueStatusServer/handlers/releasepatch.py
new file mode 100644
index 0000000..0e46e69
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/releasepatch.py
@@ -0,0 +1,62 @@
+# 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.
+
+from google.appengine.ext import webapp, db
+from google.appengine.ext.webapp import template
+
+from handlers.updatebase import UpdateBase
+from model.attachment import Attachment
+from model.queues import Queue
+
+
+class ReleasePatch(UpdateBase):
+ def get(self):
+ self.response.out.write(template.render("templates/releasepatch.html", None))
+
+ def post(self):
+ queue_name = self.request.get("queue_name")
+ # FIXME: This queue lookup should be shared between handlers.
+ queue = Queue.queue_with_name(queue_name)
+ if not queue:
+ self.error(404)
+ return
+
+ attachment_id = self._int_from_request("attachment_id")
+ attachment = Attachment(attachment_id)
+ last_status = attachment.status_for_queue(queue)
+
+ # Ideally we should use a transaction for the calls to
+ # WorkItems and ActiveWorkItems.
+
+ # Only remove it from the queue if the last message is not a retry request.
+ # Allow removing it from the queue even if there is no last_status for easier testing.
+ if not last_status or not last_status.is_retry_request():
+ queue.work_items().remove_work_item(attachment_id)
+
+ # Always release the lock on the item.
+ queue.active_work_items().expire_item(attachment_id)
diff --git a/Tools/QueueStatusServer/handlers/showresults.py b/Tools/QueueStatusServer/handlers/showresults.py
new file mode 100644
index 0000000..e4cb71b
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/showresults.py
@@ -0,0 +1,41 @@
+# 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.
+
+from google.appengine.ext import webapp
+
+from model.queuestatus import QueueStatus
+
+
+class ShowResults(webapp.RequestHandler):
+ def get(self, status_id):
+ status = QueueStatus.get_by_id(int(status_id))
+ if not status:
+ self.error(404)
+ return
+ self.response.headers["Content-Type"] = "text/plain; charset=utf-8"
+ self.response.out.write(status.results_file)
diff --git a/Tools/QueueStatusServer/handlers/statusbubble.py b/Tools/QueueStatusServer/handlers/statusbubble.py
new file mode 100644
index 0000000..5690484
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/statusbubble.py
@@ -0,0 +1,59 @@
+# 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 operator
+
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+from model.attachment import Attachment
+from model.workitems import WorkItems
+from model.queues import Queue
+
+
+class StatusBubble(webapp.RequestHandler):
+ _queues_to_display = [queue for queue in Queue.all() if queue.is_ews()]
+
+ def _build_bubble(self, queue, attachment):
+ queue_status = attachment.status_for_queue(queue)
+ bubble = {
+ "name": queue.short_name().lower(),
+ "attachment_id": attachment.id,
+ "queue_position": attachment.position_in_queue(queue),
+ "state": attachment.state_from_queue_status(queue_status) if queue_status else "none",
+ "status": queue_status,
+ }
+ return bubble
+
+ def get(self, attachment_id):
+ attachment = Attachment(int(attachment_id))
+ bubbles = [self._build_bubble(queue, attachment) for queue in self._queues_to_display]
+ template_values = {
+ "bubbles": bubbles,
+ }
+ self.response.out.write(template.render("templates/statusbubble.html", template_values))
diff --git a/Tools/QueueStatusServer/handlers/statusbubble_unittest.py b/Tools/QueueStatusServer/handlers/statusbubble_unittest.py
new file mode 100644
index 0000000..3ffbdaf
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/statusbubble_unittest.py
@@ -0,0 +1,62 @@
+# 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 Research in Motion Ltd. 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 unittest
+
+
+from handlers.statusbubble import StatusBubble
+from model.queues import Queue
+
+
+class MockAttachment(object):
+ def __init__(self):
+ self.id = 1
+
+ def status_for_queue(self, queue):
+ return None
+
+ def position_in_queue(self, queue):
+ return 1
+
+
+class StatusBubbleTest(unittest.TestCase):
+ def test_build_bubble(self):
+ bubble = StatusBubble()
+ queue = Queue("mac-ews")
+ attachment = MockAttachment()
+ bubble_dict = bubble._build_bubble(queue, attachment)
+ # FIXME: assertDictEqual (in Python 2.7) would be better to use here.
+ self.assertEqual(bubble_dict["name"], "mac")
+ self.assertEqual(bubble_dict["attachment_id"], 1)
+ self.assertEqual(bubble_dict["queue_position"], 1)
+ self.assertEqual(bubble_dict["state"], "none")
+ self.assertEqual(bubble_dict["status"], None)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/QueueStatusServer/handlers/submittoews.py b/Tools/QueueStatusServer/handlers/submittoews.py
new file mode 100644
index 0000000..3ba4373
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/submittoews.py
@@ -0,0 +1,64 @@
+# 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.
+
+from google.appengine.ext import webapp, db
+from google.appengine.ext.webapp import template
+
+from handlers.updatebase import UpdateBase
+from model.attachment import Attachment
+from model.queues import Queue
+
+
+class SubmitToEWS(UpdateBase):
+ def get(self):
+ self.response.out.write(template.render("templates/submittoews.html", None))
+
+ def _should_add_to_ews_queue(self, queue, attachment):
+ # This assert() is here to make sure we're not submitting to the commit-queue.
+ # The commit-queue clients check each patch anyway, but there is not sense
+ # in adding things to the commit-queue when they won't be processed by it.
+ assert(queue.is_ews())
+ latest_status = attachment.status_for_queue(queue)
+ if not latest_status:
+ return True
+ # Only ever re-submit to the EWS if the EWS specifically requested a retry.
+ # This allows us to restart the EWS feeder queue, without all r? patches
+ # being retried as a result of that restart!
+ # In some future version we might add a "force" button to allow the user
+ # to override this restriction.
+ return latest_status.is_retry_request()
+
+ def _add_attachment_to_ews_queues(self, attachment):
+ for queue in Queue.all_ews(): # all_ews() currently includes the style-queue
+ if self._should_add_to_ews_queue(queue, attachment):
+ queue.work_items().add_work_item(attachment.id)
+
+ def post(self):
+ attachment_id = self._int_from_request("attachment_id")
+ attachment = Attachment(attachment_id)
+ self._add_attachment_to_ews_queues(attachment)
diff --git a/Tools/QueueStatusServer/handlers/svnrevision.py b/Tools/QueueStatusServer/handlers/svnrevision.py
new file mode 100644
index 0000000..36eab33
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/svnrevision.py
@@ -0,0 +1,40 @@
+# 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.
+
+from google.appengine.ext import webapp
+
+import model
+
+
+class SVNRevision(webapp.RequestHandler):
+ def get(self, svn_revision_number):
+ svn_revisions = model.SVNRevision.all().filter('number =', int(svn_revision_number)).order('-date').fetch(1)
+ if not svn_revisions:
+ self.error(404)
+ return
+ self.response.out.write(svn_revisions[0].to_xml())
diff --git a/Tools/QueueStatusServer/handlers/updatebase.py b/Tools/QueueStatusServer/handlers/updatebase.py
new file mode 100644
index 0000000..b087e83
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/updatebase.py
@@ -0,0 +1,41 @@
+# 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.
+
+from google.appengine.api import users
+from google.appengine.ext import webapp, db
+
+
+class UpdateBase(webapp.RequestHandler):
+ def _int_from_request(self, name):
+ string_value = self.request.get(name)
+ try:
+ int_value = int(string_value)
+ return int_value
+ except ValueError, TypeError:
+ pass
+ return None
diff --git a/Tools/QueueStatusServer/handlers/updatestatus.py b/Tools/QueueStatusServer/handlers/updatestatus.py
new file mode 100644
index 0000000..7301101
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/updatestatus.py
@@ -0,0 +1,66 @@
+# 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.
+
+from google.appengine.api import users
+from google.appengine.ext import webapp, db
+from google.appengine.ext.webapp import template
+
+from handlers.updatebase import UpdateBase
+from model.attachment import Attachment
+from model.queuestatus import QueueStatus
+
+
+class UpdateStatus(UpdateBase):
+ def get(self):
+ self.response.out.write(template.render("templates/updatestatus.html", None))
+
+ def _queue_status_from_request(self):
+ queue_status = QueueStatus()
+
+ # FIXME: I think this can be removed, no one uses it.
+ if users.get_current_user():
+ queue_status.author = users.get_current_user()
+
+ bug_id = self._int_from_request("bug_id")
+ patch_id = self._int_from_request("patch_id")
+ queue_name = self.request.get("queue_name")
+ bot_id = self.request.get("bot_id")
+ queue_status.queue_name = queue_name
+ queue_status.bot_id = bot_id
+ queue_status.active_bug_id = bug_id
+ queue_status.active_patch_id = patch_id
+ queue_status.message = self.request.get("status")
+ results_file = self.request.get("results_file")
+ queue_status.results_file = db.Blob(str(results_file))
+ return queue_status
+
+ def post(self):
+ queue_status = self._queue_status_from_request()
+ queue_status.put()
+ Attachment.dirty(queue_status.active_patch_id)
+ self.response.out.write(queue_status.key().id())
diff --git a/Tools/QueueStatusServer/handlers/updatesvnrevision.py b/Tools/QueueStatusServer/handlers/updatesvnrevision.py
new file mode 100644
index 0000000..075982a
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/updatesvnrevision.py
@@ -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.
+
+from google.appengine.ext import webapp, db
+from google.appengine.ext.webapp import template
+
+import handlers
+import model
+
+
+class UpdateSVNRevision(handlers.UpdateBase):
+ def get(self):
+ self.response.out.write(template.render("templates/updatesvnrevision.html", None))
+
+ def post(self):
+ svn_revision_number = self._int_from_request("number")
+
+ svn_revisions = model.SVNRevision.all().filter('number =', svn_revision_number).order('-date').fetch(1)
+ svn_revision = None
+ if svn_revisions:
+ svn_revision = svn_revisions[0]
+ else:
+ svn_revision = model.SVNRevision()
+ svn_revision.number = svn_revision_number
+ svn_revision.broken_bots.append(self.request.get("broken_bot"))
+ svn_revision.put()
+
+ self.response.out.write(svn_revision.key().id())
diff --git a/Tools/QueueStatusServer/handlers/updateworkitems.py b/Tools/QueueStatusServer/handlers/updateworkitems.py
new file mode 100644
index 0000000..16a9d49
--- /dev/null
+++ b/Tools/QueueStatusServer/handlers/updateworkitems.py
@@ -0,0 +1,66 @@
+# 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.
+
+from google.appengine.ext import webapp, db
+from google.appengine.ext.webapp import template
+
+from handlers.updatebase import UpdateBase
+from model.queues import Queue
+from model.workitems import WorkItems
+
+from datetime import datetime
+
+
+class UpdateWorkItems(UpdateBase):
+ def get(self):
+ self.response.out.write(template.render("templates/updateworkitems.html", None))
+
+ def _parse_work_items_string(self, items_string):
+ # Our parsing could be much more robust.
+ item_strings = items_string.split(" ") if items_string else []
+ return map(int, item_strings)
+
+ def _work_items_from_request(self):
+ queue_name = self.request.get("queue_name")
+ queue = Queue.queue_with_name(queue_name)
+ if not queue:
+ self.response.out.write("\"%s\" is not in queues %s" % (queue_name, Queue.all()))
+ return None
+
+ items_string = self.request.get("work_items")
+ work_items = queue.work_items()
+ work_items.item_ids = self._parse_work_items_string(items_string)
+ work_items.date = datetime.now()
+ return work_items
+
+ def post(self):
+ work_items = self._work_items_from_request()
+ if not work_items:
+ self.response.set_status(500)
+ return
+ work_items.put()
diff --git a/Tools/QueueStatusServer/index.yaml b/Tools/QueueStatusServer/index.yaml
new file mode 100644
index 0000000..6c9a3b2
--- /dev/null
+++ b/Tools/QueueStatusServer/index.yaml
@@ -0,0 +1,41 @@
+indexes:
+
+# AUTOGENERATED
+
+# This index.yaml is automatically updated whenever the dev_appserver
+# detects that a new type of query is run. If you want to manage the
+# index.yaml file manually, remove the above marker line (the line
+# saying "# AUTOGENERATED"). If you want to manage some indexes
+# manually, move them above the marker line. The index.yaml file is
+# automatically uploaded to the admin console when you next deploy
+# your application using appcfg.py.
+
+- kind: QueueStatus
+ properties:
+ - name: active_patch_id
+ - name: date
+ direction: desc
+
+- kind: QueueStatus
+ properties:
+ - name: active_patch_id
+ - name: queue_name
+ - name: date
+ direction: desc
+
+- kind: QueueStatus
+ properties:
+ - name: queue_name
+ - name: date
+
+- kind: QueueStatus
+ properties:
+ - name: queue_name
+ - name: date
+ direction: desc
+
+- kind: SVNRevision
+ properties:
+ - name: number
+ - name: date
+ direction: desc
diff --git a/Tools/QueueStatusServer/main.py b/Tools/QueueStatusServer/main.py
new file mode 100644
index 0000000..3fbee5c
--- /dev/null
+++ b/Tools/QueueStatusServer/main.py
@@ -0,0 +1,79 @@
+# 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.
+
+# Request a modern Django
+from google.appengine.dist import use_library
+use_library('django', '1.1')
+
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp.util import run_wsgi_app
+
+from handlers.dashboard import Dashboard
+from handlers.gc import GC
+from handlers.nextpatch import NextPatch
+from handlers.patch import Patch
+from handlers.patchstatus import PatchStatus
+from handlers.queuestatus import QueueStatus
+from handlers.recentstatus import QueuesOverview
+from handlers.releasepatch import ReleasePatch
+from handlers.showresults import ShowResults
+from handlers.statusbubble import StatusBubble
+from handlers.submittoews import SubmitToEWS
+from handlers.svnrevision import SVNRevision
+from handlers.updatestatus import UpdateStatus
+from handlers.updatesvnrevision import UpdateSVNRevision
+from handlers.updateworkitems import UpdateWorkItems
+
+
+webapp.template.register_template_library('filters.webkit_extras')
+
+routes = [
+ ('/', QueuesOverview),
+ ('/dashboard', Dashboard),
+ ('/gc', GC),
+ (r'/patch-status/(.*)/(.*)', PatchStatus),
+ (r'/patch/(.*)', Patch),
+ (r'/submit-to-ews', SubmitToEWS),
+ (r'/results/(.*)', ShowResults),
+ (r'/status-bubble/(.*)', StatusBubble),
+ (r'/svn-revision/(.*)', SVNRevision),
+ (r'/queue-status/(.*)', QueueStatus),
+ (r'/next-patch/(.*)', NextPatch),
+ (r'/release-patch', ReleasePatch),
+ ('/update-status', UpdateStatus),
+ ('/update-work-items', UpdateWorkItems),
+ ('/update-svn-revision', UpdateSVNRevision),
+]
+
+application = webapp.WSGIApplication(routes, debug=True)
+
+def main():
+ run_wsgi_app(application)
+
+if __name__ == "__main__":
+ main()
diff --git a/Tools/QueueStatusServer/model/__init__.py b/Tools/QueueStatusServer/model/__init__.py
new file mode 100644
index 0000000..1eaa044
--- /dev/null
+++ b/Tools/QueueStatusServer/model/__init__.py
@@ -0,0 +1,3 @@
+# Required for Python to search this directory for module files
+
+from model.svnrevision import SVNRevision
diff --git a/Tools/QueueStatusServer/model/activeworkitems.py b/Tools/QueueStatusServer/model/activeworkitems.py
new file mode 100644
index 0000000..ab5d7a6
--- /dev/null
+++ b/Tools/QueueStatusServer/model/activeworkitems.py
@@ -0,0 +1,89 @@
+# 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.
+
+from google.appengine.ext import db
+
+from datetime import timedelta, datetime
+import time
+
+from model.queuepropertymixin import QueuePropertyMixin
+
+
+class ActiveWorkItems(db.Model, QueuePropertyMixin):
+ queue_name = db.StringProperty()
+ item_ids = db.ListProperty(int)
+ item_dates = db.ListProperty(float)
+ date = db.DateTimeProperty(auto_now_add=True)
+
+ # The id/date pairs should probably just be their own class.
+ def _item_time_pairs(self):
+ return zip(self.item_ids, self.item_dates)
+
+ def _set_item_time_pairs(self, pairs):
+ if pairs:
+ # The * operator raises on an empty list.
+ # db.Model does not tuples, we have to make lists.
+ self.item_ids, self.item_dates = map(list, zip(*pairs))
+ else:
+ self.item_ids = []
+ self.item_dates = []
+
+ def _append_item_time_pair(self, pair):
+ self.item_ids.append(pair[0])
+ self.item_dates.append(pair[1])
+
+ def _remove_item(self, item_id):
+ nonexpired_pairs = [pair for pair in self._item_time_pairs() if pair[0] != item_id]
+ self._set_item_time_pairs(nonexpired_pairs)
+
+ @staticmethod
+ def _expire_item(key, item_id):
+ active_work_items = db.get(key)
+ active_work_items._remove_item(item_id)
+ active_work_items.put()
+
+ def expire_item(self, item_id):
+ return db.run_in_transaction(self._expire_item, self.key(), item_id)
+
+ def deactivate_expired(self, now):
+ one_hour_ago = time.mktime((now - timedelta(minutes=60)).timetuple())
+ nonexpired_pairs = [pair for pair in self._item_time_pairs() if pair[1] > one_hour_ago]
+ self._set_item_time_pairs(nonexpired_pairs)
+
+ def next_item(self, work_item_ids, now):
+ for item_id in work_item_ids:
+ if item_id not in self.item_ids:
+ self._append_item_time_pair([item_id, time.mktime(now.timetuple())])
+ return item_id
+ return None
+
+ def time_for_item(self, item_id):
+ for active_item_id, time in self._item_time_pairs():
+ if active_item_id == item_id:
+ return datetime.fromtimestamp(time)
+ return None
diff --git a/Tools/QueueStatusServer/model/activeworkitems_unitest.py b/Tools/QueueStatusServer/model/activeworkitems_unitest.py
new file mode 100644
index 0000000..6d915a1
--- /dev/null
+++ b/Tools/QueueStatusServer/model/activeworkitems_unitest.py
@@ -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 Research in Motion Ltd. 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 unittest
+from datetime import datetime
+
+from model.activeworkitems import ActiveWorkItems
+
+
+class ActiveWorkItemsTest(unittest.TestCase):
+ def test_basic(self):
+ items = ActiveWorkItems()
+ queued_items = [1, 2]
+ time = datetime.now()
+ self.assertEqual(items.next_item(queued_items, time), 1)
+ self.assertEqual(items.next_item([1], time), None)
+ self.assertEqual(items.next_item([], time), None)
+
+ self.assertEqual(items.time_for_item(1), time)
+ self.assertEqual(items.time_for_item(2), None)
+
+ items.expire_item(1)
+ self.assertEqual(items.time_for_item(1), None)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/QueueStatusServer/model/attachment.py b/Tools/QueueStatusServer/model/attachment.py
new file mode 100644
index 0000000..f98f265
--- /dev/null
+++ b/Tools/QueueStatusServer/model/attachment.py
@@ -0,0 +1,133 @@
+# 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 re
+
+from google.appengine.api import memcache
+
+from model.queues import Queue
+from model.queuestatus import QueueStatus
+from model.workitems import WorkItems
+
+
+class Attachment(object):
+ @classmethod
+ def dirty(cls, attachment_id):
+ memcache.delete(str(attachment_id), namespace="attachment-summary")
+
+ @classmethod
+ def recent(cls, limit=1):
+ statuses = QueueStatus.all().order("-date")
+ # Notice that we use both a set and a list here to keep the -date ordering.
+ ids = []
+ visited_ids = set()
+ for status in statuses:
+ attachment_id = status.active_patch_id
+ if not attachment_id:
+ continue
+ if attachment_id in visited_ids:
+ continue
+ visited_ids.add(attachment_id)
+ ids.append(attachment_id)
+ if len(visited_ids) >= limit:
+ break
+ return map(cls, ids)
+
+ def __init__(self, attachment_id):
+ self.id = attachment_id
+ self._summary = None
+ self._cached_queue_positions = None
+
+ def summary(self):
+ if self._summary:
+ return self._summary
+ self._summary = memcache.get(str(self.id), namespace="attachment-summary")
+ if self._summary:
+ return self._summary
+ self._summary = self._fetch_summary()
+ memcache.set(str(self.id), self._summary, namespace="attachment-summary")
+ return self._summary
+
+ def state_from_queue_status(self, status):
+ table = {
+ "Pass" : "pass",
+ "Fail" : "fail",
+ }
+ state = table.get(status.message)
+ if state:
+ return state
+ if status.message.startswith("Error:"):
+ return "error"
+ if status:
+ return "pending"
+ return None
+
+ def position_in_queue(self, queue):
+ return self._queue_positions().get(queue.name())
+
+ def status_for_queue(self, queue):
+ # summary() is a horrible API and should be killed.
+ queue_summary = self.summary().get(queue.name_with_underscores())
+ if not queue_summary:
+ return None
+ return queue_summary.get("status")
+
+ def bug_id(self):
+ return self.summary().get("bug_id")
+
+ def _queue_positions(self):
+ if self._cached_queue_positions:
+ return self._cached_queue_positions
+ # FIXME: Should we be mem-caching this?
+ self._cached_queue_positions = self._calculate_queue_positions()
+ return self._cached_queue_positions
+
+ def _calculate_queue_positions(self):
+ all_work_items = WorkItems.all().fetch(limit=len(Queue.all()))
+ return dict([(items.queue.name(), items.display_position_for_attachment(self.id)) for items in all_work_items])
+
+ # FIXME: This is controller/view code and does not belong in a model.
+ def _fetch_summary(self):
+ summary = { "attachment_id" : self.id }
+
+ first_status = QueueStatus.all().filter('active_patch_id =', self.id).get()
+ if not first_status:
+ # We don't have any record of this attachment.
+ return summary
+ summary["bug_id"] = first_status.active_bug_id
+
+ for queue in Queue.all():
+ summary[queue.name_with_underscores()] = None
+ status = QueueStatus.all().filter('queue_name =', queue.name()).filter('active_patch_id =', self.id).order('-date').get()
+ if status:
+ # summary() is a horrible API and should be killed.
+ summary[queue.name_with_underscores()] = {
+ "state": self.state_from_queue_status(status),
+ "status": status,
+ }
+ return summary
diff --git a/Tools/QueueStatusServer/model/queuepropertymixin.py b/Tools/QueueStatusServer/model/queuepropertymixin.py
new file mode 100644
index 0000000..a462586
--- /dev/null
+++ b/Tools/QueueStatusServer/model/queuepropertymixin.py
@@ -0,0 +1,39 @@
+# 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.
+
+
+class QueuePropertyMixin(object):
+ def _queue_getter(self):
+ # Import at runtime to avoid circular imports
+ from model.queues import Queue
+ return Queue.queue_with_name(self.queue_name)
+
+ def _queue_setter(self, queue):
+ self.queue_name = queue.name() if queue else None
+
+ queue = property(_queue_getter, _queue_setter)
diff --git a/Tools/QueueStatusServer/model/queuepropertymixin_unittest.py b/Tools/QueueStatusServer/model/queuepropertymixin_unittest.py
new file mode 100644
index 0000000..9a301fe
--- /dev/null
+++ b/Tools/QueueStatusServer/model/queuepropertymixin_unittest.py
@@ -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 Research in Motion Ltd. 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 unittest
+
+from model.queuepropertymixin import QueuePropertyMixin
+from model.queues import Queue
+
+
+class ObjectWithQueueName(QueuePropertyMixin):
+ def __init__(self):
+ self.queue_name = None
+
+
+class QueuePropertyMixinTest(unittest.TestCase):
+ def test_queue_property(self):
+ test_object = ObjectWithQueueName()
+ mac_ews = Queue("mac-ews")
+ test_object.queue = mac_ews
+ self.assertEquals(test_object.queue.name(), "mac-ews")
+ self.assertEquals(test_object.queue_name, "mac-ews")
+ test_object.queue = None
+ self.assertEquals(test_object.queue_name, None)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/QueueStatusServer/model/queues.py b/Tools/QueueStatusServer/model/queues.py
new file mode 100644
index 0000000..1d46f89
--- /dev/null
+++ b/Tools/QueueStatusServer/model/queues.py
@@ -0,0 +1,113 @@
+# 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 re
+
+from model.activeworkitems import ActiveWorkItems
+from model.workitems import WorkItems
+
+
+class Queue(object):
+
+ # Eventually the list of queues may be stored in the data store.
+ _all_queue_names = [
+ "commit-queue",
+ "style-queue",
+ "chromium-ews",
+ "qt-ews",
+ "gtk-ews",
+ "mac-ews",
+ "win-ews",
+ "efl-ews",
+ "cr-mac-ews",
+ ]
+
+ def __init__(self, name):
+ assert(name in self._all_queue_names)
+ self._name = name
+
+ @classmethod
+ def queue_with_name(cls, queue_name):
+ if queue_name not in cls._all_queue_names:
+ return None
+ return Queue(queue_name)
+
+ @classmethod
+ def all(cls):
+ return [Queue(name) for name in cls._all_queue_names]
+
+ @classmethod
+ def all_ews(cls):
+ return [queue for queue in cls.all() if queue.is_ews()]
+
+ def name(self):
+ return self._name
+
+ def work_items(self):
+ key_name = "work-items-%s" % (self._name)
+ return WorkItems.get_or_insert(key_name=key_name, queue_name=self._name)
+
+ # FIXME: active_work_items is a bad name for this lock-table.
+ def active_work_items(self):
+ key_name = "active-work-items-%s" % (self._name)
+ return ActiveWorkItems.get_or_insert(key_name=key_name, queue_name=self._name)
+
+ def _caplitalize_after_dash(self, string):
+ return "-".join([word[0].upper() + word[1:] for word in string.split("-")])
+
+ # For use in status bubbles or table headers
+ def short_name(self):
+ # HACK: chromium-ews is incorrectly named.
+ short_name = self._name.replace("chromium-ews", "Cr-Linux-ews")
+ short_name = short_name.replace("-ews", "")
+ short_name = short_name.replace("-queue", "")
+ return self._caplitalize_after_dash(short_name.capitalize())
+
+ def display_name(self):
+ # HACK: chromium-ews is incorrectly named.
+ display_name = self._name.replace("chromium-ews", "cr-linux-ews")
+
+ display_name = display_name.replace("-", " ")
+ display_name = display_name.replace("cr", "chromium")
+ display_name = display_name.title()
+ display_name = display_name.replace("Ews", "EWS")
+ return display_name
+
+ _dash_regexp = re.compile("-")
+
+ def name_with_underscores(self):
+ return self._dash_regexp.sub("_", self._name)
+
+ def is_ews(self):
+ # Note: The style-queue is just like an EWS in that it has an EWS
+ # bubble, and it works off of the r? patches. If at some later
+ # point code wants to not treat the style-queue as an EWS
+ # (e.g. expecting is_ews() queues to have build results?)
+ # then we should fix all callers and change this check.
+ return self._name.endswith("-ews") or self._name == "style-queue"
diff --git a/Tools/QueueStatusServer/model/queues_unittest.py b/Tools/QueueStatusServer/model/queues_unittest.py
new file mode 100644
index 0000000..cfa7fcd
--- /dev/null
+++ b/Tools/QueueStatusServer/model/queues_unittest.py
@@ -0,0 +1,80 @@
+# Copyright (C) 2010 Google, Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Research in Motion Ltd. 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 unittest
+
+
+from model.queues import Queue
+
+
+class QueueTest(unittest.TestCase):
+ def test_is_ews(self):
+ mac_ews = Queue("mac-ews")
+ self.assertTrue(mac_ews.is_ews())
+
+ def test_queue_with_name(self):
+ self.assertEqual(Queue.queue_with_name("bogus"), None)
+ self.assertEqual(Queue.queue_with_name("mac-ews").name(), "mac-ews")
+ self.assertRaises(AssertionError, Queue, ("bogus"))
+
+ def _assert_short_name(self, queue_name, short_name):
+ self.assertEquals(Queue(queue_name).short_name(), short_name)
+
+ def test_short_name(self):
+ self._assert_short_name("mac-ews", "Mac")
+ self._assert_short_name("chromium-ews", "Cr-Linux")
+ self._assert_short_name("commit-queue", "Commit")
+ self._assert_short_name("style-queue", "Style")
+
+ def _assert_display_name(self, queue_name, short_name):
+ self.assertEquals(Queue(queue_name).display_name(), short_name)
+
+ def test_display_name(self):
+ self._assert_display_name("mac-ews", "Mac EWS")
+ self._assert_display_name("chromium-ews", "Chromium Linux EWS")
+ self._assert_display_name("commit-queue", "Commit Queue")
+ self._assert_display_name("style-queue", "Style Queue")
+
+ def _assert_name_with_underscores(self, queue_name, short_name):
+ self.assertEquals(Queue(queue_name).name_with_underscores(), short_name)
+
+ def test_name_with_underscores(self):
+ self._assert_name_with_underscores("mac-ews", "mac_ews")
+ self._assert_name_with_underscores("chromium-ews", "chromium_ews")
+ self._assert_name_with_underscores("commit-queue", "commit_queue")
+
+ def test_style_queue_is_ews(self):
+ # For now we treat the style-queue as an EWS since most users would
+ # describe it as such. If is_ews() ever needs to mean "builds the patch"
+ # or similar, then we will need to adjust all callers.
+ self.assertTrue(Queue("style-queue").is_ews())
+ self.assertTrue("style-queue" in map(Queue.name, Queue.all_ews()))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/QueueStatusServer/model/queuestatus.py b/Tools/QueueStatusServer/model/queuestatus.py
new file mode 100644
index 0000000..8002f89
--- /dev/null
+++ b/Tools/QueueStatusServer/model/queuestatus.py
@@ -0,0 +1,44 @@
+# 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.
+
+from google.appengine.ext import db
+from model.queuepropertymixin import QueuePropertyMixin
+
+
+class QueueStatus(db.Model, QueuePropertyMixin):
+ author = db.UserProperty()
+ queue_name = db.StringProperty()
+ bot_id = db.StringProperty()
+ active_bug_id = db.IntegerProperty()
+ active_patch_id = db.IntegerProperty()
+ message = db.StringProperty(multiline=True)
+ date = db.DateTimeProperty(auto_now_add=True)
+ results_file = db.BlobProperty()
+
+ def is_retry_request(self):
+ return self.message == "Retry" # From AbstractQueue._retry_status
diff --git a/Tools/QueueStatusServer/model/svnrevision.py b/Tools/QueueStatusServer/model/svnrevision.py
new file mode 100644
index 0000000..f5d3644
--- /dev/null
+++ b/Tools/QueueStatusServer/model/svnrevision.py
@@ -0,0 +1,35 @@
+# 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.
+
+from google.appengine.ext import db
+
+
+class SVNRevision(db.Model):
+ number = db.IntegerProperty()
+ broken_bots = db.StringListProperty(default=[])
+ date = db.DateTimeProperty(auto_now_add=True)
diff --git a/Tools/QueueStatusServer/model/workitems.py b/Tools/QueueStatusServer/model/workitems.py
new file mode 100644
index 0000000..772fc39
--- /dev/null
+++ b/Tools/QueueStatusServer/model/workitems.py
@@ -0,0 +1,69 @@
+# 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.
+
+from google.appengine.ext import db
+
+from model.queuepropertymixin import QueuePropertyMixin
+
+
+class WorkItems(db.Model, QueuePropertyMixin):
+ queue_name = db.StringProperty()
+ item_ids = db.ListProperty(int)
+ date = db.DateTimeProperty(auto_now_add=True)
+
+ def display_position_for_attachment(self, attachment_id):
+ """Returns a 1-based index corresponding to the position
+ of the attachment_id in the queue. If the attachment is
+ not in this queue, this returns None"""
+ if attachment_id in self.item_ids:
+ return self.item_ids.index(attachment_id) + 1
+ return None
+
+ @staticmethod
+ def _unguarded_add(key, attachment_id):
+ work_items = db.get(key)
+ if attachment_id in work_items.item_ids:
+ return
+ work_items.item_ids.append(attachment_id)
+ work_items.put()
+
+ # Because this uses .key() self.is_saved() must be True or this will throw NotSavedError.
+ def add_work_item(self, attachment_id):
+ db.run_in_transaction(self._unguarded_add, self.key(), attachment_id)
+
+ @staticmethod
+ def _unguarded_remove(key, attachment_id):
+ work_items = db.get(key)
+ if attachment_id in work_items.item_ids:
+ # We should never have more than one entry for a work item, so we only need remove the first.
+ work_items.item_ids.remove(attachment_id)
+ work_items.put()
+
+ # Because this uses .key() self.is_saved() must be True or this will throw NotSavedError.
+ def remove_work_item(self, attachment_id):
+ db.run_in_transaction(self._unguarded_remove, self.key(), attachment_id)
diff --git a/Tools/QueueStatusServer/model/workitems_unittest.py b/Tools/QueueStatusServer/model/workitems_unittest.py
new file mode 100644
index 0000000..b1ff1d3
--- /dev/null
+++ b/Tools/QueueStatusServer/model/workitems_unittest.py
@@ -0,0 +1,45 @@
+# 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 Research in Motion Ltd. 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 unittest
+
+
+from model.workitems import WorkItems
+
+
+class WorkItemsTest(unittest.TestCase):
+ def test_display_position_for_attachment(self):
+ items = WorkItems()
+ items.item_ids = [0, 1, 2]
+ self.assertEquals(items.display_position_for_attachment(0), 1)
+ self.assertEquals(items.display_position_for_attachment(1), 2)
+ self.assertEquals(items.display_position_for_attachment(3), None)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/QueueStatusServer/stylesheets/dashboard.css b/Tools/QueueStatusServer/stylesheets/dashboard.css
new file mode 100644
index 0000000..7b4f857
--- /dev/null
+++ b/Tools/QueueStatusServer/stylesheets/dashboard.css
@@ -0,0 +1,103 @@
+body {
+ font-family: Verdana, Helvetica, sans-serif;
+ width: 600px;
+ padding: 0px;
+ color: #444;
+}
+h1 {
+ background-color: #EEE;
+ color: #444;
+ font-size: 14pt;
+ font-style: italic;
+ margin: 0px;
+ padding: 5px;
+}
+h2 {
+ background-color: #AAA;
+ color: white;
+ font-weight: bold;
+ font-size: 9pt;
+ margin: 0px;
+ padding: 5px;
+}
+ul {
+ margin: 0px;
+ padding: 0px;
+ list-style: none;
+}
+li {
+ padding: 5px;
+}
+table {
+ border-spacing: 0px;
+}
+th {
+ background-color: #AAA;
+ color: white;
+ padding: 5px;
+ width: 100px;
+ font-size: 9pt;
+}
+td {
+ text-align: center;
+}
+tr:hover, li:hover {
+ background-color: #EEE;
+}
+
+.status-group {
+ font-size: 90%;
+}
+
+.status-bug {
+ font-weight: bold;
+}
+
+.status-group ul {
+ font-size: 90%;
+}
+
+.status-group ul li {
+ padding: 2px 0 2px 7px;
+ overflow: hidden;
+}
+
+.status-group ul li:hover {
+ background: #ddd;
+}
+
+.status-date {
+ color: #AAA;
+ float: right;
+ font-size: 8pt;
+}
+
+.status-cell {
+ margin: 1px;
+ padding: 1px 2px;
+ font-size: 9pt;
+ border: 1px solid transparent;
+}
+.status-cell:hover {
+ border: 1px solid black;
+}
+.status-cell.pass {
+ background-color: #8FDF5F;
+ cursor: pointer;
+ /* border: 1px solid #4F8530; */
+}
+.status-cell.fail {
+ background-color: #E98080;
+ cursor: pointer;
+ /* border: 1px solid #A77272; */
+}
+.status-cell.pending {
+ background-color: #FFFC6C;
+ cursor: pointer;
+ /* border: 1px solid #C5C56D; */
+}
+.status-cell.error {
+ background-color: #E0B0FF;
+ cursor: pointer;
+ /* border: 1px solid #ACA0B3; */
+}
diff --git a/Tools/QueueStatusServer/stylesheets/main.css b/Tools/QueueStatusServer/stylesheets/main.css
new file mode 100644
index 0000000..55d3694
--- /dev/null
+++ b/Tools/QueueStatusServer/stylesheets/main.css
@@ -0,0 +1,26 @@
+body {
+ font-family: Verdana, Helvetica, sans-serif;
+}
+
+#current_status {
+ padding: 5px;
+ font-size: larger;
+}
+
+#last_status_date {
+ font-size: small;
+}
+
+.recent_status {
+ padding-left: 10px;
+}
+
+#recent_status_table {
+ font-size: small;
+ margin: 10px;
+}
+
+#footer {
+ font-size: small;
+ padding-top: 10px;
+}
diff --git a/Tools/QueueStatusServer/templates/dashboard.html b/Tools/QueueStatusServer/templates/dashboard.html
new file mode 100644
index 0000000..f88a5ea
--- /dev/null
+++ b/Tools/QueueStatusServer/templates/dashboard.html
@@ -0,0 +1,44 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>WebKit Bot Status</title>
+<link type="text/css" rel="stylesheet" href="/stylesheets/dashboard.css" />
+<script>
+function statusDetail(patch_id) {
+ // FIXME: We'd like to use AJAX to show the details on this page.
+ window.location = "/patch/" + patch_id
+}
+</script>
+</head>
+<body>
+<h1>WebKit Bot Status</h1>
+<table>
+ <theader>
+ <tr>
+ <th>Bug</th>
+ <th>Attachment</th>
+ {% for header in headers %}
+ <th>{{ header }}</th>
+ {% endfor %}
+ </tr>
+ </thead>
+ <tbody>{% for row in rows %}
+ <tr>
+ <td class="status-cell">
+ {{ row.bug_id|force_escape|webkit_bug_id|safe }}
+ </td>
+ <td class="status-cell">
+ {{ row.attachment_id|force_escape|webkit_attachment_id|safe }}
+ </td>
+ {% for bubble in row.bubbles %}
+ <td class="status-cell {{ bubble.status_class }}"
+ {% if bubble.status %}
+ onclick="statusDetail({{ row.attachment_id }})"
+ title="{{ bubble.status_date|timesince }}"
+ {% endif %}>
+ </td>
+ {% endfor %}
+ </tr>{% endfor %}
+ </tbody>
+</table>
+</html>
diff --git a/Tools/QueueStatusServer/templates/includes/singlequeuestatus.html b/Tools/QueueStatusServer/templates/includes/singlequeuestatus.html
new file mode 100644
index 0000000..0adbfbd
--- /dev/null
+++ b/Tools/QueueStatusServer/templates/includes/singlequeuestatus.html
@@ -0,0 +1,9 @@
+<span class="status-date">{{ status.date|timesince }} ago
+{% if status.bot_id %}
+({{ status.bot_id }})
+{% endif %}
+</span>
+<span class="status-message">{{ status.message|force_escape|urlize|webkit_linkify|safe }}</span>
+{% if status.results_file %}
+ <span class="status-results">[{{ status.key.id|results_link|safe }}]</span>
+{% endif %}
diff --git a/Tools/QueueStatusServer/templates/patch.html b/Tools/QueueStatusServer/templates/patch.html
new file mode 100644
index 0000000..de334a5
--- /dev/null
+++ b/Tools/QueueStatusServer/templates/patch.html
@@ -0,0 +1,21 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Patch Status</title>
+<link type="text/css" rel="stylesheet" href="/stylesheets/dashboard.css" />
+</head>
+<body>
+<h1>
+ Patch {{ attachment_id|force_escape|webkit_attachment_id|safe }} (Bug {{ bug_id|force_escape|webkit_bug_id|safe }})
+</h1>{% for queue_name, statuses in queue_status.items %}
+<div class="status-details">
+ <h2>{{ queue_name }}</h2>
+ <ul>{% for status in statuses %}
+ <li>
+ <span class="status-message">{{ status.message|force_escape|urlize|webkit_linkify|safe }}</span>{% if status.results_file %}
+ <span class="status-results">[{{ status.key.id|results_link|safe }}]</span>{% endif %}
+ <span class="status-date">{{ status.date|timesince }} ago</span>
+ </li>{% endfor %}
+ </ul>
+</div>{% endfor %}
+</html>
diff --git a/Tools/QueueStatusServer/templates/queuestatus.html b/Tools/QueueStatusServer/templates/queuestatus.html
new file mode 100644
index 0000000..1b98952
--- /dev/null
+++ b/Tools/QueueStatusServer/templates/queuestatus.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>{{ display_queue_name }} Status</title>
+<link type="text/css" rel="stylesheet" href="/stylesheets/dashboard.css" />
+</head>
+<body>
+<h1>{{ display_queue_name }} Status</h1>
+
+<h3>Recent Status</h3>
+
+<div class="status-details">
+ <ul>
+ {% for status_group in status_groups %}
+ {% with status_group.0 as title_status %}
+ <li class="status-group">
+ {% if title_status.active_bug_id %}
+ <span class="status-bug">
+ Patch {{ title_status.active_patch_id|force_escape|webkit_attachment_id|safe }} from bug
+ {{ title_status.active_bug_id|force_escape|webkit_bug_id|safe }}:
+ </span>
+ {% endif %}
+
+ {% ifequal status_group|length 1 %}
+ {% with title_status as status %}
+ {% include 'includes/singlequeuestatus.html' %}
+ {% endwith %}
+ {% else %}
+ <ul>
+ {% for status in status_group %}
+ <li class="status">
+ {% include 'includes/singlequeuestatus.html' %}
+ </li>
+ {% endfor %}
+ </ul>
+ {% endifequal %}
+ </li>
+ {% endwith %}
+ {% endfor %}
+ </ul>
+</div>
+
+<h3>Patches in queue</h3>
+<table>
+ <tr><th>Position</th><th>Patch</th><th>Lock Acquired</th></tr>
+ {% for row in work_item_rows %}
+ <tr>
+ <td>#{{ forloop.counter }}</td>
+ <td>
+ {{ row.attachment_id|force_escape|webkit_attachment_id|safe }}
+ </td>
+ <td>
+ {% if row.lock_time %}
+ {{ row.lock_time|timesince }} ago
+ {% endif %}
+ </td>
+ </tr>
+ {% endfor %}
+</table>
+
+</body>
+</html>
diff --git a/Tools/QueueStatusServer/templates/recentstatus.html b/Tools/QueueStatusServer/templates/recentstatus.html
new file mode 100644
index 0000000..808d8d7
--- /dev/null
+++ b/Tools/QueueStatusServer/templates/recentstatus.html
@@ -0,0 +1,54 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>WebKit Queue Status</title>
+<link type="text/css" rel="stylesheet" href="/stylesheets/dashboard.css" />
+<style>
+.queue_bubble {
+ border: 1px solid black;
+ margin-bottom: 10px;
+ border-radius: 10px;
+ padding: 5px;
+}
+.queue_name {
+ float:left;
+}
+.last_heard_from {
+ float: right;
+}
+.status_text {
+ clear: both;
+}
+.alive {
+ background-color: #8FDF5F;
+}
+.behind {
+ background-color: #FFFC6C;
+}
+.dead {
+ background-color: #E98080;
+}
+</style>
+</head>
+<body>
+<h1>WebKit Queue Status</h1>
+{% for queue in queues %}
+<div class="queue_bubble {{ queue.status_class }}">
+ <div class="queue_name">
+ <a href="/queue-status/{{ queue.name }}">
+ {{ queue.display_name }}
+ </a>
+ </div>
+ {% if queue.last_heard_from %}
+ <div class="last_heard_from">{{ queue.last_heard_from|timesince }} ago</div>
+ {% endif %}
+ <div class="status_text">
+ Status: {{ queue.status_text|force_escape|urlize|webkit_linkify|safe }}
+ </div>
+ <div>
+ {{ queue.pending_items_count }} pending
+ </div>
+</div>
+{% endfor %}
+</body>
+</html>
diff --git a/Tools/QueueStatusServer/templates/releasepatch.html b/Tools/QueueStatusServer/templates/releasepatch.html
new file mode 100644
index 0000000..cbd6d6f
--- /dev/null
+++ b/Tools/QueueStatusServer/templates/releasepatch.html
@@ -0,0 +1,3 @@
+<form name="release_patch" enctype="multipart/form-data" method="post">
+Patch to release: <input name="attachment_id"> from <input name="queue_name"><input type="submit" value="Release locks and remove from queue"></div>
+</form>
diff --git a/Tools/QueueStatusServer/templates/statusbubble.html b/Tools/QueueStatusServer/templates/statusbubble.html
new file mode 100644
index 0000000..5a723e7
--- /dev/null
+++ b/Tools/QueueStatusServer/templates/statusbubble.html
@@ -0,0 +1,77 @@
+<!DOCTYPE html>
+<html>
+<head>
+<style>
+body {
+ font-family: Verdana, sans-serif;
+ margin: 0px;
+ padding: 0px;
+}
+#bubbleContainer {
+ display: inline-block;
+ white-space: nowrap;
+}
+.status {
+ display: block;
+ float: left;
+ margin: 1px;
+ padding: 1px 2px;
+ -moz-border-radius: 5px;
+ -webkit-border-radius: 5px;
+ border-radius: 5px;
+ border: 1px solid #AAA;
+ background-color: white;
+ font-size: 11px;
+ cursor: pointer;
+}
+.none {
+ cursor: auto;
+}
+.pass {
+ background-color: #8FDF5F;
+ border: 1px solid #4F8530;
+}
+.fail {
+ background-color: #E98080;
+ border: 1px solid #A77272;
+}
+.pending {
+ background-color: #FFFC6C;
+ border: 1px solid #C5C56D;
+}
+.error {
+ background-color: #E0B0FF;
+ border: 1px solid #ACA0B3;
+}
+.queue_position {
+ font-size: 9px;
+}
+</style>
+<script>
+function statusDetail(patch_id) {
+ top.location = "/patch/" + patch_id
+}
+window.addEventListener("message", function(e) {
+ if (e.data == 'containerMetrics') {
+ e.source.postMessage({'width': bubbleContainer.offsetWidth, 'height': bubbleContainer.offsetHeight},
+ e.origin);
+ } else
+ console.log("Unknown postMessage: " + e.data);
+}, false);
+</script>
+</head>
+<body>
+<div id="bubbleContainer">
+ {% for bubble in bubbles %}
+ <div class="status {{ bubble.state }}"{% if bubble.status %}
+ onclick="statusDetail({{ bubble.attachment_id }})"
+ title="{{ bubble.status.date|timesince }} ago"{% endif %}>
+ {{ bubble.name }}
+ {% if bubble.queue_position %}
+ <span class="queue_position">#{{ bubble.queue_position }}</span>
+ {% endif %}
+ </div>
+ {% endfor %}
+</div>
+</body>
+</html>
diff --git a/Tools/QueueStatusServer/templates/submittoews.html b/Tools/QueueStatusServer/templates/submittoews.html
new file mode 100644
index 0000000..fb9d8aa
--- /dev/null
+++ b/Tools/QueueStatusServer/templates/submittoews.html
@@ -0,0 +1,3 @@
+<form name="submit_to_ews" enctype="multipart/form-data" method="post">
+Patch to submit: <input name="attachment_id"><input type="submit" value="Submit for EWS Processing"></div>
+</form>
diff --git a/Tools/QueueStatusServer/templates/updatestatus.html b/Tools/QueueStatusServer/templates/updatestatus.html
new file mode 100644
index 0000000..0f98ba4
--- /dev/null
+++ b/Tools/QueueStatusServer/templates/updatestatus.html
@@ -0,0 +1,21 @@
+<form name="update_status" enctype="multipart/form-data" method="post">
+Update status for a queue: <input name="queue_name">
+ <div>
+ Bot Id:
+ <input name="bot_id">
+ </div>
+ <div>
+ Active Bug Id:
+ <input name="bug_id">
+ </div>
+ <div>
+ Active Patch Id:
+ <input name="patch_id">
+ </div>
+ <div>
+ Status Text:<br>
+ <textarea name="status" rows="3" cols="60"></textarea>
+ </div>
+ <div>Results file: <input type="file" name="results_file"></div>
+ <div><input type="submit" value="Add Status"></div>
+</form>
diff --git a/Tools/QueueStatusServer/templates/updatesvnrevision.html b/Tools/QueueStatusServer/templates/updatesvnrevision.html
new file mode 100644
index 0000000..6ea4e7b
--- /dev/null
+++ b/Tools/QueueStatusServer/templates/updatesvnrevision.html
@@ -0,0 +1,8 @@
+<form name="update_svn_revision" method="post">
+Update an SVN revision: <input name="number">
+ <div>
+ Broken Bot:
+ <input name="broken_bot">
+ </div>
+ <div><input type="submit" value="Update"></div>
+</form>
diff --git a/Tools/QueueStatusServer/templates/updateworkitems.html b/Tools/QueueStatusServer/templates/updateworkitems.html
new file mode 100644
index 0000000..b086fc3
--- /dev/null
+++ b/Tools/QueueStatusServer/templates/updateworkitems.html
@@ -0,0 +1,8 @@
+<form name="update_work_items" enctype="multipart/form-data" method="post">
+Update work items for a queue: <input name="queue_name">
+ <div>
+ Work Items:
+ <input name="work_items">
+ </div>
+ <div><input type="submit" value="Update Work Items"></div>
+</form>
diff --git a/Tools/Scripts/SpacingHeuristics.pm b/Tools/Scripts/SpacingHeuristics.pm
new file mode 100644
index 0000000..7de0172
--- /dev/null
+++ b/Tools/Scripts/SpacingHeuristics.pm
@@ -0,0 +1,101 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Used for helping remove extra blank lines from files when processing.
+# see split-class for an example usage (or other scripts in bugzilla)
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(&resetSpacingHeuristics &isOnlyWhiteSpace &applySpacingHeuristicsAndPrint &setPreviousAllowedLine &setPreviousAllowedLine &printPendingEmptyLines &ignoringLine);
+ %EXPORT_TAGS = ();
+ @EXPORT_OK = ();
+}
+
+our @EXPORT_OK;
+
+my $justFoundEmptyLine = 0;
+my $previousLineWasDisallowed = 0;
+my $previousAllowedLine = "";
+my $pendingEmptyLines = "";
+
+sub resetSpacingHeuristics
+{
+ $justFoundEmptyLine = 0;
+ $previousLineWasDisallowed = 0;
+ $previousAllowedLine = "";
+ $pendingEmptyLines = "";
+}
+
+sub isOnlyWhiteSpace
+{
+ my $line = shift;
+ my $isOnlyWhiteSpace = ($line =~ m/^\s+$/);
+ $pendingEmptyLines .= $line if ($isOnlyWhiteSpace);
+ return $isOnlyWhiteSpace;
+}
+
+sub applySpacingHeuristicsAndPrint
+{
+ my ($out, $line) = @_;
+
+ printPendingEmptyLines($out, $line);
+ $previousLineWasDisallowed = 0;
+ print $out $line;
+}
+
+sub setPreviousAllowedLine
+{
+ my $line = shift;
+ $previousAllowedLine = $line;
+}
+
+sub printPendingEmptyLines
+{
+ my $out = shift;
+ my $line = shift;
+ if ($previousLineWasDisallowed) {
+ if (!($pendingEmptyLines eq "") && !($previousAllowedLine =~ m/{\s*$/) && !($line =~ m/^\s*}/)) {
+ $pendingEmptyLines = "\n";
+ } else {
+ $pendingEmptyLines = "";
+ }
+ }
+ print $out $pendingEmptyLines;
+ $pendingEmptyLines = "";
+}
+
+sub ignoringLine
+{
+ # my $line = shift; # ignoring input argument
+ $previousLineWasDisallowed = 1;
+}
+
+1; \ No newline at end of file
diff --git a/Tools/Scripts/VCSUtils.pm b/Tools/Scripts/VCSUtils.pm
new file mode 100644
index 0000000..faed7ed
--- /dev/null
+++ b/Tools/Scripts/VCSUtils.pm
@@ -0,0 +1,1768 @@
+# Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+# Copyright (C) 2009, 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+# Copyright (C) Research In Motion Limited 2010. 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.
+
+# Module to share code to work with various version control systems.
+package VCSUtils;
+
+use strict;
+use warnings;
+
+use Cwd qw(); # "qw()" prevents warnings about redefining getcwd() with "use POSIX;"
+use English; # for $POSTMATCH, etc.
+use File::Basename;
+use File::Spec;
+use POSIX;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(
+ &callSilently
+ &canonicalizePath
+ &changeLogEmailAddress
+ &changeLogName
+ &chdirReturningRelativePath
+ &decodeGitBinaryPatch
+ &determineSVNRoot
+ &determineVCSRoot
+ &exitStatus
+ &fixChangeLogPatch
+ &gitBranch
+ &gitdiff2svndiff
+ &isGit
+ &isGitBranchBuild
+ &isGitDirectory
+ &isSVN
+ &isSVNDirectory
+ &isSVNVersion16OrNewer
+ &makeFilePathRelative
+ &mergeChangeLogs
+ &normalizePath
+ &parsePatch
+ &pathRelativeToSVNRepositoryRootForPath
+ &prepareParsedPatch
+ &removeEOL
+ &runPatchCommand
+ &scmMoveOrRenameFile
+ &scmToggleExecutableBit
+ &setChangeLogDateAndReviewer
+ &svnRevisionForDirectory
+ &svnStatus
+ &toWindowsLineEndings
+ );
+ %EXPORT_TAGS = ( );
+ @EXPORT_OK = ();
+}
+
+our @EXPORT_OK;
+
+my $gitBranch;
+my $gitRoot;
+my $isGit;
+my $isGitBranchBuild;
+my $isSVN;
+my $svnVersion;
+
+# Project time zone for Cupertino, CA, US
+my $changeLogTimeZone = "PST8PDT";
+
+my $gitDiffStartRegEx = qr#^diff --git (\w/)?(.+) (\w/)?([^\r\n]+)#;
+my $svnDiffStartRegEx = qr#^Index: ([^\r\n]+)#;
+my $svnPropertiesStartRegEx = qr#^Property changes on: ([^\r\n]+)#; # $1 is normally the same as the index path.
+my $svnPropertyStartRegEx = qr#^(Modified|Name|Added|Deleted): ([^\r\n]+)#; # $2 is the name of the property.
+my $svnPropertyValueStartRegEx = qr#^ (\+|-|Merged|Reverse-merged) ([^\r\n]+)#; # $2 is the start of the property's value (which may span multiple lines).
+
+# This method is for portability. Return the system-appropriate exit
+# status of a child process.
+#
+# Args: pass the child error status returned by the last pipe close,
+# for example "$?".
+sub exitStatus($)
+{
+ my ($returnvalue) = @_;
+ if ($^O eq "MSWin32") {
+ return $returnvalue >> 8;
+ }
+ return WEXITSTATUS($returnvalue);
+}
+
+# Call a function while suppressing STDERR, and return the return values
+# as an array.
+sub callSilently($@) {
+ my ($func, @args) = @_;
+
+ # The following pattern was taken from here:
+ # http://www.sdsc.edu/~moreland/courses/IntroPerl/docs/manual/pod/perlfunc/open.html
+ #
+ # Also see this Perl documentation (search for "open OLDERR"):
+ # http://perldoc.perl.org/functions/open.html
+ open(OLDERR, ">&STDERR");
+ close(STDERR);
+ my @returnValue = &$func(@args);
+ open(STDERR, ">&OLDERR");
+ close(OLDERR);
+
+ return @returnValue;
+}
+
+sub toWindowsLineEndings
+{
+ my ($text) = @_;
+ $text =~ s/\n/\r\n/g;
+ return $text;
+}
+
+# Note, this method will not error if the file corresponding to the $source path does not exist.
+sub scmMoveOrRenameFile
+{
+ my ($source, $destination) = @_;
+ return if ! -e $source;
+ if (isSVN()) {
+ system("svn", "move", $source, $destination);
+ } elsif (isGit()) {
+ system("git", "mv", $source, $destination);
+ }
+}
+
+# Note, this method will not error if the file corresponding to the path does not exist.
+sub scmToggleExecutableBit
+{
+ my ($path, $executableBitDelta) = @_;
+ return if ! -e $path;
+ if ($executableBitDelta == 1) {
+ scmAddExecutableBit($path);
+ } elsif ($executableBitDelta == -1) {
+ scmRemoveExecutableBit($path);
+ }
+}
+
+sub scmAddExecutableBit($)
+{
+ my ($path) = @_;
+
+ if (isSVN()) {
+ system("svn", "propset", "svn:executable", "on", $path) == 0 or die "Failed to run 'svn propset svn:executable on $path'.";
+ } elsif (isGit()) {
+ chmod(0755, $path);
+ }
+}
+
+sub scmRemoveExecutableBit($)
+{
+ my ($path) = @_;
+
+ if (isSVN()) {
+ system("svn", "propdel", "svn:executable", $path) == 0 or die "Failed to run 'svn propdel svn:executable $path'.";
+ } elsif (isGit()) {
+ chmod(0664, $path);
+ }
+}
+
+sub isGitDirectory($)
+{
+ my ($dir) = @_;
+ return system("cd $dir && git rev-parse > " . File::Spec->devnull() . " 2>&1") == 0;
+}
+
+sub isGit()
+{
+ return $isGit if defined $isGit;
+
+ $isGit = isGitDirectory(".");
+ return $isGit;
+}
+
+sub gitBranch()
+{
+ unless (defined $gitBranch) {
+ chomp($gitBranch = `git symbolic-ref -q HEAD`);
+ $gitBranch = "" if exitStatus($?);
+ $gitBranch =~ s#^refs/heads/##;
+ $gitBranch = "" if $gitBranch eq "master";
+ }
+
+ return $gitBranch;
+}
+
+sub isGitBranchBuild()
+{
+ my $branch = gitBranch();
+ chomp(my $override = `git config --bool branch.$branch.webKitBranchBuild`);
+ return 1 if $override eq "true";
+ return 0 if $override eq "false";
+
+ unless (defined $isGitBranchBuild) {
+ chomp(my $gitBranchBuild = `git config --bool core.webKitBranchBuild`);
+ $isGitBranchBuild = $gitBranchBuild eq "true";
+ }
+
+ return $isGitBranchBuild;
+}
+
+sub isSVNDirectory($)
+{
+ my ($dir) = @_;
+
+ return -d File::Spec->catdir($dir, ".svn");
+}
+
+sub isSVN()
+{
+ return $isSVN if defined $isSVN;
+
+ $isSVN = isSVNDirectory(".");
+ return $isSVN;
+}
+
+sub svnVersion()
+{
+ return $svnVersion if defined $svnVersion;
+
+ if (!isSVN()) {
+ $svnVersion = 0;
+ } else {
+ chomp($svnVersion = `svn --version --quiet`);
+ }
+ return $svnVersion;
+}
+
+sub isSVNVersion16OrNewer()
+{
+ my $version = svnVersion();
+ return eval "v$version" ge v1.6;
+}
+
+sub chdirReturningRelativePath($)
+{
+ my ($directory) = @_;
+ my $previousDirectory = Cwd::getcwd();
+ chdir $directory;
+ my $newDirectory = Cwd::getcwd();
+ return "." if $newDirectory eq $previousDirectory;
+ return File::Spec->abs2rel($previousDirectory, $newDirectory);
+}
+
+sub determineGitRoot()
+{
+ chomp(my $gitDir = `git rev-parse --git-dir`);
+ return dirname($gitDir);
+}
+
+sub determineSVNRoot()
+{
+ my $last = '';
+ my $path = '.';
+ my $parent = '..';
+ my $repositoryRoot;
+ my $repositoryUUID;
+ while (1) {
+ my $thisRoot;
+ my $thisUUID;
+ # Ignore error messages in case we've run past the root of the checkout.
+ open INFO, "svn info '$path' 2> " . File::Spec->devnull() . " |" or die;
+ while (<INFO>) {
+ if (/^Repository Root: (.+)/) {
+ $thisRoot = $1;
+ }
+ if (/^Repository UUID: (.+)/) {
+ $thisUUID = $1;
+ }
+ if ($thisRoot && $thisUUID) {
+ local $/ = undef;
+ <INFO>; # Consume the rest of the input.
+ }
+ }
+ close INFO;
+
+ # It's possible (e.g. for developers of some ports) to have a WebKit
+ # checkout in a subdirectory of another checkout. So abort if the
+ # repository root or the repository UUID suddenly changes.
+ last if !$thisUUID;
+ $repositoryUUID = $thisUUID if !$repositoryUUID;
+ last if $thisUUID ne $repositoryUUID;
+
+ last if !$thisRoot;
+ $repositoryRoot = $thisRoot if !$repositoryRoot;
+ last if $thisRoot ne $repositoryRoot;
+
+ $last = $path;
+ $path = File::Spec->catdir($parent, $path);
+ }
+
+ return File::Spec->rel2abs($last);
+}
+
+sub determineVCSRoot()
+{
+ if (isGit()) {
+ return determineGitRoot();
+ }
+
+ if (!isSVN()) {
+ # Some users have a workflow where svn-create-patch, svn-apply and
+ # svn-unapply are used outside of multiple svn working directores,
+ # so warn the user and assume Subversion is being used in this case.
+ warn "Unable to determine VCS root; assuming Subversion";
+ $isSVN = 1;
+ }
+
+ return determineSVNRoot();
+}
+
+sub svnRevisionForDirectory($)
+{
+ my ($dir) = @_;
+ my $revision;
+
+ if (isSVNDirectory($dir)) {
+ my $svnInfo = `LC_ALL=C svn info $dir | grep Revision:`;
+ ($revision) = ($svnInfo =~ m/Revision: (\d+).*/g);
+ } elsif (isGitDirectory($dir)) {
+ my $gitLog = `cd $dir && LC_ALL=C git log --grep='git-svn-id: ' -n 1 | grep git-svn-id:`;
+ ($revision) = ($gitLog =~ m/ +git-svn-id: .+@(\d+) /g);
+ }
+ die "Unable to determine current SVN revision in $dir" unless (defined $revision);
+ return $revision;
+}
+
+sub pathRelativeToSVNRepositoryRootForPath($)
+{
+ my ($file) = @_;
+ my $relativePath = File::Spec->abs2rel($file);
+
+ my $svnInfo;
+ if (isSVN()) {
+ $svnInfo = `LC_ALL=C svn info $relativePath`;
+ } elsif (isGit()) {
+ $svnInfo = `LC_ALL=C git svn info $relativePath`;
+ }
+
+ $svnInfo =~ /.*^URL: (.*?)$/m;
+ my $svnURL = $1;
+
+ $svnInfo =~ /.*^Repository Root: (.*?)$/m;
+ my $repositoryRoot = $1;
+
+ $svnURL =~ s/$repositoryRoot\///;
+ return $svnURL;
+}
+
+sub makeFilePathRelative($)
+{
+ my ($path) = @_;
+ return $path unless isGit();
+
+ unless (defined $gitRoot) {
+ chomp($gitRoot = `git rev-parse --show-cdup`);
+ }
+ return $gitRoot . $path;
+}
+
+sub normalizePath($)
+{
+ my ($path) = @_;
+ $path =~ s/\\/\//g;
+ return $path;
+}
+
+sub canonicalizePath($)
+{
+ my ($file) = @_;
+
+ # Remove extra slashes and '.' directories in path
+ $file = File::Spec->canonpath($file);
+
+ # Remove '..' directories in path
+ my @dirs = ();
+ foreach my $dir (File::Spec->splitdir($file)) {
+ if ($dir eq '..' && $#dirs >= 0 && $dirs[$#dirs] ne '..') {
+ pop(@dirs);
+ } else {
+ push(@dirs, $dir);
+ }
+ }
+ return ($#dirs >= 0) ? File::Spec->catdir(@dirs) : ".";
+}
+
+sub removeEOL($)
+{
+ my ($line) = @_;
+ return "" unless $line;
+
+ $line =~ s/[\r\n]+$//g;
+ return $line;
+}
+
+sub svnStatus($)
+{
+ my ($fullPath) = @_;
+ my $svnStatus;
+ open SVN, "svn status --non-interactive --non-recursive '$fullPath' |" or die;
+ if (-d $fullPath) {
+ # When running "svn stat" on a directory, we can't assume that only one
+ # status will be returned (since any files with a status below the
+ # directory will be returned), and we can't assume that the directory will
+ # be first (since any files with unknown status will be listed first).
+ my $normalizedFullPath = File::Spec->catdir(File::Spec->splitdir($fullPath));
+ while (<SVN>) {
+ # Input may use a different EOL sequence than $/, so avoid chomp.
+ $_ = removeEOL($_);
+ my $normalizedStatPath = File::Spec->catdir(File::Spec->splitdir(substr($_, 7)));
+ if ($normalizedFullPath eq $normalizedStatPath) {
+ $svnStatus = "$_\n";
+ last;
+ }
+ }
+ # Read the rest of the svn command output to avoid a broken pipe warning.
+ local $/ = undef;
+ <SVN>;
+ }
+ else {
+ # Files will have only one status returned.
+ $svnStatus = removeEOL(<SVN>) . "\n";
+ }
+ close SVN;
+ return $svnStatus;
+}
+
+# Return whether the given file mode is executable in the source control
+# sense. We make this determination based on whether the executable bit
+# is set for "others" rather than the stronger condition that it be set
+# for the user, group, and others. This is sufficient for distinguishing
+# the default behavior in Git and SVN.
+#
+# Args:
+# $fileMode: A number or string representing a file mode in octal notation.
+sub isExecutable($)
+{
+ my $fileMode = shift;
+
+ return $fileMode % 2;
+}
+
+# Parse the next Git diff header from the given file handle, and advance
+# the handle so the last line read is the first line after the header.
+#
+# This subroutine dies if given leading junk.
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the header to parse. This should be a line
+# beginning with "diff --git".
+# $line: the line last read from $fileHandle
+#
+# Returns ($headerHashRef, $lastReadLine):
+# $headerHashRef: a hash reference representing a diff header, as follows--
+# copiedFromPath: the path from which the file was copied or moved if
+# the diff is a copy or move.
+# executableBitDelta: the value 1 or -1 if the executable bit was added or
+# removed, respectively. New and deleted files have
+# this value only if the file is executable, in which
+# case the value is 1 and -1, respectively.
+# indexPath: the path of the target file.
+# isBinary: the value 1 if the diff is for a binary file.
+# isDeletion: the value 1 if the diff is a file deletion.
+# isCopyWithChanges: the value 1 if the file was copied or moved and
+# the target file was changed in some way after being
+# copied or moved (e.g. if its contents or executable
+# bit were changed).
+# isNew: the value 1 if the diff is for a new file.
+# shouldDeleteSource: the value 1 if the file was copied or moved and
+# the source file was deleted -- i.e. if the copy
+# was actually a move.
+# svnConvertedText: the header text with some lines converted to SVN
+# format. Git-specific lines are preserved.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseGitDiffHeader($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ $_ = $line;
+
+ my $indexPath;
+ if (/$gitDiffStartRegEx/) {
+ # The first and second paths can differ in the case of copies
+ # and renames. We use the second file path because it is the
+ # destination path.
+ $indexPath = $4;
+ # Use $POSTMATCH to preserve the end-of-line character.
+ $_ = "Index: $indexPath$POSTMATCH"; # Convert to SVN format.
+ } else {
+ die("Could not parse leading \"diff --git\" line: \"$line\".");
+ }
+
+ my $copiedFromPath;
+ my $foundHeaderEnding;
+ my $isBinary;
+ my $isDeletion;
+ my $isNew;
+ my $newExecutableBit = 0;
+ my $oldExecutableBit = 0;
+ my $shouldDeleteSource = 0;
+ my $similarityIndex = 0;
+ my $svnConvertedText;
+ while (1) {
+ # Temporarily strip off any end-of-line characters to simplify
+ # regex matching below.
+ s/([\n\r]+)$//;
+ my $eol = $1;
+
+ if (/^(deleted file|old) mode (\d+)/) {
+ $oldExecutableBit = (isExecutable($2) ? 1 : 0);
+ $isDeletion = 1 if $1 eq "deleted file";
+ } elsif (/^new( file)? mode (\d+)/) {
+ $newExecutableBit = (isExecutable($2) ? 1 : 0);
+ $isNew = 1 if $1;
+ } elsif (/^similarity index (\d+)%/) {
+ $similarityIndex = $1;
+ } elsif (/^copy from (\S+)/) {
+ $copiedFromPath = $1;
+ } elsif (/^rename from (\S+)/) {
+ # FIXME: Record this as a move rather than as a copy-and-delete.
+ # This will simplify adding rename support to svn-unapply.
+ # Otherwise, the hash for a deletion would have to know
+ # everything about the file being deleted in order to
+ # support undoing itself. Recording as a move will also
+ # permit us to use "svn move" and "git move".
+ $copiedFromPath = $1;
+ $shouldDeleteSource = 1;
+ } elsif (/^--- \S+/) {
+ $_ = "--- $indexPath"; # Convert to SVN format.
+ } elsif (/^\+\+\+ \S+/) {
+ $_ = "+++ $indexPath"; # Convert to SVN format.
+ $foundHeaderEnding = 1;
+ } elsif (/^GIT binary patch$/ ) {
+ $isBinary = 1;
+ $foundHeaderEnding = 1;
+ # The "git diff" command includes a line of the form "Binary files
+ # <path1> and <path2> differ" if the --binary flag is not used.
+ } elsif (/^Binary files / ) {
+ die("Error: the Git diff contains a binary file without the binary data in ".
+ "line: \"$_\". Be sure to use the --binary flag when invoking \"git diff\" ".
+ "with diffs containing binary files.");
+ }
+
+ $svnConvertedText .= "$_$eol"; # Also restore end-of-line characters.
+
+ $_ = <$fileHandle>; # Not defined if end-of-file reached.
+
+ last if (!defined($_) || /$gitDiffStartRegEx/ || $foundHeaderEnding);
+ }
+
+ my $executableBitDelta = $newExecutableBit - $oldExecutableBit;
+
+ my %header;
+
+ $header{copiedFromPath} = $copiedFromPath if $copiedFromPath;
+ $header{executableBitDelta} = $executableBitDelta if $executableBitDelta;
+ $header{indexPath} = $indexPath;
+ $header{isBinary} = $isBinary if $isBinary;
+ $header{isCopyWithChanges} = 1 if ($copiedFromPath && ($similarityIndex != 100 || $executableBitDelta));
+ $header{isDeletion} = $isDeletion if $isDeletion;
+ $header{isNew} = $isNew if $isNew;
+ $header{shouldDeleteSource} = $shouldDeleteSource if $shouldDeleteSource;
+ $header{svnConvertedText} = $svnConvertedText;
+
+ return (\%header, $_);
+}
+
+# Parse the next SVN diff header from the given file handle, and advance
+# the handle so the last line read is the first line after the header.
+#
+# This subroutine dies if given leading junk or if it could not detect
+# the end of the header block.
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the header to parse. This should be a line
+# beginning with "Index:".
+# $line: the line last read from $fileHandle
+#
+# Returns ($headerHashRef, $lastReadLine):
+# $headerHashRef: a hash reference representing a diff header, as follows--
+# copiedFromPath: the path from which the file was copied if the diff
+# is a copy.
+# indexPath: the path of the target file, which is the path found in
+# the "Index:" line.
+# isBinary: the value 1 if the diff is for a binary file.
+# isNew: the value 1 if the diff is for a new file.
+# sourceRevision: the revision number of the source, if it exists. This
+# is the same as the revision number the file was copied
+# from, in the case of a file copy.
+# svnConvertedText: the header text converted to a header with the paths
+# in some lines corrected.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseSvnDiffHeader($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ $_ = $line;
+
+ my $indexPath;
+ if (/$svnDiffStartRegEx/) {
+ $indexPath = $1;
+ } else {
+ die("First line of SVN diff does not begin with \"Index \": \"$_\"");
+ }
+
+ my $copiedFromPath;
+ my $foundHeaderEnding;
+ my $isBinary;
+ my $isNew;
+ my $sourceRevision;
+ my $svnConvertedText;
+ while (1) {
+ # Temporarily strip off any end-of-line characters to simplify
+ # regex matching below.
+ s/([\n\r]+)$//;
+ my $eol = $1;
+
+ # Fix paths on ""---" and "+++" lines to match the leading
+ # index line.
+ if (s/^--- \S+/--- $indexPath/) {
+ # ---
+ if (/^--- .+\(revision (\d+)\)/) {
+ $sourceRevision = $1;
+ $isNew = 1 if !$sourceRevision; # if revision 0.
+ if (/\(from (\S+):(\d+)\)$/) {
+ # The "from" clause is created by svn-create-patch, in
+ # which case there is always also a "revision" clause.
+ $copiedFromPath = $1;
+ die("Revision number \"$2\" in \"from\" clause does not match " .
+ "source revision number \"$sourceRevision\".") if ($2 != $sourceRevision);
+ }
+ }
+ } elsif (s/^\+\+\+ \S+/+++ $indexPath/) {
+ $foundHeaderEnding = 1;
+ } elsif (/^Cannot display: file marked as a binary type.$/) {
+ $isBinary = 1;
+ $foundHeaderEnding = 1;
+ }
+
+ $svnConvertedText .= "$_$eol"; # Also restore end-of-line characters.
+
+ $_ = <$fileHandle>; # Not defined if end-of-file reached.
+
+ last if (!defined($_) || /$svnDiffStartRegEx/ || $foundHeaderEnding);
+ }
+
+ if (!$foundHeaderEnding) {
+ die("Did not find end of header block corresponding to index path \"$indexPath\".");
+ }
+
+ my %header;
+
+ $header{copiedFromPath} = $copiedFromPath if $copiedFromPath;
+ $header{indexPath} = $indexPath;
+ $header{isBinary} = $isBinary if $isBinary;
+ $header{isNew} = $isNew if $isNew;
+ $header{sourceRevision} = $sourceRevision if $sourceRevision;
+ $header{svnConvertedText} = $svnConvertedText;
+
+ return (\%header, $_);
+}
+
+# Parse the next diff header from the given file handle, and advance
+# the handle so the last line read is the first line after the header.
+#
+# This subroutine dies if given leading junk or if it could not detect
+# the end of the header block.
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the header to parse. For SVN-formatted diffs, this
+# is a line beginning with "Index:". For Git, this is a line
+# beginning with "diff --git".
+# $line: the line last read from $fileHandle
+#
+# Returns ($headerHashRef, $lastReadLine):
+# $headerHashRef: a hash reference representing a diff header
+# copiedFromPath: the path from which the file was copied if the diff
+# is a copy.
+# executableBitDelta: the value 1 or -1 if the executable bit was added or
+# removed, respectively. New and deleted files have
+# this value only if the file is executable, in which
+# case the value is 1 and -1, respectively.
+# indexPath: the path of the target file.
+# isBinary: the value 1 if the diff is for a binary file.
+# isGit: the value 1 if the diff is Git-formatted.
+# isSvn: the value 1 if the diff is SVN-formatted.
+# sourceRevision: the revision number of the source, if it exists. This
+# is the same as the revision number the file was copied
+# from, in the case of a file copy.
+# svnConvertedText: the header text with some lines converted to SVN
+# format. Git-specific lines are preserved.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseDiffHeader($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ my $header; # This is a hash ref.
+ my $isGit;
+ my $isSvn;
+ my $lastReadLine;
+
+ if ($line =~ $svnDiffStartRegEx) {
+ $isSvn = 1;
+ ($header, $lastReadLine) = parseSvnDiffHeader($fileHandle, $line);
+ } elsif ($line =~ $gitDiffStartRegEx) {
+ $isGit = 1;
+ ($header, $lastReadLine) = parseGitDiffHeader($fileHandle, $line);
+ } else {
+ die("First line of diff does not begin with \"Index:\" or \"diff --git\": \"$line\"");
+ }
+
+ $header->{isGit} = $isGit if $isGit;
+ $header->{isSvn} = $isSvn if $isSvn;
+
+ return ($header, $lastReadLine);
+}
+
+# FIXME: The %diffHash "object" should not have an svnConvertedText property.
+# Instead, the hash object should store its information in a
+# structured way as properties. This should be done in a way so
+# that, if necessary, the text of an SVN or Git patch can be
+# reconstructed from the information in those hash properties.
+#
+# A %diffHash is a hash representing a source control diff of a single
+# file operation (e.g. a file modification, copy, or delete).
+#
+# These hashes appear, for example, in the parseDiff(), parsePatch(),
+# and prepareParsedPatch() subroutines of this package.
+#
+# The corresponding values are--
+#
+# copiedFromPath: the path from which the file was copied if the diff
+# is a copy.
+# executableBitDelta: the value 1 or -1 if the executable bit was added or
+# removed from the target file, respectively.
+# indexPath: the path of the target file. For SVN-formatted diffs,
+# this is the same as the path in the "Index:" line.
+# isBinary: the value 1 if the diff is for a binary file.
+# isDeletion: the value 1 if the diff is known from the header to be a deletion.
+# isGit: the value 1 if the diff is Git-formatted.
+# isNew: the value 1 if the dif is known from the header to be a new file.
+# isSvn: the value 1 if the diff is SVN-formatted.
+# sourceRevision: the revision number of the source, if it exists. This
+# is the same as the revision number the file was copied
+# from, in the case of a file copy.
+# svnConvertedText: the diff with some lines converted to SVN format.
+# Git-specific lines are preserved.
+
+# Parse one diff from a patch file created by svn-create-patch, and
+# advance the file handle so the last line read is the first line
+# of the next header block.
+#
+# This subroutine preserves any leading junk encountered before the header.
+#
+# Composition of an SVN diff
+#
+# There are three parts to an SVN diff: the header, the property change, and
+# the binary contents, in that order. Either the header or the property change
+# may be ommitted, but not both. If there are binary changes, then you always
+# have all three.
+#
+# Args:
+# $fileHandle: a file handle advanced to the first line of the next
+# header block. Leading junk is okay.
+# $line: the line last read from $fileHandle.
+#
+# Returns ($diffHashRefs, $lastReadLine):
+# $diffHashRefs: A reference to an array of references to %diffHash hashes.
+# See the %diffHash documentation above.
+# $lastReadLine: the line last read from $fileHandle
+sub parseDiff($$)
+{
+ # FIXME: Adjust this method so that it dies if the first line does not
+ # match the start of a diff. This will require a change to
+ # parsePatch() so that parsePatch() skips over leading junk.
+ my ($fileHandle, $line) = @_;
+
+ my $headerStartRegEx = $svnDiffStartRegEx; # SVN-style header for the default
+
+ my $headerHashRef; # Last header found, as returned by parseDiffHeader().
+ my $svnPropertiesHashRef; # Last SVN properties diff found, as returned by parseSvnDiffProperties().
+ my $svnText;
+ while (defined($line)) {
+ if (!$headerHashRef && ($line =~ $gitDiffStartRegEx)) {
+ # Then assume all diffs in the patch are Git-formatted. This
+ # block was made to be enterable at most once since we assume
+ # all diffs in the patch are formatted the same (SVN or Git).
+ $headerStartRegEx = $gitDiffStartRegEx;
+ }
+
+ if ($line =~ $svnPropertiesStartRegEx) {
+ my $propertyPath = $1;
+ if ($svnPropertiesHashRef || $headerHashRef && ($propertyPath ne $headerHashRef->{indexPath})) {
+ # This is the start of the second diff in the while loop, which happens to
+ # be a property diff. If $svnPropertiesHasRef is defined, then this is the
+ # second consecutive property diff, otherwise it's the start of a property
+ # diff for a file that only has property changes.
+ last;
+ }
+ ($svnPropertiesHashRef, $line) = parseSvnDiffProperties($fileHandle, $line);
+ next;
+ }
+ if ($line !~ $headerStartRegEx) {
+ # Then we are in the body of the diff.
+ $svnText .= $line;
+ $line = <$fileHandle>;
+ next;
+ } # Otherwise, we found a diff header.
+
+ if ($svnPropertiesHashRef || $headerHashRef) {
+ # Then either we just processed an SVN property change or this
+ # is the start of the second diff header of this while loop.
+ last;
+ }
+
+ ($headerHashRef, $line) = parseDiffHeader($fileHandle, $line);
+
+ $svnText .= $headerHashRef->{svnConvertedText};
+ }
+
+ my @diffHashRefs;
+
+ if ($headerHashRef->{shouldDeleteSource}) {
+ my %deletionHash;
+ $deletionHash{indexPath} = $headerHashRef->{copiedFromPath};
+ $deletionHash{isDeletion} = 1;
+ push @diffHashRefs, \%deletionHash;
+ }
+ if ($headerHashRef->{copiedFromPath}) {
+ my %copyHash;
+ $copyHash{copiedFromPath} = $headerHashRef->{copiedFromPath};
+ $copyHash{indexPath} = $headerHashRef->{indexPath};
+ $copyHash{sourceRevision} = $headerHashRef->{sourceRevision} if $headerHashRef->{sourceRevision};
+ if ($headerHashRef->{isSvn}) {
+ $copyHash{executableBitDelta} = $svnPropertiesHashRef->{executableBitDelta} if $svnPropertiesHashRef->{executableBitDelta};
+ }
+ push @diffHashRefs, \%copyHash;
+ }
+
+ # Note, the order of evaluation for the following if conditional has been explicitly chosen so that
+ # it evaluates to false when there is no headerHashRef (e.g. a property change diff for a file that
+ # only has property changes).
+ if ($headerHashRef->{isCopyWithChanges} || (%$headerHashRef && !$headerHashRef->{copiedFromPath})) {
+ # Then add the usual file modification.
+ my %diffHash;
+ # FIXME: We should expand this code to support other properties. In the future,
+ # parseSvnDiffProperties may return a hash whose keys are the properties.
+ if ($headerHashRef->{isSvn}) {
+ # SVN records the change to the executable bit in a separate property change diff
+ # that follows the contents of the diff, except for binary diffs. For binary
+ # diffs, the property change diff follows the diff header.
+ $diffHash{executableBitDelta} = $svnPropertiesHashRef->{executableBitDelta} if $svnPropertiesHashRef->{executableBitDelta};
+ } elsif ($headerHashRef->{isGit}) {
+ # Git records the change to the executable bit in the header of a diff.
+ $diffHash{executableBitDelta} = $headerHashRef->{executableBitDelta} if $headerHashRef->{executableBitDelta};
+ }
+ $diffHash{indexPath} = $headerHashRef->{indexPath};
+ $diffHash{isBinary} = $headerHashRef->{isBinary} if $headerHashRef->{isBinary};
+ $diffHash{isDeletion} = $headerHashRef->{isDeletion} if $headerHashRef->{isDeletion};
+ $diffHash{isGit} = $headerHashRef->{isGit} if $headerHashRef->{isGit};
+ $diffHash{isNew} = $headerHashRef->{isNew} if $headerHashRef->{isNew};
+ $diffHash{isSvn} = $headerHashRef->{isSvn} if $headerHashRef->{isSvn};
+ if (!$headerHashRef->{copiedFromPath}) {
+ # If the file was copied, then we have already incorporated the
+ # sourceRevision information into the change.
+ $diffHash{sourceRevision} = $headerHashRef->{sourceRevision} if $headerHashRef->{sourceRevision};
+ }
+ # FIXME: Remove the need for svnConvertedText. See the %diffHash
+ # code comments above for more information.
+ #
+ # Note, we may not always have SVN converted text since we intend
+ # to deprecate it in the future. For example, a property change
+ # diff for a file that only has property changes will not return
+ # any SVN converted text.
+ $diffHash{svnConvertedText} = $svnText if $svnText;
+ push @diffHashRefs, \%diffHash;
+ }
+
+ if (!%$headerHashRef && $svnPropertiesHashRef) {
+ # A property change diff for a file that only has property changes.
+ my %propertyChangeHash;
+ $propertyChangeHash{executableBitDelta} = $svnPropertiesHashRef->{executableBitDelta} if $svnPropertiesHashRef->{executableBitDelta};
+ $propertyChangeHash{indexPath} = $svnPropertiesHashRef->{propertyPath};
+ $propertyChangeHash{isSvn} = 1;
+ push @diffHashRefs, \%propertyChangeHash;
+ }
+
+ return (\@diffHashRefs, $line);
+}
+
+# Parse an SVN property change diff from the given file handle, and advance
+# the handle so the last line read is the first line after this diff.
+#
+# For the case of an SVN binary diff, the binary contents will follow the
+# the property changes.
+#
+# This subroutine dies if the first line does not begin with "Property changes on"
+# or if the separator line that follows this line is missing.
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the footer to parse. This line begins with
+# "Property changes on".
+# $line: the line last read from $fileHandle.
+#
+# Returns ($propertyHashRef, $lastReadLine):
+# $propertyHashRef: a hash reference representing an SVN diff footer.
+# propertyPath: the path of the target file.
+# executableBitDelta: the value 1 or -1 if the executable bit was added or
+# removed from the target file, respectively.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseSvnDiffProperties($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ $_ = $line;
+
+ my %footer;
+ if (/$svnPropertiesStartRegEx/) {
+ $footer{propertyPath} = $1;
+ } else {
+ die("Failed to find start of SVN property change, \"Property changes on \": \"$_\"");
+ }
+
+ # We advance $fileHandle two lines so that the next line that
+ # we process is $svnPropertyStartRegEx in a well-formed footer.
+ # A well-formed footer has the form:
+ # Property changes on: FileA
+ # ___________________________________________________________________
+ # Added: svn:executable
+ # + *
+ $_ = <$fileHandle>; # Not defined if end-of-file reached.
+ my $separator = "_" x 67;
+ if (defined($_) && /^$separator[\r\n]+$/) {
+ $_ = <$fileHandle>;
+ } else {
+ die("Failed to find separator line: \"$_\".");
+ }
+
+ # FIXME: We should expand this to support other SVN properties
+ # (e.g. return a hash of property key-values that represents
+ # all properties).
+ #
+ # Notice, we keep processing until we hit end-of-file or some
+ # line that does not resemble $svnPropertyStartRegEx, such as
+ # the empty line that precedes the start of the binary contents
+ # of a patch, or the start of the next diff (e.g. "Index:").
+ my $propertyHashRef;
+ while (defined($_) && /$svnPropertyStartRegEx/) {
+ ($propertyHashRef, $_) = parseSvnProperty($fileHandle, $_);
+ if ($propertyHashRef->{name} eq "svn:executable") {
+ # Notice, for SVN properties, propertyChangeDelta is always non-zero
+ # because a property can only be added or removed.
+ $footer{executableBitDelta} = $propertyHashRef->{propertyChangeDelta};
+ }
+ }
+
+ return(\%footer, $_);
+}
+
+# Parse the next SVN property from the given file handle, and advance the handle so the last
+# line read is the first line after the property.
+#
+# This subroutine dies if the first line is not a valid start of an SVN property,
+# or the property is missing a value, or the property change type (e.g. "Added")
+# does not correspond to the property value type (e.g. "+").
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the property to parse. This should be a line
+# that matches $svnPropertyStartRegEx.
+# $line: the line last read from $fileHandle.
+#
+# Returns ($propertyHashRef, $lastReadLine):
+# $propertyHashRef: a hash reference representing a SVN property.
+# name: the name of the property.
+# value: the last property value. For instance, suppose the property is "Modified".
+# Then it has both a '-' and '+' property value in that order. Therefore,
+# the value of this key is the value of the '+' property by ordering (since
+# it is the last value).
+# propertyChangeDelta: the value 1 or -1 if the property was added or
+# removed, respectively.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseSvnProperty($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ $_ = $line;
+
+ my $propertyName;
+ my $propertyChangeType;
+ if (/$svnPropertyStartRegEx/) {
+ $propertyChangeType = $1;
+ $propertyName = $2;
+ } else {
+ die("Failed to find SVN property: \"$_\".");
+ }
+
+ $_ = <$fileHandle>; # Not defined if end-of-file reached.
+
+ # The "svn diff" command neither inserts newline characters between property values
+ # nor between successive properties.
+ #
+ # FIXME: We do not support property values that contain tailing newline characters
+ # as it is difficult to disambiguate these trailing newlines from the empty
+ # line that precedes the contents of a binary patch.
+ my $propertyValue;
+ my $propertyValueType;
+ while (defined($_) && /$svnPropertyValueStartRegEx/) {
+ # Note, a '-' property may be followed by a '+' property in the case of a "Modified"
+ # or "Name" property. We only care about the ending value (i.e. the '+' property)
+ # in such circumstances. So, we take the property value for the property to be its
+ # last parsed property value.
+ #
+ # FIXME: We may want to consider strictly enforcing a '-', '+' property ordering or
+ # add error checking to prevent '+', '+', ..., '+' and other invalid combinations.
+ $propertyValueType = $1;
+ ($propertyValue, $_) = parseSvnPropertyValue($fileHandle, $_);
+ }
+
+ if (!$propertyValue) {
+ die("Failed to find the property value for the SVN property \"$propertyName\": \"$_\".");
+ }
+
+ my $propertyChangeDelta;
+ if ($propertyValueType eq "+" || $propertyValueType eq "Merged") {
+ $propertyChangeDelta = 1;
+ } elsif ($propertyValueType eq "-" || $propertyValueType eq "Reverse-merged") {
+ $propertyChangeDelta = -1;
+ } else {
+ die("Not reached.");
+ }
+
+ # We perform a simple validation that an "Added" or "Deleted" property
+ # change type corresponds with a "+" and "-" value type, respectively.
+ my $expectedChangeDelta;
+ if ($propertyChangeType eq "Added") {
+ $expectedChangeDelta = 1;
+ } elsif ($propertyChangeType eq "Deleted") {
+ $expectedChangeDelta = -1;
+ }
+
+ if ($expectedChangeDelta && $propertyChangeDelta != $expectedChangeDelta) {
+ die("The final property value type found \"$propertyValueType\" does not " .
+ "correspond to the property change type found \"$propertyChangeType\".");
+ }
+
+ my %propertyHash;
+ $propertyHash{name} = $propertyName;
+ $propertyHash{propertyChangeDelta} = $propertyChangeDelta;
+ $propertyHash{value} = $propertyValue;
+ return (\%propertyHash, $_);
+}
+
+# Parse the value of an SVN property from the given file handle, and advance
+# the handle so the last line read is the first line after the property value.
+#
+# This subroutine dies if the first line is an invalid SVN property value line
+# (i.e. a line that does not begin with " +" or " -").
+#
+# Args:
+# $fileHandle: advanced so the last line read from the handle is the first
+# line of the property value to parse. This should be a line
+# beginning with " +" or " -".
+# $line: the line last read from $fileHandle.
+#
+# Returns ($propertyValue, $lastReadLine):
+# $propertyValue: the value of the property.
+# $lastReadLine: the line last read from $fileHandle.
+sub parseSvnPropertyValue($$)
+{
+ my ($fileHandle, $line) = @_;
+
+ $_ = $line;
+
+ my $propertyValue;
+ my $eol;
+ if (/$svnPropertyValueStartRegEx/) {
+ $propertyValue = $2; # Does not include the end-of-line character(s).
+ $eol = $POSTMATCH;
+ } else {
+ die("Failed to find property value beginning with '+', '-', 'Merged', or 'Reverse-merged': \"$_\".");
+ }
+
+ while (<$fileHandle>) {
+ if (/^[\r\n]+$/ || /$svnPropertyValueStartRegEx/ || /$svnPropertyStartRegEx/) {
+ # Note, we may encounter an empty line before the contents of a binary patch.
+ # Also, we check for $svnPropertyValueStartRegEx because a '-' property may be
+ # followed by a '+' property in the case of a "Modified" or "Name" property.
+ # We check for $svnPropertyStartRegEx because it indicates the start of the
+ # next property to parse.
+ last;
+ }
+
+ # Temporarily strip off any end-of-line characters. We add the end-of-line characters
+ # from the previously processed line to the start of this line so that the last line
+ # of the property value does not end in end-of-line characters.
+ s/([\n\r]+)$//;
+ $propertyValue .= "$eol$_";
+ $eol = $1;
+ }
+
+ return ($propertyValue, $_);
+}
+
+# Parse a patch file created by svn-create-patch.
+#
+# Args:
+# $fileHandle: A file handle to the patch file that has not yet been
+# read from.
+#
+# Returns:
+# @diffHashRefs: an array of diff hash references.
+# See the %diffHash documentation above.
+sub parsePatch($)
+{
+ my ($fileHandle) = @_;
+
+ my $newDiffHashRefs;
+ my @diffHashRefs; # return value
+
+ my $line = <$fileHandle>;
+
+ while (defined($line)) { # Otherwise, at EOF.
+
+ ($newDiffHashRefs, $line) = parseDiff($fileHandle, $line);
+
+ push @diffHashRefs, @$newDiffHashRefs;
+ }
+
+ return @diffHashRefs;
+}
+
+# Prepare the results of parsePatch() for use in svn-apply and svn-unapply.
+#
+# Args:
+# $shouldForce: Whether to continue processing if an unexpected
+# state occurs.
+# @diffHashRefs: An array of references to %diffHashes.
+# See the %diffHash documentation above.
+#
+# Returns $preparedPatchHashRef:
+# copyDiffHashRefs: A reference to an array of the $diffHashRefs in
+# @diffHashRefs that represent file copies. The original
+# ordering is preserved.
+# nonCopyDiffHashRefs: A reference to an array of the $diffHashRefs in
+# @diffHashRefs that do not represent file copies.
+# The original ordering is preserved.
+# sourceRevisionHash: A reference to a hash of source path to source
+# revision number.
+sub prepareParsedPatch($@)
+{
+ my ($shouldForce, @diffHashRefs) = @_;
+
+ my %copiedFiles;
+
+ # Return values
+ my @copyDiffHashRefs = ();
+ my @nonCopyDiffHashRefs = ();
+ my %sourceRevisionHash = ();
+ for my $diffHashRef (@diffHashRefs) {
+ my $copiedFromPath = $diffHashRef->{copiedFromPath};
+ my $indexPath = $diffHashRef->{indexPath};
+ my $sourceRevision = $diffHashRef->{sourceRevision};
+ my $sourcePath;
+
+ if (defined($copiedFromPath)) {
+ # Then the diff is a copy operation.
+ $sourcePath = $copiedFromPath;
+
+ # FIXME: Consider printing a warning or exiting if
+ # exists($copiedFiles{$indexPath}) is true -- i.e. if
+ # $indexPath appears twice as a copy target.
+ $copiedFiles{$indexPath} = $sourcePath;
+
+ push @copyDiffHashRefs, $diffHashRef;
+ } else {
+ # Then the diff is not a copy operation.
+ $sourcePath = $indexPath;
+
+ push @nonCopyDiffHashRefs, $diffHashRef;
+ }
+
+ if (defined($sourceRevision)) {
+ if (exists($sourceRevisionHash{$sourcePath}) &&
+ ($sourceRevisionHash{$sourcePath} != $sourceRevision)) {
+ if (!$shouldForce) {
+ die "Two revisions of the same file required as a source:\n".
+ " $sourcePath:$sourceRevisionHash{$sourcePath}\n".
+ " $sourcePath:$sourceRevision";
+ }
+ }
+ $sourceRevisionHash{$sourcePath} = $sourceRevision;
+ }
+ }
+
+ my %preparedPatchHash;
+
+ $preparedPatchHash{copyDiffHashRefs} = \@copyDiffHashRefs;
+ $preparedPatchHash{nonCopyDiffHashRefs} = \@nonCopyDiffHashRefs;
+ $preparedPatchHash{sourceRevisionHash} = \%sourceRevisionHash;
+
+ return \%preparedPatchHash;
+}
+
+# Return localtime() for the project's time zone, given an integer time as
+# returned by Perl's time() function.
+sub localTimeInProjectTimeZone($)
+{
+ my $epochTime = shift;
+
+ # Change the time zone temporarily for the localtime() call.
+ my $savedTimeZone = $ENV{'TZ'};
+ $ENV{'TZ'} = $changeLogTimeZone;
+ my @localTime = localtime($epochTime);
+ if (defined $savedTimeZone) {
+ $ENV{'TZ'} = $savedTimeZone;
+ } else {
+ delete $ENV{'TZ'};
+ }
+
+ return @localTime;
+}
+
+# Set the reviewer and date in a ChangeLog patch, and return the new patch.
+#
+# Args:
+# $patch: a ChangeLog patch as a string.
+# $reviewer: the name of the reviewer, or undef if the reviewer should not be set.
+# $epochTime: an integer time as returned by Perl's time() function.
+sub setChangeLogDateAndReviewer($$$)
+{
+ my ($patch, $reviewer, $epochTime) = @_;
+
+ my @localTime = localTimeInProjectTimeZone($epochTime);
+ my $newDate = strftime("%Y-%m-%d", @localTime);
+
+ my $firstChangeLogLineRegEx = qr#(\n\+)\d{4}-[^-]{2}-[^-]{2}( )#;
+ $patch =~ s/$firstChangeLogLineRegEx/$1$newDate$2/;
+
+ if (defined($reviewer)) {
+ # We include a leading plus ("+") in the regular expression to make
+ # the regular expression less likely to match text in the leading junk
+ # for the patch, if the patch has leading junk.
+ $patch =~ s/(\n\+.*)NOBODY \(OOPS!\)/$1$reviewer/;
+ }
+
+ return $patch;
+}
+
+# If possible, returns a ChangeLog patch equivalent to the given one,
+# but with the newest ChangeLog entry inserted at the top of the
+# file -- i.e. no leading context and all lines starting with "+".
+#
+# If given a patch string not representable as a patch with the above
+# properties, it returns the input back unchanged.
+#
+# WARNING: This subroutine can return an inequivalent patch string if
+# both the beginning of the new ChangeLog file matches the beginning
+# of the source ChangeLog, and the source beginning was modified.
+# Otherwise, it is guaranteed to return an equivalent patch string,
+# if it returns.
+#
+# Applying this subroutine to ChangeLog patches allows svn-apply to
+# insert new ChangeLog entries at the top of the ChangeLog file.
+# svn-apply uses patch with --fuzz=3 to do this. We need to apply
+# this subroutine because the diff(1) command is greedy when matching
+# lines. A new ChangeLog entry with the same date and author as the
+# previous will match and cause the diff to have lines of starting
+# context.
+#
+# This subroutine has unit tests in VCSUtils_unittest.pl.
+#
+# Returns $changeLogHashRef:
+# $changeLogHashRef: a hash reference representing a change log patch.
+# patch: a ChangeLog patch equivalent to the given one, but with the
+# newest ChangeLog entry inserted at the top of the file, if possible.
+# hasOverlappingLines: the value 1 if the change log entry overlaps
+# some lines of another change log entry. This can
+# happen when deliberately inserting a new ChangeLog
+# entry earlier in the file above an entry with
+# the same date and author.
+sub fixChangeLogPatch($)
+{
+ my $patch = shift; # $patch will only contain patch fragments for ChangeLog.
+
+ $patch =~ /(\r?\n)/;
+ my $lineEnding = $1;
+ my @lines = split(/$lineEnding/, $patch);
+
+ my $i = 0; # We reuse the same index throughout.
+
+ # Skip to beginning of first chunk.
+ for (; $i < @lines; ++$i) {
+ if (substr($lines[$i], 0, 1) eq "@") {
+ last;
+ }
+ }
+ my $chunkStartIndex = ++$i;
+ my %changeLogHashRef;
+
+ # Optimization: do not process if new lines already begin the chunk.
+ if (substr($lines[$i], 0, 1) eq "+") {
+ $changeLogHashRef{patch} = $patch;
+ return \%changeLogHashRef;
+ }
+
+ # Skip to first line of newly added ChangeLog entry.
+ # For example, +2009-06-03 Eric Seidel <eric@webkit.org>
+ my $dateStartRegEx = '^\+(\d{4}-\d{2}-\d{2})' # leading "+" and date
+ . '\s+(.+)\s+' # name
+ . '<([^<>]+)>$'; # e-mail address
+
+ for (; $i < @lines; ++$i) {
+ my $line = $lines[$i];
+ my $firstChar = substr($line, 0, 1);
+ if ($line =~ /$dateStartRegEx/) {
+ last;
+ } elsif ($firstChar eq " " or $firstChar eq "+") {
+ next;
+ }
+ $changeLogHashRef{patch} = $patch; # Do not change if, for example, "-" or "@" found.
+ return \%changeLogHashRef;
+ }
+ if ($i >= @lines) {
+ $changeLogHashRef{patch} = $patch; # Do not change if date not found.
+ return \%changeLogHashRef;
+ }
+ my $dateStartIndex = $i;
+
+ # Rewrite overlapping lines to lead with " ".
+ my @overlappingLines = (); # These will include a leading "+".
+ for (; $i < @lines; ++$i) {
+ my $line = $lines[$i];
+ if (substr($line, 0, 1) ne "+") {
+ last;
+ }
+ push(@overlappingLines, $line);
+ $lines[$i] = " " . substr($line, 1);
+ }
+
+ # Remove excess ending context, if necessary.
+ my $shouldTrimContext = 1;
+ for (; $i < @lines; ++$i) {
+ my $firstChar = substr($lines[$i], 0, 1);
+ if ($firstChar eq " ") {
+ next;
+ } elsif ($firstChar eq "@") {
+ last;
+ }
+ $shouldTrimContext = 0; # For example, if "+" or "-" encountered.
+ last;
+ }
+ my $deletedLineCount = 0;
+ if ($shouldTrimContext) { # Also occurs if end of file reached.
+ splice(@lines, $i - @overlappingLines, @overlappingLines);
+ $deletedLineCount = @overlappingLines;
+ }
+
+ # Work backwards, shifting overlapping lines towards front
+ # while checking that patch stays equivalent.
+ for ($i = $dateStartIndex - 1; @overlappingLines && $i >= $chunkStartIndex; --$i) {
+ my $line = $lines[$i];
+ if (substr($line, 0, 1) ne " ") {
+ next;
+ }
+ my $text = substr($line, 1);
+ my $newLine = pop(@overlappingLines);
+ if ($text ne substr($newLine, 1)) {
+ $changeLogHashRef{patch} = $patch; # Unexpected difference.
+ return \%changeLogHashRef;
+ }
+ $lines[$i] = "+$text";
+ }
+
+ # Finish moving whatever overlapping lines remain, and update
+ # the initial chunk range.
+ my $chunkRangeRegEx = '^\@\@ -(\d+),(\d+) \+\d+,(\d+) \@\@$'; # e.g. @@ -2,6 +2,18 @@
+ if ($lines[$chunkStartIndex - 1] !~ /$chunkRangeRegEx/) {
+ # FIXME: Handle errors differently from ChangeLog files that
+ # are okay but should not be altered. That way we can find out
+ # if improvements to the script ever become necessary.
+ $changeLogHashRef{patch} = $patch; # Error: unexpected patch string format.
+ return \%changeLogHashRef;
+ }
+ my $skippedFirstLineCount = $1 - 1;
+ my $oldSourceLineCount = $2;
+ my $oldTargetLineCount = $3;
+
+ if (@overlappingLines != $skippedFirstLineCount) {
+ # This can happen, for example, when deliberately inserting
+ # a new ChangeLog entry earlier in the file.
+ $changeLogHashRef{hasOverlappingLines} = 1;
+ $changeLogHashRef{patch} = $patch;
+ return \%changeLogHashRef;
+ }
+ # If @overlappingLines > 0, this is where we make use of the
+ # assumption that the beginning of the source file was not modified.
+ splice(@lines, $chunkStartIndex, 0, @overlappingLines);
+
+ my $sourceLineCount = $oldSourceLineCount + @overlappingLines - $deletedLineCount;
+ my $targetLineCount = $oldTargetLineCount + @overlappingLines - $deletedLineCount;
+ $lines[$chunkStartIndex - 1] = "@@ -1,$sourceLineCount +1,$targetLineCount @@";
+
+ $changeLogHashRef{patch} = join($lineEnding, @lines) . "\n"; # patch(1) expects an extra trailing newline.
+ return \%changeLogHashRef;
+}
+
+# This is a supporting method for runPatchCommand.
+#
+# Arg: the optional $args parameter passed to runPatchCommand (can be undefined).
+#
+# Returns ($patchCommand, $isForcing).
+#
+# This subroutine has unit tests in VCSUtils_unittest.pl.
+sub generatePatchCommand($)
+{
+ my ($passedArgsHashRef) = @_;
+
+ my $argsHashRef = { # Defaults
+ ensureForce => 0,
+ shouldReverse => 0,
+ options => []
+ };
+
+ # Merges hash references. It's okay here if passed hash reference is undefined.
+ @{$argsHashRef}{keys %{$passedArgsHashRef}} = values %{$passedArgsHashRef};
+
+ my $ensureForce = $argsHashRef->{ensureForce};
+ my $shouldReverse = $argsHashRef->{shouldReverse};
+ my $options = $argsHashRef->{options};
+
+ if (! $options) {
+ $options = [];
+ } else {
+ $options = [@{$options}]; # Copy to avoid side effects.
+ }
+
+ my $isForcing = 0;
+ if (grep /^--force$/, @{$options}) {
+ $isForcing = 1;
+ } elsif ($ensureForce) {
+ push @{$options}, "--force";
+ $isForcing = 1;
+ }
+
+ if ($shouldReverse) { # No check: --reverse should never be passed explicitly.
+ push @{$options}, "--reverse";
+ }
+
+ @{$options} = sort(@{$options}); # For easier testing.
+
+ my $patchCommand = join(" ", "patch -p0", @{$options});
+
+ return ($patchCommand, $isForcing);
+}
+
+# Apply the given patch using the patch(1) command.
+#
+# On success, return the resulting exit status. Otherwise, exit with the
+# exit status. If "--force" is passed as an option, however, then never
+# exit and always return the exit status.
+#
+# Args:
+# $patch: a patch string.
+# $repositoryRootPath: an absolute path to the repository root.
+# $pathRelativeToRoot: the path of the file to be patched, relative to the
+# repository root. This should normally be the path
+# found in the patch's "Index:" line. It is passed
+# explicitly rather than reparsed from the patch
+# string for optimization purposes.
+# This is used only for error reporting. The
+# patch command gleans the actual file to patch
+# from the patch string.
+# $args: a reference to a hash of optional arguments. The possible
+# keys are --
+# ensureForce: whether to ensure --force is passed (defaults to 0).
+# shouldReverse: whether to pass --reverse (defaults to 0).
+# options: a reference to an array of options to pass to the
+# patch command. The subroutine passes the -p0 option
+# no matter what. This should not include --reverse.
+#
+# This subroutine has unit tests in VCSUtils_unittest.pl.
+sub runPatchCommand($$$;$)
+{
+ my ($patch, $repositoryRootPath, $pathRelativeToRoot, $args) = @_;
+
+ my ($patchCommand, $isForcing) = generatePatchCommand($args);
+
+ # Temporarily change the working directory since the path found
+ # in the patch's "Index:" line is relative to the repository root
+ # (i.e. the same as $pathRelativeToRoot).
+ my $cwd = Cwd::getcwd();
+ chdir $repositoryRootPath;
+
+ open PATCH, "| $patchCommand" or die "Could not call \"$patchCommand\" for file \"$pathRelativeToRoot\": $!";
+ print PATCH $patch;
+ close PATCH;
+ my $exitStatus = exitStatus($?);
+
+ chdir $cwd;
+
+ if ($exitStatus && !$isForcing) {
+ print "Calling \"$patchCommand\" for file \"$pathRelativeToRoot\" returned " .
+ "status $exitStatus. Pass --force to ignore patch failures.\n";
+ exit $exitStatus;
+ }
+
+ return $exitStatus;
+}
+
+# Merge ChangeLog patches using a three-file approach.
+#
+# This is used by resolve-ChangeLogs when it's operated as a merge driver
+# and when it's used to merge conflicts after a patch is applied or after
+# an svn update.
+#
+# It's also used for traditional rejected patches.
+#
+# Args:
+# $fileMine: The merged version of the file. Also known in git as the
+# other branch's version (%B) or "ours".
+# For traditional patch rejects, this is the *.rej file.
+# $fileOlder: The base version of the file. Also known in git as the
+# ancestor version (%O) or "base".
+# For traditional patch rejects, this is the *.orig file.
+# $fileNewer: The current version of the file. Also known in git as the
+# current version (%A) or "theirs".
+# For traditional patch rejects, this is the original-named
+# file.
+#
+# Returns 1 if merge was successful, else 0.
+sub mergeChangeLogs($$$)
+{
+ my ($fileMine, $fileOlder, $fileNewer) = @_;
+
+ my $traditionalReject = $fileMine =~ /\.rej$/ ? 1 : 0;
+
+ local $/ = undef;
+
+ my $patch;
+ if ($traditionalReject) {
+ open(DIFF, "<", $fileMine) or die $!;
+ $patch = <DIFF>;
+ close(DIFF);
+ rename($fileMine, "$fileMine.save");
+ rename($fileOlder, "$fileOlder.save");
+ } else {
+ open(DIFF, "-|", qw(diff -u -a --binary), $fileOlder, $fileMine) or die $!;
+ $patch = <DIFF>;
+ close(DIFF);
+ }
+
+ unlink("${fileNewer}.orig");
+ unlink("${fileNewer}.rej");
+
+ open(PATCH, "| patch --force --fuzz=3 --binary $fileNewer > " . File::Spec->devnull()) or die $!;
+ if ($traditionalReject) {
+ print PATCH $patch;
+ } else {
+ my $changeLogHash = fixChangeLogPatch($patch);
+ print PATCH $changeLogHash->{patch};
+ }
+ close(PATCH);
+
+ my $result = !exitStatus($?);
+
+ # Refuse to merge the patch if it did not apply cleanly
+ if (-e "${fileNewer}.rej") {
+ unlink("${fileNewer}.rej");
+ if (-f "${fileNewer}.orig") {
+ unlink($fileNewer);
+ rename("${fileNewer}.orig", $fileNewer);
+ }
+ } else {
+ unlink("${fileNewer}.orig");
+ }
+
+ if ($traditionalReject) {
+ rename("$fileMine.save", $fileMine);
+ rename("$fileOlder.save", $fileOlder);
+ }
+
+ return $result;
+}
+
+sub gitConfig($)
+{
+ return unless $isGit;
+
+ my ($config) = @_;
+
+ my $result = `git config $config`;
+ if (($? >> 8)) {
+ $result = `git repo-config $config`;
+ }
+ chomp $result;
+ return $result;
+}
+
+sub changeLogNameError($)
+{
+ my ($message) = @_;
+ print STDERR "$message\nEither:\n";
+ print STDERR " set CHANGE_LOG_NAME in your environment\n";
+ print STDERR " OR pass --name= on the command line\n";
+ print STDERR " OR set REAL_NAME in your environment";
+ print STDERR " OR git users can set 'git config user.name'\n";
+ exit(1);
+}
+
+sub changeLogName()
+{
+ my $name = $ENV{CHANGE_LOG_NAME} || $ENV{REAL_NAME} || gitConfig("user.name") || (split /\s*,\s*/, (getpwuid $<)[6])[0];
+
+ changeLogNameError("Failed to determine ChangeLog name.") unless $name;
+ # getpwuid seems to always succeed on windows, returning the username instead of the full name. This check will catch that case.
+ changeLogNameError("'$name' does not contain a space! ChangeLogs should contain your full name.") unless ($name =~ /\w \w/);
+
+ return $name;
+}
+
+sub changeLogEmailAddressError($)
+{
+ my ($message) = @_;
+ print STDERR "$message\nEither:\n";
+ print STDERR " set CHANGE_LOG_EMAIL_ADDRESS in your environment\n";
+ print STDERR " OR pass --email= on the command line\n";
+ print STDERR " OR set EMAIL_ADDRESS in your environment\n";
+ print STDERR " OR git users can set 'git config user.email'\n";
+ exit(1);
+}
+
+sub changeLogEmailAddress()
+{
+ my $emailAddress = $ENV{CHANGE_LOG_EMAIL_ADDRESS} || $ENV{EMAIL_ADDRESS} || gitConfig("user.email");
+
+ changeLogEmailAddressError("Failed to determine email address for ChangeLog.") unless $emailAddress;
+ changeLogEmailAddressError("Email address '$emailAddress' does not contain '\@' and is likely invalid.") unless ($emailAddress =~ /\@/);
+
+ return $emailAddress;
+}
+
+# http://tools.ietf.org/html/rfc1924
+sub decodeBase85($)
+{
+ my ($encoded) = @_;
+ my %table;
+ my @characters = ('0'..'9', 'A'..'Z', 'a'..'z', '!', '#', '$', '%', '&', '(', ')', '*', '+', '-', ';', '<', '=', '>', '?', '@', '^', '_', '`', '{', '|', '}', '~');
+ for (my $i = 0; $i < 85; $i++) {
+ $table{$characters[$i]} = $i;
+ }
+
+ my $decoded = '';
+ my @encodedChars = $encoded =~ /./g;
+
+ for (my $encodedIter = 0; defined($encodedChars[$encodedIter]);) {
+ my $digit = 0;
+ for (my $i = 0; $i < 5; $i++) {
+ $digit *= 85;
+ my $char = $encodedChars[$encodedIter];
+ $digit += $table{$char};
+ $encodedIter++;
+ }
+
+ for (my $i = 0; $i < 4; $i++) {
+ $decoded .= chr(($digit >> (3 - $i) * 8) & 255);
+ }
+ }
+
+ return $decoded;
+}
+
+sub decodeGitBinaryChunk($$)
+{
+ my ($contents, $fullPath) = @_;
+
+ # Load this module lazily in case the user don't have this module
+ # and won't handle git binary patches.
+ require Compress::Zlib;
+
+ my $encoded = "";
+ my $compressedSize = 0;
+ while ($contents =~ /^([A-Za-z])(.*)$/gm) {
+ my $line = $2;
+ next if $line eq "";
+ die "$fullPath: unexpected size of a line: $&" if length($2) % 5 != 0;
+ my $actualSize = length($2) / 5 * 4;
+ my $encodedExpectedSize = ord($1);
+ my $expectedSize = $encodedExpectedSize <= ord("Z") ? $encodedExpectedSize - ord("A") + 1 : $encodedExpectedSize - ord("a") + 27;
+
+ die "$fullPath: unexpected size of a line: $&" if int(($expectedSize + 3) / 4) * 4 != $actualSize;
+ $compressedSize += $expectedSize;
+ $encoded .= $line;
+ }
+
+ my $compressed = decodeBase85($encoded);
+ $compressed = substr($compressed, 0, $compressedSize);
+ return Compress::Zlib::uncompress($compressed);
+}
+
+sub decodeGitBinaryPatch($$)
+{
+ my ($contents, $fullPath) = @_;
+
+ # Git binary patch has two chunks. One is for the normal patching
+ # and another is for the reverse patching.
+ #
+ # Each chunk a line which starts from either "literal" or "delta",
+ # followed by a number which specifies decoded size of the chunk.
+ # The "delta" type chunks aren't supported by this function yet.
+ #
+ # Then, content of the chunk comes. To decode the content, we
+ # need decode it with base85 first, and then zlib.
+ my $gitPatchRegExp = '(literal|delta) ([0-9]+)\n([A-Za-z0-9!#$%&()*+-;<=>?@^_`{|}~\\n]*?)\n\n';
+ if ($contents !~ m"\nGIT binary patch\n$gitPatchRegExp$gitPatchRegExp\Z") {
+ die "$fullPath: unknown git binary patch format"
+ }
+
+ my $binaryChunkType = $1;
+ my $binaryChunkExpectedSize = $2;
+ my $encodedChunk = $3;
+ my $reverseBinaryChunkType = $4;
+ my $reverseBinaryChunkExpectedSize = $5;
+ my $encodedReverseChunk = $6;
+
+ my $binaryChunk = decodeGitBinaryChunk($encodedChunk, $fullPath);
+ my $binaryChunkActualSize = length($binaryChunk);
+ my $reverseBinaryChunk = decodeGitBinaryChunk($encodedReverseChunk, $fullPath);
+ my $reverseBinaryChunkActualSize = length($reverseBinaryChunk);
+
+ die "$fullPath: unexpected size of the first chunk (expected $binaryChunkExpectedSize but was $binaryChunkActualSize" if ($binaryChunkExpectedSize != $binaryChunkActualSize);
+ die "$fullPath: unexpected size of the second chunk (expected $reverseBinaryChunkExpectedSize but was $reverseBinaryChunkActualSize" if ($reverseBinaryChunkExpectedSize != $reverseBinaryChunkActualSize);
+
+ return ($binaryChunkType, $binaryChunk, $reverseBinaryChunkType, $reverseBinaryChunk);
+}
+
+1;
diff --git a/Tools/Scripts/add-include b/Tools/Scripts/add-include
new file mode 100755
index 0000000..d0525eb
--- /dev/null
+++ b/Tools/Scripts/add-include
@@ -0,0 +1,135 @@
+#!/usr/bin/perl -w
+
+# Copyright 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.
+
+# Helper script to add includes to source files.
+
+use strict;
+
+my $headerPattern = '[\"<][A-Za-z][A-Za-z0-9_/]+(\.h)?[\">]'; # " Make Xcode formatter happy.
+
+my $headerToAdd = shift @ARGV or die;
+$headerToAdd =~ /^([A-Za-z][A-Za-z0-9]+)\.h$/ or die "Header to add must be a .h file: $headerToAdd.\n";
+
+sub includesParagraph;
+
+FILE: for my $filename (@ARGV) {
+ unless ($filename =~ /(\w+)\.cpp$/) { print STDERR "Command line args must be .cpp files: $filename.\n"; next FILE; }
+
+ my $base = $1;
+
+ my $sawConfig = 0;
+ my $sawSelfInclude = 0;
+
+ my $pastIncludes = 0;
+ my %includes;
+
+ my $beforeIncludes = "";
+ my $afterIncludes = "";
+
+ my $currentCondition = "";
+
+ my $entireFileCondition = "";
+
+ unless (open INPUT, "<", $filename) { print STDERR "File does not exist: $filename\n"; next FILE; }
+ while (my $line = <INPUT>) {
+ if ($line =~ /^\s*#(include|import)\s*($headerPattern)\s*\n/) {
+ my $include = $2;
+ if ($pastIncludes) { print STDERR "Saw more includes after include section in $filename, line $.\n"; next FILE; }
+ if ($include eq "\"config.h\"") {
+ $sawConfig = 1;
+ } else {
+ unless ($sawConfig) { print STDERR "First include must be config.h in $filename, line $.\n"; next FILE; }
+ if ($include eq "\"$base.h\"") {
+ $sawSelfInclude = 1;
+ } else {
+ unless ($sawSelfInclude) { print STDERR "Second include must be $base.h in $filename, line $.\n"; next FILE; }
+ $includes{$currentCondition}{$include} = 1;
+ }
+ }
+ } else {
+ if ($sawConfig && !$pastIncludes) {
+ if ($line =~ /^\s*#\s*if\s+(.+?)\s*$/) {
+ my $condition = $1;
+ if (!$sawSelfInclude) {
+ $entireFileCondition = $1;
+ next;
+ }
+ unless ($currentCondition eq "") { print STDERR "Nested #if in include section in $filename, line $.\n"; next FILE; }
+ $currentCondition = $condition;
+ next;
+ }
+ if ($line =~ /^\s*#\s*endif\s*$/) {
+ unless ($currentCondition ne "") { print STDERR "Extra #endif in include section in $filename, line $.\n"; next FILE; }
+ $currentCondition = "";
+ next;
+ }
+ }
+ if (!$sawConfig) {
+ $beforeIncludes .= $line;
+ } else {
+ $pastIncludes = 1 if $line !~ /^\s*$/;
+ if ($pastIncludes) {
+ unless ($currentCondition eq "") { print STDERR "Unterminated #if in include section in $filename, line $.\n"; next FILE; }
+ $afterIncludes .= $line;
+ }
+ }
+ }
+ }
+ close INPUT or die;
+
+ $includes{""}{"\"$headerToAdd\""} = 1;
+
+ $beforeIncludes =~ s/\n+$//;
+ $afterIncludes =~ s/^\n+//;
+
+ my $contents = $beforeIncludes;
+ $contents .= "\n\n#include \"config.h\"\n";
+ $contents .= "\n#if $entireFileCondition\n" if $entireFileCondition ne "";
+ $contents .= "#include \"$base.h\"\n\n";
+ for my $condition (sort keys %includes) {
+ $contents .= "#if $condition\n" unless $condition eq "";
+ $contents .= includesParagraph($includes{$condition});
+ $contents .= "#endif\n" unless $condition eq "";
+ $contents .= "\n";
+ }
+ $contents .= $afterIncludes;
+
+ unless (open OUTPUT, ">", $filename) { print STDERR "Could not open file for writing: $filename\n"; next FILE; };
+ print OUTPUT $contents;
+ close OUTPUT or die;
+}
+
+sub includesParagraph()
+{
+ my ($includes) = @_;
+
+ my $paragraph = "";
+
+ for my $include (sort keys %{$includes}) {
+ $paragraph .= "#include $include\n";
+ }
+
+ return $paragraph;
+}
diff --git a/Tools/Scripts/bisect-builds b/Tools/Scripts/bisect-builds
new file mode 100755
index 0000000..063b61e
--- /dev/null
+++ b/Tools/Scripts/bisect-builds
@@ -0,0 +1,432 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# This script attempts to find the point at which a regression (or progression)
+# of behavior occurred by searching WebKit nightly builds.
+
+# To override the location where the nightly builds are downloaded or the path
+# to the Safari web browser, create a ~/.bisect-buildsrc file with one or more of
+# the following lines (use "~/" to specify a path from your home directory):
+#
+# $branch = "branch-name";
+# $nightlyDownloadDirectory = "~/path/to/nightly/downloads";
+# $safariPath = "/path/to/Safari.app";
+
+use strict;
+
+use File::Basename;
+use File::Path;
+use File::Spec;
+use File::Temp qw(tempfile);
+use Getopt::Long;
+use Time::HiRes qw(usleep);
+
+sub createTempFile($);
+sub downloadNightly($$$);
+sub findMacOSXVersion();
+sub findNearestNightlyIndex(\@$$);
+sub findSafariVersion($);
+sub loadSettings();
+sub makeNightlyList($$$$);
+sub max($$) { return $_[0] > $_[1] ? $_[0] : $_[1]; }
+sub mountAndRunNightly($$$$);
+sub parseRevisions($$;$);
+sub printStatus($$$);
+sub promptForTest($);
+
+loadSettings();
+
+my %validBranches = map { $_ => 1 } qw(feature-branch trunk);
+my $branch = $Settings::branch;
+my $nightlyDownloadDirectory = $Settings::nightlyDownloadDirectory;
+my $safariPath = $Settings::safariPath;
+
+my @nightlies;
+
+my $isProgression;
+my $localOnly;
+my @revisions;
+my $sanityCheck;
+my $showHelp;
+my $testURL;
+
+# Fix up -r switches in @ARGV
+@ARGV = map { /^(-r)(.+)$/ ? ($1, $2) : $_ } @ARGV;
+
+my $result = GetOptions(
+ "b|branch=s" => \$branch,
+ "d|download-directory=s" => \$nightlyDownloadDirectory,
+ "h|help" => \$showHelp,
+ "l|local!" => \$localOnly,
+ "p|progression!" => \$isProgression,
+ "r|revisions=s" => \&parseRevisions,
+ "safari-path=s" => \$safariPath,
+ "s|sanity-check!" => \$sanityCheck,
+);
+$testURL = shift @ARGV;
+
+$branch = "feature-branch" if $branch eq "feature";
+if (!exists $validBranches{$branch}) {
+ print STDERR "ERROR: Invalid branch '$branch'\n";
+ $showHelp = 1;
+}
+
+if (!$result || $showHelp || scalar(@ARGV) > 0) {
+ print STDERR "Search WebKit nightly builds for changes in behavior.\n";
+ print STDERR "Usage: " . basename($0) . " [options] [url]\n";
+ print STDERR <<END;
+ [-b|--branch name] name of the nightly build branch (default: trunk)
+ [-d|--download-directory dir] nightly build download directory (default: ~/Library/Caches/WebKit-Nightlies)
+ [-h|--help] show this help message
+ [-l|--local] only use local (already downloaded) nightlies
+ [-p|--progression] searching for a progression, not a regression
+ [-r|--revision M[:N]] specify starting (and optional ending) revisions to search
+ [--safari-path path] path to Safari application bundle (default: /Applications/Safari.app)
+ [-s|--sanity-check] verify both starting and ending revisions before bisecting
+END
+ exit 1;
+}
+
+my $nightlyWebSite = "http://nightly.webkit.org";
+my $nightlyBuildsURLBase = $nightlyWebSite . File::Spec->catdir("/builds", $branch, "mac");
+my $nightlyFilesURLBase = $nightlyWebSite . File::Spec->catdir("/files", $branch, "mac");
+
+$nightlyDownloadDirectory = glob($nightlyDownloadDirectory) if $nightlyDownloadDirectory =~ /^~/;
+$safariPath = glob($safariPath) if $safariPath =~ /^~/;
+$safariPath = File::Spec->catdir($safariPath, "Contents/MacOS/Safari") if $safariPath =~ m#\.app/*#;
+
+$nightlyDownloadDirectory = File::Spec->catdir($nightlyDownloadDirectory, $branch);
+if (! -d $nightlyDownloadDirectory) {
+ mkpath($nightlyDownloadDirectory, 0, 0755) || die "Could not create $nightlyDownloadDirectory: $!";
+}
+
+@nightlies = makeNightlyList($localOnly, $nightlyDownloadDirectory, findMacOSXVersion(), findSafariVersion($safariPath));
+
+my $startIndex = $revisions[0] ? findNearestNightlyIndex(@nightlies, $revisions[0], 'ceil') : 0;
+my $endIndex = $revisions[1] ? findNearestNightlyIndex(@nightlies, $revisions[1], 'floor') : $#nightlies;
+
+my $tempFile = createTempFile($testURL);
+
+if ($sanityCheck) {
+ my $didReproduceBug;
+
+ do {
+ printf "\nChecking starting revision r%s...\n",
+ $nightlies[$startIndex]->{rev};
+ downloadNightly($nightlies[$startIndex]->{file}, $nightlyFilesURLBase, $nightlyDownloadDirectory);
+ mountAndRunNightly($nightlies[$startIndex]->{file}, $nightlyDownloadDirectory, $safariPath, $tempFile);
+ $didReproduceBug = promptForTest($nightlies[$startIndex]->{rev});
+ $startIndex-- if $didReproduceBug < 0;
+ } while ($didReproduceBug < 0);
+ die "ERROR: Bug reproduced in starting revision! Do you need to test an earlier revision or for a progression?"
+ if $didReproduceBug && !$isProgression;
+ die "ERROR: Bug not reproduced in starting revision! Do you need to test an earlier revision or for a regression?"
+ if !$didReproduceBug && $isProgression;
+
+ do {
+ printf "\nChecking ending revision r%s...\n",
+ $nightlies[$endIndex]->{rev};
+ downloadNightly($nightlies[$endIndex]->{file}, $nightlyFilesURLBase, $nightlyDownloadDirectory);
+ mountAndRunNightly($nightlies[$endIndex]->{file}, $nightlyDownloadDirectory, $safariPath, $tempFile);
+ $didReproduceBug = promptForTest($nightlies[$endIndex]->{rev});
+ $endIndex++ if $didReproduceBug < 0;
+ } while ($didReproduceBug < 0);
+ die "ERROR: Bug NOT reproduced in ending revision! Do you need to test a later revision or for a progression?"
+ if !$didReproduceBug && !$isProgression;
+ die "ERROR: Bug reproduced in ending revision! Do you need to test a later revision or for a regression?"
+ if $didReproduceBug && $isProgression;
+}
+
+printStatus($nightlies[$startIndex]->{rev}, $nightlies[$endIndex]->{rev}, $isProgression);
+
+my %brokenRevisions = ();
+while (abs($endIndex - $startIndex) > 1) {
+ my $index = $startIndex + int(($endIndex - $startIndex) / 2);
+
+ my $didReproduceBug;
+ do {
+ if (exists $nightlies[$index]) {
+ my $buildsLeft = max(max(0, $endIndex - $index - 1), max(0, $index - $startIndex - 1));
+ my $plural = $buildsLeft == 1 ? "" : "s";
+ printf "\nChecking revision r%s (%d build%s left to test after this)...\n", $nightlies[$index]->{rev}, $buildsLeft, $plural;
+ downloadNightly($nightlies[$index]->{file}, $nightlyFilesURLBase, $nightlyDownloadDirectory);
+ mountAndRunNightly($nightlies[$index]->{file}, $nightlyDownloadDirectory, $safariPath, $tempFile);
+ $didReproduceBug = promptForTest($nightlies[$index]->{rev});
+ }
+ if ($didReproduceBug < 0) {
+ $brokenRevisions{$nightlies[$index]->{rev}} = $nightlies[$index]->{file};
+ delete $nightlies[$index];
+ $endIndex--;
+ $index = $startIndex + int(($endIndex - $startIndex) / 2);
+ }
+ } while ($didReproduceBug < 0);
+
+ if ($didReproduceBug && !$isProgression || !$didReproduceBug && $isProgression) {
+ $endIndex = $index;
+ } else {
+ $startIndex = $index;
+ }
+
+ print "\nBroken revisions skipped: r" . join(", r", keys %brokenRevisions) . "\n"
+ if scalar keys %brokenRevisions > 0;
+ printStatus($nightlies[$startIndex]->{rev}, $nightlies[$endIndex]->{rev}, $isProgression);
+}
+
+unlink $tempFile if $tempFile;
+
+exit 0;
+
+sub createTempFile($)
+{
+ my ($url) = @_;
+
+ return undef if !$url;
+
+ my ($fh, $tempFile) = tempfile(
+ basename($0) . "-XXXXXXXX",
+ DIR => File::Spec->tmpdir(),
+ SUFFIX => ".html",
+ UNLINK => 0,
+ );
+ print $fh "<meta http-equiv=\"refresh\" content=\"0; $url\">\n";
+ close($fh);
+
+ return $tempFile;
+}
+
+sub downloadNightly($$$)
+{
+ my ($filename, $urlBase, $directory) = @_;
+ my $path = File::Spec->catfile($directory, $filename);
+ if (! -f $path) {
+ print "Downloading $filename to $directory...\n";
+ `curl -# -o '$path' '$urlBase/$filename'`;
+ }
+}
+
+sub findMacOSXVersion()
+{
+ my $version;
+ open(SW_VERS, "-|", "/usr/bin/sw_vers") || die;
+ while (<SW_VERS>) {
+ $version = $1 if /^ProductVersion:\s+([^\s]+)/;
+ }
+ close(SW_VERS);
+ return $version;
+}
+
+sub findNearestNightlyIndex(\@$$)
+{
+ my ($nightlies, $revision, $round) = @_;
+
+ my $lowIndex = 0;
+ my $highIndex = $#{$nightlies};
+
+ return $highIndex if uc($revision) eq 'HEAD' || $revision >= $nightlies->[$highIndex]->{rev};
+ return $lowIndex if $revision <= $nightlies->[$lowIndex]->{rev};
+
+ while (abs($highIndex - $lowIndex) > 1) {
+ my $index = $lowIndex + int(($highIndex - $lowIndex) / 2);
+ if ($revision < $nightlies->[$index]->{rev}) {
+ $highIndex = $index;
+ } elsif ($revision > $nightlies->[$index]->{rev}) {
+ $lowIndex = $index;
+ } else {
+ return $index;
+ }
+ }
+
+ return ($round eq "floor") ? $lowIndex : $highIndex;
+}
+
+sub findSafariVersion($)
+{
+ my ($path) = @_;
+ my $versionPlist = File::Spec->catdir(dirname(dirname($path)), "version.plist");
+ my $version;
+ open(PLIST, "< $versionPlist") || die;
+ while (<PLIST>) {
+ if (m#^\s*<key>CFBundleShortVersionString</key>#) {
+ $version = <PLIST>;
+ $version =~ s#^\s*<string>([0-9.]+)[^<]*</string>\s*[\r\n]*#$1#;
+ }
+ }
+ close(PLIST);
+ return $version;
+}
+
+sub loadSettings()
+{
+ package Settings;
+
+ our $branch = "trunk";
+ our $nightlyDownloadDirectory = File::Spec->catdir($ENV{HOME}, "Library/Caches/WebKit-Nightlies");
+ our $safariPath = "/Applications/Safari.app";
+
+ my $rcfile = File::Spec->catdir($ENV{HOME}, ".bisect-buildsrc");
+ return if !-f $rcfile;
+
+ my $result = do $rcfile;
+ die "Could not parse $rcfile: $@" if $@;
+}
+
+sub makeNightlyList($$$$)
+{
+ my ($useLocalFiles, $localDirectory, $macOSXVersion, $safariVersion) = @_;
+ my @files;
+
+ if ($useLocalFiles) {
+ opendir(DIR, $localDirectory) || die "$!";
+ foreach my $file (readdir(DIR)) {
+ if ($file =~ /^WebKit-SVN-r([0-9]+)\.dmg$/) {
+ push(@files, +{ rev => $1, file => $file });
+ }
+ }
+ closedir(DIR);
+ } else {
+ open(NIGHTLIES, "curl -s $nightlyBuildsURLBase/all |") || die;
+
+ while (my $line = <NIGHTLIES>) {
+ chomp $line;
+ my ($revision, $timestamp, $url) = split(/,/, $line);
+ my $nightly = basename($url);
+ push(@files, +{ rev => $revision, file => $nightly });
+ }
+ close(NIGHTLIES);
+ }
+
+ if (eval "v$macOSXVersion" ge v10.5) {
+ if ($safariVersion eq "4 Public Beta") {
+ @files = grep { $_->{rev} >= 39682 } @files;
+ } elsif (eval "v$safariVersion" ge v3.2) {
+ @files = grep { $_->{rev} >= 37348 } @files;
+ } elsif (eval "v$safariVersion" ge v3.1) {
+ @files = grep { $_->{rev} >= 29711 } @files;
+ } elsif (eval "v$safariVersion" ge v3.0) {
+ @files = grep { $_->{rev} >= 25124 } @files;
+ } elsif (eval "v$safariVersion" ge v2.0) {
+ @files = grep { $_->{rev} >= 19594 } @files;
+ } else {
+ die "Requires Safari 2.0 or newer";
+ }
+ } elsif (eval "v$macOSXVersion" ge v10.4) {
+ if ($safariVersion eq "4 Public Beta") {
+ @files = grep { $_->{rev} >= 39682 } @files;
+ } elsif (eval "v$safariVersion" ge v3.2) {
+ @files = grep { $_->{rev} >= 37348 } @files;
+ } elsif (eval "v$safariVersion" ge v3.1) {
+ @files = grep { $_->{rev} >= 29711 } @files;
+ } elsif (eval "v$safariVersion" ge v3.0) {
+ @files = grep { $_->{rev} >= 19992 } @files;
+ } elsif (eval "v$safariVersion" ge v2.0) {
+ @files = grep { $_->{rev} >= 11976 } @files;
+ } else {
+ die "Requires Safari 2.0 or newer";
+ }
+ } else {
+ die "Requires Mac OS X 10.4 (Tiger) or 10.5 (Leopard)";
+ }
+
+ my $nightlycmp = sub { return $a->{rev} <=> $b->{rev}; };
+
+ return sort $nightlycmp @files;
+}
+
+sub mountAndRunNightly($$$$)
+{
+ my ($filename, $directory, $safari, $tempFile) = @_;
+ my $mountPath = "/Volumes/WebKit";
+ my $webkitApp = File::Spec->catfile($mountPath, "WebKit.app");
+ my $diskImage = File::Spec->catfile($directory, $filename);
+ my $devNull = File::Spec->devnull();
+
+ my $i = 0;
+ while (-e $mountPath) {
+ $i++;
+ usleep 100 if $i > 1;
+ `hdiutil detach '$mountPath' 2> $devNull`;
+ die "Could not unmount $diskImage at $mountPath" if $i > 100;
+ }
+ die "Can't mount $diskImage: $mountPath already exists!" if -e $mountPath;
+
+ print "Mounting disk image and running WebKit...\n";
+ `hdiutil attach '$diskImage'`;
+ $i = 0;
+ while (! -e $webkitApp) {
+ usleep 100;
+ $i++;
+ die "Could not mount $diskImage at $mountPath" if $i > 100;
+ }
+
+ my $frameworkPath;
+ if (-d "/Volumes/WebKit/WebKit.app/Contents/Frameworks") {
+ my $osXVersion = join('.', (split(/\./, findMacOSXVersion()))[0..1]);
+ $frameworkPath = "/Volumes/WebKit/WebKit.app/Contents/Frameworks/$osXVersion";
+ } else {
+ $frameworkPath = "/Volumes/WebKit/WebKit.app/Contents/Resources";
+ }
+
+ $tempFile ||= "";
+ `DYLD_FRAMEWORK_PATH=$frameworkPath WEBKIT_UNSET_DYLD_FRAMEWORK_PATH=YES $safari $tempFile`;
+
+ `hdiutil detach '$mountPath' 2> $devNull`;
+}
+
+sub parseRevisions($$;$)
+{
+ my ($optionName, $value, $ignored) = @_;
+
+ if ($value =~ /^r?([0-9]+|HEAD):?$/i) {
+ push(@revisions, $1);
+ die "Too many revision arguments specified" if scalar @revisions > 2;
+ } elsif ($value =~ /^r?([0-9]+):?r?([0-9]+|HEAD)$/i) {
+ $revisions[0] = $1;
+ $revisions[1] = $2;
+ } else {
+ die "Unknown revision '$value': expected 'M' or 'M:N'";
+ }
+}
+
+sub printStatus($$$)
+{
+ my ($startRevision, $endRevision, $isProgression) = @_;
+ printf "\n%s: r%s %s: r%s\n",
+ $isProgression ? "Fails" : "Works", $startRevision,
+ $isProgression ? "Works" : "Fails", $endRevision;
+}
+
+sub promptForTest($)
+{
+ my ($revision) = @_;
+ print "Did the bug reproduce in r$revision (yes/no/broken)? ";
+ my $answer = <STDIN>;
+ return 1 if $answer =~ /^(1|y.*)$/i;
+ return -1 if $answer =~ /^(-1|b.*)$/i; # Broken
+ return 0;
+}
+
diff --git a/Tools/Scripts/build-api-tests b/Tools/Scripts/build-api-tests
new file mode 100755
index 0000000..dd2231c
--- /dev/null
+++ b/Tools/Scripts/build-api-tests
@@ -0,0 +1,70 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+use strict;
+use File::Basename;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+my $showHelp = 0;
+my $clean = 0;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] [options to pass to build system]
+ --help Show this help message
+ --clean Clean up the build directory
+EOF
+
+GetOptions(
+ 'help' => \$showHelp,
+ 'clean' => \$clean,
+);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+checkRequiredSystemConfig();
+setConfiguration();
+chdirWebKit();
+
+# Build
+chdir "Tools/TestWebKitAPI" or die;
+
+my $result;
+if (isAppleMacWebKit()) {
+ $result = buildXCodeProject("TestWebKitAPI", $clean, XcodeOptions(), @ARGV);
+} elsif (isAppleWinWebKit()) {
+ $result = buildVisualStudioProject("win/TestWebKitAPI.sln", $clean);
+} else {
+ die "TestWebKitAPI is not supported on this platform.\n";
+}
+
+exit exitStatus($result);
diff --git a/Tools/Scripts/build-dumprendertree b/Tools/Scripts/build-dumprendertree
new file mode 100755
index 0000000..717f934
--- /dev/null
+++ b/Tools/Scripts/build-dumprendertree
@@ -0,0 +1,80 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+use strict;
+use File::Basename;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+my $showHelp = 0;
+my $clean = 0;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] [options to pass to build system]
+ --help Show this help message
+ --clean Clean up the build directory
+ --gtk Build the GTK+ port
+ --qt Build the Qt port
+ --wx Build the wxWindows port
+ --chromium Build the Chromium port
+EOF
+
+GetOptions(
+ 'help' => \$showHelp,
+ 'clean' => \$clean,
+);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+checkRequiredSystemConfig();
+setConfiguration();
+chdirWebKit();
+
+# Build
+chdir "Tools/DumpRenderTree" or die;
+
+my $result;
+if (isAppleMacWebKit()) {
+ $result = buildXCodeProject("DumpRenderTree", $clean, XcodeOptions(), @ARGV);
+} elsif (isAppleWinWebKit()) {
+ $result = buildVisualStudioProject("DumpRenderTree.sln", $clean);
+} elsif (isQt() || isGtk() || isWx() || isChromium()) {
+ # Qt, Gtk wxWindows, and Chromium build everything in one shot. No need to build anything here.
+ $result = 0;
+} else {
+ die "Building not defined for this platform!\n";
+}
+
+exit exitStatus($result);
diff --git a/Tools/Scripts/build-jsc b/Tools/Scripts/build-jsc
new file mode 100755
index 0000000..0316349
--- /dev/null
+++ b/Tools/Scripts/build-jsc
@@ -0,0 +1,76 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+# 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.
+
+
+use strict;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+my $coverageSupport = 0;
+my $showHelp = 0;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] [options to pass to build system]
+ --help Show this help message
+ --[no-]coverage Toggle code coverage support (default: $coverageSupport)
+EOF
+
+GetOptions(
+ 'coverage!' => \$coverageSupport,
+ 'help' => \$showHelp
+);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+checkRequiredSystemConfig();
+setConfiguration();
+chdirWebKit();
+my @options = XcodeOptions();
+my @coverageSupportOptions = ($coverageSupport) ? XcodeCoverageSupportOptions() : ();
+
+chdir "JavaScriptCore" or die "Can't find JavaScriptCore directory to build from";
+my $result;
+if (isAppleMacWebKit()) {
+ $result = system "sh", "-c", 'xcodebuild -project JavaScriptCore.xcodeproj "$@" | grep -v setenv && exit ${PIPESTATUS[0]}', "xcodebuild", @options, @ARGV, @coverageSupportOptions;
+} elsif (isAppleWinWebKit()) {
+ $result = buildVisualStudioProject("JavaScriptCore.vcproj/JavaScriptCore.sln");
+} elsif (isQt() or isGtk() or isWx()) {
+ # Qt and Gtk build everything in one-shot. No need to build anything here.
+ $result = 0;
+} else {
+ die "Building not defined for this platform!\n";
+}
+exit exitStatus($result);
diff --git a/Tools/Scripts/build-webkit b/Tools/Scripts/build-webkit
new file mode 100755
index 0000000..94b2ea2
--- /dev/null
+++ b/Tools/Scripts/build-webkit
@@ -0,0 +1,589 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+# Copyright (C) 2009 Google Inc. All rights reserved.
+# Copyright (C) 2010 moiji-mobile.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.
+# 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.
+
+# Build script wrapper for the WebKit Open Source Project.
+
+use strict;
+use File::Basename;
+use File::Find;
+use File::Spec;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use webkitperl::features;
+use POSIX;
+
+sub formatBuildTime($);
+sub writeCongrats();
+
+my $originalWorkingDirectory = getcwd();
+chdirWebKit();
+
+my $showHelp = 0;
+my $clean = 0;
+my $minimal = 0;
+my $v8 = 0;
+my $installHeaders;
+my $installLibs;
+my $prefixPath;
+my $makeArgs;
+my $noWebKit2 = 0;
+my $startTime = time();
+
+my (
+ $threeDCanvasSupport,
+ $threeDRenderingSupport,
+ $accelerated2dCanvasSupport,
+ $blobSupport,
+ $channelMessagingSupport,
+ $clientBasedGeolocationSupport,
+ $coverageSupport,
+ $databaseSupport,
+ $datagridSupport,
+ $datalistSupport,
+ $deviceOrientationSupport,
+ $directoryUploadSupport,
+ $domStorageSupport,
+ $eventsourceSupport,
+ $fileSystemSupport,
+ $filtersSupport,
+ $fullscreenAPISupport,
+ $geolocationSupport,
+ $iconDatabaseSupport,
+ $imageResizerSupport,
+ $indexedDatabaseSupport,
+ $inputSpeechSupport,
+ $javaScriptDebuggerSupport,
+ $linkPrefetchSupport,
+ $mathmlSupport,
+ $meterTagSupport,
+ $notificationsSupport,
+ $offlineWebApplicationSupport,
+ $progressTagSupport,
+ $sharedWorkersSupport,
+ $svgSupport,
+ $svgAnimationSupport,
+ $svgAsImageSupport,
+ $svgDOMObjCBindingsSupport,
+ $svgFontsSupport,
+ $svgForeignObjectSupport,
+ $svgUseSupport,
+ $systemMallocSupport,
+ $tiledBackingStoreSupport,
+ $videoSupport,
+ $wcssSupport,
+ $webAudioSupport,
+ $webInspectorSupport,
+ $webSocketsSupport,
+ $webTimingSupport,
+ $wmlSupport,
+ $workersSupport,
+ $xhtmlmpSupport,
+ $xpathSupport,
+ $xsltSupport,
+);
+
+my @features = (
+ { option => "3d-canvas", desc => "Toggle 3D canvas support",
+ define => "ENABLE_3D_CANVAS", default => (isAppleMacWebKit() && !isTiger() && !isLeopard()), value => \$threeDCanvasSupport },
+
+ { option => "3d-rendering", desc => "Toggle 3D rendering support",
+ define => "ENABLE_3D_RENDERING", default => (isAppleMacWebKit() && !isTiger()), value => \$threeDRenderingSupport },
+
+ { option => "accelerated-2d-canvas", desc => "Toggle accelerated 2D canvas support",
+ define => "ENABLE_ACCELERATED_2D_CANVAS", default => 0, value => \$accelerated2dCanvasSupport },
+
+ { option => "blob", desc => "Toggle Blob support",
+ define => "ENABLE_BLOB", default => (isAppleMacWebKit()), value => \$blobSupport },
+
+ { option => "channel-messaging", desc => "Toggle MessageChannel and MessagePort support",
+ define => "ENABLE_CHANNEL_MESSAGING", default => 1, value => \$channelMessagingSupport },
+
+ { option => "client-based-geolocation", desc => "Toggle client-based Geolocation support",
+ define => "ENABLE_CLIENT_BASED_GEOLOCATION", default => isAppleWebKit(), value => \$clientBasedGeolocationSupport },
+
+ { option => "coverage", desc => "Toggle code coverage support",
+ define => "", default => 0, value => \$coverageSupport },
+
+ { option => "database", desc => "Toggle Database Support",
+ define => "ENABLE_DATABASE", default => 1, value => \$databaseSupport },
+
+ { option => "datagrid", desc => "Toggle Datagrid Support",
+ define => "ENABLE_DATAGRID", default => 0, value => \$datagridSupport },
+
+ { option => "datalist", desc => "Toggle HTML5 datalist support",
+ define => "ENABLE_DATALIST", default => 1, value => \$datalistSupport },
+
+ { option => "device-orientation", desc => "Toggle DeviceOrientation support",
+ define => "ENABLE_DEVICE_ORIENTATION", default => 0, value => \$deviceOrientationSupport },
+
+ { option => "directory-upload", desc => "Toogle Directory upload support",
+ define => "ENABLE_DIRECTORY_UPLOAD", default => 0, value => \$directoryUploadSupport },
+
+ { option => "dom-storage", desc => "Toggle DOM Storage Support",
+ define => "ENABLE_DOM_STORAGE", default => 1, value => \$domStorageSupport },
+
+ { option => "eventsource", desc => "Toggle server-sent events support",
+ define => "ENABLE_EVENTSOURCE", default => 1, value => \$eventsourceSupport },
+
+ { option => "file-system", desc => "Toggle FileSystem support",
+ define => "ENABLE_FILE_SYSTEM", default => 0, value => \$fileSystemSupport },
+
+ { option => "filters", desc => "Toggle Filters support",
+ define => "ENABLE_FILTERS", default => (isAppleWebKit() || isGtk() || isQt() || isEfl()), value => \$filtersSupport },
+
+ { option => "fullscreen-api", desc => "Toggle Fullscreen API support",
+ define => "ENABLE_FULLSCREEN_API", default => (isAppleMacWebKit() || isGtk()), value => \$fullscreenAPISupport },
+
+ { option => "geolocation", desc => "Toggle Geolocation support",
+ define => "ENABLE_GEOLOCATION", default => (isAppleWebKit() || isGtk()), value => \$geolocationSupport },
+
+ { option => "icon-database", desc => "Toggle Icon database support",
+ define => "ENABLE_ICONDATABASE", default => 1, value => \$iconDatabaseSupport },
+
+ { option => "image-resizer", desc => "Toggle Image Resizer API support",
+ define => "ENABLE_IMAGE_RESIZER", default => 0, value => \$imageResizerSupport },
+
+ { option => "indexed-database", desc => "Toggle Indexed Database API support",
+ define => "ENABLE_INDEXED_DATABASE", default => 0, value => \$indexedDatabaseSupport },
+
+ { option => "input-speech", desc => "Speech Input API support",
+ define => "ENABLE_INPUT_SPEECH", default => 0, value => \$inputSpeechSupport },
+
+ { option => "inspector", desc => "Toggle Web Inspector support",
+ define => "ENABLE_INSPECTOR", default => 1, value => \$webInspectorSupport },
+
+ { option => "javascript-debugger", desc => "Toggle JavaScript Debugger/Profiler support",
+ define => "ENABLE_JAVASCRIPT_DEBUGGER", default => 1, value => \$javaScriptDebuggerSupport },
+
+ { option => "link-prefetch", desc => "Toggle pre fetching support",
+ define => "ENABLE_LINK_PREFETCH", default => 0, value => \$linkPrefetchSupport },
+
+ { option => "mathml", desc => "Toggle MathML support",
+ define => "ENABLE_MATHML", default => 1, value => \$mathmlSupport },
+
+ { option => "meter-tag", desc => "Meter Tag support",
+ define => "ENABLE_METER_TAG", default => !isGtk() && !isAppleWinWebKit(), value => \$meterTagSupport },
+
+ { option => "notifications", desc => "Toggle Desktop Notifications Support",
+ define => "ENABLE_NOTIFICATIONS", default => 0, value => \$notificationsSupport },
+
+ { option => "offline-web-applications", desc => "Toggle Offline Web Application Support",
+ define => "ENABLE_OFFLINE_WEB_APPLICATIONS", default => 1, value => \$offlineWebApplicationSupport },
+
+ { option => "progress-tag", desc => "Progress Tag support",
+ define => "ENABLE_PROGRESS_TAG", default => 1, value => \$progressTagSupport },
+
+ { option => "system-malloc", desc => "Toggle system allocator instead of TCmalloc",
+ define => "USE_SYSTEM_MALLOC", default => 0, value => \$systemMallocSupport },
+
+ { option => "shared-workers", desc => "Toggle SharedWorkers support",
+ define => "ENABLE_SHARED_WORKERS", default => (isAppleWebKit() || isGtk()), value => \$sharedWorkersSupport },
+
+ { option => "svg", desc => "Toggle SVG support",
+ define => "ENABLE_SVG", default => 1, value => \$svgSupport },
+
+ { option => "svg-animation", desc => "Toggle SVG animation support (implies SVG support)",
+ define => "ENABLE_SVG_ANIMATION", default => 1, value => \$svgAnimationSupport },
+
+ { option => "svg-as-image", desc => "Toggle SVG as Image support (implies SVG support)",
+ define => "ENABLE_SVG_AS_IMAGE", default => 1, value => \$svgAsImageSupport },
+
+ { option => "svg-dom-objc-bindings", desc => "Toggle SVG DOM Objective-C bindings support (implies SVG support)",
+ define => "ENABLE_SVG_DOM_OBJC_BINDINGS", default => isAppleMacWebKit(), value => \$svgDOMObjCBindingsSupport },
+
+ { option => "svg-fonts", desc => "Toggle SVG fonts support (imples SVG support)",
+ define => "ENABLE_SVG_FONTS", default => 1, value => \$svgFontsSupport },
+
+ { option => "svg-foreign-object", desc => "Toggle SVG foreign object support (implies SVG support)",
+ define => "ENABLE_SVG_FOREIGN_OBJECT", default => 1, value => \$svgForeignObjectSupport },
+
+ { option => "svg-use", desc => "Toggle SVG use element support (implies SVG support)",
+ define => "ENABLE_SVG_USE", default => 1, value => \$svgUseSupport },
+
+ { option => "tiled-backing-store", desc => "Toggle Tiled Backing Store support",
+ define => "ENABLE_TILED_BACKING_STORE", default => isQt(), value => \$tiledBackingStoreSupport },
+
+ { option => "video", desc => "Toggle Video support",
+ define => "ENABLE_VIDEO", default => (isAppleWebKit() || isGtk()), value => \$videoSupport },
+
+ { option => "wcss", desc => "Toggle WCSS support",
+ define => "ENABLE_WCSS", default => 0, value => \$wcssSupport },
+
+ { option => "web-audio", desc => "Toggle Web Audio support",
+ define => "ENABLE_WEB_AUDIO", default => 0, value=> \$webAudioSupport },
+
+ { option => "web-sockets", desc => "Toggle Web Sockets support",
+ define => "ENABLE_WEB_SOCKETS", default => 1, value=> \$webSocketsSupport },
+
+ { option => "web-timing", desc => "Toggle Web Timing support",
+ define => "ENABLE_WEB_TIMING", default => 0, value=> \$webTimingSupport },
+
+ { option => "wml", desc => "Toggle WML support",
+ define => "ENABLE_WML", default => 0, value => \$wmlSupport },
+
+ { option => "workers", desc => "Toggle Web Workers support",
+ define => "ENABLE_WORKERS", default => (isAppleWebKit() || isGtk()), value => \$workersSupport },
+
+ { option => "xhtmlmp", desc => "Toggle XHTML-MP support",
+ define => "ENABLE_XHTMLMP", default => 0, value => \$xhtmlmpSupport },
+
+ { option => "xpath", desc => "Toggle XPath support",
+ define => "ENABLE_XPATH", default => 1, value => \$xpathSupport },
+
+ { option => "xslt", desc => "Toggle XSLT support",
+ define => "ENABLE_XSLT", default => 1, value => \$xsltSupport },
+);
+
+# Update defaults from Qt's project file
+if (isQt()) {
+ my %qtDefaults = qtFeatureDefaults();
+ foreach (@features) {
+ $_->{default} = $qtDefaults{$_->{define}} || 0;
+ }
+}
+
+# Additional environment parameters
+push @ARGV, split(/ /, $ENV{'BUILD_WEBKIT_ARGS'}) if ($ENV{'BUILD_WEBKIT_ARGS'});
+
+# Initialize values from defaults
+foreach (@ARGV) {
+ if ($_ eq '--minimal') {
+ $minimal = 1;
+ } elsif ($_ eq '--v8') {
+ $v8 = 1;
+ }
+}
+
+# Initialize values from defaults
+foreach (@features) {
+ ${$_->{value}} = ($_->{default} && !$minimal) || 0;
+}
+
+$svgSupport = $svgSupport || $svgAnimationSupport || $svgAsImageSupport
+ || $svgDOMObjCBindingsSupport || $svgFontsSupport
+ || $svgForeignObjectSupport || $svgUseSupport;
+
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] [options to pass to build system]
+ --help Show this help message
+ --clean Cleanup the build directory
+ --debug Compile in debug mode
+ --wincairo Build using Cairo (rather than CoreGraphics) on Windows
+ --chromium Build the Chromium port on Mac/Win/Linux
+ --gtk Build the GTK+ port
+ --qt Build the Qt port
+ --efl Build the EFL port
+ --inspector-frontend Copy changes to the inspector front-end files to the build directory
+
+ --install-headers=<path> Set installation path for the headers (Qt only)
+ --install-libs=<path> Set installation path for the libraries (Qt only)
+ --v8 Use V8 as JavaScript engine (Qt only)
+
+ --prefix=<path> Set installation prefix to the given path (Gtk/Efl only)
+ --makeargs=<arguments> Optional Makefile flags
+
+ --minimal No optional features, unless explicitly enabled.
+
+EOF
+
+my %options = (
+ 'help' => \$showHelp,
+ 'clean' => \$clean,
+ 'install-headers=s' => \$installHeaders,
+ 'install-libs=s' => \$installLibs,
+ 'prefix=s' => \$prefixPath,
+ 'makeargs=s' => \$makeArgs,
+ 'minimal' => \$minimal,
+ 'v8' => \$v8,
+ 'no-webkit2' => \$noWebKit2,
+);
+
+# Build usage text and options list from features
+foreach (@features) {
+ my $opt = sprintf("%-35s", " --[no-]$_->{option}");
+ $usage .= "$opt $_->{desc} (default: $_->{default})\n";
+ $options{"$_->{option}!"} = $_->{value};
+}
+
+GetOptions(%options);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+checkRequiredSystemConfig();
+setConfiguration();
+
+my $productDir = productDir();
+
+# Remove 0 byte sized files from productDir after slave lost for Qt buildbots.
+File::Find::find(\&unlinkZeroFiles, $productDir) if (isQt() && -e $productDir);
+
+sub unlinkZeroFiles ()
+{
+ my $file = $File::Find::name;
+ if (! -s $file) {
+ unlink $file;
+ print "0 byte sized file removed from build directory: $file\n";
+ }
+}
+
+# Check that all the project directories are there.
+my @projects = ("JavaScriptCore", "WebCore", "WebKit");
+
+my @otherDirs = ("WebKitLibraries");
+for my $dir (@projects, @otherDirs) {
+ if (! -d $dir) {
+ die "Error: No $dir directory found. Please do a fresh checkout.\n";
+ }
+}
+
+my @options = ();
+
+# enable autotool options accordingly
+if (isGtk()) {
+ @options = @ARGV;
+ foreach (@features) {
+ push @options, autotoolsFlag(${$_->{value}}, $_->{option});
+ }
+
+ push @options, "--prefix=" . $prefixPath if defined($prefixPath);
+ push @options, "--makeargs=" . $makeArgs if defined($makeArgs);
+} elsif (isAppleMacWebKit()) {
+ push @options, XcodeOptions();
+
+ sub option($$$)
+ {
+ my ($feature, $isEnabled, $defaultValue) = @_;
+ return "" if $defaultValue == $isEnabled;
+ return $feature . "=" . ($isEnabled ? $feature : " ");
+ }
+
+ foreach (@features) {
+ if ($_->{option} ne "coverage") {
+ my $option = option($_->{define}, ${$_->{value}}, $_->{default});
+ push @options, $option unless $option eq "";
+ }
+ }
+
+ # Apple builds JavaScriptGlue, and only on the Mac.
+ splice @projects, 1, 0, "JavaScriptGlue";
+
+ # ANGLE must come before WebCore
+ splice @projects, 0, 0, "ANGLE";
+
+ # WebKit2 is only supported in SnowLeopard and later at present.
+ push @projects, ("WebKit2", "Tools/MiniBrowser") if osXVersion()->{"minor"} >= 6 and !$noWebKit2;
+
+ # Copy library and header from WebKitLibraries to a findable place in the product directory.
+ my @librariesToCopy = (
+ "libWebKitSystemInterfaceTiger.a",
+ "libWebKitSystemInterfaceLeopard.a",
+ "libWebKitSystemInterfaceSnowLeopard.a",
+ "libWebCoreSQLite3.a",
+ );
+ foreach my $libName (@librariesToCopy) {
+ my $srcLib = "WebKitLibraries/" . $libName;
+ my $lib = "$productDir/" . $libName;
+ if (!-e $lib || -M $lib > -M $srcLib) {
+ print "Updating $lib\n";
+ system "ditto", $srcLib, $lib;
+ system "ranlib", $lib;
+ }
+ }
+
+ # FIXME: This code should be abstracted to not be copy/paste.
+ my $srcHeader = "WebKitLibraries/WebKitSystemInterface.h";
+ my $header = "$productDir/usr/local/include/WebKitSystemInterface.h";
+ if (!-e $header || -M $header > -M $srcHeader) {
+ print "Updating $header\n";
+ system "mkdir", "-p", "$productDir/usr/local/include";
+ system "ditto", $srcHeader, $header;
+ }
+
+ my $srcHeaderDir = "WebKitLibraries/WebCoreSQLite3";
+ my $headerDir = "$productDir/WebCoreSQLite3";
+ if (!-e $headerDir || -M $headerDir > -M $srcHeaderDir) {
+ print "Updating $headerDir\n";
+ system "ditto", $srcHeaderDir, $headerDir;
+ }
+} elsif (isAppleWinWebKit()) {
+ # Copy WebKitSupportLibrary to the correct location in WebKitLibraries so it can be found.
+ # Will fail if WebKitSupportLibrary.zip is not in source root.
+ (system("perl Tools/Scripts/update-webkit-support-libs") == 0) or die;
+} elsif (isQt()) {
+ @options = @ARGV;
+ push @options, "--install-headers=" . $installHeaders if defined($installHeaders);
+ push @options, "--install-libs=" . $installLibs if defined($installLibs);
+ push @options, "--makeargs=" . $makeArgs if defined($makeArgs);
+
+ foreach (@features) {
+ push @options, "DEFINES+=$_->{define}=${$_->{value}}" if ${$_->{value}} != $_->{default};
+ }
+
+ if ($minimal) {
+ push @options, "CONFIG+=minimal";
+ }
+
+ if ($v8) {
+ push @options, "CONFIG+=v8";
+ }
+}
+
+# Force re-link of existing libraries if different than expected
+removeLibraryDependingOnFeature("WebCore", "SVG", $svgSupport);
+
+if (isInspectorFrontend()) {
+ exit exitStatus(copyInspectorFrontendFiles());
+}
+
+if (isWx()) {
+ downloadWafIfNeeded();
+ @options = ();
+ if (defined($makeArgs)) {
+ @options = split(/ /, $makeArgs);
+ }
+ @projects = ();
+ my $result = buildWafProject('.', $clean, @options);
+ exit exitStatus($result) if exitStatus($result);
+}
+
+if (isChromium()) {
+ @options = @ARGV;
+ # Chromium doesn't build by project directories.
+ @projects = ();
+ my $result = buildChromium($clean, @options);
+ exit exitStatus($result) if exitStatus($result);
+}
+
+if (isEfl()) {
+ @options = ();
+ @projects = ();
+ foreach (@features) {
+ my $featureName = $_->{define};
+ if ($featureName) {
+ my $featureEnabled = ${$_->{value}} ? "ON" : "OFF";
+ push @options, "-D$featureName=$featureEnabled";
+ }
+ }
+ push @options, "--makeargs=" . $makeArgs if defined($makeArgs);
+ push @options, "--prefix=" . $prefixPath if defined($prefixPath);
+ my $result = buildCMakeEflProject($clean, @options);
+ exit exitStatus($result) if exitStatus($result);
+}
+
+# Build, and abort if the build fails.
+for my $dir (@projects) {
+ chdir $dir or die;
+ my $result = 0;
+
+ # For Gtk and Qt the WebKit project builds all others
+ if ((isGtk() || isQt()) && $dir ne "WebKit") {
+ chdir ".." or die;
+ next;
+ }
+
+ if (isGtk()) {
+ $result = buildGtkProject($dir, $clean, @options);
+ } elsif (isQt()) {
+ $result = buildQMakeQtProject($dir, $clean, @options);
+ } elsif (isAppleMacWebKit()) {
+ $dir = "MiniBrowser" if $dir eq "Tools/MiniBrowser";
+ my @local_options = @options;
+ push @local_options, XcodeCoverageSupportOptions() if $coverageSupport && $dir ne "ANGLE";
+ $result = buildXCodeProject($dir, $clean, @local_options, @ARGV);
+ } elsif (isAppleWinWebKit()) {
+ if ($dir eq "WebKit") {
+ $result = buildVisualStudioProject("win/WebKit.vcproj/WebKit.sln", $clean);
+ }
+ }
+ # Various build* calls above may change the CWD.
+ chdirWebKit();
+
+ if (exitStatus($result)) {
+ my $scriptDir = relativeScriptsDir();
+ if (usingVisualStudioExpress()) {
+ # Visual Studio Express is so lame it can't stdout build failures.
+ # So we find its logs and dump them to the console ourselves.
+ system(File::Spec->catfile($scriptDir, "print-vse-failure-logs"));
+ }
+ if (isAppleWinWebKit()) {
+ print "\n\n===== BUILD FAILED ======\n\n";
+ print "Please ensure you have run $scriptDir/update-webkit to install dependencies.\n\n";
+ my $baseProductDir = baseProductDir();
+ print "You can view build errors by checking the BuildLog.htm files located at:\n$baseProductDir/obj/<project>/<config>.\n";
+ }
+ exit exitStatus($result);
+ }
+}
+
+# Don't report the "WebKit is now built" message after a clean operation.
+exit if $clean;
+
+# Write out congratulations message.
+writeCongrats();
+
+exit 0;
+
+sub formatBuildTime($)
+{
+ my ($buildTime) = @_;
+
+ my $buildHours = int($buildTime / 3600);
+ my $buildMins = int(($buildTime - $buildHours * 3600) / 60);
+ my $buildSecs = $buildTime - $buildHours * 3600 - $buildMins * 60;
+
+ if ($buildHours) {
+ return sprintf("%dh:%02dm:%02ds", $buildHours, $buildMins, $buildSecs);
+ }
+ return sprintf("%02dm:%02ds", $buildMins, $buildSecs);
+}
+
+sub writeCongrats()
+{
+ my $launcherPath = launcherPath();
+ my $launcherName = launcherName();
+ my $endTime = time();
+ my $buildTime = formatBuildTime($endTime - $startTime);
+
+ print "\n";
+ print "===========================================================\n";
+ print " WebKit is now built ($buildTime). \n";
+ if (!isChromium()) {
+ print " To run $launcherName with this newly-built code, use the\n";
+ print " \"$launcherPath\" script.\n";
+ }
+ print "===========================================================\n";
+}
diff --git a/Tools/Scripts/build-webkittestrunner b/Tools/Scripts/build-webkittestrunner
new file mode 100755
index 0000000..e96dd6a
--- /dev/null
+++ b/Tools/Scripts/build-webkittestrunner
@@ -0,0 +1,73 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+use strict;
+use File::Basename;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+my $showHelp = 0;
+my $clean = 0;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] [options to pass to build system]
+ --help Show this help message
+ --clean Clean up the build directory
+EOF
+
+GetOptions(
+ 'help' => \$showHelp,
+ 'clean' => \$clean,
+);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+checkRequiredSystemConfig();
+setConfiguration();
+chdirWebKit();
+
+# Build
+chdir "Tools/WebKitTestRunner" or die;
+
+my $result;
+if (isAppleMacWebKit()) {
+ $result = buildXCodeProject("WebKitTestRunner", $clean, XcodeOptions(), @ARGV);
+} elsif (isAppleWinWebKit()) {
+ $result = buildVisualStudioProject("WebKitTestRunner.sln", $clean);
+} elsif (isQt()) {
+ # Qt builds everything in one shot. No need to build anything here.
+ $result = 0;
+} else {
+ die "WebKitTestRunner is not supported on this platform.\n";
+}
+
+exit exitStatus($result);
diff --git a/Tools/Scripts/check-Xcode-source-file-types b/Tools/Scripts/check-Xcode-source-file-types
new file mode 100755
index 0000000..57a70b9
--- /dev/null
+++ b/Tools/Scripts/check-Xcode-source-file-types
@@ -0,0 +1,168 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Script to check that source file extensions match file types in Xcode project.pbxproj files.
+
+# TODO
+# - Add support for file types other than source code files.
+# - Can't differentiate between sourcecode.c.h and sourcecode.cpp.h.
+# (Hint: Use gcc -x c/objective-c/c++/objective-c++ -E. It will
+# take time to check each header using gcc, so make it a switch.)
+
+use strict;
+
+use File::Basename;
+use File::Spec;
+use File::Temp qw(tempfile);
+use Getopt::Long;
+
+# Map of Xcode file types to file extensions.
+my %typeExtensionMap = qw(
+ sourcecode.c.c .c
+ sourcecode.c.h .h
+ sourcecode.c.objc .m
+ sourcecode.cpp.h .h
+ sourcecode.cpp.cpp .cpp
+ sourcecode.cpp.objcpp .mm
+ sourcecode.exports .exp
+ sourcecode.javascript .js
+ sourcecode.make .make
+ sourcecode.mig .defs
+ sourcecode.yacc .y
+);
+
+# Map of file extensions to Xcode file types.
+my %extensionTypeMap = map { $typeExtensionMap{$_} => $_ } keys %typeExtensionMap;
+$extensionTypeMap{'.h'} = 'sourcecode.c.h'; # See TODO list.
+
+my $shouldFixIssues = 0;
+my $printWarnings = 1;
+my $showHelp;
+
+my $getOptionsResult = GetOptions(
+ 'f|fix' => \$shouldFixIssues,
+ 'h|help' => \$showHelp,
+ 'w|warnings!' => \$printWarnings,
+);
+
+if (scalar(@ARGV) == 0 && !$showHelp) {
+ print STDERR "ERROR: No Xcode project files (project.pbxproj) listed on command-line.\n";
+ undef $getOptionsResult;
+}
+
+if (!$getOptionsResult || $showHelp) {
+ print STDERR <<__END__;
+Usage: @{[ basename($0) ]} [options] path/to/project.pbxproj [path/to/project.pbxproj ...]
+ -f|--fix fix mismatched types in Xcode project file
+ -h|--help show this help message
+ -w|--[no-]warnings show or suppress warnings (default: show warnings)
+__END__
+ exit 1;
+}
+
+for my $projectFile (@ARGV) {
+ my $issuesFound = 0;
+ my $issuesFixed = 0;
+
+ if (basename($projectFile) =~ /\.xcodeproj$/) {
+ $projectFile = File::Spec->catfile($projectFile, "project.pbxproj");
+ }
+
+ if (basename($projectFile) ne "project.pbxproj") {
+ print STDERR "WARNING: Not an Xcode project file: $projectFile\n" if $printWarnings;
+ next;
+ }
+
+ open(IN, "< $projectFile") || die "Could not open $projectFile: $!";
+
+ my ($OUT, $tempFileName);
+ if ($shouldFixIssues) {
+ ($OUT, $tempFileName) = tempfile(
+ basename($projectFile) . "-XXXXXXXX",
+ DIR => dirname($projectFile),
+ UNLINK => 0,
+ );
+
+ # Clean up temp file in case of die()
+ $SIG{__DIE__} = sub {
+ close(IN);
+ close($OUT);
+ unlink($tempFileName);
+ };
+ }
+
+ # Fast-forward to "Begin PBXFileReference section".
+ while (my $line = <IN>) {
+ print $OUT $line if $shouldFixIssues;
+ last if $line =~ m#^\Q/* Begin PBXFileReference section */\E$#;
+ }
+
+ while (my $line = <IN>) {
+ if ($line =~ m#^\Q/* End PBXFileReference section */\E$#) {
+ print $OUT $line if $shouldFixIssues;
+ last;
+ }
+
+ if ($line =~ m#^\s*[A-Z0-9]{24} /\* (.+) \*/\s+=\s+\{.*\s+explicitFileType = (sourcecode[^;]*);.*\s+path = ([^;]+);.*\};$#) {
+ my $fileName = $1;
+ my $fileType = $2;
+ my $filePath = $3;
+ my (undef, undef, $fileExtension) = map { lc($_) } fileparse(basename($filePath), qr{\.[^.]+$});
+
+ if (!exists $typeExtensionMap{$fileType}) {
+ $issuesFound++;
+ print STDERR "WARNING: Unknown file type '$fileType' for file '$filePath'.\n" if $printWarnings;
+ } elsif ($typeExtensionMap{$fileType} ne $fileExtension) {
+ $issuesFound++;
+ print STDERR "WARNING: Incorrect file type '$fileType' for file '$filePath'.\n" if $printWarnings;
+ $line =~ s/(\s+)explicitFileType( = )(sourcecode[^;]*);/$1lastKnownFileType$2$extensionTypeMap{$fileExtension};/;
+ $issuesFixed++ if $shouldFixIssues;
+ }
+ }
+
+ print $OUT $line if $shouldFixIssues;
+ }
+
+ # Output the rest of the file.
+ print $OUT <IN> if $shouldFixIssues;
+
+ close(IN);
+
+ if ($shouldFixIssues) {
+ close($OUT);
+
+ unlink($projectFile) || die "Could not delete $projectFile: $!";
+ rename($tempFileName, $projectFile) || die "Could not rename $tempFileName to $projectFile: $!";
+ }
+
+ if ($printWarnings) {
+ printf STDERR "%s issues found for $projectFile.\n", ($issuesFound ? $issuesFound : "No");
+ print STDERR "$issuesFixed issues fixed for $projectFile.\n" if $issuesFixed && $shouldFixIssues;
+ print STDERR "NOTE: Open $projectFile in Xcode to let it have its way with the file.\n" if $issuesFixed;
+ print STDERR "\n";
+ }
+}
+
+exit 0;
diff --git a/Tools/Scripts/check-dom-results b/Tools/Scripts/check-dom-results
new file mode 100755
index 0000000..0b32406
--- /dev/null
+++ b/Tools/Scripts/check-dom-results
@@ -0,0 +1,141 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Script to check status of W3C DOM tests that are part of the WebKit tests.
+
+use strict;
+use FindBin;
+use Cwd;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+chdirWebKit();
+
+my $verbose = $ARGV[0] && $ARGV[0] eq "-v";
+
+my $workingDir = getcwd();
+my $testDirectory = "$workingDir/LayoutTests";
+
+my @suites = ( {"name" => "DOM Level 1 Core (html)", "directory" => "dom/html/level1/core"},
+ {"name" => "DOM Level 2 Core (html)", "directory" => "dom/html/level2/core"},
+ {"name" => "DOM Level 2 Events (html)", "directory" => "dom/html/level2/events"},
+ {"name" => "DOM Level 2 HTML (html)", "directory" => "dom/html/level2/html"},
+ {"name" => "DOM Level 1 Core (xhtml)", "directory" => "dom/xhtml/level1/core"},
+ {"name" => "DOM Level 2 Core (xhtml)", "directory" => "dom/xhtml/level2/core"},
+ {"name" => "DOM Level 2 Events (xhtml)", "directory" => "dom/xhtml/level2/events"},
+ {"name" => "DOM Level 2 HTML (xhtml)", "directory" => "dom/xhtml/level2/html"},
+ {"name" => "DOM Level 3 Core (xhtml)", "directory" => "dom/xhtml/level3/core"},
+ {"name" => "DOM Level 3 XPath (svg)", "directory" => "dom/svg/level3/xpath"});
+
+my $totalCount = 0;
+my $totalSuccesses = 0;
+my $totalDisabled = 0;
+my $totalFailed = 0;
+
+foreach my $suite (@suites) {
+
+ my %suite = %$suite;
+ my $directory = $suite{"directory"};
+ my $name = $suite{"name"};
+ my @results = `find "${testDirectory}/${directory}" -name "*-expected.txt"`;
+ my @disabled = `find "${testDirectory}/${directory}" -name "*-disabled"`;
+
+ my @failures = ();
+ my $count = 0;
+
+ foreach my $result (@results) {
+ $count++;
+ my $success = 0;
+ open RESULT, "<$result";
+ while (<RESULT>) {
+ if (/Success/) {
+ $success = 1;
+ last;
+ }
+ }
+ close RESULT;
+ if (!$success) {
+ push @failures, $result;
+ }
+ }
+
+ my $disabledCount = (scalar @disabled);
+ my $failureCount = (scalar @failures);
+
+ $count += $disabledCount;
+
+ my $successCount = $count - $failureCount - $disabledCount;
+ my $percentage = (sprintf "%.1f", ($successCount * 100.0 / $count));
+
+ if ($percentage == 100) {
+ print "${name}: all ${count} tests succeeded";
+ } else {
+ print "${name}: ${successCount} out of ${count} tests succeeded (${percentage}%)";
+ }
+ print " ($disabledCount disabled)" if $disabledCount;
+ print "\n";
+ if ($verbose) {
+ print "\n";
+ if (@disabled) {
+ print " Disabled:\n";
+
+ foreach my $failure (sort @disabled) {
+ $failure =~ s|.*/||;
+ $failure =~ s|-disabled||;
+ print " ${directory}/${failure}";
+ }
+ }
+ if (@failures) {
+ print " Failed:\n";
+
+ foreach my $failure (sort @failures) {
+ $directory =~ m|^dom/(\w+)|;
+ my $extension = $1;
+ $failure =~ s|.*/||;
+ $failure =~ s|-expected\.txt|.${extension}|;
+ print " ${directory}/${failure}";
+ }
+ }
+
+ print "\n";
+ }
+
+ $totalCount += $count;
+ $totalSuccesses += $successCount;
+ $totalDisabled += $disabledCount;
+ $totalFailed += $failureCount;
+}
+
+
+my $totalPercentage = (sprintf "%.1f", ($totalSuccesses * 100.0 / $totalCount));
+my $totalDisabledPercentage = (sprintf "%.1f", ($totalDisabled * 100.0 / $totalCount));
+my $totalFailedPercentage = (sprintf "%.1f", ($totalFailed * 100.0 / $totalCount));
+
+print "Total: ${totalSuccesses} out of ${totalCount} tests succeeded (${totalPercentage}%)\n";
+print " ${totalDisabled} tests disabled (${totalDisabledPercentage}%)\n";
+print " ${totalFailed} tests failed (${totalFailedPercentage}%)\n";
diff --git a/Tools/Scripts/check-for-exit-time-destructors b/Tools/Scripts/check-for-exit-time-destructors
new file mode 100755
index 0000000..249bd0b
--- /dev/null
+++ b/Tools/Scripts/check-for-exit-time-destructors
@@ -0,0 +1,151 @@
+#!/usr/bin/perl
+
+# Copyright (C) 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.
+
+# "check-for-exit-time-destructors" script for WebKit Open Source Project
+
+# Intended to be invoked from an Xcode build step to check if there are
+# any exit-time destructors in a target.
+
+use warnings;
+use strict;
+
+use File::Basename;
+
+sub touch($);
+sub printFunctions($$);
+
+my $arch = $ENV{'CURRENT_ARCH'};
+my $configuration = $ENV{'CONFIGURATION'};
+my $target = $ENV{'TARGET_NAME'};
+my $variant = $ENV{'CURRENT_VARIANT'};
+my $coverageBuild = $ENV{'WEBKIT_COVERAGE_BUILD'};
+my $debugRoot = $ENV{'WEBKIT_DEBUG_ROOT'};
+
+$arch = $ENV{'NATIVE_ARCH'} if !$arch; # for Xcode 2.1, which does not have CURRENT_ARCH
+$variant = "normal" if !$variant; # for Xcode 2.1, which does not have CURRENT_VARIANT
+
+my $executablePath = "$ENV{'TARGET_BUILD_DIR'}/$ENV{'EXECUTABLE_PATH'}";
+
+my $buildTimestampPath = $ENV{'TARGET_TEMP_DIR'} . "/" . basename($0) . ".timestamp";
+my $buildTimestampAge = -M $buildTimestampPath;
+my $scriptAge = -M $0;
+
+my $list = $ENV{"LINK_FILE_LIST_${variant}_${arch}"};
+
+if (!open LIST, $list) {
+ print "ERROR: Could not open $list\n";
+ exit 1;
+}
+
+my @files = <LIST>;
+chomp @files;
+close LIST;
+
+my $sawError = 0;
+
+for my $file (sort @files) {
+ if (defined $buildTimestampAge && $buildTimestampAge < $scriptAge) {
+ my $fileAge = -M $file;
+ next if defined $fileAge && $fileAge > $buildTimestampAge;
+ }
+ if (!open NM, "(nm '$file' | sed 's/^/STDOUT:/') 2>&1 |") {
+ print "ERROR: Could not open $file\n";
+ $sawError = 1;
+ next;
+ }
+ my $sawAtExit = 0;
+ while (<NM>) {
+ if (/^STDOUT:/) {
+ $sawAtExit = 1 if /___cxa_atexit/;
+ } else {
+ print STDERR if $_ ne "nm: no name list\n";
+ }
+ }
+ close NM;
+ next unless $sawAtExit;
+
+ my $shortName = $file;
+ $shortName =~ s/.*\///;
+
+ $sawError = 1 if printFunctions($shortName, $file);
+}
+
+if ($sawError and !$coverageBuild) {
+ print "ERROR: Use DEFINE_STATIC_LOCAL from <wtf/StdLibExtras.h>\n";
+ unlink $executablePath;
+ exit 1;
+}
+
+touch($buildTimestampPath);
+exit 0;
+
+sub touch($)
+{
+ my ($path) = @_;
+ open(TOUCH, ">", $path) or die "$!";
+ close(TOUCH);
+}
+
+sub demangle($)
+{
+ my ($symbol) = @_;
+ if (!open FILT, "c++filt $symbol |") {
+ print "ERROR: Could not open c++filt\n";
+ return;
+ }
+ my $result = <FILT>;
+ close FILT;
+ chomp $result;
+ return $result;
+}
+
+sub printFunctions($$)
+{
+ my ($shortName, $path) = @_;
+ if (!open OTOOL, "otool -tV '$path' |") {
+ print "WARNING: Could not open $path\n";
+ return 0;
+ }
+ my %functions;
+ my $currentSymbol = "";
+ while (<OTOOL>) {
+ $currentSymbol = $1 if /^(\w+):$/;
+ next unless $currentSymbol;
+ $functions{demangle($currentSymbol)} = 1 if /___cxa_atexit/;
+ }
+ close OTOOL;
+ my $result = 0;
+ for my $function (sort keys %functions) {
+ if (!$result) {
+ print "ERROR: $shortName has exit time destructors in it! ($path)\n";
+ $result = 1;
+ }
+ print "ERROR: In function $function\n";
+ }
+ return $result;
+}
diff --git a/Tools/Scripts/check-for-global-initializers b/Tools/Scripts/check-for-global-initializers
new file mode 100755
index 0000000..102fa09
--- /dev/null
+++ b/Tools/Scripts/check-for-global-initializers
@@ -0,0 +1,161 @@
+#!/usr/bin/perl
+
+# Copyright (C) 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.
+
+# "check-for-global-initializers" script for WebKit Open Source Project
+
+# Intended to be invoked from an Xcode build step to check if there are
+# any global initializers in a target.
+
+use warnings;
+use strict;
+
+use File::Basename;
+
+sub touch($);
+sub demangle($);
+
+my $arch = $ENV{'CURRENT_ARCH'};
+my $configuration = $ENV{'CONFIGURATION'};
+my $target = $ENV{'TARGET_NAME'};
+my $variant = $ENV{'CURRENT_VARIANT'};
+my $coverageBuild = $ENV{'WEBKIT_COVERAGE_BUILD'};
+my $debugRoot = $ENV{'WEBKIT_DEBUG_ROOT'};
+
+$arch = $ENV{'NATIVE_ARCH'} if !$arch; # for Xcode 2.1, which does not have CURRENT_ARCH
+$variant = "normal" if !$variant; # for Xcode 2.1, which does not have CURRENT_VARIANT
+
+my $executablePath = "$ENV{'TARGET_BUILD_DIR'}/$ENV{'EXECUTABLE_PATH'}";
+
+my $buildTimestampPath = $ENV{'TARGET_TEMP_DIR'} . "/" . basename($0) . ".timestamp";
+my $buildTimestampAge = -M $buildTimestampPath;
+my $scriptAge = -M $0;
+
+my $list = $ENV{"LINK_FILE_LIST_${variant}_${arch}"};
+
+if (!open LIST, $list) {
+ print "ERROR: Could not open $list\n";
+ exit 1;
+}
+
+my @files = <LIST>;
+chomp @files;
+close LIST;
+
+my $sawError = 0;
+
+for my $file (sort @files) {
+ if (defined $buildTimestampAge && $buildTimestampAge < $scriptAge) {
+ my $fileAge = -M $file;
+ next if defined $fileAge && $fileAge > $buildTimestampAge;
+ }
+ if (!open NM, "(nm '$file' | sed 's/^/STDOUT:/') 2>&1 |") {
+ print "ERROR: Could not open $file\n";
+ $sawError = 1;
+ next;
+ }
+ my $sawGlobal = 0;
+ my @globals;
+ while (<NM>) {
+ if (/^STDOUT:/) {
+ my $line = $_;
+ if ($line =~ /__GLOBAL__I(.+)$/) {
+ $sawGlobal = 1;
+ push(@globals, demangle($1));
+ }
+ } else {
+ print STDERR if $_ ne "nm: no name list\n";
+ }
+ }
+ close NM;
+ if ($sawGlobal) {
+ my $shortName = $file;
+ $shortName =~ s/.*\///;
+
+ # Special cases for files that have initializers in debug builds.
+ if ($configuration eq "Debug" or $variant eq "debug" or $debugRoot) {
+ if ($target eq "JavaScriptCore") {
+ next if $shortName eq "AllInOneFile.o";
+ next if $shortName eq "Opcode.o";
+ next if $shortName eq "Structure.o";
+ next if $shortName eq "nodes.o";
+ }
+ if ($target eq "WebCore") {
+ next if $shortName eq "BidiRun.o";
+ next if $shortName eq "CachedPage.o";
+ next if $shortName eq "CachedResource.o";
+ next if $shortName eq "FEGaussianBlur.o";
+ next if $shortName eq "Frame.o";
+ next if $shortName eq "JSCustomSQLTransactionCallback.o";
+ next if $shortName eq "JSLazyEventListener.o";
+ next if $shortName eq "Node.o";
+ next if $shortName eq "Page.o";
+ next if $shortName eq "Range.o";
+ next if $shortName eq "RenderObject.o";
+ next if $shortName eq "SVGElementInstance.o";
+ next if $shortName eq "SubresourceLoader.o";
+ next if $shortName eq "XMLHttpRequest.o";
+ }
+ if ($target eq "WebKit") {
+ next if $shortName eq "HostedNetscapePluginStream.o";
+ next if $shortName eq "NetscapePluginInstanceProxy.o";
+ }
+ }
+
+ print "ERROR: $shortName has one or more global initializers in it! ($file), near @globals\n";
+ $sawError = 1;
+ }
+}
+
+if ($sawError and !$coverageBuild) {
+ unlink $executablePath;
+ exit 1;
+}
+
+touch($buildTimestampPath);
+exit 0;
+
+sub touch($)
+{
+ my ($path) = @_;
+ open(TOUCH, ">", $path) or die "$!";
+ close(TOUCH);
+}
+
+sub demangle($)
+{
+ my ($symbol) = @_;
+ if (!open FILT, "c++filt $symbol |") {
+ print "ERROR: Could not open c++filt\n";
+ return;
+ }
+ my $result = <FILT>;
+ close FILT;
+ chomp $result;
+ return $result;
+}
+
diff --git a/Tools/Scripts/check-for-inappropriate-files-in-framework b/Tools/Scripts/check-for-inappropriate-files-in-framework
new file mode 100755
index 0000000..1ab71b2
--- /dev/null
+++ b/Tools/Scripts/check-for-inappropriate-files-in-framework
@@ -0,0 +1,68 @@
+#!/usr/bin/env ruby
+
+# 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.
+
+base_directory = ENV['TARGET_BUILD_DIR'] or throw "Unable to find TARGET_BUILD_DIR in the environment!"
+project_name = ENV['PROJECT_NAME'] or throw "Unable to find PROJECT_NAME in the environment!"
+is_shallow_bundle = (ENV['SHALLOW_BUNDLE'] || "NO").upcase == "YES"
+
+$INAPPROPRIATE_FILES = { "WebCore" => { "Resources" => ["*.css", "*.in", "*.idl", "*.h"] } }
+
+Dir.chdir base_directory
+
+$error_printed = false
+
+def print_error msg
+ $error_printed = true
+ STDERR.puts "ERROR: #{msg}"
+end
+
+def print_inappropriate_file_error framework, relative_path
+ print_error "#{framework}.framework/#{relative_path} should not be present in the framework."
+end
+
+def check_framework framework, is_shallow_bundle
+ $INAPPROPRIATE_FILES[framework].each do |directory, patterns|
+ framework_bundle_path = is_shallow_bundle ? "#{framework}.framework" : "#{framework}.framework/Versions/A/#{directory}"
+ Dir.chdir framework_bundle_path do
+ patterns.each do |pattern|
+ Dir.glob(pattern).each do |inappropriate_file|
+ print_inappropriate_file_error framework, is_shallow_bundle ? inappropriate_file : "#{directory}/#{inappropriate_file}"
+ File.unlink inappropriate_file
+ end
+ end
+ end
+ end
+end
+
+check_framework project_name, is_shallow_bundle
+
+if $error_printed
+ STDERR.puts
+ STDERR.puts " Inappropriate files were detected and have been removed from the framework."
+ STDERR.puts " If this error continues to appear after building again then the build system needs"
+ STDERR.puts " to be modified so that the inappropriate files are no longer copied in to the framework."
+ STDERR.puts
+ exit 1
+end
diff --git a/Tools/Scripts/check-for-weak-vtables-and-externals b/Tools/Scripts/check-for-weak-vtables-and-externals
new file mode 100755
index 0000000..a3dc364
--- /dev/null
+++ b/Tools/Scripts/check-for-weak-vtables-and-externals
@@ -0,0 +1,120 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2006, 2007, 2008, 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 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.
+
+# "check-for-weak-vtables-and-externals" script for WebKit Open Source Project
+
+# Intended to be invoked from an Xcode build step to check if there are
+# any weak vtables or weak externals in a target.
+
+use warnings;
+use strict;
+
+use File::Basename;
+
+sub touch($);
+
+my $arch = $ENV{'CURRENT_ARCH'};
+my $configuration = $ENV{'CONFIGURATION'};
+my $target = $ENV{'TARGET_NAME'};
+my $variant = $ENV{'CURRENT_VARIANT'};
+my $coverageBuild = $ENV{'WEBKIT_COVERAGE_BUILD'};
+my $debugRoot = $ENV{'WEBKIT_DEBUG_ROOT'};
+
+$arch = $ENV{'NATIVE_ARCH'} if !$arch; # for Xcode 2.1, which does not have CURRENT_ARCH
+$variant = "normal" if !$variant; # for Xcode 2.1, which does not have CURRENT_VARIANT
+
+my $executablePath = "$ENV{'TARGET_BUILD_DIR'}/$ENV{'EXECUTABLE_PATH'}";
+
+my $buildTimestampPath = $ENV{'TARGET_TEMP_DIR'} . "/" . basename($0) . ".timestamp";
+my $buildTimestampAge = -M $buildTimestampPath;
+my $executablePathAge = -M $executablePath;
+
+my $sawError = 0;
+
+if (!defined $executablePathAge || !defined $buildTimestampAge || $executablePathAge > $buildTimestampAge) {
+ if (!open NM, "(nm -m '$executablePath' | c++filt | sed 's/^/STDOUT:/') 2>&1 |") {
+ print "ERROR: Could not open $executablePath\n";
+ $sawError = 1;
+ next;
+ }
+ my @weakVTableClasses = ();
+ my @weakExternalSymbols = ();
+ while (<NM>) {
+ if (/^STDOUT:/) {
+ # Ignore undefined, RTTI and typeinfo symbols.
+ next if /\bundefined\b/ or /\b__ZT[IS]/;
+
+ if (/weak external vtable for (.*)$/) {
+ push @weakVTableClasses, $1;
+ } elsif (/weak external (.*)$/) {
+ push @weakExternalSymbols, $1;
+ }
+ } else {
+ print STDERR if $_ ne "nm: no name list\n";
+ }
+ }
+ close NM;
+
+ my $shortName = $executablePath;
+ $shortName =~ s/.*\///;
+
+ if (@weakVTableClasses) {
+ print "ERROR: $shortName has a weak vtable in it ($executablePath)\n";
+ print "ERROR: Fix by making sure the first virtual function in each of these classes is not an inline:\n";
+ for my $class (sort @weakVTableClasses) {
+ print "ERROR: class $class\n";
+ }
+ $sawError = 1;
+ }
+
+ if (@weakExternalSymbols) {
+ print "ERROR: $shortName has a weak external symbol in it ($executablePath)\n";
+ print "ERROR: A weak external symbol is generated when a symbol is defined in multiple compilation units and is also marked as being exported from the library.\n";
+ print "ERROR: A common cause of weak external symbols is when an inline function is listed in the linker export file.\n";
+ for my $symbol (sort @weakExternalSymbols) {
+ print "ERROR: symbol $symbol\n";
+ }
+ $sawError = 1;
+ }
+}
+
+if ($sawError and !$coverageBuild) {
+ unlink $executablePath;
+ exit 1;
+}
+
+touch($buildTimestampPath);
+
+exit 0;
+
+sub touch($)
+{
+ my ($path) = @_;
+ open(TOUCH, ">", $path) or die "$!";
+ close(TOUCH);
+}
diff --git a/Tools/Scripts/check-for-webkit-framework-include-consistency b/Tools/Scripts/check-for-webkit-framework-include-consistency
new file mode 100755
index 0000000..339fa7e
--- /dev/null
+++ b/Tools/Scripts/check-for-webkit-framework-include-consistency
@@ -0,0 +1,111 @@
+#!/usr/bin/env ruby
+
+# 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.
+
+
+base_directory = ENV['TARGET_BUILD_DIR'] or throw "Unable to find TARGET_BUILD_DIR in the environment!"
+is_shallow_bundle = (ENV['SHALLOW_BUNDLE'] || "NO").upcase == "YES"
+
+unless base_directory
+ throw "Unable to find TARGET_BUILD_DIR in the environment!"
+end
+
+Dir.chdir base_directory
+
+$PERMITTED_INCLUDE_TYPES = { :public => [ :public ], :private => [ :public, :private ] }
+
+$HEADER_NAMES_TO_TYPE = { }
+$HEADERS_BY_TYPE = { :public => [], :private => [] }
+
+$error_printed = false
+
+def print_error msg
+ $error_printed = true
+ STDERR.puts "ERROR: #{msg}"
+end
+
+def build_header_maps is_shallow_bundle
+ current_version_path = is_shallow_bundle ? "" : "Versions/A/"
+ all_headers = `find WebKit.framework/#{current_version_path}{,Private}Headers -type f -name '*.h'`.split
+
+ all_headers.each do |header|
+ if /\/Headers\/(.*)/.match(header)
+ $HEADER_NAMES_TO_TYPE[$1] = :public
+ $HEADERS_BY_TYPE[:public] << header
+ elsif /\/PrivateHeaders\/(.*)/.match(header)
+ $HEADER_NAMES_TO_TYPE[$1] = :private
+ $HEADERS_BY_TYPE[:private] << header
+ else
+ print_error "Unknown header type: #{header}"
+ end
+ end
+end
+
+def resolve_include(header, included_header, permitted_types)
+ # Ignore includes that aren't in the typical framework style.
+ return unless /<([^\/]+)\/(.*)>/.match(included_header)
+
+ framework, included_header_name = [$1, $2]
+
+ # Ignore includes that aren't related to other WebKit headers.
+ return unless framework =~ /^Web/
+
+ # A header of any type including a WebCore header is a recipe for disaster.
+ if framework == "WebCore"
+ # <rdar://problem/7718826> WebKeyGenerator.h should not include a WebCore header
+ return if header =~ /\/WebKeyGenerator.h$/ and included_header_name == "WebCoreKeyGenerator.h"
+
+ print_error "#{header} included #{included_header}!"
+ return
+ end
+
+ header_type = $HEADER_NAMES_TO_TYPE[included_header_name]
+
+ if not header_type
+ print_error "#{header} included #{included_header} but I could not find a header of that name!"
+ elsif not permitted_types.member?(header_type)
+ print_error "#{header} included #{included_header} which is #{header_type}!"
+ end
+end
+
+def verify_includes(header, permitted_types)
+ File.open(header) do |file|
+ file.each_line do |line|
+ if /#(include|import) (.*)/.match(line)
+ resolve_include(header, $2, permitted_types)
+ end
+ end
+ end
+end
+
+build_header_maps is_shallow_bundle
+
+$HEADERS_BY_TYPE.each do |header_type, headers|
+ permitted_types = $PERMITTED_INCLUDE_TYPES[header_type]
+ headers.each do |header|
+ verify_includes header, permitted_types
+ end
+end
+
+exit 1 if $error_printed
diff --git a/Tools/Scripts/check-webkit-style b/Tools/Scripts/check-webkit-style
new file mode 100755
index 0000000..076c712
--- /dev/null
+++ b/Tools/Scripts/check-webkit-style
@@ -0,0 +1,134 @@
+#!/usr/bin/env python
+#
+# Copyright (C) 2009 Google Inc. All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+#
+# 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.
+
+"""Does WebKit-lint on C/C++ or text files.
+
+The goal of this script is to identify places in the code that *may*
+be in non-compliance with WebKit style. It does not attempt to fix
+up these problems -- the point is to educate. It does also not
+attempt to find all problems, or to ensure that everything it does
+find is legitimately a problem.
+
+In particular, we can get very confused by /* and // inside strings!
+We do a small hack, which is to ignore //'s with "'s after them on the
+same line, but it is far from perfect (in either direction).
+"""
+
+import codecs
+import logging
+import os
+import os.path
+import sys
+
+from webkitpy.style_references import detect_checkout
+import webkitpy.style.checker as checker
+from webkitpy.style.patchreader import PatchReader
+from webkitpy.style.checker import StyleProcessor
+from webkitpy.style.filereader import TextFileReader
+from webkitpy.style.main import change_directory
+
+_log = logging.getLogger("check-webkit-style")
+
+
+# FIXME: Move this code to style.main.
+def main():
+ # Change stderr to write with replacement characters so we don't die
+ # if we try to print something containing non-ASCII characters.
+ stderr = codecs.StreamReaderWriter(sys.stderr,
+ codecs.getreader('utf8'),
+ codecs.getwriter('utf8'),
+ 'replace')
+ # Setting an "encoding" attribute on the stream is necessary to
+ # prevent the logging module from raising an error. See
+ # the checker.configure_logging() function for more information.
+ stderr.encoding = "UTF-8"
+
+ # FIXME: Change webkitpy.style so that we do not need to overwrite
+ # the global sys.stderr. This involves updating the code to
+ # accept a stream parameter where necessary, and not calling
+ # sys.stderr explicitly anywhere.
+ sys.stderr = stderr
+
+ args = sys.argv[1:]
+
+ # Checking for the verbose flag before calling check_webkit_style_parser()
+ # lets us enable verbose logging earlier.
+ is_verbose = "-v" in args or "--verbose" in args
+
+ checker.configure_logging(stream=stderr, is_verbose=is_verbose)
+ _log.debug("Verbose logging enabled.")
+
+ parser = checker.check_webkit_style_parser()
+ (paths, options) = parser.parse(args)
+
+ checkout = detect_checkout()
+
+ if checkout is None:
+ if not paths:
+ _log.error("WebKit checkout not found: You must run this script "
+ "from within a WebKit checkout if you are not passing "
+ "specific paths to check.")
+ sys.exit(1)
+
+ checkout_root = None
+ _log.debug("WebKit checkout not found for current directory.")
+ else:
+ checkout_root = checkout.root_path()
+ _log.debug("WebKit checkout found with root: %s" % checkout_root)
+
+ configuration = checker.check_webkit_style_configuration(options)
+
+ paths = change_directory(checkout_root=checkout_root, paths=paths)
+
+ style_processor = StyleProcessor(configuration)
+
+ file_reader = TextFileReader(style_processor)
+
+ if paths and not options.diff_files:
+ file_reader.process_paths(paths)
+ else:
+ changed_files = paths if options.diff_files else None
+ patch = checkout.create_patch(options.git_commit, changed_files=changed_files)
+ patch_checker = PatchReader(file_reader)
+ patch_checker.check(patch)
+
+ error_count = style_processor.error_count
+ file_count = file_reader.file_count
+ delete_only_file_count = file_reader.delete_only_file_count
+
+ _log.info("Total errors found: %d in %d files"
+ % (error_count, file_count))
+ # We fail when style errors are found or there are no checked files.
+ sys.exit(error_count > 0 or (file_count == 0 and delete_only_file_count == 0))
+
+
+if __name__ == "__main__":
+ main()
diff --git a/Tools/Scripts/clean-header-guards b/Tools/Scripts/clean-header-guards
new file mode 100755
index 0000000..2bad046
--- /dev/null
+++ b/Tools/Scripts/clean-header-guards
@@ -0,0 +1,53 @@
+#!/usr/bin/ruby
+
+require 'find'
+require 'optparse'
+
+options = {}
+OptionParser.new do |opts|
+ opts.banner = "Usage: clean-header-guards [options]"
+
+ opts.on("--prefix [PREFIX]", "Append a header prefix to all guards") do |prefix|
+ options[:prefix] = prefix
+ end
+end.parse!
+
+IgnoredFilenamePatterns = [
+ # ignore headers which are known not to have guard
+ /WebCorePrefix/,
+ /ForwardingHeaders/,
+ %r|bindings/objc|,
+ /vcproj/, # anything inside a vcproj is in the windows wasteland
+
+ # we don't own any of these headers
+ %r|icu/unicode|,
+ %r|platform/graphics/cairo|,
+ %r|platform/image-decoders|,
+
+ /config.h/ # changing this one sounds scary
+].freeze
+
+IgnoreFileNamesPattern = Regexp.union(*IgnoredFilenamePatterns).freeze
+
+Find::find(".") do |filename|
+ next unless filename =~ /\.h$/
+ next if filename.match(IgnoreFileNamesPattern)
+
+ File.open(filename, "r+") do |file|
+ contents = file.read
+ match_results = contents.match(/#ifndef (\S+)\n#define \1/s)
+ if match_results
+ current_guard = match_results[1]
+ new_guard = File.basename(filename).sub('.', '_')
+ new_guard = options[:prefix] + '_' + new_guard if options[:prefix]
+ contents.gsub!(/#{current_guard}\b/, new_guard)
+ else
+ puts "Ignoring #{filename}, failed to find existing header guards."
+ end
+ tmp_filename = filename + ".tmp"
+ File.open(tmp_filename, "w+") do |new_file|
+ new_file.write(contents)
+ end
+ File.rename tmp_filename, filename
+ end
+end
diff --git a/Tools/Scripts/commit-log-editor b/Tools/Scripts/commit-log-editor
new file mode 100755
index 0000000..f40295d
--- /dev/null
+++ b/Tools/Scripts/commit-log-editor
@@ -0,0 +1,325 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+# Copyright (C) 2009 Torch Mobile 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.
+
+# Script to put change log comments in as default check-in comment.
+
+use strict;
+use File::Basename;
+use File::Spec;
+use FindBin;
+use lib $FindBin::Bin;
+use Term::ReadKey;
+use VCSUtils;
+use webkitdirs;
+
+sub normalizeLineEndings($$);
+sub removeLongestCommonPrefixEndingInDoubleNewline(\%);
+sub isCommitLogEditor($);
+
+sub usage
+{
+ print "Usage: [--help] [--regenerate-log] <log file>\n";
+ exit 1;
+}
+
+my $help = checkForArgumentAndRemoveFromARGV("--help");
+if ($help) {
+ usage();
+}
+
+my $regenerateLog = checkForArgumentAndRemoveFromARGV("--regenerate-log");
+my $log = $ARGV[0];
+if (!$log) {
+ usage();
+}
+
+my $baseDir = baseProductDir();
+
+my $editor = $ENV{SVN_LOG_EDITOR};
+$editor = $ENV{CVS_LOG_EDITOR} if !$editor;
+$editor = "" if $editor && isCommitLogEditor($editor);
+
+my $splitEditor = 1;
+if (!$editor) {
+ my $builtEditorApplication = "$baseDir/Release/Commit Log Editor.app/Contents/MacOS/Commit Log Editor";
+ if (-x $builtEditorApplication) {
+ $editor = $builtEditorApplication;
+ $splitEditor = 0;
+ }
+}
+if (!$editor) {
+ my $builtEditorApplication = "$baseDir/Debug/Commit Log Editor.app/Contents/MacOS/Commit Log Editor";
+ if (-x $builtEditorApplication) {
+ $editor = $builtEditorApplication;
+ $splitEditor = 0;
+ }
+}
+if (!$editor) {
+ my $builtEditorApplication = "$ENV{HOME}/Applications/Commit Log Editor.app/Contents/MacOS/Commit Log Editor";
+ if (-x $builtEditorApplication) {
+ $editor = $builtEditorApplication;
+ $splitEditor = 0;
+ }
+}
+
+$editor = $ENV{EDITOR} if !$editor;
+$editor = "/usr/bin/vi" if !$editor;
+
+my @editor;
+if ($splitEditor) {
+ @editor = split ' ', $editor;
+} else {
+ @editor = ($editor);
+}
+
+my $inChangesToBeCommitted = !isGit();
+my @changeLogs = ();
+my $logContents = "";
+my $existingLog = 0;
+open LOG, $log or die "Could not open the log file.";
+while (<LOG>) {
+ if (isGit()) {
+ if (/^# Changes to be committed:$/) {
+ $inChangesToBeCommitted = 1;
+ } elsif ($inChangesToBeCommitted && /^# \S/) {
+ $inChangesToBeCommitted = 0;
+ }
+ }
+
+ if (!isGit() || /^#/) { #
+ $logContents .= $_;
+ } else {
+ # $_ contains the current git log message
+ # (without the log comment info). We don't need it.
+ }
+ $existingLog = isGit() && !(/^#/ || /^\s*$/) unless $existingLog;
+
+ push @changeLogs, makeFilePathRelative($1) if $inChangesToBeCommitted && (/^(?:M|A)....(.*ChangeLog)\r?\n?$/ || /^#\t(?:modified|new file): (.*ChangeLog)$/) && !/-ChangeLog$/;
+}
+close LOG;
+
+# We want to match the line endings of the existing log file in case they're
+# different from perl's line endings.
+my $endl = "\n";
+$endl = $1 if $logContents =~ /(\r?\n)/;
+
+my $keepExistingLog = 1;
+if ($regenerateLog && $existingLog && scalar(@changeLogs) > 0) {
+ print "Existing log message detected, Use 'r' to regenerate log message from ChangeLogs, or any other key to keep the existing message.\n";
+ ReadMode('cbreak');
+ my $key = ReadKey(0);
+ ReadMode('normal');
+ $keepExistingLog = 0 if ($key eq "r");
+}
+
+# Don't change anything if there's already a log message (as can happen with git-commit --amend).
+exec (@editor, @ARGV) if $existingLog && $keepExistingLog;
+
+my $topLevel = determineVCSRoot();
+
+my %changeLogSort;
+my %changeLogContents;
+for my $changeLog (@changeLogs) {
+ open CHANGELOG, $changeLog or die "Can't open $changeLog";
+ my $contents = "";
+ my $blankLines = "";
+ my $reviewedByLine = "";
+ my $lineCount = 0;
+ my $date = "";
+ my $author = "";
+ my $email = "";
+ my $hasAuthorInfoToWrite = 0;
+ while (<CHANGELOG>) {
+ if (/^\S/) {
+ last if $contents;
+ }
+ if (/\S/) {
+ my $previousLineWasBlank = 1 unless $blankLines eq "";
+ my $line = $_;
+ my $currentLineBlankLines = $blankLines;
+ $blankLines = "";
+
+ # Remove indentation spaces
+ $line =~ s/^ {8}//;
+
+ # Save the reviewed / rubber stamped by line.
+ if ($line =~ m/^Reviewed by .*/ || $line =~ m/^Rubber[ \-]?stamped by .*/) {
+ $reviewedByLine = $line;
+ next;
+ }
+
+ # Grab the author and the date line
+ if ($line =~ m/^([0-9]{4}-[0-9]{2}-[0-9]{2})\s+(.*[^\s])\s+<(.*)>/ && $lineCount == 0) {
+ $date = $1;
+ $author = $2;
+ $email = $3;
+ $hasAuthorInfoToWrite = 1;
+ next;
+ }
+
+ $contents .= $currentLineBlankLines if $contents;
+
+ # Attempt to insert the "patch by" line, after the first blank line.
+ if ($previousLineWasBlank && $hasAuthorInfoToWrite && $lineCount > 0) {
+ my $committerEmail = changeLogEmailAddress();
+ my $authorAndCommitterAreSamePerson = $email eq $committerEmail;
+ if (!$authorAndCommitterAreSamePerson) {
+ $contents .= "Patch by $author <$email> on $date\n";
+ $hasAuthorInfoToWrite = 0;
+ }
+ }
+
+ # Attempt to insert the "reviewed by" line, after the first blank line.
+ if ($previousLineWasBlank && $reviewedByLine && $lineCount > 0) {
+ $contents .= $reviewedByLine . "\n";
+ $reviewedByLine = "";
+ }
+
+ $lineCount++;
+ $contents .= $line;
+ } else {
+ $blankLines .= $_;
+ }
+ }
+ if ($reviewedByLine) {
+ $contents .= "\n".$reviewedByLine;
+ }
+ close CHANGELOG;
+
+ $changeLog = File::Spec->abs2rel(File::Spec->rel2abs($changeLog), $topLevel);
+
+ my $label = dirname($changeLog);
+ $label = "top level" unless length $label;
+
+ my $sortKey = lc $label;
+ if ($label eq "top level") {
+ $sortKey = "";
+ } elsif ($label eq "LayoutTests") {
+ $sortKey = lc "~, LayoutTests last";
+ }
+
+ $changeLogSort{$sortKey} = $label;
+ $changeLogContents{$label} = $contents;
+}
+
+my $commonPrefix = removeLongestCommonPrefixEndingInDoubleNewline(%changeLogContents);
+
+my $first = 1;
+open NEWLOG, ">$log.edit" or die;
+if (isGit() && scalar keys %changeLogSort == 0) {
+ # populate git commit message with WebKit-format ChangeLog entries unless explicitly disabled
+ my $branch = gitBranch();
+ chomp(my $webkitGenerateCommitMessage = `git config --bool branch.$branch.webkitGenerateCommitMessage`);
+ if ($webkitGenerateCommitMessage eq "") {
+ chomp($webkitGenerateCommitMessage = `git config --bool core.webkitGenerateCommitMessage`);
+ }
+ if ($webkitGenerateCommitMessage ne "false") {
+ open CHANGELOG_ENTRIES, "-|", "$FindBin::Bin/prepare-ChangeLog --git-index --no-write" or die "prepare-ChangeLog failed: $!.\n";
+ while (<CHANGELOG_ENTRIES>) {
+ print NEWLOG normalizeLineEndings($_, $endl);
+ }
+ close CHANGELOG_ENTRIES;
+ }
+} else {
+ print NEWLOG normalizeLineEndings($commonPrefix, $endl);
+ for my $sortKey (sort keys %changeLogSort) {
+ my $label = $changeLogSort{$sortKey};
+ if (keys %changeLogSort > 1) {
+ print NEWLOG normalizeLineEndings("\n", $endl) if !$first;
+ $first = 0;
+ print NEWLOG normalizeLineEndings("$label: ", $endl);
+ }
+ print NEWLOG normalizeLineEndings($changeLogContents{$label}, $endl);
+ }
+}
+print NEWLOG $logContents;
+close NEWLOG;
+
+system (@editor, "$log.edit");
+
+open NEWLOG, "$log.edit" or exit;
+my $foundComment = 0;
+while (<NEWLOG>) {
+ $foundComment = 1 if (/\S/ && !/^CVS:/);
+}
+close NEWLOG;
+
+if ($foundComment) {
+ open NEWLOG, "$log.edit" or die;
+ open LOG, ">$log" or die;
+ while (<NEWLOG>) {
+ print LOG;
+ }
+ close LOG;
+ close NEWLOG;
+}
+
+unlink "$log.edit";
+
+sub normalizeLineEndings($$)
+{
+ my ($string, $endl) = @_;
+ $string =~ s/\r?\n/$endl/g;
+ return $string;
+}
+
+sub removeLongestCommonPrefixEndingInDoubleNewline(\%)
+{
+ my ($hashOfStrings) = @_;
+
+ my @strings = values %{$hashOfStrings};
+ return "" unless @strings > 1;
+
+ my $prefix = shift @strings;
+ my $prefixLength = length $prefix;
+ foreach my $string (@strings) {
+ while ($prefixLength) {
+ last if substr($string, 0, $prefixLength) eq $prefix;
+ --$prefixLength;
+ $prefix = substr($prefix, 0, -1);
+ }
+ last unless $prefixLength;
+ }
+
+ return "" unless $prefixLength;
+
+ my $lastDoubleNewline = rindex($prefix, "\n\n");
+ return "" unless $lastDoubleNewline > 0;
+
+ foreach my $key (keys %{$hashOfStrings}) {
+ $hashOfStrings->{$key} = substr($hashOfStrings->{$key}, $lastDoubleNewline);
+ }
+ return substr($prefix, 0, $lastDoubleNewline + 2);
+}
+
+sub isCommitLogEditor($)
+{
+ my $editor = shift;
+ return $editor =~ m/commit-log-editor/;
+}
diff --git a/Tools/Scripts/compare-timing-files b/Tools/Scripts/compare-timing-files
new file mode 100755
index 0000000..11b470b
--- /dev/null
+++ b/Tools/Scripts/compare-timing-files
@@ -0,0 +1,88 @@
+#!/usr/bin/perl
+
+# 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.
+
+# This script takes two files that are lists of timings and compares them.
+
+use warnings;
+use strict;
+use Getopt::Long;
+
+my $usage = "compare-timing-files [-c|--count results] oldFile newFile";
+
+my $count = 1;
+GetOptions("c|count=i" => \$count);
+
+my ($file1, $file2) = @ARGV;
+die "$usage\n" unless ($file1 && $file2 && @ARGV == 2);
+
+my ($oldAverage, $oldRange, $oldRangePercent) = parseResults($file1);
+my ($newAverage, $newRange, $newRangePercent) = parseResults($file2);
+
+print "\n===== $file1 =====\n";
+if ($count == 1) {
+ print("fastest run: $oldAverage\n");
+} else {
+ print("average of fastest $count runs: $oldAverage\n");
+ printf("range of fastest $count runs: %.2f%% (%d)\n", $oldRangePercent, $oldRange);
+}
+
+print "\n===== $file2 =====\n";
+if ($count == 1) {
+ print("fastest run: $newAverage\n");
+} else {
+ print("average of fastest $count runs: $newAverage\n");
+ printf("range of fastest $count runs: %.2f%% (%d)\n", $newRangePercent, $newRange);
+}
+
+my $gainOrLoss = $newAverage <= $oldAverage ? "GAIN" : "LOSS";
+my $difference = abs($newAverage - $oldAverage);
+my $differencePercent = $difference / $oldAverage * 100;
+printf("\nperformance %s of %.2f%% (%.1f / %.1f)\n", $gainOrLoss, $differencePercent, $difference, $oldAverage);
+print "\n";
+
+sub parseResults
+{
+ my ($file) = @_;
+
+ open(FILE, $file) or die "Couldn't open file: $file";
+ my @results = <FILE>;
+ close(FILE);
+
+ @results = sort(@results);
+ my $total = 0;
+ for (my $i = 0; $i < $count; $i++) {
+ $results[$i] =~ s/\D*//; # cut out non-digits
+ $total += $results[$i];
+ }
+ my $average = $total / $count;
+ my $range = $results[$count - 1] - $results[0];
+ my $rangePercent = $range / $results[$count - 1] * 100;
+
+ return ($average, $range, $rangePercent);
+}
+
diff --git a/Tools/Scripts/create-exports b/Tools/Scripts/create-exports
new file mode 100755
index 0000000..c645d55
--- /dev/null
+++ b/Tools/Scripts/create-exports
@@ -0,0 +1,5 @@
+#!/usr/bin/perl -w
+
+while (<>) {
+ print "$1\n" if /^\s*\"(.+)\", referenced from:$/;
+}
diff --git a/Tools/Scripts/debug-minibrowser b/Tools/Scripts/debug-minibrowser
new file mode 100755
index 0000000..06685b4
--- /dev/null
+++ b/Tools/Scripts/debug-minibrowser
@@ -0,0 +1,38 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Simplified "debug" script for debugging the WebKit2 MiniBrowser.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+
+exit exitStatus(debugMiniBrowser());
diff --git a/Tools/Scripts/debug-safari b/Tools/Scripts/debug-safari
new file mode 100755
index 0000000..52e97fe
--- /dev/null
+++ b/Tools/Scripts/debug-safari
@@ -0,0 +1,38 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Script to run Safari in the platform's debugger for the WebKit Open Source Project.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+
+exit exitStatus(runSafari(1));
diff --git a/Tools/Scripts/debug-test-runner b/Tools/Scripts/debug-test-runner
new file mode 100755
index 0000000..5a9b7f9
--- /dev/null
+++ b/Tools/Scripts/debug-test-runner
@@ -0,0 +1,35 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Simplified "debug" script for debugging the WebKitTestRunner.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+
+exit exitStatus(debugWebKitTestRunner());
diff --git a/Tools/Scripts/deduplicate-tests b/Tools/Scripts/deduplicate-tests
new file mode 100755
index 0000000..f0afe13
--- /dev/null
+++ b/Tools/Scripts/deduplicate-tests
@@ -0,0 +1,84 @@
+#!/usr/bin/env python
+# 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 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.
+
+"""deduplicate-tests -- print test results duplicated between platforms.
+
+If platform/mac-leopard is missing an expected test output, we fall back on
+platform/mac. This means it's possible to grow redundant test outputs,
+where we have the same expected data in both a platform directory and another
+platform it falls back on.
+
+This command dumps out all such files. You can use it like this:
+ deduplicate-tests --verbose # print out the duplicated files
+ deduplicate-tests | xargs git rm # delete them
+"""
+
+
+import optparse
+import webkitpy.common.system.logutils as logutils
+import webkitpy.layout_tests.deduplicate_tests as deduplicate_tests
+
+
+def parse_args():
+ """Provides a default set of command line args.
+
+ Returns a tuple of options, args from optparse"""
+
+ configuration_options = [
+ optparse.make_option("-v", "--verbose", dest="verbose",
+ action="store_true", default=False,
+ help="Verbose output."),
+ optparse.make_option("-g", "--glob", dest="glob_pattern",
+ default="*-expected*",
+ help="Specify the glob to filter the files, defaults to *-expected*."),
+ ]
+
+ option_list = (configuration_options)
+ option_parser = optparse.OptionParser(option_list=option_list)
+
+ options, _ = option_parser.parse_args()
+
+ return options
+
+
+def run(options):
+ logutils.configure_logging()
+ if options.verbose:
+ format = ("* %(test)s\n"
+ "\tredundantly on %(platform)s and %(fallback)s\n"
+ "\tconsider deleting %(path)s")
+ else:
+ format = "%(path)s"
+
+ for dupe in deduplicate_tests.deduplicate(options.glob_pattern):
+ print(format % dupe)
+
+
+def main():
+ options = parse_args()
+ run(options)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/Tools/Scripts/detect-mismatched-virtual-const b/Tools/Scripts/detect-mismatched-virtual-const
new file mode 100755
index 0000000..b345cb2
--- /dev/null
+++ b/Tools/Scripts/detect-mismatched-virtual-const
@@ -0,0 +1,167 @@
+#!/usr/bin/perl -w
+
+# 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.
+# 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.
+
+#
+# This script attempts to find instances of a problem where the signatures
+# of virtual methods fail to match because one is defined 'const', and another
+# is not. For example:
+# virtual void Base::doStuff() const;
+# virtual void Derived::doStuff();
+#
+# The lack of 'const' on the derived class gives it a different signature, and
+# it will therefore not be called when doStuff() is called on a derived object
+# via a base class pointer.
+#
+# Limitations of this script:
+# * It only works on things in the WebCore namespace
+# * Not all templatized methods may be found correctly
+# * It doesn't know anything about inheritance, or if methods are actually virtual
+# * It has lots of false positives (should add a whitelist for known-good signatures,
+# and specific methods)
+# * It's rather slow
+#
+# Added by Simon Fraser <simon.fraser@apple.com>
+#
+# Run the script like this:
+# WebKitTools/Scripts/detect-mismatched-virtual-const WebKitBuild/Debug/WebCore.framework/WebCore
+#
+# Output consists of a series of warnings like this:
+#
+# Both const and non-const versions of bgColor():
+# HTMLDocument::bgColor()
+# HTMLBodyElement::bgColor() const
+# HTMLTableElement::bgColor() const
+# HTMLTableRowElement::bgColor() const
+# HTMLTableCellElement::bgColor() const
+#
+
+use strict;
+no warnings qw /syntax/;
+
+
+my $file = $ARGV[0];
+
+print "Looking for unmatched const methods in $file\n";
+
+if (!open NM, "(nm '$file' | c++filt | sed 's/^/STDOUT:/') 2>&1 |") {
+ die "Could not open $file\n";
+}
+
+my $nestedParens;
+ $nestedParens = qr /
+ [(]
+ [^()]*
+ (?:
+ (??{ $nestedParens })
+ [^()]*
+ )*
+ [)]/x;
+
+my $nestedAngleBrackets;
+ $nestedAngleBrackets = qr /
+ [<]
+ [^<>]*
+ (?:
+ (??{ $nestedAngleBrackets })
+ [^<>]*
+ )*
+ [>]/x;
+
+my $bal;
+ $bal = qr /([^:]+
+ (??{ $nestedAngleBrackets })?
+ (??{ $nestedParens }))
+ ([^()]*)$/x;
+
+my %signature_map = ();
+
+while (<NM>) {
+ my $line = $_;
+ chomp($line);
+ if ($line =~ m/ [tT] WebCore::(.+)$/) {
+ my $method = $1;
+
+ if ($method =~ /$bal/) {
+ my $signature = $1;
+ my $const = $2 eq " const";
+
+ my $class = substr($method, 0, length($method) - length($signature) - ($const ? 6 : 0));
+
+# print "line: $line\nclass: $class\nmethod: $method\nsignature: $signature\nconst: $const\n\n";
+
+ my %method_info = (
+ 'class' => $class,
+ 'const' => $const,
+ 'method' => $method,
+ );
+
+ push @{$signature_map{$signature}}, \%method_info;
+ } else {
+ print "unmatched line $method\n\n"
+ }
+ }
+}
+close NM;
+
+my $sig;
+for $sig (keys %signature_map) {
+ #print "\n$sig\n";
+
+ my @entries = @{$signature_map{$sig}};
+# print "$#entries\n";
+
+ my $num_const = 0;
+ my $num_not_const = 0;
+ my $i;
+ for $i (0 .. $#entries) {
+ my $entry = @entries[$i];
+
+ my $class = $entry->{'class'};
+ my $const = $entry->{'const'};
+
+ if ($const) {
+ $num_const++;
+ } else {
+ $num_not_const++;
+ }
+ }
+
+ if ($#entries > 1 && $num_const > 0 && $num_not_const > 0) {
+ print "Both const and non-const versions of $sig:\n";
+
+ for $i (0 .. $#entries) {
+ my $entry = @entries[$i];
+ my $method = $entry->{'method'};
+ print "\t$method\n";
+ }
+
+ }
+}
+
+
+
diff --git a/Tools/Scripts/do-file-rename b/Tools/Scripts/do-file-rename
new file mode 100755
index 0000000..9c4c898
--- /dev/null
+++ b/Tools/Scripts/do-file-rename
@@ -0,0 +1,117 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006, 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.
+
+# Script to do file renaming.
+
+use strict;
+use File::Find;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+use VCSUtils;
+
+setConfiguration();
+chdirWebKit();
+
+my %words;
+
+# find all files we want to process
+
+my @paths;
+find(\&wanted, "JavaScriptCore");
+find(\&wanted, "JavaScriptGlue");
+find(\&wanted, "WebCore");
+find(\&wanted, "WebKit");
+find(\&wanted, "WebKit2");
+
+sub wanted
+{
+ my $file = $_;
+
+ if ($file eq "icu") {
+ $File::Find::prune = 1;
+ return;
+ }
+
+ if ($file =~ /^\../) {
+ $File::Find::prune = 1;
+ return;
+ }
+
+ return if $file =~ /^ChangeLog/;
+ return if -d $file;
+
+ push @paths, $File::Find::name;
+}
+
+my %renames = (
+);
+
+my %renamesContemplatedForTheFuture = (
+);
+
+# rename files
+
+my %newFile;
+for my $file (sort @paths) {
+ my $f = $file;
+ $f = "$1$renames{$2}" if $f =~ /^(.*\/)(\w+\.\w+)$/ && $renames{$2};
+ $newFile{$file} = $f if $f ne $file;
+}
+
+for my $file (sort @paths) {
+ if ($newFile{$file}) {
+ my $newFile = $newFile{$file};
+ print "Renaming $file to $newFile\n";
+ scmMoveOrRenameFile($file, $newFile);
+ }
+}
+
+# change all file contents
+
+for my $file (sort @paths) {
+ $file = $newFile{$file} if $newFile{$file};
+ my $contents;
+ {
+ local $/;
+ open FILE, $file or die;
+ $contents = <FILE>;
+ close FILE;
+ }
+ my $newContents = $contents;
+
+ for my $from (keys %renames) {
+ $newContents =~ s/\b\Q$from\E(?!\w)/$renames{$from}/g; # this " unconfuses Xcode syntax highlighting
+ }
+
+ if ($newContents ne $contents) {
+ open FILE, ">", $file or die;
+ print FILE $newContents;
+ close FILE;
+ }
+}
diff --git a/Tools/Scripts/do-webcore-rename b/Tools/Scripts/do-webcore-rename
new file mode 100755
index 0000000..6dcb719
--- /dev/null
+++ b/Tools/Scripts/do-webcore-rename
@@ -0,0 +1,247 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 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.
+
+# Script to do a rename in JavaScriptCore, WebCore, and WebKit.
+
+use strict;
+
+use File::Find;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+
+use lib $FindBin::Bin;
+use webkitdirs;
+use VCSUtils;
+
+setConfiguration();
+chdirWebKit();
+
+my $showHelp;
+my $verbose;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options]
+ -h|--help Show this help message
+ -v|--verbose More verbose output
+EOF
+
+my $getOptionsResult = GetOptions(
+ 'help|h' => \$showHelp,
+ 'verbose|v' => \$verbose,
+);
+
+if (!$getOptionsResult || $showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+my @directoriesToIgnoreList = (
+ "icu",
+);
+my %directoriesToIgnore = map { $_ => 1 } @directoriesToIgnoreList;
+
+# find all files we want to process
+
+my @paths;
+find(\&wanted, "JavaScriptCore");
+find(\&wanted, "JavaScriptGlue");
+find(\&wanted, "WebCore");
+find(\&wanted, "WebKit");
+find(\&wanted, "WebKit2");
+
+sub wanted
+{
+ my $file = $_;
+
+ # Ignore excluded and hidden files/directories.
+ if ($directoriesToIgnore{$file} or $file =~ /^\../ or $file =~ /^ChangeLog/) {
+ print "Ignoring $File::Find::name\n" if $verbose;
+ $File::Find::prune = 1;
+ return;
+ }
+
+ return if -d $file;
+
+ push @paths, $File::Find::name;
+}
+
+# Setting isDOMTypeRename to 1 rather than 0 expands the regexps used
+# below to handle custom JavaScript bindings.
+my $isDOMTypeRename = 0;
+my %renames = (
+ # Renames go here in the form of:
+ "DocLoader" => "CachedResourceLoader",
+);
+
+my %renamesContemplatedForTheFuture = (
+ "HTMLPlugInImageElement" => "HTMLEmbeddedObjectElement",
+
+ "DOMObject" => "JSDOMObject",
+
+ "runtimeObjectGetter" => "pluginElementGetter",
+ "runtimeObjectPropertyGetter" => "pluginElementPropertyGetter",
+ "runtimeObjectCustomGetOwnPropertySlot" => "pluginElementCustomGetOwnPropertySlot",
+ "runtimeObjectCustomPut" => "pluginElementCustomPut",
+ "runtimeObjectImplementsCall" => "pluginElementImplementsCall",
+ "runtimeObjectCallAsFunction" => "pluginElementCallAsFunction",
+
+ "CLONE_CONTENTS" => "Clone",
+ "DELETE_CONTENTS" => "Delete",
+ "EXTRACT_CONTENTS" => "Extract",
+
+ "DateInstance" => "JSDate",
+ "ErrorInstance" => "JSError",
+
+ "KURL" => "URL",
+ "KURLCFNet" => "URLCF",
+ "KURLHash" => "URLHash",
+ "KURLMac" => "URLMac",
+ "KURL_h" => "URL_h",
+
+ "ThreadSafeSharedBase" => "ThreadSafeRefCountedBase",
+ "ThreadSafeShared" => "ThreadSafeRefCounted",
+ "TreeShared" => "TreeRefCounted",
+
+ "StringImpl" => "SharedString",
+
+ "RenderView" => "RenderViewport",
+
+ "ObjcFallbackObjectImp" => "ObjCFallbackObject",
+ "RuntimeObjectImp" => "ForeignObject",
+
+ "runtime_array" => "BridgedArray",
+ "runtime_method" => "BridgedFunction",
+ "runtime_object" => "BridgedObject",
+ "objc_runtime" => "ObjCBridge",
+
+ "equalIgnoringCase" => "equalFoldingCase",
+
+ "FTPDirectoryTokenizer" => "FTPDirectoryDocumentBuilder",
+ "HTMLTokenizer" => "HTMLDocumentBuilder",
+ "ImageTokenizer" => "ImageDocumentBuilder",
+ "PluginTokenizer" => "PluginDocumentBuilder",
+ "TextTokenizer" => "TextDocumentBuilder",
+ "Tokenizer" => "DocumentBuilder",
+ "Tokenizer_h" => "DocumentBuilder_h",
+ "XMLTokenizer" => "XMLDocumentBuilder",
+ "isHTMLTokenizer" => "isHTMLDocumentBuilder",
+ "m_tokenizer" => "m_builder",
+ "createTokenizer" => "createBuilder",
+ "tokenizerProcessedData" => "documentBuilderProcessedData",
+
+ "WTF_UNICODE_H" => "Unicode_h",
+ "WTF_UNICODE_ICU_H" => "UnicodeICU_h",
+ "WTF_UNICODE_QT4_H" => "UnicodeQt4_h",
+ "UnicodeIcu" => "UnicodeICU",
+
+ "m_invertibleCTM" => "m_transformIsInvertible",
+
+ "NativeFunctionWrapper_h" => "JSHostFunction_h",
+ "NativeFunctionWrapper" => "JSHostFunction",
+ "nativeFunctionThunk" => "hostFunctionThunk",
+ "nativeFunction" => "hostFunction",
+ "NativeFunction" => "HostFunction",
+);
+
+# Sort the keys of the renames hash in order of decreasing length. This
+# handles the case where some of the renames are substrings of others;
+# i.e., "Foo" => "Bar" and "FooBuffer" => "BarBuffer".
+my @sortedRenameKeys = sort { length($b) - length($a) } keys %renames;
+
+# rename files
+
+sub renameFile
+{
+ my $file = shift;
+
+ if ($isDOMTypeRename) {
+ # Find the longest key in %renames which matches this more permissive regexp.
+ # (The old regexp would match ".../Foo.cpp" but not ".../JSFooCustom.cpp".)
+ # This handles renaming of custom JavaScript bindings even when some of the
+ # renames are substrings of others. The only reason we don't do this all the
+ # time is to avoid accidental file renamings for short, non-DOM renames.
+ for my $key (@sortedRenameKeys) {
+ my $newFile = "";
+ $newFile = "$1$renames{$2}$3" if $file =~ /^(.*\/\w*)($key)(\w*\.\w+)$/;
+ if ($newFile ne "") {
+ return $newFile;
+ }
+ }
+ } else {
+ $file = "$1$renames{$2}$3" if $file =~ /^(.*\/)(\w+)(\.\w+)$/ && $renames{$2};
+ }
+ return $file;
+}
+
+my %newFile;
+for my $file (sort @paths) {
+ my $f = renameFile($file);
+ if ($f ne $file) {
+ $newFile{$file} = $f;
+ }
+}
+
+for my $file (sort @paths) {
+ if ($newFile{$file}) {
+ my $newFile = $newFile{$file};
+ print "Renaming $file to $newFile\n";
+ scmMoveOrRenameFile($file, $newFile);
+ }
+}
+
+# change all file contents
+
+for my $file (sort @paths) {
+ $file = $newFile{$file} if $newFile{$file};
+ my $contents;
+ {
+ local $/;
+ open FILE, $file or die "Failed to open $file";
+ $contents = <FILE>;
+ close FILE;
+ }
+ my $newContents = $contents;
+
+ if ($isDOMTypeRename) {
+ for my $from (@sortedRenameKeys) {
+ # Handle JavaScript custom bindings.
+ $newContents =~ s/\b(JS|V8|to|)$from/$1$renames{$from}/g;
+ }
+ } else {
+ for my $from (@sortedRenameKeys) {
+ $newContents =~ s/\b$from(?!["\w])/$renames{$from}/g; # this " unconfuses Xcode syntax highlighting
+ }
+ }
+
+ if ($newContents ne $contents) {
+ open FILE, ">", $file or die "Failed to open $file";
+ print FILE $newContents;
+ close FILE;
+ }
+}
diff --git a/Tools/Scripts/ensure-valid-python b/Tools/Scripts/ensure-valid-python
new file mode 100755
index 0000000..aede812
--- /dev/null
+++ b/Tools/Scripts/ensure-valid-python
@@ -0,0 +1,152 @@
+#!/usr/bin/perl -w
+# 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.
+# 3. Neither the name of Apple 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.
+
+use strict;
+
+use File::Basename;
+use File::Spec;
+use File::Temp qw(tempdir);
+use FindBin;
+use Getopt::Long;
+
+use lib $FindBin::Bin;
+use webkitdirs;
+use VCSUtils;
+
+my $macPythonURL = "http://www.python.org/ftp/python/2.6.5/python-2.6.5-macosx10.3-2010-03-24.dmg";
+my $macPythonMD5 = "84489bba813fdbb6041b69d4310a86da";
+my $macPythonInstallerName = "Python.mpkg";
+
+# We could use a consistent download location, like the source or build directory.
+my $tempDirectory = File::Temp::tempdir("WebKitPythonXXXX", TMPDIR => 1, CLEANUP => 1);
+my $downloadDirectory = $tempDirectory;
+my $mountPoint = File::Spec->join($tempDirectory, "mount");
+
+sub checkPythonVersion()
+{
+ # Will exit 0 if Python is 2.5 or greater, non-zero otherwise.
+ `python -c "import sys;sys.exit(sys.version_info[:2] < (2,5))"`;
+ return exitStatus($?) == 0;
+}
+
+sub downloadFileToPath($$)
+{
+ my ($remoteURL, $localPath) = @_;
+ print "Downloading $remoteURL to $localPath\n";
+ my $exitCode = system("curl", "-o", $localPath, $remoteURL);
+ return exitStatus($exitCode) == 0;
+}
+
+sub checkMD5($$)
+{
+ my ($path, $expectedMD5) = @_;
+ my $md5Output = `md5 -q "$path"`;
+ chomp($md5Output);
+ my $isValid = $md5Output eq $expectedMD5;
+ print "'$md5Output' does not match expected: '$expectedMD5'\n" unless $isValid;
+ return $isValid;
+}
+
+sub mountDMG($$)
+{
+ my ($dmgPath, $mountPoint) = @_;
+ print "Mounting $dmgPath at $mountPoint\n";
+ return system("hdiutil", "attach", "-mountpoint", $mountPoint, "-nobrowse", $dmgPath) == 0;
+}
+
+sub unmountDMG($)
+{
+ my ($mountPoint) = @_;
+ print "Unmounting disk image from $mountPoint\n";
+ my $exitCode = system("hdiutil", "detach", $mountPoint);
+ return exitStatus($exitCode) == 0;
+}
+
+sub runInstaller($)
+{
+ my ($installerPackage) = @_;
+ print "sudo will now ask for your password to run the Python installer.\n";
+ print "The installer will install Python in /Library/Frameworks/Python.framework\n";
+ print "and add symlinks from /usr/local/bin.\n";
+ return system("sudo", "installer", "-verbose", "-pkg", $installerPackage, "-target", "/") == 0;
+}
+
+sub downloadAndMountMacPythonDMG($$)
+{
+ my ($pythonURL, $pythonMD5) = @_;
+ my $localFilename = basename($pythonURL);
+ my $localPath = File::Spec->join($downloadDirectory, $localFilename);
+
+ downloadFileToPath($pythonURL, $localPath) or die "Failed to download $pythonURL";
+ checkMD5($localPath, $pythonMD5) or die "MD5 check failed on $localPath";
+ return mountDMG($localPath, $mountPoint);
+}
+
+sub installMacPython()
+{
+ downloadAndMountMacPythonDMG($macPythonURL, $macPythonMD5) or die "Failed to download and mount disk image.";
+ print "Mounted python install image at: $mountPoint\n";
+ my $installerPackage = File::Spec->join($mountPoint, $macPythonInstallerName);
+ my $installSuccess = runInstaller($installerPackage);
+ unmountDMG($mountPoint) or die "Failed to unmount disk image from $mountPoint";
+ return $installSuccess;
+}
+
+sub main()
+{
+ my $checkOnly = 0;
+ my $showHelp = 0;
+ my $getOptionsResult = GetOptions(
+ 'check-only!' => \$checkOnly,
+ 'help|h' => \$showHelp,
+ );
+ if (!$getOptionsResult || $showHelp) {
+ print STDERR <<HELP;
+Usage: $0 [options]
+ --check-only Check python version only.
+ -h|--help Show this help message.
+HELP
+ return 1;
+ }
+ # Congrats, your Python is fine.
+ return 0 if checkPythonVersion();
+
+ return 1 if $checkOnly;
+
+ if (!isTiger()) {
+ print "Your Python version is insufficient to run WebKit's Python code. Please update.\n";
+ print "See http://trac.webkit.org/wiki/PythonGuidelines for more info.\n";
+ return 1;
+ }
+
+ installMacPython() or die "Failed to install Python.";
+
+ checkPythonVersion() or die "Final version check failed, must have failed to update Python";
+ print "Successfully updated python.\n";
+}
+
+exit(main());
diff --git a/Tools/Scripts/execAppWithEnv b/Tools/Scripts/execAppWithEnv
new file mode 100755
index 0000000..d185e2f
--- /dev/null
+++ b/Tools/Scripts/execAppWithEnv
@@ -0,0 +1,38 @@
+#!/usr/bin/perl
+
+# 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.
+
+# This script launches a program with a given enviroment.
+# It is a workaround for a perl bug that apps launched from perl threads
+# use the environment of the main thread instead of the current thread.
+
+my ($unsplitEnvVar, @app) = @ARGV;
+# The first argument to this script should be perl code (in quotes) that sets the environment.
+eval substr($unsplitEnvVar, 1, -1);
+exec(@app);
diff --git a/Tools/Scripts/extract-localizable-strings b/Tools/Scripts/extract-localizable-strings
new file mode 100755
index 0000000..b31550a
--- /dev/null
+++ b/Tools/Scripts/extract-localizable-strings
@@ -0,0 +1,390 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2006, 2007, 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.
+
+# This script is like the genstrings tool (minus most of the options) with these differences.
+#
+# 1) It uses the names UI_STRING and UI_STRING_WITH_KEY for the macros, rather than the macros
+# from NSBundle.h, and doesn't support tables (although they would be easy to add).
+# 2) It supports UTF-8 in key strings (and hence uses "" strings rather than @"" strings;
+# @"" strings only reliably support ASCII since they are decoded based on the system encoding
+# at runtime, so give different results on US and Japanese systems for example).
+# 3) It looks for strings that are not marked for localization, using both macro names that are
+# known to be used for debugging in Intrigue source code and an exceptions file.
+# 4) It finds the files to work on rather than taking them as parameters, and also uses a
+# hardcoded location for both the output file and the exceptions file.
+# It would have been nice to use the project to find the source files, but it's too hard to
+# locate source files after parsing a .pbxproj file.
+
+# The exceptions file has a list of strings in quotes, filenames, and filename/string pairs separated by :.
+
+use strict;
+
+sub UnescapeHexSequence($);
+
+my %isDebugMacro = ( ASSERT_WITH_MESSAGE => 1, LOG_ERROR => 1, ERROR => 1, NSURL_ERROR => 1, FATAL => 1, LOG => 1, LOG_WARNING => 1, UI_STRING_LOCALIZE_LATER => 1, LPCTSTR_UI_STRING_LOCALIZE_LATER => 1, UNLOCALIZED_STRING => 1, UNLOCALIZED_LPCTSTR => 1, dprintf => 1, NSException => 1, NSLog => 1, printf => 1 );
+
+@ARGV >= 2 or die "Usage: extract-localizable-strings <exceptions file> <file to update> [ directory... ]\nDid you mean to run update-webkit-localizable-strings instead?\n";
+
+my $exceptionsFile = shift @ARGV;
+-f $exceptionsFile or die "Couldn't find exceptions file $exceptionsFile\n";
+
+my $fileToUpdate = shift @ARGV;
+-f $fileToUpdate or die "Couldn't find file to update $fileToUpdate\n";
+
+my @directories = ();
+my @directoriesToSkip = ();
+if (@ARGV < 1) {
+ push(@directories, ".");
+} else {
+ for my $dir (@ARGV) {
+ if ($dir =~ /^-(.*)$/) {
+ push @directoriesToSkip, $1;
+ } else {
+ push @directories, $dir;
+ }
+ }
+}
+
+my $sawError = 0;
+
+my $localizedCount = 0;
+my $keyCollisionCount = 0;
+my $notLocalizedCount = 0;
+my $NSLocalizeCount = 0;
+
+my %exception;
+my %usedException;
+
+if (open EXCEPTIONS, $exceptionsFile) {
+ while (<EXCEPTIONS>) {
+ chomp;
+ if (/^"([^\\"]|\\.)*"$/ or /^[-_\/\w.]+.(h|m|mm|c|cpp)$/ or /^[-_\/\w.]+.(h|m|mm|c|cpp):"([^\\"]|\\.)*"$/) {
+ if ($exception{$_}) {
+ print "$exceptionsFile:$.:exception for $_ appears twice\n";
+ print "$exceptionsFile:$exception{$_}:first appearance\n";
+ } else {
+ $exception{$_} = $.;
+ }
+ } else {
+ print "$exceptionsFile:$.:syntax error\n";
+ }
+ }
+ close EXCEPTIONS;
+}
+
+my $quotedDirectoriesString = '"' . join('" "', @directories) . '"';
+for my $dir (@directoriesToSkip) {
+ $quotedDirectoriesString .= ' -path "' . $dir . '" -prune -o';
+}
+
+my @files = ( split "\n", `find $quotedDirectoriesString \\( -name "*.h" -o -name "*.m" -o -name "*.mm" -o -name "*.c" -o -name "*.cpp" \\)` );
+
+for my $file (sort @files) {
+ next if $file =~ /\/\w+LocalizableStrings\.h$/;
+
+ $file =~ s-^./--;
+
+ open SOURCE, $file or die "can't open $file\n";
+
+ my $inComment = 0;
+
+ my $expected = "";
+ my $macroLine;
+ my $macro;
+ my $UIString;
+ my $key;
+ my $comment;
+
+ my $string;
+ my $stringLine;
+ my $nestingLevel;
+
+ my $previousToken = "";
+
+ while (<SOURCE>) {
+ chomp;
+
+ # Handle continued multi-line comment.
+ if ($inComment) {
+ next unless s-.*\*/--;
+ $inComment = 0;
+ }
+
+ # Handle all the tokens in the line.
+ while (s-^\s*([#\w]+|/\*|//|[^#\w/'"()\[\],]+|.)--) {
+ my $token = $1;
+
+ if ($token eq "\"") {
+ if ($expected and $expected ne "a quoted string") {
+ print "$file:$.:ERROR:found a quoted string but expected $expected\n";
+ $sawError = 1;
+ $expected = "";
+ }
+ if (s-^(([^\\$token]|\\.)*?)$token--) {
+ if (!defined $string) {
+ $stringLine = $.;
+ $string = $1;
+ } else {
+ $string .= $1;
+ }
+ } else {
+ print "$file:$.:ERROR:mismatched quotes\n";
+ $sawError = 1;
+ $_ = "";
+ }
+ next;
+ }
+
+ if (defined $string) {
+handleString:
+ if ($expected) {
+ if (!defined $UIString) {
+ # FIXME: Validate UTF-8 here?
+ $UIString = $string;
+ $expected = ",";
+ } elsif (($macro =~ /UI_STRING_KEY$/) and !defined $key) {
+ # FIXME: Validate UTF-8 here?
+ $key = $string;
+ $expected = ",";
+ } elsif (!defined $comment) {
+ # FIXME: Validate UTF-8 here?
+ $comment = $string;
+ $expected = ")";
+ }
+ } else {
+ if (defined $nestingLevel) {
+ # In a debug macro, no need to localize.
+ } elsif ($previousToken eq "#include" or $previousToken eq "#import") {
+ # File name, no need to localize.
+ } elsif ($previousToken eq "extern" and $string eq "C") {
+ # extern "C", no need to localize.
+ } elsif ($string eq "") {
+ # Empty string can sometimes be localized, but we need not complain if not.
+ } elsif ($exception{$file}) {
+ $usedException{$file} = 1;
+ } elsif ($exception{"\"$string\""}) {
+ $usedException{"\"$string\""} = 1;
+ } elsif ($exception{"$file:\"$string\""}) {
+ $usedException{"$file:\"$string\""} = 1;
+ } else {
+ print "$file:$stringLine:\"$string\" is not marked for localization\n";
+ $notLocalizedCount++;
+ }
+ }
+ $string = undef;
+ last if !defined $token;
+ }
+
+ $previousToken = $token;
+
+ if ($token =~ /^NSLocalized/ && $token !~ /NSLocalizedDescriptionKey/ && $token !~ /NSLocalizedStringFromTableInBundle/) {
+ print "$file:$.:ERROR:found a use of an NSLocalized macro; not supported\n";
+ $nestingLevel = 0 if !defined $nestingLevel;
+ $sawError = 1;
+ $NSLocalizeCount++;
+ } elsif ($token eq "/*") {
+ if (!s-^.*?\*/--) {
+ $_ = ""; # If the comment doesn't end, discard the result of the line and set flag
+ $inComment = 1;
+ }
+ } elsif ($token eq "//") {
+ $_ = ""; # Discard the rest of the line
+ } elsif ($token eq "'") {
+ if (!s-([^\\]|\\.)'--) { #' <-- that single quote makes the Project Builder editor less confused
+ print "$file:$.:ERROR:mismatched single quote\n";
+ $sawError = 1;
+ $_ = "";
+ }
+ } else {
+ if ($expected and $expected ne $token) {
+ print "$file:$.:ERROR:found $token but expected $expected\n";
+ $sawError = 1;
+ $expected = "";
+ }
+ if ($token =~ /UI_STRING(_KEY)?$/) {
+ $expected = "(";
+ $macro = $token;
+ $UIString = undef;
+ $key = undef;
+ $comment = undef;
+ $macroLine = $.;
+ } elsif ($token eq "(" or $token eq "[") {
+ ++$nestingLevel if defined $nestingLevel;
+ $expected = "a quoted string" if $expected;
+ } elsif ($token eq ",") {
+ $expected = "a quoted string" if $expected;
+ } elsif ($token eq ")" or $token eq "]") {
+ $nestingLevel = undef if defined $nestingLevel && !--$nestingLevel;
+ if ($expected) {
+ $key = $UIString if !defined $key;
+ HandleUIString($UIString, $key, $comment, $file, $macroLine);
+ $macro = "";
+ $expected = "";
+ $localizedCount++;
+ }
+ } elsif ($isDebugMacro{$token}) {
+ $nestingLevel = 0 if !defined $nestingLevel;
+ }
+ }
+ }
+
+ }
+
+ goto handleString if defined $string;
+
+ if ($expected) {
+ print "$file:ERROR:reached end of file but expected $expected\n";
+ $sawError = 1;
+ }
+
+ close SOURCE;
+}
+
+# Unescapes C language hexadecimal escape sequences.
+sub UnescapeHexSequence($)
+{
+ my ($originalStr) = @_;
+
+ my $escapedStr = $originalStr;
+ my $unescapedStr = "";
+
+ for (;;) {
+ if ($escapedStr =~ s-^\\x([[:xdigit:]]+)--) {
+ if (256 <= hex($1)) {
+ print "Hexadecimal escape sequence out of range: \\x$1\n";
+ return undef;
+ }
+ $unescapedStr .= pack("H*", $1);
+ } elsif ($escapedStr =~ s-^(.)--) {
+ $unescapedStr .= $1;
+ } else {
+ return $unescapedStr;
+ }
+ }
+}
+
+my %stringByKey;
+my %commentByKey;
+my %fileByKey;
+my %lineByKey;
+
+sub HandleUIString
+{
+ my ($string, $key, $comment, $file, $line) = @_;
+
+ my $bad = 0;
+ $string = UnescapeHexSequence($string);
+ if (!defined($string)) {
+ print "$file:$line:ERROR:string has an illegal hexadecimal escape sequence\n";
+ $bad = 1;
+ }
+ $key = UnescapeHexSequence($key);
+ if (!defined($key)) {
+ print "$file:$line:ERROR:key has an illegal hexadecimal escape sequence\n";
+ $bad = 1;
+ }
+ $comment = UnescapeHexSequence($comment);
+ if (!defined($comment)) {
+ print "$file:$line:ERROR:comment has an illegal hexadecimal escape sequence\n";
+ $bad = 1;
+ }
+ if (grep { $_ == 0xFFFD } unpack "U*", $string) {
+ print "$file:$line:ERROR:string for translation has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
+ $bad = 1;
+ }
+ if ($string ne $key && grep { $_ == 0xFFFD } unpack "U*", $key) {
+ print "$file:$line:ERROR:key has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
+ $bad = 1;
+ }
+ if (grep { $_ == 0xFFFD } unpack "U*", $comment) {
+ print "$file:$line:ERROR:comment for translation has illegal UTF-8 -- most likely a problem with the Text Encoding of the source file\n";
+ $bad = 1;
+ }
+ if ($bad) {
+ $sawError = 1;
+ return;
+ }
+
+ if ($stringByKey{$key} && $stringByKey{$key} ne $string) {
+ print "$file:$line:encountered the same key, \"$key\", twice, with different strings\n";
+ print "$fileByKey{$key}:$lineByKey{$key}:previous occurrence\n";
+ $keyCollisionCount++;
+ return;
+ }
+ if ($commentByKey{$key} && $commentByKey{$key} ne $comment) {
+ print "$file:$line:encountered the same key, \"$key\", twice, with different comments\n";
+ print "$fileByKey{$key}:$lineByKey{$key}:previous occurrence\n";
+ $keyCollisionCount++;
+ return;
+ }
+
+ $fileByKey{$key} = $file;
+ $lineByKey{$key} = $line;
+ $stringByKey{$key} = $string;
+ $commentByKey{$key} = $comment;
+}
+
+print "\n" if $sawError || $notLocalizedCount || $NSLocalizeCount;
+
+my @unusedExceptions = sort grep { !$usedException{$_} } keys %exception;
+if (@unusedExceptions) {
+ for my $unused (@unusedExceptions) {
+ print "$exceptionsFile:$exception{$unused}:exception $unused not used\n";
+ }
+ print "\n";
+}
+
+print "$localizedCount localizable strings\n" if $localizedCount;
+print "$keyCollisionCount key collisions\n" if $keyCollisionCount;
+print "$notLocalizedCount strings not marked for localization\n" if $notLocalizedCount;
+print "$NSLocalizeCount uses of NSLocalize\n" if $NSLocalizeCount;
+print scalar(@unusedExceptions), " unused exceptions\n" if @unusedExceptions;
+
+if ($sawError) {
+ print "\nErrors encountered. Exiting without writing to $fileToUpdate.\n";
+ exit 1;
+}
+
+my $localizedStrings = "";
+
+for my $key (sort keys %commentByKey) {
+ $localizedStrings .= "/* $commentByKey{$key} */\n\"$key\" = \"$stringByKey{$key}\";\n\n";
+}
+
+# Write out the strings file in UTF-16 with a BOM.
+utf8::decode($localizedStrings) if $^V ge v5.8;
+my $output = pack "n*", (0xFEFF, unpack "U*", $localizedStrings);
+
+if (-e "$fileToUpdate") {
+ open STRINGS, ">", "$fileToUpdate" or die;
+ print STRINGS $output;
+ close STRINGS;
+} else {
+ print "$fileToUpdate does not exist\n";
+ exit 1;
+}
diff --git a/Tools/Scripts/find-extra-includes b/Tools/Scripts/find-extra-includes
new file mode 100755
index 0000000..4a847ed
--- /dev/null
+++ b/Tools/Scripts/find-extra-includes
@@ -0,0 +1,102 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# "find-extra-includes" script for WebKit Open Source Project
+
+use strict;
+use File::Find;
+
+find(\&wanted, @ARGV ? @ARGV : ".");
+
+my %paths;
+my %includes;
+
+sub wanted
+{
+ my $file = $_;
+
+ if ($file eq "icu") {
+ $File::Find::prune = 1;
+ return;
+ }
+
+ if ($file !~ /^\./ && $file =~ /\.(h|cpp|c|mm|m)$/) {
+ $paths{$file} = $File::Find::name;
+ open FILE, $file or die;
+ while (<FILE>) {
+ if (m-^\s*#\s*(include|import)\s+["<]((\S+/)*)(\S+)[">]-) {
+ my $include = ($2 eq "sys/" ? $2 : "") . $4;
+ $includes{$file}{$include}++;
+ }
+ }
+ close FILE;
+ }
+}
+
+my %totalIncludes;
+
+sub fillOut
+{
+ my ($file) = @_;
+
+ return if defined $totalIncludes{$file};
+
+ for my $include (keys %{ $includes{$file} }) {
+ $totalIncludes{$file}{$include} = 1;
+ fillOut($include);
+ for my $i (keys %{ $totalIncludes{$include} }) {
+ $totalIncludes{$file}{$i} = 1;
+ }
+ }
+}
+
+sub check
+{
+ my ($file) = @_;
+
+ for my $include (keys %{ $includes{$file} }) {
+ fillOut($include);
+ }
+ for my $i1 (sort keys %{ $includes{$file} }) {
+ for my $i2 (keys %{ $includes{$file} }) {
+ next if $i1 eq $i2;
+ if ($totalIncludes{$i2}{$i1}) {
+ my $b1 = $i1;
+ my $b2 = $file;
+ $b1 =~ s/\..+$//;
+ $b2 =~ s/\..+$//;
+ print "$paths{$file} does not need to include $i1, because $i2 does\n" if $b1 ne $b2;
+ last;
+ }
+ }
+ }
+}
+
+for my $file (sort keys %includes) {
+ check($file);
+}
diff --git a/Tools/Scripts/find-included-framework-headers b/Tools/Scripts/find-included-framework-headers
new file mode 100755
index 0000000..759a60b
--- /dev/null
+++ b/Tools/Scripts/find-included-framework-headers
@@ -0,0 +1,30 @@
+#!/bin/sh
+# 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 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.
+#
+# A script to find headers included from the given frameworks by files in the
+# current directory (and subdirectories).
+
+for framework in $*; do
+ echo -e "\n$framework\n=================="
+ find . \( -name '*.cpp' -o -name '*.h' -o -name '*.m' -o -name '*.mm' \) -exec grep "<$framework/" {} ';' | sed -e 's|.*/\(.*\.h\).*|\1|' | sort -u
+done
diff --git a/Tools/Scripts/gdb-safari b/Tools/Scripts/gdb-safari
new file mode 100755
index 0000000..9776212
--- /dev/null
+++ b/Tools/Scripts/gdb-safari
@@ -0,0 +1,53 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Simplified "run under gdb" script for WebKit Open Source Project.
+
+use strict;
+use File::Temp qw/:mktemp/;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+my $productDir = productDir();
+my $safariPath = safariPath();
+
+# Check to see that gdb is in the usual place.
+my $gdbPath = "/usr/bin/gdb";
+die "Can't find gdb executable. Is gdb installed?\n" unless -x $gdbPath;
+
+# Check to see that all the frameworks are built.
+checkFrameworks();
+
+$ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+$ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = 'YES';
+
+print "Starting Safari under gdb with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+my @architectureFlags = ("-arch", architecture()) if !isTiger();
+exec $gdbPath, @architectureFlags, $safariPath or die;
diff --git a/Tools/Scripts/generate-coverage-data b/Tools/Scripts/generate-coverage-data
new file mode 100755
index 0000000..c97d086
--- /dev/null
+++ b/Tools/Scripts/generate-coverage-data
@@ -0,0 +1,71 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+# Copyright (C) 2007 Holger Hans Peter Freyther. 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.
+
+# Simple script to build, run and visualize coverage information
+
+use strict;
+use File::Basename;
+use File::Spec;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+# Generate a name for our results
+my $svnVersion = determineCurrentSVNRevision();
+my @timeData = localtime(time);
+my $resultName = $svnVersion . "-" . join('_', @timeData);
+my @otherOptions = ();
+
+# Move to the source directory
+# Delete old gcov files
+# Compile WebKit and run the tests
+# Generate the coverage graph...
+# Upload
+
+$ENV{'WEBKIT_COVERAGE_BUILD'} = 1;
+chdirWebKit();
+
+# Clean-up old files
+print "Cleaning up\n";
+system("if [ -d WebKitBuild ]; then find WebKitBuild -name '*.gcda' -delete; fi;") == 0 or die;
+
+
+print "Building and testing\n";
+system("Tools/Scripts/build-webkit", "--coverage", @ARGV) == 0 or die;
+system "Tools/Scripts/run-webkit-tests", "--no-launch-safari";
+system "Tools/Scripts/run-javascriptcore-tests", "--coverage", @ARGV;
+
+# Collect the data and generate a report
+print "Collecting coverage data\n";
+system("Tools/CodeCoverage/run-generate-coverage-data", $resultName, "WebKitBuild/Coverage") == 0 or die;
+system("Tools/CodeCoverage/regenerate-coverage-display", "WebKitBuild/Coverage", "WebKitBuild/Coverage/html") == 0 or die;
+
+print "Done\n";
diff --git a/Tools/Scripts/generate-qt-inspector-resource b/Tools/Scripts/generate-qt-inspector-resource
new file mode 100755
index 0000000..a65da13
--- /dev/null
+++ b/Tools/Scripts/generate-qt-inspector-resource
@@ -0,0 +1,53 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2008 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.
+
+# Regenerate WebCore/inspector/front-end/WebKit.qrc from the content of WebCore/inspector/front-end/
+
+sub addFiles(@)
+{
+ my @files = @_;
+
+ foreach $file (@files) {
+ $file =~ s,WebCore/inspector/front-end/,,;
+ print WEBKIT_QRC " <file>".$file . "</file>\n";
+ }
+}
+
+# Setup
+open(WEBKIT_QRC, ">WebCore/inspector/front-end/WebKit.qrc") or die;
+print WEBKIT_QRC '<!DOCTYPE RCC><RCC version="1.0">'."\n";
+print WEBKIT_QRC '<qresource prefix="/webkit/inspector">'."\n";
+
+
+# Directory with html and js files and the images
+addFiles(<WebCore/inspector/front-end/*.{*html,js,css,svg}>);
+addFiles(<WebCore/inspector/front-end/Images/*>);
+
+print WEBKIT_QRC "</qresource>\n";
+print WEBKIT_QRC "</RCC>\n";
+close(WEBKIT_QRC);
diff --git a/Tools/Scripts/make-script-test-wrappers b/Tools/Scripts/make-script-test-wrappers
new file mode 100755
index 0000000..aed1834
--- /dev/null
+++ b/Tools/Scripts/make-script-test-wrappers
@@ -0,0 +1,141 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 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.
+
+# Script to generate HTML wrappers for JavaScript tests from templates
+
+use strict;
+
+use FindBin;
+use lib $FindBin::Bin;
+
+use File::Basename;
+use File::Find;
+use Getopt::Long;
+use webkitdirs;
+
+sub directoryFilter;
+sub findTemplateFiles(@);
+
+my $showHelp;
+
+my $result = GetOptions(
+ "help" => \$showHelp,
+);
+
+if (!$result || $showHelp) {
+ print STDERR basename($0) . " [-h|--help] [path ...]\n";
+ exit 1;
+}
+
+setConfiguration();
+my $productDir = productDir();
+
+chdirWebKit();
+
+my @templates = findTemplateFiles(@ARGV);
+
+for my $tfile (@templates) {
+
+ my $tpath = $tfile;
+ my $templateDirectory;
+ my $templateRelativePath;
+ if ($tpath =~ s:/(script-tests)/TEMPLATE.html$::) {
+ $templateDirectory = $1;
+ $templateRelativePath = $1 . "/TEMPLATE.html";
+ } else {
+ print "Inappropriate position of a template: ${tpath}\n";
+ next;
+ }
+
+ print "${tpath}\n";
+
+ chdirWebKit();
+ chdir($tpath);
+
+ my @files;
+ my $fileFilter = sub {
+ push @files, $File::Find::name if substr($_, -3) eq ".js";
+ };
+ find({ preprocess => \&directoryFilter, wanted => $fileFilter }, $templateDirectory);
+
+ open TEMPLATE, "<${templateRelativePath}";
+ my $template = do { local $/; <TEMPLATE> };
+ close TEMPLATE;
+
+ my $templateNegative = $template;
+ if (-e "${templateDirectory}/TEMPLATE-n.html") {
+ open TEMPLATE, "<${templateDirectory}/TEMPLATE-n.html";
+ $templateNegative = do { local $/; <TEMPLATE> };
+ close TEMPLATE;
+ }
+
+ for my $file (@files) {
+ my $html = $file;
+ $html =~ s:${templateDirectory}/(.*)\.js:$1.html:;
+ next if -f "$html-disabled";
+
+ system("cat ${file} | tr '\\0' ' ' | grep -q 'successfullyParsed ='");
+ if ($? != 0) {
+ `echo "" >> "${file}"`;
+ `echo "var successfullyParsed = true;" >> "${file}"`;
+ }
+
+ print " ${html}\n";
+ open HTML, ">$html";
+ my $output = ($file =~ /-n\.js/) ? $templateNegative : $template;
+ $output =~ s:YOUR_JS_FILE_HERE:$file:;
+ print HTML $output;
+
+ close HTML;
+ }
+}
+
+exit 0;
+
+sub directoryFilter
+{
+ return () if basename($File::Find::dir) eq ".svn";
+ return @_;
+}
+
+sub findTemplateFiles(@) {
+ my @args = @_;
+ my @templateFiles;
+
+ push @args, "LayoutTests" if scalar(@args) == 0;
+
+ my @paths = map { -f $_ ? dirname($_) : $_ } @args;
+
+ my $fileFilter = sub {
+ push @templateFiles, $File::Find::name if $_ eq "TEMPLATE.html";
+ };
+
+ find({ preprocess => \&directoryFilter, wanted => $fileFilter }, @paths);
+
+ return @templateFiles;
+}
diff --git a/Tools/Scripts/new-run-webkit-httpd b/Tools/Scripts/new-run-webkit-httpd
new file mode 100755
index 0000000..f6ec164
--- /dev/null
+++ b/Tools/Scripts/new-run-webkit-httpd
@@ -0,0 +1,97 @@
+#!/usr/bin/env python
+# 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.
+
+"""A utility script for starting and stopping the HTTP server with the
+ same configuration as used in the layout tests."""
+
+#
+# FIXME: currently this code only works with the Chromium ports and LigHTTPd.
+# It should be made to work on all ports.
+#
+# This script is also used by Chromium's ui_tests to run http layout tests
+# in a browser.
+#
+import optparse
+import os
+import sys
+import tempfile
+
+scripts_directory = os.path.dirname(os.path.abspath(sys.argv[0]))
+webkitpy_directory = os.path.join(scripts_directory, "webkitpy")
+sys.path.append(os.path.join(webkitpy_directory, "layout_tests"))
+
+import port
+from port import http_server
+
+def run(options):
+ if not options.server:
+ print ('Usage: %s --server {start|stop} [--root=root_dir]'
+ ' [--port=port_number]' % sys.argv[0])
+ else:
+ if (options.root is None) and (options.port is not None):
+ # specifying root but not port means we want httpd on default
+ # set of ports that LayoutTest use, but pointing to a different
+ # source of tests. Specifying port but no root does not seem
+ # meaningful.
+ raise 'Specifying port requires also a root.'
+ port_obj = port.get(None, options)
+ httpd = http_server.Lighttpd(port_obj,
+ tempfile.gettempdir(),
+ port=options.port,
+ root=options.root,
+ run_background=options.run_background)
+ if options.server == 'start':
+ httpd.start()
+ else:
+ httpd.stop(force=True)
+
+
+def main():
+ option_parser = optparse.OptionParser()
+ option_parser.add_option('-k', '--server',
+ help='Server action (start|stop)')
+ option_parser.add_option('-p', '--port',
+ help='Port to listen on (overrides layout test ports)')
+ option_parser.add_option('-r', '--root',
+ help='Absolute path to DocumentRoot (overrides layout test roots)')
+ option_parser.add_option('--register_cygwin', action="store_true",
+ dest="register_cygwin", help='Register Cygwin paths (on Win try bots)')
+ option_parser.add_option('--run_background', action="store_true",
+ dest="run_background",
+ help='Run on background (for running as UI test)')
+ options, args = option_parser.parse_args()
+
+ # FIXME: Make this work with other ports as well.
+ options.chromium = True
+
+ run(options)
+
+
+if '__main__' == __name__:
+ main()
diff --git a/Tools/Scripts/new-run-webkit-tests b/Tools/Scripts/new-run-webkit-tests
new file mode 100755
index 0000000..9fcacaa
--- /dev/null
+++ b/Tools/Scripts/new-run-webkit-tests
@@ -0,0 +1,41 @@
+#!/usr/bin/env python
+# 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.
+
+"""Wrapper around webkitpy/layout_tests/run_webkit_tests.py"""
+import signal
+import sys
+
+import webkitpy.layout_tests.run_webkit_tests as run_webkit_tests
+
+if __name__ == '__main__':
+ try:
+ sys.exit(run_webkit_tests.main())
+ except KeyboardInterrupt:
+ # this mirrors what the shell normally does
+ sys.exit(signal.SIGINT + 128)
diff --git a/Tools/Scripts/new-run-webkit-websocketserver b/Tools/Scripts/new-run-webkit-websocketserver
new file mode 100644
index 0000000..3350582
--- /dev/null
+++ b/Tools/Scripts/new-run-webkit-websocketserver
@@ -0,0 +1,108 @@
+#!/usr/bin/env python
+# 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.
+
+"""A utility script for starting and stopping the web socket server with the
+ same configuration as used in the layout tests."""
+
+import logging
+import optparse
+import tempfile
+
+import webkitpy.layout_tests.port.factory as factory
+import webkitpy.layout_tests.port.websocket_server as websocket_server
+
+
+def main():
+ option_parser = optparse.OptionParser()
+ option_parser.add_option('--server', type='choice',
+ choices=['start', 'stop'], default='start',
+ help='Server action (start|stop).')
+ option_parser.add_option('-p', '--port', dest='port',
+ default=None, help='Port to listen on.')
+ option_parser.add_option('-r', '--root',
+ help='Absolute path to DocumentRoot '
+ '(overrides layout test roots).')
+ option_parser.add_option('-t', '--tls', dest='use_tls',
+ action='store_true',
+ default=False, help='use TLS (wss://).')
+ option_parser.add_option('-k', '--private_key', dest='private_key',
+ default='', help='TLS private key file.')
+ option_parser.add_option('-c', '--certificate', dest='certificate',
+ default='', help='TLS certificate file.')
+ option_parser.add_option('--chromium', action='store_true',
+ dest='chromium',
+ default=False,
+ help='Use the Chromium port.')
+ option_parser.add_option('--register_cygwin', action="store_true",
+ dest="register_cygwin",
+ help='Register Cygwin paths (on Win try bots).')
+ option_parser.add_option('--pidfile', help='path to pid file.')
+ option_parser.add_option('--output-dir', dest='output_dir',
+ default=None, help='output directory.')
+ option_parser.add_option('-v', '--verbose', action='store_true',
+ default=False,
+ help='Include debug-level logging.')
+ options, args = option_parser.parse_args()
+
+ if not options.port:
+ if options.use_tls:
+ # FIXME: We shouldn't grab at this private variable.
+ options.port = websocket_server._DEFAULT_WSS_PORT
+ else:
+ # FIXME: We shouldn't grab at this private variable.
+ options.port = websocket_server._DEFAULT_WS_PORT
+
+ if not options.output_dir:
+ options.output_dir = tempfile.gettempdir()
+
+ kwds = {'port': options.port, 'use_tls': options.use_tls}
+ if options.root:
+ kwds['root'] = options.root
+ if options.private_key:
+ kwds['private_key'] = options.private_key
+ if options.certificate:
+ kwds['certificate'] = options.certificate
+ if options.pidfile:
+ kwds['pidfile'] = options.pidfile
+
+ port_obj = factory.get(options=options)
+ pywebsocket = websocket_server.PyWebSocket(port_obj, options.output_dir, **kwds)
+
+ log_level = logging.WARN
+ if options.verbose:
+ log_level = logging.DEBUG
+ logging.basicConfig(level=log_level)
+
+ if 'start' == options.server:
+ pywebsocket.start()
+ else:
+ pywebsocket.stop(force=True)
+
+if '__main__' == __name__:
+ main()
diff --git a/Tools/Scripts/num-cpus b/Tools/Scripts/num-cpus
new file mode 100755
index 0000000..8a8c97f
--- /dev/null
+++ b/Tools/Scripts/num-cpus
@@ -0,0 +1,6 @@
+#!/usr/bin/perl -w
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+print numberOfCPUs() . "\n";
diff --git a/Tools/Scripts/old-run-webkit-tests b/Tools/Scripts/old-run-webkit-tests
new file mode 100755
index 0000000..ab41e9b
--- /dev/null
+++ b/Tools/Scripts/old-run-webkit-tests
@@ -0,0 +1,2481 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010 Apple Inc. All rights reserved.
+# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+# Copyright (C) 2007 Matt Lilek (pewtermoose@gmail.com)
+# Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+# Copyright (C) 2009 Google Inc. All rights reserved.
+# Copyright (C) 2009 Andras Becsi (becsi.andras@stud.u-szeged.hu), University of Szeged
+#
+# 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.
+
+# Script to run the WebKit Open Source Project layout tests.
+
+# Run all the tests passed in on the command line.
+# If no tests are passed, find all the .html, .shtml, .xml, .xhtml, .xhtmlmp, .pl, .php (and svg) files in the test directory.
+
+# Run each text.
+# Compare against the existing file xxx-expected.txt.
+# If there is a mismatch, generate xxx-actual.txt and xxx-diffs.txt.
+
+# At the end, report:
+# the number of tests that got the expected results
+# the number of tests that ran, but did not get the expected results
+# the number of tests that failed to run
+# the number of tests that were run but had no expected results to compare against
+
+use strict;
+use warnings;
+
+use Config;
+use Cwd;
+use Data::Dumper;
+use Fcntl qw(F_GETFL F_SETFL O_NONBLOCK);
+use File::Basename;
+use File::Copy;
+use File::Find;
+use File::Path;
+use File::Spec;
+use File::Spec::Functions;
+use File::Temp;
+use FindBin;
+use Getopt::Long;
+use IPC::Open2;
+use IPC::Open3;
+use Time::HiRes qw(time usleep);
+
+use List::Util 'shuffle';
+
+use lib $FindBin::Bin;
+use webkitperl::features;
+use webkitperl::httpd;
+use webkitdirs;
+use VCSUtils;
+use POSIX;
+
+sub buildPlatformResultHierarchy();
+sub buildPlatformTestHierarchy(@);
+sub checkPythonVersion();
+sub closeCygpaths();
+sub closeDumpTool();
+sub closeWebSocketServer();
+sub configureAndOpenHTTPDIfNeeded();
+sub countAndPrintLeaks($$$);
+sub countFinishedTest($$$$);
+sub deleteExpectedAndActualResults($);
+sub dumpToolDidCrash();
+sub epiloguesAndPrologues($$);
+sub expectedDirectoryForTest($;$;$);
+sub fileNameWithNumber($$);
+sub htmlForResultsSection(\@$&);
+sub isTextOnlyTest($);
+sub launchWithEnv(\@\%);
+sub resolveAndMakeTestResultsDirectory();
+sub numericcmp($$);
+sub openDiffTool();
+sub buildDumpTool($);
+sub openDumpTool();
+sub parseLeaksandPrintUniqueLeaks();
+sub openWebSocketServerIfNeeded();
+sub pathcmp($$);
+sub printFailureMessageForTest($$);
+sub processIgnoreTests($$);
+sub readFromDumpToolWithTimer(**);
+sub readSkippedFiles($);
+sub recordActualResultsAndDiff($$);
+sub sampleDumpTool();
+sub setFileHandleNonBlocking(*$);
+sub setUpWindowsCrashLogSaving();
+sub slowestcmp($$);
+sub splitpath($);
+sub stopRunningTestsEarlyIfNeeded();
+sub stripExtension($);
+sub stripMetrics($$);
+sub testCrashedOrTimedOut($$$$$);
+sub toCygwinPath($);
+sub toURL($);
+sub toWindowsPath($);
+sub validateSkippedArg($$;$);
+sub writeToFile($$);
+
+# Argument handling
+my $addPlatformExceptions = 0;
+my $complexText = 0;
+my $exitAfterNFailures = 0;
+my $exitAfterNCrashesOrTimeouts = 0;
+my $generateNewResults = isAppleMacWebKit() ? 1 : 0;
+my $guardMalloc = '';
+# FIXME: Dynamic HTTP-port configuration in this file is wrong. The various
+# apache config files in LayoutTests/http/config govern the port numbers.
+# Dynamic configuration as-written will also cause random failures in
+# an IPv6 environment. See https://bugs.webkit.org/show_bug.cgi?id=37104.
+my $httpdPort = 8000;
+my $httpdSSLPort = 8443;
+my $ignoreMetrics = 0;
+my $webSocketPort = 8880;
+# wss is disabled until all platforms support pyOpenSSL.
+# my $webSocketSecurePort = 9323;
+my $ignoreTests = '';
+my $iterations = 1;
+my $launchSafari = 1;
+my $mergeDepth;
+my $pixelTests = '';
+my $platform;
+my $quiet = '';
+my $randomizeTests = 0;
+my $repeatEach = 1;
+my $report10Slowest = 0;
+my $resetResults = 0;
+my $reverseTests = 0;
+my $root;
+my $runSample = 1;
+my $shouldCheckLeaks = 0;
+my $showHelp = 0;
+my $stripEditingCallbacks;
+my $testHTTP = 1;
+my $testWebSocket = 1;
+my $testMedia = 1;
+my $tmpDir = "/tmp";
+my $testResultsDirectory = File::Spec->catdir($tmpDir, "layout-test-results");
+my $testsPerDumpTool = 1000;
+my $threaded = 0;
+# DumpRenderTree has an internal timeout of 30 seconds, so this must be > 30.
+my $timeoutSeconds = 35;
+my $tolerance = 0;
+my $treatSkipped = "default";
+my $useRemoteLinksToTests = 0;
+my $useValgrind = 0;
+my $verbose = 0;
+my $shouldWaitForHTTPD = 0;
+my $useWebKitTestRunner = 0;
+
+my @leaksFilenames;
+
+if (isWindows() || isMsys()) {
+ print "This script has to be run under Cygwin to function correctly.\n";
+ exit 1;
+}
+
+# Default to --no-http for wx for now.
+$testHTTP = 0 if (isWx());
+
+my $perlInterpreter = "perl";
+
+my $expectedTag = "expected";
+my $actualTag = "actual";
+my $prettyDiffTag = "pretty-diff";
+my $diffsTag = "diffs";
+my $errorTag = "stderr";
+
+# These are defined here instead of closer to where they are used so that they
+# will always be accessible from the END block that uses them, even if the user
+# presses Ctrl-C before Perl has finished evaluating this whole file.
+my $windowsPostMortemDebuggerKey = "/HKLM/SOFTWARE/Microsoft/Windows NT/CurrentVersion/AeDebug";
+my %previousWindowsPostMortemDebuggerValues;
+
+my $realPlatform;
+
+my @macPlatforms = ("mac-tiger", "mac-leopard", "mac-snowleopard", "mac");
+my @winPlatforms = ("win-xp", "win-vista", "win-7", "win");
+
+if (isAppleMacWebKit()) {
+ if (isTiger()) {
+ $platform = "mac-tiger";
+ $tolerance = 1.0;
+ } elsif (isLeopard()) {
+ $platform = "mac-leopard";
+ $tolerance = 0.1;
+ } elsif (isSnowLeopard()) {
+ $platform = "mac-snowleopard";
+ $tolerance = 0.1;
+ } else {
+ $platform = "mac";
+ }
+} elsif (isQt()) {
+ if (isDarwin()) {
+ $platform = "qt-mac";
+ } elsif (isLinux()) {
+ $platform = "qt-linux";
+ } elsif (isWindows() || isCygwin()) {
+ $platform = "qt-win";
+ } else {
+ $platform = "qt";
+ }
+} elsif (isGtk()) {
+ $platform = "gtk";
+} elsif (isWx()) {
+ $platform = "wx";
+} elsif (isCygwin() || isWindows()) {
+ if (isWindowsXP()) {
+ $platform = "win-xp";
+ } elsif (isWindowsVista()) {
+ $platform = "win-vista";
+ } elsif (isWindows7()) {
+ $platform = "win-7";
+ } else {
+ $platform = "win";
+ }
+}
+
+if (isQt() || isAppleWinWebKit()) {
+ my $testfontPath = $ENV{"WEBKIT_TESTFONTS"};
+ if (!$testfontPath || !-d "$testfontPath") {
+ print "The WEBKIT_TESTFONTS environment variable is not defined or not set properly\n";
+ print "You must set it before running the tests.\n";
+ print "Use git to grab the actual fonts from http://gitorious.org/qtwebkit/testfonts\n";
+ exit 1;
+ }
+}
+
+if (!defined($platform)) {
+ print "WARNING: Your platform is not recognized. Any platform-specific results will be generated in platform/undefined.\n";
+ $platform = "undefined";
+}
+
+if (!checkPythonVersion()) {
+ print "WARNING: Your platform does not have Python 2.5+, which is required to run websocket server, so disabling websocket/tests.\n";
+ $testWebSocket = 0;
+}
+
+my $programName = basename($0);
+my $launchSafariDefault = $launchSafari ? "launch" : "do not launch";
+my $httpDefault = $testHTTP ? "run" : "do not run";
+my $sampleDefault = $runSample ? "run" : "do not run";
+
+my $usage = <<EOF;
+Usage: $programName [options] [testdir|testpath ...]
+ --add-platform-exceptions Put new results for non-platform-specific failing tests into the platform-specific results directory
+ --complex-text Use the complex text code path for all text (Mac OS X and Windows only)
+ -c|--configuration config Set DumpRenderTree build configuration
+ -g|--guard-malloc Enable malloc guard
+ --exit-after-n-failures N Exit after the first N failures (includes crashes) instead of running all tests
+ --exit-after-n-crashes-or-timeouts N
+ Exit after the first N crashes instead of running all tests
+ -h|--help Show this help message
+ --[no-]http Run (or do not run) http tests (default: $httpDefault)
+ --[no-]wait-for-httpd Wait for httpd if some other test session is using it already (same as WEBKIT_WAIT_FOR_HTTPD=1). (default: $shouldWaitForHTTPD)
+ -i|--ignore-tests Comma-separated list of directories or tests to ignore
+ --iterations n Number of times to run the set of tests (e.g. ABCABCABC)
+ --[no-]launch-safari Launch (or do not launch) Safari to display test results (default: $launchSafariDefault)
+ -l|--leaks Enable leaks checking
+ --[no-]new-test-results Generate results for new tests
+ --nthly n Restart DumpRenderTree every n tests (default: $testsPerDumpTool)
+ -p|--pixel-tests Enable pixel tests
+ --tolerance t Ignore image differences less than this percentage (default: $tolerance)
+ --platform Override the detected platform to use for tests and results (default: $platform)
+ --port Web server port to use with http tests
+ -q|--quiet Less verbose output
+ --reset-results Reset ALL results (including pixel tests if --pixel-tests is set)
+ -o|--results-directory Output results directory (default: $testResultsDirectory)
+ --random Run the tests in a random order
+ --repeat-each n Number of times to run each test (e.g. AAABBBCCC)
+ --reverse Run the tests in reverse alphabetical order
+ --root Path to root tools build
+ --[no-]sample-on-timeout Run sample on timeout (default: $sampleDefault) (Mac OS X only)
+ -1|--singly Isolate each test case run (implies --nthly 1 --verbose)
+ --skipped=[default|ignore|only] Specifies how to treat the Skipped file
+ default: Tests/directories listed in the Skipped file are not tested
+ ignore: The Skipped file is ignored
+ only: Only those tests/directories listed in the Skipped file will be run
+ --slowest Report the 10 slowest tests
+ --ignore-metrics Ignore metrics in tests
+ --[no-]strip-editing-callbacks Remove editing callbacks from expected results
+ -t|--threaded Run a concurrent JavaScript thead with each test
+ --timeout t Sets the number of seconds before a test times out (default: $timeoutSeconds)
+ --valgrind Run DumpRenderTree inside valgrind (Qt/Linux only)
+ -v|--verbose More verbose output (overrides --quiet)
+ -m|--merge-leak-depth arg Merges leak callStacks and prints the number of unique leaks beneath a callstack depth of arg. Defaults to 5.
+ --use-remote-links-to-tests Link to test files within the SVN repository in the results.
+ -2|--webkit-test-runner Use WebKitTestRunner rather than DumpRenderTree.
+EOF
+
+setConfiguration();
+
+my $getOptionsResult = GetOptions(
+ 'add-platform-exceptions' => \$addPlatformExceptions,
+ 'complex-text' => \$complexText,
+ 'exit-after-n-failures=i' => \$exitAfterNFailures,
+ 'exit-after-n-crashes-or-timeouts=i' => \$exitAfterNCrashesOrTimeouts,
+ 'guard-malloc|g' => \$guardMalloc,
+ 'help|h' => \$showHelp,
+ 'http!' => \$testHTTP,
+ 'wait-for-httpd!' => \$shouldWaitForHTTPD,
+ 'ignore-metrics!' => \$ignoreMetrics,
+ 'ignore-tests|i=s' => \$ignoreTests,
+ 'iterations=i' => \$iterations,
+ 'launch-safari!' => \$launchSafari,
+ 'leaks|l' => \$shouldCheckLeaks,
+ 'merge-leak-depth|m:5' => \$mergeDepth,
+ 'new-test-results!' => \$generateNewResults,
+ 'nthly=i' => \$testsPerDumpTool,
+ 'pixel-tests|p' => \$pixelTests,
+ 'platform=s' => \$platform,
+ 'port=i' => \$httpdPort,
+ 'quiet|q' => \$quiet,
+ 'random' => \$randomizeTests,
+ 'repeat-each=i' => \$repeatEach,
+ 'reset-results' => \$resetResults,
+ 'results-directory|o=s' => \$testResultsDirectory,
+ 'reverse' => \$reverseTests,
+ 'root=s' => \$root,
+ 'sample-on-timeout!' => \$runSample,
+ 'singly|1' => sub { $testsPerDumpTool = 1; },
+ 'skipped=s' => \&validateSkippedArg,
+ 'slowest' => \$report10Slowest,
+ 'strip-editing-callbacks!' => \$stripEditingCallbacks,
+ 'threaded|t' => \$threaded,
+ 'timeout=i' => \$timeoutSeconds,
+ 'tolerance=f' => \$tolerance,
+ 'use-remote-links-to-tests' => \$useRemoteLinksToTests,
+ 'valgrind' => \$useValgrind,
+ 'verbose|v' => \$verbose,
+ 'webkit-test-runner|2' => \$useWebKitTestRunner,
+);
+
+if (!$getOptionsResult || $showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+if ($useWebKitTestRunner) {
+ if (isAppleMacWebKit()) {
+ $realPlatform = $platform;
+ $platform = "mac-wk2";
+ } elsif (isAppleWinWebKit()) {
+ $stripEditingCallbacks = 0 unless defined $stripEditingCallbacks;
+ $realPlatform = $platform;
+ $platform = "win-wk2";
+ } elsif (isQt()) {
+ $realPlatform = $platform;
+ $platform = "qt-wk2";
+ }
+}
+
+$timeoutSeconds *= 10 if $guardMalloc;
+
+$stripEditingCallbacks = isCygwin() unless defined $stripEditingCallbacks;
+
+my $ignoreSkipped = $treatSkipped eq "ignore";
+my $skippedOnly = $treatSkipped eq "only";
+
+my $configuration = configuration();
+
+# We need an environment variable to be able to enable the feature per-slave
+$shouldWaitForHTTPD = $ENV{"WEBKIT_WAIT_FOR_HTTPD"} unless ($shouldWaitForHTTPD);
+$verbose = 1 if $testsPerDumpTool == 1;
+
+if ($shouldCheckLeaks && $testsPerDumpTool > 1000) {
+ print STDERR "\nWARNING: Running more than 1000 tests at a time with MallocStackLogging enabled may cause a crash.\n\n";
+}
+
+# Stack logging does not play well with QuickTime on Tiger (rdar://problem/5537157)
+$testMedia = 0 if $shouldCheckLeaks && isTiger();
+
+# Generating remote links causes a lot of unnecessary spew on GTK build bot
+$useRemoteLinksToTests = 0 if isGtk();
+
+setUpWindowsCrashLogSaving() if isCygwin();
+
+setConfigurationProductDir(Cwd::abs_path($root)) if (defined($root));
+my $productDir = productDir();
+$productDir .= "/bin" if isQt();
+$productDir .= "/Programs" if isGtk();
+
+chdirWebKit();
+
+if (!defined($root)) {
+ # FIXME: We build both DumpRenderTree and WebKitTestRunner for
+ # WebKitTestRunner runs becuase DumpRenderTree still includes
+ # the DumpRenderTreeSupport module and the TestNetscapePlugin.
+ # These two projects should be factored out into their own
+ # projects.
+ buildDumpTool("DumpRenderTree");
+ buildDumpTool("WebKitTestRunner") if $useWebKitTestRunner;
+}
+
+my $dumpToolName = $useWebKitTestRunner ? "WebKitTestRunner" : "DumpRenderTree";
+
+if (isAppleWinWebKit()) {
+ $dumpToolName .= "_debug" if configurationForVisualStudio() eq "Debug_All";
+ $dumpToolName .= $Config{_exe};
+}
+my $dumpTool = File::Spec->catfile($productDir, $dumpToolName);
+die "can't find executable $dumpToolName (looked in $productDir)\n" unless -x $dumpTool;
+
+my $imageDiffTool = "$productDir/ImageDiff";
+$imageDiffTool .= "_debug" if isCygwin() && configurationForVisualStudio() eq "Debug_All";
+die "can't find executable $imageDiffTool (looked in $productDir)\n" if $pixelTests && !-x $imageDiffTool;
+
+checkFrameworks() unless isCygwin();
+
+if (isAppleMacWebKit()) {
+ push @INC, $productDir;
+ require DumpRenderTreeSupport;
+}
+
+my $layoutTestsName = "LayoutTests";
+my $testDirectory = File::Spec->rel2abs($layoutTestsName);
+my $expectedDirectory = $testDirectory;
+my $platformBaseDirectory = catdir($testDirectory, "platform");
+my $platformTestDirectory = catdir($platformBaseDirectory, $platform);
+my @platformResultHierarchy = buildPlatformResultHierarchy();
+my @platformTestHierarchy = buildPlatformTestHierarchy(@platformResultHierarchy);
+
+$expectedDirectory = $ENV{"WebKitExpectedTestResultsDirectory"} if $ENV{"WebKitExpectedTestResultsDirectory"};
+
+$testResultsDirectory = File::Spec->rel2abs($testResultsDirectory);
+my $testResults = File::Spec->catfile($testResultsDirectory, "results.html");
+
+if (isAppleMacWebKit()) {
+ print STDERR "Compiling Java tests\n";
+ my $javaTestsDirectory = catdir($testDirectory, "java");
+
+ if (system("/usr/bin/make", "-C", "$javaTestsDirectory")) {
+ exit 1;
+ }
+}
+
+
+print "Running tests from $testDirectory\n";
+if ($pixelTests) {
+ print "Enabling pixel tests with a tolerance of $tolerance%\n";
+ if (isDarwin()) {
+ print "WARNING: Temporarily changing the main display color profile:\n";
+ print "\tThe colors on your screen will change for the duration of the testing.\n";
+ print "\tThis allows the pixel tests to have consistent color values across all machines.\n";
+
+ if (isPerianInstalled()) {
+ print "WARNING: Perian's QuickTime component is installed and this may affect pixel test results!\n";
+ print "\tYou should avoid generating new pixel results in this environment.\n";
+ print "\tSee https://bugs.webkit.org/show_bug.cgi?id=22615 for details.\n";
+ }
+ }
+}
+
+system "ln", "-s", $testDirectory, "/tmp/LayoutTests" unless -x "/tmp/LayoutTests";
+
+my %ignoredFiles = ( "results.html" => 1 );
+my %ignoredDirectories = map { $_ => 1 } qw(platform);
+my %ignoredLocalDirectories = map { $_ => 1 } qw(.svn _svn resources script-tests);
+my %supportedFileExtensions = map { $_ => 1 } qw(html shtml xml xhtml xhtmlmp pl php);
+
+if (!checkWebCoreFeatureSupport("MathML", 0)) {
+ $ignoredDirectories{'mathml'} = 1;
+}
+
+# FIXME: We should fix webkitperl/features.pm:hasFeature() to do the correct feature detection for Cygwin.
+if (checkWebCoreFeatureSupport("SVG", 0)) {
+ $supportedFileExtensions{'svg'} = 1;
+} elsif (isCygwin()) {
+ $supportedFileExtensions{'svg'} = 1;
+} else {
+ $ignoredLocalDirectories{'svg'} = 1;
+}
+
+if (!$testHTTP) {
+ $ignoredDirectories{'http'} = 1;
+ $ignoredDirectories{'websocket'} = 1;
+}
+if (!$testWebSocket) {
+ $ignoredDirectories{'websocket'} = 1;
+}
+
+if (!$testMedia) {
+ $ignoredDirectories{'media'} = 1;
+ $ignoredDirectories{'http/tests/media'} = 1;
+}
+
+my $supportedFeaturesResult = "";
+
+if (isCygwin()) {
+ # Collect supported features list
+ setPathForRunningWebKitApp(\%ENV);
+ my $supportedFeaturesCommand = "\"$dumpTool\" --print-supported-features 2>&1";
+ $supportedFeaturesResult = `$supportedFeaturesCommand 2>&1`;
+}
+
+my $hasAcceleratedCompositing = 0;
+my $has3DRendering = 0;
+
+if (isCygwin()) {
+ $hasAcceleratedCompositing = $supportedFeaturesResult =~ /AcceleratedCompositing/;
+ $has3DRendering = $supportedFeaturesResult =~ /3DRendering/;
+} else {
+ $hasAcceleratedCompositing = checkWebCoreFeatureSupport("Accelerated Compositing", 0);
+ $has3DRendering = checkWebCoreFeatureSupport("3D Rendering", 0);
+}
+
+if (!$hasAcceleratedCompositing) {
+ $ignoredDirectories{'compositing'} = 1;
+
+ # This test has slightly different floating-point rounding when accelerated
+ # compositing is enabled.
+ $ignoredFiles{'svg/custom/use-on-symbol-inside-pattern.svg'} = 1;
+
+ if (isAppleWebKit()) {
+ # In Apple's ports, the default controls for <video> contain a "full
+ # screen" button only if accelerated compositing is enabled.
+ $ignoredFiles{'media/controls-after-reload.html'} = 1;
+ $ignoredFiles{'media/controls-drag-timebar.html'} = 1;
+ $ignoredFiles{'media/controls-strict.html'} = 1;
+ $ignoredFiles{'media/controls-styling.html'} = 1;
+ $ignoredFiles{'media/video-controls-rendering.html'} = 1;
+ $ignoredFiles{'media/video-display-toggle.html'} = 1;
+ $ignoredFiles{'media/video-no-audio.html'} = 1;
+ }
+
+ # Here we're using !$hasAcceleratedCompositing as a proxy for "is a headless XP machine" (like
+ # our test slaves). Headless XP machines can neither support accelerated compositing nor pass
+ # this test, so skipping the test here is expedient, if a little sloppy. See
+ # <http://webkit.org/b/48333>.
+ $ignoredFiles{'platform/win/plugins/npn-invalidate-rect-invalidates-window.html'} = 1 if isAppleWinWebKit();
+}
+
+if (!$has3DRendering) {
+ $ignoredDirectories{'animations/3d'} = 1;
+ $ignoredDirectories{'transforms/3d'} = 1;
+
+ # These tests use the -webkit-transform-3d media query.
+ $ignoredFiles{'fast/media/mq-transform-02.html'} = 1;
+ $ignoredFiles{'fast/media/mq-transform-03.html'} = 1;
+}
+
+if (!checkWebCoreFeatureSupport("3D Canvas", 0)) {
+ $ignoredDirectories{'fast/canvas/webgl'} = 1;
+ $ignoredDirectories{'compositing/webgl'} = 1;
+ $ignoredDirectories{'http/tests/canvas/webgl'} = 1;
+}
+
+if (checkWebCoreFeatureSupport("WML", 0)) {
+ $supportedFileExtensions{'wml'} = 1;
+} else {
+ $ignoredDirectories{'http/tests/wml'} = 1;
+ $ignoredDirectories{'fast/wml'} = 1;
+ $ignoredDirectories{'wml'} = 1;
+}
+
+if (!checkWebCoreFeatureSupport("WCSS", 0)) {
+ $ignoredDirectories{'fast/wcss'} = 1;
+}
+
+if (!checkWebCoreFeatureSupport("XHTMLMP", 0)) {
+ $ignoredDirectories{'fast/xhtmlmp'} = 1;
+}
+
+processIgnoreTests($ignoreTests, "ignore-tests") if $ignoreTests;
+if (!$ignoreSkipped) {
+ if (!$skippedOnly || @ARGV == 0) {
+ readSkippedFiles("");
+ } else {
+ # Since readSkippedFiles() appends to @ARGV, we must use a foreach
+ # loop so that we only iterate over the original argument list.
+ foreach my $argnum (0 .. $#ARGV) {
+ readSkippedFiles(shift @ARGV);
+ }
+ }
+}
+
+my @tests = findTestsToRun();
+
+die "no tests to run\n" if !@tests;
+
+my %counts;
+my %tests;
+my %imagesPresent;
+my %imageDifferences;
+my %durations;
+my $count = 0;
+my $leaksOutputFileNumber = 1;
+my $totalLeaks = 0;
+
+my @toolArgs = ();
+push @toolArgs, "--pixel-tests" if $pixelTests;
+push @toolArgs, "--threaded" if $threaded;
+push @toolArgs, "--complex-text" if $complexText;
+push @toolArgs, "-";
+
+my @diffToolArgs = ();
+push @diffToolArgs, "--tolerance", $tolerance;
+
+$| = 1;
+
+my $dumpToolPID;
+my $isDumpToolOpen = 0;
+my $dumpToolCrashed = 0;
+my $imageDiffToolPID;
+my $isDiffToolOpen = 0;
+
+my $atLineStart = 1;
+my $lastDirectory = "";
+
+my $isHttpdOpen = 0;
+my $isWebSocketServerOpen = 0;
+my $webSocketServerPidFile = 0;
+my $failedToStartWebSocketServer = 0;
+# wss is disabled until all platforms support pyOpenSSL.
+# my $webSocketSecureServerPID = 0;
+
+sub catch_pipe { $dumpToolCrashed = 1; }
+$SIG{"PIPE"} = "catch_pipe";
+
+print "Testing ", scalar @tests, " test cases";
+print " $iterations times" if ($iterations > 1);
+print ", repeating each test $repeatEach times" if ($repeatEach > 1);
+print ".\n";
+
+my $overallStartTime = time;
+
+my %expectedResultPaths;
+
+my @originalTests = @tests;
+# Add individual test repetitions
+if ($repeatEach > 1) {
+ @tests = ();
+ foreach my $test (@originalTests) {
+ for (my $i = 0; $i < $repeatEach; $i++) {
+ push(@tests, $test);
+ }
+ }
+}
+# Add test set repetitions
+for (my $i = 1; $i < $iterations; $i++) {
+ push(@tests, @originalTests);
+}
+
+for my $test (@tests) {
+ my $newDumpTool = not $isDumpToolOpen;
+ openDumpTool();
+
+ my $base = stripExtension($test);
+ my $expectedExtension = ".txt";
+
+ my $dir = $base;
+ $dir =~ s|/[^/]+$||;
+
+ if ($newDumpTool || $dir ne $lastDirectory) {
+ foreach my $logue (epiloguesAndPrologues($newDumpTool ? "" : $lastDirectory, $dir)) {
+ if (isCygwin()) {
+ $logue = toWindowsPath($logue);
+ } else {
+ $logue = canonpath($logue);
+ }
+ if ($verbose) {
+ print "running epilogue or prologue $logue\n";
+ }
+ print OUT "$logue\n";
+ # Throw away output from DumpRenderTree.
+ # Once for the test output and once for pixel results (empty)
+ while (<IN>) {
+ last if /#EOF/;
+ }
+ while (<IN>) {
+ last if /#EOF/;
+ }
+ }
+ }
+
+ if ($verbose) {
+ print "running $test -> ";
+ $atLineStart = 0;
+ } elsif (!$quiet) {
+ if ($dir ne $lastDirectory) {
+ print "\n" unless $atLineStart;
+ print "$dir ";
+ }
+ print ".";
+ $atLineStart = 0;
+ }
+
+ $lastDirectory = $dir;
+
+ my $result;
+
+ my $startTime = time if $report10Slowest;
+
+ # Try to read expected hash file for pixel tests
+ my $suffixExpectedHash = "";
+ if ($pixelTests && !$resetResults) {
+ my $expectedPixelDir = expectedDirectoryForTest($base, 0, "png");
+ if (open EXPECTEDHASH, File::Spec->catfile($expectedPixelDir, "$base-$expectedTag.checksum")) {
+ my $expectedHash = <EXPECTEDHASH>;
+ chomp($expectedHash);
+ close EXPECTEDHASH;
+
+ # Format expected hash into a suffix string that is appended to the path / URL passed to DRT
+ $suffixExpectedHash = "'$expectedHash";
+ }
+ }
+
+ if ($test =~ /^http\//) {
+ configureAndOpenHTTPDIfNeeded();
+ if ($test =~ /^http\/tests\/websocket\//) {
+ if ($test =~ /^websocket\/tests\/local\//) {
+ my $testPath = "$testDirectory/$test";
+ if (isCygwin()) {
+ $testPath = toWindowsPath($testPath);
+ } else {
+ $testPath = canonpath($testPath);
+ }
+ print OUT "$testPath\n";
+ } else {
+ if (openWebSocketServerIfNeeded()) {
+ my $path = canonpath($test);
+ if ($test =~ /^http\/tests\/websocket\/tests\/ssl\//) {
+ # wss is disabled until all platforms support pyOpenSSL.
+ print STDERR "Error: wss is disabled until all platforms support pyOpenSSL.";
+ } else {
+ $path =~ s/^http\/tests\///;
+ print OUT "http://127.0.0.1:$httpdPort/$path\n";
+ }
+ } else {
+ # We failed to launch the WebSocket server. Display a useful error message rather than attempting
+ # to run tests that expect the server to be available.
+ my $errorMessagePath = "$testDirectory/http/tests/websocket/resources/server-failed-to-start.html";
+ $errorMessagePath = isCygwin() ? toWindowsPath($errorMessagePath) : canonpath($errorMessagePath);
+ print OUT "$errorMessagePath\n";
+ }
+ }
+ } elsif ($test !~ /^http\/tests\/local\// && $test !~ /^http\/tests\/ssl\// && $test !~ /^http\/tests\/wml\// && $test !~ /^http\/tests\/media\//) {
+ my $path = canonpath($test);
+ $path =~ s/^http\/tests\///;
+ print OUT "http://127.0.0.1:$httpdPort/$path$suffixExpectedHash\n";
+ } elsif ($test =~ /^http\/tests\/ssl\//) {
+ my $path = canonpath($test);
+ $path =~ s/^http\/tests\///;
+ print OUT "https://127.0.0.1:$httpdSSLPort/$path$suffixExpectedHash\n";
+ } else {
+ my $testPath = "$testDirectory/$test";
+ if (isCygwin()) {
+ $testPath = toWindowsPath($testPath);
+ } else {
+ $testPath = canonpath($testPath);
+ }
+ print OUT "$testPath$suffixExpectedHash\n";
+ }
+ } else {
+ my $testPath = "$testDirectory/$test";
+ if (isCygwin()) {
+ $testPath = toWindowsPath($testPath);
+ } else {
+ $testPath = canonpath($testPath);
+ }
+ print OUT "$testPath$suffixExpectedHash\n" if defined $testPath;
+ }
+
+ # DumpRenderTree is expected to dump two "blocks" to stdout for each test.
+ # Each block is terminated by a #EOF on a line by itself.
+ # The first block is the output of the test (in text, RenderTree or other formats).
+ # The second block is for optional pixel data in PNG format, and may be empty if
+ # pixel tests are not being run, or the test does not dump pixels (e.g. text tests).
+ my $readResults = readFromDumpToolWithTimer(IN, ERROR);
+
+ my $actual = $readResults->{output};
+ my $error = $readResults->{error};
+
+ $expectedExtension = $readResults->{extension};
+ my $expectedFileName = "$base-$expectedTag.$expectedExtension";
+
+ my $isText = isTextOnlyTest($actual);
+
+ my $expectedDir = expectedDirectoryForTest($base, $isText, $expectedExtension);
+ $expectedResultPaths{$base} = File::Spec->catfile($expectedDir, $expectedFileName);
+
+ unless ($readResults->{status} eq "success") {
+ my $crashed = $readResults->{status} eq "crashed";
+ testCrashedOrTimedOut($test, $base, $crashed, $actual, $error);
+ countFinishedTest($test, $base, $crashed ? "crash" : "timedout", 0);
+ last if stopRunningTestsEarlyIfNeeded();
+ next;
+ }
+
+ $durations{$test} = time - $startTime if $report10Slowest;
+
+ my $expected;
+
+ if (!$resetResults && open EXPECTED, "<", $expectedResultPaths{$base}) {
+ $expected = "";
+ while (<EXPECTED>) {
+ next if $stripEditingCallbacks && $_ =~ /^EDITING DELEGATE:/;
+ $expected .= $_;
+ }
+ close EXPECTED;
+ }
+
+ if ($ignoreMetrics && !$isText && defined $expected) {
+ ($actual, $expected) = stripMetrics($actual, $expected);
+ }
+
+ if ($shouldCheckLeaks && $testsPerDumpTool == 1) {
+ print " $test -> ";
+ }
+
+ my $actualPNG = "";
+ my $diffPNG = "";
+ my $diffPercentage = 0;
+ my $diffResult = "passed";
+
+ my $actualHash = "";
+ my $expectedHash = "";
+ my $actualPNGSize = 0;
+
+ while (<IN>) {
+ last if /#EOF/;
+ if (/ActualHash: ([a-f0-9]{32})/) {
+ $actualHash = $1;
+ } elsif (/ExpectedHash: ([a-f0-9]{32})/) {
+ $expectedHash = $1;
+ } elsif (/Content-Length: (\d+)\s*/) {
+ $actualPNGSize = $1;
+ read(IN, $actualPNG, $actualPNGSize);
+ }
+ }
+
+ if ($verbose && $pixelTests && !$resetResults && $actualPNGSize) {
+ if ($actualHash eq "" && $expectedHash eq "") {
+ printFailureMessageForTest($test, "WARNING: actual & expected pixel hashes are missing!");
+ } elsif ($actualHash eq "") {
+ printFailureMessageForTest($test, "WARNING: actual pixel hash is missing!");
+ } elsif ($expectedHash eq "") {
+ printFailureMessageForTest($test, "WARNING: expected pixel hash is missing!");
+ }
+ }
+
+ if ($actualPNGSize > 0) {
+ my $expectedPixelDir = expectedDirectoryForTest($base, 0, "png");
+ my $expectedPNGPath = File::Spec->catfile($expectedPixelDir, "$base-$expectedTag.png");
+
+ if (!$resetResults && ($expectedHash ne $actualHash || ($actualHash eq "" && $expectedHash eq ""))) {
+ if (-f $expectedPNGPath) {
+ my $expectedPNGSize = -s $expectedPNGPath;
+ my $expectedPNG = "";
+ open EXPECTEDPNG, $expectedPNGPath;
+ read(EXPECTEDPNG, $expectedPNG, $expectedPNGSize);
+
+ openDiffTool();
+ print DIFFOUT "Content-Length: $actualPNGSize\n";
+ print DIFFOUT $actualPNG;
+
+ print DIFFOUT "Content-Length: $expectedPNGSize\n";
+ print DIFFOUT $expectedPNG;
+
+ while (<DIFFIN>) {
+ last if /^error/ || /^diff:/;
+ if (/Content-Length: (\d+)\s*/) {
+ read(DIFFIN, $diffPNG, $1);
+ }
+ }
+
+ if (/^diff: (.+)% (passed|failed)/) {
+ $diffPercentage = $1 + 0;
+ $imageDifferences{$base} = $diffPercentage;
+ $diffResult = $2;
+ }
+
+ if (!$diffPercentage) {
+ printFailureMessageForTest($test, "pixel hash failed (but pixel test still passes)");
+ }
+ } elsif ($verbose) {
+ printFailureMessageForTest($test, "WARNING: expected image is missing!");
+ }
+ }
+
+ if ($resetResults || !-f $expectedPNGPath) {
+ mkpath catfile($expectedPixelDir, dirname($base)) if $testDirectory ne $expectedPixelDir;
+ writeToFile($expectedPNGPath, $actualPNG);
+ }
+
+ my $expectedChecksumPath = File::Spec->catfile($expectedPixelDir, "$base-$expectedTag.checksum");
+ if ($actualHash ne "" && ($resetResults || !-f $expectedChecksumPath)) {
+ writeToFile($expectedChecksumPath, $actualHash);
+ }
+ }
+
+ if (dumpToolDidCrash()) {
+ $result = "crash";
+ testCrashedOrTimedOut($test, $base, 1, $actual, $error);
+ } elsif (!defined $expected) {
+ if ($verbose) {
+ print "new " . ($resetResults ? "result" : "test");
+ }
+ $result = "new";
+
+ if ($generateNewResults || $resetResults) {
+ mkpath catfile($expectedDir, dirname($base)) if $testDirectory ne $expectedDir;
+ writeToFile("$expectedDir/$expectedFileName", $actual);
+ }
+ deleteExpectedAndActualResults($base);
+ recordActualResultsAndDiff($base, $actual);
+ if (!$resetResults) {
+ # Always print the file name for new tests, as they will probably need some manual inspection.
+ # in verbose mode we already printed the test case, so no need to do it again.
+ unless ($verbose) {
+ print "\n" unless $atLineStart;
+ print "$test -> ";
+ }
+ my $resultsDir = catdir($expectedDir, dirname($base));
+ if (!$verbose) {
+ print "new";
+ }
+ if ($generateNewResults) {
+ print " (results generated in $resultsDir)";
+ }
+ print "\n" unless $atLineStart;
+ $atLineStart = 1;
+ }
+ } elsif ($actual eq $expected && $diffResult eq "passed") {
+ if ($verbose) {
+ print "succeeded\n";
+ $atLineStart = 1;
+ }
+ $result = "match";
+ deleteExpectedAndActualResults($base);
+ } else {
+ $result = "mismatch";
+
+ my $pixelTestFailed = $pixelTests && $diffPNG && $diffPNG ne "";
+ my $testFailed = $actual ne $expected;
+
+ my $message = !$testFailed ? "pixel test failed" : "failed";
+
+ if (($testFailed || $pixelTestFailed) && $addPlatformExceptions) {
+ my $testBase = catfile($testDirectory, $base);
+ my $expectedBase = catfile($expectedDir, $base);
+ my $testIsMaximallyPlatformSpecific = $testBase =~ m|^\Q$platformTestDirectory\E/|;
+ my $expectedResultIsMaximallyPlatformSpecific = $expectedBase =~ m|^\Q$platformTestDirectory\E/|;
+ if (!$testIsMaximallyPlatformSpecific && !$expectedResultIsMaximallyPlatformSpecific) {
+ mkpath catfile($platformTestDirectory, dirname($base));
+ if ($testFailed) {
+ my $expectedFile = catfile($platformTestDirectory, "$expectedFileName");
+ writeToFile("$expectedFile", $actual);
+ }
+ if ($pixelTestFailed) {
+ my $expectedFile = catfile($platformTestDirectory, "$base-$expectedTag.checksum");
+ writeToFile("$expectedFile", $actualHash);
+
+ $expectedFile = catfile($platformTestDirectory, "$base-$expectedTag.png");
+ writeToFile("$expectedFile", $actualPNG);
+ }
+ $message .= " (results generated in $platformTestDirectory)";
+ }
+ }
+
+ printFailureMessageForTest($test, $message);
+
+ my $dir = "$testResultsDirectory/$base";
+ $dir =~ s|/([^/]+)$|| or die "Failed to find test name from base\n";
+ my $testName = $1;
+ mkpath $dir;
+
+ deleteExpectedAndActualResults($base);
+ recordActualResultsAndDiff($base, $actual);
+
+ if ($pixelTestFailed) {
+ $imagesPresent{$base} = 1;
+
+ writeToFile("$testResultsDirectory/$base-$actualTag.png", $actualPNG);
+ writeToFile("$testResultsDirectory/$base-$diffsTag.png", $diffPNG);
+
+ my $expectedPixelDir = expectedDirectoryForTest($base, 0, "png");
+ copy("$expectedPixelDir/$base-$expectedTag.png", "$testResultsDirectory/$base-$expectedTag.png");
+
+ open DIFFHTML, ">$testResultsDirectory/$base-$diffsTag.html" or die;
+ print DIFFHTML "<html>\n";
+ print DIFFHTML "<head>\n";
+ print DIFFHTML "<title>$base Image Compare</title>\n";
+ print DIFFHTML "<script language=\"Javascript\" type=\"text/javascript\">\n";
+ print DIFFHTML "var currentImage = 0;\n";
+ print DIFFHTML "var imageNames = new Array(\"Actual\", \"Expected\");\n";
+ print DIFFHTML "var imagePaths = new Array(\"$testName-$actualTag.png\", \"$testName-$expectedTag.png\");\n";
+ if (-f "$testDirectory/$base-w3c.png") {
+ copy("$testDirectory/$base-w3c.png", "$testResultsDirectory/$base-w3c.png");
+ print DIFFHTML "imageNames.push(\"W3C\");\n";
+ print DIFFHTML "imagePaths.push(\"$testName-w3c.png\");\n";
+ }
+ print DIFFHTML "function animateImage() {\n";
+ print DIFFHTML " var image = document.getElementById(\"animatedImage\");\n";
+ print DIFFHTML " var imageText = document.getElementById(\"imageText\");\n";
+ print DIFFHTML " image.src = imagePaths[currentImage];\n";
+ print DIFFHTML " imageText.innerHTML = imageNames[currentImage] + \" Image\";\n";
+ print DIFFHTML " currentImage = (currentImage + 1) % imageNames.length;\n";
+ print DIFFHTML " setTimeout('animateImage()',2000);\n";
+ print DIFFHTML "}\n";
+ print DIFFHTML "</script>\n";
+ print DIFFHTML "</head>\n";
+ print DIFFHTML "<body onLoad=\"animateImage();\">\n";
+ print DIFFHTML "<table>\n";
+ if ($diffPercentage) {
+ print DIFFHTML "<tr>\n";
+ print DIFFHTML "<td>Difference between images: <a href=\"$testName-$diffsTag.png\">$diffPercentage%</a></td>\n";
+ print DIFFHTML "</tr>\n";
+ }
+ print DIFFHTML "<tr>\n";
+ print DIFFHTML "<td><a href=\"" . toURL("$testDirectory/$test") . "\">test file</a></td>\n";
+ print DIFFHTML "</tr>\n";
+ print DIFFHTML "<tr>\n";
+ print DIFFHTML "<td id=\"imageText\" style=\"text-weight: bold;\">Actual Image</td>\n";
+ print DIFFHTML "</tr>\n";
+ print DIFFHTML "<tr>\n";
+ print DIFFHTML "<td><img src=\"$testName-$actualTag.png\" id=\"animatedImage\"></td>\n";
+ print DIFFHTML "</tr>\n";
+ print DIFFHTML "</table>\n";
+ print DIFFHTML "</body>\n";
+ print DIFFHTML "</html>\n";
+ }
+ }
+
+ if ($error) {
+ my $dir = dirname(File::Spec->catdir($testResultsDirectory, $base));
+ mkpath $dir;
+
+ writeToFile(File::Spec->catfile($testResultsDirectory, "$base-$errorTag.txt"), $error);
+
+ $counts{error}++;
+ push @{$tests{error}}, $test;
+ }
+
+ countFinishedTest($test, $base, $result, $isText);
+ last if stopRunningTestsEarlyIfNeeded();
+}
+
+my $totalTestingTime = time - $overallStartTime;
+my $waitTime = getWaitTime();
+if ($waitTime > 0.1) {
+ my $normalizedTestingTime = $totalTestingTime - $waitTime;
+ printf "\n%0.2fs HTTPD waiting time\n", $waitTime . "";
+ printf "%0.2fs normalized testing time", $normalizedTestingTime . "";
+}
+printf "\n%0.2fs total testing time\n", $totalTestingTime . "";
+
+!$isDumpToolOpen || die "Failed to close $dumpToolName.\n";
+
+$isHttpdOpen = !closeHTTPD();
+closeWebSocketServer();
+
+# Because multiple instances of this script are running concurrently we cannot
+# safely delete this symlink.
+# system "rm /tmp/LayoutTests";
+
+# FIXME: Do we really want to check the image-comparison tool for leaks every time?
+if ($isDiffToolOpen && $shouldCheckLeaks) {
+ $totalLeaks += countAndPrintLeaks("ImageDiff", $imageDiffToolPID, "$testResultsDirectory/ImageDiff-leaks.txt");
+}
+
+if ($totalLeaks) {
+ if ($mergeDepth) {
+ parseLeaksandPrintUniqueLeaks();
+ } else {
+ print "\nWARNING: $totalLeaks total leaks found!\n";
+ print "See above for individual leaks results.\n" if ($leaksOutputFileNumber > 2);
+ }
+}
+
+close IN;
+close OUT;
+close ERROR;
+
+if ($report10Slowest) {
+ print "\n\nThe 10 slowest tests:\n\n";
+ my $count = 0;
+ for my $test (sort slowestcmp keys %durations) {
+ printf "%0.2f secs: %s\n", $durations{$test}, $test;
+ last if ++$count == 10;
+ }
+}
+
+print "\n";
+
+if ($skippedOnly && $counts{"match"}) {
+ print "The following tests are in the Skipped file (" . File::Spec->abs2rel("$platformTestDirectory/Skipped", $testDirectory) . "), but succeeded:\n";
+ foreach my $test (@{$tests{"match"}}) {
+ print " $test\n";
+ }
+}
+
+if ($resetResults || ($counts{match} && $counts{match} == $count)) {
+ print "all $count test cases succeeded\n";
+ unlink $testResults;
+ exit;
+}
+
+printResults();
+
+mkpath $testResultsDirectory;
+
+open HTML, ">", $testResults or die "Failed to open $testResults. $!";
+print HTML "<html>\n";
+print HTML "<head>\n";
+print HTML "<title>Layout Test Results</title>\n";
+print HTML "</head>\n";
+print HTML "<body>\n";
+
+if ($ignoreMetrics) {
+ print HTML "<h4>Tested with metrics ignored.</h4>";
+}
+
+print HTML htmlForResultsSection(@{$tests{mismatch}}, "Tests where results did not match expected results", \&linksForMismatchTest);
+print HTML htmlForResultsSection(@{$tests{timedout}}, "Tests that timed out", \&linksForErrorTest);
+print HTML htmlForResultsSection(@{$tests{crash}}, "Tests that caused the DumpRenderTree tool to crash", \&linksForErrorTest);
+print HTML htmlForResultsSection(@{$tests{error}}, "Tests that had stderr output", \&linksForErrorTest);
+print HTML htmlForResultsSection(@{$tests{new}}, "Tests that had no expected results (probably new)", \&linksForNewTest);
+
+print HTML "</body>\n";
+print HTML "</html>\n";
+close HTML;
+
+my @configurationArgs = argumentsForConfiguration();
+
+if (isGtk()) {
+ system "Tools/Scripts/run-launcher", @configurationArgs, "file://".$testResults if $launchSafari;
+} elsif (isQt()) {
+ unshift @configurationArgs, qw(-graphicssystem raster -style windows);
+ if (isCygwin()) {
+ $testResults = "/" . toWindowsPath($testResults);
+ $testResults =~ s/\\/\//g;
+ }
+ system "Tools/Scripts/run-launcher", @configurationArgs, "file://".$testResults if $launchSafari;
+} elsif (isCygwin()) {
+ system "cygstart", $testResults if $launchSafari;
+} elsif (isWindows()) {
+ system "start", $testResults if $launchSafari;
+} else {
+ system "Tools/Scripts/run-safari", @configurationArgs, "-NSOpen", $testResults if $launchSafari;
+}
+
+closeCygpaths() if isCygwin();
+
+exit 1;
+
+sub countAndPrintLeaks($$$)
+{
+ my ($dumpToolName, $dumpToolPID, $leaksFilePath) = @_;
+
+ print "\n" unless $atLineStart;
+ $atLineStart = 1;
+
+ # We are excluding the following reported leaks so they don't get in our way when looking for WebKit leaks:
+ # This allows us ignore known leaks and only be alerted when new leaks occur. Some leaks are in the old
+ # versions of the system frameworks that are being used by the leaks bots. Even though a leak has been
+ # fixed, it will be listed here until the bot has been updated with the newer frameworks.
+
+ my @typesToExclude = (
+ );
+
+ my @callStacksToExclude = (
+ "Flash_EnforceLocalSecurity" # leaks in Flash plug-in code, rdar://problem/4449747
+ );
+
+ if (isTiger()) {
+ # Leak list for the version of Tiger used on the build bot.
+ push @callStacksToExclude, (
+ "CFRunLoopRunSpecific \\| malloc_zone_malloc", "CFRunLoopRunSpecific \\| CFAllocatorAllocate ", # leak in CFRunLoopRunSpecific, rdar://problem/4670839
+ "CGImageSourceGetPropertiesAtIndex", # leak in ImageIO, rdar://problem/4628809
+ "FOGetCoveredUnicodeChars", # leak in ATS, rdar://problem/3943604
+ "GetLineDirectionPreference", "InitUnicodeUtilities", # leaks tool falsely reporting leak in CFNotificationCenterAddObserver, rdar://problem/4964790
+ "ICCFPrefWrapper::GetPrefDictionary", # leaks in Internet Config. code, rdar://problem/4449794
+ "NSHTTPURLProtocol setResponseHeader:", # leak in multipart/mixed-replace handling in Foundation, no Radar, but fixed in Leopard
+ "NSURLCache cachedResponseForRequest", # leak in CFURL cache, rdar://problem/4768430
+ "PCFragPrepareClosureFromFile", # leak in Code Fragment Manager, rdar://problem/3426998
+ "WebCore::Selection::toRange", # bug in 'leaks', rdar://problem/4967949
+ "WebCore::SubresourceLoader::create", # bug in 'leaks', rdar://problem/4985806
+ "_CFPreferencesDomainDeepCopyDictionary", # leak in CFPreferences, rdar://problem/4220786
+ "_objc_msgForward", # leak in NSSpellChecker, rdar://problem/4965278
+ "gldGetString", # leak in OpenGL, rdar://problem/5013699
+ "_setDefaultUserInfoFromURL", # leak in NSHTTPAuthenticator, rdar://problem/5546453
+ "SSLHandshake", # leak in SSL, rdar://problem/5546440
+ "SecCertificateCreateFromData", # leak in SSL code, rdar://problem/4464397
+ );
+ push @typesToExclude, (
+ "THRD", # bug in 'leaks', rdar://problem/3387783
+ "DRHT", # ditto (endian little hate i)
+ );
+ }
+
+ if (isLeopard()) {
+ # Leak list for the version of Leopard used on the build bot.
+ push @callStacksToExclude, (
+ "CFHTTPMessageAppendBytes", # leak in CFNetwork, rdar://problem/5435912
+ "sendDidReceiveDataCallback", # leak in CFNetwork, rdar://problem/5441619
+ "_CFHTTPReadStreamReadMark", # leak in CFNetwork, rdar://problem/5441468
+ "httpProtocolStart", # leak in CFNetwork, rdar://problem/5468837
+ "_CFURLConnectionSendCallbacks", # leak in CFNetwork, rdar://problem/5441600
+ "DispatchQTMsg", # leak in QuickTime, PPC only, rdar://problem/5667132
+ "QTMovieContentView createVisualContext", # leak in QuickTime, PPC only, rdar://problem/5667132
+ "_CopyArchitecturesForJVMVersion", # leak in Java, rdar://problem/5910823
+ );
+ }
+
+ if (isSnowLeopard()) {
+ push @callStacksToExclude, (
+ "readMakerNoteProps", # <rdar://problem/7156432> leak in ImageIO
+ "QTKitMovieControllerView completeUISetup", # <rdar://problem/7155156> leak in QTKit
+ "getVMInitArgs", # <rdar://problem/7714444> leak in Java
+ "Java_java_lang_System_initProperties", # <rdar://problem/7714465> leak in Java
+ "glrCompExecuteKernel", # <rdar://problem/7815391> leak in graphics driver while using OpenGL
+ );
+ }
+
+ if (isDarwin() && !isTiger() && !isLeopard() && !isSnowLeopard()) {
+ push @callStacksToExclude, (
+ "CGGradientCreateWithColorComponents", # leak in CoreGraphics, <rdar://problem/7888492>
+ );
+ }
+
+ my $leaksTool = sourceDir() . "/Tools/Scripts/run-leaks";
+ my $excludeString = "--exclude-callstack '" . (join "' --exclude-callstack '", @callStacksToExclude) . "'";
+ $excludeString .= " --exclude-type '" . (join "' --exclude-type '", @typesToExclude) . "'" if @typesToExclude;
+
+ print " ? checking for leaks in $dumpToolName\n";
+ my $leaksOutput = `$leaksTool $excludeString $dumpToolPID`;
+ my ($count, $bytes) = $leaksOutput =~ /Process $dumpToolPID: (\d+) leaks? for (\d+) total/;
+ my ($excluded) = $leaksOutput =~ /(\d+) leaks? excluded/;
+
+ my $adjustedCount = $count;
+ $adjustedCount -= $excluded if $excluded;
+
+ if (!$adjustedCount) {
+ print " - no leaks found\n";
+ unlink $leaksFilePath;
+ return 0;
+ } else {
+ my $dir = $leaksFilePath;
+ $dir =~ s|/[^/]+$|| or die;
+ mkpath $dir;
+
+ if ($excluded) {
+ print " + $adjustedCount leaks ($bytes bytes including $excluded excluded leaks) were found, details in $leaksFilePath\n";
+ } else {
+ print " + $count leaks ($bytes bytes) were found, details in $leaksFilePath\n";
+ }
+
+ writeToFile($leaksFilePath, $leaksOutput);
+
+ push @leaksFilenames, $leaksFilePath;
+ }
+
+ return $adjustedCount;
+}
+
+sub writeToFile($$)
+{
+ my ($filePath, $contents) = @_;
+ open NEWFILE, ">", "$filePath" or die "Could not create $filePath. $!\n";
+ print NEWFILE $contents;
+ close NEWFILE;
+}
+
+# Break up a path into the directory (with slash) and base name.
+sub splitpath($)
+{
+ my ($path) = @_;
+
+ my $pathSeparator = "/";
+ my $dirname = dirname($path) . $pathSeparator;
+ $dirname = "" if $dirname eq "." . $pathSeparator;
+
+ return ($dirname, basename($path));
+}
+
+# Sort first by directory, then by file, so all paths in one directory are grouped
+# rather than being interspersed with items from subdirectories.
+# Use numericcmp to sort directory and filenames to make order logical.
+sub pathcmp($$)
+{
+ my ($patha, $pathb) = @_;
+
+ my ($dira, $namea) = splitpath($patha);
+ my ($dirb, $nameb) = splitpath($pathb);
+
+ return numericcmp($dira, $dirb) if $dira ne $dirb;
+ return numericcmp($namea, $nameb);
+}
+
+# Sort numeric parts of strings as numbers, other parts as strings.
+# Makes 1.33 come after 1.3, which is cool.
+sub numericcmp($$)
+{
+ my ($aa, $bb) = @_;
+
+ my @a = split /(\d+)/, $aa;
+ my @b = split /(\d+)/, $bb;
+
+ # Compare one chunk at a time.
+ # Each chunk is either all numeric digits, or all not numeric digits.
+ while (@a && @b) {
+ my $a = shift @a;
+ my $b = shift @b;
+
+ # Use numeric comparison if chunks are non-equal numbers.
+ return $a <=> $b if $a =~ /^\d/ && $b =~ /^\d/ && $a != $b;
+
+ # Use string comparison if chunks are any other kind of non-equal string.
+ return $a cmp $b if $a ne $b;
+ }
+
+ # One of the two is now empty; compare lengths for result in this case.
+ return @a <=> @b;
+}
+
+# Sort slowest tests first.
+sub slowestcmp($$)
+{
+ my ($testa, $testb) = @_;
+
+ my $dura = $durations{$testa};
+ my $durb = $durations{$testb};
+ return $durb <=> $dura if $dura != $durb;
+ return pathcmp($testa, $testb);
+}
+
+sub launchWithEnv(\@\%)
+{
+ my ($args, $env) = @_;
+
+ # Dump the current environment as perl code and then put it in quotes so it is one parameter.
+ my $environmentDumper = Data::Dumper->new([\%{$env}], [qw(*ENV)]);
+ $environmentDumper->Indent(0);
+ $environmentDumper->Purity(1);
+ my $allEnvVars = $environmentDumper->Dump();
+ unshift @{$args}, "\"$allEnvVars\"";
+
+ my $execScript = File::Spec->catfile(sourceDir(), qw(Tools Scripts execAppWithEnv));
+ unshift @{$args}, $perlInterpreter, $execScript;
+ return @{$args};
+}
+
+sub resolveAndMakeTestResultsDirectory()
+{
+ my $absTestResultsDirectory = File::Spec->rel2abs(glob $testResultsDirectory);
+ mkpath $absTestResultsDirectory;
+ return $absTestResultsDirectory;
+}
+
+sub openDiffTool()
+{
+ return if $isDiffToolOpen;
+ return if !$pixelTests;
+
+ my %CLEAN_ENV;
+ $CLEAN_ENV{MallocStackLogging} = 1 if $shouldCheckLeaks;
+ $imageDiffToolPID = open2(\*DIFFIN, \*DIFFOUT, $imageDiffTool, launchWithEnv(@diffToolArgs, %CLEAN_ENV)) or die "unable to open $imageDiffTool\n";
+ $isDiffToolOpen = 1;
+}
+
+sub buildDumpTool($)
+{
+ my ($dumpToolName) = @_;
+
+ my $dumpToolBuildScript = "build-" . lc($dumpToolName);
+ print STDERR "Running $dumpToolBuildScript\n";
+
+ local *DEVNULL;
+ my ($childIn, $childOut, $childErr);
+ if ($quiet) {
+ open(DEVNULL, ">", File::Spec->devnull()) or die "Failed to open /dev/null";
+ $childOut = ">&DEVNULL";
+ $childErr = ">&DEVNULL";
+ } else {
+ # When not quiet, let the child use our stdout/stderr.
+ $childOut = ">&STDOUT";
+ $childErr = ">&STDERR";
+ }
+
+ my @args = argumentsForConfiguration();
+ my $buildProcess = open3($childIn, $childOut, $childErr, $perlInterpreter, File::Spec->catfile(qw(Tools Scripts), $dumpToolBuildScript), @args) or die "Failed to run build-dumprendertree";
+ close($childIn);
+ waitpid $buildProcess, 0;
+ my $buildResult = $?;
+ close($childOut);
+ close($childErr);
+
+ close DEVNULL if ($quiet);
+
+ if ($buildResult) {
+ print STDERR "Compiling $dumpToolName failed!\n";
+ exit exitStatus($buildResult);
+ }
+}
+
+sub openDumpTool()
+{
+ return if $isDumpToolOpen;
+
+ if ($verbose && $testsPerDumpTool != 1) {
+ print "| Opening DumpTool |\n";
+ }
+
+ my %CLEAN_ENV;
+
+ # Generic environment variables
+ if (defined $ENV{'WEBKIT_TESTFONTS'}) {
+ $CLEAN_ENV{WEBKIT_TESTFONTS} = $ENV{'WEBKIT_TESTFONTS'};
+ }
+
+ # unique temporary directory for each DumpRendertree - needed for running more DumpRenderTree in parallel
+ $CLEAN_ENV{DUMPRENDERTREE_TEMP} = File::Temp::tempdir('DumpRenderTree-XXXXXX', TMPDIR => 1, CLEANUP => 1);
+ $CLEAN_ENV{XML_CATALOG_FILES} = ""; # work around missing /etc/catalog <rdar://problem/4292995>
+
+ # Platform spesifics
+ if (isLinux()) {
+ if (defined $ENV{'DISPLAY'}) {
+ $CLEAN_ENV{DISPLAY} = $ENV{'DISPLAY'};
+ } else {
+ $CLEAN_ENV{DISPLAY} = ":1";
+ }
+ if (defined $ENV{'XAUTHORITY'}) {
+ $CLEAN_ENV{XAUTHORITY} = $ENV{'XAUTHORITY'};
+ }
+
+ $CLEAN_ENV{HOME} = $ENV{'HOME'};
+
+ if (defined $ENV{'LD_LIBRARY_PATH'}) {
+ $CLEAN_ENV{LD_LIBRARY_PATH} = $ENV{'LD_LIBRARY_PATH'};
+ }
+ if (defined $ENV{'DBUS_SESSION_BUS_ADDRESS'}) {
+ $CLEAN_ENV{DBUS_SESSION_BUS_ADDRESS} = $ENV{'DBUS_SESSION_BUS_ADDRESS'};
+ }
+ } elsif (isDarwin()) {
+ if (defined $ENV{'DYLD_LIBRARY_PATH'}) {
+ $CLEAN_ENV{DYLD_LIBRARY_PATH} = $ENV{'DYLD_LIBRARY_PATH'};
+ }
+
+ $CLEAN_ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ $CLEAN_ENV{DYLD_INSERT_LIBRARIES} = "/usr/lib/libgmalloc.dylib" if $guardMalloc;
+ } elsif (isCygwin()) {
+ $CLEAN_ENV{HOMEDRIVE} = $ENV{'HOMEDRIVE'};
+ $CLEAN_ENV{HOMEPATH} = $ENV{'HOMEPATH'};
+ $CLEAN_ENV{_NT_SYMBOL_PATH} = $ENV{_NT_SYMBOL_PATH};
+
+ setPathForRunningWebKitApp(\%CLEAN_ENV);
+ }
+
+ # Port specifics
+ if (isGtk()) {
+ $CLEAN_ENV{GTK_MODULES} = "gail";
+ $CLEAN_ENV{WEBKIT_INSPECTOR_PATH} = "$productDir/resources/inspector";
+ }
+
+ if (isQt()) {
+ $CLEAN_ENV{QTWEBKIT_PLUGIN_PATH} = productDir() . "/lib/plugins";
+ $CLEAN_ENV{QT_DRT_WEBVIEW_MODE} = $ENV{"QT_DRT_WEBVIEW_MODE"};
+ }
+
+ my @args = ($dumpTool, @toolArgs);
+ if (isAppleMacWebKit() and !isTiger()) {
+ unshift @args, "arch", "-" . architecture();
+ }
+
+ if ($useValgrind) {
+ unshift @args, "valgrind", "--suppressions=$platformBaseDirectory/qt/SuppressedValgrindErrors";
+ }
+
+ if ($useWebKitTestRunner) {
+ # Make WebKitTestRunner use a similar timeout. We don't use the exact same timeout to avoid
+ # race conditions.
+ push @args, "--timeout", $timeoutSeconds - 5;
+ }
+
+ $CLEAN_ENV{MallocStackLogging} = 1 if $shouldCheckLeaks;
+
+ $dumpToolPID = open3(\*OUT, \*IN, \*ERROR, launchWithEnv(@args, %CLEAN_ENV)) or die "Failed to start tool: $dumpTool\n";
+ $isDumpToolOpen = 1;
+ $dumpToolCrashed = 0;
+}
+
+sub closeDumpTool()
+{
+ return if !$isDumpToolOpen;
+
+ if ($verbose && $testsPerDumpTool != 1) {
+ print "| Closing DumpTool |\n";
+ }
+
+ close IN;
+ close OUT;
+ waitpid $dumpToolPID, 0;
+
+ # check for WebCore counter leaks.
+ if ($shouldCheckLeaks) {
+ while (<ERROR>) {
+ print;
+ }
+ }
+ close ERROR;
+ $isDumpToolOpen = 0;
+}
+
+sub dumpToolDidCrash()
+{
+ return 1 if $dumpToolCrashed;
+ return 0 unless $isDumpToolOpen;
+ my $pid = waitpid(-1, WNOHANG);
+ return 1 if ($pid == $dumpToolPID);
+
+ # On Mac OS X, crashing may be significantly delayed by crash reporter.
+ return 0 unless isAppleMacWebKit();
+
+ return DumpRenderTreeSupport::processIsCrashing($dumpToolPID);
+}
+
+sub configureAndOpenHTTPDIfNeeded()
+{
+ return if $isHttpdOpen;
+ my $absTestResultsDirectory = resolveAndMakeTestResultsDirectory();
+ my $listen = "127.0.0.1:$httpdPort";
+ my @args = (
+ "-c", "CustomLog \"$absTestResultsDirectory/access_log.txt\" common",
+ "-c", "ErrorLog \"$absTestResultsDirectory/error_log.txt\"",
+ "-C", "Listen $listen"
+ );
+
+ my @defaultArgs = getDefaultConfigForTestDirectory($testDirectory);
+ @args = (@defaultArgs, @args);
+
+ waitForHTTPDLock() if $shouldWaitForHTTPD;
+ $isHttpdOpen = openHTTPD(@args);
+}
+
+sub checkPythonVersion()
+{
+ # we have not chdir to sourceDir yet.
+ system $perlInterpreter, File::Spec->catfile(sourceDir(), qw(Tools Scripts ensure-valid-python)), "--check-only";
+ return exitStatus($?) == 0;
+}
+
+sub openWebSocketServerIfNeeded()
+{
+ return 1 if $isWebSocketServerOpen;
+ return 0 if $failedToStartWebSocketServer;
+
+ my $webSocketHandlerDir = "$testDirectory";
+ my $absTestResultsDirectory = resolveAndMakeTestResultsDirectory();
+ $webSocketServerPidFile = "$absTestResultsDirectory/websocket.pid";
+
+ my @args = (
+ "Tools/Scripts/new-run-webkit-websocketserver",
+ "--server", "start",
+ "--port", "$webSocketPort",
+ "--root", "$webSocketHandlerDir",
+ "--output-dir", "$absTestResultsDirectory",
+ "--pidfile", "$webSocketServerPidFile"
+ );
+ system "/usr/bin/python", @args;
+
+ $isWebSocketServerOpen = 1;
+ return 1;
+}
+
+sub closeWebSocketServer()
+{
+ return if !$isWebSocketServerOpen;
+
+ my @args = (
+ "Tools/Scripts/new-run-webkit-websocketserver",
+ "--server", "stop",
+ "--pidfile", "$webSocketServerPidFile"
+ );
+ system "/usr/bin/python", @args;
+ unlink "$webSocketServerPidFile";
+
+ # wss is disabled until all platforms support pyOpenSSL.
+ $isWebSocketServerOpen = 0;
+}
+
+sub fileNameWithNumber($$)
+{
+ my ($base, $number) = @_;
+ return "$base$number" if ($number > 1);
+ return $base;
+}
+
+sub processIgnoreTests($$)
+{
+ my @ignoreList = split(/\s*,\s*/, shift);
+ my $listName = shift;
+
+ my $disabledSuffix = "-disabled";
+
+ my $addIgnoredDirectories = sub {
+ return () if exists $ignoredLocalDirectories{basename($File::Find::dir)};
+ $ignoredDirectories{File::Spec->abs2rel($File::Find::dir, $testDirectory)} = 1;
+ return @_;
+ };
+ foreach my $item (@ignoreList) {
+ my $path = catfile($testDirectory, $item);
+ if (-d $path) {
+ $ignoredDirectories{$item} = 1;
+ find({ preprocess => $addIgnoredDirectories, wanted => sub {} }, $path);
+ }
+ elsif (-f $path) {
+ $ignoredFiles{$item} = 1;
+ } elsif (-f $path . $disabledSuffix) {
+ # The test is disabled, so do nothing.
+ } else {
+ print "$listName list contained '$item', but no file of that name could be found\n";
+ }
+ }
+}
+
+sub stripExtension($)
+{
+ my ($test) = @_;
+
+ $test =~ s/\.[a-zA-Z]+$//;
+ return $test;
+}
+
+sub isTextOnlyTest($)
+{
+ my ($actual) = @_;
+ my $isText;
+ if ($actual =~ /^layer at/ms) {
+ $isText = 0;
+ } else {
+ $isText = 1;
+ }
+ return $isText;
+}
+
+sub expectedDirectoryForTest($;$;$)
+{
+ my ($base, $isText, $expectedExtension) = @_;
+
+ my @directories = @platformResultHierarchy;
+ push @directories, map { catdir($platformBaseDirectory, $_) } qw(mac-snowleopard mac) if isAppleWinWebKit();
+ push @directories, $expectedDirectory;
+
+ # If we already have expected results, just return their location.
+ foreach my $directory (@directories) {
+ return $directory if -f File::Spec->catfile($directory, "$base-$expectedTag.$expectedExtension");
+ }
+
+ # For cross-platform tests, text-only results should go in the cross-platform directory,
+ # while render tree dumps should go in the least-specific platform directory.
+ return $isText ? $expectedDirectory : $platformResultHierarchy[$#platformResultHierarchy];
+}
+
+sub countFinishedTest($$$$)
+{
+ my ($test, $base, $result, $isText) = @_;
+
+ if (($count + 1) % $testsPerDumpTool == 0 || $count == $#tests) {
+ if ($shouldCheckLeaks) {
+ my $fileName;
+ if ($testsPerDumpTool == 1) {
+ $fileName = File::Spec->catfile($testResultsDirectory, "$base-leaks.txt");
+ } else {
+ $fileName = File::Spec->catfile($testResultsDirectory, fileNameWithNumber($dumpToolName, $leaksOutputFileNumber) . "-leaks.txt");
+ }
+ my $leakCount = countAndPrintLeaks($dumpToolName, $dumpToolPID, $fileName);
+ $totalLeaks += $leakCount;
+ $leaksOutputFileNumber++ if ($leakCount);
+ }
+
+ closeDumpTool();
+ }
+
+ $count++;
+ $counts{$result}++;
+ push @{$tests{$result}}, $test;
+}
+
+sub testCrashedOrTimedOut($$$$$)
+{
+ my ($test, $base, $didCrash, $actual, $error) = @_;
+
+ printFailureMessageForTest($test, $didCrash ? "crashed" : "timed out");
+
+ sampleDumpTool() unless $didCrash;
+
+ my $dir = dirname(File::Spec->catdir($testResultsDirectory, $base));
+ mkpath $dir;
+
+ deleteExpectedAndActualResults($base);
+
+ if (defined($error) && length($error)) {
+ writeToFile(File::Spec->catfile($testResultsDirectory, "$base-$errorTag.txt"), $error);
+ }
+
+ recordActualResultsAndDiff($base, $actual);
+
+ kill 9, $dumpToolPID unless $didCrash;
+
+ closeDumpTool();
+
+ return unless isCygwin() && !$didCrash && $base =~ /^http/;
+ # On Cygwin, http tests timing out can be a symptom of a non-responsive httpd.
+ # If we timed out running an http test, try restarting httpd.
+ $isHttpdOpen = !closeHTTPD();
+ configureAndOpenHTTPDIfNeeded();
+}
+
+sub printFailureMessageForTest($$)
+{
+ my ($test, $description) = @_;
+
+ unless ($verbose) {
+ print "\n" unless $atLineStart;
+ print "$test -> ";
+ }
+ print "$description\n";
+ $atLineStart = 1;
+}
+
+my %cygpaths = ();
+
+sub openCygpathIfNeeded($)
+{
+ my ($options) = @_;
+
+ return unless isCygwin();
+ return $cygpaths{$options} if $cygpaths{$options} && $cygpaths{$options}->{"open"};
+
+ local (*CYGPATHIN, *CYGPATHOUT);
+ my $pid = open2(\*CYGPATHIN, \*CYGPATHOUT, "cygpath -f - $options");
+ my $cygpath = {
+ "pid" => $pid,
+ "in" => *CYGPATHIN,
+ "out" => *CYGPATHOUT,
+ "open" => 1
+ };
+
+ $cygpaths{$options} = $cygpath;
+
+ return $cygpath;
+}
+
+sub closeCygpaths()
+{
+ return unless isCygwin();
+
+ foreach my $cygpath (values(%cygpaths)) {
+ close $cygpath->{"in"};
+ close $cygpath->{"out"};
+ waitpid($cygpath->{"pid"}, 0);
+ $cygpath->{"open"} = 0;
+
+ }
+}
+
+sub convertPathUsingCygpath($$)
+{
+ my ($path, $options) = @_;
+
+ # cygpath -f (at least in Cygwin 1.7) converts spaces into newlines. We remove spaces here and
+ # add them back in after conversion to work around this.
+ my $spaceSubstitute = "__NOTASPACE__";
+ $path =~ s/ /\Q$spaceSubstitute\E/g;
+
+ my $cygpath = openCygpathIfNeeded($options);
+ local *inFH = $cygpath->{"in"};
+ local *outFH = $cygpath->{"out"};
+ print outFH $path . "\n";
+ my $convertedPath = <inFH>;
+ chomp($convertedPath) if defined $convertedPath;
+
+ $convertedPath =~ s/\Q$spaceSubstitute\E/ /g;
+ return $convertedPath;
+}
+
+sub toCygwinPath($)
+{
+ my ($path) = @_;
+ return unless isCygwin();
+
+ return convertPathUsingCygpath($path, "-u");
+}
+
+sub toWindowsPath($)
+{
+ my ($path) = @_;
+ return unless isCygwin();
+
+ return convertPathUsingCygpath($path, "-w");
+}
+
+sub toURL($)
+{
+ my ($path) = @_;
+
+ if ($useRemoteLinksToTests) {
+ my $relativePath = File::Spec->abs2rel($path, $testDirectory);
+
+ # If the file is below the test directory then convert it into a link to the file in SVN
+ if ($relativePath !~ /^\.\.\//) {
+ my $revision = svnRevisionForDirectory($testDirectory);
+ my $svnPath = pathRelativeToSVNRepositoryRootForPath($path);
+ return "http://trac.webkit.org/export/$revision/$svnPath";
+ }
+ }
+
+ return $path unless isCygwin();
+
+ return "file:///" . convertPathUsingCygpath($path, "-m");
+}
+
+sub validateSkippedArg($$;$)
+{
+ my ($option, $value, $value2) = @_;
+ my %validSkippedValues = map { $_ => 1 } qw(default ignore only);
+ $value = lc($value);
+ die "Invalid argument '" . $value . "' for option $option" unless $validSkippedValues{$value};
+ $treatSkipped = $value;
+}
+
+sub htmlForResultsSection(\@$&)
+{
+ my ($tests, $description, $linkGetter) = @_;
+
+ my @html = ();
+ return join("\n", @html) unless @{$tests};
+
+ push @html, "<p>$description:</p>";
+ push @html, "<table>";
+ foreach my $test (@{$tests}) {
+ push @html, "<tr>";
+ push @html, "<td><a href=\"" . toURL("$testDirectory/$test") . "\">$test</a></td>";
+ foreach my $link (@{&{$linkGetter}($test)}) {
+ push @html, "<td><a href=\"$link->{href}\">$link->{text}</a></td>";
+ }
+ push @html, "</tr>";
+ }
+ push @html, "</table>";
+
+ return join("\n", @html);
+}
+
+sub linksForExpectedAndActualResults($)
+{
+ my ($base) = @_;
+
+ my @links = ();
+
+ return \@links unless -s "$testResultsDirectory/$base-$diffsTag.txt";
+
+ my $expectedResultPath = $expectedResultPaths{$base};
+ my ($expectedResultFileName, $expectedResultsDirectory, $expectedResultExtension) = fileparse($expectedResultPath, qr{\.[^.]+$});
+
+ push @links, { href => "$base-$expectedTag$expectedResultExtension", text => "expected" };
+ push @links, { href => "$base-$actualTag$expectedResultExtension", text => "actual" };
+ push @links, { href => "$base-$diffsTag.txt", text => "diff" };
+ push @links, { href => "$base-$prettyDiffTag.html", text => "pretty diff" };
+
+ return \@links;
+}
+
+sub linksForMismatchTest
+{
+ my ($test) = @_;
+
+ my @links = ();
+
+ my $base = stripExtension($test);
+
+ push @links, @{linksForExpectedAndActualResults($base)};
+ return \@links unless $pixelTests && $imagesPresent{$base};
+
+ push @links, { href => "$base-$expectedTag.png", text => "expected image" };
+ push @links, { href => "$base-$diffsTag.html", text => "image diffs" };
+ push @links, { href => "$base-$diffsTag.png", text => "$imageDifferences{$base}%" };
+
+ return \@links;
+}
+
+sub linksForErrorTest
+{
+ my ($test) = @_;
+
+ my @links = ();
+
+ my $base = stripExtension($test);
+
+ push @links, @{linksForExpectedAndActualResults($base)};
+ push @links, { href => "$base-$errorTag.txt", text => "stderr" };
+
+ return \@links;
+}
+
+sub linksForNewTest
+{
+ my ($test) = @_;
+
+ my @links = ();
+
+ my $base = stripExtension($test);
+
+ my $expectedResultPath = $expectedResultPaths{$base};
+ my ($expectedResultFileName, $expectedResultsDirectory, $expectedResultExtension) = fileparse($expectedResultPath, qr{\.[^.]+$});
+
+ push @links, { href => "$base-$actualTag$expectedResultExtension", text => "result" };
+ if ($pixelTests && $imagesPresent{$base}) {
+ push @links, { href => "$base-$expectedTag.png", text => "image" };
+ }
+
+ return \@links;
+}
+
+sub deleteExpectedAndActualResults($)
+{
+ my ($base) = @_;
+
+ unlink "$testResultsDirectory/$base-$actualTag.txt";
+ unlink "$testResultsDirectory/$base-$diffsTag.txt";
+ unlink "$testResultsDirectory/$base-$errorTag.txt";
+}
+
+sub recordActualResultsAndDiff($$)
+{
+ my ($base, $actualResults) = @_;
+
+ return unless defined($actualResults) && length($actualResults);
+
+ my $expectedResultPath = $expectedResultPaths{$base};
+ my ($expectedResultFileNameMinusExtension, $expectedResultDirectoryPath, $expectedResultExtension) = fileparse($expectedResultPath, qr{\.[^.]+$});
+ my $actualResultsPath = File::Spec->catfile($testResultsDirectory, "$base-$actualTag$expectedResultExtension");
+ my $copiedExpectedResultsPath = File::Spec->catfile($testResultsDirectory, "$base-$expectedTag$expectedResultExtension");
+
+ mkpath(dirname($actualResultsPath));
+ writeToFile("$actualResultsPath", $actualResults);
+
+ if (-f $expectedResultPath) {
+ copy("$expectedResultPath", "$copiedExpectedResultsPath");
+ } else {
+ open EMPTY, ">$copiedExpectedResultsPath";
+ close EMPTY;
+ }
+
+ my $diffOuputBasePath = File::Spec->catfile($testResultsDirectory, $base);
+ my $diffOutputPath = "$diffOuputBasePath-$diffsTag.txt";
+ system "diff -u \"$copiedExpectedResultsPath\" \"$actualResultsPath\" > \"$diffOutputPath\"";
+
+ my $prettyDiffOutputPath = "$diffOuputBasePath-$prettyDiffTag.html";
+ my $prettyPatchPath = "Websites/bugs.webkit.org/PrettyPatch/";
+ my $prettifyPath = "$prettyPatchPath/prettify.rb";
+ system "ruby -I \"$prettyPatchPath\" \"$prettifyPath\" \"$diffOutputPath\" > \"$prettyDiffOutputPath\"";
+}
+
+sub buildPlatformResultHierarchy()
+{
+ mkpath($platformTestDirectory) if ($platform eq "undefined" && !-d "$platformTestDirectory");
+
+ my @platforms;
+
+ my $isMac = $platform =~ /^mac/;
+ my $isWin = $platform =~ /^win/;
+ if ($isMac || $isWin) {
+ my $effectivePlatform = $platform;
+ if ($platform eq "mac-wk2" || $platform eq "win-wk2") {
+ push @platforms, $platform;
+ $effectivePlatform = $realPlatform;
+ }
+
+ my @platformList = $isMac ? @macPlatforms : @winPlatforms;
+ my $i;
+ for ($i = 0; $i < @platformList; $i++) {
+ last if $platformList[$i] eq $effectivePlatform;
+ }
+ for (; $i < @platformList; $i++) {
+ push @platforms, $platformList[$i];
+ }
+ } elsif ($platform =~ /^qt-/) {
+ push @platforms, $platform;
+ push @platforms, "qt";
+ } else {
+ @platforms = $platform;
+ }
+
+ my @hierarchy;
+ for (my $i = 0; $i < @platforms; $i++) {
+ my $scoped = catdir($platformBaseDirectory, $platforms[$i]);
+ push(@hierarchy, $scoped) if (-d $scoped);
+ }
+
+ return @hierarchy;
+}
+
+sub buildPlatformTestHierarchy(@)
+{
+ my (@platformHierarchy) = @_;
+ return @platformHierarchy if (@platformHierarchy < 2);
+ if ($platformHierarchy[0] =~ /mac-wk2/) {
+ return ($platformHierarchy[0], $platformHierarchy[1], $platformHierarchy[$#platformHierarchy]);
+ }
+ return ($platformHierarchy[0], $platformHierarchy[$#platformHierarchy]);
+}
+
+sub epiloguesAndPrologues($$)
+{
+ my ($lastDirectory, $directory) = @_;
+ my @lastComponents = split('/', $lastDirectory);
+ my @components = split('/', $directory);
+
+ while (@lastComponents) {
+ if (!defined($components[0]) || $lastComponents[0] ne $components[0]) {
+ last;
+ }
+ shift @components;
+ shift @lastComponents;
+ }
+
+ my @result;
+ my $leaving = $lastDirectory;
+ foreach (@lastComponents) {
+ my $epilogue = $leaving . "/resources/run-webkit-tests-epilogue.html";
+ foreach (@platformResultHierarchy) {
+ push @result, catdir($_, $epilogue) if (stat(catdir($_, $epilogue)));
+ }
+ push @result, catdir($testDirectory, $epilogue) if (stat(catdir($testDirectory, $epilogue)));
+ $leaving =~ s|(^\|/)[^/]+$||;
+ }
+
+ my $entering = $leaving;
+ foreach (@components) {
+ $entering .= '/' . $_;
+ my $prologue = $entering . "/resources/run-webkit-tests-prologue.html";
+ push @result, catdir($testDirectory, $prologue) if (stat(catdir($testDirectory, $prologue)));
+ foreach (reverse @platformResultHierarchy) {
+ push @result, catdir($_, $prologue) if (stat(catdir($_, $prologue)));
+ }
+ }
+ return @result;
+}
+
+sub parseLeaksandPrintUniqueLeaks()
+{
+ return unless @leaksFilenames;
+
+ my $mergedFilenames = join " ", @leaksFilenames;
+ my $parseMallocHistoryTool = sourceDir() . "/Tools/Scripts/parse-malloc-history";
+
+ open MERGED_LEAKS, "cat $mergedFilenames | $parseMallocHistoryTool --merge-depth $mergeDepth - |" ;
+ my @leakLines = <MERGED_LEAKS>;
+ close MERGED_LEAKS;
+
+ my $uniqueLeakCount = 0;
+ my $totalBytes;
+ foreach my $line (@leakLines) {
+ ++$uniqueLeakCount if ($line =~ /^(\d*)\scalls/);
+ $totalBytes = $1 if $line =~ /^total\:\s(.*)\s\(/;
+ }
+
+ print "\nWARNING: $totalLeaks total leaks found for a total of $totalBytes!\n";
+ print "WARNING: $uniqueLeakCount unique leaks found!\n";
+ print "See above for individual leaks results.\n" if ($leaksOutputFileNumber > 2);
+
+}
+
+sub extensionForMimeType($)
+{
+ my ($mimeType) = @_;
+
+ if ($mimeType eq "application/x-webarchive") {
+ return "webarchive";
+ } elsif ($mimeType eq "application/pdf") {
+ return "pdf";
+ }
+ return "txt";
+}
+
+# Read up to the first #EOF (the content block of the test), or until detecting crashes or timeouts.
+sub readFromDumpToolWithTimer(**)
+{
+ my ($fhIn, $fhError) = @_;
+
+ setFileHandleNonBlocking($fhIn, 1);
+ setFileHandleNonBlocking($fhError, 1);
+
+ my $maximumSecondsWithoutOutput = $timeoutSeconds;
+ my $microsecondsToWaitBeforeReadingAgain = 1000;
+
+ my $timeOfLastSuccessfulRead = time;
+
+ my @output = ();
+ my @error = ();
+ my $status = "success";
+ my $mimeType = "text/plain";
+ # We don't have a very good way to know when the "headers" stop
+ # and the content starts, so we use this as a hack:
+ my $haveSeenContentType = 0;
+ my $haveSeenEofIn = 0;
+ my $haveSeenEofError = 0;
+
+ while (1) {
+ if (time - $timeOfLastSuccessfulRead > $maximumSecondsWithoutOutput) {
+ $status = dumpToolDidCrash() ? "crashed" : "timedOut";
+ last;
+ }
+
+ # Once we've seen the EOF, we must not read anymore.
+ my $lineIn = readline($fhIn) unless $haveSeenEofIn;
+ my $lineError = readline($fhError) unless $haveSeenEofError;
+ if (!defined($lineIn) && !defined($lineError)) {
+ last if ($haveSeenEofIn && $haveSeenEofError);
+
+ if ($! != EAGAIN) {
+ $status = "crashed";
+ last;
+ }
+
+ # No data ready
+ usleep($microsecondsToWaitBeforeReadingAgain);
+ next;
+ }
+
+ $timeOfLastSuccessfulRead = time;
+
+ if (defined($lineIn)) {
+ if (!$haveSeenContentType && $lineIn =~ /^Content-Type: (\S+)$/) {
+ $mimeType = $1;
+ $haveSeenContentType = 1;
+ } elsif ($lineIn =~ /#EOF/) {
+ $haveSeenEofIn = 1;
+ } else {
+ push @output, $lineIn;
+ }
+ }
+ if (defined($lineError)) {
+ if ($lineError =~ /#CRASHED/) {
+ $status = "crashed";
+ last;
+ }
+ if ($lineError =~ /#EOF/) {
+ $haveSeenEofError = 1;
+ } else {
+ push @error, $lineError;
+ }
+ }
+ }
+
+ setFileHandleNonBlocking($fhIn, 0);
+ setFileHandleNonBlocking($fhError, 0);
+ return {
+ output => join("", @output),
+ error => join("", @error),
+ status => $status,
+ mimeType => $mimeType,
+ extension => extensionForMimeType($mimeType)
+ };
+}
+
+sub setFileHandleNonBlocking(*$)
+{
+ my ($fh, $nonBlocking) = @_;
+
+ my $flags = fcntl($fh, F_GETFL, 0) or die "Couldn't get filehandle flags";
+
+ if ($nonBlocking) {
+ $flags |= O_NONBLOCK;
+ } else {
+ $flags &= ~O_NONBLOCK;
+ }
+
+ fcntl($fh, F_SETFL, $flags) or die "Couldn't set filehandle flags";
+
+ return 1;
+}
+
+sub sampleDumpTool()
+{
+ return unless isAppleMacWebKit();
+ return unless $runSample;
+
+ my $outputDirectory = "$ENV{HOME}/Library/Logs/DumpRenderTree";
+ -d $outputDirectory or mkdir $outputDirectory;
+
+ my $outputFile = "$outputDirectory/HangReport.txt";
+ system "/usr/bin/sample", $dumpToolPID, qw(10 10 -file), $outputFile;
+}
+
+sub stripMetrics($$)
+{
+ my ($actual, $expected) = @_;
+
+ foreach my $result ($actual, $expected) {
+ $result =~ s/at \(-?[0-9]+,-?[0-9]+\) *//g;
+ $result =~ s/size -?[0-9]+x-?[0-9]+ *//g;
+ $result =~ s/text run width -?[0-9]+: //g;
+ $result =~ s/text run width -?[0-9]+ [a-zA-Z ]+: //g;
+ $result =~ s/RenderButton {BUTTON} .*/RenderButton {BUTTON}/g;
+ $result =~ s/RenderImage {INPUT} .*/RenderImage {INPUT}/g;
+ $result =~ s/RenderBlock {INPUT} .*/RenderBlock {INPUT}/g;
+ $result =~ s/RenderTextControl {INPUT} .*/RenderTextControl {INPUT}/g;
+ $result =~ s/\([0-9]+px/px/g;
+ $result =~ s/ *" *\n +" */ /g;
+ $result =~ s/" +$/"/g;
+
+ $result =~ s/- /-/g;
+ $result =~ s/\n( *)"\s+/\n$1"/g;
+ $result =~ s/\s+"\n/"\n/g;
+ $result =~ s/scrollWidth [0-9]+/scrollWidth/g;
+ $result =~ s/scrollHeight [0-9]+/scrollHeight/g;
+ }
+
+ return ($actual, $expected);
+}
+
+sub fileShouldBeIgnored
+{
+ my ($filePath) = @_;
+ foreach my $ignoredDir (keys %ignoredDirectories) {
+ if ($filePath =~ m/^$ignoredDir/) {
+ return 1;
+ }
+ }
+ return 0;
+}
+
+sub readSkippedFiles($)
+{
+ my ($constraintPath) = @_;
+
+ my @skippedFileDirectories = @platformTestHierarchy;
+
+ # Because nearly all of the skipped tests for WebKit 2 on Mac are due to
+ # cross-platform issues, Windows will use both the Mac and Windows skipped
+ # lists to avoid maintaining separate lists.
+ push(@skippedFileDirectories, catdir($platformBaseDirectory, "mac-wk2")) if $platform eq "win-wk2";
+
+ foreach my $level (@skippedFileDirectories) {
+ if (open SKIPPED, "<", "$level/Skipped") {
+ if ($verbose) {
+ my ($dir, $name) = splitpath($level);
+ print "Skipped tests in $name:\n";
+ }
+
+ while (<SKIPPED>) {
+ my $skipped = $_;
+ chomp $skipped;
+ $skipped =~ s/^[ \n\r]+//;
+ $skipped =~ s/[ \n\r]+$//;
+ if ($skipped && $skipped !~ /^#/) {
+ if ($skippedOnly) {
+ if (!fileShouldBeIgnored($skipped)) {
+ if (!$constraintPath) {
+ # Always add $skipped since no constraint path was specified on the command line.
+ push(@ARGV, $skipped);
+ } elsif ($skipped =~ /^($constraintPath)/) {
+ # Add $skipped only if it matches the current path constraint, e.g.,
+ # "--skipped=only dir1" with "dir1/file1.html" on the skipped list.
+ push(@ARGV, $skipped);
+ } elsif ($constraintPath =~ /^($skipped)/) {
+ # Add current path constraint if it is more specific than the skip list entry,
+ # e.g., "--skipped=only dir1/dir2/dir3" with "dir1" on the skipped list.
+ push(@ARGV, $constraintPath);
+ }
+ } elsif ($verbose) {
+ print " $skipped\n";
+ }
+ } else {
+ if ($verbose) {
+ print " $skipped\n";
+ }
+ processIgnoreTests($skipped, "Skipped");
+ }
+ }
+ }
+ close SKIPPED;
+ }
+ }
+}
+
+my @testsFound;
+
+sub directoryFilter
+{
+ return () if exists $ignoredLocalDirectories{basename($File::Find::dir)};
+ return () if exists $ignoredDirectories{File::Spec->abs2rel($File::Find::dir, $testDirectory)};
+ return @_;
+}
+
+sub fileFilter
+{
+ my $filename = $_;
+ if ($filename =~ /\.([^.]+)$/) {
+ if (exists $supportedFileExtensions{$1}) {
+ my $path = File::Spec->abs2rel(catfile($File::Find::dir, $filename), $testDirectory);
+ push @testsFound, $path if !exists $ignoredFiles{$path};
+ }
+ }
+}
+
+sub findTestsToRun
+{
+ my @testsToRun = ();
+
+ for my $test (@ARGV) {
+ $test =~ s/^(\Q$layoutTestsName\E|\Q$testDirectory\E)\///;
+ my $fullPath = catfile($testDirectory, $test);
+ if (file_name_is_absolute($test)) {
+ print "can't run test $test outside $testDirectory\n";
+ } elsif (-f $fullPath) {
+ my ($filename, $pathname, $fileExtension) = fileparse($test, qr{\.[^.]+$});
+ if (!exists $supportedFileExtensions{substr($fileExtension, 1)}) {
+ print "test $test does not have a supported extension\n";
+ } elsif ($testHTTP || $pathname !~ /^http\//) {
+ push @testsToRun, $test;
+ }
+ } elsif (-d $fullPath) {
+ @testsFound = ();
+ find({ preprocess => \&directoryFilter, wanted => \&fileFilter }, $fullPath);
+ for my $level (@platformTestHierarchy) {
+ my $platformPath = catfile($level, $test);
+ find({ preprocess => \&directoryFilter, wanted => \&fileFilter }, $platformPath) if (-d $platformPath);
+ }
+ push @testsToRun, sort pathcmp @testsFound;
+ @testsFound = ();
+ } else {
+ print "test $test not found\n";
+ }
+ }
+
+ if (!scalar @ARGV) {
+ @testsFound = ();
+ find({ preprocess => \&directoryFilter, wanted => \&fileFilter }, $testDirectory);
+ for my $level (@platformTestHierarchy) {
+ find({ preprocess => \&directoryFilter, wanted => \&fileFilter }, $level);
+ }
+ push @testsToRun, sort pathcmp @testsFound;
+ @testsFound = ();
+
+ # We need to minimize the time when Apache and WebSocketServer is locked by tests
+ # so run them last if no explicit order was specified in the argument list.
+ my @httpTests;
+ my @websocketTests;
+ my @otherTests;
+ foreach my $test (@testsToRun) {
+ if ($test =~ /^http\//) {
+ push(@httpTests, $test);
+ } elsif ($test =~ /^websocket\//) {
+ push(@websocketTests, $test);
+ } else {
+ push(@otherTests, $test);
+ }
+ }
+ @testsToRun = (@otherTests, @httpTests, @websocketTests);
+ }
+
+ # Reverse the tests
+ @testsToRun = reverse @testsToRun if $reverseTests;
+
+ # Shuffle the array
+ @testsToRun = shuffle(@testsToRun) if $randomizeTests;
+
+ return @testsToRun;
+}
+
+sub printResults
+{
+ my %text = (
+ match => "succeeded",
+ mismatch => "had incorrect layout",
+ new => "were new",
+ timedout => "timed out",
+ crash => "crashed",
+ error => "had stderr output"
+ );
+
+ for my $type ("match", "mismatch", "new", "timedout", "crash", "error") {
+ my $typeCount = $counts{$type};
+ next unless $typeCount;
+ my $typeText = $text{$type};
+ my $message;
+ if ($typeCount == 1) {
+ $typeText =~ s/were/was/;
+ $message = sprintf "1 test case (%d%%) %s\n", 1 * 100 / $count, $typeText;
+ } else {
+ $message = sprintf "%d test cases (%d%%) %s\n", $typeCount, $typeCount * 100 / $count, $typeText;
+ }
+ $message =~ s-\(0%\)-(<1%)-;
+ print $message;
+ }
+}
+
+sub stopRunningTestsEarlyIfNeeded()
+{
+ # --reset-results does not check pass vs. fail, so exitAfterNFailures makes no sense with --reset-results.
+ return 0 if $resetResults;
+
+ my $passCount = $counts{match} || 0; # $counts{match} will be undefined if we've not yet passed a test (e.g. the first test fails).
+ my $newCount = $counts{new} || 0;
+ my $failureCount = $count - $passCount - $newCount; # "Failure" here includes timeouts, crashes, etc.
+ if ($exitAfterNFailures && $failureCount >= $exitAfterNFailures) {
+ print "\nExiting early after $failureCount failures. $count tests run.";
+ closeDumpTool();
+ return 1;
+ }
+
+ my $crashCount = $counts{crash} || 0;
+ my $timeoutCount = $counts{timedout} || 0;
+ if ($exitAfterNCrashesOrTimeouts && $crashCount + $timeoutCount >= $exitAfterNCrashesOrTimeouts) {
+ print "\nExiting early after $crashCount crashes and $timeoutCount timeouts. $count tests run.";
+ closeDumpTool();
+ return 1;
+ }
+
+ return 0;
+}
+
+sub setUpWindowsCrashLogSaving()
+{
+ return unless isCygwin();
+
+ unless (defined $ENV{_NT_SYMBOL_PATH}) {
+ print "The _NT_SYMBOL_PATH environment variable is not set. Crash logs will not be saved.\nSee <http://trac.webkit.org/wiki/BuildingOnWindows#GettingCrashLogs>.\n";
+ return;
+ }
+
+ my $ntsdPath = File::Spec->catfile(toCygwinPath($ENV{PROGRAMFILES}), "Debugging Tools for Windows (x86)", "ntsd.exe");
+ unless (-f $ntsdPath) {
+ $ntsdPath = File::Spec->catfile(toCygwinPath($ENV{SYSTEMROOT}), "system32", "ntsd.exe");
+ unless (-f $ntsdPath) {
+ print STDERR "Can't find ntsd.exe. Crash logs will not be saved.\nSee <http://trac.webkit.org/wiki/BuildingOnWindows#GettingCrashLogs>.\n";
+ return;
+ }
+ }
+
+ my %values = (
+ Debugger => '"' . toWindowsPath($ntsdPath) . '" -p %ld -e %ld -g -lines -c ".logopen /t \"' . toWindowsPath($testResultsDirectory) . '\CrashLog.txt\";!analyze -vv;~*kpn;q"',
+ Auto => 1
+ );
+
+ foreach my $value (keys %values) {
+ chomp($previousWindowsPostMortemDebuggerValues{$value} = `regtool get "$windowsPostMortemDebuggerKey/$value"`);
+ my $result = system "regtool", "set", "-s", "$windowsPostMortemDebuggerKey/$value", $values{$value};
+ next unless $result;
+
+ print "Failed to set \"$windowsPostMortemDebuggerKey/$value\". Crash logs will not be saved.\nSee <http://trac.webkit.org/wiki/BuildingOnWindows#GettingCrashLogs>.\n";
+ return;
+ }
+
+ print "Crash logs will be saved to $testResultsDirectory.\n";
+}
+
+END {
+ return unless isCygwin();
+
+ foreach my $value (keys %previousWindowsPostMortemDebuggerValues) {
+ my $result = system "regtool", "set", "-s", "$windowsPostMortemDebuggerKey/$value", $previousWindowsPostMortemDebuggerValues{$value};
+ !$result or print "Failed to restore \"$windowsPostMortemDebuggerKey/$value\" to its previous value \"$previousWindowsPostMortemDebuggerValues{$value}\"\n.";
+ }
+}
diff --git a/Tools/Scripts/parallelcl b/Tools/Scripts/parallelcl
new file mode 100755
index 0000000..8a46365
--- /dev/null
+++ b/Tools/Scripts/parallelcl
@@ -0,0 +1,224 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use File::Basename;
+use File::Spec;
+use File::Temp;
+use POSIX;
+
+sub makeJob(\@$);
+sub forkAndCompileFiles(\@$);
+sub Exec($);
+sub waitForChild(\@);
+sub cleanup(\@);
+
+my $debug = 0;
+
+chomp(my $clexe = `cygpath -u '$ENV{'VS80COMNTOOLS'}/../../VC/bin/cl.exe'`);
+
+if ($debug) {
+ print STDERR "Received " . @ARGV . " arguments:\n";
+ foreach my $arg (@ARGV) {
+ print STDERR "$arg\n";
+ }
+}
+
+my $commandFile;
+foreach my $arg (@ARGV) {
+ if ($arg =~ /^[\/-](E|EP|P)$/) {
+ print STDERR "The invoking process wants preprocessed source, so let's hand off this whole command to the real cl.exe\n" if $debug;
+ Exec("\"$clexe\" \"" . join('" "', @ARGV) . "\"");
+ } elsif ($arg =~ /^@(.*)$/) {
+ chomp($commandFile = `cygpath -u '$1'`);
+ }
+}
+
+die "No command file specified!" unless $commandFile;
+die "Couldn't find $commandFile!" unless -f $commandFile;
+
+my @sources;
+
+open(COMMAND, '<:raw:encoding(UTF16-LE):crlf:utf8', $commandFile) or die "Couldn't open $commandFile!";
+
+# The first line of the command file contains all the options to cl.exe plus the first (possibly quoted) filename
+my $firstLine = <COMMAND>;
+$firstLine =~ s/\r?\n$//;
+
+# To find the start of the first filename, look for either the last space on the line.
+# If the filename is quoted, the last character on the line will be a quote, so look for the quote before that.
+my $firstFileIndex;
+print STDERR "Last character of first line = '" . substr($firstLine, -1, 1) . "'\n" if $debug;
+if (substr($firstLine, -1, 1) eq '"') {
+ print STDERR "First file is quoted\n" if $debug;
+ $firstFileIndex = rindex($firstLine, '"', length($firstLine) - 2);
+} else {
+ print STDERR "First file is NOT quoted\n" if $debug;
+ $firstFileIndex = rindex($firstLine, ' ') + 1;
+}
+
+my $options = substr($firstLine, 0, $firstFileIndex) . join(' ', @ARGV[1 .. $#ARGV]);
+my $possibleFirstFile = substr($firstLine, $firstFileIndex);
+if ($possibleFirstFile =~ /\.(cpp|c)/) {
+ push(@sources, $possibleFirstFile);
+} else {
+ $options .= " $possibleFirstFile";
+}
+
+print STDERR "######## Found options $options ##########\n" if $debug;
+print STDERR "####### Found first source file $sources[0] ########\n" if @sources && $debug;
+
+# The rest of the lines of the command file just contain source files, one per line
+while (my $source = <COMMAND>) {
+ chomp($source);
+ $source =~ s/^\s+//;
+ $source =~ s/\s+$//;
+ push(@sources, $source) if length($source);
+}
+close(COMMAND);
+
+my $numSources = @sources;
+exit unless $numSources > 0;
+
+my $numJobs;
+if ($options =~ s/-j\s*([0-9]+)//) {
+ $numJobs = $1;
+} else {
+ chomp($numJobs = `num-cpus`);
+}
+
+print STDERR "\n\n####### COMPILING $numSources FILES USING AT MOST $numJobs PARALLEL INSTANCES OF cl.exe ###########\n\n";# if $debug;
+
+# Magic determination of job size
+# The hope is that by splitting the source files up into 2*$numJobs pieces, we
+# won't suffer too much if one job finishes much more quickly than another.
+# However, we don't want to split it up too much due to cl.exe overhead, so set
+# the minimum job size to 5.
+my $jobSize = POSIX::ceil($numSources / (2 * $numJobs));
+$jobSize = $jobSize < 5 ? 5 : $jobSize;
+
+print STDERR "######## jobSize = $jobSize ##########\n" if $debug;
+
+# Sort the source files randomly so that we don't end up with big clumps of large files (aka SVG)
+sub fisher_yates_shuffle(\@)
+{
+ my ($array) = @_;
+ for (my $i = @{$array}; --$i; ) {
+ my $j = int(rand($i+1));
+ next if $i == $j;
+ @{$array}[$i,$j] = @{$array}[$j,$i];
+ }
+}
+
+fisher_yates_shuffle(@sources); # permutes @array in place
+
+my @children;
+my @tmpFiles;
+my $status = 0;
+while (@sources) {
+ while (@sources && @children < $numJobs) {
+ my $pid;
+ my $tmpFile;
+ my $job = makeJob(@sources, $jobSize);
+ ($pid, $tmpFile) = forkAndCompileFiles(@{$job}, $options);
+
+ print STDERR "####### Spawned child with PID $pid and tmpFile $tmpFile ##########\n" if $debug;
+ push(@children, $pid);
+ push(@tmpFiles, $tmpFile);
+ }
+
+ $status |= waitForChild(@children);
+}
+
+while (@children) {
+ $status |= waitForChild(@children);
+}
+cleanup(@tmpFiles);
+
+exit WEXITSTATUS($status);
+
+
+sub makeJob(\@$)
+{
+ my ($files, $jobSize) = @_;
+
+ my @job;
+ if (@{$files} > ($jobSize * 1.5)) {
+ @job = splice(@{$files}, -$jobSize);
+ } else {
+ # Compile all the remaining files in this job to avoid having a small job later
+ @job = splice(@{$files});
+ }
+
+ return \@job;
+}
+
+sub forkAndCompileFiles(\@$)
+{
+ print STDERR "######## forkAndCompileFiles()\n" if $debug;
+ my ($files, $options) = @_;
+
+ if ($debug) {
+ foreach my $file (@{$files}) {
+ print STDERR "######## $file\n";
+ }
+ }
+
+ my (undef, $tmpFile) = File::Temp::tempfile('clcommandXXXXX', DIR => File::Spec->tmpdir, OPEN => 0);
+
+ my $pid = fork();
+ die "Fork failed" unless defined($pid);
+
+ unless ($pid) {
+ # Child process
+ open(TMP, '>:raw:encoding(UTF16-LE):crlf:utf8', $tmpFile) or die "Couldn't open $tmpFile";
+ print TMP "$options\n";
+ foreach my $file (@{$files}) {
+ print TMP "$file\n";
+ }
+ close(TMP);
+
+ chomp(my $winTmpFile = `cygpath -m $tmpFile`);
+ Exec "\"$clexe\" \@\"$winTmpFile\"";
+ } else {
+ return ($pid, $tmpFile);
+ }
+}
+
+sub Exec($)
+{
+ my ($command) = @_;
+
+ print STDERR "Exec($command)\n" if $debug;
+
+ exec($command);
+}
+
+sub waitForChild(\@)
+{
+ my ($children) = @_;
+
+ return unless @{$children};
+
+ my $deceased = wait();
+ my $status = $?;
+ print STDERR "######## Child with PID $deceased finished ###########\n" if $debug;
+ for (my $i = 0; $i < @{$children}; $i++) {
+ if ($children->[$i] == $deceased) {
+ splice(@{$children}, $i, 1);
+ last;
+ }
+ }
+
+ return $status;
+}
+
+sub cleanup(\@)
+{
+ my ($tmpFiles) = @_;
+
+ foreach my $file (@{$tmpFiles}) {
+ unlink $file;
+ }
+}
diff --git a/Tools/Scripts/parse-malloc-history b/Tools/Scripts/parse-malloc-history
new file mode 100755
index 0000000..177de1c
--- /dev/null
+++ b/Tools/Scripts/parse-malloc-history
@@ -0,0 +1,174 @@
+#!/usr/bin/perl
+
+# 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.
+
+# Parses the callstacks in a file with malloc_history formatted content, sorting
+# based on total number of bytes allocated, and filtering based on command-line
+# parameters.
+
+use Getopt::Long;
+use File::Basename;
+
+use strict;
+use warnings;
+
+sub commify($);
+
+sub main()
+{
+ my $usage =
+ "Usage: " . basename($0) . " [options] malloc_history.txt\n" .
+ " --grep-regexp Include only call stacks that match this regular expression.\n" .
+ " --byte-minimum Include only call stacks with allocation sizes >= this value.\n" .
+ " --merge-regexp Merge all call stacks that match this regular expression.\n" .
+ " --merge-depth Merge all call stacks that match at this stack depth and above.\n";
+
+ my $grepRegexp = "";
+ my $byteMinimum = "";
+ my @mergeRegexps = ();
+ my $mergeDepth = "";
+ my $getOptionsResult = GetOptions(
+ "grep-regexp:s" => \$grepRegexp,
+ "byte-minimum:i" => \$byteMinimum,
+ "merge-regexp:s" => \@mergeRegexps,
+ "merge-depth:i" => \$mergeDepth
+ );
+ my $fileName = $ARGV[0];
+ die $usage if (!$getOptionsResult || !$fileName);
+
+ open FILE, "<$fileName" or die "bad file: $fileName";
+ my @file = <FILE>;
+ close FILE;
+
+ my %callstacks = ();
+ my $byteCountTotal = 0;
+
+ for (my $i = 0; $i < @file; $i++) {
+ my $line = $file[$i];
+ my ($callCount, $byteCount);
+
+ # First try malloc_history format
+ # 6 calls for 664 bytes thread_ffffffff |0x0 | start
+ ($callCount, $byteCount) = ($line =~ /(\d+) calls for (\d+) bytes/);
+
+ # Then try leaks format
+ # Leak: 0x0ac3ca40 size=48
+ # 0x00020001 0x00000001 0x00000000 0x00000000 ................
+ # Call stack: [thread ffffffff]: | 0x0 | start
+ if (!$callCount || !$byteCount) {
+ $callCount = 1;
+ ($byteCount) = ($line =~ /Leak: [x[:xdigit:]]* size=(\d+)/);
+
+ if ($byteCount) {
+ while (!($line =~ "Call stack: ")) {
+ $i++;
+ $line = $file[$i];
+ }
+ }
+ }
+
+ # Then try LeakFinder format
+ # --------------- Key: 213813, 84 bytes ---------
+ # c:\cygwin\home\buildbot\webkit\opensource\webcore\rendering\renderarena.cpp(78): WebCore::RenderArena::allocate
+ # c:\cygwin\home\buildbot\webkit\opensource\webcore\rendering\renderobject.cpp(82): WebCore::RenderObject::operator new
+ if (!$callCount || !$byteCount) {
+ $callCount = 1;
+ ($byteCount) = ($line =~ /Key: (?:\d+), (\d+) bytes/);
+ if ($byteCount) {
+ $line = $file[++$i];
+ my @tempStack;
+ while ($file[$i+1] !~ /^(?:-|\d)/) {
+ if ($line =~ /\): (.*)$/) {
+ my $call = $1;
+ $call =~ s/\r$//;
+ unshift(@tempStack, $call);
+ }
+ $line = $file[++$i];
+ }
+ $line = join(" | ", @tempStack);
+ }
+ }
+
+ # Then give up
+ next if (!$callCount || !$byteCount);
+
+ $byteCountTotal += $byteCount;
+
+ next if ($grepRegexp && !($line =~ $grepRegexp));
+
+ my $callstackBegin = 0;
+ if ($mergeDepth) {
+ # count stack frames backwards from end of callstack
+ $callstackBegin = length($line);
+ for (my $pipeCount = 0; $pipeCount < $mergeDepth; $pipeCount++) {
+ my $rindexResult = rindex($line, "|", $callstackBegin - 1);
+ last if $rindexResult == -1;
+ $callstackBegin = $rindexResult;
+ }
+ } else {
+ # start at beginning of callstack
+ $callstackBegin = index($line, "|");
+ }
+
+ my $callstack = substr($line, $callstackBegin + 2); # + 2 skips "| "
+ for my $regexp (@mergeRegexps) {
+ if ($callstack =~ $regexp) {
+ $callstack = $regexp . "\n";
+ last;
+ }
+ }
+
+ if (!$callstacks{$callstack}) {
+ $callstacks{$callstack} = {"callCount" => 0, "byteCount" => 0};
+ }
+
+ $callstacks{$callstack}{"callCount"} += $callCount;
+ $callstacks{$callstack}{"byteCount"} += $byteCount;
+ }
+
+ my $byteCountTotalReported = 0;
+ for my $callstack (sort { $callstacks{$b}{"byteCount"} <=> $callstacks{$a}{"byteCount"} } keys %callstacks) {
+ my $callCount = $callstacks{$callstack}{"callCount"};
+ my $byteCount = $callstacks{$callstack}{"byteCount"};
+ last if ($byteMinimum && $byteCount < $byteMinimum);
+
+ $byteCountTotalReported += $byteCount;
+ print commify($callCount) . " calls for " . commify($byteCount) . " bytes: $callstack\n";
+ }
+
+ print "total: " . commify($byteCountTotalReported) . " bytes (" . commify($byteCountTotal - $byteCountTotalReported) . " bytes excluded).\n";
+}
+
+exit(main());
+
+# Copied from perldoc -- please excuse the style
+sub commify($)
+{
+ local $_ = shift;
+ 1 while s/^([-+]?\d+)(\d{3})/$1,$2/;
+ return $_;
+}
diff --git a/Tools/Scripts/pdevenv b/Tools/Scripts/pdevenv
new file mode 100755
index 0000000..4643728
--- /dev/null
+++ b/Tools/Scripts/pdevenv
@@ -0,0 +1,45 @@
+#!/usr/bin/perl -w
+
+use strict;
+use warnings;
+
+use File::Temp qw/tempfile/;
+use FindBin;
+
+use lib $FindBin::Bin;
+use webkitdirs;
+
+my ($fh, $path) = tempfile(UNLINK => 0, SUFFIX => '.cmd') or die;
+
+chomp(my $vcBin = `cygpath -w "$FindBin::Bin/../vcbin"`);
+chomp(my $scriptsPath = `cygpath -w "$FindBin::Bin"`);
+
+my $vsToolsVar;
+if ($ENV{'VS80COMNTOOLS'}) {
+ $vsToolsVar = "VS80COMNTOOLS";
+} elsif ($ENV{'VS90COMNTOOLS'}) {
+ $vsToolsVar = "VS90COMNTOOLS";
+} else {
+ print "*************************************************************\n";
+ print "Cannot find Visual Studio tools dir.\n";
+ print "Please ensure that \$VS80COMNTOOLS or \$VS90COMNTOOLS\n";
+ print "is set to a valid location.\n";
+ print "*************************************************************\n";
+ die;
+}
+
+print $fh "\@echo off\n\n";
+print $fh "call \"\%" . $vsToolsVar . "\%\\vsvars32.bat\"\n\n";
+print $fh "set PATH=$vcBin;$scriptsPath;\%PATH\%\n\n";
+
+print $fh "IF EXIST \"\%VSINSTALLDIR\%\\Common7\\IDE\\devenv.com\" (devenv.com /useenv " . join(" ", @ARGV) . ") ELSE ";
+print $fh "VCExpress.exe /useenv " . join(" ", @ARGV) . "\n";
+
+
+close $fh;
+
+chmod 0755, $path;
+
+chomp($path = `cygpath -w -s '$path'`);
+
+exec("cmd /c \"call $path\"");
diff --git a/Tools/Scripts/prepare-ChangeLog b/Tools/Scripts/prepare-ChangeLog
new file mode 100755
index 0000000..2fc03d2
--- /dev/null
+++ b/Tools/Scripts/prepare-ChangeLog
@@ -0,0 +1,1723 @@
+#!/usr/bin/perl -w
+# -*- Mode: perl; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+
+#
+# Copyright (C) 2000, 2001 Eazel, Inc.
+# Copyright (C) 2002, 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+# Copyright (C) 2009 Torch Mobile, Inc.
+# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
+#
+# prepare-ChangeLog is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public
+# License as published by the Free Software Foundation; either
+# version 2 of the License, or (at your option) any later version.
+#
+# prepare-ChangeLog 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public
+# License along with this program; if not, write to the Free
+# Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+#
+
+
+# Perl script to create a ChangeLog entry with names of files
+# and functions from a diff.
+#
+# Darin Adler <darin@bentspoon.com>, started 20 April 2000
+# Java support added by Maciej Stachowiak <mjs@eazel.com>
+# Objective-C, C++ and Objective-C++ support added by Maciej Stachowiak <mjs@apple.com>
+# Git support added by Adam Roben <aroben@apple.com>
+# --git-index flag added by Joe Mason <joe.mason@torchmobile.com>
+
+
+#
+# TODO:
+# List functions that have been removed too.
+# Decide what a good logical order is for the changed files
+# other than a normal text "sort" (top level first?)
+# (group directories?) (.h before .c?)
+# Handle yacc source files too (other languages?).
+# Help merge when there are ChangeLog conflicts or if there's
+# already a partly written ChangeLog entry.
+# Add command line option to put the ChangeLog into a separate file.
+# Add SVN version numbers for commit (can't do that until
+# the changes are checked in, though).
+# Work around diff stupidity where deleting a function that starts
+# with a comment makes diff think that the following function
+# has been changed (if the following function starts with a comment
+# with the same first line, such as /**)
+# Work around diff stupidity where deleting an entire function and
+# the blank lines before it makes diff think you've changed the
+# previous function.
+
+use strict;
+use warnings;
+
+use File::Basename;
+use File::Spec;
+use FindBin;
+use Getopt::Long;
+use lib $FindBin::Bin;
+use POSIX qw(strftime);
+use VCSUtils;
+
+sub changeLogDate($);
+sub changeLogEmailAddressFromArgs($);
+sub changeLogNameFromArgs($);
+sub firstDirectoryOrCwd();
+sub diffFromToString();
+sub diffCommand(@);
+sub statusCommand(@);
+sub createPatchCommand($);
+sub diffHeaderFormat();
+sub findOriginalFileFromSvn($);
+sub determinePropertyChanges($$$);
+sub pluralizeAndList($$@);
+sub generateFileList(\@\@\%);
+sub isUnmodifiedStatus($);
+sub isModifiedStatus($);
+sub isAddedStatus($);
+sub isConflictStatus($);
+sub statusDescription($$$$);
+sub propertyChangeDescription($);
+sub extractLineRange($);
+sub testListForChangeLog(@);
+sub get_function_line_ranges($$);
+sub get_function_line_ranges_for_c($$);
+sub get_function_line_ranges_for_java($$);
+sub get_function_line_ranges_for_javascript($$);
+sub get_selector_line_ranges_for_css($$);
+sub method_decl_to_selector($);
+sub processPaths(\@);
+sub reviewerAndDescriptionForGitCommit($);
+sub normalizeLineEndings($$);
+sub decodeEntities($);
+
+# Project time zone for Cupertino, CA, US
+my $changeLogTimeZone = "PST8PDT";
+
+my $bugNumber;
+my $name;
+my $emailAddress;
+my $mergeBase = 0;
+my $gitCommit = 0;
+my $gitIndex = "";
+my $gitReviewer = "";
+my $openChangeLogs = 0;
+my $writeChangeLogs = 1;
+my $showHelp = 0;
+my $spewDiff = $ENV{"PREPARE_CHANGELOG_DIFF"};
+my $updateChangeLogs = 1;
+my $parseOptionsResult =
+ GetOptions("diff|d!" => \$spewDiff,
+ "bug|b:i" => \$bugNumber,
+ "name:s" => \$name,
+ "email:s" => \$emailAddress,
+ "merge-base:s" => \$mergeBase,
+ "git-commit:s" => \$gitCommit,
+ "git-index" => \$gitIndex,
+ "git-reviewer:s" => \$gitReviewer,
+ "help|h!" => \$showHelp,
+ "open|o!" => \$openChangeLogs,
+ "write!" => \$writeChangeLogs,
+ "update!" => \$updateChangeLogs);
+if (!$parseOptionsResult || $showHelp) {
+ print STDERR basename($0) . " [-b|--bug=<bugid>] [-d|--diff] [-h|--help] [-o|--open] [--git-commit=<committish>] [--git-reviewer=<name>] [svndir1 [svndir2 ...]]\n";
+ print STDERR " -b|--bug Fill in the ChangeLog bug information from the given bug.\n";
+ print STDERR " -d|--diff Spew diff to stdout when running\n";
+ print STDERR " --merge-base Populate the ChangeLogs with the diff to this branch\n";
+ print STDERR " --git-commit Populate the ChangeLogs from the specified git commit\n";
+ print STDERR " --git-index Populate the ChangeLogs from the git index only\n";
+ print STDERR " --git-reviewer When populating the ChangeLogs from a git commit claim that the spcified name reviewed the change.\n";
+ print STDERR " This option is useful when the git commit lacks a Signed-Off-By: line\n";
+ print STDERR " -h|--help Show this help message\n";
+ print STDERR " -o|--open Open ChangeLogs in an editor when done\n";
+ print STDERR " --[no-]update Update ChangeLogs from svn before adding entry (default: update)\n";
+ print STDERR " --[no-]write Write ChangeLogs to disk (otherwise send new entries to stdout) (default: write)\n";
+ exit 1;
+}
+
+die "--git-commit and --git-index are incompatible." if ($gitIndex && $gitCommit);
+
+my %paths = processPaths(@ARGV);
+
+my $isGit = isGitDirectory(firstDirectoryOrCwd());
+my $isSVN = isSVNDirectory(firstDirectoryOrCwd());
+
+$isSVN || $isGit || die "Couldn't determine your version control system.";
+
+my $SVN = "svn";
+my $GIT = "git";
+
+# Find the list of modified files
+my @changed_files;
+my $changed_files_string;
+my %changed_line_ranges;
+my %function_lists;
+my @conflict_files;
+
+
+my %supportedTestExtensions = map { $_ => 1 } qw(html shtml svg xml xhtml pl php);
+my @addedRegressionTests = ();
+my $didChangeRegressionTests = 0;
+
+generateFileList(@changed_files, @conflict_files, %function_lists);
+
+if (!@changed_files && !@conflict_files && !keys %function_lists) {
+ print STDERR " No changes found.\n";
+ exit 1;
+}
+
+if (@conflict_files) {
+ print STDERR " The following files have conflicts. Run prepare-ChangeLog again after fixing the conflicts:\n";
+ print STDERR join("\n", @conflict_files), "\n";
+ exit 1;
+}
+
+if (@changed_files) {
+ $changed_files_string = "'" . join ("' '", @changed_files) . "'";
+
+ # For each file, build a list of modified lines.
+ # Use line numbers from the "after" side of each diff.
+ print STDERR " Reviewing diff to determine which lines changed.\n";
+ my $file;
+ open DIFF, "-|", diffCommand(@changed_files) or die "The diff failed: $!.\n";
+ while (<DIFF>) {
+ $file = makeFilePathRelative($1) if $_ =~ diffHeaderFormat();
+ if (defined $file) {
+ my ($start, $end) = extractLineRange($_);
+ if ($start >= 0 && $end >= 0) {
+ push @{$changed_line_ranges{$file}}, [ $start, $end ];
+ } elsif (/DO_NOT_COMMIT/) {
+ print STDERR "WARNING: file $file contains the string DO_NOT_COMMIT, line $.\n";
+ }
+ }
+ }
+ close DIFF;
+}
+
+# For each source file, convert line range to function list.
+if (%changed_line_ranges) {
+ print STDERR " Extracting affected function names from source files.\n";
+ foreach my $file (keys %changed_line_ranges) {
+ # Only look for function names in certain source files.
+ next unless $file =~ /\.(c|cpp|m|mm|h|java|js)/;
+
+ # Find all the functions in the file.
+ open SOURCE, $file or next;
+ my @function_ranges = get_function_line_ranges(\*SOURCE, $file);
+ close SOURCE;
+
+ # Find all the modified functions.
+ my @functions;
+ my %saw_function;
+ my @change_ranges = (@{$changed_line_ranges{$file}}, []);
+ my @change_range = (0, 0);
+ FUNCTION: foreach my $function_range_ref (@function_ranges) {
+ my @function_range = @$function_range_ref;
+
+ # Advance to successive change ranges.
+ for (;; @change_range = @{shift @change_ranges}) {
+ last FUNCTION unless @change_range;
+
+ # If past this function, move on to the next one.
+ next FUNCTION if $change_range[0] > $function_range[1];
+
+ # If an overlap with this function range, record the function name.
+ if ($change_range[1] >= $function_range[0]
+ and $change_range[0] <= $function_range[1]) {
+ if (!$saw_function{$function_range[2]}) {
+ $saw_function{$function_range[2]} = 1;
+ push @functions, $function_range[2];
+ }
+ next FUNCTION;
+ }
+ }
+ }
+
+ # Format the list of functions now.
+
+ if (@functions) {
+ $function_lists{$file} = "" if !defined $function_lists{$file};
+ $function_lists{$file} .= "\n (" . join("):\n (", @functions) . "):";
+ }
+ }
+}
+
+# Get some parameters for the ChangeLog we are about to write.
+my $date = changeLogDate($changeLogTimeZone);
+$name = changeLogNameFromArgs($name);
+$emailAddress = changeLogEmailAddressFromArgs($emailAddress);
+
+print STDERR " Change author: $name <$emailAddress>.\n";
+
+my $bugDescription;
+my $bugURL;
+if ($bugNumber) {
+ $bugURL = "https://bugs.webkit.org/show_bug.cgi?id=$bugNumber";
+ my $bugXMLURL = "$bugURL&ctype=xml";
+ # Perl has no built in XML processing, so we'll fetch and parse with curl and grep
+ # Pass --insecure because some cygwin installs have no certs we don't
+ # care about validating that bugs.webkit.org is who it says it is here.
+ my $descriptionLine = `curl --insecure --silent "$bugXMLURL" | grep short_desc`;
+ if ($descriptionLine !~ /<short_desc>(.*)<\/short_desc>/) {
+ # Maybe the reason the above did not work is because the curl that is installed doesn't
+ # support ssl at all.
+ if (`curl --version | grep ^Protocols` !~ /\bhttps\b/) {
+ print STDERR " Could not get description for bug $bugNumber.\n";
+ print STDERR " It looks like your version of curl does not support ssl.\n";
+ print STDERR " If you are using macports, this can be fixed with sudo port install curl +ssl.\n";
+ } else {
+ print STDERR " Bug $bugNumber has no bug description. Maybe you set wrong bug ID?\n";
+ print STDERR " The bug URL: $bugXMLURL\n";
+ }
+ exit 1;
+ }
+ $bugDescription = decodeEntities($1);
+ print STDERR " Description from bug $bugNumber:\n \"$bugDescription\".\n";
+}
+
+# Remove trailing parenthesized notes from user name (bit of hack).
+$name =~ s/\(.*?\)\s*$//g;
+
+# Find the change logs.
+my %has_log;
+my %files;
+foreach my $file (sort keys %function_lists) {
+ my $prefix = $file;
+ my $has_log = 0;
+ while ($prefix) {
+ $prefix =~ s-/[^/]+/?$-/- or $prefix = "";
+ $has_log = $has_log{$prefix};
+ if (!defined $has_log) {
+ $has_log = -f "${prefix}ChangeLog";
+ $has_log{$prefix} = $has_log;
+ }
+ last if $has_log;
+ }
+ if (!$has_log) {
+ print STDERR "No ChangeLog found for $file.\n";
+ } else {
+ push @{$files{$prefix}}, $file;
+ }
+}
+
+# Build the list of ChangeLog prefixes in the correct project order
+my @prefixes;
+my %prefixesSort;
+foreach my $prefix (keys %files) {
+ my $prefixDir = substr($prefix, 0, length($prefix) - 1); # strip trailing /
+ my $sortKey = lc $prefix;
+ $sortKey = "top level" unless length $sortKey;
+
+ if ($prefixDir eq "top level") {
+ $sortKey = "";
+ } elsif ($prefixDir eq "Tools") {
+ $sortKey = "-, just after top level";
+ } elsif ($prefixDir eq "WebBrowser") {
+ $sortKey = lc "WebKit, WebBrowser after";
+ } elsif ($prefixDir eq "WebCore") {
+ $sortKey = lc "WebFoundation, WebCore after";
+ } elsif ($prefixDir eq "LayoutTests") {
+ $sortKey = lc "~, LayoutTests last";
+ }
+
+ $prefixesSort{$sortKey} = $prefix;
+}
+foreach my $prefixSort (sort keys %prefixesSort) {
+ push @prefixes, $prefixesSort{$prefixSort};
+}
+
+# Get the latest ChangeLog files from svn.
+my @logs = ();
+foreach my $prefix (@prefixes) {
+ push @logs, File::Spec->catfile($prefix || ".", "ChangeLog");
+}
+
+if (@logs && $updateChangeLogs && $isSVN) {
+ print STDERR " Running 'svn update' to update ChangeLog files.\n";
+ open ERRORS, "-|", $SVN, "update", @logs
+ or die "The svn update of ChangeLog files failed: $!.\n";
+ my @conflictedChangeLogs;
+ while (my $line = <ERRORS>) {
+ print STDERR " ", $line;
+ push @conflictedChangeLogs, $1 if $line =~ m/^C\s+(.+?)[\r\n]*$/;
+ }
+ close ERRORS;
+
+ if (@conflictedChangeLogs) {
+ print STDERR " Attempting to merge conflicted ChangeLogs.\n";
+ my $resolveChangeLogsPath = File::Spec->catfile(dirname($0), "resolve-ChangeLogs");
+ open RESOLVE, "-|", $resolveChangeLogsPath, "--no-warnings", @conflictedChangeLogs
+ or die "Could not open resolve-ChangeLogs script: $!.\n";
+ print STDERR " $_" while <RESOLVE>;
+ close RESOLVE;
+ }
+}
+
+# Generate new ChangeLog entries and (optionally) write out new ChangeLog files.
+foreach my $prefix (@prefixes) {
+ my $endl = "\n";
+ my @old_change_log;
+
+ if ($writeChangeLogs) {
+ my $changeLogPath = File::Spec->catfile($prefix || ".", "ChangeLog");
+ print STDERR " Editing the ${changeLogPath} file.\n";
+ open OLD_CHANGE_LOG, ${changeLogPath} or die "Could not open ${changeLogPath} file: $!.\n";
+ # It's less efficient to read the whole thing into memory than it would be
+ # to read it while we prepend to it later, but I like doing this part first.
+ @old_change_log = <OLD_CHANGE_LOG>;
+ close OLD_CHANGE_LOG;
+ # We want to match the ChangeLog's line endings in case it doesn't match
+ # the native line endings for this version of perl.
+ if ($old_change_log[0] =~ /(\r?\n)$/g) {
+ $endl = "$1";
+ }
+ open CHANGE_LOG, "> ${changeLogPath}" or die "Could not write ${changeLogPath}\n.";
+ } else {
+ open CHANGE_LOG, ">-" or die "Could not write to STDOUT\n.";
+ print substr($prefix, 0, length($prefix) - 1) . ":\n\n" unless (scalar @prefixes) == 1;
+ }
+
+ print CHANGE_LOG normalizeLineEndings("$date $name <$emailAddress>\n\n", $endl);
+
+ my ($reviewer, $description) = reviewerAndDescriptionForGitCommit($gitCommit) if $gitCommit;
+ $reviewer = "NOBODY (OO" . "PS!)" if !$reviewer;
+
+ print CHANGE_LOG normalizeLineEndings(" Reviewed by $reviewer.\n\n", $endl);
+ print CHANGE_LOG normalizeLineEndings($description . "\n", $endl) if $description;
+
+ $bugDescription = "Need a short description and bug URL (OOPS!)" unless $bugDescription;
+ print CHANGE_LOG normalizeLineEndings(" $bugDescription\n", $endl) if $bugDescription;
+ print CHANGE_LOG normalizeLineEndings(" $bugURL\n", $endl) if $bugURL;
+ print CHANGE_LOG normalizeLineEndings("\n", $endl);
+
+ if ($prefix =~ m/WebCore/ || `pwd` =~ m/WebCore/) {
+ if ($didChangeRegressionTests) {
+ print CHANGE_LOG normalizeLineEndings(testListForChangeLog(sort @addedRegressionTests), $endl);
+ } else {
+ print CHANGE_LOG normalizeLineEndings(" No new tests. (OOPS!)\n\n", $endl);
+ }
+ }
+
+ foreach my $file (sort @{$files{$prefix}}) {
+ my $file_stem = substr $file, length $prefix;
+ print CHANGE_LOG normalizeLineEndings(" * $file_stem:$function_lists{$file}\n", $endl);
+ }
+
+ if ($writeChangeLogs) {
+ print CHANGE_LOG normalizeLineEndings("\n", $endl), @old_change_log;
+ } else {
+ print CHANGE_LOG "\n";
+ }
+
+ close CHANGE_LOG;
+}
+
+if ($writeChangeLogs) {
+ print STDERR "-- Please remember to include a detailed description in your ChangeLog entry. --\n-- See <http://webkit.org/coding/contributing.html> for more info --\n";
+}
+
+# Write out another diff.
+if ($spewDiff && @changed_files) {
+ print STDERR " Running diff to help you write the ChangeLog entries.\n";
+ local $/ = undef; # local slurp mode
+ open DIFF, "-|", createPatchCommand($changed_files_string) or die "The diff failed: $!.\n";
+ print <DIFF>;
+ close DIFF;
+}
+
+# Open ChangeLogs.
+if ($openChangeLogs && @logs) {
+ print STDERR " Opening the edited ChangeLog files.\n";
+ my $editor = $ENV{CHANGE_LOG_EDITOR};
+ if ($editor) {
+ system ((split ' ', $editor), @logs);
+ } else {
+ $editor = $ENV{CHANGE_LOG_EDIT_APPLICATION};
+ if ($editor) {
+ system "open", "-a", $editor, @logs;
+ } else {
+ system "open", "-e", @logs;
+ }
+ }
+}
+
+# Done.
+exit;
+
+
+sub changeLogDate($)
+{
+ my ($timeZone) = @_;
+ my $savedTimeZone = $ENV{'TZ'};
+ # Set TZ temporarily so that localtime() is in that time zone
+ $ENV{'TZ'} = $timeZone;
+ my $date = strftime("%Y-%m-%d", localtime());
+ if (defined $savedTimeZone) {
+ $ENV{'TZ'} = $savedTimeZone;
+ } else {
+ delete $ENV{'TZ'};
+ }
+ return $date;
+}
+
+sub changeLogNameFromArgs($)
+{
+ my ($nameFromArgs) = @_;
+ # Silently allow --git-commit to win, we could warn if $nameFromArgs is defined.
+ return `$GIT log --max-count=1 --pretty=\"format:%an\" \"$gitCommit\"` if $gitCommit;
+
+ return $nameFromArgs || changeLogName();
+}
+
+sub changeLogEmailAddressFromArgs($)
+{
+ my ($emailAddressFromArgs) = @_;
+ # Silently allow --git-commit to win, we could warn if $emailAddressFromArgs is defined.
+ return `$GIT log --max-count=1 --pretty=\"format:%ae\" \"$gitCommit\"` if $gitCommit;
+
+ return $emailAddressFromArgs || changeLogEmailAddress();
+}
+
+sub get_function_line_ranges($$)
+{
+ my ($file_handle, $file_name) = @_;
+
+ if ($file_name =~ /\.(c|cpp|m|mm|h)$/) {
+ return get_function_line_ranges_for_c ($file_handle, $file_name);
+ } elsif ($file_name =~ /\.java$/) {
+ return get_function_line_ranges_for_java ($file_handle, $file_name);
+ } elsif ($file_name =~ /\.js$/) {
+ return get_function_line_ranges_for_javascript ($file_handle, $file_name);
+ } elsif ($file_name =~ /\.css$/) {
+ return get_selector_line_ranges_for_css ($file_handle, $file_name);
+ }
+ return ();
+}
+
+
+sub method_decl_to_selector($)
+{
+ (my $method_decl) = @_;
+
+ $_ = $method_decl;
+
+ if ((my $comment_stripped) = m-([^/]*)(//|/*).*-) {
+ $_ = $comment_stripped;
+ }
+
+ s/,\s*...//;
+
+ if (/:/) {
+ my @components = split /:/;
+ pop @components if (scalar @components > 1);
+ $_ = (join ':', map {s/.*[^[:word:]]//; scalar $_;} @components) . ':';
+ } else {
+ s/\s*$//;
+ s/.*[^[:word:]]//;
+ }
+
+ return $_;
+}
+
+
+
+# Read a file and get all the line ranges of the things that look like C functions.
+# A function name is the last word before an open parenthesis before the outer
+# level open brace. A function starts at the first character after the last close
+# brace or semicolon before the function name and ends at the close brace.
+# Comment handling is simple-minded but will work for all but pathological cases.
+#
+# Result is a list of triples: [ start_line, end_line, function_name ].
+
+sub get_function_line_ranges_for_c($$)
+{
+ my ($file_handle, $file_name) = @_;
+
+ my @ranges;
+
+ my $in_comment = 0;
+ my $in_macro = 0;
+ my $in_method_declaration = 0;
+ my $in_parentheses = 0;
+ my $in_braces = 0;
+ my $brace_start = 0;
+ my $brace_end = 0;
+ my $skip_til_brace_or_semicolon = 0;
+
+ my $word = "";
+ my $interface_name = "";
+
+ my $potential_method_char = "";
+ my $potential_method_spec = "";
+
+ my $potential_start = 0;
+ my $potential_name = "";
+
+ my $start = 0;
+ my $name = "";
+
+ my $next_word_could_be_namespace = 0;
+ my $potential_namespace = "";
+ my @namespaces;
+
+ while (<$file_handle>) {
+ # Handle continued multi-line comment.
+ if ($in_comment) {
+ next unless s-.*\*/--;
+ $in_comment = 0;
+ }
+
+ # Handle continued macro.
+ if ($in_macro) {
+ $in_macro = 0 unless /\\$/;
+ next;
+ }
+
+ # Handle start of macro (or any preprocessor directive).
+ if (/^\s*\#/) {
+ $in_macro = 1 if /^([^\\]|\\.)*\\$/;
+ next;
+ }
+
+ # Handle comments and quoted text.
+ while (m-(/\*|//|\'|\")-) { # \' and \" keep emacs perl mode happy
+ my $match = $1;
+ if ($match eq "/*") {
+ if (!s-/\*.*?\*/--) {
+ s-/\*.*--;
+ $in_comment = 1;
+ }
+ } elsif ($match eq "//") {
+ s-//.*--;
+ } else { # ' or "
+ if (!s-$match([^\\]|\\.)*?$match--) {
+ warn "mismatched quotes at line $. in $file_name\n";
+ s-$match.*--;
+ }
+ }
+ }
+
+
+ # continued method declaration
+ if ($in_method_declaration) {
+ my $original = $_;
+ my $method_cont = $_;
+
+ chomp $method_cont;
+ $method_cont =~ s/[;\{].*//;
+ $potential_method_spec = "${potential_method_spec} ${method_cont}";
+
+ $_ = $original;
+ if (/;/) {
+ $potential_start = 0;
+ $potential_method_spec = "";
+ $potential_method_char = "";
+ $in_method_declaration = 0;
+ s/^[^;\{]*//;
+ } elsif (/{/) {
+ my $selector = method_decl_to_selector ($potential_method_spec);
+ $potential_name = "${potential_method_char}\[${interface_name} ${selector}\]";
+
+ $potential_method_spec = "";
+ $potential_method_char = "";
+ $in_method_declaration = 0;
+
+ $_ = $original;
+ s/^[^;{]*//;
+ } elsif (/\@end/) {
+ $in_method_declaration = 0;
+ $interface_name = "";
+ $_ = $original;
+ } else {
+ next;
+ }
+ }
+
+
+ # start of method declaration
+ if ((my $method_char, my $method_spec) = m&^([-+])([^0-9;][^;]*);?$&) {
+ my $original = $_;
+
+ if ($interface_name) {
+ chomp $method_spec;
+ $method_spec =~ s/\{.*//;
+
+ $potential_method_char = $method_char;
+ $potential_method_spec = $method_spec;
+ $potential_start = $.;
+ $in_method_declaration = 1;
+ } else {
+ warn "declaring a method but don't have interface on line $. in $file_name\n";
+ }
+ $_ = $original;
+ if (/\{/) {
+ my $selector = method_decl_to_selector ($potential_method_spec);
+ $potential_name = "${potential_method_char}\[${interface_name} ${selector}\]";
+
+ $potential_method_spec = "";
+ $potential_method_char = "";
+ $in_method_declaration = 0;
+ $_ = $original;
+ s/^[^{]*//;
+ } elsif (/\@end/) {
+ $in_method_declaration = 0;
+ $interface_name = "";
+ $_ = $original;
+ } else {
+ next;
+ }
+ }
+
+
+ # Find function, interface and method names.
+ while (m&((?:[[:word:]]+::)*operator(?:[ \t]*\(\)|[^()]*)|[[:word:]:~]+|[(){}:;])|\@(?:implementation|interface|protocol)\s+(\w+)[^{]*&g) {
+ # interface name
+ if ($2) {
+ $interface_name = $2;
+ next;
+ }
+
+ # Open parenthesis.
+ if ($1 eq "(") {
+ $potential_name = $word unless $in_parentheses || $skip_til_brace_or_semicolon;
+ $in_parentheses++;
+ next;
+ }
+
+ # Close parenthesis.
+ if ($1 eq ")") {
+ $in_parentheses--;
+ next;
+ }
+
+ # C++ constructor initializers
+ if ($1 eq ":") {
+ $skip_til_brace_or_semicolon = 1 unless ($in_parentheses || $in_braces);
+ }
+
+ # Open brace.
+ if ($1 eq "{") {
+ $skip_til_brace_or_semicolon = 0;
+
+ if ($potential_namespace) {
+ push @namespaces, $potential_namespace;
+ $potential_namespace = "";
+ next;
+ }
+
+ # Promote potential name to real function name at the
+ # start of the outer level set of braces (function body?).
+ if (!$in_braces and $potential_start) {
+ $start = $potential_start;
+ $name = $potential_name;
+ if (@namespaces && $name && (length($name) < 2 || substr($name,1,1) ne "[")) {
+ $name = join ('::', @namespaces, $name);
+ }
+ }
+
+ $in_method_declaration = 0;
+
+ $brace_start = $. if (!$in_braces);
+ $in_braces++;
+ next;
+ }
+
+ # Close brace.
+ if ($1 eq "}") {
+ if (!$in_braces && @namespaces) {
+ pop @namespaces;
+ next;
+ }
+
+ $in_braces--;
+ $brace_end = $. if (!$in_braces);
+
+ # End of an outer level set of braces.
+ # This could be a function body.
+ if (!$in_braces and $name) {
+ push @ranges, [ $start, $., $name ];
+ $name = "";
+ }
+
+ $potential_start = 0;
+ $potential_name = "";
+ next;
+ }
+
+ # Semicolon.
+ if ($1 eq ";") {
+ $skip_til_brace_or_semicolon = 0;
+ $potential_start = 0;
+ $potential_name = "";
+ $in_method_declaration = 0;
+ next;
+ }
+
+ # Ignore "const" method qualifier.
+ if ($1 eq "const") {
+ next;
+ }
+
+ if ($1 eq "namespace" || $1 eq "class" || $1 eq "struct") {
+ $next_word_could_be_namespace = 1;
+ next;
+ }
+
+ # Word.
+ $word = $1;
+ if (!$skip_til_brace_or_semicolon) {
+ if ($next_word_could_be_namespace) {
+ $potential_namespace = $word;
+ $next_word_could_be_namespace = 0;
+ } elsif ($potential_namespace) {
+ $potential_namespace = "";
+ }
+
+ if (!$in_parentheses) {
+ $potential_start = 0;
+ $potential_name = "";
+ }
+ if (!$potential_start) {
+ $potential_start = $.;
+ $potential_name = "";
+ }
+ }
+ }
+ }
+
+ warn "missing close braces in $file_name (probable start at $brace_start)\n" if ($in_braces > 0);
+ warn "too many close braces in $file_name (probable start at $brace_end)\n" if ($in_braces < 0);
+
+ warn "mismatched parentheses in $file_name\n" if $in_parentheses;
+
+ return @ranges;
+}
+
+
+
+# Read a file and get all the line ranges of the things that look like Java
+# classes, interfaces and methods.
+#
+# A class or interface name is the word that immediately follows
+# `class' or `interface' when followed by an open curly brace and not
+# a semicolon. It can appear at the top level, or inside another class
+# or interface block, but not inside a function block
+#
+# A class or interface starts at the first character after the first close
+# brace or after the function name and ends at the close brace.
+#
+# A function name is the last word before an open parenthesis before
+# an open brace rather than a semicolon. It can appear at top level or
+# inside a class or interface block, but not inside a function block.
+#
+# A function starts at the first character after the first close
+# brace or after the function name and ends at the close brace.
+#
+# Comment handling is simple-minded but will work for all but pathological cases.
+#
+# Result is a list of triples: [ start_line, end_line, function_name ].
+
+sub get_function_line_ranges_for_java($$)
+{
+ my ($file_handle, $file_name) = @_;
+
+ my @current_scopes;
+
+ my @ranges;
+
+ my $in_comment = 0;
+ my $in_macro = 0;
+ my $in_parentheses = 0;
+ my $in_braces = 0;
+ my $in_non_block_braces = 0;
+ my $class_or_interface_just_seen = 0;
+
+ my $word = "";
+
+ my $potential_start = 0;
+ my $potential_name = "";
+ my $potential_name_is_class_or_interface = 0;
+
+ my $start = 0;
+ my $name = "";
+ my $current_name_is_class_or_interface = 0;
+
+ while (<$file_handle>) {
+ # Handle continued multi-line comment.
+ if ($in_comment) {
+ next unless s-.*\*/--;
+ $in_comment = 0;
+ }
+
+ # Handle continued macro.
+ if ($in_macro) {
+ $in_macro = 0 unless /\\$/;
+ next;
+ }
+
+ # Handle start of macro (or any preprocessor directive).
+ if (/^\s*\#/) {
+ $in_macro = 1 if /^([^\\]|\\.)*\\$/;
+ next;
+ }
+
+ # Handle comments and quoted text.
+ while (m-(/\*|//|\'|\")-) { # \' and \" keep emacs perl mode happy
+ my $match = $1;
+ if ($match eq "/*") {
+ if (!s-/\*.*?\*/--) {
+ s-/\*.*--;
+ $in_comment = 1;
+ }
+ } elsif ($match eq "//") {
+ s-//.*--;
+ } else { # ' or "
+ if (!s-$match([^\\]|\\.)*?$match--) {
+ warn "mismatched quotes at line $. in $file_name\n";
+ s-$match.*--;
+ }
+ }
+ }
+
+ # Find function names.
+ while (m-(\w+|[(){};])-g) {
+ # Open parenthesis.
+ if ($1 eq "(") {
+ if (!$in_parentheses) {
+ $potential_name = $word;
+ $potential_name_is_class_or_interface = 0;
+ }
+ $in_parentheses++;
+ next;
+ }
+
+ # Close parenthesis.
+ if ($1 eq ")") {
+ $in_parentheses--;
+ next;
+ }
+
+ # Open brace.
+ if ($1 eq "{") {
+ # Promote potential name to real function name at the
+ # start of the outer level set of braces (function/class/interface body?).
+ if (!$in_non_block_braces
+ and (!$in_braces or $current_name_is_class_or_interface)
+ and $potential_start) {
+ if ($name) {
+ push @ranges, [ $start, ($. - 1),
+ join ('.', @current_scopes) ];
+ }
+
+
+ $current_name_is_class_or_interface = $potential_name_is_class_or_interface;
+
+ $start = $potential_start;
+ $name = $potential_name;
+
+ push (@current_scopes, $name);
+ } else {
+ $in_non_block_braces++;
+ }
+
+ $potential_name = "";
+ $potential_start = 0;
+
+ $in_braces++;
+ next;
+ }
+
+ # Close brace.
+ if ($1 eq "}") {
+ $in_braces--;
+
+ # End of an outer level set of braces.
+ # This could be a function body.
+ if (!$in_non_block_braces) {
+ if ($name) {
+ push @ranges, [ $start, $.,
+ join ('.', @current_scopes) ];
+
+ pop (@current_scopes);
+
+ if (@current_scopes) {
+ $current_name_is_class_or_interface = 1;
+
+ $start = $. + 1;
+ $name = $current_scopes[$#current_scopes-1];
+ } else {
+ $current_name_is_class_or_interface = 0;
+ $start = 0;
+ $name = "";
+ }
+ }
+ } else {
+ $in_non_block_braces-- if $in_non_block_braces;
+ }
+
+ $potential_start = 0;
+ $potential_name = "";
+ next;
+ }
+
+ # Semicolon.
+ if ($1 eq ";") {
+ $potential_start = 0;
+ $potential_name = "";
+ next;
+ }
+
+ if ($1 eq "class" or $1 eq "interface") {
+ $class_or_interface_just_seen = 1;
+ next;
+ }
+
+ # Word.
+ $word = $1;
+ if (!$in_parentheses) {
+ if ($class_or_interface_just_seen) {
+ $potential_name = $word;
+ $potential_start = $.;
+ $class_or_interface_just_seen = 0;
+ $potential_name_is_class_or_interface = 1;
+ next;
+ }
+ }
+ if (!$potential_start) {
+ $potential_start = $.;
+ $potential_name = "";
+ }
+ $class_or_interface_just_seen = 0;
+ }
+ }
+
+ warn "mismatched braces in $file_name\n" if $in_braces;
+ warn "mismatched parentheses in $file_name\n" if $in_parentheses;
+
+ return @ranges;
+}
+
+
+
+# Read a file and get all the line ranges of the things that look like
+# JavaScript functions.
+#
+# A function name is the word that immediately follows `function' when
+# followed by an open curly brace. It can appear at the top level, or
+# inside other functions.
+#
+# An anonymous function name is the identifier chain immediately before
+# an assignment with the equals operator or object notation that has a
+# value starting with `function' followed by an open curly brace.
+#
+# A getter or setter name is the word that immediately follows `get' or
+# `set' when followed by an open curly brace .
+#
+# Comment handling is simple-minded but will work for all but pathological cases.
+#
+# Result is a list of triples: [ start_line, end_line, function_name ].
+
+sub get_function_line_ranges_for_javascript($$)
+{
+ my ($fileHandle, $fileName) = @_;
+
+ my @currentScopes;
+ my @currentIdentifiers;
+ my @currentFunctionNames;
+ my @currentFunctionDepths;
+ my @currentFunctionStartLines;
+
+ my @ranges;
+
+ my $inComment = 0;
+ my $inQuotedText = "";
+ my $parenthesesDepth = 0;
+ my $bracesDepth = 0;
+
+ my $functionJustSeen = 0;
+ my $getterJustSeen = 0;
+ my $setterJustSeen = 0;
+ my $assignmentJustSeen = 0;
+
+ my $word = "";
+
+ while (<$fileHandle>) {
+ # Handle continued multi-line comment.
+ if ($inComment) {
+ next unless s-.*\*/--;
+ $inComment = 0;
+ }
+
+ # Handle continued quoted text.
+ if ($inQuotedText ne "") {
+ next if /\\$/;
+ s-([^\\]|\\.)*?$inQuotedText--;
+ $inQuotedText = "";
+ }
+
+ # Handle comments and quoted text.
+ while (m-(/\*|//|\'|\")-) { # \' and \" keep emacs perl mode happy
+ my $match = $1;
+ if ($match eq '/*') {
+ if (!s-/\*.*?\*/--) {
+ s-/\*.*--;
+ $inComment = 1;
+ }
+ } elsif ($match eq '//') {
+ s-//.*--;
+ } else { # ' or "
+ if (!s-$match([^\\]|\\.)*?$match--) {
+ $inQuotedText = $match if /\\$/;
+ warn "mismatched quotes at line $. in $fileName\n" if $inQuotedText eq "";
+ s-$match.*--;
+ }
+ }
+ }
+
+ # Find function names.
+ while (m-(\w+|[(){}=:;])-g) {
+ # Open parenthesis.
+ if ($1 eq '(') {
+ $parenthesesDepth++;
+ next;
+ }
+
+ # Close parenthesis.
+ if ($1 eq ')') {
+ $parenthesesDepth--;
+ next;
+ }
+
+ # Open brace.
+ if ($1 eq '{') {
+ push(@currentScopes, join(".", @currentIdentifiers));
+ @currentIdentifiers = ();
+
+ $bracesDepth++;
+ next;
+ }
+
+ # Close brace.
+ if ($1 eq '}') {
+ $bracesDepth--;
+
+ if (@currentFunctionDepths and $bracesDepth == $currentFunctionDepths[$#currentFunctionDepths]) {
+ pop(@currentFunctionDepths);
+
+ my $currentFunction = pop(@currentFunctionNames);
+ my $start = pop(@currentFunctionStartLines);
+
+ push(@ranges, [$start, $., $currentFunction]);
+ }
+
+ pop(@currentScopes);
+ @currentIdentifiers = ();
+
+ next;
+ }
+
+ # Semicolon.
+ if ($1 eq ';') {
+ @currentIdentifiers = ();
+ next;
+ }
+
+ # Function.
+ if ($1 eq 'function') {
+ $functionJustSeen = 1;
+
+ if ($assignmentJustSeen) {
+ my $currentFunction = join('.', (@currentScopes, @currentIdentifiers));
+ $currentFunction =~ s/\.{2,}/\./g; # Removes consecutive periods.
+
+ push(@currentFunctionNames, $currentFunction);
+ push(@currentFunctionDepths, $bracesDepth);
+ push(@currentFunctionStartLines, $.);
+ }
+
+ next;
+ }
+
+ # Getter prefix.
+ if ($1 eq 'get') {
+ $getterJustSeen = 1;
+ next;
+ }
+
+ # Setter prefix.
+ if ($1 eq 'set') {
+ $setterJustSeen = 1;
+ next;
+ }
+
+ # Assignment operator.
+ if ($1 eq '=' or $1 eq ':') {
+ $assignmentJustSeen = 1;
+ next;
+ }
+
+ next if $parenthesesDepth;
+
+ # Word.
+ $word = $1;
+ $word = "get $word" if $getterJustSeen;
+ $word = "set $word" if $setterJustSeen;
+
+ if (($functionJustSeen and !$assignmentJustSeen) or $getterJustSeen or $setterJustSeen) {
+ push(@currentIdentifiers, $word);
+
+ my $currentFunction = join('.', (@currentScopes, @currentIdentifiers));
+ $currentFunction =~ s/\.{2,}/\./g; # Removes consecutive periods.
+
+ push(@currentFunctionNames, $currentFunction);
+ push(@currentFunctionDepths, $bracesDepth);
+ push(@currentFunctionStartLines, $.);
+ } elsif ($word ne 'if' and $word ne 'for' and $word ne 'do' and $word ne 'while' and $word ne 'which' and $word ne 'var') {
+ push(@currentIdentifiers, $word);
+ }
+
+ $functionJustSeen = 0;
+ $getterJustSeen = 0;
+ $setterJustSeen = 0;
+ $assignmentJustSeen = 0;
+ }
+ }
+
+ warn "mismatched braces in $fileName\n" if $bracesDepth;
+ warn "mismatched parentheses in $fileName\n" if $parenthesesDepth;
+
+ return @ranges;
+}
+
+# Read a file and get all the line ranges of the things that look like CSS selectors. A selector is
+# anything before an opening brace on a line. A selector starts at the line containing the opening
+# brace and ends at the closing brace.
+# FIXME: Comments are parsed just like uncommented text.
+#
+# Result is a list of triples: [ start_line, end_line, selector ].
+
+sub get_selector_line_ranges_for_css($$)
+{
+ my ($fileHandle, $fileName) = @_;
+
+ my @ranges;
+
+ my $currentSelector = "";
+ my $start = 0;
+
+ while (<$fileHandle>) {
+ if (/^[ \t]*(.*[^ \t])[ \t]*{/) {
+ $currentSelector = $1;
+ $start = $.;
+ }
+ if (index($_, "}") >= 0) {
+ unless ($start) {
+ warn "mismatched braces in $fileName\n";
+ next;
+ }
+ push(@ranges, [$start, $., $currentSelector]);
+ $currentSelector = "";
+ $start = 0;
+ next;
+ }
+ }
+
+ return @ranges;
+}
+
+sub processPaths(\@)
+{
+ my ($paths) = @_;
+ return ("." => 1) if (!@{$paths});
+
+ my %result = ();
+
+ for my $file (@{$paths}) {
+ die "can't handle absolute paths like \"$file\"\n" if File::Spec->file_name_is_absolute($file);
+ die "can't handle empty string path\n" if $file eq "";
+ die "can't handle path with single quote in the name like \"$file\"\n" if $file =~ /'/; # ' (keep Xcode syntax highlighting happy)
+
+ my $untouchedFile = $file;
+
+ $file = canonicalizePath($file);
+
+ die "can't handle paths with .. like \"$untouchedFile\"\n" if $file =~ m|/\.\./|;
+
+ $result{$file} = 1;
+ }
+
+ return ("." => 1) if ($result{"."});
+
+ # Remove any paths that also have a parent listed.
+ for my $path (keys %result) {
+ for (my $parent = dirname($path); $parent ne '.'; $parent = dirname($parent)) {
+ if ($result{$parent}) {
+ delete $result{$path};
+ last;
+ }
+ }
+ }
+
+ return %result;
+}
+
+sub diffFromToString()
+{
+ return "" if $isSVN;
+ return $gitCommit if $gitCommit =~ m/.+\.\..+/;
+ return "\"$gitCommit^\" \"$gitCommit\"" if $gitCommit;
+ return "--cached" if $gitIndex;
+ return $mergeBase if $mergeBase;
+ return "HEAD" if $isGit;
+}
+
+sub diffCommand(@)
+{
+ my @paths = @_;
+
+ my $pathsString = "'" . join("' '", @paths) . "'";
+
+ my $command;
+ if ($isSVN) {
+ $command = "$SVN diff --diff-cmd diff -x -N $pathsString";
+ } elsif ($isGit) {
+ $command = "$GIT diff --no-ext-diff -U0 " . diffFromToString();
+ $command .= " -- $pathsString" unless $gitCommit or $mergeBase;
+ }
+
+ return $command;
+}
+
+sub statusCommand(@)
+{
+ my @files = @_;
+
+ my $filesString = "'" . join ("' '", @files) . "'";
+ my $command;
+ if ($isSVN) {
+ $command = "$SVN stat $filesString";
+ } elsif ($isGit) {
+ $command = "$GIT diff -r --name-status -M -C " . diffFromToString();
+ $command .= " -- $filesString" unless $gitCommit;
+ }
+
+ return "$command 2>&1";
+}
+
+sub createPatchCommand($)
+{
+ my ($changedFilesString) = @_;
+
+ my $command;
+ if ($isSVN) {
+ $command = "'$FindBin::Bin/svn-create-patch' $changedFilesString";
+ } elsif ($isGit) {
+ $command = "$GIT diff -M -C " . diffFromToString();
+ $command .= " -- $changedFilesString" unless $gitCommit;
+ }
+
+ return $command;
+}
+
+sub diffHeaderFormat()
+{
+ return qr/^Index: (\S+)[\r\n]*$/ if $isSVN;
+ return qr/^diff --git a\/.+ b\/(.+)$/ if $isGit;
+}
+
+sub findOriginalFileFromSvn($)
+{
+ my ($file) = @_;
+ my $baseUrl;
+ open INFO, "$SVN info . |" or die;
+ while (<INFO>) {
+ if (/^URL: (.+?)[\r\n]*$/) {
+ $baseUrl = $1;
+ }
+ }
+ close INFO;
+ my $sourceFile;
+ open INFO, "$SVN info '$file' |" or die;
+ while (<INFO>) {
+ if (/^Copied From URL: (.+?)[\r\n]*$/) {
+ $sourceFile = File::Spec->abs2rel($1, $baseUrl);
+ }
+ }
+ close INFO;
+ return $sourceFile;
+}
+
+sub determinePropertyChanges($$$)
+{
+ my ($file, $isAdd, $original) = @_;
+
+ my %changes;
+ if ($isAdd) {
+ my %addedProperties;
+ my %removedProperties;
+ open PROPLIST, "$SVN proplist '$file' |" or die;
+ while (<PROPLIST>) {
+ $addedProperties{$1} = 1 if /^ (.+?)[\r\n]*$/ && $1 ne 'svn:mergeinfo';
+ }
+ close PROPLIST;
+ if ($original) {
+ open PROPLIST, "$SVN proplist '$original' |" or die;
+ while (<PROPLIST>) {
+ next unless /^ (.+?)[\r\n]*$/;
+ my $property = $1;
+ if (exists $addedProperties{$property}) {
+ delete $addedProperties{$1};
+ } else {
+ $removedProperties{$1} = 1;
+ }
+ }
+ }
+ $changes{"A"} = [sort keys %addedProperties] if %addedProperties;
+ $changes{"D"} = [sort keys %removedProperties] if %removedProperties;
+ } else {
+ open DIFF, "$SVN diff '$file' |" or die;
+ while (<DIFF>) {
+ if (/^Property changes on:/) {
+ while (<DIFF>) {
+ my $operation;
+ my $property;
+ if (/^Added: (\S*)/) {
+ $operation = "A";
+ $property = $1;
+ } elsif (/^Modified: (\S*)/) {
+ $operation = "M";
+ $property = $1;
+ } elsif (/^Deleted: (\S*)/) {
+ $operation = "D";
+ $property = $1;
+ } elsif (/^Name: (\S*)/) {
+ # Older versions of svn just say "Name" instead of the type
+ # of property change.
+ $operation = "C";
+ $property = $1;
+ }
+ if ($operation) {
+ $changes{$operation} = [] unless exists $changes{$operation};
+ push @{$changes{$operation}}, $property;
+ }
+ }
+ }
+ }
+ close DIFF;
+ }
+ return \%changes;
+}
+
+sub pluralizeAndList($$@)
+{
+ my ($singular, $plural, @items) = @_;
+
+ return if @items == 0;
+ return "$singular $items[0]" if @items == 1;
+ return "$plural " . join(", ", @items[0 .. $#items - 1]) . " and " . $items[-1];
+}
+
+sub generateFileList(\@\@\%)
+{
+ my ($changedFiles, $conflictFiles, $functionLists) = @_;
+ print STDERR " Running status to find changed, added, or removed files.\n";
+ open STAT, "-|", statusCommand(keys %paths) or die "The status failed: $!.\n";
+ while (<STAT>) {
+ my $status;
+ my $propertyStatus;
+ my $propertyChanges;
+ my $original;
+ my $file;
+
+ if ($isSVN) {
+ my $matches;
+ if (isSVNVersion16OrNewer()) {
+ $matches = /^([ ACDMR])([ CM]).{5} (.+?)[\r\n]*$/;
+ $status = $1;
+ $propertyStatus = $2;
+ $file = $3;
+ } else {
+ $matches = /^([ ACDMR])([ CM]).{4} (.+?)[\r\n]*$/;
+ $status = $1;
+ $propertyStatus = $2;
+ $file = $3;
+ }
+ if ($matches) {
+ $file = normalizePath($file);
+ $original = findOriginalFileFromSvn($file) if substr($_, 3, 1) eq "+";
+ my $isAdd = isAddedStatus($status);
+ $propertyChanges = determinePropertyChanges($file, $isAdd, $original) if isModifiedStatus($propertyStatus) || $isAdd;
+ } else {
+ print; # error output from svn stat
+ }
+ } elsif ($isGit) {
+ if (/^([ADM])\t(.+)$/) {
+ $status = $1;
+ $propertyStatus = " "; # git doesn't have properties
+ $file = normalizePath($2);
+ } elsif (/^([CR])[0-9]{1,3}\t([^\t]+)\t([^\t\n]+)$/) { # for example: R90% newfile oldfile
+ $status = $1;
+ $propertyStatus = " ";
+ $original = normalizePath($2);
+ $file = normalizePath($3);
+ } else {
+ print; # error output from git diff
+ }
+ }
+
+ next if !$status || isUnmodifiedStatus($status) && isUnmodifiedStatus($propertyStatus);
+
+ $file = makeFilePathRelative($file);
+
+ if (isModifiedStatus($status) || isAddedStatus($status) || isModifiedStatus($propertyStatus)) {
+ my @components = File::Spec->splitdir($file);
+ if ($components[0] eq "LayoutTests") {
+ $didChangeRegressionTests = 1;
+ push @addedRegressionTests, $file
+ if isAddedStatus($status)
+ && $file =~ /\.([a-zA-Z]+)$/
+ && $supportedTestExtensions{lc($1)}
+ && !scalar(grep(/^resources$/i, @components))
+ && !scalar(grep(/^script-tests$/i, @components));
+ }
+ push @{$changedFiles}, $file if $components[$#components] ne "ChangeLog";
+ } elsif (isConflictStatus($status) || isConflictStatus($propertyStatus)) {
+ push @{$conflictFiles}, $file;
+ }
+ if (basename($file) ne "ChangeLog") {
+ my $description = statusDescription($status, $propertyStatus, $original, $propertyChanges);
+ $functionLists->{$file} = $description if defined $description;
+ }
+ }
+ close STAT;
+}
+
+sub isUnmodifiedStatus($)
+{
+ my ($status) = @_;
+
+ my %statusCodes = (
+ " " => 1,
+ );
+
+ return $statusCodes{$status};
+}
+
+sub isModifiedStatus($)
+{
+ my ($status) = @_;
+
+ my %statusCodes = (
+ "M" => 1,
+ );
+
+ return $statusCodes{$status};
+}
+
+sub isAddedStatus($)
+{
+ my ($status) = @_;
+
+ my %statusCodes = (
+ "A" => 1,
+ "C" => $isGit,
+ "R" => 1,
+ );
+
+ return $statusCodes{$status};
+}
+
+sub isConflictStatus($)
+{
+ my ($status) = @_;
+
+ my %svn = (
+ "C" => 1,
+ );
+
+ my %git = (
+ "U" => 1,
+ );
+
+ return 0 if ($gitCommit || $gitIndex); # an existing commit or staged change cannot have conflicts
+ return $svn{$status} if $isSVN;
+ return $git{$status} if $isGit;
+}
+
+sub statusDescription($$$$)
+{
+ my ($status, $propertyStatus, $original, $propertyChanges) = @_;
+
+ my $propertyDescription = defined $propertyChanges ? propertyChangeDescription($propertyChanges) : "";
+
+ my %svn = (
+ "A" => defined $original ? " Copied from \%s." : " Added.",
+ "D" => " Removed.",
+ "M" => "",
+ "R" => defined $original ? " Replaced with \%s." : " Replaced.",
+ " " => "",
+ );
+
+ my %git = %svn;
+ $git{"A"} = " Added.";
+ $git{"C"} = " Copied from \%s.";
+ $git{"R"} = " Renamed from \%s.";
+
+ my $description;
+ $description = sprintf($svn{$status}, $original) if $isSVN && exists $svn{$status};
+ $description = sprintf($git{$status}, $original) if $isGit && exists $git{$status};
+ return unless defined $description;
+
+ $description .= $propertyDescription unless isAddedStatus($status);
+ return $description;
+}
+
+sub propertyChangeDescription($)
+{
+ my ($propertyChanges) = @_;
+
+ my %operations = (
+ "A" => "Added",
+ "M" => "Modified",
+ "D" => "Removed",
+ "C" => "Changed",
+ );
+
+ my $description = "";
+ while (my ($operation, $properties) = each %$propertyChanges) {
+ my $word = $operations{$operation};
+ my $list = pluralizeAndList("property", "properties", @$properties);
+ $description .= " $word $list.";
+ }
+ return $description;
+}
+
+sub extractLineRange($)
+{
+ my ($string) = @_;
+
+ my ($start, $end) = (-1, -1);
+
+ if ($isSVN && $string =~ /^\d+(,\d+)?[acd](\d+)(,(\d+))?/) {
+ $start = $2;
+ $end = $4 || $2;
+ } elsif ($isGit && $string =~ /^@@ -\d+(,\d+)? \+(\d+)(,(\d+))? @@/) {
+ $start = $2;
+ $end = defined($4) ? $4 + $2 - 1 : $2;
+ }
+
+ return ($start, $end);
+}
+
+sub firstDirectoryOrCwd()
+{
+ my $dir = ".";
+ my @dirs = keys(%paths);
+
+ $dir = -d $dirs[0] ? $dirs[0] : dirname($dirs[0]) if @dirs;
+
+ return $dir;
+}
+
+sub testListForChangeLog(@)
+{
+ my (@tests) = @_;
+
+ return "" unless @tests;
+
+ my $leadString = " Test" . (@tests == 1 ? "" : "s") . ": ";
+ my $list = $leadString;
+ foreach my $i (0..$#tests) {
+ $list .= " " x length($leadString) if $i;
+ my $test = $tests[$i];
+ $test =~ s/^LayoutTests\///;
+ $list .= "$test\n";
+ }
+ $list .= "\n";
+
+ return $list;
+}
+
+sub reviewerAndDescriptionForGitCommit($)
+{
+ my ($commit) = @_;
+
+ my $description = '';
+ my $reviewer;
+
+ my @args = qw(rev-list --pretty);
+ push @args, '-1' if $commit !~ m/.+\.\..+/;
+ my $gitLog;
+ {
+ local $/ = undef;
+ open(GIT, "-|", $GIT, @args, $commit) || die;
+ $gitLog = <GIT>;
+ close(GIT);
+ }
+
+ my @commitLogs = split(/^[Cc]ommit [a-f0-9]{40}/m, $gitLog);
+ shift @commitLogs; # Remove initial blank commit log
+ my $commitLogCount = 0;
+ foreach my $commitLog (@commitLogs) {
+ $description .= "\n" if $commitLogCount;
+ $commitLogCount++;
+ my $inHeader = 1;
+ my $commitLogIndent;
+ my @lines = split(/\n/, $commitLog);
+ shift @lines; # Remove initial blank line
+ foreach my $line (@lines) {
+ if ($inHeader) {
+ if (!$line) {
+ $inHeader = 0;
+ }
+ next;
+ } elsif ($line =~ /[Ss]igned-[Oo]ff-[Bb]y: (.+)/) {
+ if (!$reviewer) {
+ $reviewer = $1;
+ } else {
+ $reviewer .= ", " . $1;
+ }
+ } elsif ($line =~ /^\s*$/) {
+ $description = $description . "\n";
+ } else {
+ if (!defined($commitLogIndent)) {
+ # Let the first line with non-white space determine
+ # the global indent.
+ $line =~ /^(\s*)\S/;
+ $commitLogIndent = length($1);
+ }
+ # Strip at most the indent to preserve relative indents.
+ $line =~ s/^\s{0,$commitLogIndent}//;
+ $description = $description . (" " x 8) . $line . "\n";
+ }
+ }
+ }
+ if (!$reviewer) {
+ $reviewer = $gitReviewer;
+ }
+
+ return ($reviewer, $description);
+}
+
+sub normalizeLineEndings($$)
+{
+ my ($string, $endl) = @_;
+ $string =~ s/\r?\n/$endl/g;
+ return $string;
+}
+
+sub decodeEntities($)
+{
+ my ($text) = @_;
+ $text =~ s/\&lt;/</g;
+ $text =~ s/\&gt;/>/g;
+ $text =~ s/\&quot;/\"/g;
+ $text =~ s/\&apos;/\'/g;
+ $text =~ s/\&amp;/\&/g;
+ return $text;
+}
diff --git a/Tools/Scripts/print-msvc-project-dependencies b/Tools/Scripts/print-msvc-project-dependencies
new file mode 100755
index 0000000..dbc8402
--- /dev/null
+++ b/Tools/Scripts/print-msvc-project-dependencies
@@ -0,0 +1,143 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+use strict;
+use File::Basename;
+
+sub printDependencyTree($);
+
+my $basename = basename($0);
+@ARGV or die "Usage: $basename sln1 [sln2 sln3...]";
+
+foreach my $sln (@ARGV) {
+ printDependencyTree($sln);
+}
+
+exit;
+
+sub printDependencyTree($)
+{
+ my ($sln) = @_;
+
+ unless (-f $sln) {
+ warn "Warning: Can't find $sln; skipping\n";
+ return;
+ }
+
+ unless (open SLN, "<", $sln) {
+ warn "Warning: Can't open $sln; skipping\n";
+ return;
+ }
+
+ my %projectsByUUID = ();
+ my $currentProject;
+
+ my $state = "initial";
+ foreach my $line (<SLN>) {
+ if ($state eq "initial") {
+ if ($line =~ /^Project\([^\)]+\) = "([^"]+)", "[^"]+", "([^"]+)"\r?$/) {
+ my $name = $1;
+ my $uuid = $2;
+ if (exists $projectsByUUID{$uuid}) {
+ warn "Warning: Project $name appears more than once in $sln; using first definition\n";
+ next;
+ }
+ $currentProject = {
+ name => $name,
+ uuid => $uuid,
+ dependencies => {},
+ };
+ $projectsByUUID{$uuid} = $currentProject;
+
+ $state = "inProject";
+ }
+
+ next;
+ }
+
+ if ($state eq "inProject") {
+ defined($currentProject) or die;
+
+ if ($line =~ /^\s*ProjectSection\(ProjectDependencies\) = postProject\r?$/) {
+ $state = "inDependencies";
+ } elsif ($line =~ /^EndProject\r?$/) {
+ $currentProject = undef;
+ $state = "initial";
+ }
+
+ next;
+ }
+
+ if ($state eq "inDependencies") {
+ defined($currentProject) or die;
+
+ if ($line =~ /^\s*({[^}]+}) = ({[^}]+})\r?$/) {
+ my $uuid1 = $1;
+ my $uuid2 = $2;
+ if (exists $currentProject->{dependencies}->{$uuid1}) {
+ warn "Warning: UUID $uuid1 listed more than once as dependency of project ", $currentProject->{name}, "\n";
+ next;
+ }
+
+ $uuid1 eq $uuid2 or warn "Warning: UUIDs in depedency section of project ", $currentProject->{name}, " don't match: $uuid1 $uuid2; using first UUID\n";
+
+ $currentProject->{dependencies}->{$uuid1} = 1;
+ } elsif ($line =~ /^\s*EndProjectSection\r?$/) {
+ $state = "inProject";
+ }
+
+ next;
+ }
+ }
+
+ close SLN or warn "Warning: Can't close $sln\n";
+
+ my %projectsNotDependedUpon = %projectsByUUID;
+ CANDIDATE: foreach my $candidateUUID (keys %projectsByUUID) {
+ foreach my $projectUUID (keys %projectsByUUID) {
+ next if $candidateUUID eq $projectUUID;
+ foreach my $dependencyUUID (keys %{$projectsByUUID{$projectUUID}->{dependencies}}) {
+ if ($candidateUUID eq $dependencyUUID) {
+ delete $projectsNotDependedUpon{$candidateUUID};
+ next CANDIDATE;
+ }
+ }
+ }
+ }
+
+ foreach my $project (values %projectsNotDependedUpon) {
+ printProjectAndDependencies($project, 0, \%projectsByUUID);
+ }
+}
+
+sub printProjectAndDependencies
+{
+ my ($project, $indentLevel, $projectsByUUID) = @_;
+
+ print " " x $indentLevel, $project->{name}, "\n";
+ foreach my $dependencyUUID (keys %{$project->{dependencies}}) {
+ printProjectAndDependencies($projectsByUUID->{$dependencyUUID}, $indentLevel + 1, $projectsByUUID);
+ }
+}
diff --git a/Tools/Scripts/print-vse-failure-logs b/Tools/Scripts/print-vse-failure-logs
new file mode 100755
index 0000000..7580465
--- /dev/null
+++ b/Tools/Scripts/print-vse-failure-logs
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+# 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 is a very simple script designed to crawl the build directory
+# for visual studio express build logs and print them to stdout.
+
+from __future__ import with_statement
+
+import codecs
+import os
+import re
+
+from webkitpy.common.checkout import scm
+from webkitpy.common.system.executive import Executive
+from webkitpy.thirdparty import BeautifulSoup
+
+
+class PrintVisualStudioExpressLogs(object):
+ def __init__(self):
+ self._executive = Executive()
+
+ def _find_buildlogs(self, build_directory):
+ build_log_paths = []
+ for dirpath, dirnames, filenames in os.walk(build_directory):
+ for file_name in filenames:
+ if file_name == "BuildLog.htm":
+ file_path = os.path.join(dirpath, file_name)
+ build_log_paths.append(file_path)
+ return build_log_paths
+
+ def _build_order(self):
+ """Returns a list of project names in the order in which they are built."""
+ script_path = os.path.join(self._scripts_directory(), "print-msvc-project-dependencies")
+ sln_path = os.path.join(scm.find_checkout_root(), "WebKit", "win", "WebKit.vcproj", "WebKit.sln")
+ lines = self._executive.run_command([script_path, sln_path]).splitlines()
+ order = [line.strip() for line in lines if line.find("Folder") == -1]
+ order.reverse()
+ return order
+
+ def _sort_buildlogs(self, log_paths):
+ build_order = self._build_order()
+ def sort_key(log_path):
+ project_name = os.path.basename(os.path.dirname(os.path.dirname(log_path)))
+ try:
+ index = build_order.index(project_name)
+ except ValueError:
+ # If the project isn't in the list, sort it after all items that
+ # are in the list.
+ index = len(build_order)
+ # Sort first by build order, then by project name
+ return (index, project_name)
+ return sorted(log_paths, key=sort_key)
+
+ def _obj_directory(self):
+ build_directory_script_path = os.path.join(self._scripts_directory(), "webkit-build-directory")
+ # FIXME: ports/webkit.py should provide the build directory in a nice API.
+ # NOTE: The windows VSE build does not seem to use different directories
+ # for Debug and Release.
+ build_directory = self._executive.run_command([build_directory_script_path, "--top-level"]).rstrip()
+ return os.path.join(build_directory, "obj")
+
+ def _scripts_directory(self):
+ return os.path.dirname(__file__)
+
+ def _relevant_text(self, log):
+ soup = BeautifulSoup.BeautifulSoup(log)
+ # The Output Window table is where the useful output starts in the build log.
+ output_window_table = soup.find(text=re.compile("Output Window")).findParent("table")
+ result = []
+ for table in [output_window_table] + output_window_table.findNextSiblings("table"):
+ result.extend([text.replace("&nbsp;", "") for text in table.findAll(text=True)])
+ result.append("\n")
+ return "".join(result)
+
+ def main(self):
+ build_log_paths = self._sort_buildlogs(self._find_buildlogs(self._obj_directory()))
+
+ print "Found %s Visual Studio Express Build Logs:\n%s" % (len(build_log_paths), "\n".join(build_log_paths))
+
+ for build_log_path in build_log_paths:
+ print "%s:\n" % build_log_path
+ with codecs.open(build_log_path, "r", "utf-16") as build_log:
+ print self._relevant_text(build_log)
+
+
+if __name__ == '__main__':
+ PrintVisualStudioExpressLogs().main()
diff --git a/Tools/Scripts/rebaseline-chromium-webkit-tests b/Tools/Scripts/rebaseline-chromium-webkit-tests
new file mode 100755
index 0000000..8d14b86
--- /dev/null
+++ b/Tools/Scripts/rebaseline-chromium-webkit-tests
@@ -0,0 +1,44 @@
+#!/usr/bin/env python
+# 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.
+
+"""Wrapper around webkitpy/layout_tests/rebaseline.py"""
+import os
+import sys
+
+scripts_directory = os.path.dirname(os.path.abspath(sys.argv[0]))
+webkitpy_directory = os.path.join(scripts_directory, "webkitpy")
+sys.path.append(os.path.join(webkitpy_directory, "layout_tests"))
+
+# For simplejson
+sys.path.append(os.path.join(webkitpy_directory, "thirdparty"))
+
+import rebaseline_chromium_webkit_tests
+
+if __name__ == '__main__':
+ rebaseline_chromium_webkit_tests.main()
diff --git a/Tools/Scripts/report-include-statistics b/Tools/Scripts/report-include-statistics
new file mode 100755
index 0000000..17152ab
--- /dev/null
+++ b/Tools/Scripts/report-include-statistics
@@ -0,0 +1,114 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# "report-include-statistics" script for WebKit Open Source Project
+
+use strict;
+use File::Find;
+
+find(\&wanted, @ARGV ? @ARGV : ".");
+
+my %paths;
+my %sources;
+my %includes;
+
+sub wanted
+{
+ my $file = $_;
+
+ if ($file eq "icu") {
+ $File::Find::prune = 1;
+ return;
+ }
+
+ if ($file !~ /^\./ && $file =~ /\.(h|cpp|c|mm|m)$/) {
+ $paths{$file} = $File::Find::name;
+ $sources{$file} = $File::Find::name if $file !~ /\.h/;
+ open FILE, $file or die;
+ while (<FILE>) {
+ if (m-^\s*#\s*(include|import)\s+["<]((\S+/)*)(\S+)[">]-) {
+ my $include = ($2 eq "sys/" ? $2 : "") . $4;
+ $includes{$file}{$include}++;
+ }
+ }
+ close FILE;
+ }
+}
+
+my %totalIncludes;
+
+sub fillOut
+{
+ my ($file) = @_;
+
+ return if defined $totalIncludes{$file};
+
+ for my $include (keys %{ $includes{$file} }) {
+ $totalIncludes{$file}{$include} = 1;
+ fillOut($include);
+ for my $i (keys %{ $totalIncludes{$include} }) {
+ $totalIncludes{$file}{$i} = 1;
+ }
+ }
+}
+
+my %inclusionCounts;
+for my $file (keys %includes) {
+ $inclusionCounts{$file} = 0;
+ fillOut($file);
+}
+
+for my $file (keys %sources) {
+ for my $include (keys %{ $totalIncludes{$file} }) {
+ $inclusionCounts{$include}++;
+ }
+}
+
+for my $file (sort mostincludedcmp keys %includes) {
+ next if !$paths{$file};
+ my $count = $inclusionCounts{$file};
+ my $numIncludes = keys %{ $includes{$file} };
+ my $numTotalIncludes = keys %{ $totalIncludes{$file} };
+ print "$file is included $count times, includes $numIncludes files directly, $numTotalIncludes files total.\n"
+}
+
+# Sort most-included files first.
+sub mostincludedcmp($$)
+{
+ my ($filea, $fileb) = @_;
+
+ my $counta = $inclusionCounts{$filea} || 0;
+ my $countb = $inclusionCounts{$fileb} || 0;
+ return $countb <=> $counta if $counta != $countb;
+
+ my $ta = keys %{ $totalIncludes{$filea} };
+ my $tb = keys %{ $totalIncludes{$fileb} };
+ return $ta <=> $tb if $ta != $tb;
+
+ return $filea cmp $fileb;
+}
diff --git a/Tools/Scripts/resolve-ChangeLogs b/Tools/Scripts/resolve-ChangeLogs
new file mode 100755
index 0000000..6635711
--- /dev/null
+++ b/Tools/Scripts/resolve-ChangeLogs
@@ -0,0 +1,488 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Merge and resolve ChangeLog conflicts for svn and git repositories
+
+use strict;
+
+use FindBin;
+use lib $FindBin::Bin;
+
+use File::Basename;
+use File::Copy;
+use File::Path;
+use File::Spec;
+use Getopt::Long;
+use POSIX;
+use VCSUtils;
+
+sub canonicalRelativePath($);
+sub conflictFiles($);
+sub findChangeLog($);
+sub findUnmergedChangeLogs();
+sub fixMergedChangeLogs($;@);
+sub fixOneMergedChangeLog($);
+sub hasGitUnmergedFiles();
+sub isInGitFilterBranch();
+sub parseFixMerged($$;$);
+sub removeChangeLogArguments($);
+sub resolveChangeLog($);
+sub resolveConflict($);
+sub showStatus($;$);
+sub usageAndExit();
+
+my $isGit = isGit();
+my $isSVN = isSVN();
+
+my $SVN = "svn";
+my $GIT = "git";
+
+my $fixMerged;
+my $gitRebaseContinue = 0;
+my $mergeDriver = 0;
+my $printWarnings = 1;
+my $showHelp;
+
+my $getOptionsResult = GetOptions(
+ 'c|continue!' => \$gitRebaseContinue,
+ 'f|fix-merged:s' => \&parseFixMerged,
+ 'm|merge-driver!' => \$mergeDriver,
+ 'h|help' => \$showHelp,
+ 'w|warnings!' => \$printWarnings,
+);
+
+my $relativePath = isInGitFilterBranch() ? '.' : chdirReturningRelativePath(determineVCSRoot());
+
+my @changeLogFiles = removeChangeLogArguments($relativePath);
+
+if (!defined $fixMerged && !$mergeDriver && scalar(@changeLogFiles) == 0) {
+ @changeLogFiles = findUnmergedChangeLogs();
+}
+
+if (!$mergeDriver && scalar(@ARGV) > 0) {
+ print STDERR "ERROR: Files listed on command-line that are not ChangeLogs.\n";
+ undef $getOptionsResult;
+} elsif (!defined $fixMerged && !$mergeDriver && scalar(@changeLogFiles) == 0) {
+ print STDERR "ERROR: No ChangeLog files listed on command-line or found unmerged.\n";
+ undef $getOptionsResult;
+} elsif ($gitRebaseContinue && !$isGit) {
+ print STDERR "ERROR: --continue may only be used with a git repository\n";
+ undef $getOptionsResult;
+} elsif (defined $fixMerged && !$isGit) {
+ print STDERR "ERROR: --fix-merged may only be used with a git repository\n";
+ undef $getOptionsResult;
+} elsif ($mergeDriver && !$isGit) {
+ print STDERR "ERROR: --merge-driver may only be used with a git repository\n";
+ undef $getOptionsResult;
+} elsif ($mergeDriver && scalar(@ARGV) < 3) {
+ print STDERR "ERROR: --merge-driver expects %O %A %B as arguments\n";
+ undef $getOptionsResult;
+}
+
+sub usageAndExit()
+{
+ print STDERR <<__END__;
+Usage: @{[ basename($0) ]} [options] [path/to/ChangeLog] [path/to/another/ChangeLog ...]
+ -c|--[no-]continue run "git rebase --continue" after fixing ChangeLog
+ entries (default: --no-continue)
+ -f|--fix-merged [revision-range] fix git-merged ChangeLog entries; if a revision-range
+ is specified, run git filter-branch on the range
+ -m|--merge-driver %O %A %B act as a git merge-driver on files %O %A %B
+ -h|--help show this help message
+ -w|--[no-]warnings show or suppress warnings (default: show warnings)
+__END__
+ exit 1;
+}
+
+if (!$getOptionsResult || $showHelp) {
+ usageAndExit();
+}
+
+if (defined $fixMerged && length($fixMerged) > 0) {
+ my $commitRange = $fixMerged;
+ $commitRange = $commitRange . "..HEAD" if index($commitRange, "..") < 0;
+ fixMergedChangeLogs($commitRange, @changeLogFiles);
+} elsif ($mergeDriver) {
+ my ($base, $theirs, $ours) = @ARGV;
+ if (mergeChangeLogs($ours, $base, $theirs)) {
+ unlink($ours);
+ copy($theirs, $ours) or die $!;
+ } else {
+ exec qw(git merge-file -L THEIRS -L BASE -L OURS), $theirs, $base, $ours;
+ }
+} elsif (@changeLogFiles) {
+ for my $file (@changeLogFiles) {
+ if (defined $fixMerged) {
+ fixOneMergedChangeLog($file);
+ } else {
+ resolveChangeLog($file);
+ }
+ }
+} else {
+ print STDERR "ERROR: Unknown combination of switches and arguments.\n";
+ usageAndExit();
+}
+
+if ($gitRebaseContinue) {
+ if (hasGitUnmergedFiles()) {
+ print "Unmerged files; skipping '$GIT rebase --continue'.\n";
+ } else {
+ print "Running '$GIT rebase --continue'...\n";
+ print `$GIT rebase --continue`;
+ }
+}
+
+exit 0;
+
+sub canonicalRelativePath($)
+{
+ my ($originalPath) = @_;
+ my $absolutePath = Cwd::abs_path($originalPath);
+ return File::Spec->abs2rel($absolutePath, Cwd::getcwd());
+}
+
+sub conflictFiles($)
+{
+ my ($file) = @_;
+ my $fileMine;
+ my $fileOlder;
+ my $fileNewer;
+
+ if (-e $file && -e "$file.orig" && -e "$file.rej") {
+ return ("$file.rej", "$file.orig", $file);
+ }
+
+ if ($isSVN) {
+ open STAT, "-|", $SVN, "status", $file or die $!;
+ my $status = <STAT>;
+ close STAT;
+ if (!$status || $status !~ m/^C\s+/) {
+ print STDERR "WARNING: ${file} is not in a conflicted state.\n" if $printWarnings;
+ return ();
+ }
+
+ $fileMine = "${file}.mine" if -e "${file}.mine";
+
+ my $currentRevision;
+ open INFO, "-|", $SVN, "info", $file or die $!;
+ while (my $line = <INFO>) {
+ if ($line =~ m/^Revision: ([0-9]+)/) {
+ $currentRevision = $1;
+ { local $/ = undef; <INFO>; } # Consume rest of input.
+ }
+ }
+ close INFO;
+ $fileNewer = "${file}.r${currentRevision}" if -e "${file}.r${currentRevision}";
+
+ my @matchingFiles = grep { $_ ne $fileNewer } glob("${file}.r[0-9][0-9]*");
+ if (scalar(@matchingFiles) > 1) {
+ print STDERR "WARNING: Too many conflict files exist for ${file}!\n" if $printWarnings;
+ } else {
+ $fileOlder = shift @matchingFiles;
+ }
+ } elsif ($isGit) {
+ my $gitPrefix = `$GIT rev-parse --show-prefix`;
+ chomp $gitPrefix;
+ open GIT, "-|", $GIT, "ls-files", "--unmerged", $file or die $!;
+ while (my $line = <GIT>) {
+ my ($mode, $hash, $stage, $fileName) = split(' ', $line);
+ my $outputFile;
+ if ($stage == 1) {
+ $fileOlder = "${file}.BASE.$$";
+ $outputFile = $fileOlder;
+ } elsif ($stage == 2) {
+ $fileNewer = "${file}.LOCAL.$$";
+ $outputFile = $fileNewer;
+ } elsif ($stage == 3) {
+ $fileMine = "${file}.REMOTE.$$";
+ $outputFile = $fileMine;
+ } else {
+ die "Unknown file stage: $stage";
+ }
+ system("$GIT cat-file blob :${stage}:${gitPrefix}${file} > $outputFile");
+ die $! if WEXITSTATUS($?);
+ }
+ close GIT or die $!;
+ } else {
+ die "Unknown version control system";
+ }
+
+ if (!$fileMine && !$fileOlder && !$fileNewer) {
+ print STDERR "WARNING: ${file} does not need merging.\n" if $printWarnings;
+ } elsif (!$fileMine || !$fileOlder || !$fileNewer) {
+ print STDERR "WARNING: ${file} is missing some conflict files.\n" if $printWarnings;
+ }
+
+ return ($fileMine, $fileOlder, $fileNewer);
+}
+
+sub findChangeLog($)
+{
+ return $_[0] if basename($_[0]) eq "ChangeLog";
+
+ my $file = File::Spec->catfile($_[0], "ChangeLog");
+ return $file if -d $_[0] and -e $file;
+
+ return undef;
+}
+
+sub findUnmergedChangeLogs()
+{
+ my $statCommand = "";
+
+ if ($isSVN) {
+ $statCommand = "$SVN stat | grep '^C'";
+ } elsif ($isGit) {
+ $statCommand = "$GIT diff -r --name-status --diff-filter=U -C -C -M";
+ } else {
+ return ();
+ }
+
+ my @results = ();
+ open STAT, "-|", $statCommand or die "The status failed: $!.\n";
+ while (<STAT>) {
+ if ($isSVN) {
+ my $matches;
+ my $file;
+ if (isSVNVersion16OrNewer()) {
+ $matches = /^([C]).{6} (.+?)[\r\n]*$/;
+ $file = $2;
+ } else {
+ $matches = /^([C]).{5} (.+?)[\r\n]*$/;
+ $file = $2;
+ }
+ if ($matches) {
+ $file = findChangeLog(normalizePath($file));
+ push @results, $file if $file;
+ } else {
+ print; # error output from svn stat
+ }
+ } elsif ($isGit) {
+ if (/^([U])\t(.+)$/) {
+ my $file = findChangeLog(normalizePath($2));
+ push @results, $file if $file;
+ } else {
+ print; # error output from git diff
+ }
+ }
+ }
+ close STAT;
+
+ return @results;
+}
+
+sub fixMergedChangeLogs($;@)
+{
+ my $revisionRange = shift;
+ my @changedFiles = @_;
+
+ if (scalar(@changedFiles) < 1) {
+ # Read in list of files changed in $revisionRange
+ open GIT, "-|", $GIT, "diff", "--name-only", $revisionRange or die $!;
+ push @changedFiles, <GIT>;
+ close GIT or die $!;
+ die "No changed files in $revisionRange" if scalar(@changedFiles) < 1;
+ chomp @changedFiles;
+ }
+
+ my @changeLogs = grep { defined $_ } map { findChangeLog($_) } @changedFiles;
+ die "No changed ChangeLog files in $revisionRange" if scalar(@changeLogs) < 1;
+
+ system("$GIT filter-branch --tree-filter 'PREVIOUS_COMMIT=\`$GIT rev-parse \$GIT_COMMIT^\` && MAPPED_PREVIOUS_COMMIT=\`map \$PREVIOUS_COMMIT\` \"$0\" -f \"" . join('" "', @changeLogs) . "\"' $revisionRange");
+
+ # On success, remove the backup refs directory
+ if (WEXITSTATUS($?) == 0) {
+ rmtree(qw(.git/refs/original));
+ }
+}
+
+sub fixOneMergedChangeLog($)
+{
+ my $file = shift;
+ my $patch;
+
+ # Read in patch for incorrectly merged ChangeLog entry
+ {
+ local $/ = undef;
+ open GIT, "-|", $GIT, "diff", ($ENV{GIT_COMMIT} || "HEAD") . "^", $file or die $!;
+ $patch = <GIT>;
+ close GIT or die $!;
+ }
+
+ # Always checkout the previous commit's copy of the ChangeLog
+ system($GIT, "checkout", $ENV{MAPPED_PREVIOUS_COMMIT} || "HEAD^", $file);
+ die $! if WEXITSTATUS($?);
+
+ # The patch must have 0 or more lines of context, then 1 or more lines
+ # of additions, and then 1 or more lines of context. If not, we skip it.
+ if ($patch =~ /\n@@ -(\d+),(\d+) \+(\d+),(\d+) @@\n( .*\n)*((\+.*\n)+)( .*\n)+$/m) {
+ # Copy the header from the original patch.
+ my $newPatch = substr($patch, 0, index($patch, "@@ -${1},${2} +${3},${4} @@"));
+
+ # Generate a new set of line numbers and patch lengths. Our new
+ # patch will start with the lines for the fixed ChangeLog entry,
+ # then have 3 lines of context from the top of the current file to
+ # make the patch apply cleanly.
+ $newPatch .= "@@ -1,3 +1," . ($4 - $2 + 3) . " @@\n";
+
+ # We assume that top few lines of the ChangeLog entry are actually
+ # at the bottom of the list of added lines (due to the way the patch
+ # algorithm works), so we simply search through the lines until we
+ # find the date line, then move the rest of the lines to the top.
+ my @patchLines = map { $_ . "\n" } split(/\n/, $6);
+ foreach my $i (0 .. $#patchLines) {
+ if ($patchLines[$i] =~ /^\+\d{4}-\d{2}-\d{2} /) {
+ unshift(@patchLines, splice(@patchLines, $i, scalar(@patchLines) - $i));
+ last;
+ }
+ }
+
+ $newPatch .= join("", @patchLines);
+
+ # Add 3 lines of context to the end
+ open FILE, "<", $file or die $!;
+ for (my $i = 0; $i < 3; $i++) {
+ $newPatch .= " " . <FILE>;
+ }
+ close FILE;
+
+ # Apply the new patch
+ open(PATCH, "| patch -p1 $file > " . File::Spec->devnull()) or die $!;
+ print PATCH $newPatch;
+ close(PATCH) or die $!;
+
+ # Run "git add" on the fixed ChangeLog file
+ system($GIT, "add", $file);
+ die $! if WEXITSTATUS($?);
+
+ showStatus($file, 1);
+ } elsif ($patch) {
+ # Restore the current copy of the ChangeLog file since we can't repatch it
+ system($GIT, "checkout", $ENV{GIT_COMMIT} || "HEAD", $file);
+ die $! if WEXITSTATUS($?);
+ print STDERR "WARNING: Last change to ${file} could not be fixed and re-merged.\n" if $printWarnings;
+ }
+}
+
+sub hasGitUnmergedFiles()
+{
+ my $output = `$GIT ls-files --unmerged`;
+ return $output ne "";
+}
+
+sub isInGitFilterBranch()
+{
+ return exists $ENV{MAPPED_PREVIOUS_COMMIT} && $ENV{MAPPED_PREVIOUS_COMMIT};
+}
+
+sub parseFixMerged($$;$)
+{
+ my ($switchName, $key, $value) = @_;
+ if (defined $key) {
+ if (defined findChangeLog($key)) {
+ unshift(@ARGV, $key);
+ $fixMerged = "";
+ } else {
+ $fixMerged = $key;
+ }
+ } else {
+ $fixMerged = "";
+ }
+}
+
+sub removeChangeLogArguments($)
+{
+ my ($baseDir) = @_;
+ my @results = ();
+
+ for (my $i = 0; $i < scalar(@ARGV); ) {
+ my $file = findChangeLog(canonicalRelativePath(File::Spec->catfile($baseDir, $ARGV[$i])));
+ if (defined $file) {
+ splice(@ARGV, $i, 1);
+ push @results, $file;
+ } else {
+ $i++;
+ }
+ }
+
+ return @results;
+}
+
+sub resolveChangeLog($)
+{
+ my ($file) = @_;
+
+ my ($fileMine, $fileOlder, $fileNewer) = conflictFiles($file);
+
+ return unless $fileMine && $fileOlder && $fileNewer;
+
+ if (mergeChangeLogs($fileMine, $fileOlder, $fileNewer)) {
+ if ($file ne $fileNewer) {
+ unlink($file);
+ rename($fileNewer, $file) or die $!;
+ }
+ unlink($fileMine, $fileOlder);
+ resolveConflict($file);
+ showStatus($file, 1);
+ } else {
+ showStatus($file);
+ print STDERR "WARNING: ${file} could not be merged using fuzz level 3.\n" if $printWarnings;
+ unlink($fileMine, $fileOlder, $fileNewer) if $isGit;
+ }
+}
+
+sub resolveConflict($)
+{
+ my ($file) = @_;
+
+ if ($isSVN) {
+ system($SVN, "resolved", $file);
+ die $! if WEXITSTATUS($?);
+ } elsif ($isGit) {
+ system($GIT, "add", $file);
+ die $! if WEXITSTATUS($?);
+ } else {
+ die "Unknown version control system";
+ }
+}
+
+sub showStatus($;$)
+{
+ my ($file, $isConflictResolved) = @_;
+
+ if ($isSVN) {
+ system($SVN, "status", $file);
+ } elsif ($isGit) {
+ my @args = qw(--name-status);
+ unshift @args, qw(--cached) if $isConflictResolved;
+ system($GIT, "diff", @args, $file);
+ } else {
+ die "Unknown version control system";
+ }
+}
+
diff --git a/Tools/Scripts/roll-over-ChangeLogs b/Tools/Scripts/roll-over-ChangeLogs
new file mode 100755
index 0000000..7e6d32f
--- /dev/null
+++ b/Tools/Scripts/roll-over-ChangeLogs
@@ -0,0 +1,47 @@
+#!/usr/bin/env ruby
+
+# 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.
+
+
+require 'date'
+
+CHANGELOG_SIZE_THRESHOLD = 750 * 1024
+
+scripts_directory = File.dirname(__FILE__)
+base_directory = File.expand_path(ARGV[0] || `perl -I#{scripts_directory} -Mwebkitdirs -e 'print sourceDir();'`)
+
+date_suffix = Date.today.strftime("-%Y-%m-%d")
+
+Dir.chdir base_directory
+`find . -type f -name 'ChangeLog'`.split.each do |path|
+ next unless File.stat(path).size > CHANGELOG_SIZE_THRESHOLD
+
+ old_path = "#{path}#{date_suffix}"
+ puts "Moving #{path} to #{old_path}..."
+ system "git", "mv", path, old_path
+ File.open path, "w" do |file|
+ file.write "== Rolled over to ChangeLog#{date_suffix} ==\n"
+ end
+ system "git", "add", path
+end
diff --git a/Tools/Scripts/run-api-tests b/Tools/Scripts/run-api-tests
new file mode 100755
index 0000000..29430a8
--- /dev/null
+++ b/Tools/Scripts/run-api-tests
@@ -0,0 +1,246 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Features to add:
+# - Command line option to run a single test.
+# - Command line option to run all tests in a suite.
+
+use strict;
+use warnings;
+
+use File::Basename;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use IPC::Open3;
+use lib $FindBin::Bin;
+use webkitdirs;
+use Term::ANSIColor qw(:constants);
+
+sub dumpAllTests();
+sub runAllTests();
+sub runAllTestsInSuite($);
+sub runTest($$);
+sub populateTests();
+sub buildTestTool();
+
+my $showHelp = 0;
+my $quiet = 0;
+my $dump = 0;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options]
+ --help Show this help message
+ -q|--quite Less verbose output
+ -d|--dump-tests Dump the names of testcases without running them
+EOF
+
+GetOptions(
+ 'help' => \$showHelp,
+ 'quiet|q' => \$quiet,
+ 'dump|d' => \$dump,
+);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+setConfiguration();
+buildTestTool();
+setPathForRunningWebKitApp(\%ENV);
+my %testsToRun = populateTests();
+
+if ($dump) {
+ dumpAllTests();
+ exit 0;
+}
+
+runAllTests();
+
+sub dumpAllTests()
+{
+ print "Dumping test cases\n";
+ print "------------------\n";
+ for my $suite (keys %testsToRun) {
+ print $suite . ":\n";
+ print map { " " . $_ . "\n" } @{ $testsToRun{$suite} };
+ }
+ print "------------------\n";
+}
+
+sub runAllTests()
+{
+ my $anyFailures = 0;
+ for my $suite (keys %testsToRun) {
+ my $failed = runAllTestsInSuite($suite);
+ if ($failed) {
+ $anyFailures = 1;
+ }
+ }
+ return $anyFailures;
+}
+
+sub runAllTestsInSuite($)
+{
+ my ($suite) = @_;
+ print "Suite: $suite\n";
+
+ my $anyFailures = 0;
+ for my $test (@{$testsToRun{$suite}}) {
+ my $failed = runTest($suite, $test);
+ if ($failed) {
+ $anyFailures = 1;
+ }
+ }
+
+ return $anyFailures;
+}
+
+sub runTest($$)
+{
+ my ($suite, $testName) = @_;
+ my $test = $suite . "/" . $testName;
+
+ print " Test: $testName -> ";
+
+ my $result = 0;
+ if (isAppleMacWebKit()) {
+ my $productDir = productDir();
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
+ my $apiTesterPath = "$productDir/TestWebKitAPI";
+ if (architecture()) {
+ $result = system "arch", "-" . architecture(), $apiTesterPath, $test, @ARGV;
+ } else {
+ $result = system $apiTesterPath, $test, @ARGV;
+ }
+ } elsif (isAppleWinWebKit()) {
+ my $apiTesterNameSuffix;
+ if (configurationForVisualStudio() ne "Debug_All") {
+ $apiTesterNameSuffix = "";
+ } else {
+ $apiTesterNameSuffix = "_debug";
+ }
+ my $apiTesterPath = File::Spec->catfile(productDir(), "TestWebKitAPI$apiTesterNameSuffix.exe");
+ $result = system $apiTesterPath, $test, @ARGV;
+ } else {
+ die "run-api-tests is not supported on this platform.\n"
+ }
+
+ if ($result == 0) {
+ print BOLD GREEN, "Passed", RESET, "\n";
+ } else {
+ print BOLD RED, "Failed", RESET, "\n";
+ }
+}
+
+
+sub populateTests()
+{
+ my @tests;
+
+ if (isAppleMacWebKit()) {
+ my $productDir = productDir();
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
+ my $apiTesterPath = "$productDir/TestWebKitAPI";
+
+ my ($pid, $childIn, $childOut);
+ if (architecture()) {
+ $pid = open3($childIn, $childOut, ">&STDERR", "arch", "-" . architecture(), $apiTesterPath, "--dump-tests") or die "Failed to build list of tests!";
+ } else {
+ $pid = open3($childIn, $childOut, ">&STDERR", $apiTesterPath, "--dump-tests") or die "Failed to build list of tests!";
+ }
+ close($childIn);
+ @tests = <$childOut>;
+ close($childOut);
+
+ waitpid($pid, 0);
+ my $result = $?;
+
+ if ($result) {
+ print STDERR "Failed to build list of tests!\n";
+ exit exitStatus($result);
+ }
+ } elsif (isAppleWinWebKit()) {
+ my $apiTesterNameSuffix;
+ if (configurationForVisualStudio() ne "Debug_All") {
+ $apiTesterNameSuffix = "";
+ } else {
+ $apiTesterNameSuffix = "_debug";
+ }
+ my $apiTesterPath = File::Spec->catfile(productDir(), "TestWebKitAPI$apiTesterNameSuffix.exe");
+ open(TESTS, "-|", $apiTesterPath, "--dump-tests") or die $!;
+ @tests = <TESTS>;
+ close(TESTS) or die $!;
+ } else {
+ die "run-api-tests is not supported on this platform.\n"
+ }
+
+ my %keyedTests = ();
+ for my $test (@tests) {
+ $test =~ s/[\r\n]*$//;
+ my ($suite, $testName) = split(/\//, $test);
+ push @{$keyedTests{$suite}}, $testName;
+ }
+
+ return %keyedTests;
+}
+
+sub buildTestTool()
+{
+ chdirWebKit();
+
+ my $buildTestTool = "build-api-tests";
+ print STDERR "Running $buildTestTool\n";
+
+ local *DEVNULL;
+ my ($childIn, $childOut, $childErr);
+ if ($quiet) {
+ open(DEVNULL, ">", File::Spec->devnull()) or die "Failed to open /dev/null";
+ $childOut = ">&DEVNULL";
+ $childErr = ">&DEVNULL";
+ } else {
+ # When not quiet, let the child use our stdout/stderr.
+ $childOut = ">&STDOUT";
+ $childErr = ">&STDERR";
+ }
+
+ my @args = argumentsForConfiguration();
+ my $buildProcess = open3($childIn, $childOut, $childErr, "Tools/Scripts/$buildTestTool", @args) or die "Failed to run " . $buildTestTool;
+ close($childIn);
+ waitpid $buildProcess, 0;
+ my $buildResult = $?;
+ close($childOut);
+ close($childErr);
+
+ close DEVNULL if ($quiet);
+
+ if ($buildResult) {
+ print STDERR "Compiling TestWebKitAPI failed!\n";
+ exit exitStatus($buildResult);
+ }
+}
diff --git a/Tools/Scripts/run-bindings-tests b/Tools/Scripts/run-bindings-tests
new file mode 100755
index 0000000..4a093d1
--- /dev/null
+++ b/Tools/Scripts/run-bindings-tests
@@ -0,0 +1,137 @@
+#!/usr/bin/python
+# 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 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.
+#
+
+# This script generates h and cpp file for TestObj.idl using the V8 code
+# generator. Please execute the script whenever changes are made to
+# CodeGeneratorV8.pm, and submit the changes in V8TestObj.h/cpp in the same
+# patch. This makes it easier to track and review changes in generated code.
+# To execute, invoke: 'python run_tests.py'
+
+import os
+import os.path
+import subprocess
+import sys
+import tempfile
+from webkitpy.common.checkout import scm
+
+
+def generate_from_idl(generator, idl_file, output_directory):
+ cmd = ['perl', '-w',
+ '-IWebCore/bindings/scripts',
+ 'WebCore/bindings/scripts/generate-bindings.pl',
+ # idl include directories (path relative to generate-bindings.pl)
+ '--include', '.',
+ '--defines', 'TESTING_%s' % generator,
+ '--generator', generator,
+ '--outputDir', output_directory,
+ idl_file]
+ return subprocess.call(cmd) == 0
+
+
+def detect_changes(work_directory, reference_directory):
+ changes_found = False
+ for output_file in os.listdir(work_directory):
+ print 'Detecting changes in %s...' % output_file
+ cmd = ['diff',
+ '-u',
+ os.path.join(reference_directory, output_file),
+ os.path.join(work_directory, output_file)]
+ if subprocess.call(cmd) != 0:
+ print 'Detected changes in %s (see above)' % output_file
+ changes_found = True
+ else:
+ print 'No changes found.'
+
+ return changes_found
+
+
+def run_tests(generator, input_directory, reference_directory, reset_results):
+ work_directory = reference_directory
+
+ passed = True
+ for input_file in os.listdir(input_directory):
+ (name, extension) = os.path.splitext(input_file)
+ if extension != '.idl':
+ continue
+ print 'Testing the %s generator on %s' % (generator, input_file)
+ # Generate output into the work directory (either the given one or a
+ # temp one if not reset_results is performed)
+ if not reset_results:
+ work_directory = tempfile.mkdtemp()
+ if not generate_from_idl(generator, os.path.join(input_directory,
+ input_file),
+ work_directory):
+ passed = False
+ if reset_results:
+ print "Overwrote reference files"
+ continue
+ # Detect changes
+ if detect_changes(work_directory, reference_directory):
+ passed = False
+
+ if not passed:
+ print '%s generator failed.' % generator
+ return passed
+
+
+def main(argv):
+ """Runs WebCore bindings code generators on test IDL files and compares
+ the results with reference files.
+
+ Options:
+ --reset-results: Overwrites the reference files with the generated results.
+
+ """
+ reset_results = "--reset-results" in argv
+
+ current_scm = scm.detect_scm_system(os.curdir)
+ os.chdir(current_scm.checkout_root)
+
+ all_tests_passed = True
+
+ generators = [
+ 'JS',
+ 'V8',
+ 'ObjC',
+ 'GObject',
+ 'CPP'
+ ]
+
+ for generator in generators:
+ input_directory = os.path.join('WebCore', 'bindings', 'scripts', 'test')
+ reference_directory = os.path.join('WebCore', 'bindings', 'scripts', 'test', generator)
+ if not run_tests(generator, input_directory, reference_directory, reset_results):
+ all_tests_passed = False
+
+ if all_tests_passed:
+ print 'All tests passed!'
+ return 0
+ else:
+ print '(To update the reference files, execute "run-bindings-tests --reset-results")'
+ return -1
+
+
+if __name__ == '__main__':
+ sys.exit(main(sys.argv))
diff --git a/Tools/Scripts/run-chromium-webkit-unit-tests b/Tools/Scripts/run-chromium-webkit-unit-tests
new file mode 100755
index 0000000..62646af
--- /dev/null
+++ b/Tools/Scripts/run-chromium-webkit-unit-tests
@@ -0,0 +1,51 @@
+#!/usr/bin/perl -w
+# 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.
+
+use strict;
+use File::Spec;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+# Allow running this script from any directory.
+my $sourceRootDir = File::Spec->catfile($FindBin::Bin, "../..");
+chdir($sourceRootDir);
+
+setConfiguration();
+
+my $pathToBinary;
+if (isDarwin()) {
+ $pathToBinary = "WebKit/chromium/xcodebuild/" . configuration() . "/webkit_unit_tests";
+} elsif (isCygwin() || isWindows()) {
+ $pathToBinary = "WebKit/chromium/" . configuration() . "/webkit_unit_tests.exe";
+} elsif (isLinux()) {
+ $pathToBinary = "out/" . configuration() . "/webkit_unit_tests";
+}
+
+exit system ($pathToBinary, @ARGV);
diff --git a/Tools/Scripts/run-gtk-tests b/Tools/Scripts/run-gtk-tests
new file mode 100644
index 0000000..9a57319
--- /dev/null
+++ b/Tools/Scripts/run-gtk-tests
@@ -0,0 +1,35 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org>
+#
+# 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.
+
+use strict;
+use warnings;
+
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+# This initializes the correct configuration (Release/Debug)
+setConfiguration();
+
+my $productDir = productDir();
+my @unitTests = glob $productDir . "/Programs/unittests/*";
+if ($#unitTests < 1) {
+ die "ERROR: tests not found in $productDir.\n";
+}
+system "gtester -k @unitTests"
diff --git a/Tools/Scripts/run-iexploder-tests b/Tools/Scripts/run-iexploder-tests
new file mode 100755
index 0000000..5d7ae55
--- /dev/null
+++ b/Tools/Scripts/run-iexploder-tests
@@ -0,0 +1,143 @@
+#!/usr/bin/perl
+
+# 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.
+
+# A script to semi-automatically run iExploder tests.
+
+use strict;
+use warnings;
+
+use Cwd;
+use File::Spec;
+use FindBin;
+use Getopt::Long;
+use IPC::Open2;
+
+use lib $FindBin::Bin;
+use webkitperl::httpd;
+use webkitdirs;
+
+sub configureAndOpenHTTPDIfNeeded();
+sub runSafariWithIExploder();
+
+# Argument handling
+my $guardMalloc = '';
+my $httpdPort = 8000;
+my $downloadTest;
+my $iExploderTestDirectory = "/tmp/iExploderTest";
+
+GetOptions(
+ 'guard-malloc|g' => \$guardMalloc,
+ 'get=s' => \$downloadTest,
+ 'port=i' => \$httpdPort
+);
+
+
+setConfiguration();
+my $productDir = productDir();
+
+chdirWebKit();
+
+checkFrameworks();
+
+my $isHttpdOpen = 0;
+configureAndOpenHTTPDIfNeeded();
+
+if ($downloadTest) {
+ system "/usr/bin/curl -o ~/Desktop/iexploder$downloadTest.html \"http://127.0.0.1:$httpdPort/iexploder.cgi?lookup=1&test=$downloadTest\"";
+ print "Saved the test as iexploder$downloadTest.html on the desktop\n";
+} else {
+ runSafariWithIExploder();
+ print "Last generated tests:\n";
+ system "grep 'iexploder.cgi' $iExploderTestDirectory/access_log.txt | tail -n -5 | awk -F'[ =&\\?]' '{if (\$8 == \"lookup\") print \$11; else print \$9}'";
+}
+
+rmtree $iExploderTestDirectory;
+$isHttpdOpen = !closeHTTPD();
+
+sub runSafariWithIExploder()
+{
+ my $redirectTo;
+ if (@ARGV) {
+ $redirectTo = "http://127.0.0.1:$httpdPort/iexploder.cgi?lookup=1&test=$ARGV[0]";
+ } else {
+ $redirectTo = "http://127.0.0.1:$httpdPort/index.html";
+ }
+
+ open REDIRECT_HTML, ">", "$iExploderTestDirectory/redirect.html" or die;
+ print REDIRECT_HTML "<html>\n";
+ print REDIRECT_HTML " <head>\n";
+ print REDIRECT_HTML " <meta http-equiv=\"refresh\" content=\"1;URL=$redirectTo\" />\n";
+ print REDIRECT_HTML " <script type=\"text/javascript\">\n";
+ print REDIRECT_HTML " document.location = \"$redirectTo\";\n";
+ print REDIRECT_HTML " </script>\n";
+ print REDIRECT_HTML " </head>\n";
+ print REDIRECT_HTML " <body>\n";
+ print REDIRECT_HTML " </body>\n";
+ print REDIRECT_HTML "</html>\n";
+ close REDIRECT_HTML;
+
+ if (!isAppleWebKit()) {
+ system "Tools/Scripts/run-launcher", "$iExploderTestDirectory/redirect.html";
+ } else {
+ local %ENV;
+ $ENV{DYLD_INSERT_LIBRARIES} = "/usr/lib/libgmalloc.dylib" if $guardMalloc;
+ system "Tools/Scripts/run-safari", "-NSOpen", "$iExploderTestDirectory/redirect.html";
+ }
+}
+
+sub configureAndOpenHTTPDIfNeeded()
+{
+ return if $isHttpdOpen;
+ mkdir $iExploderTestDirectory;
+ my $httpdPath = getHTTPDPath();
+ my $webkitDirectory = getcwd();
+ my $testDirectory = $webkitDirectory . "/LayoutTests";
+ my $iExploderDirectory = $webkitDirectory . "/Tools/iExploder";
+
+ my $httpdConfig = getHTTPDConfigPathForTestDirectory($testDirectory);
+
+ my $documentRoot = "$iExploderDirectory/htdocs";
+ my $typesConfig = "$testDirectory/http/conf/mime.types";
+ my $sslCertificate = "$testDirectory/http/conf/webkit-httpd.pem";
+ my $listen = "127.0.0.1:$httpdPort";
+
+
+ my @args = (
+ "-f", "$httpdConfig",
+ "-C", "DocumentRoot \"$documentRoot\"",
+ "-C", "Listen $listen",
+ "-c", "TypesConfig \"$typesConfig\"",
+ "-c", "CustomLog \"$iExploderTestDirectory/access_log.txt\" common",
+ "-c", "ErrorLog \"$iExploderTestDirectory/error_log.txt\"",
+ "-c", "SSLCertificateFile \"$sslCertificate\"",
+ # Apache wouldn't run CGIs with permissions==700 otherwise
+ "-c", "User \"#$<\""
+ );
+
+ $isHttpdOpen = openHTTPD(@args);
+}
diff --git a/Tools/Scripts/run-javascriptcore-tests b/Tools/Scripts/run-javascriptcore-tests
new file mode 100755
index 0000000..9fcbb2e
--- /dev/null
+++ b/Tools/Scripts/run-javascriptcore-tests
@@ -0,0 +1,191 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005 Apple Computer, Inc. All rights reserved.
+# 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.
+
+# Script to run the WebKit Open Source Project JavaScriptCore tests (adapted from Mozilla).
+
+use strict;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+# determine configuration
+setConfiguration();
+my $configuration = configuration();
+
+my @testsToSkip = (
+ # Various ecma/Date tests sometimes fail on Windows (but not Mac) https://bugs.webkit.org/show_bug.cgi?id=25160
+ "ecma/Date/15.9.2.1.js",
+ "ecma/Date/15.9.2.2-1.js",
+ "ecma/Date/15.9.2.2-2.js",
+ "ecma/Date/15.9.2.2-3.js",
+ "ecma/Date/15.9.2.2-4.js",
+ "ecma/Date/15.9.2.2-5.js",
+ "ecma/Date/15.9.2.2-6.js",
+ # ecma_3/Date/15.9.5.7.js fails on Mac (but not Windows) https://bugs.webkit.org/show_bug.cgi?id=25161
+ "ecma_3/Date/15.9.5.7.js",
+);
+
+my $jsDriverArgs = "-L " . join(" ", @testsToSkip);
+my $root; # intentionally left undefined
+my $skipBuild = 0;
+my $showHelp = 0;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] [options to pass to build system]
+ --help Show this help message
+ --jsDriver-args= A string of arguments to pass to jsDriver.pl
+ --root= Path to pre-built root containing jsc
+EOF
+
+GetOptions(
+ 'j|jsDriver-args=s' => \$jsDriverArgs,
+ 'root=s' => \$root,
+ 'skip-build' => \$skipBuild,
+ 'help' => \$showHelp
+);
+
+# Assume any arguments left over from GetOptions are assumed to be build arguments
+my @buildArgs = @ARGV;
+
+# Arguments passed to --jsDriver-args (if any) are passed to jsDriver.pl
+my @jsArgs = split(" ", $jsDriverArgs);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+setConfigurationProductDir(Cwd::abs_path($root)) if (defined($root));
+
+if (!defined($root) && !$skipBuild) {
+ chdirWebKit();
+
+ push(@buildArgs, argumentsForConfiguration());
+
+ print "Running: build-jsc " . join(" ", @buildArgs) . "\n";
+ my $buildResult = system "perl", "Tools/Scripts/build-jsc", @buildArgs;
+ if ($buildResult) {
+ print STDERR "Compiling jsc failed!\n";
+ exit exitStatus($buildResult);
+ }
+}
+
+
+my $productDir = jscProductDir();
+$ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+setPathForRunningWebKitApp(\%ENV) if isCygwin();
+
+sub testapiPath($)
+{
+ my ($productDir) = @_;
+ my $jscName = "testapi";
+ $jscName .= "_debug" if configurationForVisualStudio() eq "Debug_All";
+ return "$productDir/$jscName";
+}
+
+#run api tests
+if (isAppleMacWebKit() || isAppleWinWebKit()) {
+ chdirWebKit();
+ chdir($productDir) or die;
+ my $path = testapiPath($productDir);
+ # Use an "indirect object" so that system() won't get confused if the path
+ # contains spaces (see perldoc -f exec).
+ my $testapiResult = system { $path } $path;
+ exit exitStatus($testapiResult) if $testapiResult;
+}
+
+# Find JavaScriptCore directory
+chdirWebKit();
+chdir("JavaScriptCore");
+chdir "tests/mozilla" or die;
+printf "Running: jsDriver.pl -e squirrelfish -s %s -f actual.html %s\n", jscPath($productDir), join(" ", @jsArgs);
+my $result = system "perl", "jsDriver.pl", "-e", "squirrelfish", "-s", jscPath($productDir), "-f", "actual.html", @jsArgs;
+exit exitStatus($result) if $result;
+
+my %failures;
+
+open EXPECTED, "expected.html" or die;
+while (<EXPECTED>) {
+ last if /failures reported\.$/;
+}
+while (<EXPECTED>) {
+ chomp;
+ $failures{$_} = 1;
+}
+close EXPECTED;
+
+my %newFailures;
+
+open ACTUAL, "actual.html" or die;
+while (<ACTUAL>) {
+ last if /failures reported\.$/;
+}
+while (<ACTUAL>) {
+ chomp;
+ if ($failures{$_}) {
+ delete $failures{$_};
+ } else {
+ $newFailures{$_} = 1;
+ }
+}
+close ACTUAL;
+
+my $numNewFailures = keys %newFailures;
+if ($numNewFailures) {
+ print "\n** Danger, Will Robinson! Danger! The following failures have been introduced:\n";
+ foreach my $failure (sort keys %newFailures) {
+ print "\t$failure\n";
+ }
+}
+
+my $numOldFailures = keys %failures;
+if ($numOldFailures) {
+ print "\nYou fixed the following test";
+ print "s" if $numOldFailures != 1;
+ print ":\n";
+ foreach my $failure (sort keys %failures) {
+ print "\t$failure\n";
+ }
+}
+
+print "\n";
+
+print "$numNewFailures regression";
+print "s" if $numNewFailures != 1;
+print " found.\n";
+
+print "$numOldFailures test";
+print "s" if $numOldFailures != 1;
+print " fixed.\n";
+
+print "OK.\n" if $numNewFailures == 0;
+exit(1) if $numNewFailures;
diff --git a/Tools/Scripts/run-jsc b/Tools/Scripts/run-jsc
new file mode 100755
index 0000000..e5341c1
--- /dev/null
+++ b/Tools/Scripts/run-jsc
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+
+# 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.
+
+# This script runs a list of scripts through jsc a specified number of times.
+
+use strict;
+use warnings;
+use File::Spec;
+use FindBin;
+use lib $FindBin::Bin;
+use Getopt::Long;
+use webkitdirs;
+
+my $usage = "Usage: run-jsc [--count run_count] [--verbose] shell_file [file2...]";
+
+my $count = 1;
+my $verbose = 0;
+GetOptions("count|c=i" => \$count,
+ "verbose|v" => \$verbose);
+die "$usage\n" if (@ARGV < 1);
+
+my $jsc = jscProductDir() . "/jsc @ARGV";
+$jsc .= " 2> " . File::Spec->devnull() unless $verbose;
+
+my $dyld = jscProductDir();
+
+$ENV{"DYLD_FRAMEWORK_PATH"} = $dyld;
+print STDERR "Running $count time(s): DYLD_FRAMEWORK_PATH=$dyld $jsc\n";
+while ($count--) {
+ if (system("$jsc") != 0) {
+ last;
+ }
+}
+
diff --git a/Tools/Scripts/run-launcher b/Tools/Scripts/run-launcher
new file mode 100755
index 0000000..414d4af
--- /dev/null
+++ b/Tools/Scripts/run-launcher
@@ -0,0 +1,84 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2007 Apple Computer, Inc. All rights reserved.
+# Copyright (C) 2007 Staikos Computing Services, Inc. <info@staikos.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.
+
+# Simplified "run" script for WebKit Open Source Project.
+
+use strict;
+use File::Spec::Functions qw/catdir/;
+use File::Temp qw/tempfile/;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+my $productDir = productDir();
+my $launcherPath = productDir();
+my @args = @ARGV;
+
+# Check to see that all the frameworks are built.
+checkFrameworks();
+
+# Set paths according to the build system used
+if (isQt()) {
+ my $libDir = catdir(productDir(), 'lib');
+ $launcherPath = catdir($launcherPath, "bin", "QtTestBrowser");
+
+ $ENV{QTWEBKIT_PLUGIN_PATH} = catdir($libDir, 'plugins');
+
+ print "Starting webkit launcher, running against the built WebKit in $libDir...\n";
+ if (isDarwin()) {
+ $ENV{DYLD_LIBRARY_PATH} = $ENV{DYLD_LIBRARY_PATH} ? "$libDir:$ENV{DYLD_LIBRARY_PATH}" : $libDir;
+ $ENV{DYLD_FRAMEWORK_PATH} = $ENV{DYLD_FRAMEWORK_PATH} ? "$libDir:$ENV{DYLD_FRAMEWORK_PATH}" : $libDir;
+ } else {
+ $ENV{LD_LIBRARY_PATH} = $ENV{LD_LIBRARY_PATH} ? "$libDir:$ENV{LD_LIBRARY_PATH}" : $libDir;
+ }
+} else {
+
+ if (isGtk()) {
+ $launcherPath = catdir($launcherPath, "Programs", "GtkLauncher");
+ }
+
+ if (isEfl()) {
+ $launcherPath = catdir($launcherPath, "Programs", "EWebLauncher");
+ }
+
+ if (isWx()) {
+ if (isDarwin()) {
+ $launcherPath = catdir($launcherPath, 'wxBrowser.app', 'Contents', 'MacOS', 'wxBrowser');
+ } else {
+ $ENV{LD_LIBRARY_PATH} = $ENV{LD_LIBRARY_PATH} ? "$productDir:$ENV{LD_LIBRARY_PATH}" : $productDir;
+ $launcherPath = catdir($launcherPath, 'wxBrowser');
+ }
+ }
+
+ print "Starting webkit launcher.\n";
+}
+
+exec $launcherPath, @args or die;
+
diff --git a/Tools/Scripts/run-leaks b/Tools/Scripts/run-leaks
new file mode 100755
index 0000000..9dc58de
--- /dev/null
+++ b/Tools/Scripts/run-leaks
@@ -0,0 +1,221 @@
+#!/usr/bin/perl
+
+# 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.
+
+# Script to run the Mac OS X leaks tool with more expressive '-exclude' lists.
+
+use strict;
+use warnings;
+
+use File::Basename;
+use Getopt::Long;
+
+sub runLeaks($);
+sub parseLeaksOutput(\@);
+sub removeMatchingRecords(\@$\@);
+sub reportError($);
+
+sub main()
+{
+ # Read options.
+ my $usage =
+ "Usage: " . basename($0) . " [options] pid | executable name\n" .
+ " --exclude-callstack regexp Exclude leaks whose call stacks match the regular expression 'regexp'.\n" .
+ " --exclude-type regexp Exclude leaks whose data types match the regular expression 'regexp'.\n" .
+ " --help Show this help message.\n";
+
+ my @callStacksToExclude = ();
+ my @typesToExclude = ();
+ my $help = 0;
+
+ my $getOptionsResult = GetOptions(
+ 'exclude-callstack:s' => \@callStacksToExclude,
+ 'exclude-type:s' => \@typesToExclude,
+ 'help' => \$help
+ );
+ my $pidOrExecutableName = $ARGV[0];
+
+ if (!$getOptionsResult || $help) {
+ print STDERR $usage;
+ return 1;
+ }
+
+ if (!$pidOrExecutableName) {
+ reportError("Missing argument: pid | executable.");
+ print STDERR $usage;
+ return 1;
+ }
+
+ # Run leaks tool.
+ my $leaksOutput = runLeaks($pidOrExecutableName);
+ if (!$leaksOutput) {
+ return 1;
+ }
+
+ my $leakList = parseLeaksOutput(@$leaksOutput);
+ if (!$leakList) {
+ return 1;
+ }
+
+ # Filter output.
+ my $leakCount = @$leakList;
+ removeMatchingRecords(@$leakList, "callStack", @callStacksToExclude);
+ removeMatchingRecords(@$leakList, "type", @typesToExclude);
+ my $excludeCount = $leakCount - @$leakList;
+
+ # Dump results.
+ print $leaksOutput->[0];
+ print $leaksOutput->[1];
+ foreach my $leak (@$leakList) {
+ print $leak->{"leaksOutput"};
+ }
+
+ if ($excludeCount) {
+ print "$excludeCount leaks excluded (not printed)\n";
+ }
+
+ return 0;
+}
+
+exit(main());
+
+# Returns the output of the leaks tool in list form.
+sub runLeaks($)
+{
+ my ($pidOrExecutableName) = @_;
+
+ my @leaksOutput = `leaks $pidOrExecutableName`;
+ if (!@leaksOutput) {
+ reportError("Error running leaks tool.");
+ return;
+ }
+
+ return \@leaksOutput;
+}
+
+# Returns a list of hash references with the keys { address, size, type, callStack, leaksOutput }
+sub parseLeaksOutput(\@)
+{
+ my ($leaksOutput) = @_;
+
+ # Format:
+ # Process 00000: 1234 nodes malloced for 1234 KB
+ # Process 00000: XX leaks for XXX total leaked bytes.
+ # Leak: 0x00000000 size=1234 [instance of 'blah']
+ # 0x00000000 0x00000000 0x00000000 0x00000000 a..d.e.e
+ # ...
+ # Call stack: leak_caller() | leak() | malloc
+ #
+ # We treat every line except for Process 00000: and Leak: as optional
+
+ # Newer versions of the leaks output have a header section at the top, with the first line describing the version of the output format.
+ # If we detect the new format is being used then we eat all of the header section so the output matches the format of older versions.
+ # FIXME: In the future we may wish to propagate this section through to our output.
+ if ($leaksOutput->[0] =~ /^leaks Report Version:/) {
+ while ($leaksOutput->[0] !~ /^Process /) {
+ shift @$leaksOutput;
+ }
+ }
+
+ my ($leakCount) = ($leaksOutput->[1] =~ /[[:blank:]]+([0-9]+)[[:blank:]]+leaks?/);
+ if (!defined($leakCount)) {
+ reportError("Could not parse leak count reported by leaks tool.");
+ return;
+ }
+
+ my @leakList = ();
+ for my $line (@$leaksOutput) {
+ next if $line =~ /^Process/;
+ next if $line =~ /^node buffer added/;
+
+ if ($line =~ /^Leak: /) {
+ my ($address) = ($line =~ /Leak: ([[:xdigit:]x]+)/);
+ if (!defined($address)) {
+ reportError("Could not parse Leak address.");
+ return;
+ }
+
+ my ($size) = ($line =~ /size=([[:digit:]]+)/);
+ if (!defined($size)) {
+ reportError("Could not parse Leak size.");
+ return;
+ }
+
+ my ($type) = ($line =~ /'([^']+)'/); #'
+ if (!defined($type)) {
+ $type = ""; # The leaks tool sometimes omits the type.
+ }
+
+ my %leak = (
+ "address" => $address,
+ "size" => $size,
+ "type" => $type,
+ "callStack" => "", # The leaks tool sometimes omits the call stack.
+ "leaksOutput" => $line
+ );
+ push(@leakList, \%leak);
+ } else {
+ $leakList[$#leakList]->{"leaksOutput"} .= $line;
+ if ($line =~ /Call stack:/) {
+ $leakList[$#leakList]->{"callStack"} = $line;
+ }
+ }
+ }
+
+ if (@leakList != $leakCount) {
+ my $parsedLeakCount = @leakList;
+ reportError("Parsed leak count($parsedLeakCount) does not match leak count reported by leaks tool($leakCount).");
+ return;
+ }
+
+ return \@leakList;
+}
+
+sub removeMatchingRecords(\@$\@)
+{
+ my ($recordList, $key, $regexpList) = @_;
+
+ RECORD: for (my $i = 0; $i < @$recordList;) {
+ my $record = $recordList->[$i];
+
+ foreach my $regexp (@$regexpList) {
+ if ($record->{$key} =~ $regexp) {
+ splice(@$recordList, $i, 1);
+ next RECORD;
+ }
+ }
+
+ $i++;
+ }
+}
+
+sub reportError($)
+{
+ my ($errorMessage) = @_;
+
+ print STDERR basename($0) . ": $errorMessage\n";
+}
diff --git a/Tools/Scripts/run-mangleme-tests b/Tools/Scripts/run-mangleme-tests
new file mode 100755
index 0000000..10196ef
--- /dev/null
+++ b/Tools/Scripts/run-mangleme-tests
@@ -0,0 +1,176 @@
+#!/usr/bin/perl
+
+# 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.
+
+# A script to semi-automatically run mangleme tests.
+
+use strict;
+use warnings;
+
+use Cwd;
+use File::Spec;
+use FindBin;
+use Getopt::Long;
+use IPC::Open2;
+
+use lib $FindBin::Bin;
+use webkitdirs;
+
+sub openHTTPDIfNeeded();
+sub closeHTTPD();
+sub runSafariWithMangleme();
+
+# Argument handling
+my $guardMalloc = '';
+my $httpdPort = 8000;
+my $downloadTest;
+
+GetOptions(
+ 'guard-malloc|g' => \$guardMalloc,
+ 'get=s' => \$downloadTest,
+ 'port=i' => \$httpdPort
+);
+
+
+setConfiguration();
+my $productDir = productDir();
+
+chdirWebKit();
+
+checkFrameworks();
+
+mkdir "WebKitBuild/mangleme";
+(system "/usr/bin/make", "-C", "Tools/mangleme") == 0 or die;
+
+my $httpdOpen = 0;
+openHTTPDIfNeeded();
+
+if ($downloadTest) {
+ system "/usr/bin/curl -o ~/Desktop/mangleme$downloadTest.html http://127.0.0.1:$httpdPort/remangle.cgi?$downloadTest";
+ print "Saved the test as mangleme$downloadTest.html on the desktop\n";
+} else {
+ runSafariWithMangleme();
+ print "Last generated tests:\n";
+ system "grep 'Mangle attempt' /tmp/WebKit/error_log.txt | tail -n -5 | awk ' {print \$4}'";
+}
+
+closeHTTPD();
+
+
+sub runSafariWithMangleme()
+{
+ my $redirectTo;
+ if (@ARGV) {
+ $redirectTo = "http://127.0.0.1:$httpdPort/remangle.cgi?$ARGV[0]";
+ } else {
+ $redirectTo = "http://127.0.0.1:$httpdPort/mangle.cgi";
+ }
+
+ open REDIRECT_HTML, ">", "/tmp/WebKit/redirect.html" or die;
+ print REDIRECT_HTML "<html>\n";
+ print REDIRECT_HTML " <head>\n";
+ print REDIRECT_HTML " <meta http-equiv=\"refresh\" content=\"1;URL=$redirectTo\" />\n";
+ print REDIRECT_HTML " <script type=\"text/javascript\">\n";
+ print REDIRECT_HTML " document.location = \"$redirectTo\";\n";
+ print REDIRECT_HTML " </script>\n";
+ print REDIRECT_HTML " </head>\n";
+ print REDIRECT_HTML " <body>\n";
+ print REDIRECT_HTML " </body>\n";
+ print REDIRECT_HTML "</html>\n";
+ close REDIRECT_HTML;
+
+ local %ENV;
+ $ENV{DYLD_INSERT_LIBRARIES} = "/usr/lib/libgmalloc.dylib" if $guardMalloc;
+ system "Tools/Scripts/run-safari", "-NSOpen", "/tmp/WebKit/redirect.html";
+}
+
+sub openHTTPDIfNeeded()
+{
+ return if $httpdOpen;
+
+ mkdir "/tmp/WebKit";
+
+ if (-f "/tmp/WebKit/httpd.pid") {
+ my $oldPid = `cat /tmp/WebKit/httpd.pid`;
+ chomp $oldPid;
+ if (0 != kill 0, $oldPid) {
+ print "\nhttpd is already running: pid $oldPid, killing...\n";
+ kill 15, $oldPid;
+
+ my $retryCount = 20;
+ while ((0 != kill 0, $oldPid) && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+
+ die "Timed out waiting for httpd to quit" unless $retryCount;
+ }
+ }
+
+ my $testDirectory = getcwd() . "/LayoutTests";
+ my $manglemeDirectory = getcwd() . "/WebKitBuild/mangleme";
+ my $httpdPath = "/usr/sbin/httpd";
+ my $httpdConfig = "$testDirectory/http/conf/httpd.conf";
+ $httpdConfig = "$testDirectory/http/conf/apache2-httpd.conf" if `$httpdPath -v` =~ m|Apache/2|;
+ my $documentRoot = "$manglemeDirectory";
+ my $typesConfig = "$testDirectory/http/conf/mime.types";
+ my $sslCertificate = "$testDirectory/http/conf/webkit-httpd.pem";
+ my $listen = "127.0.0.1:$httpdPort";
+
+ open2(\*HTTPDIN, \*HTTPDOUT, $httpdPath,
+ "-f", "$httpdConfig",
+ "-C", "DocumentRoot \"$documentRoot\"",
+ "-C", "Listen $listen",
+ "-c", "TypesConfig \"$typesConfig\"",
+ "-c", "CustomLog \"/tmp/WebKit/access_log.txt\" common",
+ "-c", "ErrorLog \"/tmp/WebKit/error_log.txt\"",
+ "-c", "SSLCertificateFile \"$sslCertificate\"",
+ # Apache wouldn't run CGIs with permissions==700 otherwise
+ "-c", "User \"#$<\"");
+
+ my $retryCount = 20;
+ while (system("/usr/bin/curl -q --silent --stderr - --output " . File::Spec->devnull() . " $listen") && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+
+ die "Timed out waiting for httpd to start" unless $retryCount;
+
+ $httpdOpen = 1;
+}
+
+sub closeHTTPD()
+{
+ return if !$httpdOpen;
+
+ close HTTPDIN;
+ close HTTPDOUT;
+
+ kill 15, `cat /tmp/WebKit/httpd.pid` if -f "/tmp/WebKit/httpd.pid";
+
+ $httpdOpen = 0;
+}
diff --git a/Tools/Scripts/run-minibrowser b/Tools/Scripts/run-minibrowser
new file mode 100755
index 0000000..c2fd412
--- /dev/null
+++ b/Tools/Scripts/run-minibrowser
@@ -0,0 +1,38 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Simplified "run" script for launching the WebKit2 MiniBrowser.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+
+exit exitStatus(runMiniBrowser());
diff --git a/Tools/Scripts/run-pageloadtest b/Tools/Scripts/run-pageloadtest
new file mode 100755
index 0000000..ad6daa1
--- /dev/null
+++ b/Tools/Scripts/run-pageloadtest
@@ -0,0 +1,92 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2006 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.
+
+# Script to run the WebKit Open Source Project page load tests (PLTs).
+
+# Run all the tests passed in on the command line.
+
+use strict;
+use warnings;
+
+use File::Basename;
+use File::Spec;
+use FindBin;
+use Getopt::Long;
+
+use lib $FindBin::Bin;
+use webkitdirs;
+
+# Argument handling
+my $testName = 'svg';
+my $showHelp = 0;
+
+my $usage =
+ "Usage: " . basename($0) . "[options] testName\n" .
+ " --help Show this help message\n";
+
+my $getOptionsResult = GetOptions('help' => \$showHelp);
+
+if (!$getOptionsResult || $showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+$testName = shift @ARGV if (@ARGV);
+
+my $safariExecutablePath = safariPath();
+my $safariResourcePath = File::Spec->catdir(dirname(dirname($safariExecutablePath)), "Resources");
+
+# Check to see that all the frameworks are built.
+checkFrameworks();
+
+chdirWebKit();
+
+if ($testName eq 'svg') {
+ my $suiteFile = "PageLoadTests/$testName/$testName.pltsuite";
+ my $webkitPath = sourceDir();
+ `cat "$suiteFile" | perl -pe 's|WEBKIT_PATH|$webkitPath|' > $safariResourcePath/$testName.pltsuite`
+}
+
+die "Please copy ${testName}.pltsuite to ${safariResourcePath}/${testName}.pltsuite"
+ if (! -f "${safariResourcePath}/${testName}.pltsuite");
+
+setConfiguration();
+
+my $productDir = productDir();
+
+# Set up DYLD_FRAMEWORK_PATH to point to the product directory.
+print "Starting Safari with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+$ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+$ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
+
+my @testCommands = ('activate');
+# Autovicki would clear history, we skip that here as this is likely an active user account
+@testCommands = (@testCommands, ("run $testName", 'emptyCache', 'wait 30'));
+@testCommands = (@testCommands, (("run $testName", 'wait 10') x 3));
+my $testCommandsString = join('; ', @testCommands);
+exec $safariExecutablePath, '--test-commands', $testCommandsString or die;
diff --git a/Tools/Scripts/run-qtwebkit-tests b/Tools/Scripts/run-qtwebkit-tests
new file mode 100644
index 0000000..373de0a
--- /dev/null
+++ b/Tools/Scripts/run-qtwebkit-tests
@@ -0,0 +1,358 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+#Copyright (C) 2010 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.
+
+from __future__ import with_statement
+
+import sys
+import os
+import os.path
+import re
+import logging
+from subprocess import Popen, PIPE, STDOUT
+from optparse import OptionParser
+
+
+class Log(object):
+ def __init__(self, name):
+ self._log = logging.getLogger(name)
+ self.debug = self._log.debug
+ self.warn = self._log.warn
+ self.error = self._log.error
+ self.exception = self._log.exception
+ self.info = self._log.info
+
+
+class Options(Log):
+ """ Option manager. It parses and checks script's parameters, sets an internal variable. """
+
+ def __init__(self, args):
+ Log.__init__(self, "Options")
+ log = self._log
+ opt = OptionParser("%prog [options] PathToSearch.\nTry -h or --help.")
+ opt.add_option("-j", "--parallel-level", action="store", type="int",
+ dest="parallel_level", default=None,
+ help="Number of parallel processes executing the Qt's tests. Default: cpu count.")
+ opt.add_option("-v", "--verbose", action="store", type="int",
+ dest="verbose", default=2,
+ help="Verbose level (0 - quiet, 1 - errors only, 2 - infos and warnings, 3 - debug information). Default: %default.")
+ opt.add_option("", "--tests-options", action="store", type="string",
+ dest="tests_options", default="",
+ help="Parameters passed to Qt's tests (for example '-eventdelay 123').")
+ opt.add_option("-o", "--output-file", action="store", type="string",
+ dest="output_file", default="/tmp/qtwebkittests.html",
+ help="File where results will be stored. The file will be overwritten. Default: %default.")
+ opt.add_option("-b", "--browser", action="store", dest="browser",
+ default="xdg-open",
+ help="Browser in which results will be opened. Default %default.")
+ opt.add_option("", "--do-not-open-results", action="store_false",
+ dest="open_results", default=True,
+ help="The results shouldn't pop-up in a browser automatically")
+ opt.add_option("-d", "--developer-mode", action="store_true",
+ dest="developer", default=False,
+ help="Special mode for debugging. In general it simulates human behavior, running all autotests. In the mode everything is executed synchronously, no html output will be generated, no changes or transformation will be applied to stderr or stdout. In this mode options; parallel-level, output-file, browser and do-not-open-results will be ignored.")
+
+ self._o, self._a = opt.parse_args(args)
+ verbose = self._o.verbose
+ if verbose == 0:
+ logging.basicConfig(level=logging.CRITICAL,)
+ elif verbose == 1:
+ logging.basicConfig(level=logging.ERROR,)
+ elif verbose == 2:
+ logging.basicConfig(level=logging.INFO,)
+ elif verbose == 3:
+ logging.basicConfig(level=logging.DEBUG,)
+ else:
+ logging.basicConfig(level=logging.INFO,)
+ log.warn("Bad verbose level, switching to default.")
+ try:
+ if not os.path.exists(self._a[0]):
+ raise Exception("Given path doesn't exist.")
+ if len(self._a) > 1:
+ raise IndexError("Only one directory could be provided.")
+ self._o.path = self._a[0]
+ except IndexError:
+ log.error("Bad usage. Please try -h or --help.")
+ sys.exit(1)
+ except Exception:
+ log.error("Path '%s' doesn't exist", self._a[0])
+ sys.exit(2)
+ if self._o.developer:
+ if not self._o.parallel_level is None:
+ log.warn("Developer mode sets parallel-level option to one.")
+ self._o.parallel_level = 1
+ self._o.open_results = False
+
+ def __getattr__(self, attr):
+ """ Maps all options properties into this object (remove one level of indirection). """
+ return getattr(self._o, attr)
+
+
+def run_test(args):
+ """ Runs one given test.
+ args should contain a tuple with 3 elements;
+ TestSuiteResult containing full file name of an autotest executable.
+ str with options that should be passed to the autotest executable
+ bool if true then the stdout will be buffered and separated from the stderr, if it is false
+ then the stdout and the stderr will be merged together and left unbuffered (the TestSuiteResult output will be None).
+ """
+ log = logging.getLogger("Exec")
+ test_suite, options, buffered = args
+ try:
+ log.info("Running... %s", test_suite.test_file_name())
+ if buffered:
+ tst = Popen(test_suite.test_file_name() + options, stdout=PIPE, stderr=None, shell=True)
+ else:
+ tst = Popen(test_suite.test_file_name() + options, stdout=None, stderr=STDOUT, shell=True)
+ except OSError, e:
+ log.exception("Can't open an autotest file: '%s'. Skipping the test...", e.filename)
+ else:
+ test_suite.set_output(tst.communicate()[0]) # takes stdout only, in developer mode it would be None.
+ log.info("Finished %s", test_suite.test_file_name())
+ return test_suite
+
+
+class TestSuiteResult(object):
+ """ Keeps information about a test. """
+
+ def __init__(self):
+ self._output = None
+ self._test_file_name = None
+
+ def set_output(self, xml):
+ if xml:
+ self._output = xml.strip()
+
+ def output(self):
+ return self._output
+
+ def set_test_file_name(self, file_name):
+ self._test_file_name = file_name
+
+ def test_file_name(self):
+ return self._test_file_name
+
+
+class Main(Log):
+ """ The main script. All real work is done in run() method. """
+
+ def __init__(self, options):
+ Log.__init__(self, "Main")
+ self._options = options
+ if options.parallel_level > 1 or options.parallel_level is None:
+ try:
+ from multiprocessing import Pool
+ except ImportError:
+ self.warn("Import Error: the multiprocessing module couldn't be loaded (may be lack of python-multiprocessing package?). The Qt autotests will be executed one by one.")
+ options.parallel_level = 1
+ if options.parallel_level == 1:
+
+ class Pool(object):
+ """ A hack, created to avoid problems with multiprocessing module, this class is single thread replacement for the multiprocessing.Pool class. """
+ def __init__(self, processes):
+ pass
+
+ def imap_unordered(self, func, files):
+ return map(func, files)
+
+ def map(self, func, files):
+ return map(func, files)
+
+ self._Pool = Pool
+
+ def run(self):
+ """ Find && execute && publish results of all test. "All in one" function. """
+ self.debug("Searching executables...")
+ tests_executables = self.find_tests_paths(self._options.path)
+ self.debug("Found: %s", len(tests_executables))
+ self.debug("Executing tests...")
+ results = self.run_tests(tests_executables)
+ if not self._options.developer:
+ self.debug("Transforming...")
+ transformed_results = self.transform(results)
+ self.debug("Publishing...")
+ self.announce_results(transformed_results)
+
+ def find_tests_paths(self, path):
+ """ Finds all tests executables inside the given path. """
+ executables = []
+ for root, dirs, files in os.walk(path):
+ # Check only for a file that name starts from 'tst_' and that we can execute.
+ filtered_path = filter(lambda w: w.startswith('tst_') and os.access(os.path.join(root, w), os.X_OK), files)
+ filtered_path = map(lambda w: os.path.join(root, w), filtered_path)
+ for file_name in filtered_path:
+ r = TestSuiteResult()
+ r.set_test_file_name(file_name)
+ executables.append(r)
+ return executables
+
+ def run_tests(self, files):
+ """ Executes given files by using a pool of workers. """
+ workers = self._Pool(processes=self._options.parallel_level)
+ # to each file add options.
+ self.debug("Using %s the workers pool, number of workers %i", repr(workers), self._options.parallel_level)
+ package = map(lambda w: [w, self._options.tests_options, not self._options.developer], files)
+ self.debug("Generated packages for workers: %s", repr(package))
+ results = workers.map(run_test, package) # Collects results.
+ return results
+
+ def transform(self, results):
+ """ Transforms list of the results to specialized versions. """
+ stdout = self.convert_to_stdout(results)
+ html = self.convert_to_html(results)
+ return {"stdout": stdout, "html": html}
+
+ def announce_results(self, results):
+ """ Shows the results. """
+ self.announce_results_stdout(results['stdout'])
+ self.announce_results_html(results['html'])
+
+ def announce_results_stdout(self, results):
+ """ Show the results by printing to the stdout."""
+ print(results)
+
+ def announce_results_html(self, results):
+ """ Shows the result by creating a html file and calling a web browser to render it. """
+ with file(self._options.output_file, 'w') as f:
+ f.write(results)
+ if self._options.open_results:
+ Popen(self._options.browser + " " + self._options.output_file, stdout=None, stderr=None, shell=True)
+
+ def convert_to_stdout(self, results):
+ """ Converts results, that they could be nicely presented in the stdout. """
+ # Join all results into one piece.
+ txt = "\n\n".join(map(lambda w: w.output(), results))
+ # Find total count of failed, skipped and passed tests.
+ totals = re.findall(r"([0-9]+) passed, ([0-9]+) failed, ([0-9]+) skipped", txt)
+ totals = reduce(lambda x, y: (int(x[0]) + int(y[0]), int(x[1]) + int(y[1]), int(x[2]) + int(y[2])), totals)
+ totals = map(str, totals)
+ totals = totals[0] + " passed, " + totals[1] + " failed, " + totals[2] + " skipped"
+ # Add a summary.
+ txt += '\n\n\n' + '*' * 70
+ txt += "\n**" + ("TOTALS: " + totals).center(66) + '**'
+ txt += '\n' + '*' * 70 + '\n'
+ return txt
+
+ def convert_to_html(self, results):
+ """ Converts results, that they could showed as a html page. """
+ # Join results into one piece.
+ txt = "\n\n".join(map(lambda w: w.output(), results))
+ txt = txt.replace('&', '&amp;').replace('<', "&lt;").replace('>', "&gt;")
+ # Add a color and a style.
+ txt = re.sub(r"([* ]+(Finished)[ a-z_A-Z0-9]+[*]+)",
+ lambda w: r"",
+ txt)
+ txt = re.sub(r"([*]+[ a-z_A-Z0-9]+[*]+)",
+ lambda w: "<case class='good'><br><br><b>" + w.group(0) + r"</b></case>",
+ txt)
+ txt = re.sub(r"(Config: Using QTest library)((.)+)",
+ lambda w: "\n<case class='good'><br><i>" + w.group(0) + r"</i> ",
+ txt)
+ txt = re.sub(r"\n(PASS)((.)+)",
+ lambda w: "</case>\n<case class='good'><br><status class='pass'>" + w.group(1) + r"</status>" + w.group(2),
+ txt)
+ txt = re.sub(r"\n(FAIL!)((.)+)",
+ lambda w: "</case>\n<case class='bad'><br><status class='fail'>" + w.group(1) + r"</status>" + w.group(2),
+ txt)
+ txt = re.sub(r"\n(XPASS)((.)+)",
+ lambda w: "</case>\n<case class='bad'><br><status class='xpass'>" + w.group(1) + r"</status>" + w.group(2),
+ txt)
+ txt = re.sub(r"\n(XFAIL)((.)+)",
+ lambda w: "</case>\n<case class='good'><br><status class='xfail'>" + w.group(1) + r"</status>" + w.group(2),
+ txt)
+ txt = re.sub(r"\n(SKIP)((.)+)",
+ lambda w: "</case>\n<case class='good'><br><status class='xfail'>" + w.group(1) + r"</status>" + w.group(2),
+ txt)
+ txt = re.sub(r"\n(QWARN)((.)+)",
+ lambda w: "</case>\n<case class='bad'><br><status class='warn'>" + w.group(1) + r"</status>" + w.group(2),
+ txt)
+ txt = re.sub(r"\n(RESULT)((.)+)",
+ lambda w: "</case>\n<case class='good'><br><status class='benchmark'>" + w.group(1) + r"</status>" + w.group(2),
+ txt)
+ txt = re.sub(r"\n(QFATAL)((.)+)",
+ lambda w: "</case>\n<case class='bad'><br><status class='crash'>" + w.group(1) + r"</status>" + w.group(2),
+ txt)
+ txt = re.sub(r"\n(Totals:)([0-9', a-z]*)",
+ lambda w: "</case>\n<case class='good'><br><b>" + w.group(1) + r"</b>" + w.group(2) + "</case>",
+ txt)
+ # Find total count of failed, skipped and passed tests.
+ totals = re.findall(r"([0-9]+) passed, ([0-9]+) failed, ([0-9]+) skipped", txt)
+ totals = reduce(lambda x, y: (int(x[0]) + int(y[0]), int(x[1]) + int(y[1]), int(x[2]) + int(y[2])), totals)
+ totals = map(str, totals)
+ totals = totals[0] + " passed, " + totals[1] + " failed, " + totals[2] + " skipped."
+ # Create a header of the html source.
+ txt = """
+ <html>
+ <head>
+ <script>
+ function init() {
+ // Try to find the right styleSheet (this document could be embedded in an other html doc)
+ for (i = document.styleSheets.length - 1; i >= 0; --i) {
+ if (document.styleSheets[i].cssRules[0].selectorText == "case.good") {
+ resultStyleSheet = i;
+ return;
+ }
+ }
+ // The styleSheet hasn't been found, but it should be the last one.
+ resultStyleSheet = document.styleSheets.length - 1;
+ }
+
+ function hide() {
+ document.styleSheets[resultStyleSheet].cssRules[0].style.display='none';
+ }
+
+ function show() {
+ document.styleSheets[resultStyleSheet].cssRules[0].style.display='';
+ }
+
+ </script>
+ <style type="text/css">
+ case.good {color:black}
+ case.bad {color:black}
+ status.pass {color:green}
+ status.crash {color:red}
+ status.fail {color:red}
+ status.xpass {color:663300}
+ status.xfail {color:004500}
+ status.benchmark {color:000088}
+ status.warn {color:orange}
+ status.crash {color:red; text-decoration:blink; background-color:black}
+ </style>
+ </head>
+ <body onload="init()">
+ <center>
+ <h1>Qt's autotests results</h1>%(totals)s<br>
+ <hr>
+ <form>
+ <input type="button" value="Show failures only" onclick="hide()"/>
+ &nbsp;
+ <input type="button" value="Show all" onclick="show()"/>
+ </form>
+ </center>
+ <hr>
+ %(results)s
+ </body>
+ </html>""" % {"totals": totals, "results": txt}
+ return txt
+
+
+if __name__ == '__main__':
+ options = Options(sys.argv[1:])
+ main = Main(options)
+ main.run()
diff --git a/Tools/Scripts/run-safari b/Tools/Scripts/run-safari
new file mode 100755
index 0000000..d850a4a
--- /dev/null
+++ b/Tools/Scripts/run-safari
@@ -0,0 +1,41 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Simplified "run" script for WebKit Open Source Project.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+
+# Check to see that all the frameworks are built.
+checkFrameworks();
+
+exit exitStatus(runSafari());
diff --git a/Tools/Scripts/run-sunspider b/Tools/Scripts/run-sunspider
new file mode 100755
index 0000000..15894b0
--- /dev/null
+++ b/Tools/Scripts/run-sunspider
@@ -0,0 +1,129 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2007 Apple Inc. All rights reserved.
+# 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.
+#
+# 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.
+
+use strict;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+# determine configuration, but default to "Release" instead of last-used configuration
+setConfiguration("Release");
+setConfiguration();
+my $configuration = configuration();
+
+my $root;
+my $testRuns = 10; # This number may be different from what sunspider defaults to (that's OK)
+my $runShark = 0;
+my $runShark20 = 0;
+my $runSharkCache = 0;
+my $suite = "";
+my $ubench = 0;
+my $v8 = 0;
+my $parseonly = 0;
+my $setBaseline = 0;
+my $showHelp = 0;
+my $testsPattern;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] [options to pass to build system]
+ --help Show this help message
+ --set-baseline Set baseline for future comparisons
+ --root Path to root tools build
+ --runs Number of times to run tests (default: $testRuns)
+ --tests Only run tests matching provided pattern
+ --shark Sample with the Mac OS X "Shark" performance testing tool (implies --runs=1)
+ --shark20 Like --shark, but with a 20 microsecond sampling interval
+ --shark-cache Like --shark, but performs a L2 cache-miss sample instead of time sample
+ --suite Select a specific benchmark suite. The default is sunspider-0.9.1
+ --ubench Use microbenchmark suite instead of regular tests. Same as --suite=ubench
+ --v8-suite Use the V8 benchmark suite. Same as --suite=v8-v4
+ --parse-only Use the parse-only benchmark suite. Same as --suite=parse-only
+EOF
+
+GetOptions('root=s' => sub { my ($x, $value) = @_; $root = $value; setConfigurationProductDir(Cwd::abs_path($root)); },
+ 'runs=i' => \$testRuns,
+ 'set-baseline' => \$setBaseline,
+ 'shark' => \$runShark,
+ 'shark20' => \$runShark20,
+ 'shark-cache' => \$runSharkCache,
+ 'suite=s' => \$suite,
+ 'ubench' => \$ubench,
+ 'v8' => \$v8,
+ 'parse-only' => \$parseonly,
+ 'tests=s' => \$testsPattern,
+ 'help' => \$showHelp);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+sub buildJSC
+{
+ if (!defined($root)){
+ push(@ARGV, "--" . $configuration);
+
+ chdirWebKit();
+ my $buildResult = system currentPerlPath(), "Tools/Scripts/build-jsc", @ARGV;
+ if ($buildResult) {
+ print STDERR "Compiling jsc failed!\n";
+ exit exitStatus($buildResult);
+ }
+ }
+}
+
+sub setupEnvironmentForExecution($)
+{
+ my ($productDir) = @_;
+ print "Starting sunspider with DYLD_FRAMEWORK_PATH set to point to built JavaScriptCore in $productDir.\n";
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ # FIXME: Other platforms may wish to augment this method to use LD_LIBRARY_PATH, etc.
+}
+
+buildJSC();
+
+chdirWebKit();
+chdir("SunSpider");
+
+my $productDir = jscProductDir();
+
+setupEnvironmentForExecution($productDir);
+my @args = ("--shell", jscPath($productDir), "--runs", $testRuns);
+# This code could be removed if we chose to pass extra args to sunspider instead of Xcode
+push @args, "--set-baseline" if $setBaseline;
+push @args, "--shark" if $runShark;
+push @args, "--shark20" if $runShark20;
+push @args, "--shark-cache" if $runSharkCache;
+push @args, "--suite=${suite}" if $suite;
+push @args, "--ubench" if $ubench;
+push @args, "--v8" if $v8;
+push @args, "--parse-only" if $parseonly;
+push @args, "--tests", $testsPattern if $testsPattern;
+
+exec currentPerlPath(), "./sunspider", @args;
diff --git a/Tools/Scripts/run-test-runner b/Tools/Scripts/run-test-runner
new file mode 100755
index 0000000..98fa3b6
--- /dev/null
+++ b/Tools/Scripts/run-test-runner
@@ -0,0 +1,35 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Simplified "run" script for launching the WebKit2 WebKitTestRunner.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+
+exit exitStatus(runWebKitTestRunner());
diff --git a/Tools/Scripts/run-test-webkit-api b/Tools/Scripts/run-test-webkit-api
new file mode 100755
index 0000000..dfd85d5
--- /dev/null
+++ b/Tools/Scripts/run-test-webkit-api
@@ -0,0 +1,38 @@
+#!/usr/bin/perl -w
+
+# 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.
+# 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.
+
+# Simplified "run" script for launching the WebKit2 estWebKitAPI.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+
+exit exitStatus(runTestWebKitAPI());
diff --git a/Tools/Scripts/run-webkit-app b/Tools/Scripts/run-webkit-app
new file mode 100755
index 0000000..452c44c
--- /dev/null
+++ b/Tools/Scripts/run-webkit-app
@@ -0,0 +1,50 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Simplified "run" script for WebKit Open Source Project.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+setConfiguration();
+my $productDir = productDir();
+
+die "Did not specify an application to open (e.g. run-webkit-app AppName).\n" unless length($ARGV[0]) > 0;
+
+# Check to see that all the frameworks are built.
+checkFrameworks();
+
+# Set up DYLD_FRAMEWORK_PATH to point to the product directory.
+print "Start $ARGV[0] with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+$ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+$ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
+
+unshift(@ARGV, "-a");
+exec "open", @ARGV;
diff --git a/Tools/Scripts/run-webkit-httpd b/Tools/Scripts/run-webkit-httpd
new file mode 100755
index 0000000..9ea2551
--- /dev/null
+++ b/Tools/Scripts/run-webkit-httpd
@@ -0,0 +1,96 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2005, 2006, 2007 Apple 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 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.
+
+# Script to run Apache with the same configuration as used in http layout tests.
+
+use strict;
+use warnings;
+
+use Cwd;
+use File::Path;
+use File::Basename;
+use Getopt::Long;
+use FindBin;
+
+use lib $FindBin::Bin;
+use webkitperl::httpd;
+use webkitdirs;
+
+# FIXME: Dynamic HTTP-port configuration in this file is wrong. The various
+# apache config files in LayoutTests/http/config govern the port numbers.
+# Dynamic configuration as-written will also cause random failures in
+# an IPv6 environment. See https://bugs.webkit.org/show_bug.cgi?id=37104.
+# Argument handling
+my $httpdPort = 8000;
+my $allInterfaces = 0;
+my $showHelp;
+
+my $result = GetOptions(
+ 'all-interfaces|a' => \$allInterfaces,
+ 'help|h' => \$showHelp,
+ 'port=i' => \$httpdPort,
+);
+
+if (!$result || @ARGV || $showHelp) {
+ print "Usage: " . basename($0) . " [options]\n";
+ print " -a|--all-interfaces Bind to all interfaces\n";
+ print " -h|--help Show this help message\n";
+ print " -p|--port NNNN Bind to port NNNN\n";
+ exit 1;
+}
+
+setConfiguration();
+my $productDir = productDir();
+chdirWebKit();
+my $testDirectory = File::Spec->catfile(getcwd(), "LayoutTests");
+my $listen = "127.0.0.1:$httpdPort";
+$listen = "$httpdPort" if ($allInterfaces);
+
+if ($allInterfaces) {
+ print "Starting httpd on port $httpdPort (all interfaces)...\n";
+} else {
+ print "Starting httpd on <http://$listen/>...\n";
+}
+setShouldWaitForUserInterrupt();
+print "Press Ctrl+C to stop it.\n\n";
+
+my @args = (
+ "-C", "Listen $listen",
+ "-c", "CustomLog |/usr/bin/tee common",
+ "-c", "ErrorLog |/usr/bin/tee",
+ # Run in single-process mode, do not detach from the controlling terminal.
+ "-X",
+ # Disable Keep-Alive support. Makes testing in multiple browsers easier (no need to wait
+ # for another browser's connection to expire).
+ "-c", "KeepAlive 0"
+);
+
+my @defaultArgs = getDefaultConfigForTestDirectory($testDirectory);
+@args = (@defaultArgs, @args);
+openHTTPD(@args);
diff --git a/Tools/Scripts/run-webkit-nightly.cmd b/Tools/Scripts/run-webkit-nightly.cmd
new file mode 100755
index 0000000..924178a
--- /dev/null
+++ b/Tools/Scripts/run-webkit-nightly.cmd
@@ -0,0 +1,10 @@
+@echo off
+set script=%TMP%\run-webkit-nightly2.cmd
+set vsvars=%VS80COMNTOOLS%\vsvars32.bat
+if exist "%vsvars%" (
+ copy "%vsvars%" "%script%"
+) else (
+ del "%script%"
+)
+FindSafari.exe %1 /printSafariLauncher >> "%script%"
+call "%script%"
diff --git a/Tools/Scripts/run-webkit-tests b/Tools/Scripts/run-webkit-tests
new file mode 100755
index 0000000..6b530e1
--- /dev/null
+++ b/Tools/Scripts/run-webkit-tests
@@ -0,0 +1,84 @@
+#!/usr/bin/perl
+# 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 is a temporary hack.
+# It will be removed as soon as all platforms are are ready to move to
+# new-run-webkit-tests and we can then update the buildbots to explicitly
+# call old-run-webkit-tests for any platforms which will never support
+# a Python run-webkit-tests.
+
+# This is intentionally written in Perl to guarantee support on
+# the same set of platforms as old-run-webkit-tests currently supports.
+# The buildbot master.cfg also currently passes run-webkit-tests to
+# perl directly instead of executing it in a shell.
+
+use strict;
+use warnings;
+
+use File::Spec;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+sub runningOnBuildBot()
+{
+ # This is a hack to detect if we're running on the buildbot so we can
+ # pass --verbose to new-run-webkit-tests. This will be removed when we
+ # update the buildbot config to call new-run-webkit-tests explicitly.
+ my %isBuildBotUser = ("apple" => 1, "buildbot" => 1);
+ return $isBuildBotUser{$ENV{"USER"}};
+}
+
+sub useNewRunWebKitTests()
+{
+ # Change this check to control which platforms use
+ # new-run-webkit-tests by default.
+ # Example: return runningOnBuildBot() && isLeopard();
+ # would enable new-run-webkit-tests on only the leopard buildbots.
+ return 0;
+}
+
+my $harnessName = "old-run-webkit-tests";
+
+if (useNewRunWebKitTests()) {
+ $harnessName = "new-run-webkit-tests";
+ if (runningOnBuildBot()) {
+ push(@ARGV, "--verbose");
+ # old-run-webkit-tests treats --results-directory as $CWD relative.
+ # new-run-webkit-tests treats --results-directory as build directory relative.
+ # Override the passed in --results-directory by appending a new one
+ # (later arguments override earlier ones in Python's optparse).
+ push(@ARGV, "--results-directory");
+ # The buildbot always uses $SRCDIR/layout-test-results, hardcode it:
+ push(@ARGV, sourceDir() . "/layout-test-results");
+ }
+}
+
+my $harnessPath = File::Spec->catfile(relativeScriptsDir(), $harnessName);
+exec $harnessPath ($harnessPath, @ARGV) or die "Failed to execute $harnessPath";
diff --git a/Tools/Scripts/run-webkit-websocketserver b/Tools/Scripts/run-webkit-websocketserver
new file mode 100755
index 0000000..d030951
--- /dev/null
+++ b/Tools/Scripts/run-webkit-websocketserver
@@ -0,0 +1,88 @@
+#!/usr/bin/perl
+# 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.
+
+# Script to run Web Socket server.
+
+use strict;
+use warnings;
+
+use File::Spec;
+use FindBin;
+use IPC::Open2;
+
+use lib $FindBin::Bin;
+use webkitdirs;
+
+sub closeWebSocketServer();
+sub openWebSocketServer();
+
+my $webSocketPort = 8880;
+
+my $srcDir = sourceDir();
+my $layoutTestsName = "$srcDir/LayoutTests";
+my $testDirectory = File::Spec->rel2abs($layoutTestsName);
+my $webSocketServerPidFile = "$testDirectory/websocket.pid";
+
+
+print "Starting Web Socket server...\n";
+openWebSocketServer();
+print "Started.\n";
+print "Hit [ENTER] to stop it.";
+<STDIN>;
+print "Stopping Web Socket server...\n";
+closeWebSocketServer();
+print "Stopped.\n";
+exit 0;
+
+sub openWebSocketServer()
+{
+ my $webSocketHandlerDir = "$testDirectory";
+
+ my @args = (
+ "$srcDir/Tools/Scripts/new-run-webkit-websocketserver",
+ "--server", "start",
+ "--port", "$webSocketPort",
+ "--root", "$webSocketHandlerDir",
+ "--pidfile", "$webSocketServerPidFile"
+ );
+ system "/usr/bin/python", @args;
+}
+
+sub closeWebSocketServer()
+{
+ my @args = (
+ "$srcDir/Tools/Scripts/new-run-webkit-websocketserver",
+ "--server", "stop",
+ "--pidfile", "$webSocketServerPidFile"
+ );
+ system "/usr/bin/python", @args;
+ unlink "$webSocketServerPidFile";
+}
+
+
diff --git a/Tools/Scripts/set-webkit-configuration b/Tools/Scripts/set-webkit-configuration
new file mode 100755
index 0000000..4992256
--- /dev/null
+++ b/Tools/Scripts/set-webkit-configuration
@@ -0,0 +1,79 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options]
+ --32-bit Set the default architecture to 32-bit
+ --64-bit Set the default architecture to 64-bit
+ --debug Set the default configuration to debug
+ --release Set the default configuration to release
+EOF
+
+my $configuration = passedConfiguration();
+my $architecture = passedArchitecture();
+
+if (!$architecture) {
+ # Handle --64-bit explicitly here, as we don't want our other scripts to accept it
+ for my $i (0 .. $#ARGV) {
+ my $opt = $ARGV[$i];
+ if ($opt =~ /^--64-bit$/i) {
+ splice(@ARGV, $i, 1);
+ $architecture = 'x86_64';
+ }
+ }
+}
+
+if (!$configuration && !$architecture) {
+ print STDERR $usage;
+ exit 1;
+}
+
+my $baseProductDir = baseProductDir();
+system "mkdir", "-p", "$baseProductDir";
+
+if ($configuration) {
+ open CONFIGURATION, ">", "$baseProductDir/Configuration" or die;
+ print CONFIGURATION $configuration;
+ close CONFIGURATION;
+}
+
+if ($architecture) {
+ if ($architecture ne "x86_64") {
+ open ARCHITECTURE, ">", "$baseProductDir/Architecture" or die;
+ print ARCHITECTURE $architecture;
+ close ARCHITECTURE;
+ } else {
+ unlink "$baseProductDir/Architecture";
+ }
+}
diff --git a/Tools/Scripts/sort-Xcode-project-file b/Tools/Scripts/sort-Xcode-project-file
new file mode 100755
index 0000000..705b41d
--- /dev/null
+++ b/Tools/Scripts/sort-Xcode-project-file
@@ -0,0 +1,172 @@
+#!/usr/bin/perl -w
+
+# 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.
+# 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.
+
+# Script to sort "children" and "files" sections in Xcode project.pbxproj files
+
+use strict;
+
+use File::Basename;
+use File::Spec;
+use File::Temp qw(tempfile);
+use Getopt::Long;
+
+sub sortChildrenByFileName($$);
+sub sortFilesByFileName($$);
+
+# Files (or products) without extensions
+my %isFile = map { $_ => 1 } qw(
+ create_hash_table
+ jsc
+ minidom
+ testapi
+ testjsglue
+);
+
+my $printWarnings = 1;
+my $showHelp;
+
+my $getOptionsResult = GetOptions(
+ 'h|help' => \$showHelp,
+ 'w|warnings!' => \$printWarnings,
+);
+
+if (scalar(@ARGV) == 0 && !$showHelp) {
+ print STDERR "ERROR: No Xcode project files (project.pbxproj) listed on command-line.\n";
+ undef $getOptionsResult;
+}
+
+if (!$getOptionsResult || $showHelp) {
+ print STDERR <<__END__;
+Usage: @{[ basename($0) ]} [options] path/to/project.pbxproj [path/to/project.pbxproj ...]
+ -h|--help show this help message
+ -w|--[no-]warnings show or suppress warnings (default: show warnings)
+__END__
+ exit 1;
+}
+
+for my $projectFile (@ARGV) {
+ if (basename($projectFile) =~ /\.xcodeproj$/) {
+ $projectFile = File::Spec->catfile($projectFile, "project.pbxproj");
+ }
+
+ if (basename($projectFile) ne "project.pbxproj") {
+ print STDERR "WARNING: Not an Xcode project file: $projectFile\n" if $printWarnings;
+ next;
+ }
+
+ # Grab the mainGroup for the project file
+ my $mainGroup = "";
+ open(IN, "< $projectFile") || die "Could not open $projectFile: $!";
+ while (my $line = <IN>) {
+ $mainGroup = $2 if $line =~ m#^(\s*)mainGroup = ([0-9A-F]{24} /\* .+ \*/);$#;
+ }
+ close(IN);
+
+ my ($OUT, $tempFileName) = tempfile(
+ basename($projectFile) . "-XXXXXXXX",
+ DIR => dirname($projectFile),
+ UNLINK => 0,
+ );
+
+ # Clean up temp file in case of die()
+ $SIG{__DIE__} = sub {
+ close(IN);
+ close($OUT);
+ unlink($tempFileName);
+ };
+
+ my @lastTwo = ();
+ open(IN, "< $projectFile") || die "Could not open $projectFile: $!";
+ while (my $line = <IN>) {
+ if ($line =~ /^(\s*)files = \(\s*$/) {
+ print $OUT $line;
+ my $endMarker = $1 . ");";
+ my @files;
+ while (my $fileLine = <IN>) {
+ if ($fileLine =~ /^\Q$endMarker\E\s*$/) {
+ $endMarker = $fileLine;
+ last;
+ }
+ push @files, $fileLine;
+ }
+ print $OUT sort sortFilesByFileName @files;
+ print $OUT $endMarker;
+ } elsif ($line =~ /^(\s*)children = \(\s*$/) {
+ print $OUT $line;
+ my $endMarker = $1 . ");";
+ my @children;
+ while (my $childLine = <IN>) {
+ if ($childLine =~ /^\Q$endMarker\E\s*$/) {
+ $endMarker = $childLine;
+ last;
+ }
+ push @children, $childLine;
+ }
+ if ($lastTwo[0] =~ m#^\s+\Q$mainGroup\E = \{$#) {
+ # Don't sort mainGroup
+ print $OUT @children;
+ } else {
+ print $OUT sort sortChildrenByFileName @children;
+ }
+ print $OUT $endMarker;
+ } else {
+ print $OUT $line;
+ }
+
+ push @lastTwo, $line;
+ shift @lastTwo if scalar(@lastTwo) > 2;
+ }
+ close(IN);
+ close($OUT);
+
+ unlink($projectFile) || die "Could not delete $projectFile: $!";
+ rename($tempFileName, $projectFile) || die "Could not rename $tempFileName to $projectFile: $!";
+}
+
+exit 0;
+
+sub sortChildrenByFileName($$)
+{
+ my ($a, $b) = @_;
+ my $aFileName = $1 if $a =~ /^\s*[A-Z0-9]{24} \/\* (.+) \*\/,$/;
+ my $bFileName = $1 if $b =~ /^\s*[A-Z0-9]{24} \/\* (.+) \*\/,$/;
+ my $aSuffix = $1 if $aFileName =~ m/\.([^.]+)$/;
+ my $bSuffix = $1 if $bFileName =~ m/\.([^.]+)$/;
+ if ((!$aSuffix && !$isFile{$aFileName} && $bSuffix) || ($aSuffix && !$bSuffix && !$isFile{$bFileName})) {
+ return !$aSuffix ? -1 : 1;
+ }
+ return lc($aFileName) cmp lc($bFileName);
+}
+
+sub sortFilesByFileName($$)
+{
+ my ($a, $b) = @_;
+ my $aFileName = $1 if $a =~ /^\s*[A-Z0-9]{24} \/\* (.+) in /;
+ my $bFileName = $1 if $b =~ /^\s*[A-Z0-9]{24} \/\* (.+) in /;
+ return lc($aFileName) cmp lc($bFileName);
+}
diff --git a/Tools/Scripts/split-file-by-class b/Tools/Scripts/split-file-by-class
new file mode 100755
index 0000000..b6aeb68
--- /dev/null
+++ b/Tools/Scripts/split-file-by-class
@@ -0,0 +1,159 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Used for splitting a single file into multiple class files
+# Usage: split-class <header file>
+
+use strict;
+use File::Copy;
+use FindBin;
+use lib $FindBin::Bin;
+use SpacingHeuristics;
+
+
+for my $filename (@ARGV) {
+
+ $filename =~ m/^(\w+)\.h$/ or die "Command line args must be .h files.\n";
+ my $basename = $1;
+
+ open(OLDFILE, "<", $filename) or die "File does not exist: $filename\n";
+ print "Splitting class $filename.{h,cpp}:\n";
+
+ my $currentClassName = "";
+ my $classIndent = "";
+ my $fileContent = "";
+ my %classDefs = ();
+ while (my $line = <OLDFILE>) {
+ if ($currentClassName) {
+ $classDefs{$currentClassName} .= $line;
+ if ($line =~ /^$classIndent};\s*$/) {
+ $currentClassName = "";
+ }
+ } else {
+ if ($line =~ /^(\s*)class\s+(\w+)\s+[^;]*$/) {
+ $classIndent = $1;
+ $currentClassName = $2;
+ $classDefs{$currentClassName} .= $line;
+ $fileContent .= "###CLASS###$currentClassName\n";
+ } else {
+ $fileContent .= $line;
+ }
+ }
+ }
+ close(OLDFILE);
+
+ if (scalar(keys(%classDefs)) == 1) { # degenerate case
+ my ($classname) = keys(%classDefs);
+ if (!($classname eq $basename)) {
+ print "Skipping $filename, already correctly named.\n";
+ } else {
+ print "$filename only includes one class, renaming to $classname.h\n";
+ system("svn rm --force $classname.h") if (-r "$classname.h");
+ system "svn mv $basename.h $classname.h";
+ }
+ } else {
+ while (my ($classname, $classDef) = each(%classDefs)) {
+ if (($classname eq $basename)) {
+ print "Skipping $filename, already correctly named.\n";
+ } else {
+ print "Using SVN to copy $basename.{h,cpp} to $classname.{h,cpp}\n";
+
+ system("svn rm --force $classname.h") if (-r "$classname.h");
+ system "svn cp $basename.h $classname.h";
+
+ system("svn rm --force $classname.cpp") if (-r "$classname.cpp");
+ system "svn cp $basename.cpp $classname.cpp";
+ }
+
+ print "Fixing $classname.h as much as possible.\n";
+ open(NEWHEADER, ">", "$classname.h") or die "File does not exist: $filename\n";
+ my @lines = split("\n", $fileContent);
+ foreach my $line (@lines) {
+ if ($line =~ /^###CLASS###(\w+)/) {
+ if ($1 eq $classname) {
+ print NEWHEADER $classDef . "\n";
+ }
+ } else {
+ print NEWHEADER $line . "\n";
+ }
+ }
+ close(NEWHEADER);
+
+ print "Fixing $classname.cpp as much as possible.\n";
+ copy("$classname.cpp", "$classname.cpp.original");
+ open(OLDCPP, "<", "$classname.cpp.original") or die "Failed to copy file for reading: $filename\n";
+ open(NEWCPP, ">", "$classname.cpp") or die "File does not exist: $filename\n";
+ my $insideMemberFunction = 0;
+ my $shouldPrintMemberFunction = 0;
+ resetSpacingHeuristics();
+ while (my $line = <OLDCPP>) {
+ if ($insideMemberFunction) {
+ if ($shouldPrintMemberFunction) {
+ print NEWCPP $line;
+ #setPreviousAllowedLine($line);
+ } else {
+ ignoringLine($line);
+ }
+ if ($line =~ /^}\s*$/) {
+ $insideMemberFunction = 0;
+ }
+ } elsif ($line =~ /$filename/) {
+ print NEWCPP "#include \"config.h\"\n";
+ print NEWCPP "#include \"$classname.h\"\n";
+ } elsif ($line =~ /#include/ || $line =~ /#import/) {
+ next; # skip includes, they're generally wrong or unecessary anyway.
+ } else {
+ $line =~ s/DOM:://;
+ $line =~ s/khtml:://;
+ $line =~ s/namespace DOM/namespace WebCore/;
+ $line =~ s/namespace khtml/namespace WebCore/;
+
+ if ($line =~ /^(.*?\s+)?(\*|&)?(\w+)::(~)?\w+\s*\(/) {
+ $insideMemberFunction = 1;
+ $shouldPrintMemberFunction = ($classname eq $3);
+ if ($shouldPrintMemberFunction) {
+ printPendingEmptyLines(*NEWCPP, $line);
+ print NEWCPP $line;
+ }
+ } else {
+ next if isOnlyWhiteSpace($line);
+ next if ($line =~ m/------------/);
+ printPendingEmptyLines(*NEWCPP, $line);
+ applySpacingHeuristicsAndPrint(*NEWCPP, $line);
+ }
+ }
+ }
+ close(NEWCPP);
+ close(OLDCPP);
+ unlink("$classname.cpp.original");
+ }
+ }
+
+ print "Opening new files...\n";
+ system("open " . join(".* ", keys(%classDefs)) . ".*");
+} \ No newline at end of file
diff --git a/Tools/Scripts/sunspider-compare-results b/Tools/Scripts/sunspider-compare-results
new file mode 100755
index 0000000..acb2c04
--- /dev/null
+++ b/Tools/Scripts/sunspider-compare-results
@@ -0,0 +1,133 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2007 Apple Inc. All rights reserved.
+# 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.
+#
+# 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.
+
+use strict;
+use File::Spec;
+use FindBin;
+use Getopt::Long qw(:config pass_through);
+use lib $FindBin::Bin;
+use webkitdirs;
+use POSIX;
+
+# determine configuration, but default to "Release" instead of last-used configuration to match run-sunspider
+setConfiguration("Release");
+setConfiguration();
+my $configuration = configuration();
+
+my $root;
+my $showHelp = 0;
+my $suite = "";
+my $ubench = 0;
+my $v8 = 0;
+my $parseonly = 0;
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options] FILE FILE
+ --help Show this help message
+ --root Path to root tools build
+ --suite Select a specific benchmark suite. The default is sunspider-0.9.1
+ --ubench Use microbenchmark suite instead of regular tests. Same as --suite=ubench
+ --v8-suite Use the V8 benchmark suite. Same as --suite=v8-v4
+ --parse-only Use the parse-only benchmark suite. Same as --suite=parse-only
+EOF
+
+GetOptions('root=s' => sub { my ($argName, $value) = @_; setConfigurationProductDir(Cwd::abs_path($value)); $root = $value; },
+ 'suite=s' => \$suite,
+ 'ubench' => \$ubench,
+ 'v8' => \$v8,
+ 'parse-only' => \$parseonly,
+ 'help' => \$showHelp);
+
+if ($showHelp) {
+ print STDERR $usage;
+ exit 1;
+}
+
+@ARGV = map { File::Spec->rel2abs($_) } @ARGV;
+
+sub buildJSC
+{
+ if (!defined($root)){
+ chdirWebKit();
+ my $buildResult = system currentPerlPath(), "Tools/Scripts/build-jsc", "--" . $configuration;
+ if ($buildResult) {
+ print STDERR "Compiling jsc failed!\n";
+ exit WEXITSTATUS($buildResult);
+ }
+ }
+}
+
+sub setupEnvironmentForExecution($)
+{
+ my ($productDir) = @_;
+ print "Starting sunspider-compare-results with DYLD_FRAMEWORK_PATH set to point to built JavaScriptCore in $productDir.\n";
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ # FIXME: Other platforms may wish to augment this method to use LD_LIBRARY_PATH, etc.
+}
+
+sub pathToBuiltJSC($)
+{
+ my ($productDir) = @_;
+ my $jscName = "jsc";
+ $jscName .= "_debug" if configurationForVisualStudio() eq "Debug_All";
+ return "$productDir/$jscName";
+}
+
+sub pathToSystemJSC()
+{
+ my $path = "/System/Library/Frameworks/JavaScriptCore.framework/Resources/jsc";
+ if (-f $path) {
+ return $path;
+ }
+ return undef;
+}
+
+sub pathToJSC()
+{
+ my $path = pathToSystemJSC();
+ return $path if defined $path;
+
+ buildJSC();
+
+ my $productDir = jscProductDir();
+
+ setupEnvironmentForExecution($productDir);
+ return pathToBuiltJSC($productDir);
+}
+
+my $jscPath = pathToJSC();
+chdirWebKit();
+chdir("SunSpider");
+
+my @args = ("--shell", $jscPath);
+# This code could be removed if we chose to pass extra args to sunspider instead of Xcode
+push @args, "--suite=${suite}" if $suite;
+push @args, "--ubench" if $ubench;
+push @args, "--v8" if $v8;
+push @args, "--parse-only" if $parseonly;
+
+exec currentPerlPath(), "./sunspider-compare-results", @args, @ARGV;
diff --git a/Tools/Scripts/svn-apply b/Tools/Scripts/svn-apply
new file mode 100755
index 0000000..cab7fb4
--- /dev/null
+++ b/Tools/Scripts/svn-apply
@@ -0,0 +1,454 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@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.
+
+# "patch" script for WebKit Open Source Project, used to apply patches.
+
+# Differences from invoking "patch -p0":
+#
+# Handles added files (does a svn add with logic to handle local changes).
+# Handles added directories (does a svn add).
+# Handles removed files (does a svn rm with logic to handle local changes).
+# Handles removed directories--those with no more files or directories left in them
+# (does a svn rm).
+# Has mode where it will roll back to svn version numbers in the patch file so svn
+# can do a 3-way merge.
+# Paths from Index: lines are used rather than the paths on the patch lines, which
+# makes patches generated by "cvs diff" work (increasingly unimportant since we
+# use Subversion now).
+# ChangeLog patches use --fuzz=3 to prevent rejects.
+# Handles binary files (requires patches made by svn-create-patch).
+# Handles copied and moved files (requires patches made by svn-create-patch).
+# Handles git-diff patches (without binary changes) created at the top-level directory
+#
+# Missing features:
+#
+# Handle property changes.
+# Handle copied and moved directories (would require patches made by svn-create-patch).
+# When doing a removal, check that old file matches what's being removed.
+# Notice a patch that's being applied at the "wrong level" and make it work anyway.
+# Do a dry run on the whole patch and don't do anything if part of the patch is
+# going to fail (probably too strict unless we exclude ChangeLog).
+# Handle git-diff patches with binary delta
+
+use strict;
+use warnings;
+
+use Digest::MD5;
+use File::Basename;
+use File::Spec;
+use Getopt::Long;
+use MIME::Base64;
+use POSIX qw(strftime);
+
+use FindBin;
+use lib $FindBin::Bin;
+use VCSUtils;
+
+sub addDirectoriesIfNeeded($);
+sub applyPatch($$;$);
+sub checksum($);
+sub handleBinaryChange($$);
+sub handleGitBinaryChange($$);
+sub isDirectoryEmptyForRemoval($);
+sub patch($);
+sub removeDirectoriesIfNeeded();
+
+# These should be replaced by an scm class/module:
+sub scmKnowsOfFile($);
+sub scmCopy($$);
+sub scmAdd($);
+sub scmRemove($);
+
+my $merge = 0;
+my $showHelp = 0;
+my $reviewer;
+my $force = 0;
+
+my $optionParseSuccess = GetOptions(
+ "merge!" => \$merge,
+ "help!" => \$showHelp,
+ "reviewer=s" => \$reviewer,
+ "force!" => \$force
+);
+
+if (!$optionParseSuccess || $showHelp) {
+ print STDERR basename($0) . " [-h|--help] [--force] [-m|--merge] [-r|--reviewer name] patch1 [patch2 ...]\n";
+ exit 1;
+}
+
+my %removeDirectoryIgnoreList = (
+ '.' => 1,
+ '..' => 1,
+ '.git' => 1,
+ '.svn' => 1,
+ '_svn' => 1,
+);
+
+my $epochTime = time(); # This is used to set the date in ChangeLog files.
+my $globalExitStatus = 0;
+
+my $repositoryRootPath = determineVCSRoot();
+
+my %checkedDirectories;
+
+# Need to use a typeglob to pass the file handle as a parameter,
+# otherwise get a bareword error.
+my @diffHashRefs = parsePatch(*ARGV);
+
+print "Parsed " . @diffHashRefs . " diffs from patch file(s).\n";
+
+my $preparedPatchHash = prepareParsedPatch($force, @diffHashRefs);
+
+my @copyDiffHashRefs = @{$preparedPatchHash->{copyDiffHashRefs}};
+my @nonCopyDiffHashRefs = @{$preparedPatchHash->{nonCopyDiffHashRefs}};
+my %sourceRevisions = %{$preparedPatchHash->{sourceRevisionHash}};
+
+if ($merge) {
+ die "--merge is currently only supported for SVN" unless isSVN();
+ # How do we handle Git patches applied to an SVN checkout here?
+ for my $file (sort keys %sourceRevisions) {
+ my $version = $sourceRevisions{$file};
+ print "Getting version $version of $file\n";
+ system("svn", "update", "-r", $version, $file) == 0 or die "Failed to run svn update -r $version $file.";
+ }
+}
+
+# Handle copied and moved files first since moved files may have their
+# source deleted before the move.
+for my $copyDiffHashRef (@copyDiffHashRefs) {
+ my $indexPath = $copyDiffHashRef->{indexPath};
+ my $copiedFromPath = $copyDiffHashRef->{copiedFromPath};
+
+ addDirectoriesIfNeeded(dirname($indexPath));
+ scmCopy($copiedFromPath, $indexPath);
+}
+
+for my $diffHashRef (@nonCopyDiffHashRefs) {
+ patch($diffHashRef);
+}
+
+removeDirectoriesIfNeeded();
+
+exit $globalExitStatus;
+
+sub addDirectoriesIfNeeded($)
+{
+ my ($path) = @_;
+ my @dirs = File::Spec->splitdir($path);
+ my $dir = ".";
+ while (scalar @dirs) {
+ $dir = File::Spec->catdir($dir, shift @dirs);
+ next if exists $checkedDirectories{$dir};
+ if (! -e $dir) {
+ mkdir $dir or die "Failed to create required directory '$dir' for path '$path'\n";
+ scmAdd($dir);
+ $checkedDirectories{$dir} = 1;
+ }
+ elsif (-d $dir) {
+ # SVN prints "svn: warning: 'directory' is already under version control"
+ # if you try and add a directory which is already in the repository.
+ # Git will ignore the add, but re-adding large directories can be sloooow.
+ # So we check first to see if the directory is under version control first.
+ if (!scmKnowsOfFile($dir)) {
+ scmAdd($dir);
+ }
+ $checkedDirectories{$dir} = 1;
+ }
+ else {
+ die "'$dir' exists, but is not a directory";
+ }
+ }
+}
+
+# Args:
+# $patch: a patch string.
+# $pathRelativeToRoot: the path of the file to be patched, relative to the
+# repository root. This should normally be the path
+# found in the patch's "Index:" line.
+# $options: a reference to an array of options to pass to the patch command.
+sub applyPatch($$;$)
+{
+ my ($patch, $pathRelativeToRoot, $options) = @_;
+
+ my $optionalArgs = {options => $options, ensureForce => $force};
+
+ my $exitStatus = runPatchCommand($patch, $repositoryRootPath, $pathRelativeToRoot, $optionalArgs);
+
+ if ($exitStatus) {
+ $globalExitStatus = $exitStatus;
+ }
+}
+
+sub checksum($)
+{
+ my $file = shift;
+ open(FILE, $file) or die "Can't open '$file': $!";
+ binmode(FILE);
+ my $checksum = Digest::MD5->new->addfile(*FILE)->hexdigest();
+ close(FILE);
+ return $checksum;
+}
+
+sub handleBinaryChange($$)
+{
+ my ($fullPath, $contents) = @_;
+ # [A-Za-z0-9+/] is the class of allowed base64 characters.
+ # One or more lines, at most 76 characters in length.
+ # The last line is allowed to have up to two '=' characters at the end (to signify padding).
+ if ($contents =~ m#((\n[A-Za-z0-9+/]{76})*\n[A-Za-z0-9+/]{2,74}?[A-Za-z0-9+/=]{2}\n)#) {
+ # Addition or Modification
+ open FILE, ">", $fullPath or die "Failed to open $fullPath.";
+ print FILE decode_base64($1);
+ close FILE;
+ if (!scmKnowsOfFile($fullPath)) {
+ # Addition
+ scmAdd($fullPath);
+ }
+ } else {
+ # Deletion
+ scmRemove($fullPath);
+ }
+}
+
+sub handleGitBinaryChange($$)
+{
+ my ($fullPath, $diffHashRef) = @_;
+
+ my $contents = $diffHashRef->{svnConvertedText};
+
+ my ($binaryChunkType, $binaryChunk, $reverseBinaryChunkType, $reverseBinaryChunk) = decodeGitBinaryPatch($contents, $fullPath);
+ # FIXME: support "delta" type.
+ die "only literal type is supported now" if ($binaryChunkType ne "literal" || $reverseBinaryChunkType ne "literal");
+
+ my $isFileAddition = $diffHashRef->{isNew};
+ my $isFileDeletion = $diffHashRef->{isDeletion};
+
+ my $originalContents = "";
+ if (open FILE, $fullPath) {
+ die "$fullPath already exists" if $isFileAddition;
+
+ $originalContents = join("", <FILE>);
+ close FILE;
+ }
+ die "Original content of $fullPath mismatches" if $originalContents ne $reverseBinaryChunk;
+
+ if ($isFileDeletion) {
+ scmRemove($fullPath);
+ } else {
+ # Addition or Modification
+ open FILE, ">", $fullPath or die "Failed to open $fullPath.";
+ print FILE $binaryChunk;
+ close FILE;
+ if ($isFileAddition) {
+ scmAdd($fullPath);
+ }
+ }
+}
+
+sub isDirectoryEmptyForRemoval($)
+{
+ my ($dir) = @_;
+ return 1 unless -d $dir;
+ my $directoryIsEmpty = 1;
+ opendir DIR, $dir or die "Could not open '$dir' to list files: $?";
+ for (my $item = readdir DIR; $item && $directoryIsEmpty; $item = readdir DIR) {
+ next if exists $removeDirectoryIgnoreList{$item};
+ if (-d File::Spec->catdir($dir, $item)) {
+ $directoryIsEmpty = 0;
+ } else {
+ next if (scmWillDeleteFile(File::Spec->catdir($dir, $item)));
+ $directoryIsEmpty = 0;
+ }
+ }
+ closedir DIR;
+ return $directoryIsEmpty;
+}
+
+# Args:
+# $diffHashRef: a diff hash reference of the type returned by parsePatch().
+sub patch($)
+{
+ my ($diffHashRef) = @_;
+
+ # Make sure $patch is initialized to some value. A deletion can have no
+ # svnConvertedText property in the case of a deletion resulting from a
+ # Git rename.
+ my $patch = $diffHashRef->{svnConvertedText} || "";
+
+ my $fullPath = $diffHashRef->{indexPath};
+ my $isBinary = $diffHashRef->{isBinary};
+ my $isGit = $diffHashRef->{isGit};
+
+ my $deletion = 0;
+ my $addition = 0;
+
+ $addition = 1 if ($diffHashRef->{isNew} || $patch =~ /\n@@ -0,0 .* @@/);
+ $deletion = 1 if ($diffHashRef->{isDeletion} || $patch =~ /\n@@ .* \+0,0 @@/);
+
+ if (!$addition && !$deletion && !$isBinary) {
+ # Standard patch, patch tool can handle this.
+ if (basename($fullPath) eq "ChangeLog") {
+ my $changeLogDotOrigExisted = -f "${fullPath}.orig";
+ my $changeLogHash = fixChangeLogPatch($patch);
+ my $newPatch = setChangeLogDateAndReviewer($changeLogHash->{patch}, $reviewer, $epochTime);
+ applyPatch($newPatch, $fullPath, ["--fuzz=3"]);
+ unlink("${fullPath}.orig") if (! $changeLogDotOrigExisted);
+ } else {
+ applyPatch($patch, $fullPath) if $patch;
+ }
+ } else {
+ # Either a deletion, an addition or a binary change.
+
+ addDirectoriesIfNeeded(dirname($fullPath));
+
+ if ($isBinary) {
+ if ($isGit) {
+ handleGitBinaryChange($fullPath, $diffHashRef);
+ } else {
+ handleBinaryChange($fullPath, $patch) if $patch;
+ }
+ } elsif ($deletion) {
+ applyPatch($patch, $fullPath, ["--force"]) if $patch;
+ scmRemove($fullPath);
+ } else {
+ # Addition
+ rename($fullPath, "$fullPath.orig") if -e $fullPath;
+ applyPatch($patch, $fullPath) if $patch;
+ unlink("$fullPath.orig") if -e "$fullPath.orig" && checksum($fullPath) eq checksum("$fullPath.orig");
+ scmAdd($fullPath);
+ # What is this for?
+ system("svn", "stat", "$fullPath.orig") if isSVN() && -e "$fullPath.orig";
+ }
+ }
+
+ scmToggleExecutableBit($fullPath, $diffHashRef->{executableBitDelta}) if defined($diffHashRef->{executableBitDelta});
+}
+
+sub removeDirectoriesIfNeeded()
+{
+ foreach my $dir (reverse sort keys %checkedDirectories) {
+ if (isDirectoryEmptyForRemoval($dir)) {
+ scmRemove($dir);
+ }
+ }
+}
+
+# This could be made into a more general "status" call, except svn and git
+# have different ideas about "moving" files which might get confusing.
+sub scmWillDeleteFile($)
+{
+ my ($path) = @_;
+ if (isSVN()) {
+ my $svnOutput = svnStatus($path);
+ return 1 if $svnOutput && substr($svnOutput, 0, 1) eq "D";
+ } elsif (isGit()) {
+ my $gitOutput = `git diff-index --name-status HEAD -- $path`;
+ return 1 if $gitOutput && substr($gitOutput, 0, 1) eq "D";
+ }
+ return 0;
+}
+
+# Return whether the file at the given path is known to Git.
+#
+# This method outputs a message like the following to STDERR when
+# returning false:
+#
+# "error: pathspec 'test.png' did not match any file(s) known to git.
+# Did you forget to 'git add'?"
+sub gitKnowsOfFile($)
+{
+ my $path = shift;
+
+ `git ls-files --error-unmatch -- $path`;
+ my $exitStatus = exitStatus($?);
+ return $exitStatus == 0;
+}
+
+sub scmKnowsOfFile($)
+{
+ my ($path) = @_;
+ if (isSVN()) {
+ my $svnOutput = svnStatus($path);
+ # This will match more than intended. ? might not be the first field in the status
+ if ($svnOutput && $svnOutput =~ m#\?\s+$path\n#) {
+ return 0;
+ }
+ # This does not handle errors well.
+ return 1;
+ } elsif (isGit()) {
+ my @result = callSilently(\&gitKnowsOfFile, $path);
+ return $result[0];
+ }
+}
+
+sub scmCopy($$)
+{
+ my ($source, $destination) = @_;
+ if (isSVN()) {
+ system("svn", "copy", $source, $destination) == 0 or die "Failed to svn copy $source $destination.";
+ } elsif (isGit()) {
+ system("cp", $source, $destination) == 0 or die "Failed to copy $source $destination.";
+ system("git", "add", $destination) == 0 or die "Failed to git add $destination.";
+ }
+}
+
+sub scmAdd($)
+{
+ my ($path) = @_;
+ if (isSVN()) {
+ system("svn", "add", $path) == 0 or die "Failed to svn add $path.";
+ } elsif (isGit()) {
+ system("git", "add", $path) == 0 or die "Failed to git add $path.";
+ }
+}
+
+sub scmRemove($)
+{
+ my ($path) = @_;
+ if (isSVN()) {
+ # SVN is very verbose when removing directories. Squelch all output except the last line.
+ my $svnOutput;
+ open SVN, "svn rm --force '$path' |" or die "svn rm --force '$path' failed!";
+ # Only print the last line. Subversion outputs all changed statuses below $dir
+ while (<SVN>) {
+ $svnOutput = $_;
+ }
+ close SVN;
+ print $svnOutput if $svnOutput;
+ } elsif (isGit()) {
+ # Git removes a directory if it becomes empty when the last file it contains is
+ # removed by `git rm`. In svn-apply this can happen when a directory is being
+ # removed in a patch, and all of the files inside of the directory are removed
+ # before attemping to remove the directory itself. In this case, Git will have
+ # already deleted the directory and `git rm` would exit with an error claiming
+ # there was no file. The --ignore-unmatch switch gracefully handles this case.
+ system("git", "rm", "--force", "--ignore-unmatch", $path) == 0 or die "Failed to git rm --force --ignore-unmatch $path.";
+ }
+}
diff --git a/Tools/Scripts/svn-create-patch b/Tools/Scripts/svn-create-patch
new file mode 100755
index 0000000..863998d
--- /dev/null
+++ b/Tools/Scripts/svn-create-patch
@@ -0,0 +1,431 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+# Extended "svn diff" script for WebKit Open Source Project, used to make patches.
+
+# Differences from standard "svn diff":
+#
+# Uses the real diff, not svn's built-in diff.
+# Always passes "-p" to diff so it will try to include function names.
+# Handles binary files (encoded as a base64 chunk of text).
+# Sorts the diffs alphabetically by text files, then binary files.
+# Handles copied and moved files.
+#
+# Missing features:
+#
+# Handle copied and moved directories.
+
+use strict;
+use warnings;
+
+use Config;
+use File::Basename;
+use File::Spec;
+use File::stat;
+use FindBin;
+use Getopt::Long;
+use lib $FindBin::Bin;
+use MIME::Base64;
+use POSIX qw(:errno_h);
+use Time::gmtime;
+use VCSUtils;
+
+sub binarycmp($$);
+sub diffOptionsForFile($);
+sub findBaseUrl($);
+sub findMimeType($;$);
+sub findModificationType($);
+sub findSourceFileAndRevision($);
+sub generateDiff($$);
+sub generateFileList($\%);
+sub hunkHeaderLineRegExForFile($);
+sub isBinaryMimeType($);
+sub manufacturePatchForAdditionWithHistory($);
+sub numericcmp($$);
+sub outputBinaryContent($);
+sub patchpathcmp($$);
+sub pathcmp($$);
+sub processPaths(\@);
+sub splitpath($);
+sub testfilecmp($$);
+
+$ENV{'LC_ALL'} = 'C';
+
+my $showHelp;
+my $ignoreChangelogs = 0;
+my $devNull = File::Spec->devnull();
+
+my $result = GetOptions(
+ "help" => \$showHelp,
+ "ignore-changelogs" => \$ignoreChangelogs
+);
+if (!$result || $showHelp) {
+ print STDERR basename($0) . " [-h|--help] [--ignore-changelogs] [svndir1 [svndir2 ...]]\n";
+ exit 1;
+}
+
+# Sort the diffs for easier reviewing.
+my %paths = processPaths(@ARGV);
+
+# Generate a list of files requiring diffs.
+my %diffFiles;
+for my $path (keys %paths) {
+ generateFileList($path, %diffFiles);
+}
+
+my $svnRoot = determineSVNRoot();
+my $prefix = chdirReturningRelativePath($svnRoot);
+
+my $patchSize = 0;
+
+# Generate the diffs, in a order chosen for easy reviewing.
+for my $path (sort patchpathcmp values %diffFiles) {
+ $patchSize += generateDiff($path, $prefix);
+}
+
+if ($patchSize > 20480) {
+ print STDERR "WARNING: Patch's size is " . int($patchSize/1024) . " kbytes.\n";
+ print STDERR "Patches 20k or smaller are more likely to be reviewed. Larger patches may sit unreviewed for a long time.\n";
+}
+
+exit 0;
+
+# Overall sort, considering multiple criteria.
+sub patchpathcmp($$)
+{
+ my ($a, $b) = @_;
+
+ # All binary files come after all non-binary files.
+ my $result = binarycmp($a, $b);
+ return $result if $result;
+
+ # All test files come after all non-test files.
+ $result = testfilecmp($a, $b);
+ return $result if $result;
+
+ # Final sort is a "smart" sort by directory and file name.
+ return pathcmp($a, $b);
+}
+
+# Sort so text files appear before binary files.
+sub binarycmp($$)
+{
+ my ($fileDataA, $fileDataB) = @_;
+ return $fileDataA->{isBinary} <=> $fileDataB->{isBinary};
+}
+
+sub diffOptionsForFile($)
+{
+ my ($file) = @_;
+
+ my $options = "uaNp";
+
+ if (my $hunkHeaderLineRegEx = hunkHeaderLineRegExForFile($file)) {
+ $options .= "F'$hunkHeaderLineRegEx'";
+ }
+
+ return $options;
+}
+
+sub findBaseUrl($)
+{
+ my ($infoPath) = @_;
+ my $baseUrl;
+ open INFO, "svn info '$infoPath' |" or die;
+ while (<INFO>) {
+ if (/^URL: (.+?)[\r\n]*$/) {
+ $baseUrl = $1;
+ }
+ }
+ close INFO;
+ return $baseUrl;
+}
+
+sub findMimeType($;$)
+{
+ my ($file, $revision) = @_;
+ my $args = $revision ? "--revision $revision" : "";
+ open PROPGET, "svn propget svn:mime-type $args '$file' |" or die;
+ my $mimeType = <PROPGET>;
+ close PROPGET;
+ # svn may output a different EOL sequence than $/, so avoid chomp.
+ if ($mimeType) {
+ $mimeType =~ s/[\r\n]+$//g;
+ }
+ return $mimeType;
+}
+
+sub findModificationType($)
+{
+ my ($stat) = @_;
+ my $fileStat = substr($stat, 0, 1);
+ my $propertyStat = substr($stat, 1, 1);
+ if ($fileStat eq "A" || $fileStat eq "R") {
+ my $additionWithHistory = substr($stat, 3, 1);
+ return $additionWithHistory eq "+" ? "additionWithHistory" : "addition";
+ }
+ return "modification" if ($fileStat eq "M" || $propertyStat eq "M");
+ return "deletion" if ($fileStat eq "D");
+ return undef;
+}
+
+sub findSourceFileAndRevision($)
+{
+ my ($file) = @_;
+ my $baseUrl = findBaseUrl(".");
+ my $sourceFile;
+ my $sourceRevision;
+ open INFO, "svn info '$file' |" or die;
+ while (<INFO>) {
+ if (/^Copied From URL: (.+?)[\r\n]*$/) {
+ $sourceFile = File::Spec->abs2rel($1, $baseUrl);
+ } elsif (/^Copied From Rev: ([0-9]+)/) {
+ $sourceRevision = $1;
+ }
+ }
+ close INFO;
+ return ($sourceFile, $sourceRevision);
+}
+
+sub generateDiff($$)
+{
+ my ($fileData, $prefix) = @_;
+ my $file = File::Spec->catdir($prefix, $fileData->{path});
+
+ if ($ignoreChangelogs && basename($file) eq "ChangeLog") {
+ return 0;
+ }
+
+ my $patch = "";
+ if ($fileData->{modificationType} eq "additionWithHistory") {
+ manufacturePatchForAdditionWithHistory($fileData);
+ }
+
+ my $diffOptions = diffOptionsForFile($file);
+ open DIFF, "svn diff --diff-cmd diff -x -$diffOptions '$file' |" or die;
+ while (<DIFF>) {
+ $patch .= $_;
+ }
+ close DIFF;
+ if (basename($file) eq "ChangeLog") {
+ my $changeLogHash = fixChangeLogPatch($patch);
+ $patch = $changeLogHash->{patch};
+ }
+ print $patch;
+ if ($fileData->{isBinary}) {
+ print "\n" if ($patch && $patch =~ m/\n\S+$/m);
+ outputBinaryContent($file);
+ }
+ return length($patch);
+}
+
+sub generateFileList($\%)
+{
+ my ($statPath, $diffFiles) = @_;
+ my %testDirectories = map { $_ => 1 } qw(LayoutTests);
+ open STAT, "svn stat '$statPath' |" or die;
+ while (my $line = <STAT>) {
+ # svn may output a different EOL sequence than $/, so avoid chomp.
+ $line =~ s/[\r\n]+$//g;
+ my $stat;
+ my $path;
+ if (isSVNVersion16OrNewer()) {
+ $stat = substr($line, 0, 8);
+ $path = substr($line, 8);
+ } else {
+ $stat = substr($line, 0, 7);
+ $path = substr($line, 7);
+ }
+ next if -d $path;
+ my $modificationType = findModificationType($stat);
+ if ($modificationType) {
+ $diffFiles->{$path}->{path} = $path;
+ $diffFiles->{$path}->{modificationType} = $modificationType;
+ $diffFiles->{$path}->{isBinary} = isBinaryMimeType($path);
+ $diffFiles->{$path}->{isTestFile} = exists $testDirectories{(File::Spec->splitdir($path))[0]} ? 1 : 0;
+ if ($modificationType eq "additionWithHistory") {
+ my ($sourceFile, $sourceRevision) = findSourceFileAndRevision($path);
+ $diffFiles->{$path}->{sourceFile} = $sourceFile;
+ $diffFiles->{$path}->{sourceRevision} = $sourceRevision;
+ }
+ } else {
+ print STDERR $line, "\n";
+ }
+ }
+ close STAT;
+}
+
+sub hunkHeaderLineRegExForFile($)
+{
+ my ($file) = @_;
+
+ my $startOfObjCInterfaceRegEx = "@(implementation\\|interface\\|protocol)";
+ return "^[-+]\\|$startOfObjCInterfaceRegEx" if $file =~ /\.mm?$/;
+ return "^$startOfObjCInterfaceRegEx" if $file =~ /^(.*\/)?(mac|objc)\// && $file =~ /\.h$/;
+}
+
+sub isBinaryMimeType($)
+{
+ my ($file) = @_;
+ my $mimeType = findMimeType($file);
+ return 0 if (!$mimeType || substr($mimeType, 0, 5) eq "text/");
+ return 1;
+}
+
+sub manufacturePatchForAdditionWithHistory($)
+{
+ my ($fileData) = @_;
+ my $file = $fileData->{path};
+ print "Index: ${file}\n";
+ print "=" x 67, "\n";
+ my $sourceFile = $fileData->{sourceFile};
+ my $sourceRevision = $fileData->{sourceRevision};
+ print "--- ${file}\t(revision ${sourceRevision})\t(from ${sourceFile}:${sourceRevision})\n";
+ print "+++ ${file}\t(working copy)\n";
+ if ($fileData->{isBinary}) {
+ print "\nCannot display: file marked as a binary type.\n";
+ my $mimeType = findMimeType($file, $sourceRevision);
+ print "svn:mime-type = ${mimeType}\n\n";
+ } else {
+ print `svn cat ${sourceFile} | diff -u $devNull - | tail -n +3`;
+ }
+}
+
+# Sort numeric parts of strings as numbers, other parts as strings.
+# Makes 1.33 come after 1.3, which is cool.
+sub numericcmp($$)
+{
+ my ($aa, $bb) = @_;
+
+ my @a = split /(\d+)/, $aa;
+ my @b = split /(\d+)/, $bb;
+
+ # Compare one chunk at a time.
+ # Each chunk is either all numeric digits, or all not numeric digits.
+ while (@a && @b) {
+ my $a = shift @a;
+ my $b = shift @b;
+
+ # Use numeric comparison if chunks are non-equal numbers.
+ return $a <=> $b if $a =~ /^\d/ && $b =~ /^\d/ && $a != $b;
+
+ # Use string comparison if chunks are any other kind of non-equal string.
+ return $a cmp $b if $a ne $b;
+ }
+
+ # One of the two is now empty; compare lengths for result in this case.
+ return @a <=> @b;
+}
+
+sub outputBinaryContent($)
+{
+ my ($path) = @_;
+ # Deletion
+ return if (! -e $path);
+ # Addition or Modification
+ my $buffer;
+ open BINARY, $path or die;
+ while (read(BINARY, $buffer, 60*57)) {
+ print encode_base64($buffer);
+ }
+ close BINARY;
+ print "\n";
+}
+
+# Sort first by directory, then by file, so all paths in one directory are grouped
+# rather than being interspersed with items from subdirectories.
+# Use numericcmp to sort directory and filenames to make order logical.
+# Also include a special case for ChangeLog, which comes first in any directory.
+sub pathcmp($$)
+{
+ my ($fileDataA, $fileDataB) = @_;
+
+ my ($dira, $namea) = splitpath($fileDataA->{path});
+ my ($dirb, $nameb) = splitpath($fileDataB->{path});
+
+ return numericcmp($dira, $dirb) if $dira ne $dirb;
+ return -1 if $namea eq "ChangeLog" && $nameb ne "ChangeLog";
+ return +1 if $namea ne "ChangeLog" && $nameb eq "ChangeLog";
+ return numericcmp($namea, $nameb);
+}
+
+sub processPaths(\@)
+{
+ my ($paths) = @_;
+ return ("." => 1) if (!@{$paths});
+
+ my %result = ();
+
+ for my $file (@{$paths}) {
+ die "can't handle absolute paths like \"$file\"\n" if File::Spec->file_name_is_absolute($file);
+ die "can't handle empty string path\n" if $file eq "";
+ die "can't handle path with single quote in the name like \"$file\"\n" if $file =~ /'/; # ' (keep Xcode syntax highlighting happy)
+
+ my $untouchedFile = $file;
+
+ $file = canonicalizePath($file);
+
+ die "can't handle paths with .. like \"$untouchedFile\"\n" if $file =~ m|/\.\./|;
+
+ $result{$file} = 1;
+ }
+
+ return ("." => 1) if ($result{"."});
+
+ # Remove any paths that also have a parent listed.
+ for my $path (keys %result) {
+ for (my $parent = dirname($path); $parent ne '.'; $parent = dirname($parent)) {
+ if ($result{$parent}) {
+ delete $result{$path};
+ last;
+ }
+ }
+ }
+
+ return %result;
+}
+
+# Break up a path into the directory (with slash) and base name.
+sub splitpath($)
+{
+ my ($path) = @_;
+
+ my $pathSeparator = "/";
+ my $dirname = dirname($path) . $pathSeparator;
+ $dirname = "" if $dirname eq "." . $pathSeparator;
+
+ return ($dirname, basename($path));
+}
+
+# Sort so source code files appear before test files.
+sub testfilecmp($$)
+{
+ my ($fileDataA, $fileDataB) = @_;
+ return $fileDataA->{isTestFile} <=> $fileDataB->{isTestFile};
+}
+
diff --git a/Tools/Scripts/svn-unapply b/Tools/Scripts/svn-unapply
new file mode 100755
index 0000000..1dca11c
--- /dev/null
+++ b/Tools/Scripts/svn-unapply
@@ -0,0 +1,280 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007 Apple Inc. All rights reserved.
+# Copyright (C) 2009 Cameron McCormack <cam@mcc.id.au>
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@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.
+
+# "unpatch" script for WebKit Open Source Project, used to remove patches.
+
+# Differences from invoking "patch -p0 -R":
+#
+# Handles added files (does a svn revert with additional logic to handle local changes).
+# Handles added directories (does a svn revert and a rmdir).
+# Handles removed files (does a svn revert with additional logic to handle local changes).
+# Handles removed directories (does a svn revert).
+# Paths from Index: lines are used rather than the paths on the patch lines, which
+# makes patches generated by "cvs diff" work (increasingly unimportant since we
+# use Subversion now).
+# ChangeLog patches use --fuzz=3 to prevent rejects, and the entry date is reset in
+# the patch before it is applied (svn-apply sets it when applying a patch).
+# Handles binary files (requires patches made by svn-create-patch).
+# Handles copied and moved files (requires patches made by svn-create-patch).
+# Handles git-diff patches (without binary changes) created at the top-level directory
+#
+# Missing features:
+#
+# Handle property changes.
+# Handle copied and moved directories (would require patches made by svn-create-patch).
+# Use version numbers in the patch file and do a 3-way merge.
+# When reversing an addition, check that the file matches what's being removed.
+# Notice a patch that's being unapplied at the "wrong level" and make it work anyway.
+# Do a dry run on the whole patch and don't do anything if part of the patch is
+# going to fail (probably too strict unless we exclude ChangeLog).
+# Handle git-diff patches with binary changes
+
+use strict;
+use warnings;
+
+use Cwd;
+use Digest::MD5;
+use Fcntl qw(:DEFAULT :seek);
+use File::Basename;
+use File::Spec;
+use File::Temp qw(tempfile);
+use Getopt::Long;
+
+use FindBin;
+use lib $FindBin::Bin;
+use VCSUtils;
+
+sub checksum($);
+sub patch($);
+sub revertDirectories();
+sub unapplyPatch($$;$);
+sub unsetChangeLogDate($$);
+
+my $force = 0;
+my $showHelp = 0;
+
+my $optionParseSuccess = GetOptions(
+ "force!" => \$force,
+ "help!" => \$showHelp
+);
+
+if (!$optionParseSuccess || $showHelp) {
+ print STDERR basename($0) . " [-h|--help] [--force] patch1 [patch2 ...]\n";
+ exit 1;
+}
+
+my $globalExitStatus = 0;
+
+my $repositoryRootPath = determineVCSRoot();
+
+my @copiedFiles;
+my %directoriesToCheck;
+
+# Need to use a typeglob to pass the file handle as a parameter,
+# otherwise get a bareword error.
+my @diffHashRefs = parsePatch(*ARGV);
+
+print "Parsed " . @diffHashRefs . " diffs from patch file(s).\n";
+
+my $preparedPatchHash = prepareParsedPatch($force, @diffHashRefs);
+
+my @copyDiffHashRefs = @{$preparedPatchHash->{copyDiffHashRefs}};
+my @nonCopyDiffHashRefs = @{$preparedPatchHash->{nonCopyDiffHashRefs}};
+
+for my $diffHashRef (@nonCopyDiffHashRefs) {
+ patch($diffHashRef);
+}
+
+# Handle copied and moved files last since they may have had post-copy changes that have now been unapplied
+for my $diffHashRef (@copyDiffHashRefs) {
+ patch($diffHashRef);
+}
+
+if (isSVN()) {
+ revertDirectories();
+}
+
+exit $globalExitStatus;
+
+sub checksum($)
+{
+ my $file = shift;
+ open(FILE, $file) or die "Can't open '$file': $!";
+ binmode(FILE);
+ my $checksum = Digest::MD5->new->addfile(*FILE)->hexdigest();
+ close(FILE);
+ return $checksum;
+}
+
+# Args:
+# $diffHashRef: a diff hash reference of the type returned by parsePatch().
+sub patch($)
+{
+ my ($diffHashRef) = @_;
+
+ # Make sure $patch is initialized to some value. There is no
+ # svnConvertedText when reversing an svn copy/move.
+ my $patch = $diffHashRef->{svnConvertedText} || "";
+
+ my $fullPath = $diffHashRef->{indexPath};
+ my $isSvnBinary = $diffHashRef->{isBinary} && $diffHashRef->{isSvn};
+
+ $directoriesToCheck{dirname($fullPath)} = 1;
+
+ my $deletion = 0;
+ my $addition = 0;
+
+ $addition = 1 if ($diffHashRef->{isNew} || $diffHashRef->{copiedFromPath} || $patch =~ /\n@@ -0,0 .* @@/);
+ $deletion = 1 if ($diffHashRef->{isDeletion} || $patch =~ /\n@@ .* \+0,0 @@/);
+
+ if (!$addition && !$deletion && !$isSvnBinary) {
+ # Standard patch, patch tool can handle this.
+ if (basename($fullPath) eq "ChangeLog") {
+ my $changeLogDotOrigExisted = -f "${fullPath}.orig";
+ my $changeLogHash = fixChangeLogPatch($patch);
+ unapplyPatch(unsetChangeLogDate($fullPath, $changeLogHash->{patch}), $fullPath, ["--fuzz=3"]);
+ unlink("${fullPath}.orig") if (! $changeLogDotOrigExisted);
+ } else {
+ unapplyPatch($patch, $fullPath);
+ }
+ } else {
+ # Either a deletion, an addition or a binary change.
+
+ # FIXME: Add support for Git binary files.
+ if ($isSvnBinary) {
+ # Reverse binary change
+ unlink($fullPath) if (-e $fullPath);
+ system "svn", "revert", $fullPath;
+ } elsif ($deletion) {
+ # Reverse deletion
+ rename($fullPath, "$fullPath.orig") if -e $fullPath;
+
+ unapplyPatch($patch, $fullPath);
+
+ # If we don't ask for the filehandle here, we always get a warning.
+ my ($fh, $tempPath) = tempfile(basename($fullPath) . "-XXXXXXXX",
+ DIR => dirname($fullPath), UNLINK => 1);
+ close($fh);
+
+ # Keep the version from the patch in case it's different from svn.
+ rename($fullPath, $tempPath);
+ system "svn", "revert", $fullPath;
+ rename($tempPath, $fullPath);
+
+ # This works around a bug in the svn client.
+ # [Issue 1960] file modifications get lost due to FAT 2s time resolution
+ # http://subversion.tigris.org/issues/show_bug.cgi?id=1960
+ system "touch", $fullPath;
+
+ # Remove $fullPath.orig if it is the same as $fullPath
+ unlink("$fullPath.orig") if -e "$fullPath.orig" && checksum($fullPath) eq checksum("$fullPath.orig");
+
+ # Show status if the file is modifed
+ system "svn", "stat", $fullPath;
+ } else {
+ # Reverse addition
+ #
+ # FIXME: This should use the same logic as svn-apply's deletion
+ # code. In particular, svn-apply's scmRemove() subroutine
+ # should be used here.
+ unapplyPatch($patch, $fullPath, ["--force"]) if $patch;
+ unlink($fullPath) if -z $fullPath;
+ system "svn", "revert", $fullPath;
+ }
+ }
+
+ scmToggleExecutableBit($fullPath, -1 * $diffHashRef->{executableBitDelta}) if defined($diffHashRef->{executableBitDelta});
+}
+
+sub revertDirectories()
+{
+ chdir $repositoryRootPath;
+ my %checkedDirectories;
+ foreach my $path (reverse sort keys %directoriesToCheck) {
+ my @dirs = File::Spec->splitdir($path);
+ while (scalar @dirs) {
+ my $dir = File::Spec->catdir(@dirs);
+ pop(@dirs);
+ next if (exists $checkedDirectories{$dir});
+ if (-d $dir) {
+ my $svnOutput = svnStatus($dir);
+ if ($svnOutput && $svnOutput =~ m#A\s+$dir\n#) {
+ system "svn", "revert", $dir;
+ rmdir $dir;
+ }
+ elsif ($svnOutput && $svnOutput =~ m#D\s+$dir\n#) {
+ system "svn", "revert", $dir;
+ }
+ else {
+ # Modification
+ print $svnOutput if $svnOutput;
+ }
+ $checkedDirectories{$dir} = 1;
+ }
+ else {
+ die "'$dir' is not a directory";
+ }
+ }
+ }
+}
+
+# Args:
+# $patch: a patch string.
+# $pathRelativeToRoot: the path of the file to be patched, relative to the
+# repository root. This should normally be the path
+# found in the patch's "Index:" line.
+# $options: a reference to an array of options to pass to the patch command.
+# Do not include --reverse in this array.
+sub unapplyPatch($$;$)
+{
+ my ($patch, $pathRelativeToRoot, $options) = @_;
+
+ my $optionalArgs = {options => $options, ensureForce => $force, shouldReverse => 1};
+
+ my $exitStatus = runPatchCommand($patch, $repositoryRootPath, $pathRelativeToRoot, $optionalArgs);
+
+ if ($exitStatus) {
+ $globalExitStatus = $exitStatus;
+ }
+}
+
+sub unsetChangeLogDate($$)
+{
+ my $fullPath = shift;
+ my $patch = shift;
+ my $newDate;
+ sysopen(CHANGELOG, $fullPath, O_RDONLY) or die "Failed to open $fullPath: $!";
+ sysseek(CHANGELOG, 0, SEEK_SET);
+ my $byteCount = sysread(CHANGELOG, $newDate, 10);
+ die "Failed reading $fullPath: $!" if !$byteCount || $byteCount != 10;
+ close(CHANGELOG);
+ $patch =~ s/(\n\+)\d{4}-[^-]{2}-[^-]{2}( )/$1$newDate$2/;
+ return $patch;
+}
diff --git a/Tools/Scripts/test-webkit-scripts b/Tools/Scripts/test-webkit-scripts
new file mode 100755
index 0000000..781e8ce
--- /dev/null
+++ b/Tools/Scripts/test-webkit-scripts
@@ -0,0 +1,85 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2009, 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+#
+# 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 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 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.
+
+"""Run unit tests of WebKit's Perl and Python scripts."""
+
+# The docstring above is passed as the "description" to the OptionParser
+# used in this script's __main__ block.
+#
+# For the command options supported by this script, see the code below
+# that instantiates the OptionParser class, or else pass --help
+# while running this script (since argument help is auto-generated).
+
+import os
+import subprocess
+import sys
+from optparse import OptionParser
+
+class ScriptsTester(object):
+
+ """Supports running unit tests of WebKit scripts."""
+
+ def __init__(self, scripts_directory):
+ self.scripts_directory = scripts_directory
+
+ def script_path(self, script_file_name):
+ """Return an absolute path to the given script."""
+ return os.path.join(self.scripts_directory, script_file_name)
+
+ def run_test_script(self, script_title, script_path, args=None):
+ """Run the given test script."""
+ print('Testing %s:' % script_title)
+ call_args = [script_path]
+ if args:
+ call_args.extend(args)
+ subprocess.call(call_args)
+ print(70 * "*") # dividing line
+
+ def main(self):
+ parser = OptionParser(description=__doc__)
+ parser.add_option('-a', '--all', dest='all', action='store_true',
+ default=False, help='run all available tests, '
+ 'including those suppressed by default')
+ (options, args) = parser.parse_args()
+
+ self.run_test_script('Perl scripts', self.script_path('test-webkitperl'))
+ self.run_test_script('Python scripts', self.script_path('test-webkitpy'),
+ ['--all'] if options.all else None)
+
+ # FIXME: Display a cumulative indication of success or failure.
+ # In addition, call sys.exit() with 0 or 1 depending on that
+ # cumulative success or failure.
+ print('Note: Perl and Python results appear separately above.')
+
+
+if __name__ == '__main__':
+ # The scripts directory is the directory containing this file.
+ tester = ScriptsTester(os.path.dirname(__file__))
+ tester.main()
diff --git a/Tools/Scripts/test-webkitperl b/Tools/Scripts/test-webkitperl
new file mode 100755
index 0000000..6faa47c
--- /dev/null
+++ b/Tools/Scripts/test-webkitperl
@@ -0,0 +1,59 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2009 Chris Jerdonek (chris.jerdonek@gmail.com)
+#
+# 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.
+
+# Runs unit tests of WebKit Perl code.
+
+use strict;
+use warnings;
+
+use File::Spec;
+use FindBin;
+use Test::Harness;
+use lib $FindBin::Bin; # so this script can be run from any directory.
+use VCSUtils;
+
+# Change the working directory so that we can pass shorter, relative
+# paths to runtests(), rather than longer, absolute paths.
+#
+# We change to the source root so the paths can be relative to the
+# source root. These paths display on the screen, and their meaning
+# will be clearer to the user if relative to the root, rather than to
+# the Scripts directory, say.
+#
+# Source root is two levels up from the Scripts directory.
+my $sourceRootDir = File::Spec->catfile($FindBin::Bin, "../..");
+chdir($sourceRootDir);
+
+# Relative to root
+my $pattern = "Tools/Scripts/webkitperl/*_unittest/*.pl";
+
+my @files = <${pattern}>; # lists files alphabetically
+
+runtests(@files);
diff --git a/Tools/Scripts/test-webkitpy b/Tools/Scripts/test-webkitpy
new file mode 100755
index 0000000..7efacb0
--- /dev/null
+++ b/Tools/Scripts/test-webkitpy
@@ -0,0 +1,266 @@
+#!/usr/bin/env python
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.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.
+
+import logging
+import os
+import sys
+
+# Do not import anything from webkitpy prior to cleaning webkitpy of
+# orphaned *.pyc files. This ensures that no orphaned *.pyc files are
+# accidentally imported during the course of this script.
+#
+# Also, do not import or execute any Python code incompatible with
+# Python 2.4 until after execution of the init() method below.
+
+
+_log = logging.getLogger("test-webkitpy")
+
+
+# Verbose logging is useful for debugging test-webkitpy code that runs
+# before the actual unit tests -- things like autoinstall downloading and
+# unit-test auto-detection logic. This is different from verbose logging
+# of the unit tests themselves (i.e. the unittest module's --verbose flag).
+def configure_logging(is_verbose_logging):
+ """Configure the root logger.
+
+ Configure the root logger not to log any messages from webkitpy --
+ except for messages from the autoinstall module. Also set the
+ logging level as described below.
+
+ Args:
+ is_verbose_logging: A boolean value of whether logging should be
+ verbose. If this parameter is true, the logging
+ level for the handler on the root logger is set to
+ logging.DEBUG. Otherwise, it is set to logging.INFO.
+
+ """
+ # Don't use the Python ternary operator here so that this method will
+ # work with Python 2.4.
+ if is_verbose_logging:
+ logging_level = logging.DEBUG
+ else:
+ logging_level = logging.INFO
+
+ handler = logging.StreamHandler(sys.stderr)
+ # We constrain the level on the handler rather than on the root
+ # logger itself. This is probably better because the handler is
+ # configured and known only to this module, whereas the root logger
+ # is an object shared (and potentially modified) by many modules.
+ # Modifying the handler, then, is less intrusive and less likely to
+ # interfere with modifications made by other modules (e.g. in unit
+ # tests).
+ handler.setLevel(logging_level)
+ formatter = logging.Formatter("%(name)s: %(levelname)-8s %(message)s")
+ handler.setFormatter(formatter)
+
+ logger = logging.getLogger()
+ logger.addHandler(handler)
+ logger.setLevel(logging.NOTSET)
+
+ # Filter out most webkitpy messages.
+ #
+ # Messages can be selectively re-enabled for this script by updating
+ # this method accordingly.
+ def filter(record):
+ """Filter out autoinstall and non-third-party webkitpy messages."""
+ # FIXME: Figure out a way not to use strings here, for example by
+ # using syntax like webkitpy.test.__name__. We want to be
+ # sure not to import any non-Python 2.4 code, though, until
+ # after the version-checking code has executed.
+ if (record.name.startswith("webkitpy.common.system.autoinstall") or
+ record.name.startswith("webkitpy.test")):
+ return True
+ if record.name.startswith("webkitpy"):
+ return False
+ return True
+
+ testing_filter = logging.Filter()
+ testing_filter.filter = filter
+
+ # Display a message so developers are not mystified as to why
+ # logging does not work in the unit tests.
+ _log.info("Suppressing most webkitpy logging while running unit tests.")
+ handler.addFilter(testing_filter)
+
+
+def _clean_pyc_files(dir_to_clean, paths_not_to_log):
+ """Delete from a directory all .pyc files that have no .py file.
+
+ Args:
+ dir_to_clean: The path to the directory to clean.
+ paths_not_to_log: A list of paths to .pyc files whose deletions should
+ not be logged. This list should normally include
+ only test .pyc files.
+
+ """
+ _log.debug("Cleaning orphaned *.pyc files from: %s" % dir_to_clean)
+
+ # Normalize paths not to log.
+ paths_not_to_log = [os.path.abspath(path) for path in paths_not_to_log]
+
+ for dir_path, dir_names, file_names in os.walk(dir_to_clean):
+ for file_name in file_names:
+ if file_name.endswith(".pyc") and file_name[:-1] not in file_names:
+ file_path = os.path.join(dir_path, file_name)
+ if os.path.abspath(file_path) not in paths_not_to_log:
+ _log.info("Deleting orphan *.pyc file: %s" % file_path)
+ os.remove(file_path)
+
+
+# As a substitute for a unit test, this method tests _clean_pyc_files()
+# in addition to calling it. We chose not to use the unittest module
+# because _clean_pyc_files() is called only once and is not used elsewhere.
+def _clean_packages_with_test(external_package_paths):
+ webkitpy_dir = os.path.join(os.path.dirname(__file__), "webkitpy")
+ package_paths = [webkitpy_dir] + external_package_paths
+
+ # The test .pyc file is--
+ # webkitpy/python24/TEMP_test-webkitpy_test_pyc_file.pyc.
+ test_path = os.path.join(webkitpy_dir, "python24",
+ "TEMP_test-webkitpy_test_pyc_file.pyc")
+
+ test_file = open(test_path, "w")
+ try:
+ test_file.write("Test .pyc file generated by test-webkitpy.")
+ finally:
+ test_file.close()
+
+ # Confirm that the test file exists so that when we check that it does
+ # not exist, the result is meaningful.
+ if not os.path.exists(test_path):
+ raise Exception("Test .pyc file not created: %s" % test_path)
+
+ for path in package_paths:
+ _clean_pyc_files(path, [test_path])
+
+ if os.path.exists(test_path):
+ raise Exception("Test .pyc file not deleted: %s" % test_path)
+
+
+def init(command_args, external_package_paths):
+ """Execute code prior to importing from webkitpy.unittests.
+
+ Args:
+ command_args: The list of command-line arguments -- usually
+ sys.argv[1:].
+
+ """
+ verbose_logging_flag = "--verbose-logging"
+ is_verbose_logging = verbose_logging_flag in command_args
+ if is_verbose_logging:
+ # Remove the flag so it doesn't cause unittest.main() to error out.
+ #
+ # FIXME: Get documentation for the --verbose-logging flag to show
+ # up in the usage instructions, which are currently generated
+ # by unittest.main(). It's possible that this will require
+ # re-implementing the option parser for unittest.main()
+ # since there may not be an easy way to modify its existing
+ # option parser.
+ sys.argv.remove(verbose_logging_flag)
+
+ configure_logging(is_verbose_logging)
+ _log.debug("Verbose WebKit logging enabled.")
+
+ # We clean orphaned *.pyc files from the packages prior to importing from
+ # them to make sure that no import statements falsely succeed.
+ # This helps to check that import statements have been updated correctly
+ # after any file moves. Otherwise, incorrect import statements can
+ # be masked.
+ #
+ # For example, if webkitpy/python24/versioning.py were moved to a
+ # different location without changing any import statements, and if
+ # the corresponding .pyc file were left behind without deleting it,
+ # then "import webkitpy.python24.versioning" would continue to succeed
+ # even though it would fail for someone checking out a fresh copy
+ # of the source tree. This is because of a Python feature:
+ #
+ # "It is possible to have a file called spam.pyc (or spam.pyo when -O
+ # is used) without a file spam.py for the same module. This can be used
+ # to distribute a library of Python code in a form that is moderately
+ # hard to reverse engineer."
+ #
+ # ( http://docs.python.org/tutorial/modules.html#compiled-python-files )
+ #
+ # Deleting the orphaned .pyc file prior to importing, however, would
+ # cause an ImportError to occur on import as desired.
+ _clean_packages_with_test(external_package_paths)
+
+ import webkitpy.python24.versioning as versioning
+
+ versioning.check_version(log=_log)
+
+ (comparison, current_version, minimum_version) = \
+ versioning.compare_version()
+
+ if comparison > 0:
+ # Then the current version is later than the minimum version.
+ message = ("You are testing webkitpy with a Python version (%s) "
+ "higher than the minimum version (%s) it was meant "
+ "to support." % (current_version, minimum_version))
+ _log.warn(message)
+
+
+def _path_from_webkit_root(*components):
+ webkit_root = os.path.dirname(os.path.dirname(os.path.dirname(__file__)))
+ return os.path.join(webkit_root, *components)
+
+
+def _test_import(module_path):
+ try:
+ sys.path.append(os.path.dirname(module_path))
+ module_name = os.path.basename(module_path)
+ __import__(module_name)
+ return True
+ except Exception, e:
+ message = "Skipping tests in %s due to failure (%s)." % (module_path, e)
+ if module_name.endswith("QueueStatusServer"):
+ message += " This module is optional. The failure is likely due to a missing Google AppEngine install. (http://code.google.com/appengine/downloads.html)"
+ _log.warn(message)
+ return False
+
+if __name__ == "__main__":
+ # FIXME: We should probably test each package separately to avoid naming conflicts.
+ external_package_paths = [
+ _path_from_webkit_root('WebKit2', 'Scripts', 'webkit2'),
+ _path_from_webkit_root('Tools', 'QueueStatusServer'),
+ ]
+ init(sys.argv[1:], external_package_paths)
+
+ # We import the unit test code after init() to ensure that any
+ # Python version warnings are displayed in case an error occurs
+ # while interpreting webkitpy.unittests. This also allows
+ # logging to be configured prior to importing -- for example to
+ # enable the display of autoinstall logging.log messages while
+ # running the unit tests.
+ from webkitpy.test.main import Tester
+
+ external_package_paths = filter(_test_import, external_package_paths)
+
+ Tester().run_tests(sys.argv, external_package_paths)
diff --git a/Tools/Scripts/update-iexploder-cssproperties b/Tools/Scripts/update-iexploder-cssproperties
new file mode 100755
index 0000000..1a9c0d6
--- /dev/null
+++ b/Tools/Scripts/update-iexploder-cssproperties
@@ -0,0 +1,129 @@
+#!/usr/bin/perl
+
+# Copyright (C) 2007 Apple Inc. All rights reserved.
+# Copyright (C) 2010 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 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.
+
+# This script updates Tools/iExploder/htdocs/*.in based on
+# WebCore/css/CSSPropertyNames.in, WebCore/html/HTMLTagNames.in
+# and WebCore/html/HTMLAttributeNames.in
+
+use warnings;
+use strict;
+
+use FindBin;
+use lib $FindBin::Bin;
+use VCSUtils;
+use webkitdirs;
+
+use File::Spec;
+
+sub generateEntityListFromFile($);
+sub readiExploderFile($);
+sub update($$);
+sub writeiExploderFile($@);
+
+update("cssproperties.in", "css/CSSPropertyNames.in");
+update("htmlattrs.in", "html/HTMLAttributeNames.in");
+update("htmltags.in", "html/HTMLTagNames.in");
+print "Successfully updated!\n";
+
+exit 0;
+
+sub generateEntityListFromFile($)
+{
+ my ($filename) = @_;
+
+ my $revision = svnRevisionForDirectory(dirname($filename));
+ my $path = File::Spec->abs2rel($filename, sourceDir());
+ my $result = "# From WebKit svn r" . $revision . " (" . $path . ")\n";
+
+ my @entities = ();
+ my $in_namespace = 0;
+
+ open(IN, $filename) || die "$!";
+ while (my $l = <IN>) {
+ chomp $l;
+ if ($l =~ m/^namespace=\"/) {
+ $in_namespace = 1;
+ } elsif ($in_namespace && $l =~ m/^$/) {
+ $in_namespace = 0;
+ }
+
+ next if $in_namespace;
+ next if $l =~ m/^\s*#/ || $l =~ m/^\s*$/;
+
+ # For HTML Tags that can have additional information
+ if ($l =~ m/ /) {
+ my @split = split / /, $l;
+ $l = $split[0]
+ }
+
+ push(@entities, $l);
+ }
+ close(IN);
+
+ $result .= join("\n", sort { $a cmp $b } @entities) . "\n\n";
+
+ return $result;
+}
+
+sub readiExploderFile($)
+{
+ my ($filename) = @_;
+
+ my @sections = ();
+ local $/ = "\n\n";
+
+ open(IN, $filename) || die "$!";
+ @sections = <IN>;
+ close(IN);
+
+ return @sections;
+}
+
+sub update($$)
+{
+ my ($iexploderPath, $webcorePath) = @_;
+
+ $iexploderPath = File::Spec->catfile(sourceDir(), "Tools", "iExploder", "htdocs", split("/", $iexploderPath));
+ $webcorePath = File::Spec->catfile(sourceDir(), "WebCore", split("/", $webcorePath));
+
+ my @sections = readiExploderFile($iexploderPath);
+ $sections[0] = generateEntityListFromFile($webcorePath);
+ writeiExploderFile($iexploderPath, @sections);
+}
+
+
+sub writeiExploderFile($@)
+{
+ my ($filename, @sections) = @_;
+
+ open(OUT, "> $filename") || die "$!";
+ print OUT join("", @sections);
+ close(OUT);
+}
+
diff --git a/Tools/Scripts/update-javascriptcore-test-results b/Tools/Scripts/update-javascriptcore-test-results
new file mode 100755
index 0000000..dd8b9b6
--- /dev/null
+++ b/Tools/Scripts/update-javascriptcore-test-results
@@ -0,0 +1,73 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+use strict;
+use FindBin;
+use Getopt::Long;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+chdirWebKit();
+chdir "JavaScriptCore/tests/mozilla" or die;
+
+my $force = 0;
+GetOptions('force' => \$force);
+
+open EXPECTED, "expected.html" or die;
+while (<EXPECTED>) {
+ last if /failures reported\.$/;
+}
+my %expected;
+while (<EXPECTED>) {
+ chomp;
+ $expected{$_} = 1;
+}
+close EXPECTED;
+
+open ACTUAL, "actual.html" or die;
+my $actual;
+while (<ACTUAL>) {
+ $actual .= $_;
+ last if /failures reported\.$/;
+}
+my $failed = 0;
+while (<ACTUAL>) {
+ $actual .= $_;
+ chomp;
+ if (!$expected{$_}) {
+ $failed = 1;
+ print "failure not expected: $_\n";
+ }
+}
+close ACTUAL;
+
+die "won't update, failures introduced\n" if $failed && !$force;
+
+open EXPECTED, ">expected.html";
+print EXPECTED $actual;
+close EXPECTED;
diff --git a/Tools/Scripts/update-sources-list.py b/Tools/Scripts/update-sources-list.py
new file mode 100755
index 0000000..433d04a
--- /dev/null
+++ b/Tools/Scripts/update-sources-list.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2007 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.
+#
+# Make sure any port-independent files added to the Bakefile are
+# added to GTK, QT, etc. so that file updates can happen in one place.
+
+import os, sys
+from xml.dom import minidom
+
+scriptDir = os.path.abspath(sys.path[0])
+wkroot = os.path.abspath(os.path.join(scriptDir, "../.."))
+
+def getWebCoreFilesDict():
+ """
+ This method parses the WebCoreSources.bkl file, which has a list of all sources not specific
+ to any port, and returns the result as a dictionary with items of the form
+ (groupName, groupFiles).
+ """
+ sources = {}
+ sources_prefix = "WEBCORE_"
+ filepath = os.path.join(wkroot, "WebCore/WebCoreSources.bkl")
+ assert(os.path.exists(filepath))
+
+ doc = minidom.parse(filepath)
+ for sourceGroup in doc.getElementsByTagName("set"):
+ groupName = ""
+ if sourceGroup.attributes.has_key("var"):
+ groupName = sourceGroup.attributes["var"].value
+ groupName = groupName.replace(sources_prefix, "")
+
+ sourcesList = []
+ for node in sourceGroup.childNodes:
+ if node.nodeType == node.TEXT_NODE:
+ sourcesText = node.nodeValue.strip()
+ sourcesList = sourcesText.split("\n")
+
+ assert(groupName != "")
+ assert(sourcesList != [])
+
+ sources[groupName] = sourcesList
+
+ return sources
+
+def generateWebCoreSourcesGTKAndQT(sources):
+ """
+ Convert the dictionary obtained from getWebCoreFilesDict() into a Unix makefile syntax,
+ which IIUC is suitable for both GTK and QT build systems. To take advantage of this,
+ QT and GTK would have to include the file "WebCore/sources.inc" into their makefiles.
+ """
+ makefileString = ""
+
+ for key in sources.keys():
+ makefileString += key + "+="
+ for source in sources[key]:
+ makefileString += " \\\n\t\t" + source.strip()
+
+ makefileString += "\n\n"
+
+ makefileString += "BASE_SOURCES +="
+ for key in sources.keys():
+ makefileString += " \\\n\t\t" + key
+
+ outfile = os.path.join(wkroot, "WebCore/sources.inc")
+ sourcefile = open(outfile, "w")
+ sourcefile.write(makefileString)
+ sourcefile.close()
+
+sources = getWebCoreFilesDict()
+generateWebCoreSourcesGTKAndQT(sources)
+
+# Coming soon - MSVC and hopefully XCode support!
diff --git a/Tools/Scripts/update-webgl-conformance-tests b/Tools/Scripts/update-webgl-conformance-tests
new file mode 100755
index 0000000..dfe20a1
--- /dev/null
+++ b/Tools/Scripts/update-webgl-conformance-tests
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+# 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.
+
+"""Wrapper around webkitpy/layout_tests/update-webgl-conformance-tests.py"""
+
+import webkitpy.layout_tests.update_webgl_conformance_tests
+import sys
+
+if __name__ == '__main__':
+ sys.exit(webkitpy.layout_tests.update_webgl_conformance_tests.main())
diff --git a/Tools/Scripts/update-webkit b/Tools/Scripts/update-webkit
new file mode 100755
index 0000000..6d3e0ee
--- /dev/null
+++ b/Tools/Scripts/update-webkit
@@ -0,0 +1,133 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+# 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:
+#
+# 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.
+
+# Update script for WebKit Open Source Project.
+
+use strict;
+use FindBin;
+use lib $FindBin::Bin;
+use File::Basename;
+use File::Path;
+use File::Spec;
+use Getopt::Long;
+use VCSUtils;
+use webkitdirs;
+
+sub runSvnUpdate();
+sub runGitUpdate();
+
+# Handle options
+my $quiet = '';
+my $showHelp;
+
+determineIsChromium();
+
+chdirWebKit();
+
+my $isGit = isGit();
+my $isSVN = isSVN();
+
+my $getOptionsResult = GetOptions(
+ 'h|help' => \$showHelp,
+ 'q|quiet' => \$quiet,
+);
+
+if (!$getOptionsResult || $showHelp) {
+ print STDERR <<__END__;
+Usage: @{[ basename($0) ]} [options]
+ --chromium also update dependencies of the chromium port
+ -h|--help show the help message
+ -q|--quiet pass -q to svn update for quiet updates
+__END__
+ exit 1;
+}
+
+my $startTime = time();
+
+my @svnOptions = ();
+push @svnOptions, '-q' if $quiet;
+
+# Don't prompt when using svn-1.6 or newer.
+push @svnOptions, qw(--accept postpone) if isSVNVersion16OrNewer();
+
+print "Updating OpenSource\n" unless $quiet;
+runSvnUpdate() if $isSVN;
+runGitUpdate() if $isGit;
+
+if (-d "../Internal") {
+ chdir("../Internal");
+ print "Updating Internal\n" unless $quiet;
+ runSvnUpdate() if $isSVN;
+ runGitUpdate() if $isGit;
+} elsif (isChromium()) {
+ # Workaround for https://bugs.webkit.org/show_bug.cgi?id=38926
+ # We should remove the following "if" block when we find a right fix.
+ if ((isCygwin() || isWindows()) && (stat("WebKit/chromium/features.gypi"))[9] >= $startTime) {
+ print "features.gypi has been updated. Cleaning the build directories.\n";
+ rmtree(["WebKit/chromium/Debug", "WebKit/chromium/Release"]);
+ }
+
+ system("perl", "Tools/Scripts/update-webkit-chromium") == 0 or die $!;
+} elsif (isAppleWinWebKit()) {
+ system("perl", "Tools/Scripts/update-webkit-auxiliary-libs") == 0 or die;
+}
+
+setupAppleWinEnv() if isAppleWinWebKit();
+
+exit 0;
+
+sub runSvnUpdate()
+{
+ open UPDATE, "-|", "svn", "update", @svnOptions or die;
+ my @conflictedChangeLogs;
+ while (my $line = <UPDATE>) {
+ print $line;
+ $line =~ m/^C\s+(.+?)[\r\n]*$/;
+ if ($1) {
+ my $filename = normalizePath($1);
+ push @conflictedChangeLogs, $filename if basename($filename) eq "ChangeLog";
+ }
+ }
+ close UPDATE or die;
+
+ if (@conflictedChangeLogs) {
+ print "Attempting to merge conflicted ChangeLogs.\n";
+ my $resolveChangeLogsPath = File::Spec->catfile(dirname($0), "resolve-ChangeLogs");
+ (system($resolveChangeLogsPath, "--no-warnings", @conflictedChangeLogs) == 0)
+ or die "Could not open resolve-ChangeLogs script: $!.\n";
+ }
+}
+
+sub runGitUpdate()
+{
+ # Doing a git fetch first allows setups with svn-remote.svn.fetch = trunk:refs/remotes/origin/master
+ # to perform the rebase much much faster.
+ system("git", "fetch") == 0 or die;
+ system("git", "svn", "rebase") == 0 or die;
+}
diff --git a/Tools/Scripts/update-webkit-auxiliary-libs b/Tools/Scripts/update-webkit-auxiliary-libs
new file mode 100755
index 0000000..19e4ad3
--- /dev/null
+++ b/Tools/Scripts/update-webkit-auxiliary-libs
@@ -0,0 +1,134 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007 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.
+
+# Updates a development environment to the new WebKitAuxiliaryLibrary
+
+use strict;
+use warnings;
+
+use File::Find;
+use File::Spec;
+use File::Temp ();
+use FindBin;
+use HTTP::Date qw(str2time);
+use POSIX;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+sub lastModifiedToUnixTime($);
+
+# Time in seconds that the new zip file must be newer than the old for us to
+# consider them to be different. If the difference in modification time is less
+# than this threshold, we assume that the files are the same. We need this
+# because the zip file is served from a set of mirrors with slightly different
+# Last-Modified times.
+my $newnessThreshold = 30;
+
+my $sourceDir = sourceDir();
+my $file = "WebKitAuxiliaryLibrary";
+my $zipFile = "$file.zip";
+my $auxiliaryLibsURL = "http://developer.apple.com/opensource/internet/$zipFile";
+my $webkitLibrariesDir = toUnixPath($ENV{'WEBKITLIBRARIESDIR'}) || "$sourceDir/WebKitLibraries/win";
+my $tmpDir = File::Spec->rel2abs(File::Temp::tempdir("webkitlibsXXXXXXX", TMPDIR => 1, CLEANUP => 1));
+
+print "Checking Last-Modified date of $zipFile...\n";
+
+my $result = system "curl -s -I $auxiliaryLibsURL | grep Last-Modified > \"$tmpDir/$file.headers\"";
+
+if (WEXITSTATUS($result)) {
+ print STDERR "Couldn't check Last-Modified date of new $zipFile.\n";
+ print STDERR "Please ensure that $auxiliaryLibsURL is reachable.\n";
+
+ if (! -f "$webkitLibrariesDir/$file.headers") {
+ print STDERR "Unable to check Last-Modified date and no version of $file to fall back to.\n";
+ exit 1;
+ }
+
+ print STDERR "Falling back to existing version of $file.\n";
+ exit 0;
+}
+
+if (open NEW, "$tmpDir/$file.headers") {
+ my $new = lastModifiedToUnixTime(<NEW>);
+ close NEW;
+
+ if (defined $new && open OLD, "$webkitLibrariesDir/$file.headers") {
+ my $old = lastModifiedToUnixTime(<OLD>);
+ close OLD;
+ if (defined $old && abs($new - $old) < $newnessThreshold) {
+ print "Current $file is up to date\n";
+ exit 0;
+ }
+ }
+}
+
+print "Downloading $zipFile...\n\n";
+$result = system "curl -o \"$tmpDir/$zipFile\" $auxiliaryLibsURL";
+die "Couldn't download $zipFile!" if $result;
+
+$result = system "unzip", "-q", "-d", $tmpDir, "$tmpDir/$zipFile";
+die "Couldn't unzip $zipFile." if $result;
+
+print "\nInstalling $file...\n";
+
+sub wanted
+{
+ my $relativeName = File::Spec->abs2rel($File::Find::name, "$tmpDir/$file/win");
+ my $destination = "$webkitLibrariesDir/$relativeName";
+
+ if (-d $_) {
+ mkdir $destination;
+ return;
+ }
+
+ system "cp", $_, $destination;
+}
+
+File::Find::find(\&wanted, "$tmpDir/$file");
+
+$result = system "mv", "$tmpDir/$file.headers", $webkitLibrariesDir;
+print STDERR "Couldn't move $file.headers to $webkitLibrariesDir" . ".\n" if $result;
+
+print "The $file has been sucessfully installed in\n $webkitLibrariesDir\n";
+exit;
+
+sub toUnixPath
+{
+ my $path = shift;
+ return unless $path;
+ chomp($path = `cygpath -u '$path'`);
+ return $path;
+}
+
+sub lastModifiedToUnixTime($)
+{
+ my ($str) = @_;
+
+ $str =~ /^Last-Modified: (.*)$/ or return;
+ return str2time($1);
+}
diff --git a/Tools/Scripts/update-webkit-chromium b/Tools/Scripts/update-webkit-chromium
new file mode 100755
index 0000000..1db1826
--- /dev/null
+++ b/Tools/Scripts/update-webkit-chromium
@@ -0,0 +1,68 @@
+#!/usr/bin/perl -w
+
+# 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:
+#
+# 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.
+
+# Update script for the WebKit Chromium Port.
+
+use File::Path;
+use FindBin;
+use Getopt::Long;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+chdir("WebKit/chromium") or die $!;
+
+# Find gclient or install it.
+my $gclientPath;
+if (commandExists('gclient')) {
+ $gclientPath = 'gclient';
+} elsif (-e 'depot_tools/gclient') {
+ $gclientPath = 'depot_tools/gclient';
+} else {
+ print "Installing chromium's depot_tools...\n";
+ system("svn co http://src.chromium.org/svn/trunk/tools/depot_tools") == 0 or die $1;
+ $gclientPath = 'depot_tools/gclient';
+}
+
+if (! -e ".gclient") {
+ # If .gclient configuration file doesn't exist, create it.
+ print "Configuring gclient...\n";
+ system($gclientPath,
+ "config",
+ "--spec=solutions=[{'name':'./','url':None}]") == 0 or die $!;
+}
+
+my $force = 0;
+GetOptions(
+ 'force' => \$force,
+);
+
+# Execute gclient sync.
+print "Updating chromium port dependencies using gclient...\n";
+my @gclientArgs = ($gclientPath, "sync");
+push @gclientArgs, "--force" if $force;
+system(@gclientArgs) == 0 or die $!;
diff --git a/Tools/Scripts/update-webkit-localizable-strings b/Tools/Scripts/update-webkit-localizable-strings
new file mode 100755
index 0000000..7030337
--- /dev/null
+++ b/Tools/Scripts/update-webkit-localizable-strings
@@ -0,0 +1,46 @@
+#!/usr/bin/perl -w
+
+# 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.
+
+use strict;
+use warnings;
+
+use File::Basename;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+my @directoriesToScan = ("WebKit/mac", "WebKit/win", "-WebCore/icu", "-WebKit/mac/icu");
+my $fileToUpdate = "WebKit/English.lproj/Localizable.strings";
+my $exceptionsFile = "WebKit/StringsNotToBeLocalized.txt";
+
+@ARGV == 0 or die "Usage: " . basename($0) . "\n";
+
+chdirWebKit();
+
+system "sort -u $exceptionsFile -o $exceptionsFile";
+exec "./Tools/Scripts/extract-localizable-strings", $exceptionsFile, $fileToUpdate, @directoriesToScan;
diff --git a/Tools/Scripts/update-webkit-support-libs b/Tools/Scripts/update-webkit-support-libs
new file mode 100755
index 0000000..f0c897e
--- /dev/null
+++ b/Tools/Scripts/update-webkit-support-libs
@@ -0,0 +1,148 @@
+#!/usr/bin/perl -w
+
+# Copyright (C) 2005, 2006, 2007 Apple Computer, Inc. All rights reserved.
+# Copyright (C) Research In Motion Limited 2010. 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.
+
+# Updates a development environment to the new WebKitSupportLibrary
+
+use strict;
+use warnings;
+
+use File::Find;
+use File::Temp ();
+use File::Spec;
+use FindBin;
+use lib $FindBin::Bin;
+use webkitdirs;
+
+use constant NOTAVERSION => "-1";
+
+my $sourceDir = sourceDir();
+my $file = "WebKitSupportLibrary";
+my $zipFile = "$file.zip";
+my $zipDirectory = toUnixPath($ENV{'WEBKITSUPPORTLIBRARIESZIPDIR'}) || $sourceDir;
+my $pathToZip = File::Spec->catfile($zipDirectory, $zipFile);
+my $webkitLibrariesDir = toUnixPath($ENV{'WEBKITLIBRARIESDIR'}) || "$sourceDir/WebKitLibraries/win";
+my $versionFile = $file . "Version";
+my $pathToVersionFile = File::Spec->catfile($webkitLibrariesDir, $versionFile);
+my $tmpDir = File::Spec->rel2abs(File::Temp::tempdir("webkitlibsXXXXXXX", TMPDIR => 1, CLEANUP => 1));
+my $versionFileURL = "http://developer.apple.com/opensource/internet/$versionFile";
+
+my $extractedVersion = extractedVersion();
+
+# Check whether the extracted library is up-to-date. If it is, we don't have anything to do.
+my $expectedVersion = downloadExpectedVersionNumber();
+if ($extractedVersion ne NOTAVERSION && $extractedVersion eq $expectedVersion) {
+ print "$file is up-to-date.\n";
+ exit;
+}
+
+# Check whether the downloaded library is up-to-date. If it isn't, the user needs to download it.
+my $zipFileVersion = zipFileVersion();
+dieAndInstructToDownload("$zipFile could not be found in $zipDirectory.") if $zipFileVersion eq NOTAVERSION;
+dieAndInstructToDownload("$zipFile is out-of-date.") if $expectedVersion ne NOTAVERSION && $zipFileVersion ne $expectedVersion;
+if ($zipFileVersion eq $extractedVersion) {
+ print "Falling back to existing version of $file.\n";
+ exit;
+}
+
+my $result = system "unzip", "-q", "-d", $tmpDir, $pathToZip;
+die "Couldn't unzip $zipFile." if $result;
+
+print "\nInstalling $file...\n";
+
+sub wanted
+{
+ my $relativeName = File::Spec->abs2rel($File::Find::name, "$tmpDir/$file/win");
+ my $destination = "$webkitLibrariesDir/$relativeName";
+
+ if (-d $_) {
+ mkdir $destination;
+ return;
+ }
+
+ system "cp", $_, $destination;
+}
+
+File::Find::find(\&wanted, "$tmpDir/$file");
+
+print "The $file has been sucessfully installed in\n $webkitLibrariesDir\n";
+exit;
+
+sub toUnixPath
+{
+ my $path = shift;
+ return unless $path;
+ chomp($path = `cygpath -u '$path'`);
+ return $path;
+}
+
+sub extractedVersion
+{
+ if (open VERSION, "<", $pathToVersionFile) {
+ chomp(my $extractedVersion = <VERSION>);
+ close VERSION;
+ return $extractedVersion;
+ }
+ return NOTAVERSION;
+}
+
+sub downloadExpectedVersionNumber
+{
+ chomp(my $expectedVersion = `curl -s $versionFileURL`);
+ return WEXITSTATUS($?) ? NOTAVERSION : $expectedVersion;
+}
+
+sub zipFileVersion
+{
+ return NOTAVERSION unless -f $pathToZip;
+ chomp(my $zipFileVersion = `unzip -p "$pathToZip" $file/win/$versionFile`);
+ return $zipFileVersion;
+}
+
+sub dieAndInstructToDownload
+{
+ my $message = shift;
+
+ die <<EOF;
+
+===============================================================================
+$message
+Please download $zipFile from:
+
+ http://developer.apple.com/opensource/internet/webkit_sptlib_agree.html
+
+and place it in:
+
+ $sourceDir
+
+Then run build-webkit again.
+===============================================================================
+
+EOF
+
+}
diff --git a/Tools/Scripts/validate-committer-lists b/Tools/Scripts/validate-committer-lists
new file mode 100755
index 0000000..2519e01
--- /dev/null
+++ b/Tools/Scripts/validate-committer-lists
@@ -0,0 +1,260 @@
+#!/usr/bin/env python
+
+# 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.
+#
+# Checks Python's known list of committers against lists.webkit.org and SVN history.
+
+
+import os
+import subprocess
+import re
+import urllib2
+from datetime import date, datetime, timedelta
+from webkitpy.common.config.committers import CommitterList
+from webkitpy.common.system.deprecated_logging import log, error
+from webkitpy.common.checkout.scm import Git
+
+# WebKit includes a built copy of BeautifulSoup in Scripts/webkitpy
+# so this import should always succeed.
+from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
+
+def print_list_if_non_empty(title, list_to_print):
+ if not list_to_print:
+ return
+ print # Newline before the list
+ print title
+ for item in list_to_print:
+ print item
+
+class CommitterListFromMailingList:
+ committers_list_url = "http://lists.webkit.org/mailman/roster.cgi/webkit-committers"
+ reviewers_list_url = "http://lists.webkit.org/mailman/roster.cgi/webkit-reviewers"
+
+ def _fetch_emails_from_page(self, url):
+ page = urllib2.urlopen(url)
+ soup = BeautifulSoup(page)
+
+ emails = []
+ # Grab the cells in the first column (which happens to be the bug ids).
+ for email_item in soup('li'):
+ email_link = email_item.find("a")
+ email = email_link.string.replace(" at ", "@") # The email is obfuscated using " at " instead of "@".
+ emails.append(email)
+ return emails
+
+ @staticmethod
+ def _commiters_not_found_in_email_list(committers, emails):
+ missing_from_mailing_list = []
+ for committer in committers:
+ for email in committer.emails:
+ if email in emails:
+ break
+ else:
+ missing_from_mailing_list.append(committer)
+ return missing_from_mailing_list
+
+ @staticmethod
+ def _emails_not_found_in_committer_list(committers, emails):
+ email_to_committer_map = {}
+ for committer in committers:
+ for email in committer.emails:
+ email_to_committer_map[email] = committer
+
+ return filter(lambda email: not email_to_committer_map.get(email), emails)
+
+ def check_for_emails_missing_from_list(self, committer_list):
+ committer_emails = self._fetch_emails_from_page(self.committers_list_url)
+ list_name = "webkit-committers@lists.webkit.org"
+
+ missing_from_mailing_list = self._commiters_not_found_in_email_list(committer_list.committers(), committer_emails)
+ print_list_if_non_empty("Committers missing from %s:" % list_name, missing_from_mailing_list)
+
+ users_missing_from_committers = self._emails_not_found_in_committer_list(committer_list.committers(), committer_emails)
+ print_list_if_non_empty("Subcribers to %s missing from committer.py:" % list_name, users_missing_from_committers)
+
+
+ reviewer_emails = self._fetch_emails_from_page(self.reviewers_list_url)
+ list_name = "webkit-reviewers@lists.webkit.org"
+
+ missing_from_mailing_list = self._commiters_not_found_in_email_list(committer_list.reviewers(), reviewer_emails)
+ print_list_if_non_empty("Reviewers missing from %s:" % list_name, missing_from_mailing_list)
+
+ missing_from_reviewers = self._emails_not_found_in_committer_list(committer_list.reviewers(), reviewer_emails)
+ print_list_if_non_empty("Subcribers to %s missing from reviewers in committer.py:" % list_name, missing_from_reviewers)
+
+ missing_from_committers = self._emails_not_found_in_committer_list(committer_list.committers(), reviewer_emails)
+ print_list_if_non_empty("Subcribers to %s completely missing from committers.py" % list_name, missing_from_committers)
+
+
+class CommitterListFromGit:
+ login_to_email_address = {
+ 'aliceli1' : 'alice.liu@apple.com',
+ 'bdash' : 'mrowe@apple.com',
+ 'bdibello' : 'bdibello@apple.com', # Bruce DiBello, only 4 commits: r10023, r9548, r9538, r9535
+ 'cblu' : 'cblu@apple.com',
+ 'cpeterse' : 'cpetersen@apple.com',
+ 'eseidel' : 'eric@webkit.org',
+ 'gdennis' : 'gdennis@webkit.org',
+ 'goldsmit' : 'goldsmit@apple.com', # Debbie Goldsmith, only one commit r8839
+ 'gramps' : 'gramps@apple.com',
+ 'honeycutt' : 'jhoneycutt@apple.com',
+ 'jdevalk' : 'joost@webkit.org',
+ 'jens' : 'jens@apple.com',
+ 'justing' : 'justin.garcia@apple.com',
+ 'kali' : 'kali@apple.com', # Christy Warren, did BIDI work, 5 commits: r8815, r8802, r8801, r8791, r8773, r8603
+ 'kjk' : 'kkowalczyk@gmail.com',
+ 'kmccullo' : 'kmccullough@apple.com',
+ 'kocienda' : 'kocienda@apple.com',
+ 'lamadio' : 'lamadio@apple.com', # Lou Amadio, only 2 commits: r17949 and r17783
+ 'lars' : 'lars@kde.org',
+ 'lweintraub' : 'lweintraub@apple.com',
+ 'lypanov' : 'lypanov@kde.org',
+ 'mhay' : 'mhay@apple.com', # Mike Hay, 3 commits: r3813, r2552, r2548
+ 'ouch' : 'ouch@apple.com', # John Louch
+ 'pyeh' : 'patti@apple.com', # Patti Yeh, did VoiceOver work in WebKit
+ 'rjw' : 'rjw@apple.com',
+ 'seangies' : 'seangies@apple.com', # Sean Gies?, only 5 commits: r16600, r16592, r16511, r16489, r16484
+ 'sheridan' : 'sheridan@apple.com', # Shelly Sheridan
+ 'thatcher' : 'timothy@apple.com',
+ 'tomernic' : 'timo@apple.com',
+ 'trey' : 'trey@usa.net',
+ 'tristan' : 'tristan@apple.com',
+ 'vicki' : 'vicki@apple.com',
+ 'voas' : 'voas@apple.com', # Ed Voas, did some Carbon work in WebKit
+ 'zack' : 'zack@kde.org',
+ 'zimmermann' : 'zimmermann@webkit.org',
+ }
+
+ def __init__(self):
+ self._last_commit_time_by_author_cache = {}
+
+ def _fetch_authors_and_last_commit_time_from_git_log(self):
+ last_commit_dates = {}
+ git_log_args = ['git', 'log', '--reverse', '--pretty=format:%ae %at']
+ process = subprocess.Popen(git_log_args, stdout=subprocess.PIPE)
+
+ # eric@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc 1257090899
+ line_regexp = re.compile("^(?P<author>.+)@\S+ (?P<timestamp>\d+)$")
+ while True:
+ output_line = process.stdout.readline()
+ if output_line == '' and process.poll() != None:
+ return last_commit_dates
+
+ match_result = line_regexp.match(output_line)
+ if not match_result:
+ error("Failed to match line: %s" % output_line)
+ last_commit_dates[match_result.group('author')] = float(match_result.group('timestamp'))
+
+ def _fill_in_emails_for_old_logins(self):
+ authors_missing_email = filter(lambda author: author.find('@') == -1, self._last_commit_time_by_author_cache)
+ authors_with_email = filter(lambda author: author.find('@') != -1, self._last_commit_time_by_author_cache)
+ prefixes_of_authors_with_email = map(lambda author: author.split('@')[0], authors_with_email)
+
+ for author in authors_missing_email:
+ # First check to see if we have a manual mapping from login to email.
+ author_email = self.login_to_email_address.get(author)
+
+ # Most old logins like 'darin' are now just 'darin@apple.com', so check for a prefix match if a manual mapping was not found.
+ if not author_email and author in prefixes_of_authors_with_email:
+ author_email_index = prefixes_of_authors_with_email.index(author)
+ author_email = authors_with_email[author_email_index]
+
+ if not author_email:
+ # No known email mapping, likely not an active committer. We could log here.
+ continue
+
+ # log("%s -> %s" % (author, author_email)) # For sanity checking.
+ no_email_commit_time = self._last_commit_time_by_author_cache.get(author)
+ email_commit_time = self._last_commit_time_by_author_cache.get(author_email)
+ # We compare the timestamps for extra sanity even though we could assume commits before email address were used for login are always going to be older.
+ if not email_commit_time or email_commit_time < no_email_commit_time:
+ self._last_commit_time_by_author_cache[author_email] = no_email_commit_time
+ del self._last_commit_time_by_author_cache[author]
+
+ def _last_commit_by_author(self):
+ if not self._last_commit_time_by_author_cache:
+ self._last_commit_time_by_author_cache = self._fetch_authors_and_last_commit_time_from_git_log()
+ self._fill_in_emails_for_old_logins()
+ del self._last_commit_time_by_author_cache['(no author)'] # The initial svn import isn't very useful.
+ return self._last_commit_time_by_author_cache
+
+ @staticmethod
+ def _print_three_column_row(widths, values):
+ print "%s%s%s" % (values[0].ljust(widths[0]), values[1].ljust(widths[1]), values[2])
+
+ def print_possibly_expired_committers(self, committer_list):
+ authors_and_last_commits = self._last_commit_by_author().items()
+ authors_and_last_commits.sort(lambda a,b: cmp(a[1], b[1]), reverse=True)
+ committer_cuttof = date.today() - timedelta(days=365)
+ column_widths = [13, 25]
+ print
+ print "Committers who have not committed within one year:"
+ self._print_three_column_row(column_widths, ("Last Commit", "Committer Email", "Committer Record"))
+ for (author, last_commit) in authors_and_last_commits:
+ last_commit_date = date.fromtimestamp(last_commit)
+ if committer_cuttof > last_commit_date:
+ committer_record = committer_list.committer_by_email(author)
+ self._print_three_column_row(column_widths, (str(last_commit_date), author, committer_record))
+
+ def print_committers_missing_from_committer_list(self, committer_list):
+ missing_from_committers_py = []
+ last_commit_time_by_author = self._last_commit_by_author()
+ for author in last_commit_time_by_author:
+ if not committer_list.committer_by_email(author):
+ missing_from_committers_py.append(author)
+
+ never_committed = []
+ for committer in committer_list.committers():
+ for email in committer.emails:
+ if last_commit_time_by_author.get(email):
+ break
+ else:
+ never_committed.append(committer)
+
+ print_list_if_non_empty("Historical committers missing from committer.py:", missing_from_committers_py)
+ print_list_if_non_empty("Committers in committer.py who have never committed:", never_committed)
+
+
+def main():
+ committer_list = CommitterList()
+ CommitterListFromMailingList().check_for_emails_missing_from_list(committer_list)
+
+ if not Git.in_working_directory("."):
+ print """\n\nWARNING: validate-committer-lists requires a git checkout.
+The following checks are disabled:
+ - List of committers ordered by last commit
+ - List of historical committers missing from committers.py
+"""
+ return 1
+ svn_committer_list = CommitterListFromGit()
+ svn_committer_list.print_possibly_expired_committers(committer_list)
+ svn_committer_list.print_committers_missing_from_committer_list(committer_list)
+
+if __name__ == "__main__":
+ main()
diff --git a/Tools/Scripts/webkit-build-directory b/Tools/Scripts/webkit-build-directory
new file mode 100755
index 0000000..bf7d66d
--- /dev/null
+++ b/Tools/Scripts/webkit-build-directory
@@ -0,0 +1,69 @@
+#!/usr/bin/perl
+
+# 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.
+# 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.
+
+# A script to expose WebKit's build directory detection logic to non-perl scripts.
+
+use FindBin;
+use Getopt::Long;
+
+use lib $FindBin::Bin;
+use webkitdirs;
+
+my $showConfigurationDirectory = 0;
+my $showHelp = 0;
+my $showTopLevelDirectory = 0;
+
+
+my $programName = basename($0);
+my $usage = <<EOF;
+Usage: $programName [options]
+ --configuration Show the build directory for a specific configuration (e.g. Debug, Release. Defaults to the active configuration set by set-webkit-configuration)
+ -h|--help Show this help message
+ --top-level Show the top-level build directory
+
+Either --configuration or --top-level is required.
+EOF
+
+setConfiguration(); # Figure out from the command line if we're --debug or --release or the default.
+
+my $getOptionsResult = GetOptions(
+ 'configuration' => \$showConfigurationDirectory,
+ 'top-level' => \$showTopLevelDirectory,
+ 'help|h' => \$showHelp,
+);
+
+if (!$getOptionsResult || $showHelp || (!$showConfigurationDirectory && !$showTopLevelDirectory)) {
+ print STDERR $usage;
+ exit 1;
+}
+
+if ($showTopLevelDirectory) {
+ print baseProductDir() . "\n";
+} else {
+ print productDir() . "\n";
+}
diff --git a/Tools/Scripts/webkit-patch b/Tools/Scripts/webkit-patch
new file mode 100755
index 0000000..007f919
--- /dev/null
+++ b/Tools/Scripts/webkit-patch
@@ -0,0 +1,70 @@
+#!/usr/bin/env python
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.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.
+#
+# A tool for automating dealing with bugzilla, posting patches, committing patches, etc.
+
+import logging
+import os
+import sys
+
+from webkitpy.common.system.logutils import configure_logging
+import webkitpy.python24.versioning as versioning
+
+_log = logging.getLogger("webkit-patch")
+
+def main():
+ # This is a hack to let us enable DEBUG logging as early as possible.
+ # Note this can't be ternary as versioning.check_version()
+ # hasn't run yet and this python might be older than 2.5.
+ if set(["-v", "--verbose"]).intersection(set(sys.argv)):
+ logging_level = logging.DEBUG
+ else:
+ logging_level = logging.INFO
+ configure_logging(logging_level=logging_level)
+
+ versioning.check_version()
+
+ if sys.platform == "win32":
+ _log.fatal("webkit-patch is only supported under Cygwin Python, "
+ "not Win32 Python")
+ sys.exit(1)
+
+ # Import webkit-patch code only after version-checking so that
+ # script doesn't error out before having a chance to report the
+ # version warning.
+ from webkitpy.tool.main import WebKitPatch
+
+ WebKitPatch(__file__).main()
+
+
+if __name__ == "__main__":
+
+ main()
diff --git a/Tools/Scripts/webkit-tools-completion.sh b/Tools/Scripts/webkit-tools-completion.sh
new file mode 100644
index 0000000..cdedfe3
--- /dev/null
+++ b/Tools/Scripts/webkit-tools-completion.sh
@@ -0,0 +1,95 @@
+# 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.
+#
+# Command line completion for common commands used in WebKit development.
+#
+# Set-up:
+# Add a line like this to your .bashrc:
+# source /path/to/WebKitCode/Tools/Scripts/webkit-tools-completion.sh
+
+__webkit-patch_generate_reply()
+{
+ COMPREPLY=( $(compgen -W "$1" -- "${COMP_WORDS[COMP_CWORD]}") )
+}
+
+_webkit-patch_complete()
+{
+ local command current_command="${COMP_WORDS[1]}"
+ case "$current_command" in
+ -h|--help)
+ command="help";
+ ;;
+ *)
+ command="$current_command"
+ ;;
+ esac
+
+ if [ $COMP_CWORD -eq 1 ]; then
+ __webkit-patch_generate_reply "--help apply-from-bug bugs-to-commit commit-message land land-from-bug obsolete-attachments patches-to-commit post upload tree-status rollout reviewed-patches"
+ return
+ fi
+
+ case "$command" in
+ apply-from-bug)
+ __webkit-patch_generate_reply "--force-clean --local-commit --no-clean --no-update"
+ return
+ ;;
+ commit-message)
+ return
+ ;;
+ land)
+ __webkit-patch_generate_reply "--no-build --no-close --no-test --reviewer= -r"
+ return
+ ;;
+ land-from-bug)
+ __webkit-patch_generate_reply "--force-clean --no-build --no-clean --no-test"
+ return
+ ;;
+ obsolete-attachments)
+ return
+ ;;
+ post)
+ __webkit-patch_generate_reply "--description --no-obsolete --no-review --request-commit -m --open-bug"
+ return
+ ;;
+ upload)
+ __webkit-patch_generate_reply "--description --no-obsolete --no-review --request-commit --cc -m --open-bug"
+ return
+ ;;
+ post-commits)
+ __webkit-patch_generate_reply "--bug-id= --no-comment --no-obsolete --no-review -b"
+ return
+ ;;
+ esac
+}
+
+complete -F _webkit-patch_complete webkit-patch
+complete -W "--continue --fix-merged --help --no-continue --no-warnings --warnings -c -f -h -w" resolve-ChangeLogs
+complete -W "--bug --diff --git-commit --git-index --git-reviewer --help --no-update --no-write --open --update --write -d -h -o" prepare-ChangeLog
+complete -W "--clean --debug --help -h" build-webkit
+complete -o default -W "--add-platform-exceptions --complex-text --configuration --guard-malloc --help --http --ignore-tests --launch-safari --leaks --merge-leak-depth --new-test-results --no-http --no-launch-safari --no-new-test-results --no-sample-on-timeout --no-strip-editing-callbacks --pixel-tests --platform --port --quiet --random --reset-results --results-directory --reverse --root --sample-on-timeout --singly --skipped --slowest --strict --strip-editing-callbacks --threaded --timeout --tolerance --use-remote-links-to-tests --valgrind --verbose -1 -c -g -h -i -l -m -o -p -q -t -v" run-webkit-tests
diff --git a/Tools/Scripts/webkitdirs.pm b/Tools/Scripts/webkitdirs.pm
new file mode 100644
index 0000000..ac40ec6
--- /dev/null
+++ b/Tools/Scripts/webkitdirs.pm
@@ -0,0 +1,1872 @@
+# Copyright (C) 2005, 2006, 2007, 2010 Apple Inc. All rights reserved.
+# 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:
+#
+# 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.
+
+# Module to share code to get to WebKit directories.
+
+use strict;
+use warnings;
+use Config;
+use FindBin;
+use File::Basename;
+use File::Path;
+use File::Spec;
+use POSIX;
+use VCSUtils;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(&chdirWebKit &baseProductDir &productDir &XcodeOptions &XcodeOptionString &XcodeOptionStringNoConfig &passedConfiguration &setConfiguration &safariPath &checkFrameworks &currentSVNRevision);
+ %EXPORT_TAGS = ( );
+ @EXPORT_OK = ();
+}
+
+our @EXPORT_OK;
+
+my $architecture;
+my $numberOfCPUs;
+my $baseProductDir;
+my @baseProductDirOption;
+my $configuration;
+my $configurationForVisualStudio;
+my $configurationProductDir;
+my $sourceDir;
+my $currentSVNRevision;
+my $osXVersion;
+my $isQt;
+my $isSymbian;
+my %qtFeatureDefaults;
+my $isGtk;
+my $isWx;
+my $isEfl;
+my @wxArgs;
+my $isChromium;
+my $isInspectorFrontend;
+
+# Variables for Win32 support
+my $vcBuildPath;
+my $windowsSourceDir;
+my $winVersion;
+my $willUseVCExpressWhenBuilding = 0;
+
+# Defined in VCSUtils.
+sub exitStatus($);
+
+sub determineSourceDir
+{
+ return if $sourceDir;
+ $sourceDir = $FindBin::Bin;
+ $sourceDir =~ s|/+$||; # Remove trailing '/' as we would die later
+
+ # walks up path checking each directory to see if it is the main WebKit project dir,
+ # defined by containing JavaScriptCore, WebCore, and WebKit
+ until ((-d "$sourceDir/JavaScriptCore" && -d "$sourceDir/WebCore" && -d "$sourceDir/WebKit") || (-d "$sourceDir/Internal" && -d "$sourceDir/OpenSource"))
+ {
+ if ($sourceDir !~ s|/[^/]+$||) {
+ die "Could not find top level webkit directory above source directory using FindBin.\n";
+ }
+ }
+
+ $sourceDir = "$sourceDir/OpenSource" if -d "$sourceDir/OpenSource";
+}
+
+sub currentPerlPath()
+{
+ my $thisPerl = $^X;
+ if ($^O ne 'VMS') {
+ $thisPerl .= $Config{_exe} unless $thisPerl =~ m/$Config{_exe}$/i;
+ }
+ return $thisPerl;
+}
+
+# used for scripts which are stored in a non-standard location
+sub setSourceDir($)
+{
+ ($sourceDir) = @_;
+}
+
+sub determineBaseProductDir
+{
+ return if defined $baseProductDir;
+ determineSourceDir();
+
+ $baseProductDir = $ENV{"WEBKITOUTPUTDIR"};
+
+ if (!defined($baseProductDir) and isAppleMacWebKit()) {
+ # Silently remove ~/Library/Preferences/xcodebuild.plist which can
+ # cause build failure. The presence of
+ # ~/Library/Preferences/xcodebuild.plist can prevent xcodebuild from
+ # respecting global settings such as a custom build products directory
+ # (<rdar://problem/5585899>).
+ my $personalPlistFile = $ENV{HOME} . "/Library/Preferences/xcodebuild.plist";
+ if (-e $personalPlistFile) {
+ unlink($personalPlistFile) || die "Could not delete $personalPlistFile: $!";
+ }
+
+ open PRODUCT, "defaults read com.apple.Xcode PBXApplicationwideBuildSettings 2> " . File::Spec->devnull() . " |" or die;
+ $baseProductDir = join '', <PRODUCT>;
+ close PRODUCT;
+
+ $baseProductDir = $1 if $baseProductDir =~ /SYMROOT\s*=\s*\"(.*?)\";/s;
+ undef $baseProductDir unless $baseProductDir =~ /^\//;
+
+ if (!defined($baseProductDir)) {
+ open PRODUCT, "defaults read com.apple.Xcode PBXProductDirectory 2> " . File::Spec->devnull() . " |" or die;
+ $baseProductDir = <PRODUCT>;
+ close PRODUCT;
+ if ($baseProductDir) {
+ chomp $baseProductDir;
+ undef $baseProductDir unless $baseProductDir =~ /^\//;
+ }
+ }
+ } elsif (isSymbian()) {
+ # Shadow builds are not supported on Symbian
+ $baseProductDir = $sourceDir;
+ }
+
+ if (!defined($baseProductDir)) { # Port-spesific checks failed, use default
+ $baseProductDir = "$sourceDir/WebKitBuild";
+ }
+
+ if (isGit() && isGitBranchBuild()) {
+ my $branch = gitBranch();
+ $baseProductDir = "$baseProductDir/$branch";
+ }
+
+ if (isAppleMacWebKit()) {
+ $baseProductDir =~ s|^\Q$(SRCROOT)/..\E$|$sourceDir|;
+ $baseProductDir =~ s|^\Q$(SRCROOT)/../|$sourceDir/|;
+ $baseProductDir =~ s|^~/|$ENV{HOME}/|;
+ die "Can't handle Xcode product directory with a ~ in it.\n" if $baseProductDir =~ /~/;
+ die "Can't handle Xcode product directory with a variable in it.\n" if $baseProductDir =~ /\$/;
+ @baseProductDirOption = ("SYMROOT=$baseProductDir", "OBJROOT=$baseProductDir");
+ }
+
+ if (isCygwin()) {
+ my $dosBuildPath = `cygpath --windows \"$baseProductDir\"`;
+ chomp $dosBuildPath;
+ $ENV{"WEBKITOUTPUTDIR"} = $dosBuildPath;
+ my $unixBuildPath = `cygpath --unix \"$baseProductDir\"`;
+ chomp $unixBuildPath;
+ $baseProductDir = $unixBuildPath;
+ }
+}
+
+sub setBaseProductDir($)
+{
+ ($baseProductDir) = @_;
+}
+
+sub determineConfiguration
+{
+ return if defined $configuration;
+ determineBaseProductDir();
+ if (open CONFIGURATION, "$baseProductDir/Configuration") {
+ $configuration = <CONFIGURATION>;
+ close CONFIGURATION;
+ }
+ if ($configuration) {
+ chomp $configuration;
+ # compatibility for people who have old Configuration files
+ $configuration = "Release" if $configuration eq "Deployment";
+ $configuration = "Debug" if $configuration eq "Development";
+ } else {
+ $configuration = "Release";
+ }
+}
+
+sub determineArchitecture
+{
+ return if defined $architecture;
+ # make sure $architecture is defined for non-apple-mac builds
+ $architecture = "";
+ return unless isAppleMacWebKit();
+
+ determineBaseProductDir();
+ if (open ARCHITECTURE, "$baseProductDir/Architecture") {
+ $architecture = <ARCHITECTURE>;
+ close ARCHITECTURE;
+ }
+ if ($architecture) {
+ chomp $architecture;
+ } else {
+ if (isTiger() or isLeopard()) {
+ $architecture = `arch`;
+ } else {
+ my $supports64Bit = `sysctl -n hw.optional.x86_64`;
+ chomp $supports64Bit;
+ $architecture = $supports64Bit ? 'x86_64' : `arch`;
+ }
+ chomp $architecture;
+ }
+}
+
+sub determineNumberOfCPUs
+{
+ return if defined $numberOfCPUs;
+ if (isLinux()) {
+ # First try the nproc utility, if it exists. If we get no
+ # results fall back to just interpretting /proc directly.
+ chomp($numberOfCPUs = `nproc 2> /dev/null`);
+ if ($numberOfCPUs eq "") {
+ $numberOfCPUs = (grep /processor/, `cat /proc/cpuinfo`);
+ }
+ } elsif (isWindows() || isCygwin()) {
+ if (defined($ENV{NUMBER_OF_PROCESSORS})) {
+ $numberOfCPUs = $ENV{NUMBER_OF_PROCESSORS};
+ } else {
+ # Assumes cygwin
+ $numberOfCPUs = `ls /proc/registry/HKEY_LOCAL_MACHINE/HARDWARE/DESCRIPTION/System/CentralProcessor | wc -w`;
+ }
+ } elsif (isDarwin()) {
+ $numberOfCPUs = `sysctl -n hw.ncpu`;
+ }
+}
+
+sub jscPath($)
+{
+ my ($productDir) = @_;
+ my $jscName = "jsc";
+ $jscName .= "_debug" if configurationForVisualStudio() eq "Debug_All";
+ $jscName .= ".exe" if (isWindows() || isCygwin());
+ return "$productDir/$jscName" if -e "$productDir/$jscName";
+ return "$productDir/JavaScriptCore.framework/Resources/$jscName";
+}
+
+sub argumentsForConfiguration()
+{
+ determineConfiguration();
+ determineArchitecture();
+
+ my @args = ();
+ push(@args, '--debug') if $configuration eq "Debug";
+ push(@args, '--release') if $configuration eq "Release";
+ push(@args, '--32-bit') if $architecture ne "x86_64";
+ push(@args, '--qt') if isQt();
+ push(@args, '--symbian') if isSymbian();
+ push(@args, '--gtk') if isGtk();
+ push(@args, '--efl') if isEfl();
+ push(@args, '--wx') if isWx();
+ push(@args, '--chromium') if isChromium();
+ push(@args, '--inspector-frontend') if isInspectorFrontend();
+ return @args;
+}
+
+sub determineConfigurationForVisualStudio
+{
+ return if defined $configurationForVisualStudio;
+ determineConfiguration();
+ # FIXME: We should detect when Debug_All or Release_LTCG has been chosen.
+ $configurationForVisualStudio = $configuration;
+}
+
+sub determineConfigurationProductDir
+{
+ return if defined $configurationProductDir;
+ determineBaseProductDir();
+ determineConfiguration();
+ if (isAppleWinWebKit() && !isWx()) {
+ $configurationProductDir = File::Spec->catdir($baseProductDir, "bin");
+ } else {
+ # [Gtk][Efl] We don't have Release/Debug configurations in straight
+ # autotool builds (non build-webkit). In this case and if
+ # WEBKITOUTPUTDIR exist, use that as our configuration dir. This will
+ # allows us to run run-webkit-tests without using build-webkit.
+ if ($ENV{"WEBKITOUTPUTDIR"} && (isGtk() || isEfl())) {
+ $configurationProductDir = "$baseProductDir";
+ } else {
+ $configurationProductDir = "$baseProductDir/$configuration";
+ }
+ }
+}
+
+sub setConfigurationProductDir($)
+{
+ ($configurationProductDir) = @_;
+}
+
+sub determineCurrentSVNRevision
+{
+ return if defined $currentSVNRevision;
+ determineSourceDir();
+ $currentSVNRevision = svnRevisionForDirectory($sourceDir);
+ return $currentSVNRevision;
+}
+
+
+sub chdirWebKit
+{
+ determineSourceDir();
+ chdir $sourceDir or die;
+}
+
+sub baseProductDir
+{
+ determineBaseProductDir();
+ return $baseProductDir;
+}
+
+sub sourceDir
+{
+ determineSourceDir();
+ return $sourceDir;
+}
+
+sub productDir
+{
+ determineConfigurationProductDir();
+ return $configurationProductDir;
+}
+
+sub jscProductDir
+{
+ my $productDir = productDir();
+ $productDir .= "/JavaScriptCore" if isQt();
+ $productDir .= "/$configuration" if (isQt() && isWindows());
+ $productDir .= "/Programs" if (isGtk() || isEfl());
+
+ return $productDir;
+}
+
+sub configuration()
+{
+ determineConfiguration();
+ return $configuration;
+}
+
+sub configurationForVisualStudio()
+{
+ determineConfigurationForVisualStudio();
+ return $configurationForVisualStudio;
+}
+
+sub currentSVNRevision
+{
+ determineCurrentSVNRevision();
+ return $currentSVNRevision;
+}
+
+sub XcodeOptions
+{
+ determineBaseProductDir();
+ determineConfiguration();
+ determineArchitecture();
+ return (@baseProductDirOption, "-configuration", $configuration, "ARCHS=$architecture");
+}
+
+sub XcodeOptionString
+{
+ return join " ", XcodeOptions();
+}
+
+sub XcodeOptionStringNoConfig
+{
+ return join " ", @baseProductDirOption;
+}
+
+sub XcodeCoverageSupportOptions()
+{
+ my @coverageSupportOptions = ();
+ push @coverageSupportOptions, "GCC_GENERATE_TEST_COVERAGE_FILES=YES";
+ push @coverageSupportOptions, "GCC_INSTRUMENT_PROGRAM_FLOW_ARCS=YES";
+ push @coverageSupportOptions, "EXTRA_LINK= \$(EXTRA_LINK) -ftest-coverage -fprofile-arcs";
+ push @coverageSupportOptions, "OTHER_CFLAGS= \$(OTHER_CFLAGS) -DCOVERAGE -MD";
+ push @coverageSupportOptions, "OTHER_LDFLAGS=\$(OTHER_LDFLAGS) -ftest-coverage -fprofile-arcs -lgcov";
+ return @coverageSupportOptions;
+}
+
+my $passedConfiguration;
+my $searchedForPassedConfiguration;
+sub determinePassedConfiguration
+{
+ return if $searchedForPassedConfiguration;
+ $searchedForPassedConfiguration = 1;
+
+ my $isWinCairo = checkForArgumentAndRemoveFromARGV("--wincairo");
+
+ for my $i (0 .. $#ARGV) {
+ my $opt = $ARGV[$i];
+ if ($opt =~ /^--debug$/i || $opt =~ /^--devel/i) {
+ splice(@ARGV, $i, 1);
+ $passedConfiguration = "Debug";
+ $passedConfiguration .= "_Cairo_CFLite" if ($isWinCairo && isCygwin());
+ return;
+ }
+ if ($opt =~ /^--release$/i || $opt =~ /^--deploy/i) {
+ splice(@ARGV, $i, 1);
+ $passedConfiguration = "Release";
+ $passedConfiguration .= "_Cairo_CFLite" if ($isWinCairo && isCygwin());
+ return;
+ }
+ if ($opt =~ /^--profil(e|ing)$/i) {
+ splice(@ARGV, $i, 1);
+ $passedConfiguration = "Profiling";
+ $passedConfiguration .= "_Cairo_CFLite" if ($isWinCairo && isCygwin());
+ return;
+ }
+ }
+ $passedConfiguration = undef;
+}
+
+sub passedConfiguration
+{
+ determinePassedConfiguration();
+ return $passedConfiguration;
+}
+
+sub setConfiguration
+{
+ setArchitecture();
+
+ if (my $config = shift @_) {
+ $configuration = $config;
+ return;
+ }
+
+ determinePassedConfiguration();
+ $configuration = $passedConfiguration if $passedConfiguration;
+}
+
+
+my $passedArchitecture;
+my $searchedForPassedArchitecture;
+sub determinePassedArchitecture
+{
+ return if $searchedForPassedArchitecture;
+ $searchedForPassedArchitecture = 1;
+
+ for my $i (0 .. $#ARGV) {
+ my $opt = $ARGV[$i];
+ if ($opt =~ /^--32-bit$/i) {
+ splice(@ARGV, $i, 1);
+ if (isAppleMacWebKit()) {
+ $passedArchitecture = `arch`;
+ chomp $passedArchitecture;
+ }
+ return;
+ }
+ }
+ $passedArchitecture = undef;
+}
+
+sub passedArchitecture
+{
+ determinePassedArchitecture();
+ return $passedArchitecture;
+}
+
+sub architecture()
+{
+ determineArchitecture();
+ return $architecture;
+}
+
+sub numberOfCPUs()
+{
+ determineNumberOfCPUs();
+ return $numberOfCPUs;
+}
+
+sub setArchitecture
+{
+ if (my $arch = shift @_) {
+ $architecture = $arch;
+ return;
+ }
+
+ determinePassedArchitecture();
+ $architecture = $passedArchitecture if $passedArchitecture;
+}
+
+
+sub safariPathFromSafariBundle
+{
+ my ($safariBundle) = @_;
+
+ return "$safariBundle/Contents/MacOS/Safari" if isAppleMacWebKit();
+ return $safariBundle if isAppleWinWebKit();
+}
+
+sub installedSafariPath
+{
+ my $safariBundle;
+
+ if (isAppleMacWebKit()) {
+ $safariBundle = "/Applications/Safari.app";
+ } elsif (isAppleWinWebKit()) {
+ $safariBundle = `"$configurationProductDir/FindSafari.exe"`;
+ $safariBundle =~ s/[\r\n]+$//;
+ $safariBundle = `cygpath -u '$safariBundle'` if isCygwin();
+ $safariBundle =~ s/[\r\n]+$//;
+ $safariBundle .= "Safari.exe";
+ }
+
+ return safariPathFromSafariBundle($safariBundle);
+}
+
+# Locate Safari.
+sub safariPath
+{
+ # Use WEBKIT_SAFARI environment variable if present.
+ my $safariBundle = $ENV{WEBKIT_SAFARI};
+ if (!$safariBundle) {
+ determineConfigurationProductDir();
+ # Use Safari.app in product directory if present (good for Safari development team).
+ if (isAppleMacWebKit() && -d "$configurationProductDir/Safari.app") {
+ $safariBundle = "$configurationProductDir/Safari.app";
+ } elsif (isAppleWinWebKit()) {
+ my $path = "$configurationProductDir/Safari.exe";
+ my $debugPath = "$configurationProductDir/Safari_debug.exe";
+
+ if (configurationForVisualStudio() eq "Debug_All" && -x $debugPath) {
+ $safariBundle = $debugPath;
+ } elsif (-x $path) {
+ $safariBundle = $path;
+ }
+ }
+ if (!$safariBundle) {
+ return installedSafariPath();
+ }
+ }
+ my $safariPath = safariPathFromSafariBundle($safariBundle);
+ die "Can't find executable at $safariPath.\n" if isAppleMacWebKit() && !-x $safariPath;
+ return $safariPath;
+}
+
+sub builtDylibPathForName
+{
+ my $libraryName = shift;
+ determineConfigurationProductDir();
+ if (isChromium()) {
+ return "$configurationProductDir/$libraryName";
+ }
+ if (isQt()) {
+ $libraryName = "QtWebKit";
+ if (isDarwin() and -d "$configurationProductDir/lib/$libraryName.framework") {
+ return "$configurationProductDir/lib/$libraryName.framework/$libraryName";
+ } elsif (isDarwin() and -d "$configurationProductDir/lib") {
+ return "$configurationProductDir/lib/lib$libraryName.dylib";
+ } elsif (isWindows()) {
+ if (configuration() eq "Debug") {
+ # On Windows, there is a "d" suffix to the library name. See <http://trac.webkit.org/changeset/53924/>.
+ $libraryName .= "d";
+ }
+
+ my $mkspec = `qmake -query QMAKE_MKSPECS`;
+ $mkspec =~ s/[\n|\r]$//g;
+ my $qtMajorVersion = retrieveQMakespecVar("$mkspec/qconfig.pri", "QT_MAJOR_VERSION");
+ if (not $qtMajorVersion) {
+ $qtMajorVersion = "";
+ }
+ return "$configurationProductDir/lib/$libraryName$qtMajorVersion.dll";
+ } else {
+ return "$configurationProductDir/lib/lib$libraryName.so";
+ }
+ }
+ if (isWx()) {
+ return "$configurationProductDir/libwxwebkit.dylib";
+ }
+ if (isGtk()) {
+ my $libraryDir = "$configurationProductDir/$libraryName/../.libs/";
+ if (-e $libraryDir . "libwebkitgtk-3.0.so") {
+ return $libraryDir . "libwebkitgtk-3.0.so";
+ }
+ return $libraryDir . "libwebkitgtk-1.0.so";
+ }
+ if (isEfl()) {
+ return "$configurationProductDir/$libraryName/../.libs/libewebkit.so";
+ }
+ if (isAppleMacWebKit()) {
+ return "$configurationProductDir/$libraryName.framework/Versions/A/$libraryName";
+ }
+ if (isAppleWinWebKit()) {
+ if ($libraryName eq "JavaScriptCore") {
+ return "$baseProductDir/lib/$libraryName.lib";
+ } else {
+ return "$baseProductDir/$libraryName.intermediate/$configuration/$libraryName.intermediate/$libraryName.lib";
+ }
+ }
+
+ die "Unsupported platform, can't determine built library locations.\nTry `build-webkit --help` for more information.\n";
+}
+
+# Check to see that all the frameworks are built.
+sub checkFrameworks # FIXME: This is a poor name since only the Mac calls built WebCore a Framework.
+{
+ return if isCygwin() || isWindows();
+ my @frameworks = ("JavaScriptCore", "WebCore");
+ push(@frameworks, "WebKit") if isAppleMacWebKit(); # FIXME: This seems wrong, all ports should have a WebKit these days.
+ for my $framework (@frameworks) {
+ my $path = builtDylibPathForName($framework);
+ die "Can't find built framework at \"$path\".\n" unless -e $path;
+ }
+}
+
+sub isInspectorFrontend()
+{
+ determineIsInspectorFrontend();
+ return $isInspectorFrontend;
+}
+
+sub determineIsInspectorFrontend()
+{
+ return if defined($isInspectorFrontend);
+ $isInspectorFrontend = checkForArgumentAndRemoveFromARGV("--inspector-frontend");
+}
+
+sub isQt()
+{
+ determineIsQt();
+ return $isQt;
+}
+
+sub isSymbian()
+{
+ determineIsSymbian();
+ return $isSymbian;
+}
+
+sub qtFeatureDefaults()
+{
+ determineQtFeatureDefaults();
+ return %qtFeatureDefaults;
+}
+
+sub commandExists($)
+{
+ my $command = shift;
+ my $devnull = File::Spec->devnull();
+ return `$command --version 2> $devnull`;
+}
+
+sub determineQtFeatureDefaults()
+{
+ return if %qtFeatureDefaults;
+ die "ERROR: qmake missing but required to build WebKit.\n" if not commandExists("qmake");
+ my $originalCwd = getcwd();
+ chdir File::Spec->catfile(sourceDir(), "WebCore");
+ my $defaults = `qmake CONFIG+=compute_defaults 2>&1`;
+ chdir $originalCwd;
+
+ while ($defaults =~ m/(\S+?)=(\S+?)/gi) {
+ $qtFeatureDefaults{$1}=$2;
+ }
+}
+
+sub checkForArgumentAndRemoveFromARGV
+{
+ my $argToCheck = shift;
+ return checkForArgumentAndRemoveFromArrayRef($argToCheck, \@ARGV);
+}
+
+sub checkForArgumentAndRemoveFromArrayRef
+{
+ my ($argToCheck, $arrayRef) = @_;
+ my @indicesToRemove;
+ foreach my $index (0 .. $#$arrayRef) {
+ my $opt = $$arrayRef[$index];
+ if ($opt =~ /^$argToCheck$/i ) {
+ push(@indicesToRemove, $index);
+ }
+ }
+ foreach my $index (@indicesToRemove) {
+ splice(@$arrayRef, $index, 1);
+ }
+ return $#indicesToRemove > -1;
+}
+
+
+sub determineIsQt()
+{
+ return if defined($isQt);
+
+ # Allow override in case QTDIR is not set.
+ if (checkForArgumentAndRemoveFromARGV("--qt")) {
+ $isQt = 1;
+ return;
+ }
+
+ # The presence of QTDIR only means Qt if --gtk or --wx or --efl are not on the command-line
+ if (isGtk() || isWx() || isEfl()) {
+ $isQt = 0;
+ return;
+ }
+
+ $isQt = defined($ENV{'QTDIR'});
+}
+
+sub determineIsSymbian()
+{
+ return if defined($isSymbian);
+
+ if (checkForArgumentAndRemoveFromARGV("--symbian")) {
+ $isSymbian = 1;
+ return;
+ }
+}
+
+sub determineIsEfl()
+{
+ return if defined($isEfl);
+ $isEfl = checkForArgumentAndRemoveFromARGV("--efl");
+}
+
+sub isEfl()
+{
+ determineIsEfl();
+ return $isEfl;
+}
+
+sub isGtk()
+{
+ determineIsGtk();
+ return $isGtk;
+}
+
+sub determineIsGtk()
+{
+ return if defined($isGtk);
+ $isGtk = checkForArgumentAndRemoveFromARGV("--gtk");
+}
+
+sub isWx()
+{
+ determineIsWx();
+ return $isWx;
+}
+
+sub determineIsWx()
+{
+ return if defined($isWx);
+ $isWx = checkForArgumentAndRemoveFromARGV("--wx");
+}
+
+sub getWxArgs()
+{
+ if (!@wxArgs) {
+ @wxArgs = ("");
+ my $rawWxArgs = "";
+ foreach my $opt (@ARGV) {
+ if ($opt =~ /^--wx-args/i ) {
+ @ARGV = grep(!/^--wx-args/i, @ARGV);
+ $rawWxArgs = $opt;
+ $rawWxArgs =~ s/--wx-args=//i;
+ }
+ }
+ @wxArgs = split(/,/, $rawWxArgs);
+ }
+ return @wxArgs;
+}
+
+# Determine if this is debian, ubuntu, linspire, or something similar.
+sub isDebianBased()
+{
+ return -e "/etc/debian_version";
+}
+
+sub isFedoraBased()
+{
+ return -e "/etc/fedora-release";
+}
+
+sub isChromium()
+{
+ determineIsChromium();
+ return $isChromium;
+}
+
+sub determineIsChromium()
+{
+ return if defined($isChromium);
+ $isChromium = checkForArgumentAndRemoveFromARGV("--chromium");
+}
+
+sub isCygwin()
+{
+ return ($^O eq "cygwin") || 0;
+}
+
+sub determineWinVersion()
+{
+ return if $winVersion;
+
+ if (!isCygwin()) {
+ $winVersion = -1;
+ return;
+ }
+
+ my $versionString = `uname -s`;
+ $versionString =~ /(\d\.\d)/;
+ $winVersion = $1;
+}
+
+sub winVersion()
+{
+ determineWinVersion();
+ return $winVersion;
+}
+
+sub isWindows7()
+{
+ return winVersion() eq "6.1";
+}
+
+sub isWindowsVista()
+{
+ return winVersion() eq "6.0";
+}
+
+sub isWindowsXP()
+{
+ return winVersion() eq "5.1";
+}
+
+sub isDarwin()
+{
+ return ($^O eq "darwin") || 0;
+}
+
+sub isWindows()
+{
+ return ($^O eq "MSWin32") || 0;
+}
+
+sub isMsys()
+{
+ return ($^O eq "msys") || 0;
+}
+
+sub isLinux()
+{
+ return ($^O eq "linux") || 0;
+}
+
+sub isAppleWebKit()
+{
+ return !(isQt() or isGtk() or isWx() or isChromium() or isEfl());
+}
+
+sub isAppleMacWebKit()
+{
+ return isAppleWebKit() && isDarwin();
+}
+
+sub isAppleWinWebKit()
+{
+ return isAppleWebKit() && (isCygwin() || isWindows());
+}
+
+sub isPerianInstalled()
+{
+ if (!isAppleWebKit()) {
+ return 0;
+ }
+
+ if (-d "/Library/QuickTime/Perian.component") {
+ return 1;
+ }
+
+ if (-d "$ENV{HOME}/Library/QuickTime/Perian.component") {
+ return 1;
+ }
+
+ return 0;
+}
+
+sub determineOSXVersion()
+{
+ return if $osXVersion;
+
+ if (!isDarwin()) {
+ $osXVersion = -1;
+ return;
+ }
+
+ my $version = `sw_vers -productVersion`;
+ my @splitVersion = split(/\./, $version);
+ @splitVersion >= 2 or die "Invalid version $version";
+ $osXVersion = {
+ "major" => $splitVersion[0],
+ "minor" => $splitVersion[1],
+ "subminor" => (defined($splitVersion[2]) ? $splitVersion[2] : 0),
+ };
+}
+
+sub osXVersion()
+{
+ determineOSXVersion();
+ return $osXVersion;
+}
+
+sub isTiger()
+{
+ return isDarwin() && osXVersion()->{"minor"} == 4;
+}
+
+sub isLeopard()
+{
+ return isDarwin() && osXVersion()->{"minor"} == 5;
+}
+
+sub isSnowLeopard()
+{
+ return isDarwin() && osXVersion()->{"minor"} == 6;
+}
+
+sub isWindowsNT()
+{
+ return $ENV{'OS'} eq 'Windows_NT';
+}
+
+sub relativeScriptsDir()
+{
+ my $scriptDir = File::Spec->catpath("", File::Spec->abs2rel(dirname($0), getcwd()), "");
+ if ($scriptDir eq "") {
+ $scriptDir = ".";
+ }
+ return $scriptDir;
+}
+
+sub launcherPath()
+{
+ my $relativeScriptsPath = relativeScriptsDir();
+ if (isGtk() || isQt() || isWx() || isEfl()) {
+ return "$relativeScriptsPath/run-launcher";
+ } elsif (isAppleWebKit()) {
+ return "$relativeScriptsPath/run-safari";
+ }
+}
+
+sub launcherName()
+{
+ if (isGtk()) {
+ return "GtkLauncher";
+ } elsif (isQt()) {
+ return "QtTestBrowser";
+ } elsif (isWx()) {
+ return "wxBrowser";
+ } elsif (isAppleWebKit()) {
+ return "Safari";
+ } elsif (isEfl()) {
+ return "EWebLauncher";
+ }
+}
+
+sub checkRequiredSystemConfig
+{
+ if (isDarwin()) {
+ chomp(my $productVersion = `sw_vers -productVersion`);
+ if ($productVersion lt "10.4") {
+ print "*************************************************************\n";
+ print "Mac OS X Version 10.4.0 or later is required to build WebKit.\n";
+ print "You have " . $productVersion . ", thus the build will most likely fail.\n";
+ print "*************************************************************\n";
+ }
+ my $xcodeVersion = `xcodebuild -version`;
+ if ($xcodeVersion !~ /DevToolsCore-(\d+)/ || $1 < 747) {
+ print "*************************************************************\n";
+ print "Xcode Version 2.3 or later is required to build WebKit.\n";
+ print "You have an earlier version of Xcode, thus the build will\n";
+ print "most likely fail. The latest Xcode is available from the web:\n";
+ print "http://developer.apple.com/tools/xcode\n";
+ print "*************************************************************\n";
+ }
+ } elsif (isGtk() or isQt() or isWx() or isEfl()) {
+ my @cmds = qw(flex bison gperf);
+ my @missing = ();
+ foreach my $cmd (@cmds) {
+ push @missing, $cmd if not commandExists($cmd);
+ }
+
+ if (@missing) {
+ my $list = join ", ", @missing;
+ die "ERROR: $list missing but required to build WebKit.\n";
+ }
+ }
+ # Win32 and other platforms may want to check for minimum config
+}
+
+sub determineWindowsSourceDir()
+{
+ return if $windowsSourceDir;
+ $windowsSourceDir = sourceDir();
+ chomp($windowsSourceDir = `cygpath -w '$windowsSourceDir'`) if isCygwin();
+}
+
+sub windowsSourceDir()
+{
+ determineWindowsSourceDir();
+ return $windowsSourceDir;
+}
+
+sub windowsLibrariesDir()
+{
+ return windowsSourceDir() . "\\WebKitLibraries\\win";
+}
+
+sub windowsOutputDir()
+{
+ return windowsSourceDir() . "\\WebKitBuild";
+}
+
+sub setupAppleWinEnv()
+{
+ return unless isAppleWinWebKit();
+
+ if (isWindowsNT()) {
+ my $restartNeeded = 0;
+ my %variablesToSet = ();
+
+ # Setting the environment variable 'CYGWIN' to 'tty' makes cygwin enable extra support (i.e., termios)
+ # for UNIX-like ttys in the Windows console
+ $variablesToSet{CYGWIN} = "tty" unless $ENV{CYGWIN};
+
+ # Those environment variables must be set to be able to build inside Visual Studio.
+ $variablesToSet{WEBKITLIBRARIESDIR} = windowsLibrariesDir() unless $ENV{WEBKITLIBRARIESDIR};
+ $variablesToSet{WEBKITOUTPUTDIR} = windowsOutputDir() unless $ENV{WEBKITOUTPUTDIR};
+
+ foreach my $variable (keys %variablesToSet) {
+ print "Setting the Environment Variable '" . $variable . "' to '" . $variablesToSet{$variable} . "'\n\n";
+ system qw(regtool -s set), '\\HKEY_CURRENT_USER\\Environment\\' . $variable, $variablesToSet{$variable};
+ $restartNeeded ||= $variable eq "WEBKITLIBRARIESDIR" || $variable eq "WEBKITOUTPUTDIR";
+ }
+
+ if ($restartNeeded) {
+ print "Please restart your computer before attempting to build inside Visual Studio.\n\n";
+ }
+ } else {
+ if (!$ENV{'WEBKITLIBRARIESDIR'}) {
+ print "Warning: You must set the 'WebKitLibrariesDir' environment variable\n";
+ print " to be able build WebKit from within Visual Studio.\n";
+ print " Make sure that 'WebKitLibrariesDir' points to the\n";
+ print " 'WebKitLibraries/win' directory, not the 'WebKitLibraries/' directory.\n\n";
+ }
+ if (!$ENV{'WEBKITOUTPUTDIR'}) {
+ print "Warning: You must set the 'WebKitOutputDir' environment variable\n";
+ print " to be able build WebKit from within Visual Studio.\n\n";
+ }
+ }
+}
+
+sub setupCygwinEnv()
+{
+ return if !isCygwin() && !isWindows();
+ return if $vcBuildPath;
+
+ my $vsInstallDir;
+ my $programFilesPath = $ENV{'PROGRAMFILES(X86)'} || $ENV{'PROGRAMFILES'} || "C:\\Program Files";
+ if ($ENV{'VSINSTALLDIR'}) {
+ $vsInstallDir = $ENV{'VSINSTALLDIR'};
+ } else {
+ $vsInstallDir = File::Spec->catdir($programFilesPath, "Microsoft Visual Studio 8");
+ }
+ chomp($vsInstallDir = `cygpath "$vsInstallDir"`) if isCygwin();
+ $vcBuildPath = File::Spec->catfile($vsInstallDir, qw(Common7 IDE devenv.com));
+ if (-e $vcBuildPath) {
+ # Visual Studio is installed; we can use pdevenv to build.
+ # FIXME: Make pdevenv work with non-Cygwin Perl.
+ $vcBuildPath = File::Spec->catfile(sourceDir(), qw(Tools Scripts pdevenv)) if isCygwin();
+ } else {
+ # Visual Studio not found, try VC++ Express
+ $vcBuildPath = File::Spec->catfile($vsInstallDir, qw(Common7 IDE VCExpress.exe));
+ if (! -e $vcBuildPath) {
+ print "*************************************************************\n";
+ print "Cannot find '$vcBuildPath'\n";
+ print "Please execute the file 'vcvars32.bat' from\n";
+ print "'$programFilesPath\\Microsoft Visual Studio 8\\VC\\bin\\'\n";
+ print "to setup the necessary environment variables.\n";
+ print "*************************************************************\n";
+ die;
+ }
+ $willUseVCExpressWhenBuilding = 1;
+ }
+
+ my $qtSDKPath = File::Spec->catdir($programFilesPath, "QuickTime SDK");
+ if (0 && ! -e $qtSDKPath) {
+ print "*************************************************************\n";
+ print "Cannot find '$qtSDKPath'\n";
+ print "Please download the QuickTime SDK for Windows from\n";
+ print "http://developer.apple.com/quicktime/download/\n";
+ print "*************************************************************\n";
+ die;
+ }
+
+ unless ($ENV{WEBKITLIBRARIESDIR}) {
+ $ENV{'WEBKITLIBRARIESDIR'} = File::Spec->catdir($sourceDir, "WebKitLibraries", "win");
+ chomp($ENV{WEBKITLIBRARIESDIR} = `cygpath -wa $ENV{WEBKITLIBRARIESDIR}`) if isCygwin();
+ }
+
+ print "Building results into: ", baseProductDir(), "\n";
+ print "WEBKITOUTPUTDIR is set to: ", $ENV{"WEBKITOUTPUTDIR"}, "\n";
+ print "WEBKITLIBRARIESDIR is set to: ", $ENV{"WEBKITLIBRARIESDIR"}, "\n";
+}
+
+sub dieIfWindowsPlatformSDKNotInstalled
+{
+ my $registry32Path = "/proc/registry/";
+ my $registry64Path = "/proc/registry64/";
+ my $windowsPlatformSDKRegistryEntry = "HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/MicrosoftSDK/InstalledSDKs/D2FF9F89-8AA2-4373-8A31-C838BF4DBBE1";
+
+ # FIXME: It would be better to detect whether we are using 32- or 64-bit Windows
+ # and only check the appropriate entry. But for now we just blindly check both.
+ return if (-e $registry32Path . $windowsPlatformSDKRegistryEntry) || (-e $registry64Path . $windowsPlatformSDKRegistryEntry);
+
+ print "*************************************************************\n";
+ print "Cannot find registry entry '$windowsPlatformSDKRegistryEntry'.\n";
+ print "Please download and install the Microsoft Windows Server 2003 R2\n";
+ print "Platform SDK from <http://www.microsoft.com/downloads/details.aspx?\n";
+ print "familyid=0baf2b35-c656-4969-ace8-e4c0c0716adb&displaylang=en>.\n\n";
+ print "Then follow step 2 in the Windows section of the \"Installing Developer\n";
+ print "Tools\" instructions at <http://www.webkit.org/building/tools.html>.\n";
+ print "*************************************************************\n";
+ die;
+}
+
+sub copyInspectorFrontendFiles
+{
+ my $productDir = productDir();
+ my $sourceInspectorPath = sourceDir() . "/WebCore/inspector/front-end/";
+ my $inspectorResourcesDirPath = $ENV{"WEBKITINSPECTORRESOURCESDIR"};
+
+ if (!defined($inspectorResourcesDirPath)) {
+ $inspectorResourcesDirPath = "";
+ }
+
+ if (isAppleMacWebKit()) {
+ $inspectorResourcesDirPath = $productDir . "/WebCore.framework/Resources/inspector";
+ } elsif (isAppleWinWebKit()) {
+ $inspectorResourcesDirPath = $productDir . "/WebKit.resources/inspector";
+ } elsif (isQt() || isGtk()) {
+ my $prefix = $ENV{"WebKitInstallationPrefix"};
+ $inspectorResourcesDirPath = (defined($prefix) ? $prefix : "/usr/share") . "/webkit-1.0/webinspector";
+ } elsif (isEfl()) {
+ my $prefix = $ENV{"WebKitInstallationPrefix"};
+ $inspectorResourcesDirPath = (defined($prefix) ? $prefix : "/usr/share") . "/ewebkit/webinspector";
+ }
+
+ if (! -d $inspectorResourcesDirPath) {
+ print "*************************************************************\n";
+ print "Cannot find '$inspectorResourcesDirPath'.\n" if (defined($inspectorResourcesDirPath));
+ print "Make sure that you have built WebKit first.\n" if (! -d $productDir || defined($inspectorResourcesDirPath));
+ print "Optionally, set the environment variable 'WebKitInspectorResourcesDir'\n";
+ print "to point to the directory that contains the WebKit Inspector front-end\n";
+ print "files for the built WebCore framework.\n";
+ print "*************************************************************\n";
+ die;
+ }
+ return system "rsync", "-aut", "--exclude=/.DS_Store", "--exclude=*.re2js", "--exclude=.svn/", !isQt() ? "--exclude=/WebKit.qrc" : "", $sourceInspectorPath, $inspectorResourcesDirPath;
+}
+
+sub buildXCodeProject($$@)
+{
+ my ($project, $clean, @extraOptions) = @_;
+
+ if ($clean) {
+ push(@extraOptions, "-alltargets");
+ push(@extraOptions, "clean");
+ }
+
+ return system "xcodebuild", "-project", "$project.xcodeproj", @extraOptions;
+}
+
+sub usingVisualStudioExpress()
+{
+ setupCygwinEnv();
+ return $willUseVCExpressWhenBuilding;
+}
+
+sub buildVisualStudioProject
+{
+ my ($project, $clean) = @_;
+ setupCygwinEnv();
+
+ my $config = configurationForVisualStudio();
+
+ dieIfWindowsPlatformSDKNotInstalled() if $willUseVCExpressWhenBuilding;
+
+ chomp($project = `cygpath -w "$project"`) if isCygwin();
+
+ my $action = "/build";
+ if ($clean) {
+ $action = "/clean";
+ }
+
+ my @command = ($vcBuildPath, $project, $action, $config);
+
+ print join(" ", @command), "\n";
+ return system @command;
+}
+
+sub downloadWafIfNeeded
+{
+ # get / update waf if needed
+ my $waf = "$sourceDir/Tools/wx/waf";
+ my $wafURL = 'http://wxwebkit.wxcommunity.com/downloads/deps/waf';
+ if (!-f $waf) {
+ my $result = system "curl -o $waf $wafURL";
+ chmod 0755, $waf;
+ }
+}
+
+sub buildWafProject
+{
+ my ($project, $shouldClean, @options) = @_;
+
+ # set the PYTHONPATH for waf
+ my $pythonPath = $ENV{'PYTHONPATH'};
+ if (!defined($pythonPath)) {
+ $pythonPath = '';
+ }
+ my $sourceDir = sourceDir();
+ my $newPythonPath = "$sourceDir/Tools/wx/build:$pythonPath";
+ if (isCygwin()) {
+ $newPythonPath = `cygpath --mixed --path $newPythonPath`;
+ }
+ $ENV{'PYTHONPATH'} = $newPythonPath;
+
+ print "Building $project\n";
+
+ my $wafCommand = "$sourceDir/Tools/wx/waf";
+ if ($ENV{'WXWEBKIT_WAF'}) {
+ $wafCommand = $ENV{'WXWEBKIT_WAF'};
+ }
+ if (isCygwin()) {
+ $wafCommand = `cygpath --windows "$wafCommand"`;
+ chomp($wafCommand);
+ }
+ if ($shouldClean) {
+ return system $wafCommand, "clean", "distclean";
+ }
+
+ return system $wafCommand, 'configure', 'build', 'install', @options;
+}
+
+sub retrieveQMakespecVar
+{
+ my $mkspec = $_[0];
+ my $varname = $_[1];
+
+ my $varvalue = undef;
+ #print "retrieveMakespecVar " . $mkspec . ", " . $varname . "\n";
+
+ local *SPEC;
+ open SPEC, "<$mkspec" or return $varvalue;
+ while (<SPEC>) {
+ if ($_ =~ /\s*include\((.+)\)/) {
+ # open the included mkspec
+ my $oldcwd = getcwd();
+ (my $volume, my $directories, my $file) = File::Spec->splitpath($mkspec);
+ my $newcwd = "$volume$directories";
+ chdir $newcwd if $newcwd;
+ $varvalue = retrieveQMakespecVar($1, $varname);
+ chdir $oldcwd;
+ } elsif ($_ =~ /$varname\s*=\s*([^\s]+)/) {
+ $varvalue = $1;
+ last;
+ }
+ }
+ close SPEC;
+ return $varvalue;
+}
+
+sub qtMakeCommand($)
+{
+ my ($qmakebin) = @_;
+ chomp(my $mkspec = `$qmakebin -query QMAKE_MKSPECS`);
+ $mkspec .= "/default";
+ my $compiler = retrieveQMakespecVar("$mkspec/qmake.conf", "QMAKE_CC");
+
+ #print "default spec: " . $mkspec . "\n";
+ #print "compiler found: " . $compiler . "\n";
+
+ if ($compiler && $compiler eq "cl") {
+ return "nmake";
+ }
+
+ return "make";
+}
+
+sub autotoolsFlag($$)
+{
+ my ($flag, $feature) = @_;
+ my $prefix = $flag ? "--enable" : "--disable";
+
+ return $prefix . '-' . $feature;
+}
+
+sub autogenArgumentsHaveChanged($@)
+{
+ my ($filename, @currentArguments) = @_;
+
+ if (! -e $filename) {
+ return 1;
+ }
+
+ open(AUTOTOOLS_ARGUMENTS, $filename);
+ chomp(my $previousArguments = <AUTOTOOLS_ARGUMENTS>);
+ close(AUTOTOOLS_ARGUMENTS);
+
+ return $previousArguments ne join(" ", @currentArguments);
+}
+
+sub buildAutotoolsProject($@)
+{
+ my ($clean, @buildParams) = @_;
+
+ my $make = 'make';
+ my $dir = productDir();
+ my $config = passedConfiguration() || configuration();
+ my $prefix;
+
+ my @buildArgs = ();
+ my $makeArgs = $ENV{"WebKitMakeArguments"} || "";
+ for my $i (0 .. $#buildParams) {
+ my $opt = $buildParams[$i];
+ if ($opt =~ /^--makeargs=(.*)/i ) {
+ $makeArgs = $makeArgs . " " . $1;
+ } elsif ($opt =~ /^--prefix=(.*)/i ) {
+ $prefix = $1;
+ } else {
+ push @buildArgs, $opt;
+ }
+ }
+
+ # Automatically determine the number of CPUs for make only
+ # if make arguments haven't already been specified.
+ if ($makeArgs eq "") {
+ $makeArgs = "-j" . numberOfCPUs();
+ }
+
+ $prefix = $ENV{"WebKitInstallationPrefix"} if !defined($prefix);
+ push @buildArgs, "--prefix=" . $prefix if defined($prefix);
+
+ # check if configuration is Debug
+ if ($config =~ m/debug/i) {
+ push @buildArgs, "--enable-debug";
+ } else {
+ push @buildArgs, "--disable-debug";
+ }
+
+ # Use rm to clean the build directory since distclean may miss files
+ if ($clean && -d $dir) {
+ system "rm", "-rf", "$dir";
+ }
+
+ if (! -d $dir) {
+ File::Path::mkpath($dir) or die "Failed to create build directory " . $dir
+ }
+ chdir $dir or die "Failed to cd into " . $dir . "\n";
+
+ if ($clean) {
+ return 0;
+ }
+
+ # If GNUmakefile exists, don't run autogen.sh. The makefile should be
+ # smart enough to track autotools dependencies and re-run autogen.sh
+ # when build files change.
+ my $autogenArgumentsFile = "previous-autogen-arguments.txt";
+ my $result;
+ if (!(-e "GNUmakefile") or autogenArgumentsHaveChanged($autogenArgumentsFile, @buildArgs)) {
+
+ # Write autogen.sh arguments to a file so that we can detect
+ # when they change and automatically re-run it.
+ open(AUTOTOOLS_ARGUMENTS, ">$autogenArgumentsFile");
+ print AUTOTOOLS_ARGUMENTS join(" ", @buildArgs);
+ close(AUTOTOOLS_ARGUMENTS);
+
+ print "Calling configure in " . $dir . "\n\n";
+ print "Installation prefix directory: $prefix\n" if(defined($prefix));
+
+ # Make the path relative since it will appear in all -I compiler flags.
+ # Long argument lists cause bizarre slowdowns in libtool.
+ my $relSourceDir = File::Spec->abs2rel($sourceDir) || ".";
+ $result = system "$relSourceDir/autogen.sh", @buildArgs;
+ if ($result ne 0) {
+ die "Failed to setup build environment using 'autotools'!\n";
+ }
+ }
+
+ $result = system "$make $makeArgs";
+ if ($result ne 0) {
+ die "\nFailed to build WebKit using '$make'!\n";
+ }
+
+ chdir ".." or die;
+ return $result;
+}
+
+sub buildCMakeProject($@)
+{
+ my ($port, $clean, @buildParams) = @_;
+ my $dir = File::Spec->canonpath(baseProductDir());
+ my $config = configuration();
+ my $result;
+ my $makeArgs = "";
+ my @buildArgs;
+
+ $makeArgs .= " -j" . numberOfCPUs() if ($makeArgs !~ m/-j\s*\d+/);
+
+ if ($clean) {
+ print "Cleaning the build directory '$dir'\n";
+ $dir = File::Spec->catfile($dir, $config);
+ File::Path::remove_tree($dir, {keep_root => 1});
+ $result = 0;
+ } else {
+ my $cmakebin = "cmake";
+ my $make = "make";
+
+ push @buildArgs, "-DPORT=$port";
+
+ for my $i (0 .. $#buildParams) {
+ my $opt = $buildParams[$i];
+ if ($opt =~ /^--makeargs=(.*)/i ) {
+ $makeArgs = $1;
+ } elsif ($opt =~ /^--prefix=(.*)/i ) {
+ push @buildArgs, "-DCMAKE_INSTALL_PREFIX=$1";
+ } else {
+ push @buildArgs, $opt;
+ }
+ }
+
+ if ($config =~ m/debug/i) {
+ push @buildArgs, "-DCMAKE_BUILD_TYPE=Debug";
+ } elsif ($config =~ m/release/i) {
+ push @buildArgs, "-DCMAKE_BUILD_TYPE=Release";
+ }
+
+ push @buildArgs, sourceDir();
+
+ $dir = File::Spec->catfile($dir, $config);
+ File::Path::mkpath($dir);
+ chdir $dir or die "Failed to cd into " . $dir . "\n";
+
+ print "Calling '$cmakebin @buildArgs' in " . $dir . "\n\n";
+ my $result = system "$cmakebin @buildArgs";
+ if ($result ne 0) {
+ die "Failed while running $cmakebin to generate makefiles!\n";
+ }
+
+ print "Calling '$make $makeArgs' in " . $dir . "\n\n";
+ $result = system "$make $makeArgs";
+ if ($result ne 0) {
+ die "Failed to build $port port\n";
+ }
+
+ chdir ".." or die;
+ }
+
+ return $result;
+}
+
+sub buildCMakeEflProject($@)
+{
+ my ($clean, @buildArgs) = @_;
+ return buildCMakeProject("Efl", $clean, @buildArgs);
+}
+
+sub buildQMakeProject($@)
+{
+ my ($clean, @buildParams) = @_;
+
+ my @buildArgs = ("-r");
+
+ my $qmakebin = "qmake"; # Allow override of the qmake binary from $PATH
+ my $makeargs = "";
+ my $installHeaders;
+ my $installLibs;
+ for my $i (0 .. $#buildParams) {
+ my $opt = $buildParams[$i];
+ if ($opt =~ /^--qmake=(.*)/i ) {
+ $qmakebin = $1;
+ } elsif ($opt =~ /^--qmakearg=(.*)/i ) {
+ push @buildArgs, $1;
+ } elsif ($opt =~ /^--makeargs=(.*)/i ) {
+ $makeargs = $1;
+ } elsif ($opt =~ /^--install-headers=(.*)/i ) {
+ $installHeaders = $1;
+ } elsif ($opt =~ /^--install-libs=(.*)/i ) {
+ $installLibs = $1;
+ } else {
+ push @buildArgs, $opt;
+ }
+ }
+
+ my $make = qtMakeCommand($qmakebin);
+ my $config = configuration();
+ push @buildArgs, "INSTALL_HEADERS=" . $installHeaders if defined($installHeaders);
+ push @buildArgs, "INSTALL_LIBS=" . $installLibs if defined($installLibs);
+ my $dir = File::Spec->canonpath(baseProductDir());
+ $dir = File::Spec->catfile($dir, $config) unless isSymbian();
+ File::Path::mkpath($dir);
+ chdir $dir or die "Failed to cd into " . $dir . "\n";
+
+ print "Generating derived sources\n\n";
+
+ push @buildArgs, "OUTPUT_DIR=" . baseProductDir() . "/$config";
+
+ my @dsQmakeArgs = @buildArgs;
+ push @dsQmakeArgs, "-r";
+ push @dsQmakeArgs, sourceDir() . "/DerivedSources.pro";
+ push @dsQmakeArgs, "-o Makefile.DerivedSources";
+ print "Calling '$qmakebin @dsQmakeArgs' in " . $dir . "\n\n";
+ my $result = system "$qmakebin @dsQmakeArgs";
+ if ($result ne 0) {
+ die "Failed while running $qmakebin to generate derived sources!\n";
+ }
+
+ my $dsMakefile = "Makefile.DerivedSources";
+
+ # Iterate over different source directories manually to workaround a problem with qmake+extraTargets+s60
+ my @subdirs = ("JavaScriptCore", "WebCore", "WebKit/qt/Api");
+ if (grep { $_ eq "CONFIG+=webkit2"} @buildArgs) {
+ push @subdirs, "WebKit2";
+ push @subdirs, "Tools/WebKitTestRunner";
+ push @subdirs, "Tools/MiniBrowser";
+ }
+
+ for my $subdir (@subdirs) {
+ print "Calling '$make $makeargs -f $dsMakefile generated_files' in " . $dir . "/$subdir\n\n";
+ if ($make eq "nmake") {
+ my $subdirWindows = $subdir;
+ $subdirWindows =~ s:/:\\:g;
+ $result = system "pushd $subdirWindows && $make $makeargs -f $dsMakefile generated_files && popd";
+ } else {
+ $result = system "$make $makeargs -C $subdir -f $dsMakefile generated_files";
+ }
+ if ($result ne 0) {
+ die "Failed to generate ${subdir}'s derived sources!\n";
+ }
+ }
+
+ if ($config =~ m/debug/i) {
+ push @buildArgs, "CONFIG-=release";
+ push @buildArgs, "CONFIG+=debug";
+ } else {
+ my $passedConfig = passedConfiguration() || "";
+ if (!isDarwin() || $passedConfig =~ m/release/i) {
+ push @buildArgs, "CONFIG+=release";
+ push @buildArgs, "CONFIG-=debug";
+ } else {
+ push @buildArgs, "CONFIG+=debug";
+ push @buildArgs, "CONFIG+=debug_and_release";
+ }
+ }
+
+ push @buildArgs, sourceDir() . "/WebKit.pro";
+
+ print "Calling '$qmakebin @buildArgs' in " . $dir . "\n\n";
+ print "Installation headers directory: $installHeaders\n" if(defined($installHeaders));
+ print "Installation libraries directory: $installLibs\n" if(defined($installLibs));
+
+ $result = system "$qmakebin @buildArgs";
+ if ($result ne 0) {
+ die "Failed to setup build environment using $qmakebin!\n";
+ }
+
+ # Manually create makefiles for the examples so we don't build by default
+ my $examplesDir = $dir . "/WebKit/qt/examples";
+ File::Path::mkpath($examplesDir);
+ $buildArgs[-1] = sourceDir() . "/WebKit/qt/examples/examples.pro";
+ chdir $examplesDir or die;
+ print "Calling '$qmakebin @buildArgs' in " . $examplesDir . "\n\n";
+ $result = system "$qmakebin @buildArgs";
+ die "Failed to create makefiles for the examples!\n" if $result ne 0;
+ chdir $dir or die;
+
+ if ($clean) {
+ print "Calling '$make $makeargs distclean' in " . $dir . "\n\n";
+ $result = system "$make $makeargs distclean";
+ } elsif (isSymbian()) {
+ print "\n\nWebKit is now configured for building, but you have to make\n";
+ print "a choice about the target yourself. To start the build run:\n\n";
+ print " make release-armv5|debug-winscw|etc.\n\n";
+ } else {
+ print "Calling '$make $makeargs' in " . $dir . "\n\n";
+ $result = system "$make $makeargs";
+ }
+
+ chdir ".." or die;
+ return $result;
+}
+
+sub buildQMakeQtProject($$@)
+{
+ my ($project, $clean, @buildArgs) = @_;
+
+ return buildQMakeProject($clean, @buildArgs);
+}
+
+sub buildGtkProject($$@)
+{
+ my ($project, $clean, @buildArgs) = @_;
+
+ if ($project ne "WebKit") {
+ die "The Gtk port builds JavaScriptCore, WebCore and WebKit in one shot! Only call it for 'WebKit'.\n";
+ }
+
+ return buildAutotoolsProject($clean, @buildArgs);
+}
+
+sub buildChromiumMakefile($$)
+{
+ my ($target, $clean) = @_;
+ if ($clean) {
+ return system qw(rm -rf out);
+ }
+ my $config = configuration();
+ my $numCpus = numberOfCPUs();
+ my @command = ("make", "-fMakefile.chromium", "-j$numCpus", "BUILDTYPE=$config", $target);
+ print join(" ", @command) . "\n";
+ return system @command;
+}
+
+sub buildChromiumVisualStudioProject($$)
+{
+ my ($projectPath, $clean) = @_;
+
+ my $config = configuration();
+ my $action = "/build";
+ $action = "/clean" if $clean;
+
+ # Find Visual Studio installation.
+ my $vsInstallDir;
+ my $programFilesPath = $ENV{'PROGRAMFILES'} || "C:\\Program Files";
+ if ($ENV{'VSINSTALLDIR'}) {
+ $vsInstallDir = $ENV{'VSINSTALLDIR'};
+ } else {
+ $vsInstallDir = "$programFilesPath/Microsoft Visual Studio 8";
+ }
+ $vsInstallDir = `cygpath "$vsInstallDir"` if isCygwin();
+ chomp $vsInstallDir;
+ $vcBuildPath = "$vsInstallDir/Common7/IDE/devenv.com";
+ if (! -e $vcBuildPath) {
+ # Visual Studio not found, try VC++ Express
+ $vcBuildPath = "$vsInstallDir/Common7/IDE/VCExpress.exe";
+ if (! -e $vcBuildPath) {
+ print "*************************************************************\n";
+ print "Cannot find '$vcBuildPath'\n";
+ print "Please execute the file 'vcvars32.bat' from\n";
+ print "'$programFilesPath\\Microsoft Visual Studio 8\\VC\\bin\\'\n";
+ print "to setup the necessary environment variables.\n";
+ print "*************************************************************\n";
+ die;
+ }
+ }
+
+ # Create command line and execute it.
+ my @command = ($vcBuildPath, $projectPath, $action, $config);
+ print "Building results into: ", baseProductDir(), "\n";
+ print join(" ", @command), "\n";
+ return system @command;
+}
+
+sub buildChromium($@)
+{
+ my ($clean, @options) = @_;
+
+ # We might need to update DEPS or re-run GYP if things have changed.
+ if (checkForArgumentAndRemoveFromArrayRef("--update-chromium", \@options)) {
+ system("perl", "Tools/Scripts/update-webkit-chromium") == 0 or die $!;
+ }
+
+ my $result = 1;
+ if (isDarwin()) {
+ # Mac build - builds the root xcode project.
+ $result = buildXCodeProject("WebKit/chromium/WebKit", $clean, "-configuration", configuration(), @options);
+ } elsif (isCygwin() || isWindows()) {
+ # Windows build - builds the root visual studio solution.
+ $result = buildChromiumVisualStudioProject("WebKit/chromium/WebKit.sln", $clean);
+ } elsif (isLinux()) {
+ # Linux build - build using make.
+ $ result = buildChromiumMakefile("all", $clean);
+ } else {
+ print STDERR "This platform is not supported by chromium.\n";
+ }
+ return $result;
+}
+
+sub appleApplicationSupportPath
+{
+ open INSTALL_DIR, "</proc/registry/HKEY_LOCAL_MACHINE/SOFTWARE/Apple\ Inc./Apple\ Application\ Support/InstallDir";
+ my $path = <INSTALL_DIR>;
+ $path =~ s/[\r\n\x00].*//;
+ close INSTALL_DIR;
+
+ my $unixPath = `cygpath -u '$path'`;
+ chomp $unixPath;
+ return $unixPath;
+}
+
+sub setPathForRunningWebKitApp
+{
+ my ($env) = @_;
+
+ if (isAppleWinWebKit()) {
+ $env->{PATH} = join(':', productDir(), dirname(installedSafariPath()), appleApplicationSupportPath(), $env->{PATH} || "");
+ } elsif (isQt()) {
+ my $qtLibs = `qmake -query QT_INSTALL_LIBS`;
+ $qtLibs =~ s/[\n|\r]$//g;
+ $env->{PATH} = join(';', $qtLibs, productDir() . "/lib", $env->{PATH} || "");
+ }
+}
+
+sub runSafari
+{
+ my ($debugger) = @_;
+
+ if (isAppleMacWebKit()) {
+ return system "$FindBin::Bin/gdb-safari", argumentsForConfiguration() if $debugger;
+
+ my $productDir = productDir();
+ print "Starting Safari with DYLD_FRAMEWORK_PATH set to point to built WebKit in $productDir.\n";
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
+ if (!isTiger() && architecture()) {
+ return system "arch", "-" . architecture(), safariPath(), @ARGV;
+ } else {
+ return system safariPath(), @ARGV;
+ }
+ }
+
+ if (isAppleWinWebKit()) {
+ my $result;
+ my $productDir = productDir();
+ if ($debugger) {
+ setupCygwinEnv();
+ chomp($ENV{WEBKITNIGHTLY} = `cygpath -wa "$productDir"`);
+ my $safariPath = safariPath();
+ chomp($safariPath = `cygpath -wa "$safariPath"`);
+ $result = system $vcBuildPath, "/debugexe", "\"$safariPath\"", @ARGV;
+ } else {
+ $result = system File::Spec->catfile(productDir(), "WebKit.exe"), @ARGV;
+ }
+ return $result if $result;
+ }
+
+ return 1;
+}
+
+sub runMiniBrowser
+{
+ if (isAppleMacWebKit()) {
+ my $productDir = productDir();
+ print "Starting MiniBrowser with DYLD_FRAMEWORK_PATH set to point to $productDir.\n";
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
+ my $miniBrowserPath = "$productDir/MiniBrowser.app/Contents/MacOS/MiniBrowser";
+ if (!isTiger() && architecture()) {
+ return system "arch", "-" . architecture(), $miniBrowserPath, @ARGV;
+ } else {
+ return system $miniBrowserPath, @ARGV;
+ }
+ }
+
+ return 1;
+}
+
+sub debugMiniBrowser
+{
+ if (isAppleMacWebKit()) {
+ my $gdbPath = "/usr/bin/gdb";
+ die "Can't find gdb executable. Is gdb installed?\n" unless -x $gdbPath;
+
+ my $productDir = productDir();
+
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = 'YES';
+
+ my $miniBrowserPath = "$productDir/MiniBrowser.app/Contents/MacOS/MiniBrowser";
+
+ print "Starting MiniBrowser under gdb with DYLD_FRAMEWORK_PATH set to point to built WebKit2 in $productDir.\n";
+ my @architectureFlags = ("-arch", architecture()) if !isTiger();
+ exec $gdbPath, @architectureFlags, $miniBrowserPath or die;
+ return;
+ }
+
+ return 1;
+}
+
+sub runWebKitTestRunner
+{
+ if (isAppleMacWebKit()) {
+ my $productDir = productDir();
+ print "Starting WebKitTestRunner with DYLD_FRAMEWORK_PATH set to point to $productDir.\n";
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
+ my $webKitTestRunnerPath = "$productDir/WebKitTestRunner";
+ if (!isTiger() && architecture()) {
+ return system "arch", "-" . architecture(), $webKitTestRunnerPath, @ARGV;
+ } else {
+ return system $webKitTestRunnerPath, @ARGV;
+ }
+ }
+
+ return 1;
+}
+
+sub debugWebKitTestRunner
+{
+ if (isAppleMacWebKit()) {
+ my $gdbPath = "/usr/bin/gdb";
+ die "Can't find gdb executable. Is gdb installed?\n" unless -x $gdbPath;
+
+ my $productDir = productDir();
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = 'YES';
+
+ my $webKitTestRunnerPath = "$productDir/WebKitTestRunner";
+
+ print "Starting WebKitTestRunner under gdb with DYLD_FRAMEWORK_PATH set to point to $productDir.\n";
+ my @architectureFlags = ("-arch", architecture()) if !isTiger();
+ exec $gdbPath, @architectureFlags, $webKitTestRunnerPath or die;
+ return;
+ }
+
+ return 1;
+}
+
+sub runTestWebKitAPI
+{
+ if (isAppleMacWebKit()) {
+ my $productDir = productDir();
+ print "Starting TestWebKitAPI with DYLD_FRAMEWORK_PATH set to point to $productDir.\n";
+ $ENV{DYLD_FRAMEWORK_PATH} = $productDir;
+ $ENV{WEBKIT_UNSET_DYLD_FRAMEWORK_PATH} = "YES";
+ my $testWebKitAPIPath = "$productDir/TestWebKitAPI";
+ if (!isTiger() && architecture()) {
+ return system "arch", "-" . architecture(), $testWebKitAPIPath, @ARGV;
+ } else {
+ return system $testWebKitAPIPath, @ARGV;
+ }
+ }
+
+ return 1;
+}
+
+1;
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/fixChangeLogPatch.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/fixChangeLogPatch.pl
new file mode 100644
index 0000000..a7282c7
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/fixChangeLogPatch.pl
@@ -0,0 +1,533 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2009, 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+# Copyright (C) Research In Motion 2010. 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.
+
+# Unit tests of VCSUtils::fixChangeLogPatch().
+
+use strict;
+use warnings;
+
+use Test::More;
+use VCSUtils;
+
+# The source ChangeLog for these tests is the following:
+#
+# 2009-12-22 Alice <alice@email.address>
+#
+# Reviewed by Ray.
+#
+# Changed some code on 2009-12-22.
+#
+# * File:
+# * File2:
+#
+# 2009-12-21 Alice <alice@email.address>
+#
+# Reviewed by Ray.
+#
+# Changed some code on 2009-12-21.
+#
+# * File:
+# * File2:
+
+my @testCaseHashRefs = (
+{ # New test
+ diffName => "fixChangeLogPatch: [no change] In-place change.",
+ inputText => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -1,5 +1,5 @@
+ 2010-12-22 Bob <bob@email.address>
+
+- Reviewed by Sue.
++ Reviewed by Ray.
+
+ Changed some code on 2010-12-22.
+END
+ expectedReturn => {
+ patch => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -1,5 +1,5 @@
+ 2010-12-22 Bob <bob@email.address>
+
+- Reviewed by Sue.
++ Reviewed by Ray.
+
+ Changed some code on 2010-12-22.
+END
+ }
+},
+{ # New test
+ diffName => "fixChangeLogPatch: [no change] Remove first entry.",
+ inputText => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -1,11 +1,3 @@
+-2010-12-22 Bob <bob@email.address>
+-
+- Reviewed by Ray.
+-
+- Changed some code on 2010-12-22.
+-
+- * File:
+-
+ 2010-12-22 Alice <alice@email.address>
+
+ Reviewed by Ray.
+END
+ expectedReturn => {
+ patch => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -1,11 +1,3 @@
+-2010-12-22 Bob <bob@email.address>
+-
+- Reviewed by Ray.
+-
+- Changed some code on 2010-12-22.
+-
+- * File:
+-
+ 2010-12-22 Alice <alice@email.address>
+
+ Reviewed by Ray.
+END
+ }
+},
+{ # New test
+ diffName => "fixChangeLogPatch: [no change] Remove entry in the middle.",
+ inputText => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@@ -7,10 +7,6 @@
+
+ * File:
+
+-2010-12-22 Bob <bob@email.address>
+-
+- Changed some code on 2010-12-22.
+-
+ 2010-12-22 Alice <alice@email.address>
+
+ Reviewed by Ray.
+END
+ expectedReturn => {
+ patch => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@@ -7,10 +7,6 @@
+
+ * File:
+
+-2010-12-22 Bob <bob@email.address>
+-
+- Changed some code on 2010-12-22.
+-
+ 2010-12-22 Alice <alice@email.address>
+
+ Reviewed by Ray.
+END
+ }
+},
+{ # New test
+ diffName => "fixChangeLogPatch: [no change] Far apart changes (i.e. more than one chunk).",
+ inputText => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -7,7 +7,7 @@
+
+ * File:
+
+-2010-12-22 Bob <bob@email.address>
++2010-12-22 Bobby <bob@email.address>
+
+ Changed some code on 2010-12-22.
+
+@@ -21,7 +21,7 @@
+
+ * File2:
+
+-2010-12-21 Bob <bob@email.address>
++2010-12-21 Bobby <bob@email.address>
+
+ Changed some code on 2010-12-21.
+END
+ expectedReturn => {
+ patch => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -7,7 +7,7 @@
+
+ * File:
+
+-2010-12-22 Bob <bob@email.address>
++2010-12-22 Bobby <bob@email.address>
+
+ Changed some code on 2010-12-22.
+
+@@ -21,7 +21,7 @@
+
+ * File2:
+
+-2010-12-21 Bob <bob@email.address>
++2010-12-21 Bobby <bob@email.address>
+
+ Changed some code on 2010-12-21.
+END
+ }
+},
+{ # New test
+ diffName => "fixChangeLogPatch: [no change] First line is new line.",
+ inputText => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -1,3 +1,11 @@
++2009-12-22 Bob <bob@email.address>
++
++ Reviewed by Ray.
++
++ Changed some more code on 2009-12-22.
++
++ * File:
++
+ 2009-12-22 Alice <alice@email.address>
+
+ Reviewed by Ray.
+END
+ expectedReturn => {
+ patch => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -1,3 +1,11 @@
++2009-12-22 Bob <bob@email.address>
++
++ Reviewed by Ray.
++
++ Changed some more code on 2009-12-22.
++
++ * File:
++
+ 2009-12-22 Alice <alice@email.address>
+
+ Reviewed by Ray.
+END
+ }
+},
+{ # New test
+ diffName => "fixChangeLogPatch: [no change] No date string.",
+ inputText => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -6,6 +6,7 @@
+
+ * File:
+ * File2:
++ * File3:
+
+ 2009-12-21 Alice <alice@email.address>
+
+END
+ expectedReturn => {
+ patch => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -6,6 +6,7 @@
+
+ * File:
+ * File2:
++ * File3:
+
+ 2009-12-21 Alice <alice@email.address>
+
+END
+ }
+},
+{ # New test
+ diffName => "fixChangeLogPatch: [no change] New entry inserted in middle.",
+ inputText => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -11,6 +11,14 @@
+
+ Reviewed by Ray.
+
++ Changed some more code on 2009-12-21.
++
++ * File:
++
++2009-12-21 Alice <alice@email.address>
++
++ Reviewed by Ray.
++
+ Changed some code on 2009-12-21.
+
+ * File:
+END
+ expectedReturn => {
+ hasOverlappingLines => 1,
+ patch => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -11,6 +11,14 @@
+
+ Reviewed by Ray.
+
++ Changed some more code on 2009-12-21.
++
++ * File:
++
++2009-12-21 Alice <alice@email.address>
++
++ Reviewed by Ray.
++
+ Changed some code on 2009-12-21.
+
+ * File:
+END
+ }
+},
+{ # New test
+ diffName => "fixChangeLogPatch: [no change] New entry inserted earlier in the file, but after an entry with the same author and date.",
+ inputText => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -70,6 +70,14 @@
+
+ 2009-12-22 Alice <alice@email.address>
+
++ Reviewed by Sue.
++
++ Changed some more code on 2009-12-22.
++
++ * File:
++
++2009-12-22 Alice <alice@email.address>
++
+ Reviewed by Ray.
+
+ Changed some code on 2009-12-22.
+END
+ expectedReturn => {
+ hasOverlappingLines => 1,
+ patch => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -70,6 +70,14 @@
+
+ 2009-12-22 Alice <alice@email.address>
+
++ Reviewed by Sue.
++
++ Changed some more code on 2009-12-22.
++
++ * File:
++
++2009-12-22 Alice <alice@email.address>
++
+ Reviewed by Ray.
+
+ Changed some code on 2009-12-22.
+END
+ }
+},
+{ # New test
+ diffName => "fixChangeLogPatch: Leading context includes first line.",
+ inputText => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -1,5 +1,13 @@
+ 2009-12-22 Alice <alice@email.address>
+
++ Reviewed by Sue.
++
++ Changed some more code on 2009-12-22.
++
++ * File:
++
++2009-12-22 Alice <alice@email.address>
++
+ Reviewed by Ray.
+
+ Changed some code on 2009-12-22.
+END
+ expectedReturn => {
+ patch => <<'END',
+--- ChangeLog
++++ ChangeLog
+@@ -1,3 +1,11 @@
++2009-12-22 Alice <alice@email.address>
++
++ Reviewed by Sue.
++
++ Changed some more code on 2009-12-22.
++
++ * File:
++
+ 2009-12-22 Alice <alice@email.address>
+
+ Reviewed by Ray.
+END
+ }
+},
+{ # New test
+ diffName => "fixChangeLogPatch: Leading context does not include first line.",
+ inputText => <<'END',
+@@ -2,6 +2,14 @@
+
+ Reviewed by Ray.
+
++ Changed some more code on 2009-12-22.
++
++ * File:
++
++2009-12-22 Alice <alice@email.address>
++
++ Reviewed by Ray.
++
+ Changed some code on 2009-12-22.
+
+ * File:
+END
+ expectedReturn => {
+ patch => <<'END',
+@@ -1,3 +1,11 @@
++2009-12-22 Alice <alice@email.address>
++
++ Reviewed by Ray.
++
++ Changed some more code on 2009-12-22.
++
++ * File:
++
+ 2009-12-22 Alice <alice@email.address>
+
+ Reviewed by Ray.
+END
+ }
+},
+{ # New test
+ diffName => "fixChangeLogPatch: Non-consecutive line additions.",
+
+# This can occur, for example, if the new ChangeLog entry includes
+# trailing white space in the first blank line but not the second.
+# A diff command can then match the second blank line of the new
+# ChangeLog entry with the first blank line of the old.
+# The svn diff command with the default --diff-cmd has done this.
+ inputText => <<'END',
+@@ -1,5 +1,11 @@
+ 2009-12-22 Alice <alice@email.address>
++ <pretend-whitespace>
++ Reviewed by Ray.
+
++ Changed some more code on 2009-12-22.
++
++2009-12-22 Alice <alice@email.address>
++
+ Reviewed by Ray.
+
+ Changed some code on 2009-12-22.
+END
+ expectedReturn => {
+ patch => <<'END',
+@@ -1,3 +1,9 @@
++2009-12-22 Alice <alice@email.address>
++ <pretend-whitespace>
++ Reviewed by Ray.
++
++ Changed some more code on 2009-12-22.
++
+ 2009-12-22 Alice <alice@email.address>
+
+ Reviewed by Ray.
+END
+ }
+},
+{ # New test
+ diffName => "fixChangeLogPatch: Additional edits after new entry.",
+ inputText => <<'END',
+@@ -2,10 +2,17 @@
+
+ Reviewed by Ray.
+
++ Changed some more code on 2009-12-22.
++
++ * File:
++
++2009-12-22 Alice <alice@email.address>
++
++ Reviewed by Ray.
++
+ Changed some code on 2009-12-22.
+
+ * File:
+- * File2:
+
+ 2009-12-21 Alice <alice@email.address>
+
+END
+ expectedReturn => {
+ patch => <<'END',
+@@ -1,11 +1,18 @@
++2009-12-22 Alice <alice@email.address>
++
++ Reviewed by Ray.
++
++ Changed some more code on 2009-12-22.
++
++ * File:
++
+ 2009-12-22 Alice <alice@email.address>
+
+ Reviewed by Ray.
+
+ Changed some code on 2009-12-22.
+
+ * File:
+- * File2:
+
+ 2009-12-21 Alice <alice@email.address>
+
+END
+ }
+},
+);
+
+my $testCasesCount = @testCaseHashRefs;
+plan(tests => $testCasesCount); # Total number of assertions.
+
+foreach my $testCase (@testCaseHashRefs) {
+ my $testNameStart = "fixChangeLogPatch(): $testCase->{diffName}: comparing";
+
+ my $got = VCSUtils::fixChangeLogPatch($testCase->{inputText});
+ my $expectedReturn = $testCase->{expectedReturn};
+
+ is_deeply($got, $expectedReturn, "$testNameStart return value.");
+}
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/generatePatchCommand.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/generatePatchCommand.pl
new file mode 100644
index 0000000..483a0a8
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/generatePatchCommand.pl
@@ -0,0 +1,87 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2009, 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+#
+# 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.
+
+# Unit tests of VCSUtils::generatePatchCommand().
+
+use Test::Simple tests => 10;
+use VCSUtils;
+
+# New test
+$title = "generatePatchCommand: Undefined optional arguments.";
+
+my $argsHashRef;
+my ($patchCommand, $isForcing) = VCSUtils::generatePatchCommand($argsHashRef);
+
+ok($patchCommand eq "patch -p0", $title);
+ok($isForcing == 0, $title);
+
+# New test
+$title = "generatePatchCommand: Undefined options.";
+
+my $options;
+$argsHashRef = {options => $options};
+($patchCommand, $isForcing) = VCSUtils::generatePatchCommand($argsHashRef);
+
+ok($patchCommand eq "patch -p0", $title);
+ok($isForcing == 0, $title);
+
+# New test
+$title = "generatePatchCommand: --force and no \"ensure force\".";
+
+$argsHashRef = {options => ["--force"]};
+($patchCommand, $isForcing) = VCSUtils::generatePatchCommand($argsHashRef);
+
+ok($patchCommand eq "patch -p0 --force", $title);
+ok($isForcing == 1, $title);
+
+# New test
+$title = "generatePatchCommand: no --force and \"ensure force\".";
+
+$argsHashRef = {ensureForce => 1};
+($patchCommand, $isForcing) = VCSUtils::generatePatchCommand($argsHashRef);
+
+ok($patchCommand eq "patch -p0 --force", $title);
+ok($isForcing == 1, $title);
+
+# New test
+$title = "generatePatchCommand: \"should reverse\".";
+
+$argsHashRef = {shouldReverse => 1};
+($patchCommand, $isForcing) = VCSUtils::generatePatchCommand($argsHashRef);
+
+ok($patchCommand eq "patch -p0 --reverse", $title);
+
+# New test
+$title = "generatePatchCommand: --fuzz=3, --force.";
+
+$argsHashRef = {options => ["--fuzz=3", "--force"]};
+($patchCommand, $isForcing) = VCSUtils::generatePatchCommand($argsHashRef);
+
+ok($patchCommand eq "patch -p0 --force --fuzz=3", $title);
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/mergeChangeLogs.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/mergeChangeLogs.pl
new file mode 100644
index 0000000..a226e43
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/mergeChangeLogs.pl
@@ -0,0 +1,336 @@
+#!/usr/bin/perl
+#
+# 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.
+
+# Unit tests of VCSUtils::mergeChangeLogs().
+
+use strict;
+
+use Test::Simple tests => 16;
+use File::Temp qw(tempfile);
+use VCSUtils;
+
+# Read contents of a file and return it.
+sub readFile($)
+{
+ my ($fileName) = @_;
+
+ local $/;
+ open(FH, "<", $fileName);
+ my $content = <FH>;
+ close(FH);
+
+ return $content;
+}
+
+# Write a temporary file and return the filename.
+sub writeTempFile($$$)
+{
+ my ($name, $extension, $content) = @_;
+
+ my ($FH, $fileName) = tempfile(
+ $name . "-XXXXXXXX",
+ DIR => ($ENV{'TMPDIR'} || "/tmp"),
+ UNLINK => 0,
+ );
+ print $FH $content;
+ close $FH;
+
+ if ($extension) {
+ my $newFileName = $fileName . $extension;
+ rename($fileName, $newFileName);
+ $fileName = $newFileName;
+ }
+
+ return $fileName;
+}
+
+# --------------------------------------------------------------------------------
+
+{
+ # New test
+ my $title = "mergeChangeLogs: traditional rejected patch success";
+
+ my $fileNewerContent = <<'EOF';
+2010-01-29 Mark Rowe <mrowe@apple.com>
+
+ Fix the Mac build.
+
+ Disable ENABLE_INDEXED_DATABASE since it is "completely non-functional".
+
+2010-01-29 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Fix the ARM build.
+EOF
+ my $fileNewer = writeTempFile("file", "", $fileNewerContent);
+
+ my $fileMineContent = <<'EOF';
+***************
+*** 1,3 ****
+ 2010-01-29 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+--- 1,9 ----
++ 2010-01-29 Oliver Hunt <oliver@apple.com>
++
++ Reviewed by Darin Adler.
++
++ JSC is failing to propagate anonymous slot count on some transitions
++
+ 2010-01-29 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+EOF
+ my $fileMine = writeTempFile("file", ".rej", $fileMineContent);
+ rename($fileMine, $fileNewer . ".rej");
+ $fileMine = $fileNewer . ".rej";
+
+ my $fileOlderContent = $fileNewerContent;
+ my $fileOlder = writeTempFile("file", ".orig", $fileOlderContent);
+ rename($fileOlder, $fileNewer . ".orig");
+ $fileOlder = $fileNewer . ".orig";
+
+ my $exitStatus = mergeChangeLogs($fileMine, $fileOlder, $fileNewer);
+
+ # mergeChangeLogs() should return 1 since the patch succeeded.
+ ok($exitStatus == 1, "$title: should return 1 for success");
+
+ ok(readFile($fileMine) eq $fileMineContent, "$title: \$fileMine should be unchanged");
+ ok(readFile($fileOlder) eq $fileOlderContent, "$title: \$fileOlder should be unchanged");
+
+ my $expectedContent = <<'EOF';
+2010-01-29 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Darin Adler.
+
+ JSC is failing to propagate anonymous slot count on some transitions
+
+EOF
+ $expectedContent .= $fileNewerContent;
+ ok(readFile($fileNewer) eq $expectedContent, "$title: \$fileNewer should be updated to include patch");
+
+ unlink($fileMine, $fileOlder, $fileNewer);
+}
+
+# --------------------------------------------------------------------------------
+
+{
+ # New test
+ my $title = "mergeChangeLogs: traditional rejected patch failure";
+
+ my $fileNewerContent = <<'EOF';
+2010-01-29 Mark Rowe <mrowe@apple.com>
+
+ Fix the Mac build.
+
+ Disable ENABLE_INDEXED_DATABASE since it is "completely non-functional".
+
+2010-01-29 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Fix the ARM build.
+EOF
+ my $fileNewer = writeTempFile("file", "", $fileNewerContent);
+
+ my $fileMineContent = <<'EOF';
+***************
+*** 1,9 ****
+- 2010-01-29 Oliver Hunt <oliver@apple.com>
+-
+- Reviewed by Darin Adler.
+-
+- JSC is failing to propagate anonymous slot count on some transitions
+-
+ 2010-01-29 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+--- 1,3 ----
+ 2010-01-29 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+EOF
+ my $fileMine = writeTempFile("file", ".rej", $fileMineContent);
+ rename($fileMine, $fileNewer . ".rej");
+ $fileMine = $fileNewer . ".rej";
+
+ my $fileOlderContent = $fileNewerContent;
+ my $fileOlder = writeTempFile("file", ".orig", $fileOlderContent);
+ rename($fileOlder, $fileNewer . ".orig");
+ $fileOlder = $fileNewer . ".orig";
+
+ my $exitStatus = mergeChangeLogs($fileMine, $fileOlder, $fileNewer);
+
+ # mergeChangeLogs() should return 0 since the patch failed.
+ ok($exitStatus == 0, "$title: should return 0 for failure");
+
+ ok(readFile($fileMine) eq $fileMineContent, "$title: \$fileMine should be unchanged");
+ ok(readFile($fileOlder) eq $fileOlderContent, "$title: \$fileOlder should be unchanged");
+ ok(readFile($fileNewer) eq $fileNewerContent, "$title: \$fileNewer should be unchanged");
+
+ unlink($fileMine, $fileOlder, $fileNewer);
+}
+
+# --------------------------------------------------------------------------------
+
+{
+ # New test
+ my $title = "mergeChangeLogs: patch succeeds";
+
+ my $fileMineContent = <<'EOF';
+2010-01-29 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Darin Adler.
+
+ JSC is failing to propagate anonymous slot count on some transitions
+
+2010-01-29 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Fix the ARM build.
+EOF
+ my $fileMine = writeTempFile("fileMine", "", $fileMineContent);
+
+ my $fileOlderContent = <<'EOF';
+2010-01-29 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Fix the ARM build.
+EOF
+ my $fileOlder = writeTempFile("fileOlder", "", $fileOlderContent);
+
+ my $fileNewerContent = <<'EOF';
+2010-01-29 Mark Rowe <mrowe@apple.com>
+
+ Fix the Mac build.
+
+ Disable ENABLE_INDEXED_DATABASE since it is "completely non-functional".
+
+2010-01-29 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Fix the ARM build.
+EOF
+ my $fileNewer = writeTempFile("fileNewer", "", $fileNewerContent);
+
+ my $exitStatus = mergeChangeLogs($fileMine, $fileOlder, $fileNewer);
+
+ # mergeChangeLogs() should return 1 since the patch succeeded.
+ ok($exitStatus == 1, "$title: should return 1 for success");
+
+ ok(readFile($fileMine) eq $fileMineContent, "$title: \$fileMine should be unchanged");
+ ok(readFile($fileOlder) eq $fileOlderContent, "$title: \$fileOlder should be unchanged");
+
+ my $expectedContent = <<'EOF';
+2010-01-29 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Darin Adler.
+
+ JSC is failing to propagate anonymous slot count on some transitions
+
+EOF
+ $expectedContent .= $fileNewerContent;
+
+ ok(readFile($fileNewer) eq $expectedContent, "$title: \$fileNewer should be patched");
+
+ unlink($fileMine, $fileOlder, $fileNewer);
+}
+
+# --------------------------------------------------------------------------------
+
+{
+ # New test
+ my $title = "mergeChangeLogs: patch fails";
+
+ my $fileMineContent = <<'EOF';
+2010-01-29 Mark Rowe <mrowe@apple.com>
+
+ Fix the Mac build.
+
+ Disable ENABLE_INDEXED_DATABASE since it is "completely non-functional".
+
+2010-01-29 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Fix the ARM build.
+EOF
+ my $fileMine = writeTempFile("fileMine", "", $fileMineContent);
+
+ my $fileOlderContent = <<'EOF';
+2010-01-29 Mark Rowe <mrowe@apple.com>
+
+ Fix the Mac build.
+
+ Disable ENABLE_INDEXED_DATABASE since it is "completely non-functional".
+
+2010-01-29 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Darin Adler.
+
+ JSC is failing to propagate anonymous slot count on some transitions
+
+2010-01-29 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Fix the ARM build.
+EOF
+ my $fileOlder = writeTempFile("fileOlder", "", $fileOlderContent);
+
+ my $fileNewerContent = <<'EOF';
+2010-01-29 Oliver Hunt <oliver@apple.com>
+
+ Reviewed by Darin Adler.
+
+ JSC is failing to propagate anonymous slot count on some transitions
+
+2010-01-29 Simon Hausmann <simon.hausmann@nokia.com>
+
+ Rubber-stamped by Maciej Stachowiak.
+
+ Fix the ARM build.
+EOF
+ my $fileNewer = writeTempFile("fileNewer", "", $fileNewerContent);
+
+ my $exitStatus = mergeChangeLogs($fileMine, $fileOlder, $fileNewer);
+
+ # mergeChangeLogs() should return a non-zero exit status since the patch failed.
+ ok($exitStatus == 0, "$title: return non-zero exit status for failure");
+
+ ok(readFile($fileMine) eq $fileMineContent, "$title: \$fileMine should be unchanged");
+ ok(readFile($fileOlder) eq $fileOlderContent, "$title: \$fileOlder should be unchanged");
+
+ # $fileNewer should still exist unchanged because the patch failed
+ ok(readFile($fileNewer) eq $fileNewerContent, "$title: \$fileNewer should be unchanged");
+
+ unlink($fileMine, $fileOlder, $fileNewer);
+}
+
+# --------------------------------------------------------------------------------
+
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl
new file mode 100644
index 0000000..9fe077f
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiff.pl
@@ -0,0 +1,1208 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@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.
+#
+# 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.
+
+# Unit tests of parseDiff().
+
+use strict;
+use warnings;
+
+use Test::More;
+use VCSUtils;
+
+# The array of test cases.
+my @testCaseHashRefs = (
+{
+ # New test
+ diffName => "SVN: simple",
+ inputText => <<'END',
+Index: Makefile
+===================================================================
+--- Makefile (revision 53052)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools
+
+ all:
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END', # Same as input text
+Index: Makefile
+===================================================================
+--- Makefile (revision 53052)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools
+
+ all:
+END
+ indexPath => "Makefile",
+ isSvn => 1,
+ sourceRevision => "53052",
+}],
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "SVN: binary file (isBinary true)",
+ inputText => <<'END',
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+Property changes on: test_file.swf
+___________________________________________________________________
+Name: svn:mime-type
+ + application/octet-stream
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END', # Same as input text
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+ indexPath => "test_file.swf",
+ isBinary => 1,
+ isSvn => 1,
+}],
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "SVN: binary file (isBinary true) using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+Property changes on: test_file.swf
+___________________________________________________________________
+Name: svn:mime-type
+ + application/octet-stream
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+),
+ expectedReturn => [
+[{
+ svnConvertedText => toWindowsLineEndings(<<'END', # Same as input text
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+),
+ indexPath => "test_file.swf",
+ isBinary => 1,
+ isSvn => 1,
+}],
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "SVN: leading junk",
+ inputText => <<'END',
+
+LEADING JUNK
+
+Index: Makefile
+===================================================================
+--- Makefile (revision 53052)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools
+
+ all:
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END', # Same as input text
+
+LEADING JUNK
+
+Index: Makefile
+===================================================================
+--- Makefile (revision 53052)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools
+
+ all:
+END
+ indexPath => "Makefile",
+ isSvn => 1,
+ sourceRevision => "53052",
+}],
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "SVN: copied file",
+ inputText => <<'END',
+Index: Makefile_new
+===================================================================
+--- Makefile_new (revision 53131) (from Makefile:53131)
++++ Makefile_new (working copy)
+@@ -0,0 +1,1 @@
++MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools
+END
+ expectedReturn => [
+[{
+ copiedFromPath => "Makefile",
+ indexPath => "Makefile_new",
+ sourceRevision => "53131",
+}],
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "SVN: two diffs",
+ inputText => <<'END',
+Index: Makefile
+===================================================================
+--- Makefile (revision 53131)
++++ Makefile (working copy)
+@@ -1,1 +0,0 @@
+-MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools
+Index: Makefile_new
+===================================================================
+--- Makefile_new (revision 53131) (from Makefile:53131)
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END',
+Index: Makefile
+===================================================================
+--- Makefile (revision 53131)
++++ Makefile (working copy)
+@@ -1,1 +0,0 @@
+-MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools
+END
+ indexPath => "Makefile",
+ isSvn => 1,
+ sourceRevision => "53131",
+}],
+"Index: Makefile_new\n"],
+ expectedNextLine => "===================================================================\n",
+},
+{
+ # New test
+ diffName => "SVN: SVN diff followed by Git diff", # Should not recognize Git start
+ inputText => <<'END',
+Index: Makefile
+===================================================================
+--- Makefile (revision 53131)
++++ Makefile (working copy)
+@@ -1,1 +0,0 @@
+-MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools
+diff --git a/Makefile b/Makefile
+index f5d5e74..3b6aa92 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,1 1,1 @@ public:
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END', # Same as input text
+Index: Makefile
+===================================================================
+--- Makefile (revision 53131)
++++ Makefile (working copy)
+@@ -1,1 +0,0 @@
+-MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools
+diff --git a/Makefile b/Makefile
+index f5d5e74..3b6aa92 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,1 1,1 @@ public:
+END
+ indexPath => "Makefile",
+ isSvn => 1,
+ sourceRevision => "53131",
+}],
+undef],
+ expectedNextLine => undef,
+},
+####
+# Property Changes: Simple
+##
+{
+ # New test
+ diffName => "SVN: file change diff with property change diff",
+ inputText => <<'END',
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+
+Property changes on: Makefile
+___________________________________________________________________
+Name: svn:executable
+ + *
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END', # Same as input text
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+
+END
+ executableBitDelta => 1,
+ indexPath => "Makefile",
+ isSvn => 1,
+ sourceRevision => "60021",
+}],
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "SVN: file change diff, followed by property change diff on different file",
+ inputText => <<'END',
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+
+Property changes on: Makefile.shared
+___________________________________________________________________
+Name: svn:executable
+ + *
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END', # Same as input text
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+
+END
+ indexPath => "Makefile",
+ isSvn => 1,
+ sourceRevision => "60021",
+}],
+"Property changes on: Makefile.shared\n"],
+ expectedNextLine => "___________________________________________________________________\n",
+},
+{
+ # New test
+ diffName => "SVN: property diff, followed by file change diff",
+ inputText => <<'END',
+Property changes on: Makefile
+___________________________________________________________________
+Deleted: svn:executable
+ - *
+
+Index: Makefile.shared
+===================================================================
+--- Makefile.shared (revision 60021)
++++ Makefile.shared (working copy)
+@@ -1,3 +1,4 @@
++
+SCRIPTS_PATH ?= ../WebKitTools/Scripts
+XCODE_OPTIONS = `perl -I$(SCRIPTS_PATH) -Mwebkitdirs -e 'print XcodeOptionString()'` $(ARGS)
+END
+ expectedReturn => [
+[{
+ executableBitDelta => -1,
+ indexPath => "Makefile",
+ isSvn => 1,
+}],
+"Index: Makefile.shared\n"],
+ expectedNextLine => "===================================================================\n",
+},
+{
+ # New test
+ diffName => "SVN: property diff, followed by file change diff using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Property changes on: Makefile
+___________________________________________________________________
+Deleted: svn:executable
+ - *
+
+Index: Makefile.shared
+===================================================================
+--- Makefile.shared (revision 60021)
++++ Makefile.shared (working copy)
+@@ -1,3 +1,4 @@
++
+SCRIPTS_PATH ?= ../WebKitTools/Scripts
+XCODE_OPTIONS = `perl -I$(SCRIPTS_PATH) -Mwebkitdirs -e 'print XcodeOptionString()'` $(ARGS)
+END
+),
+ expectedReturn => [
+[{
+ executableBitDelta => -1,
+ indexPath => "Makefile",
+ isSvn => 1,
+}],
+"Index: Makefile.shared\r\n"],
+ expectedNextLine => "===================================================================\r\n",
+},
+{
+ # New test
+ diffName => "SVN: copied file with property change",
+ inputText => <<'END',
+Index: NMakefile
+===================================================================
+--- NMakefile (revision 60021) (from Makefile:60021)
++++ NMakefile (working copy)
+@@ -0,0 +1,1 @@
++MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+Property changes on: NMakefile
+___________________________________________________________________
+Added: svn:executable
+ + *
+END
+ expectedReturn => [
+[{
+ copiedFromPath => "Makefile",
+ executableBitDelta => 1,
+ indexPath => "NMakefile",
+ sourceRevision => "60021",
+}],
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "SVN: two consecutive property diffs",
+ inputText => <<'END',
+Property changes on: Makefile
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+
+Property changes on: Makefile.shared
+___________________________________________________________________
+Added: svn:executable
+ + *
+END
+ expectedReturn => [
+[{
+ executableBitDelta => 1,
+ indexPath => "Makefile",
+ isSvn => 1,
+}],
+"Property changes on: Makefile.shared\n"],
+ expectedNextLine => "___________________________________________________________________\n",
+},
+{
+ # New test
+ diffName => "SVN: two consecutive property diffs using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Property changes on: Makefile
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+
+Property changes on: Makefile.shared
+___________________________________________________________________
+Added: svn:executable
+ + *
+END
+),
+ expectedReturn => [
+[{
+ executableBitDelta => 1,
+ indexPath => "Makefile",
+ isSvn => 1,
+}],
+"Property changes on: Makefile.shared\r\n"],
+ expectedNextLine => "___________________________________________________________________\r\n",
+},
+####
+# Property Changes: Binary files
+##
+{
+ # New test
+ diffName => "SVN: binary file with executable bit change",
+ inputText => <<'END',
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+Property changes on: test_file.swf
+___________________________________________________________________
+Name: svn:mime-type
+ + application/octet-stream
+Name: svn:executable
+ + *
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END', # Same as input text
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+ executableBitDelta => 1,
+ indexPath => "test_file.swf",
+ isBinary => 1,
+ isSvn => 1,
+}],
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "SVN: binary file with executable bit change usng Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+Property changes on: test_file.swf
+___________________________________________________________________
+Name: svn:mime-type
+ + application/octet-stream
+Name: svn:executable
+ + *
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+),
+ expectedReturn => [
+[{
+ svnConvertedText => toWindowsLineEndings(<<'END', # Same as input text
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+),
+ executableBitDelta => 1,
+ indexPath => "test_file.swf",
+ isBinary => 1,
+ isSvn => 1,
+}],
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "SVN: binary file followed by property change on different file",
+ inputText => <<'END',
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+Property changes on: test_file.swf
+___________________________________________________________________
+Name: svn:mime-type
+ + application/octet-stream
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+
+Property changes on: Makefile
+___________________________________________________________________
+Added: svn:executable
+ + *
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END', # Same as input text
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+
+END
+ indexPath => "test_file.swf",
+ isBinary => 1,
+ isSvn => 1,
+}],
+"Property changes on: Makefile\n"],
+ expectedNextLine => "___________________________________________________________________\n",
+},
+{
+ # New test
+ diffName => "SVN: binary file followed by property change on different file using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+Property changes on: test_file.swf
+___________________________________________________________________
+Name: svn:mime-type
+ + application/octet-stream
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+
+Property changes on: Makefile
+___________________________________________________________________
+Added: svn:executable
+ + *
+END
+),
+ expectedReturn => [
+[{
+ svnConvertedText => toWindowsLineEndings(<<'END', # Same as input text
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+
+END
+),
+ indexPath => "test_file.swf",
+ isBinary => 1,
+ isSvn => 1,
+}],
+"Property changes on: Makefile\r\n"],
+ expectedNextLine => "___________________________________________________________________\r\n",
+},
+{
+ # New test
+ diffName => "SVN: binary file followed by file change on different file",
+ inputText => <<'END',
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+Property changes on: test_file.swf
+___________________________________________________________________
+Name: svn:mime-type
+ + application/octet-stream
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END', # Same as input text
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+
+END
+ indexPath => "test_file.swf",
+ isBinary => 1,
+ isSvn => 1,
+}],
+"Index: Makefile\n"],
+ expectedNextLine => "===================================================================\n",
+},
+{
+ # New test
+ diffName => "SVN: binary file followed by file change on different file using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+Property changes on: test_file.swf
+___________________________________________________________________
+Name: svn:mime-type
+ + application/octet-stream
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+END
+),
+ expectedReturn => [
+[{
+ svnConvertedText => toWindowsLineEndings(<<'END', # Same as input text
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+
+END
+),
+ indexPath => "test_file.swf",
+ isBinary => 1,
+ isSvn => 1,
+}],
+"Index: Makefile\r\n"],
+ expectedNextLine => "===================================================================\r\n",
+},
+####
+# Property Changes: File change with property change
+##
+{
+ # New test
+ diffName => "SVN: file change diff with property change, followed by property change diff",
+ inputText => <<'END',
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+
+Property changes on: Makefile
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+
+Property changes on: Makefile.shared
+___________________________________________________________________
+Deleted: svn:executable
+ - *
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END', # Same as input text
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+
+
+
+END
+ executableBitDelta => 1,
+ indexPath => "Makefile",
+ isSvn => 1,
+ sourceRevision => "60021",
+}],
+"Property changes on: Makefile.shared\n"],
+ expectedNextLine => "___________________________________________________________________\n",
+},
+{
+ # New test
+ diffName => "SVN: file change diff with property change, followed by property change diff using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+
+Property changes on: Makefile
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+
+Property changes on: Makefile.shared
+___________________________________________________________________
+Deleted: svn:executable
+ - *
+END
+),
+ expectedReturn => [
+[{
+ svnConvertedText => toWindowsLineEndings(<<'END', # Same as input text
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+
+
+
+END
+),
+ executableBitDelta => 1,
+ indexPath => "Makefile",
+ isSvn => 1,
+ sourceRevision => "60021",
+}],
+"Property changes on: Makefile.shared\r\n"],
+ expectedNextLine => "___________________________________________________________________\r\n",
+},
+{
+ # New test
+ diffName => "SVN: file change diff with property change, followed by file change diff",
+ inputText => <<'END',
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+
+Property changes on: Makefile
+___________________________________________________________________
+Name: svn:executable
+ - *
+
+Index: Makefile.shared
+===================================================================
+--- Makefile.shared (revision 60021)
++++ Makefile.shared (working copy)
+@@ -1,3 +1,4 @@
++
+SCRIPTS_PATH ?= ../WebKitTools/Scripts
+XCODE_OPTIONS = `perl -I$(SCRIPTS_PATH) -Mwebkitdirs -e 'print XcodeOptionString()'` $(ARGS)
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END', # Same as input text
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+
+
+END
+ executableBitDelta => -1,
+ indexPath => "Makefile",
+ isSvn => 1,
+ sourceRevision => "60021",
+}],
+"Index: Makefile.shared\n"],
+ expectedNextLine => "===================================================================\n",
+},
+{
+ # New test
+ diffName => "SVN: file change diff with property change, followed by file change diff using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+
+Property changes on: Makefile
+___________________________________________________________________
+Name: svn:executable
+ - *
+
+Index: Makefile.shared
+===================================================================
+--- Makefile.shared (revision 60021)
++++ Makefile.shared (working copy)
+@@ -1,3 +1,4 @@
++
+SCRIPTS_PATH ?= ../WebKitTools/Scripts
+XCODE_OPTIONS = `perl -I$(SCRIPTS_PATH) -Mwebkitdirs -e 'print XcodeOptionString()'` $(ARGS)
+END
+),
+ expectedReturn => [
+[{
+ svnConvertedText => toWindowsLineEndings(<<'END', # Same as input text
+Index: Makefile
+===================================================================
+--- Makefile (revision 60021)
++++ Makefile (working copy)
+@@ -1,3 +1,4 @@
++
+ MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKit2 WebKitTools
+
+ all:
+
+
+END
+),
+ executableBitDelta => -1,
+ indexPath => "Makefile",
+ isSvn => 1,
+ sourceRevision => "60021",
+}],
+"Index: Makefile.shared\r\n"],
+ expectedNextLine => "===================================================================\r\n",
+},
+####
+# Git test cases
+##
+{
+ # New test
+ diffName => "Git: simple",
+ inputText => <<'END',
+diff --git a/Makefile b/Makefile
+index f5d5e74..3b6aa92 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,1 1,1 @@ public:
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END',
+Index: Makefile
+index f5d5e74..3b6aa92 100644
+--- Makefile
++++ Makefile
+@@ -1,1 1,1 @@ public:
+END
+ indexPath => "Makefile",
+ isGit => 1,
+}],
+undef],
+ expectedNextLine => undef,
+},
+{ # New test
+ diffName => "Git: new file",
+ inputText => <<'END',
+diff --git a/foo.h b/foo.h
+new file mode 100644
+index 0000000..3c9f114
+--- /dev/null
++++ b/foo.h
+@@ -0,0 +1,34 @@
++<html>
+diff --git a/bar b/bar
+index d45dd40..3494526 100644
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END',
+Index: foo.h
+new file mode 100644
+index 0000000..3c9f114
+--- foo.h
++++ foo.h
+@@ -0,0 +1,34 @@
++<html>
+END
+ indexPath => "foo.h",
+ isGit => 1,
+ isNew => 1,
+}],
+"diff --git a/bar b/bar\n"],
+ expectedNextLine => "index d45dd40..3494526 100644\n",
+},
+{ # New test
+ diffName => "Git: file deletion",
+ inputText => <<'END',
+diff --git a/foo b/foo
+deleted file mode 100644
+index 1e50d1d..0000000
+--- a/foo
++++ /dev/null
+@@ -1,1 +0,0 @@
+-line1
+diff --git a/bar b/bar
+index d45dd40..3494526 100644
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END',
+Index: foo
+deleted file mode 100644
+index 1e50d1d..0000000
+--- foo
++++ foo
+@@ -1,1 +0,0 @@
+-line1
+END
+ indexPath => "foo",
+ isDeletion => 1,
+ isGit => 1,
+}],
+"diff --git a/bar b/bar\n"],
+ expectedNextLine => "index d45dd40..3494526 100644\n",
+},
+{
+ # New test
+ diffName => "Git: Git diff followed by SVN diff", # Should not recognize SVN start
+ inputText => <<'END',
+diff --git a/Makefile b/Makefile
+index f5d5e74..3b6aa92 100644
+--- a/Makefile
++++ b/Makefile
+@@ -1,1 1,1 @@ public:
+Index: Makefile_new
+===================================================================
+--- Makefile_new (revision 53131) (from Makefile:53131)
+END
+ expectedReturn => [
+[{
+ svnConvertedText => <<'END',
+Index: Makefile
+index f5d5e74..3b6aa92 100644
+--- Makefile
++++ Makefile
+@@ -1,1 1,1 @@ public:
+Index: Makefile_new
+===================================================================
+--- Makefile_new (revision 53131) (from Makefile:53131)
+END
+ indexPath => "Makefile",
+ isGit => 1,
+}],
+undef],
+ expectedNextLine => undef,
+},
+####
+# Git test cases: file moves (multiple return values)
+##
+{
+ diffName => "Git: rename (with similarity index 100%)",
+ inputText => <<'END',
+diff --git a/foo b/foo_new
+similarity index 100%
+rename from foo
+rename to foo_new
+diff --git a/bar b/bar
+index d45dd40..3494526 100644
+END
+ expectedReturn => [
+[{
+ indexPath => "foo",
+ isDeletion => 1,
+},
+{
+ copiedFromPath => "foo",
+ indexPath => "foo_new",
+}],
+"diff --git a/bar b/bar\n"],
+ expectedNextLine => "index d45dd40..3494526 100644\n",
+},
+{
+ diffName => "rename (with similarity index < 100%)",
+ inputText => <<'END',
+diff --git a/foo b/foo_new
+similarity index 99%
+rename from foo
+rename to foo_new
+index 1e50d1d..1459d21 100644
+--- a/foo
++++ b/foo_new
+@@ -15,3 +15,4 @@ release r deployment dep deploy:
+ line1
+ line2
+ line3
++line4
+diff --git a/bar b/bar
+index d45dd40..3494526 100644
+END
+ expectedReturn => [
+[{
+ indexPath => "foo",
+ isDeletion => 1,
+},
+{
+ copiedFromPath => "foo",
+ indexPath => "foo_new",
+},
+{
+ indexPath => "foo_new",
+ isGit => 1,
+ svnConvertedText => <<'END',
+Index: foo_new
+similarity index 99%
+rename from foo
+rename to foo_new
+index 1e50d1d..1459d21 100644
+--- foo_new
++++ foo_new
+@@ -15,3 +15,4 @@ release r deployment dep deploy:
+ line1
+ line2
+ line3
++line4
+END
+}],
+"diff --git a/bar b/bar\n"],
+ expectedNextLine => "index d45dd40..3494526 100644\n",
+},
+{
+ diffName => "rename (with executable bit change)",
+ inputText => <<'END',
+diff --git a/foo b/foo_new
+old mode 100644
+new mode 100755
+similarity index 100%
+rename from foo
+rename to foo_new
+diff --git a/bar b/bar
+index d45dd40..3494526 100644
+END
+ expectedReturn => [
+[{
+ indexPath => "foo",
+ isDeletion => 1,
+},
+{
+ copiedFromPath => "foo",
+ indexPath => "foo_new",
+},
+{
+ executableBitDelta => 1,
+ indexPath => "foo_new",
+ isGit => 1,
+ svnConvertedText => <<'END',
+Index: foo_new
+old mode 100644
+new mode 100755
+similarity index 100%
+rename from foo
+rename to foo_new
+END
+}],
+"diff --git a/bar b/bar\n"],
+ expectedNextLine => "index d45dd40..3494526 100644\n",
+},
+);
+
+my $testCasesCount = @testCaseHashRefs;
+plan(tests => 2 * $testCasesCount); # Total number of assertions.
+
+foreach my $testCase (@testCaseHashRefs) {
+ my $testNameStart = "parseDiff(): $testCase->{diffName}: comparing";
+
+ my $fileHandle;
+ open($fileHandle, "<", \$testCase->{inputText});
+ my $line = <$fileHandle>;
+
+ my @got = VCSUtils::parseDiff($fileHandle, $line);
+ my $expectedReturn = $testCase->{expectedReturn};
+
+ is_deeply(\@got, $expectedReturn, "$testNameStart return value.");
+
+ my $gotNextLine = <$fileHandle>;
+ is($gotNextLine, $testCase->{expectedNextLine}, "$testNameStart next read line.");
+}
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl
new file mode 100644
index 0000000..8c20f65
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl
@@ -0,0 +1,121 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+#
+# 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 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 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.
+
+# Unit tests of parseDiffHeader().
+
+use strict;
+use warnings;
+
+use Test::More;
+use VCSUtils;
+
+# The unit tests for parseGitDiffHeader() and parseSvnDiffHeader()
+# already thoroughly test parsing each format.
+#
+# For parseDiffHeader(), it should suffice to verify that -- (1) for each
+# format, the method can return non-trivial values back for each key
+# supported by that format (e.g. "sourceRevision" for SVN), (2) the method
+# correctly sets default values when specific key-values are not set
+# (e.g. undef for "sourceRevision" for Git), and (3) key-values unique to
+# this method are set correctly (e.g. "scmFormat").
+my @testCaseHashRefs = (
+####
+# SVN test cases
+##
+{ # New test
+ diffName => "SVN: non-trivial copiedFromPath and sourceRevision values",
+ inputText => <<'END',
+Index: index_path.py
+===================================================================
+--- index_path.py (revision 53048) (from copied_from_path.py:53048)
++++ index_path.py (working copy)
+@@ -0,0 +1,7 @@
++# Python file...
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: index_path.py
+===================================================================
+--- index_path.py (revision 53048) (from copied_from_path.py:53048)
++++ index_path.py (working copy)
+END
+ copiedFromPath => "copied_from_path.py",
+ indexPath => "index_path.py",
+ isSvn => 1,
+ sourceRevision => 53048,
+},
+"@@ -0,0 +1,7 @@\n"],
+ expectedNextLine => "+# Python file...\n",
+},
+####
+# Git test cases
+##
+{ # New test case
+ diffName => "Git: Non-zero executable bit",
+ inputText => <<'END',
+diff --git a/foo.exe b/foo.exe
+old mode 100644
+new mode 100755
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo.exe
+old mode 100644
+new mode 100755
+END
+ executableBitDelta => 1,
+ indexPath => "foo.exe",
+ isGit => 1,
+},
+undef],
+ expectedNextLine => undef,
+},
+);
+
+my $testCasesCount = @testCaseHashRefs;
+plan(tests => 2 * $testCasesCount); # Total number of assertions.
+
+foreach my $testCase (@testCaseHashRefs) {
+ my $testNameStart = "parseDiffHeader(): $testCase->{diffName}: comparing";
+
+ my $fileHandle;
+ open($fileHandle, "<", \$testCase->{inputText});
+ my $line = <$fileHandle>;
+
+ my @got = VCSUtils::parseDiffHeader($fileHandle, $line);
+ my $expectedReturn = $testCase->{expectedReturn};
+
+ is_deeply(\@got, $expectedReturn, "$testNameStart return value.");
+
+ my $gotNextLine = <$fileHandle>;
+ is($gotNextLine, $testCase->{expectedNextLine}, "$testNameStart next read line.");
+}
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/parseGitDiffHeader.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseGitDiffHeader.pl
new file mode 100644
index 0000000..bc0d4d4
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseGitDiffHeader.pl
@@ -0,0 +1,494 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+# Unit tests of parseGitDiffHeader().
+
+use strict;
+use warnings;
+
+use Test::More;
+use VCSUtils;
+
+# The array of test cases.
+my @testCaseHashRefs = (
+{ # New test
+ diffName => "Modified file",
+ inputText => <<'END',
+diff --git a/foo.h b/foo.h
+index f5d5e74..3b6aa92 100644
+--- a/foo.h
++++ b/foo.h
+@@ -1 +1 @@
+-file contents
++new file contents
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo.h
+index f5d5e74..3b6aa92 100644
+--- foo.h
++++ foo.h
+END
+ indexPath => "foo.h",
+},
+"@@ -1 +1 @@\n"],
+ expectedNextLine => "-file contents\n",
+},
+{ # New test
+ diffName => "new file",
+ inputText => <<'END',
+diff --git a/foo.h b/foo.h
+new file mode 100644
+index 0000000..3c9f114
+--- /dev/null
++++ b/foo.h
+@@ -0,0 +1,34 @@
++<html>
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo.h
+new file mode 100644
+index 0000000..3c9f114
+--- foo.h
++++ foo.h
+END
+ indexPath => "foo.h",
+ isNew => 1,
+},
+"@@ -0,0 +1,34 @@\n"],
+ expectedNextLine => "+<html>\n",
+},
+{ # New test
+ diffName => "file deletion",
+ inputText => <<'END',
+diff --git a/foo b/foo
+deleted file mode 100644
+index 1e50d1d..0000000
+--- a/foo
++++ /dev/null
+@@ -1,1 +0,0 @@
+-line1
+diff --git a/configure.ac b/configure.ac
+index d45dd40..3494526 100644
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo
+deleted file mode 100644
+index 1e50d1d..0000000
+--- foo
++++ foo
+END
+ indexPath => "foo",
+ isDeletion => 1,
+},
+"@@ -1,1 +0,0 @@\n"],
+ expectedNextLine => "-line1\n",
+},
+{ # New test
+ diffName => "using --no-prefix",
+ inputText => <<'END',
+diff --git foo.h foo.h
+index c925780..9e65c43 100644
+--- foo.h
++++ foo.h
+@@ -1,3 +1,17 @@
++contents
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo.h
+index c925780..9e65c43 100644
+--- foo.h
++++ foo.h
+END
+ indexPath => "foo.h",
+},
+"@@ -1,3 +1,17 @@\n"],
+ expectedNextLine => "+contents\n",
+},
+####
+# Copy operations
+##
+{ # New test
+ diffName => "copy (with similarity index 100%)",
+ inputText => <<'END',
+diff --git a/foo b/foo_new
+similarity index 100%
+copy from foo
+copy to foo_new
+diff --git a/bar b/bar
+index d45dd40..3494526 100644
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo_new
+similarity index 100%
+copy from foo
+copy to foo_new
+END
+ copiedFromPath => "foo",
+ indexPath => "foo_new",
+},
+"diff --git a/bar b/bar\n"],
+ expectedNextLine => "index d45dd40..3494526 100644\n",
+},
+{ # New test
+ diffName => "copy (with similarity index < 100%)",
+ inputText => <<'END',
+diff --git a/foo b/foo_new
+similarity index 99%
+copy from foo
+copy to foo_new
+diff --git a/bar b/bar
+index d45dd40..3494526 100644
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo_new
+similarity index 99%
+copy from foo
+copy to foo_new
+END
+ copiedFromPath => "foo",
+ indexPath => "foo_new",
+ isCopyWithChanges => 1,
+},
+"diff --git a/bar b/bar\n"],
+ expectedNextLine => "index d45dd40..3494526 100644\n",
+},
+{ # New test
+ diffName => "rename (with similarity index 100%)",
+ inputText => <<'END',
+diff --git a/foo b/foo_new
+similarity index 100%
+rename from foo
+rename to foo_new
+diff --git a/bar b/bar
+index d45dd40..3494526 100644
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo_new
+similarity index 100%
+rename from foo
+rename to foo_new
+END
+ copiedFromPath => "foo",
+ indexPath => "foo_new",
+ shouldDeleteSource => 1,
+},
+"diff --git a/bar b/bar\n"],
+ expectedNextLine => "index d45dd40..3494526 100644\n",
+},
+{ # New test
+ diffName => "rename (with similarity index < 100%)",
+ inputText => <<'END',
+diff --git a/foo b/foo_new
+similarity index 99%
+rename from foo
+rename to foo_new
+index 1e50d1d..1459d21 100644
+--- a/foo
++++ b/foo_new
+@@ -15,3 +15,4 @@ release r deployment dep deploy:
+ line1
+ line2
+ line3
++line4
+diff --git a/bar b/bar
+index d45dd40..3494526 100644
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo_new
+similarity index 99%
+rename from foo
+rename to foo_new
+index 1e50d1d..1459d21 100644
+--- foo_new
++++ foo_new
+END
+ copiedFromPath => "foo",
+ indexPath => "foo_new",
+ isCopyWithChanges => 1,
+ shouldDeleteSource => 1,
+},
+"@@ -15,3 +15,4 @@ release r deployment dep deploy:\n"],
+ expectedNextLine => " line1\n",
+},
+{ # New test
+ diffName => "rename (with executable bit change)",
+ inputText => <<'END',
+diff --git a/foo b/foo_new
+old mode 100644
+new mode 100755
+similarity index 100%
+rename from foo
+rename to foo_new
+diff --git a/bar b/bar
+index d45dd40..3494526 100644
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo_new
+old mode 100644
+new mode 100755
+similarity index 100%
+rename from foo
+rename to foo_new
+END
+ copiedFromPath => "foo",
+ executableBitDelta => 1,
+ indexPath => "foo_new",
+ isCopyWithChanges => 1,
+ shouldDeleteSource => 1,
+},
+"diff --git a/bar b/bar\n"],
+ expectedNextLine => "index d45dd40..3494526 100644\n",
+},
+####
+# Binary file test cases
+##
+{
+ # New test case
+ diffName => "New binary file",
+ inputText => <<'END',
+diff --git a/foo.gif b/foo.gif
+new file mode 100644
+index 0000000000000000000000000000000000000000..64a9532e7794fcd791f6f12157406d9060151690
+GIT binary patch
+literal 7
+OcmYex&reDa;sO8*F9L)B
+
+literal 0
+HcmV?d00001
+
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo.gif
+new file mode 100644
+index 0000000000000000000000000000000000000000..64a9532e7794fcd791f6f12157406d9060151690
+GIT binary patch
+END
+ indexPath => "foo.gif",
+ isBinary => 1,
+ isNew => 1,
+},
+"literal 7\n"],
+ expectedNextLine => "OcmYex&reDa;sO8*F9L)B\n",
+},
+{
+ # New test case
+ diffName => "Deleted binary file",
+ inputText => <<'END',
+diff --git a/foo.gif b/foo.gif
+deleted file mode 100644
+index 323fae0..0000000
+GIT binary patch
+literal 0
+HcmV?d00001
+
+literal 7
+OcmYex&reDa;sO8*F9L)B
+
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo.gif
+deleted file mode 100644
+index 323fae0..0000000
+GIT binary patch
+END
+ indexPath => "foo.gif",
+ isBinary => 1,
+ isDeletion => 1,
+},
+"literal 0\n"],
+ expectedNextLine => "HcmV?d00001\n",
+},
+####
+# Executable bit test cases
+##
+{
+ # New test case
+ diffName => "Modified executable file",
+ inputText => <<'END',
+diff --git a/foo b/foo
+index d03e242..435ad3a 100755
+--- a/foo
++++ b/foo
+@@ -1 +1 @@
+-file contents
++new file contents
+
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo
+index d03e242..435ad3a 100755
+--- foo
++++ foo
+END
+ indexPath => "foo",
+},
+"@@ -1 +1 @@\n"],
+ expectedNextLine => "-file contents\n",
+},
+{
+ # New test case
+ diffName => "Making file executable (last diff)",
+ inputText => <<'END',
+diff --git a/foo.exe b/foo.exe
+old mode 100644
+new mode 100755
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo.exe
+old mode 100644
+new mode 100755
+END
+ executableBitDelta => 1,
+ indexPath => "foo.exe",
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test case
+ diffName => "Making file executable (not last diff)",
+ inputText => <<'END',
+diff --git a/foo.exe b/foo.exe
+old mode 100644
+new mode 100755
+diff --git a/another_file.txt b/another_file.txt
+index d03e242..435ad3a 100755
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo.exe
+old mode 100644
+new mode 100755
+END
+ executableBitDelta => 1,
+ indexPath => "foo.exe",
+},
+"diff --git a/another_file.txt b/another_file.txt\n"],
+ expectedNextLine => "index d03e242..435ad3a 100755\n",
+},
+{
+ # New test case
+ diffName => "New executable file",
+ inputText => <<'END',
+diff --git a/foo b/foo
+new file mode 100755
+index 0000000..d03e242
+--- /dev/null
++++ b/foo
+@@ -0,0 +1 @@
++file contents
+
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo
+new file mode 100755
+index 0000000..d03e242
+--- foo
++++ foo
+END
+ executableBitDelta => 1,
+ indexPath => "foo",
+ isNew => 1,
+},
+"@@ -0,0 +1 @@\n"],
+ expectedNextLine => "+file contents\n",
+},
+{
+ # New test case
+ diffName => "Deleted executable file",
+ inputText => <<'END',
+diff --git a/foo b/foo
+deleted file mode 100755
+index d03e242..0000000
+--- a/foo
++++ /dev/null
+@@ -1 +0,0 @@
+-file contents
+
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: foo
+deleted file mode 100755
+index d03e242..0000000
+--- foo
++++ foo
+END
+ executableBitDelta => -1,
+ indexPath => "foo",
+ isDeletion => 1,
+},
+"@@ -1 +0,0 @@\n"],
+ expectedNextLine => "-file contents\n",
+},
+);
+
+my $testCasesCount = @testCaseHashRefs;
+plan(tests => 2 * $testCasesCount); # Total number of assertions.
+
+foreach my $testCase (@testCaseHashRefs) {
+ my $testNameStart = "parseGitDiffHeader(): $testCase->{diffName}: comparing";
+
+ my $fileHandle;
+ open($fileHandle, "<", \$testCase->{inputText});
+ my $line = <$fileHandle>;
+
+ my @got = VCSUtils::parseGitDiffHeader($fileHandle, $line);
+ my $expectedReturn = $testCase->{expectedReturn};
+
+ is_deeply(\@got, $expectedReturn, "$testNameStart return value.");
+
+ my $gotNextLine = <$fileHandle>;
+ is($gotNextLine, $testCase->{expectedNextLine}, "$testNameStart next read line.");
+}
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/parsePatch.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/parsePatch.pl
new file mode 100644
index 0000000..8aae3d4
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/parsePatch.pl
@@ -0,0 +1,94 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@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.
+#
+# 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.
+
+# Unit tests of parseDiffHeader().
+
+use strict;
+use warnings;
+
+use Test::More;
+use VCSUtils;
+
+my @diffHashRefKeys = ( # The hash reference keys to check per diff.
+ "copiedFromPath",
+ "indexPath",
+ "sourceRevision",
+ "svnConvertedText",
+);
+
+# New test
+my $testNameStart = "parsePatch(): [SVN: Rename] ";
+my $patch = <<'END',
+Index: Makefile
+===================================================================
+--- Makefile (revision 53131)
++++ Makefile (working copy)
+@@ -1,1 +0,0 @@
+-MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools
+Index: Makefile_new
+===================================================================
+--- Makefile_new (revision 53131) (from Makefile:53131)
++++ Makefile_new (working copy)
+@@ -0,0 +1,1 @@
++MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools
+END
+
+my @expectedDiffHashRefs = (
+{
+ svnConvertedText => <<'END',
+Index: Makefile
+===================================================================
+--- Makefile (revision 53131)
++++ Makefile (working copy)
+@@ -1,1 +0,0 @@
+-MODULES = JavaScriptCore JavaScriptGlue WebCore WebKit WebKitTools
+END
+ copiedFromPath => undef,
+ indexPath => "Makefile",
+ sourceRevision => "53131",
+},
+{
+ copiedFromPath => "Makefile",
+ indexPath => "Makefile_new",
+ sourceRevision => "53131",
+},
+);
+
+plan(tests => @expectedDiffHashRefs * @diffHashRefKeys);
+
+my $fileHandle;
+open($fileHandle, "<", \$patch);
+
+my @gotDiffHashRefs = parsePatch($fileHandle);
+
+my $i = 0;
+foreach my $expectedDiffHashRef (@expectedDiffHashRefs) {
+
+ my $gotDiffHashRef = $gotDiffHashRefs[$i++];
+
+ foreach my $diffHashRefKey (@diffHashRefKeys) {
+ my $testName = "${testNameStart}[diff $i] key=\"$diffHashRefKey\"";
+ is($gotDiffHashRef->{$diffHashRefKey}, $expectedDiffHashRef->{$diffHashRefKey}, $testName);
+ }
+}
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl
new file mode 100644
index 0000000..4f05431
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffFooter.pl
@@ -0,0 +1,397 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) Research in Motion Limited 2010. All Rights Reserved.
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+#
+# 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 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 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.
+
+# Unit tests of parseSvnDiffProperties().
+
+use strict;
+use warnings;
+
+use Test::More;
+use VCSUtils;
+
+my @testCaseHashRefs = (
+####
+# Simple test cases
+##
+{
+ # New test
+ diffName => "simple: add svn:executable",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Added: svn:executable
+ + *
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+ executableBitDelta => 1,
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "simple: add svn:mergeinfo",
+ inputText => <<'END',
+Property changes on: Makefile
+___________________________________________________________________
+Added: svn:mergeinfo
+ Merged /trunk/Makefile:r33020
+END
+ expectedReturn => [
+{
+ propertyPath => "Makefile",
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "simple: delete svn:mergeinfo",
+ inputText => <<'END',
+Property changes on: Makefile
+___________________________________________________________________
+Deleted: svn:mergeinfo
+ Reverse-merged /trunk/Makefile:r33020
+END
+ expectedReturn => [
+{
+ propertyPath => "Makefile",
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "simple: modified svn:mergeinfo",
+ inputText => <<'END',
+Property changes on: Makefile
+___________________________________________________________________
+Modified: svn:mergeinfo
+ Reverse-merged /trunk/Makefile:r33020
+ Merged /trunk/Makefile:r41697
+END
+ expectedReturn => [
+{
+ propertyPath => "Makefile",
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "simple: delete svn:executable",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Deleted: svn:executable
+ - *
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+ executableBitDelta => -1,
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "simple: delete svn:executable using SVN 1.4 syntax",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Name: svn:executable
+ - *
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+ executableBitDelta => -1,
+},
+undef],
+ expectedNextLine => undef,
+},
+####
+# Property value followed by empty line and start of next diff
+##
+{
+ # New test
+ diffName => "add svn:executable, followed by empty line and start of next diff",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Index: Makefile.shared
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+ executableBitDelta => 1,
+},
+"\n"],
+ expectedNextLine => "Index: Makefile.shared\n",
+},
+{
+ # New test
+ diffName => "add svn:executable, followed by empty line and start of next property diff",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Property changes on: Makefile.shared
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+ executableBitDelta => 1,
+},
+"\n"],
+ expectedNextLine => "Property changes on: Makefile.shared\n",
+},
+####
+# Property value followed by empty line and start of the binary contents
+##
+{
+ # New test
+ diffName => "add svn:executable, followed by empty line and start of binary contents",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Added: svn:executable
+ + *
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+ executableBitDelta => 1,
+},
+"\n"],
+ expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\n",
+},
+{
+ # New test
+ diffName => "custom property followed by svn:executable, empty line and start of binary contents",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Added: documentation
+ + This is an example sentence.
+Added: svn:executable
+ + *
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+ executableBitDelta => 1,
+},
+"\n"],
+ expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\n",
+},
+####
+# Successive properties
+##
+{
+ # New test
+ diffName => "svn:executable followed by custom property",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Added: svn:executable
+ + *
+Added: documentation
+ + This is an example sentence.
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+ executableBitDelta => 1,
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "custom property followed by svn:executable",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Added: documentation
+ + This is an example sentence.
+Added: svn:executable
+ + *
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+ executableBitDelta => 1,
+},
+undef],
+ expectedNextLine => undef,
+},
+####
+# Successive properties followed by empty line and start of next diff
+##
+{
+ # New test
+ diffName => "custom property followed by svn:executable, empty line and start of next property diff",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Added: documentation
+ + This is an example sentence.
+Added: svn:executable
+ + *
+
+Property changes on: Makefile.shared
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+ executableBitDelta => 1,
+},
+"\n"],
+ expectedNextLine => "Property changes on: Makefile.shared\n",
+},
+{
+ # New test
+ diffName => "custom property followed by svn:executable, empty line and start of next index diff",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Added: documentation
+ + This is an example sentence.
+Added: svn:executable
+ + *
+
+Index: Makefile.shared
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+ executableBitDelta => 1,
+},
+"\n"],
+ expectedNextLine => "Index: Makefile.shared\n",
+},
+####
+# Custom properties
+##
+# FIXME: We do not support anything other than the svn:executable property.
+# We should add support for handling other properties.
+{
+ # New test
+ diffName => "simple: custom property",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Name: documentation
+ + This is an example sentence.
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "custom property followed by custom property",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Added: copyright
+ + Copyright (C) Research in Motion Limited 2010. All Rights Reserved.
+Added: documentation
+ + This is an example sentence.
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+},
+undef],
+ expectedNextLine => undef,
+},
+####
+# Malformed property diffs
+##
+# We shouldn't encounter such diffs in practice.
+{
+ # New test
+ diffName => "svn:executable followed by custom property and svn:executable",
+ inputText => <<'END',
+Property changes on: FileA
+___________________________________________________________________
+Added: svn:executable
+ + *
+Added: documentation
+ + This is an example sentence.
+Deleted: svn:executable
+ - *
+END
+ expectedReturn => [
+{
+ propertyPath => "FileA",
+ executableBitDelta => -1,
+},
+undef],
+ expectedNextLine => undef,
+},
+);
+
+my $testCasesCount = @testCaseHashRefs;
+plan(tests => 2 * $testCasesCount); # Total number of assertions.
+
+foreach my $testCase (@testCaseHashRefs) {
+ my $testNameStart = "parseSvnDiffProperties(): $testCase->{diffName}: comparing";
+
+ my $fileHandle;
+ open($fileHandle, "<", \$testCase->{inputText});
+ my $line = <$fileHandle>;
+
+ my @got = VCSUtils::parseSvnDiffProperties($fileHandle, $line);
+ my $expectedReturn = $testCase->{expectedReturn};
+
+ is_deeply(\@got, $expectedReturn, "$testNameStart return value.");
+
+ my $gotNextLine = <$fileHandle>;
+ is($gotNextLine, $testCase->{expectedNextLine}, "$testNameStart next read line.");
+}
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffHeader.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffHeader.pl
new file mode 100644
index 0000000..ed8550d
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnDiffHeader.pl
@@ -0,0 +1,220 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+#
+# 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 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 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.
+
+# Unit tests of parseSvnDiffHeader().
+
+use strict;
+use warnings;
+
+use Test::More;
+use VCSUtils;
+
+# The array of test cases.
+my @testCaseHashRefs = (
+{
+ # New test
+ diffName => "simple diff",
+ inputText => <<'END',
+Index: WebKitTools/Scripts/VCSUtils.pm
+===================================================================
+--- WebKitTools/Scripts/VCSUtils.pm (revision 53004)
++++ WebKitTools/Scripts/VCSUtils.pm (working copy)
+@@ -32,6 +32,7 @@ use strict;
+ use warnings;
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: WebKitTools/Scripts/VCSUtils.pm
+===================================================================
+--- WebKitTools/Scripts/VCSUtils.pm (revision 53004)
++++ WebKitTools/Scripts/VCSUtils.pm (working copy)
+END
+ indexPath => "WebKitTools/Scripts/VCSUtils.pm",
+ sourceRevision => "53004",
+},
+"@@ -32,6 +32,7 @@ use strict;\n"],
+ expectedNextLine => " use warnings;\n",
+},
+{
+ # New test
+ diffName => "new file",
+ inputText => <<'END',
+Index: WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl
+===================================================================
+--- WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl (revision 0)
++++ WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl (revision 0)
+@@ -0,0 +1,262 @@
++#!/usr/bin/perl -w
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl
+===================================================================
+--- WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl (revision 0)
++++ WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl (revision 0)
+END
+ indexPath => "WebKitTools/Scripts/webkitperl/VCSUtils_unittest/parseDiffHeader.pl",
+ isNew => 1,
+},
+"@@ -0,0 +1,262 @@\n"],
+ expectedNextLine => "+#!/usr/bin/perl -w\n",
+},
+{
+ # New test
+ diffName => "copied file",
+ inputText => <<'END',
+Index: index_path.py
+===================================================================
+--- index_path.py (revision 53048) (from copied_from_path.py:53048)
++++ index_path.py (working copy)
+@@ -0,0 +1,7 @@
++# Python file...
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: index_path.py
+===================================================================
+--- index_path.py (revision 53048) (from copied_from_path.py:53048)
++++ index_path.py (working copy)
+END
+ copiedFromPath => "copied_from_path.py",
+ indexPath => "index_path.py",
+ sourceRevision => 53048,
+},
+"@@ -0,0 +1,7 @@\n"],
+ expectedNextLine => "+# Python file...\n",
+},
+{
+ # New test
+ diffName => "contains \\r\\n lines",
+ inputText => <<END, # No single quotes to allow interpolation of "\r"
+Index: index_path.py\r
+===================================================================\r
+--- index_path.py (revision 53048)\r
++++ index_path.py (working copy)\r
+@@ -0,0 +1,7 @@\r
++# Python file...\r
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<END, # No single quotes to allow interpolation of "\r"
+Index: index_path.py\r
+===================================================================\r
+--- index_path.py (revision 53048)\r
++++ index_path.py (working copy)\r
+END
+ indexPath => "index_path.py",
+ sourceRevision => 53048,
+},
+"@@ -0,0 +1,7 @@\r\n"],
+ expectedNextLine => "+# Python file...\r\n",
+},
+{
+ # New test
+ diffName => "contains path corrections",
+ inputText => <<'END',
+Index: index_path.py
+===================================================================
+--- bad_path (revision 53048) (from copied_from_path.py:53048)
++++ bad_path (working copy)
+@@ -0,0 +1,7 @@
++# Python file...
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: index_path.py
+===================================================================
+--- index_path.py (revision 53048) (from copied_from_path.py:53048)
++++ index_path.py (working copy)
+END
+ copiedFromPath => "copied_from_path.py",
+ indexPath => "index_path.py",
+ sourceRevision => 53048,
+},
+"@@ -0,0 +1,7 @@\n"],
+ expectedNextLine => "+# Python file...\n",
+},
+####
+# Binary test cases
+##
+{
+ # New test
+ diffName => "binary file",
+ inputText => <<'END',
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+Property changes on: test_file.swf
+___________________________________________________________________
+Name: svn:mime-type
+ + application/octet-stream
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+ expectedReturn => [
+{
+ svnConvertedText => <<'END',
+Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+END
+ indexPath => "test_file.swf",
+ isBinary => 1,
+},
+"svn:mime-type = application/octet-stream\n"],
+ expectedNextLine => "\n",
+},
+);
+
+my $testCasesCount = @testCaseHashRefs;
+plan(tests => 2 * $testCasesCount); # Total number of assertions.
+
+foreach my $testCase (@testCaseHashRefs) {
+ my $testNameStart = "parseSvnDiffHeader(): $testCase->{diffName}: comparing";
+
+ my $fileHandle;
+ open($fileHandle, "<", \$testCase->{inputText});
+ my $line = <$fileHandle>;
+
+ my @got = VCSUtils::parseSvnDiffHeader($fileHandle, $line);
+ my $expectedReturn = $testCase->{expectedReturn};
+
+ is_deeply(\@got, $expectedReturn, "$testNameStart return value.");
+
+ my $gotNextLine = <$fileHandle>;
+ is($gotNextLine, $testCase->{expectedNextLine}, "$testNameStart next read line.");
+}
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnProperty.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnProperty.pl
new file mode 100644
index 0000000..6914051
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnProperty.pl
@@ -0,0 +1,743 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) Research in Motion Limited 2010. All Rights Reserved.
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+#
+# 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 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 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.
+
+# Unit tests of parseSvnProperty().
+
+use strict;
+use warnings;
+
+use Test::More;
+use VCSUtils;
+
+my @testCaseHashRefs = (
+####
+# Simple test cases
+##
+{
+ # New test
+ diffName => "simple: add svn:executable",
+ inputText => <<'END',
+Added: svn:executable
+ + *
+END
+ expectedReturn => [
+{
+ name => "svn:executable",
+ propertyChangeDelta => 1,
+ value => "*",
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "simple: delete svn:executable",
+ inputText => <<'END',
+Deleted: svn:executable
+ - *
+END
+ expectedReturn => [
+{
+ name => "svn:executable",
+ propertyChangeDelta => -1,
+ value => "*",
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "simple: add svn:mergeinfo",
+ inputText => <<'END',
+Added: svn:mergeinfo
+ Merged /trunk/Makefile:r33020
+END
+ expectedReturn => [
+{
+ name => "svn:mergeinfo",
+ propertyChangeDelta => 1,
+ value => "/trunk/Makefile:r33020",
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "simple: delete svn:mergeinfo",
+ inputText => <<'END',
+Deleted: svn:mergeinfo
+ Reverse-merged /trunk/Makefile:r33020
+END
+ expectedReturn => [
+{
+ name => "svn:mergeinfo",
+ propertyChangeDelta => -1,
+ value => "/trunk/Makefile:r33020",
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "simple: modified svn:mergeinfo",
+ inputText => <<'END',
+Modified: svn:mergeinfo
+ Reverse-merged /trunk/Makefile:r33020
+ Merged /trunk/Makefile:r41697
+END
+ expectedReturn => [
+{
+ name => "svn:mergeinfo",
+ propertyChangeDelta => 1,
+ value => "/trunk/Makefile:r41697",
+},
+undef],
+ expectedNextLine => undef,
+},
+####
+# Using SVN 1.4 syntax
+##
+{
+ # New test
+ diffName => "simple: modified svn:mergeinfo using SVN 1.4 syntax",
+ inputText => <<'END',
+Name: svn:mergeinfo
+ Reverse-merged /trunk/Makefile:r33020
+ Merged /trunk/Makefile:r41697
+END
+ expectedReturn => [
+{
+ name => "svn:mergeinfo",
+ propertyChangeDelta => 1,
+ value => "/trunk/Makefile:r41697",
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "simple: delete svn:executable using SVN 1.4 syntax",
+ inputText => <<'END',
+Name: svn:executable
+ - *
+END
+ expectedReturn => [
+{
+ name => "svn:executable",
+ propertyChangeDelta => -1,
+ value => "*",
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "simple: add svn:executable using SVN 1.4 syntax",
+ inputText => <<'END',
+Name: svn:executable
+ + *
+END
+ expectedReturn => [
+{
+ name => "svn:executable",
+ propertyChangeDelta => 1,
+ value => "*",
+},
+undef],
+ expectedNextLine => undef,
+},
+####
+# Property value followed by empty line and start of next diff
+##
+{
+ # New test
+ diffName => "add svn:executable, followed by empty line and start of next diff",
+ inputText => <<'END',
+Added: svn:executable
+ + *
+
+Index: Makefile.shared
+END
+ expectedReturn => [
+{
+ name => "svn:executable",
+ propertyChangeDelta => 1,
+ value => "*",
+},
+"\n"],
+ expectedNextLine => "Index: Makefile.shared\n",
+},
+{
+ # New test
+ diffName => "add svn:executable, followed by empty line and start of next diff using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Added: svn:executable
+ + *
+
+Index: Makefile.shared
+END
+),
+ expectedReturn => [
+{
+ name => "svn:executable",
+ propertyChangeDelta => 1,
+ value => "*",
+},
+"\r\n"],
+ expectedNextLine => "Index: Makefile.shared\r\n",
+},
+{
+ # New test
+ diffName => "add svn:executable, followed by empty line and start of next property diff",
+ inputText => <<'END',
+Added: svn:executable
+ + *
+
+Property changes on: Makefile.shared
+END
+ expectedReturn => [
+{
+ name => "svn:executable",
+ propertyChangeDelta => 1,
+ value => "*",
+},
+"\n"],
+ expectedNextLine => "Property changes on: Makefile.shared\n",
+},
+{
+ # New test
+ diffName => "add svn:executable, followed by empty line and start of next property diff using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Added: svn:executable
+ + *
+
+Property changes on: Makefile.shared
+END
+),
+ expectedReturn => [
+{
+ name => "svn:executable",
+ propertyChangeDelta => 1,
+ value => "*",
+},
+"\r\n"],
+ expectedNextLine => "Property changes on: Makefile.shared\r\n",
+},
+{
+ # New test
+ diffName => "multi-line '+' change, followed by empty line and start of next diff",
+ inputText => <<'END',
+Name: documentation
+ + A
+long sentence that spans
+multiple lines.
+
+Index: Makefile.shared
+END
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "A\nlong sentence that spans\nmultiple lines.",
+},
+"\n"],
+ expectedNextLine => "Index: Makefile.shared\n",
+},
+{
+ # New test
+ diffName => "multi-line '+' change, followed by empty line and start of next diff using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Name: documentation
+ + A
+long sentence that spans
+multiple lines.
+
+Index: Makefile.shared
+END
+),
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "A\r\nlong sentence that spans\r\nmultiple lines.",
+},
+"\r\n"],
+ expectedNextLine => "Index: Makefile.shared\r\n",
+},
+{
+ # New test
+ diffName => "multi-line '+' change, followed by empty line and start of next property diff",
+ inputText => <<'END',
+Name: documentation
+ + A
+long sentence that spans
+multiple lines.
+
+Property changes on: Makefile.shared
+END
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "A\nlong sentence that spans\nmultiple lines.",
+},
+"\n"],
+ expectedNextLine => "Property changes on: Makefile.shared\n",
+},
+{
+ # New test
+ diffName => "multi-line '+' change, followed by empty line and start of next property diff using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Name: documentation
+ + A
+long sentence that spans
+multiple lines.
+
+Property changes on: Makefile.shared
+END
+),
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "A\r\nlong sentence that spans\r\nmultiple lines.",
+},
+"\r\n"],
+ expectedNextLine => "Property changes on: Makefile.shared\r\n",
+},
+####
+# Property value followed by empty line and start of binary patch
+##
+{
+ # New test
+ diffName => "add svn:executable, followed by empty line and start of binary patch",
+ inputText => <<'END',
+Added: svn:executable
+ + *
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+ expectedReturn => [
+{
+ name => "svn:executable",
+ propertyChangeDelta => 1,
+ value => "*",
+},
+"\n"],
+ expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\n",
+},
+{
+ # New test
+ diffName => "add svn:executable, followed by empty line and start of binary patch using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Added: svn:executable
+ + *
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+),
+ expectedReturn => [
+{
+ name => "svn:executable",
+ propertyChangeDelta => 1,
+ value => "*",
+},
+"\r\n"],
+ expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\r\n",
+},
+{
+ # New test
+ diffName => "multi-line '+' change, followed by empty line and start of binary patch",
+ inputText => <<'END',
+Name: documentation
+ + A
+long sentence that spans
+multiple lines.
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "A\nlong sentence that spans\nmultiple lines.",
+},
+"\n"],
+ expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\n",
+},
+{
+ # New test
+ diffName => "multi-line '+' change, followed by empty line and start of binary patch using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Name: documentation
+ + A
+long sentence that spans
+multiple lines.
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+),
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "A\r\nlong sentence that spans\r\nmultiple lines.",
+},
+"\r\n"],
+ expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\r\n",
+},
+{
+ # New test
+ diffName => "multi-line '-' change, followed by multi-line '+' change, empty line, and start of binary patch",
+ inputText => <<'END',
+Modified: documentation
+ - A
+long sentence that spans
+multiple lines.
+ + Another
+long sentence that spans
+multiple lines.
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "Another\nlong sentence that spans\nmultiple lines.",
+},
+"\n"],
+ expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\n",
+},
+{
+ # New test
+ diffName => "multi-line '-' change, followed by multi-line '+' change, empty line, and start of binary patch using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Modified: documentation
+ - A
+long sentence that spans
+multiple lines.
+ + Another
+long sentence that spans
+multiple lines.
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+),
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "Another\r\nlong sentence that spans\r\nmultiple lines.",
+},
+"\r\n"],
+ expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\r\n",
+},
+####
+# Successive properties
+##
+{
+ # New test
+ diffName => "single-line '+' change followed by custom property with single-line '+' change",
+ inputText => <<'END',
+Added: svn:executable
+ + *
+Added: documentation
+ + A sentence.
+END
+ expectedReturn => [
+{
+ name => "svn:executable",
+ propertyChangeDelta => 1,
+ value => "*",
+},
+"Added: documentation\n"],
+ expectedNextLine => " + A sentence.\n",
+},
+{
+ # New test
+ diffName => "multi-line '+' change, followed by svn:executable",
+ inputText => <<'END',
+Name: documentation
+ + A
+long sentence that spans
+multiple lines.
+Name: svn:executable
+ + *
+END
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "A\nlong sentence that spans\nmultiple lines.",
+},
+"Name: svn:executable\n"],
+ expectedNextLine => " + *\n",
+},
+{
+ # New test
+ diffName => "multi-line '-' change, followed by multi-line '+' change and add svn:executable",
+ inputText => <<'END',
+Modified: documentation
+ - A
+long sentence that spans
+multiple lines.
+ + Another
+long sentence that spans
+multiple lines.
+Added: svn:executable
+ + *
+END
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "Another\nlong sentence that spans\nmultiple lines.",
+},
+"Added: svn:executable\n"],
+ expectedNextLine => " + *\n",
+},
+{
+ # New test
+ diffName => "'Merged' change followed by 'Merged' change",
+ inputText => <<'END',
+Added: svn:mergeinfo
+ Merged /trunk/Makefile:r33020
+ Merged /trunk/Makefile.shared:r58350
+END
+ expectedReturn => [
+{
+ name => "svn:mergeinfo",
+ propertyChangeDelta => 1,
+ value => "/trunk/Makefile.shared:r58350",
+},
+undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "'Reverse-merged' change followed by 'Reverse-merged' change",
+ inputText => <<'END',
+Deleted: svn:mergeinfo
+ Reverse-merged /trunk/Makefile:r33020
+ Reverse-merged /trunk/Makefile.shared:r58350
+END
+ expectedReturn => [
+{
+ name => "svn:mergeinfo",
+ propertyChangeDelta => -1,
+ value => "/trunk/Makefile.shared:r58350",
+},
+undef],
+ expectedNextLine => undef,
+},
+####
+# Property values with trailing new lines.
+##
+# FIXME: We do not support property values with trailing new lines, since it is difficult to
+# disambiguate them from the empty line that preceeds the contents of a binary patch as
+# in the test case (above): "multi-line '+' change, followed by empty line and start of binary patch".
+{
+ # New test
+ diffName => "single-line '+' with trailing new line",
+ inputText => <<'END',
+Added: documentation
+ + A sentence.
+
+END
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "A sentence.",
+},
+"\n"],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "single-line '+' with trailing new line using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Added: documentation
+ + A sentence.
+
+END
+),
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "A sentence.",
+},
+"\r\n"],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "single-line '+' with trailing new line, followed by empty line and start of binary patch",
+ inputText => <<'END',
+Added: documentation
+ + A sentence.
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "A sentence.",
+},
+"\n"],
+ expectedNextLine => "\n",
+},
+{
+ # New test
+ diffName => "single-line '+' with trailing new line, followed by empty line and start of binary patch using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Added: documentation
+ + A sentence.
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+),
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => 1,
+ value => "A sentence.",
+},
+"\r\n"],
+ expectedNextLine => "\r\n",
+},
+{
+ # New test
+ diffName => "single-line '-' change with trailing new line, and single-line '+' change",
+ inputText => <<'END',
+Modified: documentation
+ - A long sentence.
+
+ + A sentence.
+END
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => -1, # Since we only interpret the '-' property.
+ value => "A long sentence.",
+},
+"\n"],
+ expectedNextLine => " + A sentence.\n",
+},
+{
+ # New test
+ diffName => "single-line '-' change with trailing new line, and single-line '+' change using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Modified: documentation
+ - A long sentence.
+
+ + A sentence.
+END
+),
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => -1, # Since we only interpret the '-' property.
+ value => "A long sentence.",
+},
+"\r\n"],
+ expectedNextLine => " + A sentence.\r\n",
+},
+{
+ # New test
+ diffName => "multi-line '-' change with trailing new line, and multi-line '+' change",
+ inputText => <<'END',
+Modified: documentation
+ - A
+long sentence that spans
+multiple lines.
+
+ + Another
+long sentence that spans
+multiple lines.
+END
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => -1, # Since we only interpret the '-' property.
+ value => "A\nlong sentence that spans\nmultiple lines.",
+},
+"\n"],
+ expectedNextLine => " + Another\n",
+},
+{
+ # New test
+ diffName => "multi-line '-' change with trailing new line, and multi-line '+' change using Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+Modified: documentation
+ - A
+long sentence that spans
+multiple lines.
+
+ + Another
+long sentence that spans
+multiple lines.
+END
+),
+ expectedReturn => [
+{
+ name => "documentation",
+ propertyChangeDelta => -1, # Since we only interpret the '-' property.
+ value => "A\r\nlong sentence that spans\r\nmultiple lines.",
+},
+"\r\n"],
+ expectedNextLine => " + Another\r\n",
+},
+);
+
+my $testCasesCount = @testCaseHashRefs;
+plan(tests => 2 * $testCasesCount); # Total number of assertions.
+
+foreach my $testCase (@testCaseHashRefs) {
+ my $testNameStart = "parseSvnProperty(): $testCase->{diffName}: comparing";
+
+ my $fileHandle;
+ open($fileHandle, "<", \$testCase->{inputText});
+ my $line = <$fileHandle>;
+
+ my @got = VCSUtils::parseSvnProperty($fileHandle, $line);
+ my $expectedReturn = $testCase->{expectedReturn};
+
+ is_deeply(\@got, $expectedReturn, "$testNameStart return value.");
+
+ my $gotNextLine = <$fileHandle>;
+ is($gotNextLine, $testCase->{expectedNextLine}, "$testNameStart next read line.");
+}
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl
new file mode 100644
index 0000000..2de8ae3
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/parseSvnPropertyValue.pl
@@ -0,0 +1,233 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) Research in Motion Limited 2010. All Rights Reserved.
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+#
+# 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 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 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.
+
+# Unit tests of parseSvnPropertyValue().
+
+use strict;
+use warnings;
+
+use Test::More;
+use VCSUtils;
+
+my @testCaseHashRefs = (
+{
+ # New test
+ diffName => "singe-line '+' change",
+ inputText => <<'END',
+ + *
+END
+ expectedReturn => ["*", undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "single-line '-' change",
+ inputText => <<'END',
+ - *
+END
+ expectedReturn => ["*", undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "'Merged' change",
+ inputText => <<'END',
+ Merged /trunk/Makefile:r33020
+END
+ expectedReturn => ["/trunk/Makefile:r33020", undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "'Reverse-merged' change",
+ inputText => <<'END',
+ Reverse-merged /trunk/Makefile:r33020
+END
+ expectedReturn => ["/trunk/Makefile:r33020", undef],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "single-line '-' change followed by empty line with Unix line endings",
+ inputText => <<'END',
+ - *
+
+END
+ expectedReturn => ["*", "\n"],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "single-line '-' change followed by empty line with Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+ - *
+
+END
+),
+ expectedReturn => ["*", "\r\n"],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "single-line '-' change followed by the next property",
+ inputText => <<'END',
+ - *
+Deleted: svn:executable
+END
+ expectedReturn => ["*", "Deleted: svn:executable\n"],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "multi-line '+' change and start of binary patch",
+ inputText => <<'END',
+ + A
+long sentence that spans
+multiple lines.
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+ expectedReturn => ["A\nlong sentence that spans\nmultiple lines.", "\n"],
+ expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\n",
+},
+{
+ # New test
+ diffName => "multi-line '+' change and start of binary patch with Windows line endings",
+ inputText => toWindowsLineEndings(<<'END',
+ + A
+long sentence that spans
+multiple lines.
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+END
+),
+ expectedReturn => ["A\r\nlong sentence that spans\r\nmultiple lines.", "\r\n"],
+ expectedNextLine => "Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==\r\n",
+},
+{
+ # New test
+ diffName => "multi-line '-' change followed by '+' single-line change",
+ inputText => <<'END',
+ - A
+long sentence that spans
+multiple lines.
+ + A single-line.
+END
+ expectedReturn => ["A\nlong sentence that spans\nmultiple lines.", " + A single-line.\n"],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "multi-line '-' change followed by the next property",
+ inputText => <<'END',
+ - A
+long sentence that spans
+multiple lines.
+Added: svn:executable
+END
+ expectedReturn => ["A\nlong sentence that spans\nmultiple lines.", "Added: svn:executable\n"],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "multi-line '-' change followed by '+' multi-line change",
+ inputText => <<'END',
+ - A
+long sentence that spans
+multiple lines.
+ + Another
+long sentence that spans
+multiple lines.
+END
+ expectedReturn => ["A\nlong sentence that spans\nmultiple lines.", " + Another\n"],
+ expectedNextLine => "long sentence that spans\n",
+},
+{
+ # New test
+ diffName => "'Reverse-merged' change followed by 'Merge' change",
+ inputText => <<'END',
+ Reverse-merged /trunk/Makefile:r33020
+ Merged /trunk/Makefile:r41697
+END
+ expectedReturn => ["/trunk/Makefile:r33020", " Merged /trunk/Makefile:r41697\n"],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "'Merged' change followed by 'Merge' change",
+ inputText => <<'END',
+ Merged /trunk/Makefile:r33020
+ Merged /trunk/Makefile.shared:r58350
+END
+ expectedReturn => ["/trunk/Makefile:r33020", " Merged /trunk/Makefile.shared:r58350\n"],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "'Reverse-merged' change followed by 'Reverse-merged' change",
+ inputText => <<'END',
+ Reverse-merged /trunk/Makefile:r33020
+ Reverse-merged /trunk/Makefile.shared:r58350
+END
+ expectedReturn => ["/trunk/Makefile:r33020", " Reverse-merged /trunk/Makefile.shared:r58350\n"],
+ expectedNextLine => undef,
+},
+{
+ # New test
+ diffName => "'Reverse-merged' change followed by 'Reverse-merged' change followed by 'Merged' change",
+ inputText => <<'END',
+ Reverse-merged /trunk/Makefile:r33020
+ Reverse-merged /trunk/Makefile.shared:r58350
+ Merged /trunk/ChangeLog:r64190
+END
+ expectedReturn => ["/trunk/Makefile:r33020", " Reverse-merged /trunk/Makefile.shared:r58350\n"],
+ expectedNextLine => " Merged /trunk/ChangeLog:r64190\n",
+},
+);
+
+my $testCasesCount = @testCaseHashRefs;
+plan(tests => 2 * $testCasesCount); # Total number of assertions.
+
+foreach my $testCase (@testCaseHashRefs) {
+ my $testNameStart = "parseSvnPropertyValue(): $testCase->{diffName}: comparing";
+
+ my $fileHandle;
+ open($fileHandle, "<", \$testCase->{inputText});
+ my $line = <$fileHandle>;
+
+ my @got = VCSUtils::parseSvnPropertyValue($fileHandle, $line);
+ my $expectedReturn = $testCase->{expectedReturn};
+
+ is_deeply(\@got, $expectedReturn, "$testNameStart return value.");
+
+ my $gotNextLine = <$fileHandle>;
+ is($gotNextLine, $testCase->{expectedNextLine}, "$testNameStart next read line.");
+}
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/prepareParsedPatch.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/prepareParsedPatch.pl
new file mode 100644
index 0000000..a7ae807
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/prepareParsedPatch.pl
@@ -0,0 +1,136 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+# Unit tests of prepareParsedPatch().
+
+use strict;
+use warnings;
+
+use Test::More;
+use VCSUtils;
+
+my $diffHashRef1 = { # not a copy, no source revision
+ copiedFromPath => undef,
+ indexPath => "indexPath1",
+ sourceRevision => undef,
+ svnConvertedText => "diff1",
+};
+my $diffHashRef2 = { # not a copy, has source revision
+ copiedFromPath => undef,
+ indexPath => "indexPath2",
+ sourceRevision => 20,
+ svnConvertedText => "diff2",
+};
+my $diffHashRef3 = { # a copy (copies always have source revision)
+ copiedFromPath => "sourcePath3",
+ indexPath => "indexPath2", # Deliberately choosing same as $diffHashRef2
+ sourceRevision => 3,
+ svnConvertedText => "diff3",
+};
+
+my @testCases = (
+{
+ # New test
+ testName => "zero diffs: empty array",
+ diffHashRefsInput => [],
+ expected => {
+ copyDiffHashRefs => [],
+ nonCopyDiffHashRefs => [],
+ sourceRevisionHash => {},
+ },
+},
+{
+ # New test
+ testName => "one diff: non-copy, no revision",
+ diffHashRefsInput => [$diffHashRef1],
+ expected => {
+ copyDiffHashRefs => [],
+ nonCopyDiffHashRefs => [$diffHashRef1],
+ sourceRevisionHash => {},
+ },
+},
+{
+ # New test
+ testName => "one diff: non-copy, has revision",
+ diffHashRefsInput => [$diffHashRef2],
+ expected => {
+ copyDiffHashRefs => [],
+ nonCopyDiffHashRefs => [$diffHashRef2],
+ sourceRevisionHash => {
+ "indexPath2" => 20,
+ }
+ },
+},
+{
+ # New test
+ testName => "one diff: copy (has revision)",
+ diffHashRefsInput => [$diffHashRef3],
+ expected => {
+ copyDiffHashRefs => [$diffHashRef3],
+ nonCopyDiffHashRefs => [],
+ sourceRevisionHash => {
+ "sourcePath3" => 3,
+ }
+ },
+},
+{
+ # New test
+ testName => "two diffs: two non-copies",
+ diffHashRefsInput => [$diffHashRef1, $diffHashRef2],
+ expected => {
+ copyDiffHashRefs => [],
+ nonCopyDiffHashRefs => [$diffHashRef1, $diffHashRef2],
+ sourceRevisionHash => {
+ "indexPath2" => 20,
+ }
+ },
+},
+{
+ # New test
+ testName => "two diffs: non-copy and copy",
+ diffHashRefsInput => [$diffHashRef2, $diffHashRef3],
+ expected => {
+ copyDiffHashRefs => [$diffHashRef3],
+ nonCopyDiffHashRefs => [$diffHashRef2],
+ sourceRevisionHash => {
+ "sourcePath3" => 3,
+ "indexPath2" => 20,
+ }
+ },
+},
+);
+
+my $testCasesCount = @testCases;
+plan(tests => $testCasesCount);
+
+foreach my $testCase (@testCases) {
+ my $testName = $testCase->{testName};
+ my @diffHashRefs = @{$testCase->{diffHashRefsInput}};
+ my $expected = $testCase->{expected};
+
+ my $got = prepareParsedPatch(0, @diffHashRefs);
+
+ is_deeply($got, $expected, $testName);
+}
+
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/removeEOL.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/removeEOL.pl
new file mode 100644
index 0000000..8bd8e90
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/removeEOL.pl
@@ -0,0 +1,56 @@
+#!/usr/bin/perl
+#
+# Copyright (C) Research In Motion Limited 2010. 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 Research In Motion Limited 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.
+
+# Unit tests of VCSUtils::removeEOL().
+
+use Test::Simple tests => 5;
+use VCSUtils;
+
+my $title;
+
+# New test
+$title = "removeEOL: Undefined argument.";
+ok(removeEOL(undef) eq "");
+
+# New test
+$title = "removeEOL: Line with Windows line ending.";
+ok(removeEOL("This line ends with a Windows line ending.\r\n") eq "This line ends with a Windows line ending.");
+
+# New test
+$title = "removeEOL: Line with Unix line ending.";
+ok(removeEOL("This line ends with a Unix line ending.\n") eq "This line ends with a Unix line ending.");
+
+# New test
+$title = "removeEOL: Line with Mac line ending.";
+ok(removeEOL("This line ends with a Mac line ending.\r") eq "This line ends with a Mac line ending.");
+
+# New test
+$title = "removeEOL: Line with a mix of line endings.";
+ok(removeEOL("This line contains a mix of line endings.\r\n\r\n\r\r\n\n\n\n") eq "This line contains a mix of line endings.");
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/runPatchCommand.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/runPatchCommand.pl
new file mode 100644
index 0000000..5acc517
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/runPatchCommand.pl
@@ -0,0 +1,92 @@
+#!/usr/bin/perl
+#
+# Copyright (C) 2009, 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+#
+# 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.
+
+# Unit tests of VCSUtils::runPatchCommand().
+
+use Test::Simple tests => 4;
+use VCSUtils;
+
+# New test
+$title = "runPatchCommand: Unsuccessful patch, forcing.";
+
+# Since $patch has no "Index:" path, passing this to runPatchCommand
+# should not affect any files.
+my $patch = <<'END';
+Garbage patch contents
+END
+
+# We call via callSilently() to avoid output like the following to STDERR:
+# patch: **** Only garbage was found in the patch input.
+$argsHashRef = {ensureForce => 1};
+$exitStatus = callSilently(\&runPatchCommand, $patch, ".", "file_to_patch.txt", $argsHashRef);
+
+ok($exitStatus != 0, $title);
+
+# New test
+$title = "runPatchCommand: New file, --dry-run.";
+
+# This file should not exist after the tests, but we take care with the
+# file name and contents just in case.
+my $fileToPatch = "temp_OK_TO_ERASE__README_FOR_MORE.txt";
+$patch = <<END;
+Index: $fileToPatch
+===================================================================
+--- $fileToPatch (revision 0)
++++ $fileToPatch (revision 0)
+@@ -0,0 +1,5 @@
++This is a test file for WebKitTools/Scripts/VCSUtils_unittest.pl.
++This file should not have gotten created on your system.
++If it did, some unit tests don't seem to be working quite right:
++It would be great if you could file a bug report. Thanks!
++---------------------------------------------------------------------
+END
+
+# --dry-run prevents creating any files.
+# --silent suppresses the success message to STDOUT.
+$argsHashRef = {options => ["--dry-run", "--silent"]};
+$exitStatus = runPatchCommand($patch, ".", $fileToPatch, $argsHashRef);
+
+ok($exitStatus == 0, $title);
+
+# New test
+$title = "runPatchCommand: New file: \"$fileToPatch\".";
+
+$argsHashRef = {options => ["--silent"]};
+$exitStatus = runPatchCommand($patch, ".", $fileToPatch, $argsHashRef);
+
+ok($exitStatus == 0, $title);
+
+# New test
+$title = "runPatchCommand: Reverse new file (clean up previous).";
+
+$argsHashRef = {shouldReverse => 1,
+ options => ["--silent", "--remove-empty-files"]}; # To clean up.
+$exitStatus = runPatchCommand($patch, ".", $fileToPatch, $argsHashRef);
+ok($exitStatus == 0, $title);
diff --git a/Tools/Scripts/webkitperl/VCSUtils_unittest/setChangeLogDateAndReviewer.pl b/Tools/Scripts/webkitperl/VCSUtils_unittest/setChangeLogDateAndReviewer.pl
new file mode 100644
index 0000000..076d88c
--- /dev/null
+++ b/Tools/Scripts/webkitperl/VCSUtils_unittest/setChangeLogDateAndReviewer.pl
@@ -0,0 +1,128 @@
+#!/usr/bin/perl -w
+#
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+# Unit tests of setChangeLogDateAndReviewer().
+
+use strict;
+use warnings;
+
+use Test::More;
+use VCSUtils;
+
+my @testCaseHashRefs = (
+{
+ testName => "reviewer defined and \"NOBODY (OOPS!)\" in leading junk",
+ reviewer => "John Doe",
+ epochTime => 1273414321,
+ patch => <<'END',
+Subject: [PATCH]
+
+Reviewed by NOBODY (OOPS!).
+
+diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
+--- a/WebCore/ChangeLog
++++ b/WebCore/ChangeLog
+@@ -1,3 +1,15 @@
++2010-05-08 Chris Jerdonek <cjerdonek@webkit.org>
++
++ Reviewed by NOBODY (OOPS!).
++
+ 2010-05-08 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Jane Doe.
+END
+ expectedReturn => <<'END',
+Subject: [PATCH]
+
+Reviewed by NOBODY (OOPS!).
+
+diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
+--- a/WebCore/ChangeLog
++++ b/WebCore/ChangeLog
+@@ -1,3 +1,15 @@
++2010-05-09 Chris Jerdonek <cjerdonek@webkit.org>
++
++ Reviewed by John Doe.
++
+ 2010-05-08 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Jane Doe.
+END
+},
+{
+ testName => "reviewer not defined and \"NOBODY (OOPS!)\" in leading junk",
+ reviewer => undef,
+ epochTime => 1273414321,
+ patch => <<'END',
+Subject: [PATCH]
+
+Reviewed by NOBODY (OOPS!).
+
+diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
+--- a/WebCore/ChangeLog
++++ b/WebCore/ChangeLog
+@@ -1,3 +1,15 @@
++2010-05-08 Chris Jerdonek <cjerdonek@webkit.org>
++
++ Reviewed by NOBODY (OOPS!).
++
+ 2010-05-08 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Jane Doe.
+END
+ expectedReturn => <<'END',
+Subject: [PATCH]
+
+Reviewed by NOBODY (OOPS!).
+
+diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
+--- a/WebCore/ChangeLog
++++ b/WebCore/ChangeLog
+@@ -1,3 +1,15 @@
++2010-05-09 Chris Jerdonek <cjerdonek@webkit.org>
++
++ Reviewed by NOBODY (OOPS!).
++
+ 2010-05-08 Chris Jerdonek <cjerdonek@webkit.org>
+
+ Reviewed by Jane Doe.
+END
+},
+);
+
+my $testCasesCount = @testCaseHashRefs;
+plan(tests => 1 * $testCasesCount); # Total number of assertions.
+
+foreach my $testCase (@testCaseHashRefs) {
+ my $testNameStart = "setChangeLogDateAndReviewer(): $testCase->{testName}: comparing";
+
+ my $patch = $testCase->{patch};
+ my $reviewer = $testCase->{reviewer};
+ my $epochTime = $testCase->{epochTime};
+
+ my $got = VCSUtils::setChangeLogDateAndReviewer($patch, $reviewer, $epochTime);
+ my $expectedReturn = $testCase->{expectedReturn};
+
+ is($got, $expectedReturn, "$testNameStart return value.");
+}
diff --git a/Tools/Scripts/webkitperl/features.pm b/Tools/Scripts/webkitperl/features.pm
new file mode 100644
index 0000000..7ca924b
--- /dev/null
+++ b/Tools/Scripts/webkitperl/features.pm
@@ -0,0 +1,105 @@
+# Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved
+# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+# Copyright (C) 2010 Andras Becsi (abecsi@inf.u-szeged.hu), University of Szeged
+#
+# 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.
+
+# Module to share code to detect the existance of features in built binaries.
+
+use strict;
+use warnings;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(&checkWebCoreFeatureSupport
+ &removeLibraryDependingOnFeature);
+ %EXPORT_TAGS = ( );
+ @EXPORT_OK = ();
+}
+
+sub libraryContainsSymbol($$)
+{
+ my ($path, $symbol) = @_;
+
+ if (isCygwin() or isWindows()) {
+ # FIXME: Implement this for Windows.
+ return 0;
+ }
+
+ my $foundSymbol = 0;
+ if (-e $path) {
+ open NM, "-|", "nm", $path or die;
+ while (<NM>) {
+ $foundSymbol = 1 if /$symbol/; # FIXME: This should probably check for word boundaries before/after the symbol name.
+ }
+ close NM;
+ }
+ return $foundSymbol;
+}
+
+sub hasFeature($$)
+{
+ my ($featureName, $path) = @_;
+ my %symbolForFeature = (
+ "MathML" => "MathMLElement",
+ "SVG" => "SVGDefsElement", # We used to look for SVGElement but isSVGElement exists (and would match) in --no-svg builds.
+ "Accelerated Compositing" => "GraphicsLayer",
+ "3D Rendering" => "WebCoreHas3DRendering",
+ "3D Canvas" => "WebGLShader",
+ "WML" => "WMLElement",
+ "WCSS" => "parseWCSSInputProperty",
+ "XHTMLMP" => "isXHTMLMPDocument",
+ );
+ my $symbolName = $symbolForFeature{$featureName};
+ die "Unknown feature: $featureName" unless $symbolName;
+ return libraryContainsSymbol($path, $symbolName);
+}
+
+sub checkWebCoreFeatureSupport($$)
+{
+ my ($feature, $required) = @_;
+ my $libraryName = "WebCore";
+ my $path = builtDylibPathForName($libraryName);
+ my $hasFeature = hasFeature($feature, $path);
+ if ($required && !$hasFeature) {
+ die "$libraryName at \"$path\" does not include $hasFeature support. See build-webkit --help\n";
+ }
+ return $hasFeature;
+}
+
+sub removeLibraryDependingOnFeature($$$)
+{
+ my ($libraryName, $featureName, $shouldHaveFeature) = @_;
+ my $path = builtDylibPathForName($libraryName);
+ return unless -x $path;
+
+ my $hasFeature = hasFeature($featureName, $path);
+ system "rm -f $path" if ($shouldHaveFeature xor $hasFeature);
+}
+
+1;
diff --git a/Tools/Scripts/webkitperl/httpd.pm b/Tools/Scripts/webkitperl/httpd.pm
new file mode 100644
index 0000000..b415db6
--- /dev/null
+++ b/Tools/Scripts/webkitperl/httpd.pm
@@ -0,0 +1,321 @@
+# Copyright (C) 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved
+# Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+# Copyright (C) 2010 Andras Becsi (abecsi@inf.u-szeged.hu), University of Szeged
+#
+# 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.
+
+# Module to share code to start and stop the Apache daemon.
+
+use strict;
+use warnings;
+
+use File::Copy;
+use File::Path;
+use File::Spec;
+use File::Spec::Functions;
+use Fcntl ':flock';
+use IPC::Open2;
+
+use webkitdirs;
+
+BEGIN {
+ use Exporter ();
+ our ($VERSION, @ISA, @EXPORT, @EXPORT_OK, %EXPORT_TAGS);
+ $VERSION = 1.00;
+ @ISA = qw(Exporter);
+ @EXPORT = qw(&getHTTPDPath
+ &getHTTPDConfigPathForTestDirectory
+ &getDefaultConfigForTestDirectory
+ &openHTTPD
+ &closeHTTPD
+ &setShouldWaitForUserInterrupt
+ &waitForHTTPDLock
+ &getWaitTime);
+ %EXPORT_TAGS = ( );
+ @EXPORT_OK = ();
+}
+
+my $tmpDir = "/tmp";
+my $httpdLockPrefix = "WebKitHttpd.lock.";
+my $myLockFile;
+my $exclusiveLockFile = File::Spec->catfile($tmpDir, "WebKit.lock");
+my $httpdPath;
+my $httpdPidDir = File::Spec->catfile($tmpDir, "WebKit");
+my $httpdPidFile = File::Spec->catfile($httpdPidDir, "httpd.pid");
+my $httpdPid;
+my $waitForUserInterrupt = 0;
+my $waitBeginTime;
+my $waitEndTime;
+
+$SIG{'INT'} = 'handleInterrupt';
+$SIG{'TERM'} = 'handleInterrupt';
+
+sub getHTTPDPath
+{
+ if (isDebianBased()) {
+ $httpdPath = "/usr/sbin/apache2";
+ } else {
+ $httpdPath = "/usr/sbin/httpd";
+ }
+ return $httpdPath;
+}
+
+sub getDefaultConfigForTestDirectory
+{
+ my ($testDirectory) = @_;
+ die "No test directory has been specified." unless ($testDirectory);
+
+ my $httpdConfig = getHTTPDConfigPathForTestDirectory($testDirectory);
+ my $documentRoot = "$testDirectory/http/tests";
+ my $jsTestResourcesDirectory = $testDirectory . "/fast/js/resources";
+ my $typesConfig = "$testDirectory/http/conf/mime.types";
+ my $httpdLockFile = File::Spec->catfile($httpdPidDir, "httpd.lock");
+ my $httpdScoreBoardFile = File::Spec->catfile($httpdPidDir, "httpd.scoreboard");
+
+ my @httpdArgs = (
+ "-f", "$httpdConfig",
+ "-C", "DocumentRoot \"$documentRoot\"",
+ # Setup a link to where the js test templates are stored, use -c so that mod_alias will already be loaded.
+ "-c", "Alias /js-test-resources \"$jsTestResourcesDirectory\"",
+ "-c", "TypesConfig \"$typesConfig\"",
+ # Apache wouldn't run CGIs with permissions==700 otherwise
+ "-c", "User \"#$<\"",
+ "-c", "LockFile \"$httpdLockFile\"",
+ "-c", "PidFile \"$httpdPidFile\"",
+ "-c", "ScoreBoardFile \"$httpdScoreBoardFile\"",
+ );
+
+ # FIXME: Enable this on Windows once <rdar://problem/5345985> is fixed
+ # The version of Apache we use with Cygwin does not support SSL
+ my $sslCertificate = "$testDirectory/http/conf/webkit-httpd.pem";
+ push(@httpdArgs, "-c", "SSLCertificateFile \"$sslCertificate\"") unless isCygwin();
+
+ return @httpdArgs;
+
+}
+
+sub getHTTPDConfigPathForTestDirectory
+{
+ my ($testDirectory) = @_;
+ die "No test directory has been specified." unless ($testDirectory);
+ my $httpdConfig;
+ getHTTPDPath();
+ if (isCygwin()) {
+ my $windowsConfDirectory = "$testDirectory/http/conf/";
+ unless (-x "/usr/lib/apache/libphp4.dll") {
+ copy("$windowsConfDirectory/libphp4.dll", "/usr/lib/apache/libphp4.dll");
+ chmod(0755, "/usr/lib/apache/libphp4.dll");
+ }
+ $httpdConfig = "$windowsConfDirectory/cygwin-httpd.conf";
+ } elsif (isDebianBased()) {
+ $httpdConfig = "$testDirectory/http/conf/apache2-debian-httpd.conf";
+ } elsif (isFedoraBased()) {
+ $httpdConfig = "$testDirectory/http/conf/fedora-httpd.conf";
+ } else {
+ $httpdConfig = "$testDirectory/http/conf/httpd.conf";
+ $httpdConfig = "$testDirectory/http/conf/apache2-httpd.conf" if `$httpdPath -v` =~ m|Apache/2|;
+ }
+ return $httpdConfig;
+}
+
+sub openHTTPD(@)
+{
+ my (@args) = @_;
+ die "No HTTPD configuration has been specified" unless (@args);
+ mkdir($httpdPidDir, 0755);
+ die "No write permissions to $httpdPidDir" unless (-w $httpdPidDir);
+
+ if (-f $httpdPidFile) {
+ open (PIDFILE, $httpdPidFile);
+ my $oldPid = <PIDFILE>;
+ chomp $oldPid;
+ close PIDFILE;
+ if (0 != kill 0, $oldPid) {
+ print "\nhttpd is already running: pid $oldPid, killing...\n";
+ if (!killHTTPD($oldPid)) {
+ cleanUp();
+ die "Timed out waiting for httpd to quit";
+ }
+ }
+ unlink $httpdPidFile;
+ }
+
+ $httpdPath = "/usr/sbin/httpd" unless ($httpdPath);
+
+ open2(">&1", \*HTTPDIN, $httpdPath, @args);
+
+ my $retryCount = 20;
+ while (!-f $httpdPidFile && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+
+ if (!$retryCount) {
+ cleanUp();
+ die "Timed out waiting for httpd to start";
+ }
+
+ $httpdPid = <PIDFILE> if open(PIDFILE, $httpdPidFile);
+ chomp $httpdPid if $httpdPid;
+ close PIDFILE;
+
+ waitpid($httpdPid, 0) if ($waitForUserInterrupt && $httpdPid);
+
+ return 1;
+}
+
+sub closeHTTPD
+{
+ close HTTPDIN;
+ my $succeeded = killHTTPD($httpdPid);
+ cleanUp();
+ unless ($succeeded) {
+ print STDERR "Timed out waiting for httpd to terminate!\n" unless $succeeded;
+ return 0;
+ }
+ return 1;
+}
+
+sub killHTTPD
+{
+ my ($pid) = @_;
+
+ return 1 unless $pid;
+
+ kill 15, $pid;
+
+ my $retryCount = 20;
+ while (kill(0, $pid) && $retryCount) {
+ sleep 1;
+ --$retryCount;
+ }
+ return $retryCount != 0;
+}
+
+sub setShouldWaitForUserInterrupt
+{
+ $waitForUserInterrupt = 1;
+}
+
+sub handleInterrupt
+{
+ # On Cygwin, when we receive a signal Apache is still running, so we need
+ # to kill it. On other platforms (at least Mac OS X), Apache will have
+ # already been killed, and trying to kill it again will cause us to hang.
+ # All we need to do in this case is clean up our own files.
+ if (isCygwin()) {
+ closeHTTPD();
+ } else {
+ cleanUp();
+ }
+
+ print "\n";
+ exit(1);
+}
+
+sub cleanUp
+{
+ rmdir $httpdPidDir;
+ unlink $exclusiveLockFile;
+ unlink $myLockFile if $myLockFile;
+}
+
+sub extractLockNumber
+{
+ my ($lockFile) = @_;
+ return -1 unless $lockFile;
+ return substr($lockFile, length($httpdLockPrefix));
+}
+
+sub getLockFiles
+{
+ opendir(TMPDIR, $tmpDir) or die "Could not open " . $tmpDir . ".";
+ my @lockFiles = grep {m/^$httpdLockPrefix\d+$/} readdir(TMPDIR);
+ @lockFiles = sort { extractLockNumber($a) <=> extractLockNumber($b) } @lockFiles;
+ closedir(TMPDIR);
+ return @lockFiles;
+}
+
+sub getNextAvailableLockNumber
+{
+ my @lockFiles = getLockFiles();
+ return 0 unless @lockFiles;
+ return extractLockNumber($lockFiles[-1]) + 1;
+}
+
+sub getLockNumberForCurrentRunning
+{
+ my @lockFiles = getLockFiles();
+ return 0 unless @lockFiles;
+ return extractLockNumber($lockFiles[0]);
+}
+
+sub waitForHTTPDLock
+{
+ $waitBeginTime = time;
+ scheduleHttpTesting();
+ # If we are the only one waiting for Apache just run the tests without any further checking
+ if (scalar getLockFiles() > 1) {
+ my $currentLockFile = File::Spec->catfile($tmpDir, "$httpdLockPrefix" . getLockNumberForCurrentRunning());
+ my $currentLockPid = <SCHEDULER_LOCK> if (-f $currentLockFile && open(SCHEDULER_LOCK, "<$currentLockFile"));
+ # Wait until we are allowed to run the http tests
+ while ($currentLockPid && $currentLockPid != $$) {
+ $currentLockFile = File::Spec->catfile($tmpDir, "$httpdLockPrefix" . getLockNumberForCurrentRunning());
+ if ($currentLockFile eq $myLockFile) {
+ $currentLockPid = <SCHEDULER_LOCK> if open(SCHEDULER_LOCK, "<$currentLockFile");
+ if ($currentLockPid != $$) {
+ print STDERR "\nPID mismatch.\n";
+ last;
+ }
+ } else {
+ sleep 1;
+ }
+ }
+ }
+ $waitEndTime = time;
+}
+
+sub scheduleHttpTesting
+{
+ # We need an exclusive lock file to avoid deadlocks and starvation and ensure that the scheduler lock numbers are sequential.
+ # The scheduler locks are used to schedule the running test sessions in first come first served order.
+ while (!(open(SEQUENTIAL_GUARD_LOCK, ">$exclusiveLockFile") && flock(SEQUENTIAL_GUARD_LOCK, LOCK_EX|LOCK_NB))) {}
+ $myLockFile = File::Spec->catfile($tmpDir, "$httpdLockPrefix" . getNextAvailableLockNumber());
+ open(SCHEDULER_LOCK, ">$myLockFile");
+ print SCHEDULER_LOCK "$$";
+ print SEQUENTIAL_GUARD_LOCK "$$";
+ close(SCHEDULER_LOCK);
+ close(SEQUENTIAL_GUARD_LOCK);
+ unlink $exclusiveLockFile;
+}
+
+sub getWaitTime
+{
+ my $waitTime = 0;
+ if ($waitBeginTime && $waitEndTime) {
+ $waitTime = $waitEndTime - $waitBeginTime;
+ }
+ return $waitTime;
+}
diff --git a/Tools/Scripts/webkitpy/__init__.py b/Tools/Scripts/webkitpy/__init__.py
new file mode 100644
index 0000000..b376bf2
--- /dev/null
+++ b/Tools/Scripts/webkitpy/__init__.py
@@ -0,0 +1,13 @@
+# Required for Python to search this directory for module files
+
+# Keep this file free of any code or import statements that could
+# cause either an error to occur or a log message to be logged.
+# This ensures that calling code can import initialization code from
+# webkitpy before any errors or log messages due to code in this file.
+# Initialization code can include things like version-checking code and
+# logging configuration code.
+#
+# We do not execute any version-checking code or logging configuration
+# code in this file so that callers can opt-in as they want. This also
+# allows different callers to choose different initialization code,
+# as necessary.
diff --git a/Tools/Scripts/webkitpy/common/__init__.py b/Tools/Scripts/webkitpy/common/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/common/array_stream.py b/Tools/Scripts/webkitpy/common/array_stream.py
new file mode 100644
index 0000000..e425d02
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/array_stream.py
@@ -0,0 +1,66 @@
+#!/usr/bin/python
+# 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.
+
+"""Package that private an array-based implementation of a stream."""
+
+
+class ArrayStream(object):
+ """Simple class that implmements a stream interface on top of an array.
+
+ This is used primarily by unit test classes to mock output streams. It
+ performs a similar function to StringIO, but (a) it is write-only, and
+ (b) it can be used to retrieve each individual write(); StringIO
+ concatenates all of the writes together.
+ """
+
+ def __init__(self):
+ self._contents = []
+
+ def write(self, msg):
+ """Implement stream.write() by appending to the stream's contents."""
+ self._contents.append(msg)
+
+ def get(self):
+ """Return the contents of a stream (as an array)."""
+ return self._contents
+
+ def reset(self):
+ """Empty the stream."""
+ self._contents = []
+
+ def empty(self):
+ """Return whether the stream is empty."""
+ return (len(self._contents) == 0)
+
+ def flush(self):
+ """Flush the stream (a no-op implemented for compatibility)."""
+ pass
+
+ def __repr__(self):
+ return '<ArrayStream: ' + str(self._contents) + '>'
diff --git a/Tools/Scripts/webkitpy/common/array_stream_unittest.py b/Tools/Scripts/webkitpy/common/array_stream_unittest.py
new file mode 100644
index 0000000..1a9b34a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/array_stream_unittest.py
@@ -0,0 +1,78 @@
+#!/usr/bin/python
+# 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.
+
+"""Unit tests for array_stream.py."""
+
+import pdb
+import unittest
+
+from webkitpy.common.array_stream import ArrayStream
+
+
+class ArrayStreamTest(unittest.TestCase):
+ def assertEmpty(self, a_stream):
+ self.assertTrue(a_stream.empty())
+
+ def assertNotEmpty(self, a_stream):
+ self.assertFalse(a_stream.empty())
+
+ def assertContentsMatch(self, a_stream, contents):
+ self.assertEquals(a_stream.get(), contents)
+
+ def test_basics(self):
+ a = ArrayStream()
+ self.assertEmpty(a)
+ self.assertContentsMatch(a, [])
+
+ a.flush()
+ self.assertEmpty(a)
+ self.assertContentsMatch(a, [])
+
+ a.write("foo")
+ a.write("bar")
+ self.assertNotEmpty(a)
+ self.assertContentsMatch(a, ["foo", "bar"])
+
+ a.flush()
+ self.assertNotEmpty(a)
+ self.assertContentsMatch(a, ["foo", "bar"])
+
+ a.reset()
+ self.assertEmpty(a)
+ self.assertContentsMatch(a, [])
+
+ self.assertEquals(str(a), "<ArrayStream: []>")
+
+ a.write("foo")
+ self.assertNotEmpty(a)
+ self.assertContentsMatch(a, ["foo"])
+ self.assertEquals(str(a), "<ArrayStream: ['foo']>")
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/checkout/__init__.py b/Tools/Scripts/webkitpy/common/checkout/__init__.py
new file mode 100644
index 0000000..597dcbd
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/checkout/__init__.py
@@ -0,0 +1,3 @@
+# Required for Python to search this directory for module files
+
+from api import Checkout
diff --git a/Tools/Scripts/webkitpy/common/checkout/api.py b/Tools/Scripts/webkitpy/common/checkout/api.py
new file mode 100644
index 0000000..6357982
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/checkout/api.py
@@ -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.
+
+import os
+import StringIO
+
+from webkitpy.common.config import urls
+from webkitpy.common.checkout.changelog import ChangeLog
+from webkitpy.common.checkout.commitinfo import CommitInfo
+from webkitpy.common.checkout.scm import CommitMessage
+from webkitpy.common.memoized import memoized
+from webkitpy.common.net.bugzilla import parse_bug_id
+from webkitpy.common.system.executive import Executive, run_command, ScriptError
+from webkitpy.common.system.deprecated_logging import log
+
+
+# This class represents the WebKit-specific parts of the checkout (like
+# ChangeLogs).
+# FIXME: Move a bunch of ChangeLog-specific processing from SCM to this object.
+class Checkout(object):
+ def __init__(self, scm):
+ self._scm = scm
+
+ def _is_path_to_changelog(self, path):
+ return os.path.basename(path) == "ChangeLog"
+
+ def _latest_entry_for_changelog_at_revision(self, changelog_path, revision):
+ changelog_contents = self._scm.contents_at_revision(changelog_path, revision)
+ # contents_at_revision returns a byte array (str()), but we know
+ # that ChangeLog files are utf-8. parse_latest_entry_from_file
+ # expects a file-like object which vends unicode(), so we decode here.
+ changelog_file = StringIO.StringIO(changelog_contents.decode("utf-8"))
+ return ChangeLog.parse_latest_entry_from_file(changelog_file)
+
+ def changelog_entries_for_revision(self, revision):
+ changed_files = self._scm.changed_files_for_revision(revision)
+ return [self._latest_entry_for_changelog_at_revision(path, revision) for path in changed_files if self._is_path_to_changelog(path)]
+
+ @memoized
+ def commit_info_for_revision(self, revision):
+ committer_email = self._scm.committer_email_for_revision(revision)
+ changelog_entries = self.changelog_entries_for_revision(revision)
+ # Assume for now that the first entry has everything we need:
+ # FIXME: This will throw an exception if there were no ChangeLogs.
+ if not len(changelog_entries):
+ return None
+ changelog_entry = changelog_entries[0]
+ changelog_data = {
+ "bug_id": parse_bug_id(changelog_entry.contents()),
+ "author_name": changelog_entry.author_name(),
+ "author_email": changelog_entry.author_email(),
+ "author": changelog_entry.author(),
+ "reviewer_text": changelog_entry.reviewer_text(),
+ "reviewer": changelog_entry.reviewer(),
+ }
+ # We could pass the changelog_entry instead of a dictionary here, but that makes
+ # mocking slightly more involved, and would make aggregating data from multiple
+ # entries more difficult to wire in if we need to do that in the future.
+ return CommitInfo(revision, committer_email, changelog_data)
+
+ def bug_id_for_revision(self, revision):
+ return self.commit_info_for_revision(revision).bug_id()
+
+ def _modified_files_matching_predicate(self, git_commit, predicate, changed_files=None):
+ # SCM returns paths relative to scm.checkout_root
+ # Callers (especially those using the ChangeLog class) may
+ # expect absolute paths, so this method returns absolute paths.
+ if not changed_files:
+ changed_files = self._scm.changed_files(git_commit)
+ absolute_paths = [os.path.join(self._scm.checkout_root, path) for path in changed_files]
+ return [path for path in absolute_paths if predicate(path)]
+
+ def modified_changelogs(self, git_commit, changed_files=None):
+ return self._modified_files_matching_predicate(git_commit, self._is_path_to_changelog, changed_files=changed_files)
+
+ def modified_non_changelogs(self, git_commit, changed_files=None):
+ return self._modified_files_matching_predicate(git_commit, lambda path: not self._is_path_to_changelog(path), changed_files=changed_files)
+
+ def commit_message_for_this_commit(self, git_commit, changed_files=None):
+ changelog_paths = self.modified_changelogs(git_commit, changed_files)
+ if not len(changelog_paths):
+ raise ScriptError(message="Found no modified ChangeLogs, cannot create a commit message.\n"
+ "All changes require a ChangeLog. See:\n %s" % urls.contribution_guidelines)
+
+ changelog_messages = []
+ for changelog_path in changelog_paths:
+ log("Parsing ChangeLog: %s" % changelog_path)
+ changelog_entry = ChangeLog(changelog_path).latest_entry()
+ if not changelog_entry:
+ raise ScriptError(message="Failed to parse ChangeLog: %s" % os.path.abspath(changelog_path))
+ changelog_messages.append(changelog_entry.contents())
+
+ # FIXME: We should sort and label the ChangeLog messages like commit-log-editor does.
+ return CommitMessage("".join(changelog_messages).splitlines())
+
+ def recent_commit_infos_for_files(self, paths):
+ revisions = set(sum(map(self._scm.revisions_changing_file, paths), []))
+ return set(map(self.commit_info_for_revision, revisions))
+
+ def suggested_reviewers(self, git_commit, changed_files=None):
+ changed_files = self.modified_non_changelogs(git_commit, changed_files)
+ commit_infos = self.recent_commit_infos_for_files(changed_files)
+ reviewers = [commit_info.reviewer() for commit_info in commit_infos if commit_info.reviewer()]
+ reviewers.extend([commit_info.author() for commit_info in commit_infos if commit_info.author() and commit_info.author().can_review])
+ return sorted(set(reviewers))
+
+ def bug_id_for_this_commit(self, git_commit, changed_files=None):
+ try:
+ return parse_bug_id(self.commit_message_for_this_commit(git_commit, changed_files).message())
+ except ScriptError, e:
+ pass # We might not have ChangeLogs.
+
+ def apply_patch(self, patch, force=False):
+ # It's possible that the patch was not made from the root directory.
+ # We should detect and handle that case.
+ # FIXME: Move _scm.script_path here once we get rid of all the dependencies.
+ args = [self._scm.script_path('svn-apply')]
+ if patch.reviewer():
+ args += ['--reviewer', patch.reviewer().full_name]
+ if force:
+ args.append('--force')
+ run_command(args, input=patch.contents())
+
+ def apply_reverse_diff(self, revision):
+ self._scm.apply_reverse_diff(revision)
+
+ # We revert the ChangeLogs because removing lines from a ChangeLog
+ # doesn't make sense. ChangeLogs are append only.
+ changelog_paths = self.modified_changelogs(git_commit=None)
+ if len(changelog_paths):
+ self._scm.revert_files(changelog_paths)
+
+ conflicts = self._scm.conflicted_files()
+ if len(conflicts):
+ raise ScriptError(message="Failed to apply reverse diff for revision %s because of the following conflicts:\n%s" % (revision, "\n".join(conflicts)))
+
+ def apply_reverse_diffs(self, revision_list):
+ for revision in sorted(revision_list, reverse=True):
+ self.apply_reverse_diff(revision)
diff --git a/Tools/Scripts/webkitpy/common/checkout/api_unittest.py b/Tools/Scripts/webkitpy/common/checkout/api_unittest.py
new file mode 100644
index 0000000..1f97abd
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/checkout/api_unittest.py
@@ -0,0 +1,196 @@
+# 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.
+
+from __future__ import with_statement
+
+import codecs
+import os
+import shutil
+import tempfile
+import unittest
+
+from webkitpy.common.checkout.api import Checkout
+from webkitpy.common.checkout.changelog import ChangeLogEntry
+from webkitpy.common.checkout.scm import detect_scm_system, CommitMessage
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.thirdparty.mock import Mock
+
+
+# FIXME: Copied from scm_unittest.py
+def write_into_file_at_path(file_path, contents, encoding="utf-8"):
+ with codecs.open(file_path, "w", encoding) as file:
+ file.write(contents)
+
+
+_changelog1entry1 = u"""2010-03-25 Tor Arne Vestb\u00f8 <vestbo@webkit.org>
+
+ Unreviewed build fix to un-break webkit-patch land.
+
+ Move commit_message_for_this_commit from scm to checkout
+ https://bugs.webkit.org/show_bug.cgi?id=36629
+
+ * Scripts/webkitpy/common/checkout/api.py: import scm.CommitMessage
+"""
+_changelog1entry2 = u"""2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Move commit_message_for_this_commit from scm to checkout
+ https://bugs.webkit.org/show_bug.cgi?id=36629
+
+ * Scripts/webkitpy/common/checkout/api.py:
+"""
+_changelog1 = u"\n".join([_changelog1entry1, _changelog1entry2])
+_changelog2 = u"""2010-03-25 Tor Arne Vestb\u00f8 <vestbo@webkit.org>
+
+ Unreviewed build fix to un-break webkit-patch land.
+
+ Second part of this complicated change.
+
+ * Path/To/Complicated/File: Added.
+
+2010-03-25 Adam Barth <abarth@webkit.org>
+
+ Reviewed by Eric Seidel.
+
+ Filler change.
+"""
+
+class CommitMessageForThisCommitTest(unittest.TestCase):
+ expected_commit_message = u"""2010-03-25 Tor Arne Vestb\u00f8 <vestbo@webkit.org>
+
+ Unreviewed build fix to un-break webkit-patch land.
+
+ Move commit_message_for_this_commit from scm to checkout
+ https://bugs.webkit.org/show_bug.cgi?id=36629
+
+ * Scripts/webkitpy/common/checkout/api.py: import scm.CommitMessage
+2010-03-25 Tor Arne Vestb\u00f8 <vestbo@webkit.org>
+
+ Unreviewed build fix to un-break webkit-patch land.
+
+ Second part of this complicated change.
+
+ * Path/To/Complicated/File: Added.
+"""
+
+ def setUp(self):
+ self.temp_dir = tempfile.mkdtemp(suffix="changelogs")
+ self.old_cwd = os.getcwd()
+ os.chdir(self.temp_dir)
+ write_into_file_at_path("ChangeLog1", _changelog1)
+ write_into_file_at_path("ChangeLog2", _changelog2)
+
+ def tearDown(self):
+ shutil.rmtree(self.temp_dir, ignore_errors=True)
+ os.chdir(self.old_cwd)
+
+ # FIXME: This should not need to touch the file system, however
+ # ChangeLog is difficult to mock at current.
+ def test_commit_message_for_this_commit(self):
+ checkout = Checkout(None)
+ checkout.modified_changelogs = lambda git_commit, changed_files=None: ["ChangeLog1", "ChangeLog2"]
+ output = OutputCapture()
+ expected_stderr = "Parsing ChangeLog: ChangeLog1\nParsing ChangeLog: ChangeLog2\n"
+ commit_message = output.assert_outputs(self, checkout.commit_message_for_this_commit,
+ kwargs={"git_commit": None}, expected_stderr=expected_stderr)
+ self.assertEqual(commit_message.message(), self.expected_commit_message)
+
+
+class CheckoutTest(unittest.TestCase):
+ def test_latest_entry_for_changelog_at_revision(self):
+ scm = Mock()
+ def mock_contents_at_revision(changelog_path, revision):
+ self.assertEqual(changelog_path, "foo")
+ self.assertEqual(revision, "bar")
+ # contents_at_revision is expected to return a byte array (str)
+ # so we encode our unicode ChangeLog down to a utf-8 stream.
+ return _changelog1.encode("utf-8")
+ scm.contents_at_revision = mock_contents_at_revision
+ checkout = Checkout(scm)
+ entry = checkout._latest_entry_for_changelog_at_revision("foo", "bar")
+ self.assertEqual(entry.contents(), _changelog1entry1)
+
+ def test_commit_info_for_revision(self):
+ scm = Mock()
+ scm.committer_email_for_revision = lambda revision: "committer@example.com"
+ checkout = Checkout(scm)
+ checkout.changelog_entries_for_revision = lambda revision: [ChangeLogEntry(_changelog1entry1)]
+ commitinfo = checkout.commit_info_for_revision(4)
+ self.assertEqual(commitinfo.bug_id(), 36629)
+ self.assertEqual(commitinfo.author_name(), u"Tor Arne Vestb\u00f8")
+ self.assertEqual(commitinfo.author_email(), "vestbo@webkit.org")
+ self.assertEqual(commitinfo.reviewer_text(), None)
+ self.assertEqual(commitinfo.reviewer(), None)
+ self.assertEqual(commitinfo.committer_email(), "committer@example.com")
+ self.assertEqual(commitinfo.committer(), None)
+
+ checkout.changelog_entries_for_revision = lambda revision: []
+ self.assertEqual(checkout.commit_info_for_revision(1), None)
+
+ def test_bug_id_for_revision(self):
+ scm = Mock()
+ scm.committer_email_for_revision = lambda revision: "committer@example.com"
+ checkout = Checkout(scm)
+ checkout.changelog_entries_for_revision = lambda revision: [ChangeLogEntry(_changelog1entry1)]
+ self.assertEqual(checkout.bug_id_for_revision(4), 36629)
+
+ def test_bug_id_for_this_commit(self):
+ scm = Mock()
+ checkout = Checkout(scm)
+ checkout.commit_message_for_this_commit = lambda git_commit, changed_files=None: CommitMessage(ChangeLogEntry(_changelog1entry1).contents().splitlines())
+ self.assertEqual(checkout.bug_id_for_this_commit(git_commit=None), 36629)
+
+ def test_modified_changelogs(self):
+ scm = Mock()
+ scm.checkout_root = "/foo/bar"
+ scm.changed_files = lambda git_commit: ["file1", "ChangeLog", "relative/path/ChangeLog"]
+ checkout = Checkout(scm)
+ expected_changlogs = ["/foo/bar/ChangeLog", "/foo/bar/relative/path/ChangeLog"]
+ self.assertEqual(checkout.modified_changelogs(git_commit=None), expected_changlogs)
+
+ def test_suggested_reviewers(self):
+ def mock_changelog_entries_for_revision(revision):
+ if revision % 2 == 0:
+ return [ChangeLogEntry(_changelog1entry1)]
+ return [ChangeLogEntry(_changelog1entry2)]
+
+ def mock_revisions_changing_file(path, limit=5):
+ if path.endswith("ChangeLog"):
+ return [3]
+ return [4, 8]
+
+ scm = Mock()
+ scm.checkout_root = "/foo/bar"
+ scm.changed_files = lambda git_commit: ["file1", "file2", "relative/path/ChangeLog"]
+ scm.revisions_changing_file = mock_revisions_changing_file
+ checkout = Checkout(scm)
+ checkout.changelog_entries_for_revision = mock_changelog_entries_for_revision
+ reviewers = checkout.suggested_reviewers(git_commit=None)
+ reviewer_names = [reviewer.full_name for reviewer in reviewers]
+ self.assertEqual(reviewer_names, [u'Tor Arne Vestb\xf8'])
diff --git a/Tools/Scripts/webkitpy/common/checkout/changelog.py b/Tools/Scripts/webkitpy/common/checkout/changelog.py
new file mode 100644
index 0000000..07f905d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/checkout/changelog.py
@@ -0,0 +1,191 @@
+# 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.
+#
+# WebKit's Python module for parsing and modifying ChangeLog files
+
+import codecs
+import fileinput # inplace file editing for set_reviewer_in_changelog
+import os.path
+import re
+import textwrap
+
+from webkitpy.common.system.deprecated_logging import log
+from webkitpy.common.config.committers import CommitterList
+from webkitpy.common.config import urls
+from webkitpy.common.net.bugzilla import parse_bug_id
+from webkitpy.tool.grammar import join_with_separators
+
+
+class ChangeLogEntry(object):
+ # e.g. 2009-06-03 Eric Seidel <eric@webkit.org>
+ date_line_regexp = r'^(?P<date>\d{4}-\d{2}-\d{2})\s+(?P<name>.+?)\s+<(?P<email>[^<>]+)>$'
+
+ def __init__(self, contents, committer_list=CommitterList()):
+ self._contents = contents
+ self._committer_list = committer_list
+ self._parse_entry()
+
+ def _parse_entry(self):
+ match = re.match(self.date_line_regexp, self._contents, re.MULTILINE)
+ if not match:
+ log("WARNING: Creating invalid ChangeLogEntry:\n%s" % self._contents)
+
+ # FIXME: group("name") does not seem to be Unicode? Probably due to self._contents not being unicode.
+ self._author_name = match.group("name") if match else None
+ self._author_email = match.group("email") if match else None
+
+ match = re.search("^\s+Reviewed by (?P<reviewer>.*?)[\.,]?\s*$", self._contents, re.MULTILINE) # Discard everything after the first period
+ self._reviewer_text = match.group("reviewer") if match else None
+
+ self._reviewer = self._committer_list.committer_by_name(self._reviewer_text)
+ self._author = self._committer_list.committer_by_email(self._author_email) or self._committer_list.committer_by_name(self._author_name)
+
+ def author_name(self):
+ return self._author_name
+
+ def author_email(self):
+ return self._author_email
+
+ def author(self):
+ return self._author # Might be None
+
+ # FIXME: Eventually we would like to map reviwer names to reviewer objects.
+ # See https://bugs.webkit.org/show_bug.cgi?id=26533
+ def reviewer_text(self):
+ return self._reviewer_text
+
+ def reviewer(self):
+ return self._reviewer # Might be None
+
+ def contents(self):
+ return self._contents
+
+ def bug_id(self):
+ return parse_bug_id(self._contents)
+
+
+# FIXME: Various methods on ChangeLog should move into ChangeLogEntry instead.
+class ChangeLog(object):
+
+ def __init__(self, path):
+ self.path = path
+
+ _changelog_indent = " " * 8
+
+ @staticmethod
+ def parse_latest_entry_from_file(changelog_file):
+ """changelog_file must be a file-like object which returns
+ unicode strings. Use codecs.open or StringIO(unicode())
+ to pass file objects to this class."""
+ date_line_regexp = re.compile(ChangeLogEntry.date_line_regexp)
+ entry_lines = []
+ # The first line should be a date line.
+ first_line = changelog_file.readline()
+ assert(isinstance(first_line, unicode))
+ if not date_line_regexp.match(first_line):
+ return None
+ entry_lines.append(first_line)
+
+ for line in changelog_file:
+ # If we've hit the next entry, return.
+ if date_line_regexp.match(line):
+ # Remove the extra newline at the end
+ return ChangeLogEntry(''.join(entry_lines[:-1]))
+ entry_lines.append(line)
+ return None # We never found a date line!
+
+ def latest_entry(self):
+ # ChangeLog files are always UTF-8, we read them in as such to support Reviewers with unicode in their names.
+ changelog_file = codecs.open(self.path, "r", "utf-8")
+ try:
+ return self.parse_latest_entry_from_file(changelog_file)
+ finally:
+ changelog_file.close()
+
+ # _wrap_line and _wrap_lines exist to work around
+ # http://bugs.python.org/issue1859
+
+ def _wrap_line(self, line):
+ return textwrap.fill(line,
+ width=70,
+ initial_indent=self._changelog_indent,
+ # Don't break urls which may be longer than width.
+ break_long_words=False,
+ subsequent_indent=self._changelog_indent)
+
+ # Workaround as suggested by guido in
+ # http://bugs.python.org/issue1859#msg60040
+
+ def _wrap_lines(self, message):
+ lines = [self._wrap_line(line) for line in message.splitlines()]
+ return "\n".join(lines)
+
+ # This probably does not belong in changelogs.py
+ def _message_for_revert(self, revision_list, reason, bug_url):
+ message = "Unreviewed, rolling out %s.\n" % join_with_separators(['r' + str(revision) for revision in revision_list])
+ for revision in revision_list:
+ message += "%s\n" % urls.view_revision_url(revision)
+ if bug_url:
+ message += "%s\n" % bug_url
+ # Add an extra new line after the rollout links, before any reason.
+ message += "\n"
+ if reason:
+ message += "%s\n\n" % reason
+ return self._wrap_lines(message)
+
+ def update_for_revert(self, revision_list, reason, bug_url=None):
+ reviewed_by_regexp = re.compile(
+ "%sReviewed by NOBODY \(OOPS!\)\." % self._changelog_indent)
+ removing_boilerplate = False
+ # inplace=1 creates a backup file and re-directs stdout to the file
+ for line in fileinput.FileInput(self.path, inplace=1):
+ if reviewed_by_regexp.search(line):
+ message_lines = self._message_for_revert(revision_list,
+ reason,
+ bug_url)
+ print reviewed_by_regexp.sub(message_lines, line),
+ # Remove all the ChangeLog boilerplate between the Reviewed by
+ # line and the first changed file.
+ removing_boilerplate = True
+ elif removing_boilerplate:
+ if line.find('*') >= 0: # each changed file is preceded by a *
+ removing_boilerplate = False
+
+ if not removing_boilerplate:
+ print line,
+
+ def set_reviewer(self, reviewer):
+ # inplace=1 creates a backup file and re-directs stdout to the file
+ for line in fileinput.FileInput(self.path, inplace=1):
+ # Trailing comma suppresses printing newline
+ print line.replace("NOBODY (OOPS!)", reviewer.encode("utf-8")),
+
+ def set_short_description_and_bug_url(self, short_description, bug_url):
+ message = "%s\n %s" % (short_description, bug_url)
+ for line in fileinput.FileInput(self.path, inplace=1):
+ print line.replace("Need a short description and bug URL (OOPS!)", message.encode("utf-8")),
diff --git a/Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py b/Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py
new file mode 100644
index 0000000..20c6cfa
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/checkout/changelog_unittest.py
@@ -0,0 +1,230 @@
+# 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.
+
+from __future__ import with_statement
+
+import codecs
+import os
+import tempfile
+import unittest
+
+from StringIO import StringIO
+
+from webkitpy.common.checkout.changelog import *
+
+
+class ChangeLogTest(unittest.TestCase):
+
+ _example_entry = u'''2009-08-17 Peter Kasting <pkasting@google.com>
+
+ Reviewed by Tor Arne Vestb\xf8.
+
+ https://bugs.webkit.org/show_bug.cgi?id=27323
+ Only add Cygwin to the path when it isn't already there. This avoids
+ causing problems for people who purposefully have non-Cygwin versions of
+ executables like svn in front of the Cygwin ones in their paths.
+
+ * DumpRenderTree/win/DumpRenderTree.vcproj:
+ * DumpRenderTree/win/ImageDiff.vcproj:
+ * DumpRenderTree/win/TestNetscapePlugin/TestNetscapePlugin.vcproj:
+'''
+
+ # More example text than we need. Eventually we need to support parsing this all and write tests for the parsing.
+ _example_changelog = u"""2009-08-17 Tor Arne Vestb\xf8 <vestbo@webkit.org>
+
+ <http://webkit.org/b/28393> check-webkit-style: add check for use of std::max()/std::min() instead of MAX()/MIN()
+
+ Reviewed by David Levin.
+
+ * Scripts/modules/cpp_style.py:
+ (_ERROR_CATEGORIES): Added 'runtime/max_min_macros'.
+ (check_max_min_macros): Added. Returns level 4 error when MAX()
+ and MIN() macros are used in header files and C++ source files.
+ (check_style): Added call to check_max_min_macros().
+ * Scripts/modules/cpp_style_unittest.py: Added unit tests.
+ (test_max_macro): Added.
+ (test_min_macro): Added.
+
+2009-08-16 David Kilzer <ddkilzer@apple.com>
+
+ Backed out r47343 which was mistakenly committed
+
+ * Scripts/bugzilla-tool:
+ * Scripts/modules/scm.py:
+
+2009-06-18 Darin Adler <darin@apple.com>
+
+ Rubber stamped by Mark Rowe.
+
+ * DumpRenderTree/mac/DumpRenderTreeWindow.mm:
+ (-[DumpRenderTreeWindow close]): Resolved crashes seen during regression
+ tests. The close method can be called on a window that's already closed
+ so we can't assert here.
+
+== Rolled over to ChangeLog-2009-06-16 ==
+"""
+
+ def test_latest_entry_parse(self):
+ changelog_contents = u"%s\n%s" % (self._example_entry, self._example_changelog)
+ changelog_file = StringIO(changelog_contents)
+ latest_entry = ChangeLog.parse_latest_entry_from_file(changelog_file)
+ self.assertEquals(latest_entry.contents(), self._example_entry)
+ self.assertEquals(latest_entry.author_name(), "Peter Kasting")
+ self.assertEquals(latest_entry.author_email(), "pkasting@google.com")
+ self.assertEquals(latest_entry.reviewer_text(), u"Tor Arne Vestb\xf8")
+ self.assertTrue(latest_entry.reviewer()) # Make sure that our UTF8-based lookup of Tor works.
+
+ @staticmethod
+ def _write_tmp_file_with_contents(byte_array):
+ assert(isinstance(byte_array, str))
+ (file_descriptor, file_path) = tempfile.mkstemp() # NamedTemporaryFile always deletes the file on close in python < 2.6
+ with os.fdopen(file_descriptor, "w") as file:
+ file.write(byte_array)
+ return file_path
+
+ @staticmethod
+ def _read_file_contents(file_path, encoding):
+ with codecs.open(file_path, "r", encoding) as file:
+ return file.read()
+
+ _new_entry_boilerplate = '''2009-08-19 Eric Seidel <eric@webkit.org>
+
+ Reviewed by NOBODY (OOPS!).
+
+ Need a short description and bug URL (OOPS!)
+
+ * Scripts/bugzilla-tool:
+'''
+
+ def test_set_reviewer(self):
+ changelog_contents = u"%s\n%s" % (self._new_entry_boilerplate, self._example_changelog)
+ changelog_path = self._write_tmp_file_with_contents(changelog_contents.encode("utf-8"))
+ reviewer_name = 'Test Reviewer'
+ ChangeLog(changelog_path).set_reviewer(reviewer_name)
+ actual_contents = self._read_file_contents(changelog_path, "utf-8")
+ expected_contents = changelog_contents.replace('NOBODY (OOPS!)', reviewer_name)
+ os.remove(changelog_path)
+ self.assertEquals(actual_contents, expected_contents)
+
+ def test_set_short_description_and_bug_url(self):
+ changelog_contents = u"%s\n%s" % (self._new_entry_boilerplate, self._example_changelog)
+ changelog_path = self._write_tmp_file_with_contents(changelog_contents.encode("utf-8"))
+ short_description = "A short description"
+ bug_url = "http://example.com/b/2344"
+ ChangeLog(changelog_path).set_short_description_and_bug_url(short_description, bug_url)
+ actual_contents = self._read_file_contents(changelog_path, "utf-8")
+ expected_message = "%s\n %s" % (short_description, bug_url)
+ expected_contents = changelog_contents.replace("Need a short description and bug URL (OOPS!)", expected_message)
+ os.remove(changelog_path)
+ self.assertEquals(actual_contents, expected_contents)
+
+ _revert_message = """ Unreviewed, rolling out r12345.
+ http://trac.webkit.org/changeset/12345
+ http://example.com/123
+
+ This is a very long reason which should be long enough so that
+ _message_for_revert will need to wrap it. We'll also include
+ a
+ https://veryveryveryveryverylongbugurl.com/reallylongbugthingy.cgi?bug_id=12354
+ link so that we can make sure we wrap that right too.
+"""
+
+ def test_message_for_revert(self):
+ changelog = ChangeLog("/fake/path")
+ long_reason = "This is a very long reason which should be long enough so that _message_for_revert will need to wrap it. We'll also include a https://veryveryveryveryverylongbugurl.com/reallylongbugthingy.cgi?bug_id=12354 link so that we can make sure we wrap that right too."
+ message = changelog._message_for_revert([12345], long_reason, "http://example.com/123")
+ self.assertEquals(message, self._revert_message)
+
+ _revert_entry_with_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r12345.
+ http://trac.webkit.org/changeset/12345
+ http://example.com/123
+
+ Reason
+
+ * Scripts/bugzilla-tool:
+'''
+
+ _revert_entry_without_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r12345.
+ http://trac.webkit.org/changeset/12345
+
+ Reason
+
+ * Scripts/bugzilla-tool:
+'''
+
+ _multiple_revert_entry_with_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r12345, r12346, and r12347.
+ http://trac.webkit.org/changeset/12345
+ http://trac.webkit.org/changeset/12346
+ http://trac.webkit.org/changeset/12347
+ http://example.com/123
+
+ Reason
+
+ * Scripts/bugzilla-tool:
+'''
+
+ _multiple_revert_entry_without_bug_url = '''2009-08-19 Eric Seidel <eric@webkit.org>
+
+ Unreviewed, rolling out r12345, r12346, and r12347.
+ http://trac.webkit.org/changeset/12345
+ http://trac.webkit.org/changeset/12346
+ http://trac.webkit.org/changeset/12347
+
+ Reason
+
+ * Scripts/bugzilla-tool:
+'''
+
+ def _assert_update_for_revert_output(self, args, expected_entry):
+ changelog_contents = u"%s\n%s" % (self._new_entry_boilerplate, self._example_changelog)
+ changelog_path = self._write_tmp_file_with_contents(changelog_contents.encode("utf-8"))
+ changelog = ChangeLog(changelog_path)
+ changelog.update_for_revert(*args)
+ actual_entry = changelog.latest_entry()
+ os.remove(changelog_path)
+ self.assertEquals(actual_entry.contents(), expected_entry)
+ self.assertEquals(actual_entry.reviewer_text(), None)
+ # These checks could be removed to allow this to work on other entries:
+ self.assertEquals(actual_entry.author_name(), "Eric Seidel")
+ self.assertEquals(actual_entry.author_email(), "eric@webkit.org")
+
+ def test_update_for_revert(self):
+ self._assert_update_for_revert_output([[12345], "Reason"], self._revert_entry_without_bug_url)
+ self._assert_update_for_revert_output([[12345], "Reason", "http://example.com/123"], self._revert_entry_with_bug_url)
+ self._assert_update_for_revert_output([[12345, 12346, 12347], "Reason"], self._multiple_revert_entry_without_bug_url)
+ self._assert_update_for_revert_output([[12345, 12346, 12347], "Reason", "http://example.com/123"], self._multiple_revert_entry_with_bug_url)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/checkout/commitinfo.py b/Tools/Scripts/webkitpy/common/checkout/commitinfo.py
new file mode 100644
index 0000000..f121f36
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/checkout/commitinfo.py
@@ -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.
+#
+# WebKit's python module for holding information on a commit
+
+from webkitpy.common.config import urls
+from webkitpy.common.config.committers import CommitterList
+
+
+class CommitInfo(object):
+ def __init__(self, revision, committer_email, changelog_data, committer_list=CommitterList()):
+ self._revision = revision
+ self._committer_email = committer_email
+ self._bug_id = changelog_data["bug_id"]
+ self._author_name = changelog_data["author_name"]
+ self._author_email = changelog_data["author_email"]
+ self._author = changelog_data["author"]
+ self._reviewer_text = changelog_data["reviewer_text"]
+ self._reviewer = changelog_data["reviewer"]
+
+ # Derived values:
+ self._committer = committer_list.committer_by_email(committer_email)
+
+ def revision(self):
+ return self._revision
+
+ def committer(self):
+ return self._committer # None if committer isn't in committers.py
+
+ def committer_email(self):
+ return self._committer_email
+
+ def bug_id(self):
+ return self._bug_id # May be None
+
+ def author(self):
+ return self._author # May be None
+
+ def author_name(self):
+ return self._author_name
+
+ def author_email(self):
+ return self._author_email
+
+ def reviewer(self):
+ return self._reviewer # May be None
+
+ def reviewer_text(self):
+ return self._reviewer_text # May be None
+
+ def responsible_parties(self):
+ responsible_parties = [
+ self.committer(),
+ self.author(),
+ self.reviewer(),
+ ]
+ return set([party for party in responsible_parties if party]) # Filter out None
+
+ # FIXME: It is slightly lame that this "view" method is on this "model" class (in MVC terms)
+ def blame_string(self, bugs):
+ string = "r%s:\n" % self.revision()
+ string += " %s\n" % urls.view_revision_url(self.revision())
+ string += " Bug: %s (%s)\n" % (self.bug_id(), bugs.bug_url_for_bug_id(self.bug_id()))
+ author_line = "\"%s\" <%s>" % (self.author_name(), self.author_email())
+ string += " Author: %s\n" % (self.author() or author_line)
+ string += " Reviewer: %s\n" % (self.reviewer() or self.reviewer_text())
+ string += " Committer: %s" % self.committer()
+ return string
diff --git a/Tools/Scripts/webkitpy/common/checkout/commitinfo_unittest.py b/Tools/Scripts/webkitpy/common/checkout/commitinfo_unittest.py
new file mode 100644
index 0000000..f58e6f1
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/checkout/commitinfo_unittest.py
@@ -0,0 +1,61 @@
+# 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 unittest
+
+from webkitpy.common.checkout.commitinfo import CommitInfo
+from webkitpy.common.config.committers import CommitterList, Committer, Reviewer
+
+class CommitInfoTest(unittest.TestCase):
+
+ def test_commit_info_creation(self):
+ author = Committer("Author", "author@example.com")
+ committer = Committer("Committer", "committer@example.com")
+ reviewer = Reviewer("Reviewer", "reviewer@example.com")
+ committer_list = CommitterList(committers=[author, committer], reviewers=[reviewer])
+
+ changelog_data = {
+ "bug_id": 1234,
+ "author_name": "Committer",
+ "author_email": "author@example.com",
+ "author": author,
+ "reviewer_text": "Reviewer",
+ "reviewer": reviewer,
+ }
+ commit = CommitInfo(123, "committer@example.com", changelog_data, committer_list)
+
+ self.assertEqual(commit.revision(), 123)
+ self.assertEqual(commit.bug_id(), 1234)
+ self.assertEqual(commit.author_name(), "Committer")
+ self.assertEqual(commit.author_email(), "author@example.com")
+ self.assertEqual(commit.author(), author)
+ self.assertEqual(commit.reviewer_text(), "Reviewer")
+ self.assertEqual(commit.reviewer(), reviewer)
+ self.assertEqual(commit.committer(), committer)
+ self.assertEqual(commit.committer_email(), "committer@example.com")
+ self.assertEqual(commit.responsible_parties(), set([author, committer, reviewer]))
diff --git a/Tools/Scripts/webkitpy/common/checkout/diff_parser.py b/Tools/Scripts/webkitpy/common/checkout/diff_parser.py
new file mode 100644
index 0000000..a6ea756
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/checkout/diff_parser.py
@@ -0,0 +1,181 @@
+# 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.
+
+"""WebKit's Python module for interacting with patches."""
+
+import logging
+import re
+
+_log = logging.getLogger("webkitpy.common.checkout.diff_parser")
+
+
+# FIXME: This is broken. We should compile our regexps up-front
+# instead of using a custom cache.
+_regexp_compile_cache = {}
+
+
+# FIXME: This function should be removed.
+def match(pattern, string):
+ """Matches the string with the pattern, caching the compiled regexp."""
+ if not pattern in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = re.compile(pattern)
+ return _regexp_compile_cache[pattern].match(string)
+
+
+# FIXME: This belongs on DiffParser (e.g. as to_svn_diff()).
+def git_diff_to_svn_diff(line):
+ """Converts a git formatted diff line to a svn formatted line.
+
+ Args:
+ line: A string representing a line of the diff.
+ """
+ # FIXME: This list should be a class member on DiffParser.
+ # These regexp patterns should be compiled once instead of every time.
+ conversion_patterns = (("^diff --git \w/(.+) \w/(?P<FilePath>.+)", lambda matched: "Index: " + matched.group('FilePath') + "\n"),
+ ("^new file.*", lambda matched: "\n"),
+ ("^index [0-9a-f]{7}\.\.[0-9a-f]{7} [0-9]{6}", lambda matched: "===================================================================\n"),
+ ("^--- \w/(?P<FilePath>.+)", lambda matched: "--- " + matched.group('FilePath') + "\n"),
+ ("^\+\+\+ \w/(?P<FilePath>.+)", lambda matched: "+++ " + matched.group('FilePath') + "\n"))
+
+ for pattern, conversion in conversion_patterns:
+ matched = match(pattern, line)
+ if matched:
+ return conversion(matched)
+ return line
+
+
+# FIXME: This method belongs on DiffParser
+def get_diff_converter(first_diff_line):
+ """Gets a converter function of diff lines.
+
+ Args:
+ first_diff_line: The first filename line of a diff file.
+ If this line is git formatted, we'll return a
+ converter from git to SVN.
+ """
+ if match(r"^diff --git \w/", first_diff_line):
+ return git_diff_to_svn_diff
+ return lambda input: input
+
+
+_INITIAL_STATE = 1
+_DECLARED_FILE_PATH = 2
+_PROCESSING_CHUNK = 3
+
+
+class DiffFile(object):
+ """Contains the information for one file in a patch.
+
+ The field "lines" is a list which contains tuples in this format:
+ (deleted_line_number, new_line_number, line_string)
+ If deleted_line_number is zero, it means this line is newly added.
+ If new_line_number is zero, it means this line is deleted.
+ """
+ # FIXME: Tuples generally grow into classes. We should consider
+ # adding a DiffLine object.
+
+ def added_or_modified_line_numbers(self):
+ # This logic was moved from patchreader.py, but may not be
+ # the right API for this object long-term.
+ return [line[1] for line in self.lines if not line[0]]
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.lines = []
+
+ def add_new_line(self, line_number, line):
+ self.lines.append((0, line_number, line))
+
+ def add_deleted_line(self, line_number, line):
+ self.lines.append((line_number, 0, line))
+
+ def add_unchanged_line(self, deleted_line_number, new_line_number, line):
+ self.lines.append((deleted_line_number, new_line_number, line))
+
+
+class DiffParser(object):
+ """A parser for a patch file.
+
+ The field "files" is a dict whose key is the filename and value is
+ a DiffFile object.
+ """
+
+ # FIXME: This function is way too long and needs to be broken up.
+ def __init__(self, diff_input):
+ """Parses a diff.
+
+ Args:
+ diff_input: An iterable object.
+ """
+ state = _INITIAL_STATE
+
+ self.files = {}
+ current_file = None
+ old_diff_line = None
+ new_diff_line = None
+ for line in diff_input:
+ line = line.rstrip("\n")
+ if state == _INITIAL_STATE:
+ transform_line = get_diff_converter(line)
+ line = transform_line(line)
+
+ file_declaration = match(r"^Index: (?P<FilePath>.+)", line)
+ if file_declaration:
+ filename = file_declaration.group('FilePath')
+ current_file = DiffFile(filename)
+ self.files[filename] = current_file
+ state = _DECLARED_FILE_PATH
+ continue
+
+ lines_changed = match(r"^@@ -(?P<OldStartLine>\d+)(,\d+)? \+(?P<NewStartLine>\d+)(,\d+)? @@", line)
+ if lines_changed:
+ if state != _DECLARED_FILE_PATH and state != _PROCESSING_CHUNK:
+ _log.error('Unexpected line change without file path '
+ 'declaration: %r' % line)
+ old_diff_line = int(lines_changed.group('OldStartLine'))
+ new_diff_line = int(lines_changed.group('NewStartLine'))
+ state = _PROCESSING_CHUNK
+ continue
+
+ if state == _PROCESSING_CHUNK:
+ if line.startswith('+'):
+ current_file.add_new_line(new_diff_line, line[1:])
+ new_diff_line += 1
+ elif line.startswith('-'):
+ current_file.add_deleted_line(old_diff_line, line[1:])
+ old_diff_line += 1
+ elif line.startswith(' '):
+ current_file.add_unchanged_line(old_diff_line, new_diff_line, line[1:])
+ old_diff_line += 1
+ new_diff_line += 1
+ elif line == '\\ No newline at end of file':
+ # Nothing to do. We may still have some added lines.
+ pass
+ else:
+ _log.error('Unexpected diff format when parsing a '
+ 'chunk: %r' % line)
diff --git a/Tools/Scripts/webkitpy/common/checkout/diff_parser_unittest.py b/Tools/Scripts/webkitpy/common/checkout/diff_parser_unittest.py
new file mode 100644
index 0000000..7eb0eab
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/checkout/diff_parser_unittest.py
@@ -0,0 +1,146 @@
+# 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 unittest
+import diff_parser
+import re
+
+
+class DiffParserTest(unittest.TestCase):
+
+ _PATCH = '''diff --git a/WebCore/rendering/style/StyleFlexibleBoxData.h b/WebCore/rendering/style/StyleFlexibleBoxData.h
+index f5d5e74..3b6aa92 100644
+--- a/WebCore/rendering/style/StyleFlexibleBoxData.h
++++ b/WebCore/rendering/style/StyleFlexibleBoxData.h
+@@ -47,7 +47,6 @@ public:
+
+ unsigned align : 3; // EBoxAlignment
+ unsigned pack: 3; // EBoxAlignment
+- unsigned orient: 1; // EBoxOrient
+ unsigned lines : 1; // EBoxLines
+
+ private:
+diff --git a/WebCore/rendering/style/StyleRareInheritedData.cpp b/WebCore/rendering/style/StyleRareInheritedData.cpp
+index ce21720..324929e 100644
+--- a/WebCore/rendering/style/StyleRareInheritedData.cpp
++++ b/WebCore/rendering/style/StyleRareInheritedData.cpp
+@@ -39,6 +39,7 @@ StyleRareInheritedData::StyleRareInheritedData()
+ , textSizeAdjust(RenderStyle::initialTextSizeAdjust())
+ , resize(RenderStyle::initialResize())
+ , userSelect(RenderStyle::initialUserSelect())
++ , boxOrient(RenderStyle::initialBoxOrient())
+ {
+ }
+
+@@ -58,6 +59,7 @@ StyleRareInheritedData::StyleRareInheritedData(const StyleRareInheritedData& o)
+ , textSizeAdjust(o.textSizeAdjust)
+ , resize(o.resize)
+ , userSelect(o.userSelect)
++ , boxOrient(o.boxOrient)
+ {
+ }
+
+@@ -81,7 +83,8 @@ bool StyleRareInheritedData::operator==(const StyleRareInheritedData& o) const
+ && khtmlLineBreak == o.khtmlLineBreak
+ && textSizeAdjust == o.textSizeAdjust
+ && resize == o.resize
+- && userSelect == o.userSelect;
++ && userSelect == o.userSelect
++ && boxOrient == o.boxOrient;
+ }
+
+ bool StyleRareInheritedData::shadowDataEquivalent(const StyleRareInheritedData& o) const
+diff --git a/LayoutTests/platform/mac/fast/flexbox/box-orient-button-expected.checksum b/LayoutTests/platform/mac/fast/flexbox/box-orient-button-expected.checksum
+new file mode 100644
+index 0000000..6db26bd
+--- /dev/null
++++ b/LayoutTests/platform/mac/fast/flexbox/box-orient-button-expected.checksum
+@@ -0,0 +1 @@
++61a373ee739673a9dcd7bac62b9f182e
+\ No newline at end of file
+'''
+
+ def test_diff_parser(self, parser = None):
+ if not parser:
+ parser = diff_parser.DiffParser(self._PATCH.splitlines())
+ self.assertEquals(3, len(parser.files))
+
+ self.assertTrue('WebCore/rendering/style/StyleFlexibleBoxData.h' in parser.files)
+ diff = parser.files['WebCore/rendering/style/StyleFlexibleBoxData.h']
+ self.assertEquals(7, len(diff.lines))
+ # The first two unchaged lines.
+ self.assertEquals((47, 47), diff.lines[0][0:2])
+ self.assertEquals('', diff.lines[0][2])
+ self.assertEquals((48, 48), diff.lines[1][0:2])
+ self.assertEquals(' unsigned align : 3; // EBoxAlignment', diff.lines[1][2])
+ # The deleted line
+ self.assertEquals((50, 0), diff.lines[3][0:2])
+ self.assertEquals(' unsigned orient: 1; // EBoxOrient', diff.lines[3][2])
+
+ # The first file looks OK. Let's check the next, more complicated file.
+ self.assertTrue('WebCore/rendering/style/StyleRareInheritedData.cpp' in parser.files)
+ diff = parser.files['WebCore/rendering/style/StyleRareInheritedData.cpp']
+ # There are 3 chunks.
+ self.assertEquals(7 + 7 + 9, len(diff.lines))
+ # Around an added line.
+ self.assertEquals((60, 61), diff.lines[9][0:2])
+ self.assertEquals((0, 62), diff.lines[10][0:2])
+ self.assertEquals((61, 63), diff.lines[11][0:2])
+ # Look through the last chunk, which contains both add's and delete's.
+ self.assertEquals((81, 83), diff.lines[14][0:2])
+ self.assertEquals((82, 84), diff.lines[15][0:2])
+ self.assertEquals((83, 85), diff.lines[16][0:2])
+ self.assertEquals((84, 0), diff.lines[17][0:2])
+ self.assertEquals((0, 86), diff.lines[18][0:2])
+ self.assertEquals((0, 87), diff.lines[19][0:2])
+ self.assertEquals((85, 88), diff.lines[20][0:2])
+ self.assertEquals((86, 89), diff.lines[21][0:2])
+ self.assertEquals((87, 90), diff.lines[22][0:2])
+
+ # Check if a newly added file is correctly handled.
+ diff = parser.files['LayoutTests/platform/mac/fast/flexbox/box-orient-button-expected.checksum']
+ self.assertEquals(1, len(diff.lines))
+ self.assertEquals((0, 1), diff.lines[0][0:2])
+
+ def test_git_mnemonicprefix(self):
+ p = re.compile(r' ([a|b])/')
+
+ prefixes = [
+ { 'a' : 'i', 'b' : 'w' }, # git-diff (compares the (i)ndex and the (w)ork tree)
+ { 'a' : 'c', 'b' : 'w' }, # git-diff HEAD (compares a (c)ommit and the (w)ork tree)
+ { 'a' : 'c', 'b' : 'i' }, # git diff --cached (compares a (c)ommit and the (i)ndex)
+ { 'a' : 'o', 'b' : 'w' }, # git-diff HEAD:file1 file2 (compares an (o)bject and a (w)ork tree entity)
+ { 'a' : '1', 'b' : '2' }, # git diff --no-index a b (compares two non-git things (1) and (2))
+ ]
+
+ for prefix in prefixes:
+ patch = p.sub(lambda x: " %s/" % prefix[x.group(1)], self._PATCH)
+ self.test_diff_parser(diff_parser.DiffParser(patch.splitlines()))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/checkout/scm.py b/Tools/Scripts/webkitpy/common/checkout/scm.py
new file mode 100644
index 0000000..c54fb42
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/checkout/scm.py
@@ -0,0 +1,941 @@
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# 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:
+#
+# * 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.
+#
+# Python module for interacting with an SCM system (like SVN or Git)
+
+import os
+import re
+import sys
+import shutil
+
+from webkitpy.common.system.executive import Executive, run_command, ScriptError
+from webkitpy.common.system.deprecated_logging import error, log
+from webkitpy.common.memoized import memoized
+
+
+def find_checkout_root():
+ """Returns the current checkout root (as determined by default_scm().
+
+ Returns the absolute path to the top of the WebKit checkout, or None
+ if it cannot be determined.
+
+ """
+ scm_system = default_scm()
+ if scm_system:
+ return scm_system.checkout_root
+ return None
+
+
+def default_scm():
+ """Return the default SCM object as determined by the CWD and running code.
+
+ Returns the default SCM object for the current working directory; if the
+ CWD is not in a checkout, then we attempt to figure out if the SCM module
+ itself is part of a checkout, and return that one. If neither is part of
+ a checkout, None is returned.
+
+ """
+ cwd = os.getcwd()
+ scm_system = detect_scm_system(cwd)
+ if not scm_system:
+ script_directory = os.path.dirname(os.path.abspath(__file__))
+ scm_system = detect_scm_system(script_directory)
+ if scm_system:
+ log("The current directory (%s) is not a WebKit checkout, using %s" % (cwd, scm_system.checkout_root))
+ else:
+ error("FATAL: Failed to determine the SCM system for either %s or %s" % (cwd, script_directory))
+ return scm_system
+
+
+def detect_scm_system(path):
+ absolute_path = os.path.abspath(path)
+
+ if SVN.in_working_directory(absolute_path):
+ return SVN(cwd=absolute_path)
+
+ if Git.in_working_directory(absolute_path):
+ return Git(cwd=absolute_path)
+
+ return None
+
+
+def first_non_empty_line_after_index(lines, index=0):
+ first_non_empty_line = index
+ for line in lines[index:]:
+ if re.match("^\s*$", line):
+ first_non_empty_line += 1
+ else:
+ break
+ return first_non_empty_line
+
+
+class CommitMessage:
+ def __init__(self, message):
+ self.message_lines = message[first_non_empty_line_after_index(message, 0):]
+
+ def body(self, lstrip=False):
+ lines = self.message_lines[first_non_empty_line_after_index(self.message_lines, 1):]
+ if lstrip:
+ lines = [line.lstrip() for line in lines]
+ return "\n".join(lines) + "\n"
+
+ def description(self, lstrip=False, strip_url=False):
+ line = self.message_lines[0]
+ if lstrip:
+ line = line.lstrip()
+ if strip_url:
+ line = re.sub("^(\s*)<.+> ", "\1", line)
+ return line
+
+ def message(self):
+ return "\n".join(self.message_lines) + "\n"
+
+
+class CheckoutNeedsUpdate(ScriptError):
+ def __init__(self, script_args, exit_code, output, cwd):
+ ScriptError.__init__(self, script_args=script_args, exit_code=exit_code, output=output, cwd=cwd)
+
+
+def commit_error_handler(error):
+ if re.search("resource out of date", error.output):
+ raise CheckoutNeedsUpdate(script_args=error.script_args, exit_code=error.exit_code, output=error.output, cwd=error.cwd)
+ Executive.default_error_handler(error)
+
+
+class AuthenticationError(Exception):
+ def __init__(self, server_host):
+ self.server_host = server_host
+
+
+class AmbiguousCommitError(Exception):
+ def __init__(self, num_local_commits, working_directory_is_clean):
+ self.num_local_commits = num_local_commits
+ self.working_directory_is_clean = working_directory_is_clean
+
+
+# SCM methods are expected to return paths relative to self.checkout_root.
+class SCM:
+ def __init__(self, cwd):
+ self.cwd = cwd
+ self.checkout_root = self.find_checkout_root(self.cwd)
+ self.dryrun = False
+
+ # A wrapper used by subclasses to create processes.
+ def run(self, args, cwd=None, input=None, error_handler=None, return_exit_code=False, return_stderr=True, decode_output=True):
+ # FIXME: We should set cwd appropriately.
+ # FIXME: We should use Executive.
+ return run_command(args,
+ cwd=cwd,
+ input=input,
+ error_handler=error_handler,
+ return_exit_code=return_exit_code,
+ return_stderr=return_stderr,
+ decode_output=decode_output)
+
+ # SCM always returns repository relative path, but sometimes we need
+ # absolute paths to pass to rm, etc.
+ def absolute_path(self, repository_relative_path):
+ return os.path.join(self.checkout_root, repository_relative_path)
+
+ # FIXME: This belongs in Checkout, not SCM.
+ def scripts_directory(self):
+ return os.path.join(self.checkout_root, "Tools", "Scripts")
+
+ # FIXME: This belongs in Checkout, not SCM.
+ def script_path(self, script_name):
+ return os.path.join(self.scripts_directory(), script_name)
+
+ def ensure_clean_working_directory(self, force_clean):
+ if not force_clean and not self.working_directory_is_clean():
+ # FIXME: Shouldn't this use cwd=self.checkout_root?
+ print self.run(self.status_command(), error_handler=Executive.ignore_error)
+ raise ScriptError(message="Working directory has modifications, pass --force-clean or --no-clean to continue.")
+
+ log("Cleaning working directory")
+ self.clean_working_directory()
+
+ def ensure_no_local_commits(self, force):
+ if not self.supports_local_commits():
+ return
+ commits = self.local_commits()
+ if not len(commits):
+ return
+ if not force:
+ error("Working directory has local commits, pass --force-clean to continue.")
+ self.discard_local_commits()
+
+ def run_status_and_extract_filenames(self, status_command, status_regexp):
+ filenames = []
+ # We run with cwd=self.checkout_root so that returned-paths are root-relative.
+ for line in self.run(status_command, cwd=self.checkout_root).splitlines():
+ match = re.search(status_regexp, line)
+ if not match:
+ continue
+ # status = match.group('status')
+ filename = match.group('filename')
+ filenames.append(filename)
+ return filenames
+
+ def strip_r_from_svn_revision(self, svn_revision):
+ match = re.match("^r(?P<svn_revision>\d+)", unicode(svn_revision))
+ if (match):
+ return match.group('svn_revision')
+ return svn_revision
+
+ def svn_revision_from_commit_text(self, commit_text):
+ match = re.search(self.commit_success_regexp(), commit_text, re.MULTILINE)
+ return match.group('svn_revision')
+
+ @staticmethod
+ def _subclass_must_implement():
+ raise NotImplementedError("subclasses must implement")
+
+ @staticmethod
+ def in_working_directory(path):
+ SCM._subclass_must_implement()
+
+ @staticmethod
+ def find_checkout_root(path):
+ SCM._subclass_must_implement()
+
+ @staticmethod
+ def commit_success_regexp():
+ SCM._subclass_must_implement()
+
+ def working_directory_is_clean(self):
+ self._subclass_must_implement()
+
+ def clean_working_directory(self):
+ self._subclass_must_implement()
+
+ def status_command(self):
+ self._subclass_must_implement()
+
+ def add(self, path, return_exit_code=False):
+ self._subclass_must_implement()
+
+ def delete(self, path):
+ self._subclass_must_implement()
+
+ def changed_files(self, git_commit=None):
+ self._subclass_must_implement()
+
+ def changed_files_for_revision(self, revision):
+ self._subclass_must_implement()
+
+ def revisions_changing_file(self, path, limit=5):
+ self._subclass_must_implement()
+
+ def added_files(self):
+ self._subclass_must_implement()
+
+ def conflicted_files(self):
+ self._subclass_must_implement()
+
+ def display_name(self):
+ self._subclass_must_implement()
+
+ def create_patch(self, git_commit=None, changed_files=[]):
+ self._subclass_must_implement()
+
+ def committer_email_for_revision(self, revision):
+ self._subclass_must_implement()
+
+ def contents_at_revision(self, path, revision):
+ self._subclass_must_implement()
+
+ def diff_for_revision(self, revision):
+ self._subclass_must_implement()
+
+ def diff_for_file(self, path, log=None):
+ self._subclass_must_implement()
+
+ def show_head(self, path):
+ self._subclass_must_implement()
+
+ def apply_reverse_diff(self, revision):
+ self._subclass_must_implement()
+
+ def revert_files(self, file_paths):
+ self._subclass_must_implement()
+
+ def commit_with_message(self, message, username=None, git_commit=None, force_squash=False):
+ self._subclass_must_implement()
+
+ def svn_commit_log(self, svn_revision):
+ self._subclass_must_implement()
+
+ def last_svn_commit_log(self):
+ self._subclass_must_implement()
+
+ # Subclasses must indicate if they support local commits,
+ # but the SCM baseclass will only call local_commits methods when this is true.
+ @staticmethod
+ def supports_local_commits():
+ SCM._subclass_must_implement()
+
+ def remote_merge_base():
+ SCM._subclass_must_implement()
+
+ def commit_locally_with_message(self, message):
+ error("Your source control manager does not support local commits.")
+
+ def discard_local_commits(self):
+ pass
+
+ def local_commits(self):
+ return []
+
+
+class SVN(SCM):
+ # FIXME: We should move these values to a WebKit-specific config. file.
+ svn_server_host = "svn.webkit.org"
+ svn_server_realm = "<http://svn.webkit.org:80> Mac OS Forge"
+
+ def __init__(self, cwd):
+ SCM.__init__(self, cwd)
+ self._bogus_dir = None
+
+ @staticmethod
+ def in_working_directory(path):
+ return os.path.isdir(os.path.join(path, '.svn'))
+
+ @classmethod
+ def find_uuid(cls, path):
+ if not cls.in_working_directory(path):
+ return None
+ return cls.value_from_svn_info(path, 'Repository UUID')
+
+ @classmethod
+ def value_from_svn_info(cls, path, field_name):
+ svn_info_args = ['svn', 'info', path]
+ info_output = run_command(svn_info_args).rstrip()
+ match = re.search("^%s: (?P<value>.+)$" % field_name, info_output, re.MULTILINE)
+ if not match:
+ raise ScriptError(script_args=svn_info_args, message='svn info did not contain a %s.' % field_name)
+ return match.group('value')
+
+ @staticmethod
+ def find_checkout_root(path):
+ uuid = SVN.find_uuid(path)
+ # If |path| is not in a working directory, we're supposed to return |path|.
+ if not uuid:
+ return path
+ # Search up the directory hierarchy until we find a different UUID.
+ last_path = None
+ while True:
+ if uuid != SVN.find_uuid(path):
+ return last_path
+ last_path = path
+ (path, last_component) = os.path.split(path)
+ if last_path == path:
+ return None
+
+ @staticmethod
+ def commit_success_regexp():
+ return "^Committed revision (?P<svn_revision>\d+)\.$"
+
+ def has_authorization_for_realm(self, realm=svn_server_realm, home_directory=os.getenv("HOME")):
+ # Assumes find and grep are installed.
+ if not os.path.isdir(os.path.join(home_directory, ".subversion")):
+ return False
+ find_args = ["find", ".subversion", "-type", "f", "-exec", "grep", "-q", realm, "{}", ";", "-print"];
+ find_output = self.run(find_args, cwd=home_directory, error_handler=Executive.ignore_error).rstrip()
+ return find_output and os.path.isfile(os.path.join(home_directory, find_output))
+
+ @memoized
+ def svn_version(self):
+ return self.run(['svn', '--version', '--quiet'])
+
+ def working_directory_is_clean(self):
+ return self.run(["svn", "diff"], cwd=self.checkout_root, decode_output=False) == ""
+
+ def clean_working_directory(self):
+ # Make sure there are no locks lying around from a previously aborted svn invocation.
+ # This is slightly dangerous, as it's possible the user is running another svn process
+ # on this checkout at the same time. However, it's much more likely that we're running
+ # under windows and svn just sucks (or the user interrupted svn and it failed to clean up).
+ self.run(["svn", "cleanup"], cwd=self.checkout_root)
+
+ # svn revert -R is not as awesome as git reset --hard.
+ # It will leave added files around, causing later svn update
+ # calls to fail on the bots. We make this mirror git reset --hard
+ # by deleting any added files as well.
+ added_files = reversed(sorted(self.added_files()))
+ # added_files() returns directories for SVN, we walk the files in reverse path
+ # length order so that we remove files before we try to remove the directories.
+ self.run(["svn", "revert", "-R", "."], cwd=self.checkout_root)
+ for path in added_files:
+ # This is robust against cwd != self.checkout_root
+ absolute_path = self.absolute_path(path)
+ # Completely lame that there is no easy way to remove both types with one call.
+ if os.path.isdir(path):
+ os.rmdir(absolute_path)
+ else:
+ os.remove(absolute_path)
+
+ def status_command(self):
+ return ['svn', 'status']
+
+ def _status_regexp(self, expected_types):
+ field_count = 6 if self.svn_version() > "1.6" else 5
+ return "^(?P<status>[%s]).{%s} (?P<filename>.+)$" % (expected_types, field_count)
+
+ def _add_parent_directories(self, path):
+ """Does 'svn add' to the path and its parents."""
+ if self.in_working_directory(path):
+ return
+ dirname = os.path.dirname(path)
+ # We have dirname directry - ensure it added.
+ if dirname != path:
+ self._add_parent_directories(dirname)
+ self.add(path)
+
+ def add(self, path, return_exit_code=False):
+ self._add_parent_directories(os.path.dirname(os.path.abspath(path)))
+ return self.run(["svn", "add", path], return_exit_code=return_exit_code)
+
+ def delete(self, path):
+ parent, base = os.path.split(os.path.abspath(path))
+ return self.run(["svn", "delete", "--force", base], cwd=parent)
+
+ def changed_files(self, git_commit=None):
+ return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("ACDMR"))
+
+ def changed_files_for_revision(self, revision):
+ # As far as I can tell svn diff --summarize output looks just like svn status output.
+ # No file contents printed, thus utf-8 auto-decoding in self.run is fine.
+ status_command = ["svn", "diff", "--summarize", "-c", revision]
+ return self.run_status_and_extract_filenames(status_command, self._status_regexp("ACDMR"))
+
+ def revisions_changing_file(self, path, limit=5):
+ revisions = []
+ # svn log will exit(1) (and thus self.run will raise) if the path does not exist.
+ log_command = ['svn', 'log', '--quiet', '--limit=%s' % limit, path]
+ for line in self.run(log_command, cwd=self.checkout_root).splitlines():
+ match = re.search('^r(?P<revision>\d+) ', line)
+ if not match:
+ continue
+ revisions.append(int(match.group('revision')))
+ return revisions
+
+ def conflicted_files(self):
+ return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("C"))
+
+ def added_files(self):
+ return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("A"))
+
+ def deleted_files(self):
+ return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("D"))
+
+ @staticmethod
+ def supports_local_commits():
+ return False
+
+ def display_name(self):
+ return "svn"
+
+ # FIXME: This method should be on Checkout.
+ def create_patch(self, git_commit=None, changed_files=[]):
+ """Returns a byte array (str()) representing the patch file.
+ Patch files are effectively binary since they may contain
+ files of multiple different encodings."""
+ return self.run([self.script_path("svn-create-patch")] + changed_files,
+ cwd=self.checkout_root, return_stderr=False,
+ decode_output=False)
+
+ def committer_email_for_revision(self, revision):
+ return self.run(["svn", "propget", "svn:author", "--revprop", "-r", revision]).rstrip()
+
+ def contents_at_revision(self, path, revision):
+ """Returns a byte array (str()) containing the contents
+ of path @ revision in the repository."""
+ remote_path = "%s/%s" % (self._repository_url(), path)
+ return self.run(["svn", "cat", "-r", revision, remote_path], decode_output=False)
+
+ def diff_for_revision(self, revision):
+ # FIXME: This should probably use cwd=self.checkout_root
+ return self.run(['svn', 'diff', '-c', revision])
+
+ def _bogus_dir_name(self):
+ if sys.platform.startswith("win"):
+ parent_dir = tempfile.gettempdir()
+ else:
+ parent_dir = sys.path[0] # tempdir is not secure.
+ return os.path.join(parent_dir, "temp_svn_config")
+
+ def _setup_bogus_dir(self, log):
+ self._bogus_dir = self._bogus_dir_name()
+ if not os.path.exists(self._bogus_dir):
+ os.mkdir(self._bogus_dir)
+ self._delete_bogus_dir = True
+ else:
+ self._delete_bogus_dir = False
+ if log:
+ log.debug(' Html: temp config dir: "%s".', self._bogus_dir)
+
+ def _teardown_bogus_dir(self, log):
+ if self._delete_bogus_dir:
+ shutil.rmtree(self._bogus_dir, True)
+ if log:
+ log.debug(' Html: removed temp config dir: "%s".', self._bogus_dir)
+ self._bogus_dir = None
+
+ def diff_for_file(self, path, log=None):
+ self._setup_bogus_dir(log)
+ try:
+ args = ['svn', 'diff']
+ if self._bogus_dir:
+ args += ['--config-dir', self._bogus_dir]
+ args.append(path)
+ return self.run(args)
+ finally:
+ self._teardown_bogus_dir(log)
+
+ def show_head(self, path):
+ return self.run(['svn', 'cat', '-r', 'BASE', path], decode_output=False)
+
+ def _repository_url(self):
+ return self.value_from_svn_info(self.checkout_root, 'URL')
+
+ def apply_reverse_diff(self, revision):
+ # '-c -revision' applies the inverse diff of 'revision'
+ svn_merge_args = ['svn', 'merge', '--non-interactive', '-c', '-%s' % revision, self._repository_url()]
+ log("WARNING: svn merge has been known to take more than 10 minutes to complete. It is recommended you use git for rollouts.")
+ log("Running '%s'" % " ".join(svn_merge_args))
+ # FIXME: Should this use cwd=self.checkout_root?
+ self.run(svn_merge_args)
+
+ def revert_files(self, file_paths):
+ # FIXME: This should probably use cwd=self.checkout_root.
+ self.run(['svn', 'revert'] + file_paths)
+
+ def commit_with_message(self, message, username=None, git_commit=None, force_squash=False):
+ # git-commit and force are not used by SVN.
+ if self.dryrun:
+ # Return a string which looks like a commit so that things which parse this output will succeed.
+ return "Dry run, no commit.\nCommitted revision 0."
+
+ svn_commit_args = ["svn", "commit"]
+
+ if not username and not self.has_authorization_for_realm():
+ raise AuthenticationError(self.svn_server_host)
+ if username:
+ svn_commit_args.extend(["--username", username])
+
+ svn_commit_args.extend(["-m", message])
+ # FIXME: Should this use cwd=self.checkout_root?
+ return self.run(svn_commit_args, error_handler=commit_error_handler)
+
+ def svn_commit_log(self, svn_revision):
+ svn_revision = self.strip_r_from_svn_revision(svn_revision)
+ return self.run(['svn', 'log', '--non-interactive', '--revision', svn_revision])
+
+ def last_svn_commit_log(self):
+ # BASE is the checkout revision, HEAD is the remote repository revision
+ # http://svnbook.red-bean.com/en/1.0/ch03s03.html
+ return self.svn_commit_log('BASE')
+
+ def propset(self, pname, pvalue, path):
+ dir, base = os.path.split(path)
+ return self.run(['svn', 'pset', pname, pvalue, base], cwd=dir)
+
+ def propget(self, pname, path):
+ dir, base = os.path.split(path)
+ return self.run(['svn', 'pget', pname, base], cwd=dir).encode('utf-8').rstrip("\n")
+
+
+# All git-specific logic should go here.
+class Git(SCM):
+ def __init__(self, cwd):
+ SCM.__init__(self, cwd)
+ self._check_git_architecture()
+
+ def _machine_is_64bit(self):
+ import platform
+ # This only is tested on Mac.
+ if not platform.mac_ver()[0]:
+ return False
+
+ # platform.architecture()[0] can be '64bit' even if the machine is 32bit:
+ # http://mail.python.org/pipermail/pythonmac-sig/2009-September/021648.html
+ # Use the sysctl command to find out what the processor actually supports.
+ return self.run(['sysctl', '-n', 'hw.cpu64bit_capable']).rstrip() == '1'
+
+ def _executable_is_64bit(self, path):
+ # Again, platform.architecture() fails us. On my machine
+ # git_bits = platform.architecture(executable=git_path, bits='default')[0]
+ # git_bits is just 'default', meaning the call failed.
+ file_output = self.run(['file', path])
+ return re.search('x86_64', file_output)
+
+ def _check_git_architecture(self):
+ if not self._machine_is_64bit():
+ return
+
+ # We could path-search entirely in python or with
+ # which.py (http://code.google.com/p/which), but this is easier:
+ git_path = self.run(['which', 'git']).rstrip()
+ if self._executable_is_64bit(git_path):
+ return
+
+ webkit_dev_thead_url = "https://lists.webkit.org/pipermail/webkit-dev/2010-December/015249.html"
+ log("Warning: This machine is 64-bit, but the git binary (%s) does not support 64-bit.\nInstall a 64-bit git for better performance, see:\n%s\n" % (git_path, webkit_dev_thead_url))
+
+ @classmethod
+ def in_working_directory(cls, path):
+ return run_command(['git', 'rev-parse', '--is-inside-work-tree'], cwd=path, error_handler=Executive.ignore_error).rstrip() == "true"
+
+ @classmethod
+ def find_checkout_root(cls, path):
+ # "git rev-parse --show-cdup" would be another way to get to the root
+ (checkout_root, dot_git) = os.path.split(run_command(['git', 'rev-parse', '--git-dir'], cwd=(path or "./")))
+ # If we were using 2.6 # checkout_root = os.path.relpath(checkout_root, path)
+ if not os.path.isabs(checkout_root): # Sometimes git returns relative paths
+ checkout_root = os.path.join(path, checkout_root)
+ return checkout_root
+
+ @classmethod
+ def to_object_name(cls, filepath):
+ root_end_with_slash = os.path.join(cls.find_checkout_root(os.path.dirname(filepath)), '')
+ return filepath.replace(root_end_with_slash, '')
+
+ @classmethod
+ def read_git_config(cls, key):
+ # FIXME: This should probably use cwd=self.checkout_root.
+ # Pass --get-all for cases where the config has multiple values
+ return run_command(["git", "config", "--get-all", key],
+ error_handler=Executive.ignore_error).rstrip('\n')
+
+ @staticmethod
+ def commit_success_regexp():
+ return "^Committed r(?P<svn_revision>\d+)$"
+
+ def discard_local_commits(self):
+ # FIXME: This should probably use cwd=self.checkout_root
+ self.run(['git', 'reset', '--hard', self.remote_branch_ref()])
+
+ def local_commits(self):
+ # FIXME: This should probably use cwd=self.checkout_root
+ return self.run(['git', 'log', '--pretty=oneline', 'HEAD...' + self.remote_branch_ref()]).splitlines()
+
+ def rebase_in_progress(self):
+ return os.path.exists(os.path.join(self.checkout_root, '.git/rebase-apply'))
+
+ def working_directory_is_clean(self):
+ # FIXME: This should probably use cwd=self.checkout_root
+ return self.run(['git', 'diff', 'HEAD', '--name-only']) == ""
+
+ def clean_working_directory(self):
+ # FIXME: These should probably use cwd=self.checkout_root.
+ # Could run git clean here too, but that wouldn't match working_directory_is_clean
+ self.run(['git', 'reset', '--hard', 'HEAD'])
+ # Aborting rebase even though this does not match working_directory_is_clean
+ if self.rebase_in_progress():
+ self.run(['git', 'rebase', '--abort'])
+
+ def status_command(self):
+ # git status returns non-zero when there are changes, so we use git diff name --name-status HEAD instead.
+ # No file contents printed, thus utf-8 autodecoding in self.run is fine.
+ return ["git", "diff", "--name-status", "HEAD"]
+
+ def _status_regexp(self, expected_types):
+ return '^(?P<status>[%s])\t(?P<filename>.+)$' % expected_types
+
+ def add(self, path, return_exit_code=False):
+ return self.run(["git", "add", path], return_exit_code=return_exit_code)
+
+ def delete(self, path):
+ return self.run(["git", "rm", "-f", path])
+
+ def merge_base(self, git_commit):
+ if git_commit:
+ # Special-case HEAD.. to mean working-copy changes only.
+ if git_commit.upper() == 'HEAD..':
+ return 'HEAD'
+
+ if '..' not in git_commit:
+ git_commit = git_commit + "^.." + git_commit
+ return git_commit
+
+ return self.remote_merge_base()
+
+ def changed_files(self, git_commit=None):
+ status_command = ['git', 'diff', '-r', '--name-status', '-C', '-M', "--no-ext-diff", "--full-index", self.merge_base(git_commit)]
+ return self.run_status_and_extract_filenames(status_command, self._status_regexp("ADM"))
+
+ def _changes_files_for_commit(self, git_commit):
+ # --pretty="format:" makes git show not print the commit log header,
+ changed_files = self.run(["git", "show", "--pretty=format:", "--name-only", git_commit]).splitlines()
+ # instead it just prints a blank line at the top, so we skip the blank line:
+ return changed_files[1:]
+
+ def changed_files_for_revision(self, revision):
+ commit_id = self.git_commit_from_svn_revision(revision)
+ return self._changes_files_for_commit(commit_id)
+
+ def revisions_changing_file(self, path, limit=5):
+ # git rev-list head --remove-empty --limit=5 -- path would be equivalent.
+ commit_ids = self.run(["git", "log", "--remove-empty", "--pretty=format:%H", "-%s" % limit, "--", path]).splitlines()
+ return filter(lambda revision: revision, map(self.svn_revision_from_git_commit, commit_ids))
+
+ def conflicted_files(self):
+ # We do not need to pass decode_output for this diff command
+ # as we're passing --name-status which does not output any data.
+ status_command = ['git', 'diff', '--name-status', '-C', '-M', '--diff-filter=U']
+ return self.run_status_and_extract_filenames(status_command, self._status_regexp("U"))
+
+ def added_files(self):
+ return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("A"))
+
+ def deleted_files(self):
+ return self.run_status_and_extract_filenames(self.status_command(), self._status_regexp("D"))
+
+ @staticmethod
+ def supports_local_commits():
+ return True
+
+ def display_name(self):
+ return "git"
+
+ def create_patch(self, git_commit=None, changed_files=[]):
+ """Returns a byte array (str()) representing the patch file.
+ Patch files are effectively binary since they may contain
+ files of multiple different encodings."""
+ return self.run(['git', 'diff', '--binary', "--no-ext-diff", "--full-index", "-M", self.merge_base(git_commit), "--"] + changed_files, decode_output=False, cwd=self.checkout_root)
+
+ def _run_git_svn_find_rev(self, arg):
+ # git svn find-rev always exits 0, even when the revision or commit is not found.
+ return self.run(['git', 'svn', 'find-rev', arg], cwd=self.checkout_root).rstrip()
+
+ def _string_to_int_or_none(self, string):
+ try:
+ return int(string)
+ except ValueError, e:
+ return None
+
+ @memoized
+ def git_commit_from_svn_revision(self, svn_revision):
+ git_commit = self._run_git_svn_find_rev('r%s' % svn_revision)
+ if not git_commit:
+ # FIXME: Alternatively we could offer to update the checkout? Or return None?
+ raise ScriptError(message='Failed to find git commit for revision %s, your checkout likely needs an update.' % svn_revision)
+ return git_commit
+
+ @memoized
+ def svn_revision_from_git_commit(self, git_commit):
+ svn_revision = self._run_git_svn_find_rev(git_commit)
+ return self._string_to_int_or_none(svn_revision)
+
+ def contents_at_revision(self, path, revision):
+ """Returns a byte array (str()) containing the contents
+ of path @ revision in the repository."""
+ return self.run(["git", "show", "%s:%s" % (self.git_commit_from_svn_revision(revision), path)], decode_output=False)
+
+ def diff_for_revision(self, revision):
+ git_commit = self.git_commit_from_svn_revision(revision)
+ return self.create_patch(git_commit)
+
+ def diff_for_file(self, path, log=None):
+ return self.run(['git', 'diff', 'HEAD', '--', path])
+
+ def show_head(self, path):
+ return self.run(['git', 'show', 'HEAD:' + self.to_object_name(path)], decode_output=False)
+
+ def committer_email_for_revision(self, revision):
+ git_commit = self.git_commit_from_svn_revision(revision)
+ committer_email = self.run(["git", "log", "-1", "--pretty=format:%ce", git_commit])
+ # Git adds an extra @repository_hash to the end of every committer email, remove it:
+ return committer_email.rsplit("@", 1)[0]
+
+ def apply_reverse_diff(self, revision):
+ # Assume the revision is an svn revision.
+ git_commit = self.git_commit_from_svn_revision(revision)
+ # I think this will always fail due to ChangeLogs.
+ self.run(['git', 'revert', '--no-commit', git_commit], error_handler=Executive.ignore_error)
+
+ def revert_files(self, file_paths):
+ self.run(['git', 'checkout', 'HEAD'] + file_paths)
+
+ def _assert_can_squash(self, working_directory_is_clean):
+ squash = Git.read_git_config('webkit-patch.commit-should-always-squash')
+ should_squash = squash and squash.lower() == "true"
+
+ if not should_squash:
+ # Only warn if there are actually multiple commits to squash.
+ num_local_commits = len(self.local_commits())
+ if num_local_commits > 1 or (num_local_commits > 0 and not working_directory_is_clean):
+ raise AmbiguousCommitError(num_local_commits, working_directory_is_clean)
+
+ def commit_with_message(self, message, username=None, git_commit=None, force_squash=False):
+ # Username is ignored during Git commits.
+ working_directory_is_clean = self.working_directory_is_clean()
+
+ if git_commit:
+ # Special-case HEAD.. to mean working-copy changes only.
+ if git_commit.upper() == 'HEAD..':
+ if working_directory_is_clean:
+ raise ScriptError(message="The working copy is not modified. --git-commit=HEAD.. only commits working copy changes.")
+ self.commit_locally_with_message(message)
+ return self._commit_on_branch(message, 'HEAD')
+
+ # Need working directory changes to be committed so we can checkout the merge branch.
+ if not working_directory_is_clean:
+ # FIXME: webkit-patch land will modify the ChangeLogs to correct the reviewer.
+ # That will modify the working-copy and cause us to hit this error.
+ # The ChangeLog modification could be made to modify the existing local commit.
+ raise ScriptError(message="Working copy is modified. Cannot commit individual git_commits.")
+ return self._commit_on_branch(message, git_commit)
+
+ if not force_squash:
+ self._assert_can_squash(working_directory_is_clean)
+ self.run(['git', 'reset', '--soft', self.remote_merge_base()])
+ self.commit_locally_with_message(message)
+ return self.push_local_commits_to_server()
+
+ def _commit_on_branch(self, message, git_commit):
+ branch_ref = self.run(['git', 'symbolic-ref', 'HEAD']).strip()
+ branch_name = branch_ref.replace('refs/heads/', '')
+ commit_ids = self.commit_ids_from_commitish_arguments([git_commit])
+
+ # We want to squash all this branch's commits into one commit with the proper description.
+ # We do this by doing a "merge --squash" into a new commit branch, then dcommitting that.
+ MERGE_BRANCH_NAME = 'webkit-patch-land'
+ self.delete_branch(MERGE_BRANCH_NAME)
+
+ # We might be in a directory that's present in this branch but not in the
+ # trunk. Move up to the top of the tree so that git commands that expect a
+ # valid CWD won't fail after we check out the merge branch.
+ os.chdir(self.checkout_root)
+
+ # Stuff our change into the merge branch.
+ # We wrap in a try...finally block so if anything goes wrong, we clean up the branches.
+ commit_succeeded = True
+ try:
+ self.run(['git', 'checkout', '-q', '-b', MERGE_BRANCH_NAME, self.remote_branch_ref()])
+
+ for commit in commit_ids:
+ # We're on a different branch now, so convert "head" to the branch name.
+ commit = re.sub(r'(?i)head', branch_name, commit)
+ # FIXME: Once changed_files and create_patch are modified to separately handle each
+ # commit in a commit range, commit each cherry pick so they'll get dcommitted separately.
+ self.run(['git', 'cherry-pick', '--no-commit', commit])
+
+ self.run(['git', 'commit', '-m', message])
+ output = self.push_local_commits_to_server()
+ except Exception, e:
+ log("COMMIT FAILED: " + str(e))
+ output = "Commit failed."
+ commit_succeeded = False
+ finally:
+ # And then swap back to the original branch and clean up.
+ self.clean_working_directory()
+ self.run(['git', 'checkout', '-q', branch_name])
+ self.delete_branch(MERGE_BRANCH_NAME)
+
+ return output
+
+ def svn_commit_log(self, svn_revision):
+ svn_revision = self.strip_r_from_svn_revision(svn_revision)
+ return self.run(['git', 'svn', 'log', '-r', svn_revision])
+
+ def last_svn_commit_log(self):
+ return self.run(['git', 'svn', 'log', '--limit=1'])
+
+ # Git-specific methods:
+ def _branch_ref_exists(self, branch_ref):
+ return self.run(['git', 'show-ref', '--quiet', '--verify', branch_ref], return_exit_code=True) == 0
+
+ def delete_branch(self, branch_name):
+ if self._branch_ref_exists('refs/heads/' + branch_name):
+ self.run(['git', 'branch', '-D', branch_name])
+
+ def remote_merge_base(self):
+ return self.run(['git', 'merge-base', self.remote_branch_ref(), 'HEAD']).strip()
+
+ def remote_branch_ref(self):
+ # Use references so that we can avoid collisions, e.g. we don't want to operate on refs/heads/trunk if it exists.
+ remote_branch_refs = Git.read_git_config('svn-remote.svn.fetch')
+ if not remote_branch_refs:
+ remote_master_ref = 'refs/remotes/origin/master'
+ if not self._branch_ref_exists(remote_master_ref):
+ raise ScriptError(message="Can't find a branch to diff against. svn-remote.svn.fetch is not in the git config and %s does not exist" % remote_master_ref)
+ return remote_master_ref
+
+ # FIXME: What's the right behavior when there are multiple svn-remotes listed?
+ # For now, just use the first one.
+ first_remote_branch_ref = remote_branch_refs.split('\n')[0]
+ return first_remote_branch_ref.split(':')[1]
+
+ def commit_locally_with_message(self, message):
+ self.run(['git', 'commit', '--all', '-F', '-'], input=message)
+
+ def push_local_commits_to_server(self):
+ dcommit_command = ['git', 'svn', 'dcommit']
+ if self.dryrun:
+ dcommit_command.append('--dry-run')
+ output = self.run(dcommit_command, error_handler=commit_error_handler)
+ # Return a string which looks like a commit so that things which parse this output will succeed.
+ if self.dryrun:
+ output += "\nCommitted r0"
+ return output
+
+ # This function supports the following argument formats:
+ # no args : rev-list trunk..HEAD
+ # A..B : rev-list A..B
+ # A...B : error!
+ # A B : [A, B] (different from git diff, which would use "rev-list A..B")
+ def commit_ids_from_commitish_arguments(self, args):
+ if not len(args):
+ args.append('%s..HEAD' % self.remote_branch_ref())
+
+ commit_ids = []
+ for commitish in args:
+ if '...' in commitish:
+ raise ScriptError(message="'...' is not supported (found in '%s'). Did you mean '..'?" % commitish)
+ elif '..' in commitish:
+ commit_ids += reversed(self.run(['git', 'rev-list', commitish]).splitlines())
+ else:
+ # Turn single commits or branch or tag names into commit ids.
+ commit_ids += self.run(['git', 'rev-parse', '--revs-only', commitish]).splitlines()
+ return commit_ids
+
+ def commit_message_for_local_commit(self, commit_id):
+ commit_lines = self.run(['git', 'cat-file', 'commit', commit_id]).splitlines()
+
+ # Skip the git headers.
+ first_line_after_headers = 0
+ for line in commit_lines:
+ first_line_after_headers += 1
+ if line == "":
+ break
+ return CommitMessage(commit_lines[first_line_after_headers:])
+
+ def files_changed_summary_for_commit(self, commit_id):
+ return self.run(['git', 'diff-tree', '--shortstat', '--no-commit-id', commit_id])
diff --git a/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py b/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py
new file mode 100644
index 0000000..8f24beb
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/checkout/scm_unittest.py
@@ -0,0 +1,1320 @@
+# Copyright (C) 2009 Google Inc. All rights reserved.
+# 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:
+#
+# * 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.
+
+from __future__ import with_statement
+
+import base64
+import codecs
+import getpass
+import os
+import os.path
+import re
+import stat
+import sys
+import subprocess
+import tempfile
+import unittest
+import urllib
+import shutil
+
+from datetime import date
+from webkitpy.common.checkout.api import Checkout
+from webkitpy.common.checkout.scm import detect_scm_system, SCM, SVN, CheckoutNeedsUpdate, commit_error_handler, AuthenticationError, AmbiguousCommitError, find_checkout_root, default_scm
+from webkitpy.common.config.committers import Committer # FIXME: This should not be needed
+from webkitpy.common.net.bugzilla import Attachment # FIXME: This should not be needed
+from webkitpy.common.system.executive import Executive, run_command, ScriptError
+from webkitpy.common.system.outputcapture import OutputCapture
+
+# Eventually we will want to write tests which work for both scms. (like update_webkit, changed_files, etc.)
+# Perhaps through some SCMTest base-class which both SVNTest and GitTest inherit from.
+
+# FIXME: This should be unified into one of the executive.py commands!
+# Callers could use run_and_throw_if_fail(args, cwd=cwd, quiet=True)
+def run_silent(args, cwd=None):
+ # Note: Not thread safe: http://bugs.python.org/issue2320
+ process = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, cwd=cwd)
+ process.communicate() # ignore output
+ exit_code = process.wait()
+ if exit_code:
+ raise ScriptError('Failed to run "%s" exit_code: %d cwd: %s' % (args, exit_code, cwd))
+
+
+def write_into_file_at_path(file_path, contents, encoding="utf-8"):
+ if encoding:
+ with codecs.open(file_path, "w", encoding) as file:
+ file.write(contents)
+ else:
+ with open(file_path, "w") as file:
+ file.write(contents)
+
+
+def read_from_path(file_path, encoding="utf-8"):
+ with codecs.open(file_path, "r", encoding) as file:
+ return file.read()
+
+
+def _make_diff(command, *args):
+ # We use this wrapper to disable output decoding. diffs should be treated as
+ # binary files since they may include text files of multiple differnet encodings.
+ return run_command([command, "diff"] + list(args), decode_output=False)
+
+
+def _svn_diff(*args):
+ return _make_diff("svn", *args)
+
+
+def _git_diff(*args):
+ return _make_diff("git", *args)
+
+
+# Exists to share svn repository creation code between the git and svn tests
+class SVNTestRepository:
+ @classmethod
+ def _svn_add(cls, path):
+ run_command(["svn", "add", path])
+
+ @classmethod
+ def _svn_commit(cls, message):
+ run_command(["svn", "commit", "--quiet", "--message", message])
+
+ @classmethod
+ def _setup_test_commits(cls, test_object):
+ # Add some test commits
+ os.chdir(test_object.svn_checkout_path)
+
+ write_into_file_at_path("test_file", "test1")
+ cls._svn_add("test_file")
+ cls._svn_commit("initial commit")
+
+ write_into_file_at_path("test_file", "test1test2")
+ # This used to be the last commit, but doing so broke
+ # GitTest.test_apply_git_patch which use the inverse diff of the last commit.
+ # svn-apply fails to remove directories in Git, see:
+ # https://bugs.webkit.org/show_bug.cgi?id=34871
+ os.mkdir("test_dir")
+ # Slash should always be the right path separator since we use cygwin on Windows.
+ test_file3_path = "test_dir/test_file3"
+ write_into_file_at_path(test_file3_path, "third file")
+ cls._svn_add("test_dir")
+ cls._svn_commit("second commit")
+
+ write_into_file_at_path("test_file", "test1test2test3\n")
+ write_into_file_at_path("test_file2", "second file")
+ cls._svn_add("test_file2")
+ cls._svn_commit("third commit")
+
+ # This 4th commit is used to make sure that our patch file handling
+ # code correctly treats patches as binary and does not attempt to
+ # decode them assuming they're utf-8.
+ write_into_file_at_path("test_file", u"latin1 test: \u00A0\n", "latin1")
+ write_into_file_at_path("test_file2", u"utf-8 test: \u00A0\n", "utf-8")
+ cls._svn_commit("fourth commit")
+
+ # svn does not seem to update after commit as I would expect.
+ run_command(['svn', 'update'])
+
+ @classmethod
+ def setup(cls, test_object):
+ # Create an test SVN repository
+ test_object.svn_repo_path = tempfile.mkdtemp(suffix="svn_test_repo")
+ test_object.svn_repo_url = "file://%s" % test_object.svn_repo_path # Not sure this will work on windows
+ # git svn complains if we don't pass --pre-1.5-compatible, not sure why:
+ # Expected FS format '2'; found format '3' at /usr/local/libexec/git-core//git-svn line 1477
+ run_command(['svnadmin', 'create', '--pre-1.5-compatible', test_object.svn_repo_path])
+
+ # Create a test svn checkout
+ test_object.svn_checkout_path = tempfile.mkdtemp(suffix="svn_test_checkout")
+ run_command(['svn', 'checkout', '--quiet', test_object.svn_repo_url, test_object.svn_checkout_path])
+
+ # Create and checkout a trunk dir to match the standard svn configuration to match git-svn's expectations
+ os.chdir(test_object.svn_checkout_path)
+ os.mkdir('trunk')
+ cls._svn_add('trunk')
+ # We can add tags and branches as well if we ever need to test those.
+ cls._svn_commit('add trunk')
+
+ # Change directory out of the svn checkout so we can delete the checkout directory.
+ # _setup_test_commits will CD back to the svn checkout directory.
+ os.chdir('/')
+ run_command(['rm', '-rf', test_object.svn_checkout_path])
+ run_command(['svn', 'checkout', '--quiet', test_object.svn_repo_url + '/trunk', test_object.svn_checkout_path])
+
+ cls._setup_test_commits(test_object)
+
+ @classmethod
+ def tear_down(cls, test_object):
+ run_command(['rm', '-rf', test_object.svn_repo_path])
+ run_command(['rm', '-rf', test_object.svn_checkout_path])
+
+ # Now that we've deleted the checkout paths, cwddir may be invalid
+ # Change back to a valid directory so that later calls to os.getcwd() do not fail.
+ os.chdir(detect_scm_system(os.path.dirname(__file__)).checkout_root)
+
+
+class StandaloneFunctionsTest(unittest.TestCase):
+ """This class tests any standalone/top-level functions in the package."""
+ def setUp(self):
+ self.orig_cwd = os.path.abspath(os.getcwd())
+ self.orig_abspath = os.path.abspath
+
+ # We capture but ignore the output from stderr to reduce unwanted
+ # logging.
+ self.output = OutputCapture()
+ self.output.capture_output()
+
+ def tearDown(self):
+ os.chdir(self.orig_cwd)
+ os.path.abspath = self.orig_abspath
+ self.output.restore_output()
+
+ def test_find_checkout_root(self):
+ # Test from inside the tree.
+ os.chdir(sys.path[0])
+ dir = find_checkout_root()
+ self.assertNotEqual(dir, None)
+ self.assertTrue(os.path.exists(dir))
+
+ # Test from outside the tree.
+ os.chdir(os.path.expanduser("~"))
+ dir = find_checkout_root()
+ self.assertNotEqual(dir, None)
+ self.assertTrue(os.path.exists(dir))
+
+ # Mock out abspath() to test being not in a checkout at all.
+ os.path.abspath = lambda x: "/"
+ self.assertRaises(SystemExit, find_checkout_root)
+ os.path.abspath = self.orig_abspath
+
+ def test_default_scm(self):
+ # Test from inside the tree.
+ os.chdir(sys.path[0])
+ scm = default_scm()
+ self.assertNotEqual(scm, None)
+
+ # Test from outside the tree.
+ os.chdir(os.path.expanduser("~"))
+ dir = find_checkout_root()
+ self.assertNotEqual(dir, None)
+
+ # Mock out abspath() to test being not in a checkout at all.
+ os.path.abspath = lambda x: "/"
+ self.assertRaises(SystemExit, default_scm)
+ os.path.abspath = self.orig_abspath
+
+# For testing the SCM baseclass directly.
+class SCMClassTests(unittest.TestCase):
+ def setUp(self):
+ self.dev_null = open(os.devnull, "w") # Used to make our Popen calls quiet.
+
+ def tearDown(self):
+ self.dev_null.close()
+
+ def test_run_command_with_pipe(self):
+ input_process = subprocess.Popen(['echo', 'foo\nbar'], stdout=subprocess.PIPE, stderr=self.dev_null)
+ self.assertEqual(run_command(['grep', 'bar'], input=input_process.stdout), "bar\n")
+
+ # Test the non-pipe case too:
+ self.assertEqual(run_command(['grep', 'bar'], input="foo\nbar"), "bar\n")
+
+ command_returns_non_zero = ['/bin/sh', '--invalid-option']
+ # Test when the input pipe process fails.
+ input_process = subprocess.Popen(command_returns_non_zero, stdout=subprocess.PIPE, stderr=self.dev_null)
+ self.assertTrue(input_process.poll() != 0)
+ self.assertRaises(ScriptError, run_command, ['grep', 'bar'], input=input_process.stdout)
+
+ # Test when the run_command process fails.
+ input_process = subprocess.Popen(['echo', 'foo\nbar'], stdout=subprocess.PIPE, stderr=self.dev_null) # grep shows usage and calls exit(2) when called w/o arguments.
+ self.assertRaises(ScriptError, run_command, command_returns_non_zero, input=input_process.stdout)
+
+ def test_error_handlers(self):
+ git_failure_message="Merge conflict during commit: Your file or directory 'WebCore/ChangeLog' is probably out-of-date: resource out of date; try updating at /usr/local/libexec/git-core//git-svn line 469"
+ svn_failure_message="""svn: Commit failed (details follow):
+svn: File or directory 'ChangeLog' is out of date; try updating
+svn: resource out of date; try updating
+"""
+ command_does_not_exist = ['does_not_exist', 'invalid_option']
+ self.assertRaises(OSError, run_command, command_does_not_exist)
+ self.assertRaises(OSError, run_command, command_does_not_exist, error_handler=Executive.ignore_error)
+
+ command_returns_non_zero = ['/bin/sh', '--invalid-option']
+ self.assertRaises(ScriptError, run_command, command_returns_non_zero)
+ # Check if returns error text:
+ self.assertTrue(run_command(command_returns_non_zero, error_handler=Executive.ignore_error))
+
+ self.assertRaises(CheckoutNeedsUpdate, commit_error_handler, ScriptError(output=git_failure_message))
+ self.assertRaises(CheckoutNeedsUpdate, commit_error_handler, ScriptError(output=svn_failure_message))
+ self.assertRaises(ScriptError, commit_error_handler, ScriptError(output='blah blah blah'))
+
+
+# GitTest and SVNTest inherit from this so any test_ methods here will be run once for this class and then once for each subclass.
+class SCMTest(unittest.TestCase):
+ def _create_patch(self, patch_contents):
+ # FIXME: This code is brittle if the Attachment API changes.
+ attachment = Attachment({"bug_id": 12345}, None)
+ attachment.contents = lambda: patch_contents
+
+ joe_cool = Committer(name="Joe Cool", email_or_emails=None)
+ attachment.reviewer = lambda: joe_cool
+
+ return attachment
+
+ def _setup_webkittools_scripts_symlink(self, local_scm):
+ webkit_scm = detect_scm_system(os.path.dirname(os.path.abspath(__file__)))
+ webkit_scripts_directory = webkit_scm.scripts_directory()
+ local_scripts_directory = local_scm.scripts_directory()
+ os.mkdir(os.path.dirname(local_scripts_directory))
+ os.symlink(webkit_scripts_directory, local_scripts_directory)
+
+ # Tests which both GitTest and SVNTest should run.
+ # FIXME: There must be a simpler way to add these w/o adding a wrapper method to both subclasses
+
+ def _shared_test_changed_files(self):
+ write_into_file_at_path("test_file", "changed content")
+ self.assertEqual(self.scm.changed_files(), ["test_file"])
+ write_into_file_at_path("test_dir/test_file3", "new stuff")
+ self.assertEqual(self.scm.changed_files(), ["test_dir/test_file3", "test_file"])
+ old_cwd = os.getcwd()
+ os.chdir("test_dir")
+ # Validate that changed_files does not change with our cwd, see bug 37015.
+ self.assertEqual(self.scm.changed_files(), ["test_dir/test_file3", "test_file"])
+ os.chdir(old_cwd)
+
+ def _shared_test_added_files(self):
+ write_into_file_at_path("test_file", "changed content")
+ self.assertEqual(self.scm.added_files(), [])
+
+ write_into_file_at_path("added_file", "new stuff")
+ self.scm.add("added_file")
+
+ os.mkdir("added_dir")
+ write_into_file_at_path("added_dir/added_file2", "new stuff")
+ self.scm.add("added_dir")
+
+ # SVN reports directory changes, Git does not.
+ added_files = self.scm.added_files()
+ if "added_dir" in added_files:
+ added_files.remove("added_dir")
+ self.assertEqual(added_files, ["added_dir/added_file2", "added_file"])
+
+ # Test also to make sure clean_working_directory removes added files
+ self.scm.clean_working_directory()
+ self.assertEqual(self.scm.added_files(), [])
+ self.assertFalse(os.path.exists("added_file"))
+ self.assertFalse(os.path.exists("added_dir"))
+
+ def _shared_test_changed_files_for_revision(self):
+ # SVN reports directory changes, Git does not.
+ changed_files = self.scm.changed_files_for_revision(3)
+ if "test_dir" in changed_files:
+ changed_files.remove("test_dir")
+ self.assertEqual(changed_files, ["test_dir/test_file3", "test_file"])
+ self.assertEqual(sorted(self.scm.changed_files_for_revision(4)), sorted(["test_file", "test_file2"])) # Git and SVN return different orders.
+ self.assertEqual(self.scm.changed_files_for_revision(2), ["test_file"])
+
+ def _shared_test_contents_at_revision(self):
+ self.assertEqual(self.scm.contents_at_revision("test_file", 3), "test1test2")
+ self.assertEqual(self.scm.contents_at_revision("test_file", 4), "test1test2test3\n")
+
+ # Verify that contents_at_revision returns a byte array, aka str():
+ self.assertEqual(self.scm.contents_at_revision("test_file", 5), u"latin1 test: \u00A0\n".encode("latin1"))
+ self.assertEqual(self.scm.contents_at_revision("test_file2", 5), u"utf-8 test: \u00A0\n".encode("utf-8"))
+
+ self.assertEqual(self.scm.contents_at_revision("test_file2", 4), "second file")
+ # Files which don't exist:
+ # Currently we raise instead of returning None because detecting the difference between
+ # "file not found" and any other error seems impossible with svn (git seems to expose such through the return code).
+ self.assertRaises(ScriptError, self.scm.contents_at_revision, "test_file2", 2)
+ self.assertRaises(ScriptError, self.scm.contents_at_revision, "does_not_exist", 2)
+
+ def _shared_test_revisions_changing_file(self):
+ self.assertEqual(self.scm.revisions_changing_file("test_file"), [5, 4, 3, 2])
+ self.assertRaises(ScriptError, self.scm.revisions_changing_file, "non_existent_file")
+
+ def _shared_test_committer_email_for_revision(self):
+ self.assertEqual(self.scm.committer_email_for_revision(3), getpass.getuser()) # Committer "email" will be the current user
+
+ def _shared_test_reverse_diff(self):
+ self._setup_webkittools_scripts_symlink(self.scm) # Git's apply_reverse_diff uses resolve-ChangeLogs
+ # Only test the simple case, as any other will end up with conflict markers.
+ self.scm.apply_reverse_diff('5')
+ self.assertEqual(read_from_path('test_file'), "test1test2test3\n")
+
+ def _shared_test_diff_for_revision(self):
+ # Patch formats are slightly different between svn and git, so just regexp for things we know should be there.
+ r3_patch = self.scm.diff_for_revision(4)
+ self.assertTrue(re.search('test3', r3_patch))
+ self.assertFalse(re.search('test4', r3_patch))
+ self.assertTrue(re.search('test2', r3_patch))
+ self.assertTrue(re.search('test2', self.scm.diff_for_revision(3)))
+
+ def _shared_test_svn_apply_git_patch(self):
+ self._setup_webkittools_scripts_symlink(self.scm)
+ git_binary_addition = """diff --git a/fizzbuzz7.gif b/fizzbuzz7.gif
+new file mode 100644
+index 0000000000000000000000000000000000000000..64a9532e7794fcd791f6f12157406d90
+60151690
+GIT binary patch
+literal 512
+zcmZ?wbhEHbRAx|MU|?iW{Kxc~?KofD;ckY;H+&5HnHl!!GQMD7h+sU{_)e9f^V3c?
+zhJP##HdZC#4K}7F68@!1jfWQg2daCm-gs#3|JREDT>c+pG4L<_2;w##WMO#ysPPap
+zLqpAf1OE938xAsSp4!5f-o><?VKe(#0jEcwfHGF4%M1^kRs14oVBp2ZEL{E1N<-zJ
+zsfLmOtKta;2_;2c#^S1-8cf<nb!QnGl>c!Xe6RXvrEtAWBvSDTgTO1j3vA31Puw!A
+zs(87q)j_mVDTqBo-P+03-P5mHCEnJ+x}YdCuS7#bCCyePUe(ynK+|4b-3qK)T?Z&)
+zYG+`tl4h?GZv_$t82}X4*DTE|$;{DEiPyF@)U-1+FaX++T9H{&%cag`W1|zVP@`%b
+zqiSkp6{BTpWTkCr!=<C6Q=?#~R8^JfrliAF6Q^gV9Iup8RqCXqqhqC`qsyhk<-nlB
+z00f{QZvfK&|Nm#oZ0TQl`Yr$BIa6A@16O26ud7H<QM=xl`toLKnz-3h@9c9q&wm|X
+z{89I|WPyD!*M?gv?q`;L=2YFeXrJQNti4?}s!zFo=5CzeBxC69xA<zrjP<wUcCRh4
+ptUl-ZG<%a~#LwkIWv&q!KSCH7tQ8cJDiw+|GV?MN)RjY50RTb-xvT&H
+
+literal 0
+HcmV?d00001
+
+"""
+ self.checkout.apply_patch(self._create_patch(git_binary_addition))
+ added = read_from_path('fizzbuzz7.gif', encoding=None)
+ self.assertEqual(512, len(added))
+ self.assertTrue(added.startswith('GIF89a'))
+ self.assertTrue('fizzbuzz7.gif' in self.scm.changed_files())
+
+ # The file already exists.
+ self.assertRaises(ScriptError, self.checkout.apply_patch, self._create_patch(git_binary_addition))
+
+ git_binary_modification = """diff --git a/fizzbuzz7.gif b/fizzbuzz7.gif
+index 64a9532e7794fcd791f6f12157406d9060151690..323fae03f4606ea9991df8befbb2fca7
+GIT binary patch
+literal 7
+OcmYex&reD$;sO8*F9L)B
+
+literal 512
+zcmZ?wbhEHbRAx|MU|?iW{Kxc~?KofD;ckY;H+&5HnHl!!GQMD7h+sU{_)e9f^V3c?
+zhJP##HdZC#4K}7F68@!1jfWQg2daCm-gs#3|JREDT>c+pG4L<_2;w##WMO#ysPPap
+zLqpAf1OE938xAsSp4!5f-o><?VKe(#0jEcwfHGF4%M1^kRs14oVBp2ZEL{E1N<-zJ
+zsfLmOtKta;2_;2c#^S1-8cf<nb!QnGl>c!Xe6RXvrEtAWBvSDTgTO1j3vA31Puw!A
+zs(87q)j_mVDTqBo-P+03-P5mHCEnJ+x}YdCuS7#bCCyePUe(ynK+|4b-3qK)T?Z&)
+zYG+`tl4h?GZv_$t82}X4*DTE|$;{DEiPyF@)U-1+FaX++T9H{&%cag`W1|zVP@`%b
+zqiSkp6{BTpWTkCr!=<C6Q=?#~R8^JfrliAF6Q^gV9Iup8RqCXqqhqC`qsyhk<-nlB
+z00f{QZvfK&|Nm#oZ0TQl`Yr$BIa6A@16O26ud7H<QM=xl`toLKnz-3h@9c9q&wm|X
+z{89I|WPyD!*M?gv?q`;L=2YFeXrJQNti4?}s!zFo=5CzeBxC69xA<zrjP<wUcCRh4
+ptUl-ZG<%a~#LwkIWv&q!KSCH7tQ8cJDiw+|GV?MN)RjY50RTb-xvT&H
+
+"""
+ self.checkout.apply_patch(self._create_patch(git_binary_modification))
+ modified = read_from_path('fizzbuzz7.gif', encoding=None)
+ self.assertEqual('foobar\n', modified)
+ self.assertTrue('fizzbuzz7.gif' in self.scm.changed_files())
+
+ # Applying the same modification should fail.
+ self.assertRaises(ScriptError, self.checkout.apply_patch, self._create_patch(git_binary_modification))
+
+ git_binary_deletion = """diff --git a/fizzbuzz7.gif b/fizzbuzz7.gif
+deleted file mode 100644
+index 323fae0..0000000
+GIT binary patch
+literal 0
+HcmV?d00001
+
+literal 7
+OcmYex&reD$;sO8*F9L)B
+
+"""
+ self.checkout.apply_patch(self._create_patch(git_binary_deletion))
+ self.assertFalse(os.path.exists('fizzbuzz7.gif'))
+ self.assertFalse('fizzbuzz7.gif' in self.scm.changed_files())
+
+ # Cannot delete again.
+ self.assertRaises(ScriptError, self.checkout.apply_patch, self._create_patch(git_binary_deletion))
+
+ def _shared_test_add_recursively(self):
+ os.mkdir("added_dir")
+ write_into_file_at_path("added_dir/added_file", "new stuff")
+ self.scm.add("added_dir/added_file")
+ self.assertTrue("added_dir/added_file" in self.scm.added_files())
+
+class SVNTest(SCMTest):
+
+ @staticmethod
+ def _set_date_and_reviewer(changelog_entry):
+ # Joe Cool matches the reviewer set in SCMTest._create_patch
+ changelog_entry = changelog_entry.replace('REVIEWER_HERE', 'Joe Cool')
+ # svn-apply will update ChangeLog entries with today's date.
+ return changelog_entry.replace('DATE_HERE', date.today().isoformat())
+
+ def test_svn_apply(self):
+ first_entry = """2009-10-26 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Foo Bar.
+
+ Most awesome change ever.
+
+ * scm_unittest.py:
+"""
+ intermediate_entry = """2009-10-27 Eric Seidel <eric@webkit.org>
+
+ Reviewed by Baz Bar.
+
+ A more awesomer change yet!
+
+ * scm_unittest.py:
+"""
+ one_line_overlap_patch = """Index: ChangeLog
+===================================================================
+--- ChangeLog (revision 5)
++++ ChangeLog (working copy)
+@@ -1,5 +1,13 @@
+ 2009-10-26 Eric Seidel <eric@webkit.org>
+
++ Reviewed by NOBODY (OOPS!).
++
++ Second most awesome change ever.
++
++ * scm_unittest.py:
++
++2009-10-26 Eric Seidel <eric@webkit.org>
++
+ Reviewed by Foo Bar.
+
+ Most awesome change ever.
+"""
+ one_line_overlap_entry = """DATE_HERE Eric Seidel <eric@webkit.org>
+
+ Reviewed by REVIEWER_HERE.
+
+ Second most awesome change ever.
+
+ * scm_unittest.py:
+"""
+ two_line_overlap_patch = """Index: ChangeLog
+===================================================================
+--- ChangeLog (revision 5)
++++ ChangeLog (working copy)
+@@ -2,6 +2,14 @@
+
+ Reviewed by Foo Bar.
+
++ Second most awesome change ever.
++
++ * scm_unittest.py:
++
++2009-10-26 Eric Seidel <eric@webkit.org>
++
++ Reviewed by Foo Bar.
++
+ Most awesome change ever.
+
+ * scm_unittest.py:
+"""
+ two_line_overlap_entry = """DATE_HERE Eric Seidel <eric@webkit.org>
+
+ Reviewed by Foo Bar.
+
+ Second most awesome change ever.
+
+ * scm_unittest.py:
+"""
+ write_into_file_at_path('ChangeLog', first_entry)
+ run_command(['svn', 'add', 'ChangeLog'])
+ run_command(['svn', 'commit', '--quiet', '--message', 'ChangeLog commit'])
+
+ # Patch files were created against just 'first_entry'.
+ # Add a second commit to make svn-apply have to apply the patches with fuzz.
+ changelog_contents = "%s\n%s" % (intermediate_entry, first_entry)
+ write_into_file_at_path('ChangeLog', changelog_contents)
+ run_command(['svn', 'commit', '--quiet', '--message', 'Intermediate commit'])
+
+ self._setup_webkittools_scripts_symlink(self.scm)
+ self.checkout.apply_patch(self._create_patch(one_line_overlap_patch))
+ expected_changelog_contents = "%s\n%s" % (self._set_date_and_reviewer(one_line_overlap_entry), changelog_contents)
+ self.assertEquals(read_from_path('ChangeLog'), expected_changelog_contents)
+
+ self.scm.revert_files(['ChangeLog'])
+ self.checkout.apply_patch(self._create_patch(two_line_overlap_patch))
+ expected_changelog_contents = "%s\n%s" % (self._set_date_and_reviewer(two_line_overlap_entry), changelog_contents)
+ self.assertEquals(read_from_path('ChangeLog'), expected_changelog_contents)
+
+ def setUp(self):
+ SVNTestRepository.setup(self)
+ os.chdir(self.svn_checkout_path)
+ self.scm = detect_scm_system(self.svn_checkout_path)
+ # For historical reasons, we test some checkout code here too.
+ self.checkout = Checkout(self.scm)
+
+ def tearDown(self):
+ SVNTestRepository.tear_down(self)
+
+ def test_detect_scm_system_relative_url(self):
+ scm = detect_scm_system(".")
+ # I wanted to assert that we got the right path, but there was some
+ # crazy magic with temp folder names that I couldn't figure out.
+ self.assertTrue(scm.checkout_root)
+
+ def test_create_patch_is_full_patch(self):
+ test_dir_path = os.path.join(self.svn_checkout_path, "test_dir2")
+ os.mkdir(test_dir_path)
+ test_file_path = os.path.join(test_dir_path, 'test_file2')
+ write_into_file_at_path(test_file_path, 'test content')
+ run_command(['svn', 'add', 'test_dir2'])
+
+ # create_patch depends on 'svn-create-patch', so make a dummy version.
+ scripts_path = os.path.join(self.svn_checkout_path, 'Tools', 'Scripts')
+ os.makedirs(scripts_path)
+ create_patch_path = os.path.join(scripts_path, 'svn-create-patch')
+ write_into_file_at_path(create_patch_path, '#!/bin/sh\necho $PWD') # We could pass -n to prevent the \n, but not all echo accept -n.
+ os.chmod(create_patch_path, stat.S_IXUSR | stat.S_IRUSR)
+
+ # Change into our test directory and run the create_patch command.
+ os.chdir(test_dir_path)
+ scm = detect_scm_system(test_dir_path)
+ self.assertEqual(scm.checkout_root, self.svn_checkout_path) # Sanity check that detection worked right.
+ patch_contents = scm.create_patch()
+ # Our fake 'svn-create-patch' returns $PWD instead of a patch, check that it was executed from the root of the repo.
+ self.assertEqual("%s\n" % os.path.realpath(scm.checkout_root), patch_contents) # Add a \n because echo adds a \n.
+
+ def test_detection(self):
+ scm = detect_scm_system(self.svn_checkout_path)
+ self.assertEqual(scm.display_name(), "svn")
+ self.assertEqual(scm.supports_local_commits(), False)
+
+ def test_apply_small_binary_patch(self):
+ patch_contents = """Index: test_file.swf
+===================================================================
+Cannot display: file marked as a binary type.
+svn:mime-type = application/octet-stream
+
+Property changes on: test_file.swf
+___________________________________________________________________
+Name: svn:mime-type
+ + application/octet-stream
+
+
+Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==
+"""
+ expected_contents = base64.b64decode("Q1dTBx0AAAB42itg4GlgYJjGwMDDyODMxMDw34GBgQEAJPQDJA==")
+ self._setup_webkittools_scripts_symlink(self.scm)
+ patch_file = self._create_patch(patch_contents)
+ self.checkout.apply_patch(patch_file)
+ actual_contents = read_from_path("test_file.swf", encoding=None)
+ self.assertEqual(actual_contents, expected_contents)
+
+ def test_apply_svn_patch(self):
+ scm = detect_scm_system(self.svn_checkout_path)
+ patch = self._create_patch(_svn_diff("-r5:4"))
+ self._setup_webkittools_scripts_symlink(scm)
+ Checkout(scm).apply_patch(patch)
+
+ def test_apply_svn_patch_force(self):
+ scm = detect_scm_system(self.svn_checkout_path)
+ patch = self._create_patch(_svn_diff("-r3:5"))
+ self._setup_webkittools_scripts_symlink(scm)
+ self.assertRaises(ScriptError, Checkout(scm).apply_patch, patch, force=True)
+
+ def test_commit_logs(self):
+ # Commits have dates and usernames in them, so we can't just direct compare.
+ self.assertTrue(re.search('fourth commit', self.scm.last_svn_commit_log()))
+ self.assertTrue(re.search('second commit', self.scm.svn_commit_log(3)))
+
+ def _shared_test_commit_with_message(self, username=None):
+ write_into_file_at_path('test_file', 'more test content')
+ commit_text = self.scm.commit_with_message("another test commit", username)
+ self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '6')
+
+ self.scm.dryrun = True
+ write_into_file_at_path('test_file', 'still more test content')
+ commit_text = self.scm.commit_with_message("yet another test commit", username)
+ self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '0')
+
+ def test_commit_text_parsing(self):
+ self._shared_test_commit_with_message()
+
+ def test_commit_with_username(self):
+ self._shared_test_commit_with_message("dbates@webkit.org")
+
+ def test_commit_without_authorization(self):
+ self.scm.has_authorization_for_realm = lambda: False
+ self.assertRaises(AuthenticationError, self._shared_test_commit_with_message)
+
+ def test_has_authorization_for_realm(self):
+ scm = detect_scm_system(self.svn_checkout_path)
+ fake_home_dir = tempfile.mkdtemp(suffix="fake_home_dir")
+ svn_config_dir_path = os.path.join(fake_home_dir, ".subversion")
+ os.mkdir(svn_config_dir_path)
+ fake_webkit_auth_file = os.path.join(svn_config_dir_path, "fake_webkit_auth_file")
+ write_into_file_at_path(fake_webkit_auth_file, SVN.svn_server_realm)
+ self.assertTrue(scm.has_authorization_for_realm(home_directory=fake_home_dir))
+ os.remove(fake_webkit_auth_file)
+ os.rmdir(svn_config_dir_path)
+ os.rmdir(fake_home_dir)
+
+ def test_not_have_authorization_for_realm(self):
+ scm = detect_scm_system(self.svn_checkout_path)
+ fake_home_dir = tempfile.mkdtemp(suffix="fake_home_dir")
+ svn_config_dir_path = os.path.join(fake_home_dir, ".subversion")
+ os.mkdir(svn_config_dir_path)
+ self.assertFalse(scm.has_authorization_for_realm(home_directory=fake_home_dir))
+ os.rmdir(svn_config_dir_path)
+ os.rmdir(fake_home_dir)
+
+ def test_reverse_diff(self):
+ self._shared_test_reverse_diff()
+
+ def test_diff_for_revision(self):
+ self._shared_test_diff_for_revision()
+
+ def test_svn_apply_git_patch(self):
+ self._shared_test_svn_apply_git_patch()
+
+ def test_changed_files(self):
+ self._shared_test_changed_files()
+
+ def test_changed_files_for_revision(self):
+ self._shared_test_changed_files_for_revision()
+
+ def test_added_files(self):
+ self._shared_test_added_files()
+
+ def test_contents_at_revision(self):
+ self._shared_test_contents_at_revision()
+
+ def test_revisions_changing_file(self):
+ self._shared_test_revisions_changing_file()
+
+ def test_committer_email_for_revision(self):
+ self._shared_test_committer_email_for_revision()
+
+ def test_add_recursively(self):
+ self._shared_test_add_recursively()
+
+ def test_delete(self):
+ os.chdir(self.svn_checkout_path)
+ self.scm.delete("test_file")
+ self.assertTrue("test_file" in self.scm.deleted_files())
+
+ def test_propset_propget(self):
+ filepath = os.path.join(self.svn_checkout_path, "test_file")
+ expected_mime_type = "x-application/foo-bar"
+ self.scm.propset("svn:mime-type", expected_mime_type, filepath)
+ self.assertEqual(expected_mime_type, self.scm.propget("svn:mime-type", filepath))
+
+ def test_show_head(self):
+ write_into_file_at_path("test_file", u"Hello!", "utf-8")
+ SVNTestRepository._svn_commit("fourth commit")
+ self.assertEqual("Hello!", self.scm.show_head('test_file'))
+
+ def test_show_head_binary(self):
+ data = "\244"
+ write_into_file_at_path("binary_file", data, encoding=None)
+ self.scm.add("binary_file")
+ self.scm.commit_with_message("a test commit")
+ self.assertEqual(data, self.scm.show_head('binary_file'))
+
+ def do_test_diff_for_file(self):
+ write_into_file_at_path('test_file', 'some content')
+ self.scm.commit_with_message("a test commit")
+ diff = self.scm.diff_for_file('test_file')
+ self.assertEqual(diff, "")
+
+ write_into_file_at_path("test_file", "changed content")
+ diff = self.scm.diff_for_file('test_file')
+ self.assertTrue("-some content" in diff)
+ self.assertTrue("+changed content" in diff)
+
+ def clean_bogus_dir(self):
+ self.bogus_dir = self.scm._bogus_dir_name()
+ if os.path.exists(self.bogus_dir):
+ shutil.rmtree(self.bogus_dir)
+
+ def test_diff_for_file_with_existing_bogus_dir(self):
+ self.clean_bogus_dir()
+ os.mkdir(self.bogus_dir)
+ self.do_test_diff_for_file()
+ self.assertTrue(os.path.exists(self.bogus_dir))
+ shutil.rmtree(self.bogus_dir)
+
+ def test_diff_for_file_with_missing_bogus_dir(self):
+ self.clean_bogus_dir()
+ self.do_test_diff_for_file()
+ self.assertFalse(os.path.exists(self.bogus_dir))
+
+ def test_svn_lock(self):
+ svn_root_lock_path = ".svn/lock"
+ write_into_file_at_path(svn_root_lock_path, "", "utf-8")
+ # webkit-patch uses a Checkout object and runs update-webkit, just use svn update here.
+ self.assertRaises(ScriptError, run_command, ['svn', 'update'])
+ self.scm.clean_working_directory()
+ self.assertFalse(os.path.exists(svn_root_lock_path))
+ run_command(['svn', 'update']) # Should succeed and not raise.
+
+
+class GitTest(SCMTest):
+
+ def setUp(self):
+ """Sets up fresh git repository with one commit. Then setups a second git
+ repo that tracks the first one."""
+ self.original_dir = os.getcwd()
+
+ self.untracking_checkout_path = tempfile.mkdtemp(suffix="git_test_checkout2")
+ run_command(['git', 'init', self.untracking_checkout_path])
+
+ os.chdir(self.untracking_checkout_path)
+ write_into_file_at_path('foo_file', 'foo')
+ run_command(['git', 'add', 'foo_file'])
+ run_command(['git', 'commit', '-am', 'dummy commit'])
+ self.untracking_scm = detect_scm_system(self.untracking_checkout_path)
+
+ self.tracking_git_checkout_path = tempfile.mkdtemp(suffix="git_test_checkout")
+ run_command(['git', 'clone', '--quiet', self.untracking_checkout_path, self.tracking_git_checkout_path])
+ os.chdir(self.tracking_git_checkout_path)
+ self.tracking_scm = detect_scm_system(self.tracking_git_checkout_path)
+
+ def tearDown(self):
+ # Change back to a valid directory so that later calls to os.getcwd() do not fail.
+ os.chdir(self.original_dir)
+ run_command(['rm', '-rf', self.tracking_git_checkout_path])
+ run_command(['rm', '-rf', self.untracking_checkout_path])
+
+ def test_remote_branch_ref(self):
+ self.assertEqual(self.tracking_scm.remote_branch_ref(), 'refs/remotes/origin/master')
+
+ os.chdir(self.untracking_checkout_path)
+ self.assertRaises(ScriptError, self.untracking_scm.remote_branch_ref)
+
+ def test_multiple_remotes(self):
+ run_command(['git', 'config', '--add', 'svn-remote.svn.fetch', 'trunk:remote1'])
+ run_command(['git', 'config', '--add', 'svn-remote.svn.fetch', 'trunk:remote2'])
+ self.assertEqual(self.tracking_scm.remote_branch_ref(), 'remote1')
+
+class GitSVNTest(SCMTest):
+
+ def _setup_git_checkout(self):
+ self.git_checkout_path = tempfile.mkdtemp(suffix="git_test_checkout")
+ # --quiet doesn't make git svn silent, so we use run_silent to redirect output
+ run_silent(['git', 'svn', 'clone', '-T', 'trunk', self.svn_repo_url, self.git_checkout_path])
+ os.chdir(self.git_checkout_path)
+
+ def _tear_down_git_checkout(self):
+ # Change back to a valid directory so that later calls to os.getcwd() do not fail.
+ os.chdir(self.original_dir)
+ run_command(['rm', '-rf', self.git_checkout_path])
+
+ def setUp(self):
+ self.original_dir = os.getcwd()
+
+ SVNTestRepository.setup(self)
+ self._setup_git_checkout()
+ self.scm = detect_scm_system(self.git_checkout_path)
+ # For historical reasons, we test some checkout code here too.
+ self.checkout = Checkout(self.scm)
+
+ def tearDown(self):
+ SVNTestRepository.tear_down(self)
+ self._tear_down_git_checkout()
+
+ def test_detection(self):
+ scm = detect_scm_system(self.git_checkout_path)
+ self.assertEqual(scm.display_name(), "git")
+ self.assertEqual(scm.supports_local_commits(), True)
+
+ def test_read_git_config(self):
+ key = 'test.git-config'
+ value = 'git-config value'
+ run_command(['git', 'config', key, value])
+ self.assertEqual(self.scm.read_git_config(key), value)
+
+ def test_local_commits(self):
+ test_file = os.path.join(self.git_checkout_path, 'test_file')
+ write_into_file_at_path(test_file, 'foo')
+ run_command(['git', 'commit', '-a', '-m', 'local commit'])
+
+ self.assertEqual(len(self.scm.local_commits()), 1)
+
+ def test_discard_local_commits(self):
+ test_file = os.path.join(self.git_checkout_path, 'test_file')
+ write_into_file_at_path(test_file, 'foo')
+ run_command(['git', 'commit', '-a', '-m', 'local commit'])
+
+ self.assertEqual(len(self.scm.local_commits()), 1)
+ self.scm.discard_local_commits()
+ self.assertEqual(len(self.scm.local_commits()), 0)
+
+ def test_delete_branch(self):
+ new_branch = 'foo'
+
+ run_command(['git', 'checkout', '-b', new_branch])
+ self.assertEqual(run_command(['git', 'symbolic-ref', 'HEAD']).strip(), 'refs/heads/' + new_branch)
+
+ run_command(['git', 'checkout', '-b', 'bar'])
+ self.scm.delete_branch(new_branch)
+
+ self.assertFalse(re.search(r'foo', run_command(['git', 'branch'])))
+
+ def test_remote_merge_base(self):
+ # Diff to merge-base should include working-copy changes,
+ # which the diff to svn_branch.. doesn't.
+ test_file = os.path.join(self.git_checkout_path, 'test_file')
+ write_into_file_at_path(test_file, 'foo')
+
+ diff_to_common_base = _git_diff(self.scm.remote_branch_ref() + '..')
+ diff_to_merge_base = _git_diff(self.scm.remote_merge_base())
+
+ self.assertFalse(re.search(r'foo', diff_to_common_base))
+ self.assertTrue(re.search(r'foo', diff_to_merge_base))
+
+ def test_rebase_in_progress(self):
+ svn_test_file = os.path.join(self.svn_checkout_path, 'test_file')
+ write_into_file_at_path(svn_test_file, "svn_checkout")
+ run_command(['svn', 'commit', '--message', 'commit to conflict with git commit'], cwd=self.svn_checkout_path)
+
+ git_test_file = os.path.join(self.git_checkout_path, 'test_file')
+ write_into_file_at_path(git_test_file, "git_checkout")
+ run_command(['git', 'commit', '-a', '-m', 'commit to be thrown away by rebase abort'])
+
+ # --quiet doesn't make git svn silent, so use run_silent to redirect output
+ self.assertRaises(ScriptError, run_silent, ['git', 'svn', '--quiet', 'rebase']) # Will fail due to a conflict leaving us mid-rebase.
+
+ scm = detect_scm_system(self.git_checkout_path)
+ self.assertTrue(scm.rebase_in_progress())
+
+ # Make sure our cleanup works.
+ scm.clean_working_directory()
+ self.assertFalse(scm.rebase_in_progress())
+
+ # Make sure cleanup doesn't throw when no rebase is in progress.
+ scm.clean_working_directory()
+
+ def test_commitish_parsing(self):
+ scm = detect_scm_system(self.git_checkout_path)
+
+ # Multiple revisions are cherry-picked.
+ self.assertEqual(len(scm.commit_ids_from_commitish_arguments(['HEAD~2'])), 1)
+ self.assertEqual(len(scm.commit_ids_from_commitish_arguments(['HEAD', 'HEAD~2'])), 2)
+
+ # ... is an invalid range specifier
+ self.assertRaises(ScriptError, scm.commit_ids_from_commitish_arguments, ['trunk...HEAD'])
+
+ def test_commitish_order(self):
+ scm = detect_scm_system(self.git_checkout_path)
+
+ commit_range = 'HEAD~3..HEAD'
+
+ actual_commits = scm.commit_ids_from_commitish_arguments([commit_range])
+ expected_commits = []
+ expected_commits += reversed(run_command(['git', 'rev-list', commit_range]).splitlines())
+
+ self.assertEqual(actual_commits, expected_commits)
+
+ def test_apply_git_patch(self):
+ scm = detect_scm_system(self.git_checkout_path)
+ # We carefullly pick a diff which does not have a directory addition
+ # as currently svn-apply will error out when trying to remove directories
+ # in Git: https://bugs.webkit.org/show_bug.cgi?id=34871
+ patch = self._create_patch(_git_diff('HEAD..HEAD^'))
+ self._setup_webkittools_scripts_symlink(scm)
+ Checkout(scm).apply_patch(patch)
+
+ def test_apply_git_patch_force(self):
+ scm = detect_scm_system(self.git_checkout_path)
+ patch = self._create_patch(_git_diff('HEAD~2..HEAD'))
+ self._setup_webkittools_scripts_symlink(scm)
+ self.assertRaises(ScriptError, Checkout(scm).apply_patch, patch, force=True)
+
+ def test_commit_text_parsing(self):
+ write_into_file_at_path('test_file', 'more test content')
+ commit_text = self.scm.commit_with_message("another test commit")
+ self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '6')
+
+ self.scm.dryrun = True
+ write_into_file_at_path('test_file', 'still more test content')
+ commit_text = self.scm.commit_with_message("yet another test commit")
+ self.assertEqual(self.scm.svn_revision_from_commit_text(commit_text), '0')
+
+ def test_commit_with_message_working_copy_only(self):
+ write_into_file_at_path('test_file_commit1', 'more test content')
+ run_command(['git', 'add', 'test_file_commit1'])
+ scm = detect_scm_system(self.git_checkout_path)
+ commit_text = scm.commit_with_message("yet another test commit")
+
+ self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
+ svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
+ self.assertTrue(re.search(r'test_file_commit1', svn_log))
+
+ def _local_commit(self, filename, contents, message):
+ write_into_file_at_path(filename, contents)
+ run_command(['git', 'add', filename])
+ self.scm.commit_locally_with_message(message)
+
+ def _one_local_commit(self):
+ self._local_commit('test_file_commit1', 'more test content', 'another test commit')
+
+ def _one_local_commit_plus_working_copy_changes(self):
+ self._one_local_commit()
+ write_into_file_at_path('test_file_commit2', 'still more test content')
+ run_command(['git', 'add', 'test_file_commit2'])
+
+ def _two_local_commits(self):
+ self._one_local_commit()
+ self._local_commit('test_file_commit2', 'still more test content', 'yet another test commit')
+
+ def _three_local_commits(self):
+ self._local_commit('test_file_commit0', 'more test content', 'another test commit')
+ self._two_local_commits()
+
+ def test_revisions_changing_files_with_local_commit(self):
+ self._one_local_commit()
+ self.assertEquals(self.scm.revisions_changing_file('test_file_commit1'), [])
+
+ def test_commit_with_message(self):
+ self._one_local_commit_plus_working_copy_changes()
+ scm = detect_scm_system(self.git_checkout_path)
+ self.assertRaises(AmbiguousCommitError, scm.commit_with_message, "yet another test commit")
+ commit_text = scm.commit_with_message("yet another test commit", force_squash=True)
+
+ self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
+ svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
+ self.assertTrue(re.search(r'test_file_commit2', svn_log))
+ self.assertTrue(re.search(r'test_file_commit1', svn_log))
+
+ def test_commit_with_message_git_commit(self):
+ self._two_local_commits()
+
+ scm = detect_scm_system(self.git_checkout_path)
+ commit_text = scm.commit_with_message("another test commit", git_commit="HEAD^")
+ self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
+
+ svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
+ self.assertTrue(re.search(r'test_file_commit1', svn_log))
+ self.assertFalse(re.search(r'test_file_commit2', svn_log))
+
+ def test_commit_with_message_git_commit_range(self):
+ self._three_local_commits()
+
+ scm = detect_scm_system(self.git_checkout_path)
+ commit_text = scm.commit_with_message("another test commit", git_commit="HEAD~2..HEAD")
+ self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
+
+ svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
+ self.assertFalse(re.search(r'test_file_commit0', svn_log))
+ self.assertTrue(re.search(r'test_file_commit1', svn_log))
+ self.assertTrue(re.search(r'test_file_commit2', svn_log))
+
+ def test_changed_files_working_copy_only(self):
+ self._one_local_commit_plus_working_copy_changes()
+ scm = detect_scm_system(self.git_checkout_path)
+ commit_text = scm.commit_with_message("another test commit", git_commit="HEAD..")
+ self.assertFalse(re.search(r'test_file_commit1', svn_log))
+ self.assertTrue(re.search(r'test_file_commit2', svn_log))
+
+ def test_commit_with_message_only_local_commit(self):
+ self._one_local_commit()
+ scm = detect_scm_system(self.git_checkout_path)
+ commit_text = scm.commit_with_message("another test commit")
+ svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
+ self.assertTrue(re.search(r'test_file_commit1', svn_log))
+
+ def test_commit_with_message_multiple_local_commits_and_working_copy(self):
+ self._two_local_commits()
+ write_into_file_at_path('test_file_commit1', 'working copy change')
+ scm = detect_scm_system(self.git_checkout_path)
+
+ self.assertRaises(AmbiguousCommitError, scm.commit_with_message, "another test commit")
+ commit_text = scm.commit_with_message("another test commit", force_squash=True)
+
+ self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
+ svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
+ self.assertTrue(re.search(r'test_file_commit2', svn_log))
+ self.assertTrue(re.search(r'test_file_commit1', svn_log))
+
+ def test_commit_with_message_git_commit_and_working_copy(self):
+ self._two_local_commits()
+ write_into_file_at_path('test_file_commit1', 'working copy change')
+ scm = detect_scm_system(self.git_checkout_path)
+ self.assertRaises(ScriptError, scm.commit_with_message, "another test commit", git_commit="HEAD^")
+
+ def test_commit_with_message_multiple_local_commits_always_squash(self):
+ self._two_local_commits()
+ scm = detect_scm_system(self.git_checkout_path)
+ scm._assert_can_squash = lambda working_directory_is_clean: True
+ commit_text = scm.commit_with_message("yet another test commit")
+ self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
+
+ svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
+ self.assertTrue(re.search(r'test_file_commit2', svn_log))
+ self.assertTrue(re.search(r'test_file_commit1', svn_log))
+
+ def test_commit_with_message_multiple_local_commits(self):
+ self._two_local_commits()
+ scm = detect_scm_system(self.git_checkout_path)
+ self.assertRaises(AmbiguousCommitError, scm.commit_with_message, "yet another test commit")
+ commit_text = scm.commit_with_message("yet another test commit", force_squash=True)
+
+ self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
+
+ svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
+ self.assertTrue(re.search(r'test_file_commit2', svn_log))
+ self.assertTrue(re.search(r'test_file_commit1', svn_log))
+
+ def test_commit_with_message_not_synced(self):
+ run_command(['git', 'checkout', '-b', 'my-branch', 'trunk~3'])
+ self._two_local_commits()
+ scm = detect_scm_system(self.git_checkout_path)
+ self.assertRaises(AmbiguousCommitError, scm.commit_with_message, "another test commit")
+ commit_text = scm.commit_with_message("another test commit", force_squash=True)
+
+ self.assertEqual(scm.svn_revision_from_commit_text(commit_text), '6')
+
+ svn_log = run_command(['git', 'svn', 'log', '--limit=1', '--verbose'])
+ self.assertFalse(re.search(r'test_file2', svn_log))
+ self.assertTrue(re.search(r'test_file_commit2', svn_log))
+ self.assertTrue(re.search(r'test_file_commit1', svn_log))
+
+ def test_commit_with_message_not_synced_with_conflict(self):
+ run_command(['git', 'checkout', '-b', 'my-branch', 'trunk~3'])
+ self._local_commit('test_file2', 'asdf', 'asdf commit')
+
+ scm = detect_scm_system(self.git_checkout_path)
+ # There's a conflict between trunk and the test_file2 modification.
+ self.assertRaises(ScriptError, scm.commit_with_message, "another test commit", force_squash=True)
+
+ def test_remote_branch_ref(self):
+ self.assertEqual(self.scm.remote_branch_ref(), 'refs/remotes/trunk')
+
+ def test_reverse_diff(self):
+ self._shared_test_reverse_diff()
+
+ def test_diff_for_revision(self):
+ self._shared_test_diff_for_revision()
+
+ def test_svn_apply_git_patch(self):
+ self._shared_test_svn_apply_git_patch()
+
+ def test_create_patch_local_plus_working_copy(self):
+ self._one_local_commit_plus_working_copy_changes()
+ scm = detect_scm_system(self.git_checkout_path)
+ patch = scm.create_patch()
+ self.assertTrue(re.search(r'test_file_commit1', patch))
+ self.assertTrue(re.search(r'test_file_commit2', patch))
+
+ def test_create_patch(self):
+ self._one_local_commit_plus_working_copy_changes()
+ scm = detect_scm_system(self.git_checkout_path)
+ patch = scm.create_patch()
+ self.assertTrue(re.search(r'test_file_commit2', patch))
+ self.assertTrue(re.search(r'test_file_commit1', patch))
+
+ def test_create_patch_with_changed_files(self):
+ self._one_local_commit_plus_working_copy_changes()
+ scm = detect_scm_system(self.git_checkout_path)
+ patch = scm.create_patch(changed_files=['test_file_commit2'])
+ self.assertTrue(re.search(r'test_file_commit2', patch))
+
+ def test_create_patch_with_rm_and_changed_files(self):
+ self._one_local_commit_plus_working_copy_changes()
+ scm = detect_scm_system(self.git_checkout_path)
+ os.remove('test_file_commit1')
+ patch = scm.create_patch()
+ patch_with_changed_files = scm.create_patch(changed_files=['test_file_commit1', 'test_file_commit2'])
+ self.assertEquals(patch, patch_with_changed_files)
+
+ def test_create_patch_git_commit(self):
+ self._two_local_commits()
+ scm = detect_scm_system(self.git_checkout_path)
+ patch = scm.create_patch(git_commit="HEAD^")
+ self.assertTrue(re.search(r'test_file_commit1', patch))
+ self.assertFalse(re.search(r'test_file_commit2', patch))
+
+ def test_create_patch_git_commit_range(self):
+ self._three_local_commits()
+ scm = detect_scm_system(self.git_checkout_path)
+ patch = scm.create_patch(git_commit="HEAD~2..HEAD")
+ self.assertFalse(re.search(r'test_file_commit0', patch))
+ self.assertTrue(re.search(r'test_file_commit2', patch))
+ self.assertTrue(re.search(r'test_file_commit1', patch))
+
+ def test_create_patch_working_copy_only(self):
+ self._one_local_commit_plus_working_copy_changes()
+ scm = detect_scm_system(self.git_checkout_path)
+ patch = scm.create_patch(git_commit="HEAD..")
+ self.assertFalse(re.search(r'test_file_commit1', patch))
+ self.assertTrue(re.search(r'test_file_commit2', patch))
+
+ def test_create_patch_multiple_local_commits(self):
+ self._two_local_commits()
+ scm = detect_scm_system(self.git_checkout_path)
+ patch = scm.create_patch()
+ self.assertTrue(re.search(r'test_file_commit2', patch))
+ self.assertTrue(re.search(r'test_file_commit1', patch))
+
+ def test_create_patch_not_synced(self):
+ run_command(['git', 'checkout', '-b', 'my-branch', 'trunk~3'])
+ self._two_local_commits()
+ scm = detect_scm_system(self.git_checkout_path)
+ patch = scm.create_patch()
+ self.assertFalse(re.search(r'test_file2', patch))
+ self.assertTrue(re.search(r'test_file_commit2', patch))
+ self.assertTrue(re.search(r'test_file_commit1', patch))
+
+ def test_create_binary_patch(self):
+ # Create a git binary patch and check the contents.
+ scm = detect_scm_system(self.git_checkout_path)
+ test_file_name = 'binary_file'
+ test_file_path = os.path.join(self.git_checkout_path, test_file_name)
+ file_contents = ''.join(map(chr, range(256)))
+ write_into_file_at_path(test_file_path, file_contents, encoding=None)
+ run_command(['git', 'add', test_file_name])
+ patch = scm.create_patch()
+ self.assertTrue(re.search(r'\nliteral 0\n', patch))
+ self.assertTrue(re.search(r'\nliteral 256\n', patch))
+
+ # Check if we can apply the created patch.
+ run_command(['git', 'rm', '-f', test_file_name])
+ self._setup_webkittools_scripts_symlink(scm)
+ self.checkout.apply_patch(self._create_patch(patch))
+ self.assertEqual(file_contents, read_from_path(test_file_path, encoding=None))
+
+ # Check if we can create a patch from a local commit.
+ write_into_file_at_path(test_file_path, file_contents, encoding=None)
+ run_command(['git', 'add', test_file_name])
+ run_command(['git', 'commit', '-m', 'binary diff'])
+ patch_from_local_commit = scm.create_patch('HEAD')
+ self.assertTrue(re.search(r'\nliteral 0\n', patch_from_local_commit))
+ self.assertTrue(re.search(r'\nliteral 256\n', patch_from_local_commit))
+
+ def test_changed_files_local_plus_working_copy(self):
+ self._one_local_commit_plus_working_copy_changes()
+ scm = detect_scm_system(self.git_checkout_path)
+ files = scm.changed_files()
+ self.assertTrue('test_file_commit1' in files)
+ self.assertTrue('test_file_commit2' in files)
+
+ def test_changed_files_git_commit(self):
+ self._two_local_commits()
+ scm = detect_scm_system(self.git_checkout_path)
+ files = scm.changed_files(git_commit="HEAD^")
+ self.assertTrue('test_file_commit1' in files)
+ self.assertFalse('test_file_commit2' in files)
+
+ def test_changed_files_git_commit_range(self):
+ self._three_local_commits()
+ scm = detect_scm_system(self.git_checkout_path)
+ files = scm.changed_files(git_commit="HEAD~2..HEAD")
+ self.assertTrue('test_file_commit0' not in files)
+ self.assertTrue('test_file_commit1' in files)
+ self.assertTrue('test_file_commit2' in files)
+
+ def test_changed_files_working_copy_only(self):
+ self._one_local_commit_plus_working_copy_changes()
+ scm = detect_scm_system(self.git_checkout_path)
+ files = scm.changed_files(git_commit="HEAD..")
+ self.assertFalse('test_file_commit1' in files)
+ self.assertTrue('test_file_commit2' in files)
+
+ def test_changed_files_multiple_local_commits(self):
+ self._two_local_commits()
+ scm = detect_scm_system(self.git_checkout_path)
+ files = scm.changed_files()
+ self.assertTrue('test_file_commit2' in files)
+ self.assertTrue('test_file_commit1' in files)
+
+ def test_changed_files_not_synced(self):
+ run_command(['git', 'checkout', '-b', 'my-branch', 'trunk~3'])
+ self._two_local_commits()
+ scm = detect_scm_system(self.git_checkout_path)
+ files = scm.changed_files()
+ self.assertFalse('test_file2' in files)
+ self.assertTrue('test_file_commit2' in files)
+ self.assertTrue('test_file_commit1' in files)
+
+ def test_changed_files_not_synced(self):
+ run_command(['git', 'checkout', '-b', 'my-branch', 'trunk~3'])
+ self._two_local_commits()
+ scm = detect_scm_system(self.git_checkout_path)
+ files = scm.changed_files()
+ self.assertFalse('test_file2' in files)
+ self.assertTrue('test_file_commit2' in files)
+ self.assertTrue('test_file_commit1' in files)
+
+ def test_changed_files(self):
+ self._shared_test_changed_files()
+
+ def test_changed_files_for_revision(self):
+ self._shared_test_changed_files_for_revision()
+
+ def test_contents_at_revision(self):
+ self._shared_test_contents_at_revision()
+
+ def test_revisions_changing_file(self):
+ self._shared_test_revisions_changing_file()
+
+ def test_added_files(self):
+ self._shared_test_added_files()
+
+ def test_committer_email_for_revision(self):
+ self._shared_test_committer_email_for_revision()
+
+ def test_add_recursively(self):
+ self._shared_test_add_recursively()
+
+ def test_delete(self):
+ self._two_local_commits()
+ self.scm.delete('test_file_commit1')
+ self.assertTrue("test_file_commit1" in self.scm.deleted_files())
+
+ def test_to_object_name(self):
+ relpath = 'test_file_commit1'
+ fullpath = os.path.join(self.git_checkout_path, relpath)
+ self._two_local_commits()
+ self.assertEqual(relpath, self.scm.to_object_name(fullpath))
+
+ def test_show_head(self):
+ self._two_local_commits()
+ self.assertEqual("more test content", self.scm.show_head('test_file_commit1'))
+
+ def test_show_head_binary(self):
+ self._two_local_commits()
+ data = "\244"
+ write_into_file_at_path("binary_file", data, encoding=None)
+ self.scm.add("binary_file")
+ self.scm.commit_locally_with_message("a test commit")
+ self.assertEqual(data, self.scm.show_head('binary_file'))
+
+ def test_diff_for_file(self):
+ self._two_local_commits()
+ write_into_file_at_path('test_file_commit1', "Updated", encoding=None)
+
+ diff = self.scm.diff_for_file('test_file_commit1')
+ cached_diff = self.scm.diff_for_file('test_file_commit1')
+ self.assertTrue("+Updated" in diff)
+ self.assertTrue("-more test content" in diff)
+
+ self.scm.add('test_file_commit1')
+
+ cached_diff = self.scm.diff_for_file('test_file_commit1')
+ self.assertTrue("+Updated" in cached_diff)
+ self.assertTrue("-more test content" in cached_diff)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/config/__init__.py b/Tools/Scripts/webkitpy/common/config/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/config/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/common/config/build.py b/Tools/Scripts/webkitpy/common/config/build.py
new file mode 100644
index 0000000..2a432ce
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/config/build.py
@@ -0,0 +1,136 @@
+# 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.
+
+"""Functions relating to building WebKit"""
+
+import re
+
+
+def _should_file_trigger_build(target_platform, file):
+ # The directories and patterns lists below map directory names or
+ # regexp patterns to the bot platforms for which they should trigger a
+ # build. Mapping to the empty list means that no builds should be
+ # triggered on any platforms. Earlier directories/patterns take
+ # precendence over later ones.
+
+ # FIXME: The patterns below have only been verified to be correct on
+ # Windows. We should implement this for other platforms and start using
+ # it for their bots. Someone familiar with each platform will have to
+ # figure out what the right set of directories/patterns is for that
+ # platform.
+ assert(target_platform == "win")
+
+ directories = [
+ # Directories that shouldn't trigger builds on any bots.
+ ("PageLoadTests", []),
+ ("WebCore/manual-tests", []),
+ ("Examples", []),
+ ("Websites", []),
+ ("android", []),
+ ("brew", []),
+ ("efl", []),
+ ("haiku", []),
+ ("iphone", []),
+ ("opengl", []),
+ ("opentype", []),
+ ("openvg", []),
+ ("wx", []),
+ ("wince", []),
+
+ # Directories that should trigger builds on only some bots.
+ ("JavaScriptGlue", ["mac"]),
+ ("LayoutTests/platform/mac", ["mac", "win"]),
+ ("LayoutTests/platform/mac-snowleopard", ["mac-snowleopard", "win"]),
+ ("WebCore/image-decoders", ["chromium"]),
+ ("cairo", ["gtk", "wincairo"]),
+ ("cf", ["chromium-mac", "mac", "qt", "win"]),
+ ("chromium", ["chromium"]),
+ ("cocoa", ["chromium-mac", "mac"]),
+ ("curl", ["gtk", "wincairo"]),
+ ("gobject", ["gtk"]),
+ ("gpu", ["chromium", "mac"]),
+ ("gstreamer", ["gtk"]),
+ ("gtk", ["gtk"]),
+ ("mac", ["chromium-mac", "mac"]),
+ ("mac-leopard", ["mac-leopard"]),
+ ("mac-snowleopard", ["mac-snowleopard"]),
+ ("mac-wk2", ["mac-snowleopard", "win"]),
+ ("objc", ["mac"]),
+ ("qt", ["qt"]),
+ ("skia", ["chromium"]),
+ ("soup", ["gtk"]),
+ ("v8", ["chromium"]),
+ ("win", ["chromium-win", "win"]),
+ ]
+ patterns = [
+ # Patterns that shouldn't trigger builds on any bots.
+ (r"(?:^|/)Makefile$", []),
+ (r"/ARM", []),
+ (r"/CMake.*", []),
+ (r"/ChangeLog.*$", []),
+ (r"/LICENSE[^/]+$", []),
+ (r"ARM(?:v7)?\.(?:cpp|h)$", []),
+ (r"MIPS\.(?:cpp|h)$", []),
+ (r"WinCE\.(?:cpp|h|mm)$", []),
+ (r"\.(?:bkl|mk)$", []),
+
+ # Patterns that should trigger builds on only some bots.
+ (r"/GNUmakefile\.am$", ["gtk"]),
+ (r"/\w+Chromium\w*\.(?:cpp|h|mm)$", ["chromium"]),
+ (r"Mac\.(?:cpp|h|mm)$", ["mac"]),
+ (r"\.exp$", ["mac"]),
+ (r"\.gypi?", ["chromium"]),
+ (r"\.order$", ["mac"]),
+ (r"\.pr[io]$", ["qt"]),
+ (r"\.xcconfig$", ["mac"]),
+ (r"\.xcodeproj/", ["mac"]),
+ ]
+
+ base_platform = target_platform.split("-")[0]
+
+ # See if the file is in one of the known directories.
+ for directory, platforms in directories:
+ if re.search(r"(?:^|/)%s/" % directory, file):
+ return target_platform in platforms or base_platform in platforms
+
+ # See if the file matches a known pattern.
+ for pattern, platforms in patterns:
+ if re.search(pattern, file):
+ return target_platform in platforms or base_platform in platforms
+
+ # See if the file is a platform-specific test result.
+ match = re.match("LayoutTests/platform/(?P<platform>[^/]+)/", file)
+ if match:
+ # See if the file is a test result for this platform, our base
+ # platform, or one of our sub-platforms.
+ return match.group("platform") in (target_platform, base_platform) or match.group("platform").startswith("%s-" % target_platform)
+
+ # The file isn't one we know about specifically, so we should assume we
+ # have to build.
+ return True
+
+
+def should_build(target_platform, changed_files):
+ """Returns true if the changed files affect the given platform, and
+ thus a build should be performed. target_platform should be one of the
+ platforms used in the build.webkit.org master's config.json file."""
+ return any(_should_file_trigger_build(target_platform, file) for file in changed_files)
diff --git a/Tools/Scripts/webkitpy/common/config/build_unittest.py b/Tools/Scripts/webkitpy/common/config/build_unittest.py
new file mode 100644
index 0000000..d833464
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/config/build_unittest.py
@@ -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.
+
+import unittest
+
+from webkitpy.common.config import build
+
+
+class ShouldBuildTest(unittest.TestCase):
+ _should_build_tests = [
+ (["Websites/bugs.webkit.org/foo", "WebCore/bar"], ["*"]),
+ (["Websites/bugs.webkit.org/foo"], []),
+ (["JavaScriptCore/JavaScriptCore.xcodeproj/foo"], ["mac-leopard", "mac-snowleopard"]),
+ (["JavaScriptGlue/foo", "WebCore/bar"], ["*"]),
+ (["JavaScriptGlue/foo"], ["mac-leopard", "mac-snowleopard"]),
+ (["LayoutTests/foo"], ["*"]),
+ (["LayoutTests/platform/chromium-linux/foo"], ["chromium-linux"]),
+ (["LayoutTests/platform/chromium-win/fast/compact/001-expected.txt"], ["chromium-win"]),
+ (["LayoutTests/platform/mac-leopard/foo"], ["mac-leopard"]),
+ (["LayoutTests/platform/mac-snowleopard/foo"], ["mac-snowleopard", "win"]),
+ (["LayoutTests/platform/mac-wk2/Skipped"], ["mac-snowleopard", "win"]),
+ (["LayoutTests/platform/mac/foo"], ["mac-leopard", "mac-snowleopard", "win"]),
+ (["LayoutTests/platform/win-xp/foo"], ["win"]),
+ (["LayoutTests/platform/win-wk2/foo"], ["win"]),
+ (["LayoutTests/platform/win/foo"], ["win"]),
+ (["WebCore/mac/foo"], ["chromium-mac", "mac-leopard", "mac-snowleopard"]),
+ (["WebCore/win/foo"], ["chromium-win", "win"]),
+ (["WebCore/platform/graphics/gpu/foo"], ["mac-leopard", "mac-snowleopard"]),
+ (["WebCore/platform/wx/wxcode/win/foo"], []),
+ (["WebCore/rendering/RenderThemeMac.mm", "WebCore/rendering/RenderThemeMac.h"], ["mac-leopard", "mac-snowleopard"]),
+ (["WebCore/rendering/RenderThemeChromiumLinux.h"], ["chromium-linux"]),
+ (["WebCore/rendering/RenderThemeWinCE.h"], []),
+ ]
+
+ def test_should_build(self):
+ for files, platforms in self._should_build_tests:
+ # FIXME: We should test more platforms here once
+ # build._should_file_trigger_build is implemented for them.
+ for platform in ["win"]:
+ should_build = platform in platforms or "*" in platforms
+ self.assertEqual(build.should_build(platform, files), should_build, "%s should%s have built but did%s (files: %s)" % (platform, "" if should_build else "n't", "n't" if should_build else "", str(files)))
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/config/committers.py b/Tools/Scripts/webkitpy/common/config/committers.py
new file mode 100644
index 0000000..7c5bf8b
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/config/committers.py
@@ -0,0 +1,335 @@
+# 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.
+#
+# WebKit's Python module for committer and reviewer validation
+
+
+class Committer:
+
+ def __init__(self, name, email_or_emails, irc_nickname=None):
+ self.full_name = name
+ if isinstance(email_or_emails, str):
+ self.emails = [email_or_emails]
+ else:
+ self.emails = email_or_emails
+ self.irc_nickname = irc_nickname
+ self.can_review = False
+
+ def bugzilla_email(self):
+ # FIXME: We're assuming the first email is a valid bugzilla email,
+ # which might not be right.
+ return self.emails[0]
+
+ def __str__(self):
+ return '"%s" <%s>' % (self.full_name, self.emails[0])
+
+
+class Reviewer(Committer):
+
+ def __init__(self, name, email_or_emails, irc_nickname=None):
+ Committer.__init__(self, name, email_or_emails, irc_nickname)
+ self.can_review = True
+
+
+# This is intended as a canonical, machine-readable list of all non-reviewer
+# committers for WebKit. If your name is missing here and you are a committer,
+# please add it. No review needed. All reviewers are committers, so this list
+# is only of committers who are not reviewers.
+
+
+committers_unable_to_review = [
+ Committer("Aaron Boodman", "aa@chromium.org", "aboodman"),
+ Committer("Abhishek Arya", "inferno@chromium.org", "inferno-sec"),
+ Committer("Adam Langley", "agl@chromium.org", "agl"),
+ Committer("Adrienne Walker", ["enne@google.com", "enne@chromium.org"], "enne"),
+ Committer("Albert J. Wong", "ajwong@chromium.org"),
+ Committer("Alejandro G. Castro", ["alex@igalia.com", "alex@webkit.org"]),
+ Committer("Alexander Kellett", ["lypanov@mac.com", "a-lists001@lypanov.net", "lypanov@kde.org"], "lypanov"),
+ Committer("Alexander Pavlov", "apavlov@chromium.org", "apavlov"),
+ Committer("Andre Boule", "aboule@apple.com"),
+ Committer("Andrei Popescu", "andreip@google.com", "andreip"),
+ Committer("Andrew Wellington", ["andrew@webkit.org", "proton@wiretapped.net"], "proton"),
+ Committer("Andrew Scherkus", "scherkus@chromium.org", "scherkus"),
+ Committer("Andrey Kosyakov", "caseq@chromium.org", "caseq"),
+ Committer("Andras Becsi", ["abecsi@webkit.org", "abecsi@inf.u-szeged.hu"], "bbandix"),
+ Committer("Andy Estes", "aestes@apple.com", "estes"),
+ Committer("Anthony Ricaud", "rik@webkit.org", "rik"),
+ Committer("Anton Muhin", "antonm@chromium.org", "antonm"),
+ Committer("Balazs Kelemen", "kbalazs@webkit.org", "kbalazs"),
+ Committer("Ben Murdoch", "benm@google.com", "benm"),
+ Committer("Benjamin C Meyer", ["ben@meyerhome.net", "ben@webkit.org"], "icefox"),
+ Committer("Benjamin Otte", ["otte@gnome.org", "otte@webkit.org"], "otte"),
+ Committer("Benjamin Poulain", ["benjamin.poulain@nokia.com", "ikipou@gmail.com"]),
+ Committer("Brent Fulgham", "bfulgham@webkit.org", "bfulgham"),
+ Committer("Brett Wilson", "brettw@chromium.org", "brettx"),
+ Committer("Brian Weinstein", "bweinstein@apple.com", "bweinstein"),
+ Committer("Cameron McCormack", "cam@webkit.org", "heycam"),
+ Committer("Carol Szabo", "carol.szabo@nokia.com"),
+ Committer("Chang Shu", "Chang.Shu@nokia.com"),
+ Committer("Chris Evans", "cevans@google.com"),
+ Committer("Chris Petersen", "cpetersen@apple.com", "cpetersen"),
+ Committer("Chris Rogers", "crogers@google.com", "crogers"),
+ Committer("Christian Dywan", ["christian@twotoasts.de", "christian@webkit.org"]),
+ Committer("Collin Jackson", "collinj@webkit.org"),
+ Committer("David Smith", ["catfish.man@gmail.com", "dsmith@webkit.org"], "catfishman"),
+ Committer("Dean Jackson", "dino@apple.com", "dino"),
+ Committer("Diego Gonzalez", ["diegohcg@webkit.org", "diego.gonzalez@openbossa.org"], "diegohcg"),
+ Committer("Dirk Pranke", "dpranke@chromium.org"),
+ Committer("Drew Wilson", "atwilson@chromium.org", "atwilson"),
+ Committer("Eli Fidler", "eli@staikos.net", "QBin"),
+ Committer("Enrica Casucci", "enrica@apple.com"),
+ Committer("Erik Arvidsson", "arv@chromium.org", "arv"),
+ Committer("Eric Roman", "eroman@chromium.org", "eroman"),
+ Committer("Evan Martin", "evan@chromium.org", "evmar"),
+ Committer("Evan Stade", "estade@chromium.org", "estade"),
+ Committer("Fady Samuel", "fsamuel@chromium.org", "fsamuel"),
+ Committer("Feng Qian", "feng@chromium.org"),
+ Committer("Fumitoshi Ukai", "ukai@chromium.org", "ukai"),
+ Committer("Gabor Loki", "loki@webkit.org", "loki04"),
+ Committer("Girish Ramakrishnan", ["girish@forwardbias.in", "ramakrishnan.girish@gmail.com"]),
+ Committer("Graham Dennis", ["Graham.Dennis@gmail.com", "gdennis@webkit.org"]),
+ Committer("Greg Bolsinga", "bolsinga@apple.com"),
+ Committer("Gyuyoung Kim", ["gyuyoung.kim@samsung.com", "gyuyoung@gmail.com", "gyuyoung@webkit.org"], "gyuyoung"),
+ Committer("Hans Wennborg", "hans@chromium.org", "hwennborg"),
+ Committer("Hayato Ito", "hayato@chromium.org", "hayato"),
+ Committer("Hin-Chung Lam", ["hclam@google.com", "hclam@chromium.org"]),
+ Committer("Ilya Tikhonovsky", "loislo@chromium.org", "loislo"),
+ Committer("Jakob Petsovits", ["jpetsovits@rim.com", "jpetso@gmx.at"], "jpetso"),
+ Committer("Jakub Wieczorek", "jwieczorek@webkit.org", "fawek"),
+ Committer("James Hawkins", ["jhawkins@chromium.org", "jhawkins@google.com"], "jhawkins"),
+ Committer("Jay Civelli", "jcivelli@chromium.org", "jcivelli"),
+ Committer("Jens Alfke", ["snej@chromium.org", "jens@apple.com"]),
+ Committer("Jer Noble", "jer.noble@apple.com", "jernoble"),
+ Committer("Jeremy Moskovich", ["playmobil@google.com", "jeremy@chromium.org"], "jeremymos"),
+ Committer("Jessie Berlin", ["jberlin@webkit.org", "jberlin@apple.com"]),
+ Committer("Jesus Sanchez-Palencia", ["jesus@webkit.org", "jesus.palencia@openbossa.org"], "jeez_"),
+ Committer("Jocelyn Turcotte", "jocelyn.turcotte@nokia.com", "jturcotte"),
+ Committer("Jochen Eisinger", "jochen@chromium.org", "jochen__"),
+ Committer("John Abd-El-Malek", "jam@chromium.org", "jam"),
+ Committer("John Gregg", ["johnnyg@google.com", "johnnyg@chromium.org"], "johnnyg"),
+ Committer("Johnny Ding", ["jnd@chromium.org", "johnnyding.webkit@gmail.com"], "johnnyding"),
+ Committer("Joost de Valk", ["joost@webkit.org", "webkit-dev@joostdevalk.nl"], "Altha"),
+ Committer("Julie Parent", ["jparent@google.com", "jparent@chromium.org"], "jparent"),
+ Committer("Julien Chaffraix", ["jchaffraix@webkit.org", "julien.chaffraix@gmail.com"]),
+ Committer("Jungshik Shin", "jshin@chromium.org"),
+ Committer("Justin Schuh", "jschuh@chromium.org", "jschuh"),
+ Committer("Keishi Hattori", "keishi@webkit.org", "keishi"),
+ Committer("Kelly Norton", "knorton@google.com"),
+ Committer("Kent Hansen", "kent.hansen@nokia.com", "khansen"),
+ Committer("Kimmo Kinnunen", ["kimmo.t.kinnunen@nokia.com", "kimmok@iki.fi", "ktkinnun@webkit.org"], "kimmok"),
+ Committer("Kinuko Yasuda", "kinuko@chromium.org", "kinuko"),
+ Committer("Krzysztof Kowalczyk", "kkowalczyk@gmail.com"),
+ Committer("Kwang Yul Seo", ["kwangyul.seo@gmail.com", "skyul@company100.net", "kseo@webkit.org"], "kwangseo"),
+ Committer("Leandro Pereira", ["leandro@profusion.mobi", "leandro@webkit.org"], "acidx"),
+ Committer("Levi Weintraub", "lweintraub@apple.com"),
+ Committer("Lucas De Marchi", ["lucas.demarchi@profusion.mobi", "demarchi@webkit.org"], "demarchi"),
+ Committer("Luiz Agostini", ["luiz@webkit.org", "luiz.agostini@openbossa.org"], "lca"),
+ Committer("Mads Ager", "ager@chromium.org"),
+ Committer("Marcus Voltis Bulach", "bulach@chromium.org"),
+ Committer("Mario Sanchez Prada", ["msanchez@igalia.com", "mario@webkit.org"], "msanchez"),
+ Committer("Matt Delaney", "mdelaney@apple.com"),
+ Committer("Matt Lilek", ["webkit@mattlilek.com", "pewtermoose@webkit.org"]),
+ Committer("Matt Perry", "mpcomplete@chromium.org"),
+ Committer("Maxime Britto", ["maxime.britto@gmail.com", "britto@apple.com"]),
+ Committer("Maxime Simon", ["simon.maxime@gmail.com", "maxime.simon@webkit.org"], "maxime.simon"),
+ Committer("Michael Nordman", "michaeln@google.com", "michaeln"),
+ Committer("Michael Saboff", "msaboff@apple.com"),
+ Committer("Michelangelo De Simone", "michelangelo@webkit.org", "michelangelo"),
+ Committer("Mihai Parparita", "mihaip@chromium.org", "mihaip"),
+ Committer("Mike Belshe", ["mbelshe@chromium.org", "mike@belshe.com"]),
+ Committer("Mike Fenton", ["mifenton@rim.com", "mike.fenton@torchmobile.com"], "mfenton"),
+ Committer("Mike Thole", ["mthole@mikethole.com", "mthole@apple.com"]),
+ Committer("Mikhail Naganov", "mnaganov@chromium.org"),
+ Committer("MORITA Hajime", "morrita@google.com", "morrita"),
+ Committer("Nico Weber", ["thakis@chromium.org", "thakis@google.com"], "thakis"),
+ Committer("Noam Rosenthal", "noam.rosenthal@nokia.com", "noamr"),
+ Committer("Pam Greene", "pam@chromium.org", "pamg"),
+ Committer("Patrick Gansterer", ["paroga@paroga.com", "paroga@webkit.org"], "paroga"),
+ Committer("Pavel Podivilov", "podivilov@chromium.org", "podivilov"),
+ Committer("Peter Kasting", ["pkasting@google.com", "pkasting@chromium.org"], "pkasting"),
+ Committer("Philippe Normand", ["pnormand@igalia.com", "philn@webkit.org"], "philn-tp"),
+ Committer("Pierre d'Herbemont", ["pdherbemont@free.fr", "pdherbemont@apple.com"], "pdherbemont"),
+ Committer("Pierre-Olivier Latour", "pol@apple.com", "pol"),
+ Committer("Renata Hodovan", "reni@webkit.org", "reni"),
+ Committer("Robert Hogan", ["robert@webkit.org", "robert@roberthogan.net", "lists@roberthogan.net"], "mwenge"),
+ Committer("Roland Steiner", "rolandsteiner@chromium.org"),
+ Committer("Satish Sampath", "satish@chromium.org"),
+ Committer("Scott Violet", "sky@chromium.org", "sky"),
+ Committer("Sergio Villar Senin", ["svillar@igalia.com", "sergio@webkit.org"], "svillar"),
+ Committer("Stephen White", "senorblanco@chromium.org", "senorblanco"),
+ Committer("Tony Gentilcore", "tonyg@chromium.org", "tonyg-cr"),
+ Committer("Trey Matteson", "trey@usa.net", "trey"),
+ Committer("Tristan O'Tierney", ["tristan@otierney.net", "tristan@apple.com"]),
+ Committer("Vangelis Kokkevis", "vangelis@chromium.org", "vangelis"),
+ Committer("Victor Wang", "victorw@chromium.org", "victorw"),
+ Committer("Vitaly Repeshko", "vitalyr@chromium.org"),
+ Committer("William Siegrist", "wsiegrist@apple.com", "wms"),
+ Committer("Xiaomei Ji", "xji@chromium.org", "xji"),
+ Committer("Yael Aharon", "yael.aharon@nokia.com"),
+ Committer("Yaar Schnitman", ["yaar@chromium.org", "yaar@google.com"]),
+ Committer("Yong Li", ["yong.li.webkit@gmail.com", "yong.li@torchmobile.com"], "yong"),
+ Committer("Yongjun Zhang", "yongjun.zhang@nokia.com"),
+ Committer("Yuta Kitamura", "yutak@chromium.org", "yutak"),
+ Committer("Yuzo Fujishima", "yuzo@google.com", "yuzo"),
+ Committer("Zhenyao Mo", "zmo@google.com", "zhenyao"),
+ Committer("Zoltan Herczeg", "zherczeg@webkit.org", "zherczeg"),
+ Committer("Zoltan Horvath", ["zoltan@webkit.org", "hzoltan@inf.u-szeged.hu", "horvath.zoltan.6@stud.u-szeged.hu"], "zoltan"),
+]
+
+
+# This is intended as a canonical, machine-readable list of all reviewers for
+# WebKit. If your name is missing here and you are a reviewer, please add it.
+# No review needed.
+
+
+reviewers_list = [
+ Reviewer("Ada Chan", "adachan@apple.com", "chanada"),
+ Reviewer("Adam Barth", "abarth@webkit.org", "abarth"),
+ Reviewer("Adam Roben", "aroben@apple.com", "aroben"),
+ Reviewer("Adam Treat", ["treat@kde.org", "treat@webkit.org", "atreat@rim.com"], "manyoso"),
+ Reviewer("Adele Peterson", "adele@apple.com", "adele"),
+ Reviewer("Alexey Proskuryakov", ["ap@webkit.org", "ap@apple.com"], "ap"),
+ Reviewer("Alice Liu", "alice.liu@apple.com", "aliu"),
+ Reviewer("Alp Toker", ["alp@nuanti.com", "alp@atoker.com", "alp@webkit.org"], "alp"),
+ Reviewer("Anders Carlsson", ["andersca@apple.com", "acarlsson@apple.com"], "andersca"),
+ Reviewer("Andreas Kling", ["kling@webkit.org", "andreas.kling@nokia.com"], "kling"),
+ Reviewer("Antonio Gomes", ["tonikitoo@webkit.org", "agomes@rim.com"], "tonikitoo"),
+ Reviewer("Antti Koivisto", ["koivisto@iki.fi", "antti@apple.com", "antti.j.koivisto@nokia.com"], "anttik"),
+ Reviewer("Ariya Hidayat", ["ariya.hidayat@gmail.com", "ariya@sencha.com", "ariya@webkit.org"], "ariya"),
+ Reviewer("Beth Dakin", "bdakin@apple.com", "dethbakin"),
+ Reviewer("Brady Eidson", "beidson@apple.com", "bradee-oh"),
+ Reviewer("Cameron Zwarich", ["zwarich@apple.com", "cwzwarich@apple.com", "cwzwarich@webkit.org"]),
+ Reviewer("Chris Blumenberg", "cblu@apple.com", "cblu"),
+ Reviewer("Chris Marrin", "cmarrin@apple.com", "cmarrin"),
+ Reviewer("Chris Fleizach", "cfleizach@apple.com", "cfleizach"),
+ Reviewer("Chris Jerdonek", "cjerdonek@webkit.org", "cjerdonek"),
+ Reviewer(u"Csaba Osztrogon\u00e1c", "ossy@webkit.org", "ossy"),
+ Reviewer("Dan Bernstein", ["mitz@webkit.org", "mitz@apple.com"], "mitzpettel"),
+ Reviewer("Daniel Bates", "dbates@webkit.org", "dydz"),
+ Reviewer("Darin Adler", "darin@apple.com", "darin"),
+ Reviewer("Darin Fisher", ["fishd@chromium.org", "darin@chromium.org"], "fishd"),
+ Reviewer("David Harrison", "harrison@apple.com", "harrison"),
+ Reviewer("David Hyatt", "hyatt@apple.com", "hyatt"),
+ Reviewer("David Kilzer", ["ddkilzer@webkit.org", "ddkilzer@apple.com"], "ddkilzer"),
+ Reviewer("David Levin", "levin@chromium.org", "dave_levin"),
+ Reviewer("Dimitri Glazkov", "dglazkov@chromium.org", "dglazkov"),
+ Reviewer("Dirk Schulze", "krit@webkit.org", "krit"),
+ Reviewer("Dmitry Titov", "dimich@chromium.org", "dimich"),
+ Reviewer("Don Melton", "gramps@apple.com", "gramps"),
+ Reviewer("Dumitru Daniliuc", "dumi@chromium.org", "dumi"),
+ Reviewer("Eric Carlson", "eric.carlson@apple.com"),
+ Reviewer("Eric Seidel", "eric@webkit.org", "eseidel"),
+ Reviewer("Gavin Barraclough", "barraclough@apple.com", "gbarra"),
+ Reviewer("Geoffrey Garen", "ggaren@apple.com", "ggaren"),
+ Reviewer("George Staikos", ["staikos@kde.org", "staikos@webkit.org"]),
+ Reviewer("Gustavo Noronha Silva", ["gns@gnome.org", "kov@webkit.org", "gustavo.noronha@collabora.co.uk"], "kov"),
+ Reviewer("Holger Freyther", ["zecke@selfish.org", "zecke@webkit.org"], "zecke"),
+ Reviewer("James Robinson", ["jamesr@chromium.org", "jamesr@google.com"], "jamesr"),
+ Reviewer("Jan Alonzo", ["jmalonzo@gmail.com", "jmalonzo@webkit.org"], "janm"),
+ Reviewer("Jeremy Orlow", "jorlow@chromium.org", "jorlow"),
+ Reviewer("Jian Li", "jianli@chromium.org", "jianli"),
+ Reviewer("John Sullivan", "sullivan@apple.com", "sullivan"),
+ Reviewer("Jon Honeycutt", "jhoneycutt@apple.com", "jhoneycutt"),
+ Reviewer("Joseph Pecoraro", ["joepeck@webkit.org", "pecoraro@apple.com"], "JoePeck"),
+ Reviewer("Justin Garcia", "justin.garcia@apple.com", "justing"),
+ Reviewer("Ken Kocienda", "kocienda@apple.com"),
+ Reviewer("Kenneth Rohde Christiansen", ["kenneth@webkit.org", "kenneth.christiansen@openbossa.org", "kenneth.christiansen@gmail.com"], "kenne"),
+ Reviewer("Kenneth Russell", "kbr@google.com", "kbr_google"),
+ Reviewer("Kent Tamura", "tkent@chromium.org", "tkent"),
+ Reviewer("Kevin Decker", "kdecker@apple.com", "superkevin"),
+ Reviewer("Kevin McCullough", "kmccullough@apple.com", "maculloch"),
+ Reviewer("Kevin Ollivier", ["kevino@theolliviers.com", "kevino@webkit.org"], "kollivier"),
+ Reviewer("Lars Knoll", ["lars@trolltech.com", "lars@kde.org", "lars.knoll@nokia.com"], "lars"),
+ Reviewer("Laszlo Gombos", "laszlo.1.gombos@nokia.com", "lgombos"),
+ Reviewer("Maciej Stachowiak", "mjs@apple.com", "othermaciej"),
+ Reviewer("Mark Rowe", "mrowe@apple.com", "bdash"),
+ Reviewer("Martin Robinson", ["mrobinson@webkit.org", "mrobinson@igalia.com", "martin.james.robinson@gmail.com"], "mrobinson"),
+ Reviewer("Nate Chapin", "japhet@chromium.org", "japhet"),
+ Reviewer("Nikolas Zimmermann", ["zimmermann@kde.org", "zimmermann@physik.rwth-aachen.de", "zimmermann@webkit.org"], "wildfox"),
+ Reviewer("Ojan Vafai", "ojan@chromium.org", "ojan"),
+ Reviewer("Oliver Hunt", "oliver@apple.com", "olliej"),
+ Reviewer("Pavel Feldman", "pfeldman@chromium.org", "pfeldman"),
+ Reviewer("Richard Williamson", "rjw@apple.com", "rjw"),
+ Reviewer("Rob Buis", ["rwlbuis@gmail.com", "rwlbuis@webkit.org"], "rwlbuis"),
+ Reviewer("Ryosuke Niwa", "rniwa@webkit.org", "rniwa"),
+ Reviewer("Sam Weinig", ["sam@webkit.org", "weinig@apple.com"], "weinig"),
+ Reviewer("Shinichiro Hamaji", "hamaji@chromium.org", "hamaji"),
+ Reviewer("Simon Fraser", "simon.fraser@apple.com", "smfr"),
+ Reviewer("Simon Hausmann", ["hausmann@webkit.org", "hausmann@kde.org", "simon.hausmann@nokia.com"], "tronical"),
+ Reviewer("Stephanie Lewis", "slewis@apple.com", "sundiamonde"),
+ Reviewer("Steve Block", "steveblock@google.com", "steveblock"),
+ Reviewer("Steve Falkenburg", "sfalken@apple.com", "sfalken"),
+ Reviewer("Tim Omernick", "timo@apple.com"),
+ Reviewer("Timothy Hatcher", ["timothy@apple.com", "timothy@hatcher.name"], "xenon"),
+ Reviewer("Tony Chang", "tony@chromium.org", "tony^work"),
+ Reviewer(u"Tor Arne Vestb\u00f8", ["vestbo@webkit.org", "tor.arne.vestbo@nokia.com"], "torarne"),
+ Reviewer("Vicki Murley", "vicki@apple.com"),
+ Reviewer("Xan Lopez", ["xan.lopez@gmail.com", "xan@gnome.org", "xan@webkit.org"], "xan"),
+ Reviewer("Yury Semikhatsky", "yurys@chromium.org", "yurys"),
+ Reviewer("Zack Rusin", "zack@kde.org", "zackr"),
+]
+
+
+class CommitterList:
+
+ # Committers and reviewers are passed in to allow easy testing
+
+ def __init__(self,
+ committers=committers_unable_to_review,
+ reviewers=reviewers_list):
+ self._committers = committers + reviewers
+ self._reviewers = reviewers
+ self._committers_by_email = {}
+
+ def committers(self):
+ return self._committers
+
+ def reviewers(self):
+ return self._reviewers
+
+ def _email_to_committer_map(self):
+ if not len(self._committers_by_email):
+ for committer in self._committers:
+ for email in committer.emails:
+ self._committers_by_email[email] = committer
+ return self._committers_by_email
+
+ def committer_by_name(self, name):
+ # This could be made into a hash lookup if callers need it to be fast.
+ for committer in self.committers():
+ if committer.full_name == name:
+ return committer
+
+ def committer_by_email(self, email):
+ return self._email_to_committer_map().get(email)
+
+ def reviewer_by_email(self, email):
+ committer = self.committer_by_email(email)
+ if committer and not committer.can_review:
+ return None
+ return committer
diff --git a/Tools/Scripts/webkitpy/common/config/committers_unittest.py b/Tools/Scripts/webkitpy/common/config/committers_unittest.py
new file mode 100644
index 0000000..068c0ee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/config/committers_unittest.py
@@ -0,0 +1,72 @@
+# 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 unittest
+from webkitpy.common.config.committers import CommitterList, Committer, Reviewer
+
+class CommittersTest(unittest.TestCase):
+
+ def test_committer_lookup(self):
+ committer = Committer('Test One', 'one@test.com', 'one')
+ reviewer = Reviewer('Test Two', ['two@test.com', 'two@rad.com', 'so_two@gmail.com'])
+ committer_list = CommitterList(committers=[committer], reviewers=[reviewer])
+
+ # Test valid committer and reviewer lookup
+ self.assertEqual(committer_list.committer_by_email('one@test.com'), committer)
+ self.assertEqual(committer_list.reviewer_by_email('two@test.com'), reviewer)
+ self.assertEqual(committer_list.committer_by_email('two@test.com'), reviewer)
+ self.assertEqual(committer_list.committer_by_email('two@rad.com'), reviewer)
+ self.assertEqual(committer_list.reviewer_by_email('so_two@gmail.com'), reviewer)
+
+ # Test valid committer and reviewer lookup
+ self.assertEqual(committer_list.committer_by_name("Test One"), committer)
+ self.assertEqual(committer_list.committer_by_name("Test Two"), reviewer)
+ self.assertEqual(committer_list.committer_by_name("Test Three"), None)
+
+ # Test that the first email is assumed to be the Bugzilla email address (for now)
+ self.assertEqual(committer_list.committer_by_email('two@rad.com').bugzilla_email(), 'two@test.com')
+
+ # Test that a known committer is not returned during reviewer lookup
+ self.assertEqual(committer_list.reviewer_by_email('one@test.com'), None)
+
+ # Test that unknown email address fail both committer and reviewer lookup
+ self.assertEqual(committer_list.committer_by_email('bar@bar.com'), None)
+ self.assertEqual(committer_list.reviewer_by_email('bar@bar.com'), None)
+
+ # Test that emails returns a list.
+ self.assertEqual(committer.emails, ['one@test.com'])
+
+ self.assertEqual(committer.irc_nickname, 'one')
+
+ # Test that committers returns committers and reviewers and reviewers() just reviewers.
+ self.assertEqual(committer_list.committers(), [committer, reviewer])
+ self.assertEqual(committer_list.reviewers(), [reviewer])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/config/committervalidator.py b/Tools/Scripts/webkitpy/common/config/committervalidator.py
new file mode 100644
index 0000000..9b1bbea
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/config/committervalidator.py
@@ -0,0 +1,114 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+# Copyright (c) 2010 Research In Motion Limited. 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 os
+
+from webkitpy.common.system.ospath import relpath
+from webkitpy.common.config import committers, urls
+
+
+class CommitterValidator(object):
+
+ def __init__(self, bugzilla):
+ self._bugzilla = bugzilla
+
+ def _checkout_root(self):
+ # FIXME: This is a hack, we would have this from scm.checkout_root
+ # if we had any way to get to an scm object here.
+ components = __file__.split(os.sep)
+ tools_index = components.index("Tools")
+ return os.sep.join(components[:tools_index])
+
+ def _committers_py_path(self):
+ # extension can sometimes be .pyc, we always want .py
+ (path, extension) = os.path.splitext(committers.__file__)
+ # FIXME: When we're allowed to use python 2.6 we can use the real
+ # os.path.relpath
+ path = relpath(path, self._checkout_root())
+ return ".".join([path, "py"])
+
+ def _flag_permission_rejection_message(self, setter_email, flag_name):
+ # This could be queried from the status_server.
+ queue_administrator = "eseidel@chromium.org"
+ # This could be queried from the tool.
+ queue_name = "commit-queue"
+ committers_list = self._committers_py_path()
+ message = "%s does not have %s permissions according to %s." % (
+ setter_email,
+ flag_name,
+ urls.view_source_url(committers_list))
+ message += "\n\n- If you do not have %s rights please read %s for instructions on how to use bugzilla flags." % (
+ flag_name, urls.contribution_guidelines)
+ message += "\n\n- If you have %s rights please correct the error in %s by adding yourself to the file (no review needed). " % (
+ flag_name, committers_list)
+ message += "The %s restarts itself every 2 hours. After restart the %s will correctly respect your %s rights." % (
+ queue_name, queue_name, flag_name)
+ return message
+
+ def _validate_setter_email(self, patch, result_key, rejection_function):
+ committer = getattr(patch, result_key)()
+ # If the flag is set, and we don't recognize the setter, reject the
+ # flag!
+ setter_email = patch._attachment_dictionary.get("%s_email" % result_key)
+ if setter_email and not committer:
+ rejection_function(patch.id(),
+ self._flag_permission_rejection_message(setter_email,
+ result_key))
+ return False
+ return True
+
+ def _reject_patch_if_flags_are_invalid(self, patch):
+ return (self._validate_setter_email(
+ patch, "reviewer", self.reject_patch_from_review_queue)
+ and self._validate_setter_email(
+ patch, "committer", self.reject_patch_from_commit_queue))
+
+ def patches_after_rejecting_invalid_commiters_and_reviewers(self, patches):
+ return [patch for patch in patches if self._reject_patch_if_flags_are_invalid(patch)]
+
+ def reject_patch_from_commit_queue(self,
+ attachment_id,
+ additional_comment_text=None):
+ comment_text = "Rejecting attachment %s from commit-queue." % attachment_id
+ self._bugzilla.set_flag_on_attachment(attachment_id,
+ "commit-queue",
+ "-",
+ comment_text,
+ additional_comment_text)
+
+ def reject_patch_from_review_queue(self,
+ attachment_id,
+ additional_comment_text=None):
+ comment_text = "Rejecting attachment %s from review queue." % attachment_id
+ self._bugzilla.set_flag_on_attachment(attachment_id,
+ 'review',
+ '-',
+ comment_text,
+ additional_comment_text)
diff --git a/Tools/Scripts/webkitpy/common/config/committervalidator_unittest.py b/Tools/Scripts/webkitpy/common/config/committervalidator_unittest.py
new file mode 100644
index 0000000..58fd3a5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/config/committervalidator_unittest.py
@@ -0,0 +1,43 @@
+# 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 unittest
+
+from .committervalidator import CommitterValidator
+
+
+class CommitterValidatorTest(unittest.TestCase):
+ def test_flag_permission_rejection_message(self):
+ validator = CommitterValidator(bugzilla=None)
+ self.assertEqual(validator._committers_py_path(), "Tools/Scripts/webkitpy/common/config/committers.py")
+ expected_messsage = """foo@foo.com does not have review permissions according to http://trac.webkit.org/browser/trunk/Tools/Scripts/webkitpy/common/config/committers.py.
+
+- If you do not have review rights please read http://webkit.org/coding/contributing.html for instructions on how to use bugzilla flags.
+
+- If you have review rights please correct the error in Tools/Scripts/webkitpy/common/config/committers.py by adding yourself to the file (no review needed). The commit-queue restarts itself every 2 hours. After restart the commit-queue will correctly respect your review rights."""
+ self.assertEqual(validator._flag_permission_rejection_message("foo@foo.com", "review"), expected_messsage)
diff --git a/Tools/Scripts/webkitpy/common/config/irc.py b/Tools/Scripts/webkitpy/common/config/irc.py
new file mode 100644
index 0000000..950c573
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/config/irc.py
@@ -0,0 +1,31 @@
+# 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.
+
+server="irc.freenode.net"
+port=6667
+channel="#webkit"
diff --git a/Tools/Scripts/webkitpy/common/config/ports.py b/Tools/Scripts/webkitpy/common/config/ports.py
new file mode 100644
index 0000000..163d5ef
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/config/ports.py
@@ -0,0 +1,249 @@
+# 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.
+#
+# WebKit's Python module for understanding the various ports
+
+import os
+import platform
+
+from webkitpy.common.system.executive import Executive
+
+
+class WebKitPort(object):
+
+ # We might need to pass scm into this function for scm.checkout_root
+ @classmethod
+ def script_path(cls, script_name):
+ return os.path.join("Tools", "Scripts", script_name)
+
+ @staticmethod
+ def port(port_name):
+ ports = {
+ "chromium": ChromiumPort,
+ "chromium-xvfb": ChromiumXVFBPort,
+ "gtk": GtkPort,
+ "mac": MacPort,
+ "win": WinPort,
+ "qt": QtPort,
+ "efl": EflPort,
+ }
+ default_port = {
+ "Windows": WinPort,
+ "Darwin": MacPort,
+ }
+ # Do we really need MacPort as the ultimate default?
+ return ports.get(port_name, default_port.get(platform.system(), MacPort))
+
+ @staticmethod
+ def makeArgs():
+ args = '--makeargs="-j%s"' % Executive().cpu_count()
+ if os.environ.has_key('MAKEFLAGS'):
+ args = '--makeargs="%s"' % os.environ['MAKEFLAGS']
+ return args
+
+ @classmethod
+ def name(cls):
+ raise NotImplementedError("subclasses must implement")
+
+ @classmethod
+ def flag(cls):
+ raise NotImplementedError("subclasses must implement")
+
+ @classmethod
+ def update_webkit_command(cls):
+ return [cls.script_path("update-webkit")]
+
+ @classmethod
+ def build_webkit_command(cls, build_style=None):
+ command = [cls.script_path("build-webkit")]
+ if build_style == "debug":
+ command.append("--debug")
+ if build_style == "release":
+ command.append("--release")
+ return command
+
+ @classmethod
+ def run_javascriptcore_tests_command(cls):
+ return [cls.script_path("run-javascriptcore-tests")]
+
+ @classmethod
+ def run_webkit_tests_command(cls):
+ return [cls.script_path("run-webkit-tests")]
+
+ @classmethod
+ def run_python_unittests_command(cls):
+ return [cls.script_path("test-webkitpy")]
+
+ @classmethod
+ def run_perl_unittests_command(cls):
+ return [cls.script_path("test-webkitperl")]
+
+ @classmethod
+ def layout_tests_results_path(cls):
+ return "/tmp/layout-test-results/results.html"
+
+
+class MacPort(WebKitPort):
+
+ @classmethod
+ def name(cls):
+ return "Mac"
+
+ @classmethod
+ def flag(cls):
+ return "--port=mac"
+
+ @classmethod
+ def _system_version(cls):
+ version_string = platform.mac_ver()[0] # e.g. "10.5.6"
+ version_tuple = version_string.split('.')
+ return map(int, version_tuple)
+
+ @classmethod
+ def is_leopard(cls):
+ return tuple(cls._system_version()[:2]) == (10, 5)
+
+
+class WinPort(WebKitPort):
+
+ @classmethod
+ def name(cls):
+ return "Win"
+
+ @classmethod
+ def flag(cls):
+ # FIXME: This is lame. We should autogenerate this from a codename or something.
+ return "--port=win"
+
+
+class GtkPort(WebKitPort):
+
+ @classmethod
+ def name(cls):
+ return "Gtk"
+
+ @classmethod
+ def flag(cls):
+ return "--port=gtk"
+
+ @classmethod
+ def build_webkit_command(cls, build_style=None):
+ command = WebKitPort.build_webkit_command(build_style=build_style)
+ command.append("--gtk")
+ command.append(WebKitPort.makeArgs())
+ return command
+
+ @classmethod
+ def run_webkit_tests_command(cls):
+ command = WebKitPort.run_webkit_tests_command()
+ command.append("--gtk")
+ return command
+
+
+class QtPort(WebKitPort):
+
+ @classmethod
+ def name(cls):
+ return "Qt"
+
+ @classmethod
+ def flag(cls):
+ return "--port=qt"
+
+ @classmethod
+ def build_webkit_command(cls, build_style=None):
+ command = WebKitPort.build_webkit_command(build_style=build_style)
+ command.append("--qt")
+ command.append(WebKitPort.makeArgs())
+ return command
+
+
+class EflPort(WebKitPort):
+
+ @classmethod
+ def name(cls):
+ return "Efl"
+
+ @classmethod
+ def flag(cls):
+ return "--port=efl"
+
+ @classmethod
+ def build_webkit_command(cls, build_style=None):
+ command = WebKitPort.build_webkit_command(build_style=build_style)
+ command.append("--efl")
+ command.append(WebKitPort.makeArgs())
+ return command
+
+
+class ChromiumPort(WebKitPort):
+
+ @classmethod
+ def name(cls):
+ return "Chromium"
+
+ @classmethod
+ def flag(cls):
+ return "--port=chromium"
+
+ @classmethod
+ def update_webkit_command(cls):
+ command = WebKitPort.update_webkit_command()
+ command.append("--chromium")
+ return command
+
+ @classmethod
+ def build_webkit_command(cls, build_style=None):
+ command = WebKitPort.build_webkit_command(build_style=build_style)
+ command.append("--chromium")
+ command.append("--update-chromium")
+ return command
+
+ @classmethod
+ def run_webkit_tests_command(cls):
+ return [
+ cls.script_path("new-run-webkit-tests"),
+ "--chromium",
+ "--no-pixel-tests",
+ ]
+
+ @classmethod
+ def run_javascriptcore_tests_command(cls):
+ return None
+
+
+class ChromiumXVFBPort(ChromiumPort):
+
+ @classmethod
+ def flag(cls):
+ return "--port=chromium-xvfb"
+
+ @classmethod
+ def run_webkit_tests_command(cls):
+ # FIXME: We should find a better way to do this.
+ return ["xvfb-run"] + ChromiumPort.run_webkit_tests_command()
diff --git a/Tools/Scripts/webkitpy/common/config/ports_unittest.py b/Tools/Scripts/webkitpy/common/config/ports_unittest.py
new file mode 100644
index 0000000..ba255c0
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/config/ports_unittest.py
@@ -0,0 +1,76 @@
+#!/usr/bin/env python
+# 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 unittest
+
+from webkitpy.common.config.ports import *
+
+
+class WebKitPortTest(unittest.TestCase):
+ def test_mac_port(self):
+ self.assertEquals(MacPort.name(), "Mac")
+ self.assertEquals(MacPort.flag(), "--port=mac")
+ self.assertEquals(MacPort.run_webkit_tests_command(), [WebKitPort.script_path("run-webkit-tests")])
+ self.assertEquals(MacPort.build_webkit_command(), [WebKitPort.script_path("build-webkit")])
+ self.assertEquals(MacPort.build_webkit_command(build_style="debug"), [WebKitPort.script_path("build-webkit"), "--debug"])
+ self.assertEquals(MacPort.build_webkit_command(build_style="release"), [WebKitPort.script_path("build-webkit"), "--release"])
+
+ class TestIsLeopard(MacPort):
+ @classmethod
+ def _system_version(cls):
+ return [10, 5]
+ self.assertTrue(TestIsLeopard.is_leopard())
+
+ def test_gtk_port(self):
+ self.assertEquals(GtkPort.name(), "Gtk")
+ self.assertEquals(GtkPort.flag(), "--port=gtk")
+ self.assertEquals(GtkPort.run_webkit_tests_command(), [WebKitPort.script_path("run-webkit-tests"), "--gtk"])
+ self.assertEquals(GtkPort.build_webkit_command(), [WebKitPort.script_path("build-webkit"), "--gtk", WebKitPort.makeArgs()])
+ self.assertEquals(GtkPort.build_webkit_command(build_style="debug"), [WebKitPort.script_path("build-webkit"), "--debug", "--gtk", WebKitPort.makeArgs()])
+
+ def test_qt_port(self):
+ self.assertEquals(QtPort.name(), "Qt")
+ self.assertEquals(QtPort.flag(), "--port=qt")
+ self.assertEquals(QtPort.run_webkit_tests_command(), [WebKitPort.script_path("run-webkit-tests")])
+ self.assertEquals(QtPort.build_webkit_command(), [WebKitPort.script_path("build-webkit"), "--qt", WebKitPort.makeArgs()])
+ self.assertEquals(QtPort.build_webkit_command(build_style="debug"), [WebKitPort.script_path("build-webkit"), "--debug", "--qt", WebKitPort.makeArgs()])
+
+ def test_chromium_port(self):
+ self.assertEquals(ChromiumPort.name(), "Chromium")
+ self.assertEquals(ChromiumPort.flag(), "--port=chromium")
+ self.assertEquals(ChromiumPort.run_webkit_tests_command(), [WebKitPort.script_path("new-run-webkit-tests"), "--chromium", "--no-pixel-tests"])
+ self.assertEquals(ChromiumPort.build_webkit_command(), [WebKitPort.script_path("build-webkit"), "--chromium", "--update-chromium"])
+ self.assertEquals(ChromiumPort.build_webkit_command(build_style="debug"), [WebKitPort.script_path("build-webkit"), "--debug", "--chromium", "--update-chromium"])
+ self.assertEquals(ChromiumPort.update_webkit_command(), [WebKitPort.script_path("update-webkit"), "--chromium"])
+
+ def test_chromium_xvfb_port(self):
+ self.assertEquals(ChromiumXVFBPort.run_webkit_tests_command(), ["xvfb-run", "Tools/Scripts/new-run-webkit-tests", "--chromium", "--no-pixel-tests"])
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/config/urls.py b/Tools/Scripts/webkitpy/common/config/urls.py
new file mode 100644
index 0000000..dfa6d69
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/config/urls.py
@@ -0,0 +1,38 @@
+# 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.
+
+
+def view_source_url(local_path):
+ return "http://trac.webkit.org/browser/trunk/%s" % local_path
+
+
+def view_revision_url(revision_number):
+ return "http://trac.webkit.org/changeset/%s" % revision_number
+
+
+contribution_guidelines = "http://webkit.org/coding/contributing.html"
diff --git a/Tools/Scripts/webkitpy/common/memoized.py b/Tools/Scripts/webkitpy/common/memoized.py
new file mode 100644
index 0000000..dc844a5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/memoized.py
@@ -0,0 +1,55 @@
+# 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.
+
+# Python does not (yet) seem to provide automatic memoization. So we've
+# written a small decorator to do so.
+
+import functools
+
+
+class memoized(object):
+ def __init__(self, function):
+ self._function = function
+ self._results_cache = {}
+
+ def __call__(self, *args):
+ try:
+ return self._results_cache[args]
+ except KeyError:
+ # If we didn't find the args in our cache, call and save the results.
+ result = self._function(*args)
+ self._results_cache[args] = result
+ return result
+ # FIXME: We may need to handle TypeError here in the case
+ # that "args" is not a valid dictionary key.
+
+ # Use python "descriptor" protocol __get__ to appear
+ # invisible during property access.
+ def __get__(self, instance, owner):
+ # Return a function partial with obj already bound as self.
+ return functools.partial(self.__call__, instance)
diff --git a/Tools/Scripts/webkitpy/common/memoized_unittest.py b/Tools/Scripts/webkitpy/common/memoized_unittest.py
new file mode 100644
index 0000000..dd7c793
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/memoized_unittest.py
@@ -0,0 +1,65 @@
+# 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 unittest
+
+from webkitpy.common.memoized import memoized
+
+
+class _TestObject(object):
+ def __init__(self):
+ self.callCount = 0
+
+ @memoized
+ def memoized_add(self, argument):
+ """testing docstring"""
+ self.callCount += 1
+ if argument is None:
+ return None # Avoid the TypeError from None + 1
+ return argument + 1
+
+
+class MemoizedTest(unittest.TestCase):
+ def test_caching(self):
+ test = _TestObject()
+ test.callCount = 0
+ self.assertEqual(test.memoized_add(1), 2)
+ self.assertEqual(test.callCount, 1)
+ self.assertEqual(test.memoized_add(1), 2)
+ self.assertEqual(test.callCount, 1)
+
+ # Validate that callCount is working as expected.
+ self.assertEqual(test.memoized_add(2), 3)
+ self.assertEqual(test.callCount, 2)
+
+ def test_tearoff(self):
+ test = _TestObject()
+ # Make sure that get()/tear-offs work:
+ tearoff = test.memoized_add
+ self.assertEqual(tearoff(4), 5)
+ self.assertEqual(test.callCount, 1)
diff --git a/Tools/Scripts/webkitpy/common/net/__init__.py b/Tools/Scripts/webkitpy/common/net/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/__init__.py b/Tools/Scripts/webkitpy/common/net/bugzilla/__init__.py
new file mode 100644
index 0000000..cfaf3b1
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/bugzilla/__init__.py
@@ -0,0 +1,8 @@
+# Required for Python to search this directory for module files
+
+# We only export public API here.
+# FIXME: parse_bug_id should not be a free function.
+from .bugzilla import Bugzilla, parse_bug_id
+# Unclear if Bug and Attachment need to be public classes.
+from .bug import Bug
+from .attachment import Attachment
diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/attachment.py b/Tools/Scripts/webkitpy/common/net/bugzilla/attachment.py
new file mode 100644
index 0000000..85761fe
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/bugzilla/attachment.py
@@ -0,0 +1,114 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+# Copyright (c) 2010 Research In Motion Limited. 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.
+
+from webkitpy.common.system.deprecated_logging import log
+
+
+class Attachment(object):
+
+ rollout_preamble = "ROLLOUT of r"
+
+ def __init__(self, attachment_dictionary, bug):
+ self._attachment_dictionary = attachment_dictionary
+ self._bug = bug
+ self._reviewer = None
+ self._committer = None
+
+ def _bugzilla(self):
+ return self._bug._bugzilla
+
+ def id(self):
+ return int(self._attachment_dictionary.get("id"))
+
+ def attacher_is_committer(self):
+ return self._bugzilla.committers.committer_by_email(
+ patch.attacher_email())
+
+ def attacher_email(self):
+ return self._attachment_dictionary.get("attacher_email")
+
+ def bug(self):
+ return self._bug
+
+ def bug_id(self):
+ return int(self._attachment_dictionary.get("bug_id"))
+
+ def is_patch(self):
+ return not not self._attachment_dictionary.get("is_patch")
+
+ def is_obsolete(self):
+ return not not self._attachment_dictionary.get("is_obsolete")
+
+ def is_rollout(self):
+ return self.name().startswith(self.rollout_preamble)
+
+ def name(self):
+ return self._attachment_dictionary.get("name")
+
+ def attach_date(self):
+ return self._attachment_dictionary.get("attach_date")
+
+ def review(self):
+ return self._attachment_dictionary.get("review")
+
+ def commit_queue(self):
+ return self._attachment_dictionary.get("commit-queue")
+
+ def url(self):
+ # FIXME: This should just return
+ # self._bugzilla().attachment_url_for_id(self.id()). scm_unittest.py
+ # depends on the current behavior.
+ return self._attachment_dictionary.get("url")
+
+ def contents(self):
+ # FIXME: We shouldn't be grabbing at _bugzilla.
+ return self._bug._bugzilla.fetch_attachment_contents(self.id())
+
+ def _validate_flag_value(self, flag):
+ email = self._attachment_dictionary.get("%s_email" % flag)
+ if not email:
+ return None
+ committer = getattr(self._bugzilla().committers,
+ "%s_by_email" % flag)(email)
+ if committer:
+ return committer
+ log("Warning, attachment %s on bug %s has invalid %s (%s)" % (
+ self._attachment_dictionary['id'],
+ self._attachment_dictionary['bug_id'], flag, email))
+
+ def reviewer(self):
+ if not self._reviewer:
+ self._reviewer = self._validate_flag_value("reviewer")
+ return self._reviewer
+
+ def committer(self):
+ if not self._committer:
+ self._committer = self._validate_flag_value("committer")
+ return self._committer
diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py b/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
new file mode 100644
index 0000000..af258eb
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/bugzilla/bug.py
@@ -0,0 +1,111 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+# Copyright (c) 2010 Research In Motion Limited. 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.
+
+from .attachment import Attachment
+
+
+class Bug(object):
+ # FIXME: This class is kinda a hack for now. It exists so we have one
+ # place to hold bug logic, even if much of the code deals with
+ # dictionaries still.
+
+ def __init__(self, bug_dictionary, bugzilla):
+ self.bug_dictionary = bug_dictionary
+ self._bugzilla = bugzilla
+
+ def id(self):
+ return self.bug_dictionary["id"]
+
+ def title(self):
+ return self.bug_dictionary["title"]
+
+ def reporter_email(self):
+ return self.bug_dictionary["reporter_email"]
+
+ def assigned_to_email(self):
+ return self.bug_dictionary["assigned_to_email"]
+
+ # FIXME: This information should be stored in some sort of webkit_config.py instead of here.
+ unassigned_emails = frozenset([
+ "webkit-unassigned@lists.webkit.org",
+ "webkit-qt-unassigned@trolltech.com",
+ ])
+
+ def is_unassigned(self):
+ return self.assigned_to_email() in self.unassigned_emails
+
+ def status(self):
+ return self.bug_dictionary["bug_status"]
+
+ # Bugzilla has many status states we don't really use in WebKit:
+ # https://bugs.webkit.org/page.cgi?id=fields.html#status
+ _open_states = ["UNCONFIRMED", "NEW", "ASSIGNED", "REOPENED"]
+ _closed_states = ["RESOLVED", "VERIFIED", "CLOSED"]
+
+ def is_open(self):
+ return self.status() in self._open_states
+
+ def is_closed(self):
+ return not self.is_open()
+
+ def duplicate_of(self):
+ return self.bug_dictionary.get('dup_id', None)
+
+ # Rarely do we actually want obsolete attachments
+ def attachments(self, include_obsolete=False):
+ attachments = self.bug_dictionary["attachments"]
+ if not include_obsolete:
+ attachments = filter(lambda attachment:
+ not attachment["is_obsolete"], attachments)
+ return [Attachment(attachment, self) for attachment in attachments]
+
+ def patches(self, include_obsolete=False):
+ return [patch for patch in self.attachments(include_obsolete)
+ if patch.is_patch()]
+
+ def unreviewed_patches(self):
+ return [patch for patch in self.patches() if patch.review() == "?"]
+
+ def reviewed_patches(self, include_invalid=False):
+ patches = [patch for patch in self.patches() if patch.review() == "+"]
+ if include_invalid:
+ return patches
+ # Checking reviewer() ensures that it was both reviewed and has a valid
+ # reviewer.
+ return filter(lambda patch: patch.reviewer(), patches)
+
+ def commit_queued_patches(self, include_invalid=False):
+ patches = [patch for patch in self.patches()
+ if patch.commit_queue() == "+"]
+ if include_invalid:
+ return patches
+ # Checking committer() ensures that it was both commit-queue+'d and has
+ # a valid committer.
+ return filter(lambda patch: patch.committer(), patches)
diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/bug_unittest.py b/Tools/Scripts/webkitpy/common/net/bugzilla/bug_unittest.py
new file mode 100644
index 0000000..d43d64f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/bugzilla/bug_unittest.py
@@ -0,0 +1,40 @@
+# 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 unittest
+
+from .bug import Bug
+
+
+class BugTest(unittest.TestCase):
+ def test_is_unassigned(self):
+ for email in Bug.unassigned_emails:
+ bug = Bug({"assigned_to_email": email}, bugzilla=None)
+ self.assertTrue(bug.is_unassigned())
+ bug = Bug({"assigned_to_email": "test@test.com"}, bugzilla=None)
+ self.assertFalse(bug.is_unassigned())
diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py
new file mode 100644
index 0000000..d6210d5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla.py
@@ -0,0 +1,761 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# Copyright (c) 2009 Apple Inc. All rights reserved.
+# Copyright (c) 2010 Research In Motion Limited. 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.
+#
+# WebKit's Python module for interacting with Bugzilla
+
+import os.path
+import re
+import StringIO
+import urllib
+
+from datetime import datetime # used in timestamp()
+
+from .attachment import Attachment
+from .bug import Bug
+
+from webkitpy.common.system.deprecated_logging import log
+from webkitpy.common.config import committers
+from webkitpy.common.net.credentials import Credentials
+from webkitpy.common.system.user import User
+from webkitpy.thirdparty.autoinstalled.mechanize import Browser
+from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup, SoupStrainer
+
+
+# FIXME: parse_bug_id should not be a free function.
+def parse_bug_id(message):
+ if not message:
+ return None
+ match = re.search("http\://webkit\.org/b/(?P<bug_id>\d+)", message)
+ if match:
+ return int(match.group('bug_id'))
+ match = re.search(
+ Bugzilla.bug_server_regex + "show_bug\.cgi\?id=(?P<bug_id>\d+)",
+ message)
+ if match:
+ return int(match.group('bug_id'))
+ return None
+
+
+def timestamp():
+ return datetime.now().strftime("%Y%m%d%H%M%S")
+
+
+# A container for all of the logic for making and parsing buzilla queries.
+class BugzillaQueries(object):
+
+ def __init__(self, bugzilla):
+ self._bugzilla = bugzilla
+
+ def _is_xml_bugs_form(self, form):
+ # ClientForm.HTMLForm.find_control throws if the control is not found,
+ # so we do a manual search instead:
+ return "xml" in [control.id for control in form.controls]
+
+ # This is kinda a hack. There is probably a better way to get this information from bugzilla.
+ def _parse_result_count(self, results_page):
+ result_count_text = BeautifulSoup(results_page).find(attrs={'class': 'bz_result_count'}).string
+ result_count_parts = result_count_text.strip().split(" ")
+ if result_count_parts[0] == "Zarro":
+ return 0
+ if result_count_parts[0] == "One":
+ return 1
+ return int(result_count_parts[0])
+
+ # Note: _load_query, _fetch_bug and _fetch_bugs_from_advanced_query
+ # are the only methods which access self._bugzilla.
+
+ def _load_query(self, query):
+ self._bugzilla.authenticate()
+ full_url = "%s%s" % (self._bugzilla.bug_server_url, query)
+ return self._bugzilla.browser.open(full_url)
+
+ def _fetch_bugs_from_advanced_query(self, query):
+ results_page = self._load_query(query)
+ if not self._parse_result_count(results_page):
+ return []
+ # Bugzilla results pages have an "XML" submit button at the bottom
+ # which can be used to get an XML page containing all of the <bug> elements.
+ # This is slighty lame that this assumes that _load_query used
+ # self._bugzilla.browser and that it's in an acceptable state.
+ self._bugzilla.browser.select_form(predicate=self._is_xml_bugs_form)
+ bugs_xml = self._bugzilla.browser.submit()
+ return self._bugzilla._parse_bugs_from_xml(bugs_xml)
+
+ def _fetch_bug(self, bug_id):
+ return self._bugzilla.fetch_bug(bug_id)
+
+ def _fetch_bug_ids_advanced_query(self, query):
+ soup = BeautifulSoup(self._load_query(query))
+ # The contents of the <a> inside the cells in the first column happen
+ # to be the bug id.
+ return [int(bug_link_cell.find("a").string)
+ for bug_link_cell in soup('td', "first-child")]
+
+ def _parse_attachment_ids_request_query(self, page):
+ digits = re.compile("\d+")
+ attachment_href = re.compile("attachment.cgi\?id=\d+&action=review")
+ attachment_links = SoupStrainer("a", href=attachment_href)
+ return [int(digits.search(tag["href"]).group(0))
+ for tag in BeautifulSoup(page, parseOnlyThese=attachment_links)]
+
+ def _fetch_attachment_ids_request_query(self, query):
+ return self._parse_attachment_ids_request_query(self._load_query(query))
+
+ def _parse_quips(self, page):
+ soup = BeautifulSoup(page, convertEntities=BeautifulSoup.HTML_ENTITIES)
+ quips = soup.find(text=re.compile(r"Existing quips:")).findNext("ul").findAll("li")
+ return [unicode(quip_entry.string) for quip_entry in quips]
+
+ def fetch_quips(self):
+ return self._parse_quips(self._load_query("/quips.cgi?action=show"))
+
+ # List of all r+'d bugs.
+ def fetch_bug_ids_from_pending_commit_list(self):
+ needs_commit_query_url = "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=review%2B"
+ return self._fetch_bug_ids_advanced_query(needs_commit_query_url)
+
+ def fetch_bugs_matching_quicksearch(self, search_string):
+ # We may want to use a more explicit query than "quicksearch".
+ # If quicksearch changes we should probably change to use
+ # a normal buglist.cgi?query_format=advanced query.
+ quicksearch_url = "buglist.cgi?quicksearch=%s" % urllib.quote(search_string)
+ return self._fetch_bugs_from_advanced_query(quicksearch_url)
+
+ # Currently this returns all bugs across all components.
+ # In the future we may wish to extend this API to construct more restricted searches.
+ def fetch_bugs_matching_search(self, search_string, author_email=None):
+ query = "buglist.cgi?query_format=advanced"
+ if search_string:
+ query += "&short_desc_type=allwordssubstr&short_desc=%s" % urllib.quote(search_string)
+ if author_email:
+ query += "&emailreporter1=1&emailtype1=substring&email1=%s" % urllib.quote(search_string)
+ return self._fetch_bugs_from_advanced_query(query)
+
+ def fetch_patches_from_pending_commit_list(self):
+ return sum([self._fetch_bug(bug_id).reviewed_patches()
+ for bug_id in self.fetch_bug_ids_from_pending_commit_list()], [])
+
+ def fetch_bug_ids_from_commit_queue(self):
+ commit_queue_url = "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=commit-queue%2B&order=Last+Changed"
+ return self._fetch_bug_ids_advanced_query(commit_queue_url)
+
+ def fetch_patches_from_commit_queue(self):
+ # This function will only return patches which have valid committers
+ # set. It won't reject patches with invalid committers/reviewers.
+ return sum([self._fetch_bug(bug_id).commit_queued_patches()
+ for bug_id in self.fetch_bug_ids_from_commit_queue()], [])
+
+ def fetch_bug_ids_from_review_queue(self):
+ review_queue_url = "buglist.cgi?query_format=advanced&bug_status=UNCONFIRMED&bug_status=NEW&bug_status=ASSIGNED&bug_status=REOPENED&field0-0-0=flagtypes.name&type0-0-0=equals&value0-0-0=review?"
+ return self._fetch_bug_ids_advanced_query(review_queue_url)
+
+ # This method will make several requests to bugzilla.
+ def fetch_patches_from_review_queue(self, limit=None):
+ # [:None] returns the whole array.
+ return sum([self._fetch_bug(bug_id).unreviewed_patches()
+ for bug_id in self.fetch_bug_ids_from_review_queue()[:limit]], [])
+
+ # NOTE: This is the only client of _fetch_attachment_ids_request_query
+ # This method only makes one request to bugzilla.
+ def fetch_attachment_ids_from_review_queue(self):
+ review_queue_url = "request.cgi?action=queue&type=review&group=type"
+ return self._fetch_attachment_ids_request_query(review_queue_url)
+
+
+class Bugzilla(object):
+
+ def __init__(self, dryrun=False, committers=committers.CommitterList()):
+ self.dryrun = dryrun
+ self.authenticated = False
+ self.queries = BugzillaQueries(self)
+ self.committers = committers
+ self.cached_quips = []
+
+ # FIXME: We should use some sort of Browser mock object when in dryrun
+ # mode (to prevent any mistakes).
+ self.browser = Browser()
+ # Ignore bugs.webkit.org/robots.txt until we fix it to allow this
+ # script.
+ self.browser.set_handle_robots(False)
+
+ # FIXME: Much of this should go into some sort of config module:
+ bug_server_host = "bugs.webkit.org"
+ bug_server_regex = "https?://%s/" % re.sub('\.', '\\.', bug_server_host)
+ bug_server_url = "https://%s/" % bug_server_host
+
+ def quips(self):
+ # We only fetch and parse the list of quips once per instantiation
+ # so that we do not burden bugs.webkit.org.
+ if not self.cached_quips and not self.dryrun:
+ self.cached_quips = self.queries.fetch_quips()
+ return self.cached_quips
+
+ def bug_url_for_bug_id(self, bug_id, xml=False):
+ if not bug_id:
+ return None
+ content_type = "&ctype=xml" if xml else ""
+ return "%sshow_bug.cgi?id=%s%s" % (self.bug_server_url, bug_id, content_type)
+
+ def short_bug_url_for_bug_id(self, bug_id):
+ if not bug_id:
+ return None
+ return "http://webkit.org/b/%s" % bug_id
+
+ def add_attachment_url(self, bug_id):
+ return "%sattachment.cgi?action=enter&bugid=%s" % (self.bug_server_url, bug_id)
+
+ def attachment_url_for_id(self, attachment_id, action="view"):
+ if not attachment_id:
+ return None
+ action_param = ""
+ if action and action != "view":
+ action_param = "&action=%s" % action
+ return "%sattachment.cgi?id=%s%s" % (self.bug_server_url,
+ attachment_id,
+ action_param)
+
+ def _parse_attachment_flag(self,
+ element,
+ flag_name,
+ attachment,
+ result_key):
+ flag = element.find('flag', attrs={'name': flag_name})
+ if flag:
+ attachment[flag_name] = flag['status']
+ if flag['status'] == '+':
+ attachment[result_key] = flag['setter']
+ # Sadly show_bug.cgi?ctype=xml does not expose the flag modification date.
+
+ def _string_contents(self, soup):
+ # WebKit's bugzilla instance uses UTF-8.
+ # BeautifulSoup always returns Unicode strings, however
+ # the .string method returns a (unicode) NavigableString.
+ # NavigableString can confuse other parts of the code, so we
+ # convert from NavigableString to a real unicode() object using unicode().
+ return unicode(soup.string)
+
+ # Example: 2010-01-20 14:31 PST
+ # FIXME: Some bugzilla dates seem to have seconds in them?
+ # Python does not support timezones out of the box.
+ # Assume that bugzilla always uses PST (which is true for bugs.webkit.org)
+ _bugzilla_date_format = "%Y-%m-%d %H:%M"
+
+ @classmethod
+ def _parse_date(cls, date_string):
+ (date, time, time_zone) = date_string.split(" ")
+ # Ignore the timezone because python doesn't understand timezones out of the box.
+ date_string = "%s %s" % (date, time)
+ return datetime.strptime(date_string, cls._bugzilla_date_format)
+
+ def _date_contents(self, soup):
+ return self._parse_date(self._string_contents(soup))
+
+ def _parse_attachment_element(self, element, bug_id):
+ attachment = {}
+ attachment['bug_id'] = bug_id
+ attachment['is_obsolete'] = (element.has_key('isobsolete') and element['isobsolete'] == "1")
+ attachment['is_patch'] = (element.has_key('ispatch') and element['ispatch'] == "1")
+ attachment['id'] = int(element.find('attachid').string)
+ # FIXME: No need to parse out the url here.
+ attachment['url'] = self.attachment_url_for_id(attachment['id'])
+ attachment["attach_date"] = self._date_contents(element.find("date"))
+ attachment['name'] = self._string_contents(element.find('desc'))
+ attachment['attacher_email'] = self._string_contents(element.find('attacher'))
+ attachment['type'] = self._string_contents(element.find('type'))
+ self._parse_attachment_flag(
+ element, 'review', attachment, 'reviewer_email')
+ self._parse_attachment_flag(
+ element, 'commit-queue', attachment, 'committer_email')
+ return attachment
+
+ def _parse_bugs_from_xml(self, page):
+ soup = BeautifulSoup(page)
+ # Without the unicode() call, BeautifulSoup occasionally complains of being
+ # passed None for no apparent reason.
+ return [Bug(self._parse_bug_dictionary_from_xml(unicode(bug_xml)), self) for bug_xml in soup('bug')]
+
+ def _parse_bug_dictionary_from_xml(self, page):
+ soup = BeautifulSoup(page)
+ bug = {}
+ bug["id"] = int(soup.find("bug_id").string)
+ bug["title"] = self._string_contents(soup.find("short_desc"))
+ bug["bug_status"] = self._string_contents(soup.find("bug_status"))
+ dup_id = soup.find("dup_id")
+ if dup_id:
+ bug["dup_id"] = self._string_contents(dup_id)
+ bug["reporter_email"] = self._string_contents(soup.find("reporter"))
+ bug["assigned_to_email"] = self._string_contents(soup.find("assigned_to"))
+ bug["cc_emails"] = [self._string_contents(element) for element in soup.findAll('cc')]
+ bug["attachments"] = [self._parse_attachment_element(element, bug["id"]) for element in soup.findAll('attachment')]
+ return bug
+
+ # Makes testing fetch_*_from_bug() possible until we have a better
+ # BugzillaNetwork abstration.
+
+ def _fetch_bug_page(self, bug_id):
+ bug_url = self.bug_url_for_bug_id(bug_id, xml=True)
+ log("Fetching: %s" % bug_url)
+ return self.browser.open(bug_url)
+
+ def fetch_bug_dictionary(self, bug_id):
+ try:
+ return self._parse_bug_dictionary_from_xml(self._fetch_bug_page(bug_id))
+ except KeyboardInterrupt:
+ raise
+ except:
+ self.authenticate()
+ return self._parse_bug_dictionary_from_xml(self._fetch_bug_page(bug_id))
+
+ # FIXME: A BugzillaCache object should provide all these fetch_ methods.
+
+ def fetch_bug(self, bug_id):
+ return Bug(self.fetch_bug_dictionary(bug_id), self)
+
+ def fetch_attachment_contents(self, attachment_id):
+ attachment_url = self.attachment_url_for_id(attachment_id)
+ # We need to authenticate to download patches from security bugs.
+ self.authenticate()
+ return self.browser.open(attachment_url).read()
+
+ def _parse_bug_id_from_attachment_page(self, page):
+ # The "Up" relation happens to point to the bug.
+ up_link = BeautifulSoup(page).find('link', rel='Up')
+ if not up_link:
+ # This attachment does not exist (or you don't have permissions to
+ # view it).
+ return None
+ match = re.search("show_bug.cgi\?id=(?P<bug_id>\d+)", up_link['href'])
+ return int(match.group('bug_id'))
+
+ def bug_id_for_attachment_id(self, attachment_id):
+ self.authenticate()
+
+ attachment_url = self.attachment_url_for_id(attachment_id, 'edit')
+ log("Fetching: %s" % attachment_url)
+ page = self.browser.open(attachment_url)
+ return self._parse_bug_id_from_attachment_page(page)
+
+ # FIXME: This should just return Attachment(id), which should be able to
+ # lazily fetch needed data.
+
+ def fetch_attachment(self, attachment_id):
+ # We could grab all the attachment details off of the attachment edit
+ # page but we already have working code to do so off of the bugs page,
+ # so re-use that.
+ bug_id = self.bug_id_for_attachment_id(attachment_id)
+ if not bug_id:
+ return None
+ attachments = self.fetch_bug(bug_id).attachments(include_obsolete=True)
+ for attachment in attachments:
+ if attachment.id() == int(attachment_id):
+ return attachment
+ return None # This should never be hit.
+
+ def authenticate(self):
+ if self.authenticated:
+ return
+
+ if self.dryrun:
+ log("Skipping log in for dry run...")
+ self.authenticated = True
+ return
+
+ credentials = Credentials(self.bug_server_host, git_prefix="bugzilla")
+
+ attempts = 0
+ while not self.authenticated:
+ attempts += 1
+ username, password = credentials.read_credentials()
+
+ log("Logging in as %s..." % username)
+ self.browser.open(self.bug_server_url +
+ "index.cgi?GoAheadAndLogIn=1")
+ self.browser.select_form(name="login")
+ self.browser['Bugzilla_login'] = username
+ self.browser['Bugzilla_password'] = password
+ response = self.browser.submit()
+
+ match = re.search("<title>(.+?)</title>", response.read())
+ # If the resulting page has a title, and it contains the word
+ # "invalid" assume it's the login failure page.
+ if match and re.search("Invalid", match.group(1), re.IGNORECASE):
+ errorMessage = "Bugzilla login failed: %s" % match.group(1)
+ # raise an exception only if this was the last attempt
+ if attempts < 5:
+ log(errorMessage)
+ else:
+ raise Exception(errorMessage)
+ else:
+ self.authenticated = True
+ self.username = username
+
+ def _commit_queue_flag(self, mark_for_landing, mark_for_commit_queue):
+ if mark_for_landing:
+ return '+'
+ elif mark_for_commit_queue:
+ return '?'
+ return 'X'
+
+ # FIXME: mark_for_commit_queue and mark_for_landing should be joined into a single commit_flag argument.
+ def _fill_attachment_form(self,
+ description,
+ file_object,
+ mark_for_review=False,
+ mark_for_commit_queue=False,
+ mark_for_landing=False,
+ is_patch=False,
+ filename=None,
+ mimetype=None):
+ self.browser['description'] = description
+ if is_patch:
+ self.browser['ispatch'] = ("1",)
+ # FIXME: Should this use self._find_select_element_for_flag?
+ self.browser['flag_type-1'] = ('?',) if mark_for_review else ('X',)
+ self.browser['flag_type-3'] = (self._commit_queue_flag(mark_for_landing, mark_for_commit_queue),)
+
+ filename = filename or "%s.patch" % timestamp()
+ mimetype = mimetype or "text/plain"
+ self.browser.add_file(file_object, mimetype, filename, 'data')
+
+ def _file_object_for_upload(self, file_or_string):
+ if hasattr(file_or_string, 'read'):
+ return file_or_string
+ # Only if file_or_string is not already encoded do we want to encode it.
+ if isinstance(file_or_string, unicode):
+ file_or_string = file_or_string.encode('utf-8')
+ return StringIO.StringIO(file_or_string)
+
+ # timestamp argument is just for unittests.
+ def _filename_for_upload(self, file_object, bug_id, extension="txt", timestamp=timestamp):
+ if hasattr(file_object, "name"):
+ return file_object.name
+ return "bug-%s-%s.%s" % (bug_id, timestamp(), extension)
+
+ def add_attachment_to_bug(self,
+ bug_id,
+ file_or_string,
+ description,
+ filename=None,
+ comment_text=None):
+ self.authenticate()
+ log('Adding attachment "%s" to %s' % (description, self.bug_url_for_bug_id(bug_id)))
+ if self.dryrun:
+ log(comment_text)
+ return
+
+ self.browser.open(self.add_attachment_url(bug_id))
+ self.browser.select_form(name="entryform")
+ file_object = self._file_object_for_upload(file_or_string)
+ filename = filename or self._filename_for_upload(file_object, bug_id)
+ self._fill_attachment_form(description, file_object, filename=filename)
+ if comment_text:
+ log(comment_text)
+ self.browser['comment'] = comment_text
+ self.browser.submit()
+
+ # FIXME: The arguments to this function should be simplified and then
+ # this should be merged into add_attachment_to_bug
+ def add_patch_to_bug(self,
+ bug_id,
+ file_or_string,
+ description,
+ comment_text=None,
+ mark_for_review=False,
+ mark_for_commit_queue=False,
+ mark_for_landing=False):
+ self.authenticate()
+ log('Adding patch "%s" to %s' % (description, self.bug_url_for_bug_id(bug_id)))
+
+ if self.dryrun:
+ log(comment_text)
+ return
+
+ self.browser.open(self.add_attachment_url(bug_id))
+ self.browser.select_form(name="entryform")
+ file_object = self._file_object_for_upload(file_or_string)
+ filename = self._filename_for_upload(file_object, bug_id, extension="patch")
+ self._fill_attachment_form(description,
+ file_object,
+ mark_for_review=mark_for_review,
+ mark_for_commit_queue=mark_for_commit_queue,
+ mark_for_landing=mark_for_landing,
+ is_patch=True,
+ filename=filename)
+ if comment_text:
+ log(comment_text)
+ self.browser['comment'] = comment_text
+ self.browser.submit()
+
+ # FIXME: There has to be a more concise way to write this method.
+ def _check_create_bug_response(self, response_html):
+ match = re.search("<title>Bug (?P<bug_id>\d+) Submitted</title>",
+ response_html)
+ if match:
+ return match.group('bug_id')
+
+ match = re.search(
+ '<div id="bugzilla-body">(?P<error_message>.+)<div id="footer">',
+ response_html,
+ re.DOTALL)
+ error_message = "FAIL"
+ if match:
+ text_lines = BeautifulSoup(
+ match.group('error_message')).findAll(text=True)
+ error_message = "\n" + '\n'.join(
+ [" " + line.strip()
+ for line in text_lines if line.strip()])
+ raise Exception("Bug not created: %s" % error_message)
+
+ def create_bug(self,
+ bug_title,
+ bug_description,
+ component=None,
+ diff=None,
+ patch_description=None,
+ cc=None,
+ blocked=None,
+ assignee=None,
+ mark_for_review=False,
+ mark_for_commit_queue=False):
+ self.authenticate()
+
+ log('Creating bug with title "%s"' % bug_title)
+ if self.dryrun:
+ log(bug_description)
+ # FIXME: This will make some paths fail, as they assume this returns an id.
+ return
+
+ self.browser.open(self.bug_server_url + "enter_bug.cgi?product=WebKit")
+ self.browser.select_form(name="Create")
+ component_items = self.browser.find_control('component').items
+ component_names = map(lambda item: item.name, component_items)
+ if not component:
+ component = "New Bugs"
+ if component not in component_names:
+ component = User.prompt_with_list("Please pick a component:", component_names)
+ self.browser["component"] = [component]
+ if cc:
+ self.browser["cc"] = cc
+ if blocked:
+ self.browser["blocked"] = unicode(blocked)
+ if not assignee:
+ assignee = self.username
+ if assignee and not self.browser.find_control("assigned_to").disabled:
+ self.browser["assigned_to"] = assignee
+ self.browser["short_desc"] = bug_title
+ self.browser["comment"] = bug_description
+
+ if diff:
+ # _fill_attachment_form expects a file-like object
+ # Patch files are already binary, so no encoding needed.
+ assert(isinstance(diff, str))
+ patch_file_object = StringIO.StringIO(diff)
+ self._fill_attachment_form(
+ patch_description,
+ patch_file_object,
+ mark_for_review=mark_for_review,
+ mark_for_commit_queue=mark_for_commit_queue,
+ is_patch=True)
+
+ response = self.browser.submit()
+
+ bug_id = self._check_create_bug_response(response.read())
+ log("Bug %s created." % bug_id)
+ log("%sshow_bug.cgi?id=%s" % (self.bug_server_url, bug_id))
+ return bug_id
+
+ def _find_select_element_for_flag(self, flag_name):
+ # FIXME: This will break if we ever re-order attachment flags
+ if flag_name == "review":
+ return self.browser.find_control(type='select', nr=0)
+ elif flag_name == "commit-queue":
+ return self.browser.find_control(type='select', nr=1)
+ raise Exception("Don't know how to find flag named \"%s\"" % flag_name)
+
+ def clear_attachment_flags(self,
+ attachment_id,
+ additional_comment_text=None):
+ self.authenticate()
+
+ comment_text = "Clearing flags on attachment: %s" % attachment_id
+ if additional_comment_text:
+ comment_text += "\n\n%s" % additional_comment_text
+ log(comment_text)
+
+ if self.dryrun:
+ return
+
+ self.browser.open(self.attachment_url_for_id(attachment_id, 'edit'))
+ self.browser.select_form(nr=1)
+ self.browser.set_value(comment_text, name='comment', nr=0)
+ self._find_select_element_for_flag('review').value = ("X",)
+ self._find_select_element_for_flag('commit-queue').value = ("X",)
+ self.browser.submit()
+
+ def set_flag_on_attachment(self,
+ attachment_id,
+ flag_name,
+ flag_value,
+ comment_text=None,
+ additional_comment_text=None):
+ # FIXME: We need a way to test this function on a live bugzilla
+ # instance.
+
+ self.authenticate()
+
+ if additional_comment_text:
+ comment_text += "\n\n%s" % additional_comment_text
+ log(comment_text)
+
+ if self.dryrun:
+ return
+
+ self.browser.open(self.attachment_url_for_id(attachment_id, 'edit'))
+ self.browser.select_form(nr=1)
+
+ if comment_text:
+ self.browser.set_value(comment_text, name='comment', nr=0)
+
+ self._find_select_element_for_flag(flag_name).value = (flag_value,)
+ self.browser.submit()
+
+ # FIXME: All of these bug editing methods have a ridiculous amount of
+ # copy/paste code.
+
+ def obsolete_attachment(self, attachment_id, comment_text=None):
+ self.authenticate()
+
+ log("Obsoleting attachment: %s" % attachment_id)
+ if self.dryrun:
+ log(comment_text)
+ return
+
+ self.browser.open(self.attachment_url_for_id(attachment_id, 'edit'))
+ self.browser.select_form(nr=1)
+ self.browser.find_control('isobsolete').items[0].selected = True
+ # Also clear any review flag (to remove it from review/commit queues)
+ self._find_select_element_for_flag('review').value = ("X",)
+ self._find_select_element_for_flag('commit-queue').value = ("X",)
+ if comment_text:
+ log(comment_text)
+ # Bugzilla has two textareas named 'comment', one is somehow
+ # hidden. We want the first.
+ self.browser.set_value(comment_text, name='comment', nr=0)
+ self.browser.submit()
+
+ def add_cc_to_bug(self, bug_id, email_address_list):
+ self.authenticate()
+
+ log("Adding %s to the CC list for bug %s" % (email_address_list,
+ bug_id))
+ if self.dryrun:
+ return
+
+ self.browser.open(self.bug_url_for_bug_id(bug_id))
+ self.browser.select_form(name="changeform")
+ self.browser["newcc"] = ", ".join(email_address_list)
+ self.browser.submit()
+
+ def post_comment_to_bug(self, bug_id, comment_text, cc=None):
+ self.authenticate()
+
+ log("Adding comment to bug %s" % bug_id)
+ if self.dryrun:
+ log(comment_text)
+ return
+
+ self.browser.open(self.bug_url_for_bug_id(bug_id))
+ self.browser.select_form(name="changeform")
+ self.browser["comment"] = comment_text
+ if cc:
+ self.browser["newcc"] = ", ".join(cc)
+ self.browser.submit()
+
+ def close_bug_as_fixed(self, bug_id, comment_text=None):
+ self.authenticate()
+
+ log("Closing bug %s as fixed" % bug_id)
+ if self.dryrun:
+ log(comment_text)
+ return
+
+ self.browser.open(self.bug_url_for_bug_id(bug_id))
+ self.browser.select_form(name="changeform")
+ if comment_text:
+ self.browser['comment'] = comment_text
+ self.browser['bug_status'] = ['RESOLVED']
+ self.browser['resolution'] = ['FIXED']
+ self.browser.submit()
+
+ def reassign_bug(self, bug_id, assignee, comment_text=None):
+ self.authenticate()
+
+ log("Assigning bug %s to %s" % (bug_id, assignee))
+ if self.dryrun:
+ log(comment_text)
+ return
+
+ self.browser.open(self.bug_url_for_bug_id(bug_id))
+ self.browser.select_form(name="changeform")
+ if comment_text:
+ log(comment_text)
+ self.browser["comment"] = comment_text
+ self.browser["assigned_to"] = assignee
+ self.browser.submit()
+
+ def reopen_bug(self, bug_id, comment_text):
+ self.authenticate()
+
+ log("Re-opening bug %s" % bug_id)
+ # Bugzilla requires a comment when re-opening a bug, so we know it will
+ # never be None.
+ log(comment_text)
+ if self.dryrun:
+ return
+
+ self.browser.open(self.bug_url_for_bug_id(bug_id))
+ self.browser.select_form(name="changeform")
+ bug_status = self.browser.find_control("bug_status", type="select")
+ # This is a hack around the fact that ClientForm.ListControl seems to
+ # have no simpler way to ask if a control has an item named "REOPENED"
+ # without using exceptions for control flow.
+ possible_bug_statuses = map(lambda item: item.name, bug_status.items)
+ if "REOPENED" in possible_bug_statuses:
+ bug_status.value = ["REOPENED"]
+ # If the bug was never confirmed it will not have a "REOPENED"
+ # state, but only an "UNCONFIRMED" state.
+ elif "UNCONFIRMED" in possible_bug_statuses:
+ bug_status.value = ["UNCONFIRMED"]
+ else:
+ # FIXME: This logic is slightly backwards. We won't print this
+ # message if the bug is already open with state "UNCONFIRMED".
+ log("Did not reopen bug %s, it appears to already be open with status %s." % (bug_id, bug_status.value))
+ self.browser['comment'] = comment_text
+ self.browser.submit()
diff --git a/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py
new file mode 100644
index 0000000..1d08ca5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/bugzilla/bugzilla_unittest.py
@@ -0,0 +1,392 @@
+# 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 unittest
+import datetime
+import StringIO
+
+from .bugzilla import Bugzilla, BugzillaQueries, parse_bug_id
+
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.mocktool import MockBrowser
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
+
+
+class BugzillaTest(unittest.TestCase):
+ _example_attachment = '''
+ <attachment
+ isobsolete="1"
+ ispatch="1"
+ isprivate="0"
+ >
+ <attachid>33721</attachid>
+ <date>2009-07-29 10:23 PDT</date>
+ <desc>Fixed whitespace issue</desc>
+ <filename>patch</filename>
+ <type>text/plain</type>
+ <size>9719</size>
+ <attacher>christian.plesner.hansen@gmail.com</attacher>
+ <flag name="review"
+ id="17931"
+ status="+"
+ setter="one@test.com"
+ />
+ <flag name="commit-queue"
+ id="17932"
+ status="+"
+ setter="two@test.com"
+ />
+ </attachment>
+'''
+ _expected_example_attachment_parsing = {
+ 'attach_date': datetime.datetime(2009, 07, 29, 10, 23),
+ 'bug_id' : 100,
+ 'is_obsolete' : True,
+ 'is_patch' : True,
+ 'id' : 33721,
+ 'url' : "https://bugs.webkit.org/attachment.cgi?id=33721",
+ 'name' : "Fixed whitespace issue",
+ 'type' : "text/plain",
+ 'review' : '+',
+ 'reviewer_email' : 'one@test.com',
+ 'commit-queue' : '+',
+ 'committer_email' : 'two@test.com',
+ 'attacher_email' : 'christian.plesner.hansen@gmail.com',
+ }
+
+ def test_url_creation(self):
+ # FIXME: These would be all better as doctests
+ bugs = Bugzilla()
+ self.assertEquals(None, bugs.bug_url_for_bug_id(None))
+ self.assertEquals(None, bugs.short_bug_url_for_bug_id(None))
+ self.assertEquals(None, bugs.attachment_url_for_id(None))
+
+ def test_parse_bug_id(self):
+ # FIXME: These would be all better as doctests
+ bugs = Bugzilla()
+ self.assertEquals(12345, parse_bug_id("http://webkit.org/b/12345"))
+ self.assertEquals(12345, parse_bug_id("http://bugs.webkit.org/show_bug.cgi?id=12345"))
+ self.assertEquals(12345, parse_bug_id(bugs.short_bug_url_for_bug_id(12345)))
+ self.assertEquals(12345, parse_bug_id(bugs.bug_url_for_bug_id(12345)))
+ self.assertEquals(12345, parse_bug_id(bugs.bug_url_for_bug_id(12345, xml=True)))
+
+ # Our bug parser is super-fragile, but at least we're testing it.
+ self.assertEquals(None, parse_bug_id("http://www.webkit.org/b/12345"))
+ self.assertEquals(None, parse_bug_id("http://bugs.webkit.org/show_bug.cgi?ctype=xml&id=12345"))
+
+ _bug_xml = """
+ <bug>
+ <bug_id>32585</bug_id>
+ <creation_ts>2009-12-15 15:17 PST</creation_ts>
+ <short_desc>bug to test webkit-patch and commit-queue failures</short_desc>
+ <delta_ts>2009-12-27 21:04:50 PST</delta_ts>
+ <reporter_accessible>1</reporter_accessible>
+ <cclist_accessible>1</cclist_accessible>
+ <classification_id>1</classification_id>
+ <classification>Unclassified</classification>
+ <product>WebKit</product>
+ <component>Tools / Tests</component>
+ <version>528+ (Nightly build)</version>
+ <rep_platform>PC</rep_platform>
+ <op_sys>Mac OS X 10.5</op_sys>
+ <bug_status>NEW</bug_status>
+ <priority>P2</priority>
+ <bug_severity>Normal</bug_severity>
+ <target_milestone>---</target_milestone>
+ <everconfirmed>1</everconfirmed>
+ <reporter name="Eric Seidel">eric@webkit.org</reporter>
+ <assigned_to name="Nobody">webkit-unassigned@lists.webkit.org</assigned_to>
+ <cc>foo@bar.com</cc>
+ <cc>example@example.com</cc>
+ <long_desc isprivate="0">
+ <who name="Eric Seidel">eric@webkit.org</who>
+ <bug_when>2009-12-15 15:17:28 PST</bug_when>
+ <thetext>bug to test webkit-patch and commit-queue failures
+
+Ignore this bug. Just for testing failure modes of webkit-patch and the commit-queue.</thetext>
+ </long_desc>
+ <attachment
+ isobsolete="0"
+ ispatch="1"
+ isprivate="0"
+ >
+ <attachid>45548</attachid>
+ <date>2009-12-27 23:51 PST</date>
+ <desc>Patch</desc>
+ <filename>bug-32585-20091228005112.patch</filename>
+ <type>text/plain</type>
+ <size>10882</size>
+ <attacher>mjs@apple.com</attacher>
+
+ <token>1261988248-dc51409e9c421a4358f365fa8bec8357</token>
+ <data encoding="base64">SW5kZXg6IFdlYktpdC9tYWMvQ2hhbmdlTG9nCj09PT09PT09PT09PT09PT09PT09PT09PT09PT09
+removed-because-it-was-really-long
+ZEZpbmlzaExvYWRXaXRoUmVhc29uOnJlYXNvbl07Cit9CisKIEBlbmQKIAogI2VuZGlmCg==
+</data>
+
+ <flag name="review"
+ id="27602"
+ status="?"
+ setter="mjs@apple.com"
+ />
+ </attachment>
+ </bug>
+"""
+
+ _single_bug_xml = """
+<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
+<!DOCTYPE bugzilla SYSTEM "https://bugs.webkit.org/bugzilla.dtd">
+<bugzilla version="3.2.3"
+ urlbase="https://bugs.webkit.org/"
+ maintainer="admin@webkit.org"
+ exporter="eric@webkit.org"
+>
+%s
+</bugzilla>
+""" % _bug_xml
+
+ _expected_example_bug_parsing = {
+ "id" : 32585,
+ "title" : u"bug to test webkit-patch and commit-queue failures",
+ "cc_emails" : ["foo@bar.com", "example@example.com"],
+ "reporter_email" : "eric@webkit.org",
+ "assigned_to_email" : "webkit-unassigned@lists.webkit.org",
+ "bug_status": "NEW",
+ "attachments" : [{
+ "attach_date": datetime.datetime(2009, 12, 27, 23, 51),
+ 'name': u'Patch',
+ 'url' : "https://bugs.webkit.org/attachment.cgi?id=45548",
+ 'is_obsolete': False,
+ 'review': '?',
+ 'is_patch': True,
+ 'attacher_email': 'mjs@apple.com',
+ 'bug_id': 32585,
+ 'type': 'text/plain',
+ 'id': 45548
+ }],
+ }
+
+ # FIXME: This should move to a central location and be shared by more unit tests.
+ def _assert_dictionaries_equal(self, actual, expected):
+ # Make sure we aren't parsing more or less than we expect
+ self.assertEquals(sorted(actual.keys()), sorted(expected.keys()))
+
+ for key, expected_value in expected.items():
+ self.assertEquals(actual[key], expected_value, ("Failure for key: %s: Actual='%s' Expected='%s'" % (key, actual[key], expected_value)))
+
+ def test_parse_bug_dictionary_from_xml(self):
+ bug = Bugzilla()._parse_bug_dictionary_from_xml(self._single_bug_xml)
+ self._assert_dictionaries_equal(bug, self._expected_example_bug_parsing)
+
+ _sample_multi_bug_xml = """
+<bugzilla version="3.2.3" urlbase="https://bugs.webkit.org/" maintainer="admin@webkit.org" exporter="eric@webkit.org">
+ %s
+ %s
+</bugzilla>
+""" % (_bug_xml, _bug_xml)
+
+ def test_parse_bugs_from_xml(self):
+ bugzilla = Bugzilla()
+ bugs = bugzilla._parse_bugs_from_xml(self._sample_multi_bug_xml)
+ self.assertEquals(len(bugs), 2)
+ self.assertEquals(bugs[0].id(), self._expected_example_bug_parsing['id'])
+ bugs = bugzilla._parse_bugs_from_xml("")
+ self.assertEquals(len(bugs), 0)
+
+ # This could be combined into test_bug_parsing later if desired.
+ def test_attachment_parsing(self):
+ bugzilla = Bugzilla()
+ soup = BeautifulSoup(self._example_attachment)
+ attachment_element = soup.find("attachment")
+ attachment = bugzilla._parse_attachment_element(attachment_element, self._expected_example_attachment_parsing['bug_id'])
+ self.assertTrue(attachment)
+ self._assert_dictionaries_equal(attachment, self._expected_example_attachment_parsing)
+
+ _sample_attachment_detail_page = """
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <title>
+ Attachment 41073 Details for Bug 27314</title>
+<link rel="Top" href="https://bugs.webkit.org/">
+ <link rel="Up" href="show_bug.cgi?id=27314">
+"""
+
+ def test_attachment_detail_bug_parsing(self):
+ bugzilla = Bugzilla()
+ self.assertEquals(27314, bugzilla._parse_bug_id_from_attachment_page(self._sample_attachment_detail_page))
+
+ def test_add_cc_to_bug(self):
+ bugzilla = Bugzilla()
+ bugzilla.browser = MockBrowser()
+ bugzilla.authenticate = lambda: None
+ expected_stderr = "Adding ['adam@example.com'] to the CC list for bug 42\n"
+ OutputCapture().assert_outputs(self, bugzilla.add_cc_to_bug, [42, ["adam@example.com"]], expected_stderr=expected_stderr)
+
+ def _mock_control_item(self, name):
+ mock_item = Mock()
+ mock_item.name = name
+ return mock_item
+
+ def _mock_find_control(self, item_names=[], selected_index=0):
+ mock_control = Mock()
+ mock_control.items = [self._mock_control_item(name) for name in item_names]
+ mock_control.value = [item_names[selected_index]] if item_names else None
+ return lambda name, type: mock_control
+
+ def _assert_reopen(self, item_names=None, selected_index=None, extra_stderr=None):
+ bugzilla = Bugzilla()
+ bugzilla.browser = MockBrowser()
+ bugzilla.authenticate = lambda: None
+
+ mock_find_control = self._mock_find_control(item_names, selected_index)
+ bugzilla.browser.find_control = mock_find_control
+ expected_stderr = "Re-opening bug 42\n['comment']\n"
+ if extra_stderr:
+ expected_stderr += extra_stderr
+ OutputCapture().assert_outputs(self, bugzilla.reopen_bug, [42, ["comment"]], expected_stderr=expected_stderr)
+
+ def test_reopen_bug(self):
+ self._assert_reopen(item_names=["REOPENED", "RESOLVED", "CLOSED"], selected_index=1)
+ self._assert_reopen(item_names=["UNCONFIRMED", "RESOLVED", "CLOSED"], selected_index=1)
+ extra_stderr = "Did not reopen bug 42, it appears to already be open with status ['NEW'].\n"
+ self._assert_reopen(item_names=["NEW", "RESOLVED"], selected_index=0, extra_stderr=extra_stderr)
+
+ def test_file_object_for_upload(self):
+ bugzilla = Bugzilla()
+ file_object = StringIO.StringIO()
+ unicode_tor = u"WebKit \u2661 Tor Arne Vestb\u00F8!"
+ utf8_tor = unicode_tor.encode("utf-8")
+ self.assertEqual(bugzilla._file_object_for_upload(file_object), file_object)
+ self.assertEqual(bugzilla._file_object_for_upload(utf8_tor).read(), utf8_tor)
+ self.assertEqual(bugzilla._file_object_for_upload(unicode_tor).read(), utf8_tor)
+
+ def test_filename_for_upload(self):
+ bugzilla = Bugzilla()
+ mock_file = Mock()
+ mock_file.name = "foo"
+ self.assertEqual(bugzilla._filename_for_upload(mock_file, 1234), 'foo')
+ mock_timestamp = lambda: "now"
+ filename = bugzilla._filename_for_upload(StringIO.StringIO(), 1234, extension="patch", timestamp=mock_timestamp)
+ self.assertEqual(filename, "bug-1234-now.patch")
+
+
+class BugzillaQueriesTest(unittest.TestCase):
+ _sample_request_page = """
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <title>Request Queue</title>
+ </head>
+<body>
+
+<h3>Flag: review</h3>
+ <table class="requests" cellspacing="0" cellpadding="4" border="1">
+ <tr>
+ <th>Requester</th>
+ <th>Requestee</th>
+ <th>Bug</th>
+ <th>Attachment</th>
+ <th>Created</th>
+ </tr>
+ <tr>
+ <td>Shinichiro Hamaji &lt;hamaji&#64;chromium.org&gt;</td>
+ <td></td>
+ <td><a href="show_bug.cgi?id=30015">30015: text-transform:capitalize is failing in CSS2.1 test suite</a></td>
+ <td><a href="attachment.cgi?id=40511&amp;action=review">
+40511: Patch v0</a></td>
+ <td>2009-10-02 04:58 PST</td>
+ </tr>
+ <tr>
+ <td>Zan Dobersek &lt;zandobersek&#64;gmail.com&gt;</td>
+ <td></td>
+ <td><a href="show_bug.cgi?id=26304">26304: [GTK] Add controls for playing html5 video.</a></td>
+ <td><a href="attachment.cgi?id=40722&amp;action=review">
+40722: Media controls, the simple approach</a></td>
+ <td>2009-10-06 09:13 PST</td>
+ </tr>
+ <tr>
+ <td>Zan Dobersek &lt;zandobersek&#64;gmail.com&gt;</td>
+ <td></td>
+ <td><a href="show_bug.cgi?id=26304">26304: [GTK] Add controls for playing html5 video.</a></td>
+ <td><a href="attachment.cgi?id=40723&amp;action=review">
+40723: Adjust the media slider thumb size</a></td>
+ <td>2009-10-06 09:15 PST</td>
+ </tr>
+ </table>
+</body>
+</html>
+"""
+ _sample_quip_page = u"""
+<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html>
+ <head>
+ <title>Bugzilla Quip System</title>
+ </head>
+ <body>
+ <h2>
+
+ Existing quips:
+ </h2>
+ <ul>
+ <li>Everything should be made as simple as possible, but not simpler. - Albert Einstein</li>
+ <li>Good artists copy. Great artists steal. - Pablo Picasso</li>
+ <li>\u00e7gua mole em pedra dura, tanto bate at\u008e que fura.</li>
+
+ </ul>
+ </body>
+</html>
+"""
+
+ def _assert_result_count(self, queries, html, count):
+ self.assertEquals(queries._parse_result_count(html), count)
+
+ def test_parse_result_count(self):
+ queries = BugzillaQueries(None)
+ # Pages with results, always list the count at least twice.
+ self._assert_result_count(queries, '<span class="bz_result_count">314 bugs found.</span><span class="bz_result_count">314 bugs found.</span>', 314)
+ self._assert_result_count(queries, '<span class="bz_result_count">Zarro Boogs found.</span>', 0)
+ self._assert_result_count(queries, '<span class="bz_result_count">\n \nOne bug found.</span>', 1)
+ self.assertRaises(Exception, queries._parse_result_count, ['Invalid'])
+
+ def test_request_page_parsing(self):
+ queries = BugzillaQueries(None)
+ self.assertEquals([40511, 40722, 40723], queries._parse_attachment_ids_request_query(self._sample_request_page))
+
+ def test_quip_page_parsing(self):
+ queries = BugzillaQueries(None)
+ expected_quips = ["Everything should be made as simple as possible, but not simpler. - Albert Einstein", "Good artists copy. Great artists steal. - Pablo Picasso", u"\u00e7gua mole em pedra dura, tanto bate at\u008e que fura."]
+ self.assertEquals(expected_quips, queries._parse_quips(self._sample_quip_page))
+
+ def test_load_query(self):
+ queries = BugzillaQueries(Mock())
+ queries._load_query("request.cgi?action=queue&type=review&group=type")
diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/__init__.py b/Tools/Scripts/webkitpy/common/net/buildbot/__init__.py
new file mode 100644
index 0000000..631ef6b
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/buildbot/__init__.py
@@ -0,0 +1,5 @@
+# Required for Python to search this directory for module files
+
+# We only export public API here.
+# It's unclear if Builder and Build need to be public.
+from .buildbot import BuildBot, Builder, Build
diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
new file mode 100644
index 0000000..3cb6da5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot.py
@@ -0,0 +1,463 @@
+# 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.
+#
+# WebKit's Python module for interacting with WebKit's buildbot
+
+try:
+ import json
+except ImportError:
+ # python 2.5 compatibility
+ import webkitpy.thirdparty.simplejson as json
+
+import operator
+import re
+import urllib
+import urllib2
+
+from webkitpy.common.net.failuremap import FailureMap
+from webkitpy.common.net.layouttestresults import LayoutTestResults
+from webkitpy.common.net.regressionwindow import RegressionWindow
+from webkitpy.common.system.logutils import get_logger
+from webkitpy.thirdparty.autoinstalled.mechanize import Browser
+from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
+
+_log = get_logger(__file__)
+
+
+class Builder(object):
+ def __init__(self, name, buildbot):
+ self._name = name
+ self._buildbot = buildbot
+ self._builds_cache = {}
+ self._revision_to_build_number = None
+ self._browser = Browser()
+ self._browser.set_handle_robots(False) # The builder pages are excluded by robots.txt
+
+ def name(self):
+ return self._name
+
+ def results_url(self):
+ return "http://%s/results/%s" % (self._buildbot.buildbot_host, self.url_encoded_name())
+
+ def url_encoded_name(self):
+ return urllib.quote(self._name)
+
+ def url(self):
+ return "http://%s/builders/%s" % (self._buildbot.buildbot_host, self.url_encoded_name())
+
+ # This provides a single place to mock
+ def _fetch_build(self, build_number):
+ build_dictionary = self._buildbot._fetch_build_dictionary(self, build_number)
+ if not build_dictionary:
+ return None
+ return Build(self,
+ build_number=int(build_dictionary['number']),
+ revision=int(build_dictionary['sourceStamp']['revision']),
+ is_green=(build_dictionary['results'] == 0) # Undocumented, 0 seems to mean "pass"
+ )
+
+ def build(self, build_number):
+ if not build_number:
+ return None
+ cached_build = self._builds_cache.get(build_number)
+ if cached_build:
+ return cached_build
+
+ build = self._fetch_build(build_number)
+ self._builds_cache[build_number] = build
+ return build
+
+ def force_build(self, username="webkit-patch", comments=None):
+ def predicate(form):
+ try:
+ return form.find_control("username")
+ except Exception, e:
+ return False
+ self._browser.open(self.url())
+ self._browser.select_form(predicate=predicate)
+ self._browser["username"] = username
+ if comments:
+ self._browser["comments"] = comments
+ return self._browser.submit()
+
+ file_name_regexp = re.compile(r"r(?P<revision>\d+) \((?P<build_number>\d+)\)")
+ def _revision_and_build_for_filename(self, filename):
+ # Example: "r47483 (1)/" or "r47483 (1).zip"
+ match = self.file_name_regexp.match(filename)
+ return (int(match.group("revision")), int(match.group("build_number")))
+
+ def _fetch_revision_to_build_map(self):
+ # All _fetch requests go through _buildbot for easier mocking
+ # FIXME: This should use NetworkTransaction's 404 handling instead.
+ try:
+ # FIXME: This method is horribly slow due to the huge network load.
+ # FIXME: This is a poor way to do revision -> build mapping.
+ # Better would be to ask buildbot through some sort of API.
+ print "Loading revision/build list from %s." % self.results_url()
+ print "This may take a while..."
+ result_files = self._buildbot._fetch_twisted_directory_listing(self.results_url())
+ except urllib2.HTTPError, error:
+ if error.code != 404:
+ raise
+ result_files = []
+
+ # This assumes there was only one build per revision, which is false but we don't care for now.
+ return dict([self._revision_and_build_for_filename(file_info["filename"]) for file_info in result_files])
+
+ def _revision_to_build_map(self):
+ if not self._revision_to_build_number:
+ self._revision_to_build_number = self._fetch_revision_to_build_map()
+ return self._revision_to_build_number
+
+ def revision_build_pairs_with_results(self):
+ return self._revision_to_build_map().items()
+
+ # This assumes there can be only one build per revision, which is false, but we don't care for now.
+ def build_for_revision(self, revision, allow_failed_lookups=False):
+ # NOTE: This lookup will fail if that exact revision was never built.
+ build_number = self._revision_to_build_map().get(int(revision))
+ if not build_number:
+ return None
+ build = self.build(build_number)
+ if not build and allow_failed_lookups:
+ # Builds for old revisions with fail to lookup via buildbot's json api.
+ build = Build(self,
+ build_number=build_number,
+ revision=revision,
+ is_green=False,
+ )
+ return build
+
+ def find_regression_window(self, red_build, look_back_limit=30):
+ if not red_build or red_build.is_green():
+ return RegressionWindow(None, None)
+ common_failures = None
+ current_build = red_build
+ build_after_current_build = None
+ look_back_count = 0
+ while current_build:
+ if current_build.is_green():
+ # current_build can't possibly have any failures in common
+ # with red_build because it's green.
+ break
+ results = current_build.layout_test_results()
+ # We treat a lack of results as if all the test failed.
+ # This occurs, for example, when we can't compile at all.
+ if results:
+ failures = set(results.failing_tests())
+ if common_failures == None:
+ common_failures = failures
+ else:
+ common_failures = common_failures.intersection(failures)
+ if not common_failures:
+ # current_build doesn't have any failures in common with
+ # the red build we're worried about. We assume that any
+ # failures in current_build were due to flakiness.
+ break
+ look_back_count += 1
+ if look_back_count > look_back_limit:
+ return RegressionWindow(None, current_build, failing_tests=common_failures)
+ build_after_current_build = current_build
+ current_build = current_build.previous_build()
+ # We must iterate at least once because red_build is red.
+ assert(build_after_current_build)
+ # Current build must either be green or have no failures in common
+ # with red build, so we've found our failure transition.
+ return RegressionWindow(current_build, build_after_current_build, failing_tests=common_failures)
+
+ def find_blameworthy_regression_window(self, red_build_number, look_back_limit=30, avoid_flakey_tests=True):
+ red_build = self.build(red_build_number)
+ regression_window = self.find_regression_window(red_build, look_back_limit)
+ if not regression_window.build_before_failure():
+ return None # We ran off the limit of our search
+ # If avoid_flakey_tests, require at least 2 bad builds before we
+ # suspect a real failure transition.
+ if avoid_flakey_tests and regression_window.failing_build() == red_build:
+ return None
+ return regression_window
+
+
+class Build(object):
+ def __init__(self, builder, build_number, revision, is_green):
+ self._builder = builder
+ self._number = build_number
+ self._revision = revision
+ self._is_green = is_green
+ self._layout_test_results = None
+
+ @staticmethod
+ def build_url(builder, build_number):
+ return "%s/builds/%s" % (builder.url(), build_number)
+
+ def url(self):
+ return self.build_url(self.builder(), self._number)
+
+ def results_url(self):
+ results_directory = "r%s (%s)" % (self.revision(), self._number)
+ return "%s/%s" % (self._builder.results_url(), urllib.quote(results_directory))
+
+ def _fetch_results_html(self):
+ results_html = "%s/results.html" % (self.results_url())
+ # FIXME: This should use NetworkTransaction's 404 handling instead.
+ try:
+ # It seems this can return None if the url redirects and then returns 404.
+ return urllib2.urlopen(results_html)
+ except urllib2.HTTPError, error:
+ if error.code != 404:
+ raise
+
+ def layout_test_results(self):
+ if not self._layout_test_results:
+ # FIXME: This should cache that the result was a 404 and stop hitting the network.
+ self._layout_test_results = LayoutTestResults.results_from_string(self._fetch_results_html())
+ return self._layout_test_results
+
+ def builder(self):
+ return self._builder
+
+ def revision(self):
+ return self._revision
+
+ def is_green(self):
+ return self._is_green
+
+ def previous_build(self):
+ # previous_build() allows callers to avoid assuming build numbers are sequential.
+ # They may not be sequential across all master changes, or when non-trunk builds are made.
+ return self._builder.build(self._number - 1)
+
+
+class BuildBot(object):
+ # FIXME: This should move into some sort of webkit_config.py
+ default_host = "build.webkit.org"
+
+ def __init__(self, host=default_host):
+ self.buildbot_host = host
+ self._builder_by_name = {}
+
+ # If any core builder is red we should not be landing patches. Other
+ # builders should be added to this list once they are known to be
+ # reliable.
+ # See https://bugs.webkit.org/show_bug.cgi?id=33296 and related bugs.
+ self.core_builder_names_regexps = [
+ "SnowLeopard.*Build",
+ "SnowLeopard.*\(Test", # Exclude WebKit2 for now.
+ "Leopard",
+ "Tiger",
+ "Windows.*Build",
+ "GTK.*32",
+ "GTK.*64.*Debug", # Disallow the 64-bit Release bot which is broken.
+ "Qt",
+ "Chromium.*Release$",
+ ]
+
+ def _parse_last_build_cell(self, builder, cell):
+ status_link = cell.find('a')
+ if status_link:
+ # Will be either a revision number or a build number
+ revision_string = status_link.string
+ # If revision_string has non-digits assume it's not a revision number.
+ builder['built_revision'] = int(revision_string) \
+ if not re.match('\D', revision_string) \
+ else None
+
+ # FIXME: We treat slave lost as green even though it is not to
+ # work around the Qts bot being on a broken internet connection.
+ # The real fix is https://bugs.webkit.org/show_bug.cgi?id=37099
+ builder['is_green'] = not re.search('fail', cell.renderContents()) or \
+ not not re.search('lost', cell.renderContents())
+
+ status_link_regexp = r"builders/(?P<builder_name>.*)/builds/(?P<build_number>\d+)"
+ link_match = re.match(status_link_regexp, status_link['href'])
+ builder['build_number'] = int(link_match.group("build_number"))
+ else:
+ # We failed to find a link in the first cell, just give up. This
+ # can happen if a builder is just-added, the first cell will just
+ # be "no build"
+ # Other parts of the code depend on is_green being present.
+ builder['is_green'] = False
+ builder['built_revision'] = None
+ builder['build_number'] = None
+
+ def _parse_current_build_cell(self, builder, cell):
+ activity_lines = cell.renderContents().split("<br />")
+ builder["activity"] = activity_lines[0] # normally "building" or "idle"
+ # The middle lines document how long left for any current builds.
+ match = re.match("(?P<pending_builds>\d) pending", activity_lines[-1])
+ builder["pending_builds"] = int(match.group("pending_builds")) if match else 0
+
+ def _parse_builder_status_from_row(self, status_row):
+ status_cells = status_row.findAll('td')
+ builder = {}
+
+ # First cell is the name
+ name_link = status_cells[0].find('a')
+ builder["name"] = unicode(name_link.string)
+
+ self._parse_last_build_cell(builder, status_cells[1])
+ self._parse_current_build_cell(builder, status_cells[2])
+ return builder
+
+ def _matches_regexps(self, builder_name, name_regexps):
+ for name_regexp in name_regexps:
+ if re.match(name_regexp, builder_name):
+ return True
+ return False
+
+ # FIXME: Should move onto Builder
+ def _is_core_builder(self, builder_name):
+ return self._matches_regexps(builder_name, self.core_builder_names_regexps)
+
+ # FIXME: This method needs to die, but is used by a unit test at the moment.
+ def _builder_statuses_with_names_matching_regexps(self, builder_statuses, name_regexps):
+ return [builder for builder in builder_statuses if self._matches_regexps(builder["name"], name_regexps)]
+
+ def red_core_builders(self):
+ return [builder for builder in self.core_builder_statuses() if not builder["is_green"]]
+
+ def red_core_builders_names(self):
+ return [builder["name"] for builder in self.red_core_builders()]
+
+ def idle_red_core_builders(self):
+ return [builder for builder in self.red_core_builders() if builder["activity"] == "idle"]
+
+ def core_builders_are_green(self):
+ return not self.red_core_builders()
+
+ # FIXME: These _fetch methods should move to a networking class.
+ def _fetch_build_dictionary(self, builder, build_number):
+ try:
+ base = "http://%s" % self.buildbot_host
+ path = urllib.quote("json/builders/%s/builds/%s" % (builder.name(),
+ build_number))
+ url = "%s/%s" % (base, path)
+ jsondata = urllib2.urlopen(url)
+ return json.load(jsondata)
+ except urllib2.URLError, err:
+ build_url = Build.build_url(builder, build_number)
+ _log.error("Error fetching data for %s build %s (%s): %s" % (builder.name(), build_number, build_url, err))
+ return None
+ except ValueError, err:
+ build_url = Build.build_url(builder, build_number)
+ _log.error("Error decoding json data from %s: %s" % (build_url, err))
+ return None
+
+ def _fetch_one_box_per_builder(self):
+ build_status_url = "http://%s/one_box_per_builder" % self.buildbot_host
+ return urllib2.urlopen(build_status_url)
+
+ def _file_cell_text(self, file_cell):
+ """Traverses down through firstChild elements until one containing a string is found, then returns that string"""
+ element = file_cell
+ while element.string is None and element.contents:
+ element = element.contents[0]
+ return element.string
+
+ def _parse_twisted_file_row(self, file_row):
+ string_or_empty = lambda string: unicode(string) if string else u""
+ file_cells = file_row.findAll('td')
+ return {
+ "filename": string_or_empty(self._file_cell_text(file_cells[0])),
+ "size": string_or_empty(self._file_cell_text(file_cells[1])),
+ "type": string_or_empty(self._file_cell_text(file_cells[2])),
+ "encoding": string_or_empty(self._file_cell_text(file_cells[3])),
+ }
+
+ def _parse_twisted_directory_listing(self, page):
+ soup = BeautifulSoup(page)
+ # HACK: Match only table rows with a class to ignore twisted header/footer rows.
+ file_rows = soup.find('table').findAll('tr', {'class': re.compile(r'\b(?:directory|file)\b')})
+ return [self._parse_twisted_file_row(file_row) for file_row in file_rows]
+
+ # FIXME: There should be a better way to get this information directly from twisted.
+ def _fetch_twisted_directory_listing(self, url):
+ return self._parse_twisted_directory_listing(urllib2.urlopen(url))
+
+ def builders(self):
+ return [self.builder_with_name(status["name"]) for status in self.builder_statuses()]
+
+ # This method pulls from /one_box_per_builder as an efficient way to get information about
+ def builder_statuses(self):
+ soup = BeautifulSoup(self._fetch_one_box_per_builder())
+ return [self._parse_builder_status_from_row(status_row) for status_row in soup.find('table').findAll('tr')]
+
+ def core_builder_statuses(self):
+ return [builder for builder in self.builder_statuses() if self._is_core_builder(builder["name"])]
+
+ def builder_with_name(self, name):
+ builder = self._builder_by_name.get(name)
+ if not builder:
+ builder = Builder(name, self)
+ self._builder_by_name[name] = builder
+ return builder
+
+ def failure_map(self, only_core_builders=True):
+ builder_statuses = self.core_builder_statuses() if only_core_builders else self.builder_statuses()
+ failure_map = FailureMap()
+ revision_to_failing_bots = {}
+ for builder_status in builder_statuses:
+ if builder_status["is_green"]:
+ continue
+ builder = self.builder_with_name(builder_status["name"])
+ regression_window = builder.find_blameworthy_regression_window(builder_status["build_number"])
+ if regression_window:
+ failure_map.add_regression_window(builder, regression_window)
+ return failure_map
+
+ # This makes fewer requests than calling Builder.latest_build would. It grabs all builder
+ # statuses in one request using self.builder_statuses (fetching /one_box_per_builder instead of builder pages).
+ def _latest_builds_from_builders(self, only_core_builders=True):
+ builder_statuses = self.core_builder_statuses() if only_core_builders else self.builder_statuses()
+ return [self.builder_with_name(status["name"]).build(status["build_number"]) for status in builder_statuses]
+
+ def _build_at_or_before_revision(self, build, revision):
+ while build:
+ if build.revision() <= revision:
+ return build
+ build = build.previous_build()
+
+ def last_green_revision(self, only_core_builders=True):
+ builds = self._latest_builds_from_builders(only_core_builders)
+ target_revision = builds[0].revision()
+ # An alternate way to do this would be to start at one revision and walk backwards
+ # checking builder.build_for_revision, however build_for_revision is very slow on first load.
+ while True:
+ # Make builds agree on revision
+ builds = [self._build_at_or_before_revision(build, target_revision) for build in builds]
+ if None in builds: # One of the builds failed to load from the server.
+ return None
+ min_revision = min(map(lambda build: build.revision(), builds))
+ if min_revision != target_revision:
+ target_revision = min_revision
+ continue # Builds don't all agree on revision, keep searching
+ # Check to make sure they're all green
+ all_are_green = reduce(operator.and_, map(lambda build: build.is_green(), builds))
+ if not all_are_green:
+ target_revision -= 1
+ continue
+ return min_revision
diff --git a/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py
new file mode 100644
index 0000000..a10e432
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/buildbot/buildbot_unittest.py
@@ -0,0 +1,413 @@
+# 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 unittest
+
+from webkitpy.common.net.layouttestresults import LayoutTestResults
+from webkitpy.common.net.buildbot import BuildBot, Builder, Build
+from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
+
+
+class BuilderTest(unittest.TestCase):
+ def _install_fetch_build(self, failure):
+ def _mock_fetch_build(build_number):
+ build = Build(
+ builder=self.builder,
+ build_number=build_number,
+ revision=build_number + 1000,
+ is_green=build_number < 4
+ )
+ parsed_results = {LayoutTestResults.fail_key: failure(build_number)}
+ build._layout_test_results = LayoutTestResults(parsed_results)
+ return build
+ self.builder._fetch_build = _mock_fetch_build
+
+ def setUp(self):
+ self.buildbot = BuildBot()
+ self.builder = Builder(u"Test Builder \u2661", self.buildbot)
+ self._install_fetch_build(lambda build_number: ["test1", "test2"])
+
+ def test_find_regression_window(self):
+ regression_window = self.builder.find_regression_window(self.builder.build(10))
+ self.assertEqual(regression_window.build_before_failure().revision(), 1003)
+ self.assertEqual(regression_window.failing_build().revision(), 1004)
+
+ regression_window = self.builder.find_regression_window(self.builder.build(10), look_back_limit=2)
+ self.assertEqual(regression_window.build_before_failure(), None)
+ self.assertEqual(regression_window.failing_build().revision(), 1008)
+
+ def test_none_build(self):
+ self.builder._fetch_build = lambda build_number: None
+ regression_window = self.builder.find_regression_window(self.builder.build(10))
+ self.assertEqual(regression_window.build_before_failure(), None)
+ self.assertEqual(regression_window.failing_build(), None)
+
+ def test_flaky_tests(self):
+ self._install_fetch_build(lambda build_number: ["test1"] if build_number % 2 else ["test2"])
+ regression_window = self.builder.find_regression_window(self.builder.build(10))
+ self.assertEqual(regression_window.build_before_failure().revision(), 1009)
+ self.assertEqual(regression_window.failing_build().revision(), 1010)
+
+ def test_failure_and_flaky(self):
+ self._install_fetch_build(lambda build_number: ["test1", "test2"] if build_number % 2 else ["test2"])
+ regression_window = self.builder.find_regression_window(self.builder.build(10))
+ self.assertEqual(regression_window.build_before_failure().revision(), 1003)
+ self.assertEqual(regression_window.failing_build().revision(), 1004)
+
+ def test_no_results(self):
+ self._install_fetch_build(lambda build_number: ["test1", "test2"] if build_number % 2 else ["test2"])
+ regression_window = self.builder.find_regression_window(self.builder.build(10))
+ self.assertEqual(regression_window.build_before_failure().revision(), 1003)
+ self.assertEqual(regression_window.failing_build().revision(), 1004)
+
+ def test_failure_after_flaky(self):
+ self._install_fetch_build(lambda build_number: ["test1", "test2"] if build_number > 6 else ["test3"])
+ regression_window = self.builder.find_regression_window(self.builder.build(10))
+ self.assertEqual(regression_window.build_before_failure().revision(), 1006)
+ self.assertEqual(regression_window.failing_build().revision(), 1007)
+
+ def test_find_blameworthy_regression_window(self):
+ self.assertEqual(self.builder.find_blameworthy_regression_window(10).revisions(), [1004])
+ self.assertEqual(self.builder.find_blameworthy_regression_window(10, look_back_limit=2), None)
+ # Flakey test avoidance requires at least 2 red builds:
+ self.assertEqual(self.builder.find_blameworthy_regression_window(4), None)
+ self.assertEqual(self.builder.find_blameworthy_regression_window(4, avoid_flakey_tests=False).revisions(), [1004])
+ # Green builder:
+ self.assertEqual(self.builder.find_blameworthy_regression_window(3), None)
+
+ def test_build_caching(self):
+ self.assertEqual(self.builder.build(10), self.builder.build(10))
+
+ def test_build_and_revision_for_filename(self):
+ expectations = {
+ "r47483 (1)/" : (47483, 1),
+ "r47483 (1).zip" : (47483, 1),
+ }
+ for filename, revision_and_build in expectations.items():
+ self.assertEqual(self.builder._revision_and_build_for_filename(filename), revision_and_build)
+
+
+class BuildTest(unittest.TestCase):
+ def test_layout_test_results(self):
+ build = Build(None, None, None, None)
+ build._fetch_results_html = lambda: None
+ # Test that layout_test_results() returns None if the fetch fails.
+ self.assertEqual(build.layout_test_results(), None)
+
+
+class BuildBotTest(unittest.TestCase):
+
+ _example_one_box_status = '''
+ <table>
+ <tr>
+ <td class="box"><a href="builders/Windows%20Debug%20%28Tests%29">Windows Debug (Tests)</a></td>
+ <td align="center" class="LastBuild box success"><a href="builders/Windows%20Debug%20%28Tests%29/builds/3693">47380</a><br />build<br />successful</td>
+ <td align="center" class="Activity building">building<br />ETA in<br />~ 14 mins<br />at 13:40</td>
+ <tr>
+ <td class="box"><a href="builders/SnowLeopard%20Intel%20Release">SnowLeopard Intel Release</a></td>
+ <td class="LastBuild box" >no build</td>
+ <td align="center" class="Activity building">building<br />< 1 min</td>
+ <tr>
+ <td class="box"><a href="builders/Qt%20Linux%20Release">Qt Linux Release</a></td>
+ <td align="center" class="LastBuild box failure"><a href="builders/Qt%20Linux%20Release/builds/654">47383</a><br />failed<br />compile-webkit</td>
+ <td align="center" class="Activity idle">idle<br />3 pending</td>
+ <tr>
+ <td class="box"><a href="builders/Qt%20Windows%2032-bit%20Debug">Qt Windows 32-bit Debug</a></td>
+ <td align="center" class="LastBuild box failure"><a href="builders/Qt%20Windows%2032-bit%20Debug/builds/2090">60563</a><br />failed<br />failed<br />slave<br />lost</td>
+ <td align="center" class="Activity building">building<br />ETA in<br />~ 5 mins<br />at 08:25</td>
+ </table>
+'''
+ _expected_example_one_box_parsings = [
+ {
+ 'is_green': True,
+ 'build_number' : 3693,
+ 'name': u'Windows Debug (Tests)',
+ 'built_revision': 47380,
+ 'activity': 'building',
+ 'pending_builds': 0,
+ },
+ {
+ 'is_green': False,
+ 'build_number' : None,
+ 'name': u'SnowLeopard Intel Release',
+ 'built_revision': None,
+ 'activity': 'building',
+ 'pending_builds': 0,
+ },
+ {
+ 'is_green': False,
+ 'build_number' : 654,
+ 'name': u'Qt Linux Release',
+ 'built_revision': 47383,
+ 'activity': 'idle',
+ 'pending_builds': 3,
+ },
+ {
+ 'is_green': True,
+ 'build_number' : 2090,
+ 'name': u'Qt Windows 32-bit Debug',
+ 'built_revision': 60563,
+ 'activity': 'building',
+ 'pending_builds': 0,
+ },
+ ]
+
+ def test_status_parsing(self):
+ buildbot = BuildBot()
+
+ soup = BeautifulSoup(self._example_one_box_status)
+ status_table = soup.find("table")
+ input_rows = status_table.findAll('tr')
+
+ for x in range(len(input_rows)):
+ status_row = input_rows[x]
+ expected_parsing = self._expected_example_one_box_parsings[x]
+
+ builder = buildbot._parse_builder_status_from_row(status_row)
+
+ # Make sure we aren't parsing more or less than we expect
+ self.assertEquals(builder.keys(), expected_parsing.keys())
+
+ for key, expected_value in expected_parsing.items():
+ self.assertEquals(builder[key], expected_value, ("Builder %d parse failure for key: %s: Actual='%s' Expected='%s'" % (x, key, builder[key], expected_value)))
+
+ def test_core_builder_methods(self):
+ buildbot = BuildBot()
+
+ # Override builder_statuses function to not touch the network.
+ def example_builder_statuses(): # We could use instancemethod() to bind 'self' but we don't need to.
+ return BuildBotTest._expected_example_one_box_parsings
+ buildbot.builder_statuses = example_builder_statuses
+
+ buildbot.core_builder_names_regexps = [ 'Leopard', "Windows.*Build" ]
+ self.assertEquals(buildbot.red_core_builders_names(), [])
+ self.assertTrue(buildbot.core_builders_are_green())
+
+ buildbot.core_builder_names_regexps = [ 'SnowLeopard', 'Qt' ]
+ self.assertEquals(buildbot.red_core_builders_names(), [ u'SnowLeopard Intel Release', u'Qt Linux Release' ])
+ self.assertFalse(buildbot.core_builders_are_green())
+
+ def test_builder_name_regexps(self):
+ buildbot = BuildBot()
+
+ # For complete testing, this list should match the list of builders at build.webkit.org:
+ example_builders = [
+ {'name': u'Tiger Intel Release', },
+ {'name': u'Leopard Intel Release (Build)', },
+ {'name': u'Leopard Intel Release (Tests)', },
+ {'name': u'Leopard Intel Debug (Build)', },
+ {'name': u'Leopard Intel Debug (Tests)', },
+ {'name': u'SnowLeopard Intel Release (Build)', },
+ {'name': u'SnowLeopard Intel Release (Tests)', },
+ {'name': u'SnowLeopard Intel Release (WebKit2 Tests)', },
+ {'name': u'SnowLeopard Intel Leaks', },
+ {'name': u'Windows Release (Build)', },
+ {'name': u'Windows Release (Tests)', },
+ {'name': u'Windows Debug (Build)', },
+ {'name': u'Windows Debug (Tests)', },
+ {'name': u'GTK Linux 32-bit Release', },
+ {'name': u'GTK Linux 32-bit Debug', },
+ {'name': u'GTK Linux 64-bit Debug', },
+ {'name': u'GTK Linux 64-bit Release', },
+ {'name': u'Qt Linux Release', },
+ {'name': u'Qt Linux Release minimal', },
+ {'name': u'Qt Linux ARMv5 Release', },
+ {'name': u'Qt Linux ARMv7 Release', },
+ {'name': u'Qt Windows 32-bit Release', },
+ {'name': u'Qt Windows 32-bit Debug', },
+ {'name': u'Chromium Linux Release', },
+ {'name': u'Chromium Mac Release', },
+ {'name': u'Chromium Win Release', },
+ {'name': u'Chromium Linux Release (Tests)', },
+ {'name': u'Chromium Mac Release (Tests)', },
+ {'name': u'Chromium Win Release (Tests)', },
+ {'name': u'New run-webkit-tests', },
+ ]
+ name_regexps = [
+ "SnowLeopard.*Build",
+ "SnowLeopard.*\(Test",
+ "Leopard",
+ "Tiger",
+ "Windows.*Build",
+ "GTK.*32",
+ "GTK.*64.*Debug", # Disallow the 64-bit Release bot which is broken.
+ "Qt",
+ "Chromium.*Release$",
+ ]
+ expected_builders = [
+ {'name': u'Tiger Intel Release', },
+ {'name': u'Leopard Intel Release (Build)', },
+ {'name': u'Leopard Intel Release (Tests)', },
+ {'name': u'Leopard Intel Debug (Build)', },
+ {'name': u'Leopard Intel Debug (Tests)', },
+ {'name': u'SnowLeopard Intel Release (Build)', },
+ {'name': u'SnowLeopard Intel Release (Tests)', },
+ {'name': u'Windows Release (Build)', },
+ {'name': u'Windows Debug (Build)', },
+ {'name': u'GTK Linux 32-bit Release', },
+ {'name': u'GTK Linux 32-bit Debug', },
+ {'name': u'GTK Linux 64-bit Debug', },
+ {'name': u'Qt Linux Release', },
+ {'name': u'Qt Linux Release minimal', },
+ {'name': u'Qt Linux ARMv5 Release', },
+ {'name': u'Qt Linux ARMv7 Release', },
+ {'name': u'Qt Windows 32-bit Release', },
+ {'name': u'Qt Windows 32-bit Debug', },
+ {'name': u'Chromium Linux Release', },
+ {'name': u'Chromium Mac Release', },
+ {'name': u'Chromium Win Release', },
+ ]
+
+ # This test should probably be updated if the default regexp list changes
+ self.assertEquals(buildbot.core_builder_names_regexps, name_regexps)
+
+ builders = buildbot._builder_statuses_with_names_matching_regexps(example_builders, name_regexps)
+ self.assertEquals(builders, expected_builders)
+
+ def test_builder_with_name(self):
+ buildbot = BuildBot()
+
+ builder = buildbot.builder_with_name("Test Builder")
+ self.assertEqual(builder.name(), "Test Builder")
+ self.assertEqual(builder.url(), "http://build.webkit.org/builders/Test%20Builder")
+ self.assertEqual(builder.url_encoded_name(), "Test%20Builder")
+ self.assertEqual(builder.results_url(), "http://build.webkit.org/results/Test%20Builder")
+
+ # Override _fetch_build_dictionary function to not touch the network.
+ def mock_fetch_build_dictionary(self, build_number):
+ build_dictionary = {
+ "sourceStamp": {
+ "revision" : 2 * build_number,
+ },
+ "number" : int(build_number),
+ "results" : build_number % 2, # 0 means pass
+ }
+ return build_dictionary
+ buildbot._fetch_build_dictionary = mock_fetch_build_dictionary
+
+ build = builder.build(10)
+ self.assertEqual(build.builder(), builder)
+ self.assertEqual(build.url(), "http://build.webkit.org/builders/Test%20Builder/builds/10")
+ self.assertEqual(build.results_url(), "http://build.webkit.org/results/Test%20Builder/r20%20%2810%29")
+ self.assertEqual(build.revision(), 20)
+ self.assertEqual(build.is_green(), True)
+
+ build = build.previous_build()
+ self.assertEqual(build.builder(), builder)
+ self.assertEqual(build.url(), "http://build.webkit.org/builders/Test%20Builder/builds/9")
+ self.assertEqual(build.results_url(), "http://build.webkit.org/results/Test%20Builder/r18%20%289%29")
+ self.assertEqual(build.revision(), 18)
+ self.assertEqual(build.is_green(), False)
+
+ self.assertEqual(builder.build(None), None)
+
+ _example_directory_listing = '''
+<h1>Directory listing for /results/SnowLeopard Intel Leaks/</h1>
+
+<table>
+ <tr class="alt">
+ <th>Filename</th>
+ <th>Size</th>
+ <th>Content type</th>
+ <th>Content encoding</th>
+ </tr>
+<tr class="directory ">
+ <td><a href="r47483%20%281%29/"><b>r47483 (1)/</b></a></td>
+ <td><b></b></td>
+ <td><b>[Directory]</b></td>
+ <td><b></b></td>
+</tr>
+<tr class="file alt">
+ <td><a href="r47484%20%282%29.zip">r47484 (2).zip</a></td>
+ <td>89K</td>
+ <td>[application/zip]</td>
+ <td></td>
+</tr>
+'''
+ _expected_files = [
+ {
+ "filename" : "r47483 (1)/",
+ "size" : "",
+ "type" : "[Directory]",
+ "encoding" : "",
+ },
+ {
+ "filename" : "r47484 (2).zip",
+ "size" : "89K",
+ "type" : "[application/zip]",
+ "encoding" : "",
+ },
+ ]
+
+ def test_parse_build_to_revision_map(self):
+ buildbot = BuildBot()
+ files = buildbot._parse_twisted_directory_listing(self._example_directory_listing)
+ self.assertEqual(self._expected_files, files)
+
+ # Revision, is_green
+ # Ordered from newest (highest number) to oldest.
+ fake_builder1 = [
+ [2, False],
+ [1, True],
+ ]
+ fake_builder2 = [
+ [2, False],
+ [1, True],
+ ]
+ fake_builders = [
+ fake_builder1,
+ fake_builder2,
+ ]
+ def _build_from_fake(self, fake_builder, index):
+ if index >= len(fake_builder):
+ return None
+ fake_build = fake_builder[index]
+ build = Build(
+ builder=fake_builder,
+ build_number=index,
+ revision=fake_build[0],
+ is_green=fake_build[1],
+ )
+ def mock_previous_build():
+ return self._build_from_fake(fake_builder, index + 1)
+ build.previous_build = mock_previous_build
+ return build
+
+ def _fake_builds_at_index(self, index):
+ return [self._build_from_fake(builder, index) for builder in self.fake_builders]
+
+ def test_last_green_revision(self):
+ buildbot = BuildBot()
+ def mock_builds_from_builders(only_core_builders):
+ return self._fake_builds_at_index(0)
+ buildbot._latest_builds_from_builders = mock_builds_from_builders
+ self.assertEqual(buildbot.last_green_revision(), 1)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/net/credentials.py b/Tools/Scripts/webkitpy/common/net/credentials.py
new file mode 100644
index 0000000..30480b3
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/credentials.py
@@ -0,0 +1,155 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# 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:
+#
+# * 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.
+#
+# Python module for reading stored web credentials from the OS.
+
+import getpass
+import os
+import platform
+import re
+
+from webkitpy.common.checkout.scm import Git
+from webkitpy.common.system.executive import Executive, ScriptError
+from webkitpy.common.system.user import User
+from webkitpy.common.system.deprecated_logging import log
+
+try:
+ # Use keyring, a cross platform keyring interface, as a fallback:
+ # http://pypi.python.org/pypi/keyring
+ import keyring
+except ImportError:
+ keyring = None
+
+
+class Credentials(object):
+ _environ_prefix = "webkit_bugzilla_"
+
+ def __init__(self, host, git_prefix=None, executive=None, cwd=os.getcwd(),
+ keyring=keyring):
+ self.host = host
+ self.git_prefix = "%s." % git_prefix if git_prefix else ""
+ self.executive = executive or Executive()
+ self.cwd = cwd
+ self._keyring = keyring
+
+ def _credentials_from_git(self):
+ try:
+ if not Git.in_working_directory(self.cwd):
+ return (None, None)
+ return (Git.read_git_config(self.git_prefix + "username"),
+ Git.read_git_config(self.git_prefix + "password"))
+ except OSError, e:
+ # Catch and ignore OSError exceptions such as "no such file
+ # or directory" (OSError errno 2), which imply that the Git
+ # command cannot be found/is not installed.
+ pass
+ return (None, None)
+
+ def _keychain_value_with_label(self, label, source_text):
+ match = re.search("%s\"(?P<value>.+)\"" % label,
+ source_text,
+ re.MULTILINE)
+ if match:
+ return match.group('value')
+
+ def _is_mac_os_x(self):
+ return platform.mac_ver()[0]
+
+ def _parse_security_tool_output(self, security_output):
+ username = self._keychain_value_with_label("^\s*\"acct\"<blob>=",
+ security_output)
+ password = self._keychain_value_with_label("^password: ",
+ security_output)
+ return [username, password]
+
+ def _run_security_tool(self, username=None):
+ security_command = [
+ "/usr/bin/security",
+ "find-internet-password",
+ "-g",
+ "-s",
+ self.host,
+ ]
+ if username:
+ security_command += ["-a", username]
+
+ log("Reading Keychain for %s account and password. "
+ "Click \"Allow\" to continue..." % self.host)
+ try:
+ return self.executive.run_command(security_command)
+ except ScriptError:
+ # Failed to either find a keychain entry or somekind of OS-related
+ # error occured (for instance, couldn't find the /usr/sbin/security
+ # command).
+ log("Could not find a keychain entry for %s." % self.host)
+ return None
+
+ def _credentials_from_keychain(self, username=None):
+ if not self._is_mac_os_x():
+ return [username, None]
+
+ security_output = self._run_security_tool(username)
+ if security_output:
+ return self._parse_security_tool_output(security_output)
+ else:
+ return [None, None]
+
+ def _read_environ(self, key):
+ environ_key = self._environ_prefix + key
+ return os.environ.get(environ_key.upper())
+
+ def _credentials_from_environment(self):
+ return (self._read_environ("username"), self._read_environ("password"))
+
+ def _offer_to_store_credentials_in_keyring(self, username, password):
+ if not self._keyring:
+ return
+ if not User().confirm("Store password in system keyring?", User.DEFAULT_NO):
+ return
+ self._keyring.set_password(self.host, username, password)
+
+ def read_credentials(self):
+ username, password = self._credentials_from_environment()
+ # FIXME: We don't currently support pulling the username from one
+ # source and the password from a separate source.
+ if not username or not password:
+ username, password = self._credentials_from_git()
+ if not username or not password:
+ username, password = self._credentials_from_keychain(username)
+
+ if username and not password and self._keyring:
+ password = self._keyring.get_password(self.host, username)
+
+ if not username:
+ username = User.prompt("%s login: " % self.host)
+ if not password:
+ password = getpass.getpass("%s password for %s: " % (self.host, username))
+ self._offer_to_store_credentials_in_keyring(username, password)
+
+ return (username, password)
diff --git a/Tools/Scripts/webkitpy/common/net/credentials_unittest.py b/Tools/Scripts/webkitpy/common/net/credentials_unittest.py
new file mode 100644
index 0000000..6f2d909
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/credentials_unittest.py
@@ -0,0 +1,176 @@
+# 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.
+
+from __future__ import with_statement
+
+import os
+import tempfile
+import unittest
+from webkitpy.common.net.credentials import Credentials
+from webkitpy.common.system.executive import Executive
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.thirdparty.mock import Mock
+
+
+# FIXME: Other unit tests probably want this class.
+class _TemporaryDirectory(object):
+ def __init__(self, **kwargs):
+ self._kwargs = kwargs
+ self._directory_path = None
+
+ def __enter__(self):
+ self._directory_path = tempfile.mkdtemp(**self._kwargs)
+ return self._directory_path
+
+ def __exit__(self, type, value, traceback):
+ os.rmdir(self._directory_path)
+
+
+class CredentialsTest(unittest.TestCase):
+ example_security_output = """keychain: "/Users/test/Library/Keychains/login.keychain"
+class: "inet"
+attributes:
+ 0x00000007 <blob>="bugs.webkit.org (test@webkit.org)"
+ 0x00000008 <blob>=<NULL>
+ "acct"<blob>="test@webkit.org"
+ "atyp"<blob>="form"
+ "cdat"<timedate>=0x32303039303832353233353231365A00 "20090825235216Z\000"
+ "crtr"<uint32>=<NULL>
+ "cusi"<sint32>=<NULL>
+ "desc"<blob>="Web form password"
+ "icmt"<blob>="default"
+ "invi"<sint32>=<NULL>
+ "mdat"<timedate>=0x32303039303930393137323635315A00 "20090909172651Z\000"
+ "nega"<sint32>=<NULL>
+ "path"<blob>=<NULL>
+ "port"<uint32>=0x00000000
+ "prot"<blob>=<NULL>
+ "ptcl"<uint32>="htps"
+ "scrp"<sint32>=<NULL>
+ "sdmn"<blob>=<NULL>
+ "srvr"<blob>="bugs.webkit.org"
+ "type"<uint32>=<NULL>
+password: "SECRETSAUCE"
+"""
+
+ def test_keychain_lookup_on_non_mac(self):
+ class FakeCredentials(Credentials):
+ def _is_mac_os_x(self):
+ return False
+ credentials = FakeCredentials("bugs.webkit.org")
+ self.assertEqual(credentials._is_mac_os_x(), False)
+ self.assertEqual(credentials._credentials_from_keychain("foo"), ["foo", None])
+
+ def test_security_output_parse(self):
+ credentials = Credentials("bugs.webkit.org")
+ self.assertEqual(credentials._parse_security_tool_output(self.example_security_output), ["test@webkit.org", "SECRETSAUCE"])
+
+ def test_security_output_parse_entry_not_found(self):
+ credentials = Credentials("foo.example.com")
+ if not credentials._is_mac_os_x():
+ return # This test does not run on a non-Mac.
+
+ # Note, we ignore the captured output because it is already covered
+ # by the test case CredentialsTest._assert_security_call (below).
+ outputCapture = OutputCapture()
+ outputCapture.capture_output()
+ self.assertEqual(credentials._run_security_tool(), None)
+ outputCapture.restore_output()
+
+ def _assert_security_call(self, username=None):
+ executive_mock = Mock()
+ credentials = Credentials("example.com", executive=executive_mock)
+
+ expected_stderr = "Reading Keychain for example.com account and password. Click \"Allow\" to continue...\n"
+ OutputCapture().assert_outputs(self, credentials._run_security_tool, [username], expected_stderr=expected_stderr)
+
+ security_args = ["/usr/bin/security", "find-internet-password", "-g", "-s", "example.com"]
+ if username:
+ security_args += ["-a", username]
+ executive_mock.run_command.assert_called_with(security_args)
+
+ def test_security_calls(self):
+ self._assert_security_call()
+ self._assert_security_call(username="foo")
+
+ def test_credentials_from_environment(self):
+ executive_mock = Mock()
+ credentials = Credentials("example.com", executive=executive_mock)
+
+ saved_environ = os.environ.copy()
+ os.environ['WEBKIT_BUGZILLA_USERNAME'] = "foo"
+ os.environ['WEBKIT_BUGZILLA_PASSWORD'] = "bar"
+ username, password = credentials._credentials_from_environment()
+ self.assertEquals(username, "foo")
+ self.assertEquals(password, "bar")
+ os.environ = saved_environ
+
+ def test_read_credentials_without_git_repo(self):
+ # FIXME: This should share more code with test_keyring_without_git_repo
+ class FakeCredentials(Credentials):
+ def _is_mac_os_x(self):
+ return True
+
+ def _credentials_from_keychain(self, username):
+ return ("test@webkit.org", "SECRETSAUCE")
+
+ def _credentials_from_environment(self):
+ return (None, None)
+
+ with _TemporaryDirectory(suffix="not_a_git_repo") as temp_dir_path:
+ credentials = FakeCredentials("bugs.webkit.org", cwd=temp_dir_path)
+ # FIXME: Using read_credentials here seems too broad as higher-priority
+ # credential source could be affected by the user's environment.
+ self.assertEqual(credentials.read_credentials(), ("test@webkit.org", "SECRETSAUCE"))
+
+
+ def test_keyring_without_git_repo(self):
+ # FIXME: This should share more code with test_read_credentials_without_git_repo
+ class MockKeyring(object):
+ def get_password(self, host, username):
+ return "NOMNOMNOM"
+
+ class FakeCredentials(Credentials):
+ def _is_mac_os_x(self):
+ return True
+
+ def _credentials_from_keychain(self, username):
+ return ("test@webkit.org", None)
+
+ def _credentials_from_environment(self):
+ return (None, None)
+
+ with _TemporaryDirectory(suffix="not_a_git_repo") as temp_dir_path:
+ credentials = FakeCredentials("fake.hostname", cwd=temp_dir_path, keyring=MockKeyring())
+ # FIXME: Using read_credentials here seems too broad as higher-priority
+ # credential source could be affected by the user's environment.
+ self.assertEqual(credentials.read_credentials(), ("test@webkit.org", "NOMNOMNOM"))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/net/failuremap.py b/Tools/Scripts/webkitpy/common/net/failuremap.py
new file mode 100644
index 0000000..48cd3e6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/failuremap.py
@@ -0,0 +1,85 @@
+# Copyright (C) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+# FIXME: This probably belongs in the buildbot module.
+class FailureMap(object):
+ def __init__(self):
+ self._failures = []
+
+ def add_regression_window(self, builder, regression_window):
+ self._failures.append({
+ 'builder': builder,
+ 'regression_window': regression_window,
+ })
+
+ def is_empty(self):
+ return not self._failures
+
+ def failing_revisions(self):
+ failing_revisions = [failure_info['regression_window'].revisions()
+ for failure_info in self._failures]
+ return sorted(set(sum(failing_revisions, [])))
+
+ def builders_failing_for(self, revision):
+ return self._builders_failing_because_of([revision])
+
+ def tests_failing_for(self, revision):
+ tests = [failure_info['regression_window'].failing_tests()
+ for failure_info in self._failures
+ if revision in failure_info['regression_window'].revisions()
+ and failure_info['regression_window'].failing_tests()]
+ result = set()
+ for test in tests:
+ result = result.union(test)
+ return sorted(result)
+
+ def _old_failures(self, is_old_failure):
+ return filter(lambda revision: is_old_failure(revision),
+ self.failing_revisions())
+
+ def _builders_failing_because_of(self, revisions):
+ revision_set = set(revisions)
+ return [failure_info['builder'] for failure_info in self._failures
+ if revision_set.intersection(
+ failure_info['regression_window'].revisions())]
+
+ # FIXME: We should re-process old failures after some time delay.
+ # https://bugs.webkit.org/show_bug.cgi?id=36581
+ def filter_out_old_failures(self, is_old_failure):
+ old_failures = self._old_failures(is_old_failure)
+ old_failing_builder_names = set([builder.name()
+ for builder in self._builders_failing_because_of(old_failures)])
+
+ # We filter out all the failing builders that could have been caused
+ # by old_failures. We could miss some new failures this way, but
+ # emperically, this reduces the amount of spam we generate.
+ failures = self._failures
+ self._failures = [failure_info for failure_info in failures
+ if failure_info['builder'].name() not in old_failing_builder_names]
+ self._cache = {}
diff --git a/Tools/Scripts/webkitpy/common/net/failuremap_unittest.py b/Tools/Scripts/webkitpy/common/net/failuremap_unittest.py
new file mode 100644
index 0000000..2f0b49d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/failuremap_unittest.py
@@ -0,0 +1,76 @@
+# 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 unittest
+
+from webkitpy.common.net.buildbot import Build
+from webkitpy.common.net.failuremap import *
+from webkitpy.common.net.regressionwindow import RegressionWindow
+from webkitpy.tool.mocktool import MockBuilder
+
+
+class FailureMapTest(unittest.TestCase):
+ builder1 = MockBuilder("Builder1")
+ builder2 = MockBuilder("Builder2")
+
+ build1a = Build(builder1, build_number=22, revision=1233, is_green=True)
+ build1b = Build(builder1, build_number=23, revision=1234, is_green=False)
+ build2a = Build(builder2, build_number=89, revision=1233, is_green=True)
+ build2b = Build(builder2, build_number=90, revision=1235, is_green=False)
+
+ regression_window1 = RegressionWindow(build1a, build1b, failing_tests=[u'test1', u'test1'])
+ regression_window2 = RegressionWindow(build2a, build2b, failing_tests=[u'test1'])
+
+ def _make_failure_map(self):
+ failure_map = FailureMap()
+ failure_map.add_regression_window(self.builder1, self.regression_window1)
+ failure_map.add_regression_window(self.builder2, self.regression_window2)
+ return failure_map
+
+ def test_failing_revisions(self):
+ failure_map = self._make_failure_map()
+ self.assertEquals(failure_map.failing_revisions(), [1234, 1235])
+
+ def test_new_failures(self):
+ failure_map = self._make_failure_map()
+ failure_map.filter_out_old_failures(lambda revision: False)
+ self.assertEquals(failure_map.failing_revisions(), [1234, 1235])
+
+ def test_new_failures_with_old_revisions(self):
+ failure_map = self._make_failure_map()
+ failure_map.filter_out_old_failures(lambda revision: revision == 1234)
+ self.assertEquals(failure_map.failing_revisions(), [])
+
+ def test_new_failures_with_more_old_revisions(self):
+ failure_map = self._make_failure_map()
+ failure_map.filter_out_old_failures(lambda revision: revision == 1235)
+ self.assertEquals(failure_map.failing_revisions(), [1234])
+
+ def test_tests_failing_for(self):
+ failure_map = self._make_failure_map()
+ self.assertEquals(failure_map.tests_failing_for(1234), [u'test1'])
diff --git a/Tools/Scripts/webkitpy/common/net/irc/__init__.py b/Tools/Scripts/webkitpy/common/net/irc/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/irc/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/common/net/irc/ircbot.py b/Tools/Scripts/webkitpy/common/net/irc/ircbot.py
new file mode 100644
index 0000000..f742867
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/irc/ircbot.py
@@ -0,0 +1,91 @@
+# 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 webkitpy.common.config.irc as config_irc
+
+from webkitpy.common.thread.messagepump import MessagePump, MessagePumpDelegate
+from webkitpy.thirdparty.autoinstalled.irc import ircbot
+from webkitpy.thirdparty.autoinstalled.irc import irclib
+
+
+class IRCBotDelegate(object):
+ def irc_message_received(self, nick, message):
+ raise NotImplementedError, "subclasses must implement"
+
+ def irc_nickname(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def irc_password(self):
+ raise NotImplementedError, "subclasses must implement"
+
+
+class IRCBot(ircbot.SingleServerIRCBot, MessagePumpDelegate):
+ # FIXME: We should get this information from a config file.
+ def __init__(self,
+ message_queue,
+ delegate):
+ self._message_queue = message_queue
+ self._delegate = delegate
+ ircbot.SingleServerIRCBot.__init__(
+ self,
+ [(
+ config_irc.server,
+ config_irc.port,
+ self._delegate.irc_password()
+ )],
+ self._delegate.irc_nickname(),
+ self._delegate.irc_nickname())
+ self._channel = config_irc.channel
+
+ # ircbot.SingleServerIRCBot methods
+
+ def on_nicknameinuse(self, connection, event):
+ connection.nick(connection.get_nickname() + "_")
+
+ def on_welcome(self, connection, event):
+ connection.join(self._channel)
+ self._message_pump = MessagePump(self, self._message_queue)
+
+ def on_pubmsg(self, connection, event):
+ nick = irclib.nm_to_n(event.source())
+ request = event.arguments()[0].split(":", 1)
+ if len(request) > 1 and irclib.irc_lower(request[0]) == irclib.irc_lower(self.connection.get_nickname()):
+ response = self._delegate.irc_message_received(nick, request[1])
+ if response:
+ connection.privmsg(self._channel, response)
+
+ # MessagePumpDelegate methods
+
+ def schedule(self, interval, callback):
+ self.connection.execute_delayed(interval, callback)
+
+ def message_available(self, message):
+ self.connection.privmsg(self._channel, message)
+
+ def final_message_delivered(self):
+ self.die()
diff --git a/Tools/Scripts/webkitpy/common/net/irc/ircproxy.py b/Tools/Scripts/webkitpy/common/net/irc/ircproxy.py
new file mode 100644
index 0000000..13348b4
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/irc/ircproxy.py
@@ -0,0 +1,62 @@
+# 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 threading
+
+from webkitpy.common.net.irc.ircbot import IRCBot
+from webkitpy.common.thread.threadedmessagequeue import ThreadedMessageQueue
+from webkitpy.common.system.deprecated_logging import log
+
+
+class _IRCThread(threading.Thread):
+ def __init__(self, message_queue, irc_delegate, irc_bot):
+ threading.Thread.__init__(self)
+ self.setDaemon(True)
+ self._message_queue = message_queue
+ self._irc_delegate = irc_delegate
+ self._irc_bot = irc_bot
+
+ def run(self):
+ bot = self._irc_bot(self._message_queue, self._irc_delegate)
+ bot.start()
+
+
+class IRCProxy(object):
+ def __init__(self, irc_delegate, irc_bot=IRCBot):
+ log("Connecting to IRC")
+ self._message_queue = ThreadedMessageQueue()
+ self._child_thread = _IRCThread(self._message_queue, irc_delegate, irc_bot)
+ self._child_thread.start()
+
+ def post(self, message):
+ self._message_queue.post(message)
+
+ def disconnect(self):
+ log("Disconnecting from IRC...")
+ self._message_queue.stop()
+ self._child_thread.join()
diff --git a/Tools/Scripts/webkitpy/common/net/irc/ircproxy_unittest.py b/Tools/Scripts/webkitpy/common/net/irc/ircproxy_unittest.py
new file mode 100644
index 0000000..b44ce40
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/irc/ircproxy_unittest.py
@@ -0,0 +1,43 @@
+# 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 unittest
+
+from webkitpy.common.net.irc.ircproxy import IRCProxy
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.thirdparty.mock import Mock
+
+class IRCProxyTest(unittest.TestCase):
+ def test_trivial(self):
+ def fun():
+ proxy = IRCProxy(Mock(), Mock())
+ proxy.post("hello")
+ proxy.disconnect()
+
+ expected_stderr = "Connecting to IRC\nDisconnecting from IRC...\n"
+ OutputCapture().assert_outputs(self, fun, expected_stderr=expected_stderr)
diff --git a/Tools/Scripts/webkitpy/common/net/layouttestresults.py b/Tools/Scripts/webkitpy/common/net/layouttestresults.py
new file mode 100644
index 0000000..15e95ce
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/layouttestresults.py
@@ -0,0 +1,92 @@
+# 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.
+#
+# A module for parsing results.html files generated by old-run-webkit-tests
+
+from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup, SoupStrainer
+
+
+# FIXME: This should be unified with all the layout test results code in the layout_tests package
+# This doesn't belong in common.net, but we don't have a better place for it yet.
+def path_for_layout_test(test_name):
+ return "LayoutTests/%s" % test_name
+
+
+# FIXME: This should be unified with all the layout test results code in the layout_tests package
+# This doesn't belong in common.net, but we don't have a better place for it yet.
+class LayoutTestResults(object):
+ """This class knows how to parse old-run-webkit-tests results.html files."""
+
+ stderr_key = u'Tests that had stderr output:'
+ fail_key = u'Tests where results did not match expected results:'
+ timeout_key = u'Tests that timed out:'
+ crash_key = u'Tests that caused the DumpRenderTree tool to crash:'
+ missing_key = u'Tests that had no expected results (probably new):'
+
+ expected_keys = [
+ stderr_key,
+ fail_key,
+ crash_key,
+ timeout_key,
+ missing_key,
+ ]
+
+ @classmethod
+ def _parse_results_html(cls, page):
+ if not page:
+ return None
+ parsed_results = {}
+ tables = BeautifulSoup(page).findAll("table")
+ for table in tables:
+ table_title = unicode(table.findPreviousSibling("p").string)
+ if table_title not in cls.expected_keys:
+ # This Exception should only ever be hit if run-webkit-tests changes its results.html format.
+ raise Exception("Unhandled title: %s" % table_title)
+ # We might want to translate table titles into identifiers before storing.
+ parsed_results[table_title] = [unicode(row.find("a").string) for row in table.findAll("tr")]
+
+ return parsed_results
+
+ @classmethod
+ def results_from_string(cls, string):
+ parsed_results = cls._parse_results_html(string)
+ if not parsed_results:
+ return None
+ return cls(parsed_results)
+
+ def __init__(self, parsed_results):
+ self._parsed_results = parsed_results
+
+ def parsed_results(self):
+ return self._parsed_results
+
+ def results_matching_keys(self, result_keys):
+ return sorted(sum([tests for key, tests in self._parsed_results.items() if key in result_keys], []))
+
+ def failing_tests(self):
+ return self.results_matching_keys([self.fail_key, self.crash_key, self.timeout_key])
diff --git a/Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py b/Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py
new file mode 100644
index 0000000..8490eae
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/layouttestresults_unittest.py
@@ -0,0 +1,77 @@
+# 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 unittest
+
+from webkitpy.common.net.layouttestresults import LayoutTestResults
+
+
+class LayoutTestResultsTest(unittest.TestCase):
+ _example_results_html = """
+<html>
+<head>
+<title>Layout Test Results</title>
+</head>
+<body>
+<p>Tests that had stderr output:</p>
+<table>
+<tr>
+<td><a href="/var/lib/buildbot/build/gtk-linux-64-release/build/LayoutTests/accessibility/aria-activedescendant-crash.html">accessibility/aria-activedescendant-crash.html</a></td>
+<td><a href="accessibility/aria-activedescendant-crash-stderr.txt">stderr</a></td>
+</tr>
+<td><a href="/var/lib/buildbot/build/gtk-linux-64-release/build/LayoutTests/http/tests/security/canvas-remote-read-svg-image.html">http/tests/security/canvas-remote-read-svg-image.html</a></td>
+<td><a href="http/tests/security/canvas-remote-read-svg-image-stderr.txt">stderr</a></td>
+</tr>
+</table><p>Tests that had no expected results (probably new):</p>
+<table>
+<tr>
+<td><a href="/var/lib/buildbot/build/gtk-linux-64-release/build/LayoutTests/fast/repaint/no-caret-repaint-in-non-content-editable-element.html">fast/repaint/no-caret-repaint-in-non-content-editable-element.html</a></td>
+<td><a href="fast/repaint/no-caret-repaint-in-non-content-editable-element-actual.txt">result</a></td>
+</tr>
+</table></body>
+</html>
+"""
+
+ _expected_layout_test_results = {
+ 'Tests that had stderr output:': [
+ 'accessibility/aria-activedescendant-crash.html',
+ ],
+ 'Tests that had no expected results (probably new):': [
+ 'fast/repaint/no-caret-repaint-in-non-content-editable-element.html',
+ ],
+ }
+
+ def test_parse_layout_test_results(self):
+ results = LayoutTestResults._parse_results_html(self._example_results_html)
+ self.assertEqual(self._expected_layout_test_results, results)
+
+ def test_results_from_string(self):
+ self.assertEqual(LayoutTestResults.results_from_string(None), None)
+ self.assertEqual(LayoutTestResults.results_from_string(""), None)
+ results = LayoutTestResults.results_from_string(self._example_results_html)
+ self.assertEqual(len(results.failing_tests()), 0)
diff --git a/Tools/Scripts/webkitpy/common/net/networktransaction.py b/Tools/Scripts/webkitpy/common/net/networktransaction.py
new file mode 100644
index 0000000..de19e94
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/networktransaction.py
@@ -0,0 +1,72 @@
+# 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 logging
+import time
+
+from webkitpy.thirdparty.autoinstalled import mechanize
+from webkitpy.common.system.deprecated_logging import log
+
+
+_log = logging.getLogger(__name__)
+
+
+class NetworkTimeout(Exception):
+ pass
+
+
+class NetworkTransaction(object):
+ def __init__(self, initial_backoff_seconds=10, grown_factor=1.5, timeout_seconds=(10 * 60), convert_404_to_None=False):
+ self._initial_backoff_seconds = initial_backoff_seconds
+ self._grown_factor = grown_factor
+ self._timeout_seconds = timeout_seconds
+ self._convert_404_to_None = convert_404_to_None
+
+ def run(self, request):
+ self._total_sleep = 0
+ self._backoff_seconds = self._initial_backoff_seconds
+ while True:
+ try:
+ return request()
+ # FIXME: We should catch urllib2.HTTPError here too.
+ except mechanize.HTTPError, e:
+ if self._convert_404_to_None and e.code == 404:
+ return None
+ self._check_for_timeout()
+ _log.warn("Received HTTP status %s from server. Retrying in "
+ "%s seconds..." % (e.code, self._backoff_seconds))
+ self._sleep()
+
+ def _check_for_timeout(self):
+ if self._total_sleep + self._backoff_seconds > self._timeout_seconds:
+ raise NetworkTimeout()
+
+ def _sleep(self):
+ time.sleep(self._backoff_seconds)
+ self._total_sleep += self._backoff_seconds
+ self._backoff_seconds *= self._grown_factor
diff --git a/Tools/Scripts/webkitpy/common/net/networktransaction_unittest.py b/Tools/Scripts/webkitpy/common/net/networktransaction_unittest.py
new file mode 100644
index 0000000..49aaeed
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/networktransaction_unittest.py
@@ -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.
+
+import unittest
+
+from webkitpy.common.net.networktransaction import NetworkTransaction, NetworkTimeout
+from webkitpy.common.system.logtesting import LoggingTestCase
+from webkitpy.thirdparty.autoinstalled.mechanize import HTTPError
+
+
+class NetworkTransactionTest(LoggingTestCase):
+ exception = Exception("Test exception")
+
+ def test_success(self):
+ transaction = NetworkTransaction()
+ self.assertEqual(transaction.run(lambda: 42), 42)
+
+ def _raise_exception(self):
+ raise self.exception
+
+ def test_exception(self):
+ transaction = NetworkTransaction()
+ did_process_exception = False
+ did_throw_exception = True
+ try:
+ transaction.run(lambda: self._raise_exception())
+ did_throw_exception = False
+ except Exception, e:
+ did_process_exception = True
+ self.assertEqual(e, self.exception)
+ self.assertTrue(did_throw_exception)
+ self.assertTrue(did_process_exception)
+
+ def _raise_500_error(self):
+ self._run_count += 1
+ if self._run_count < 3:
+ raise HTTPError("http://example.com/", 500, "internal server error", None, None)
+ return 42
+
+ def _raise_404_error(self):
+ raise HTTPError("http://foo.com/", 404, "not found", None, None)
+
+ def test_retry(self):
+ self._run_count = 0
+ transaction = NetworkTransaction(initial_backoff_seconds=0)
+ self.assertEqual(transaction.run(lambda: self._raise_500_error()), 42)
+ self.assertEqual(self._run_count, 3)
+ self.assertLog(['WARNING: Received HTTP status 500 from server. '
+ 'Retrying in 0 seconds...\n',
+ 'WARNING: Received HTTP status 500 from server. '
+ 'Retrying in 0.0 seconds...\n'])
+
+ def test_convert_404_to_None(self):
+ transaction = NetworkTransaction(convert_404_to_None=True)
+ self.assertEqual(transaction.run(lambda: self._raise_404_error()), None)
+
+ def test_timeout(self):
+ self._run_count = 0
+ transaction = NetworkTransaction(initial_backoff_seconds=60*60, timeout_seconds=60)
+ did_process_exception = False
+ did_throw_exception = True
+ try:
+ transaction.run(lambda: self._raise_500_error())
+ did_throw_exception = False
+ except NetworkTimeout, e:
+ did_process_exception = True
+ self.assertTrue(did_throw_exception)
+ self.assertTrue(did_process_exception)
diff --git a/Tools/Scripts/webkitpy/common/net/regressionwindow.py b/Tools/Scripts/webkitpy/common/net/regressionwindow.py
new file mode 100644
index 0000000..3960ba2
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/regressionwindow.py
@@ -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.
+
+
+# FIXME: This probably belongs in the buildbot module.
+class RegressionWindow(object):
+ def __init__(self, build_before_failure, failing_build, failing_tests=None):
+ self._build_before_failure = build_before_failure
+ self._failing_build = failing_build
+ self._failing_tests = failing_tests
+ self._revisions = None
+
+ def build_before_failure(self):
+ return self._build_before_failure
+
+ def failing_build(self):
+ return self._failing_build
+
+ def failing_tests(self):
+ return self._failing_tests
+
+ def revisions(self):
+ # Cache revisions to avoid excessive allocations.
+ if not self._revisions:
+ self._revisions = range(self._failing_build.revision(), self._build_before_failure.revision(), -1)
+ self._revisions.reverse()
+ return self._revisions
diff --git a/Tools/Scripts/webkitpy/common/net/statusserver.py b/Tools/Scripts/webkitpy/common/net/statusserver.py
new file mode 100644
index 0000000..64dd77b
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/statusserver.py
@@ -0,0 +1,160 @@
+# 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.
+
+from webkitpy.common.net.networktransaction import NetworkTransaction
+from webkitpy.common.system.deprecated_logging import log
+from webkitpy.thirdparty.autoinstalled.mechanize import Browser
+from webkitpy.thirdparty.BeautifulSoup import BeautifulSoup
+
+import logging
+import urllib2
+
+
+_log = logging.getLogger("webkitpy.common.net.statusserver")
+
+
+class StatusServer:
+ default_host = "queues.webkit.org"
+
+ def __init__(self, host=default_host, browser=None, bot_id=None):
+ self.set_host(host)
+ self._browser = browser or Browser()
+ self.set_bot_id(bot_id)
+
+ def set_host(self, host):
+ self.host = host
+ self.url = "http://%s" % self.host
+
+ def set_bot_id(self, bot_id):
+ self.bot_id = bot_id
+
+ def results_url_for_status(self, status_id):
+ return "%s/results/%s" % (self.url, status_id)
+
+ def _add_patch(self, patch):
+ if not patch:
+ return
+ if patch.bug_id():
+ self._browser["bug_id"] = unicode(patch.bug_id())
+ if patch.id():
+ self._browser["patch_id"] = unicode(patch.id())
+
+ def _add_results_file(self, results_file):
+ if not results_file:
+ return
+ self._browser.add_file(results_file, "text/plain", "results.txt", 'results_file')
+
+ def _post_status_to_server(self, queue_name, status, patch, results_file):
+ if results_file:
+ # We might need to re-wind the file if we've already tried to post it.
+ results_file.seek(0)
+
+ update_status_url = "%s/update-status" % self.url
+ self._browser.open(update_status_url)
+ self._browser.select_form(name="update_status")
+ self._browser["queue_name"] = queue_name
+ if self.bot_id:
+ self._browser["bot_id"] = self.bot_id
+ self._add_patch(patch)
+ self._browser["status"] = status
+ self._add_results_file(results_file)
+ return self._browser.submit().read() # This is the id of the newly created status object.
+
+ def _post_svn_revision_to_server(self, svn_revision_number, broken_bot):
+ update_svn_revision_url = "%s/update-svn-revision" % self.url
+ self._browser.open(update_svn_revision_url)
+ self._browser.select_form(name="update_svn_revision")
+ self._browser["number"] = unicode(svn_revision_number)
+ self._browser["broken_bot"] = broken_bot
+ return self._browser.submit().read()
+
+ def _post_work_items_to_server(self, queue_name, work_items):
+ update_work_items_url = "%s/update-work-items" % self.url
+ self._browser.open(update_work_items_url)
+ self._browser.select_form(name="update_work_items")
+ self._browser["queue_name"] = queue_name
+ work_items = map(unicode, work_items) # .join expects strings
+ self._browser["work_items"] = " ".join(work_items)
+ return self._browser.submit().read()
+
+ def _post_work_item_to_ews(self, attachment_id):
+ submit_to_ews_url = "%s/submit-to-ews" % self.url
+ self._browser.open(submit_to_ews_url)
+ self._browser.select_form(name="submit_to_ews")
+ self._browser["attachment_id"] = unicode(attachment_id)
+ self._browser.submit()
+
+ def submit_to_ews(self, attachment_id):
+ _log.info("Submitting attachment %s to EWS queues" % attachment_id)
+ return NetworkTransaction().run(lambda: self._post_work_item_to_ews(attachment_id))
+
+ def next_work_item(self, queue_name):
+ _log.debug("Fetching next work item for %s" % queue_name)
+ patch_status_url = "%s/next-patch/%s" % (self.url, queue_name)
+ return self._fetch_url(patch_status_url)
+
+ def _post_release_work_item(self, queue_name, patch):
+ release_patch_url = "%s/release-patch" % (self.url)
+ self._browser.open(release_patch_url)
+ self._browser.select_form(name="release_patch")
+ self._browser["queue_name"] = queue_name
+ self._browser["attachment_id"] = unicode(patch.id())
+ self._browser.submit()
+
+ def release_work_item(self, queue_name, patch):
+ _log.info("Releasing work item %s from %s" % (patch.id(), queue_name))
+ return NetworkTransaction(convert_404_to_None=True).run(lambda: self._post_release_work_item(queue_name, patch))
+
+ def update_work_items(self, queue_name, work_items):
+ _log.debug("Recording work items: %s for %s" % (work_items, queue_name))
+ return NetworkTransaction().run(lambda: self._post_work_items_to_server(queue_name, work_items))
+
+ def update_status(self, queue_name, status, patch=None, results_file=None):
+ log(status)
+ return NetworkTransaction().run(lambda: self._post_status_to_server(queue_name, status, patch, results_file))
+
+ def update_svn_revision(self, svn_revision_number, broken_bot):
+ log("SVN revision: %s broke %s" % (svn_revision_number, broken_bot))
+ return NetworkTransaction().run(lambda: self._post_svn_revision_to_server(svn_revision_number, broken_bot))
+
+ def _fetch_url(self, url):
+ # FIXME: This should use NetworkTransaction's 404 handling instead.
+ try:
+ return urllib2.urlopen(url).read()
+ except urllib2.HTTPError, e:
+ if e.code == 404:
+ return None
+ raise e
+
+ def patch_status(self, queue_name, patch_id):
+ patch_status_url = "%s/patch-status/%s/%s" % (self.url, queue_name, patch_id)
+ return self._fetch_url(patch_status_url)
+
+ def svn_revision(self, svn_revision_number):
+ svn_revision_url = "%s/svn-revision/%s" % (self.url, svn_revision_number)
+ return self._fetch_url(svn_revision_url)
diff --git a/Tools/Scripts/webkitpy/common/net/statusserver_unittest.py b/Tools/Scripts/webkitpy/common/net/statusserver_unittest.py
new file mode 100644
index 0000000..1169ba0
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/net/statusserver_unittest.py
@@ -0,0 +1,43 @@
+# 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 unittest
+
+from webkitpy.common.net.statusserver import StatusServer
+from webkitpy.common.system.outputcapture import OutputCaptureTestCaseBase
+from webkitpy.tool.mocktool import MockBrowser
+
+
+class StatusServerTest(OutputCaptureTestCaseBase):
+ def test_url_for_issue(self):
+ mock_browser = MockBrowser()
+ status_server = StatusServer(browser=mock_browser, bot_id='123')
+ status_server.update_status('queue name', 'the status')
+ self.assertEqual('queue name', mock_browser.params['queue_name'])
+ self.assertEqual('the status', mock_browser.params['status'])
+ self.assertEqual('123', mock_browser.params['bot_id'])
diff --git a/Tools/Scripts/webkitpy/common/newstringio.py b/Tools/Scripts/webkitpy/common/newstringio.py
new file mode 100644
index 0000000..f6d08ec
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/newstringio.py
@@ -0,0 +1,40 @@
+#!/usr/bin/env python
+# 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.
+
+"""'with'-compliant StringIO implementation."""
+
+import StringIO
+
+
+class StringIO(StringIO.StringIO):
+ def __enter__(self):
+ return self
+
+ def __exit__(self, type, value, traceback):
+ pass
diff --git a/Tools/Scripts/webkitpy/common/newstringio_unittest.py b/Tools/Scripts/webkitpy/common/newstringio_unittest.py
new file mode 100644
index 0000000..5755c98
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/newstringio_unittest.py
@@ -0,0 +1,46 @@
+#!/usr/bin/env python
+# 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.
+
+"""Unit tests for newstringio module."""
+
+from __future__ import with_statement
+
+import unittest
+
+import newstringio
+
+
+class NewStringIOTest(unittest.TestCase):
+ def test_with(self):
+ with newstringio.StringIO("foo") as f:
+ contents = f.read()
+ self.assertEqual(contents, "foo")
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/prettypatch.py b/Tools/Scripts/webkitpy/common/prettypatch.py
new file mode 100644
index 0000000..e8a913a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/prettypatch.py
@@ -0,0 +1,67 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import os
+import tempfile
+
+
+class PrettyPatch(object):
+ # FIXME: PrettyPatch should not require checkout_root.
+ def __init__(self, executive, checkout_root):
+ self._executive = executive
+ self._checkout_root = checkout_root
+
+ def pretty_diff_file(self, diff):
+ # Diffs can contain multiple text files of different encodings
+ # so we always deal with them as byte arrays, not unicode strings.
+ assert(isinstance(diff, str))
+ pretty_diff = self.pretty_diff(diff)
+ diff_file = tempfile.NamedTemporaryFile(suffix=".html")
+ diff_file.write(pretty_diff)
+ diff_file.flush()
+ return diff_file
+
+ def pretty_diff(self, diff):
+ # pretify.rb will hang forever if given no input.
+ # Avoid the hang by returning an empty string.
+ if not diff:
+ return ""
+
+ pretty_patch_path = os.path.join(self._checkout_root,
+ "Websites", "bugs.webkit.org",
+ "PrettyPatch")
+ prettify_path = os.path.join(pretty_patch_path, "prettify.rb")
+ args = [
+ "ruby",
+ "-I",
+ pretty_patch_path,
+ prettify_path,
+ ]
+ # PrettyPatch does not modify the encoding of the diff output
+ # so we can't expect it to be utf-8.
+ return self._executive.run_command(args, input=diff, decode_output=False)
diff --git a/Tools/Scripts/webkitpy/common/prettypatch_unittest.py b/Tools/Scripts/webkitpy/common/prettypatch_unittest.py
new file mode 100644
index 0000000..1307856
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/prettypatch_unittest.py
@@ -0,0 +1,70 @@
+# 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 os.path
+import unittest
+
+from webkitpy.common.system.executive import Executive
+from webkitpy.common.prettypatch import PrettyPatch
+
+
+class PrettyPatchTest(unittest.TestCase):
+
+ _diff_with_multiple_encodings = """
+Index: utf8_test
+===================================================================
+--- utf8_test\t(revision 0)
++++ utf8_test\t(revision 0)
+@@ -0,0 +1 @@
++utf-8 test: \xc2\xa0
+Index: latin1_test
+===================================================================
+--- latin1_test\t(revision 0)
++++ latin1_test\t(revision 0)
+@@ -0,0 +1 @@
++latin1 test: \xa0
+"""
+
+ def _webkit_root(self):
+ webkitpy_common = os.path.dirname(__file__)
+ webkitpy = os.path.dirname(webkitpy_common)
+ scripts = os.path.dirname(webkitpy)
+ webkit_tools = os.path.dirname(scripts)
+ webkit_root = os.path.dirname(webkit_tools)
+ return webkit_root
+
+ def test_pretty_diff_encodings(self):
+ pretty_patch = PrettyPatch(Executive(), self._webkit_root())
+ pretty = pretty_patch.pretty_diff(self._diff_with_multiple_encodings)
+ self.assertTrue(pretty) # We got some output
+ self.assertTrue(isinstance(pretty, str)) # It's a byte array, not unicode
+
+ def test_pretty_print_empty_string(self):
+ # Make sure that an empty diff does not hang the process.
+ pretty_patch = PrettyPatch(Executive(), self._webkit_root())
+ self.assertEqual(pretty_patch.pretty_diff(""), "")
diff --git a/Tools/Scripts/webkitpy/common/system/__init__.py b/Tools/Scripts/webkitpy/common/system/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/common/system/autoinstall.py b/Tools/Scripts/webkitpy/common/system/autoinstall.py
new file mode 100755
index 0000000..9adab29
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/autoinstall.py
@@ -0,0 +1,517 @@
+# Copyright (c) 2009, Daniel Krech All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.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 the Daniel Krech 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
+# HOLDER 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.
+
+"""Support for automatically downloading Python packages from an URL."""
+
+
+from __future__ import with_statement
+
+import codecs
+import logging
+import new
+import os
+import shutil
+import sys
+import tarfile
+import tempfile
+import urllib
+import urlparse
+import zipfile
+import zipimport
+
+_log = logging.getLogger(__name__)
+
+
+class AutoInstaller(object):
+
+ """Supports automatically installing Python packages from an URL.
+
+ Supports uncompressed files, .tar.gz, and .zip formats.
+
+ Basic usage:
+
+ installer = AutoInstaller()
+
+ installer.install(url="http://pypi.python.org/packages/source/p/pep8/pep8-0.5.0.tar.gz#md5=512a818af9979290cd619cce8e9c2e2b",
+ url_subpath="pep8-0.5.0/pep8.py")
+ installer.install(url="http://pypi.python.org/packages/source/m/mechanize/mechanize-0.1.11.zip",
+ url_subpath="mechanize")
+
+ """
+
+ def __init__(self, append_to_search_path=False, make_package=True,
+ target_dir=None, temp_dir=None):
+ """Create an AutoInstaller instance, and set up the target directory.
+
+ Args:
+ append_to_search_path: A boolean value of whether to append the
+ target directory to the sys.path search path.
+ make_package: A boolean value of whether to make the target
+ directory a package. This adds an __init__.py file
+ to the target directory -- allowing packages and
+ modules within the target directory to be imported
+ explicitly using dotted module names.
+ target_dir: The directory path to which packages should be installed.
+ Defaults to a subdirectory of the folder containing
+ this module called "autoinstalled".
+ temp_dir: The directory path to use for any temporary files
+ generated while downloading, unzipping, and extracting
+ packages to install. Defaults to a standard temporary
+ location generated by the tempfile module. This
+ parameter should normally be used only for development
+ testing.
+
+ """
+ if target_dir is None:
+ this_dir = os.path.dirname(__file__)
+ target_dir = os.path.join(this_dir, "autoinstalled")
+
+ # Ensure that the target directory exists.
+ self._set_up_target_dir(target_dir, append_to_search_path, make_package)
+
+ self._target_dir = target_dir
+ self._temp_dir = temp_dir
+
+ def _log_transfer(self, message, source, target, log_method=None):
+ """Log a debug message that involves a source and target."""
+ if log_method is None:
+ log_method = _log.debug
+
+ log_method("%s" % message)
+ log_method(' From: "%s"' % source)
+ log_method(' To: "%s"' % target)
+
+ def _create_directory(self, path, name=None):
+ """Create a directory."""
+ log = _log.debug
+
+ name = name + " " if name is not None else ""
+ log('Creating %sdirectory...' % name)
+ log(' "%s"' % path)
+
+ os.makedirs(path)
+
+ def _write_file(self, path, text, encoding):
+ """Create a file at the given path with given text.
+
+ This method overwrites any existing file.
+
+ """
+ _log.debug("Creating file...")
+ _log.debug(' "%s"' % path)
+ with codecs.open(path, "w", encoding) as file:
+ file.write(text)
+
+ def _set_up_target_dir(self, target_dir, append_to_search_path,
+ make_package):
+ """Set up a target directory.
+
+ Args:
+ target_dir: The path to the target directory to set up.
+ append_to_search_path: A boolean value of whether to append the
+ target directory to the sys.path search path.
+ make_package: A boolean value of whether to make the target
+ directory a package. This adds an __init__.py file
+ to the target directory -- allowing packages and
+ modules within the target directory to be imported
+ explicitly using dotted module names.
+
+ """
+ if not os.path.exists(target_dir):
+ self._create_directory(target_dir, "autoinstall target")
+
+ if append_to_search_path:
+ sys.path.append(target_dir)
+
+ if make_package:
+ init_path = os.path.join(target_dir, "__init__.py")
+ if not os.path.exists(init_path):
+ text = ("# This file is required for Python to search this "
+ "directory for modules.\n")
+ self._write_file(init_path, text, "ascii")
+
+ def _create_scratch_directory_inner(self, prefix):
+ """Create a scratch directory without exception handling.
+
+ Creates a scratch directory inside the AutoInstaller temp
+ directory self._temp_dir, or inside a platform-dependent temp
+ directory if self._temp_dir is None. Returns the path to the
+ created scratch directory.
+
+ Raises:
+ OSError: [Errno 2] if the containing temp directory self._temp_dir
+ is not None and does not exist.
+
+ """
+ # The tempfile.mkdtemp() method function requires that the
+ # directory corresponding to the "dir" parameter already exist
+ # if it is not None.
+ scratch_dir = tempfile.mkdtemp(prefix=prefix, dir=self._temp_dir)
+ return scratch_dir
+
+ def _create_scratch_directory(self, target_name):
+ """Create a temporary scratch directory, and return its path.
+
+ The scratch directory is generated inside the temp directory
+ of this AutoInstaller instance. This method also creates the
+ temp directory if it does not already exist.
+
+ """
+ prefix = target_name + "_"
+ try:
+ scratch_dir = self._create_scratch_directory_inner(prefix)
+ except OSError:
+ # Handle case of containing temp directory not existing--
+ # OSError: [Errno 2] No such file or directory:...
+ temp_dir = self._temp_dir
+ if temp_dir is None or os.path.exists(temp_dir):
+ raise
+ # Else try again after creating the temp directory.
+ self._create_directory(temp_dir, "autoinstall temp")
+ scratch_dir = self._create_scratch_directory_inner(prefix)
+
+ return scratch_dir
+
+ def _url_downloaded_path(self, target_name):
+ """Return the path to the file containing the URL downloaded."""
+ filename = ".%s.url" % target_name
+ path = os.path.join(self._target_dir, filename)
+ return path
+
+ def _is_downloaded(self, target_name, url):
+ """Return whether a package version has been downloaded."""
+ version_path = self._url_downloaded_path(target_name)
+
+ _log.debug('Checking %s URL downloaded...' % target_name)
+ _log.debug(' "%s"' % version_path)
+
+ if not os.path.exists(version_path):
+ # Then no package version has been downloaded.
+ _log.debug("No URL file found.")
+ return False
+
+ with codecs.open(version_path, "r", "utf-8") as file:
+ version = file.read()
+
+ return version.strip() == url.strip()
+
+ def _record_url_downloaded(self, target_name, url):
+ """Record the URL downloaded to a file."""
+ version_path = self._url_downloaded_path(target_name)
+ _log.debug("Recording URL downloaded...")
+ _log.debug(' URL: "%s"' % url)
+ _log.debug(' To: "%s"' % version_path)
+
+ self._write_file(version_path, url, "utf-8")
+
+ def _extract_targz(self, path, scratch_dir):
+ # tarfile.extractall() extracts to a path without the
+ # trailing ".tar.gz".
+ target_basename = os.path.basename(path[:-len(".tar.gz")])
+ target_path = os.path.join(scratch_dir, target_basename)
+
+ self._log_transfer("Starting gunzip/extract...", path, target_path)
+
+ try:
+ tar_file = tarfile.open(path)
+ except tarfile.ReadError, err:
+ # Append existing Error message to new Error.
+ message = ("Could not open tar file: %s\n"
+ " The file probably does not have the correct format.\n"
+ " --> Inner message: %s"
+ % (path, err))
+ raise Exception(message)
+
+ try:
+ # This is helpful for debugging purposes.
+ _log.debug("Listing tar file contents...")
+ for name in tar_file.getnames():
+ _log.debug(' * "%s"' % name)
+ _log.debug("Extracting gzipped tar file...")
+ tar_file.extractall(target_path)
+ finally:
+ tar_file.close()
+
+ return target_path
+
+ # This is a replacement for ZipFile.extractall(), which is
+ # available in Python 2.6 but not in earlier versions.
+ def _extract_all(self, zip_file, target_dir):
+ self._log_transfer("Extracting zip file...", zip_file, target_dir)
+
+ # This is helpful for debugging purposes.
+ _log.debug("Listing zip file contents...")
+ for name in zip_file.namelist():
+ _log.debug(' * "%s"' % name)
+
+ for name in zip_file.namelist():
+ path = os.path.join(target_dir, name)
+ self._log_transfer("Extracting...", name, path)
+
+ if not os.path.basename(path):
+ # Then the path ends in a slash, so it is a directory.
+ self._create_directory(path)
+ continue
+ # Otherwise, it is a file.
+
+ try:
+ # We open this file w/o encoding, as we're reading/writing
+ # the raw byte-stream from the zip file.
+ outfile = open(path, 'wb')
+ except IOError, err:
+ # Not all zip files seem to list the directories explicitly,
+ # so try again after creating the containing directory.
+ _log.debug("Got IOError: retrying after creating directory...")
+ dir = os.path.dirname(path)
+ self._create_directory(dir)
+ outfile = open(path, 'wb')
+
+ try:
+ outfile.write(zip_file.read(name))
+ finally:
+ outfile.close()
+
+ def _unzip(self, path, scratch_dir):
+ # zipfile.extractall() extracts to a path without the
+ # trailing ".zip".
+ target_basename = os.path.basename(path[:-len(".zip")])
+ target_path = os.path.join(scratch_dir, target_basename)
+
+ self._log_transfer("Starting unzip...", path, target_path)
+
+ try:
+ zip_file = zipfile.ZipFile(path, "r")
+ except zipfile.BadZipfile, err:
+ message = ("Could not open zip file: %s\n"
+ " --> Inner message: %s"
+ % (path, err))
+ raise Exception(message)
+
+ try:
+ self._extract_all(zip_file, scratch_dir)
+ finally:
+ zip_file.close()
+
+ return target_path
+
+ def _prepare_package(self, path, scratch_dir):
+ """Prepare a package for use, if necessary, and return the new path.
+
+ For example, this method unzips zipped files and extracts
+ tar files.
+
+ Args:
+ path: The path to the downloaded URL contents.
+ scratch_dir: The scratch directory. Note that the scratch
+ directory contains the file designated by the
+ path parameter.
+
+ """
+ # FIXME: Add other natural extensions.
+ if path.endswith(".zip"):
+ new_path = self._unzip(path, scratch_dir)
+ elif path.endswith(".tar.gz"):
+ new_path = self._extract_targz(path, scratch_dir)
+ else:
+ # No preparation is needed.
+ new_path = path
+
+ return new_path
+
+ def _download_to_stream(self, url, stream):
+ """Download an URL to a stream, and return the number of bytes."""
+ try:
+ netstream = urllib.urlopen(url)
+ except IOError, err:
+ # Append existing Error message to new Error.
+ message = ('Could not download Python modules from URL "%s".\n'
+ " Make sure you are connected to the internet.\n"
+ " You must be connected to the internet when "
+ "downloading needed modules for the first time.\n"
+ " --> Inner message: %s"
+ % (url, err))
+ raise IOError(message)
+ code = 200
+ if hasattr(netstream, "getcode"):
+ code = netstream.getcode()
+ if not 200 <= code < 300:
+ raise ValueError("HTTP Error code %s" % code)
+
+ BUFSIZE = 2**13 # 8KB
+ bytes = 0
+ while True:
+ data = netstream.read(BUFSIZE)
+ if not data:
+ break
+ stream.write(data)
+ bytes += len(data)
+ netstream.close()
+ return bytes
+
+ def _download(self, url, scratch_dir):
+ """Download URL contents, and return the download path."""
+ url_path = urlparse.urlsplit(url)[2]
+ url_path = os.path.normpath(url_path) # Removes trailing slash.
+ target_filename = os.path.basename(url_path)
+ target_path = os.path.join(scratch_dir, target_filename)
+
+ self._log_transfer("Starting download...", url, target_path)
+
+ with open(target_path, "wb") as stream:
+ bytes = self._download_to_stream(url, stream)
+
+ _log.debug("Downloaded %s bytes." % bytes)
+
+ return target_path
+
+ def _install(self, scratch_dir, package_name, target_path, url,
+ url_subpath):
+ """Install a python package from an URL.
+
+ This internal method overwrites the target path if the target
+ path already exists.
+
+ """
+ path = self._download(url=url, scratch_dir=scratch_dir)
+ path = self._prepare_package(path, scratch_dir)
+
+ if url_subpath is None:
+ source_path = path
+ else:
+ source_path = os.path.join(path, url_subpath)
+
+ if os.path.exists(target_path):
+ _log.debug('Refreshing install: deleting "%s".' % target_path)
+ if os.path.isdir(target_path):
+ shutil.rmtree(target_path)
+ else:
+ os.remove(target_path)
+
+ self._log_transfer("Moving files into place...", source_path, target_path)
+
+ # The shutil.move() command creates intermediate directories if they
+ # do not exist, but we do not rely on this behavior since we
+ # need to create the __init__.py file anyway.
+ shutil.move(source_path, target_path)
+
+ self._record_url_downloaded(package_name, url)
+
+ def install(self, url, should_refresh=False, target_name=None,
+ url_subpath=None):
+ """Install a python package from an URL.
+
+ Args:
+ url: The URL from which to download the package.
+
+ Optional Args:
+ should_refresh: A boolean value of whether the package should be
+ downloaded again if the package is already present.
+ target_name: The name of the folder or file in the autoinstaller
+ target directory at which the package should be
+ installed. Defaults to the base name of the
+ URL sub-path. This parameter must be provided if
+ the URL sub-path is not specified.
+ url_subpath: The relative path of the URL directory that should
+ be installed. Defaults to the full directory, or
+ the entire URL contents.
+
+ """
+ if target_name is None:
+ if not url_subpath:
+ raise ValueError('The "target_name" parameter must be '
+ 'provided if the "url_subpath" parameter '
+ "is not provided.")
+ # Remove any trailing slashes.
+ url_subpath = os.path.normpath(url_subpath)
+ target_name = os.path.basename(url_subpath)
+
+ target_path = os.path.join(self._target_dir, target_name)
+ if not should_refresh and self._is_downloaded(target_name, url):
+ _log.debug('URL for %s already downloaded. Skipping...'
+ % target_name)
+ _log.debug(' "%s"' % url)
+ return
+
+ self._log_transfer("Auto-installing package: %s" % target_name,
+ url, target_path, log_method=_log.info)
+
+ # The scratch directory is where we will download and prepare
+ # files specific to this install until they are ready to move
+ # into place.
+ scratch_dir = self._create_scratch_directory(target_name)
+
+ try:
+ self._install(package_name=target_name,
+ target_path=target_path,
+ scratch_dir=scratch_dir,
+ url=url,
+ url_subpath=url_subpath)
+ except Exception, err:
+ # Append existing Error message to new Error.
+ message = ("Error auto-installing the %s package to:\n"
+ ' "%s"\n'
+ " --> Inner message: %s"
+ % (target_name, target_path, err))
+ raise Exception(message)
+ finally:
+ _log.debug('Cleaning up: deleting "%s".' % scratch_dir)
+ shutil.rmtree(scratch_dir)
+ _log.debug('Auto-installed %s to:' % target_name)
+ _log.debug(' "%s"' % target_path)
+
+
+if __name__=="__main__":
+
+ # Configure the autoinstall logger to log DEBUG messages for
+ # development testing purposes.
+ console = logging.StreamHandler()
+
+ formatter = logging.Formatter('%(name)s: %(levelname)-8s %(message)s')
+ console.setFormatter(formatter)
+ _log.addHandler(console)
+ _log.setLevel(logging.DEBUG)
+
+ # Use a more visible temp directory for debug purposes.
+ this_dir = os.path.dirname(__file__)
+ target_dir = os.path.join(this_dir, "autoinstalled")
+ temp_dir = os.path.join(target_dir, "Temp")
+
+ installer = AutoInstaller(target_dir=target_dir,
+ temp_dir=temp_dir)
+
+ installer.install(should_refresh=False,
+ target_name="pep8.py",
+ url="http://pypi.python.org/packages/source/p/pep8/pep8-0.5.0.tar.gz#md5=512a818af9979290cd619cce8e9c2e2b",
+ url_subpath="pep8-0.5.0/pep8.py")
+ installer.install(should_refresh=False,
+ target_name="mechanize",
+ url="http://pypi.python.org/packages/source/m/mechanize/mechanize-0.1.11.zip",
+ url_subpath="mechanize")
+
diff --git a/Tools/Scripts/webkitpy/common/system/deprecated_logging.py b/Tools/Scripts/webkitpy/common/system/deprecated_logging.py
new file mode 100644
index 0000000..9e6b529
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/deprecated_logging.py
@@ -0,0 +1,91 @@
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# 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:
+#
+# * 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.
+#
+# WebKit's Python module for logging
+# This module is now deprecated in favor of python's built-in logging.py.
+
+import codecs
+import os
+import sys
+
+
+def log(string):
+ print >> sys.stderr, string
+
+
+def error(string):
+ log("ERROR: %s" % string)
+ exit(1)
+
+
+# Simple class to split output between multiple destinations
+class tee:
+ def __init__(self, *files):
+ self.files = files
+
+ # Callers should pass an already encoded string for writing.
+ def write(self, bytes):
+ for file in self.files:
+ file.write(bytes)
+
+
+class OutputTee:
+ def __init__(self):
+ self._original_stdout = None
+ self._original_stderr = None
+ self._files_for_output = []
+
+ def add_log(self, path):
+ log_file = self._open_log_file(path)
+ self._files_for_output.append(log_file)
+ self._tee_outputs_to_files(self._files_for_output)
+ return log_file
+
+ def remove_log(self, log_file):
+ self._files_for_output.remove(log_file)
+ self._tee_outputs_to_files(self._files_for_output)
+ log_file.close()
+
+ @staticmethod
+ def _open_log_file(log_path):
+ (log_directory, log_name) = os.path.split(log_path)
+ if log_directory and not os.path.exists(log_directory):
+ os.makedirs(log_directory)
+ return codecs.open(log_path, "a+", "utf-8")
+
+ def _tee_outputs_to_files(self, files):
+ if not self._original_stdout:
+ self._original_stdout = sys.stdout
+ self._original_stderr = sys.stderr
+ if files and len(files):
+ sys.stdout = tee(self._original_stdout, *files)
+ sys.stderr = tee(self._original_stderr, *files)
+ else:
+ sys.stdout = self._original_stdout
+ sys.stderr = self._original_stderr
diff --git a/Tools/Scripts/webkitpy/common/system/deprecated_logging_unittest.py b/Tools/Scripts/webkitpy/common/system/deprecated_logging_unittest.py
new file mode 100644
index 0000000..3778162
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/deprecated_logging_unittest.py
@@ -0,0 +1,60 @@
+# 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 os
+import StringIO
+import tempfile
+import unittest
+
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.common.system.deprecated_logging import *
+
+class LoggingTest(unittest.TestCase):
+
+ def assert_log_equals(self, log_input, expected_output):
+ original_stderr = sys.stderr
+ test_stderr = StringIO.StringIO()
+ sys.stderr = test_stderr
+
+ try:
+ log(log_input)
+ actual_output = test_stderr.getvalue()
+ finally:
+ sys.stderr = original_stderr
+
+ self.assertEquals(actual_output, expected_output, "log(\"%s\") expected: %s actual: %s" % (log_input, expected_output, actual_output))
+
+ def test_log(self):
+ self.assert_log_equals("test", "test\n")
+
+ # Test that log() does not throw an exception when passed an object instead of a string.
+ self.assert_log_equals(ScriptError(message="ScriptError"), "ScriptError\n")
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/system/executive.py b/Tools/Scripts/webkitpy/common/system/executive.py
new file mode 100644
index 0000000..85a683a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/executive.py
@@ -0,0 +1,399 @@
+# Copyright (c) 2009, Google Inc. All rights reserved.
+# 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:
+#
+# * 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.
+
+try:
+ # This API exists only in Python 2.6 and higher. :(
+ import multiprocessing
+except ImportError:
+ multiprocessing = None
+
+import ctypes
+import errno
+import logging
+import os
+import platform
+import StringIO
+import signal
+import subprocess
+import sys
+import time
+
+from webkitpy.common.system.deprecated_logging import tee
+from webkitpy.python24 import versioning
+
+
+_log = logging.getLogger("webkitpy.common.system")
+
+
+class ScriptError(Exception):
+
+ def __init__(self,
+ message=None,
+ script_args=None,
+ exit_code=None,
+ output=None,
+ cwd=None):
+ if not message:
+ message = 'Failed to run "%s"' % script_args
+ if exit_code:
+ message += " exit_code: %d" % exit_code
+ if cwd:
+ message += " cwd: %s" % cwd
+
+ Exception.__init__(self, message)
+ self.script_args = script_args # 'args' is already used by Exception
+ self.exit_code = exit_code
+ self.output = output
+ self.cwd = cwd
+
+ def message_with_output(self, output_limit=500):
+ if self.output:
+ if output_limit and len(self.output) > output_limit:
+ return u"%s\nLast %s characters of output:\n%s" % \
+ (self, output_limit, self.output[-output_limit:])
+ return u"%s\n%s" % (self, self.output)
+ return unicode(self)
+
+ def command_name(self):
+ command_path = self.script_args
+ if type(command_path) is list:
+ command_path = command_path[0]
+ return os.path.basename(command_path)
+
+
+def run_command(*args, **kwargs):
+ # FIXME: This should not be a global static.
+ # New code should use Executive.run_command directly instead
+ return Executive().run_command(*args, **kwargs)
+
+
+class Executive(object):
+
+ def _should_close_fds(self):
+ # We need to pass close_fds=True to work around Python bug #2320
+ # (otherwise we can hang when we kill DumpRenderTree when we are running
+ # multiple threads). See http://bugs.python.org/issue2320 .
+ # Note that close_fds isn't supported on Windows, but this bug only
+ # shows up on Mac and Linux.
+ return sys.platform not in ('win32', 'cygwin')
+
+ def _run_command_with_teed_output(self, args, teed_output):
+ args = map(unicode, args) # Popen will throw an exception if args are non-strings (like int())
+ args = map(self._encode_argument_if_needed, args)
+
+ child_process = subprocess.Popen(args,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ close_fds=self._should_close_fds())
+
+ # Use our own custom wait loop because Popen ignores a tee'd
+ # stderr/stdout.
+ # FIXME: This could be improved not to flatten output to stdout.
+ while True:
+ output_line = child_process.stdout.readline()
+ if output_line == "" and child_process.poll() != None:
+ # poll() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ return child_process.poll()
+ # We assume that the child process wrote to us in utf-8,
+ # so no re-encoding is necessary before writing here.
+ teed_output.write(output_line)
+
+ # FIXME: Remove this deprecated method and move callers to run_command.
+ # FIXME: This method is a hack to allow running command which both
+ # capture their output and print out to stdin. Useful for things
+ # like "build-webkit" where we want to display to the user that we're building
+ # but still have the output to stuff into a log file.
+ def run_and_throw_if_fail(self, args, quiet=False, decode_output=True):
+ # Cache the child's output locally so it can be used for error reports.
+ child_out_file = StringIO.StringIO()
+ tee_stdout = sys.stdout
+ if quiet:
+ dev_null = open(os.devnull, "w") # FIXME: Does this need an encoding?
+ tee_stdout = dev_null
+ child_stdout = tee(child_out_file, tee_stdout)
+ exit_code = self._run_command_with_teed_output(args, child_stdout)
+ if quiet:
+ dev_null.close()
+
+ child_output = child_out_file.getvalue()
+ child_out_file.close()
+
+ if decode_output:
+ child_output = child_output.decode(self._child_process_encoding())
+
+ if exit_code:
+ raise ScriptError(script_args=args,
+ exit_code=exit_code,
+ output=child_output)
+ return child_output
+
+ def cpu_count(self):
+ if multiprocessing:
+ return multiprocessing.cpu_count()
+ # Darn. We don't have the multiprocessing package.
+ system_name = platform.system()
+ if system_name == "Darwin":
+ return int(self.run_command(["sysctl", "-n", "hw.ncpu"]))
+ elif system_name == "Windows":
+ return int(os.environ.get('NUMBER_OF_PROCESSORS', 1))
+ elif system_name == "Linux":
+ num_cores = os.sysconf("SC_NPROCESSORS_ONLN")
+ if isinstance(num_cores, int) and num_cores > 0:
+ return num_cores
+ # This quantity is a lie but probably a reasonable guess for modern
+ # machines.
+ return 2
+
+ def kill_process(self, pid):
+ """Attempts to kill the given pid.
+ Will fail silently if pid does not exist or insufficient permisssions."""
+ if sys.platform == "win32":
+ # We only use taskkill.exe on windows (not cygwin) because subprocess.pid
+ # is a CYGWIN pid and taskkill.exe expects a windows pid.
+ # Thankfully os.kill on CYGWIN handles either pid type.
+ command = ["taskkill.exe", "/f", "/pid", pid]
+ # taskkill will exit 128 if the process is not found. We should log.
+ self.run_command(command, error_handler=self.ignore_error)
+ return
+
+ # According to http://docs.python.org/library/os.html
+ # os.kill isn't available on Windows. python 2.5.5 os.kill appears
+ # to work in cygwin, however it occasionally raises EAGAIN.
+ retries_left = 10 if sys.platform == "cygwin" else 1
+ while retries_left > 0:
+ try:
+ retries_left -= 1
+ os.kill(pid, signal.SIGKILL)
+ except OSError, e:
+ if e.errno == errno.EAGAIN:
+ if retries_left <= 0:
+ _log.warn("Failed to kill pid %s. Too many EAGAIN errors." % pid)
+ continue
+ if e.errno == errno.ESRCH: # The process does not exist.
+ _log.warn("Called kill_process with a non-existant pid %s" % pid)
+ return
+ raise
+
+ def _win32_check_running_pid(self, pid):
+
+ class PROCESSENTRY32(ctypes.Structure):
+ _fields_ = [("dwSize", ctypes.c_ulong),
+ ("cntUsage", ctypes.c_ulong),
+ ("th32ProcessID", ctypes.c_ulong),
+ ("th32DefaultHeapID", ctypes.c_ulong),
+ ("th32ModuleID", ctypes.c_ulong),
+ ("cntThreads", ctypes.c_ulong),
+ ("th32ParentProcessID", ctypes.c_ulong),
+ ("pcPriClassBase", ctypes.c_ulong),
+ ("dwFlags", ctypes.c_ulong),
+ ("szExeFile", ctypes.c_char * 260)]
+
+ CreateToolhelp32Snapshot = ctypes.windll.kernel32.CreateToolhelp32Snapshot
+ Process32First = ctypes.windll.kernel32.Process32First
+ Process32Next = ctypes.windll.kernel32.Process32Next
+ CloseHandle = ctypes.windll.kernel32.CloseHandle
+ TH32CS_SNAPPROCESS = 0x00000002 # win32 magic number
+ hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)
+ pe32 = PROCESSENTRY32()
+ pe32.dwSize = ctypes.sizeof(PROCESSENTRY32)
+ result = False
+ if not Process32First(hProcessSnap, ctypes.byref(pe32)):
+ _log.debug("Failed getting first process.")
+ CloseHandle(hProcessSnap)
+ return result
+ while True:
+ if pe32.th32ProcessID == pid:
+ result = True
+ break
+ if not Process32Next(hProcessSnap, ctypes.byref(pe32)):
+ break
+ CloseHandle(hProcessSnap)
+ return result
+
+ def check_running_pid(self, pid):
+ """Return True if pid is alive, otherwise return False."""
+ if sys.platform in ('darwin', 'linux2', 'cygwin'):
+ try:
+ os.kill(pid, 0)
+ return True
+ except OSError:
+ return False
+ elif sys.platform == 'win32':
+ return self._win32_check_running_pid(pid)
+
+ assert(False)
+
+ def _windows_image_name(self, process_name):
+ name, extension = os.path.splitext(process_name)
+ if not extension:
+ # taskkill expects processes to end in .exe
+ # If necessary we could add a flag to disable appending .exe.
+ process_name = "%s.exe" % name
+ return process_name
+
+ def kill_all(self, process_name):
+ """Attempts to kill processes matching process_name.
+ Will fail silently if no process are found."""
+ if sys.platform in ("win32", "cygwin"):
+ image_name = self._windows_image_name(process_name)
+ command = ["taskkill.exe", "/f", "/im", image_name]
+ # taskkill will exit 128 if the process is not found. We should log.
+ self.run_command(command, error_handler=self.ignore_error)
+ return
+
+ # FIXME: This is inconsistent that kill_all uses TERM and kill_process
+ # uses KILL. Windows is always using /f (which seems like -KILL).
+ # We should pick one mode, or add support for switching between them.
+ # Note: Mac OS X 10.6 requires -SIGNALNAME before -u USER
+ command = ["killall", "-TERM", "-u", os.getenv("USER"), process_name]
+ # killall returns 1 if no process can be found and 2 on command error.
+ # FIXME: We should pass a custom error_handler to allow only exit_code 1.
+ # We should log in exit_code == 1
+ self.run_command(command, error_handler=self.ignore_error)
+
+ # Error handlers do not need to be static methods once all callers are
+ # updated to use an Executive object.
+
+ @staticmethod
+ def default_error_handler(error):
+ raise error
+
+ @staticmethod
+ def ignore_error(error):
+ pass
+
+ def _compute_stdin(self, input):
+ """Returns (stdin, string_to_communicate)"""
+ # FIXME: We should be returning /dev/null for stdin
+ # or closing stdin after process creation to prevent
+ # child processes from getting input from the user.
+ if not input:
+ return (None, None)
+ if hasattr(input, "read"): # Check if the input is a file.
+ return (input, None) # Assume the file is in the right encoding.
+
+ # Popen in Python 2.5 and before does not automatically encode unicode objects.
+ # http://bugs.python.org/issue5290
+ # See https://bugs.webkit.org/show_bug.cgi?id=37528
+ # for an example of a regresion caused by passing a unicode string directly.
+ # FIXME: We may need to encode differently on different platforms.
+ if isinstance(input, unicode):
+ input = input.encode(self._child_process_encoding())
+ return (subprocess.PIPE, input)
+
+ def _command_for_printing(self, args):
+ """Returns a print-ready string representing command args.
+ The string should be copy/paste ready for execution in a shell."""
+ escaped_args = []
+ for arg in args:
+ if isinstance(arg, unicode):
+ # Escape any non-ascii characters for easy copy/paste
+ arg = arg.encode("unicode_escape")
+ # FIXME: Do we need to fix quotes here?
+ escaped_args.append(arg)
+ return " ".join(escaped_args)
+
+ # FIXME: run_and_throw_if_fail should be merged into this method.
+ def run_command(self,
+ args,
+ cwd=None,
+ input=None,
+ error_handler=None,
+ return_exit_code=False,
+ return_stderr=True,
+ decode_output=True):
+ """Popen wrapper for convenience and to work around python bugs."""
+ assert(isinstance(args, list) or isinstance(args, tuple))
+ start_time = time.time()
+ args = map(unicode, args) # Popen will throw an exception if args are non-strings (like int())
+ args = map(self._encode_argument_if_needed, args)
+
+ stdin, string_to_communicate = self._compute_stdin(input)
+ stderr = subprocess.STDOUT if return_stderr else None
+
+ process = subprocess.Popen(args,
+ stdin=stdin,
+ stdout=subprocess.PIPE,
+ stderr=stderr,
+ cwd=cwd,
+ close_fds=self._should_close_fds())
+ output = process.communicate(string_to_communicate)[0]
+
+ # run_command automatically decodes to unicode() unless explicitly told not to.
+ if decode_output:
+ output = output.decode(self._child_process_encoding())
+
+ # wait() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ exit_code = process.wait()
+
+ _log.debug('"%s" took %.2fs' % (self._command_for_printing(args), time.time() - start_time))
+
+ if return_exit_code:
+ return exit_code
+
+ if exit_code:
+ script_error = ScriptError(script_args=args,
+ exit_code=exit_code,
+ output=output,
+ cwd=cwd)
+ (error_handler or self.default_error_handler)(script_error)
+ return output
+
+ def _child_process_encoding(self):
+ # Win32 Python 2.x uses CreateProcessA rather than CreateProcessW
+ # to launch subprocesses, so we have to encode arguments using the
+ # current code page.
+ if sys.platform == 'win32' and versioning.compare_version(sys, '3.0')[0] < 0:
+ return 'mbcs'
+ # All other platforms use UTF-8.
+ # FIXME: Using UTF-8 on Cygwin will confuse Windows-native commands
+ # which will expect arguments to be encoded using the current code
+ # page.
+ return 'utf-8'
+
+ def _should_encode_child_process_arguments(self):
+ # Cygwin's Python's os.execv doesn't support unicode command
+ # arguments, and neither does Cygwin's execv itself.
+ if sys.platform == 'cygwin':
+ return True
+
+ # Win32 Python 2.x uses CreateProcessA rather than CreateProcessW
+ # to launch subprocesses, so we have to encode arguments using the
+ # current code page.
+ if sys.platform == 'win32' and versioning.compare_version(sys, '3.0')[0] < 0:
+ return True
+
+ return False
+
+ def _encode_argument_if_needed(self, argument):
+ if not self._should_encode_child_process_arguments():
+ return argument
+ return argument.encode(self._child_process_encoding())
diff --git a/Tools/Scripts/webkitpy/common/system/executive_mock.py b/Tools/Scripts/webkitpy/common/system/executive_mock.py
new file mode 100644
index 0000000..c1cf999
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/executive_mock.py
@@ -0,0 +1,59 @@
+# 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.
+
+# FIXME: Implement the rest of the interface as needed for testing :).
+
+# FIXME: Unify with tool/mocktool.MockExecutive.
+
+
+class MockExecutive2(object):
+ def __init__(self, output='', exit_code=0, exception=None,
+ run_command_fn=None):
+ self._output = output
+ self._exit_code = exit_code
+ self._exception = exception
+ self._run_command_fn = run_command_fn
+
+ def cpu_count(self):
+ return 2
+
+ def kill_all(self, process_name):
+ pass
+
+ def kill_process(self, pid):
+ pass
+
+ def run_command(self, arg_list, return_exit_code=False,
+ decode_output=False):
+ if self._exception:
+ raise self._exception
+ if return_exit_code:
+ return self._exit_code
+ if self._run_command_fn:
+ return self._run_command_fn(arg_list)
+ return self._output
diff --git a/Tools/Scripts/webkitpy/common/system/executive_unittest.py b/Tools/Scripts/webkitpy/common/system/executive_unittest.py
new file mode 100644
index 0000000..b8fd82e
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/executive_unittest.py
@@ -0,0 +1,151 @@
+# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2009 Daniel Bates (dbates@intudata.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:
+#
+# * 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 os
+import signal
+import subprocess
+import sys
+import unittest
+
+from webkitpy.common.system.executive import Executive, run_command, ScriptError
+from webkitpy.test import cat, echo
+
+
+def never_ending_command():
+ """Arguments for a command that will never end (useful for testing process
+ killing). It should be a process that is unlikely to already be running
+ because all instances will be killed."""
+ if sys.platform == 'win32':
+ return ['wmic']
+ return ['yes']
+
+
+class ExecutiveTest(unittest.TestCase):
+
+ def test_run_command_with_bad_command(self):
+ def run_bad_command():
+ run_command(["foo_bar_command_blah"], error_handler=Executive.ignore_error, return_exit_code=True)
+ self.failUnlessRaises(OSError, run_bad_command)
+
+ def test_run_command_args_type(self):
+ executive = Executive()
+ self.assertRaises(AssertionError, executive.run_command, "echo")
+ self.assertRaises(AssertionError, executive.run_command, u"echo")
+ executive.run_command(echo.command_arguments('foo'))
+ executive.run_command(tuple(echo.command_arguments('foo')))
+
+ def test_run_command_with_unicode(self):
+ """Validate that it is safe to pass unicode() objects
+ to Executive.run* methods, and they will return unicode()
+ objects by default unless decode_output=False"""
+ unicode_tor_input = u"WebKit \u2661 Tor Arne Vestb\u00F8!"
+ if sys.platform == 'win32':
+ encoding = 'mbcs'
+ else:
+ encoding = 'utf-8'
+ encoded_tor = unicode_tor_input.encode(encoding)
+ # On Windows, we expect the unicode->mbcs->unicode roundtrip to be
+ # lossy. On other platforms, we expect a lossless roundtrip.
+ if sys.platform == 'win32':
+ unicode_tor_output = encoded_tor.decode(encoding)
+ else:
+ unicode_tor_output = unicode_tor_input
+
+ executive = Executive()
+
+ output = executive.run_command(cat.command_arguments(), input=unicode_tor_input)
+ self.assertEquals(output, unicode_tor_output)
+
+ output = executive.run_command(echo.command_arguments("-n", unicode_tor_input))
+ self.assertEquals(output, unicode_tor_output)
+
+ output = executive.run_command(echo.command_arguments("-n", unicode_tor_input), decode_output=False)
+ self.assertEquals(output, encoded_tor)
+
+ # Make sure that str() input also works.
+ output = executive.run_command(cat.command_arguments(), input=encoded_tor, decode_output=False)
+ self.assertEquals(output, encoded_tor)
+
+ # FIXME: We should only have one run* method to test
+ output = executive.run_and_throw_if_fail(echo.command_arguments("-n", unicode_tor_input), quiet=True)
+ self.assertEquals(output, unicode_tor_output)
+
+ output = executive.run_and_throw_if_fail(echo.command_arguments("-n", unicode_tor_input), quiet=True, decode_output=False)
+ self.assertEquals(output, encoded_tor)
+
+ def test_kill_process(self):
+ executive = Executive()
+ process = subprocess.Popen(never_ending_command(), stdout=subprocess.PIPE)
+ self.assertEqual(process.poll(), None) # Process is running
+ executive.kill_process(process.pid)
+ # Note: Can't use a ternary since signal.SIGKILL is undefined for sys.platform == "win32"
+ if sys.platform == "win32":
+ expected_exit_code = 1
+ else:
+ expected_exit_code = -signal.SIGKILL
+ self.assertEqual(process.wait(), expected_exit_code)
+ # Killing again should fail silently.
+ executive.kill_process(process.pid)
+
+ def _assert_windows_image_name(self, name, expected_windows_name):
+ executive = Executive()
+ windows_name = executive._windows_image_name(name)
+ self.assertEqual(windows_name, expected_windows_name)
+
+ def test_windows_image_name(self):
+ self._assert_windows_image_name("foo", "foo.exe")
+ self._assert_windows_image_name("foo.exe", "foo.exe")
+ self._assert_windows_image_name("foo.com", "foo.com")
+ # If the name looks like an extension, even if it isn't
+ # supposed to, we have no choice but to return the original name.
+ self._assert_windows_image_name("foo.baz", "foo.baz")
+ self._assert_windows_image_name("foo.baz.exe", "foo.baz.exe")
+
+ def test_kill_all(self):
+ executive = Executive()
+ # We use "yes" because it loops forever.
+ process = subprocess.Popen(never_ending_command(), stdout=subprocess.PIPE)
+ self.assertEqual(process.poll(), None) # Process is running
+ executive.kill_all(never_ending_command()[0])
+ # Note: Can't use a ternary since signal.SIGTERM is undefined for sys.platform == "win32"
+ if sys.platform == "cygwin":
+ expected_exit_code = 0 # os.kill results in exit(0) for this process.
+ elif sys.platform == "win32":
+ expected_exit_code = 1
+ else:
+ expected_exit_code = -signal.SIGTERM
+ self.assertEqual(process.wait(), expected_exit_code)
+ # Killing again should fail silently.
+ executive.kill_all(never_ending_command()[0])
+
+ def test_check_running_pid(self):
+ executive = Executive()
+ self.assertTrue(executive.check_running_pid(os.getpid()))
+ # Maximum pid number on Linux is 32768 by default
+ self.assertFalse(executive.check_running_pid(100000))
diff --git a/Tools/Scripts/webkitpy/common/system/file_lock.py b/Tools/Scripts/webkitpy/common/system/file_lock.py
new file mode 100644
index 0000000..7296958
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/file_lock.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
+#
+# 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 UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED 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 class helps to lock files exclusively across processes."""
+
+import logging
+import os
+import sys
+import time
+
+
+_log = logging.getLogger("webkitpy.common.system.file_lock")
+
+
+class FileLock(object):
+
+ def __init__(self, lock_file_path, max_wait_time_sec=20):
+ self._lock_file_path = lock_file_path
+ self._lock_file_descriptor = None
+ self._max_wait_time_sec = max_wait_time_sec
+
+ def _create_lock(self):
+ if sys.platform in ('darwin', 'linux2', 'cygwin'):
+ import fcntl
+ fcntl.flock(self._lock_file_descriptor, fcntl.LOCK_EX | fcntl.LOCK_NB)
+ elif sys.platform == 'win32':
+ import msvcrt
+ msvcrt.locking(self._lock_file_descriptor, msvcrt.LK_NBLCK, 32)
+
+ def _remove_lock(self):
+ if sys.platform in ('darwin', 'linux2', 'cygwin'):
+ import fcntl
+ fcntl.flock(self._lock_file_descriptor, fcntl.LOCK_UN)
+ elif sys.platform == 'win32':
+ import msvcrt
+ msvcrt.locking(self._lock_file_descriptor, msvcrt.LK_UNLCK, 32)
+
+ def acquire_lock(self):
+ self._lock_file_descriptor = os.open(self._lock_file_path, os.O_TRUNC | os.O_CREAT)
+ start_time = time.time()
+ while True:
+ try:
+ self._create_lock()
+ return True
+ except IOError:
+ if time.time() - start_time > self._max_wait_time_sec:
+ _log.debug("File locking failed: %s" % str(sys.exc_info()))
+ os.close(self._lock_file_descriptor)
+ self._lock_file_descriptor = None
+ return False
+
+ def release_lock(self):
+ try:
+ if self._lock_file_descriptor:
+ self._remove_lock()
+ os.close(self._lock_file_descriptor)
+ self._lock_file_descriptor = None
+ os.unlink(self._lock_file_path)
+ except (IOError, OSError):
+ _log.debug("Warning in release lock: %s" % str(sys.exc_info()))
diff --git a/Tools/Scripts/webkitpy/common/system/file_lock_unittest.py b/Tools/Scripts/webkitpy/common/system/file_lock_unittest.py
new file mode 100644
index 0000000..c5c1db3
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/file_lock_unittest.py
@@ -0,0 +1,61 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
+#
+# 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 UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED 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 os
+import tempfile
+import unittest
+
+from webkitpy.common.system.file_lock import FileLock
+
+
+class FileLockTest(unittest.TestCase):
+
+ def setUp(self):
+ self._lock_name = "TestWebKit" + str(os.getpid()) + ".lock"
+ self._lock_path = os.path.join(tempfile.gettempdir(), self._lock_name)
+ self._file_lock1 = FileLock(self._lock_path, 1)
+ self._file_lock2 = FileLock(self._lock_path, 1)
+
+ def tearDown(self):
+ self._file_lock1.release_lock()
+ self._file_lock2.release_lock()
+
+ def test_lock_lifecycle(self):
+ # Create the lock.
+ self._file_lock1.acquire_lock()
+ self.assertTrue(os.path.exists(self._lock_path))
+
+ # Try to lock again.
+ self.assertFalse(self._file_lock2.acquire_lock())
+
+ # Release the lock.
+ self._file_lock1.release_lock()
+ self.assertFalse(os.path.exists(self._lock_path))
+
+ def test_stuck_lock(self):
+ open(self._lock_path, 'w').close()
+ self._file_lock1.acquire_lock()
+ self._file_lock1.release_lock()
diff --git a/Tools/Scripts/webkitpy/common/system/filesystem.py b/Tools/Scripts/webkitpy/common/system/filesystem.py
new file mode 100644
index 0000000..f0b5e44
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/filesystem.py
@@ -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.
+
+"""Wrapper object for the file system / source tree."""
+
+from __future__ import with_statement
+
+import codecs
+import errno
+import exceptions
+import os
+import shutil
+import tempfile
+import time
+
+class FileSystem(object):
+ """FileSystem interface for webkitpy.
+
+ Unless otherwise noted, all paths are allowed to be either absolute
+ or relative."""
+
+ def exists(self, path):
+ """Return whether the path exists in the filesystem."""
+ return os.path.exists(path)
+
+ def isfile(self, path):
+ """Return whether the path refers to a file."""
+ return os.path.isfile(path)
+
+ def isdir(self, path):
+ """Return whether the path refers to a directory."""
+ return os.path.isdir(path)
+
+ def join(self, *comps):
+ """Return the path formed by joining the components."""
+ return os.path.join(*comps)
+
+ def listdir(self, path):
+ """Return the contents of the directory pointed to by path."""
+ return os.listdir(path)
+
+ def mkdtemp(self, **kwargs):
+ """Create and return a uniquely named directory.
+
+ This is like tempfile.mkdtemp, but if used in a with statement
+ the directory will self-delete at the end of the block (if the
+ directory is empty; non-empty directories raise errors). The
+ directory can be safely deleted inside the block as well, if so
+ desired."""
+ class TemporaryDirectory(object):
+ def __init__(self, **kwargs):
+ self._kwargs = kwargs
+ self._directory_path = None
+
+ def __enter__(self):
+ self._directory_path = tempfile.mkdtemp(**self._kwargs)
+ return self._directory_path
+
+ def __exit__(self, type, value, traceback):
+ # Only self-delete if necessary.
+
+ # FIXME: Should we delete non-empty directories?
+ if os.path.exists(self._directory_path):
+ os.rmdir(self._directory_path)
+
+ return TemporaryDirectory(**kwargs)
+
+ def maybe_make_directory(self, *path):
+ """Create the specified directory if it doesn't already exist."""
+ try:
+ os.makedirs(os.path.join(*path))
+ except OSError, e:
+ if e.errno != errno.EEXIST:
+ raise
+
+ class _WindowsError(exceptions.OSError):
+ """Fake exception for Linux and Mac."""
+ pass
+
+ def remove(self, path, osremove=os.remove):
+ """On Windows, if a process was recently killed and it held on to a
+ file, the OS will hold on to the file for a short while. This makes
+ attempts to delete the file fail. To work around that, this method
+ will retry for a few seconds until Windows is done with the file."""
+ try:
+ exceptions.WindowsError
+ except AttributeError:
+ exceptions.WindowsError = FileSystem._WindowsError
+
+ retry_timeout_sec = 3.0
+ sleep_interval = 0.1
+ while True:
+ try:
+ osremove(path)
+ return True
+ except exceptions.WindowsError, e:
+ time.sleep(sleep_interval)
+ retry_timeout_sec -= sleep_interval
+ if retry_timeout_sec < 0:
+ raise e
+
+ def read_binary_file(self, path):
+ """Return the contents of the file at the given path as a byte string."""
+ with file(path, 'rb') as f:
+ return f.read()
+
+ def read_text_file(self, path):
+ """Return the contents of the file at the given path as a Unicode string.
+
+ The file is read assuming it is a UTF-8 encoded file with no BOM."""
+ with codecs.open(path, 'r', 'utf8') as f:
+ return f.read()
+
+ def write_binary_file(self, path, contents):
+ """Write the contents to the file at the given location."""
+ with file(path, 'wb') as f:
+ f.write(contents)
+
+ def write_text_file(self, path, contents):
+ """Write the contents to the file at the given location.
+
+ The file is written encoded as UTF-8 with no BOM."""
+ with codecs.open(path, 'w', 'utf8') as f:
+ f.write(contents)
+
+ def copyfile(self, source, destination):
+ """Copies the contents of the file at the given path to the destination
+ path."""
+ shutil.copyfile(source, destination)
diff --git a/Tools/Scripts/webkitpy/common/system/filesystem_mock.py b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py
new file mode 100644
index 0000000..ea0f3f9
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/filesystem_mock.py
@@ -0,0 +1,109 @@
+# 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 errno
+import os
+import path
+
+
+class MockFileSystem(object):
+ def __init__(self, files=None):
+ """Initializes a "mock" filesystem that can be used to completely
+ stub out a filesystem.
+
+ Args:
+ files: a dict of filenames -> file contents. A file contents
+ value of None is used to indicate that the file should
+ not exist.
+ """
+ self.files = files or {}
+
+ def exists(self, path):
+ return self.isfile(path) or self.isdir(path)
+
+ def isfile(self, path):
+ return path in self.files and self.files[path] is not None
+
+ def isdir(self, path):
+ if path in self.files:
+ return False
+ if not path.endswith('/'):
+ path += '/'
+ return any(f.startswith(path) for f in self.files)
+
+ def join(self, *comps):
+ return '/'.join(comps)
+
+ def listdir(self, path):
+ if not self.isdir(path):
+ raise OSError("%s is not a directory" % path)
+
+ if not path.endswith('/'):
+ path += '/'
+
+ dirs = []
+ files = []
+ for f in self.files:
+ if self.exists(f) and f.startswith(path):
+ remaining = f[len(path):]
+ if '/' in remaining:
+ dir = remaining[:remaining.index('/')]
+ if not dir in dirs:
+ dirs.append(dir)
+ else:
+ files.append(remaining)
+ return dirs + files
+
+ def maybe_make_directory(self, *path):
+ # FIXME: Implement such that subsequent calls to isdir() work?
+ pass
+
+ def read_text_file(self, path):
+ return self.read_binary_file(path)
+
+ def read_binary_file(self, path):
+ if path in self.files:
+ if self.files[path] is None:
+ raise IOError(errno.ENOENT, path, os.strerror(errno.ENOENT))
+ return self.files[path]
+
+ def write_text_file(self, path, contents):
+ return self.write_binary_file(path, contents)
+
+ def write_binary_file(self, path, contents):
+ self.files[path] = contents
+
+ def copyfile(self, source, destination):
+ if not self.exists(source):
+ raise IOError(errno.ENOENT, source, os.strerror(errno.ENOENT))
+ if self.isdir(source):
+ raise IOError(errno.EISDIR, source, os.strerror(errno.ISDIR))
+ if self.isdir(destination):
+ raise IOError(errno.EISDIR, destination, os.strerror(errno.ISDIR))
+
+ self.files[destination] = self.files[source]
diff --git a/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py b/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py
new file mode 100644
index 0000000..267ca13
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/filesystem_unittest.py
@@ -0,0 +1,172 @@
+# vim: set fileencoding=utf-8 :
+# 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.
+
+# NOTE: The fileencoding comment on the first line of the file is
+# important; without it, Python will choke while trying to parse the file,
+# since it includes non-ASCII characters.
+
+from __future__ import with_statement
+
+import os
+import stat
+import sys
+import tempfile
+import unittest
+
+from filesystem import FileSystem
+
+
+class FileSystemTest(unittest.TestCase):
+ def setUp(self):
+ self._this_dir = os.path.dirname(os.path.abspath(__file__))
+ self._missing_file = os.path.join(self._this_dir, 'missing_file.py')
+ self._this_file = os.path.join(self._this_dir, 'filesystem_unittest.py')
+
+ def test_exists__true(self):
+ fs = FileSystem()
+ self.assertTrue(fs.exists(self._this_file))
+
+ def test_exists__false(self):
+ fs = FileSystem()
+ self.assertFalse(fs.exists(self._missing_file))
+
+ def test_isdir__true(self):
+ fs = FileSystem()
+ self.assertTrue(fs.isdir(self._this_dir))
+
+ def test_isdir__false(self):
+ fs = FileSystem()
+ self.assertFalse(fs.isdir(self._this_file))
+
+ def test_join(self):
+ fs = FileSystem()
+ self.assertEqual(fs.join('foo', 'bar'),
+ os.path.join('foo', 'bar'))
+
+ def test_listdir(self):
+ fs = FileSystem()
+ with fs.mkdtemp(prefix='filesystem_unittest_') as d:
+ self.assertEqual(fs.listdir(d), [])
+ new_file = os.path.join(d, 'foo')
+ fs.write_text_file(new_file, u'foo')
+ self.assertEqual(fs.listdir(d), ['foo'])
+ os.remove(new_file)
+
+ def test_maybe_make_directory__success(self):
+ fs = FileSystem()
+
+ with fs.mkdtemp(prefix='filesystem_unittest_') as base_path:
+ sub_path = os.path.join(base_path, "newdir")
+ self.assertFalse(os.path.exists(sub_path))
+ self.assertFalse(fs.isdir(sub_path))
+
+ fs.maybe_make_directory(sub_path)
+ self.assertTrue(os.path.exists(sub_path))
+ self.assertTrue(fs.isdir(sub_path))
+
+ # Make sure we can re-create it.
+ fs.maybe_make_directory(sub_path)
+ self.assertTrue(os.path.exists(sub_path))
+ self.assertTrue(fs.isdir(sub_path))
+
+ # Clean up.
+ os.rmdir(sub_path)
+
+ self.assertFalse(os.path.exists(base_path))
+ self.assertFalse(fs.isdir(base_path))
+
+ def test_maybe_make_directory__failure(self):
+ # FIXME: os.chmod() doesn't work on Windows to set directories
+ # as readonly, so we skip this test for now.
+ if sys.platform in ('win32', 'cygwin'):
+ return
+
+ fs = FileSystem()
+ with fs.mkdtemp(prefix='filesystem_unittest_') as d:
+ # Remove write permissions on the parent directory.
+ os.chmod(d, stat.S_IRUSR)
+
+ # Now try to create a sub directory - should fail.
+ sub_dir = fs.join(d, 'subdir')
+ self.assertRaises(OSError, fs.maybe_make_directory, sub_dir)
+
+ # Clean up in case the test failed and we did create the
+ # directory.
+ if os.path.exists(sub_dir):
+ os.rmdir(sub_dir)
+
+ def test_read_and_write_file(self):
+ fs = FileSystem()
+ text_path = None
+ binary_path = None
+
+ unicode_text_string = u'ŪnÄ­cÅde̽'
+ hex_equivalent = '\xC5\xAA\x6E\xC4\xAD\x63\xC5\x8D\x64\x65\xCC\xBD'
+ try:
+ text_path = tempfile.mktemp(prefix='tree_unittest_')
+ binary_path = tempfile.mktemp(prefix='tree_unittest_')
+ fs.write_text_file(text_path, unicode_text_string)
+ contents = fs.read_binary_file(text_path)
+ self.assertEqual(contents, hex_equivalent)
+
+ fs.write_text_file(binary_path, hex_equivalent)
+ text_contents = fs.read_text_file(binary_path)
+ self.assertEqual(text_contents, unicode_text_string)
+ except:
+ if text_path:
+ os.remove(text_path)
+ if binary_path:
+ os.remove(binary_path)
+
+ def test_read_binary_file__missing(self):
+ fs = FileSystem()
+ self.assertRaises(IOError, fs.read_binary_file, self._missing_file)
+
+ def test_read_text_file__missing(self):
+ fs = FileSystem()
+ self.assertRaises(IOError, fs.read_text_file, self._missing_file)
+
+ def test_remove_file_with_retry(self):
+ FileSystemTest._remove_failures = 2
+
+ def remove_with_exception(filename):
+ FileSystemTest._remove_failures -= 1
+ if FileSystemTest._remove_failures >= 0:
+ try:
+ raise WindowsError
+ except NameError:
+ raise FileSystem._WindowsError
+
+ fs = FileSystem()
+ self.assertTrue(fs.remove('filename', remove_with_exception))
+ self.assertEquals(-1, FileSystemTest._remove_failures)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/system/fileutils.py b/Tools/Scripts/webkitpy/common/system/fileutils.py
new file mode 100644
index 0000000..55821f8
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/fileutils.py
@@ -0,0 +1,33 @@
+# 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.
+
+import sys
+
+
+def make_stdout_binary():
+ """Puts sys.stdout into binary mode (on platforms that have a distinction
+ between text and binary mode)."""
+ if sys.platform != 'win32' or not hasattr(sys.stdout, 'fileno'):
+ return
+ import msvcrt
+ import os
+ msvcrt.setmode(sys.stdout.fileno(), os.O_BINARY)
diff --git a/Tools/Scripts/webkitpy/common/system/logtesting.py b/Tools/Scripts/webkitpy/common/system/logtesting.py
new file mode 100644
index 0000000..e361cb5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/logtesting.py
@@ -0,0 +1,258 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Supports the unit-testing of logging code.
+
+Provides support for unit-testing messages logged using the built-in
+logging module.
+
+Inherit from the LoggingTestCase class for basic testing needs. For
+more advanced needs (e.g. unit-testing methods that configure logging),
+see the TestLogStream class, and perhaps also the LogTesting class.
+
+"""
+
+import logging
+import unittest
+
+
+class TestLogStream(object):
+
+ """Represents a file-like object for unit-testing logging.
+
+ This is meant for passing to the logging.StreamHandler constructor.
+ Log messages captured by instances of this object can be tested
+ using self.assertMessages() below.
+
+ """
+
+ def __init__(self, test_case):
+ """Create an instance.
+
+ Args:
+ test_case: A unittest.TestCase instance.
+
+ """
+ self._test_case = test_case
+ self.messages = []
+ """A list of log messages written to the stream."""
+
+ # Python documentation says that any object passed to the StreamHandler
+ # constructor should support write() and flush():
+ #
+ # http://docs.python.org/library/logging.html#module-logging.handlers
+ def write(self, message):
+ self.messages.append(message)
+
+ def flush(self):
+ pass
+
+ def assertMessages(self, messages):
+ """Assert that the given messages match the logged messages.
+
+ messages: A list of log message strings.
+
+ """
+ self._test_case.assertEquals(messages, self.messages)
+
+
+class LogTesting(object):
+
+ """Supports end-to-end unit-testing of log messages.
+
+ Sample usage:
+
+ class SampleTest(unittest.TestCase):
+
+ def setUp(self):
+ self._log = LogTesting.setUp(self) # Turn logging on.
+
+ def tearDown(self):
+ self._log.tearDown() # Turn off and reset logging.
+
+ def test_logging_in_some_method(self):
+ call_some_method() # Contains calls to _log.info(), etc.
+
+ # Check the resulting log messages.
+ self._log.assertMessages(["INFO: expected message #1",
+ "WARNING: expected message #2"])
+
+ """
+
+ def __init__(self, test_stream, handler):
+ """Create an instance.
+
+ This method should never be called directly. Instances should
+ instead be created using the static setUp() method.
+
+ Args:
+ test_stream: A TestLogStream instance.
+ handler: The handler added to the logger.
+
+ """
+ self._test_stream = test_stream
+ self._handler = handler
+
+ @staticmethod
+ def _getLogger():
+ """Return the logger being tested."""
+ # It is possible we might want to return something other than
+ # the root logger in some special situation. For now, the
+ # root logger seems to suffice.
+ return logging.getLogger()
+
+ @staticmethod
+ def setUp(test_case, logging_level=logging.INFO):
+ """Configure logging for unit testing.
+
+ Configures the root logger to log to a testing log stream.
+ Only messages logged at or above the given level are logged
+ to the stream. Messages logged to the stream are formatted
+ in the following way, for example--
+
+ "INFO: This is a test log message."
+
+ This method should normally be called in the setUp() method
+ of a unittest.TestCase. See the docstring of this class
+ for more details.
+
+ Returns:
+ A LogTesting instance.
+
+ Args:
+ test_case: A unittest.TestCase instance.
+ logging_level: An integer logging level that is the minimum level
+ of log messages you would like to test.
+
+ """
+ stream = TestLogStream(test_case)
+ handler = logging.StreamHandler(stream)
+ handler.setLevel(logging_level)
+ formatter = logging.Formatter("%(levelname)s: %(message)s")
+ handler.setFormatter(formatter)
+
+ # Notice that we only change the root logger by adding a handler
+ # to it. In particular, we do not reset its level using
+ # logger.setLevel(). This ensures that we have not interfered
+ # with how the code being tested may have configured the root
+ # logger.
+ logger = LogTesting._getLogger()
+ logger.addHandler(handler)
+
+ return LogTesting(stream, handler)
+
+ def tearDown(self):
+ """Assert there are no remaining log messages, and reset logging.
+
+ This method asserts that there are no more messages in the array of
+ log messages, and then restores logging to its original state.
+ This method should normally be called in the tearDown() method of a
+ unittest.TestCase. See the docstring of this class for more details.
+
+ """
+ self.assertMessages([])
+ logger = LogTesting._getLogger()
+ logger.removeHandler(self._handler)
+
+ def messages(self):
+ """Return the current list of log messages."""
+ return self._test_stream.messages
+
+ # FIXME: Add a clearMessages() method for cases where the caller
+ # deliberately doesn't want to assert every message.
+
+ # We clear the log messages after asserting since they are no longer
+ # needed after asserting. This serves two purposes: (1) it simplifies
+ # the calling code when we want to check multiple logging calls in a
+ # single test method, and (2) it lets us check in the tearDown() method
+ # that there are no remaining log messages to be asserted.
+ #
+ # The latter ensures that no extra log messages are getting logged that
+ # the caller might not be aware of or may have forgotten to check for.
+ # This gets us a bit more mileage out of our tests without writing any
+ # additional code.
+ def assertMessages(self, messages):
+ """Assert the current array of log messages, and clear its contents.
+
+ Args:
+ messages: A list of log message strings.
+
+ """
+ try:
+ self._test_stream.assertMessages(messages)
+ finally:
+ # We want to clear the array of messages even in the case of
+ # an Exception (e.g. an AssertionError). Otherwise, another
+ # AssertionError can occur in the tearDown() because the
+ # array might not have gotten emptied.
+ self._test_stream.messages = []
+
+
+# This class needs to inherit from unittest.TestCase. Otherwise, the
+# setUp() and tearDown() methods will not get fired for test case classes
+# that inherit from this class -- even if the class inherits from *both*
+# unittest.TestCase and LoggingTestCase.
+#
+# FIXME: Rename this class to LoggingTestCaseBase to be sure that
+# the unittest module does not interpret this class as a unittest
+# test case itself.
+class LoggingTestCase(unittest.TestCase):
+
+ """Supports end-to-end unit-testing of log messages.
+
+ Sample usage:
+
+ class SampleTest(LoggingTestCase):
+
+ def test_logging_in_some_method(self):
+ call_some_method() # Contains calls to _log.info(), etc.
+
+ # Check the resulting log messages.
+ self.assertLog(["INFO: expected message #1",
+ "WARNING: expected message #2"])
+
+ """
+
+ def setUp(self):
+ self._log = LogTesting.setUp(self)
+
+ def tearDown(self):
+ self._log.tearDown()
+
+ def logMessages(self):
+ """Return the current list of log messages."""
+ return self._log.messages()
+
+ # FIXME: Add a clearMessages() method for cases where the caller
+ # deliberately doesn't want to assert every message.
+
+ # See the code comments preceding LogTesting.assertMessages() for
+ # an explanation of why we clear the array of messages after
+ # asserting its contents.
+ def assertLog(self, messages):
+ """Assert the current array of log messages, and clear its contents.
+
+ Args:
+ messages: A list of log message strings.
+
+ """
+ self._log.assertMessages(messages)
diff --git a/Tools/Scripts/webkitpy/common/system/logutils.py b/Tools/Scripts/webkitpy/common/system/logutils.py
new file mode 100644
index 0000000..cd4e60f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/logutils.py
@@ -0,0 +1,207 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Supports webkitpy logging."""
+
+# FIXME: Move this file to webkitpy/python24 since logging needs to
+# be configured prior to running version-checking code.
+
+import logging
+import os
+import sys
+
+import webkitpy
+
+
+_log = logging.getLogger(__name__)
+
+# We set these directory paths lazily in get_logger() below.
+_scripts_dir = ""
+"""The normalized, absolute path to the ...Scripts directory."""
+
+_webkitpy_dir = ""
+"""The normalized, absolute path to the ...Scripts/webkitpy directory."""
+
+
+def _normalize_path(path):
+ """Return the given path normalized.
+
+ Converts a path to an absolute path, removes any trailing slashes,
+ removes any extension, and lower-cases it.
+
+ """
+ path = os.path.abspath(path)
+ path = os.path.normpath(path)
+ path = os.path.splitext(path)[0] # Remove the extension, if any.
+ path = path.lower()
+
+ return path
+
+
+# Observe that the implementation of this function does not require
+# the use of any hard-coded strings like "webkitpy", etc.
+#
+# The main benefit this function has over using--
+#
+# _log = logging.getLogger(__name__)
+#
+# is that get_logger() returns the same value even if __name__ is
+# "__main__" -- i.e. even if the module is the script being executed
+# from the command-line.
+def get_logger(path):
+ """Return a logging.logger for the given path.
+
+ Returns:
+ A logger whose name is the name of the module corresponding to
+ the given path. If the module is in webkitpy, the name is
+ the fully-qualified dotted module name beginning with webkitpy....
+ Otherwise, the name is the base name of the module (i.e. without
+ any dotted module name prefix).
+
+ Args:
+ path: The path of the module. Normally, this parameter should be
+ the __file__ variable of the module.
+
+ Sample usage:
+
+ import webkitpy.common.system.logutils as logutils
+
+ _log = logutils.get_logger(__file__)
+
+ """
+ # Since we assign to _scripts_dir and _webkitpy_dir in this function,
+ # we need to declare them global.
+ global _scripts_dir
+ global _webkitpy_dir
+
+ path = _normalize_path(path)
+
+ # Lazily evaluate _webkitpy_dir and _scripts_dir.
+ if not _scripts_dir:
+ # The normalized, absolute path to ...Scripts/webkitpy/__init__.
+ webkitpy_path = _normalize_path(webkitpy.__file__)
+
+ _webkitpy_dir = os.path.split(webkitpy_path)[0]
+ _scripts_dir = os.path.split(_webkitpy_dir)[0]
+
+ if path.startswith(_webkitpy_dir):
+ # Remove the initial Scripts directory portion, so the path
+ # starts with /webkitpy, for example "/webkitpy/init/logutils".
+ path = path[len(_scripts_dir):]
+
+ parts = []
+ while True:
+ (path, tail) = os.path.split(path)
+ if not tail:
+ break
+ parts.insert(0, tail)
+
+ logger_name = ".".join(parts) # For example, webkitpy.common.system.logutils.
+ else:
+ # The path is outside of webkitpy. Default to the basename
+ # without the extension.
+ basename = os.path.basename(path)
+ logger_name = os.path.splitext(basename)[0]
+
+ return logging.getLogger(logger_name)
+
+
+def _default_handlers(stream):
+ """Return a list of the default logging handlers to use.
+
+ Args:
+ stream: See the configure_logging() docstring.
+
+ """
+ # Create the filter.
+ def should_log(record):
+ """Return whether a logging.LogRecord should be logged."""
+ # FIXME: Enable the logging of autoinstall messages once
+ # autoinstall is adjusted. Currently, autoinstall logs
+ # INFO messages when importing already-downloaded packages,
+ # which is too verbose.
+ if record.name.startswith("webkitpy.thirdparty.autoinstall"):
+ return False
+ return True
+
+ logging_filter = logging.Filter()
+ logging_filter.filter = should_log
+
+ # Create the handler.
+ handler = logging.StreamHandler(stream)
+ formatter = logging.Formatter("%(name)s: [%(levelname)s] %(message)s")
+ handler.setFormatter(formatter)
+ handler.addFilter(logging_filter)
+
+ return [handler]
+
+
+def configure_logging(logging_level=None, logger=None, stream=None,
+ handlers=None):
+ """Configure logging for standard purposes.
+
+ Returns:
+ A list of references to the logging handlers added to the root
+ logger. This allows the caller to later remove the handlers
+ using logger.removeHandler. This is useful primarily during unit
+ testing where the caller may want to configure logging temporarily
+ and then undo the configuring.
+
+ Args:
+ logging_level: The minimum logging level to log. Defaults to
+ logging.INFO.
+ logger: A logging.logger instance to configure. This parameter
+ should be used only in unit tests. Defaults to the
+ root logger.
+ stream: A file-like object to which to log used in creating the default
+ handlers. The stream must define an "encoding" data attribute,
+ or else logging raises an error. Defaults to sys.stderr.
+ handlers: A list of logging.Handler instances to add to the logger
+ being configured. If this parameter is provided, then the
+ stream parameter is not used.
+
+ """
+ # If the stream does not define an "encoding" data attribute, the
+ # logging module can throw an error like the following:
+ #
+ # Traceback (most recent call last):
+ # File "/System/Library/Frameworks/Python.framework/Versions/2.6/...
+ # lib/python2.6/logging/__init__.py", line 761, in emit
+ # self.stream.write(fs % msg.encode(self.stream.encoding))
+ # LookupError: unknown encoding: unknown
+ if logging_level is None:
+ logging_level = logging.INFO
+ if logger is None:
+ logger = logging.getLogger()
+ if stream is None:
+ stream = sys.stderr
+ if handlers is None:
+ handlers = _default_handlers(stream)
+
+ logger.setLevel(logging_level)
+
+ for handler in handlers:
+ logger.addHandler(handler)
+
+ _log.debug("Debug logging enabled.")
+
+ return handlers
diff --git a/Tools/Scripts/webkitpy/common/system/logutils_unittest.py b/Tools/Scripts/webkitpy/common/system/logutils_unittest.py
new file mode 100644
index 0000000..b77c284
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/logutils_unittest.py
@@ -0,0 +1,142 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Unit tests for logutils.py."""
+
+import logging
+import os
+import unittest
+
+from webkitpy.common.system.logtesting import LogTesting
+from webkitpy.common.system.logtesting import TestLogStream
+import webkitpy.common.system.logutils as logutils
+
+
+class GetLoggerTest(unittest.TestCase):
+
+ """Tests get_logger()."""
+
+ def test_get_logger_in_webkitpy(self):
+ logger = logutils.get_logger(__file__)
+ self.assertEquals(logger.name, "webkitpy.common.system.logutils_unittest")
+
+ def test_get_logger_not_in_webkitpy(self):
+ # Temporarily change the working directory so that we
+ # can test get_logger() for a path outside of webkitpy.
+ working_directory = os.getcwd()
+ root_dir = "/"
+ os.chdir(root_dir)
+
+ logger = logutils.get_logger("/Tools/Scripts/test-webkitpy")
+ self.assertEquals(logger.name, "test-webkitpy")
+
+ logger = logutils.get_logger("/Tools/Scripts/test-webkitpy.py")
+ self.assertEquals(logger.name, "test-webkitpy")
+
+ os.chdir(working_directory)
+
+
+class ConfigureLoggingTestBase(unittest.TestCase):
+
+ """Base class for configure_logging() unit tests."""
+
+ def _logging_level(self):
+ raise Exception("Not implemented.")
+
+ def setUp(self):
+ log_stream = TestLogStream(self)
+
+ # Use a logger other than the root logger or one prefixed with
+ # "webkitpy." so as not to conflict with test-webkitpy logging.
+ logger = logging.getLogger("unittest")
+
+ # Configure the test logger not to pass messages along to the
+ # root logger. This prevents test messages from being
+ # propagated to loggers used by test-webkitpy logging (e.g.
+ # the root logger).
+ logger.propagate = False
+
+ logging_level = self._logging_level()
+ self._handlers = logutils.configure_logging(logging_level=logging_level,
+ logger=logger,
+ stream=log_stream)
+ self._log = logger
+ self._log_stream = log_stream
+
+ def tearDown(self):
+ """Reset logging to its original state.
+
+ This method ensures that the logging configuration set up
+ for a unit test does not affect logging in other unit tests.
+
+ """
+ logger = self._log
+ for handler in self._handlers:
+ logger.removeHandler(handler)
+
+ def _assert_log_messages(self, messages):
+ """Assert that the logged messages equal the given messages."""
+ self._log_stream.assertMessages(messages)
+
+
+class ConfigureLoggingTest(ConfigureLoggingTestBase):
+
+ """Tests configure_logging() with the default logging level."""
+
+ def _logging_level(self):
+ return None
+
+ def test_info_message(self):
+ self._log.info("test message")
+ self._assert_log_messages(["unittest: [INFO] test message\n"])
+
+ def test_below_threshold_message(self):
+ # We test the boundary case of a logging level equal to 19.
+ # In practice, we will probably only be calling log.debug(),
+ # which corresponds to a logging level of 10.
+ level = logging.INFO - 1 # Equals 19.
+ self._log.log(level, "test message")
+ self._assert_log_messages([])
+
+ def test_two_messages(self):
+ self._log.info("message1")
+ self._log.info("message2")
+ self._assert_log_messages(["unittest: [INFO] message1\n",
+ "unittest: [INFO] message2\n"])
+
+
+class ConfigureLoggingCustomLevelTest(ConfigureLoggingTestBase):
+
+ """Tests configure_logging() with a custom logging level."""
+
+ _level = 36
+
+ def _logging_level(self):
+ return self._level
+
+ def test_logged_message(self):
+ self._log.log(self._level, "test message")
+ self._assert_log_messages(["unittest: [Level 36] test message\n"])
+
+ def test_below_threshold_message(self):
+ self._log.log(self._level - 1, "test message")
+ self._assert_log_messages([])
diff --git a/Tools/Scripts/webkitpy/common/system/ospath.py b/Tools/Scripts/webkitpy/common/system/ospath.py
new file mode 100644
index 0000000..aed7a3d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/ospath.py
@@ -0,0 +1,83 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Contains a substitute for Python 2.6's os.path.relpath()."""
+
+import os
+
+
+# This function is a replacement for os.path.relpath(), which is only
+# available in Python 2.6:
+#
+# http://docs.python.org/library/os.path.html#os.path.relpath
+#
+# It should behave essentially the same as os.path.relpath(), except for
+# returning None on paths not contained in abs_start_path.
+def relpath(path, start_path, os_path_abspath=None):
+ """Return a path relative to the given start path, or None.
+
+ Returns None if the path is not contained in the directory start_path.
+
+ Args:
+ path: An absolute or relative path to convert to a relative path.
+ start_path: The path relative to which the given path should be
+ converted.
+ os_path_abspath: A replacement function for unit testing. This
+ function should strip trailing slashes just like
+ os.path.abspath(). Defaults to os.path.abspath.
+
+ """
+ if os_path_abspath is None:
+ os_path_abspath = os.path.abspath
+
+ # Since os_path_abspath() calls os.path.normpath()--
+ #
+ # (see http://docs.python.org/library/os.path.html#os.path.abspath )
+ #
+ # it also removes trailing slashes and converts forward and backward
+ # slashes to the preferred slash os.sep.
+ start_path = os_path_abspath(start_path)
+ path = os_path_abspath(path)
+
+ if not path.lower().startswith(start_path.lower()):
+ # Then path is outside the directory given by start_path.
+ return None
+
+ rel_path = path[len(start_path):]
+
+ if not rel_path:
+ # Then the paths are the same.
+ pass
+ elif rel_path[0] == os.sep:
+ # It is probably sufficient to remove just the first character
+ # since os.path.normpath() collapses separators, but we use
+ # lstrip() just to be sure.
+ rel_path = rel_path.lstrip(os.sep)
+ else:
+ # We are in the case typified by the following example:
+ #
+ # start_path = "/tmp/foo"
+ # path = "/tmp/foobar"
+ # rel_path = "bar"
+ return None
+
+ return rel_path
diff --git a/Tools/Scripts/webkitpy/common/system/ospath_unittest.py b/Tools/Scripts/webkitpy/common/system/ospath_unittest.py
new file mode 100644
index 0000000..d84c2c6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/ospath_unittest.py
@@ -0,0 +1,62 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Unit tests for ospath.py."""
+
+import os
+import unittest
+
+from webkitpy.common.system.ospath import relpath
+
+
+# Make sure the tests in this class are platform independent.
+class RelPathTest(unittest.TestCase):
+
+ """Tests relpath()."""
+
+ os_path_abspath = lambda self, path: path
+
+ def _rel_path(self, path, abs_start_path):
+ return relpath(path, abs_start_path, self.os_path_abspath)
+
+ def test_same_path(self):
+ rel_path = self._rel_path("WebKit", "WebKit")
+ self.assertEquals(rel_path, "")
+
+ def test_long_rel_path(self):
+ start_path = "WebKit"
+ expected_rel_path = os.path.join("test", "Foo.txt")
+ path = os.path.join(start_path, expected_rel_path)
+
+ rel_path = self._rel_path(path, start_path)
+ self.assertEquals(expected_rel_path, rel_path)
+
+ def test_none_rel_path(self):
+ """Test _rel_path() with None return value."""
+ start_path = "WebKit"
+ path = os.path.join("other_dir", "foo.txt")
+
+ rel_path = self._rel_path(path, start_path)
+ self.assertTrue(rel_path is None)
+
+ rel_path = self._rel_path("Tools", "WebKit")
+ self.assertTrue(rel_path is None)
diff --git a/Tools/Scripts/webkitpy/common/system/outputcapture.py b/Tools/Scripts/webkitpy/common/system/outputcapture.py
new file mode 100644
index 0000000..45e0e3f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/outputcapture.py
@@ -0,0 +1,86 @@
+# 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.
+#
+# Class for unittest support. Used for capturing stderr/stdout.
+
+import sys
+import unittest
+from StringIO import StringIO
+
+class OutputCapture(object):
+ def __init__(self):
+ self.saved_outputs = dict()
+
+ def _capture_output_with_name(self, output_name):
+ self.saved_outputs[output_name] = getattr(sys, output_name)
+ captured_output = StringIO()
+ setattr(sys, output_name, captured_output)
+ return captured_output
+
+ def _restore_output_with_name(self, output_name):
+ captured_output = getattr(sys, output_name).getvalue()
+ setattr(sys, output_name, self.saved_outputs[output_name])
+ del self.saved_outputs[output_name]
+ return captured_output
+
+ def capture_output(self):
+ return (self._capture_output_with_name("stdout"), self._capture_output_with_name("stderr"))
+
+ def restore_output(self):
+ return (self._restore_output_with_name("stdout"), self._restore_output_with_name("stderr"))
+
+ def assert_outputs(self, testcase, function, args=[], kwargs={}, expected_stdout="", expected_stderr="", expected_exception=None):
+ self.capture_output()
+ if expected_exception:
+ return_value = testcase.assertRaises(expected_exception, function, *args, **kwargs)
+ else:
+ return_value = function(*args, **kwargs)
+ (stdout_string, stderr_string) = self.restore_output()
+ testcase.assertEqual(stdout_string, expected_stdout)
+ testcase.assertEqual(stderr_string, expected_stderr)
+ # This is a little strange, but I don't know where else to return this information.
+ return return_value
+
+
+class OutputCaptureTestCaseBase(unittest.TestCase):
+ def setUp(self):
+ unittest.TestCase.setUp(self)
+ self.output_capture = OutputCapture()
+ (self.__captured_stdout, self.__captured_stderr) = self.output_capture.capture_output()
+
+ def tearDown(self):
+ del self.__captured_stdout
+ del self.__captured_stderr
+ self.output_capture.restore_output()
+ unittest.TestCase.tearDown(self)
+
+ def assertStdout(self, expected_stdout):
+ self.assertEquals(expected_stdout, self.__captured_stdout.getvalue())
+
+ def assertStderr(self, expected_stderr):
+ self.assertEquals(expected_stderr, self.__captured_stderr.getvalue())
diff --git a/Tools/Scripts/webkitpy/common/system/path.py b/Tools/Scripts/webkitpy/common/system/path.py
new file mode 100644
index 0000000..09787d7
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/path.py
@@ -0,0 +1,138 @@
+# 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.
+
+"""generic routines to convert platform-specific paths to URIs."""
+from __future__ import with_statement
+
+import atexit
+import subprocess
+import sys
+import threading
+import urllib
+
+
+def abspath_to_uri(path, platform=None):
+ """Converts a platform-specific absolute path to a file: URL."""
+ if platform is None:
+ platform = sys.platform
+ return "file:" + _escape(_convert_path(path, platform))
+
+
+def cygpath(path):
+ """Converts an absolute cygwin path to an absolute Windows path."""
+ return _CygPath.convert_using_singleton(path)
+
+
+# Note that this object is not threadsafe and must only be called
+# from multiple threads under protection of a lock (as is done in cygpath())
+class _CygPath(object):
+ """Manages a long-running 'cygpath' process for file conversion."""
+ _lock = None
+ _singleton = None
+
+ @staticmethod
+ def stop_cygpath_subprocess():
+ if not _CygPath._lock:
+ return
+
+ with _CygPath._lock:
+ if _CygPath._singleton:
+ _CygPath._singleton.stop()
+
+ @staticmethod
+ def convert_using_singleton(path):
+ if not _CygPath._lock:
+ _CygPath._lock = threading.Lock()
+
+ with _CygPath._lock:
+ if not _CygPath._singleton:
+ _CygPath._singleton = _CygPath()
+ # Make sure the cygpath subprocess always gets shutdown cleanly.
+ atexit.register(_CygPath.stop_cygpath_subprocess)
+
+ return _CygPath._singleton.convert(path)
+
+ def __init__(self):
+ self._child_process = None
+
+ def start(self):
+ assert(self._child_process is None)
+ args = ['cygpath', '-f', '-', '-wa']
+ self._child_process = subprocess.Popen(args,
+ stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE)
+
+ def is_running(self):
+ if not self._child_process:
+ return False
+ return self._child_process.returncode is None
+
+ def stop(self):
+ if self._child_process:
+ self._child_process.stdin.close()
+ self._child_process.wait()
+ self._child_process = None
+
+ def convert(self, path):
+ if not self.is_running():
+ self.start()
+ self._child_process.stdin.write("%s\r\n" % path)
+ self._child_process.stdin.flush()
+ windows_path = self._child_process.stdout.readline().rstrip()
+ # Some versions of cygpath use lowercase drive letters while others
+ # use uppercase. We always convert to uppercase for consistency.
+ windows_path = '%s%s' % (windows_path[0].upper(), windows_path[1:])
+ return windows_path
+
+
+def _escape(path):
+ """Handle any characters in the path that should be escaped."""
+ # FIXME: web browsers don't appear to blindly quote every character
+ # when converting filenames to files. Instead of using urllib's default
+ # rules, we allow a small list of other characters through un-escaped.
+ # It's unclear if this is the best possible solution.
+ return urllib.quote(path, safe='/+:')
+
+
+def _convert_path(path, platform):
+ """Handles any os-specific path separators, mappings, etc."""
+ if platform == 'win32':
+ return _winpath_to_uri(path)
+ if platform == 'cygwin':
+ return _winpath_to_uri(cygpath(path))
+ return _unixypath_to_uri(path)
+
+
+def _winpath_to_uri(path):
+ """Converts a window absolute path to a file: URL."""
+ return "///" + path.replace("\\", "/")
+
+
+def _unixypath_to_uri(path):
+ """Converts a unix-style path to a file: URL."""
+ return "//" + path
diff --git a/Tools/Scripts/webkitpy/common/system/path_unittest.py b/Tools/Scripts/webkitpy/common/system/path_unittest.py
new file mode 100644
index 0000000..4dbd38a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/path_unittest.py
@@ -0,0 +1,105 @@
+# 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 unittest
+import sys
+
+import path
+
+class AbspathTest(unittest.TestCase):
+ def assertMatch(self, test_path, expected_uri,
+ platform=None):
+ if platform == 'cygwin' and sys.platform != 'cygwin':
+ return
+ self.assertEqual(path.abspath_to_uri(test_path, platform=platform),
+ expected_uri)
+
+ def test_abspath_to_uri_cygwin(self):
+ if sys.platform != 'cygwin':
+ return
+
+ self.assertMatch('/cygdrive/c/foo/bar.html',
+ 'file:///C:/foo/bar.html',
+ platform='cygwin')
+ self.assertEqual(path.abspath_to_uri('/cygdrive/c/foo/bar.html',
+ platform='cygwin'),
+ 'file:///C:/foo/bar.html')
+
+ def test_abspath_to_uri_darwin(self):
+ self.assertMatch('/foo/bar.html',
+ 'file:///foo/bar.html',
+ platform='darwin')
+ self.assertEqual(path.abspath_to_uri("/foo/bar.html",
+ platform='darwin'),
+ "file:///foo/bar.html")
+
+ def test_abspath_to_uri_linux2(self):
+ self.assertMatch('/foo/bar.html',
+ 'file:///foo/bar.html',
+ platform='darwin')
+ self.assertEqual(path.abspath_to_uri("/foo/bar.html",
+ platform='linux2'),
+ "file:///foo/bar.html")
+
+ def test_abspath_to_uri_win(self):
+ self.assertMatch('c:\\foo\\bar.html',
+ 'file:///c:/foo/bar.html',
+ platform='win32')
+ self.assertEqual(path.abspath_to_uri("c:\\foo\\bar.html",
+ platform='win32'),
+ "file:///c:/foo/bar.html")
+
+ def test_abspath_to_uri_escaping(self):
+ self.assertMatch('/foo/bar + baz%?.html',
+ 'file:///foo/bar%20+%20baz%25%3F.html',
+ platform='darwin')
+ self.assertMatch('/foo/bar + baz%?.html',
+ 'file:///foo/bar%20+%20baz%25%3F.html',
+ platform='linux2')
+
+ # Note that you can't have '?' in a filename on windows.
+ self.assertMatch('/cygdrive/c/foo/bar + baz%.html',
+ 'file:///C:/foo/bar%20+%20baz%25.html',
+ platform='cygwin')
+
+ def test_stop_cygpath_subprocess(self):
+ if sys.platform != 'cygwin':
+ return
+
+ # Call cygpath to ensure the subprocess is running.
+ path.cygpath("/cygdrive/c/foo.txt")
+ self.assertTrue(path._CygPath._singleton.is_running())
+
+ # Stop it.
+ path._CygPath.stop_cygpath_subprocess()
+
+ # Ensure that it is stopped.
+ self.assertFalse(path._CygPath._singleton.is_running())
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/common/system/platforminfo.py b/Tools/Scripts/webkitpy/common/system/platforminfo.py
new file mode 100644
index 0000000..cc370ba
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/platforminfo.py
@@ -0,0 +1,43 @@
+# 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 platform
+
+
+# We use this instead of calls to platform directly to allow mocking.
+class PlatformInfo(object):
+
+ def display_name(self):
+ # platform.platform() returns Darwin information for Mac, which is just confusing.
+ if platform.system() == "Darwin":
+ return "Mac OS X %s" % platform.mac_ver()[0]
+
+ # Returns strings like:
+ # Linux-2.6.18-194.3.1.el5-i686-with-redhat-5.5-Final
+ # Windows-2008ServerR2-6.1.7600
+ return platform.platform()
diff --git a/Tools/Scripts/webkitpy/common/system/user.py b/Tools/Scripts/webkitpy/common/system/user.py
new file mode 100644
index 0000000..b79536c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/user.py
@@ -0,0 +1,143 @@
+# 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 logging
+import os
+import re
+import shlex
+import subprocess
+import sys
+import webbrowser
+
+
+_log = logging.getLogger("webkitpy.common.system.user")
+
+
+try:
+ import readline
+except ImportError:
+ if sys.platform != "win32":
+ # There is no readline module for win32, not much to do except cry.
+ _log.warn("Unable to import readline.")
+ # FIXME: We could give instructions for non-mac platforms.
+ # Lack of readline results in a very bad user experiance.
+ if sys.platform == "darwin":
+ _log.warn("If you're using MacPorts, try running:")
+ _log.warn(" sudo port install py25-readline")
+
+
+class User(object):
+ DEFAULT_NO = 'n'
+ DEFAULT_YES = 'y'
+
+ # FIXME: These are @classmethods because bugzilla.py doesn't have a Tool object (thus no User instance).
+ @classmethod
+ def prompt(cls, message, repeat=1, raw_input=raw_input):
+ response = None
+ while (repeat and not response):
+ repeat -= 1
+ response = raw_input(message)
+ return response
+
+ @classmethod
+ def prompt_with_list(cls, list_title, list_items, can_choose_multiple=False, raw_input=raw_input):
+ print list_title
+ i = 0
+ for item in list_items:
+ i += 1
+ print "%2d. %s" % (i, item)
+
+ # Loop until we get valid input
+ while True:
+ if can_choose_multiple:
+ response = cls.prompt("Enter one or more numbers (comma-separated), or \"all\": ", raw_input=raw_input)
+ if not response.strip() or response == "all":
+ return list_items
+ try:
+ indices = [int(r) - 1 for r in re.split("\s*,\s*", response)]
+ except ValueError, err:
+ continue
+ return [list_items[i] for i in indices]
+ else:
+ try:
+ result = int(cls.prompt("Enter a number: ", raw_input=raw_input)) - 1
+ except ValueError, err:
+ continue
+ return list_items[result]
+
+ def edit(self, files):
+ editor = os.environ.get("EDITOR") or "vi"
+ args = shlex.split(editor)
+ # Note: Not thread safe: http://bugs.python.org/issue2320
+ subprocess.call(args + files)
+
+ def _warn_if_application_is_xcode(self, edit_application):
+ if "Xcode" in edit_application:
+ print "Instead of using Xcode.app, consider using EDITOR=\"xed --wait\"."
+
+ def edit_changelog(self, files):
+ edit_application = os.environ.get("CHANGE_LOG_EDIT_APPLICATION")
+ if edit_application and sys.platform == "darwin":
+ # On Mac we support editing ChangeLogs using an application.
+ args = shlex.split(edit_application)
+ print "Using editor in the CHANGE_LOG_EDIT_APPLICATION environment variable."
+ print "Please quit the editor application when done editing."
+ self._warn_if_application_is_xcode(edit_application)
+ subprocess.call(["open", "-W", "-n", "-a"] + args + files)
+ return
+ self.edit(files)
+
+ def page(self, message):
+ pager = os.environ.get("PAGER") or "less"
+ try:
+ # Note: Not thread safe: http://bugs.python.org/issue2320
+ child_process = subprocess.Popen([pager], stdin=subprocess.PIPE)
+ child_process.communicate(input=message)
+ except IOError, e:
+ pass
+
+ def confirm(self, message=None, default=DEFAULT_YES, raw_input=raw_input):
+ if not message:
+ message = "Continue?"
+ choice = {'y': 'Y/n', 'n': 'y/N'}[default]
+ response = raw_input("%s [%s]: " % (message, choice))
+ if not response:
+ response = default
+ return response.lower() == 'y'
+
+ def can_open_url(self):
+ try:
+ webbrowser.get()
+ return True
+ except webbrowser.Error, e:
+ return False
+
+ def open_url(self, url):
+ if not self.can_open_url():
+ _log.warn("Failed to open %s" % url)
+ webbrowser.open(url)
diff --git a/Tools/Scripts/webkitpy/common/system/user_unittest.py b/Tools/Scripts/webkitpy/common/system/user_unittest.py
new file mode 100644
index 0000000..7ec9b34
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/system/user_unittest.py
@@ -0,0 +1,109 @@
+# Copyright (C) 2010 Research in Motion 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:
+#
+# * 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 Research in Motion Ltd. 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 unittest
+
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.common.system.user import User
+
+class UserTest(unittest.TestCase):
+
+ example_user_response = "example user response"
+
+ def test_prompt_repeat(self):
+ self.repeatsRemaining = 2
+ def mock_raw_input(message):
+ self.repeatsRemaining -= 1
+ if not self.repeatsRemaining:
+ return UserTest.example_user_response
+ return None
+ self.assertEqual(User.prompt("input", repeat=self.repeatsRemaining, raw_input=mock_raw_input), UserTest.example_user_response)
+
+ def test_prompt_when_exceeded_repeats(self):
+ self.repeatsRemaining = 2
+ def mock_raw_input(message):
+ self.repeatsRemaining -= 1
+ return None
+ self.assertEqual(User.prompt("input", repeat=self.repeatsRemaining, raw_input=mock_raw_input), None)
+
+ def test_prompt_with_list(self):
+ def run_prompt_test(inputs, expected_result, can_choose_multiple=False):
+ def mock_raw_input(message):
+ return inputs.pop(0)
+ output_capture = OutputCapture()
+ actual_result = output_capture.assert_outputs(
+ self,
+ User.prompt_with_list,
+ args=["title", ["foo", "bar"]],
+ kwargs={"can_choose_multiple": can_choose_multiple, "raw_input": mock_raw_input},
+ expected_stdout="title\n 1. foo\n 2. bar\n")
+ self.assertEqual(actual_result, expected_result)
+ self.assertEqual(len(inputs), 0)
+
+ run_prompt_test(["1"], "foo")
+ run_prompt_test(["badinput", "2"], "bar")
+
+ run_prompt_test(["1,2"], ["foo", "bar"], can_choose_multiple=True)
+ run_prompt_test([" 1, 2 "], ["foo", "bar"], can_choose_multiple=True)
+ run_prompt_test(["all"], ["foo", "bar"], can_choose_multiple=True)
+ run_prompt_test([""], ["foo", "bar"], can_choose_multiple=True)
+ run_prompt_test([" "], ["foo", "bar"], can_choose_multiple=True)
+ run_prompt_test(["badinput", "all"], ["foo", "bar"], can_choose_multiple=True)
+
+ def test_confirm(self):
+ test_cases = (
+ (("Continue? [Y/n]: ", True), (User.DEFAULT_YES, 'y')),
+ (("Continue? [Y/n]: ", False), (User.DEFAULT_YES, 'n')),
+ (("Continue? [Y/n]: ", True), (User.DEFAULT_YES, '')),
+ (("Continue? [Y/n]: ", False), (User.DEFAULT_YES, 'q')),
+ (("Continue? [y/N]: ", True), (User.DEFAULT_NO, 'y')),
+ (("Continue? [y/N]: ", False), (User.DEFAULT_NO, 'n')),
+ (("Continue? [y/N]: ", False), (User.DEFAULT_NO, '')),
+ (("Continue? [y/N]: ", False), (User.DEFAULT_NO, 'q')),
+ )
+ for test_case in test_cases:
+ expected, inputs = test_case
+
+ def mock_raw_input(message):
+ self.assertEquals(expected[0], message)
+ return inputs[1]
+
+ result = User().confirm(default=inputs[0],
+ raw_input=mock_raw_input)
+ self.assertEquals(expected[1], result)
+
+ def test_warn_if_application_is_xcode(self):
+ output = OutputCapture()
+ user = User()
+ output.assert_outputs(self, user._warn_if_application_is_xcode, ["TextMate"])
+ output.assert_outputs(self, user._warn_if_application_is_xcode, ["/Applications/TextMate.app"])
+ output.assert_outputs(self, user._warn_if_application_is_xcode, ["XCode"]) # case sensitive matching
+
+ xcode_warning = "Instead of using Xcode.app, consider using EDITOR=\"xed --wait\".\n"
+ output.assert_outputs(self, user._warn_if_application_is_xcode, ["Xcode"], expected_stdout=xcode_warning)
+ output.assert_outputs(self, user._warn_if_application_is_xcode, ["/Developer/Applications/Xcode.app"], expected_stdout=xcode_warning)
diff --git a/Tools/Scripts/webkitpy/common/thread/__init__.py b/Tools/Scripts/webkitpy/common/thread/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/thread/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/common/thread/messagepump.py b/Tools/Scripts/webkitpy/common/thread/messagepump.py
new file mode 100644
index 0000000..0e39285
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/thread/messagepump.py
@@ -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:
+#
+# * 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.
+
+
+class MessagePumpDelegate(object):
+ def schedule(self, interval, callback):
+ raise NotImplementedError, "subclasses must implement"
+
+ def message_available(self, message):
+ raise NotImplementedError, "subclasses must implement"
+
+ def final_message_delivered(self):
+ raise NotImplementedError, "subclasses must implement"
+
+
+class MessagePump(object):
+ interval = 10 # seconds
+
+ def __init__(self, delegate, message_queue):
+ self._delegate = delegate
+ self._message_queue = message_queue
+ self._schedule()
+
+ def _schedule(self):
+ self._delegate.schedule(self.interval, self._callback)
+
+ def _callback(self):
+ (messages, is_running) = self._message_queue.take_all()
+ for message in messages:
+ self._delegate.message_available(message)
+ if not is_running:
+ self._delegate.final_message_delivered()
+ return
+ self._schedule()
diff --git a/Tools/Scripts/webkitpy/common/thread/messagepump_unittest.py b/Tools/Scripts/webkitpy/common/thread/messagepump_unittest.py
new file mode 100644
index 0000000..f731db2
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/thread/messagepump_unittest.py
@@ -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.
+
+import unittest
+
+from webkitpy.common.thread.messagepump import MessagePump, MessagePumpDelegate
+from webkitpy.common.thread.threadedmessagequeue import ThreadedMessageQueue
+
+
+class TestDelegate(MessagePumpDelegate):
+ def __init__(self):
+ self.log = []
+
+ def schedule(self, interval, callback):
+ self.callback = callback
+ self.log.append("schedule")
+
+ def message_available(self, message):
+ self.log.append("message_available: %s" % message)
+
+ def final_message_delivered(self):
+ self.log.append("final_message_delivered")
+
+
+class MessagePumpTest(unittest.TestCase):
+
+ def test_basic(self):
+ queue = ThreadedMessageQueue()
+ delegate = TestDelegate()
+ pump = MessagePump(delegate, queue)
+ self.assertEqual(delegate.log, [
+ 'schedule'
+ ])
+ delegate.callback()
+ queue.post("Hello")
+ queue.post("There")
+ delegate.callback()
+ self.assertEqual(delegate.log, [
+ 'schedule',
+ 'schedule',
+ 'message_available: Hello',
+ 'message_available: There',
+ 'schedule'
+ ])
+ queue.post("More")
+ queue.post("Messages")
+ queue.stop()
+ delegate.callback()
+ self.assertEqual(delegate.log, [
+ 'schedule',
+ 'schedule',
+ 'message_available: Hello',
+ 'message_available: There',
+ 'schedule',
+ 'message_available: More',
+ 'message_available: Messages',
+ 'final_message_delivered'
+ ])
diff --git a/Tools/Scripts/webkitpy/common/thread/threadedmessagequeue.py b/Tools/Scripts/webkitpy/common/thread/threadedmessagequeue.py
new file mode 100644
index 0000000..17b6277
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/thread/threadedmessagequeue.py
@@ -0,0 +1,54 @@
+# 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.
+
+from __future__ import with_statement
+
+import threading
+
+
+class ThreadedMessageQueue(object):
+ def __init__(self):
+ self._messages = []
+ self._is_running = True
+ self._lock = threading.Lock()
+
+ def post(self, message):
+ with self._lock:
+ self._messages.append(message)
+
+ def stop(self):
+ with self._lock:
+ self._is_running = False
+
+ def take_all(self):
+ with self._lock:
+ messages = self._messages
+ is_running = self._is_running
+ self._messages = []
+ return (messages, is_running)
+
diff --git a/Tools/Scripts/webkitpy/common/thread/threadedmessagequeue_unittest.py b/Tools/Scripts/webkitpy/common/thread/threadedmessagequeue_unittest.py
new file mode 100644
index 0000000..cb67c1e
--- /dev/null
+++ b/Tools/Scripts/webkitpy/common/thread/threadedmessagequeue_unittest.py
@@ -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.
+
+import unittest
+
+from webkitpy.common.thread.threadedmessagequeue import ThreadedMessageQueue
+
+class ThreadedMessageQueueTest(unittest.TestCase):
+
+ def test_basic(self):
+ queue = ThreadedMessageQueue()
+ queue.post("Hello")
+ queue.post("There")
+ (messages, is_running) = queue.take_all()
+ self.assertEqual(messages, ["Hello", "There"])
+ self.assertTrue(is_running)
+ (messages, is_running) = queue.take_all()
+ self.assertEqual(messages, [])
+ self.assertTrue(is_running)
+ queue.post("More")
+ queue.stop()
+ queue.post("Messages")
+ (messages, is_running) = queue.take_all()
+ self.assertEqual(messages, ["More", "Messages"])
+ self.assertFalse(is_running)
+ (messages, is_running) = queue.take_all()
+ self.assertEqual(messages, [])
+ self.assertFalse(is_running)
diff --git a/Tools/Scripts/webkitpy/layout_tests/__init__.py b/Tools/Scripts/webkitpy/layout_tests/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/layout_tests/deduplicate_tests.py b/Tools/Scripts/webkitpy/layout_tests/deduplicate_tests.py
new file mode 100644
index 0000000..51dcac8
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/deduplicate_tests.py
@@ -0,0 +1,231 @@
+#!/usr/bin/env python
+# 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 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.
+
+"""deduplicate_tests -- lists duplicated between platforms.
+
+If platform/mac-leopard is missing an expected test output, we fall back on
+platform/mac. This means it's possible to grow redundant test outputs,
+where we have the same expected data in both a platform directory and another
+platform it falls back on.
+"""
+
+import collections
+import fnmatch
+import os
+import subprocess
+import sys
+import re
+import webkitpy.common.checkout.scm as scm
+import webkitpy.common.system.executive as executive
+import webkitpy.common.system.logutils as logutils
+import webkitpy.common.system.ospath as ospath
+import webkitpy.layout_tests.port.factory as port_factory
+
+_log = logutils.get_logger(__file__)
+
+_BASE_PLATFORM = 'base'
+
+
+def port_fallbacks():
+ """Get the port fallback information.
+ Returns:
+ A dictionary mapping platform name to a list of other platforms to fall
+ back on. All platforms fall back on 'base'.
+ """
+ fallbacks = {_BASE_PLATFORM: []}
+ platform_dir = os.path.join(scm.find_checkout_root(), 'LayoutTests',
+ 'platform')
+ for port_name in os.listdir(platform_dir):
+ try:
+ platforms = port_factory.get(port_name).baseline_search_path()
+ except NotImplementedError:
+ _log.error("'%s' lacks baseline_search_path(), please fix."
+ % port_name)
+ fallbacks[port_name] = [_BASE_PLATFORM]
+ continue
+ fallbacks[port_name] = [os.path.basename(p) for p in platforms][1:]
+ fallbacks[port_name].append(_BASE_PLATFORM)
+ return fallbacks
+
+
+def parse_git_output(git_output, glob_pattern):
+ """Parses the output of git ls-tree and filters based on glob_pattern.
+ Args:
+ git_output: result of git ls-tree -r HEAD LayoutTests.
+ glob_pattern: a pattern to filter the files.
+ Returns:
+ A dictionary mapping (test name, hash of content) => [paths]
+ """
+ hashes = collections.defaultdict(set)
+ for line in git_output.split('\n'):
+ if not line:
+ break
+ attrs, path = line.strip().split('\t')
+ if not fnmatch.fnmatch(path, glob_pattern):
+ continue
+ path = path[len('LayoutTests/'):]
+ match = re.match(r'^(platform/.*?/)?(.*)', path)
+ test = match.group(2)
+ _, _, hash = attrs.split(' ')
+ hashes[(test, hash)].add(path)
+ return hashes
+
+
+def cluster_file_hashes(glob_pattern):
+ """Get the hashes of all the test expectations in the tree.
+ We cheat and use git's hashes.
+ Args:
+ glob_pattern: a pattern to filter the files.
+ Returns:
+ A dictionary mapping (test name, hash of content) => [paths]
+ """
+
+ # A map of file hash => set of all files with that hash.
+ hashes = collections.defaultdict(set)
+
+ # Fill in the map.
+ cmd = ('git', 'ls-tree', '-r', 'HEAD', 'LayoutTests')
+ try:
+ git_output = executive.Executive().run_command(cmd,
+ cwd=scm.find_checkout_root())
+ except OSError, e:
+ if e.errno == 2: # No such file or directory.
+ _log.error("Error: 'No such file' when running git.")
+ _log.error("This script requires git.")
+ sys.exit(1)
+ raise e
+ return parse_git_output(git_output, glob_pattern)
+
+
+def extract_platforms(paths):
+ """Extracts the platforms from a list of paths matching ^platform/(.*?)/.
+ Args:
+ paths: a list of paths.
+ Returns:
+ A dictionary containing all platforms from paths.
+ """
+ platforms = {}
+ for path in paths:
+ match = re.match(r'^platform/(.*?)/', path)
+ if match:
+ platform = match.group(1)
+ else:
+ platform = _BASE_PLATFORM
+ platforms[platform] = path
+ return platforms
+
+
+def has_intermediate_results(test, fallbacks, matching_platform,
+ path_exists=os.path.exists):
+ """Returns True if there is a test result that causes us to not delete
+ this duplicate.
+
+ For example, chromium-linux may be a duplicate of the checked in result,
+ but chromium-win may have a different result checked in. In this case,
+ we need to keep the duplicate results.
+
+ Args:
+ test: The test name.
+ fallbacks: A list of platforms we fall back on.
+ matching_platform: The platform that we found the duplicate test
+ result. We can stop checking here.
+ path_exists: Optional parameter that allows us to stub out
+ os.path.exists for testing.
+ """
+ for platform in fallbacks:
+ if platform == matching_platform:
+ return False
+ test_path = os.path.join('LayoutTests', 'platform', platform, test)
+ if path_exists(test_path):
+ return True
+ return False
+
+
+def get_relative_test_path(filename, relative_to,
+ checkout_root=scm.find_checkout_root()):
+ """Constructs a relative path to |filename| from |relative_to|.
+ Args:
+ filename: The test file we're trying to get a relative path to.
+ relative_to: The absolute path we're relative to.
+ Returns:
+ A relative path to filename or None if |filename| is not below
+ |relative_to|.
+ """
+ layout_test_dir = os.path.join(checkout_root, 'LayoutTests')
+ abs_path = os.path.join(layout_test_dir, filename)
+ return ospath.relpath(abs_path, relative_to)
+
+
+def find_dups(hashes, port_fallbacks, relative_to):
+ """Yields info about redundant test expectations.
+ Args:
+ hashes: a list of hashes as returned by cluster_file_hashes.
+ port_fallbacks: a list of fallback information as returned by
+ get_port_fallbacks.
+ relative_to: the directory that we want the results relative to
+ Returns:
+ a tuple containing (test, platform, fallback, platforms)
+ """
+ for (test, hash), cluster in hashes.items():
+ if len(cluster) < 2:
+ continue # Common case: only one file with that hash.
+
+ # Compute the list of platforms we have this particular hash for.
+ platforms = extract_platforms(cluster)
+ if len(platforms) == 1:
+ continue
+
+ # See if any of the platforms are redundant with each other.
+ for platform in platforms.keys():
+ for fallback in port_fallbacks[platform]:
+ if fallback not in platforms.keys():
+ continue
+ # We have to verify that there isn't an intermediate result
+ # that causes this duplicate hash to exist.
+ if has_intermediate_results(test, port_fallbacks[platform],
+ fallback):
+ continue
+ # We print the relative path so it's easy to pipe the results
+ # to xargs rm.
+ path = get_relative_test_path(platforms[platform], relative_to)
+ if not path:
+ continue
+ yield {
+ 'test': test,
+ 'platform': platform,
+ 'fallback': fallback,
+ 'path': path,
+ }
+
+
+def deduplicate(glob_pattern):
+ """Traverses LayoutTests and returns information about duplicated files.
+ Args:
+ glob pattern to filter the files in LayoutTests.
+ Returns:
+ a dictionary containing test, path, platform and fallback.
+ """
+ fallbacks = port_fallbacks()
+ hashes = cluster_file_hashes(glob_pattern)
+ return list(find_dups(hashes, fallbacks, os.getcwd()))
diff --git a/Tools/Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py b/Tools/Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py
new file mode 100644
index 0000000..309bf8d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/deduplicate_tests_unittest.py
@@ -0,0 +1,210 @@
+#!/usr/bin/env python
+# 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 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.
+
+"""Unit tests for deduplicate_tests.py."""
+
+import deduplicate_tests
+import os
+import unittest
+import webkitpy.common.checkout.scm as scm
+
+
+class MockExecutive(object):
+ last_run_command = []
+ response = ''
+
+ class Executive(object):
+ def run_command(self,
+ args,
+ cwd=None,
+ input=None,
+ error_handler=None,
+ return_exit_code=False,
+ return_stderr=True,
+ decode_output=True):
+ MockExecutive.last_run_command += [args]
+ return MockExecutive.response
+
+
+class ListDuplicatesTest(unittest.TestCase):
+ def setUp(self):
+ MockExecutive.last_run_command = []
+ MockExecutive.response = ''
+ deduplicate_tests.executive = MockExecutive
+ self._original_cwd = os.getcwd()
+ checkout_root = scm.find_checkout_root()
+ self.assertNotEqual(checkout_root, None)
+ os.chdir(checkout_root)
+
+ def tearDown(self):
+ os.chdir(self._original_cwd)
+
+ def test_parse_git_output(self):
+ git_output = (
+ '100644 blob 5053240b3353f6eb39f7cb00259785f16d121df2\tLayoutTests/mac/foo-expected.txt\n'
+ '100644 blob a004548d107ecc4e1ea08019daf0a14e8634a1ff\tLayoutTests/platform/chromium/foo-expected.txt\n'
+ '100644 blob d6bb0bc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-linux/foo-expected.txt\n'
+ '100644 blob abcdebc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-linux/animage.png\n'
+ '100644 blob d6bb0bc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-win/foo-expected.txt\n'
+ '100644 blob abcdebc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-win/animage.png\n'
+ '100644 blob 4303df5389ca87cae83dd3236b8dd84e16606517\tLayoutTests/platform/mac/foo-expected.txt\n')
+ hashes = deduplicate_tests.parse_git_output(git_output, '*')
+ expected = {('mac/foo-expected.txt', '5053240b3353f6eb39f7cb00259785f16d121df2'): set(['mac/foo-expected.txt']),
+ ('animage.png', 'abcdebc762e3aec5df03b5c04485b2cb3b65ffb1'): set(['platform/chromium-linux/animage.png', 'platform/chromium-win/animage.png']),
+ ('foo-expected.txt', '4303df5389ca87cae83dd3236b8dd84e16606517'): set(['platform/mac/foo-expected.txt']),
+ ('foo-expected.txt', 'd6bb0bc762e3aec5df03b5c04485b2cb3b65ffb1'): set(['platform/chromium-linux/foo-expected.txt', 'platform/chromium-win/foo-expected.txt']),
+ ('foo-expected.txt', 'a004548d107ecc4e1ea08019daf0a14e8634a1ff'): set(['platform/chromium/foo-expected.txt'])}
+ self.assertEquals(expected, hashes)
+
+ hashes = deduplicate_tests.parse_git_output(git_output, '*.png')
+ expected = {('animage.png', 'abcdebc762e3aec5df03b5c04485b2cb3b65ffb1'): set(['platform/chromium-linux/animage.png', 'platform/chromium-win/animage.png'])}
+ self.assertEquals(expected, hashes)
+
+ def test_extract_platforms(self):
+ self.assertEquals({'foo': 'platform/foo/bar',
+ 'zoo': 'platform/zoo/com'},
+ deduplicate_tests.extract_platforms(['platform/foo/bar', 'platform/zoo/com']))
+ self.assertEquals({'foo': 'platform/foo/bar',
+ deduplicate_tests._BASE_PLATFORM: 'what/'},
+ deduplicate_tests.extract_platforms(['platform/foo/bar', 'what/']))
+
+ def test_has_intermediate_results(self):
+ test_cases = (
+ # If we found a duplicate in our first fallback, we have no
+ # intermediate results.
+ (False, ('fast/foo-expected.txt',
+ ['chromium-win', 'chromium', 'base'],
+ 'chromium-win',
+ lambda path: True)),
+ # Since chromium-win has a result, we have an intermediate result.
+ (True, ('fast/foo-expected.txt',
+ ['chromium-win', 'chromium', 'base'],
+ 'chromium',
+ lambda path: True)),
+ # There are no intermediate results.
+ (False, ('fast/foo-expected.txt',
+ ['chromium-win', 'chromium', 'base'],
+ 'chromium',
+ lambda path: False)),
+ # There are no intermediate results since a result for chromium is
+ # our duplicate file.
+ (False, ('fast/foo-expected.txt',
+ ['chromium-win', 'chromium', 'base'],
+ 'chromium',
+ lambda path: path == 'LayoutTests/platform/chromium/fast/foo-expected.txt')),
+ # We have an intermediate result in 'chromium' even though our
+ # duplicate is with the file in 'base'.
+ (True, ('fast/foo-expected.txt',
+ ['chromium-win', 'chromium', 'base'],
+ 'base',
+ lambda path: path == 'LayoutTests/platform/chromium/fast/foo-expected.txt')),
+ # We have an intermediate result in 'chromium-win' even though our
+ # duplicate is in 'base'.
+ (True, ('fast/foo-expected.txt',
+ ['chromium-win', 'chromium', 'base'],
+ 'base',
+ lambda path: path == 'LayoutTests/platform/chromium-win/fast/foo-expected.txt')),
+ )
+ for expected, inputs in test_cases:
+ self.assertEquals(expected,
+ deduplicate_tests.has_intermediate_results(*inputs))
+
+ def test_unique(self):
+ MockExecutive.response = (
+ '100644 blob 5053240b3353f6eb39f7cb00259785f16d121df2\tLayoutTests/mac/foo-expected.txt\n'
+ '100644 blob a004548d107ecc4e1ea08019daf0a14e8634a1ff\tLayoutTests/platform/chromium/foo-expected.txt\n'
+ '100644 blob abcd0bc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-linux/foo-expected.txt\n'
+ '100644 blob d6bb0bc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-win/foo-expected.txt\n'
+ '100644 blob 4303df5389ca87cae83dd3236b8dd84e16606517\tLayoutTests/platform/mac/foo-expected.txt\n')
+ result = deduplicate_tests.deduplicate('*')
+ self.assertEquals(1, len(MockExecutive.last_run_command))
+ self.assertEquals(('git', 'ls-tree', '-r', 'HEAD', 'LayoutTests'), MockExecutive.last_run_command[-1])
+ self.assertEquals(0, len(result))
+
+ def test_duplicates(self):
+ MockExecutive.response = (
+ '100644 blob 5053240b3353f6eb39f7cb00259785f16d121df2\tLayoutTests/mac/foo-expected.txt\n'
+ '100644 blob a004548d107ecc4e1ea08019daf0a14e8634a1ff\tLayoutTests/platform/chromium/foo-expected.txt\n'
+ '100644 blob d6bb0bc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-linux/foo-expected.txt\n'
+ '100644 blob abcdebc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-linux/animage.png\n'
+ '100644 blob d6bb0bc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-win/foo-expected.txt\n'
+ '100644 blob abcdebc762e3aec5df03b5c04485b2cb3b65ffb1\tLayoutTests/platform/chromium-win/animage.png\n'
+ '100644 blob 4303df5389ca87cae83dd3236b8dd84e16606517\tLayoutTests/platform/mac/foo-expected.txt\n')
+
+ result = deduplicate_tests.deduplicate('*')
+ self.assertEquals(1, len(MockExecutive.last_run_command))
+ self.assertEquals(('git', 'ls-tree', '-r', 'HEAD', 'LayoutTests'), MockExecutive.last_run_command[-1])
+ self.assertEquals(2, len(result))
+ self.assertEquals({'test': 'animage.png',
+ 'path': 'LayoutTests/platform/chromium-linux/animage.png',
+ 'fallback': 'chromium-win',
+ 'platform': 'chromium-linux'},
+ result[0])
+ self.assertEquals({'test': 'foo-expected.txt',
+ 'path': 'LayoutTests/platform/chromium-linux/foo-expected.txt',
+ 'fallback': 'chromium-win',
+ 'platform': 'chromium-linux'},
+ result[1])
+
+ result = deduplicate_tests.deduplicate('*.txt')
+ self.assertEquals(2, len(MockExecutive.last_run_command))
+ self.assertEquals(('git', 'ls-tree', '-r', 'HEAD', 'LayoutTests'), MockExecutive.last_run_command[-1])
+ self.assertEquals(1, len(result))
+ self.assertEquals({'test': 'foo-expected.txt',
+ 'path': 'LayoutTests/platform/chromium-linux/foo-expected.txt',
+ 'fallback': 'chromium-win',
+ 'platform': 'chromium-linux'},
+ result[0])
+
+ result = deduplicate_tests.deduplicate('*.png')
+ self.assertEquals(3, len(MockExecutive.last_run_command))
+ self.assertEquals(('git', 'ls-tree', '-r', 'HEAD', 'LayoutTests'), MockExecutive.last_run_command[-1])
+ self.assertEquals(1, len(result))
+ self.assertEquals({'test': 'animage.png',
+ 'path': 'LayoutTests/platform/chromium-linux/animage.png',
+ 'fallback': 'chromium-win',
+ 'platform': 'chromium-linux'},
+ result[0])
+
+ def test_get_relative_test_path(self):
+ checkout_root = scm.find_checkout_root()
+ layout_test_dir = os.path.join(checkout_root, 'LayoutTests')
+ test_cases = (
+ ('platform/mac/test.html',
+ ('platform/mac/test.html', layout_test_dir)),
+ ('LayoutTests/platform/mac/test.html',
+ ('platform/mac/test.html', checkout_root)),
+ (None,
+ ('platform/mac/test.html', os.path.join(checkout_root, 'WebCore'))),
+ ('test.html',
+ ('platform/mac/test.html', os.path.join(layout_test_dir, 'platform/mac'))),
+ (None,
+ ('platform/mac/test.html', os.path.join(layout_test_dir, 'platform/win'))),
+ )
+ for expected, inputs in test_cases:
+ self.assertEquals(expected,
+ deduplicate_tests.get_relative_test_path(*inputs))
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py
new file mode 100644
index 0000000..fdb8da6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/dump_render_tree_thread.py
@@ -0,0 +1,569 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
+#
+# 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.
+
+"""A Thread object for running DumpRenderTree and processing URLs from a
+shared queue.
+
+Each thread runs a separate instance of the DumpRenderTree binary and validates
+the output. When there are no more URLs to process in the shared queue, the
+thread exits.
+"""
+
+from __future__ import with_statement
+
+import codecs
+import copy
+import logging
+import os
+import Queue
+import signal
+import sys
+import thread
+import threading
+import time
+
+
+from webkitpy.layout_tests.test_types import image_diff
+from webkitpy.layout_tests.test_types import test_type_base
+from webkitpy.layout_tests.test_types import text_diff
+
+import test_failures
+import test_output
+import test_results
+
+_log = logging.getLogger("webkitpy.layout_tests.layout_package."
+ "dump_render_tree_thread")
+
+
+def _expected_test_output(port, filename):
+ """Returns an expected TestOutput object."""
+ return test_output.TestOutput(port.expected_text(filename),
+ port.expected_image(filename),
+ port.expected_checksum(filename))
+
+def _process_output(port, options, test_input, test_types, test_args,
+ test_output, worker_name):
+ """Receives the output from a DumpRenderTree process, subjects it to a
+ number of tests, and returns a list of failure types the test produced.
+
+ Args:
+ port: port-specific hooks
+ options: command line options argument from optparse
+ proc: an active DumpRenderTree process
+ test_input: Object containing the test filename and timeout
+ test_types: list of test types to subject the output to
+ test_args: arguments to be passed to each test
+ test_output: a TestOutput object containing the output of the test
+ worker_name: worker name for logging
+
+ Returns: a TestResult object
+ """
+ failures = []
+
+ if test_output.crash:
+ failures.append(test_failures.FailureCrash())
+ if test_output.timeout:
+ failures.append(test_failures.FailureTimeout())
+
+ test_name = port.relative_test_filename(test_input.filename)
+ if test_output.crash:
+ _log.debug("%s Stacktrace for %s:\n%s" % (worker_name, test_name,
+ test_output.error))
+ filename = os.path.join(options.results_directory, test_name)
+ filename = os.path.splitext(filename)[0] + "-stack.txt"
+ port.maybe_make_directory(os.path.split(filename)[0])
+ with codecs.open(filename, "wb", "utf-8") as file:
+ file.write(test_output.error)
+ elif test_output.error:
+ _log.debug("%s %s output stderr lines:\n%s" % (worker_name, test_name,
+ test_output.error))
+
+ expected_test_output = _expected_test_output(port, test_input.filename)
+
+ # Check the output and save the results.
+ start_time = time.time()
+ time_for_diffs = {}
+ for test_type in test_types:
+ start_diff_time = time.time()
+ new_failures = test_type.compare_output(port, test_input.filename,
+ test_args, test_output,
+ expected_test_output)
+ # Don't add any more failures if we already have a crash, so we don't
+ # double-report those tests. We do double-report for timeouts since
+ # we still want to see the text and image output.
+ if not test_output.crash:
+ failures.extend(new_failures)
+ time_for_diffs[test_type.__class__.__name__] = (
+ time.time() - start_diff_time)
+
+ total_time_for_all_diffs = time.time() - start_diff_time
+ return test_results.TestResult(test_input.filename, failures, test_output.test_time,
+ total_time_for_all_diffs, time_for_diffs)
+
+
+def _pad_timeout(timeout):
+ """Returns a safe multiple of the per-test timeout value to use
+ to detect hung test threads.
+
+ """
+ # When we're running one test per DumpRenderTree process, we can
+ # enforce a hard timeout. The DumpRenderTree watchdog uses 2.5x
+ # the timeout; we want to be larger than that.
+ return timeout * 3
+
+
+def _milliseconds_to_seconds(msecs):
+ return float(msecs) / 1000.0
+
+
+def _should_fetch_expected_checksum(options):
+ return options.pixel_tests and not (options.new_baseline or options.reset_results)
+
+
+def _run_single_test(port, options, test_input, test_types, test_args, driver, worker_name):
+ # FIXME: Pull this into TestShellThread._run().
+
+ # The image hash is used to avoid doing an image dump if the
+ # checksums match, so it should be set to a blank value if we
+ # are generating a new baseline. (Otherwise, an image from a
+ # previous run will be copied into the baseline."""
+ if _should_fetch_expected_checksum(options):
+ test_input.image_hash = port.expected_checksum(test_input.filename)
+ test_output = driver.run_test(test_input)
+ return _process_output(port, options, test_input, test_types, test_args,
+ test_output, worker_name)
+
+
+class SingleTestThread(threading.Thread):
+ """Thread wrapper for running a single test file."""
+
+ def __init__(self, port, options, worker_number, worker_name,
+ test_input, test_types, test_args):
+ """
+ Args:
+ port: object implementing port-specific hooks
+ options: command line argument object from optparse
+ worker_number: worker number for tests
+ worker_name: for logging
+ test_input: Object containing the test filename and timeout
+ test_types: A list of TestType objects to run the test output
+ against.
+ test_args: A TestArguments object to pass to each TestType.
+ """
+
+ threading.Thread.__init__(self)
+ self._port = port
+ self._options = options
+ self._test_input = test_input
+ self._test_types = test_types
+ self._test_args = test_args
+ self._driver = None
+ self._worker_number = worker_number
+ self._name = worker_name
+
+ def run(self):
+ self._covered_run()
+
+ def _covered_run(self):
+ # FIXME: this is a separate routine to work around a bug
+ # in coverage: see http://bitbucket.org/ned/coveragepy/issue/85.
+ self._driver = self._port.create_driver(self._worker_number)
+ self._driver.start()
+ self._test_result = _run_single_test(self._port, self._options,
+ self._test_input, self._test_types,
+ self._test_args, self._driver,
+ self._name)
+ self._driver.stop()
+
+ def get_test_result(self):
+ return self._test_result
+
+
+class WatchableThread(threading.Thread):
+ """This class abstracts an interface used by
+ run_webkit_tests.TestRunner._wait_for_threads_to_finish for thread
+ management."""
+ def __init__(self):
+ threading.Thread.__init__(self)
+ self._canceled = False
+ self._exception_info = None
+ self._next_timeout = None
+ self._thread_id = None
+
+ def cancel(self):
+ """Set a flag telling this thread to quit."""
+ self._canceled = True
+
+ def clear_next_timeout(self):
+ """Mark a flag telling this thread to stop setting timeouts."""
+ self._timeout = 0
+
+ def exception_info(self):
+ """If run() terminated on an uncaught exception, return it here
+ ((type, value, traceback) tuple).
+ Returns None if run() terminated normally. Meant to be called after
+ joining this thread."""
+ return self._exception_info
+
+ def id(self):
+ """Return a thread identifier."""
+ return self._thread_id
+
+ def next_timeout(self):
+ """Return the time the test is supposed to finish by."""
+ return self._next_timeout
+
+
+class TestShellThread(WatchableThread):
+ def __init__(self, port, options, worker_number, worker_name,
+ filename_list_queue, result_queue):
+ """Initialize all the local state for this DumpRenderTree thread.
+
+ Args:
+ port: interface to port-specific hooks
+ options: command line options argument from optparse
+ worker_number: identifier for a particular worker thread.
+ worker_name: for logging.
+ filename_list_queue: A thread safe Queue class that contains lists
+ of tuples of (filename, uri) pairs.
+ result_queue: A thread safe Queue class that will contain
+ serialized TestResult objects.
+ """
+ WatchableThread.__init__(self)
+ self._port = port
+ self._options = options
+ self._worker_number = worker_number
+ self._name = worker_name
+ self._filename_list_queue = filename_list_queue
+ self._result_queue = result_queue
+ self._filename_list = []
+ self._driver = None
+ self._test_group_timing_stats = {}
+ self._test_results = []
+ self._num_tests = 0
+ self._start_time = 0
+ self._stop_time = 0
+ self._have_http_lock = False
+ self._http_lock_wait_begin = 0
+ self._http_lock_wait_end = 0
+
+ self._test_types = []
+ for cls in self._get_test_type_classes():
+ self._test_types.append(cls(self._port,
+ self._options.results_directory))
+ self._test_args = self._get_test_args(worker_number)
+
+ # Current group of tests we're running.
+ self._current_group = None
+ # Number of tests in self._current_group.
+ self._num_tests_in_current_group = None
+ # Time at which we started running tests from self._current_group.
+ self._current_group_start_time = None
+
+ def _get_test_args(self, worker_number):
+ """Returns the tuple of arguments for tests and for DumpRenderTree."""
+ test_args = test_type_base.TestArguments()
+ test_args.new_baseline = self._options.new_baseline
+ test_args.reset_results = self._options.reset_results
+
+ return test_args
+
+ def _get_test_type_classes(self):
+ classes = [text_diff.TestTextDiff]
+ if self._options.pixel_tests:
+ classes.append(image_diff.ImageDiff)
+ return classes
+
+ def get_test_group_timing_stats(self):
+ """Returns a dictionary mapping test group to a tuple of
+ (number of tests in that group, time to run the tests)"""
+ return self._test_group_timing_stats
+
+ def get_test_results(self):
+ """Return the list of all tests run on this thread.
+
+ This is used to calculate per-thread statistics.
+
+ """
+ return self._test_results
+
+ def get_total_time(self):
+ return max(self._stop_time - self._start_time -
+ self._http_lock_wait_time(), 0.0)
+
+ def get_num_tests(self):
+ return self._num_tests
+
+ def run(self):
+ """Delegate main work to a helper method and watch for uncaught
+ exceptions."""
+ self._covered_run()
+
+ def _covered_run(self):
+ # FIXME: this is a separate routine to work around a bug
+ # in coverage: see http://bitbucket.org/ned/coveragepy/issue/85.
+ self._thread_id = thread.get_ident()
+ self._start_time = time.time()
+ self._num_tests = 0
+ try:
+ _log.debug('%s starting' % (self.getName()))
+ self._run(test_runner=None, result_summary=None)
+ _log.debug('%s done (%d tests)' % (self.getName(),
+ self.get_num_tests()))
+ except KeyboardInterrupt:
+ self._exception_info = sys.exc_info()
+ _log.debug("%s interrupted" % self.getName())
+ except:
+ # Save the exception for our caller to see.
+ self._exception_info = sys.exc_info()
+ self._stop_time = time.time()
+ _log.error('%s dying, exception raised' % self.getName())
+
+ self._stop_time = time.time()
+
+ def run_in_main_thread(self, test_runner, result_summary):
+ """This hook allows us to run the tests from the main thread if
+ --num-test-shells==1, instead of having to always run two or more
+ threads. This allows us to debug the test harness without having to
+ do multi-threaded debugging."""
+ self._run(test_runner, result_summary)
+
+ def cancel(self):
+ """Clean up http lock and set a flag telling this thread to quit."""
+ self._stop_servers_with_lock()
+ WatchableThread.cancel(self)
+
+ def next_timeout(self):
+ """Return the time the test is supposed to finish by."""
+ if self._next_timeout:
+ return self._next_timeout + self._http_lock_wait_time()
+ return self._next_timeout
+
+ def _http_lock_wait_time(self):
+ """Return the time what http locking takes."""
+ if self._http_lock_wait_begin == 0:
+ return 0
+ if self._http_lock_wait_end == 0:
+ return time.time() - self._http_lock_wait_begin
+ return self._http_lock_wait_end - self._http_lock_wait_begin
+
+ def _run(self, test_runner, result_summary):
+ """Main work entry point of the thread. Basically we pull urls from the
+ filename queue and run the tests until we run out of urls.
+
+ If test_runner is not None, then we call test_runner.UpdateSummary()
+ with the results of each test."""
+ batch_size = self._options.batch_size
+ batch_count = 0
+
+ # Append tests we're running to the existing tests_run.txt file.
+ # This is created in run_webkit_tests.py:_PrepareListsAndPrintOutput.
+ tests_run_filename = os.path.join(self._options.results_directory,
+ "tests_run.txt")
+ tests_run_file = codecs.open(tests_run_filename, "a", "utf-8")
+
+ while True:
+ if self._canceled:
+ _log.debug('Testing cancelled')
+ tests_run_file.close()
+ return
+
+ if len(self._filename_list) is 0:
+ if self._current_group is not None:
+ self._test_group_timing_stats[self._current_group] = \
+ (self._num_tests_in_current_group,
+ time.time() - self._current_group_start_time)
+
+ try:
+ self._current_group, self._filename_list = \
+ self._filename_list_queue.get_nowait()
+ except Queue.Empty:
+ self._stop_servers_with_lock()
+ self._kill_dump_render_tree()
+ tests_run_file.close()
+ return
+
+ if self._current_group == "tests_to_http_lock":
+ self._start_servers_with_lock()
+ elif self._have_http_lock:
+ self._stop_servers_with_lock()
+
+ self._num_tests_in_current_group = len(self._filename_list)
+ self._current_group_start_time = time.time()
+
+ test_input = self._filename_list.pop()
+
+ # We have a url, run tests.
+ batch_count += 1
+ self._num_tests += 1
+ if self._options.run_singly:
+ result = self._run_test_in_another_thread(test_input)
+ else:
+ result = self._run_test_in_this_thread(test_input)
+
+ filename = test_input.filename
+ tests_run_file.write(filename + "\n")
+ if result.failures:
+ # Check and kill DumpRenderTree if we need to.
+ if len([1 for f in result.failures
+ if f.should_kill_dump_render_tree()]):
+ self._kill_dump_render_tree()
+ # Reset the batch count since the shell just bounced.
+ batch_count = 0
+ # Print the error message(s).
+ error_str = '\n'.join([' ' + f.message() for
+ f in result.failures])
+ _log.debug("%s %s failed:\n%s" % (self.getName(),
+ self._port.relative_test_filename(filename),
+ error_str))
+ else:
+ _log.debug("%s %s passed" % (self.getName(),
+ self._port.relative_test_filename(filename)))
+ self._result_queue.put(result.dumps())
+
+ if batch_size > 0 and batch_count >= batch_size:
+ # Bounce the shell and reset count.
+ self._kill_dump_render_tree()
+ batch_count = 0
+
+ if test_runner:
+ test_runner.update_summary(result_summary)
+
+ def _run_test_in_another_thread(self, test_input):
+ """Run a test in a separate thread, enforcing a hard time limit.
+
+ Since we can only detect the termination of a thread, not any internal
+ state or progress, we can only run per-test timeouts when running test
+ files singly.
+
+ Args:
+ test_input: Object containing the test filename and timeout
+
+ Returns:
+ A TestResult
+ """
+ worker = SingleTestThread(self._port,
+ self._options,
+ self._worker_number,
+ self._name,
+ test_input,
+ self._test_types,
+ self._test_args)
+
+ worker.start()
+
+ thread_timeout = _milliseconds_to_seconds(
+ _pad_timeout(int(test_input.timeout)))
+ thread._next_timeout = time.time() + thread_timeout
+ worker.join(thread_timeout)
+ if worker.isAlive():
+ # If join() returned with the thread still running, the
+ # DumpRenderTree is completely hung and there's nothing
+ # more we can do with it. We have to kill all the
+ # DumpRenderTrees to free it up. If we're running more than
+ # one DumpRenderTree thread, we'll end up killing the other
+ # DumpRenderTrees too, introducing spurious crashes. We accept
+ # that tradeoff in order to avoid losing the rest of this
+ # thread's results.
+ _log.error('Test thread hung: killing all DumpRenderTrees')
+ if worker._driver:
+ worker._driver.stop()
+
+ try:
+ result = worker.get_test_result()
+ except AttributeError, e:
+ # This gets raised if the worker thread has already exited.
+ failures = []
+ _log.error('Cannot get results of test: %s' %
+ test_input.filename)
+ result = test_results.TestResult(test_input.filename, failures=[],
+ test_run_time=0, total_time_for_all_diffs=0, time_for_diffs={})
+
+ return result
+
+ def _run_test_in_this_thread(self, test_input):
+ """Run a single test file using a shared DumpRenderTree process.
+
+ Args:
+ test_input: Object containing the test filename, uri and timeout
+
+ Returns: a TestResult object.
+ """
+ self._ensure_dump_render_tree_is_running()
+ thread_timeout = _milliseconds_to_seconds(
+ _pad_timeout(int(test_input.timeout)))
+ self._next_timeout = time.time() + thread_timeout
+ test_result = _run_single_test(self._port, self._options, test_input,
+ self._test_types, self._test_args,
+ self._driver, self._name)
+ self._test_results.append(test_result)
+ return test_result
+
+ def _ensure_dump_render_tree_is_running(self):
+ """Start the shared DumpRenderTree, if it's not running.
+
+ This is not for use when running tests singly, since those each start
+ a separate DumpRenderTree in their own thread.
+
+ """
+ # poll() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ if not self._driver or self._driver.poll() is not None:
+ self._driver = self._port.create_driver(self._worker_number)
+ self._driver.start()
+
+ def _start_servers_with_lock(self):
+ """Acquire http lock and start the servers."""
+ self._http_lock_wait_begin = time.time()
+ _log.debug('Acquire http lock ...')
+ self._port.acquire_http_lock()
+ _log.debug('Starting HTTP server ...')
+ self._port.start_http_server()
+ _log.debug('Starting WebSocket server ...')
+ self._port.start_websocket_server()
+ self._http_lock_wait_end = time.time()
+ self._have_http_lock = True
+
+ def _stop_servers_with_lock(self):
+ """Stop the servers and release http lock."""
+ if self._have_http_lock:
+ _log.debug('Stopping HTTP server ...')
+ self._port.stop_http_server()
+ _log.debug('Stopping WebSocket server ...')
+ self._port.stop_websocket_server()
+ _log.debug('Release http lock ...')
+ self._port.release_http_lock()
+ self._have_http_lock = False
+
+ def _kill_dump_render_tree(self):
+ """Kill the DumpRenderTree process if it's running."""
+ if self._driver:
+ self._driver.stop()
+ self._driver = None
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py
new file mode 100644
index 0000000..b054c5b
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_layout_results_generator.py
@@ -0,0 +1,212 @@
+# 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 logging
+import os
+
+from webkitpy.layout_tests.layout_package import json_results_generator
+from webkitpy.layout_tests.layout_package import test_expectations
+from webkitpy.layout_tests.layout_package import test_failures
+import webkitpy.thirdparty.simplejson as simplejson
+
+
+class JSONLayoutResultsGenerator(json_results_generator.JSONResultsGeneratorBase):
+ """A JSON results generator for layout tests."""
+
+ LAYOUT_TESTS_PATH = "LayoutTests"
+
+ # Additional JSON fields.
+ WONTFIX = "wontfixCounts"
+
+ # Note that we omit test_expectations.FAIL from this list because
+ # it should never show up (it's a legacy input expectation, never
+ # an output expectation).
+ FAILURE_TO_CHAR = {test_expectations.CRASH: "C",
+ test_expectations.TIMEOUT: "T",
+ test_expectations.IMAGE: "I",
+ test_expectations.TEXT: "F",
+ test_expectations.MISSING: "O",
+ test_expectations.IMAGE_PLUS_TEXT: "Z"}
+
+ def __init__(self, port, builder_name, build_name, build_number,
+ results_file_base_path, builder_base_url,
+ test_timings, expectations, result_summary, all_tests,
+ generate_incremental_results=False, test_results_server=None,
+ test_type="", master_name=""):
+ """Modifies the results.json file. Grabs it off the archive directory
+ if it is not found locally.
+
+ Args:
+ result_summary: ResultsSummary object storing the summary of the test
+ results.
+ """
+ super(JSONLayoutResultsGenerator, self).__init__(
+ builder_name, build_name, build_number, results_file_base_path,
+ builder_base_url, {}, port.test_repository_paths(),
+ generate_incremental_results, test_results_server,
+ test_type, master_name)
+
+ self._port = port
+ self._expectations = expectations
+
+ # We want relative paths to LayoutTest root for JSON output.
+ path_to_name = self._get_path_relative_to_layout_test_root
+ self._result_summary = result_summary
+ self._failures = dict(
+ (path_to_name(test), test_failures.determine_result_type(failures))
+ for (test, failures) in result_summary.failures.iteritems())
+ self._all_tests = [path_to_name(test) for test in all_tests]
+ self._test_timings = dict(
+ (path_to_name(test_tuple.filename), test_tuple.test_run_time)
+ for test_tuple in test_timings)
+
+ self.generate_json_output()
+
+ def _get_path_relative_to_layout_test_root(self, test):
+ """Returns the path of the test relative to the layout test root.
+ For example, for:
+ src/third_party/WebKit/LayoutTests/fast/forms/foo.html
+ We would return
+ fast/forms/foo.html
+ """
+ index = test.find(self.LAYOUT_TESTS_PATH)
+ if index is not -1:
+ index += len(self.LAYOUT_TESTS_PATH)
+
+ if index is -1:
+ # Already a relative path.
+ relativePath = test
+ else:
+ relativePath = test[index + 1:]
+
+ # Make sure all paths are unix-style.
+ return relativePath.replace('\\', '/')
+
+ # override
+ def _get_test_timing(self, test_name):
+ if test_name in self._test_timings:
+ # Floor for now to get time in seconds.
+ return int(self._test_timings[test_name])
+ return 0
+
+ # override
+ def _get_failed_test_names(self):
+ return set(self._failures.keys())
+
+ # override
+ def _get_modifier_char(self, test_name):
+ if test_name not in self._all_tests:
+ return self.NO_DATA_RESULT
+
+ if test_name in self._failures:
+ return self.FAILURE_TO_CHAR[self._failures[test_name]]
+
+ return self.PASS_RESULT
+
+ # override
+ def _get_result_char(self, test_name):
+ return self._get_modifier_char(test_name)
+
+ # override
+ def _convert_json_to_current_version(self, results_json):
+ archive_version = None
+ if self.VERSION_KEY in results_json:
+ archive_version = results_json[self.VERSION_KEY]
+
+ super(JSONLayoutResultsGenerator,
+ self)._convert_json_to_current_version(results_json)
+
+ # version 2->3
+ if archive_version == 2:
+ for results_for_builder in results_json.itervalues():
+ try:
+ test_results = results_for_builder[self.TESTS]
+ except:
+ continue
+
+ for test in test_results:
+ # Make sure all paths are relative
+ test_path = self._get_path_relative_to_layout_test_root(test)
+ if test_path != test:
+ test_results[test_path] = test_results[test]
+ del test_results[test]
+
+ # override
+ def _insert_failure_summaries(self, results_for_builder):
+ summary = self._result_summary
+
+ self._insert_item_into_raw_list(results_for_builder,
+ len((set(summary.failures.keys()) |
+ summary.tests_by_expectation[test_expectations.SKIP]) &
+ summary.tests_by_timeline[test_expectations.NOW]),
+ self.FIXABLE_COUNT)
+ self._insert_item_into_raw_list(results_for_builder,
+ self._get_failure_summary_entry(test_expectations.NOW),
+ self.FIXABLE)
+ self._insert_item_into_raw_list(results_for_builder,
+ len(self._expectations.get_tests_with_timeline(
+ test_expectations.NOW)), self.ALL_FIXABLE_COUNT)
+ self._insert_item_into_raw_list(results_for_builder,
+ self._get_failure_summary_entry(test_expectations.WONTFIX),
+ self.WONTFIX)
+
+ # override
+ def _normalize_results_json(self, test, test_name, tests):
+ super(JSONLayoutResultsGenerator, self)._normalize_results_json(
+ test, test_name, tests)
+
+ # Remove tests that don't exist anymore.
+ full_path = os.path.join(self._port.layout_tests_dir(), test_name)
+ full_path = os.path.normpath(full_path)
+ if not os.path.exists(full_path):
+ del tests[test_name]
+
+ def _get_failure_summary_entry(self, timeline):
+ """Creates a summary object to insert into the JSON.
+
+ Args:
+ summary ResultSummary object with test results
+ timeline current test_expectations timeline to build entry for
+ (e.g., test_expectations.NOW, etc.)
+ """
+ entry = {}
+ summary = self._result_summary
+ timeline_tests = summary.tests_by_timeline[timeline]
+ entry[self.SKIP_RESULT] = len(
+ summary.tests_by_expectation[test_expectations.SKIP] &
+ timeline_tests)
+ entry[self.PASS_RESULT] = len(
+ summary.tests_by_expectation[test_expectations.PASS] &
+ timeline_tests)
+ for failure_type in summary.tests_by_expectation.keys():
+ if failure_type not in self.FAILURE_TO_CHAR:
+ continue
+ count = len(summary.tests_by_expectation[failure_type] &
+ timeline_tests)
+ entry[self.FAILURE_TO_CHAR[failure_type]] = count
+ return entry
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py
new file mode 100644
index 0000000..54d129b
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator.py
@@ -0,0 +1,598 @@
+# 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.
+
+from __future__ import with_statement
+
+import codecs
+import logging
+import os
+import subprocess
+import sys
+import time
+import urllib2
+import xml.dom.minidom
+
+from webkitpy.layout_tests.layout_package import test_results_uploader
+
+import webkitpy.thirdparty.simplejson as simplejson
+
+# A JSON results generator for generic tests.
+# FIXME: move this code out of the layout_package directory.
+
+_log = logging.getLogger("webkitpy.layout_tests.layout_package.json_results_generator")
+
+class TestResult(object):
+ """A simple class that represents a single test result."""
+
+ # Test modifier constants.
+ (NONE, FAILS, FLAKY, DISABLED) = range(4)
+
+ def __init__(self, name, failed=False, elapsed_time=0):
+ self.name = name
+ self.failed = failed
+ self.time = elapsed_time
+
+ test_name = name
+ try:
+ test_name = name.split('.')[1]
+ except IndexError:
+ _log.warn("Invalid test name: %s.", name)
+ pass
+
+ if test_name.startswith('FAILS_'):
+ self.modifier = self.FAILS
+ elif test_name.startswith('FLAKY_'):
+ self.modifier = self.FLAKY
+ elif test_name.startswith('DISABLED_'):
+ self.modifier = self.DISABLED
+ else:
+ self.modifier = self.NONE
+
+ def fixable(self):
+ return self.failed or self.modifier == self.DISABLED
+
+
+class JSONResultsGeneratorBase(object):
+ """A JSON results generator for generic tests."""
+
+ MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG = 750
+ # Min time (seconds) that will be added to the JSON.
+ MIN_TIME = 1
+ JSON_PREFIX = "ADD_RESULTS("
+ JSON_SUFFIX = ");"
+
+ # Note that in non-chromium tests those chars are used to indicate
+ # test modifiers (FAILS, FLAKY, etc) but not actual test results.
+ PASS_RESULT = "P"
+ SKIP_RESULT = "X"
+ FAIL_RESULT = "F"
+ FLAKY_RESULT = "L"
+ NO_DATA_RESULT = "N"
+
+ MODIFIER_TO_CHAR = {TestResult.NONE: PASS_RESULT,
+ TestResult.DISABLED: SKIP_RESULT,
+ TestResult.FAILS: FAIL_RESULT,
+ TestResult.FLAKY: FLAKY_RESULT}
+
+ VERSION = 3
+ VERSION_KEY = "version"
+ RESULTS = "results"
+ TIMES = "times"
+ BUILD_NUMBERS = "buildNumbers"
+ TIME = "secondsSinceEpoch"
+ TESTS = "tests"
+
+ FIXABLE_COUNT = "fixableCount"
+ FIXABLE = "fixableCounts"
+ ALL_FIXABLE_COUNT = "allFixableCount"
+
+ RESULTS_FILENAME = "results.json"
+ INCREMENTAL_RESULTS_FILENAME = "incremental_results.json"
+
+ URL_FOR_TEST_LIST_JSON = \
+ "http://%s/testfile?builder=%s&name=%s&testlistjson=1&testtype=%s"
+
+ def __init__(self, builder_name, build_name, build_number,
+ results_file_base_path, builder_base_url,
+ test_results_map, svn_repositories=None,
+ generate_incremental_results=False,
+ test_results_server=None,
+ test_type="",
+ master_name=""):
+ """Modifies the results.json file. Grabs it off the archive directory
+ if it is not found locally.
+
+ Args
+ builder_name: the builder name (e.g. Webkit).
+ build_name: the build name (e.g. webkit-rel).
+ build_number: the build number.
+ results_file_base_path: Absolute path to the directory containing the
+ results json file.
+ builder_base_url: the URL where we have the archived test results.
+ If this is None no archived results will be retrieved.
+ test_results_map: A dictionary that maps test_name to TestResult.
+ svn_repositories: A (json_field_name, svn_path) pair for SVN
+ repositories that tests rely on. The SVN revision will be
+ included in the JSON with the given json_field_name.
+ generate_incremental_results: If true, generate incremental json file
+ from current run results.
+ test_results_server: server that hosts test results json.
+ test_type: test type string (e.g. 'layout-tests').
+ master_name: the name of the buildbot master.
+ """
+ self._builder_name = builder_name
+ self._build_name = build_name
+ self._build_number = build_number
+ self._builder_base_url = builder_base_url
+ self._results_directory = results_file_base_path
+ self._results_file_path = os.path.join(results_file_base_path,
+ self.RESULTS_FILENAME)
+ self._incremental_results_file_path = os.path.join(
+ results_file_base_path, self.INCREMENTAL_RESULTS_FILENAME)
+
+ self._test_results_map = test_results_map
+ self._test_results = test_results_map.values()
+ self._generate_incremental_results = generate_incremental_results
+
+ self._svn_repositories = svn_repositories
+ if not self._svn_repositories:
+ self._svn_repositories = {}
+
+ self._test_results_server = test_results_server
+ self._test_type = test_type
+ self._master_name = master_name
+
+ self._json = None
+ self._archived_results = None
+
+ def generate_json_output(self):
+ """Generates the JSON output file."""
+
+ # Generate the JSON output file that has full results.
+ # FIXME: stop writing out the full results file once all bots use
+ # incremental results.
+ if not self._json:
+ self._json = self.get_json()
+ if self._json:
+ self._generate_json_file(self._json, self._results_file_path)
+
+ # Generate the JSON output file that only has incremental results.
+ if self._generate_incremental_results:
+ json = self.get_json(incremental=True)
+ if json:
+ self._generate_json_file(
+ json, self._incremental_results_file_path)
+
+ def get_json(self, incremental=False):
+ """Gets the results for the results.json file."""
+ results_json = {}
+ if not incremental:
+ if self._json:
+ return self._json
+
+ if self._archived_results:
+ results_json = self._archived_results
+
+ if not results_json:
+ results_json, error = self._get_archived_json_results(incremental)
+ if error:
+ # If there was an error don't write a results.json
+ # file at all as it would lose all the information on the
+ # bot.
+ _log.error("Archive directory is inaccessible. Not "
+ "modifying or clobbering the results.json "
+ "file: " + str(error))
+ return None
+
+ builder_name = self._builder_name
+ if results_json and builder_name not in results_json:
+ _log.debug("Builder name (%s) is not in the results.json file."
+ % builder_name)
+
+ self._convert_json_to_current_version(results_json)
+
+ if builder_name not in results_json:
+ results_json[builder_name] = (
+ self._create_results_for_builder_json())
+
+ results_for_builder = results_json[builder_name]
+
+ self._insert_generic_metadata(results_for_builder)
+
+ self._insert_failure_summaries(results_for_builder)
+
+ # Update the all failing tests with result type and time.
+ tests = results_for_builder[self.TESTS]
+ all_failing_tests = self._get_failed_test_names()
+ all_failing_tests.update(tests.iterkeys())
+ for test in all_failing_tests:
+ self._insert_test_time_and_result(test, tests, incremental)
+
+ return results_json
+
+ def set_archived_results(self, archived_results):
+ self._archived_results = archived_results
+
+ def upload_json_files(self, json_files):
+ """Uploads the given json_files to the test_results_server (if the
+ test_results_server is given)."""
+ if not self._test_results_server:
+ return
+
+ if not self._master_name:
+ _log.error("--test-results-server was set, but --master-name was not. Not uploading JSON files.")
+ return
+
+ _log.info("Uploading JSON files for builder: %s", self._builder_name)
+ attrs = [("builder", self._builder_name),
+ ("testtype", self._test_type),
+ ("master", self._master_name)]
+
+ files = [(file, os.path.join(self._results_directory, file))
+ for file in json_files]
+
+ uploader = test_results_uploader.TestResultsUploader(
+ self._test_results_server)
+ try:
+ # Set uploading timeout in case appengine server is having problem.
+ # 120 seconds are more than enough to upload test results.
+ uploader.upload(attrs, files, 120)
+ except Exception, err:
+ _log.error("Upload failed: %s" % err)
+ return
+
+ _log.info("JSON files uploaded.")
+
+ def _generate_json_file(self, json, file_path):
+ # Specify separators in order to get compact encoding.
+ json_data = simplejson.dumps(json, separators=(',', ':'))
+ json_string = self.JSON_PREFIX + json_data + self.JSON_SUFFIX
+
+ results_file = codecs.open(file_path, "w", "utf-8")
+ results_file.write(json_string)
+ results_file.close()
+
+ def _get_test_timing(self, test_name):
+ """Returns test timing data (elapsed time) in second
+ for the given test_name."""
+ if test_name in self._test_results_map:
+ # Floor for now to get time in seconds.
+ return int(self._test_results_map[test_name].time)
+ return 0
+
+ def _get_failed_test_names(self):
+ """Returns a set of failed test names."""
+ return set([r.name for r in self._test_results if r.failed])
+
+ def _get_modifier_char(self, test_name):
+ """Returns a single char (e.g. SKIP_RESULT, FAIL_RESULT,
+ PASS_RESULT, NO_DATA_RESULT, etc) that indicates the test modifier
+ for the given test_name.
+ """
+ if test_name not in self._test_results_map:
+ return self.__class__.NO_DATA_RESULT
+
+ test_result = self._test_results_map[test_name]
+ if test_result.modifier in self.MODIFIER_TO_CHAR.keys():
+ return self.MODIFIER_TO_CHAR[test_result.modifier]
+
+ return self.__class__.PASS_RESULT
+
+ def _get_result_char(self, test_name):
+ """Returns a single char (e.g. SKIP_RESULT, FAIL_RESULT,
+ PASS_RESULT, NO_DATA_RESULT, etc) that indicates the test result
+ for the given test_name.
+ """
+ if test_name not in self._test_results_map:
+ return self.__class__.NO_DATA_RESULT
+
+ test_result = self._test_results_map[test_name]
+ if test_result.modifier == TestResult.DISABLED:
+ return self.__class__.SKIP_RESULT
+
+ if test_result.failed:
+ return self.__class__.FAIL_RESULT
+
+ return self.__class__.PASS_RESULT
+
+ # FIXME: Callers should use scm.py instead.
+ # FIXME: Identify and fix the run-time errors that were observed on Windows
+ # chromium buildbot when we had updated this code to use scm.py once before.
+ def _get_svn_revision(self, in_directory):
+ """Returns the svn revision for the given directory.
+
+ Args:
+ in_directory: The directory where svn is to be run.
+ """
+ if os.path.exists(os.path.join(in_directory, '.svn')):
+ # Note: Not thread safe: http://bugs.python.org/issue2320
+ output = subprocess.Popen(["svn", "info", "--xml"],
+ cwd=in_directory,
+ shell=(sys.platform == 'win32'),
+ stdout=subprocess.PIPE).communicate()[0]
+ try:
+ dom = xml.dom.minidom.parseString(output)
+ return dom.getElementsByTagName('entry')[0].getAttribute(
+ 'revision')
+ except xml.parsers.expat.ExpatError:
+ return ""
+ return ""
+
+ def _get_archived_json_results(self, for_incremental=False):
+ """Reads old results JSON file if it exists.
+ Returns (archived_results, error) tuple where error is None if results
+ were successfully read.
+
+ if for_incremental is True, download JSON file that only contains test
+ name list from test-results server. This is for generating incremental
+ JSON so the file generated has info for tests that failed before but
+ pass or are skipped from current run.
+ """
+ results_json = {}
+ old_results = None
+ error = None
+
+ if os.path.exists(self._results_file_path) and not for_incremental:
+ with codecs.open(self._results_file_path, "r", "utf-8") as file:
+ old_results = file.read()
+ elif self._builder_base_url or for_incremental:
+ if for_incremental:
+ if not self._test_results_server:
+ # starting from fresh if no test results server specified.
+ return {}, None
+
+ results_file_url = (self.URL_FOR_TEST_LIST_JSON %
+ (urllib2.quote(self._test_results_server),
+ urllib2.quote(self._builder_name),
+ self.RESULTS_FILENAME,
+ urllib2.quote(self._test_type)))
+ else:
+ # Check if we have the archived JSON file on the buildbot
+ # server.
+ results_file_url = (self._builder_base_url +
+ self._build_name + "/" + self.RESULTS_FILENAME)
+ _log.error("Local results.json file does not exist. Grabbing "
+ "it off the archive at " + results_file_url)
+
+ try:
+ results_file = urllib2.urlopen(results_file_url)
+ info = results_file.info()
+ old_results = results_file.read()
+ except urllib2.HTTPError, http_error:
+ # A non-4xx status code means the bot is hosed for some reason
+ # and we can't grab the results.json file off of it.
+ if (http_error.code < 400 and http_error.code >= 500):
+ error = http_error
+ except urllib2.URLError, url_error:
+ error = url_error
+
+ if old_results:
+ # Strip the prefix and suffix so we can get the actual JSON object.
+ old_results = old_results[len(self.JSON_PREFIX):
+ len(old_results) - len(self.JSON_SUFFIX)]
+
+ try:
+ results_json = simplejson.loads(old_results)
+ except:
+ _log.debug("results.json was not valid JSON. Clobbering.")
+ # The JSON file is not valid JSON. Just clobber the results.
+ results_json = {}
+ else:
+ _log.debug('Old JSON results do not exist. Starting fresh.')
+ results_json = {}
+
+ return results_json, error
+
+ def _insert_failure_summaries(self, results_for_builder):
+ """Inserts aggregate pass/failure statistics into the JSON.
+ This method reads self._test_results and generates
+ FIXABLE, FIXABLE_COUNT and ALL_FIXABLE_COUNT entries.
+
+ Args:
+ results_for_builder: Dictionary containing the test results for a
+ single builder.
+ """
+ # Insert the number of tests that failed or skipped.
+ fixable_count = len([r for r in self._test_results if r.fixable()])
+ self._insert_item_into_raw_list(results_for_builder,
+ fixable_count, self.FIXABLE_COUNT)
+
+ # Create a test modifiers (FAILS, FLAKY etc) summary dictionary.
+ entry = {}
+ for test_name in self._test_results_map.iterkeys():
+ result_char = self._get_modifier_char(test_name)
+ entry[result_char] = entry.get(result_char, 0) + 1
+
+ # Insert the pass/skip/failure summary dictionary.
+ self._insert_item_into_raw_list(results_for_builder, entry,
+ self.FIXABLE)
+
+ # Insert the number of all the tests that are supposed to pass.
+ all_test_count = len(self._test_results)
+ self._insert_item_into_raw_list(results_for_builder,
+ all_test_count, self.ALL_FIXABLE_COUNT)
+
+ def _insert_item_into_raw_list(self, results_for_builder, item, key):
+ """Inserts the item into the list with the given key in the results for
+ this builder. Creates the list if no such list exists.
+
+ Args:
+ results_for_builder: Dictionary containing the test results for a
+ single builder.
+ item: Number or string to insert into the list.
+ key: Key in results_for_builder for the list to insert into.
+ """
+ if key in results_for_builder:
+ raw_list = results_for_builder[key]
+ else:
+ raw_list = []
+
+ raw_list.insert(0, item)
+ raw_list = raw_list[:self.MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG]
+ results_for_builder[key] = raw_list
+
+ def _insert_item_run_length_encoded(self, item, encoded_results):
+ """Inserts the item into the run-length encoded results.
+
+ Args:
+ item: String or number to insert.
+ encoded_results: run-length encoded results. An array of arrays, e.g.
+ [[3,'A'],[1,'Q']] encodes AAAQ.
+ """
+ if len(encoded_results) and item == encoded_results[0][1]:
+ num_results = encoded_results[0][0]
+ if num_results <= self.MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG:
+ encoded_results[0][0] = num_results + 1
+ else:
+ # Use a list instead of a class for the run-length encoding since
+ # we want the serialized form to be concise.
+ encoded_results.insert(0, [1, item])
+
+ def _insert_generic_metadata(self, results_for_builder):
+ """ Inserts generic metadata (such as version number, current time etc)
+ into the JSON.
+
+ Args:
+ results_for_builder: Dictionary containing the test results for
+ a single builder.
+ """
+ self._insert_item_into_raw_list(results_for_builder,
+ self._build_number, self.BUILD_NUMBERS)
+
+ # Include SVN revisions for the given repositories.
+ for (name, path) in self._svn_repositories:
+ self._insert_item_into_raw_list(results_for_builder,
+ self._get_svn_revision(path),
+ name + 'Revision')
+
+ self._insert_item_into_raw_list(results_for_builder,
+ int(time.time()),
+ self.TIME)
+
+ def _insert_test_time_and_result(self, test_name, tests, incremental=False):
+ """ Insert a test item with its results to the given tests dictionary.
+
+ Args:
+ tests: Dictionary containing test result entries.
+ """
+
+ result = self._get_result_char(test_name)
+ time = self._get_test_timing(test_name)
+
+ if test_name not in tests:
+ tests[test_name] = self._create_results_and_times_json()
+
+ thisTest = tests[test_name]
+ if self.RESULTS in thisTest:
+ self._insert_item_run_length_encoded(result, thisTest[self.RESULTS])
+ else:
+ thisTest[self.RESULTS] = [[1, result]]
+
+ if self.TIMES in thisTest:
+ self._insert_item_run_length_encoded(time, thisTest[self.TIMES])
+ else:
+ thisTest[self.TIMES] = [[1, time]]
+
+ # Don't normalize the incremental results json because we need results
+ # for tests that pass or have no data from current run.
+ if not incremental:
+ self._normalize_results_json(thisTest, test_name, tests)
+
+ def _convert_json_to_current_version(self, results_json):
+ """If the JSON does not match the current version, converts it to the
+ current version and adds in the new version number.
+ """
+ if (self.VERSION_KEY in results_json and
+ results_json[self.VERSION_KEY] == self.VERSION):
+ return
+
+ results_json[self.VERSION_KEY] = self.VERSION
+
+ def _create_results_and_times_json(self):
+ results_and_times = {}
+ results_and_times[self.RESULTS] = []
+ results_and_times[self.TIMES] = []
+ return results_and_times
+
+ def _create_results_for_builder_json(self):
+ results_for_builder = {}
+ results_for_builder[self.TESTS] = {}
+ return results_for_builder
+
+ def _remove_items_over_max_number_of_builds(self, encoded_list):
+ """Removes items from the run-length encoded list after the final
+ item that exceeds the max number of builds to track.
+
+ Args:
+ encoded_results: run-length encoded results. An array of arrays, e.g.
+ [[3,'A'],[1,'Q']] encodes AAAQ.
+ """
+ num_builds = 0
+ index = 0
+ for result in encoded_list:
+ num_builds = num_builds + result[0]
+ index = index + 1
+ if num_builds > self.MAX_NUMBER_OF_BUILD_RESULTS_TO_LOG:
+ return encoded_list[:index]
+ return encoded_list
+
+ def _normalize_results_json(self, test, test_name, tests):
+ """ Prune tests where all runs pass or tests that no longer exist and
+ truncate all results to maxNumberOfBuilds.
+
+ Args:
+ test: ResultsAndTimes object for this test.
+ test_name: Name of the test.
+ tests: The JSON object with all the test results for this builder.
+ """
+ test[self.RESULTS] = self._remove_items_over_max_number_of_builds(
+ test[self.RESULTS])
+ test[self.TIMES] = self._remove_items_over_max_number_of_builds(
+ test[self.TIMES])
+
+ is_all_pass = self._is_results_all_of_type(test[self.RESULTS],
+ self.PASS_RESULT)
+ is_all_no_data = self._is_results_all_of_type(test[self.RESULTS],
+ self.NO_DATA_RESULT)
+ max_time = max([time[1] for time in test[self.TIMES]])
+
+ # Remove all passes/no-data from the results to reduce noise and
+ # filesize. If a test passes every run, but takes > MIN_TIME to run,
+ # don't throw away the data.
+ if is_all_no_data or (is_all_pass and max_time <= self.MIN_TIME):
+ del tests[test_name]
+
+ def _is_results_all_of_type(self, results, type):
+ """Returns whether all the results are of the given type
+ (e.g. all passes)."""
+ return len(results) == 1 and results[0][1] == type
+
+
+# Left here not to break anything.
+class JSONResultsGenerator(JSONResultsGeneratorBase):
+ pass
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py
new file mode 100644
index 0000000..dad549a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/json_results_generator_unittest.py
@@ -0,0 +1,220 @@
+# 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.
+
+"""Unit tests for json_results_generator.py."""
+
+import unittest
+import optparse
+import random
+import shutil
+import tempfile
+
+from webkitpy.layout_tests.layout_package import json_results_generator
+from webkitpy.layout_tests.layout_package import test_expectations
+
+
+class JSONGeneratorTest(unittest.TestCase):
+ def setUp(self):
+ self.builder_name = 'DUMMY_BUILDER_NAME'
+ self.build_name = 'DUMMY_BUILD_NAME'
+ self.build_number = 'DUMMY_BUILDER_NUMBER'
+
+ # For archived results.
+ self._json = None
+ self._num_runs = 0
+ self._tests_set = set([])
+ self._test_timings = {}
+ self._failed_count_map = {}
+
+ self._PASS_count = 0
+ self._DISABLED_count = 0
+ self._FLAKY_count = 0
+ self._FAILS_count = 0
+ self._fixable_count = 0
+
+ def _test_json_generation(self, passed_tests_list, failed_tests_list):
+ tests_set = set(passed_tests_list) | set(failed_tests_list)
+
+ DISABLED_tests = set([t for t in tests_set
+ if t.startswith('DISABLED_')])
+ FLAKY_tests = set([t for t in tests_set
+ if t.startswith('FLAKY_')])
+ FAILS_tests = set([t for t in tests_set
+ if t.startswith('FAILS_')])
+ PASS_tests = tests_set - (DISABLED_tests | FLAKY_tests | FAILS_tests)
+
+ failed_tests = set(failed_tests_list) - DISABLED_tests
+ failed_count_map = dict([(t, 1) for t in failed_tests])
+
+ test_timings = {}
+ i = 0
+ for test in tests_set:
+ test_timings[test] = float(self._num_runs * 100 + i)
+ i += 1
+
+ test_results_map = dict()
+ for test in tests_set:
+ test_results_map[test] = json_results_generator.TestResult(test,
+ failed=(test in failed_tests),
+ elapsed_time=test_timings[test])
+
+ generator = json_results_generator.JSONResultsGeneratorBase(
+ self.builder_name, self.build_name, self.build_number,
+ '',
+ None, # don't fetch past json results archive
+ test_results_map)
+
+ failed_count_map = dict([(t, 1) for t in failed_tests])
+
+ # Test incremental json results
+ incremental_json = generator.get_json(incremental=True)
+ self._verify_json_results(
+ tests_set,
+ test_timings,
+ failed_count_map,
+ len(PASS_tests),
+ len(DISABLED_tests),
+ len(FLAKY_tests),
+ len(DISABLED_tests | failed_tests),
+ incremental_json,
+ 1)
+
+ # Test aggregated json results
+ generator.set_archived_results(self._json)
+ json = generator.get_json(incremental=False)
+ self._json = json
+ self._num_runs += 1
+ self._tests_set |= tests_set
+ self._test_timings.update(test_timings)
+ self._PASS_count += len(PASS_tests)
+ self._DISABLED_count += len(DISABLED_tests)
+ self._FLAKY_count += len(FLAKY_tests)
+ self._fixable_count += len(DISABLED_tests | failed_tests)
+
+ get = self._failed_count_map.get
+ for test in failed_count_map.iterkeys():
+ self._failed_count_map[test] = get(test, 0) + 1
+
+ self._verify_json_results(
+ self._tests_set,
+ self._test_timings,
+ self._failed_count_map,
+ self._PASS_count,
+ self._DISABLED_count,
+ self._FLAKY_count,
+ self._fixable_count,
+ self._json,
+ self._num_runs)
+
+ def _verify_json_results(self, tests_set, test_timings, failed_count_map,
+ PASS_count, DISABLED_count, FLAKY_count,
+ fixable_count,
+ json, num_runs):
+ # Aliasing to a short name for better access to its constants.
+ JRG = json_results_generator.JSONResultsGeneratorBase
+
+ self.assertTrue(JRG.VERSION_KEY in json)
+ self.assertTrue(self.builder_name in json)
+
+ buildinfo = json[self.builder_name]
+ self.assertTrue(JRG.FIXABLE in buildinfo)
+ self.assertTrue(JRG.TESTS in buildinfo)
+ self.assertEqual(len(buildinfo[JRG.BUILD_NUMBERS]), num_runs)
+ self.assertEqual(buildinfo[JRG.BUILD_NUMBERS][0], self.build_number)
+
+ if tests_set or DISABLED_count:
+ fixable = {}
+ for fixable_items in buildinfo[JRG.FIXABLE]:
+ for (type, count) in fixable_items.iteritems():
+ if type in fixable:
+ fixable[type] = fixable[type] + count
+ else:
+ fixable[type] = count
+
+ if PASS_count:
+ self.assertEqual(fixable[JRG.PASS_RESULT], PASS_count)
+ else:
+ self.assertTrue(JRG.PASS_RESULT not in fixable or
+ fixable[JRG.PASS_RESULT] == 0)
+ if DISABLED_count:
+ self.assertEqual(fixable[JRG.SKIP_RESULT], DISABLED_count)
+ else:
+ self.assertTrue(JRG.SKIP_RESULT not in fixable or
+ fixable[JRG.SKIP_RESULT] == 0)
+ if FLAKY_count:
+ self.assertEqual(fixable[JRG.FLAKY_RESULT], FLAKY_count)
+ else:
+ self.assertTrue(JRG.FLAKY_RESULT not in fixable or
+ fixable[JRG.FLAKY_RESULT] == 0)
+
+ if failed_count_map:
+ tests = buildinfo[JRG.TESTS]
+ for test_name in failed_count_map.iterkeys():
+ self.assertTrue(test_name in tests)
+ test = tests[test_name]
+
+ failed = 0
+ for result in test[JRG.RESULTS]:
+ if result[1] == JRG.FAIL_RESULT:
+ failed += result[0]
+ self.assertEqual(failed_count_map[test_name], failed)
+
+ timing_count = 0
+ for timings in test[JRG.TIMES]:
+ if timings[1] == test_timings[test_name]:
+ timing_count = timings[0]
+ self.assertEqual(1, timing_count)
+
+ if fixable_count:
+ self.assertEqual(sum(buildinfo[JRG.FIXABLE_COUNT]), fixable_count)
+
+ def test_json_generation(self):
+ self._test_json_generation([], [])
+ self._test_json_generation(['A1', 'B1'], [])
+ self._test_json_generation([], ['FAILS_A2', 'FAILS_B2'])
+ self._test_json_generation(['DISABLED_A3', 'DISABLED_B3'], [])
+ self._test_json_generation(['A4'], ['B4', 'FAILS_C4'])
+ self._test_json_generation(['DISABLED_C5', 'DISABLED_D5'], ['A5', 'B5'])
+ self._test_json_generation(
+ ['A6', 'B6', 'FAILS_C6', 'DISABLED_E6', 'DISABLED_F6'],
+ ['FAILS_D6'])
+
+ # Generate JSON with the same test sets. (Both incremental results and
+ # archived results must be updated appropriately.)
+ self._test_json_generation(
+ ['A', 'FLAKY_B', 'DISABLED_C'],
+ ['FAILS_D', 'FLAKY_E'])
+ self._test_json_generation(
+ ['A', 'DISABLED_C', 'FLAKY_E'],
+ ['FLAKY_B', 'FAILS_D'])
+ self._test_json_generation(
+ ['FLAKY_B', 'DISABLED_C', 'FAILS_D'],
+ ['A', 'FLAKY_E'])
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py
new file mode 100644
index 0000000..e0ca8db
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker.py
@@ -0,0 +1,197 @@
+# 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.
+
+"""Module for handling messages, threads, processes, and concurrency for run-webkit-tests.
+
+Testing is accomplished by having a manager (TestRunner) gather all of the
+tests to be run, and sending messages to a pool of workers (TestShellThreads)
+to run each test. Each worker communicates with one driver (usually
+DumpRenderTree) to run one test at a time and then compare the output against
+what we expected to get.
+
+This modules provides a message broker that connects the manager to the
+workers: it provides a messaging abstraction and message loops, and
+handles launching threads and/or processes depending on the
+requested configuration.
+"""
+
+import logging
+import sys
+import time
+import traceback
+
+import dump_render_tree_thread
+
+_log = logging.getLogger(__name__)
+
+
+def get(port, options):
+ """Return an instance of a WorkerMessageBroker."""
+ worker_model = options.worker_model
+ if worker_model == 'old-inline':
+ return InlineBroker(port, options)
+ if worker_model == 'old-threads':
+ return MultiThreadedBroker(port, options)
+ raise ValueError('unsupported value for --worker-model: %s' % worker_model)
+
+
+class _WorkerState(object):
+ def __init__(self, name):
+ self.name = name
+ self.thread = None
+
+
+class WorkerMessageBroker(object):
+ def __init__(self, port, options):
+ self._port = port
+ self._options = options
+ self._num_workers = int(self._options.child_processes)
+
+ # This maps worker names to their _WorkerState values.
+ self._workers = {}
+
+ def _threads(self):
+ return tuple([w.thread for w in self._workers.values()])
+
+ def start_workers(self, test_runner):
+ """Starts up the pool of workers for running the tests.
+
+ Args:
+ test_runner: a handle to the manager/TestRunner object
+ """
+ self._test_runner = test_runner
+ for worker_number in xrange(self._num_workers):
+ worker = _WorkerState('worker-%d' % worker_number)
+ worker.thread = self._start_worker(worker_number, worker.name)
+ self._workers[worker.name] = worker
+ return self._threads()
+
+ def _start_worker(self, worker_number, worker_name):
+ raise NotImplementedError
+
+ def run_message_loop(self):
+ """Loop processing messages until done."""
+ raise NotImplementedError
+
+ def cancel_workers(self):
+ """Cancel/interrupt any workers that are still alive."""
+ pass
+
+ def cleanup(self):
+ """Perform any necessary cleanup on shutdown."""
+ pass
+
+
+class InlineBroker(WorkerMessageBroker):
+ def _start_worker(self, worker_number, worker_name):
+ # FIXME: Replace with something that isn't a thread.
+ thread = dump_render_tree_thread.TestShellThread(self._port,
+ self._options, worker_number, worker_name,
+ self._test_runner._current_filename_queue,
+ self._test_runner._result_queue)
+ # Note: Don't start() the thread! If we did, it would actually
+ # create another thread and start executing it, and we'd no longer
+ # be single-threaded.
+ return thread
+
+ def run_message_loop(self):
+ thread = self._threads()[0]
+ thread.run_in_main_thread(self._test_runner,
+ self._test_runner._current_result_summary)
+ self._test_runner.update()
+
+
+class MultiThreadedBroker(WorkerMessageBroker):
+ def _start_worker(self, worker_number, worker_name):
+ thread = dump_render_tree_thread.TestShellThread(self._port,
+ self._options, worker_number, worker_name,
+ self._test_runner._current_filename_queue,
+ self._test_runner._result_queue)
+ thread.start()
+ return thread
+
+ def run_message_loop(self):
+ threads = self._threads()
+
+ # Loop through all the threads waiting for them to finish.
+ some_thread_is_alive = True
+ while some_thread_is_alive:
+ some_thread_is_alive = False
+ t = time.time()
+ for thread in threads:
+ exception_info = thread.exception_info()
+ if exception_info is not None:
+ # Re-raise the thread's exception here to make it
+ # clear that testing was aborted. Otherwise,
+ # the tests that did not run would be assumed
+ # to have passed.
+ raise exception_info[0], exception_info[1], exception_info[2]
+
+ if thread.isAlive():
+ some_thread_is_alive = True
+ next_timeout = thread.next_timeout()
+ if next_timeout and t > next_timeout:
+ log_wedged_worker(thread.getName(), thread.id())
+ thread.clear_next_timeout()
+
+ self._test_runner.update()
+
+ if some_thread_is_alive:
+ time.sleep(0.01)
+
+ def cancel_workers(self):
+ threads = self._threads()
+ for thread in threads:
+ thread.cancel()
+
+
+def log_wedged_worker(name, id):
+ """Log information about the given worker state."""
+ stack = _find_thread_stack(id)
+ assert(stack is not None)
+ _log.error("")
+ _log.error("%s (tid %d) is wedged" % (name, id))
+ _log_stack(stack)
+ _log.error("")
+
+
+def _find_thread_stack(id):
+ """Returns a stack object that can be used to dump a stack trace for
+ the given thread id (or None if the id is not found)."""
+ for thread_id, stack in sys._current_frames().items():
+ if thread_id == id:
+ return stack
+ return None
+
+
+def _log_stack(stack):
+ """Log a stack trace to log.error()."""
+ for filename, lineno, name, line in traceback.extract_stack(stack):
+ _log.error('File: "%s", line %d, in %s' % (filename, lineno, name))
+ if line:
+ _log.error(' %s' % line.strip())
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py
new file mode 100644
index 0000000..6f04fd3
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/message_broker_unittest.py
@@ -0,0 +1,183 @@
+# 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 logging
+import Queue
+import sys
+import thread
+import threading
+import time
+import unittest
+
+from webkitpy.common import array_stream
+from webkitpy.common.system import outputcapture
+from webkitpy.tool import mocktool
+
+from webkitpy.layout_tests import run_webkit_tests
+
+import message_broker
+
+
+class TestThread(threading.Thread):
+ def __init__(self, started_queue, stopping_queue):
+ threading.Thread.__init__(self)
+ self._thread_id = None
+ self._started_queue = started_queue
+ self._stopping_queue = stopping_queue
+ self._timeout = False
+ self._timeout_queue = Queue.Queue()
+ self._exception_info = None
+
+ def id(self):
+ return self._thread_id
+
+ def getName(self):
+ return "worker-0"
+
+ def run(self):
+ self._covered_run()
+
+ def _covered_run(self):
+ # FIXME: this is a separate routine to work around a bug
+ # in coverage: see http://bitbucket.org/ned/coveragepy/issue/85.
+ self._thread_id = thread.get_ident()
+ try:
+ self._started_queue.put('')
+ msg = self._stopping_queue.get()
+ if msg == 'KeyboardInterrupt':
+ raise KeyboardInterrupt
+ elif msg == 'Exception':
+ raise ValueError()
+ elif msg == 'Timeout':
+ self._timeout = True
+ self._timeout_queue.get()
+ except:
+ self._exception_info = sys.exc_info()
+
+ def exception_info(self):
+ return self._exception_info
+
+ def next_timeout(self):
+ if self._timeout:
+ self._timeout_queue.put('done')
+ return time.time() - 10
+ return time.time()
+
+ def clear_next_timeout(self):
+ self._next_timeout = None
+
+class TestHandler(logging.Handler):
+ def __init__(self, astream):
+ logging.Handler.__init__(self)
+ self._stream = astream
+
+ def emit(self, record):
+ self._stream.write(self.format(record))
+
+
+class MultiThreadedBrokerTest(unittest.TestCase):
+ class MockTestRunner(object):
+ def __init__(self):
+ pass
+
+ def __del__(self):
+ pass
+
+ def update(self):
+ pass
+
+ def run_one_thread(self, msg):
+ runner = self.MockTestRunner()
+ port = None
+ options = mocktool.MockOptions(child_processes='1')
+ starting_queue = Queue.Queue()
+ stopping_queue = Queue.Queue()
+ broker = message_broker.MultiThreadedBroker(port, options)
+ broker._test_runner = runner
+ child_thread = TestThread(starting_queue, stopping_queue)
+ broker._workers['worker-0'] = message_broker._WorkerState('worker-0')
+ broker._workers['worker-0'].thread = child_thread
+ child_thread.start()
+ started_msg = starting_queue.get()
+ stopping_queue.put(msg)
+ return broker.run_message_loop()
+
+ def test_basic(self):
+ interrupted = self.run_one_thread('')
+ self.assertFalse(interrupted)
+
+ def test_interrupt(self):
+ self.assertRaises(KeyboardInterrupt, self.run_one_thread, 'KeyboardInterrupt')
+
+ def test_timeout(self):
+ oc = outputcapture.OutputCapture()
+ oc.capture_output()
+ interrupted = self.run_one_thread('Timeout')
+ self.assertFalse(interrupted)
+ oc.restore_output()
+
+ def test_exception(self):
+ self.assertRaises(ValueError, self.run_one_thread, 'Exception')
+
+
+class Test(unittest.TestCase):
+ def test_find_thread_stack_found(self):
+ id, stack = sys._current_frames().items()[0]
+ found_stack = message_broker._find_thread_stack(id)
+ self.assertNotEqual(found_stack, None)
+
+ def test_find_thread_stack_not_found(self):
+ found_stack = message_broker._find_thread_stack(0)
+ self.assertEqual(found_stack, None)
+
+ def test_log_wedged_worker(self):
+ oc = outputcapture.OutputCapture()
+ oc.capture_output()
+ logger = message_broker._log
+ astream = array_stream.ArrayStream()
+ handler = TestHandler(astream)
+ logger.addHandler(handler)
+
+ starting_queue = Queue.Queue()
+ stopping_queue = Queue.Queue()
+ child_thread = TestThread(starting_queue, stopping_queue)
+ child_thread.start()
+ msg = starting_queue.get()
+
+ message_broker.log_wedged_worker(child_thread.getName(),
+ child_thread.id())
+ stopping_queue.put('')
+ child_thread.join(timeout=1.0)
+
+ self.assertFalse(astream.empty())
+ self.assertFalse(child_thread.isAlive())
+ oc.restore_output()
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/metered_stream.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/metered_stream.py
new file mode 100644
index 0000000..20646a1
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/metered_stream.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python
+# 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.
+
+"""
+Package that implements a stream wrapper that has 'meters' as well as
+regular output. A 'meter' is a single line of text that can be erased
+and rewritten repeatedly, without producing multiple lines of output. It
+can be used to produce effects like progress bars.
+
+This package should only be called by the printing module in the layout_tests
+package.
+"""
+
+import logging
+
+_log = logging.getLogger("webkitpy.layout_tests.metered_stream")
+
+
+class MeteredStream:
+ """This class is a wrapper around a stream that allows you to implement
+ meters (progress bars, etc.).
+
+ It can be used directly as a stream, by calling write(), but provides
+ two other methods for output, update(), and progress().
+
+ In normal usage, update() will overwrite the output of the immediately
+ preceding update() (write() also will overwrite update()). So, calling
+ multiple update()s in a row can provide an updating status bar (note that
+ if an update string contains newlines, only the text following the last
+ newline will be overwritten/erased).
+
+ If the MeteredStream is constructed in "verbose" mode (i.e., by passing
+ verbose=true), then update() no longer overwrite a previous update(), and
+ instead the call is equivalent to write(), although the text is
+ actually sent to the logger rather than to the stream passed
+ to the constructor.
+
+ progress() is just like update(), except that if you are in verbose mode,
+ progress messages are not output at all (they are dropped). This is
+ used for things like progress bars which are presumed to be unwanted in
+ verbose mode.
+
+ Note that the usual usage for this class is as a destination for
+ a logger that can also be written to directly (i.e., some messages go
+ through the logger, some don't). We thus have to dance around a
+ layering inversion in update() for things to work correctly.
+ """
+
+ def __init__(self, verbose, stream):
+ """
+ Args:
+ verbose: whether progress is a no-op and updates() aren't overwritten
+ stream: output stream to write to
+ """
+ self._dirty = False
+ self._verbose = verbose
+ self._stream = stream
+ self._last_update = ""
+
+ def write(self, txt):
+ """Write to the stream, overwriting and resetting the meter."""
+ if self._dirty:
+ self._write(txt)
+ self._dirty = False
+ self._last_update = ''
+ else:
+ self._stream.write(txt)
+
+ def flush(self):
+ """Flush any buffered output."""
+ self._stream.flush()
+
+ def progress(self, str):
+ """
+ Write a message to the stream that will get overwritten.
+
+ This is used for progress updates that don't need to be preserved in
+ the log. If the MeteredStream was initialized with verbose==True,
+ then this output is discarded. We have this in case we are logging
+ lots of output and the update()s will get lost or won't work
+ properly (typically because verbose streams are redirected to files).
+
+ """
+ if self._verbose:
+ return
+ self._write(str)
+
+ def update(self, str):
+ """
+ Write a message that is also included when logging verbosely.
+
+ This routine preserves the same console logging behavior as progress(),
+ but will also log the message if verbose() was true.
+
+ """
+ # Note this is a separate routine that calls either into the logger
+ # or the metering stream. We have to be careful to avoid a layering
+ # inversion (stream calling back into the logger).
+ if self._verbose:
+ _log.info(str)
+ else:
+ self._write(str)
+
+ def _write(self, str):
+ """Actually write the message to the stream."""
+
+ # FIXME: Figure out if there is a way to detect if we're writing
+ # to a stream that handles CRs correctly (e.g., terminals). That might
+ # be a cleaner way of handling this.
+
+ # Print the necessary number of backspaces to erase the previous
+ # message.
+ if len(self._last_update):
+ self._stream.write("\b" * len(self._last_update) +
+ " " * len(self._last_update) +
+ "\b" * len(self._last_update))
+ self._stream.write(str)
+ last_newline = str.rfind("\n")
+ self._last_update = str[(last_newline + 1):]
+ self._dirty = True
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/metered_stream_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/metered_stream_unittest.py
new file mode 100644
index 0000000..9421ff8
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/metered_stream_unittest.py
@@ -0,0 +1,115 @@
+#!/usr/bin/python
+# 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.
+
+"""Unit tests for metered_stream.py."""
+
+import os
+import optparse
+import pdb
+import sys
+import unittest
+
+from webkitpy.common.array_stream import ArrayStream
+from webkitpy.layout_tests.layout_package import metered_stream
+
+
+class TestMeteredStream(unittest.TestCase):
+ def test_regular(self):
+ a = ArrayStream()
+ m = metered_stream.MeteredStream(verbose=False, stream=a)
+ self.assertTrue(a.empty())
+
+ # basic test - note that the flush() is a no-op, but we include it
+ # for coverage.
+ m.write("foo")
+ m.flush()
+ exp = ['foo']
+ self.assertEquals(a.get(), exp)
+
+ # now check that a second write() does not overwrite the first.
+ m.write("bar")
+ exp.append('bar')
+ self.assertEquals(a.get(), exp)
+
+ m.update("batter")
+ exp.append('batter')
+ self.assertEquals(a.get(), exp)
+
+ # The next update() should overwrite the laste update() but not the
+ # other text. Note that the cursor is effectively positioned at the
+ # end of 'foo', even though we had to erase three more characters.
+ m.update("foo")
+ exp.append('\b\b\b\b\b\b \b\b\b\b\b\b')
+ exp.append('foo')
+ self.assertEquals(a.get(), exp)
+
+ m.progress("progress")
+ exp.append('\b\b\b \b\b\b')
+ exp.append('progress')
+ self.assertEquals(a.get(), exp)
+
+ # now check that a write() does overwrite the progress bar
+ m.write("foo")
+ exp.append('\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b')
+ exp.append('foo')
+ self.assertEquals(a.get(), exp)
+
+ # Now test that we only back up to the most recent newline.
+
+ # Note also that we do not back up to erase the most recent write(),
+ # i.e., write()s do not get erased.
+ a.reset()
+ m.update("foo\nbar")
+ m.update("baz")
+ self.assertEquals(a.get(), ['foo\nbar', '\b\b\b \b\b\b', 'baz'])
+
+ def test_verbose(self):
+ a = ArrayStream()
+ m = metered_stream.MeteredStream(verbose=True, stream=a)
+ self.assertTrue(a.empty())
+ m.write("foo")
+ self.assertEquals(a.get(), ['foo'])
+
+ import logging
+ b = ArrayStream()
+ logger = logging.getLogger()
+ handler = logging.StreamHandler(b)
+ logger.addHandler(handler)
+ m.update("bar")
+ logger.handlers.remove(handler)
+ self.assertEquals(a.get(), ['foo'])
+ self.assertEquals(b.get(), ['bar\n'])
+
+ m.progress("dropped")
+ self.assertEquals(a.get(), ['foo'])
+ self.assertEquals(b.get(), ['bar\n'])
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py
new file mode 100644
index 0000000..7a6aad1
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing.py
@@ -0,0 +1,553 @@
+#!/usr/bin/env python
+# 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.
+
+"""Package that handles non-debug, non-file output for run-webkit-tests."""
+
+import logging
+import optparse
+import os
+import pdb
+
+from webkitpy.layout_tests.layout_package import metered_stream
+from webkitpy.layout_tests.layout_package import test_expectations
+
+_log = logging.getLogger("webkitpy.layout_tests.printer")
+
+TestExpectationsFile = test_expectations.TestExpectationsFile
+
+NUM_SLOW_TESTS_TO_LOG = 10
+
+PRINT_DEFAULT = ("misc,one-line-progress,one-line-summary,unexpected,"
+ "unexpected-results,updates")
+PRINT_EVERYTHING = ("actual,config,expected,misc,one-line-progress,"
+ "one-line-summary,slowest,timing,unexpected,"
+ "unexpected-results,updates")
+
+HELP_PRINTING = """
+Output for run-webkit-tests is controlled by a comma-separated list of
+values passed to --print. Values either influence the overall output, or
+the output at the beginning of the run, during the run, or at the end:
+
+Overall options:
+ nothing don't print anything. This overrides every other option
+ default include the default options. This is useful for logging
+ the default options plus additional settings.
+ everything print everything (except the trace-* options and the
+ detailed-progress option, see below for the full list )
+ misc print miscellaneous things like blank lines
+
+At the beginning of the run:
+ config print the test run configuration
+ expected print a summary of what is expected to happen
+ (# passes, # failures, etc.)
+
+During the run:
+ detailed-progress print one dot per test completed
+ one-line-progress print a one-line progress bar
+ unexpected print any unexpected results as they occur
+ updates print updates on which stage is executing
+ trace-everything print detailed info on every test's results
+ (baselines, expectation, time it took to run). If
+ this is specified it will override the '*-progress'
+ options, the 'trace-unexpected' option, and the
+ 'unexpected' option.
+ trace-unexpected like 'trace-everything', but only for tests with
+ unexpected results. If this option is specified,
+ it will override the 'unexpected' option.
+
+At the end of the run:
+ actual print a summary of the actual results
+ slowest print %(slowest)d slowest tests and the time they took
+ timing print timing statistics
+ unexpected-results print a list of the tests with unexpected results
+ one-line-summary print a one-line summary of the run
+
+Notes:
+ - 'detailed-progress' can only be used if running in a single thread
+ (using --child-processes=1) or a single queue of tests (using
+ --experimental-fully-parallel). If these conditions aren't true,
+ 'one-line-progress' will be used instead.
+ - If both 'detailed-progress' and 'one-line-progress' are specified (and
+ both are possible), 'detailed-progress' will be used.
+ - If 'nothing' is specified, it overrides all of the other options.
+ - Specifying --verbose is equivalent to --print everything plus it
+ changes the format of the log messages to add timestamps and other
+ information. If you specify --verbose and --print X, then X overrides
+ the --print everything implied by --verbose.
+
+--print 'everything' is equivalent to --print '%(everything)s'.
+
+The default (--print default) is equivalent to --print '%(default)s'.
+""" % {'slowest': NUM_SLOW_TESTS_TO_LOG, 'everything': PRINT_EVERYTHING,
+ 'default': PRINT_DEFAULT}
+
+
+def print_options():
+ return [
+ # Note: We use print_options rather than just 'print' because print
+ # is a reserved word.
+ # Note: Also, we don't specify a default value so we can detect when
+ # no flag is specified on the command line and use different defaults
+ # based on whether or not --verbose is specified (since --print
+ # overrides --verbose).
+ optparse.make_option("--print", dest="print_options",
+ help=("controls print output of test run. "
+ "Use --help-printing for more.")),
+ optparse.make_option("--help-printing", action="store_true",
+ help="show detailed help on controlling print output"),
+ optparse.make_option("-v", "--verbose", action="store_true",
+ default=False, help="include debug-level logging"),
+ ]
+
+
+def parse_print_options(print_options, verbose, child_processes,
+ is_fully_parallel):
+ """Parse the options provided to --print and dedup and rank them.
+
+ Returns
+ a set() of switches that govern how logging is done
+
+ """
+ if print_options:
+ switches = set(print_options.split(','))
+ elif verbose:
+ switches = set(PRINT_EVERYTHING.split(','))
+ else:
+ switches = set(PRINT_DEFAULT.split(','))
+
+ if 'nothing' in switches:
+ return set()
+
+ if (child_processes != 1 and not is_fully_parallel and
+ 'detailed-progress' in switches):
+ _log.warn("Can only print 'detailed-progress' if running "
+ "with --child-processes=1 or "
+ "with --experimental-fully-parallel. "
+ "Using 'one-line-progress' instead.")
+ switches.discard('detailed-progress')
+ switches.add('one-line-progress')
+
+ if 'everything' in switches:
+ switches.discard('everything')
+ switches.update(set(PRINT_EVERYTHING.split(',')))
+
+ if 'default' in switches:
+ switches.discard('default')
+ switches.update(set(PRINT_DEFAULT.split(',')))
+
+ if 'detailed-progress' in switches:
+ switches.discard('one-line-progress')
+
+ if 'trace-everything' in switches:
+ switches.discard('detailed-progress')
+ switches.discard('one-line-progress')
+ switches.discard('trace-unexpected')
+ switches.discard('unexpected')
+
+ if 'trace-unexpected' in switches:
+ switches.discard('unexpected')
+
+ return switches
+
+
+def _configure_logging(stream, verbose):
+ log_fmt = '%(message)s'
+ log_datefmt = '%y%m%d %H:%M:%S'
+ log_level = logging.INFO
+ if verbose:
+ log_fmt = ('%(asctime)s %(process)d %(filename)s:%(lineno)d '
+ '%(levelname)s %(message)s')
+ log_level = logging.DEBUG
+
+ root = logging.getLogger()
+ handler = logging.StreamHandler(stream)
+ handler.setFormatter(logging.Formatter(log_fmt, None))
+ root.addHandler(handler)
+ root.setLevel(log_level)
+ return handler
+
+
+def _restore_logging(handler_to_remove):
+ root = logging.getLogger()
+ root.handlers.remove(handler_to_remove)
+
+
+class Printer(object):
+ """Class handling all non-debug-logging printing done by run-webkit-tests.
+
+ Printing from run-webkit-tests falls into two buckets: general or
+ regular output that is read only by humans and can be changed at any
+ time, and output that is parsed by buildbots (and humans) and hence
+ must be changed more carefully and in coordination with the buildbot
+ parsing code (in chromium.org's buildbot/master.chromium/scripts/master/
+ log_parser/webkit_test_command.py script).
+
+ By default the buildbot-parsed code gets logged to stdout, and regular
+ output gets logged to stderr."""
+ def __init__(self, port, options, regular_output, buildbot_output,
+ child_processes, is_fully_parallel):
+ """
+ Args
+ port interface to port-specific routines
+ options OptionParser object with command line settings
+ regular_output stream to which output intended only for humans
+ should be written
+ buildbot_output stream to which output intended to be read by
+ the buildbots (and humans) should be written
+ child_processes number of parallel threads running (usually
+ controlled by --child-processes)
+ is_fully_parallel are the tests running in a single queue, or
+ in shards (usually controlled by
+ --experimental-fully-parallel)
+
+ Note that the last two args are separate rather than bundled into
+ the options structure so that this object does not assume any flags
+ set in options that weren't returned from logging_options(), above.
+ The two are used to determine whether or not we can sensibly use
+ the 'detailed-progress' option, or can only use 'one-line-progress'.
+ """
+ self._buildbot_stream = buildbot_output
+ self._options = options
+ self._port = port
+ self._stream = regular_output
+
+ # These are used for --print detailed-progress to track status by
+ # directory.
+ self._current_dir = None
+ self._current_progress_str = ""
+ self._current_test_number = 0
+
+ self._meter = metered_stream.MeteredStream(options.verbose,
+ regular_output)
+ self._logging_handler = _configure_logging(self._meter,
+ options.verbose)
+
+ self.switches = parse_print_options(options.print_options,
+ options.verbose, child_processes, is_fully_parallel)
+
+ def cleanup(self):
+ """Restore logging configuration to its initial settings."""
+ if self._logging_handler:
+ _restore_logging(self._logging_handler)
+ self._logging_handler = None
+
+ def __del__(self):
+ self.cleanup()
+
+ # These two routines just hide the implementation of the switches.
+ def disabled(self, option):
+ return not option in self.switches
+
+ def enabled(self, option):
+ return option in self.switches
+
+ def help_printing(self):
+ self._write(HELP_PRINTING)
+
+ def print_actual(self, msg):
+ if self.disabled('actual'):
+ return
+ self._buildbot_stream.write("%s\n" % msg)
+
+ def print_config(self, msg):
+ self.write(msg, 'config')
+
+ def print_expected(self, msg):
+ self.write(msg, 'expected')
+
+ def print_timing(self, msg):
+ self.write(msg, 'timing')
+
+ def print_one_line_summary(self, total, expected, unexpected):
+ """Print a one-line summary of the test run to stdout.
+
+ Args:
+ total: total number of tests run
+ expected: number of expected results
+ unexpected: number of unexpected results
+ """
+ if self.disabled('one-line-summary'):
+ return
+
+ incomplete = total - expected - unexpected
+ if incomplete:
+ self._write("")
+ incomplete_str = " (%d didn't run)" % incomplete
+ expected_str = str(expected)
+ else:
+ incomplete_str = ""
+ expected_str = "All %d" % expected
+
+ if unexpected == 0:
+ self._write("%s tests ran as expected%s." %
+ (expected_str, incomplete_str))
+ elif expected == 1:
+ self._write("1 test ran as expected, %d didn't%s:" %
+ (unexpected, incomplete_str))
+ else:
+ self._write("%d tests ran as expected, %d didn't%s:" %
+ (expected, unexpected, incomplete_str))
+ self._write("")
+
+ def print_test_result(self, result, expected, exp_str, got_str):
+ """Print the result of the test as determined by --print.
+
+ This routine is used to print the details of each test as it completes.
+
+ Args:
+ result - The actual TestResult object
+ expected - Whether the result we got was an expected result
+ exp_str - What we expected to get (used for tracing)
+ got_str - What we actually got (used for tracing)
+
+ Note that we need all of these arguments even though they seem
+ somewhat redundant, in order to keep this routine from having to
+ known anything about the set of expectations.
+ """
+ if (self.enabled('trace-everything') or
+ self.enabled('trace-unexpected') and not expected):
+ self._print_test_trace(result, exp_str, got_str)
+ elif (not expected and self.enabled('unexpected') and
+ self.disabled('detailed-progress')):
+ # Note: 'detailed-progress' handles unexpected results internally,
+ # so we skip it here.
+ self._print_unexpected_test_result(result)
+
+ def _print_test_trace(self, result, exp_str, got_str):
+ """Print detailed results of a test (triggered by --print trace-*).
+ For each test, print:
+ - location of the expected baselines
+ - expected results
+ - actual result
+ - timing info
+ """
+ filename = result.filename
+ test_name = self._port.relative_test_filename(filename)
+ self._write('trace: %s' % test_name)
+ txt_file = self._port.expected_filename(filename, '.txt')
+ if self._port.path_exists(txt_file):
+ self._write(' txt: %s' %
+ self._port.relative_test_filename(txt_file))
+ else:
+ self._write(' txt: <none>')
+ checksum_file = self._port.expected_filename(filename, '.checksum')
+ if self._port.path_exists(checksum_file):
+ self._write(' sum: %s' %
+ self._port.relative_test_filename(checksum_file))
+ else:
+ self._write(' sum: <none>')
+ png_file = self._port.expected_filename(filename, '.png')
+ if self._port.path_exists(png_file):
+ self._write(' png: %s' %
+ self._port.relative_test_filename(png_file))
+ else:
+ self._write(' png: <none>')
+ self._write(' exp: %s' % exp_str)
+ self._write(' got: %s' % got_str)
+ self._write(' took: %-.3f' % result.test_run_time)
+ self._write('')
+
+ def _print_unexpected_test_result(self, result):
+ """Prints one unexpected test result line."""
+ desc = TestExpectationsFile.EXPECTATION_DESCRIPTIONS[result.type][0]
+ self.write(" %s -> unexpected %s" %
+ (self._port.relative_test_filename(result.filename),
+ desc), "unexpected")
+
+ def print_progress(self, result_summary, retrying, test_list):
+ """Print progress through the tests as determined by --print."""
+ if self.enabled('detailed-progress'):
+ self._print_detailed_progress(result_summary, test_list)
+ elif self.enabled('one-line-progress'):
+ self._print_one_line_progress(result_summary, retrying)
+ else:
+ return
+
+ if result_summary.remaining == 0:
+ self._meter.update('')
+
+ def _print_one_line_progress(self, result_summary, retrying):
+ """Displays the progress through the test run."""
+ percent_complete = 100 * (result_summary.expected +
+ result_summary.unexpected) / result_summary.total
+ action = "Testing"
+ if retrying:
+ action = "Retrying"
+ self._meter.progress("%s (%d%%): %d ran as expected, %d didn't,"
+ " %d left" % (action, percent_complete, result_summary.expected,
+ result_summary.unexpected, result_summary.remaining))
+
+ def _print_detailed_progress(self, result_summary, test_list):
+ """Display detailed progress output where we print the directory name
+ and one dot for each completed test. This is triggered by
+ "--log detailed-progress"."""
+ if self._current_test_number == len(test_list):
+ return
+
+ next_test = test_list[self._current_test_number]
+ next_dir = os.path.dirname(
+ self._port.relative_test_filename(next_test))
+ if self._current_progress_str == "":
+ self._current_progress_str = "%s: " % (next_dir)
+ self._current_dir = next_dir
+
+ while next_test in result_summary.results:
+ if next_dir != self._current_dir:
+ self._meter.write("%s\n" % (self._current_progress_str))
+ self._current_progress_str = "%s: ." % (next_dir)
+ self._current_dir = next_dir
+ else:
+ self._current_progress_str += "."
+
+ if (next_test in result_summary.unexpected_results and
+ self.enabled('unexpected')):
+ self._meter.write("%s\n" % self._current_progress_str)
+ test_result = result_summary.results[next_test]
+ self._print_unexpected_test_result(test_result)
+ self._current_progress_str = "%s: " % self._current_dir
+
+ self._current_test_number += 1
+ if self._current_test_number == len(test_list):
+ break
+
+ next_test = test_list[self._current_test_number]
+ next_dir = os.path.dirname(
+ self._port.relative_test_filename(next_test))
+
+ if result_summary.remaining:
+ remain_str = " (%d)" % (result_summary.remaining)
+ self._meter.progress("%s%s" % (self._current_progress_str,
+ remain_str))
+ else:
+ self._meter.progress("%s" % (self._current_progress_str))
+
+ def print_unexpected_results(self, unexpected_results):
+ """Prints a list of the unexpected results to the buildbot stream."""
+ if self.disabled('unexpected-results'):
+ return
+
+ passes = {}
+ flaky = {}
+ regressions = {}
+
+ for test, results in unexpected_results['tests'].iteritems():
+ actual = results['actual'].split(" ")
+ expected = results['expected'].split(" ")
+ if actual == ['PASS']:
+ if 'CRASH' in expected:
+ _add_to_dict_of_lists(passes,
+ 'Expected to crash, but passed',
+ test)
+ elif 'TIMEOUT' in expected:
+ _add_to_dict_of_lists(passes,
+ 'Expected to timeout, but passed',
+ test)
+ else:
+ _add_to_dict_of_lists(passes,
+ 'Expected to fail, but passed',
+ test)
+ elif len(actual) > 1:
+ # We group flaky tests by the first actual result we got.
+ _add_to_dict_of_lists(flaky, actual[0], test)
+ else:
+ _add_to_dict_of_lists(regressions, results['actual'], test)
+
+ if len(passes) or len(flaky) or len(regressions):
+ self._buildbot_stream.write("\n")
+
+ if len(passes):
+ for key, tests in passes.iteritems():
+ self._buildbot_stream.write("%s: (%d)\n" % (key, len(tests)))
+ tests.sort()
+ for test in tests:
+ self._buildbot_stream.write(" %s\n" % test)
+ self._buildbot_stream.write("\n")
+ self._buildbot_stream.write("\n")
+
+ if len(flaky):
+ descriptions = TestExpectationsFile.EXPECTATION_DESCRIPTIONS
+ for key, tests in flaky.iteritems():
+ result = TestExpectationsFile.EXPECTATIONS[key.lower()]
+ self._buildbot_stream.write("Unexpected flakiness: %s (%d)\n"
+ % (descriptions[result][1], len(tests)))
+ tests.sort()
+
+ for test in tests:
+ result = unexpected_results['tests'][test]
+ actual = result['actual'].split(" ")
+ expected = result['expected'].split(" ")
+ result = TestExpectationsFile.EXPECTATIONS[key.lower()]
+ new_expectations_list = list(set(actual) | set(expected))
+ self._buildbot_stream.write(" %s = %s\n" %
+ (test, " ".join(new_expectations_list)))
+ self._buildbot_stream.write("\n")
+ self._buildbot_stream.write("\n")
+
+ if len(regressions):
+ descriptions = TestExpectationsFile.EXPECTATION_DESCRIPTIONS
+ for key, tests in regressions.iteritems():
+ result = TestExpectationsFile.EXPECTATIONS[key.lower()]
+ self._buildbot_stream.write(
+ "Regressions: Unexpected %s : (%d)\n" % (
+ descriptions[result][1], len(tests)))
+ tests.sort()
+ for test in tests:
+ self._buildbot_stream.write(" %s = %s\n" % (test, key))
+ self._buildbot_stream.write("\n")
+ self._buildbot_stream.write("\n")
+
+ if len(unexpected_results['tests']) and self._options.verbose:
+ self._buildbot_stream.write("%s\n" % ("-" * 78))
+
+ def print_update(self, msg):
+ if self.disabled('updates'):
+ return
+ self._meter.update(msg)
+
+ def write(self, msg, option="misc"):
+ if self.disabled(option):
+ return
+ self._write(msg)
+
+ def _write(self, msg):
+ # FIXME: we could probably get away with calling _log.info() all of
+ # the time, but there doesn't seem to be a good way to test the output
+ # from the logger :(.
+ if self._options.verbose:
+ _log.info(msg)
+ else:
+ self._meter.write("%s\n" % msg)
+
+#
+# Utility routines used by the Controller class
+#
+
+
+def _add_to_dict_of_lists(dict, key, value):
+ dict.setdefault(key, []).append(value)
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py
new file mode 100644
index 0000000..0e478c8
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/printing_unittest.py
@@ -0,0 +1,608 @@
+#!/usr/bin/python
+# 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.
+
+"""Unit tests for printing.py."""
+
+import os
+import optparse
+import pdb
+import sys
+import unittest
+import logging
+
+from webkitpy.common import array_stream
+from webkitpy.common.system import logtesting
+from webkitpy.layout_tests import port
+
+from webkitpy.layout_tests.layout_package import printing
+from webkitpy.layout_tests.layout_package import result_summary
+from webkitpy.layout_tests.layout_package import test_expectations
+from webkitpy.layout_tests.layout_package import test_failures
+from webkitpy.layout_tests.layout_package import test_results
+from webkitpy.layout_tests.layout_package import test_runner
+
+
+def get_options(args):
+ print_options = printing.print_options()
+ option_parser = optparse.OptionParser(option_list=print_options)
+ return option_parser.parse_args(args)
+
+
+class TestUtilityFunctions(unittest.TestCase):
+ def test_configure_logging(self):
+ options, args = get_options([])
+ stream = array_stream.ArrayStream()
+ handler = printing._configure_logging(stream, options.verbose)
+ logging.info("this should be logged")
+ self.assertFalse(stream.empty())
+
+ stream.reset()
+ logging.debug("this should not be logged")
+ self.assertTrue(stream.empty())
+
+ printing._restore_logging(handler)
+
+ stream.reset()
+ options, args = get_options(['--verbose'])
+ handler = printing._configure_logging(stream, options.verbose)
+ logging.debug("this should be logged")
+ self.assertFalse(stream.empty())
+ printing._restore_logging(handler)
+
+ def test_print_options(self):
+ options, args = get_options([])
+ self.assertTrue(options is not None)
+
+ def test_parse_print_options(self):
+ def test_switches(args, expected_switches_str,
+ verbose=False, child_processes=1,
+ is_fully_parallel=False):
+ options, args = get_options(args)
+ if expected_switches_str:
+ expected_switches = set(expected_switches_str.split(','))
+ else:
+ expected_switches = set()
+ switches = printing.parse_print_options(options.print_options,
+ verbose,
+ child_processes,
+ is_fully_parallel)
+ self.assertEqual(expected_switches, switches)
+
+ # test that we default to the default set of switches
+ test_switches([], printing.PRINT_DEFAULT)
+
+ # test that verbose defaults to everything
+ test_switches([], printing.PRINT_EVERYTHING, verbose=True)
+
+ # test that --print default does what it's supposed to
+ test_switches(['--print', 'default'], printing.PRINT_DEFAULT)
+
+ # test that --print nothing does what it's supposed to
+ test_switches(['--print', 'nothing'], None)
+
+ # test that --print everything does what it's supposed to
+ test_switches(['--print', 'everything'], printing.PRINT_EVERYTHING)
+
+ # this tests that '--print X' overrides '--verbose'
+ test_switches(['--print', 'actual'], 'actual', verbose=True)
+
+
+
+class Testprinter(unittest.TestCase):
+ def get_printer(self, args=None, single_threaded=False,
+ is_fully_parallel=False):
+ printing_options = printing.print_options()
+ option_parser = optparse.OptionParser(option_list=printing_options)
+ options, args = option_parser.parse_args(args)
+ self._port = port.get('test', options)
+ nproc = 2
+ if single_threaded:
+ nproc = 1
+
+ regular_output = array_stream.ArrayStream()
+ buildbot_output = array_stream.ArrayStream()
+ printer = printing.Printer(self._port, options, regular_output,
+ buildbot_output, single_threaded,
+ is_fully_parallel)
+ return printer, regular_output, buildbot_output
+
+ def get_result(self, test, result_type=test_expectations.PASS, run_time=0):
+ failures = []
+ if result_type == test_expectations.TIMEOUT:
+ failures = [test_failures.FailureTimeout()]
+ elif result_type == test_expectations.CRASH:
+ failures = [test_failures.FailureCrash()]
+ path = os.path.join(self._port.layout_tests_dir(), test)
+ return test_results.TestResult(path, failures, run_time,
+ total_time_for_all_diffs=0,
+ time_for_diffs=0)
+
+ def get_result_summary(self, tests, expectations_str):
+ test_paths = [os.path.join(self._port.layout_tests_dir(), test) for
+ test in tests]
+ expectations = test_expectations.TestExpectations(
+ self._port, test_paths, expectations_str,
+ self._port.test_platform_name(), is_debug_mode=False,
+ is_lint_mode=False)
+
+ rs = result_summary.ResultSummary(expectations, test_paths)
+ return test_paths, rs, expectations
+
+ def test_help_printer(self):
+ # Here and below we'll call the "regular" printer err and the
+ # buildbot printer out; this corresponds to how things run on the
+ # bots with stderr and stdout.
+ printer, err, out = self.get_printer()
+
+ # This routine should print something to stdout. testing what it is
+ # is kind of pointless.
+ printer.help_printing()
+ self.assertFalse(err.empty())
+ self.assertTrue(out.empty())
+
+ def do_switch_tests(self, method_name, switch, to_buildbot,
+ message='hello', exp_err=None, exp_bot=None):
+ def do_helper(method_name, switch, message, exp_err, exp_bot):
+ printer, err, bot = self.get_printer(['--print', switch])
+ getattr(printer, method_name)(message)
+ self.assertEqual(err.get(), exp_err)
+ self.assertEqual(bot.get(), exp_bot)
+
+ if to_buildbot:
+ if exp_err is None:
+ exp_err = []
+ if exp_bot is None:
+ exp_bot = [message + "\n"]
+ else:
+ if exp_err is None:
+ exp_err = [message + "\n"]
+ if exp_bot is None:
+ exp_bot = []
+ do_helper(method_name, 'nothing', 'hello', [], [])
+ do_helper(method_name, switch, 'hello', exp_err, exp_bot)
+ do_helper(method_name, 'everything', 'hello', exp_err, exp_bot)
+
+ def test_configure_and_cleanup(self):
+ # This test verifies that calling cleanup repeatedly and deleting
+ # the object is safe.
+ printer, err, out = self.get_printer(['--print', 'everything'])
+ printer.cleanup()
+ printer.cleanup()
+ printer = None
+
+ def test_print_actual(self):
+ # Actual results need to be logged to the buildbot's stream.
+ self.do_switch_tests('print_actual', 'actual', to_buildbot=True)
+
+ def test_print_actual_buildbot(self):
+ # FIXME: Test that the format of the actual results matches what the
+ # buildbot is expecting.
+ pass
+
+ def test_print_config(self):
+ self.do_switch_tests('print_config', 'config', to_buildbot=False)
+
+ def test_print_expected(self):
+ self.do_switch_tests('print_expected', 'expected', to_buildbot=False)
+
+ def test_print_timing(self):
+ self.do_switch_tests('print_timing', 'timing', to_buildbot=False)
+
+ def test_print_update(self):
+ # Note that there shouldn't be a carriage return here; updates()
+ # are meant to be overwritten.
+ self.do_switch_tests('print_update', 'updates', to_buildbot=False,
+ message='hello', exp_err=['hello'])
+
+ def test_print_one_line_summary(self):
+ printer, err, out = self.get_printer(['--print', 'nothing'])
+ printer.print_one_line_summary(1, 1, 0)
+ self.assertTrue(err.empty())
+
+ printer, err, out = self.get_printer(['--print', 'one-line-summary'])
+ printer.print_one_line_summary(1, 1, 0)
+ self.assertEquals(err.get(), ["All 1 tests ran as expected.\n", "\n"])
+
+ printer, err, out = self.get_printer(['--print', 'everything'])
+ printer.print_one_line_summary(1, 1, 0)
+ self.assertEquals(err.get(), ["All 1 tests ran as expected.\n", "\n"])
+
+ err.reset()
+ printer.print_one_line_summary(2, 1, 1)
+ self.assertEquals(err.get(),
+ ["1 test ran as expected, 1 didn't:\n", "\n"])
+
+ err.reset()
+ printer.print_one_line_summary(3, 2, 1)
+ self.assertEquals(err.get(),
+ ["2 tests ran as expected, 1 didn't:\n", "\n"])
+
+ err.reset()
+ printer.print_one_line_summary(3, 2, 0)
+ self.assertEquals(err.get(),
+ ['\n', "2 tests ran as expected (1 didn't run).\n",
+ '\n'])
+
+
+ def test_print_test_result(self):
+ # Note here that we don't use meaningful exp_str and got_str values;
+ # the actual contents of the string are treated opaquely by
+ # print_test_result() when tracing, and usually we don't want
+ # to test what exactly is printed, just that something
+ # was printed (or that nothing was printed).
+ #
+ # FIXME: this is actually some goofy layering; it would be nice
+ # we could refactor it so that the args weren't redundant. Maybe
+ # the TestResult should contain what was expected, and the
+ # strings could be derived from the TestResult?
+ printer, err, out = self.get_printer(['--print', 'nothing'])
+ result = self.get_result('passes/image.html')
+ printer.print_test_result(result, expected=False, exp_str='',
+ got_str='')
+ self.assertTrue(err.empty())
+
+ printer, err, out = self.get_printer(['--print', 'unexpected'])
+ printer.print_test_result(result, expected=True, exp_str='',
+ got_str='')
+ self.assertTrue(err.empty())
+ printer.print_test_result(result, expected=False, exp_str='',
+ got_str='')
+ self.assertEquals(err.get(),
+ [' passes/image.html -> unexpected pass\n'])
+
+ printer, err, out = self.get_printer(['--print', 'everything'])
+ printer.print_test_result(result, expected=True, exp_str='',
+ got_str='')
+ self.assertTrue(err.empty())
+
+ printer.print_test_result(result, expected=False, exp_str='',
+ got_str='')
+ self.assertEquals(err.get(),
+ [' passes/image.html -> unexpected pass\n'])
+
+ printer, err, out = self.get_printer(['--print', 'nothing'])
+ printer.print_test_result(result, expected=False, exp_str='',
+ got_str='')
+ self.assertTrue(err.empty())
+
+ printer, err, out = self.get_printer(['--print',
+ 'trace-unexpected'])
+ printer.print_test_result(result, expected=True, exp_str='',
+ got_str='')
+ self.assertTrue(err.empty())
+
+ printer, err, out = self.get_printer(['--print',
+ 'trace-unexpected'])
+ printer.print_test_result(result, expected=False, exp_str='',
+ got_str='')
+ self.assertFalse(err.empty())
+
+ printer, err, out = self.get_printer(['--print',
+ 'trace-unexpected'])
+ result = self.get_result("passes/text.html")
+ printer.print_test_result(result, expected=False, exp_str='',
+ got_str='')
+ self.assertFalse(err.empty())
+
+ err.reset()
+ printer.print_test_result(result, expected=False, exp_str='',
+ got_str='')
+ self.assertFalse(err.empty())
+
+ printer, err, out = self.get_printer(['--print', 'trace-everything'])
+ result = self.get_result('passes/image.html')
+ printer.print_test_result(result, expected=True, exp_str='',
+ got_str='')
+ result = self.get_result('failures/expected/missing_text.html')
+ printer.print_test_result(result, expected=True, exp_str='',
+ got_str='')
+ result = self.get_result('failures/expected/missing_check.html')
+ printer.print_test_result(result, expected=True, exp_str='',
+ got_str='')
+ result = self.get_result('failures/expected/missing_image.html')
+ printer.print_test_result(result, expected=True, exp_str='',
+ got_str='')
+ self.assertFalse(err.empty())
+
+ err.reset()
+ printer.print_test_result(result, expected=False, exp_str='',
+ got_str='')
+
+ def test_print_progress(self):
+ expectations = ''
+
+ # test that we print nothing
+ printer, err, out = self.get_printer(['--print', 'nothing'])
+ tests = ['passes/text.html', 'failures/expected/timeout.html',
+ 'failures/expected/crash.html']
+ paths, rs, exp = self.get_result_summary(tests, expectations)
+
+ printer.print_progress(rs, False, paths)
+ self.assertTrue(out.empty())
+ self.assertTrue(err.empty())
+
+ printer.print_progress(rs, True, paths)
+ self.assertTrue(out.empty())
+ self.assertTrue(err.empty())
+
+ # test regular functionality
+ printer, err, out = self.get_printer(['--print',
+ 'one-line-progress'])
+ printer.print_progress(rs, False, paths)
+ self.assertTrue(out.empty())
+ self.assertFalse(err.empty())
+
+ err.reset()
+ out.reset()
+ printer.print_progress(rs, True, paths)
+ self.assertFalse(err.empty())
+ self.assertTrue(out.empty())
+
+ def test_print_progress__detailed(self):
+ tests = ['passes/text.html', 'failures/expected/timeout.html',
+ 'failures/expected/crash.html']
+ expectations = 'failures/expected/timeout.html = TIMEOUT'
+
+ # first, test that it is disabled properly
+ # should still print one-line-progress
+ printer, err, out = self.get_printer(
+ ['--print', 'detailed-progress'], single_threaded=False)
+ paths, rs, exp = self.get_result_summary(tests, expectations)
+ printer.print_progress(rs, False, paths)
+ self.assertFalse(err.empty())
+ self.assertTrue(out.empty())
+
+ # now test the enabled paths
+ printer, err, out = self.get_printer(
+ ['--print', 'detailed-progress'], single_threaded=True)
+ paths, rs, exp = self.get_result_summary(tests, expectations)
+ printer.print_progress(rs, False, paths)
+ self.assertFalse(err.empty())
+ self.assertTrue(out.empty())
+
+ err.reset()
+ out.reset()
+ printer.print_progress(rs, True, paths)
+ self.assertFalse(err.empty())
+ self.assertTrue(out.empty())
+
+ rs.add(self.get_result('passes/text.html', test_expectations.TIMEOUT), False)
+ rs.add(self.get_result('failures/expected/timeout.html'), True)
+ rs.add(self.get_result('failures/expected/crash.html', test_expectations.CRASH), True)
+ err.reset()
+ out.reset()
+ printer.print_progress(rs, False, paths)
+ self.assertFalse(err.empty())
+ self.assertTrue(out.empty())
+
+ # We only clear the meter when retrying w/ detailed-progress.
+ err.reset()
+ out.reset()
+ printer.print_progress(rs, True, paths)
+ self.assertFalse(err.empty())
+ self.assertTrue(out.empty())
+
+ printer, err, out = self.get_printer(
+ ['--print', 'detailed-progress,unexpected'], single_threaded=True)
+ paths, rs, exp = self.get_result_summary(tests, expectations)
+ printer.print_progress(rs, False, paths)
+ self.assertFalse(err.empty())
+ self.assertTrue(out.empty())
+
+ err.reset()
+ out.reset()
+ printer.print_progress(rs, True, paths)
+ self.assertFalse(err.empty())
+ self.assertTrue(out.empty())
+
+ rs.add(self.get_result('passes/text.html', test_expectations.TIMEOUT), False)
+ rs.add(self.get_result('failures/expected/timeout.html'), True)
+ rs.add(self.get_result('failures/expected/crash.html', test_expectations.CRASH), True)
+ err.reset()
+ out.reset()
+ printer.print_progress(rs, False, paths)
+ self.assertFalse(err.empty())
+ self.assertTrue(out.empty())
+
+ # We only clear the meter when retrying w/ detailed-progress.
+ err.reset()
+ out.reset()
+ printer.print_progress(rs, True, paths)
+ self.assertFalse(err.empty())
+ self.assertTrue(out.empty())
+
+ def test_write_nothing(self):
+ printer, err, out = self.get_printer(['--print', 'nothing'])
+ printer.write("foo")
+ self.assertTrue(err.empty())
+
+ def test_write_misc(self):
+ printer, err, out = self.get_printer(['--print', 'misc'])
+ printer.write("foo")
+ self.assertFalse(err.empty())
+ err.reset()
+ printer.write("foo", "config")
+ self.assertTrue(err.empty())
+
+ def test_write_everything(self):
+ printer, err, out = self.get_printer(['--print', 'everything'])
+ printer.write("foo")
+ self.assertFalse(err.empty())
+ err.reset()
+ printer.write("foo", "config")
+ self.assertFalse(err.empty())
+
+ def test_write_verbose(self):
+ printer, err, out = self.get_printer(['--verbose'])
+ printer.write("foo")
+ self.assertTrue(not err.empty() and "foo" in err.get()[0])
+ self.assertTrue(out.empty())
+
+ def test_print_unexpected_results(self):
+ # This routine is the only one that prints stuff that the bots
+ # care about.
+ #
+ # FIXME: there's some weird layering going on here. It seems
+ # like we shouldn't be both using an expectations string and
+ # having to specify whether or not the result was expected.
+ # This whole set of tests should probably be rewritten.
+ #
+ # FIXME: Plus, the fact that we're having to call into
+ # run_webkit_tests is clearly a layering inversion.
+ def get_unexpected_results(expected, passing, flaky):
+ """Return an unexpected results summary matching the input description.
+
+ There are a lot of different combinations of test results that
+ can be tested; this routine produces various combinations based
+ on the values of the input flags.
+
+ Args
+ expected: whether the tests ran as expected
+ passing: whether the tests should all pass
+ flaky: whether the tests should be flaky (if False, they
+ produce the same results on both runs; if True, they
+ all pass on the second run).
+
+ """
+ paths, rs, exp = self.get_result_summary(tests, expectations)
+ if expected:
+ rs.add(self.get_result('passes/text.html', test_expectations.PASS),
+ expected)
+ rs.add(self.get_result('failures/expected/timeout.html',
+ test_expectations.TIMEOUT), expected)
+ rs.add(self.get_result('failures/expected/crash.html', test_expectations.CRASH),
+ expected)
+ elif passing:
+ rs.add(self.get_result('passes/text.html'), expected)
+ rs.add(self.get_result('failures/expected/timeout.html'), expected)
+ rs.add(self.get_result('failures/expected/crash.html'), expected)
+ else:
+ rs.add(self.get_result('passes/text.html', test_expectations.TIMEOUT),
+ expected)
+ rs.add(self.get_result('failures/expected/timeout.html',
+ test_expectations.CRASH), expected)
+ rs.add(self.get_result('failures/expected/crash.html',
+ test_expectations.TIMEOUT),
+ expected)
+ retry = rs
+ if flaky:
+ paths, retry, exp = self.get_result_summary(tests,
+ expectations)
+ retry.add(self.get_result('passes/text.html'), True)
+ retry.add(self.get_result('failures/expected/timeout.html'), True)
+ retry.add(self.get_result('failures/expected/crash.html'), True)
+ unexpected_results = test_runner.summarize_unexpected_results(
+ self._port, exp, rs, retry)
+ return unexpected_results
+
+ tests = ['passes/text.html', 'failures/expected/timeout.html',
+ 'failures/expected/crash.html']
+ expectations = ''
+
+ printer, err, out = self.get_printer(['--print', 'nothing'])
+ ur = get_unexpected_results(expected=False, passing=False, flaky=False)
+ printer.print_unexpected_results(ur)
+ self.assertTrue(err.empty())
+ self.assertTrue(out.empty())
+
+ printer, err, out = self.get_printer(['--print',
+ 'unexpected-results'])
+
+ # test everything running as expected
+ ur = get_unexpected_results(expected=True, passing=False, flaky=False)
+ printer.print_unexpected_results(ur)
+ self.assertTrue(err.empty())
+ self.assertTrue(out.empty())
+
+ # test failures
+ err.reset()
+ out.reset()
+ ur = get_unexpected_results(expected=False, passing=False, flaky=False)
+ printer.print_unexpected_results(ur)
+ self.assertTrue(err.empty())
+ self.assertFalse(out.empty())
+
+ # test unexpected flaky results
+ err.reset()
+ out.reset()
+ ur = get_unexpected_results(expected=False, passing=True, flaky=False)
+ printer.print_unexpected_results(ur)
+ self.assertTrue(err.empty())
+ self.assertFalse(out.empty())
+
+ # test unexpected passes
+ err.reset()
+ out.reset()
+ ur = get_unexpected_results(expected=False, passing=False, flaky=True)
+ printer.print_unexpected_results(ur)
+ self.assertTrue(err.empty())
+ self.assertFalse(out.empty())
+
+ err.reset()
+ out.reset()
+ printer, err, out = self.get_printer(['--print', 'everything'])
+ ur = get_unexpected_results(expected=False, passing=False, flaky=False)
+ printer.print_unexpected_results(ur)
+ self.assertTrue(err.empty())
+ self.assertFalse(out.empty())
+
+ expectations = """
+failures/expected/crash.html = CRASH
+failures/expected/timeout.html = TIMEOUT
+"""
+ err.reset()
+ out.reset()
+ ur = get_unexpected_results(expected=False, passing=False, flaky=False)
+ printer.print_unexpected_results(ur)
+ self.assertTrue(err.empty())
+ self.assertFalse(out.empty())
+
+ err.reset()
+ out.reset()
+ ur = get_unexpected_results(expected=False, passing=True, flaky=False)
+ printer.print_unexpected_results(ur)
+ self.assertTrue(err.empty())
+ self.assertFalse(out.empty())
+
+ # Test handling of --verbose as well.
+ err.reset()
+ out.reset()
+ printer, err, out = self.get_printer(['--verbose'])
+ ur = get_unexpected_results(expected=False, passing=False, flaky=False)
+ printer.print_unexpected_results(ur)
+ self.assertTrue(err.empty())
+ self.assertFalse(out.empty())
+
+ def test_print_unexpected_results_buildbot(self):
+ # FIXME: Test that print_unexpected_results() produces the printer the
+ # buildbot is expecting.
+ pass
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/result_summary.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/result_summary.py
new file mode 100644
index 0000000..80fd6ac
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/result_summary.py
@@ -0,0 +1,89 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
+#
+# 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.
+
+"""Run layout tests."""
+
+import logging
+
+import test_expectations
+
+_log = logging.getLogger("webkitpy.layout_tests.run_webkit_tests")
+
+TestExpectationsFile = test_expectations.TestExpectationsFile
+
+
+class ResultSummary(object):
+ """A class for partitioning the test results we get into buckets.
+
+ This class is basically a glorified struct and it's private to this file
+ so we don't bother with any information hiding."""
+
+ def __init__(self, expectations, test_files):
+ self.total = len(test_files)
+ self.remaining = self.total
+ self.expectations = expectations
+ self.expected = 0
+ self.unexpected = 0
+ self.unexpected_failures = 0
+ self.unexpected_crashes_or_timeouts = 0
+ self.tests_by_expectation = {}
+ self.tests_by_timeline = {}
+ self.results = {}
+ self.unexpected_results = {}
+ self.failures = {}
+ self.tests_by_expectation[test_expectations.SKIP] = set()
+ for expectation in TestExpectationsFile.EXPECTATIONS.values():
+ self.tests_by_expectation[expectation] = set()
+ for timeline in TestExpectationsFile.TIMELINES.values():
+ self.tests_by_timeline[timeline] = (
+ expectations.get_tests_with_timeline(timeline))
+
+ def add(self, result, expected):
+ """Add a TestResult into the appropriate bin.
+
+ Args:
+ result: TestResult
+ expected: whether the result was what we expected it to be.
+ """
+
+ self.tests_by_expectation[result.type].add(result.filename)
+ self.results[result.filename] = result
+ self.remaining -= 1
+ if len(result.failures):
+ self.failures[result.filename] = result.failures
+ if expected:
+ self.expected += 1
+ else:
+ self.unexpected_results[result.filename] = result.type
+ self.unexpected += 1
+ if len(result.failures):
+ self.unexpected_failures += 1
+ if result.type == test_expectations.CRASH or result.type == test_expectations.TIMEOUT:
+ self.unexpected_crashes_or_timeouts += 1
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py
new file mode 100644
index 0000000..8645fc1
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations.py
@@ -0,0 +1,868 @@
+#!/usr/bin/env python
+# 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.
+
+"""A helper class for reading in and dealing with tests expectations
+for layout tests.
+"""
+
+import logging
+import os
+import re
+import sys
+
+import webkitpy.thirdparty.simplejson as simplejson
+
+_log = logging.getLogger("webkitpy.layout_tests.layout_package."
+ "test_expectations")
+
+# Test expectation and modifier constants.
+(PASS, FAIL, TEXT, IMAGE, IMAGE_PLUS_TEXT, TIMEOUT, CRASH, SKIP, WONTFIX,
+ SLOW, REBASELINE, MISSING, FLAKY, NOW, NONE) = range(15)
+
+# Test expectation file update action constants
+(NO_CHANGE, REMOVE_TEST, REMOVE_PLATFORM, ADD_PLATFORMS_EXCEPT_THIS) = range(4)
+
+
+def result_was_expected(result, expected_results, test_needs_rebaselining,
+ test_is_skipped):
+ """Returns whether we got a result we were expecting.
+ Args:
+ result: actual result of a test execution
+ expected_results: set of results listed in test_expectations
+ test_needs_rebaselining: whether test was marked as REBASELINE
+ test_is_skipped: whether test was marked as SKIP"""
+ if result in expected_results:
+ return True
+ if result in (IMAGE, TEXT, IMAGE_PLUS_TEXT) and FAIL in expected_results:
+ return True
+ if result == MISSING and test_needs_rebaselining:
+ return True
+ if result == SKIP and test_is_skipped:
+ return True
+ return False
+
+
+def remove_pixel_failures(expected_results):
+ """Returns a copy of the expected results for a test, except that we
+ drop any pixel failures and return the remaining expectations. For example,
+ if we're not running pixel tests, then tests expected to fail as IMAGE
+ will PASS."""
+ expected_results = expected_results.copy()
+ if IMAGE in expected_results:
+ expected_results.remove(IMAGE)
+ expected_results.add(PASS)
+ if IMAGE_PLUS_TEXT in expected_results:
+ expected_results.remove(IMAGE_PLUS_TEXT)
+ expected_results.add(TEXT)
+ return expected_results
+
+
+class TestExpectations:
+ TEST_LIST = "test_expectations.txt"
+
+ def __init__(self, port, tests, expectations, test_platform_name,
+ is_debug_mode, is_lint_mode, overrides=None):
+ """Loads and parses the test expectations given in the string.
+ Args:
+ port: handle to object containing platform-specific functionality
+ test: list of all of the test files
+ expectations: test expectations as a string
+ test_platform_name: name of the platform to match expectations
+ against. Note that this may be different than
+ port.test_platform_name() when is_lint_mode is True.
+ is_debug_mode: whether to use the DEBUG or RELEASE modifiers
+ in the expectations
+ is_lint_mode: If True, just parse the expectations string
+ looking for errors.
+ overrides: test expectations that are allowed to override any
+ entries in |expectations|. This is used by callers
+ that need to manage two sets of expectations (e.g., upstream
+ and downstream expectations).
+ """
+ self._expected_failures = TestExpectationsFile(port, expectations,
+ tests, test_platform_name, is_debug_mode, is_lint_mode,
+ overrides=overrides)
+
+ # TODO(ojan): Allow for removing skipped tests when getting the list of
+ # tests to run, but not when getting metrics.
+ # TODO(ojan): Replace the Get* calls here with the more sane API exposed
+ # by TestExpectationsFile below. Maybe merge the two classes entirely?
+
+ def get_expectations_json_for_all_platforms(self):
+ return (
+ self._expected_failures.get_expectations_json_for_all_platforms())
+
+ def get_rebaselining_failures(self):
+ return (self._expected_failures.get_test_set(REBASELINE, FAIL) |
+ self._expected_failures.get_test_set(REBASELINE, IMAGE) |
+ self._expected_failures.get_test_set(REBASELINE, TEXT) |
+ self._expected_failures.get_test_set(REBASELINE,
+ IMAGE_PLUS_TEXT))
+
+ def get_options(self, test):
+ return self._expected_failures.get_options(test)
+
+ def get_expectations(self, test):
+ return self._expected_failures.get_expectations(test)
+
+ def get_expectations_string(self, test):
+ """Returns the expectatons for the given test as an uppercase string.
+ If there are no expectations for the test, then "PASS" is returned."""
+ expectations = self.get_expectations(test)
+ retval = []
+
+ for expectation in expectations:
+ retval.append(self.expectation_to_string(expectation))
+
+ return " ".join(retval)
+
+ def expectation_to_string(self, expectation):
+ """Return the uppercased string equivalent of a given expectation."""
+ for item in TestExpectationsFile.EXPECTATIONS.items():
+ if item[1] == expectation:
+ return item[0].upper()
+ raise ValueError(expectation)
+
+ def get_tests_with_result_type(self, result_type):
+ return self._expected_failures.get_tests_with_result_type(result_type)
+
+ def get_tests_with_timeline(self, timeline):
+ return self._expected_failures.get_tests_with_timeline(timeline)
+
+ def matches_an_expected_result(self, test, result,
+ pixel_tests_are_enabled):
+ expected_results = self._expected_failures.get_expectations(test)
+ if not pixel_tests_are_enabled:
+ expected_results = remove_pixel_failures(expected_results)
+ return result_was_expected(result, expected_results,
+ self.is_rebaselining(test), self.has_modifier(test, SKIP))
+
+ def is_rebaselining(self, test):
+ return self._expected_failures.has_modifier(test, REBASELINE)
+
+ def has_modifier(self, test, modifier):
+ return self._expected_failures.has_modifier(test, modifier)
+
+ def remove_platform_from_expectations(self, tests, platform):
+ return self._expected_failures.remove_platform_from_expectations(
+ tests, platform)
+
+
+def strip_comments(line):
+ """Strips comments from a line and return None if the line is empty
+ or else the contents of line with leading and trailing spaces removed
+ and all other whitespace collapsed"""
+
+ commentIndex = line.find('//')
+ if commentIndex is -1:
+ commentIndex = len(line)
+
+ line = re.sub(r'\s+', ' ', line[:commentIndex].strip())
+ if line == '':
+ return None
+ else:
+ return line
+
+
+class ParseError(Exception):
+ def __init__(self, fatal, errors):
+ self.fatal = fatal
+ self.errors = errors
+
+ def __str__(self):
+ return '\n'.join(map(str, self.errors))
+
+ def __repr__(self):
+ return 'ParseError(fatal=%s, errors=%s)' % (fatal, errors)
+
+
+class ModifiersAndExpectations:
+ """A holder for modifiers and expectations on a test that serializes to
+ JSON."""
+
+ def __init__(self, modifiers, expectations):
+ self.modifiers = modifiers
+ self.expectations = expectations
+
+
+class ExpectationsJsonEncoder(simplejson.JSONEncoder):
+ """JSON encoder that can handle ModifiersAndExpectations objects."""
+ def default(self, obj):
+ # A ModifiersAndExpectations object has two fields, each of which
+ # is a dict. Since JSONEncoders handle all the builtin types directly,
+ # the only time this routine should be called is on the top level
+ # object (i.e., the encoder shouldn't recurse).
+ assert isinstance(obj, ModifiersAndExpectations)
+ return {"modifiers": obj.modifiers,
+ "expectations": obj.expectations}
+
+
+class TestExpectationsFile:
+ """Test expectation files consist of lines with specifications of what
+ to expect from layout test cases. The test cases can be directories
+ in which case the expectations apply to all test cases in that
+ directory and any subdirectory. The format of the file is along the
+ lines of:
+
+ LayoutTests/fast/js/fixme.js = FAIL
+ LayoutTests/fast/js/flaky.js = FAIL PASS
+ LayoutTests/fast/js/crash.js = CRASH TIMEOUT FAIL PASS
+ ...
+
+ To add other options:
+ SKIP : LayoutTests/fast/js/no-good.js = TIMEOUT PASS
+ DEBUG : LayoutTests/fast/js/no-good.js = TIMEOUT PASS
+ DEBUG SKIP : LayoutTests/fast/js/no-good.js = TIMEOUT PASS
+ LINUX DEBUG SKIP : LayoutTests/fast/js/no-good.js = TIMEOUT PASS
+ LINUX WIN : LayoutTests/fast/js/no-good.js = TIMEOUT PASS
+
+ SKIP: Doesn't run the test.
+ SLOW: The test takes a long time to run, but does not timeout indefinitely.
+ WONTFIX: For tests that we never intend to pass on a given platform.
+ DEBUG: Expectations apply only to the debug build.
+ RELEASE: Expectations apply only to release build.
+ LINUX/WIN/WIN-XP/WIN-VISTA/WIN-7/MAC: Expectations apply only to these
+ platforms.
+
+ Notes:
+ -A test cannot be both SLOW and TIMEOUT
+ -A test should only be one of IMAGE, TEXT, IMAGE+TEXT, or FAIL. FAIL is
+ a migratory state that currently means either IMAGE, TEXT, or
+ IMAGE+TEXT. Once we have finished migrating the expectations, we will
+ change FAIL to have the meaning of IMAGE+TEXT and remove the IMAGE+TEXT
+ identifier.
+ -A test can be included twice, but not via the same path.
+ -If a test is included twice, then the more precise path wins.
+ -CRASH tests cannot be WONTFIX
+ """
+
+ EXPECTATIONS = {'pass': PASS,
+ 'fail': FAIL,
+ 'text': TEXT,
+ 'image': IMAGE,
+ 'image+text': IMAGE_PLUS_TEXT,
+ 'timeout': TIMEOUT,
+ 'crash': CRASH,
+ 'missing': MISSING}
+
+ EXPECTATION_DESCRIPTIONS = {SKIP: ('skipped', 'skipped'),
+ PASS: ('pass', 'passes'),
+ FAIL: ('failure', 'failures'),
+ TEXT: ('text diff mismatch',
+ 'text diff mismatch'),
+ IMAGE: ('image mismatch', 'image mismatch'),
+ IMAGE_PLUS_TEXT: ('image and text mismatch',
+ 'image and text mismatch'),
+ CRASH: ('DumpRenderTree crash',
+ 'DumpRenderTree crashes'),
+ TIMEOUT: ('test timed out', 'tests timed out'),
+ MISSING: ('no expected result found',
+ 'no expected results found')}
+
+ EXPECTATION_ORDER = (PASS, CRASH, TIMEOUT, MISSING, IMAGE_PLUS_TEXT,
+ TEXT, IMAGE, FAIL, SKIP)
+
+ BUILD_TYPES = ('debug', 'release')
+
+ MODIFIERS = {'skip': SKIP,
+ 'wontfix': WONTFIX,
+ 'slow': SLOW,
+ 'rebaseline': REBASELINE,
+ 'none': NONE}
+
+ TIMELINES = {'wontfix': WONTFIX,
+ 'now': NOW}
+
+ RESULT_TYPES = {'skip': SKIP,
+ 'pass': PASS,
+ 'fail': FAIL,
+ 'flaky': FLAKY}
+
+ def __init__(self, port, expectations, full_test_list, test_platform_name,
+ is_debug_mode, is_lint_mode, overrides=None):
+ """
+ expectations: Contents of the expectations file
+ full_test_list: The list of all tests to be run pending processing of
+ the expections for those tests.
+ test_platform_name: name of the platform to match expectations
+ against. Note that this may be different than
+ port.test_platform_name() when is_lint_mode is True.
+ is_debug_mode: Whether we testing a test_shell built debug mode.
+ is_lint_mode: Whether this is just linting test_expecatations.txt.
+ overrides: test expectations that are allowed to override any
+ entries in |expectations|. This is used by callers
+ that need to manage two sets of expectations (e.g., upstream
+ and downstream expectations).
+ """
+
+ self._port = port
+ self._expectations = expectations
+ self._full_test_list = full_test_list
+ self._test_platform_name = test_platform_name
+ self._is_debug_mode = is_debug_mode
+ self._is_lint_mode = is_lint_mode
+ self._overrides = overrides
+ self._errors = []
+ self._non_fatal_errors = []
+
+ # Maps relative test paths as listed in the expectations file to a
+ # list of maps containing modifiers and expectations for each time
+ # the test is listed in the expectations file.
+ self._all_expectations = {}
+
+ # Maps a test to its list of expectations.
+ self._test_to_expectations = {}
+
+ # Maps a test to its list of options (string values)
+ self._test_to_options = {}
+
+ # Maps a test to its list of modifiers: the constants associated with
+ # the options minus any bug or platform strings
+ self._test_to_modifiers = {}
+
+ # Maps a test to the base path that it was listed with in the list.
+ self._test_list_paths = {}
+
+ self._modifier_to_tests = self._dict_of_sets(self.MODIFIERS)
+ self._expectation_to_tests = self._dict_of_sets(self.EXPECTATIONS)
+ self._timeline_to_tests = self._dict_of_sets(self.TIMELINES)
+ self._result_type_to_tests = self._dict_of_sets(self.RESULT_TYPES)
+
+ self._read(self._get_iterable_expectations(self._expectations),
+ overrides_allowed=False)
+
+ # List of tests that are in the overrides file (used for checking for
+ # duplicates inside the overrides file itself). Note that just because
+ # a test is in this set doesn't mean it's necessarily overridding a
+ # expectation in the regular expectations; the test might not be
+ # mentioned in the regular expectations file at all.
+ self._overridding_tests = set()
+
+ if overrides:
+ self._read(self._get_iterable_expectations(self._overrides),
+ overrides_allowed=True)
+
+ self._handle_any_read_errors()
+ self._process_tests_without_expectations()
+
+ def _handle_any_read_errors(self):
+ if len(self._errors) or len(self._non_fatal_errors):
+ if self._is_debug_mode:
+ build_type = 'DEBUG'
+ else:
+ build_type = 'RELEASE'
+ _log.error('')
+ _log.error("FAILURES FOR PLATFORM: %s, BUILD_TYPE: %s" %
+ (self._test_platform_name.upper(), build_type))
+
+ for error in self._errors:
+ _log.error(error)
+ for error in self._non_fatal_errors:
+ _log.error(error)
+
+ if len(self._errors):
+ raise ParseError(fatal=True, errors=self._errors)
+ if len(self._non_fatal_errors) and self._is_lint_mode:
+ raise ParseError(fatal=False, errors=self._non_fatal_errors)
+
+ def _process_tests_without_expectations(self):
+ expectations = set([PASS])
+ options = []
+ modifiers = []
+ if self._full_test_list:
+ for test in self._full_test_list:
+ if not test in self._test_list_paths:
+ self._add_test(test, modifiers, expectations, options,
+ overrides_allowed=False)
+
+ def _dict_of_sets(self, strings_to_constants):
+ """Takes a dict of strings->constants and returns a dict mapping
+ each constant to an empty set."""
+ d = {}
+ for c in strings_to_constants.values():
+ d[c] = set()
+ return d
+
+ def _get_iterable_expectations(self, expectations_str):
+ """Returns an object that can be iterated over. Allows for not caring
+ about whether we're iterating over a file or a new-line separated
+ string."""
+ iterable = [x + "\n" for x in expectations_str.split("\n")]
+ # Strip final entry if it's empty to avoid added in an extra
+ # newline.
+ if iterable[-1] == "\n":
+ return iterable[:-1]
+ return iterable
+
+ def get_test_set(self, modifier, expectation=None, include_skips=True):
+ if expectation is None:
+ tests = self._modifier_to_tests[modifier]
+ else:
+ tests = (self._expectation_to_tests[expectation] &
+ self._modifier_to_tests[modifier])
+
+ if not include_skips:
+ tests = tests - self.get_test_set(SKIP, expectation)
+
+ return tests
+
+ def get_tests_with_result_type(self, result_type):
+ return self._result_type_to_tests[result_type]
+
+ def get_tests_with_timeline(self, timeline):
+ return self._timeline_to_tests[timeline]
+
+ def get_options(self, test):
+ """This returns the entire set of options for the given test
+ (the modifiers plus the BUGXXXX identifier). This is used by the
+ LTTF dashboard."""
+ return self._test_to_options[test]
+
+ def has_modifier(self, test, modifier):
+ return test in self._modifier_to_tests[modifier]
+
+ def get_expectations(self, test):
+ return self._test_to_expectations[test]
+
+ def get_expectations_json_for_all_platforms(self):
+ # Specify separators in order to get compact encoding.
+ return ExpectationsJsonEncoder(separators=(',', ':')).encode(
+ self._all_expectations)
+
+ def get_non_fatal_errors(self):
+ return self._non_fatal_errors
+
+ def remove_platform_from_expectations(self, tests, platform):
+ """Returns a copy of the expectations with the tests matching the
+ platform removed.
+
+ If a test is in the test list and has an option that matches the given
+ platform, remove the matching platform and save the updated test back
+ to the file. If no other platforms remaining after removal, delete the
+ test from the file.
+
+ Args:
+ tests: list of tests that need to update..
+ platform: which platform option to remove.
+
+ Returns:
+ the updated string.
+ """
+
+ assert(platform)
+ f_orig = self._get_iterable_expectations(self._expectations)
+ f_new = []
+
+ tests_removed = 0
+ tests_updated = 0
+ lineno = 0
+ for line in f_orig:
+ lineno += 1
+ action = self._get_platform_update_action(line, lineno, tests,
+ platform)
+ assert(action in (NO_CHANGE, REMOVE_TEST, REMOVE_PLATFORM,
+ ADD_PLATFORMS_EXCEPT_THIS))
+ if action == NO_CHANGE:
+ # Save the original line back to the file
+ _log.debug('No change to test: %s', line)
+ f_new.append(line)
+ elif action == REMOVE_TEST:
+ tests_removed += 1
+ _log.info('Test removed: %s', line)
+ elif action == REMOVE_PLATFORM:
+ parts = line.split(':')
+ new_options = parts[0].replace(platform.upper() + ' ', '', 1)
+ new_line = ('%s:%s' % (new_options, parts[1]))
+ f_new.append(new_line)
+ tests_updated += 1
+ _log.info('Test updated: ')
+ _log.info(' old: %s', line)
+ _log.info(' new: %s', new_line)
+ elif action == ADD_PLATFORMS_EXCEPT_THIS:
+ parts = line.split(':')
+ new_options = parts[0]
+ for p in self._port.test_platform_names():
+ p = p.upper()
+ # This is a temp solution for rebaselining tool.
+ # Do not add tags WIN-7 and WIN-VISTA to test expectations
+ # if the original line does not specify the platform
+ # option.
+ # TODO(victorw): Remove WIN-VISTA and WIN-7 once we have
+ # reliable Win 7 and Win Vista buildbots setup.
+ if not p in (platform.upper(), 'WIN-VISTA', 'WIN-7'):
+ new_options += p + ' '
+ new_line = ('%s:%s' % (new_options, parts[1]))
+ f_new.append(new_line)
+ tests_updated += 1
+ _log.info('Test updated: ')
+ _log.info(' old: %s', line)
+ _log.info(' new: %s', new_line)
+
+ _log.info('Total tests removed: %d', tests_removed)
+ _log.info('Total tests updated: %d', tests_updated)
+
+ return "".join(f_new)
+
+ def parse_expectations_line(self, line, lineno):
+ """Parses a line from test_expectations.txt and returns a tuple
+ with the test path, options as a list, expectations as a list."""
+ line = strip_comments(line)
+ if not line:
+ return (None, None, None)
+
+ options = []
+ if line.find(":") is -1:
+ test_and_expectation = line.split("=")
+ else:
+ parts = line.split(":")
+ options = self._get_options_list(parts[0])
+ test_and_expectation = parts[1].split('=')
+
+ test = test_and_expectation[0].strip()
+ if (len(test_and_expectation) is not 2):
+ self._add_error(lineno, "Missing expectations.",
+ test_and_expectation)
+ expectations = None
+ else:
+ expectations = self._get_options_list(test_and_expectation[1])
+
+ return (test, options, expectations)
+
+ def _get_platform_update_action(self, line, lineno, tests, platform):
+ """Check the platform option and return the action needs to be taken.
+
+ Args:
+ line: current line in test expectations file.
+ lineno: current line number of line
+ tests: list of tests that need to update..
+ platform: which platform option to remove.
+
+ Returns:
+ NO_CHANGE: no change to the line (comments, test not in the list etc)
+ REMOVE_TEST: remove the test from file.
+ REMOVE_PLATFORM: remove this platform option from the test.
+ ADD_PLATFORMS_EXCEPT_THIS: add all the platforms except this one.
+ """
+ test, options, expectations = self.parse_expectations_line(line,
+ lineno)
+ if not test or test not in tests:
+ return NO_CHANGE
+
+ has_any_platform = False
+ for option in options:
+ if option in self._port.test_platform_names():
+ has_any_platform = True
+ if not option == platform:
+ return REMOVE_PLATFORM
+
+ # If there is no platform specified, then it means apply to all
+ # platforms. Return the action to add all the platforms except this
+ # one.
+ if not has_any_platform:
+ return ADD_PLATFORMS_EXCEPT_THIS
+
+ return REMOVE_TEST
+
+ def _has_valid_modifiers_for_current_platform(self, options, lineno,
+ test_and_expectations, modifiers):
+ """Returns true if the current platform is in the options list or if
+ no platforms are listed and if there are no fatal errors in the
+ options list.
+
+ Args:
+ options: List of lowercase options.
+ lineno: The line in the file where the test is listed.
+ test_and_expectations: The path and expectations for the test.
+ modifiers: The set to populate with modifiers.
+ """
+ has_any_platform = False
+ has_bug_id = False
+ for option in options:
+ if option in self.MODIFIERS:
+ modifiers.add(option)
+ elif option in self._port.test_platform_names():
+ has_any_platform = True
+ elif re.match(r'bug\d', option) != None:
+ self._add_error(lineno, 'Bug must be either BUGCR, BUGWK, or BUGV8_ for test: %s' %
+ option, test_and_expectations)
+ elif option.startswith('bug'):
+ has_bug_id = True
+ elif option not in self.BUILD_TYPES:
+ self._add_error(lineno, 'Invalid modifier for test: %s' %
+ option, test_and_expectations)
+
+ if has_any_platform and not self._match_platform(options):
+ return False
+
+ if not has_bug_id and 'wontfix' not in options:
+ # TODO(ojan): Turn this into an AddError call once all the
+ # tests have BUG identifiers.
+ self._log_non_fatal_error(lineno, 'Test lacks BUG modifier.',
+ test_and_expectations)
+
+ if 'release' in options or 'debug' in options:
+ if self._is_debug_mode and 'debug' not in options:
+ return False
+ if not self._is_debug_mode and 'release' not in options:
+ return False
+
+ if self._is_lint_mode and 'rebaseline' in options:
+ self._add_error(lineno,
+ 'REBASELINE should only be used for running rebaseline.py. '
+ 'Cannot be checked in.', test_and_expectations)
+
+ return True
+
+ def _match_platform(self, options):
+ """Match the list of options against our specified platform. If any
+ of the options prefix-match self._platform, return True. This handles
+ the case where a test is marked WIN and the platform is WIN-VISTA.
+
+ Args:
+ options: list of options
+ """
+ for opt in options:
+ if self._test_platform_name.startswith(opt):
+ return True
+ return False
+
+ def _add_to_all_expectations(self, test, options, expectations):
+ # Make all paths unix-style so the dashboard doesn't need to.
+ test = test.replace('\\', '/')
+ if not test in self._all_expectations:
+ self._all_expectations[test] = []
+ self._all_expectations[test].append(
+ ModifiersAndExpectations(options, expectations))
+
+ def _read(self, expectations, overrides_allowed):
+ """For each test in an expectations iterable, generate the
+ expectations for it."""
+ lineno = 0
+ for line in expectations:
+ lineno += 1
+
+ test_list_path, options, expectations = \
+ self.parse_expectations_line(line, lineno)
+ if not expectations:
+ continue
+
+ self._add_to_all_expectations(test_list_path,
+ " ".join(options).upper(),
+ " ".join(expectations).upper())
+
+ modifiers = set()
+ if options and not self._has_valid_modifiers_for_current_platform(
+ options, lineno, test_list_path, modifiers):
+ continue
+
+ expectations = self._parse_expectations(expectations, lineno,
+ test_list_path)
+
+ if 'slow' in options and TIMEOUT in expectations:
+ self._add_error(lineno,
+ 'A test can not be both slow and timeout. If it times out '
+ 'indefinitely, then it should be just timeout.',
+ test_list_path)
+
+ full_path = os.path.join(self._port.layout_tests_dir(),
+ test_list_path)
+ full_path = os.path.normpath(full_path)
+ # WebKit's way of skipping tests is to add a -disabled suffix.
+ # So we should consider the path existing if the path or the
+ # -disabled version exists.
+ if (not self._port.path_exists(full_path)
+ and not self._port.path_exists(full_path + '-disabled')):
+ # Log a non fatal error here since you hit this case any
+ # time you update test_expectations.txt without syncing
+ # the LayoutTests directory
+ self._log_non_fatal_error(lineno, 'Path does not exist.',
+ test_list_path)
+ continue
+
+ if not self._full_test_list:
+ tests = [test_list_path]
+ else:
+ tests = self._expand_tests(test_list_path)
+
+ self._add_tests(tests, expectations, test_list_path, lineno,
+ modifiers, options, overrides_allowed)
+
+ def _get_options_list(self, listString):
+ return [part.strip().lower() for part in listString.strip().split(' ')]
+
+ def _parse_expectations(self, expectations, lineno, test_list_path):
+ result = set()
+ for part in expectations:
+ if not part in self.EXPECTATIONS:
+ self._add_error(lineno, 'Unsupported expectation: %s' % part,
+ test_list_path)
+ continue
+ expectation = self.EXPECTATIONS[part]
+ result.add(expectation)
+ return result
+
+ def _expand_tests(self, test_list_path):
+ """Convert the test specification to an absolute, normalized
+ path and make sure directories end with the OS path separator."""
+ # FIXME: full_test_list can quickly contain a big amount of
+ # elements. We should consider at some point to use a more
+ # efficient structure instead of a list. Maybe a dictionary of
+ # lists to represent the tree of tests, leaves being test
+ # files and nodes being categories.
+
+ path = os.path.join(self._port.layout_tests_dir(), test_list_path)
+ path = os.path.normpath(path)
+ if self._port.path_isdir(path):
+ # this is a test category, return all the tests of the category.
+ path = os.path.join(path, '')
+
+ return [test for test in self._full_test_list if test.startswith(path)]
+
+ # this is a test file, do a quick check if it's in the
+ # full test suite.
+ result = []
+ if path in self._full_test_list:
+ result = [path, ]
+ return result
+
+ def _add_tests(self, tests, expectations, test_list_path, lineno,
+ modifiers, options, overrides_allowed):
+ for test in tests:
+ if self._already_seen_test(test, test_list_path, lineno,
+ overrides_allowed):
+ continue
+
+ self._clear_expectations_for_test(test, test_list_path)
+ self._add_test(test, modifiers, expectations, options,
+ overrides_allowed)
+
+ def _add_test(self, test, modifiers, expectations, options,
+ overrides_allowed):
+ """Sets the expected state for a given test.
+
+ This routine assumes the test has not been added before. If it has,
+ use _ClearExpectationsForTest() to reset the state prior to
+ calling this.
+
+ Args:
+ test: test to add
+ modifiers: sequence of modifier keywords ('wontfix', 'slow', etc.)
+ expectations: sequence of expectations (PASS, IMAGE, etc.)
+ options: sequence of keywords and bug identifiers.
+ overrides_allowed: whether we're parsing the regular expectations
+ or the overridding expectations"""
+ self._test_to_expectations[test] = expectations
+ for expectation in expectations:
+ self._expectation_to_tests[expectation].add(test)
+
+ self._test_to_options[test] = options
+ self._test_to_modifiers[test] = set()
+ for modifier in modifiers:
+ mod_value = self.MODIFIERS[modifier]
+ self._modifier_to_tests[mod_value].add(test)
+ self._test_to_modifiers[test].add(mod_value)
+
+ if 'wontfix' in modifiers:
+ self._timeline_to_tests[WONTFIX].add(test)
+ else:
+ self._timeline_to_tests[NOW].add(test)
+
+ if 'skip' in modifiers:
+ self._result_type_to_tests[SKIP].add(test)
+ elif expectations == set([PASS]):
+ self._result_type_to_tests[PASS].add(test)
+ elif len(expectations) > 1:
+ self._result_type_to_tests[FLAKY].add(test)
+ else:
+ self._result_type_to_tests[FAIL].add(test)
+
+ if overrides_allowed:
+ self._overridding_tests.add(test)
+
+ def _clear_expectations_for_test(self, test, test_list_path):
+ """Remove prexisting expectations for this test.
+ This happens if we are seeing a more precise path
+ than a previous listing.
+ """
+ if test in self._test_list_paths:
+ self._test_to_expectations.pop(test, '')
+ self._remove_from_sets(test, self._expectation_to_tests)
+ self._remove_from_sets(test, self._modifier_to_tests)
+ self._remove_from_sets(test, self._timeline_to_tests)
+ self._remove_from_sets(test, self._result_type_to_tests)
+
+ self._test_list_paths[test] = os.path.normpath(test_list_path)
+
+ def _remove_from_sets(self, test, dict):
+ """Removes the given test from the sets in the dictionary.
+
+ Args:
+ test: test to look for
+ dict: dict of sets of files"""
+ for set_of_tests in dict.itervalues():
+ if test in set_of_tests:
+ set_of_tests.remove(test)
+
+ def _already_seen_test(self, test, test_list_path, lineno,
+ allow_overrides):
+ """Returns true if we've already seen a more precise path for this test
+ than the test_list_path.
+ """
+ if not test in self._test_list_paths:
+ return False
+
+ prev_base_path = self._test_list_paths[test]
+ if (prev_base_path == os.path.normpath(test_list_path)):
+ if (not allow_overrides or test in self._overridding_tests):
+ if allow_overrides:
+ expectation_source = "override"
+ else:
+ expectation_source = "expectation"
+ self._add_error(lineno, 'Duplicate %s.' % expectation_source,
+ test)
+ return True
+ else:
+ # We have seen this path, but that's okay because its
+ # in the overrides and the earlier path was in the
+ # expectations.
+ return False
+
+ # Check if we've already seen a more precise path.
+ return prev_base_path.startswith(os.path.normpath(test_list_path))
+
+ def _add_error(self, lineno, msg, path):
+ """Reports an error that will prevent running the tests. Does not
+ immediately raise an exception because we'd like to aggregate all the
+ errors so they can all be printed out."""
+ self._errors.append('Line:%s %s %s' % (lineno, msg, path))
+
+ def _log_non_fatal_error(self, lineno, msg, path):
+ """Reports an error that will not prevent running the tests. These are
+ still errors, but not bad enough to warrant breaking test running."""
+ self._non_fatal_errors.append('Line:%s %s %s' % (lineno, msg, path))
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py
new file mode 100644
index 0000000..34771f3
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_expectations_unittest.py
@@ -0,0 +1,350 @@
+#!/usr/bin/python
+# 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.
+
+"""Unit tests for test_expectations.py."""
+
+import os
+import sys
+import unittest
+
+from webkitpy.layout_tests import port
+from webkitpy.layout_tests.layout_package.test_expectations import *
+
+class FunctionsTest(unittest.TestCase):
+ def test_result_was_expected(self):
+ # test basics
+ self.assertEquals(result_was_expected(PASS, set([PASS]),
+ False, False), True)
+ self.assertEquals(result_was_expected(TEXT, set([PASS]),
+ False, False), False)
+
+ # test handling of FAIL expectations
+ self.assertEquals(result_was_expected(IMAGE_PLUS_TEXT, set([FAIL]),
+ False, False), True)
+ self.assertEquals(result_was_expected(IMAGE, set([FAIL]),
+ False, False), True)
+ self.assertEquals(result_was_expected(TEXT, set([FAIL]),
+ False, False), True)
+ self.assertEquals(result_was_expected(CRASH, set([FAIL]),
+ False, False), False)
+
+ # test handling of SKIPped tests and results
+ self.assertEquals(result_was_expected(SKIP, set([CRASH]),
+ False, True), True)
+ self.assertEquals(result_was_expected(SKIP, set([CRASH]),
+ False, False), False)
+
+ # test handling of MISSING results and the REBASELINE modifier
+ self.assertEquals(result_was_expected(MISSING, set([PASS]),
+ True, False), True)
+ self.assertEquals(result_was_expected(MISSING, set([PASS]),
+ False, False), False)
+
+ def test_remove_pixel_failures(self):
+ self.assertEquals(remove_pixel_failures(set([TEXT])),
+ set([TEXT]))
+ self.assertEquals(remove_pixel_failures(set([PASS])),
+ set([PASS]))
+ self.assertEquals(remove_pixel_failures(set([IMAGE])),
+ set([PASS]))
+ self.assertEquals(remove_pixel_failures(set([IMAGE_PLUS_TEXT])),
+ set([TEXT]))
+ self.assertEquals(remove_pixel_failures(set([PASS, IMAGE, CRASH])),
+ set([PASS, CRASH]))
+
+
+class Base(unittest.TestCase):
+ def __init__(self, testFunc, setUp=None, tearDown=None, description=None):
+ self._port = port.get('test', None)
+ self._exp = None
+ unittest.TestCase.__init__(self, testFunc)
+
+ def get_test(self, test_name):
+ return os.path.join(self._port.layout_tests_dir(), test_name)
+
+ def get_basic_tests(self):
+ return [self.get_test('failures/expected/text.html'),
+ self.get_test('failures/expected/image_checksum.html'),
+ self.get_test('failures/expected/crash.html'),
+ self.get_test('failures/expected/missing_text.html'),
+ self.get_test('failures/expected/image.html'),
+ self.get_test('passes/text.html')]
+
+ def get_basic_expectations(self):
+ return """
+BUG_TEST : failures/expected/text.html = TEXT
+BUG_TEST WONTFIX SKIP : failures/expected/crash.html = CRASH
+BUG_TEST REBASELINE : failures/expected/missing_image.html = MISSING
+BUG_TEST WONTFIX : failures/expected/image_checksum.html = IMAGE
+BUG_TEST WONTFIX WIN : failures/expected/image.html = IMAGE
+"""
+
+ def parse_exp(self, expectations, overrides=None, is_lint_mode=False,
+ is_debug_mode=False):
+ self._exp = TestExpectations(self._port,
+ tests=self.get_basic_tests(),
+ expectations=expectations,
+ test_platform_name=self._port.test_platform_name(),
+ is_debug_mode=is_debug_mode,
+ is_lint_mode=is_lint_mode,
+ overrides=overrides)
+
+ def assert_exp(self, test, result):
+ self.assertEquals(self._exp.get_expectations(self.get_test(test)),
+ set([result]))
+
+
+class TestExpectationsTest(Base):
+ def test_basic(self):
+ self.parse_exp(self.get_basic_expectations())
+ self.assert_exp('failures/expected/text.html', TEXT)
+ self.assert_exp('failures/expected/image_checksum.html', IMAGE)
+ self.assert_exp('passes/text.html', PASS)
+ self.assert_exp('failures/expected/image.html', PASS)
+
+ def test_multiple_results(self):
+ self.parse_exp('BUGX : failures/expected/text.html = TEXT CRASH')
+ self.assertEqual(self._exp.get_expectations(
+ self.get_test('failures/expected/text.html')),
+ set([TEXT, CRASH]))
+
+ def test_precedence(self):
+ # This tests handling precedence of specific lines over directories
+ # and tests expectations covering entire directories.
+ exp_str = """
+BUGX : failures/expected/text.html = TEXT
+BUGX WONTFIX : failures/expected = IMAGE
+"""
+ self.parse_exp(exp_str)
+ self.assert_exp('failures/expected/text.html', TEXT)
+ self.assert_exp('failures/expected/crash.html', IMAGE)
+
+ def test_category_expectations(self):
+ # This test checks unknown tests are not present in the
+ # expectations and that known test part of a test category is
+ # present in the expectations.
+ exp_str = """
+BUGX WONTFIX : failures/expected = IMAGE
+"""
+ self.parse_exp(exp_str)
+ test_name = 'failures/expected/unknown-test.html'
+ unknown_test = self.get_test(test_name)
+ self.assertRaises(KeyError, self._exp.get_expectations,
+ unknown_test)
+ self.assert_exp('failures/expected/crash.html', IMAGE)
+
+ def test_release_mode(self):
+ self.parse_exp('BUGX DEBUG : failures/expected/text.html = TEXT',
+ is_debug_mode=True)
+ self.assert_exp('failures/expected/text.html', TEXT)
+ self.parse_exp('BUGX RELEASE : failures/expected/text.html = TEXT',
+ is_debug_mode=True)
+ self.assert_exp('failures/expected/text.html', PASS)
+ self.parse_exp('BUGX DEBUG : failures/expected/text.html = TEXT',
+ is_debug_mode=False)
+ self.assert_exp('failures/expected/text.html', PASS)
+ self.parse_exp('BUGX RELEASE : failures/expected/text.html = TEXT',
+ is_debug_mode=False)
+ self.assert_exp('failures/expected/text.html', TEXT)
+
+ def test_get_options(self):
+ self.parse_exp(self.get_basic_expectations())
+ self.assertEqual(self._exp.get_options(
+ self.get_test('passes/text.html')), [])
+
+ def test_expectations_json_for_all_platforms(self):
+ self.parse_exp(self.get_basic_expectations())
+ json_str = self._exp.get_expectations_json_for_all_platforms()
+ # FIXME: test actual content?
+ self.assertTrue(json_str)
+
+ def test_get_expectations_string(self):
+ self.parse_exp(self.get_basic_expectations())
+ self.assertEquals(self._exp.get_expectations_string(
+ self.get_test('failures/expected/text.html')),
+ 'TEXT')
+
+ def test_expectation_to_string(self):
+ # Normal cases are handled by other tests.
+ self.parse_exp(self.get_basic_expectations())
+ self.assertRaises(ValueError, self._exp.expectation_to_string,
+ -1)
+
+ def test_get_test_set(self):
+ # Handle some corner cases for this routine not covered by other tests.
+ self.parse_exp(self.get_basic_expectations())
+ s = self._exp._expected_failures.get_test_set(WONTFIX)
+ self.assertEqual(s,
+ set([self.get_test('failures/expected/crash.html'),
+ self.get_test('failures/expected/image_checksum.html')]))
+ s = self._exp._expected_failures.get_test_set(WONTFIX, CRASH)
+ self.assertEqual(s,
+ set([self.get_test('failures/expected/crash.html')]))
+ s = self._exp._expected_failures.get_test_set(WONTFIX, CRASH,
+ include_skips=False)
+ self.assertEqual(s, set([]))
+
+ def test_parse_error_fatal(self):
+ try:
+ self.parse_exp("""FOO : failures/expected/text.html = TEXT
+SKIP : failures/expected/image.html""")
+ self.assertFalse(True, "ParseError wasn't raised")
+ except ParseError, e:
+ self.assertTrue(e.fatal)
+ exp_errors = [u'Line:1 Invalid modifier for test: foo failures/expected/text.html',
+ u"Line:2 Missing expectations. [' failures/expected/image.html']"]
+ self.assertEqual(str(e), '\n'.join(map(str, exp_errors)))
+ self.assertEqual(e.errors, exp_errors)
+
+ def test_parse_error_nonfatal(self):
+ try:
+ self.parse_exp('SKIP : failures/expected/text.html = TEXT',
+ is_lint_mode=True)
+ self.assertFalse(True, "ParseError wasn't raised")
+ except ParseError, e:
+ self.assertFalse(e.fatal)
+ exp_errors = [u'Line:1 Test lacks BUG modifier. failures/expected/text.html']
+ self.assertEqual(str(e), '\n'.join(map(str, exp_errors)))
+ self.assertEqual(e.errors, exp_errors)
+
+ def test_syntax_missing_expectation(self):
+ # This is missing the expectation.
+ self.assertRaises(ParseError, self.parse_exp,
+ 'BUG_TEST: failures/expected/text.html',
+ is_debug_mode=True)
+
+ def test_syntax_invalid_option(self):
+ self.assertRaises(ParseError, self.parse_exp,
+ 'BUG_TEST FOO: failures/expected/text.html = PASS')
+
+ def test_syntax_invalid_expectation(self):
+ # This is missing the expectation.
+ self.assertRaises(ParseError, self.parse_exp,
+ 'BUG_TEST: failures/expected/text.html = FOO')
+
+ def test_syntax_missing_bugid(self):
+ # This should log a non-fatal error.
+ self.parse_exp('SLOW : failures/expected/text.html = TEXT')
+ self.assertEqual(
+ len(self._exp._expected_failures.get_non_fatal_errors()), 1)
+
+ def test_semantic_slow_and_timeout(self):
+ # A test cannot be SLOW and expected to TIMEOUT.
+ self.assertRaises(ParseError, self.parse_exp,
+ 'BUG_TEST SLOW : failures/expected/timeout.html = TIMEOUT')
+
+ def test_semantic_rebaseline(self):
+ # Can't lint a file w/ 'REBASELINE' in it.
+ self.assertRaises(ParseError, self.parse_exp,
+ 'BUG_TEST REBASELINE : failures/expected/text.html = TEXT',
+ is_lint_mode=True)
+
+ def test_semantic_duplicates(self):
+ self.assertRaises(ParseError, self.parse_exp, """
+BUG_TEST : failures/expected/text.html = TEXT
+BUG_TEST : failures/expected/text.html = IMAGE""")
+
+ self.assertRaises(ParseError, self.parse_exp,
+ self.get_basic_expectations(), """
+BUG_TEST : failures/expected/text.html = TEXT
+BUG_TEST : failures/expected/text.html = IMAGE""")
+
+ def test_semantic_missing_file(self):
+ # This should log a non-fatal error.
+ self.parse_exp('BUG_TEST : missing_file.html = TEXT')
+ self.assertEqual(
+ len(self._exp._expected_failures.get_non_fatal_errors()), 1)
+
+
+ def test_overrides(self):
+ self.parse_exp(self.get_basic_expectations(), """
+BUG_OVERRIDE : failures/expected/text.html = IMAGE""")
+ self.assert_exp('failures/expected/text.html', IMAGE)
+
+ def test_matches_an_expected_result(self):
+
+ def match(test, result, pixel_tests_enabled):
+ return self._exp.matches_an_expected_result(
+ self.get_test(test), result, pixel_tests_enabled)
+
+ self.parse_exp(self.get_basic_expectations())
+ self.assertTrue(match('failures/expected/text.html', TEXT, True))
+ self.assertTrue(match('failures/expected/text.html', TEXT, False))
+ self.assertFalse(match('failures/expected/text.html', CRASH, True))
+ self.assertFalse(match('failures/expected/text.html', CRASH, False))
+ self.assertTrue(match('failures/expected/image_checksum.html', IMAGE,
+ True))
+ self.assertTrue(match('failures/expected/image_checksum.html', PASS,
+ False))
+ self.assertTrue(match('failures/expected/crash.html', SKIP, False))
+ self.assertTrue(match('passes/text.html', PASS, False))
+
+
+class RebaseliningTest(Base):
+ """Test rebaselining-specific functionality."""
+ def assertRemove(self, platform, input_expectations, expected_expectations):
+ self.parse_exp(input_expectations)
+ test = self.get_test('failures/expected/text.html')
+ actual_expectations = self._exp.remove_platform_from_expectations(
+ test, platform)
+ self.assertEqual(expected_expectations, actual_expectations)
+
+ def test_no_get_rebaselining_failures(self):
+ self.parse_exp(self.get_basic_expectations())
+ self.assertEqual(len(self._exp.get_rebaselining_failures()), 0)
+
+ def test_get_rebaselining_failures_expand(self):
+ self.parse_exp("""
+BUG_TEST REBASELINE : failures/expected/text.html = TEXT
+""")
+ self.assertEqual(len(self._exp.get_rebaselining_failures()), 1)
+
+ def test_remove_expand(self):
+ self.assertRemove('mac',
+ 'BUGX REBASELINE : failures/expected/text.html = TEXT\n',
+ 'BUGX REBASELINE WIN : failures/expected/text.html = TEXT\n')
+
+ def test_remove_mac_win(self):
+ self.assertRemove('mac',
+ 'BUGX REBASELINE MAC WIN : failures/expected/text.html = TEXT\n',
+ 'BUGX REBASELINE WIN : failures/expected/text.html = TEXT\n')
+
+ def test_remove_mac_mac(self):
+ self.assertRemove('mac',
+ 'BUGX REBASELINE MAC : failures/expected/text.html = TEXT\n',
+ '')
+
+ def test_remove_nothing(self):
+ self.assertRemove('mac',
+ '\n\n',
+ '\n\n')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py
new file mode 100644
index 0000000..6d55761
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures.py
@@ -0,0 +1,282 @@
+#!/usr/bin/env python
+# 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.
+
+"""Classes for failures that occur during tests."""
+
+import os
+import test_expectations
+
+import cPickle
+
+
+def determine_result_type(failure_list):
+ """Takes a set of test_failures and returns which result type best fits
+ the list of failures. "Best fits" means we use the worst type of failure.
+
+ Returns:
+ one of the test_expectations result types - PASS, TEXT, CRASH, etc."""
+
+ if not failure_list or len(failure_list) == 0:
+ return test_expectations.PASS
+
+ failure_types = [type(f) for f in failure_list]
+ if FailureCrash in failure_types:
+ return test_expectations.CRASH
+ elif FailureTimeout in failure_types:
+ return test_expectations.TIMEOUT
+ elif (FailureMissingResult in failure_types or
+ FailureMissingImage in failure_types or
+ FailureMissingImageHash in failure_types):
+ return test_expectations.MISSING
+ else:
+ is_text_failure = FailureTextMismatch in failure_types
+ is_image_failure = (FailureImageHashIncorrect in failure_types or
+ FailureImageHashMismatch in failure_types)
+ if is_text_failure and is_image_failure:
+ return test_expectations.IMAGE_PLUS_TEXT
+ elif is_text_failure:
+ return test_expectations.TEXT
+ elif is_image_failure:
+ return test_expectations.IMAGE
+ else:
+ raise ValueError("unclassifiable set of failures: "
+ + str(failure_types))
+
+
+class TestFailure(object):
+ """Abstract base class that defines the failure interface."""
+
+ @staticmethod
+ def loads(s):
+ """Creates a TestFailure object from the specified string."""
+ return cPickle.loads(s)
+
+ @staticmethod
+ def message():
+ """Returns a string describing the failure in more detail."""
+ raise NotImplementedError
+
+ def __eq__(self, other):
+ return self.__class__.__name__ == other.__class__.__name__
+
+ def __ne__(self, other):
+ return self.__class__.__name__ != other.__class__.__name__
+
+ def dumps(self):
+ """Returns the string/JSON representation of a TestFailure."""
+ return cPickle.dumps(self)
+
+ def result_html_output(self, filename):
+ """Returns an HTML string to be included on the results.html page."""
+ raise NotImplementedError
+
+ def should_kill_dump_render_tree(self):
+ """Returns True if we should kill DumpRenderTree before the next
+ test."""
+ return False
+
+ def relative_output_filename(self, filename, modifier):
+ """Returns a relative filename inside the output dir that contains
+ modifier.
+
+ For example, if filename is fast\dom\foo.html and modifier is
+ "-expected.txt", the return value is fast\dom\foo-expected.txt
+
+ Args:
+ filename: relative filename to test file
+ modifier: a string to replace the extension of filename with
+
+ Return:
+ The relative windows path to the output filename
+ """
+ return os.path.splitext(filename)[0] + modifier
+
+
+class FailureWithType(TestFailure):
+ """Base class that produces standard HTML output based on the test type.
+
+ Subclasses may commonly choose to override the ResultHtmlOutput, but still
+ use the standard OutputLinks.
+ """
+
+ def __init__(self):
+ TestFailure.__init__(self)
+
+ # Filename suffixes used by ResultHtmlOutput.
+ OUT_FILENAMES = ()
+
+ def output_links(self, filename, out_names):
+ """Returns a string holding all applicable output file links.
+
+ Args:
+ filename: the test filename, used to construct the result file names
+ out_names: list of filename suffixes for the files. If three or more
+ suffixes are in the list, they should be [actual, expected, diff,
+ wdiff]. Two suffixes should be [actual, expected], and a
+ single item is the [actual] filename suffix.
+ If out_names is empty, returns the empty string.
+ """
+ # FIXME: Seems like a bad idea to separate the display name data
+ # from the path data by hard-coding the display name here
+ # and passing in the path information via out_names.
+ #
+ # FIXME: Also, we don't know for sure that these files exist,
+ # and we shouldn't be creating links to files that don't exist
+ # (for example, if we don't actually have wdiff output).
+ links = ['']
+ uris = [self.relative_output_filename(filename, fn) for
+ fn in out_names]
+ if len(uris) > 1:
+ links.append("<a href='%s'>expected</a>" % uris[1])
+ if len(uris) > 0:
+ links.append("<a href='%s'>actual</a>" % uris[0])
+ if len(uris) > 2:
+ links.append("<a href='%s'>diff</a>" % uris[2])
+ if len(uris) > 3:
+ links.append("<a href='%s'>wdiff</a>" % uris[3])
+ if len(uris) > 4:
+ links.append("<a href='%s'>pretty diff</a>" % uris[4])
+ return ' '.join(links)
+
+ def result_html_output(self, filename):
+ return self.message() + self.output_links(filename, self.OUT_FILENAMES)
+
+
+class FailureTimeout(TestFailure):
+ """Test timed out. We also want to restart DumpRenderTree if this
+ happens."""
+
+ @staticmethod
+ def message():
+ return "Test timed out"
+
+ def result_html_output(self, filename):
+ return "<strong>%s</strong>" % self.message()
+
+ def should_kill_dump_render_tree(self):
+ return True
+
+
+class FailureCrash(TestFailure):
+ """Test shell crashed."""
+
+ @staticmethod
+ def message():
+ return "Test shell crashed"
+
+ def result_html_output(self, filename):
+ # FIXME: create a link to the minidump file
+ stack = self.relative_output_filename(filename, "-stack.txt")
+ return "<strong>%s</strong> <a href=%s>stack</a>" % (self.message(),
+ stack)
+
+ def should_kill_dump_render_tree(self):
+ return True
+
+
+class FailureMissingResult(FailureWithType):
+ """Expected result was missing."""
+ OUT_FILENAMES = ("-actual.txt",)
+
+ @staticmethod
+ def message():
+ return "No expected results found"
+
+ def result_html_output(self, filename):
+ return ("<strong>%s</strong>" % self.message() +
+ self.output_links(filename, self.OUT_FILENAMES))
+
+
+class FailureTextMismatch(FailureWithType):
+ """Text diff output failed."""
+ # Filename suffixes used by ResultHtmlOutput.
+ # FIXME: Why don't we use the constants from TestTypeBase here?
+ OUT_FILENAMES = ("-actual.txt", "-expected.txt", "-diff.txt",
+ "-wdiff.html", "-pretty-diff.html")
+
+ @staticmethod
+ def message():
+ return "Text diff mismatch"
+
+
+class FailureMissingImageHash(FailureWithType):
+ """Actual result hash was missing."""
+ # Chrome doesn't know to display a .checksum file as text, so don't bother
+ # putting in a link to the actual result.
+
+ @staticmethod
+ def message():
+ return "No expected image hash found"
+
+ def result_html_output(self, filename):
+ return "<strong>%s</strong>" % self.message()
+
+
+class FailureMissingImage(FailureWithType):
+ """Actual result image was missing."""
+ OUT_FILENAMES = ("-actual.png",)
+
+ @staticmethod
+ def message():
+ return "No expected image found"
+
+ def result_html_output(self, filename):
+ return ("<strong>%s</strong>" % self.message() +
+ self.output_links(filename, self.OUT_FILENAMES))
+
+
+class FailureImageHashMismatch(FailureWithType):
+ """Image hashes didn't match."""
+ OUT_FILENAMES = ("-actual.png", "-expected.png", "-diff.png")
+
+ @staticmethod
+ def message():
+ # We call this a simple image mismatch to avoid confusion, since
+ # we link to the PNGs rather than the checksums.
+ return "Image mismatch"
+
+
+class FailureImageHashIncorrect(FailureWithType):
+ """Actual result hash is incorrect."""
+ # Chrome doesn't know to display a .checksum file as text, so don't bother
+ # putting in a link to the actual result.
+
+ @staticmethod
+ def message():
+ return "Images match, expected image hash incorrect. "
+
+ def result_html_output(self, filename):
+ return "<strong>%s</strong>" % self.message()
+
+# Convenient collection of all failure classes for anything that might
+# need to enumerate over them all.
+ALL_FAILURE_CLASSES = (FailureTimeout, FailureCrash, FailureMissingResult,
+ FailureTextMismatch, FailureMissingImageHash,
+ FailureMissingImage, FailureImageHashMismatch,
+ FailureImageHashIncorrect)
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py
new file mode 100644
index 0000000..3e3528d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_failures_unittest.py
@@ -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.
+
+""""Tests code paths not covered by the regular unit tests."""
+
+import unittest
+
+from webkitpy.layout_tests.layout_package.test_failures import *
+
+
+class Test(unittest.TestCase):
+ def assertResultHtml(self, failure_obj):
+ self.assertNotEqual(failure_obj.result_html_output('foo'), None)
+
+ def assert_loads(self, cls):
+ failure_obj = cls()
+ s = failure_obj.dumps()
+ new_failure_obj = TestFailure.loads(s)
+ self.assertTrue(isinstance(new_failure_obj, cls))
+
+ self.assertEqual(failure_obj, new_failure_obj)
+
+ # Also test that != is implemented.
+ self.assertFalse(failure_obj != new_failure_obj)
+
+ def test_crash(self):
+ self.assertResultHtml(FailureCrash())
+
+ def test_hash_incorrect(self):
+ self.assertResultHtml(FailureImageHashIncorrect())
+
+ def test_missing(self):
+ self.assertResultHtml(FailureMissingResult())
+
+ def test_missing_image(self):
+ self.assertResultHtml(FailureMissingImage())
+
+ def test_missing_image_hash(self):
+ self.assertResultHtml(FailureMissingImageHash())
+
+ def test_timeout(self):
+ self.assertResultHtml(FailureTimeout())
+
+ def test_unknown_failure_type(self):
+ class UnknownFailure(TestFailure):
+ pass
+
+ failure_obj = UnknownFailure()
+ self.assertRaises(ValueError, determine_result_type, [failure_obj])
+ self.assertRaises(NotImplementedError, failure_obj.message)
+ self.assertRaises(NotImplementedError, failure_obj.result_html_output,
+ "foo.txt")
+
+ def test_loads(self):
+ for c in ALL_FAILURE_CLASSES:
+ self.assert_loads(c)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_input.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_input.py
new file mode 100644
index 0000000..4b027c0
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_input.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
+#
+# 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.
+
+
+class TestInput:
+ """Groups information about a test for easy passing of data."""
+
+ def __init__(self, filename, timeout):
+ """Holds the input parameters for a test.
+ Args:
+ filename: Full path to the test.
+ timeout: Timeout in msecs the driver should use while running the test
+ """
+ # FIXME: filename should really be test_name as a relative path.
+ self.filename = filename
+ self.timeout = timeout
+ # The image_hash is used to avoid doing an image dump if the
+ # checksums match. The image_hash is set later, and only if it is needed
+ # for the test.
+ self.image_hash = None
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_output.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_output.py
new file mode 100644
index 0000000..e809be6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_output.py
@@ -0,0 +1,56 @@
+# 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.
+
+
+class TestOutput(object):
+ """Groups information about a test output for easy passing of data.
+
+ This is used not only for a actual test output, but also for grouping
+ expected test output.
+ """
+
+ def __init__(self, text, image, image_hash,
+ crash=None, test_time=None, timeout=None, error=None):
+ """Initializes a TestOutput object.
+
+ Args:
+ text: a text output
+ image: an image output
+ image_hash: a string containing the checksum of the image
+ crash: a boolean indicating whether the driver crashed on the test
+ test_time: a time which the test has taken
+ timeout: a boolean indicating whehter the test timed out
+ error: any unexpected or additional (or error) text output
+ """
+ self.text = text
+ self.image = image
+ self.image_hash = image_hash
+ self.crash = crash
+ self.test_time = test_time
+ self.timeout = timeout
+ self.error = error
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_results.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_results.py
new file mode 100644
index 0000000..2417fb7
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_results.py
@@ -0,0 +1,61 @@
+# 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 cPickle
+
+import test_failures
+
+
+class TestResult(object):
+ """Data object containing the results of a single test."""
+
+ @staticmethod
+ def loads(str):
+ return cPickle.loads(str)
+
+ def __init__(self, filename, failures, test_run_time,
+ total_time_for_all_diffs, time_for_diffs):
+ self.failures = failures
+ self.filename = filename
+ self.test_run_time = test_run_time
+ self.time_for_diffs = time_for_diffs
+ self.total_time_for_all_diffs = total_time_for_all_diffs
+ self.type = test_failures.determine_result_type(failures)
+
+ def __eq__(self, other):
+ return (self.filename == other.filename and
+ self.failures == other.failures and
+ self.test_run_time == other.test_run_time and
+ self.time_for_diffs == other.time_for_diffs and
+ self.total_time_for_all_diffs == other.total_time_for_all_diffs)
+
+ def __ne__(self, other):
+ return not (self == other)
+
+ def dumps(self):
+ return cPickle.dumps(self)
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_results_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_results_unittest.py
new file mode 100644
index 0000000..5921666
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_results_unittest.py
@@ -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.
+
+import unittest
+
+from test_results import TestResult
+
+
+class Test(unittest.TestCase):
+ def test_loads(self):
+ result = TestResult(filename='foo',
+ failures=[],
+ test_run_time=1.1,
+ total_time_for_all_diffs=0.5,
+ time_for_diffs=0.5)
+ s = result.dumps()
+ new_result = TestResult.loads(s)
+ self.assertTrue(isinstance(new_result, TestResult))
+
+ self.assertEqual(new_result, result)
+
+ # Also check that != is implemented.
+ self.assertFalse(new_result != result)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_results_uploader.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_results_uploader.py
new file mode 100644
index 0000000..033c8c6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_results_uploader.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python
+# 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.
+
+from __future__ import with_statement
+
+import codecs
+import mimetypes
+import socket
+import urllib2
+
+from webkitpy.common.net.networktransaction import NetworkTransaction
+
+def get_mime_type(filename):
+ return mimetypes.guess_type(filename)[0] or 'application/octet-stream'
+
+
+def _encode_multipart_form_data(fields, files):
+ """Encode form fields for multipart/form-data.
+
+ Args:
+ fields: A sequence of (name, value) elements for regular form fields.
+ files: A sequence of (name, filename, value) elements for data to be
+ uploaded as files.
+ Returns:
+ (content_type, body) ready for httplib.HTTP instance.
+
+ Source:
+ http://code.google.com/p/rietveld/source/browse/trunk/upload.py
+ """
+ BOUNDARY = '-M-A-G-I-C---B-O-U-N-D-A-R-Y-'
+ CRLF = '\r\n'
+ lines = []
+
+ for key, value in fields:
+ lines.append('--' + BOUNDARY)
+ lines.append('Content-Disposition: form-data; name="%s"' % key)
+ lines.append('')
+ if isinstance(value, unicode):
+ value = value.encode('utf-8')
+ lines.append(value)
+
+ for key, filename, value in files:
+ lines.append('--' + BOUNDARY)
+ lines.append('Content-Disposition: form-data; name="%s"; filename="%s"' % (key, filename))
+ lines.append('Content-Type: %s' % get_mime_type(filename))
+ lines.append('')
+ if isinstance(value, unicode):
+ value = value.encode('utf-8')
+ lines.append(value)
+
+ lines.append('--' + BOUNDARY + '--')
+ lines.append('')
+ body = CRLF.join(lines)
+ content_type = 'multipart/form-data; boundary=%s' % BOUNDARY
+ return content_type, body
+
+
+class TestResultsUploader:
+ def __init__(self, host):
+ self._host = host
+
+ def _upload_files(self, attrs, file_objs):
+ url = "http://%s/testfile/upload" % self._host
+ content_type, data = _encode_multipart_form_data(attrs, file_objs)
+ headers = {"Content-Type": content_type}
+ request = urllib2.Request(url, data, headers)
+ urllib2.urlopen(request)
+
+ def upload(self, params, files, timeout_seconds):
+ file_objs = []
+ for filename, path in files:
+ with codecs.open(path, "rb") as file:
+ file_objs.append(('file', filename, file.read()))
+
+ orig_timeout = socket.getdefaulttimeout()
+ try:
+ socket.setdefaulttimeout(timeout_seconds)
+ NetworkTransaction(timeout_seconds=timeout_seconds).run(
+ lambda: self._upload_files(params, file_objs))
+ finally:
+ socket.setdefaulttimeout(orig_timeout)
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py
new file mode 100644
index 0000000..24d04ca
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner.py
@@ -0,0 +1,1218 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
+#
+# 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.
+
+"""
+The TestRunner class runs a series of tests (TestType interface) against a set
+of test files. If a test file fails a TestType, it returns a list TestFailure
+objects to the TestRunner. The TestRunner then aggregates the TestFailures to
+create a final report.
+"""
+
+from __future__ import with_statement
+
+import codecs
+import errno
+import logging
+import math
+import os
+import Queue
+import random
+import shutil
+import sys
+import time
+
+from result_summary import ResultSummary
+from test_input import TestInput
+
+import dump_render_tree_thread
+import json_layout_results_generator
+import message_broker
+import printing
+import test_expectations
+import test_failures
+import test_results
+import test_results_uploader
+
+from webkitpy.thirdparty import simplejson
+from webkitpy.tool import grammar
+
+_log = logging.getLogger("webkitpy.layout_tests.run_webkit_tests")
+
+# Builder base URL where we have the archived test results.
+BUILDER_BASE_URL = "http://build.chromium.org/buildbot/layout_test_results/"
+
+LAYOUT_TESTS_DIRECTORY = "LayoutTests" + os.sep
+
+TestExpectationsFile = test_expectations.TestExpectationsFile
+
+
+def summarize_unexpected_results(port_obj, expectations, result_summary,
+ retry_summary):
+ """Summarize any unexpected results as a dict.
+
+ FIXME: split this data structure into a separate class?
+
+ Args:
+ port_obj: interface to port-specific hooks
+ expectations: test_expectations.TestExpectations object
+ result_summary: summary object from initial test runs
+ retry_summary: summary object from final test run of retried tests
+ Returns:
+ A dictionary containing a summary of the unexpected results from the
+ run, with the following fields:
+ 'version': a version indicator (1 in this version)
+ 'fixable': # of fixable tests (NOW - PASS)
+ 'skipped': # of skipped tests (NOW & SKIPPED)
+ 'num_regressions': # of non-flaky failures
+ 'num_flaky': # of flaky failures
+ 'num_passes': # of unexpected passes
+ 'tests': a dict of tests -> {'expected': '...', 'actual': '...'}
+ """
+ results = {}
+ results['version'] = 1
+
+ tbe = result_summary.tests_by_expectation
+ tbt = result_summary.tests_by_timeline
+ results['fixable'] = len(tbt[test_expectations.NOW] -
+ tbe[test_expectations.PASS])
+ results['skipped'] = len(tbt[test_expectations.NOW] &
+ tbe[test_expectations.SKIP])
+
+ num_passes = 0
+ num_flaky = 0
+ num_regressions = 0
+ keywords = {}
+ for k, v in TestExpectationsFile.EXPECTATIONS.iteritems():
+ keywords[v] = k.upper()
+
+ tests = {}
+ for filename, result in result_summary.unexpected_results.iteritems():
+ # Note that if a test crashed in the original run, we ignore
+ # whether or not it crashed when we retried it (if we retried it),
+ # and always consider the result not flaky.
+ test = port_obj.relative_test_filename(filename)
+ expected = expectations.get_expectations_string(filename)
+ actual = [keywords[result]]
+
+ if result == test_expectations.PASS:
+ num_passes += 1
+ elif result == test_expectations.CRASH:
+ num_regressions += 1
+ else:
+ if filename not in retry_summary.unexpected_results:
+ actual.extend(expectations.get_expectations_string(
+ filename).split(" "))
+ num_flaky += 1
+ else:
+ retry_result = retry_summary.unexpected_results[filename]
+ if result != retry_result:
+ actual.append(keywords[retry_result])
+ num_flaky += 1
+ else:
+ num_regressions += 1
+
+ tests[test] = {}
+ tests[test]['expected'] = expected
+ tests[test]['actual'] = " ".join(actual)
+
+ results['tests'] = tests
+ results['num_passes'] = num_passes
+ results['num_flaky'] = num_flaky
+ results['num_regressions'] = num_regressions
+
+ return results
+
+
+class TestRunInterruptedException(Exception):
+ """Raised when a test run should be stopped immediately."""
+ def __init__(self, reason):
+ self.reason = reason
+
+
+class TestRunner:
+ """A class for managing running a series of tests on a series of layout
+ test files."""
+
+ HTTP_SUBDIR = os.sep.join(['', 'http', ''])
+ WEBSOCKET_SUBDIR = os.sep.join(['', 'websocket', ''])
+
+ # The per-test timeout in milliseconds, if no --time-out-ms option was
+ # given to run_webkit_tests. This should correspond to the default timeout
+ # in DumpRenderTree.
+ DEFAULT_TEST_TIMEOUT_MS = 6 * 1000
+
+ def __init__(self, port, options, printer):
+ """Initialize test runner data structures.
+
+ Args:
+ port: an object implementing port-specific
+ options: a dictionary of command line options
+ printer: a Printer object to record updates to.
+ """
+ self._port = port
+ self._options = options
+ self._printer = printer
+ self._message_broker = None
+
+ # disable wss server. need to install pyOpenSSL on buildbots.
+ # self._websocket_secure_server = websocket_server.PyWebSocket(
+ # options.results_directory, use_tls=True, port=9323)
+
+ # a set of test files, and the same tests as a list
+ self._test_files = set()
+ self._test_files_list = None
+ self._result_queue = Queue.Queue()
+ self._retrying = False
+
+ def collect_tests(self, args, last_unexpected_results):
+ """Find all the files to test.
+
+ Args:
+ args: list of test arguments from the command line
+ last_unexpected_results: list of unexpected results to retest, if any
+
+ """
+ paths = [self._strip_test_dir_prefix(arg) for arg in args if arg and arg != '']
+ paths += last_unexpected_results
+ if self._options.test_list:
+ paths += read_test_files(self._options.test_list)
+ self._test_files = self._port.tests(paths)
+
+ def _strip_test_dir_prefix(self, path):
+ if path.startswith(LAYOUT_TESTS_DIRECTORY):
+ return path[len(LAYOUT_TESTS_DIRECTORY):]
+ return path
+
+ def lint(self):
+ lint_failed = False
+
+ # Creating the expecations for each platform/configuration pair does
+ # all the test list parsing and ensures it's correct syntax (e.g. no
+ # dupes).
+ for platform_name in self._port.test_platform_names():
+ try:
+ self.parse_expectations(platform_name, is_debug_mode=True)
+ except test_expectations.ParseError:
+ lint_failed = True
+ try:
+ self.parse_expectations(platform_name, is_debug_mode=False)
+ except test_expectations.ParseError:
+ lint_failed = True
+
+ self._printer.write("")
+ if lint_failed:
+ _log.error("Lint failed.")
+ return -1
+
+ _log.info("Lint succeeded.")
+ return 0
+
+ def parse_expectations(self, test_platform_name, is_debug_mode):
+ """Parse the expectations from the test_list files and return a data
+ structure holding them. Throws an error if the test_list files have
+ invalid syntax."""
+ if self._options.lint_test_files:
+ test_files = None
+ else:
+ test_files = self._test_files
+
+ expectations_str = self._port.test_expectations()
+ overrides_str = self._port.test_expectations_overrides()
+ self._expectations = test_expectations.TestExpectations(
+ self._port, test_files, expectations_str, test_platform_name,
+ is_debug_mode, self._options.lint_test_files,
+ overrides=overrides_str)
+ return self._expectations
+
+ def prepare_lists_and_print_output(self):
+ """Create appropriate subsets of test lists and returns a
+ ResultSummary object. Also prints expected test counts.
+ """
+
+ # Remove skipped - both fixable and ignored - files from the
+ # top-level list of files to test.
+ num_all_test_files = len(self._test_files)
+ self._printer.print_expected("Found: %d tests" %
+ (len(self._test_files)))
+ if not num_all_test_files:
+ _log.critical('No tests to run.')
+ return None
+
+ skipped = set()
+ if num_all_test_files > 1 and not self._options.force:
+ skipped = self._expectations.get_tests_with_result_type(
+ test_expectations.SKIP)
+ self._test_files -= skipped
+
+ # Create a sorted list of test files so the subset chunk,
+ # if used, contains alphabetically consecutive tests.
+ self._test_files_list = list(self._test_files)
+ if self._options.randomize_order:
+ random.shuffle(self._test_files_list)
+ else:
+ self._test_files_list.sort()
+
+ # If the user specifies they just want to run a subset of the tests,
+ # just grab a subset of the non-skipped tests.
+ if self._options.run_chunk or self._options.run_part:
+ chunk_value = self._options.run_chunk or self._options.run_part
+ test_files = self._test_files_list
+ try:
+ (chunk_num, chunk_len) = chunk_value.split(":")
+ chunk_num = int(chunk_num)
+ assert(chunk_num >= 0)
+ test_size = int(chunk_len)
+ assert(test_size > 0)
+ except:
+ _log.critical("invalid chunk '%s'" % chunk_value)
+ return None
+
+ # Get the number of tests
+ num_tests = len(test_files)
+
+ # Get the start offset of the slice.
+ if self._options.run_chunk:
+ chunk_len = test_size
+ # In this case chunk_num can be really large. We need
+ # to make the slave fit in the current number of tests.
+ slice_start = (chunk_num * chunk_len) % num_tests
+ else:
+ # Validate the data.
+ assert(test_size <= num_tests)
+ assert(chunk_num <= test_size)
+
+ # To count the chunk_len, and make sure we don't skip
+ # some tests, we round to the next value that fits exactly
+ # all the parts.
+ rounded_tests = num_tests
+ if rounded_tests % test_size != 0:
+ rounded_tests = (num_tests + test_size -
+ (num_tests % test_size))
+
+ chunk_len = rounded_tests / test_size
+ slice_start = chunk_len * (chunk_num - 1)
+ # It does not mind if we go over test_size.
+
+ # Get the end offset of the slice.
+ slice_end = min(num_tests, slice_start + chunk_len)
+
+ files = test_files[slice_start:slice_end]
+
+ tests_run_msg = 'Running: %d tests (chunk slice [%d:%d] of %d)' % (
+ (slice_end - slice_start), slice_start, slice_end, num_tests)
+ self._printer.print_expected(tests_run_msg)
+
+ # If we reached the end and we don't have enough tests, we run some
+ # from the beginning.
+ if slice_end - slice_start < chunk_len:
+ extra = chunk_len - (slice_end - slice_start)
+ extra_msg = (' last chunk is partial, appending [0:%d]' %
+ extra)
+ self._printer.print_expected(extra_msg)
+ tests_run_msg += "\n" + extra_msg
+ files.extend(test_files[0:extra])
+ tests_run_filename = os.path.join(self._options.results_directory,
+ "tests_run.txt")
+ with codecs.open(tests_run_filename, "w", "utf-8") as file:
+ file.write(tests_run_msg + "\n")
+
+ len_skip_chunk = int(len(files) * len(skipped) /
+ float(len(self._test_files)))
+ skip_chunk_list = list(skipped)[0:len_skip_chunk]
+ skip_chunk = set(skip_chunk_list)
+
+ # Update expectations so that the stats are calculated correctly.
+ # We need to pass a list that includes the right # of skipped files
+ # to ParseExpectations so that ResultSummary() will get the correct
+ # stats. So, we add in the subset of skipped files, and then
+ # subtract them back out.
+ self._test_files_list = files + skip_chunk_list
+ self._test_files = set(self._test_files_list)
+
+ self._expectations = self.parse_expectations(
+ self._port.test_platform_name(),
+ self._options.configuration == 'Debug')
+
+ self._test_files = set(files)
+ self._test_files_list = files
+ else:
+ skip_chunk = skipped
+
+ result_summary = ResultSummary(self._expectations,
+ self._test_files | skip_chunk)
+ self._print_expected_results_of_type(result_summary,
+ test_expectations.PASS, "passes")
+ self._print_expected_results_of_type(result_summary,
+ test_expectations.FAIL, "failures")
+ self._print_expected_results_of_type(result_summary,
+ test_expectations.FLAKY, "flaky")
+ self._print_expected_results_of_type(result_summary,
+ test_expectations.SKIP, "skipped")
+
+ if self._options.force:
+ self._printer.print_expected('Running all tests, including '
+ 'skips (--force)')
+ else:
+ # Note that we don't actually run the skipped tests (they were
+ # subtracted out of self._test_files, above), but we stub out the
+ # results here so the statistics can remain accurate.
+ for test in skip_chunk:
+ result = test_results.TestResult(test,
+ failures=[], test_run_time=0, total_time_for_all_diffs=0,
+ time_for_diffs=0)
+ result.type = test_expectations.SKIP
+ result_summary.add(result, expected=True)
+ self._printer.print_expected('')
+
+ return result_summary
+
+ def _get_dir_for_test_file(self, test_file):
+ """Returns the highest-level directory by which to shard the given
+ test file."""
+ index = test_file.rfind(os.sep + LAYOUT_TESTS_DIRECTORY)
+
+ test_file = test_file[index + len(LAYOUT_TESTS_DIRECTORY):]
+ test_file_parts = test_file.split(os.sep, 1)
+ directory = test_file_parts[0]
+ test_file = test_file_parts[1]
+
+ # The http tests are very stable on mac/linux.
+ # TODO(ojan): Make the http server on Windows be apache so we can
+ # turn shard the http tests there as well. Switching to apache is
+ # what made them stable on linux/mac.
+ return_value = directory
+ while ((directory != 'http' or sys.platform in ('darwin', 'linux2'))
+ and test_file.find(os.sep) >= 0):
+ test_file_parts = test_file.split(os.sep, 1)
+ directory = test_file_parts[0]
+ return_value = os.path.join(return_value, directory)
+ test_file = test_file_parts[1]
+
+ return return_value
+
+ def _get_test_input_for_file(self, test_file):
+ """Returns the appropriate TestInput object for the file. Mostly this
+ is used for looking up the timeout value (in ms) to use for the given
+ test."""
+ if self._test_is_slow(test_file):
+ return TestInput(test_file, self._options.slow_time_out_ms)
+ return TestInput(test_file, self._options.time_out_ms)
+
+ def _test_requires_lock(self, test_file):
+ """Return True if the test needs to be locked when
+ running multiple copies of NRWTs."""
+ split_path = test_file.split(os.sep)
+ return 'http' in split_path or 'websocket' in split_path
+
+ def _test_is_slow(self, test_file):
+ return self._expectations.has_modifier(test_file,
+ test_expectations.SLOW)
+
+ def _shard_tests(self, test_files, use_real_shards):
+ """Groups tests into batches.
+ This helps ensure that tests that depend on each other (aka bad tests!)
+ continue to run together as most cross-tests dependencies tend to
+ occur within the same directory. If use_real_shards is False, we
+ put each (non-HTTP/websocket) test into its own shard for maximum
+ concurrency instead of trying to do any sort of real sharding.
+
+ Return:
+ A list of lists of TestInput objects.
+ """
+ # FIXME: when we added http locking, we changed how this works such
+ # that we always lump all of the HTTP threads into a single shard.
+ # That will slow down experimental-fully-parallel, but it's unclear
+ # what the best alternative is completely revamping how we track
+ # when to grab the lock.
+
+ test_lists = []
+ tests_to_http_lock = []
+ if not use_real_shards:
+ for test_file in test_files:
+ test_input = self._get_test_input_for_file(test_file)
+ if self._test_requires_lock(test_file):
+ tests_to_http_lock.append(test_input)
+ else:
+ test_lists.append((".", [test_input]))
+ else:
+ tests_by_dir = {}
+ for test_file in test_files:
+ directory = self._get_dir_for_test_file(test_file)
+ test_input = self._get_test_input_for_file(test_file)
+ if self._test_requires_lock(test_file):
+ tests_to_http_lock.append(test_input)
+ else:
+ tests_by_dir.setdefault(directory, [])
+ tests_by_dir[directory].append(test_input)
+ # Sort by the number of tests in the dir so that the ones with the
+ # most tests get run first in order to maximize parallelization.
+ # Number of tests is a good enough, but not perfect, approximation
+ # of how long that set of tests will take to run. We can't just use
+ # a PriorityQueue until we move to Python 2.6.
+ for directory in tests_by_dir:
+ test_list = tests_by_dir[directory]
+ # Keep the tests in alphabetical order.
+ # FIXME: Remove once tests are fixed so they can be run in any
+ # order.
+ test_list.reverse()
+ test_list_tuple = (directory, test_list)
+ test_lists.append(test_list_tuple)
+ test_lists.sort(lambda a, b: cmp(len(b[1]), len(a[1])))
+
+ # Put the http tests first. There are only a couple hundred of them,
+ # but each http test takes a very long time to run, so sorting by the
+ # number of tests doesn't accurately capture how long they take to run.
+ if tests_to_http_lock:
+ tests_to_http_lock.reverse()
+ test_lists.insert(0, ("tests_to_http_lock", tests_to_http_lock))
+
+ return test_lists
+
+ def _contains_tests(self, subdir):
+ for test_file in self._test_files:
+ if test_file.find(subdir) >= 0:
+ return True
+ return False
+
+ def _num_workers(self):
+ return int(self._options.child_processes)
+
+ def _run_tests(self, file_list, result_summary):
+ """Runs the tests in the file_list.
+
+ Return: A tuple (interrupted, keyboard_interrupted, thread_timings,
+ test_timings, individual_test_timings)
+ interrupted is whether the run was interrupted
+ keyboard_interrupted is whether the interruption was because someone
+ typed Ctrl^C
+ thread_timings is a list of dicts with the total runtime
+ of each thread with 'name', 'num_tests', 'total_time' properties
+ test_timings is a list of timings for each sharded subdirectory
+ of the form [time, directory_name, num_tests]
+ individual_test_timings is a list of run times for each test
+ in the form {filename:filename, test_run_time:test_run_time}
+ result_summary: summary object to populate with the results
+ """
+
+ self._printer.print_update('Sharding tests ...')
+ num_workers = self._num_workers()
+ test_lists = self._shard_tests(file_list,
+ num_workers > 1 and not self._options.experimental_fully_parallel)
+ filename_queue = Queue.Queue()
+ for item in test_lists:
+ filename_queue.put(item)
+
+ self._printer.print_update('Starting %s ...' %
+ grammar.pluralize('worker', num_workers))
+ self._message_broker = message_broker.get(self._port, self._options)
+ broker = self._message_broker
+ self._current_filename_queue = filename_queue
+ self._current_result_summary = result_summary
+
+ if not self._options.dry_run:
+ threads = broker.start_workers(self)
+ else:
+ threads = {}
+
+ self._printer.print_update("Starting testing ...")
+ keyboard_interrupted = False
+ interrupted = False
+ if not self._options.dry_run:
+ try:
+ broker.run_message_loop()
+ except KeyboardInterrupt:
+ _log.info("Interrupted, exiting")
+ broker.cancel_workers()
+ keyboard_interrupted = True
+ interrupted = True
+ except TestRunInterruptedException, e:
+ _log.info(e.reason)
+ broker.cancel_workers()
+ interrupted = True
+ except:
+ # Unexpected exception; don't try to clean up workers.
+ _log.info("Exception raised, exiting")
+ raise
+
+ thread_timings, test_timings, individual_test_timings = \
+ self._collect_timing_info(threads)
+
+ broker.cleanup()
+ self._message_broker = None
+ return (interrupted, keyboard_interrupted, thread_timings, test_timings,
+ individual_test_timings)
+
+ def update(self):
+ self.update_summary(self._current_result_summary)
+
+ def _collect_timing_info(self, threads):
+ test_timings = {}
+ individual_test_timings = []
+ thread_timings = []
+
+ for thread in threads:
+ thread_timings.append({'name': thread.getName(),
+ 'num_tests': thread.get_num_tests(),
+ 'total_time': thread.get_total_time()})
+ test_timings.update(thread.get_test_group_timing_stats())
+ individual_test_timings.extend(thread.get_test_results())
+
+ return (thread_timings, test_timings, individual_test_timings)
+
+ def needs_http(self):
+ """Returns whether the test runner needs an HTTP server."""
+ return self._contains_tests(self.HTTP_SUBDIR)
+
+ def needs_websocket(self):
+ """Returns whether the test runner needs a WEBSOCKET server."""
+ return self._contains_tests(self.WEBSOCKET_SUBDIR)
+
+ def set_up_run(self):
+ """Configures the system to be ready to run tests.
+
+ Returns a ResultSummary object if we should continue to run tests,
+ or None if we should abort.
+
+ """
+ # This must be started before we check the system dependencies,
+ # since the helper may do things to make the setup correct.
+ self._printer.print_update("Starting helper ...")
+ self._port.start_helper()
+
+ # Check that the system dependencies (themes, fonts, ...) are correct.
+ if not self._options.nocheck_sys_deps:
+ self._printer.print_update("Checking system dependencies ...")
+ if not self._port.check_sys_deps(self.needs_http()):
+ self._port.stop_helper()
+ return None
+
+ if self._options.clobber_old_results:
+ self._clobber_old_results()
+
+ # Create the output directory if it doesn't already exist.
+ self._port.maybe_make_directory(self._options.results_directory)
+
+ self._port.setup_test_run()
+
+ self._printer.print_update("Preparing tests ...")
+ result_summary = self.prepare_lists_and_print_output()
+ if not result_summary:
+ return None
+
+ return result_summary
+
+ def run(self, result_summary):
+ """Run all our tests on all our test files.
+
+ For each test file, we run each test type. If there are any failures,
+ we collect them for reporting.
+
+ Args:
+ result_summary: a summary object tracking the test results.
+
+ Return:
+ The number of unexpected results (0 == success)
+ """
+ # gather_test_files() must have been called first to initialize us.
+ # If we didn't find any files to test, we've errored out already in
+ # prepare_lists_and_print_output().
+ assert(len(self._test_files))
+
+ start_time = time.time()
+
+ interrupted, keyboard_interrupted, thread_timings, test_timings, \
+ individual_test_timings = (
+ self._run_tests(self._test_files_list, result_summary))
+
+ # We exclude the crashes from the list of results to retry, because
+ # we want to treat even a potentially flaky crash as an error.
+ failures = self._get_failures(result_summary, include_crashes=False)
+ retry_summary = result_summary
+ while (len(failures) and self._options.retry_failures and
+ not self._retrying and not interrupted):
+ _log.info('')
+ _log.info("Retrying %d unexpected failure(s) ..." % len(failures))
+ _log.info('')
+ self._retrying = True
+ retry_summary = ResultSummary(self._expectations, failures.keys())
+ # Note that we intentionally ignore the return value here.
+ self._run_tests(failures.keys(), retry_summary)
+ failures = self._get_failures(retry_summary, include_crashes=True)
+
+ end_time = time.time()
+
+ self._print_timing_statistics(end_time - start_time,
+ thread_timings, test_timings,
+ individual_test_timings,
+ result_summary)
+
+ self._print_result_summary(result_summary)
+
+ sys.stdout.flush()
+ sys.stderr.flush()
+
+ self._printer.print_one_line_summary(result_summary.total,
+ result_summary.expected,
+ result_summary.unexpected)
+
+ unexpected_results = summarize_unexpected_results(self._port,
+ self._expectations, result_summary, retry_summary)
+ self._printer.print_unexpected_results(unexpected_results)
+
+ if (self._options.record_results and not self._options.dry_run and
+ not interrupted):
+ # Write the same data to log files and upload generated JSON files
+ # to appengine server.
+ self._upload_json_files(unexpected_results, result_summary,
+ individual_test_timings)
+
+ # Write the summary to disk (results.html) and display it if requested.
+ if not self._options.dry_run:
+ wrote_results = self._write_results_html_file(result_summary)
+ if self._options.show_results and wrote_results:
+ self._show_results_html_file()
+
+ # Now that we've completed all the processing we can, we re-raise
+ # a KeyboardInterrupt if necessary so the caller can handle it.
+ if keyboard_interrupted:
+ raise KeyboardInterrupt
+
+ # Ignore flaky failures and unexpected passes so we don't turn the
+ # bot red for those.
+ return unexpected_results['num_regressions']
+
+ def clean_up_run(self):
+ """Restores the system after we're done running tests."""
+
+ _log.debug("flushing stdout")
+ sys.stdout.flush()
+ _log.debug("flushing stderr")
+ sys.stderr.flush()
+ _log.debug("stopping helper")
+ self._port.stop_helper()
+
+ def update_summary(self, result_summary):
+ """Update the summary and print results with any completed tests."""
+ while True:
+ try:
+ result = test_results.TestResult.loads(self._result_queue.get_nowait())
+ except Queue.Empty:
+ return
+
+ expected = self._expectations.matches_an_expected_result(
+ result.filename, result.type, self._options.pixel_tests)
+ result_summary.add(result, expected)
+ exp_str = self._expectations.get_expectations_string(
+ result.filename)
+ got_str = self._expectations.expectation_to_string(result.type)
+ self._printer.print_test_result(result, expected, exp_str, got_str)
+ self._printer.print_progress(result_summary, self._retrying,
+ self._test_files_list)
+
+ def interrupt_if_at_failure_limit(limit, count, message):
+ if limit and count >= limit:
+ raise TestRunInterruptedException(message % count)
+
+ interrupt_if_at_failure_limit(
+ self._options.exit_after_n_failures,
+ result_summary.unexpected_failures,
+ "Aborting run since %d failures were reached")
+ interrupt_if_at_failure_limit(
+ self._options.exit_after_n_crashes_or_timeouts,
+ result_summary.unexpected_crashes_or_timeouts,
+ "Aborting run since %d crashes or timeouts were reached")
+
+ def _clobber_old_results(self):
+ # Just clobber the actual test results directories since the other
+ # files in the results directory are explicitly used for cross-run
+ # tracking.
+ self._printer.print_update("Clobbering old results in %s" %
+ self._options.results_directory)
+ layout_tests_dir = self._port.layout_tests_dir()
+ possible_dirs = self._port.test_dirs()
+ for dirname in possible_dirs:
+ if os.path.isdir(os.path.join(layout_tests_dir, dirname)):
+ shutil.rmtree(os.path.join(self._options.results_directory,
+ dirname),
+ ignore_errors=True)
+
+ def _get_failures(self, result_summary, include_crashes):
+ """Filters a dict of results and returns only the failures.
+
+ Args:
+ result_summary: the results of the test run
+ include_crashes: whether crashes are included in the output.
+ We use False when finding the list of failures to retry
+ to see if the results were flaky. Although the crashes may also be
+ flaky, we treat them as if they aren't so that they're not ignored.
+ Returns:
+ a dict of files -> results
+ """
+ failed_results = {}
+ for test, result in result_summary.unexpected_results.iteritems():
+ if (result == test_expectations.PASS or
+ result == test_expectations.CRASH and not include_crashes):
+ continue
+ failed_results[test] = result
+
+ return failed_results
+
+ def _upload_json_files(self, unexpected_results, result_summary,
+ individual_test_timings):
+ """Writes the results of the test run as JSON files into the results
+ dir and upload the files to the appengine server.
+
+ There are three different files written into the results dir:
+ unexpected_results.json: A short list of any unexpected results.
+ This is used by the buildbots to display results.
+ expectations.json: This is used by the flakiness dashboard.
+ results.json: A full list of the results - used by the flakiness
+ dashboard and the aggregate results dashboard.
+
+ Args:
+ unexpected_results: dict of unexpected results
+ result_summary: full summary object
+ individual_test_timings: list of test times (used by the flakiness
+ dashboard).
+ """
+ results_directory = self._options.results_directory
+ _log.debug("Writing JSON files in %s." % results_directory)
+ unexpected_json_path = os.path.join(results_directory, "unexpected_results.json")
+ with codecs.open(unexpected_json_path, "w", "utf-8") as file:
+ simplejson.dump(unexpected_results, file, sort_keys=True, indent=2)
+
+ # Write a json file of the test_expectations.txt file for the layout
+ # tests dashboard.
+ expectations_path = os.path.join(results_directory, "expectations.json")
+ expectations_json = \
+ self._expectations.get_expectations_json_for_all_platforms()
+ with codecs.open(expectations_path, "w", "utf-8") as file:
+ file.write(u"ADD_EXPECTATIONS(%s);" % expectations_json)
+
+ generator = json_layout_results_generator.JSONLayoutResultsGenerator(
+ self._port, self._options.builder_name, self._options.build_name,
+ self._options.build_number, self._options.results_directory,
+ BUILDER_BASE_URL, individual_test_timings,
+ self._expectations, result_summary, self._test_files_list,
+ not self._options.upload_full_results,
+ self._options.test_results_server,
+ "layout-tests",
+ self._options.master_name)
+
+ _log.debug("Finished writing JSON files.")
+
+ json_files = ["expectations.json"]
+ if self._options.upload_full_results:
+ json_files.append("results.json")
+ else:
+ json_files.append("incremental_results.json")
+
+ generator.upload_json_files(json_files)
+
+ def _print_config(self):
+ """Prints the configuration for the test run."""
+ p = self._printer
+ p.print_config("Using port '%s'" % self._port.name())
+ p.print_config("Placing test results in %s" %
+ self._options.results_directory)
+ if self._options.new_baseline:
+ p.print_config("Placing new baselines in %s" %
+ self._port.baseline_path())
+ p.print_config("Using %s build" % self._options.configuration)
+ if self._options.pixel_tests:
+ p.print_config("Pixel tests enabled")
+ else:
+ p.print_config("Pixel tests disabled")
+
+ p.print_config("Regular timeout: %s, slow test timeout: %s" %
+ (self._options.time_out_ms,
+ self._options.slow_time_out_ms))
+
+ if self._num_workers() == 1:
+ p.print_config("Running one %s" % self._port.driver_name())
+ else:
+ p.print_config("Running %s %ss in parallel" %
+ (self._options.child_processes,
+ self._port.driver_name()))
+ p.print_config('Command line: ' +
+ ' '.join(self._port.driver_cmd_line()))
+ p.print_config("Worker model: %s" % self._options.worker_model)
+ p.print_config("")
+
+ def _print_expected_results_of_type(self, result_summary,
+ result_type, result_type_str):
+ """Print the number of the tests in a given result class.
+
+ Args:
+ result_summary - the object containing all the results to report on
+ result_type - the particular result type to report in the summary.
+ result_type_str - a string description of the result_type.
+ """
+ tests = self._expectations.get_tests_with_result_type(result_type)
+ now = result_summary.tests_by_timeline[test_expectations.NOW]
+ wontfix = result_summary.tests_by_timeline[test_expectations.WONTFIX]
+
+ # We use a fancy format string in order to print the data out in a
+ # nicely-aligned table.
+ fmtstr = ("Expect: %%5d %%-8s (%%%dd now, %%%dd wontfix)"
+ % (self._num_digits(now), self._num_digits(wontfix)))
+ self._printer.print_expected(fmtstr %
+ (len(tests), result_type_str, len(tests & now), len(tests & wontfix)))
+
+ def _num_digits(self, num):
+ """Returns the number of digits needed to represent the length of a
+ sequence."""
+ ndigits = 1
+ if len(num):
+ ndigits = int(math.log10(len(num))) + 1
+ return ndigits
+
+ def _print_timing_statistics(self, total_time, thread_timings,
+ directory_test_timings, individual_test_timings,
+ result_summary):
+ """Record timing-specific information for the test run.
+
+ Args:
+ total_time: total elapsed time (in seconds) for the test run
+ thread_timings: wall clock time each thread ran for
+ directory_test_timings: timing by directory
+ individual_test_timings: timing by file
+ result_summary: summary object for the test run
+ """
+ self._printer.print_timing("Test timing:")
+ self._printer.print_timing(" %6.2f total testing time" % total_time)
+ self._printer.print_timing("")
+ self._printer.print_timing("Thread timing:")
+ cuml_time = 0
+ for t in thread_timings:
+ self._printer.print_timing(" %10s: %5d tests, %6.2f secs" %
+ (t['name'], t['num_tests'], t['total_time']))
+ cuml_time += t['total_time']
+ self._printer.print_timing(" %6.2f cumulative, %6.2f optimal" %
+ (cuml_time, cuml_time / int(self._options.child_processes)))
+ self._printer.print_timing("")
+
+ self._print_aggregate_test_statistics(individual_test_timings)
+ self._print_individual_test_times(individual_test_timings,
+ result_summary)
+ self._print_directory_timings(directory_test_timings)
+
+ def _print_aggregate_test_statistics(self, individual_test_timings):
+ """Prints aggregate statistics (e.g. median, mean, etc.) for all tests.
+ Args:
+ individual_test_timings: List of TestResults for all tests.
+ """
+ test_types = [] # Unit tests don't actually produce any timings.
+ if individual_test_timings:
+ test_types = individual_test_timings[0].time_for_diffs.keys()
+ times_for_dump_render_tree = []
+ times_for_diff_processing = []
+ times_per_test_type = {}
+ for test_type in test_types:
+ times_per_test_type[test_type] = []
+
+ for test_stats in individual_test_timings:
+ times_for_dump_render_tree.append(test_stats.test_run_time)
+ times_for_diff_processing.append(
+ test_stats.total_time_for_all_diffs)
+ time_for_diffs = test_stats.time_for_diffs
+ for test_type in test_types:
+ times_per_test_type[test_type].append(
+ time_for_diffs[test_type])
+
+ self._print_statistics_for_test_timings(
+ "PER TEST TIME IN TESTSHELL (seconds):",
+ times_for_dump_render_tree)
+ self._print_statistics_for_test_timings(
+ "PER TEST DIFF PROCESSING TIMES (seconds):",
+ times_for_diff_processing)
+ for test_type in test_types:
+ self._print_statistics_for_test_timings(
+ "PER TEST TIMES BY TEST TYPE: %s" % test_type,
+ times_per_test_type[test_type])
+
+ def _print_individual_test_times(self, individual_test_timings,
+ result_summary):
+ """Prints the run times for slow, timeout and crash tests.
+ Args:
+ individual_test_timings: List of TestStats for all tests.
+ result_summary: summary object for test run
+ """
+ # Reverse-sort by the time spent in DumpRenderTree.
+ individual_test_timings.sort(lambda a, b:
+ cmp(b.test_run_time, a.test_run_time))
+
+ num_printed = 0
+ slow_tests = []
+ timeout_or_crash_tests = []
+ unexpected_slow_tests = []
+ for test_tuple in individual_test_timings:
+ filename = test_tuple.filename
+ is_timeout_crash_or_slow = False
+ if self._test_is_slow(filename):
+ is_timeout_crash_or_slow = True
+ slow_tests.append(test_tuple)
+
+ if filename in result_summary.failures:
+ result = result_summary.results[filename].type
+ if (result == test_expectations.TIMEOUT or
+ result == test_expectations.CRASH):
+ is_timeout_crash_or_slow = True
+ timeout_or_crash_tests.append(test_tuple)
+
+ if (not is_timeout_crash_or_slow and
+ num_printed < printing.NUM_SLOW_TESTS_TO_LOG):
+ num_printed = num_printed + 1
+ unexpected_slow_tests.append(test_tuple)
+
+ self._printer.print_timing("")
+ self._print_test_list_timing("%s slowest tests that are not "
+ "marked as SLOW and did not timeout/crash:" %
+ printing.NUM_SLOW_TESTS_TO_LOG, unexpected_slow_tests)
+ self._printer.print_timing("")
+ self._print_test_list_timing("Tests marked as SLOW:", slow_tests)
+ self._printer.print_timing("")
+ self._print_test_list_timing("Tests that timed out or crashed:",
+ timeout_or_crash_tests)
+ self._printer.print_timing("")
+
+ def _print_test_list_timing(self, title, test_list):
+ """Print timing info for each test.
+
+ Args:
+ title: section heading
+ test_list: tests that fall in this section
+ """
+ if self._printer.disabled('slowest'):
+ return
+
+ self._printer.print_timing(title)
+ for test_tuple in test_list:
+ filename = test_tuple.filename[len(
+ self._port.layout_tests_dir()) + 1:]
+ filename = filename.replace('\\', '/')
+ test_run_time = round(test_tuple.test_run_time, 1)
+ self._printer.print_timing(" %s took %s seconds" %
+ (filename, test_run_time))
+
+ def _print_directory_timings(self, directory_test_timings):
+ """Print timing info by directory for any directories that
+ take > 10 seconds to run.
+
+ Args:
+ directory_test_timing: time info for each directory
+ """
+ timings = []
+ for directory in directory_test_timings:
+ num_tests, time_for_directory = directory_test_timings[directory]
+ timings.append((round(time_for_directory, 1), directory,
+ num_tests))
+ timings.sort()
+
+ self._printer.print_timing("Time to process slowest subdirectories:")
+ min_seconds_to_print = 10
+ for timing in timings:
+ if timing[0] > min_seconds_to_print:
+ self._printer.print_timing(
+ " %s took %s seconds to run %s tests." % (timing[1],
+ timing[0], timing[2]))
+ self._printer.print_timing("")
+
+ def _print_statistics_for_test_timings(self, title, timings):
+ """Prints the median, mean and standard deviation of the values in
+ timings.
+
+ Args:
+ title: Title for these timings.
+ timings: A list of floats representing times.
+ """
+ self._printer.print_timing(title)
+ timings.sort()
+
+ num_tests = len(timings)
+ if not num_tests:
+ return
+ percentile90 = timings[int(.9 * num_tests)]
+ percentile99 = timings[int(.99 * num_tests)]
+
+ if num_tests % 2 == 1:
+ median = timings[((num_tests - 1) / 2) - 1]
+ else:
+ lower = timings[num_tests / 2 - 1]
+ upper = timings[num_tests / 2]
+ median = (float(lower + upper)) / 2
+
+ mean = sum(timings) / num_tests
+
+ for time in timings:
+ sum_of_deviations = math.pow(time - mean, 2)
+
+ std_deviation = math.sqrt(sum_of_deviations / num_tests)
+ self._printer.print_timing(" Median: %6.3f" % median)
+ self._printer.print_timing(" Mean: %6.3f" % mean)
+ self._printer.print_timing(" 90th percentile: %6.3f" % percentile90)
+ self._printer.print_timing(" 99th percentile: %6.3f" % percentile99)
+ self._printer.print_timing(" Standard dev: %6.3f" % std_deviation)
+ self._printer.print_timing("")
+
+ def _print_result_summary(self, result_summary):
+ """Print a short summary about how many tests passed.
+
+ Args:
+ result_summary: information to log
+ """
+ failed = len(result_summary.failures)
+ skipped = len(
+ result_summary.tests_by_expectation[test_expectations.SKIP])
+ total = result_summary.total
+ passed = total - failed - skipped
+ pct_passed = 0.0
+ if total > 0:
+ pct_passed = float(passed) * 100 / total
+
+ self._printer.print_actual("")
+ self._printer.print_actual("=> Results: %d/%d tests passed (%.1f%%)" %
+ (passed, total, pct_passed))
+ self._printer.print_actual("")
+ self._print_result_summary_entry(result_summary,
+ test_expectations.NOW, "Tests to be fixed")
+
+ self._printer.print_actual("")
+ self._print_result_summary_entry(result_summary,
+ test_expectations.WONTFIX,
+ "Tests that will only be fixed if they crash (WONTFIX)")
+ self._printer.print_actual("")
+
+ def _print_result_summary_entry(self, result_summary, timeline,
+ heading):
+ """Print a summary block of results for a particular timeline of test.
+
+ Args:
+ result_summary: summary to print results for
+ timeline: the timeline to print results for (NOT, WONTFIX, etc.)
+ heading: a textual description of the timeline
+ """
+ total = len(result_summary.tests_by_timeline[timeline])
+ not_passing = (total -
+ len(result_summary.tests_by_expectation[test_expectations.PASS] &
+ result_summary.tests_by_timeline[timeline]))
+ self._printer.print_actual("=> %s (%d):" % (heading, not_passing))
+
+ for result in TestExpectationsFile.EXPECTATION_ORDER:
+ if result == test_expectations.PASS:
+ continue
+ results = (result_summary.tests_by_expectation[result] &
+ result_summary.tests_by_timeline[timeline])
+ desc = TestExpectationsFile.EXPECTATION_DESCRIPTIONS[result]
+ if not_passing and len(results):
+ pct = len(results) * 100.0 / not_passing
+ self._printer.print_actual(" %5d %-24s (%4.1f%%)" %
+ (len(results), desc[len(results) != 1], pct))
+
+ def _results_html(self, test_files, failures, title="Test Failures", override_time=None):
+ """
+ test_files = a list of file paths
+ failures = dictionary mapping test paths to failure objects
+ title = title printed at top of test
+ override_time = current time (used by unit tests)
+ """
+ page = """<html>
+ <head>
+ <title>Layout Test Results (%(time)s)</title>
+ </head>
+ <body>
+ <h2>%(title)s (%(time)s)</h2>
+ """ % {'title': title, 'time': override_time or time.asctime()}
+
+ for test_file in sorted(test_files):
+ test_name = self._port.relative_test_filename(test_file)
+ test_url = self._port.filename_to_uri(test_file)
+ page += u"<p><a href='%s'>%s</a><br />\n" % (test_url, test_name)
+ test_failures = failures.get(test_file, [])
+ for failure in test_failures:
+ page += (u"&nbsp;&nbsp;%s<br/>" %
+ failure.result_html_output(test_name))
+ page += "</p>\n"
+ page += "</body></html>\n"
+ return page
+
+ def _write_results_html_file(self, result_summary):
+ """Write results.html which is a summary of tests that failed.
+
+ Args:
+ result_summary: a summary of the results :)
+
+ Returns:
+ True if any results were written (since expected failures may be
+ omitted)
+ """
+ # test failures
+ if self._options.full_results_html:
+ results_title = "Test Failures"
+ test_files = result_summary.failures.keys()
+ else:
+ results_title = "Unexpected Test Failures"
+ unexpected_failures = self._get_failures(result_summary,
+ include_crashes=True)
+ test_files = unexpected_failures.keys()
+ if not len(test_files):
+ return False
+
+ out_filename = os.path.join(self._options.results_directory,
+ "results.html")
+ with codecs.open(out_filename, "w", "utf-8") as results_file:
+ html = self._results_html(test_files, result_summary.failures, results_title)
+ results_file.write(html)
+
+ return True
+
+ def _show_results_html_file(self):
+ """Shows the results.html page."""
+ results_filename = os.path.join(self._options.results_directory,
+ "results.html")
+ self._port.show_results_html_file(results_filename)
+
+
+def read_test_files(files):
+ tests = []
+ for file in files:
+ try:
+ with codecs.open(file, 'r', 'utf-8') as file_contents:
+ # FIXME: This could be cleaner using a list comprehension.
+ for line in file_contents:
+ line = test_expectations.strip_comments(line)
+ if line:
+ tests.append(line)
+ except IOError, e:
+ if e.errno == errno.ENOENT:
+ _log.critical('')
+ _log.critical('--test-list file "%s" not found' % file)
+ raise
+ return tests
diff --git a/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py
new file mode 100644
index 0000000..3c564ae
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/layout_package/test_runner_unittest.py
@@ -0,0 +1,102 @@
+#!/usr/bin/python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
+#
+# 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.
+
+"""Unit tests for TestRunner()."""
+
+import unittest
+
+from webkitpy.thirdparty.mock import Mock
+
+import test_runner
+
+
+class TestRunnerWrapper(test_runner.TestRunner):
+ def _get_test_input_for_file(self, test_file):
+ return test_file
+
+
+class TestRunnerTest(unittest.TestCase):
+ def test_results_html(self):
+ mock_port = Mock()
+ mock_port.relative_test_filename = lambda name: name
+ mock_port.filename_to_uri = lambda name: name
+
+ runner = test_runner.TestRunner(port=mock_port, options=Mock(),
+ printer=Mock())
+ expected_html = u"""<html>
+ <head>
+ <title>Layout Test Results (time)</title>
+ </head>
+ <body>
+ <h2>Title (time)</h2>
+ <p><a href='test_path'>test_path</a><br />
+</p>
+</body></html>
+"""
+ html = runner._results_html(["test_path"], {}, "Title", override_time="time")
+ self.assertEqual(html, expected_html)
+
+ def test_shard_tests(self):
+ # Test that _shard_tests in test_runner.TestRunner really
+ # put the http tests first in the queue.
+ runner = TestRunnerWrapper(port=Mock(), options=Mock(),
+ printer=Mock())
+
+ test_list = [
+ "LayoutTests/websocket/tests/unicode.htm",
+ "LayoutTests/animations/keyframes.html",
+ "LayoutTests/http/tests/security/view-source-no-refresh.html",
+ "LayoutTests/websocket/tests/websocket-protocol-ignored.html",
+ "LayoutTests/fast/css/display-none-inline-style-change-crash.html",
+ "LayoutTests/http/tests/xmlhttprequest/supported-xml-content-types.html",
+ "LayoutTests/dom/html/level2/html/HTMLAnchorElement03.html",
+ "LayoutTests/ietestcenter/Javascript/11.1.5_4-4-c-1.html",
+ "LayoutTests/dom/html/level2/html/HTMLAnchorElement06.html",
+ ]
+
+ expected_tests_to_http_lock = set([
+ 'LayoutTests/websocket/tests/unicode.htm',
+ 'LayoutTests/http/tests/security/view-source-no-refresh.html',
+ 'LayoutTests/websocket/tests/websocket-protocol-ignored.html',
+ 'LayoutTests/http/tests/xmlhttprequest/supported-xml-content-types.html',
+ ])
+
+ # FIXME: Ideally the HTTP tests don't have to all be in one shard.
+ single_thread_results = runner._shard_tests(test_list, False)
+ multi_thread_results = runner._shard_tests(test_list, True)
+
+ self.assertEqual("tests_to_http_lock", single_thread_results[0][0])
+ self.assertEqual(expected_tests_to_http_lock, set(single_thread_results[0][1]))
+ self.assertEqual("tests_to_http_lock", multi_thread_results[0][0])
+ self.assertEqual(expected_tests_to_http_lock, set(multi_thread_results[0][1]))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/__init__.py b/Tools/Scripts/webkitpy/layout_tests/port/__init__.py
new file mode 100644
index 0000000..e3ad6f4
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/__init__.py
@@ -0,0 +1,32 @@
+#!/usr/bin/env python
+# 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.
+
+"""Port-specific entrypoints for the layout tests test infrastructure."""
+
+from factory import get
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/apache_http_server.py b/Tools/Scripts/webkitpy/layout_tests/port/apache_http_server.py
new file mode 100644
index 0000000..46617f6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/apache_http_server.py
@@ -0,0 +1,230 @@
+#!/usr/bin/env python
+# 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.
+
+"""A class to start/stop the apache http server used by layout tests."""
+
+
+from __future__ import with_statement
+
+import codecs
+import logging
+import optparse
+import os
+import re
+import subprocess
+import sys
+
+import http_server_base
+
+_log = logging.getLogger("webkitpy.layout_tests.port.apache_http_server")
+
+
+class LayoutTestApacheHttpd(http_server_base.HttpServerBase):
+
+ def __init__(self, port_obj, output_dir):
+ """Args:
+ port_obj: handle to the platform-specific routines
+ output_dir: the absolute path to the layout test result directory
+ """
+ http_server_base.HttpServerBase.__init__(self, port_obj)
+ self._output_dir = output_dir
+ self._httpd_proc = None
+ port_obj.maybe_make_directory(output_dir)
+
+ self.mappings = [{'port': 8000},
+ {'port': 8080},
+ {'port': 8081},
+ {'port': 8443, 'sslcert': True}]
+
+ # The upstream .conf file assumed the existence of /tmp/WebKit for
+ # placing apache files like the lock file there.
+ self._runtime_path = os.path.join("/tmp", "WebKit")
+ port_obj.maybe_make_directory(self._runtime_path)
+
+ # The PID returned when Apache is started goes away (due to dropping
+ # privileges?). The proper controlling PID is written to a file in the
+ # apache runtime directory.
+ self._pid_file = os.path.join(self._runtime_path, 'httpd.pid')
+
+ test_dir = self._port_obj.layout_tests_dir()
+ js_test_resources_dir = self._cygwin_safe_join(test_dir, "fast", "js",
+ "resources")
+ mime_types_path = self._cygwin_safe_join(test_dir, "http", "conf",
+ "mime.types")
+ cert_file = self._cygwin_safe_join(test_dir, "http", "conf",
+ "webkit-httpd.pem")
+ access_log = self._cygwin_safe_join(output_dir, "access_log.txt")
+ error_log = self._cygwin_safe_join(output_dir, "error_log.txt")
+ document_root = self._cygwin_safe_join(test_dir, "http", "tests")
+
+ # FIXME: We shouldn't be calling a protected method of _port_obj!
+ executable = self._port_obj._path_to_apache()
+ if self._is_cygwin():
+ executable = self._get_cygwin_path(executable)
+
+ cmd = [executable,
+ '-f', "\"%s\"" % self._get_apache_config_file_path(test_dir, output_dir),
+ '-C', "\'DocumentRoot \"%s\"\'" % document_root,
+ '-c', "\'Alias /js-test-resources \"%s\"'" % js_test_resources_dir,
+ '-C', "\'Listen %s\'" % "127.0.0.1:8000",
+ '-C', "\'Listen %s\'" % "127.0.0.1:8081",
+ '-c', "\'TypesConfig \"%s\"\'" % mime_types_path,
+ '-c', "\'CustomLog \"%s\" common\'" % access_log,
+ '-c', "\'ErrorLog \"%s\"\'" % error_log,
+ '-C', "\'User \"%s\"\'" % os.environ.get("USERNAME",
+ os.environ.get("USER", ""))]
+
+ if self._is_cygwin():
+ cygbin = self._port_obj._path_from_base('third_party', 'cygwin',
+ 'bin')
+ # Not entirely sure why, but from cygwin we need to run the
+ # httpd command through bash.
+ self._start_cmd = [
+ os.path.join(cygbin, 'bash.exe'),
+ '-c',
+ 'PATH=%s %s' % (self._get_cygwin_path(cygbin), " ".join(cmd)),
+ ]
+ else:
+ # TODO(ojan): When we get cygwin using Apache 2, use set the
+ # cert file for cygwin as well.
+ cmd.extend(['-c', "\'SSLCertificateFile %s\'" % cert_file])
+ # Join the string here so that Cygwin/Windows and Mac/Linux
+ # can use the same code. Otherwise, we could remove the single
+ # quotes above and keep cmd as a sequence.
+ self._start_cmd = " ".join(cmd)
+
+ def _is_cygwin(self):
+ return sys.platform in ("win32", "cygwin")
+
+ def _cygwin_safe_join(self, *parts):
+ """Returns a platform appropriate path."""
+ path = os.path.join(*parts)
+ if self._is_cygwin():
+ return self._get_cygwin_path(path)
+ return path
+
+ def _get_cygwin_path(self, path):
+ """Convert a Windows path to a cygwin path.
+
+ The cygpath utility insists on converting paths that it thinks are
+ Cygwin root paths to what it thinks the correct roots are. So paths
+ such as "C:\b\slave\webkit-release\build\third_party\cygwin\bin"
+ are converted to plain "/usr/bin". To avoid this, we
+ do the conversion manually.
+
+ The path is expected to be an absolute path, on any drive.
+ """
+ drive_regexp = re.compile(r'([a-z]):[/\\]', re.IGNORECASE)
+
+ def lower_drive(matchobj):
+ return '/cygdrive/%s/' % matchobj.group(1).lower()
+ path = drive_regexp.sub(lower_drive, path)
+ return path.replace('\\', '/')
+
+ def _get_apache_config_file_path(self, test_dir, output_dir):
+ """Returns the path to the apache config file to use.
+ Args:
+ test_dir: absolute path to the LayoutTests directory.
+ output_dir: absolute path to the layout test results directory.
+ """
+ httpd_config = self._port_obj._path_to_apache_config_file()
+ httpd_config_copy = os.path.join(output_dir, "httpd.conf")
+ # httpd.conf is always utf-8 according to http://archive.apache.org/gnats/10125
+ with codecs.open(httpd_config, "r", "utf-8") as httpd_config_file:
+ httpd_conf = httpd_config_file.read()
+ if self._is_cygwin():
+ # This is a gross hack, but it lets us use the upstream .conf file
+ # and our checked in cygwin. This tells the server the root
+ # directory to look in for .so modules. It will use this path
+ # plus the relative paths to the .so files listed in the .conf
+ # file. We have apache/cygwin checked into our tree so
+ # people don't have to install it into their cygwin.
+ cygusr = self._port_obj._path_from_base('third_party', 'cygwin',
+ 'usr')
+ httpd_conf = httpd_conf.replace('ServerRoot "/usr"',
+ 'ServerRoot "%s"' % self._get_cygwin_path(cygusr))
+
+ with codecs.open(httpd_config_copy, "w", "utf-8") as file:
+ file.write(httpd_conf)
+
+ if self._is_cygwin():
+ return self._get_cygwin_path(httpd_config_copy)
+ return httpd_config_copy
+
+ def _get_virtual_host_config(self, document_root, port, ssl=False):
+ """Returns a <VirtualHost> directive block for an httpd.conf file.
+ It will listen to 127.0.0.1 on each of the given port.
+ """
+ return '\n'.join(('<VirtualHost 127.0.0.1:%s>' % port,
+ 'DocumentRoot "%s"' % document_root,
+ ssl and 'SSLEngine On' or '',
+ '</VirtualHost>', ''))
+
+ def _start_httpd_process(self):
+ """Starts the httpd process and returns whether there were errors."""
+ # Use shell=True because we join the arguments into a string for
+ # the sake of Window/Cygwin and it needs quoting that breaks
+ # shell=False.
+ # FIXME: We should not need to be joining shell arguments into strings.
+ # shell=True is a trail of tears.
+ # Note: Not thread safe: http://bugs.python.org/issue2320
+ self._httpd_proc = subprocess.Popen(self._start_cmd,
+ stderr=subprocess.PIPE,
+ shell=True)
+ err = self._httpd_proc.stderr.read()
+ if len(err):
+ _log.debug(err)
+ return False
+ return True
+
+ def start(self):
+ """Starts the apache http server."""
+ # Stop any currently running servers.
+ self.stop()
+
+ _log.debug("Starting apache http server")
+ server_started = self.wait_for_action(self._start_httpd_process)
+ if server_started:
+ _log.debug("Apache started. Testing ports")
+ server_started = self.wait_for_action(
+ self.is_server_running_on_all_ports)
+
+ if server_started:
+ _log.debug("Server successfully started")
+ else:
+ raise Exception('Failed to start http server')
+
+ def stop(self):
+ """Stops the apache http server."""
+ _log.debug("Shutting down any running http servers")
+ httpd_pid = None
+ if os.path.exists(self._pid_file):
+ httpd_pid = int(open(self._pid_file).readline())
+ # FIXME: We shouldn't be calling a protected method of _port_obj!
+ self._port_obj._shut_down_http_server(httpd_pid)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base.py b/Tools/Scripts/webkitpy/layout_tests/port/base.py
new file mode 100644
index 0000000..97b54c9
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/base.py
@@ -0,0 +1,862 @@
+#!/usr/bin/env python
+# 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 Google name 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.
+
+"""Abstract base class of Port-specific entrypoints for the layout tests
+test infrastructure (the Port and Driver classes)."""
+
+import cgi
+import difflib
+import errno
+import os
+import shlex
+import sys
+import time
+
+import apache_http_server
+import config as port_config
+import http_lock
+import http_server
+import test_files
+import websocket_server
+
+from webkitpy.common import system
+from webkitpy.common.system import filesystem
+from webkitpy.common.system import logutils
+from webkitpy.common.system import path
+from webkitpy.common.system.executive import Executive, ScriptError
+from webkitpy.common.system.user import User
+
+
+_log = logutils.get_logger(__file__)
+
+
+class DummyOptions(object):
+ """Fake implementation of optparse.Values. Cloned from
+ webkitpy.tool.mocktool.MockOptions.
+
+ """
+
+ def __init__(self, **kwargs):
+ # The caller can set option values using keyword arguments. We don't
+ # set any values by default because we don't know how this
+ # object will be used. Generally speaking unit tests should
+ # subclass this or provider wrapper functions that set a common
+ # set of options.
+ for key, value in kwargs.items():
+ self.__dict__[key] = value
+
+
+# FIXME: This class should merge with webkitpy.webkit_port at some point.
+class Port(object):
+ """Abstract class for Port-specific hooks for the layout_test package."""
+
+ def __init__(self, port_name=None, options=None,
+ executive=None,
+ user=None,
+ filesystem=None,
+ config=None,
+ **kwargs):
+ self._name = port_name
+ self._options = options
+ if self._options is None:
+ # FIXME: Ideally we'd have a package-wide way to get a
+ # well-formed options object that had all of the necessary
+ # options defined on it.
+ self._options = DummyOptions()
+ self._executive = executive or Executive()
+ self._user = user or User()
+ self._filesystem = filesystem or system.filesystem.FileSystem()
+ self._config = config or port_config.Config(self._executive,
+ self._filesystem)
+ self._helper = None
+ self._http_server = None
+ self._webkit_base_dir = None
+ self._websocket_server = None
+ self._http_lock = None
+
+ # Python's Popen has a bug that causes any pipes opened to a
+ # process that can't be executed to be leaked. Since this
+ # code is specifically designed to tolerate exec failures
+ # to gracefully handle cases where wdiff is not installed,
+ # the bug results in a massive file descriptor leak. As a
+ # workaround, if an exec failure is ever experienced for
+ # wdiff, assume it's not available. This will leak one
+ # file descriptor but that's better than leaking each time
+ # wdiff would be run.
+ #
+ # http://mail.python.org/pipermail/python-list/
+ # 2008-August/505753.html
+ # http://bugs.python.org/issue3210
+ self._wdiff_available = True
+
+ self._pretty_patch_path = self.path_from_webkit_base("Websites",
+ "bugs.webkit.org", "PrettyPatch", "prettify.rb")
+ self._pretty_patch_available = True
+ self.set_option_default('configuration', None)
+ if self._options.configuration is None:
+ self._options.configuration = self.default_configuration()
+
+ def default_child_processes(self):
+ """Return the number of DumpRenderTree instances to use for this
+ port."""
+ return self._executive.cpu_count()
+
+ def baseline_path(self):
+ """Return the absolute path to the directory to store new baselines
+ in for this port."""
+ raise NotImplementedError('Port.baseline_path')
+
+ def baseline_search_path(self):
+ """Return a list of absolute paths to directories to search under for
+ baselines. The directories are searched in order."""
+ raise NotImplementedError('Port.baseline_search_path')
+
+ def check_build(self, needs_http):
+ """This routine is used to ensure that the build is up to date
+ and all the needed binaries are present."""
+ raise NotImplementedError('Port.check_build')
+
+ def check_sys_deps(self, needs_http):
+ """If the port needs to do some runtime checks to ensure that the
+ tests can be run successfully, it should override this routine.
+ This step can be skipped with --nocheck-sys-deps.
+
+ Returns whether the system is properly configured."""
+ return True
+
+ def check_image_diff(self, override_step=None, logging=True):
+ """This routine is used to check whether image_diff binary exists."""
+ raise NotImplementedError('Port.check_image_diff')
+
+ def check_pretty_patch(self):
+ """Checks whether we can use the PrettyPatch ruby script."""
+
+ # check if Ruby is installed
+ try:
+ result = self._executive.run_command(['ruby', '--version'])
+ except OSError, e:
+ if e.errno in [errno.ENOENT, errno.EACCES, errno.ECHILD]:
+ _log.error("Ruby is not installed; "
+ "can't generate pretty patches.")
+ _log.error('')
+ return False
+
+ if not self.path_exists(self._pretty_patch_path):
+ _log.error('Unable to find %s .' % self._pretty_patch_path)
+ _log.error("Can't generate pretty patches.")
+ _log.error('')
+ return False
+
+ return True
+
+ def compare_text(self, expected_text, actual_text):
+ """Return whether or not the two strings are *not* equal. This
+ routine is used to diff text output.
+
+ While this is a generic routine, we include it in the Port
+ interface so that it can be overriden for testing purposes."""
+ return expected_text != actual_text
+
+ def diff_image(self, expected_contents, actual_contents,
+ diff_filename=None, tolerance=0):
+ """Compare two images and produce a delta image file.
+
+ Return True if the two images are different, False if they are the same.
+ Also produce a delta image of the two images and write that into
+ |diff_filename| if it is not None.
+
+ |tolerance| should be a percentage value (0.0 - 100.0).
+ If it is omitted, the port default tolerance value is used.
+
+ """
+ raise NotImplementedError('Port.diff_image')
+
+
+ def diff_text(self, expected_text, actual_text,
+ expected_filename, actual_filename):
+ """Returns a string containing the diff of the two text strings
+ in 'unified diff' format.
+
+ While this is a generic routine, we include it in the Port
+ interface so that it can be overriden for testing purposes."""
+
+ # The filenames show up in the diff output, make sure they're
+ # raw bytes and not unicode, so that they don't trigger join()
+ # trying to decode the input.
+ def to_raw_bytes(str):
+ if isinstance(str, unicode):
+ return str.encode('utf-8')
+ return str
+ expected_filename = to_raw_bytes(expected_filename)
+ actual_filename = to_raw_bytes(actual_filename)
+ diff = difflib.unified_diff(expected_text.splitlines(True),
+ actual_text.splitlines(True),
+ expected_filename,
+ actual_filename)
+ return ''.join(diff)
+
+ def driver_name(self):
+ """Returns the name of the actual binary that is performing the test,
+ so that it can be referred to in log messages. In most cases this
+ will be DumpRenderTree, but if a port uses a binary with a different
+ name, it can be overridden here."""
+ return "DumpRenderTree"
+
+ def expected_baselines(self, filename, suffix, all_baselines=False):
+ """Given a test name, finds where the baseline results are located.
+
+ Args:
+ filename: absolute filename to test file
+ suffix: file suffix of the expected results, including dot; e.g.
+ '.txt' or '.png'. This should not be None, but may be an empty
+ string.
+ all_baselines: If True, return an ordered list of all baseline paths
+ for the given platform. If False, return only the first one.
+ Returns
+ a list of ( platform_dir, results_filename ), where
+ platform_dir - abs path to the top of the results tree (or test
+ tree)
+ results_filename - relative path from top of tree to the results
+ file
+ (os.path.join of the two gives you the full path to the file,
+ unless None was returned.)
+ Return values will be in the format appropriate for the current
+ platform (e.g., "\\" for path separators on Windows). If the results
+ file is not found, then None will be returned for the directory,
+ but the expected relative pathname will still be returned.
+
+ This routine is generic but lives here since it is used in
+ conjunction with the other baseline and filename routines that are
+ platform specific.
+ """
+ testname = os.path.splitext(self.relative_test_filename(filename))[0]
+
+ baseline_filename = testname + '-expected' + suffix
+
+ baseline_search_path = self.baseline_search_path()
+
+ baselines = []
+ for platform_dir in baseline_search_path:
+ if self.path_exists(self._filesystem.join(platform_dir,
+ baseline_filename)):
+ baselines.append((platform_dir, baseline_filename))
+
+ if not all_baselines and baselines:
+ return baselines
+
+ # If it wasn't found in a platform directory, return the expected
+ # result in the test directory, even if no such file actually exists.
+ platform_dir = self.layout_tests_dir()
+ if self.path_exists(self._filesystem.join(platform_dir,
+ baseline_filename)):
+ baselines.append((platform_dir, baseline_filename))
+
+ if baselines:
+ return baselines
+
+ return [(None, baseline_filename)]
+
+ def expected_filename(self, filename, suffix):
+ """Given a test name, returns an absolute path to its expected results.
+
+ If no expected results are found in any of the searched directories,
+ the directory in which the test itself is located will be returned.
+ The return value is in the format appropriate for the platform
+ (e.g., "\\" for path separators on windows).
+
+ Args:
+ filename: absolute filename to test file
+ suffix: file suffix of the expected results, including dot; e.g. '.txt'
+ or '.png'. This should not be None, but may be an empty string.
+ platform: the most-specific directory name to use to build the
+ search list of directories, e.g., 'chromium-win', or
+ 'chromium-mac-leopard' (we follow the WebKit format)
+
+ This routine is generic but is implemented here to live alongside
+ the other baseline and filename manipulation routines.
+ """
+ platform_dir, baseline_filename = self.expected_baselines(
+ filename, suffix)[0]
+ if platform_dir:
+ return self._filesystem.join(platform_dir, baseline_filename)
+ return self._filesystem.join(self.layout_tests_dir(), baseline_filename)
+
+ def expected_checksum(self, test):
+ """Returns the checksum of the image we expect the test to produce, or None if it is a text-only test."""
+ path = self.expected_filename(test, '.checksum')
+ if not self.path_exists(path):
+ return None
+ return self._filesystem.read_text_file(path)
+
+ def expected_image(self, test):
+ """Returns the image we expect the test to produce."""
+ path = self.expected_filename(test, '.png')
+ if not self.path_exists(path):
+ return None
+ return self._filesystem.read_binary_file(path)
+
+ def expected_text(self, test):
+ """Returns the text output we expect the test to produce.
+ End-of-line characters are normalized to '\n'."""
+ # FIXME: DRT output is actually utf-8, but since we don't decode the
+ # output from DRT (instead treating it as a binary string), we read the
+ # baselines as a binary string, too.
+ path = self.expected_filename(test, '.txt')
+ if not self.path_exists(path):
+ return ''
+ text = self._filesystem.read_binary_file(path)
+ return text.replace("\r\n", "\n")
+
+ def filename_to_uri(self, filename):
+ """Convert a test file (which is an absolute path) to a URI."""
+ LAYOUTTEST_HTTP_DIR = "http/tests/"
+ LAYOUTTEST_WEBSOCKET_DIR = "http/tests/websocket/tests/"
+
+ relative_path = self.relative_test_filename(filename)
+ port = None
+ use_ssl = False
+
+ if (relative_path.startswith(LAYOUTTEST_WEBSOCKET_DIR)
+ or relative_path.startswith(LAYOUTTEST_HTTP_DIR)):
+ relative_path = relative_path[len(LAYOUTTEST_HTTP_DIR):]
+ port = 8000
+
+ # Make http/tests/local run as local files. This is to mimic the
+ # logic in run-webkit-tests.
+ #
+ # TODO(dpranke): remove the media reference and the SSL reference?
+ if (port and not relative_path.startswith("local/") and
+ not relative_path.startswith("media/")):
+ if relative_path.startswith("ssl/"):
+ port += 443
+ protocol = "https"
+ else:
+ protocol = "http"
+ return "%s://127.0.0.1:%u/%s" % (protocol, port, relative_path)
+
+ return path.abspath_to_uri(os.path.abspath(filename))
+
+ def tests(self, paths):
+ """Return the list of tests found (relative to layout_tests_dir()."""
+ return test_files.find(self, paths)
+
+ def test_dirs(self):
+ """Returns the list of top-level test directories.
+
+ Used by --clobber-old-results."""
+ layout_tests_dir = self.layout_tests_dir()
+ return filter(lambda x: self._filesystem.isdir(self._filesystem.join(layout_tests_dir, x)),
+ self._filesystem.listdir(layout_tests_dir))
+
+ def path_isdir(self, path):
+ """Return True if the path refers to a directory of tests."""
+ # Used by test_expectations.py to apply rules to whole directories.
+ return self._filesystem.isdir(path)
+
+ def path_exists(self, path):
+ """Return True if the path refers to an existing test or baseline."""
+ # Used by test_expectations.py to determine if an entry refers to a
+ # valid test and by printing.py to determine if baselines exist.
+ return self._filesystem.exists(path)
+
+ def driver_cmd_line(self):
+ """Prints the DRT command line that will be used."""
+ driver = self.create_driver(0)
+ return driver.cmd_line()
+
+ def update_baseline(self, path, data, encoding):
+ """Updates the baseline for a test.
+
+ Args:
+ path: the actual path to use for baseline, not the path to
+ the test. This function is used to update either generic or
+ platform-specific baselines, but we can't infer which here.
+ data: contents of the baseline.
+ encoding: file encoding to use for the baseline.
+ """
+ # FIXME: remove the encoding parameter in favor of text/binary
+ # functions.
+ if encoding is None:
+ self._filesystem.write_binary_file(path, data)
+ else:
+ self._filesystem.write_text_file(path, data)
+
+ def uri_to_test_name(self, uri):
+ """Return the base layout test name for a given URI.
+
+ This returns the test name for a given URI, e.g., if you passed in
+ "file:///src/LayoutTests/fast/html/keygen.html" it would return
+ "fast/html/keygen.html".
+
+ """
+ test = uri
+ if uri.startswith("file:///"):
+ prefix = path.abspath_to_uri(self.layout_tests_dir()) + "/"
+ return test[len(prefix):]
+
+ if uri.startswith("http://127.0.0.1:8880/"):
+ # websocket tests
+ return test.replace('http://127.0.0.1:8880/', '')
+
+ if uri.startswith("http://"):
+ # regular HTTP test
+ return test.replace('http://127.0.0.1:8000/', 'http/tests/')
+
+ if uri.startswith("https://"):
+ return test.replace('https://127.0.0.1:8443/', 'http/tests/')
+
+ raise NotImplementedError('unknown url type: %s' % uri)
+
+ def layout_tests_dir(self):
+ """Return the absolute path to the top of the LayoutTests directory."""
+ return self.path_from_webkit_base('LayoutTests')
+
+ def skips_layout_test(self, test_name):
+ """Figures out if the givent test is being skipped or not.
+
+ Test categories are handled as well."""
+ for test_or_category in self.skipped_layout_tests():
+ if test_or_category == test_name:
+ return True
+ category = self._filesystem.join(self.layout_tests_dir(),
+ test_or_category)
+ if (self._filesystem.isdir(category) and
+ test_name.startswith(test_or_category)):
+ return True
+ return False
+
+ def maybe_make_directory(self, *path):
+ """Creates the specified directory if it doesn't already exist."""
+ self._filesystem.maybe_make_directory(*path)
+
+ def name(self):
+ """Return the name of the port (e.g., 'mac', 'chromium-win-xp').
+
+ Note that this is different from the test_platform_name(), which
+ may be different (e.g., 'win-xp' instead of 'chromium-win-xp'."""
+ return self._name
+
+ def get_option(self, name, default_value=None):
+ # FIXME: Eventually we should not have to do a test for
+ # hasattr(), and we should be able to just do
+ # self.options.value. See additional FIXME in the constructor.
+ if hasattr(self._options, name):
+ return getattr(self._options, name)
+ return default_value
+
+ def set_option_default(self, name, default_value):
+ if not hasattr(self._options, name):
+ return setattr(self._options, name, default_value)
+
+ def path_from_webkit_base(self, *comps):
+ """Returns the full path to path made by joining the top of the
+ WebKit source tree and the list of path components in |*comps|."""
+ return self._config.path_from_webkit_base(*comps)
+
+ def script_path(self, script_name):
+ return self._config.script_path(script_name)
+
+ def path_to_test_expectations_file(self):
+ """Update the test expectations to the passed-in string.
+
+ This is used by the rebaselining tool. Raises NotImplementedError
+ if the port does not use expectations files."""
+ raise NotImplementedError('Port.path_to_test_expectations_file')
+
+ def relative_test_filename(self, filename):
+ """Relative unix-style path for a filename under the LayoutTests
+ directory. Filenames outside the LayoutTests directory should raise
+ an error."""
+ assert filename.startswith(self.layout_tests_dir()), "%s did not start with %s" % (filename, self.layout_tests_dir())
+ return filename[len(self.layout_tests_dir()) + 1:]
+
+ def results_directory(self):
+ """Absolute path to the place to store the test results."""
+ raise NotImplementedError('Port.results_directory')
+
+ def setup_test_run(self):
+ """Perform port-specific work at the beginning of a test run."""
+ pass
+
+ def setup_environ_for_server(self):
+ """Perform port-specific work at the beginning of a server launch.
+
+ Returns:
+ Operating-system's environment.
+ """
+ return os.environ.copy()
+
+ def show_results_html_file(self, results_filename):
+ """This routine should display the HTML file pointed at by
+ results_filename in a users' browser."""
+ return self._user.open_url(results_filename)
+
+ def create_driver(self, worker_number):
+ """Return a newly created base.Driver subclass for starting/stopping
+ the test driver."""
+ raise NotImplementedError('Port.create_driver')
+
+ def start_helper(self):
+ """If a port needs to reconfigure graphics settings or do other
+ things to ensure a known test configuration, it should override this
+ method."""
+ pass
+
+ def start_http_server(self):
+ """Start a web server if it is available. Do nothing if
+ it isn't. This routine is allowed to (and may) fail if a server
+ is already running."""
+ if self.get_option('use_apache'):
+ self._http_server = apache_http_server.LayoutTestApacheHttpd(self,
+ self.get_option('results_directory'))
+ else:
+ self._http_server = http_server.Lighttpd(self,
+ self.get_option('results_directory'))
+ self._http_server.start()
+
+ def start_websocket_server(self):
+ """Start a websocket server if it is available. Do nothing if
+ it isn't. This routine is allowed to (and may) fail if a server
+ is already running."""
+ self._websocket_server = websocket_server.PyWebSocket(self,
+ self.get_option('results_directory'))
+ self._websocket_server.start()
+
+ def acquire_http_lock(self):
+ self._http_lock = http_lock.HttpLock(None)
+ self._http_lock.wait_for_httpd_lock()
+
+ def stop_helper(self):
+ """Shut down the test helper if it is running. Do nothing if
+ it isn't, or it isn't available. If a port overrides start_helper()
+ it must override this routine as well."""
+ pass
+
+ def stop_http_server(self):
+ """Shut down the http server if it is running. Do nothing if
+ it isn't, or it isn't available."""
+ if self._http_server:
+ self._http_server.stop()
+
+ def stop_websocket_server(self):
+ """Shut down the websocket server if it is running. Do nothing if
+ it isn't, or it isn't available."""
+ if self._websocket_server:
+ self._websocket_server.stop()
+
+ def release_http_lock(self):
+ if self._http_lock:
+ self._http_lock.cleanup_http_lock()
+
+ def test_expectations(self):
+ """Returns the test expectations for this port.
+
+ Basically this string should contain the equivalent of a
+ test_expectations file. See test_expectations.py for more details."""
+ raise NotImplementedError('Port.test_expectations')
+
+ def test_expectations_overrides(self):
+ """Returns an optional set of overrides for the test_expectations.
+
+ This is used by ports that have code in two repositories, and where
+ it is possible that you might need "downstream" expectations that
+ temporarily override the "upstream" expectations until the port can
+ sync up the two repos."""
+ return None
+
+ def test_base_platform_names(self):
+ """Return a list of the 'base' platforms on your port. The base
+ platforms represent different architectures, operating systems,
+ or implementations (as opposed to different versions of a single
+ platform). For example, 'mac' and 'win' might be different base
+ platforms, wherease 'mac-tiger' and 'mac-leopard' might be
+ different platforms. This routine is used by the rebaselining tool
+ and the dashboards, and the strings correspond to the identifiers
+ in your test expectations (*not* necessarily the platform names
+ themselves)."""
+ raise NotImplementedError('Port.base_test_platforms')
+
+ def test_platform_name(self):
+ """Returns the string that corresponds to the given platform name
+ in the test expectations. This may be the same as name(), or it
+ may be different. For example, chromium returns 'mac' for
+ 'chromium-mac'."""
+ raise NotImplementedError('Port.test_platform_name')
+
+ def test_platforms(self):
+ """Returns the list of test platform identifiers as used in the
+ test_expectations and on dashboards, the rebaselining tool, etc.
+
+ Note that this is not necessarily the same as the list of ports,
+ which must be globally unique (e.g., both 'chromium-mac' and 'mac'
+ might return 'mac' as a test_platform name'."""
+ raise NotImplementedError('Port.platforms')
+
+ def test_platform_name_to_name(self, test_platform_name):
+ """Returns the Port platform name that corresponds to the name as
+ referenced in the expectations file. E.g., "mac" returns
+ "chromium-mac" on the Chromium ports."""
+ raise NotImplementedError('Port.test_platform_name_to_name')
+
+ def version(self):
+ """Returns a string indicating the version of a given platform, e.g.
+ '-leopard' or '-xp'.
+
+ This is used to help identify the exact port when parsing test
+ expectations, determining search paths, and logging information."""
+ raise NotImplementedError('Port.version')
+
+ def test_repository_paths(self):
+ """Returns a list of (repository_name, repository_path) tuples
+ of its depending code base. By default it returns a list that only
+ contains a ('webkit', <webkitRepossitoryPath>) tuple.
+ """
+ return [('webkit', self.layout_tests_dir())]
+
+
+ _WDIFF_DEL = '##WDIFF_DEL##'
+ _WDIFF_ADD = '##WDIFF_ADD##'
+ _WDIFF_END = '##WDIFF_END##'
+
+ def _format_wdiff_output_as_html(self, wdiff):
+ wdiff = cgi.escape(wdiff)
+ wdiff = wdiff.replace(self._WDIFF_DEL, "<span class=del>")
+ wdiff = wdiff.replace(self._WDIFF_ADD, "<span class=add>")
+ wdiff = wdiff.replace(self._WDIFF_END, "</span>")
+ html = "<head><style>.del { background: #faa; } "
+ html += ".add { background: #afa; }</style></head>"
+ html += "<pre>%s</pre>" % wdiff
+ return html
+
+ def _wdiff_command(self, actual_filename, expected_filename):
+ executable = self._path_to_wdiff()
+ return [executable,
+ "--start-delete=%s" % self._WDIFF_DEL,
+ "--end-delete=%s" % self._WDIFF_END,
+ "--start-insert=%s" % self._WDIFF_ADD,
+ "--end-insert=%s" % self._WDIFF_END,
+ actual_filename,
+ expected_filename]
+
+ @staticmethod
+ def _handle_wdiff_error(script_error):
+ # Exit 1 means the files differed, any other exit code is an error.
+ if script_error.exit_code != 1:
+ raise script_error
+
+ def _run_wdiff(self, actual_filename, expected_filename):
+ """Runs wdiff and may throw exceptions.
+ This is mostly a hook for unit testing."""
+ # Diffs are treated as binary as they may include multiple files
+ # with conflicting encodings. Thus we do not decode the output.
+ command = self._wdiff_command(actual_filename, expected_filename)
+ wdiff = self._executive.run_command(command, decode_output=False,
+ error_handler=self._handle_wdiff_error)
+ return self._format_wdiff_output_as_html(wdiff)
+
+ def wdiff_text(self, actual_filename, expected_filename):
+ """Returns a string of HTML indicating the word-level diff of the
+ contents of the two filenames. Returns an empty string if word-level
+ diffing isn't available."""
+ if not self._wdiff_available:
+ return ""
+ try:
+ # It's possible to raise a ScriptError we pass wdiff invalid paths.
+ return self._run_wdiff(actual_filename, expected_filename)
+ except OSError, e:
+ if e.errno in [errno.ENOENT, errno.EACCES, errno.ECHILD]:
+ # Silently ignore cases where wdiff is missing.
+ self._wdiff_available = False
+ return ""
+ raise
+
+ # This is a class variable so we can test error output easily.
+ _pretty_patch_error_html = "Failed to run PrettyPatch, see error log."
+
+ def pretty_patch_text(self, diff_path):
+ if not self._pretty_patch_available:
+ return self._pretty_patch_error_html
+ command = ("ruby", "-I", os.path.dirname(self._pretty_patch_path),
+ self._pretty_patch_path, diff_path)
+ try:
+ # Diffs are treated as binary (we pass decode_output=False) as they
+ # may contain multiple files of conflicting encodings.
+ return self._executive.run_command(command, decode_output=False)
+ except OSError, e:
+ # If the system is missing ruby log the error and stop trying.
+ self._pretty_patch_available = False
+ _log.error("Failed to run PrettyPatch (%s): %s" % (command, e))
+ return self._pretty_patch_error_html
+ except ScriptError, e:
+ # If ruby failed to run for some reason, log the command
+ # output and stop trying.
+ self._pretty_patch_available = False
+ _log.error("Failed to run PrettyPatch (%s):\n%s" % (command,
+ e.message_with_output()))
+ return self._pretty_patch_error_html
+
+ def default_configuration(self):
+ return self._config.default_configuration()
+
+ #
+ # PROTECTED ROUTINES
+ #
+ # The routines below should only be called by routines in this class
+ # or any of its subclasses.
+ #
+ def _webkit_build_directory(self, args):
+ return self._config.build_directory(args[0])
+
+ def _path_to_apache(self):
+ """Returns the full path to the apache binary.
+
+ This is needed only by ports that use the apache_http_server module."""
+ raise NotImplementedError('Port.path_to_apache')
+
+ def _path_to_apache_config_file(self):
+ """Returns the full path to the apache binary.
+
+ This is needed only by ports that use the apache_http_server module."""
+ raise NotImplementedError('Port.path_to_apache_config_file')
+
+ def _path_to_driver(self, configuration=None):
+ """Returns the full path to the test driver (DumpRenderTree)."""
+ raise NotImplementedError('Port._path_to_driver')
+
+ def _path_to_webcore_library(self):
+ """Returns the full path to a built copy of WebCore."""
+ raise NotImplementedError('Port.path_to_webcore_library')
+
+ def _path_to_helper(self):
+ """Returns the full path to the layout_test_helper binary, which
+ is used to help configure the system for the test run, or None
+ if no helper is needed.
+
+ This is likely only used by start/stop_helper()."""
+ raise NotImplementedError('Port._path_to_helper')
+
+ def _path_to_image_diff(self):
+ """Returns the full path to the image_diff binary, or None if it
+ is not available.
+
+ This is likely used only by diff_image()"""
+ raise NotImplementedError('Port.path_to_image_diff')
+
+ def _path_to_lighttpd(self):
+ """Returns the path to the LigHTTPd binary.
+
+ This is needed only by ports that use the http_server.py module."""
+ raise NotImplementedError('Port._path_to_lighttpd')
+
+ def _path_to_lighttpd_modules(self):
+ """Returns the path to the LigHTTPd modules directory.
+
+ This is needed only by ports that use the http_server.py module."""
+ raise NotImplementedError('Port._path_to_lighttpd_modules')
+
+ def _path_to_lighttpd_php(self):
+ """Returns the path to the LigHTTPd PHP executable.
+
+ This is needed only by ports that use the http_server.py module."""
+ raise NotImplementedError('Port._path_to_lighttpd_php')
+
+ def _path_to_wdiff(self):
+ """Returns the full path to the wdiff binary, or None if it is
+ not available.
+
+ This is likely used only by wdiff_text()"""
+ raise NotImplementedError('Port._path_to_wdiff')
+
+ def _shut_down_http_server(self, pid):
+ """Forcefully and synchronously kills the web server.
+
+ This routine should only be called from http_server.py or its
+ subclasses."""
+ raise NotImplementedError('Port._shut_down_http_server')
+
+ def _webkit_baseline_path(self, platform):
+ """Return the full path to the top of the baseline tree for a
+ given platform."""
+ return self._filesystem.join(self.layout_tests_dir(), 'platform',
+ platform)
+
+
+class Driver:
+ """Abstract interface for the DumpRenderTree interface."""
+
+ def __init__(self, port, worker_number):
+ """Initialize a Driver to subsequently run tests.
+
+ Typically this routine will spawn DumpRenderTree in a config
+ ready for subsequent input.
+
+ port - reference back to the port object.
+ worker_number - identifier for a particular worker/driver instance
+ """
+ raise NotImplementedError('Driver.__init__')
+
+ def run_test(self, test_input):
+ """Run a single test and return the results.
+
+ Note that it is okay if a test times out or crashes and leaves
+ the driver in an indeterminate state. The upper layers of the program
+ are responsible for cleaning up and ensuring things are okay.
+
+ Args:
+ test_input: a TestInput object
+
+ Returns a TestOutput object.
+ """
+ raise NotImplementedError('Driver.run_test')
+
+ # FIXME: This is static so we can test it w/o creating a Base instance.
+ @classmethod
+ def _command_wrapper(cls, wrapper_option):
+ # Hook for injecting valgrind or other runtime instrumentation,
+ # used by e.g. tools/valgrind/valgrind_tests.py.
+ wrapper = []
+ browser_wrapper = os.environ.get("BROWSER_WRAPPER", None)
+ if browser_wrapper:
+ # FIXME: There seems to be no reason to use BROWSER_WRAPPER over --wrapper.
+ # Remove this code any time after the date listed below.
+ _log.error("BROWSER_WRAPPER is deprecated, please use --wrapper instead.")
+ _log.error("BROWSER_WRAPPER will be removed any time after June 1st 2010 and your scripts will break.")
+ wrapper += [browser_wrapper]
+
+ if wrapper_option:
+ wrapper += shlex.split(wrapper_option)
+ return wrapper
+
+ def poll(self):
+ """Returns None if the Driver is still running. Returns the returncode
+ if it has exited."""
+ raise NotImplementedError('Driver.poll')
+
+ def stop(self):
+ raise NotImplementedError('Driver.stop')
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
new file mode 100644
index 0000000..8d586e3
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/base_unittest.py
@@ -0,0 +1,315 @@
+# 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 optparse
+import os
+import sys
+import tempfile
+import unittest
+
+from webkitpy.common.system.executive import Executive, ScriptError
+from webkitpy.common.system import executive_mock
+from webkitpy.common.system import filesystem
+from webkitpy.common.system import outputcapture
+from webkitpy.common.system.path import abspath_to_uri
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.tool import mocktool
+
+import base
+import config
+import config_mock
+
+
+class PortTest(unittest.TestCase):
+ def test_format_wdiff_output_as_html(self):
+ output = "OUTPUT %s %s %s" % (base.Port._WDIFF_DEL, base.Port._WDIFF_ADD, base.Port._WDIFF_END)
+ html = base.Port()._format_wdiff_output_as_html(output)
+ expected_html = "<head><style>.del { background: #faa; } .add { background: #afa; }</style></head><pre>OUTPUT <span class=del> <span class=add> </span></pre>"
+ self.assertEqual(html, expected_html)
+
+ def test_wdiff_command(self):
+ port = base.Port()
+ port._path_to_wdiff = lambda: "/path/to/wdiff"
+ command = port._wdiff_command("/actual/path", "/expected/path")
+ expected_command = [
+ "/path/to/wdiff",
+ "--start-delete=##WDIFF_DEL##",
+ "--end-delete=##WDIFF_END##",
+ "--start-insert=##WDIFF_ADD##",
+ "--end-insert=##WDIFF_END##",
+ "/actual/path",
+ "/expected/path",
+ ]
+ self.assertEqual(command, expected_command)
+
+ def _file_with_contents(self, contents, encoding="utf-8"):
+ new_file = tempfile.NamedTemporaryFile()
+ new_file.write(contents.encode(encoding))
+ new_file.flush()
+ return new_file
+
+ def test_pretty_patch_os_error(self):
+ port = base.Port(executive=executive_mock.MockExecutive2(exception=OSError))
+ oc = outputcapture.OutputCapture()
+ oc.capture_output()
+ self.assertEqual(port.pretty_patch_text("patch.txt"),
+ port._pretty_patch_error_html)
+
+ # This tests repeated calls to make sure we cache the result.
+ self.assertEqual(port.pretty_patch_text("patch.txt"),
+ port._pretty_patch_error_html)
+ oc.restore_output()
+
+ def test_pretty_patch_script_error(self):
+ # FIXME: This is some ugly white-box test hacking ...
+ base._pretty_patch_available = True
+ port = base.Port(executive=executive_mock.MockExecutive2(exception=ScriptError))
+ self.assertEqual(port.pretty_patch_text("patch.txt"),
+ port._pretty_patch_error_html)
+
+ # This tests repeated calls to make sure we cache the result.
+ self.assertEqual(port.pretty_patch_text("patch.txt"),
+ port._pretty_patch_error_html)
+
+ def test_run_wdiff(self):
+ executive = Executive()
+ # This may fail on some systems. We could ask the port
+ # object for the wdiff path, but since we don't know what
+ # port object to use, this is sufficient for now.
+ try:
+ wdiff_path = executive.run_command(["which", "wdiff"]).rstrip()
+ except Exception, e:
+ wdiff_path = None
+
+ port = base.Port()
+ port._path_to_wdiff = lambda: wdiff_path
+
+ if wdiff_path:
+ # "with tempfile.NamedTemporaryFile() as actual" does not seem to work in Python 2.5
+ actual = self._file_with_contents(u"foo")
+ expected = self._file_with_contents(u"bar")
+ wdiff = port._run_wdiff(actual.name, expected.name)
+ expected_wdiff = "<head><style>.del { background: #faa; } .add { background: #afa; }</style></head><pre><span class=del>foo</span><span class=add>bar</span></pre>"
+ self.assertEqual(wdiff, expected_wdiff)
+ # Running the full wdiff_text method should give the same result.
+ port._wdiff_available = True # In case it's somehow already disabled.
+ wdiff = port.wdiff_text(actual.name, expected.name)
+ self.assertEqual(wdiff, expected_wdiff)
+ # wdiff should still be available after running wdiff_text with a valid diff.
+ self.assertTrue(port._wdiff_available)
+ actual.close()
+ expected.close()
+
+ # Bogus paths should raise a script error.
+ self.assertRaises(ScriptError, port._run_wdiff, "/does/not/exist", "/does/not/exist2")
+ self.assertRaises(ScriptError, port.wdiff_text, "/does/not/exist", "/does/not/exist2")
+ # wdiff will still be available after running wdiff_text with invalid paths.
+ self.assertTrue(port._wdiff_available)
+ base._wdiff_available = True
+
+ # If wdiff does not exist _run_wdiff should throw an OSError.
+ port._path_to_wdiff = lambda: "/invalid/path/to/wdiff"
+ self.assertRaises(OSError, port._run_wdiff, "foo", "bar")
+
+ # wdiff_text should not throw an error if wdiff does not exist.
+ self.assertEqual(port.wdiff_text("foo", "bar"), "")
+ # However wdiff should not be available after running wdiff_text if wdiff is missing.
+ self.assertFalse(port._wdiff_available)
+
+ def test_diff_text(self):
+ port = base.Port()
+ # Make sure that we don't run into decoding exceptions when the
+ # filenames are unicode, with regular or malformed input (expected or
+ # actual input is always raw bytes, not unicode).
+ port.diff_text('exp', 'act', 'exp.txt', 'act.txt')
+ port.diff_text('exp', 'act', u'exp.txt', 'act.txt')
+ port.diff_text('exp', 'act', u'a\xac\u1234\u20ac\U00008000', 'act.txt')
+
+ port.diff_text('exp' + chr(255), 'act', 'exp.txt', 'act.txt')
+ port.diff_text('exp' + chr(255), 'act', u'exp.txt', 'act.txt')
+
+ # Though expected and actual files should always be read in with no
+ # encoding (and be stored as str objects), test unicode inputs just to
+ # be safe.
+ port.diff_text(u'exp', 'act', 'exp.txt', 'act.txt')
+ port.diff_text(
+ u'a\xac\u1234\u20ac\U00008000', 'act', 'exp.txt', 'act.txt')
+
+ # And make sure we actually get diff output.
+ diff = port.diff_text('foo', 'bar', 'exp.txt', 'act.txt')
+ self.assertTrue('foo' in diff)
+ self.assertTrue('bar' in diff)
+ self.assertTrue('exp.txt' in diff)
+ self.assertTrue('act.txt' in diff)
+ self.assertFalse('nosuchthing' in diff)
+
+ def test_default_configuration_notfound(self):
+ # Test that we delegate to the config object properly.
+ port = base.Port(config=config_mock.MockConfig(default_configuration='default'))
+ self.assertEqual(port.default_configuration(), 'default')
+
+ def test_layout_tests_skipping(self):
+ port = base.Port()
+ port.skipped_layout_tests = lambda: ['foo/bar.html', 'media']
+ self.assertTrue(port.skips_layout_test('foo/bar.html'))
+ self.assertTrue(port.skips_layout_test('media/video-zoom.html'))
+ self.assertFalse(port.skips_layout_test('foo/foo.html'))
+
+ def test_setup_test_run(self):
+ port = base.Port()
+ # This routine is a no-op. We just test it for coverage.
+ port.setup_test_run()
+
+ def test_test_dirs(self):
+ port = base.Port()
+ dirs = port.test_dirs()
+ self.assertTrue('canvas' in dirs)
+ self.assertTrue('css2.1' in dirs)
+
+ def test_filename_to_uri(self):
+ port = base.Port()
+ layout_test_dir = port.layout_tests_dir()
+ test_file = os.path.join(layout_test_dir, "foo", "bar.html")
+
+ # On Windows, absolute paths are of the form "c:\foo.txt". However,
+ # all current browsers (except for Opera) normalize file URLs by
+ # prepending an additional "/" as if the absolute path was
+ # "/c:/foo.txt". This means that all file URLs end up with "file:///"
+ # at the beginning.
+ if sys.platform == 'win32':
+ prefix = "file:///"
+ path = test_file.replace("\\", "/")
+ else:
+ prefix = "file://"
+ path = test_file
+
+ self.assertEqual(port.filename_to_uri(test_file),
+ abspath_to_uri(test_file))
+
+ def test_get_option__set(self):
+ options, args = optparse.OptionParser().parse_args([])
+ options.foo = 'bar'
+ port = base.Port(options=options)
+ self.assertEqual(port.get_option('foo'), 'bar')
+
+ def test_get_option__unset(self):
+ port = base.Port()
+ self.assertEqual(port.get_option('foo'), None)
+
+ def test_get_option__default(self):
+ port = base.Port()
+ self.assertEqual(port.get_option('foo', 'bar'), 'bar')
+
+ def test_set_option_default__unset(self):
+ port = base.Port()
+ port.set_option_default('foo', 'bar')
+ self.assertEqual(port.get_option('foo'), 'bar')
+
+ def test_set_option_default__set(self):
+ options, args = optparse.OptionParser().parse_args([])
+ options.foo = 'bar'
+ port = base.Port(options=options)
+ # This call should have no effect.
+ port.set_option_default('foo', 'new_bar')
+ self.assertEqual(port.get_option('foo'), 'bar')
+
+ def test_name__unset(self):
+ port = base.Port()
+ self.assertEqual(port.name(), None)
+
+ def test_name__set(self):
+ port = base.Port(port_name='foo')
+ self.assertEqual(port.name(), 'foo')
+
+
+class VirtualTest(unittest.TestCase):
+ """Tests that various methods expected to be virtual are."""
+ def assertVirtual(self, method, *args, **kwargs):
+ self.assertRaises(NotImplementedError, method, *args, **kwargs)
+
+ def test_virtual_methods(self):
+ port = base.Port()
+ self.assertVirtual(port.baseline_path)
+ self.assertVirtual(port.baseline_search_path)
+ self.assertVirtual(port.check_build, None)
+ self.assertVirtual(port.check_image_diff)
+ self.assertVirtual(port.create_driver, 0)
+ self.assertVirtual(port.diff_image, None, None)
+ self.assertVirtual(port.path_to_test_expectations_file)
+ self.assertVirtual(port.test_platform_name)
+ self.assertVirtual(port.results_directory)
+ self.assertVirtual(port.test_expectations)
+ self.assertVirtual(port.test_base_platform_names)
+ self.assertVirtual(port.test_platform_name)
+ self.assertVirtual(port.test_platforms)
+ self.assertVirtual(port.test_platform_name_to_name, None)
+ self.assertVirtual(port.version)
+ self.assertVirtual(port._path_to_apache)
+ self.assertVirtual(port._path_to_apache_config_file)
+ self.assertVirtual(port._path_to_driver)
+ self.assertVirtual(port._path_to_helper)
+ self.assertVirtual(port._path_to_image_diff)
+ self.assertVirtual(port._path_to_lighttpd)
+ self.assertVirtual(port._path_to_lighttpd_modules)
+ self.assertVirtual(port._path_to_lighttpd_php)
+ self.assertVirtual(port._path_to_wdiff)
+ self.assertVirtual(port._shut_down_http_server, None)
+
+ def test_virtual_driver_method(self):
+ self.assertRaises(NotImplementedError, base.Driver, base.Port(),
+ 0)
+
+ def test_virtual_driver_methods(self):
+ class VirtualDriver(base.Driver):
+ def __init__(self):
+ pass
+
+ driver = VirtualDriver()
+ self.assertVirtual(driver.run_test, None)
+ self.assertVirtual(driver.poll)
+ self.assertVirtual(driver.stop)
+
+
+class DriverTest(unittest.TestCase):
+
+ def _assert_wrapper(self, wrapper_string, expected_wrapper):
+ wrapper = base.Driver._command_wrapper(wrapper_string)
+ self.assertEqual(wrapper, expected_wrapper)
+
+ def test_command_wrapper(self):
+ self._assert_wrapper(None, [])
+ self._assert_wrapper("valgrind", ["valgrind"])
+
+ # Validate that shlex works as expected.
+ command_with_spaces = "valgrind --smc-check=\"check with spaces!\" --foo"
+ expected_parse = ["valgrind", "--smc-check=check with spaces!", "--foo"]
+ self._assert_wrapper(command_with_spaces, expected_parse)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
new file mode 100644
index 0000000..012e9cc
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium.py
@@ -0,0 +1,546 @@
+#!/usr/bin/env python
+# 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.
+
+"""Chromium implementations of the Port interface."""
+
+from __future__ import with_statement
+
+import codecs
+import errno
+import logging
+import os
+import re
+import shutil
+import signal
+import subprocess
+import sys
+import tempfile
+import time
+import webbrowser
+
+from webkitpy.common.system.path import cygpath
+from webkitpy.layout_tests.layout_package import test_expectations
+from webkitpy.layout_tests.layout_package import test_output
+
+import base
+import http_server
+
+# Chromium DRT on OSX uses WebKitDriver.
+if sys.platform == 'darwin':
+ import webkit
+
+import websocket_server
+
+_log = logging.getLogger("webkitpy.layout_tests.port.chromium")
+
+
+# FIXME: This function doesn't belong in this package.
+def check_file_exists(path_to_file, file_description, override_step=None,
+ logging=True):
+ """Verify the file is present where expected or log an error.
+
+ Args:
+ file_name: The (human friendly) name or description of the file
+ you're looking for (e.g., "HTTP Server"). Used for error logging.
+ override_step: An optional string to be logged if the check fails.
+ logging: Whether or not log the error messages."""
+ if not os.path.exists(path_to_file):
+ if logging:
+ _log.error('Unable to find %s' % file_description)
+ _log.error(' at %s' % path_to_file)
+ if override_step:
+ _log.error(' %s' % override_step)
+ _log.error('')
+ return False
+ return True
+
+
+class ChromiumPort(base.Port):
+ """Abstract base class for Chromium implementations of the Port class."""
+
+ def __init__(self, **kwargs):
+ base.Port.__init__(self, **kwargs)
+ self._chromium_base_dir = None
+
+ def baseline_path(self):
+ return self._webkit_baseline_path(self._name)
+
+ def check_build(self, needs_http):
+ result = True
+
+ dump_render_tree_binary_path = self._path_to_driver()
+ result = check_file_exists(dump_render_tree_binary_path,
+ 'test driver') and result
+ if result and self.get_option('build'):
+ result = self._check_driver_build_up_to_date(
+ self.get_option('configuration'))
+ else:
+ _log.error('')
+
+ helper_path = self._path_to_helper()
+ if helper_path:
+ result = check_file_exists(helper_path,
+ 'layout test helper') and result
+
+ if self.get_option('pixel_tests'):
+ result = self.check_image_diff(
+ 'To override, invoke with --no-pixel-tests') and result
+
+ # It's okay if pretty patch isn't available, but we will at
+ # least log a message.
+ self.check_pretty_patch()
+
+ return result
+
+ def check_sys_deps(self, needs_http):
+ cmd = [self._path_to_driver(), '--check-layout-test-sys-deps']
+ if self._executive.run_command(cmd, return_exit_code=True):
+ _log.error('System dependencies check failed.')
+ _log.error('To override, invoke with --nocheck-sys-deps')
+ _log.error('')
+ return False
+ return True
+
+ def check_image_diff(self, override_step=None, logging=True):
+ image_diff_path = self._path_to_image_diff()
+ return check_file_exists(image_diff_path, 'image diff exe',
+ override_step, logging)
+
+ def diff_image(self, expected_contents, actual_contents,
+ diff_filename=None):
+ executable = self._path_to_image_diff()
+
+ tempdir = tempfile.mkdtemp()
+ expected_filename = os.path.join(tempdir, "expected.png")
+ with open(expected_filename, 'w+b') as file:
+ file.write(expected_contents)
+ actual_filename = os.path.join(tempdir, "actual.png")
+ with open(actual_filename, 'w+b') as file:
+ file.write(actual_contents)
+
+ if diff_filename:
+ cmd = [executable, '--diff', expected_filename,
+ actual_filename, diff_filename]
+ else:
+ cmd = [executable, expected_filename, actual_filename]
+
+ result = True
+ try:
+ exit_code = self._executive.run_command(cmd, return_exit_code=True)
+ if exit_code == 0:
+ # The images are the same.
+ result = False
+ elif exit_code != 1:
+ _log.error("image diff returned an exit code of "
+ + str(exit_code))
+ # Returning False here causes the script to think that we
+ # successfully created the diff even though we didn't. If
+ # we return True, we think that the images match but the hashes
+ # don't match.
+ # FIXME: Figure out why image_diff returns other values.
+ result = False
+ except OSError, e:
+ if e.errno == errno.ENOENT or e.errno == errno.EACCES:
+ _compare_available = False
+ else:
+ raise e
+ finally:
+ shutil.rmtree(tempdir, ignore_errors=True)
+ return result
+
+ def driver_name(self):
+ if self._options.use_test_shell:
+ return "test_shell"
+ return "DumpRenderTree"
+
+ def path_from_chromium_base(self, *comps):
+ """Returns the full path to path made by joining the top of the
+ Chromium source tree and the list of path components in |*comps|."""
+ if not self._chromium_base_dir:
+ abspath = os.path.abspath(__file__)
+ offset = abspath.find('third_party')
+ if offset == -1:
+ self._chromium_base_dir = os.path.join(
+ abspath[0:abspath.find('Tools')],
+ 'WebKit', 'chromium')
+ else:
+ self._chromium_base_dir = abspath[0:offset]
+ return os.path.join(self._chromium_base_dir, *comps)
+
+ def path_to_test_expectations_file(self):
+ return self.path_from_webkit_base('LayoutTests', 'platform',
+ 'chromium', 'test_expectations.txt')
+
+ def results_directory(self):
+ try:
+ return self.path_from_chromium_base('webkit',
+ self.get_option('configuration'),
+ self.get_option('results_directory'))
+ except AssertionError:
+ return self._build_path(self.get_option('configuration'),
+ self.get_option('results_directory'))
+
+ def setup_test_run(self):
+ # Delete the disk cache if any to ensure a clean test run.
+ dump_render_tree_binary_path = self._path_to_driver()
+ cachedir = os.path.split(dump_render_tree_binary_path)[0]
+ cachedir = os.path.join(cachedir, "cache")
+ if os.path.exists(cachedir):
+ shutil.rmtree(cachedir)
+
+ def create_driver(self, worker_number):
+ """Starts a new Driver and returns a handle to it."""
+ if not self.get_option('use_test_shell') and sys.platform == 'darwin':
+ return webkit.WebKitDriver(self, worker_number)
+ return ChromiumDriver(self, worker_number)
+
+ def start_helper(self):
+ helper_path = self._path_to_helper()
+ if helper_path:
+ _log.debug("Starting layout helper %s" % helper_path)
+ # Note: Not thread safe: http://bugs.python.org/issue2320
+ self._helper = subprocess.Popen([helper_path],
+ stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=None)
+ is_ready = self._helper.stdout.readline()
+ if not is_ready.startswith('ready'):
+ _log.error("layout_test_helper failed to be ready")
+
+ def stop_helper(self):
+ if self._helper:
+ _log.debug("Stopping layout test helper")
+ self._helper.stdin.write("x\n")
+ self._helper.stdin.close()
+ # wait() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ self._helper.wait()
+
+ def test_base_platform_names(self):
+ return ('linux', 'mac', 'win')
+
+ def test_expectations(self):
+ """Returns the test expectations for this port.
+
+ Basically this string should contain the equivalent of a
+ test_expectations file. See test_expectations.py for more details."""
+ expectations_path = self.path_to_test_expectations_file()
+ with codecs.open(expectations_path, "r", "utf-8") as file:
+ return file.read()
+
+ def test_expectations_overrides(self):
+ try:
+ overrides_path = self.path_from_chromium_base('webkit', 'tools',
+ 'layout_tests', 'test_expectations.txt')
+ except AssertionError:
+ return None
+ if not os.path.exists(overrides_path):
+ return None
+ with codecs.open(overrides_path, "r", "utf-8") as file:
+ return file.read()
+
+ def skipped_layout_tests(self, extra_test_files=None):
+ expectations_str = self.test_expectations()
+ overrides_str = self.test_expectations_overrides()
+ test_platform_name = self.test_platform_name()
+ is_debug_mode = False
+
+ all_test_files = self.tests([])
+ if extra_test_files:
+ all_test_files.update(extra_test_files)
+
+ expectations = test_expectations.TestExpectations(
+ self, all_test_files, expectations_str, test_platform_name,
+ is_debug_mode, is_lint_mode=False, overrides=overrides_str)
+ tests_dir = self.layout_tests_dir()
+ return [self.relative_test_filename(test)
+ for test in expectations.get_tests_with_result_type(test_expectations.SKIP)]
+
+ def test_platform_names(self):
+ return self.test_base_platform_names() + ('win-xp',
+ 'win-vista', 'win-7')
+
+ def test_platform_name_to_name(self, test_platform_name):
+ if test_platform_name in self.test_platform_names():
+ return 'chromium-' + test_platform_name
+ raise ValueError('Unsupported test_platform_name: %s' %
+ test_platform_name)
+
+ def test_repository_paths(self):
+ # Note: for JSON file's backward-compatibility we use 'chrome' rather
+ # than 'chromium' here.
+ repos = super(ChromiumPort, self).test_repository_paths()
+ repos.append(('chrome', self.path_from_chromium_base()))
+ return repos
+
+ #
+ # PROTECTED METHODS
+ #
+ # These routines should only be called by other methods in this file
+ # or any subclasses.
+ #
+
+ def _check_driver_build_up_to_date(self, configuration):
+ if configuration in ('Debug', 'Release'):
+ try:
+ debug_path = self._path_to_driver('Debug')
+ release_path = self._path_to_driver('Release')
+
+ debug_mtime = os.stat(debug_path).st_mtime
+ release_mtime = os.stat(release_path).st_mtime
+
+ if (debug_mtime > release_mtime and configuration == 'Release' or
+ release_mtime > debug_mtime and configuration == 'Debug'):
+ _log.warning('You are not running the most '
+ 'recent DumpRenderTree binary. You need to '
+ 'pass --debug or not to select between '
+ 'Debug and Release.')
+ _log.warning('')
+ # This will fail if we don't have both a debug and release binary.
+ # That's fine because, in this case, we must already be running the
+ # most up-to-date one.
+ except OSError:
+ pass
+ return True
+
+ def _chromium_baseline_path(self, platform):
+ if platform is None:
+ platform = self.name()
+ return self.path_from_webkit_base('LayoutTests', 'platform', platform)
+
+ def _convert_path(self, path):
+ """Handles filename conversion for subprocess command line args."""
+ # See note above in diff_image() for why we need this.
+ if sys.platform == 'cygwin':
+ return cygpath(path)
+ return path
+
+ def _path_to_image_diff(self):
+ binary_name = 'ImageDiff'
+ if self.get_option('use_test_shell'):
+ binary_name = 'image_diff'
+ return self._build_path(self.get_option('configuration'), binary_name)
+
+
+class ChromiumDriver(base.Driver):
+ """Abstract interface for test_shell."""
+
+ def __init__(self, port, worker_number):
+ self._port = port
+ self._worker_number = worker_number
+ self._image_path = None
+ if self._port.get_option('pixel_tests'):
+ self._image_path = os.path.join(
+ self._port.get_option('results_directory'),
+ 'png_result%s.png' % self._worker_number)
+
+ def cmd_line(self):
+ cmd = self._command_wrapper(self._port.get_option('wrapper'))
+ cmd.append(self._port._path_to_driver())
+ if self._port.get_option('pixel_tests'):
+ # See note above in diff_image() for why we need _convert_path().
+ cmd.append("--pixel-tests=" +
+ self._port._convert_path(self._image_path))
+
+ if self._port.get_option('use_test_shell'):
+ cmd.append('--layout-tests')
+ else:
+ cmd.append('--test-shell')
+
+ if self._port.get_option('startup_dialog'):
+ cmd.append('--testshell-startup-dialog')
+
+ if self._port.get_option('gp_fault_error_box'):
+ cmd.append('--gp-fault-error-box')
+
+ if self._port.get_option('js_flags') is not None:
+ cmd.append('--js-flags="' + self._port.get_option('js_flags') + '"')
+
+ if self._port.get_option('multiple_loads') > 0:
+ cmd.append('--multiple-loads=' + str(self._port.get_option('multiple_loads')))
+
+ # test_shell does not support accelerated compositing.
+ if not self._port.get_option("use_test_shell"):
+ if self._port.get_option('accelerated_compositing'):
+ cmd.append('--enable-accelerated-compositing')
+ if self._port.get_option('accelerated_2d_canvas'):
+ cmd.append('--enable-accelerated-2d-canvas')
+ return cmd
+
+ def start(self):
+ # FIXME: Should be an error to call this method twice.
+ cmd = self.cmd_line()
+
+ # We need to pass close_fds=True to work around Python bug #2320
+ # (otherwise we can hang when we kill DumpRenderTree when we are running
+ # multiple threads). See http://bugs.python.org/issue2320 .
+ # Note that close_fds isn't supported on Windows, but this bug only
+ # shows up on Mac and Linux.
+ close_flag = sys.platform not in ('win32', 'cygwin')
+ self._proc = subprocess.Popen(cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT,
+ close_fds=close_flag)
+
+ def poll(self):
+ # poll() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ return self._proc.poll()
+
+ def _write_command_and_read_line(self, input=None):
+ """Returns a tuple: (line, did_crash)"""
+ try:
+ if input:
+ if isinstance(input, unicode):
+ # TestShell expects utf-8
+ input = input.encode("utf-8")
+ self._proc.stdin.write(input)
+ # DumpRenderTree text output is always UTF-8. However some tests
+ # (e.g. webarchive) may spit out binary data instead of text so we
+ # don't bother to decode the output (for either DRT or test_shell).
+ line = self._proc.stdout.readline()
+ # We could assert() here that line correctly decodes as UTF-8.
+ return (line, False)
+ except IOError, e:
+ _log.error("IOError communicating w/ test_shell: " + str(e))
+ return (None, True)
+
+ def _test_shell_command(self, uri, timeoutms, checksum):
+ cmd = uri
+ if timeoutms:
+ cmd += ' ' + str(timeoutms)
+ if checksum:
+ cmd += ' ' + checksum
+ cmd += "\n"
+ return cmd
+
+ def _output_image(self):
+ """Returns the image output which driver generated."""
+ png_path = self._image_path
+ if png_path and os.path.isfile(png_path):
+ with open(png_path, 'rb') as image_file:
+ return image_file.read()
+ else:
+ return None
+
+ def _output_image_with_retry(self):
+ # Retry a few more times because open() sometimes fails on Windows,
+ # raising "IOError: [Errno 13] Permission denied:"
+ retry_num = 50
+ timeout_seconds = 5.0
+ for i in range(retry_num):
+ try:
+ return self._output_image()
+ except IOError, e:
+ if e.errno == errno.EACCES:
+ time.sleep(timeout_seconds / retry_num)
+ else:
+ raise e
+ return self._output_image()
+
+ def run_test(self, test_input):
+ output = []
+ error = []
+ crash = False
+ timeout = False
+ actual_uri = None
+ actual_checksum = None
+
+ start_time = time.time()
+
+ uri = self._port.filename_to_uri(test_input.filename)
+ cmd = self._test_shell_command(uri, test_input.timeout,
+ test_input.image_hash)
+ (line, crash) = self._write_command_and_read_line(input=cmd)
+
+ while not crash and line.rstrip() != "#EOF":
+ # Make sure we haven't crashed.
+ if line == '' and self.poll() is not None:
+ # This is hex code 0xc000001d, which is used for abrupt
+ # termination. This happens if we hit ctrl+c from the prompt
+ # and we happen to be waiting on test_shell.
+ # sdoyon: Not sure for which OS and in what circumstances the
+ # above code is valid. What works for me under Linux to detect
+ # ctrl+c is for the subprocess returncode to be negative
+ # SIGINT. And that agrees with the subprocess documentation.
+ if (-1073741510 == self._proc.returncode or
+ - signal.SIGINT == self._proc.returncode):
+ raise KeyboardInterrupt
+ crash = True
+ break
+
+ # Don't include #URL lines in our output
+ if line.startswith("#URL:"):
+ actual_uri = line.rstrip()[5:]
+ if uri != actual_uri:
+ # GURL capitalizes the drive letter of a file URL.
+ if (not re.search("^file:///[a-z]:", uri) or
+ uri.lower() != actual_uri.lower()):
+ _log.fatal("Test got out of sync:\n|%s|\n|%s|" %
+ (uri, actual_uri))
+ raise AssertionError("test out of sync")
+ elif line.startswith("#MD5:"):
+ actual_checksum = line.rstrip()[5:]
+ elif line.startswith("#TEST_TIMED_OUT"):
+ timeout = True
+ # Test timed out, but we still need to read until #EOF.
+ elif actual_uri:
+ output.append(line)
+ else:
+ error.append(line)
+
+ (line, crash) = self._write_command_and_read_line(input=None)
+
+ run_time = time.time() - start_time
+ return test_output.TestOutput(
+ ''.join(output), self._output_image_with_retry(), actual_checksum,
+ crash, run_time, timeout, ''.join(error))
+
+ def stop(self):
+ if self._proc:
+ self._proc.stdin.close()
+ self._proc.stdout.close()
+ if self._proc.stderr:
+ self._proc.stderr.close()
+ if sys.platform not in ('win32', 'cygwin'):
+ # Closing stdin/stdout/stderr hangs sometimes on OS X,
+ # (see __init__(), above), and anyway we don't want to hang
+ # the harness if test_shell is buggy, so we wait a couple
+ # seconds to give test_shell a chance to clean up, but then
+ # force-kill the process if necessary.
+ KILL_TIMEOUT = 3.0
+ timeout = time.time() + KILL_TIMEOUT
+ # poll() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ while self._proc.poll() is None and time.time() < timeout:
+ time.sleep(0.1)
+ # poll() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ if self._proc.poll() is None:
+ _log.warning('stopping test driver timed out, '
+ 'killing it')
+ self._port._executive.kill_process(self._proc.pid)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py
new file mode 100644
index 0000000..c1f5c8d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu.py
@@ -0,0 +1,152 @@
+#!/usr/bin/env python
+# 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.
+
+# 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.
+
+from __future__ import with_statement
+
+import codecs
+import os
+import sys
+
+import chromium_linux
+import chromium_mac
+import chromium_win
+
+
+def get(**kwargs):
+ """Some tests have slightly different results when run while using
+ hardware acceleration. In those cases, we prepend an additional directory
+ to the baseline paths."""
+ port_name = kwargs.get('port_name', None)
+ if port_name == 'chromium-gpu':
+ if sys.platform in ('cygwin', 'win32'):
+ port_name = 'chromium-gpu-win'
+ elif sys.platform == 'linux2':
+ port_name = 'chromium-gpu-linux'
+ elif sys.platform == 'darwin':
+ port_name = 'chromium-gpu-mac'
+ else:
+ raise NotImplementedError('unsupported platform: %s' %
+ sys.platform)
+
+ if port_name == 'chromium-gpu-linux':
+ return ChromiumGpuLinuxPort(**kwargs)
+
+ if port_name.startswith('chromium-gpu-mac'):
+ return ChromiumGpuMacPort(**kwargs)
+
+ if port_name.startswith('chromium-gpu-win'):
+ return ChromiumGpuWinPort(**kwargs)
+
+ raise NotImplementedError('unsupported port: %s' % port_name)
+
+
+def _set_gpu_options(options):
+ if options:
+ if options.accelerated_compositing is None:
+ options.accelerated_compositing = True
+ if options.accelerated_2d_canvas is None:
+ options.accelerated_2d_canvas = True
+
+ # FIXME: Remove this after http://codereview.chromium.org/5133001/ is enabled
+ # on the bots.
+ if options.builder_name is not None and not ' - GPU' in options.builder_name:
+ options.builder_name = options.builder_name + ' - GPU'
+
+
+def _gpu_overrides(port):
+ try:
+ overrides_path = port.path_from_chromium_base('webkit', 'tools',
+ 'layout_tests', 'test_expectations_gpu.txt')
+ except AssertionError:
+ return None
+ if not os.path.exists(overrides_path):
+ return None
+ with codecs.open(overrides_path, "r", "utf-8") as file:
+ return file.read()
+
+
+class ChromiumGpuLinuxPort(chromium_linux.ChromiumLinuxPort):
+ def __init__(self, **kwargs):
+ kwargs.setdefault('port_name', 'chromium-gpu-linux')
+ _set_gpu_options(kwargs.get('options'))
+ chromium_linux.ChromiumLinuxPort.__init__(self, **kwargs)
+
+ def baseline_search_path(self):
+ # Mimic the Linux -> Win expectations fallback in the ordinary Chromium port.
+ return (map(self._webkit_baseline_path, ['chromium-gpu-linux', 'chromium-gpu-win', 'chromium-gpu']) +
+ chromium_linux.ChromiumLinuxPort.baseline_search_path(self))
+
+ def default_child_processes(self):
+ return 1
+
+ def path_to_test_expectations_file(self):
+ return self.path_from_webkit_base('LayoutTests', 'platform',
+ 'chromium-gpu', 'test_expectations.txt')
+
+ def test_expectations_overrides(self):
+ return _gpu_overrides(self)
+
+
+class ChromiumGpuMacPort(chromium_mac.ChromiumMacPort):
+ def __init__(self, **kwargs):
+ kwargs.setdefault('port_name', 'chromium-gpu-mac')
+ _set_gpu_options(kwargs.get('options'))
+ chromium_mac.ChromiumMacPort.__init__(self, **kwargs)
+
+ def baseline_search_path(self):
+ return (map(self._webkit_baseline_path, ['chromium-gpu-mac', 'chromium-gpu']) +
+ chromium_mac.ChromiumMacPort.baseline_search_path(self))
+
+ def default_child_processes(self):
+ return 1
+
+ def path_to_test_expectations_file(self):
+ return self.path_from_webkit_base('LayoutTests', 'platform',
+ 'chromium-gpu', 'test_expectations.txt')
+
+ def test_expectations_overrides(self):
+ return _gpu_overrides(self)
+
+
+class ChromiumGpuWinPort(chromium_win.ChromiumWinPort):
+ def __init__(self, **kwargs):
+ kwargs.setdefault('port_name', 'chromium-gpu-win' + self.version())
+ _set_gpu_options(kwargs.get('options'))
+ chromium_win.ChromiumWinPort.__init__(self, **kwargs)
+
+ def baseline_search_path(self):
+ return (map(self._webkit_baseline_path, ['chromium-gpu-win', 'chromium-gpu']) +
+ chromium_win.ChromiumWinPort.baseline_search_path(self))
+
+ def default_child_processes(self):
+ return 1
+
+ def path_to_test_expectations_file(self):
+ return self.path_from_webkit_base('LayoutTests', 'platform',
+ 'chromium-gpu', 'test_expectations.txt')
+
+ def test_expectations_overrides(self):
+ return _gpu_overrides(self)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py
new file mode 100644
index 0000000..ad0404c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_gpu_unittest.py
@@ -0,0 +1,73 @@
+#!/usr/bin/env python
+# 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.
+
+# 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 os
+import unittest
+
+from webkitpy.tool import mocktool
+import chromium_gpu
+
+
+class ChromiumGpuTest(unittest.TestCase):
+ def test_get_chromium_gpu_linux(self):
+ self.assertOverridesWorked('chromium-gpu-linux')
+
+ def test_get_chromium_gpu_mac(self):
+ self.assertOverridesWorked('chromium-gpu-mac')
+
+ def test_get_chromium_gpu_win(self):
+ self.assertOverridesWorked('chromium-gpu-win')
+
+ def assertOverridesWorked(self, port_name):
+ # test that we got the right port
+ mock_options = mocktool.MockOptions(accelerated_compositing=None,
+ accelerated_2d_canvas=None,
+ builder_name='foo',
+ child_processes=None)
+ port = chromium_gpu.get(port_name=port_name, options=mock_options)
+ self.assertTrue(port._options.accelerated_compositing)
+ self.assertTrue(port._options.accelerated_2d_canvas)
+ self.assertEqual(port.default_child_processes(), 1)
+ self.assertEqual(port._options.builder_name, 'foo - GPU')
+
+ # we use startswith() instead of Equal to gloss over platform versions.
+ self.assertTrue(port.name().startswith(port_name))
+
+ # test that it has the right directories in front of the search path.
+ paths = port.baseline_search_path()
+ self.assertEqual(port._webkit_baseline_path(port_name), paths[0])
+ if port_name == 'chromium-gpu-linux':
+ self.assertEqual(port._webkit_baseline_path('chromium-gpu-win'), paths[1])
+ self.assertEqual(port._webkit_baseline_path('chromium-gpu'), paths[2])
+ else:
+ self.assertEqual(port._webkit_baseline_path('chromium-gpu'), paths[1])
+
+ # Test that we have the right expectations file.
+ self.assertTrue('chromium-gpu' in
+ port.path_to_test_expectations_file())
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
new file mode 100644
index 0000000..5d9dd87
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_linux.py
@@ -0,0 +1,190 @@
+#!/usr/bin/env python
+# 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.
+
+"""Chromium Linux implementation of the Port interface."""
+
+import logging
+import os
+import signal
+
+import chromium
+
+_log = logging.getLogger("webkitpy.layout_tests.port.chromium_linux")
+
+
+class ChromiumLinuxPort(chromium.ChromiumPort):
+ """Chromium Linux implementation of the Port class."""
+
+ def __init__(self, **kwargs):
+ kwargs.setdefault('port_name', 'chromium-linux')
+ chromium.ChromiumPort.__init__(self, **kwargs)
+
+ def baseline_search_path(self):
+ port_names = ["chromium-linux", "chromium-win", "chromium", "win", "mac"]
+ return map(self._webkit_baseline_path, port_names)
+
+ def check_build(self, needs_http):
+ result = chromium.ChromiumPort.check_build(self, needs_http)
+ if needs_http:
+ if self.get_option('use_apache'):
+ result = self._check_apache_install() and result
+ else:
+ result = self._check_lighttpd_install() and result
+ result = self._check_wdiff_install() and result
+
+ if not result:
+ _log.error('For complete Linux build requirements, please see:')
+ _log.error('')
+ _log.error(' http://code.google.com/p/chromium/wiki/'
+ 'LinuxBuildInstructions')
+ return result
+
+ def test_platform_name(self):
+ # We use 'linux' instead of 'chromium-linux' in test_expectations.txt.
+ return 'linux'
+
+ def version(self):
+ # We don't have different versions on linux.
+ return ''
+
+ #
+ # PROTECTED METHODS
+ #
+
+ def _build_path(self, *comps):
+ base = self.path_from_chromium_base()
+ if os.path.exists(os.path.join(base, 'sconsbuild')):
+ return os.path.join(base, 'sconsbuild', *comps)
+ if os.path.exists(os.path.join(base, 'out', *comps)) or self.get_option('use_test_shell'):
+ return os.path.join(base, 'out', *comps)
+ base = self.path_from_webkit_base()
+ if os.path.exists(os.path.join(base, 'sconsbuild')):
+ return os.path.join(base, 'sconsbuild', *comps)
+ return os.path.join(base, 'out', *comps)
+
+ def _check_apache_install(self):
+ result = chromium.check_file_exists(self._path_to_apache(),
+ "apache2")
+ result = chromium.check_file_exists(self._path_to_apache_config_file(),
+ "apache2 config file") and result
+ if not result:
+ _log.error(' Please install using: "sudo apt-get install '
+ 'apache2 libapache2-mod-php5"')
+ _log.error('')
+ return result
+
+ def _check_lighttpd_install(self):
+ result = chromium.check_file_exists(
+ self._path_to_lighttpd(), "LigHTTPd executable")
+ result = chromium.check_file_exists(self._path_to_lighttpd_php(),
+ "PHP CGI executable") and result
+ result = chromium.check_file_exists(self._path_to_lighttpd_modules(),
+ "LigHTTPd modules") and result
+ if not result:
+ _log.error(' Please install using: "sudo apt-get install '
+ 'lighttpd php5-cgi"')
+ _log.error('')
+ return result
+
+ def _check_wdiff_install(self):
+ result = chromium.check_file_exists(self._path_to_wdiff(), 'wdiff')
+ if not result:
+ _log.error(' Please install using: "sudo apt-get install '
+ 'wdiff"')
+ _log.error('')
+ # FIXME: The ChromiumMac port always returns True.
+ return result
+
+ def _path_to_apache(self):
+ if self._is_redhat_based():
+ return '/usr/sbin/httpd'
+ else:
+ return '/usr/sbin/apache2'
+
+ def _path_to_apache_config_file(self):
+ if self._is_redhat_based():
+ config_name = 'fedora-httpd.conf'
+ else:
+ config_name = 'apache2-debian-httpd.conf'
+
+ return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ config_name)
+
+ def _path_to_lighttpd(self):
+ return "/usr/sbin/lighttpd"
+
+ def _path_to_lighttpd_modules(self):
+ return "/usr/lib/lighttpd"
+
+ def _path_to_lighttpd_php(self):
+ return "/usr/bin/php-cgi"
+
+ def _path_to_driver(self, configuration=None):
+ if not configuration:
+ configuration = self.get_option('configuration')
+ binary_name = 'DumpRenderTree'
+ if self.get_option('use_test_shell'):
+ binary_name = 'test_shell'
+ return self._build_path(configuration, binary_name)
+
+ def _path_to_helper(self):
+ return None
+
+ def _path_to_wdiff(self):
+ if self._is_redhat_based():
+ return '/usr/bin/dwdiff'
+ else:
+ return '/usr/bin/wdiff'
+
+ def _is_redhat_based(self):
+ return os.path.exists(os.path.join('/etc', 'redhat-release'))
+
+ def _shut_down_http_server(self, server_pid):
+ """Shut down the lighttpd web server. Blocks until it's fully
+ shut down.
+
+ Args:
+ server_pid: The process ID of the running server.
+ """
+ # server_pid is not set when "http_server.py stop" is run manually.
+ if server_pid is None:
+ # TODO(mmoss) This isn't ideal, since it could conflict with
+ # lighttpd processes not started by http_server.py,
+ # but good enough for now.
+ self._executive.kill_all("lighttpd")
+ self._executive.kill_all("apache2")
+ else:
+ try:
+ os.kill(server_pid, signal.SIGTERM)
+ # TODO(mmoss) Maybe throw in a SIGKILL just to be sure?
+ except OSError:
+ # Sometimes we get a bad PID (e.g. from a stale httpd.pid
+ # file), so if kill fails on the given PID, just try to
+ # 'killall' web servers.
+ self._shut_down_http_server(None)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
new file mode 100644
index 0000000..f638e01
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac.py
@@ -0,0 +1,182 @@
+#!/usr/bin/env python
+# 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.
+
+"""Chromium Mac implementation of the Port interface."""
+
+import logging
+import os
+import platform
+import signal
+
+import chromium
+
+from webkitpy.common.system.executive import Executive
+
+_log = logging.getLogger("webkitpy.layout_tests.port.chromium_mac")
+
+
+class ChromiumMacPort(chromium.ChromiumPort):
+ """Chromium Mac implementation of the Port class."""
+
+ def __init__(self, **kwargs):
+ kwargs.setdefault('port_name', 'chromium-mac')
+ chromium.ChromiumPort.__init__(self, **kwargs)
+
+ def baseline_search_path(self):
+ port_names = [
+ "chromium-mac" + self.version(),
+ "chromium-mac",
+ "chromium",
+ "mac" + self.version(),
+ "mac",
+ ]
+ return map(self._webkit_baseline_path, port_names)
+
+ def check_build(self, needs_http):
+ result = chromium.ChromiumPort.check_build(self, needs_http)
+ result = self._check_wdiff_install() and result
+ if not result:
+ _log.error('For complete Mac build requirements, please see:')
+ _log.error('')
+ _log.error(' http://code.google.com/p/chromium/wiki/'
+ 'MacBuildInstructions')
+ return result
+
+ def default_child_processes(self):
+ # FIXME: we need to run single-threaded for now. See
+ # https://bugs.webkit.org/show_bug.cgi?id=38553. Unfortunately this
+ # routine is called right before the logger is configured, so if we
+ # try to _log.warning(), it gets thrown away.
+ import sys
+ sys.stderr.write("Defaulting to one child - see https://bugs.webkit.org/show_bug.cgi?id=38553\n")
+ return 1
+
+ def driver_name(self):
+ """name for this port's equivalent of DumpRenderTree."""
+ if self.get_option('use_test_shell'):
+ return "TestShell"
+ return "DumpRenderTree"
+
+ def test_platform_name(self):
+ # We use 'mac' instead of 'chromium-mac'
+ return 'mac'
+
+ def version(self):
+ # FIXME: It's strange that this string is -version, not just version.
+ os_version_string = platform.mac_ver()[0] # e.g. "10.5.6"
+ if not os_version_string:
+ return '-leopard'
+ release_version = int(os_version_string.split('.')[1])
+ # we don't support 'tiger' or earlier releases
+ if release_version == 5:
+ return '-leopard'
+ elif release_version == 6:
+ return '-snowleopard'
+ return ''
+
+ #
+ # PROTECTED METHODS
+ #
+
+ def _build_path(self, *comps):
+ path = self.path_from_chromium_base('xcodebuild', *comps)
+ if os.path.exists(path) or self.get_option('use_test_shell'):
+ return path
+ return self.path_from_webkit_base('WebKit', 'chromium', 'xcodebuild',
+ *comps)
+
+ def _check_wdiff_install(self):
+ try:
+ # We're ignoring the return and always returning True
+ self._executive.run_command([self._path_to_wdiff()], error_handler=Executive.ignore_error)
+ except OSError:
+ _log.warning('wdiff not found. Install using MacPorts or some '
+ 'other means')
+ return True
+
+ def _lighttpd_path(self, *comps):
+ return self.path_from_chromium_base('third_party', 'lighttpd',
+ 'mac', *comps)
+
+ def _path_to_apache(self):
+ return '/usr/sbin/httpd'
+
+ def _path_to_apache_config_file(self):
+ return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ 'apache2-httpd.conf')
+
+ def _path_to_lighttpd(self):
+ return self._lighttpd_path('bin', 'lighttpd')
+
+ def _path_to_lighttpd_modules(self):
+ return self._lighttpd_path('lib')
+
+ def _path_to_lighttpd_php(self):
+ return self._lighttpd_path('bin', 'php-cgi')
+
+ def _path_to_driver(self, configuration=None):
+ # FIXME: make |configuration| happy with case-sensitive file
+ # systems.
+ if not configuration:
+ configuration = self.get_option('configuration')
+ return self._build_path(configuration, self.driver_name() + '.app',
+ 'Contents', 'MacOS', self.driver_name())
+
+ def _path_to_helper(self):
+ binary_name = 'LayoutTestHelper'
+ if self.get_option('use_test_shell'):
+ binary_name = 'layout_test_helper'
+ return self._build_path(self.get_option('configuration'), binary_name)
+
+ def _path_to_wdiff(self):
+ return 'wdiff'
+
+ def _shut_down_http_server(self, server_pid):
+ """Shut down the lighttpd web server. Blocks until it's fully
+ shut down.
+
+ Args:
+ server_pid: The process ID of the running server.
+ """
+ # server_pid is not set when "http_server.py stop" is run manually.
+ if server_pid is None:
+ # TODO(mmoss) This isn't ideal, since it could conflict with
+ # lighttpd processes not started by http_server.py,
+ # but good enough for now.
+ self._executive.kill_all('lighttpd')
+ self._executive.kill_all('httpd')
+ else:
+ try:
+ os.kill(server_pid, signal.SIGTERM)
+ # TODO(mmoss) Maybe throw in a SIGKILL just to be sure?
+ except OSError:
+ # Sometimes we get a bad PID (e.g. from a stale httpd.pid
+ # file), so if kill fails on the given PID, just try to
+ # 'killall' web servers.
+ self._shut_down_http_server(None)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py
new file mode 100644
index 0000000..d63faa0
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_mac_unittest.py
@@ -0,0 +1,40 @@
+# 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 chromium_mac
+import unittest
+
+from webkitpy.thirdparty.mock import Mock
+
+
+class ChromiumMacPortTest(unittest.TestCase):
+
+ def test_check_wdiff_install(self):
+ port = chromium_mac.ChromiumMacPort()
+ # Currently is always true, just logs if missing.
+ self.assertTrue(port._check_wdiff_install())
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py
new file mode 100644
index 0000000..c87984f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_unittest.py
@@ -0,0 +1,193 @@
+# 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 os
+import unittest
+import StringIO
+
+from webkitpy.tool import mocktool
+from webkitpy.thirdparty.mock import Mock
+
+import chromium
+import chromium_linux
+import chromium_mac
+import chromium_win
+
+class ChromiumDriverTest(unittest.TestCase):
+
+ def setUp(self):
+ mock_port = Mock()
+ mock_port.get_option = lambda option_name: ''
+ self.driver = chromium.ChromiumDriver(mock_port, worker_number=0)
+
+ def test_test_shell_command(self):
+ expected_command = "test.html 2 checksum\n"
+ self.assertEqual(self.driver._test_shell_command("test.html", 2, "checksum"), expected_command)
+
+ def _assert_write_command_and_read_line(self, input=None, expected_line=None, expected_stdin=None, expected_crash=False):
+ if not expected_stdin:
+ if input:
+ expected_stdin = input
+ else:
+ # We reset stdin, so we should expect stdin.getValue = ""
+ expected_stdin = ""
+ self.driver._proc.stdin = StringIO.StringIO()
+ line, did_crash = self.driver._write_command_and_read_line(input)
+ self.assertEqual(self.driver._proc.stdin.getvalue(), expected_stdin)
+ self.assertEqual(line, expected_line)
+ self.assertEqual(did_crash, expected_crash)
+
+ def test_write_command_and_read_line(self):
+ self.driver._proc = Mock()
+ # Set up to read 3 lines before we get an IOError
+ self.driver._proc.stdout = StringIO.StringIO("first\nsecond\nthird\n")
+
+ unicode_input = u"I \u2661 Unicode"
+ utf8_input = unicode_input.encode("utf-8")
+ # Test unicode input conversion to utf-8
+ self._assert_write_command_and_read_line(input=unicode_input, expected_stdin=utf8_input, expected_line="first\n")
+ # Test str() input.
+ self._assert_write_command_and_read_line(input="foo", expected_line="second\n")
+ # Test input=None
+ self._assert_write_command_and_read_line(expected_line="third\n")
+ # Test reading from a closed/empty stream.
+ # reading from a StringIO does not raise IOError like a real file would, so raise IOError manually.
+ def mock_readline():
+ raise IOError
+ self.driver._proc.stdout.readline = mock_readline
+ self._assert_write_command_and_read_line(expected_crash=True)
+
+
+class ChromiumPortTest(unittest.TestCase):
+ class TestMacPort(chromium_mac.ChromiumMacPort):
+ def __init__(self, options):
+ chromium_mac.ChromiumMacPort.__init__(self,
+ port_name='test-port',
+ options=options)
+
+ def default_configuration(self):
+ self.default_configuration_called = True
+ return 'default'
+
+ class TestLinuxPort(chromium_linux.ChromiumLinuxPort):
+ def __init__(self, options):
+ chromium_linux.ChromiumLinuxPort.__init__(self,
+ port_name='test-port',
+ options=options)
+
+ def default_configuration(self):
+ self.default_configuration_called = True
+ return 'default'
+
+ def test_path_to_image_diff(self):
+ mock_options = mocktool.MockOptions()
+ port = ChromiumPortTest.TestLinuxPort(options=mock_options)
+ self.assertTrue(port._path_to_image_diff().endswith(
+ '/out/default/ImageDiff'), msg=port._path_to_image_diff())
+ port = ChromiumPortTest.TestMacPort(options=mock_options)
+ self.assertTrue(port._path_to_image_diff().endswith(
+ '/xcodebuild/default/ImageDiff'))
+ mock_options = mocktool.MockOptions(use_test_shell=True)
+ port = ChromiumPortTest.TestLinuxPort(options=mock_options)
+ self.assertTrue(port._path_to_image_diff().endswith(
+ '/out/default/image_diff'), msg=port._path_to_image_diff())
+ port = ChromiumPortTest.TestMacPort(options=mock_options)
+ self.assertTrue(port._path_to_image_diff().endswith(
+ '/xcodebuild/default/image_diff'))
+ # FIXME: Figure out how this is going to work on Windows.
+ #port = chromium_win.ChromiumWinPort('test-port', options=MockOptions())
+
+ def test_skipped_layout_tests(self):
+ mock_options = mocktool.MockOptions()
+ port = ChromiumPortTest.TestLinuxPort(options=mock_options)
+
+ fake_test = os.path.join(port.layout_tests_dir(), "fast/js/not-good.js")
+
+ port.test_expectations = lambda: """BUG_TEST SKIP : fast/js/not-good.js = TEXT
+LINUX WIN : fast/js/very-good.js = TIMEOUT PASS"""
+ port.test_expectations_overrides = lambda: ''
+ port.tests = lambda paths: set()
+ port.path_exists = lambda test: True
+
+ skipped_tests = port.skipped_layout_tests(extra_test_files=[fake_test, ])
+ self.assertTrue("fast/js/not-good.js" in skipped_tests)
+
+ def test_default_configuration(self):
+ mock_options = mocktool.MockOptions()
+ port = ChromiumPortTest.TestLinuxPort(options=mock_options)
+ self.assertEquals(mock_options.configuration, 'default')
+ self.assertTrue(port.default_configuration_called)
+
+ mock_options = mocktool.MockOptions(configuration=None)
+ port = ChromiumPortTest.TestLinuxPort(mock_options)
+ self.assertEquals(mock_options.configuration, 'default')
+ self.assertTrue(port.default_configuration_called)
+
+ def test_diff_image(self):
+ class TestPort(ChromiumPortTest.TestLinuxPort):
+ def _path_to_image_diff(self):
+ return "/path/to/image_diff"
+
+ class MockExecute:
+ def __init__(self, result):
+ self._result = result
+
+ def run_command(self,
+ args,
+ cwd=None,
+ input=None,
+ error_handler=None,
+ return_exit_code=False,
+ return_stderr=True,
+ decode_output=False):
+ if return_exit_code:
+ return self._result
+ return ''
+
+ mock_options = mocktool.MockOptions()
+ port = ChromiumPortTest.TestLinuxPort(mock_options)
+
+ # Images are different.
+ port._executive = MockExecute(0)
+ self.assertEquals(False, port.diff_image("EXPECTED", "ACTUAL"))
+
+ # Images are the same.
+ port._executive = MockExecute(1)
+ self.assertEquals(True, port.diff_image("EXPECTED", "ACTUAL"))
+
+ # There was some error running image_diff.
+ port._executive = MockExecute(2)
+ exception_raised = False
+ try:
+ port.diff_image("EXPECTED", "ACTUAL")
+ except ValueError, e:
+ exception_raised = True
+ self.assertFalse(exception_raised)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py
new file mode 100644
index 0000000..d080f82
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win.py
@@ -0,0 +1,173 @@
+#!/usr/bin/env python
+# 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.
+
+"""Chromium Win implementation of the Port interface."""
+
+import logging
+import os
+import sys
+
+import chromium
+
+_log = logging.getLogger("webkitpy.layout_tests.port.chromium_win")
+
+
+class ChromiumWinPort(chromium.ChromiumPort):
+ """Chromium Win implementation of the Port class."""
+
+ def __init__(self, **kwargs):
+ kwargs.setdefault('port_name', 'chromium-win' + self.version())
+ chromium.ChromiumPort.__init__(self, **kwargs)
+
+ def setup_environ_for_server(self):
+ env = chromium.ChromiumPort.setup_environ_for_server(self)
+ # Put the cygwin directory first in the path to find cygwin1.dll.
+ env["PATH"] = "%s;%s" % (
+ self.path_from_chromium_base("third_party", "cygwin", "bin"),
+ env["PATH"])
+ # Configure the cygwin directory so that pywebsocket finds proper
+ # python executable to run cgi program.
+ env["CYGWIN_PATH"] = self.path_from_chromium_base(
+ "third_party", "cygwin", "bin")
+ if (sys.platform == "win32" and self.get_option('register_cygwin')):
+ setup_mount = self.path_from_chromium_base("third_party",
+ "cygwin",
+ "setup_mount.bat")
+ self._executive.run_command([setup_mount])
+ return env
+
+ def baseline_search_path(self):
+ port_names = []
+ if self._name.endswith('-win-xp'):
+ port_names.append("chromium-win-xp")
+ if self._name.endswith('-win-xp') or self._name.endswith('-win-vista'):
+ port_names.append("chromium-win-vista")
+ # FIXME: This may need to include mac-snowleopard like win.py.
+ port_names.extend(["chromium-win", "chromium", "win", "mac"])
+ return map(self._webkit_baseline_path, port_names)
+
+ def check_build(self, needs_http):
+ result = chromium.ChromiumPort.check_build(self, needs_http)
+ if not result:
+ _log.error('For complete Windows build requirements, please '
+ 'see:')
+ _log.error('')
+ _log.error(' http://dev.chromium.org/developers/how-tos/'
+ 'build-instructions-windows')
+ return result
+
+ def relative_test_filename(self, filename):
+ path = filename[len(self.layout_tests_dir()) + 1:]
+ return path.replace('\\', '/')
+
+ def test_platform_name(self):
+ # We return 'win-xp', not 'chromium-win-xp' here, for convenience.
+ return 'win' + self.version()
+
+ def version(self):
+ if not hasattr(sys, 'getwindowsversion'):
+ return ''
+ winver = sys.getwindowsversion()
+ if winver[0] == 6 and (winver[1] == 1):
+ return '-7'
+ if winver[0] == 6 and (winver[1] == 0):
+ return '-vista'
+ if winver[0] == 5 and (winver[1] == 1 or winver[1] == 2):
+ return '-xp'
+ return ''
+
+ #
+ # PROTECTED ROUTINES
+ #
+ def _build_path(self, *comps):
+ p = self.path_from_chromium_base('webkit', *comps)
+ if os.path.exists(p):
+ return p
+ p = self.path_from_chromium_base('chrome', *comps)
+ if os.path.exists(p) or self.get_option('use_test_shell'):
+ return p
+ return os.path.join(self.path_from_webkit_base(), 'WebKit', 'chromium',
+ *comps)
+
+ def _lighttpd_path(self, *comps):
+ return self.path_from_chromium_base('third_party', 'lighttpd', 'win',
+ *comps)
+
+ def _path_to_apache(self):
+ return self.path_from_chromium_base('third_party', 'cygwin', 'usr',
+ 'sbin', 'httpd')
+
+ def _path_to_apache_config_file(self):
+ return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ 'cygwin-httpd.conf')
+
+ def _path_to_lighttpd(self):
+ return self._lighttpd_path('LightTPD.exe')
+
+ def _path_to_lighttpd_modules(self):
+ return self._lighttpd_path('lib')
+
+ def _path_to_lighttpd_php(self):
+ return self._lighttpd_path('php5', 'php-cgi.exe')
+
+ def _path_to_driver(self, configuration=None):
+ if not configuration:
+ configuration = self.get_option('configuration')
+ binary_name = 'DumpRenderTree.exe'
+ if self.get_option('use_test_shell'):
+ binary_name = 'test_shell.exe'
+ return self._build_path(configuration, binary_name)
+
+ def _path_to_helper(self):
+ binary_name = 'LayoutTestHelper.exe'
+ if self.get_option('use_test_shell'):
+ binary_name = 'layout_test_helper.exe'
+ return self._build_path(self.get_option('configuration'), binary_name)
+
+ def _path_to_image_diff(self):
+ binary_name = 'ImageDiff.exe'
+ if self.get_option('use_test_shell'):
+ binary_name = 'image_diff.exe'
+ return self._build_path(self.get_option('configuration'), binary_name)
+
+ def _path_to_wdiff(self):
+ return self.path_from_chromium_base('third_party', 'cygwin', 'bin',
+ 'wdiff.exe')
+
+ def _shut_down_http_server(self, server_pid):
+ """Shut down the lighttpd web server. Blocks until it's fully
+ shut down.
+
+ Args:
+ server_pid: The process ID of the running server.
+ """
+ # FIXME: Why are we ignoring server_pid and calling
+ # _kill_all instead of Executive.kill_process(pid)?
+ self._executive.kill_all("LightTPD.exe")
+ self._executive.kill_all("httpd.exe")
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py
new file mode 100644
index 0000000..36f3c6b
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/chromium_win_unittest.py
@@ -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.
+
+import os
+import sys
+import unittest
+import chromium_win
+from webkitpy.common.system import outputcapture
+from webkitpy.tool import mocktool
+
+
+class ChromiumWinTest(unittest.TestCase):
+
+ class RegisterCygwinOption(object):
+ def __init__(self):
+ self.register_cygwin = True
+
+ def setUp(self):
+ self.orig_platform = sys.platform
+
+ def tearDown(self):
+ sys.platform = self.orig_platform
+
+ def _mock_path_from_chromium_base(self, *comps):
+ return os.path.join("/chromium/src", *comps)
+
+ def test_setup_environ_for_server(self):
+ port = chromium_win.ChromiumWinPort()
+ port._executive = mocktool.MockExecutive(should_log=True)
+ port.path_from_chromium_base = self._mock_path_from_chromium_base
+ output = outputcapture.OutputCapture()
+ orig_environ = os.environ.copy()
+ env = output.assert_outputs(self, port.setup_environ_for_server)
+ self.assertEqual(orig_environ["PATH"], os.environ["PATH"])
+ self.assertNotEqual(env["PATH"], os.environ["PATH"])
+
+ def test_setup_environ_for_server_register_cygwin(self):
+ sys.platform = "win32"
+ port = chromium_win.ChromiumWinPort(
+ options=ChromiumWinTest.RegisterCygwinOption())
+ port._executive = mocktool.MockExecutive(should_log=True)
+ port.path_from_chromium_base = self._mock_path_from_chromium_base
+ setup_mount = self._mock_path_from_chromium_base("third_party",
+ "cygwin",
+ "setup_mount.bat")
+ expected_stderr = "MOCK run_command: %s\n" % [setup_mount]
+ output = outputcapture.OutputCapture()
+ output.assert_outputs(self, port.setup_environ_for_server,
+ expected_stderr=expected_stderr)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/config.py b/Tools/Scripts/webkitpy/layout_tests/port/config.py
new file mode 100644
index 0000000..e08ed9d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/config.py
@@ -0,0 +1,169 @@
+#!/usr/bin/env python
+# 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.
+
+"""Wrapper objects for WebKit-specific utility routines."""
+
+# FIXME: This file needs to be unified with common/checkout/scm.py and
+# common/config/ports.py .
+
+import os
+
+from webkitpy.common.system import logutils
+from webkitpy.common.system import executive
+
+
+_log = logutils.get_logger(__file__)
+
+#
+# FIXME: This is used to record if we've already hit the filesystem to look
+# for a default configuration. We cache this to speed up the unit tests,
+# but this can be reset with clear_cached_configuration(). This should be
+# replaced with us consistently using MockConfigs() for tests that don't
+# hit the filesystem at all and provide a reliable value.
+#
+_have_determined_configuration = False
+_configuration = "Release"
+
+
+def clear_cached_configuration():
+ global _have_determined_configuration, _configuration
+ _have_determined_configuration = False
+ _configuration = "Release"
+
+
+class Config(object):
+ _FLAGS_FROM_CONFIGURATIONS = {
+ "Debug": "--debug",
+ "Release": "--release",
+ }
+
+ def __init__(self, executive, filesystem):
+ self._executive = executive
+ self._filesystem = filesystem
+ self._webkit_base_dir = None
+ self._default_configuration = None
+ self._build_directories = {}
+
+ def build_directory(self, configuration):
+ """Returns the path to the build directory for the configuration."""
+ if configuration:
+ flags = ["--configuration",
+ self._FLAGS_FROM_CONFIGURATIONS[configuration]]
+ else:
+ configuration = ""
+ flags = ["--top-level"]
+
+ if not self._build_directories.get(configuration):
+ args = ["perl", self._script_path("webkit-build-directory")] + flags
+ self._build_directories[configuration] = (
+ self._executive.run_command(args).rstrip())
+
+ return self._build_directories[configuration]
+
+ def build_dumprendertree(self, configuration):
+ """Builds DRT in the given configuration.
+
+ Returns True if the build was successful and up-to-date."""
+ flag = self._FLAGS_FROM_CONFIGURATIONS[configuration]
+ exit_code = self._executive.run_command([
+ self._script_path("build-dumprendertree"), flag],
+ return_exit_code=True)
+ if exit_code != 0:
+ _log.error("Failed to build DumpRenderTree")
+ return False
+ return True
+
+ def default_configuration(self):
+ """Returns the default configuration for the user.
+
+ Returns the value set by 'set-webkit-configuration', or "Release"
+ if that has not been set. This mirrors the logic in webkitdirs.pm."""
+ if not self._default_configuration:
+ self._default_configuration = self._determine_configuration()
+ if not self._default_configuration:
+ self._default_configuration = 'Release'
+ if self._default_configuration not in self._FLAGS_FROM_CONFIGURATIONS:
+ _log.warn("Configuration \"%s\" is not a recognized value.\n" %
+ self._default_configuration)
+ _log.warn("Scripts may fail. "
+ "See 'set-webkit-configuration --help'.")
+ return self._default_configuration
+
+ def path_from_webkit_base(self, *comps):
+ return self._filesystem.join(self.webkit_base_dir(), *comps)
+
+ def webkit_base_dir(self):
+ """Returns the absolute path to the top of the WebKit tree.
+
+ Raises an AssertionError if the top dir can't be determined."""
+ # Note: this code somewhat duplicates the code in
+ # scm.find_checkout_root(). However, that code only works if the top
+ # of the SCM repository also matches the top of the WebKit tree. The
+ # Chromium ports, for example, only check out subdirectories like
+ # Tools/Scripts, and so we still have to do additional work
+ # to find the top of the tree.
+ #
+ # This code will also work if there is no SCM system at all.
+ if not self._webkit_base_dir:
+ abspath = os.path.abspath(__file__)
+ self._webkit_base_dir = abspath[0:abspath.find('Tools') - 1]
+ return self._webkit_base_dir
+
+ def _script_path(self, script_name):
+ return self._filesystem.join(self.webkit_base_dir(), "Tools",
+ "Scripts", script_name)
+
+ def _determine_configuration(self):
+ # This mirrors the logic in webkitdirs.pm:determineConfiguration().
+ #
+ # FIXME: See the comment at the top of the file regarding unit tests
+ # and our use of global mutable static variables.
+ global _have_determined_configuration, _configuration
+ if not _have_determined_configuration:
+ contents = self._read_configuration()
+ if not contents:
+ contents = "Release"
+ if contents == "Deployment":
+ contents = "Release"
+ if contents == "Development":
+ contents = "Debug"
+ _configuration = contents
+ _have_determined_configuration = True
+ return _configuration
+
+ def _read_configuration(self):
+ try:
+ configuration_path = self._filesystem.join(self.build_directory(None),
+ "Configuration")
+ if not self._filesystem.exists(configuration_path):
+ return None
+ except (OSError, executive.ScriptError):
+ return None
+
+ return self._filesystem.read_text_file(configuration_path).rstrip()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/config_mock.py b/Tools/Scripts/webkitpy/layout_tests/port/config_mock.py
new file mode 100644
index 0000000..af71fa3
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/config_mock.py
@@ -0,0 +1,50 @@
+#!/usr/bin/env python
+# 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.
+
+"""Wrapper objects for WebKit-specific utility routines."""
+
+
+class MockConfig(object):
+ def __init__(self, default_configuration='Release'):
+ self._default_configuration = default_configuration
+
+ def build_directory(self, configuration):
+ return "/build"
+
+ def build_dumprendertree(self, configuration):
+ return True
+
+ def default_configuration(self):
+ return self._default_configuration
+
+ def path_from_webkit_base(self, *comps):
+ return "/" + "/".join(list(comps))
+
+ def webkit_base_dir(self):
+ return "/"
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/config_standalone.py b/Tools/Scripts/webkitpy/layout_tests/port/config_standalone.py
new file mode 100644
index 0000000..3dec3b9
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/config_standalone.py
@@ -0,0 +1,70 @@
+# Copyright (C) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""FIXME: This script is used by
+config_unittest.test_default_configuration__standalone() to read the
+default configuration to work around any possible caching / reset bugs. See
+https://bugs.webkit.org/show_bug?id=49360 for the motivation. We can remove
+this test when we remove the global configuration cache in config.py."""
+
+import os
+import unittest
+import sys
+
+
+# Ensure that webkitpy is in PYTHONPATH.
+this_dir = os.path.abspath(sys.path[0])
+up = os.path.dirname
+script_dir = up(up(up(this_dir)))
+if script_dir not in sys.path:
+ sys.path.append(script_dir)
+
+from webkitpy.common.system import executive
+from webkitpy.common.system import executive_mock
+from webkitpy.common.system import filesystem
+from webkitpy.common.system import filesystem_mock
+
+import config
+
+
+def main(argv=None):
+ if not argv:
+ argv = sys.argv
+
+ if len(argv) == 3 and argv[1] == '--mock':
+ e = executive_mock.MockExecutive2(output='foo')
+ fs = filesystem_mock.MockFileSystem({'foo/Configuration': argv[2]})
+ else:
+ e = executive.Executive()
+ fs = filesystem.FileSystem()
+
+ c = config.Config(e, fs)
+ print c.default_configuration()
+
+if __name__ == '__main__':
+ main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/config_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/config_unittest.py
new file mode 100644
index 0000000..2cce3cc
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/config_unittest.py
@@ -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.
+
+import os
+import sys
+import unittest
+
+from webkitpy.common.system import executive
+from webkitpy.common.system import executive_mock
+from webkitpy.common.system import filesystem
+from webkitpy.common.system import filesystem_mock
+from webkitpy.common.system import outputcapture
+
+import config
+
+
+def mock_run_command(arg_list):
+ # Set this to True to test actual output (where possible).
+ integration_test = False
+ if integration_test:
+ return executive.Executive().run_command(arg_list)
+
+ if 'webkit-build-directory' in arg_list[1]:
+ return mock_webkit_build_directory(arg_list[2:])
+ return 'Error'
+
+
+def mock_webkit_build_directory(arg_list):
+ if arg_list == ['--top-level']:
+ return '/WebKitBuild'
+ elif arg_list == ['--configuration', '--debug']:
+ return '/WebKitBuild/Debug'
+ elif arg_list == ['--configuration', '--release']:
+ return '/WebKitBuild/Release'
+ return 'Error'
+
+
+class ConfigTest(unittest.TestCase):
+ def tearDown(self):
+ config.clear_cached_configuration()
+
+ def make_config(self, output='', files={}, exit_code=0, exception=None,
+ run_command_fn=None):
+ e = executive_mock.MockExecutive2(output=output, exit_code=exit_code,
+ exception=exception,
+ run_command_fn=run_command_fn)
+ fs = filesystem_mock.MockFileSystem(files)
+ return config.Config(e, fs)
+
+ def assert_configuration(self, contents, expected):
+ # This tests that a configuration file containing
+ # _contents_ ends up being interpreted as _expected_.
+ c = self.make_config('foo', {'foo/Configuration': contents})
+ self.assertEqual(c.default_configuration(), expected)
+
+ def test_build_directory(self):
+ # --top-level
+ c = self.make_config(run_command_fn=mock_run_command)
+ self.assertTrue(c.build_directory(None).endswith('WebKitBuild'))
+
+ # Test again to check caching
+ self.assertTrue(c.build_directory(None).endswith('WebKitBuild'))
+
+ # Test other values
+ self.assertTrue(c.build_directory('Release').endswith('/Release'))
+ self.assertTrue(c.build_directory('Debug').endswith('/Debug'))
+ self.assertRaises(KeyError, c.build_directory, 'Unknown')
+
+ def test_build_dumprendertree__success(self):
+ c = self.make_config(exit_code=0)
+ self.assertTrue(c.build_dumprendertree("Debug"))
+ self.assertTrue(c.build_dumprendertree("Release"))
+ self.assertRaises(KeyError, c.build_dumprendertree, "Unknown")
+
+ def test_build_dumprendertree__failure(self):
+ c = self.make_config(exit_code=-1)
+
+ # FIXME: Build failures should log errors. However, the message we
+ # get depends on how we're being called; as a standalone test,
+ # we'll get the "no handlers found" message. As part of
+ # test-webkitpy, we get the actual message. Really, we need
+ # outputcapture to install its own handler.
+ oc = outputcapture.OutputCapture()
+ oc.capture_output()
+ self.assertFalse(c.build_dumprendertree('Debug'))
+ oc.restore_output()
+
+ oc.capture_output()
+ self.assertFalse(c.build_dumprendertree('Release'))
+ oc.restore_output()
+
+ def test_default_configuration__release(self):
+ self.assert_configuration('Release', 'Release')
+
+ def test_default_configuration__debug(self):
+ self.assert_configuration('Debug', 'Debug')
+
+ def test_default_configuration__deployment(self):
+ self.assert_configuration('Deployment', 'Release')
+
+ def test_default_configuration__development(self):
+ self.assert_configuration('Development', 'Debug')
+
+ def test_default_configuration__notfound(self):
+ # This tests what happens if the default configuration file
+ # doesn't exist.
+ c = self.make_config(output='foo', files={'foo/Configuration': None})
+ self.assertEqual(c.default_configuration(), "Release")
+
+ def test_default_configuration__unknown(self):
+ # Ignore the warning about an unknown configuration value.
+ oc = outputcapture.OutputCapture()
+ oc.capture_output()
+ self.assert_configuration('Unknown', 'Unknown')
+ oc.restore_output()
+
+ def test_default_configuration__standalone(self):
+ # FIXME: This test runs a standalone python script to test
+ # reading the default configuration to work around any possible
+ # caching / reset bugs. See https://bugs.webkit.org/show_bug?id=49360
+ # for the motivation. We can remove this test when we remove the
+ # global configuration cache in config.py.
+ e = executive.Executive()
+ fs = filesystem.FileSystem()
+ c = config.Config(e, fs)
+ script = c.path_from_webkit_base('Tools', 'Scripts',
+ 'webkitpy', 'layout_tests', 'port', 'config_standalone.py')
+
+ # Note: don't use 'Release' here, since that's the normal default.
+ expected = 'Debug'
+
+ args = [sys.executable, script, '--mock', expected]
+ actual = e.run_command(args).rstrip()
+ self.assertEqual(actual, expected)
+
+ def test_default_configuration__no_perl(self):
+ # We need perl to run webkit-build-directory to find out where the
+ # default configuration file is. See what happens if perl isn't
+ # installed. (We should get the default value, 'Release').
+ c = self.make_config(exception=OSError)
+ actual = c.default_configuration()
+ self.assertEqual(actual, 'Release')
+
+ def test_default_configuration__scripterror(self):
+ # We run webkit-build-directory to find out where the default
+ # configuration file is. See what happens if that script fails.
+ # (We should get the default value, 'Release').
+ c = self.make_config(exception=executive.ScriptError())
+ actual = c.default_configuration()
+ self.assertEqual(actual, 'Release')
+
+ def test_path_from_webkit_base(self):
+ # FIXME: We use a real filesystem here. Should this move to a
+ # mocked one?
+ c = config.Config(executive.Executive(), filesystem.FileSystem())
+ self.assertTrue(c.path_from_webkit_base('foo'))
+
+ def test_webkit_base_dir(self):
+ # FIXME: We use a real filesystem here. Should this move to a
+ # mocked one?
+ c = config.Config(executive.Executive(), filesystem.FileSystem())
+ base_dir = c.webkit_base_dir()
+ self.assertTrue(base_dir)
+ self.assertNotEqual(base_dir[-1], '/')
+
+ orig_cwd = os.getcwd()
+ os.chdir(os.environ['HOME'])
+ c = config.Config(executive.Executive(), filesystem.FileSystem())
+ try:
+ base_dir_2 = c.webkit_base_dir()
+ self.assertEqual(base_dir, base_dir_2)
+ finally:
+ os.chdir(orig_cwd)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/dryrun.py b/Tools/Scripts/webkitpy/layout_tests/port/dryrun.py
new file mode 100644
index 0000000..4ed34e6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/dryrun.py
@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+# 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 Google name 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 is a test implementation of the Port interface that generates the
+ correct output for every test. It can be used for perf testing, because
+ it is pretty much a lower limit on how fast a port can possibly run.
+
+ This implementation acts as a wrapper around a real port (the real port
+ is held as a delegate object). To specify which port, use the port name
+ 'dryrun-XXX' (e.g., 'dryrun-chromium-mac-leopard'). If you use just
+ 'dryrun', it uses the default port.
+
+ Note that because this is really acting as a wrapper around the underlying
+ port, you must be able to run the underlying port as well
+ (check_build() and check_sys_deps() must pass and auxiliary binaries
+ like layout_test_helper and httpd must work).
+
+ This implementation also modifies the test expectations so that all
+ tests are either SKIPPED or expected to PASS."""
+
+from __future__ import with_statement
+
+import os
+import sys
+import time
+
+from webkitpy.layout_tests.layout_package import test_output
+
+import base
+import factory
+
+
+class DryRunPort(object):
+ """DryRun implementation of the Port interface."""
+
+ def __init__(self, **kwargs):
+ pfx = 'dryrun-'
+ if 'port_name' in kwargs:
+ if kwargs['port_name'].startswith(pfx):
+ kwargs['port_name'] = kwargs['port_name'][len(pfx):]
+ else:
+ kwargs['port_name'] = None
+ self.__delegate = factory.get(**kwargs)
+
+ def __getattr__(self, name):
+ return getattr(self.__delegate, name)
+
+ def check_build(self, needs_http):
+ return True
+
+ def check_sys_deps(self, needs_http):
+ return True
+
+ def start_helper(self):
+ pass
+
+ def start_http_server(self):
+ pass
+
+ def start_websocket_server(self):
+ pass
+
+ def stop_helper(self):
+ pass
+
+ def stop_http_server(self):
+ pass
+
+ def stop_websocket_server(self):
+ pass
+
+ def create_driver(self, worker_number):
+ return DryrunDriver(self, worker_number)
+
+
+class DryrunDriver(base.Driver):
+ """Dryrun implementation of the DumpRenderTree / Driver interface."""
+
+ def __init__(self, port, worker_number):
+ self._port = port
+ self._worker_number = worker_number
+
+ def cmd_line(self):
+ return ['None']
+
+ def poll(self):
+ return None
+
+ def run_test(self, test_input):
+ start_time = time.time()
+ text_output = self._port.expected_text(test_input.filename)
+
+ if test_input.image_hash is not None:
+ image = self._port.expected_image(test_input.filename)
+ hash = self._port.expected_checksum(test_input.filename)
+ else:
+ image = None
+ hash = None
+ return test_output.TestOutput(text_output, image, hash, False,
+ time.time() - start_time, False, None)
+
+ def start(self):
+ pass
+
+ def stop(self):
+ pass
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/factory.py b/Tools/Scripts/webkitpy/layout_tests/port/factory.py
new file mode 100644
index 0000000..6935744
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/factory.py
@@ -0,0 +1,113 @@
+#!/usr/bin/env python
+# 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.
+
+"""Factory method to retrieve the appropriate port implementation."""
+
+
+import sys
+
+ALL_PORT_NAMES = ['test', 'dryrun', 'mac', 'win', 'gtk', 'qt', 'chromium-mac',
+ 'chromium-linux', 'chromium-win', 'google-chrome-win',
+ 'google-chrome-mac', 'google-chrome-linux32', 'google-chrome-linux64']
+
+
+def get(port_name=None, options=None, **kwargs):
+ """Returns an object implementing the Port interface. If
+ port_name is None, this routine attempts to guess at the most
+ appropriate port on this platform."""
+ # Wrapped for backwards-compatibility
+ if port_name:
+ kwargs['port_name'] = port_name
+ if options:
+ kwargs['options'] = options
+ return _get_kwargs(**kwargs)
+
+
+def _get_kwargs(**kwargs):
+ port_to_use = kwargs.get('port_name', None)
+ options = kwargs.get('options', None)
+ if port_to_use is None:
+ if sys.platform == 'win32' or sys.platform == 'cygwin':
+ if options and hasattr(options, 'chromium') and options.chromium:
+ port_to_use = 'chromium-win'
+ else:
+ port_to_use = 'win'
+ elif sys.platform == 'linux2':
+ port_to_use = 'chromium-linux'
+ elif sys.platform == 'darwin':
+ if options and hasattr(options, 'chromium') and options.chromium:
+ port_to_use = 'chromium-mac'
+ else:
+ port_to_use = 'mac'
+
+ if port_to_use is None:
+ raise NotImplementedError('unknown port; sys.platform = "%s"' %
+ sys.platform)
+
+ if port_to_use == 'test':
+ import test
+ maker = test.TestPort
+ elif port_to_use.startswith('dryrun'):
+ import dryrun
+ maker = dryrun.DryRunPort
+ elif port_to_use.startswith('mac'):
+ import mac
+ maker = mac.MacPort
+ elif port_to_use.startswith('win'):
+ import win
+ maker = win.WinPort
+ elif port_to_use.startswith('gtk'):
+ import gtk
+ maker = gtk.GtkPort
+ elif port_to_use.startswith('qt'):
+ import qt
+ maker = qt.QtPort
+ elif port_to_use.startswith('chromium-gpu'):
+ import chromium_gpu
+ maker = chromium_gpu.get
+ elif port_to_use.startswith('chromium-mac'):
+ import chromium_mac
+ maker = chromium_mac.ChromiumMacPort
+ elif port_to_use.startswith('chromium-linux'):
+ import chromium_linux
+ maker = chromium_linux.ChromiumLinuxPort
+ elif port_to_use.startswith('chromium-win'):
+ import chromium_win
+ maker = chromium_win.ChromiumWinPort
+ elif port_to_use.startswith('google-chrome'):
+ import google_chrome
+ maker = google_chrome.GetGoogleChromePort
+ else:
+ raise NotImplementedError('unsupported port: %s' % port_to_use)
+ return maker(**kwargs)
+
+def get_all(options=None):
+ """Returns all the objects implementing the Port interface."""
+ return dict([(port_name, get(port_name, options=options))
+ for port_name in ALL_PORT_NAMES])
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/factory_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/factory_unittest.py
new file mode 100644
index 0000000..978a557
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/factory_unittest.py
@@ -0,0 +1,188 @@
+# 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 sys
+import unittest
+
+from webkitpy.tool import mocktool
+
+import chromium_gpu
+import chromium_linux
+import chromium_mac
+import chromium_win
+import dryrun
+import factory
+import google_chrome
+import gtk
+import mac
+import qt
+import test
+import win
+
+
+class FactoryTest(unittest.TestCase):
+ """Test factory creates proper port object for the target.
+
+ Target is specified by port_name, sys.platform and options.
+
+ """
+ # FIXME: The ports themselves should expose what options they require,
+ # instead of passing generic "options".
+
+ def setUp(self):
+ self.real_sys_platform = sys.platform
+ self.webkit_options = mocktool.MockOptions(pixel_tests=False)
+ self.chromium_options = mocktool.MockOptions(pixel_tests=False,
+ chromium=True)
+
+ def tearDown(self):
+ sys.platform = self.real_sys_platform
+
+ def assert_port(self, port_name, expected_port, port_obj=None):
+ """Helper assert for port_name.
+
+ Args:
+ port_name: port name to get port object.
+ expected_port: class of expected port object.
+ port_obj: optional port object
+ """
+ port_obj = port_obj or factory.get(port_name=port_name)
+ self.assertTrue(isinstance(port_obj, expected_port))
+
+ def assert_platform_port(self, platform, options, expected_port):
+ """Helper assert for platform and options.
+
+ Args:
+ platform: sys.platform.
+ options: options to get port object.
+ expected_port: class of expected port object.
+
+ """
+ orig_platform = sys.platform
+ sys.platform = platform
+ self.assertTrue(isinstance(factory.get(options=options),
+ expected_port))
+ sys.platform = orig_platform
+
+ def test_test(self):
+ self.assert_port("test", test.TestPort)
+
+ def test_dryrun(self):
+ self.assert_port("dryrun-test", dryrun.DryRunPort)
+ self.assert_port("dryrun-mac", dryrun.DryRunPort)
+
+ def test_mac(self):
+ self.assert_port("mac", mac.MacPort)
+ self.assert_platform_port("darwin", None, mac.MacPort)
+ self.assert_platform_port("darwin", self.webkit_options, mac.MacPort)
+
+ def test_win(self):
+ self.assert_port("win", win.WinPort)
+ self.assert_platform_port("win32", None, win.WinPort)
+ self.assert_platform_port("win32", self.webkit_options, win.WinPort)
+ self.assert_platform_port("cygwin", None, win.WinPort)
+ self.assert_platform_port("cygwin", self.webkit_options, win.WinPort)
+
+ def test_google_chrome(self):
+ # The actual Chrome class names aren't available so we test that the
+ # objects we get are at least subclasses of the Chromium versions.
+ self.assert_port("google-chrome-linux32",
+ chromium_linux.ChromiumLinuxPort)
+ self.assert_port("google-chrome-linux64",
+ chromium_linux.ChromiumLinuxPort)
+ self.assert_port("google-chrome-win",
+ chromium_win.ChromiumWinPort)
+ self.assert_port("google-chrome-mac",
+ chromium_mac.ChromiumMacPort)
+
+ def test_gtk(self):
+ self.assert_port("gtk", gtk.GtkPort)
+
+ def test_qt(self):
+ self.assert_port("qt", qt.QtPort)
+
+ def test_chromium_gpu_linux(self):
+ self.assert_port("chromium-gpu-linux", chromium_gpu.ChromiumGpuLinuxPort)
+
+ def test_chromium_gpu_mac(self):
+ self.assert_port("chromium-gpu-mac", chromium_gpu.ChromiumGpuMacPort)
+
+ def test_chromium_gpu_win(self):
+ self.assert_port("chromium-gpu-win", chromium_gpu.ChromiumGpuWinPort)
+
+ def test_chromium_mac(self):
+ self.assert_port("chromium-mac", chromium_mac.ChromiumMacPort)
+ self.assert_platform_port("darwin", self.chromium_options,
+ chromium_mac.ChromiumMacPort)
+
+ def test_chromium_linux(self):
+ self.assert_port("chromium-linux", chromium_linux.ChromiumLinuxPort)
+ self.assert_platform_port("linux2", self.chromium_options,
+ chromium_linux.ChromiumLinuxPort)
+
+ def test_chromium_win(self):
+ self.assert_port("chromium-win", chromium_win.ChromiumWinPort)
+ self.assert_platform_port("win32", self.chromium_options,
+ chromium_win.ChromiumWinPort)
+ self.assert_platform_port("cygwin", self.chromium_options,
+ chromium_win.ChromiumWinPort)
+
+ def test_get_all_ports(self):
+ ports = factory.get_all()
+ for name in factory.ALL_PORT_NAMES:
+ self.assertTrue(name in ports.keys())
+ self.assert_port("test", test.TestPort, ports["test"])
+ self.assert_port("dryrun-test", dryrun.DryRunPort, ports["dryrun"])
+ self.assert_port("dryrun-mac", dryrun.DryRunPort, ports["dryrun"])
+ self.assert_port("mac", mac.MacPort, ports["mac"])
+ self.assert_port("win", win.WinPort, ports["win"])
+ self.assert_port("gtk", gtk.GtkPort, ports["gtk"])
+ self.assert_port("qt", qt.QtPort, ports["qt"])
+ self.assert_port("chromium-mac", chromium_mac.ChromiumMacPort,
+ ports["chromium-mac"])
+ self.assert_port("chromium-linux", chromium_linux.ChromiumLinuxPort,
+ ports["chromium-linux"])
+ self.assert_port("chromium-win", chromium_win.ChromiumWinPort,
+ ports["chromium-win"])
+
+ def test_unknown_specified(self):
+ # Test what happens when you specify an unknown port.
+ orig_platform = sys.platform
+ self.assertRaises(NotImplementedError, factory.get,
+ port_name='unknown')
+
+ def test_unknown_default(self):
+ # Test what happens when you're running on an unknown platform.
+ orig_platform = sys.platform
+ sys.platform = 'unknown'
+ self.assertRaises(NotImplementedError, factory.get)
+ sys.platform = orig_platform
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py b/Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py
new file mode 100644
index 0000000..8d94bb5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/google_chrome.py
@@ -0,0 +1,122 @@
+#!/usr/bin/env python
+# 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.
+
+# 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.
+
+from __future__ import with_statement
+
+import codecs
+import os
+
+
+def _test_expectations_overrides(port, super):
+ # The chrome ports use the regular overrides plus anything in the
+ # official test_expectations as well. Hopefully we don't get collisions.
+ chromium_overrides = super.test_expectations_overrides(port)
+
+ # FIXME: It used to be that AssertionError would get raised by
+ # path_from_chromium_base() if we weren't in a Chromium checkout, but
+ # this changed in r60427. This should probably be changed back.
+ overrides_path = port.path_from_chromium_base('webkit', 'tools',
+ 'layout_tests', 'test_expectations_chrome.txt')
+ if not os.path.exists(overrides_path):
+ return chromium_overrides
+
+ with codecs.open(overrides_path, "r", "utf-8") as file:
+ if chromium_overrides:
+ return chromium_overrides + file.read()
+ else:
+ return file.read()
+
+def GetGoogleChromePort(**kwargs):
+ """Some tests have slightly different results when compiled as Google
+ Chrome vs Chromium. In those cases, we prepend an additional directory to
+ to the baseline paths."""
+ port_name = kwargs['port_name']
+ del kwargs['port_name']
+ if port_name == 'google-chrome-linux32':
+ import chromium_linux
+
+ class GoogleChromeLinux32Port(chromium_linux.ChromiumLinuxPort):
+ def baseline_search_path(self):
+ paths = chromium_linux.ChromiumLinuxPort.baseline_search_path(
+ self)
+ paths.insert(0, self._webkit_baseline_path(
+ 'google-chrome-linux32'))
+ return paths
+
+ def test_expectations_overrides(self):
+ return _test_expectations_overrides(self,
+ chromium_linux.ChromiumLinuxPort)
+
+ return GoogleChromeLinux32Port(**kwargs)
+ elif port_name == 'google-chrome-linux64':
+ import chromium_linux
+
+ class GoogleChromeLinux64Port(chromium_linux.ChromiumLinuxPort):
+ def baseline_search_path(self):
+ paths = chromium_linux.ChromiumLinuxPort.baseline_search_path(
+ self)
+ paths.insert(0, self._webkit_baseline_path(
+ 'google-chrome-linux64'))
+ return paths
+
+ def test_expectations_overrides(self):
+ return _test_expectations_overrides(self,
+ chromium_linux.ChromiumLinuxPort)
+
+ return GoogleChromeLinux64Port(**kwargs)
+ elif port_name.startswith('google-chrome-mac'):
+ import chromium_mac
+
+ class GoogleChromeMacPort(chromium_mac.ChromiumMacPort):
+ def baseline_search_path(self):
+ paths = chromium_mac.ChromiumMacPort.baseline_search_path(
+ self)
+ paths.insert(0, self._webkit_baseline_path(
+ 'google-chrome-mac'))
+ return paths
+
+ def test_expectations_overrides(self):
+ return _test_expectations_overrides(self,
+ chromium_mac.ChromiumMacPort)
+
+ return GoogleChromeMacPort(**kwargs)
+ elif port_name.startswith('google-chrome-win'):
+ import chromium_win
+
+ class GoogleChromeWinPort(chromium_win.ChromiumWinPort):
+ def baseline_search_path(self):
+ paths = chromium_win.ChromiumWinPort.baseline_search_path(
+ self)
+ paths.insert(0, self._webkit_baseline_path(
+ 'google-chrome-win'))
+ return paths
+
+ def test_expectations_overrides(self):
+ return _test_expectations_overrides(self,
+ chromium_win.ChromiumWinPort)
+
+ return GoogleChromeWinPort(**kwargs)
+ raise NotImplementedError('unsupported port: %s' % port_name)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py
new file mode 100644
index 0000000..e60c274
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/google_chrome_unittest.py
@@ -0,0 +1,103 @@
+#!/usr/bin/env python
+# 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.
+
+# 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 codecs
+import os
+import unittest
+
+from webkitpy.common import newstringio
+
+import factory
+import google_chrome
+
+
+class GetGoogleChromePortTest(unittest.TestCase):
+ def test_get_google_chrome_port(self):
+ test_ports = ('google-chrome-linux32', 'google-chrome-linux64',
+ 'google-chrome-mac', 'google-chrome-win')
+ for port in test_ports:
+ self._verify_baseline_path(port, port)
+ self._verify_expectations_overrides(port)
+
+ self._verify_baseline_path('google-chrome-mac', 'google-chrome-mac-leopard')
+ self._verify_baseline_path('google-chrome-win', 'google-chrome-win-xp')
+ self._verify_baseline_path('google-chrome-win', 'google-chrome-win-vista')
+
+ def _verify_baseline_path(self, expected_path, port_name):
+ port = google_chrome.GetGoogleChromePort(port_name=port_name,
+ options=None)
+ path = port.baseline_search_path()[0]
+ self.assertEqual(expected_path, os.path.split(path)[1])
+
+ def _verify_expectations_overrides(self, port_name):
+ # FIXME: make this more robust when we have the Tree() abstraction.
+ # we should be able to test for the files existing or not, and
+ # be able to control the contents better.
+
+ chromium_port = factory.get("chromium-mac")
+ chromium_overrides = chromium_port.test_expectations_overrides()
+ port = google_chrome.GetGoogleChromePort(port_name=port_name,
+ options=None)
+
+ orig_exists = os.path.exists
+ orig_open = codecs.open
+ expected_string = "// hello, world\n"
+
+ def mock_exists_chrome_not_found(path):
+ if 'test_expectations_chrome.txt' in path:
+ return False
+ return orig_exists(path)
+
+ def mock_exists_chrome_found(path):
+ if 'test_expectations_chrome.txt' in path:
+ return True
+ return orig_exists(path)
+
+ def mock_open(path, mode, encoding):
+ if 'test_expectations_chrome.txt' in path:
+ return newstringio.StringIO(expected_string)
+ return orig_open(path, mode, encoding)
+
+ try:
+ os.path.exists = mock_exists_chrome_not_found
+ chrome_overrides = port.test_expectations_overrides()
+ self.assertEqual(chromium_overrides, chrome_overrides)
+
+ os.path.exists = mock_exists_chrome_found
+ codecs.open = mock_open
+ chrome_overrides = port.test_expectations_overrides()
+ if chromium_overrides:
+ self.assertEqual(chrome_overrides,
+ chromium_overrides + expected_string)
+ else:
+ self.assertEqual(chrome_overrides, expected_string)
+ finally:
+ os.path.exists = orig_exists
+ codecs.open = orig_open
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/gtk.py b/Tools/Scripts/webkitpy/layout_tests/port/gtk.py
new file mode 100644
index 0000000..a18fdff
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/gtk.py
@@ -0,0 +1,116 @@
+# 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 Google name 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.
+
+"""WebKit Gtk implementation of the Port interface."""
+
+import logging
+import os
+import signal
+
+from webkitpy.layout_tests.port.webkit import WebKitPort
+
+_log = logging.getLogger("webkitpy.layout_tests.port.gtk")
+
+
+class GtkPort(WebKitPort):
+ """WebKit Gtk implementation of the Port class."""
+
+ def __init__(self, **kwargs):
+ kwargs.setdefault('port_name', 'gtk')
+ WebKitPort.__init__(self, **kwargs)
+
+ def _tests_for_other_platforms(self):
+ # FIXME: This list could be dynamic based on platform name and
+ # pushed into base.Port.
+ # This really need to be automated.
+ return [
+ "platform/chromium",
+ "platform/win",
+ "platform/qt",
+ "platform/mac",
+ ]
+
+ def _path_to_apache_config_file(self):
+ # FIXME: This needs to detect the distribution and change config files.
+ return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ 'apache2-debian-httpd.conf')
+
+ def _shut_down_http_server(self, server_pid):
+ """Shut down the httpd web server. Blocks until it's fully
+ shut down.
+
+ Args:
+ server_pid: The process ID of the running server.
+ """
+ # server_pid is not set when "http_server.py stop" is run manually.
+ if server_pid is None:
+ # FIXME: This isn't ideal, since it could conflict with
+ # lighttpd processes not started by http_server.py,
+ # but good enough for now.
+ self._executive.kill_all('apache2')
+ else:
+ try:
+ os.kill(server_pid, signal.SIGTERM)
+ # TODO(mmoss) Maybe throw in a SIGKILL just to be sure?
+ except OSError:
+ # Sometimes we get a bad PID (e.g. from a stale httpd.pid
+ # file), so if kill fails on the given PID, just try to
+ # 'killall' web servers.
+ self._shut_down_http_server(None)
+
+ def _path_to_driver(self):
+ return self._build_path('Programs', 'DumpRenderTree')
+
+ def check_build(self, needs_http):
+ if not self._check_driver():
+ return False
+ return True
+
+ def _path_to_apache(self):
+ if self._is_redhat_based():
+ return '/usr/sbin/httpd'
+ else:
+ return '/usr/sbin/apache2'
+
+ def _path_to_apache_config_file(self):
+ if self._is_redhat_based():
+ config_name = 'fedora-httpd.conf'
+ else:
+ config_name = 'apache2-debian-httpd.conf'
+
+ return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ config_name)
+
+ def _path_to_wdiff(self):
+ if self._is_redhat_based():
+ return '/usr/bin/dwdiff'
+ else:
+ return '/usr/bin/wdiff'
+
+ def _is_redhat_based(self):
+ return os.path.exists(os.path.join('/etc', 'redhat-release'))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/http_lock.py b/Tools/Scripts/webkitpy/layout_tests/port/http_lock.py
new file mode 100644
index 0000000..f5946b6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/http_lock.py
@@ -0,0 +1,133 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
+# Copyright (C) 2010 Andras Becsi (abecsi@inf.u-szeged.hu), University of Szeged
+#
+# 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 UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED 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 class helps to block NRWT threads when more NRWTs run
+http and websocket tests in a same time."""
+
+import glob
+import logging
+import os
+import sys
+import tempfile
+import time
+
+from webkitpy.common.system.executive import Executive
+from webkitpy.common.system.file_lock import FileLock
+from webkitpy.common.system.filesystem import FileSystem
+
+
+_log = logging.getLogger("webkitpy.layout_tests.port.http_lock")
+
+
+class HttpLock(object):
+
+ def __init__(self, lock_path, lock_file_prefix="WebKitHttpd.lock.",
+ guard_lock="WebKit.lock"):
+ self._lock_path = lock_path
+ if not self._lock_path:
+ self._lock_path = tempfile.gettempdir()
+ self._lock_file_prefix = lock_file_prefix
+ self._lock_file_path_prefix = os.path.join(self._lock_path,
+ self._lock_file_prefix)
+ self._guard_lock_file = os.path.join(self._lock_path, guard_lock)
+ self._guard_lock = FileLock(self._guard_lock_file)
+ self._process_lock_file_name = ""
+ self._executive = Executive()
+
+ def cleanup_http_lock(self):
+ """Delete the lock file if exists."""
+ if os.path.exists(self._process_lock_file_name):
+ _log.debug("Removing lock file: %s" % self._process_lock_file_name)
+ FileSystem().remove(self._process_lock_file_name)
+
+ def _extract_lock_number(self, lock_file_name):
+ """Return the lock number from lock file."""
+ prefix_length = len(self._lock_file_path_prefix)
+ return int(lock_file_name[prefix_length:])
+
+ def _lock_file_list(self):
+ """Return the list of lock files sequentially."""
+ lock_list = glob.glob(self._lock_file_path_prefix + '*')
+ lock_list.sort(key=self._extract_lock_number)
+ return lock_list
+
+ def _next_lock_number(self):
+ """Return the next available lock number."""
+ lock_list = self._lock_file_list()
+ if not lock_list:
+ return 0
+ return self._extract_lock_number(lock_list[-1]) + 1
+
+ def _curent_lock_pid(self):
+ """Return with the current lock pid. If the lock is not valid
+ it deletes the lock file."""
+ lock_list = self._lock_file_list()
+ if not lock_list:
+ return
+ try:
+ current_lock_file = open(lock_list[0], 'r')
+ current_pid = current_lock_file.readline()
+ current_lock_file.close()
+ if not (current_pid and self._executive.check_running_pid(int(current_pid))):
+ _log.debug("Removing stuck lock file: %s" % lock_list[0])
+ FileSystem().remove(lock_list[0])
+ return
+ except (IOError, OSError):
+ return
+ return int(current_pid)
+
+ def _create_lock_file(self):
+ """The lock files are used to schedule the running test sessions in first
+ come first served order. The guard lock ensures that the lock numbers are
+ sequential."""
+ if not os.path.exists(self._lock_path):
+ _log.debug("Lock directory does not exist: %s" % self._lock_path)
+ return False
+
+ if not self._guard_lock.acquire_lock():
+ _log.debug("Guard lock timed out!")
+ return False
+
+ self._process_lock_file_name = (self._lock_file_path_prefix +
+ str(self._next_lock_number()))
+ _log.debug("Creating lock file: %s" % self._process_lock_file_name)
+ lock_file = open(self._process_lock_file_name, 'w')
+ lock_file.write(str(os.getpid()))
+ lock_file.close()
+ self._guard_lock.release_lock()
+ return True
+
+
+ def wait_for_httpd_lock(self):
+ """Create a lock file and wait until it's turn comes. If something goes wrong
+ it wont do any locking."""
+ if not self._create_lock_file():
+ _log.debug("Warning, http locking failed!")
+ return
+
+ while self._curent_lock_pid() != os.getpid():
+ time.sleep(1)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/http_lock_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/http_lock_unittest.py
new file mode 100644
index 0000000..85c760a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/http_lock_unittest.py
@@ -0,0 +1,111 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
+#
+# 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 UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED 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 glob
+import http_lock
+import os
+import unittest
+
+
+class HttpLockTest(unittest.TestCase):
+
+ def __init__(self, testFunc):
+ self.http_lock_obj = http_lock.HttpLock(None, "WebKitTestHttpd.lock.", "WebKitTest.lock")
+ self.lock_file_path_prefix = os.path.join(self.http_lock_obj._lock_path,
+ self.http_lock_obj._lock_file_prefix)
+ self.lock_file_name = self.lock_file_path_prefix + "0"
+ self.guard_lock_file = self.http_lock_obj._guard_lock_file
+ self.clean_all_lockfile()
+ unittest.TestCase.__init__(self, testFunc)
+
+ def clean_all_lockfile(self):
+ if os.path.exists(self.guard_lock_file):
+ os.unlink(self.guard_lock_file)
+ lock_list = glob.glob(self.lock_file_path_prefix + '*')
+ for file_name in lock_list:
+ os.unlink(file_name)
+
+ def assertEqual(self, first, second):
+ if first != second:
+ self.clean_all_lockfile()
+ unittest.TestCase.assertEqual(self, first, second)
+
+ def _check_lock_file(self):
+ if os.path.exists(self.lock_file_name):
+ pid = os.getpid()
+ lock_file = open(self.lock_file_name, 'r')
+ lock_file_pid = lock_file.readline()
+ lock_file.close()
+ self.assertEqual(pid, int(lock_file_pid))
+ return True
+ return False
+
+ def test_lock_lifecycle(self):
+ self.http_lock_obj._create_lock_file()
+
+ self.assertEqual(True, self._check_lock_file())
+ self.assertEqual(1, self.http_lock_obj._next_lock_number())
+
+ self.http_lock_obj.cleanup_http_lock()
+
+ self.assertEqual(False, self._check_lock_file())
+ self.assertEqual(0, self.http_lock_obj._next_lock_number())
+
+ def test_extract_lock_number(self,):
+ lock_file_list = (
+ self.lock_file_path_prefix + "00",
+ self.lock_file_path_prefix + "9",
+ self.lock_file_path_prefix + "001",
+ self.lock_file_path_prefix + "021",
+ )
+
+ expected_number_list = (0, 9, 1, 21)
+
+ for lock_file, expected in zip(lock_file_list, expected_number_list):
+ self.assertEqual(self.http_lock_obj._extract_lock_number(lock_file), expected)
+
+ def test_lock_file_list(self):
+ lock_file_list = [
+ self.lock_file_path_prefix + "6",
+ self.lock_file_path_prefix + "1",
+ self.lock_file_path_prefix + "4",
+ self.lock_file_path_prefix + "3",
+ ]
+
+ expected_file_list = [
+ self.lock_file_path_prefix + "1",
+ self.lock_file_path_prefix + "3",
+ self.lock_file_path_prefix + "4",
+ self.lock_file_path_prefix + "6",
+ ]
+
+ for file_name in lock_file_list:
+ open(file_name, 'w')
+
+ self.assertEqual(self.http_lock_obj._lock_file_list(), expected_file_list)
+
+ for file_name in lock_file_list:
+ os.unlink(file_name)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/http_server.py b/Tools/Scripts/webkitpy/layout_tests/port/http_server.py
new file mode 100755
index 0000000..bd75e27
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/http_server.py
@@ -0,0 +1,233 @@
+#!/usr/bin/env python
+# 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.
+
+"""A class to help start/stop the lighttpd server used by layout tests."""
+
+from __future__ import with_statement
+
+import codecs
+import logging
+import optparse
+import os
+import shutil
+import subprocess
+import sys
+import tempfile
+import time
+import urllib
+
+import factory
+import http_server_base
+
+_log = logging.getLogger("webkitpy.layout_tests.port.http_server")
+
+
+class HttpdNotStarted(Exception):
+ pass
+
+
+class Lighttpd(http_server_base.HttpServerBase):
+
+ def __init__(self, port_obj, output_dir, background=False, port=None,
+ root=None, run_background=None):
+ """Args:
+ output_dir: the absolute path to the layout test result directory
+ """
+ # Webkit tests
+ http_server_base.HttpServerBase.__init__(self, port_obj)
+ self._output_dir = output_dir
+ self._process = None
+ self._port = port
+ self._root = root
+ self._run_background = run_background
+ if self._port:
+ self._port = int(self._port)
+
+ try:
+ self._webkit_tests = os.path.join(
+ self._port_obj.layout_tests_dir(), 'http', 'tests')
+ self._js_test_resource = os.path.join(
+ self._port_obj.layout_tests_dir(), 'fast', 'js', 'resources')
+ except:
+ self._webkit_tests = None
+ self._js_test_resource = None
+
+ # Self generated certificate for SSL server (for client cert get
+ # <base-path>\chrome\test\data\ssl\certs\root_ca_cert.crt)
+ self._pem_file = os.path.join(
+ os.path.dirname(os.path.abspath(__file__)), 'httpd2.pem')
+
+ # One mapping where we can get to everything
+ self.VIRTUALCONFIG = []
+
+ if self._webkit_tests:
+ self.VIRTUALCONFIG.extend(
+ # Three mappings (one with SSL) for LayoutTests http tests
+ [{'port': 8000, 'docroot': self._webkit_tests},
+ {'port': 8080, 'docroot': self._webkit_tests},
+ {'port': 8443, 'docroot': self._webkit_tests,
+ 'sslcert': self._pem_file}])
+
+ def is_running(self):
+ return self._process != None
+
+ def start(self):
+ if self.is_running():
+ raise 'Lighttpd already running'
+
+ base_conf_file = self._port_obj.path_from_webkit_base('Tools',
+ 'Scripts', 'webkitpy', 'layout_tests', 'port', 'lighttpd.conf')
+ out_conf_file = os.path.join(self._output_dir, 'lighttpd.conf')
+ time_str = time.strftime("%d%b%Y-%H%M%S")
+ access_file_name = "access.log-" + time_str + ".txt"
+ access_log = os.path.join(self._output_dir, access_file_name)
+ log_file_name = "error.log-" + time_str + ".txt"
+ error_log = os.path.join(self._output_dir, log_file_name)
+
+ # Remove old log files. We only need to keep the last ones.
+ self.remove_log_files(self._output_dir, "access.log-")
+ self.remove_log_files(self._output_dir, "error.log-")
+
+ # Write out the config
+ with codecs.open(base_conf_file, "r", "utf-8") as file:
+ base_conf = file.read()
+
+ # FIXME: This should be re-worked so that this block can
+ # use with open() instead of a manual file.close() call.
+ # lighttpd.conf files seem to be UTF-8 without BOM:
+ # http://redmine.lighttpd.net/issues/992
+ f = codecs.open(out_conf_file, "w", "utf-8")
+ f.write(base_conf)
+
+ # Write out our cgi handlers. Run perl through env so that it
+ # processes the #! line and runs perl with the proper command
+ # line arguments. Emulate apache's mod_asis with a cat cgi handler.
+ f.write(('cgi.assign = ( ".cgi" => "/usr/bin/env",\n'
+ ' ".pl" => "/usr/bin/env",\n'
+ ' ".asis" => "/bin/cat",\n'
+ ' ".php" => "%s" )\n\n') %
+ self._port_obj._path_to_lighttpd_php())
+
+ # Setup log files
+ f.write(('server.errorlog = "%s"\n'
+ 'accesslog.filename = "%s"\n\n') % (error_log, access_log))
+
+ # Setup upload folders. Upload folder is to hold temporary upload files
+ # and also POST data. This is used to support XHR layout tests that
+ # does POST.
+ f.write(('server.upload-dirs = ( "%s" )\n\n') % (self._output_dir))
+
+ # Setup a link to where the js test templates are stored
+ f.write(('alias.url = ( "/js-test-resources" => "%s" )\n\n') %
+ (self._js_test_resource))
+
+ # dump out of virtual host config at the bottom.
+ if self._root:
+ if self._port:
+ # Have both port and root dir.
+ mappings = [{'port': self._port, 'docroot': self._root}]
+ else:
+ # Have only a root dir - set the ports as for LayoutTests.
+ # This is used in ui_tests to run http tests against a browser.
+
+ # default set of ports as for LayoutTests but with a
+ # specified root.
+ mappings = [{'port': 8000, 'docroot': self._root},
+ {'port': 8080, 'docroot': self._root},
+ {'port': 8443, 'docroot': self._root,
+ 'sslcert': self._pem_file}]
+ else:
+ mappings = self.VIRTUALCONFIG
+ for mapping in mappings:
+ ssl_setup = ''
+ if 'sslcert' in mapping:
+ ssl_setup = (' ssl.engine = "enable"\n'
+ ' ssl.pemfile = "%s"\n' % mapping['sslcert'])
+
+ f.write(('$SERVER["socket"] == "127.0.0.1:%d" {\n'
+ ' server.document-root = "%s"\n' +
+ ssl_setup +
+ '}\n\n') % (mapping['port'], mapping['docroot']))
+ f.close()
+
+ executable = self._port_obj._path_to_lighttpd()
+ module_path = self._port_obj._path_to_lighttpd_modules()
+ start_cmd = [executable,
+ # Newly written config file
+ '-f', os.path.join(self._output_dir, 'lighttpd.conf'),
+ # Where it can find its module dynamic libraries
+ '-m', module_path]
+
+ if not self._run_background:
+ start_cmd.append(# Don't background
+ '-D')
+
+ # Copy liblightcomp.dylib to /tmp/lighttpd/lib to work around the
+ # bug that mod_alias.so loads it from the hard coded path.
+ if sys.platform == 'darwin':
+ tmp_module_path = '/tmp/lighttpd/lib'
+ if not os.path.exists(tmp_module_path):
+ os.makedirs(tmp_module_path)
+ lib_file = 'liblightcomp.dylib'
+ shutil.copyfile(os.path.join(module_path, lib_file),
+ os.path.join(tmp_module_path, lib_file))
+
+ env = self._port_obj.setup_environ_for_server()
+ _log.debug('Starting http server')
+ # FIXME: Should use Executive.run_command
+ self._process = subprocess.Popen(start_cmd, env=env)
+
+ # Wait for server to start.
+ self.mappings = mappings
+ server_started = self.wait_for_action(
+ self.is_server_running_on_all_ports)
+
+ # Our process terminated already
+ if not server_started or self._process.returncode != None:
+ raise google.httpd_utils.HttpdNotStarted('Failed to start httpd.')
+
+ _log.debug("Server successfully started")
+
+ # TODO(deanm): Find a nicer way to shutdown cleanly. Our log files are
+ # probably not being flushed, etc... why doesn't our python have os.kill ?
+
+ def stop(self, force=False):
+ if not force and not self.is_running():
+ return
+
+ httpd_pid = None
+ if self._process:
+ httpd_pid = self._process.pid
+ self._port_obj._shut_down_http_server(httpd_pid)
+
+ if self._process:
+ # wait() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ self._process.wait()
+ self._process = None
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/http_server_base.py b/Tools/Scripts/webkitpy/layout_tests/port/http_server_base.py
new file mode 100644
index 0000000..52a0403
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/http_server_base.py
@@ -0,0 +1,83 @@
+#!/usr/bin/env python
+# 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.
+
+"""Base class with common routines between the Apache and Lighttpd servers."""
+
+import logging
+import os
+import time
+import urllib
+
+from webkitpy.common.system import filesystem
+
+_log = logging.getLogger("webkitpy.layout_tests.port.http_server_base")
+
+
+class HttpServerBase(object):
+
+ def __init__(self, port_obj):
+ self._port_obj = port_obj
+
+ def wait_for_action(self, action):
+ """Repeat the action for 20 seconds or until it succeeds. Returns
+ whether it succeeded."""
+ start_time = time.time()
+ while time.time() - start_time < 20:
+ if action():
+ return True
+ _log.debug("Waiting for action: %s" % action)
+ time.sleep(1)
+
+ return False
+
+ def is_server_running_on_all_ports(self):
+ """Returns whether the server is running on all the desired ports."""
+ for mapping in self.mappings:
+ if 'sslcert' in mapping:
+ http_suffix = 's'
+ else:
+ http_suffix = ''
+
+ url = 'http%s://127.0.0.1:%d/' % (http_suffix, mapping['port'])
+
+ try:
+ response = urllib.urlopen(url)
+ _log.debug("Server running at %s" % url)
+ except IOError, e:
+ _log.debug("Server NOT running at %s: %s" % (url, e))
+ return False
+
+ return True
+
+ def remove_log_files(self, folder, starts_with):
+ files = os.listdir(folder)
+ for file in files:
+ if file.startswith(starts_with):
+ full_path = os.path.join(folder, file)
+ filesystem.FileSystem().remove(full_path)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/httpd2.pem b/Tools/Scripts/webkitpy/layout_tests/port/httpd2.pem
new file mode 100644
index 0000000..6349b78
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/httpd2.pem
@@ -0,0 +1,41 @@
+-----BEGIN CERTIFICATE-----
+MIIEZDCCAkygAwIBAgIBATANBgkqhkiG9w0BAQUFADBgMRAwDgYDVQQDEwdUZXN0
+IENBMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMN
+TW91bnRhaW4gVmlldzESMBAGA1UEChMJQ2VydCBUZXN0MB4XDTA4MDcyODIyMzIy
+OFoXDTEzMDcyNzIyMzIyOFowSjELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlm
+b3JuaWExEjAQBgNVBAoTCUNlcnQgVGVzdDESMBAGA1UEAxMJMTI3LjAuMC4xMIGf
+MA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDQj2tPWPUgbuI4H3/3dnttqVbndwU3
+3BdRCd67DFM44GRrsjDSH4bY/EbFyX9D52d/iy6ZaAmDePcCz5k/fgP3DMujykYG
+qgNiV2ywxTlMj7NlN2C7SRt68fQMZr5iI7rypdxuaZt9lSMD3ENBffYtuLTyZd9a
+3JPJe1TaIab5GwIDAQABo4HCMIG/MAkGA1UdEwQCMAAwHQYDVR0OBBYEFCYLBv5K
+x5sLNVlpLh5FwTwhdDl7MIGSBgNVHSMEgYowgYeAFF3Of5nj1BlBMU/Gz7El9Vqv
+45cxoWSkYjBgMRAwDgYDVQQDEwdUZXN0IENBMQswCQYDVQQGEwJVUzETMBEGA1UE
+CBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNTW91bnRhaW4gVmlldzESMBAGA1UEChMJ
+Q2VydCBUZXN0ggkA1FGT1D/e2U4wDQYJKoZIhvcNAQEFBQADggIBAEtkVmLObUgk
+b2cIA2S+QDtifq1UgVfBbytvR2lFmnADOR55mo0gHQG3HHqq4g034LmoVXDHhUk8
+Gb6aFiv4QubmVhLXcUelTRXwiNvGzkW7pC6Jrq105hdPjzXMKTcmiLaopm5Fqfc7
+hj5Cn1Sjspc8pdeQjrbeMdvca7KlFrGP8YkwCU2xOOX9PiN9G0966BWfjnr/fZZp
++OQVuUFHdiAZwthEMuDpAAXHqYXIsermgdOpgJaA53cf8NqBV2QGhtFgtsJCRoiu
+7DKqhyRWBGyz19VIH2b7y+6qvQVxuHk19kKRM0nftw/yNcJnm7gtttespMUPsOMa
+a2SD1G0hm0TND6vxaBhgR3cVqpl/qIpAdFi00Tm7hTyYE7I43zPW03t+/DpCt3Um
+EMRZsQ90co5q+bcx/vQ7YAtwUh30uMb0wpibeyCwDp8cqNmSiRkEuc/FjTYes5t8
+5gR//WX1l0+qjrjusO9NmoLnq2Yk6UcioX+z+q6Z/dudGfqhLfeWD2Q0LWYA242C
+d7km5Y3KAt1PJdVsof/aiVhVdddY/OIEKTRQhWEdDbosy2eh16BCKXT2FFvhNDg1
+AYFvn6I8nj9IldMJiIc3DdhacEAEzRMeRgPdzAa1griKUGknxsyTyRii8ru0WS6w
+DCNrlDOVXdzYGEZooBI76BDVY0W0akjV
+-----END CERTIFICATE-----
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDQj2tPWPUgbuI4H3/3dnttqVbndwU33BdRCd67DFM44GRrsjDS
+H4bY/EbFyX9D52d/iy6ZaAmDePcCz5k/fgP3DMujykYGqgNiV2ywxTlMj7NlN2C7
+SRt68fQMZr5iI7rypdxuaZt9lSMD3ENBffYtuLTyZd9a3JPJe1TaIab5GwIDAQAB
+AoGANHXu8z2YIzlhE+bwhGm8MGBpKL3qhRuKjeriqMA36tWezOw8lY4ymEAU+Ulv
+BsCdaxqydQoTYou57m4TyUHEcxq9pq3H0zB0qL709DdHi/t4zbV9XIoAzC5v0/hG
+9+Ca29TwC02FCw+qLkNrtwCpwOcQmc+bPxqvFu1iMiahURECQQD2I/Hi2413CMZz
+TBjl8fMiVO9GhA2J0sc8Qi+YcgJakaLD9xcbaiLkTzPZDlA389C1b6Ia+poAr4YA
+Ve0FFbxpAkEA2OobayyHE/QtPEqoy6NLR57jirmVBNmSWWd4lAyL5UIHIYVttJZg
+8CLvbzaU/iDGwR+wKsM664rKPHEmtlyo4wJBAMeSqYO5ZOCJGu9NWjrHjM3fdAsG
+8zs2zhiLya+fcU0iHIksBW5TBmt71Jw/wMc9R5J1K0kYvFml98653O5si1ECQBCk
+RV4/mE1rmlzZzYFyEcB47DQkcM5ictvxGEsje0gnfKyRtAz6zI0f4QbDRUMJ+LWw
+XK+rMsYHa+SfOb0b9skCQQCLdeonsIpFDv/Uv+flHISy0WA+AFkLXrRkBKh6G/OD
+dMHaNevkJgUnpceVEnkrdenp5CcEoFTI17pd+nBgDm/B
+-----END RSA PRIVATE KEY-----
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/lighttpd.conf b/Tools/Scripts/webkitpy/layout_tests/port/lighttpd.conf
new file mode 100644
index 0000000..26ca22f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/lighttpd.conf
@@ -0,0 +1,90 @@
+server.tag = "LightTPD/1.4.19 (Win32)"
+server.modules = ( "mod_accesslog",
+ "mod_alias",
+ "mod_cgi",
+ "mod_rewrite" )
+
+# default document root required
+server.document-root = "."
+
+# files to check for if .../ is requested
+index-file.names = ( "index.php", "index.pl", "index.cgi",
+ "index.html", "index.htm", "default.htm" )
+# mimetype mapping
+mimetype.assign = (
+ ".gif" => "image/gif",
+ ".jpg" => "image/jpeg",
+ ".jpeg" => "image/jpeg",
+ ".png" => "image/png",
+ ".svg" => "image/svg+xml",
+ ".css" => "text/css",
+ ".html" => "text/html",
+ ".htm" => "text/html",
+ ".xhtml" => "application/xhtml+xml",
+ ".xhtmlmp" => "application/vnd.wap.xhtml+xml",
+ ".js" => "application/x-javascript",
+ ".log" => "text/plain",
+ ".conf" => "text/plain",
+ ".text" => "text/plain",
+ ".txt" => "text/plain",
+ ".dtd" => "text/xml",
+ ".xml" => "text/xml",
+ ".manifest" => "text/cache-manifest",
+ )
+
+# Use the "Content-Type" extended attribute to obtain mime type if possible
+mimetype.use-xattr = "enable"
+
+##
+# which extensions should not be handle via static-file transfer
+#
+# .php, .pl, .fcgi are most often handled by mod_fastcgi or mod_cgi
+static-file.exclude-extensions = ( ".php", ".pl", ".cgi" )
+
+server.bind = "localhost"
+server.port = 8001
+
+## virtual directory listings
+dir-listing.activate = "enable"
+#dir-listing.encoding = "iso-8859-2"
+#dir-listing.external-css = "style/oldstyle.css"
+
+## enable debugging
+#debug.log-request-header = "enable"
+#debug.log-response-header = "enable"
+#debug.log-request-handling = "enable"
+#debug.log-file-not-found = "enable"
+
+#### SSL engine
+#ssl.engine = "enable"
+#ssl.pemfile = "server.pem"
+
+# Rewrite rule for utf-8 path test (LayoutTests/http/tests/uri/utf8-path.html)
+# See the apache rewrite rule at LayoutTests/http/tests/uri/intercept/.htaccess
+# Rewrite rule for LayoutTests/http/tests/appcache/cyrillic-uri.html.
+# See the apache rewrite rule at
+# LayoutTests/http/tests/appcache/resources/intercept/.htaccess
+url.rewrite-once = (
+ "^/uri/intercept/(.*)" => "/uri/resources/print-uri.php",
+ "^/appcache/resources/intercept/(.*)" => "/appcache/resources/print-uri.php"
+)
+
+# LayoutTests/http/tests/xmlhttprequest/response-encoding.html uses an htaccess
+# to override charset for reply2.txt, reply2.xml, and reply4.txt.
+$HTTP["url"] =~ "^/xmlhttprequest/resources/reply2.(txt|xml)" {
+ mimetype.assign = (
+ ".txt" => "text/plain; charset=windows-1251",
+ ".xml" => "text/xml; charset=windows-1251"
+ )
+}
+$HTTP["url"] =~ "^/xmlhttprequest/resources/reply4.txt" {
+ mimetype.assign = ( ".txt" => "text/plain; charset=koi8-r" )
+}
+
+# LayoutTests/http/tests/appcache/wrong-content-type.html uses an htaccess
+# to override mime type for wrong-content-type.manifest.
+$HTTP["url"] =~ "^/appcache/resources/wrong-content-type.manifest" {
+ mimetype.assign = ( ".manifest" => "text/plain" )
+}
+
+# Autogenerated test-specific config follows.
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mac.py b/Tools/Scripts/webkitpy/layout_tests/port/mac.py
new file mode 100644
index 0000000..696e339
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/mac.py
@@ -0,0 +1,152 @@
+# 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 Google name 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.
+
+"""WebKit Mac implementation of the Port interface."""
+
+import logging
+import os
+import platform
+import signal
+
+import webkitpy.common.system.ospath as ospath
+import webkitpy.layout_tests.port.server_process as server_process
+from webkitpy.layout_tests.port.webkit import WebKitPort, WebKitDriver
+
+_log = logging.getLogger("webkitpy.layout_tests.port.mac")
+
+
+class MacPort(WebKitPort):
+ """WebKit Mac implementation of the Port class."""
+
+ def __init__(self, **kwargs):
+ kwargs.setdefault('port_name', 'mac' + self.version())
+ WebKitPort.__init__(self, **kwargs)
+
+ def default_child_processes(self):
+ # FIXME: new-run-webkit-tests is unstable on Mac running more than
+ # four threads in parallel.
+ # See https://bugs.webkit.org/show_bug.cgi?id=36622
+ child_processes = WebKitPort.default_child_processes(self)
+ if child_processes > 4:
+ return 4
+ return child_processes
+
+ def baseline_search_path(self):
+ port_names = []
+ if self._name == 'mac-tiger':
+ port_names.append("mac-tiger")
+ if self._name in ('mac-tiger', 'mac-leopard'):
+ port_names.append("mac-leopard")
+ if self._name in ('mac-tiger', 'mac-leopard', 'mac-snowleopard'):
+ port_names.append("mac-snowleopard")
+ port_names.append("mac")
+ return map(self._webkit_baseline_path, port_names)
+
+ def path_to_test_expectations_file(self):
+ return self.path_from_webkit_base('LayoutTests', 'platform',
+ 'mac', 'test_expectations.txt')
+
+ def _skipped_file_paths(self):
+ # FIXME: This method will need to be made work for non-mac
+ # platforms and moved into base.Port.
+ skipped_files = []
+ if self._name in ('mac-tiger', 'mac-leopard', 'mac-snowleopard'):
+ skipped_files.append(os.path.join(
+ self._webkit_baseline_path(self._name), 'Skipped'))
+ skipped_files.append(os.path.join(self._webkit_baseline_path('mac'),
+ 'Skipped'))
+ return skipped_files
+
+ def test_platform_name(self):
+ return 'mac' + self.version()
+
+ def version(self):
+ os_version_string = platform.mac_ver()[0] # e.g. "10.5.6"
+ if not os_version_string:
+ return '-leopard'
+ release_version = int(os_version_string.split('.')[1])
+ if release_version == 4:
+ return '-tiger'
+ elif release_version == 5:
+ return '-leopard'
+ elif release_version == 6:
+ return '-snowleopard'
+ return ''
+
+ def _build_java_test_support(self):
+ java_tests_path = os.path.join(self.layout_tests_dir(), "java")
+ build_java = ["/usr/bin/make", "-C", java_tests_path]
+ if self._executive.run_command(build_java, return_exit_code=True):
+ _log.error("Failed to build Java support files: %s" % build_java)
+ return False
+ return True
+
+ def _check_port_build(self):
+ return self._build_java_test_support()
+
+ def _tests_for_other_platforms(self):
+ # The original run-webkit-tests builds up a "whitelist" of tests to
+ # run, and passes that to DumpRenderTree. new-run-webkit-tests assumes
+ # we run *all* tests and test_expectations.txt functions as a
+ # blacklist.
+ # FIXME: This list could be dynamic based on platform name and
+ # pushed into base.Port.
+ return [
+ "platform/chromium",
+ "platform/gtk",
+ "platform/qt",
+ "platform/win",
+ ]
+
+ def _path_to_apache_config_file(self):
+ return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ 'apache2-httpd.conf')
+
+ # FIXME: This doesn't have anything to do with WebKit.
+ def _shut_down_http_server(self, server_pid):
+ """Shut down the lighttpd web server. Blocks until it's fully
+ shut down.
+
+ Args:
+ server_pid: The process ID of the running server.
+ """
+ # server_pid is not set when "http_server.py stop" is run manually.
+ if server_pid is None:
+ # FIXME: This isn't ideal, since it could conflict with
+ # lighttpd processes not started by http_server.py,
+ # but good enough for now.
+ self._executive.kill_all('httpd')
+ else:
+ try:
+ os.kill(server_pid, signal.SIGTERM)
+ # FIXME: Maybe throw in a SIGKILL just to be sure?
+ except OSError:
+ # Sometimes we get a bad PID (e.g. from a stale httpd.pid
+ # file), so if kill fails on the given PID, just try to
+ # 'killall' web servers.
+ self._shut_down_http_server(None)
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py
new file mode 100644
index 0000000..d383a4c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/mac_unittest.py
@@ -0,0 +1,81 @@
+# 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 StringIO
+import sys
+import unittest
+
+import mac
+import port_testcase
+
+
+class MacTest(port_testcase.PortTestCase):
+ def make_port(self, options=port_testcase.mock_options):
+ if sys.platform != 'darwin':
+ return None
+ port_obj = mac.MacPort(options=options)
+ port_obj._options.results_directory = port_obj.results_directory()
+ port_obj._options.configuration = 'Release'
+ return port_obj
+
+ def test_skipped_file_paths(self):
+ port = self.make_port()
+ if not port:
+ return
+ skipped_paths = port._skipped_file_paths()
+ # FIXME: _skipped_file_paths should return WebKit-relative paths.
+ # So to make it unit testable, we strip the WebKit directory from the path.
+ relative_paths = [path[len(port.path_from_webkit_base()):] for path in skipped_paths]
+ self.assertEqual(relative_paths, ['LayoutTests/platform/mac-leopard/Skipped', 'LayoutTests/platform/mac/Skipped'])
+
+ example_skipped_file = u"""
+# <rdar://problem/5647952> fast/events/mouseout-on-window.html needs mac DRT to issue mouse out events
+fast/events/mouseout-on-window.html
+
+# <rdar://problem/5643675> window.scrollTo scrolls a window with no scrollbars
+fast/events/attempt-scroll-with-no-scrollbars.html
+
+# see bug <rdar://problem/5646437> REGRESSION (r28015): svg/batik/text/smallFonts fails
+svg/batik/text/smallFonts.svg
+"""
+ example_skipped_tests = [
+ "fast/events/mouseout-on-window.html",
+ "fast/events/attempt-scroll-with-no-scrollbars.html",
+ "svg/batik/text/smallFonts.svg",
+ ]
+
+ def test_skipped_file_paths(self):
+ port = self.make_port()
+ if not port:
+ return
+ skipped_file = StringIO.StringIO(self.example_skipped_file)
+ self.assertEqual(port._tests_from_skipped_file(skipped_file), self.example_skipped_tests)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py b/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
new file mode 100644
index 0000000..c4b36ac
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/port_testcase.py
@@ -0,0 +1,97 @@
+# 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.
+
+"""Unit testing base class for Port implementations."""
+
+import os
+import tempfile
+import unittest
+
+from webkitpy.tool import mocktool
+mock_options = mocktool.MockOptions(results_directory='layout-test-results',
+ use_apache=True,
+ configuration='Release')
+
+# FIXME: This should be used for all ports, not just WebKit Mac. See
+# https://bugs.webkit.org/show_bug.cgi?id=50043 .
+
+class PortTestCase(unittest.TestCase):
+ """Tests the WebKit port implementation."""
+ def make_port(self, options=mock_options):
+ """Override in subclass."""
+ raise NotImplementedError()
+
+ def test_driver_cmd_line(self):
+ port = self.make_port()
+ if not port:
+ return
+ self.assertTrue(len(port.driver_cmd_line()))
+
+ def test_http_server(self):
+ port = self.make_port()
+ if not port:
+ return
+ port.start_http_server()
+ port.stop_http_server()
+
+ def test_image_diff(self):
+ port = self.make_port()
+ if not port:
+ return
+
+ # FIXME: not sure why this shouldn't always be True
+ #self.assertTrue(port.check_image_diff())
+ if not port.check_image_diff():
+ return
+
+ dir = port.layout_tests_dir()
+ file1 = os.path.join(dir, 'fast', 'css', 'button_center.png')
+ fh1 = file(file1)
+ contents1 = fh1.read()
+ file2 = os.path.join(dir, 'fast', 'css',
+ 'remove-shorthand-expected.png')
+ fh2 = file(file2)
+ contents2 = fh2.read()
+ tmpfile = tempfile.mktemp()
+
+ self.assertFalse(port.diff_image(contents1, contents1))
+ self.assertTrue(port.diff_image(contents1, contents2))
+
+ self.assertTrue(port.diff_image(contents1, contents2, tmpfile))
+ fh1.close()
+ fh2.close()
+ # FIXME: this may not be being written?
+ # self.assertTrue(os.path.exists(tmpfile))
+ # os.remove(tmpfile)
+
+ def test_websocket_server(self):
+ port = self.make_port()
+ if not port:
+ return
+ port.start_websocket_server()
+ port.stop_websocket_server()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/qt.py b/Tools/Scripts/webkitpy/layout_tests/port/qt.py
new file mode 100644
index 0000000..af94acc
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/qt.py
@@ -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 Google name 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.
+
+"""QtWebKit implementation of the Port interface."""
+
+import logging
+import os
+import signal
+import sys
+
+import webkit
+
+from webkitpy.layout_tests.port.webkit import WebKitPort
+
+_log = logging.getLogger("webkitpy.layout_tests.port.qt")
+
+
+class QtPort(WebKitPort):
+ """QtWebKit implementation of the Port class."""
+
+ def __init__(self, **kwargs):
+ kwargs.setdefault('port_name', 'qt')
+ WebKitPort.__init__(self, **kwargs)
+
+ def baseline_search_path(self):
+ port_names = []
+ if sys.platform == 'linux2':
+ port_names.append("qt-linux")
+ elif sys.platform in ('win32', 'cygwin'):
+ port_names.append("qt-win")
+ elif sys.platform == 'darwin':
+ port_names.append("qt-mac")
+ port_names.append("qt")
+ return map(self._webkit_baseline_path, port_names)
+
+ def _tests_for_other_platforms(self):
+ # FIXME: This list could be dynamic based on platform name and
+ # pushed into base.Port.
+ # This really need to be automated.
+ return [
+ "platform/chromium",
+ "platform/win",
+ "platform/gtk",
+ "platform/mac",
+ ]
+
+ def _path_to_apache_config_file(self):
+ # FIXME: This needs to detect the distribution and change config files.
+ return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ 'apache2-debian-httpd.conf')
+
+ def _shut_down_http_server(self, server_pid):
+ """Shut down the httpd web server. Blocks until it's fully
+ shut down.
+
+ Args:
+ server_pid: The process ID of the running server.
+ """
+ # server_pid is not set when "http_server.py stop" is run manually.
+ if server_pid is None:
+ # FIXME: This isn't ideal, since it could conflict with
+ # lighttpd processes not started by http_server.py,
+ # but good enough for now.
+ self._executive.kill_all('apache2')
+ else:
+ try:
+ os.kill(server_pid, signal.SIGTERM)
+ # TODO(mmoss) Maybe throw in a SIGKILL just to be sure?
+ except OSError:
+ # Sometimes we get a bad PID (e.g. from a stale httpd.pid
+ # file), so if kill fails on the given PID, just try to
+ # 'killall' web servers.
+ self._shut_down_http_server(None)
+
+ def _build_driver(self):
+ # The Qt port builds DRT as part of the main build step
+ return True
+
+ def _path_to_driver(self):
+ return self._build_path('bin/DumpRenderTree')
+
+ def _path_to_image_diff(self):
+ return self._build_path('bin/ImageDiff')
+
+ def _path_to_webcore_library(self):
+ return self._build_path('lib/libQtWebKit.so')
+
+ def _runtime_feature_list(self):
+ return None
+
+ def setup_environ_for_server(self):
+ env = webkit.WebKitPort.setup_environ_for_server(self)
+ env['QTWEBKIT_PLUGIN_PATH'] = self._build_path('lib/plugins')
+ return env
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/server_process.py b/Tools/Scripts/webkitpy/layout_tests/port/server_process.py
new file mode 100644
index 0000000..5a0a40c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/server_process.py
@@ -0,0 +1,225 @@
+#!/usr/bin/env python
+# 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 Google name 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.
+
+"""Package that implements the ServerProcess wrapper class"""
+
+import logging
+import os
+import select
+import signal
+import subprocess
+import sys
+import time
+if sys.platform != 'win32':
+ import fcntl
+
+from webkitpy.common.system.executive import Executive
+
+_log = logging.getLogger("webkitpy.layout_tests.port.server_process")
+
+
+class ServerProcess:
+ """This class provides a wrapper around a subprocess that
+ implements a simple request/response usage model. The primary benefit
+ is that reading responses takes a timeout, so that we don't ever block
+ indefinitely. The class also handles transparently restarting processes
+ as necessary to keep issuing commands."""
+
+ def __init__(self, port_obj, name, cmd, env=None, executive=Executive()):
+ self._port = port_obj
+ self._name = name
+ self._cmd = cmd
+ self._env = env
+ self._reset()
+ self._executive = executive
+
+ def _reset(self):
+ self._proc = None
+ self._output = ''
+ self.crashed = False
+ self.timed_out = False
+ self.error = ''
+
+ def _start(self):
+ if self._proc:
+ raise ValueError("%s already running" % self._name)
+ self._reset()
+ # close_fds is a workaround for http://bugs.python.org/issue2320
+ close_fds = sys.platform not in ('win32', 'cygwin')
+ self._proc = subprocess.Popen(self._cmd, stdin=subprocess.PIPE,
+ stdout=subprocess.PIPE,
+ stderr=subprocess.PIPE,
+ close_fds=close_fds,
+ env=self._env)
+ fd = self._proc.stdout.fileno()
+ fl = fcntl.fcntl(fd, fcntl.F_GETFL)
+ fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+ fd = self._proc.stderr.fileno()
+ fl = fcntl.fcntl(fd, fcntl.F_GETFL)
+ fcntl.fcntl(fd, fcntl.F_SETFL, fl | os.O_NONBLOCK)
+
+ def handle_interrupt(self):
+ """This routine checks to see if the process crashed or exited
+ because of a keyboard interrupt and raises KeyboardInterrupt
+ accordingly."""
+ if self.crashed:
+ # This is hex code 0xc000001d, which is used for abrupt
+ # termination. This happens if we hit ctrl+c from the prompt
+ # and we happen to be waiting on the DumpRenderTree.
+ # sdoyon: Not sure for which OS and in what circumstances the
+ # above code is valid. What works for me under Linux to detect
+ # ctrl+c is for the subprocess returncode to be negative
+ # SIGINT. And that agrees with the subprocess documentation.
+ if (-1073741510 == self._proc.returncode or
+ - signal.SIGINT == self._proc.returncode):
+ raise KeyboardInterrupt
+ return
+
+ def poll(self):
+ """Check to see if the underlying process is running; returns None
+ if it still is (wrapper around subprocess.poll)."""
+ if self._proc:
+ # poll() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ return self._proc.poll()
+ return None
+
+ def write(self, input):
+ """Write a request to the subprocess. The subprocess is (re-)start()'ed
+ if is not already running."""
+ if not self._proc:
+ self._start()
+ self._proc.stdin.write(input)
+
+ def read_line(self, timeout):
+ """Read a single line from the subprocess, waiting until the deadline.
+ If the deadline passes, the call times out. Note that even if the
+ subprocess has crashed or the deadline has passed, if there is output
+ pending, it will be returned.
+
+ Args:
+ timeout: floating-point number of seconds the call is allowed
+ to block for. A zero or negative number will attempt to read
+ any existing data, but will not block. There is no way to
+ block indefinitely.
+ Returns:
+ output: data returned, if any. If no data is available and the
+ call times out or crashes, an empty string is returned. Note
+ that the returned string includes the newline ('\n')."""
+ return self._read(timeout, size=0)
+
+ def read(self, timeout, size):
+ """Attempts to read size characters from the subprocess, waiting until
+ the deadline passes. If the deadline passes, any available data will be
+ returned. Note that even if the deadline has passed or if the
+ subprocess has crashed, any available data will still be returned.
+
+ Args:
+ timeout: floating-point number of seconds the call is allowed
+ to block for. A zero or negative number will attempt to read
+ any existing data, but will not block. There is no way to
+ block indefinitely.
+ size: amount of data to read. Must be a postive integer.
+ Returns:
+ output: data returned, if any. If no data is available, an empty
+ string is returned.
+ """
+ if size <= 0:
+ raise ValueError('ServerProcess.read() called with a '
+ 'non-positive size: %d ' % size)
+ return self._read(timeout, size)
+
+ def _read(self, timeout, size):
+ """Internal routine that actually does the read."""
+ index = -1
+ out_fd = self._proc.stdout.fileno()
+ err_fd = self._proc.stderr.fileno()
+ select_fds = (out_fd, err_fd)
+ deadline = time.time() + timeout
+ while not self.timed_out and not self.crashed:
+ # poll() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ if self._proc.poll() != None:
+ self.crashed = True
+ self.handle_interrupt()
+
+ now = time.time()
+ if now > deadline:
+ self.timed_out = True
+
+ # Check to see if we have any output we can return.
+ if size and len(self._output) >= size:
+ index = size
+ elif size == 0:
+ index = self._output.find('\n') + 1
+
+ if index > 0 or self.crashed or self.timed_out:
+ output = self._output[0:index]
+ self._output = self._output[index:]
+ return output
+
+ # Nope - wait for more data.
+ (read_fds, write_fds, err_fds) = select.select(select_fds, [],
+ select_fds,
+ deadline - now)
+ try:
+ if out_fd in read_fds:
+ self._output += self._proc.stdout.read()
+ if err_fd in read_fds:
+ self.error += self._proc.stderr.read()
+ except IOError, e:
+ pass
+
+ def stop(self):
+ """Stop (shut down) the subprocess), if it is running."""
+ pid = self._proc.pid
+ self._proc.stdin.close()
+ self._proc.stdout.close()
+ if self._proc.stderr:
+ self._proc.stderr.close()
+ if sys.platform not in ('win32', 'cygwin'):
+ # Closing stdin/stdout/stderr hangs sometimes on OS X,
+ # (see restart(), above), and anyway we don't want to hang
+ # the harness if DumpRenderTree is buggy, so we wait a couple
+ # seconds to give DumpRenderTree a chance to clean up, but then
+ # force-kill the process if necessary.
+ KILL_TIMEOUT = 3.0
+ timeout = time.time() + KILL_TIMEOUT
+ # poll() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ while self._proc.poll() is None and time.time() < timeout:
+ time.sleep(0.1)
+ # poll() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ if self._proc.poll() is None:
+ _log.warning('stopping %s timed out, killing it' %
+ self._name)
+ self._executive.kill_process(self._proc.pid)
+ _log.warning('killed')
+ self._reset()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test.py b/Tools/Scripts/webkitpy/layout_tests/port/test.py
new file mode 100644
index 0000000..935881c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/test.py
@@ -0,0 +1,343 @@
+#!/usr/bin/env python
+# 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 Google name 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.
+
+"""Dummy Port implementation used for testing."""
+from __future__ import with_statement
+
+import codecs
+import fnmatch
+import os
+import sys
+import time
+
+from webkitpy.layout_tests.layout_package import test_output
+
+import base
+
+
+# This sets basic expectations for a test. Each individual expectation
+# can be overridden by a keyword argument in TestList.add().
+class TestInstance:
+ def __init__(self, name):
+ self.name = name
+ self.base = name[(name.rfind("/") + 1):name.rfind(".html")]
+ self.crash = False
+ self.exception = False
+ self.hang = False
+ self.keyboard = False
+ self.error = ''
+ self.timeout = False
+ self.actual_text = self.base + '-txt\n'
+ self.actual_checksum = self.base + '-checksum\n'
+ self.actual_image = self.base + '-png\n'
+ self.expected_text = self.actual_text
+ self.expected_checksum = self.actual_checksum
+ self.expected_image = self.actual_image
+
+
+# This is an in-memory list of tests, what we want them to produce, and
+# what we want to claim are the expected results.
+class TestList:
+ def __init__(self, port):
+ self.port = port
+ self.tests = {}
+
+ def add(self, name, **kwargs):
+ test = TestInstance(name)
+ for key, value in kwargs.items():
+ test.__dict__[key] = value
+ self.tests[name] = test
+
+ def keys(self):
+ return self.tests.keys()
+
+ def __contains__(self, item):
+ return item in self.tests
+
+ def __getitem__(self, item):
+ return self.tests[item]
+
+
+class TestPort(base.Port):
+ """Test implementation of the Port interface."""
+
+ def __init__(self, **kwargs):
+ base.Port.__init__(self, **kwargs)
+ tests = TestList(self)
+ tests.add('failures/expected/checksum.html',
+ actual_checksum='checksum_fail-checksum')
+ tests.add('failures/expected/crash.html', crash=True)
+ tests.add('failures/expected/exception.html', exception=True)
+ tests.add('failures/expected/timeout.html', timeout=True)
+ tests.add('failures/expected/hang.html', hang=True)
+ tests.add('failures/expected/missing_text.html',
+ expected_text=None)
+ tests.add('failures/expected/image.html',
+ actual_image='image_fail-png',
+ expected_image='image-png')
+ tests.add('failures/expected/image_checksum.html',
+ actual_checksum='image_checksum_fail-checksum',
+ actual_image='image_checksum_fail-png')
+ tests.add('failures/expected/keyboard.html',
+ keyboard=True)
+ tests.add('failures/expected/missing_check.html',
+ expected_checksum=None)
+ tests.add('failures/expected/missing_image.html',
+ expected_image=None)
+ tests.add('failures/expected/missing_text.html',
+ expected_text=None)
+ tests.add('failures/expected/newlines_leading.html',
+ expected_text="\nfoo\n",
+ actual_text="foo\n")
+ tests.add('failures/expected/newlines_trailing.html',
+ expected_text="foo\n\n",
+ actual_text="foo\n")
+ tests.add('failures/expected/newlines_with_excess_CR.html',
+ expected_text="foo\r\r\r\n",
+ actual_text="foo\n")
+ tests.add('failures/expected/text.html',
+ actual_text='text_fail-png')
+ tests.add('failures/unexpected/crash.html', crash=True)
+ tests.add('failures/unexpected/text-image-checksum.html',
+ actual_text='text-image-checksum_fail-txt',
+ actual_checksum='text-image-checksum_fail-checksum')
+ tests.add('failures/unexpected/timeout.html', timeout=True)
+ tests.add('http/tests/passes/text.html')
+ tests.add('http/tests/ssl/text.html')
+ tests.add('passes/error.html', error='stuff going to stderr')
+ tests.add('passes/image.html')
+ tests.add('passes/platform_image.html')
+ # Text output files contain "\r\n" on Windows. This may be
+ # helpfully filtered to "\r\r\n" by our Python/Cygwin tooling.
+ tests.add('passes/text.html',
+ expected_text='\nfoo\n\n',
+ actual_text='\nfoo\r\n\r\r\n')
+ tests.add('websocket/tests/passes/text.html')
+ self._tests = tests
+
+ def baseline_path(self):
+ return os.path.join(self.layout_tests_dir(), 'platform',
+ self.name() + self.version())
+
+ def baseline_search_path(self):
+ return [self.baseline_path()]
+
+ def check_build(self, needs_http):
+ return True
+
+ def diff_image(self, expected_contents, actual_contents,
+ diff_filename=None):
+ diffed = actual_contents != expected_contents
+ if diffed and diff_filename:
+ with codecs.open(diff_filename, "w", "utf-8") as diff_fh:
+ diff_fh.write("< %s\n---\n> %s\n" %
+ (expected_contents, actual_contents))
+ return diffed
+
+ def expected_checksum(self, test):
+ test = self.relative_test_filename(test)
+ return self._tests[test].expected_checksum
+
+ def expected_image(self, test):
+ test = self.relative_test_filename(test)
+ return self._tests[test].expected_image
+
+ def expected_text(self, test):
+ test = self.relative_test_filename(test)
+ text = self._tests[test].expected_text
+ if not text:
+ text = ''
+ return text
+
+ def tests(self, paths):
+ # Test the idea of port-specific overrides for test lists. Also
+ # keep in memory to speed up the test harness.
+ if not paths:
+ paths = ['*']
+
+ matched_tests = []
+ for p in paths:
+ if self.path_isdir(p):
+ matched_tests.extend(fnmatch.filter(self._tests.keys(), p + '*'))
+ else:
+ matched_tests.extend(fnmatch.filter(self._tests.keys(), p))
+ layout_tests_dir = self.layout_tests_dir()
+ return set([os.path.join(layout_tests_dir, p) for p in matched_tests])
+
+ def path_exists(self, path):
+ # used by test_expectations.py and printing.py
+ rpath = self.relative_test_filename(path)
+ if rpath in self._tests:
+ return True
+ if self.path_isdir(rpath):
+ return True
+ if rpath.endswith('-expected.txt'):
+ test = rpath.replace('-expected.txt', '.html')
+ return (test in self._tests and
+ self._tests[test].expected_text)
+ if rpath.endswith('-expected.checksum'):
+ test = rpath.replace('-expected.checksum', '.html')
+ return (test in self._tests and
+ self._tests[test].expected_checksum)
+ if rpath.endswith('-expected.png'):
+ test = rpath.replace('-expected.png', '.html')
+ return (test in self._tests and
+ self._tests[test].expected_image)
+ return False
+
+ def layout_tests_dir(self):
+ return self.path_from_webkit_base('Tools', 'Scripts',
+ 'webkitpy', 'layout_tests', 'data')
+
+ def path_isdir(self, path):
+ # Used by test_expectations.py
+ #
+ # We assume that a path is a directory if we have any tests
+ # that whose prefix matches the path plus a directory modifier
+ # and not a file extension.
+ if path[-1] != '/':
+ path += '/'
+
+ # FIXME: Directories can have a dot in the name. We should
+ # probably maintain a white list of known cases like CSS2.1
+ # and check it here in the future.
+ if path.find('.') != -1:
+ # extension separator found, assume this is a file
+ return False
+
+ # strip out layout tests directory path if found. The tests
+ # keys are relative to it.
+ tests_dir = self.layout_tests_dir()
+ if path.startswith(tests_dir):
+ path = path[len(tests_dir) + 1:]
+
+ return any([t.startswith(path) for t in self._tests.keys()])
+
+ def test_dirs(self):
+ return ['passes', 'failures']
+
+ def name(self):
+ return self._name
+
+ def _path_to_wdiff(self):
+ return None
+
+ def results_directory(self):
+ return '/tmp/' + self.get_option('results_directory')
+
+ def setup_test_run(self):
+ pass
+
+ def create_driver(self, worker_number):
+ return TestDriver(self, worker_number)
+
+ def start_http_server(self):
+ pass
+
+ def start_websocket_server(self):
+ pass
+
+ def stop_http_server(self):
+ pass
+
+ def stop_websocket_server(self):
+ pass
+
+ def test_expectations(self):
+ """Returns the test expectations for this port.
+
+ Basically this string should contain the equivalent of a
+ test_expectations file. See test_expectations.py for more details."""
+ return """
+WONTFIX : failures/expected/checksum.html = IMAGE
+WONTFIX : failures/expected/crash.html = CRASH
+// This one actually passes because the checksums will match.
+WONTFIX : failures/expected/image.html = PASS
+WONTFIX : failures/expected/image_checksum.html = IMAGE
+WONTFIX : failures/expected/missing_check.html = MISSING PASS
+WONTFIX : failures/expected/missing_image.html = MISSING PASS
+WONTFIX : failures/expected/missing_text.html = MISSING PASS
+WONTFIX : failures/expected/newlines_leading.html = TEXT
+WONTFIX : failures/expected/newlines_trailing.html = TEXT
+WONTFIX : failures/expected/newlines_with_excess_CR.html = TEXT
+WONTFIX : failures/expected/text.html = TEXT
+WONTFIX : failures/expected/timeout.html = TIMEOUT
+WONTFIX SKIP : failures/expected/hang.html = TIMEOUT
+WONTFIX SKIP : failures/expected/keyboard.html = CRASH
+WONTFIX SKIP : failures/expected/exception.html = CRASH
+"""
+
+ def test_base_platform_names(self):
+ return ('mac', 'win')
+
+ def test_platform_name(self):
+ return 'mac'
+
+ def test_platform_names(self):
+ return self.test_base_platform_names()
+
+ def test_platform_name_to_name(self, test_platform_name):
+ return test_platform_name
+
+ def version(self):
+ return ''
+
+
+class TestDriver(base.Driver):
+ """Test/Dummy implementation of the DumpRenderTree interface."""
+
+ def __init__(self, port, worker_number):
+ self._port = port
+
+ def cmd_line(self):
+ return ['None']
+
+ def poll(self):
+ return True
+
+ def run_test(self, test_input):
+ start_time = time.time()
+ test_name = self._port.relative_test_filename(test_input.filename)
+ test = self._port._tests[test_name]
+ if test.keyboard:
+ raise KeyboardInterrupt
+ if test.exception:
+ raise ValueError('exception from ' + test_name)
+ if test.hang:
+ time.sleep((float(test_input.timeout) * 4) / 1000.0)
+ return test_output.TestOutput(test.actual_text, test.actual_image,
+ test.actual_checksum, test.crash,
+ time.time() - start_time, test.timeout,
+ test.error)
+
+ def start(self):
+ pass
+
+ def stop(self):
+ pass
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test_files.py b/Tools/Scripts/webkitpy/layout_tests/port/test_files.py
new file mode 100644
index 0000000..2c0a7b6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/test_files.py
@@ -0,0 +1,128 @@
+#!/usr/bin/env python
+# 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 module is used to find all of the layout test files used by
+run-webkit-tests. It exposes one public function - find() -
+which takes an optional list of paths. If a list is passed in, the returned
+list of test files is constrained to those found under the paths passed in,
+i.e. calling find(["LayoutTests/fast"]) will only return files
+under that directory."""
+
+import glob
+import os
+import time
+
+from webkitpy.common.system import logutils
+
+
+_log = logutils.get_logger(__file__)
+
+
+# When collecting test cases, we include any file with these extensions.
+_supported_file_extensions = set(['.html', '.shtml', '.xml', '.xhtml', '.xhtmlmp', '.pl',
+ '.php', '.svg'])
+# When collecting test cases, skip these directories
+_skipped_directories = set(['.svn', '_svn', 'resources', 'script-tests'])
+
+
+def find(port, paths):
+ """Finds the set of tests under port.layout_tests_dir().
+
+ Args:
+ paths: a list of command line paths relative to the layout_tests_dir()
+ to limit the search to. glob patterns are ok.
+ """
+ gather_start_time = time.time()
+ paths_to_walk = set()
+ # if paths is empty, provide a pre-defined list.
+ if paths:
+ _log.debug("Gathering tests from: %s relative to %s" % (paths, port.layout_tests_dir()))
+ for path in paths:
+ # If there's an * in the name, assume it's a glob pattern.
+ path = os.path.join(port.layout_tests_dir(), path)
+ if path.find('*') > -1:
+ filenames = glob.glob(path)
+ paths_to_walk.update(filenames)
+ else:
+ paths_to_walk.add(path)
+ else:
+ _log.debug("Gathering tests from: %s" % port.layout_tests_dir())
+ paths_to_walk.add(port.layout_tests_dir())
+
+ # Now walk all the paths passed in on the command line and get filenames
+ test_files = set()
+ for path in paths_to_walk:
+ if os.path.isfile(path) and _is_test_file(path):
+ test_files.add(os.path.normpath(path))
+ continue
+
+ for root, dirs, files in os.walk(path):
+ # Don't walk skipped directories or their sub-directories.
+ if os.path.basename(root) in _skipped_directories:
+ del dirs[:]
+ continue
+ # This copy and for-in is slightly inefficient, but
+ # the extra walk avoidance consistently shaves .5 seconds
+ # off of total walk() time on my MacBook Pro.
+ for directory in dirs[:]:
+ if directory in _skipped_directories:
+ dirs.remove(directory)
+
+ for filename in files:
+ if _is_test_file(filename):
+ filename = os.path.join(root, filename)
+ filename = os.path.normpath(filename)
+ test_files.add(filename)
+
+ gather_time = time.time() - gather_start_time
+ _log.debug("Test gathering took %f seconds" % gather_time)
+
+ return test_files
+
+
+def _has_supported_extension(filename):
+ """Return true if filename is one of the file extensions we want to run a
+ test on."""
+ extension = os.path.splitext(filename)[1]
+ return extension in _supported_file_extensions
+
+
+def _is_reference_html_file(filename):
+ """Return true if the filename points to a reference HTML file."""
+ if (filename.endswith('-expected.html') or
+ filename.endswith('-expected-mismatch.html')):
+ _log.warn("Reftests are not supported - ignoring %s" % filename)
+ return True
+ return False
+
+
+def _is_test_file(filename):
+ """Return true if the filename points to a test file."""
+ return (_has_supported_extension(filename) and
+ not _is_reference_html_file(filename))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py
new file mode 100644
index 0000000..83525c8
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/test_files_unittest.py
@@ -0,0 +1,75 @@
+# 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 os
+import unittest
+
+import base
+import test_files
+
+
+class TestFilesTest(unittest.TestCase):
+ def test_find_no_paths_specified(self):
+ port = base.Port()
+ layout_tests_dir = port.layout_tests_dir()
+ port.layout_tests_dir = lambda: os.path.join(layout_tests_dir,
+ 'fast', 'html')
+ tests = test_files.find(port, [])
+ self.assertNotEqual(tests, 0)
+
+ def test_find_one_test(self):
+ port = base.Port()
+ # This is just a test picked at random but known to exist.
+ tests = test_files.find(port, ['fast/html/keygen.html'])
+ self.assertEqual(len(tests), 1)
+
+ def test_find_glob(self):
+ port = base.Port()
+ tests = test_files.find(port, ['fast/html/key*'])
+ self.assertEqual(len(tests), 1)
+
+ def test_find_with_skipped_directories(self):
+ port = base.Port()
+ tests = port.tests('userscripts')
+ self.assertTrue('userscripts/resources/frame1.html' not in tests)
+
+ def test_find_with_skipped_directories_2(self):
+ port = base.Port()
+ tests = test_files.find(port, ['userscripts/resources'])
+ self.assertEqual(tests, set([]))
+
+ def test_is_test_file(self):
+ self.assertTrue(test_files._is_test_file('foo.html'))
+ self.assertTrue(test_files._is_test_file('foo.shtml'))
+ self.assertFalse(test_files._is_test_file('foo.png'))
+ self.assertFalse(test_files._is_test_file('foo-expected.html'))
+ self.assertFalse(test_files._is_test_file('foo-expected-mismatch.html'))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py
new file mode 100644
index 0000000..afdebeb
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/webkit.py
@@ -0,0 +1,497 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2010 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>, University of Szeged
+#
+# 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 Google name 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.
+
+"""WebKit implementations of the Port interface."""
+
+
+from __future__ import with_statement
+
+import codecs
+import logging
+import os
+import re
+import shutil
+import signal
+import sys
+import time
+import webbrowser
+import operator
+import tempfile
+import shutil
+
+import webkitpy.common.system.ospath as ospath
+import webkitpy.layout_tests.layout_package.test_output as test_output
+import webkitpy.layout_tests.port.base as base
+import webkitpy.layout_tests.port.server_process as server_process
+
+_log = logging.getLogger("webkitpy.layout_tests.port.webkit")
+
+
+class WebKitPort(base.Port):
+ """WebKit implementation of the Port class."""
+
+ def __init__(self, **kwargs):
+ base.Port.__init__(self, **kwargs)
+ self._cached_apache_path = None
+
+ # FIXME: disable pixel tests until they are run by default on the
+ # build machines.
+ self.set_option_default('pixel_tests', False)
+
+ def baseline_path(self):
+ return self._webkit_baseline_path(self._name)
+
+ def baseline_search_path(self):
+ return [self._webkit_baseline_path(self._name)]
+
+ def path_to_test_expectations_file(self):
+ return os.path.join(self._webkit_baseline_path(self._name),
+ 'test_expectations.txt')
+
+ # Only needed by ports which maintain versioned test expectations (like mac-tiger vs. mac-leopard)
+ def version(self):
+ return ''
+
+ def _build_driver(self):
+ configuration = self.get_option('configuration')
+ return self._config.build_dumprendertree(configuration)
+
+ def _check_driver(self):
+ driver_path = self._path_to_driver()
+ if not os.path.exists(driver_path):
+ _log.error("DumpRenderTree was not found at %s" % driver_path)
+ return False
+ return True
+
+ def check_build(self, needs_http):
+ if self.get_option('build') and not self._build_driver():
+ return False
+ if not self._check_driver():
+ return False
+ if self.get_option('pixel_tests'):
+ if not self.check_image_diff():
+ return False
+ if not self._check_port_build():
+ return False
+ return True
+
+ def _check_port_build(self):
+ # Ports can override this method to do additional checks.
+ return True
+
+ def check_image_diff(self, override_step=None, logging=True):
+ image_diff_path = self._path_to_image_diff()
+ if not os.path.exists(image_diff_path):
+ _log.error("ImageDiff was not found at %s" % image_diff_path)
+ return False
+ return True
+
+ def diff_image(self, expected_contents, actual_contents,
+ diff_filename=None):
+ """Return True if the two files are different. Also write a delta
+ image of the two images into |diff_filename| if it is not None."""
+
+ # Handle the case where the test didn't actually generate an image.
+ if not actual_contents:
+ return True
+
+ sp = self._diff_image_request(expected_contents, actual_contents)
+ return self._diff_image_reply(sp, diff_filename)
+
+ def _diff_image_request(self, expected_contents, actual_contents):
+ # FIXME: use self.get_option('tolerance') and
+ # self.set_option_default('tolerance', 0.1) once that behaves correctly
+ # with default values.
+ if self.get_option('tolerance') is not None:
+ tolerance = self.get_option('tolerance')
+ else:
+ tolerance = 0.1
+ command = [self._path_to_image_diff(), '--tolerance', str(tolerance)]
+ sp = server_process.ServerProcess(self, 'ImageDiff', command)
+
+ sp.write('Content-Length: %d\n%sContent-Length: %d\n%s' %
+ (len(actual_contents), actual_contents,
+ len(expected_contents), expected_contents))
+
+ return sp
+
+ def _diff_image_reply(self, sp, diff_filename):
+ timeout = 2.0
+ deadline = time.time() + timeout
+ output = sp.read_line(timeout)
+ while not sp.timed_out and not sp.crashed and output:
+ if output.startswith('Content-Length'):
+ m = re.match('Content-Length: (\d+)', output)
+ content_length = int(m.group(1))
+ timeout = deadline - time.time()
+ output = sp.read(timeout, content_length)
+ break
+ elif output.startswith('diff'):
+ break
+ else:
+ timeout = deadline - time.time()
+ output = sp.read_line(deadline)
+
+ result = True
+ if output.startswith('diff'):
+ m = re.match('diff: (.+)% (passed|failed)', output)
+ if m.group(2) == 'passed':
+ result = False
+ elif output and diff_filename:
+ with open(diff_filename, 'w') as file:
+ file.write(output)
+ elif sp.timed_out:
+ _log.error("ImageDiff timed out")
+ elif sp.crashed:
+ _log.error("ImageDiff crashed")
+ sp.stop()
+ return result
+
+ def results_directory(self):
+ # Results are store relative to the built products to make it easy
+ # to have multiple copies of webkit checked out and built.
+ return self._build_path(self.get_option('results_directory'))
+
+ def setup_test_run(self):
+ # This port doesn't require any specific configuration.
+ pass
+
+ def create_driver(self, worker_number):
+ return WebKitDriver(self, worker_number)
+
+ def test_base_platform_names(self):
+ # At the moment we don't use test platform names, but we have
+ # to return something.
+ return ('mac', 'win')
+
+ def _tests_for_other_platforms(self):
+ raise NotImplementedError('WebKitPort._tests_for_other_platforms')
+ # The original run-webkit-tests builds up a "whitelist" of tests to
+ # run, and passes that to DumpRenderTree. new-run-webkit-tests assumes
+ # we run *all* tests and test_expectations.txt functions as a
+ # blacklist.
+ # FIXME: This list could be dynamic based on platform name and
+ # pushed into base.Port.
+ return [
+ "platform/chromium",
+ "platform/gtk",
+ "platform/qt",
+ "platform/win",
+ ]
+
+ def _runtime_feature_list(self):
+ """Return the supported features of DRT. If a port doesn't support
+ this DRT switch, it has to override this method to return None"""
+ driver_path = self._path_to_driver()
+ feature_list = ' '.join(os.popen(driver_path + " --print-supported-features 2>&1").readlines())
+ if "SupportedFeatures:" in feature_list:
+ return feature_list
+ return None
+
+ def _supported_symbol_list(self):
+ """Return the supported symbols of WebCore."""
+ webcore_library_path = self._path_to_webcore_library()
+ if not webcore_library_path:
+ return None
+ symbol_list = ' '.join(os.popen("nm " + webcore_library_path).readlines())
+ return symbol_list
+
+ def _directories_for_features(self):
+ """Return the supported feature dictionary. The keys are the
+ features and the values are the directories in lists."""
+ directories_for_features = {
+ "Accelerated Compositing": ["compositing"],
+ "3D Rendering": ["animations/3d", "transforms/3d"],
+ }
+ return directories_for_features
+
+ def _directories_for_symbols(self):
+ """Return the supported feature dictionary. The keys are the
+ symbols and the values are the directories in lists."""
+ directories_for_symbol = {
+ "MathMLElement": ["mathml"],
+ "GraphicsLayer": ["compositing"],
+ "WebCoreHas3DRendering": ["animations/3d", "transforms/3d"],
+ "WebGLShader": ["fast/canvas/webgl", "compositing/webgl", "http/tests/canvas/webgl"],
+ "WMLElement": ["http/tests/wml", "fast/wml", "wml"],
+ "parseWCSSInputProperty": ["fast/wcss"],
+ "isXHTMLMPDocument": ["fast/xhtmlmp"],
+ }
+ return directories_for_symbol
+
+ def _skipped_tests_for_unsupported_features(self):
+ """Return the directories of unsupported tests. Search for the
+ symbols in the symbol_list, if found add the corresponding
+ directories to the skipped directory list."""
+ feature_list = self._runtime_feature_list()
+ directories = self._directories_for_features()
+
+ # if DRT feature detection not supported
+ if not feature_list:
+ feature_list = self._supported_symbol_list()
+ directories = self._directories_for_symbols()
+
+ if not feature_list:
+ return []
+
+ skipped_directories = [directories[feature]
+ for feature in directories.keys()
+ if feature not in feature_list]
+ return reduce(operator.add, skipped_directories)
+
+ def _tests_for_disabled_features(self):
+ # FIXME: This should use the feature detection from
+ # webkitperl/features.pm to match run-webkit-tests.
+ # For now we hard-code a list of features known to be disabled on
+ # the Mac platform.
+ disabled_feature_tests = [
+ "fast/xhtmlmp",
+ "http/tests/wml",
+ "mathml",
+ "wml",
+ ]
+ # FIXME: webarchive tests expect to read-write from
+ # -expected.webarchive files instead of .txt files.
+ # This script doesn't know how to do that yet, so pretend they're
+ # just "disabled".
+ webarchive_tests = [
+ "webarchive",
+ "svg/webarchive",
+ "http/tests/webarchive",
+ "svg/custom/image-with-prefix-in-webarchive.svg",
+ ]
+ unsupported_feature_tests = self._skipped_tests_for_unsupported_features()
+ return disabled_feature_tests + webarchive_tests + unsupported_feature_tests
+
+ def _tests_from_skipped_file(self, skipped_file):
+ tests_to_skip = []
+ for line in skipped_file.readlines():
+ line = line.strip()
+ if line.startswith('#') or not len(line):
+ continue
+ tests_to_skip.append(line)
+ return tests_to_skip
+
+ def _skipped_file_paths(self):
+ return [os.path.join(self._webkit_baseline_path(self._name),
+ 'Skipped')]
+
+ def _expectations_from_skipped_files(self):
+ tests_to_skip = []
+ for filename in self._skipped_file_paths():
+ if not os.path.exists(filename):
+ _log.warn("Failed to open Skipped file: %s" % filename)
+ continue
+ with codecs.open(filename, "r", "utf-8") as skipped_file:
+ tests_to_skip.extend(self._tests_from_skipped_file(skipped_file))
+ return tests_to_skip
+
+ def test_expectations(self):
+ # The WebKit mac port uses a combination of a test_expectations file
+ # and 'Skipped' files.
+ expectations_path = self.path_to_test_expectations_file()
+ with codecs.open(expectations_path, "r", "utf-8") as file:
+ return file.read() + self._skips()
+
+ def _skips(self):
+ # Each Skipped file contains a list of files
+ # or directories to be skipped during the test run. The total list
+ # of tests to skipped is given by the contents of the generic
+ # Skipped file found in platform/X plus a version-specific file
+ # found in platform/X-version. Duplicate entries are allowed.
+ # This routine reads those files and turns contents into the
+ # format expected by test_expectations.
+
+ tests_to_skip = self.skipped_layout_tests()
+ skip_lines = map(lambda test_path: "BUG_SKIPPED SKIP : %s = FAIL" %
+ test_path, tests_to_skip)
+ return "\n".join(skip_lines)
+
+ def skipped_layout_tests(self):
+ # Use a set to allow duplicates
+ tests_to_skip = set(self._expectations_from_skipped_files())
+ tests_to_skip.update(self._tests_for_other_platforms())
+ tests_to_skip.update(self._tests_for_disabled_features())
+ return tests_to_skip
+
+ def test_platform_name(self):
+ return self._name + self.version()
+
+ def test_platform_names(self):
+ return self.test_base_platform_names() + (
+ 'mac-tiger', 'mac-leopard', 'mac-snowleopard')
+
+ def _build_path(self, *comps):
+ return self._filesystem.join(self._config.build_directory(
+ self.get_option('configuration')), *comps)
+
+ def _path_to_driver(self):
+ return self._build_path('DumpRenderTree')
+
+ def _path_to_webcore_library(self):
+ return None
+
+ def _path_to_helper(self):
+ return None
+
+ def _path_to_image_diff(self):
+ return self._build_path('ImageDiff')
+
+ def _path_to_wdiff(self):
+ # FIXME: This does not exist on a default Mac OS X Leopard install.
+ return 'wdiff'
+
+ def _path_to_apache(self):
+ if not self._cached_apache_path:
+ # The Apache binary path can vary depending on OS and distribution
+ # See http://wiki.apache.org/httpd/DistrosDefaultLayout
+ for path in ["/usr/sbin/httpd", "/usr/sbin/apache2"]:
+ if os.path.exists(path):
+ self._cached_apache_path = path
+ break
+
+ if not self._cached_apache_path:
+ _log.error("Could not find apache. Not installed or unknown path.")
+
+ return self._cached_apache_path
+
+
+class WebKitDriver(base.Driver):
+ """WebKit implementation of the DumpRenderTree interface."""
+
+ def __init__(self, port, worker_number):
+ self._worker_number = worker_number
+ self._port = port
+ self._driver_tempdir = tempfile.mkdtemp(prefix='DumpRenderTree-')
+
+ def __del__(self):
+ shutil.rmtree(self._driver_tempdir)
+
+ def cmd_line(self):
+ cmd = self._command_wrapper(self._port.get_option('wrapper'))
+ cmd += [self._port._path_to_driver(), '-']
+
+ if self._port.get_option('pixel_tests'):
+ cmd.append('--pixel-tests')
+
+ return cmd
+
+ def start(self):
+ environment = self._port.setup_environ_for_server()
+ environment['DYLD_FRAMEWORK_PATH'] = self._port._build_path()
+ environment['DUMPRENDERTREE_TEMP'] = self._driver_tempdir
+ self._server_process = server_process.ServerProcess(self._port,
+ "DumpRenderTree", self.cmd_line(), environment)
+
+ def poll(self):
+ return self._server_process.poll()
+
+ def restart(self):
+ self._server_process.stop()
+ self._server_process.start()
+ return
+
+ # FIXME: This function is huge.
+ def run_test(self, test_input):
+ uri = self._port.filename_to_uri(test_input.filename)
+ if uri.startswith("file:///"):
+ command = uri[7:]
+ else:
+ command = uri
+
+ if test_input.image_hash:
+ command += "'" + test_input.image_hash
+ command += "\n"
+
+ start_time = time.time()
+ self._server_process.write(command)
+
+ have_seen_content_type = False
+ actual_image_hash = None
+ output = str() # Use a byte array for output, even though it should be UTF-8.
+ image = str()
+
+ timeout = int(test_input.timeout) / 1000.0
+ deadline = time.time() + timeout
+ line = self._server_process.read_line(timeout)
+ while (not self._server_process.timed_out
+ and not self._server_process.crashed
+ and line.rstrip() != "#EOF"):
+ if (line.startswith('Content-Type:') and not
+ have_seen_content_type):
+ have_seen_content_type = True
+ else:
+ # Note: Text output from DumpRenderTree is always UTF-8.
+ # However, some tests (e.g. webarchives) spit out binary
+ # data instead of text. So to make things simple, we
+ # always treat the output as binary.
+ output += line
+ line = self._server_process.read_line(timeout)
+ timeout = deadline - time.time()
+
+ # Now read a second block of text for the optional image data
+ remaining_length = -1
+ HASH_HEADER = 'ActualHash: '
+ LENGTH_HEADER = 'Content-Length: '
+ line = self._server_process.read_line(timeout)
+ while (not self._server_process.timed_out
+ and not self._server_process.crashed
+ and line.rstrip() != "#EOF"):
+ if line.startswith(HASH_HEADER):
+ actual_image_hash = line[len(HASH_HEADER):].strip()
+ elif line.startswith('Content-Type:'):
+ pass
+ elif line.startswith(LENGTH_HEADER):
+ timeout = deadline - time.time()
+ content_length = int(line[len(LENGTH_HEADER):])
+ image = self._server_process.read(timeout, content_length)
+ timeout = deadline - time.time()
+ line = self._server_process.read_line(timeout)
+
+ error_lines = self._server_process.error.splitlines()
+ # FIXME: This is a hack. It is unclear why sometimes
+ # we do not get any error lines from the server_process
+ # probably we are not flushing stderr.
+ if error_lines and error_lines[-1] == "#EOF":
+ error_lines.pop() # Remove the expected "#EOF"
+ error = "\n".join(error_lines)
+ # FIXME: This seems like the wrong section of code to be doing
+ # this reset in.
+ self._server_process.error = ""
+ return test_output.TestOutput(output, image, actual_image_hash,
+ self._server_process.crashed,
+ time.time() - start_time,
+ self._server_process.timed_out,
+ error)
+
+ def stop(self):
+ if self._server_process:
+ self._server_process.stop()
+ self._server_process = None
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py b/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py
new file mode 100644
index 0000000..7b68310
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/webkit_unittest.py
@@ -0,0 +1,68 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Gabor Rapcsanyi <rgabor@inf.u-szeged.hu>, University of Szeged
+#
+# 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 UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED 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 unittest
+
+from webkitpy.layout_tests.port.webkit import WebKitPort
+
+
+class TestWebKitPort(WebKitPort):
+ def __init__(self, symbol_list=None, feature_list=None):
+ self.symbol_list = symbol_list
+ self.feature_list = feature_list
+
+ def _runtime_feature_list(self):
+ return self.feature_list
+
+ def _supported_symbol_list(self):
+ return self.symbol_list
+
+ def _tests_for_other_platforms(self):
+ return ["media", ]
+
+ def _tests_for_disabled_features(self):
+ return ["accessibility", ]
+
+ def _skipped_file_paths(self):
+ return []
+
+class WebKitPortTest(unittest.TestCase):
+
+ def test_skipped_directories_for_symbols(self):
+ supported_symbols = ["GraphicsLayer", "WebCoreHas3DRendering", "isXHTMLMPDocument", "fooSymbol"]
+ expected_directories = set(["mathml", "fast/canvas/webgl", "compositing/webgl", "http/tests/canvas/webgl", "http/tests/wml", "fast/wml", "wml", "fast/wcss"])
+ result_directories = set(TestWebKitPort(supported_symbols, None)._skipped_tests_for_unsupported_features())
+ self.assertEqual(result_directories, expected_directories)
+
+ def test_skipped_directories_for_features(self):
+ supported_features = ["Accelerated Compositing", "Foo Feature"]
+ expected_directories = set(["animations/3d", "transforms/3d"])
+ result_directories = set(TestWebKitPort(None, supported_features)._skipped_tests_for_unsupported_features())
+ self.assertEqual(result_directories, expected_directories)
+
+ def test_skipped_layout_tests(self):
+ self.assertEqual(TestWebKitPort(None, None).skipped_layout_tests(),
+ set(["media", "accessibility"]))
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/websocket_server.py b/Tools/Scripts/webkitpy/layout_tests/port/websocket_server.py
new file mode 100644
index 0000000..926bc04
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/websocket_server.py
@@ -0,0 +1,257 @@
+#!/usr/bin/env python
+# 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.
+
+"""A class to help start/stop the PyWebSocket server used by layout tests."""
+
+
+from __future__ import with_statement
+
+import codecs
+import logging
+import optparse
+import os
+import subprocess
+import sys
+import tempfile
+import time
+import urllib
+
+import factory
+import http_server
+
+from webkitpy.common.system.executive import Executive
+from webkitpy.thirdparty.autoinstalled.pywebsocket import mod_pywebsocket
+
+
+_log = logging.getLogger("webkitpy.layout_tests.port.websocket_server")
+
+_WS_LOG_PREFIX = 'pywebsocket.ws.log-'
+_WSS_LOG_PREFIX = 'pywebsocket.wss.log-'
+
+_DEFAULT_WS_PORT = 8880
+_DEFAULT_WSS_PORT = 9323
+
+
+def url_is_alive(url):
+ """Checks to see if we get an http response from |url|.
+ We poll the url 20 times with a 0.5 second delay. If we don't
+ get a reply in that time, we give up and assume the httpd
+ didn't start properly.
+
+ Args:
+ url: The URL to check.
+ Return:
+ True if the url is alive.
+ """
+ sleep_time = 0.5
+ wait_time = 10
+ while wait_time > 0:
+ try:
+ response = urllib.urlopen(url)
+ # Server is up and responding.
+ return True
+ except IOError:
+ pass
+ # Wait for sleep_time before trying again.
+ wait_time -= sleep_time
+ time.sleep(sleep_time)
+
+ return False
+
+
+class PyWebSocketNotStarted(Exception):
+ pass
+
+
+class PyWebSocketNotFound(Exception):
+ pass
+
+
+class PyWebSocket(http_server.Lighttpd):
+
+ def __init__(self, port_obj, output_dir, port=_DEFAULT_WS_PORT,
+ root=None, use_tls=False,
+ pidfile=None):
+ """Args:
+ output_dir: the absolute path to the layout test result directory
+ """
+ http_server.Lighttpd.__init__(self, port_obj, output_dir,
+ port=_DEFAULT_WS_PORT,
+ root=root)
+ self._output_dir = output_dir
+ self._process = None
+ self._port = port
+ self._root = root
+ self._use_tls = use_tls
+ self._private_key = self._pem_file
+ self._certificate = self._pem_file
+ if self._port:
+ self._port = int(self._port)
+ if self._use_tls:
+ self._server_name = 'PyWebSocket(Secure)'
+ else:
+ self._server_name = 'PyWebSocket'
+ self._pidfile = pidfile
+ self._wsout = None
+
+ # Webkit tests
+ if self._root:
+ self._layout_tests = os.path.abspath(self._root)
+ self._web_socket_tests = os.path.abspath(
+ os.path.join(self._root, 'http', 'tests',
+ 'websocket', 'tests'))
+ else:
+ try:
+ self._layout_tests = self._port_obj.layout_tests_dir()
+ self._web_socket_tests = os.path.join(self._layout_tests,
+ 'http', 'tests', 'websocket', 'tests')
+ except:
+ self._web_socket_tests = None
+
+ def start(self):
+ if not self._web_socket_tests:
+ _log.info('No need to start %s server.' % self._server_name)
+ return
+ if self.is_running():
+ raise PyWebSocketNotStarted('%s is already running.' %
+ self._server_name)
+
+ time_str = time.strftime('%d%b%Y-%H%M%S')
+ if self._use_tls:
+ log_prefix = _WSS_LOG_PREFIX
+ else:
+ log_prefix = _WS_LOG_PREFIX
+ log_file_name = log_prefix + time_str
+
+ # Remove old log files. We only need to keep the last ones.
+ self.remove_log_files(self._output_dir, log_prefix)
+
+ error_log = os.path.join(self._output_dir, log_file_name + "-err.txt")
+
+ output_log = os.path.join(self._output_dir, log_file_name + "-out.txt")
+ self._wsout = codecs.open(output_log, "w", "utf-8")
+
+ python_interp = sys.executable
+ pywebsocket_base = os.path.join(
+ os.path.dirname(os.path.dirname(os.path.dirname(
+ os.path.abspath(__file__)))), 'thirdparty',
+ 'autoinstalled', 'pywebsocket')
+ pywebsocket_script = os.path.join(pywebsocket_base, 'mod_pywebsocket',
+ 'standalone.py')
+ start_cmd = [
+ python_interp, '-u', pywebsocket_script,
+ '--server-host', '127.0.0.1',
+ '--port', str(self._port),
+ '--document-root', os.path.join(self._layout_tests, 'http', 'tests'),
+ '--scan-dir', self._web_socket_tests,
+ '--cgi-paths', '/websocket/tests',
+ '--log-file', error_log,
+ ]
+
+ handler_map_file = os.path.join(self._web_socket_tests,
+ 'handler_map.txt')
+ if os.path.exists(handler_map_file):
+ _log.debug('Using handler_map_file: %s' % handler_map_file)
+ start_cmd.append('--websock-handlers-map-file')
+ start_cmd.append(handler_map_file)
+ else:
+ _log.warning('No handler_map_file found')
+
+ if self._use_tls:
+ start_cmd.extend(['-t', '-k', self._private_key,
+ '-c', self._certificate])
+
+ env = self._port_obj.setup_environ_for_server()
+ env['PYTHONPATH'] = (pywebsocket_base + os.path.pathsep +
+ env.get('PYTHONPATH', ''))
+
+ _log.debug('Starting %s server on %d.' % (
+ self._server_name, self._port))
+ _log.debug('cmdline: %s' % ' '.join(start_cmd))
+ # FIXME: We should direct this call through Executive for testing.
+ # Note: Not thread safe: http://bugs.python.org/issue2320
+ self._process = subprocess.Popen(start_cmd,
+ stdin=open(os.devnull, 'r'),
+ stdout=self._wsout,
+ stderr=subprocess.STDOUT,
+ env=env)
+
+ if self._use_tls:
+ url = 'https'
+ else:
+ url = 'http'
+ url = url + '://127.0.0.1:%d/' % self._port
+ if not url_is_alive(url):
+ if self._process.returncode == None:
+ # FIXME: We should use a non-static Executive for easier
+ # testing.
+ Executive().kill_process(self._process.pid)
+ with codecs.open(output_log, "r", "utf-8") as fp:
+ for line in fp:
+ _log.error(line)
+ raise PyWebSocketNotStarted(
+ 'Failed to start %s server on port %s.' %
+ (self._server_name, self._port))
+
+ # Our process terminated already
+ if self._process.returncode != None:
+ raise PyWebSocketNotStarted(
+ 'Failed to start %s server.' % self._server_name)
+ if self._pidfile:
+ with codecs.open(self._pidfile, "w", "ascii") as file:
+ file.write("%d" % self._process.pid)
+
+ def stop(self, force=False):
+ if not force and not self.is_running():
+ return
+
+ pid = None
+ if self._process:
+ pid = self._process.pid
+ elif self._pidfile:
+ with codecs.open(self._pidfile, "r", "ascii") as file:
+ pid = int(file.read().strip())
+
+ if not pid:
+ raise PyWebSocketNotFound(
+ 'Failed to find %s server pid.' % self._server_name)
+
+ _log.debug('Shutting down %s server %d.' % (self._server_name, pid))
+ # FIXME: We should use a non-static Executive for easier testing.
+ Executive().kill_process(pid)
+
+ if self._process:
+ # wait() is not threadsafe and can throw OSError due to:
+ # http://bugs.python.org/issue1731717
+ self._process.wait()
+ self._process = None
+
+ if self._wsout:
+ self._wsout.close()
+ self._wsout = None
diff --git a/Tools/Scripts/webkitpy/layout_tests/port/win.py b/Tools/Scripts/webkitpy/layout_tests/port/win.py
new file mode 100644
index 0000000..9e30155
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/port/win.py
@@ -0,0 +1,75 @@
+# 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 Google name 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.
+
+"""WebKit Win implementation of the Port interface."""
+
+import logging
+import os
+
+from webkitpy.layout_tests.port.webkit import WebKitPort
+
+_log = logging.getLogger("webkitpy.layout_tests.port.win")
+
+
+class WinPort(WebKitPort):
+ """WebKit Win implementation of the Port class."""
+
+ def __init__(self, **kwargs):
+ kwargs.setdefault('port_name', 'win')
+ WebKitPort.__init__(self, **kwargs)
+
+ def baseline_search_path(self):
+ # Based on code from old-run-webkit-tests expectedDirectoryForTest()
+ port_names = ["win", "mac-snowleopard", "mac"]
+ return map(self._webkit_baseline_path, port_names)
+
+ def _tests_for_other_platforms(self):
+ # FIXME: This list could be dynamic based on platform name and
+ # pushed into base.Port.
+ # This really need to be automated.
+ return [
+ "platform/chromium",
+ "platform/gtk",
+ "platform/qt",
+ "platform/mac",
+ ]
+
+ def _path_to_apache_config_file(self):
+ return os.path.join(self.layout_tests_dir(), 'http', 'conf',
+ 'cygwin-httpd.conf')
+
+ def _shut_down_http_server(self, server_pid):
+ """Shut down the httpd web server. Blocks until it's fully
+ shut down.
+
+ Args:
+ server_pid: The process ID of the running server.
+ """
+ # Looks like we ignore server_pid.
+ # Copy/pasted from chromium-win.
+ self._executive.kill_all("httpd.exe")
diff --git a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py
new file mode 100644
index 0000000..4d8b7c9
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests.py
@@ -0,0 +1,966 @@
+#!/usr/bin/env python
+# 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.
+
+"""Rebaselining tool that automatically produces baselines for all platforms.
+
+The script does the following for each platform specified:
+ 1. Compile a list of tests that need rebaselining.
+ 2. Download test result archive from buildbot for the platform.
+ 3. Extract baselines from the archive file for all identified files.
+ 4. Add new baselines to SVN repository.
+ 5. For each test that has been rebaselined, remove this platform option from
+ the test in test_expectation.txt. If no other platforms remain after
+ removal, delete the rebaselined test from the file.
+
+At the end, the script generates a html that compares old and new baselines.
+"""
+
+from __future__ import with_statement
+
+import codecs
+import copy
+import logging
+import optparse
+import os
+import re
+import shutil
+import subprocess
+import sys
+import tempfile
+import time
+import urllib
+import zipfile
+
+from webkitpy.common.system import path
+from webkitpy.common.system import user
+from webkitpy.common.system.executive import Executive, ScriptError
+import webkitpy.common.checkout.scm as scm
+
+import port
+from layout_package import test_expectations
+
+_log = logging.getLogger("webkitpy.layout_tests."
+ "rebaseline_chromium_webkit_tests")
+
+BASELINE_SUFFIXES = ['.txt', '.png', '.checksum']
+REBASELINE_PLATFORM_ORDER = ['mac', 'win', 'win-xp', 'win-vista', 'linux']
+ARCHIVE_DIR_NAME_DICT = {'win': 'Webkit_Win',
+ 'win-vista': 'webkit-dbg-vista',
+ 'win-xp': 'Webkit_Win',
+ 'mac': 'Webkit_Mac10_5',
+ 'linux': 'webkit-rel-linux64',
+ 'win-canary': 'webkit-rel-webkit-org',
+ 'win-vista-canary': 'webkit-dbg-vista',
+ 'win-xp-canary': 'webkit-rel-webkit-org',
+ 'mac-canary': 'webkit-rel-mac-webkit-org',
+ 'linux-canary': 'webkit-rel-linux-webkit-org'}
+
+
+def log_dashed_string(text, platform, logging_level=logging.INFO):
+ """Log text message with dashes on both sides."""
+
+ msg = text
+ if platform:
+ msg += ': ' + platform
+ if len(msg) < 78:
+ dashes = '-' * ((78 - len(msg)) / 2)
+ msg = '%s %s %s' % (dashes, msg, dashes)
+
+ if logging_level == logging.ERROR:
+ _log.error(msg)
+ elif logging_level == logging.WARNING:
+ _log.warn(msg)
+ else:
+ _log.info(msg)
+
+
+def setup_html_directory(html_directory):
+ """Setup the directory to store html results.
+
+ All html related files are stored in the "rebaseline_html" subdirectory.
+
+ Args:
+ html_directory: parent directory that stores the rebaselining results.
+ If None, a temp directory is created.
+
+ Returns:
+ the directory that stores the html related rebaselining results.
+ """
+
+ if not html_directory:
+ html_directory = tempfile.mkdtemp()
+ elif not os.path.exists(html_directory):
+ os.mkdir(html_directory)
+
+ html_directory = os.path.join(html_directory, 'rebaseline_html')
+ _log.info('Html directory: "%s"', html_directory)
+
+ if os.path.exists(html_directory):
+ shutil.rmtree(html_directory, True)
+ _log.info('Deleted file at html directory: "%s"', html_directory)
+
+ if not os.path.exists(html_directory):
+ os.mkdir(html_directory)
+ return html_directory
+
+
+def get_result_file_fullpath(html_directory, baseline_filename, platform,
+ result_type):
+ """Get full path of the baseline result file.
+
+ Args:
+ html_directory: directory that stores the html related files.
+ baseline_filename: name of the baseline file.
+ platform: win, linux or mac
+ result_type: type of the baseline result: '.txt', '.png'.
+
+ Returns:
+ Full path of the baseline file for rebaselining result comparison.
+ """
+
+ base, ext = os.path.splitext(baseline_filename)
+ result_filename = '%s-%s-%s%s' % (base, platform, result_type, ext)
+ fullpath = os.path.join(html_directory, result_filename)
+ _log.debug(' Result file full path: "%s".', fullpath)
+ return fullpath
+
+
+class Rebaseliner(object):
+ """Class to produce new baselines for a given platform."""
+
+ REVISION_REGEX = r'<a href=\"(\d+)/\">'
+
+ def __init__(self, running_port, target_port, platform, options):
+ """
+ Args:
+ running_port: the Port the script is running on.
+ target_port: the Port the script uses to find port-specific
+ configuration information like the test_expectations.txt
+ file location and the list of test platforms.
+ platform: the test platform to rebaseline
+ options: the command-line options object."""
+ self._platform = platform
+ self._options = options
+ self._port = running_port
+ self._target_port = target_port
+ self._rebaseline_port = port.get(
+ self._target_port.test_platform_name_to_name(platform), options)
+ self._rebaselining_tests = []
+ self._rebaselined_tests = []
+
+ # Create tests and expectations helper which is used to:
+ # -. compile list of tests that need rebaselining.
+ # -. update the tests in test_expectations file after rebaseline
+ # is done.
+ expectations_str = self._rebaseline_port.test_expectations()
+ self._test_expectations = \
+ test_expectations.TestExpectations(self._rebaseline_port,
+ None,
+ expectations_str,
+ self._platform,
+ False,
+ False)
+ self._scm = scm.default_scm()
+
+ def run(self, backup):
+ """Run rebaseline process."""
+
+ log_dashed_string('Compiling rebaselining tests', self._platform)
+ if not self._compile_rebaselining_tests():
+ return True
+
+ log_dashed_string('Downloading archive', self._platform)
+ archive_file = self._download_buildbot_archive()
+ _log.info('')
+ if not archive_file:
+ _log.error('No archive found.')
+ return False
+
+ log_dashed_string('Extracting and adding new baselines',
+ self._platform)
+ if not self._extract_and_add_new_baselines(archive_file):
+ return False
+
+ log_dashed_string('Updating rebaselined tests in file',
+ self._platform)
+ self._update_rebaselined_tests_in_file(backup)
+ _log.info('')
+
+ if len(self._rebaselining_tests) != len(self._rebaselined_tests):
+ _log.warning('NOT ALL TESTS THAT NEED REBASELINING HAVE BEEN '
+ 'REBASELINED.')
+ _log.warning(' Total tests needing rebaselining: %d',
+ len(self._rebaselining_tests))
+ _log.warning(' Total tests rebaselined: %d',
+ len(self._rebaselined_tests))
+ return False
+
+ _log.warning('All tests needing rebaselining were successfully '
+ 'rebaselined.')
+
+ return True
+
+ def get_rebaselining_tests(self):
+ return self._rebaselining_tests
+
+ def _compile_rebaselining_tests(self):
+ """Compile list of tests that need rebaselining for the platform.
+
+ Returns:
+ List of tests that need rebaselining or
+ None if there is no such test.
+ """
+
+ self._rebaselining_tests = \
+ self._test_expectations.get_rebaselining_failures()
+ if not self._rebaselining_tests:
+ _log.warn('No tests found that need rebaselining.')
+ return None
+
+ _log.info('Total number of tests needing rebaselining '
+ 'for "%s": "%d"', self._platform,
+ len(self._rebaselining_tests))
+
+ test_no = 1
+ for test in self._rebaselining_tests:
+ _log.info(' %d: %s', test_no, test)
+ test_no += 1
+
+ return self._rebaselining_tests
+
+ def _get_latest_revision(self, url):
+ """Get the latest layout test revision number from buildbot.
+
+ Args:
+ url: Url to retrieve layout test revision numbers.
+
+ Returns:
+ latest revision or
+ None on failure.
+ """
+
+ _log.debug('Url to retrieve revision: "%s"', url)
+
+ f = urllib.urlopen(url)
+ content = f.read()
+ f.close()
+
+ revisions = re.findall(self.REVISION_REGEX, content)
+ if not revisions:
+ _log.error('Failed to find revision, content: "%s"', content)
+ return None
+
+ revisions.sort(key=int)
+ _log.info('Latest revision: "%s"', revisions[len(revisions) - 1])
+ return revisions[len(revisions) - 1]
+
+ def _get_archive_dir_name(self, platform, webkit_canary):
+ """Get name of the layout test archive directory.
+
+ Returns:
+ Directory name or
+ None on failure
+ """
+
+ if webkit_canary:
+ platform += '-canary'
+
+ if platform in ARCHIVE_DIR_NAME_DICT:
+ return ARCHIVE_DIR_NAME_DICT[platform]
+ else:
+ _log.error('Cannot find platform key %s in archive '
+ 'directory name dictionary', platform)
+ return None
+
+ def _get_archive_url(self):
+ """Generate the url to download latest layout test archive.
+
+ Returns:
+ Url to download archive or
+ None on failure
+ """
+
+ if self._options.force_archive_url:
+ return self._options.force_archive_url
+
+ dir_name = self._get_archive_dir_name(self._platform,
+ self._options.webkit_canary)
+ if not dir_name:
+ return None
+
+ _log.debug('Buildbot platform dir name: "%s"', dir_name)
+
+ url_base = '%s/%s/' % (self._options.archive_url, dir_name)
+ latest_revision = self._get_latest_revision(url_base)
+ if latest_revision is None or latest_revision <= 0:
+ return None
+ archive_url = ('%s%s/layout-test-results.zip' % (url_base,
+ latest_revision))
+ _log.info('Archive url: "%s"', archive_url)
+ return archive_url
+
+ def _download_buildbot_archive(self):
+ """Download layout test archive file from buildbot.
+
+ Returns:
+ True if download succeeded or
+ False otherwise.
+ """
+
+ url = self._get_archive_url()
+ if url is None:
+ return None
+
+ fn = urllib.urlretrieve(url)[0]
+ _log.info('Archive downloaded and saved to file: "%s"', fn)
+ return fn
+
+ def _extract_and_add_new_baselines(self, archive_file):
+ """Extract new baselines from archive and add them to SVN repository.
+
+ Args:
+ archive_file: full path to the archive file.
+
+ Returns:
+ List of tests that have been rebaselined or
+ None on failure.
+ """
+
+ zip_file = zipfile.ZipFile(archive_file, 'r')
+ zip_namelist = zip_file.namelist()
+
+ _log.debug('zip file namelist:')
+ for name in zip_namelist:
+ _log.debug(' ' + name)
+
+ platform = self._rebaseline_port.test_platform_name_to_name(
+ self._platform)
+ _log.debug('Platform dir: "%s"', platform)
+
+ test_no = 1
+ self._rebaselined_tests = []
+ for test in self._rebaselining_tests:
+ _log.info('Test %d: %s', test_no, test)
+
+ found = False
+ scm_error = False
+ test_basename = os.path.splitext(test)[0]
+ for suffix in BASELINE_SUFFIXES:
+ archive_test_name = ('layout-test-results/%s-actual%s' %
+ (test_basename, suffix))
+ _log.debug(' Archive test file name: "%s"',
+ archive_test_name)
+ if not archive_test_name in zip_namelist:
+ _log.info(' %s file not in archive.', suffix)
+ continue
+
+ found = True
+ _log.info(' %s file found in archive.', suffix)
+
+ # Extract new baseline from archive and save it to a temp file.
+ data = zip_file.read(archive_test_name)
+ temp_fd, temp_name = tempfile.mkstemp(suffix)
+ f = os.fdopen(temp_fd, 'wb')
+ f.write(data)
+ f.close()
+
+ expected_filename = '%s-expected%s' % (test_basename, suffix)
+ expected_fullpath = os.path.join(
+ self._rebaseline_port.baseline_path(), expected_filename)
+ expected_fullpath = os.path.normpath(expected_fullpath)
+ _log.debug(' Expected file full path: "%s"',
+ expected_fullpath)
+
+ # TODO(victorw): for now, the rebaselining tool checks whether
+ # or not THIS baseline is duplicate and should be skipped.
+ # We could improve the tool to check all baselines in upper
+ # and lower
+ # levels and remove all duplicated baselines.
+ if self._is_dup_baseline(temp_name,
+ expected_fullpath,
+ test,
+ suffix,
+ self._platform):
+ os.remove(temp_name)
+ self._delete_baseline(expected_fullpath)
+ continue
+
+ # Create the new baseline directory if it doesn't already
+ # exist.
+ self._port.maybe_make_directory(
+ os.path.dirname(expected_fullpath))
+
+ shutil.move(temp_name, expected_fullpath)
+
+ if 0 != self._scm.add(expected_fullpath, return_exit_code=True):
+ # FIXME: print detailed diagnose messages
+ scm_error = True
+ elif suffix != '.checksum':
+ self._create_html_baseline_files(expected_fullpath)
+
+ if not found:
+ _log.warn(' No new baselines found in archive.')
+ else:
+ if scm_error:
+ _log.warn(' Failed to add baselines to your repository.')
+ else:
+ _log.info(' Rebaseline succeeded.')
+ self._rebaselined_tests.append(test)
+
+ test_no += 1
+
+ zip_file.close()
+ os.remove(archive_file)
+
+ return self._rebaselined_tests
+
+ def _is_dup_baseline(self, new_baseline, baseline_path, test, suffix,
+ platform):
+ """Check whether a baseline is duplicate and can fallback to same
+ baseline for another platform. For example, if a test has same
+ baseline on linux and windows, then we only store windows
+ baseline and linux baseline will fallback to the windows version.
+
+ Args:
+ expected_filename: baseline expectation file name.
+ test: test name.
+ suffix: file suffix of the expected results, including dot;
+ e.g. '.txt' or '.png'.
+ platform: baseline platform 'mac', 'win' or 'linux'.
+
+ Returns:
+ True if the baseline is unnecessary.
+ False otherwise.
+ """
+ test_filepath = os.path.join(self._target_port.layout_tests_dir(),
+ test)
+ all_baselines = self._rebaseline_port.expected_baselines(
+ test_filepath, suffix, True)
+ for (fallback_dir, fallback_file) in all_baselines:
+ if fallback_dir and fallback_file:
+ fallback_fullpath = os.path.normpath(
+ os.path.join(fallback_dir, fallback_file))
+ if fallback_fullpath.lower() != baseline_path.lower():
+ with codecs.open(new_baseline, "r",
+ None) as file_handle1:
+ new_output = file_handle1.read()
+ with codecs.open(fallback_fullpath, "r",
+ None) as file_handle2:
+ fallback_output = file_handle2.read()
+ is_image = baseline_path.lower().endswith('.png')
+ if not self._diff_baselines(new_output, fallback_output,
+ is_image):
+ _log.info(' Found same baseline at %s',
+ fallback_fullpath)
+ return True
+ else:
+ return False
+
+ return False
+
+ def _diff_baselines(self, output1, output2, is_image):
+ """Check whether two baselines are different.
+
+ Args:
+ output1, output2: contents of the baselines to compare.
+
+ Returns:
+ True if two files are different or have different extensions.
+ False otherwise.
+ """
+
+ if is_image:
+ return self._port.diff_image(output1, output2, None)
+ else:
+ return self._port.compare_text(output1, output2)
+
+ def _delete_baseline(self, filename):
+ """Remove the file from repository and delete it from disk.
+
+ Args:
+ filename: full path of the file to delete.
+ """
+
+ if not filename or not os.path.isfile(filename):
+ return
+ self._scm.delete(filename)
+
+ def _update_rebaselined_tests_in_file(self, backup):
+ """Update the rebaselined tests in test expectations file.
+
+ Args:
+ backup: if True, backup the original test expectations file.
+
+ Returns:
+ no
+ """
+
+ if self._rebaselined_tests:
+ new_expectations = (
+ self._test_expectations.remove_platform_from_expectations(
+ self._rebaselined_tests, self._platform))
+ path = self._target_port.path_to_test_expectations_file()
+ if backup:
+ date_suffix = time.strftime('%Y%m%d%H%M%S',
+ time.localtime(time.time()))
+ backup_file = ('%s.orig.%s' % (path, date_suffix))
+ if os.path.exists(backup_file):
+ os.remove(backup_file)
+ _log.info('Saving original file to "%s"', backup_file)
+ os.rename(path, backup_file)
+ # FIXME: What encoding are these files?
+ # Or is new_expectations always a byte array?
+ with open(path, "w") as file:
+ file.write(new_expectations)
+ # self._scm.add(path)
+ else:
+ _log.info('No test was rebaselined so nothing to remove.')
+
+ def _create_html_baseline_files(self, baseline_fullpath):
+ """Create baseline files (old, new and diff) in html directory.
+
+ The files are used to compare the rebaselining results.
+
+ Args:
+ baseline_fullpath: full path of the expected baseline file.
+ """
+
+ if not baseline_fullpath or not os.path.exists(baseline_fullpath):
+ return
+
+ # Copy the new baseline to html directory for result comparison.
+ baseline_filename = os.path.basename(baseline_fullpath)
+ new_file = get_result_file_fullpath(self._options.html_directory,
+ baseline_filename, self._platform,
+ 'new')
+ shutil.copyfile(baseline_fullpath, new_file)
+ _log.info(' Html: copied new baseline file from "%s" to "%s".',
+ baseline_fullpath, new_file)
+
+ # Get the old baseline from the repository and save to the html directory.
+ try:
+ output = self._scm.show_head(baseline_fullpath)
+ except ScriptError, e:
+ _log.info(e)
+ output = ""
+
+ if (not output) or (output.upper().rstrip().endswith(
+ 'NO SUCH FILE OR DIRECTORY')):
+ _log.info(' No base file: "%s"', baseline_fullpath)
+ return
+ base_file = get_result_file_fullpath(self._options.html_directory,
+ baseline_filename, self._platform,
+ 'old')
+ # We should be using an explicit encoding here.
+ with open(base_file, "wb") as file:
+ file.write(output)
+ _log.info(' Html: created old baseline file: "%s".',
+ base_file)
+
+ # Get the diff between old and new baselines and save to the html dir.
+ if baseline_filename.upper().endswith('.TXT'):
+ output = self._scm.diff_for_file(baseline_fullpath, log=_log)
+ if output:
+ diff_file = get_result_file_fullpath(
+ self._options.html_directory, baseline_filename,
+ self._platform, 'diff')
+ with open(diff_file, 'wb') as file:
+ file.write(output)
+ _log.info(' Html: created baseline diff file: "%s".',
+ diff_file)
+
+
+class HtmlGenerator(object):
+ """Class to generate rebaselining result comparison html."""
+
+ HTML_REBASELINE = ('<html>'
+ '<head>'
+ '<style>'
+ 'body {font-family: sans-serif;}'
+ '.mainTable {background: #666666;}'
+ '.mainTable td , .mainTable th {background: white;}'
+ '.detail {margin-left: 10px; margin-top: 3px;}'
+ '</style>'
+ '<title>Rebaselining Result Comparison (%(time)s)'
+ '</title>'
+ '</head>'
+ '<body>'
+ '<h2>Rebaselining Result Comparison (%(time)s)</h2>'
+ '%(body)s'
+ '</body>'
+ '</html>')
+ HTML_NO_REBASELINING_TESTS = (
+ '<p>No tests found that need rebaselining.</p>')
+ HTML_TABLE_TEST = ('<table class="mainTable" cellspacing=1 cellpadding=5>'
+ '%s</table><br>')
+ HTML_TR_TEST = ('<tr>'
+ '<th style="background-color: #CDECDE; border-bottom: '
+ '1px solid black; font-size: 18pt; font-weight: bold" '
+ 'colspan="5">'
+ '<a href="%s">%s</a>'
+ '</th>'
+ '</tr>')
+ HTML_TEST_DETAIL = ('<div class="detail">'
+ '<tr>'
+ '<th width="100">Baseline</th>'
+ '<th width="100">Platform</th>'
+ '<th width="200">Old</th>'
+ '<th width="200">New</th>'
+ '<th width="150">Difference</th>'
+ '</tr>'
+ '%s'
+ '</div>')
+ HTML_TD_NOLINK = '<td align=center><a>%s</a></td>'
+ HTML_TD_LINK = '<td align=center><a href="%(uri)s">%(name)s</a></td>'
+ HTML_TD_LINK_IMG = ('<td><a href="%(uri)s">'
+ '<img style="width: 200" src="%(uri)s" /></a></td>')
+ HTML_TR = '<tr>%s</tr>'
+
+ def __init__(self, target_port, options, platforms, rebaselining_tests,
+ executive):
+ self._html_directory = options.html_directory
+ self._target_port = target_port
+ self._platforms = platforms
+ self._rebaselining_tests = rebaselining_tests
+ self._executive = executive
+ self._html_file = os.path.join(options.html_directory,
+ 'rebaseline.html')
+
+ def abspath_to_uri(self, filename):
+ """Converts an absolute path to a file: URI."""
+ return path.abspath_to_uri(filename, self._executive)
+
+ def generate_html(self):
+ """Generate html file for rebaselining result comparison."""
+
+ _log.info('Generating html file')
+
+ html_body = ''
+ if not self._rebaselining_tests:
+ html_body += self.HTML_NO_REBASELINING_TESTS
+ else:
+ tests = list(self._rebaselining_tests)
+ tests.sort()
+
+ test_no = 1
+ for test in tests:
+ _log.info('Test %d: %s', test_no, test)
+ html_body += self._generate_html_for_one_test(test)
+
+ html = self.HTML_REBASELINE % ({'time': time.asctime(),
+ 'body': html_body})
+ _log.debug(html)
+
+ with codecs.open(self._html_file, "w", "utf-8") as file:
+ file.write(html)
+
+ _log.info('Baseline comparison html generated at "%s"',
+ self._html_file)
+
+ def show_html(self):
+ """Launch the rebaselining html in brwoser."""
+
+ _log.info('Launching html: "%s"', self._html_file)
+ user.User().open_url(self._html_file)
+ _log.info('Html launched.')
+
+ def _generate_baseline_links(self, test_basename, suffix, platform):
+ """Generate links for baseline results (old, new and diff).
+
+ Args:
+ test_basename: base filename of the test
+ suffix: baseline file suffixes: '.txt', '.png'
+ platform: win, linux or mac
+
+ Returns:
+ html links for showing baseline results (old, new and diff)
+ """
+
+ baseline_filename = '%s-expected%s' % (test_basename, suffix)
+ _log.debug(' baseline filename: "%s"', baseline_filename)
+
+ new_file = get_result_file_fullpath(self._html_directory,
+ baseline_filename, platform, 'new')
+ _log.info(' New baseline file: "%s"', new_file)
+ if not os.path.exists(new_file):
+ _log.info(' No new baseline file: "%s"', new_file)
+ return ''
+
+ old_file = get_result_file_fullpath(self._html_directory,
+ baseline_filename, platform, 'old')
+ _log.info(' Old baseline file: "%s"', old_file)
+ if suffix == '.png':
+ html_td_link = self.HTML_TD_LINK_IMG
+ else:
+ html_td_link = self.HTML_TD_LINK
+
+ links = ''
+ if os.path.exists(old_file):
+ links += html_td_link % {
+ 'uri': self.abspath_to_uri(old_file),
+ 'name': baseline_filename}
+ else:
+ _log.info(' No old baseline file: "%s"', old_file)
+ links += self.HTML_TD_NOLINK % ''
+
+ links += html_td_link % {'uri': self.abspath_to_uri(new_file),
+ 'name': baseline_filename}
+
+ diff_file = get_result_file_fullpath(self._html_directory,
+ baseline_filename, platform,
+ 'diff')
+ _log.info(' Baseline diff file: "%s"', diff_file)
+ if os.path.exists(diff_file):
+ links += html_td_link % {'uri': self.abspath_to_uri(diff_file),
+ 'name': 'Diff'}
+ else:
+ _log.info(' No baseline diff file: "%s"', diff_file)
+ links += self.HTML_TD_NOLINK % ''
+
+ return links
+
+ def _generate_html_for_one_test(self, test):
+ """Generate html for one rebaselining test.
+
+ Args:
+ test: layout test name
+
+ Returns:
+ html that compares baseline results for the test.
+ """
+
+ test_basename = os.path.basename(os.path.splitext(test)[0])
+ _log.info(' basename: "%s"', test_basename)
+ rows = []
+ for suffix in BASELINE_SUFFIXES:
+ if suffix == '.checksum':
+ continue
+
+ _log.info(' Checking %s files', suffix)
+ for platform in self._platforms:
+ links = self._generate_baseline_links(test_basename, suffix,
+ platform)
+ if links:
+ row = self.HTML_TD_NOLINK % self._get_baseline_result_type(
+ suffix)
+ row += self.HTML_TD_NOLINK % platform
+ row += links
+ _log.debug(' html row: %s', row)
+
+ rows.append(self.HTML_TR % row)
+
+ if rows:
+ test_path = os.path.join(self._target_port.layout_tests_dir(),
+ test)
+ html = self.HTML_TR_TEST % (self.abspath_to_uri(test_path), test)
+ html += self.HTML_TEST_DETAIL % ' '.join(rows)
+
+ _log.debug(' html for test: %s', html)
+ return self.HTML_TABLE_TEST % html
+
+ return ''
+
+ def _get_baseline_result_type(self, suffix):
+ """Name of the baseline result type."""
+
+ if suffix == '.png':
+ return 'Pixel'
+ elif suffix == '.txt':
+ return 'Render Tree'
+ else:
+ return 'Other'
+
+
+def get_host_port_object(options):
+ """Return a port object for the platform we're running on."""
+ # The only thing we really need on the host is a way to diff
+ # text files and image files, which means we need to check that some
+ # version of ImageDiff has been built. We will look for either Debug
+ # or Release versions of the default port on the platform.
+ options.configuration = "Release"
+ port_obj = port.get(None, options)
+ if not port_obj.check_image_diff(override_step=None, logging=False):
+ _log.debug('No release version of the image diff binary was found.')
+ options.configuration = "Debug"
+ port_obj = port.get(None, options)
+ if not port_obj.check_image_diff(override_step=None, logging=False):
+ _log.error('No version of image diff was found. Check your build.')
+ return None
+ else:
+ _log.debug('Found the debug version of the image diff binary.')
+ else:
+ _log.debug('Found the release version of the image diff binary.')
+ return port_obj
+
+
+def parse_options(args):
+ """Parse options and return a pair of host options and target options."""
+ option_parser = optparse.OptionParser()
+ option_parser.add_option('-v', '--verbose',
+ action='store_true',
+ default=False,
+ help='include debug-level logging.')
+
+ option_parser.add_option('-q', '--quiet',
+ action='store_true',
+ help='Suppress result HTML viewing')
+
+ option_parser.add_option('-p', '--platforms',
+ default='mac,win,win-xp,win-vista,linux',
+ help=('Comma delimited list of platforms '
+ 'that need rebaselining.'))
+
+ option_parser.add_option('-u', '--archive_url',
+ default=('http://build.chromium.org/f/chromium/'
+ 'layout_test_results'),
+ help=('Url to find the layout test result archive'
+ ' file.'))
+ option_parser.add_option('-U', '--force_archive_url',
+ help=('Url of result zip file. This option is for debugging '
+ 'purposes'))
+
+ option_parser.add_option('-w', '--webkit_canary',
+ action='store_true',
+ default=False,
+ help=('If True, pull baselines from webkit.org '
+ 'canary bot.'))
+
+ option_parser.add_option('-b', '--backup',
+ action='store_true',
+ default=False,
+ help=('Whether or not to backup the original test'
+ ' expectations file after rebaseline.'))
+
+ option_parser.add_option('-d', '--html_directory',
+ default='',
+ help=('The directory that stores the results for '
+ 'rebaselining comparison.'))
+
+ option_parser.add_option('', '--use_drt',
+ action='store_true',
+ default=False,
+ help=('Use ImageDiff from DumpRenderTree instead '
+ 'of image_diff for pixel tests.'))
+
+ option_parser.add_option('', '--target-platform',
+ default='chromium',
+ help=('The target platform to rebaseline '
+ '("mac", "chromium", "qt", etc.). Defaults '
+ 'to "chromium".'))
+ options = option_parser.parse_args(args)[0]
+
+ target_options = copy.copy(options)
+ if options.target_platform == 'chromium':
+ target_options.chromium = True
+ options.tolerance = 0
+
+ return (options, target_options)
+
+
+def main(executive=Executive()):
+ """Main function to produce new baselines."""
+
+ (options, target_options) = parse_options(sys.argv[1:])
+
+ # We need to create three different Port objects over the life of this
+ # script. |target_port_obj| is used to determine configuration information:
+ # location of the expectations file, names of ports to rebaseline, etc.
+ # |port_obj| is used for runtime functionality like actually diffing
+ # Then we create a rebaselining port to actual find and manage the
+ # baselines.
+ target_port_obj = port.get(None, target_options)
+
+ # Set up our logging format.
+ log_level = logging.INFO
+ if options.verbose:
+ log_level = logging.DEBUG
+ logging.basicConfig(level=log_level,
+ format=('%(asctime)s %(filename)s:%(lineno)-3d '
+ '%(levelname)s %(message)s'),
+ datefmt='%y%m%d %H:%M:%S')
+
+ host_port_obj = get_host_port_object(options)
+ if not host_port_obj:
+ sys.exit(1)
+
+ # Verify 'platforms' option is valid.
+ if not options.platforms:
+ _log.error('Invalid "platforms" option. --platforms must be '
+ 'specified in order to rebaseline.')
+ sys.exit(1)
+ platforms = [p.strip().lower() for p in options.platforms.split(',')]
+ for platform in platforms:
+ if not platform in REBASELINE_PLATFORM_ORDER:
+ _log.error('Invalid platform: "%s"' % (platform))
+ sys.exit(1)
+
+ # Adjust the platform order so rebaseline tool is running at the order of
+ # 'mac', 'win' and 'linux'. This is in same order with layout test baseline
+ # search paths. It simplifies how the rebaseline tool detects duplicate
+ # baselines. Check _IsDupBaseline method for details.
+ rebaseline_platforms = []
+ for platform in REBASELINE_PLATFORM_ORDER:
+ if platform in platforms:
+ rebaseline_platforms.append(platform)
+
+ options.html_directory = setup_html_directory(options.html_directory)
+
+ rebaselining_tests = set()
+ backup = options.backup
+ for platform in rebaseline_platforms:
+ rebaseliner = Rebaseliner(host_port_obj, target_port_obj,
+ platform, options)
+
+ _log.info('')
+ log_dashed_string('Rebaseline started', platform)
+ if rebaseliner.run(backup):
+ # Only need to backup one original copy of test expectation file.
+ backup = False
+ log_dashed_string('Rebaseline done', platform)
+ else:
+ log_dashed_string('Rebaseline failed', platform, logging.ERROR)
+
+ rebaselining_tests |= set(rebaseliner.get_rebaselining_tests())
+
+ _log.info('')
+ log_dashed_string('Rebaselining result comparison started', None)
+ html_generator = HtmlGenerator(target_port_obj,
+ options,
+ rebaseline_platforms,
+ rebaselining_tests,
+ executive=executive)
+ html_generator.generate_html()
+ if not options.quiet:
+ html_generator.show_html()
+ log_dashed_string('Rebaselining result comparison done', None)
+
+ sys.exit(0)
+
+if '__main__' == __name__:
+ main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py
new file mode 100644
index 0000000..7c55b94
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/rebaseline_chromium_webkit_tests_unittest.py
@@ -0,0 +1,157 @@
+#!/usr/bin/python
+# 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.
+
+"""Unit tests for rebaseline_chromium_webkit_tests.py."""
+
+import os
+import sys
+import unittest
+
+from webkitpy.tool import mocktool
+from webkitpy.layout_tests import port
+from webkitpy.layout_tests import rebaseline_chromium_webkit_tests
+from webkitpy.common.system.executive import Executive, ScriptError
+
+
+class MockPort(object):
+ def __init__(self, image_diff_exists):
+ self.image_diff_exists = image_diff_exists
+
+ def check_image_diff(self, override_step, logging):
+ return self.image_diff_exists
+
+
+def get_mock_get(config_expectations):
+ def mock_get(port_name, options):
+ return MockPort(config_expectations[options.configuration])
+ return mock_get
+
+
+class TestGetHostPortObject(unittest.TestCase):
+ def assert_result(self, release_present, debug_present, valid_port_obj):
+ # Tests whether we get a valid port object returned when we claim
+ # that Image diff is (or isn't) present in the two configs.
+ port.get = get_mock_get({'Release': release_present,
+ 'Debug': debug_present})
+ options = mocktool.MockOptions(configuration=None,
+ html_directory=None)
+ port_obj = rebaseline_chromium_webkit_tests.get_host_port_object(
+ options)
+ if valid_port_obj:
+ self.assertNotEqual(port_obj, None)
+ else:
+ self.assertEqual(port_obj, None)
+
+ def test_get_host_port_object(self):
+ # Save the normal port.get() function for future testing.
+ old_get = port.get
+
+ # Test whether we get a valid port object back for the four
+ # possible cases of having ImageDiffs built. It should work when
+ # there is at least one binary present.
+ self.assert_result(False, False, False)
+ self.assert_result(True, False, True)
+ self.assert_result(False, True, True)
+ self.assert_result(True, True, True)
+
+ # Restore the normal port.get() function.
+ port.get = old_get
+
+
+class TestRebaseliner(unittest.TestCase):
+ def make_rebaseliner(self):
+ options = mocktool.MockOptions(configuration=None,
+ html_directory=None)
+ host_port_obj = port.get('test', options)
+ target_options = options
+ target_port_obj = port.get('test', target_options)
+ platform = 'test'
+ return rebaseline_chromium_webkit_tests.Rebaseliner(
+ host_port_obj, target_port_obj, platform, options)
+
+ def test_parse_options(self):
+ (options, target_options) = rebaseline_chromium_webkit_tests.parse_options([])
+ self.assertTrue(target_options.chromium)
+ self.assertEqual(options.tolerance, 0)
+
+ (options, target_options) = rebaseline_chromium_webkit_tests.parse_options(['--target-platform', 'qt'])
+ self.assertFalse(hasattr(target_options, 'chromium'))
+ self.assertEqual(options.tolerance, 0)
+
+ def test_noop(self):
+ # this method tests that was can at least instantiate an object, even
+ # if there is nothing to do.
+ rebaseliner = self.make_rebaseliner()
+ self.assertNotEqual(rebaseliner, None)
+
+ def test_diff_baselines_txt(self):
+ rebaseliner = self.make_rebaseliner()
+ output = rebaseliner._port.expected_text(
+ os.path.join(rebaseliner._port.layout_tests_dir(),
+ 'passes/text.html'))
+ self.assertFalse(rebaseliner._diff_baselines(output, output,
+ is_image=False))
+
+ def test_diff_baselines_png(self):
+ rebaseliner = self.make_rebaseliner()
+ image = rebaseliner._port.expected_image(
+ os.path.join(rebaseliner._port.layout_tests_dir(),
+ 'passes/image.html'))
+ self.assertFalse(rebaseliner._diff_baselines(image, image,
+ is_image=True))
+
+
+class TestHtmlGenerator(unittest.TestCase):
+ def make_generator(self, tests):
+ return rebaseline_chromium_webkit_tests.HtmlGenerator(
+ target_port=None,
+ options=mocktool.MockOptions(configuration=None,
+ html_directory='/tmp'),
+ platforms=['mac'],
+ rebaselining_tests=tests,
+ executive=Executive())
+
+ def test_generate_baseline_links(self):
+ orig_platform = sys.platform
+ orig_exists = os.path.exists
+
+ try:
+ sys.platform = 'darwin'
+ os.path.exists = lambda x: True
+ generator = self.make_generator(["foo.txt"])
+ links = generator._generate_baseline_links("foo", ".txt", "mac")
+ expected_links = '<td align=center><a href="file:///tmp/foo-expected-mac-old.txt">foo-expected.txt</a></td><td align=center><a href="file:///tmp/foo-expected-mac-new.txt">foo-expected.txt</a></td><td align=center><a href="file:///tmp/foo-expected-mac-diff.txt">Diff</a></td>'
+ self.assertEqual(links, expected_links)
+ finally:
+ sys.platform = orig_platform
+ os.path.exists = orig_exists
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
new file mode 100755
index 0000000..f7e5330
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests.py
@@ -0,0 +1,434 @@
+#!/usr/bin/env python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
+#
+# 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.
+
+"""Run layout tests."""
+
+from __future__ import with_statement
+
+import codecs
+import errno
+import logging
+import optparse
+import os
+import signal
+import sys
+
+from layout_package import printing
+from layout_package import test_runner
+
+from webkitpy.common.system import user
+from webkitpy.thirdparty import simplejson
+
+import port
+
+_log = logging.getLogger(__name__)
+
+
+def run(port, options, args, regular_output=sys.stderr,
+ buildbot_output=sys.stdout):
+ """Run the tests.
+
+ Args:
+ port: Port object for port-specific behavior
+ options: a dictionary of command line options
+ args: a list of sub directories or files to test
+ regular_output: a stream-like object that we can send logging/debug
+ output to
+ buildbot_output: a stream-like object that we can write all output that
+ is intended to be parsed by the buildbot to
+ Returns:
+ the number of unexpected results that occurred, or -1 if there is an
+ error.
+
+ """
+ warnings = _set_up_derived_options(port, options)
+
+ printer = printing.Printer(port, options, regular_output, buildbot_output,
+ int(options.child_processes), options.experimental_fully_parallel)
+ for w in warnings:
+ _log.warning(w)
+
+ if options.help_printing:
+ printer.help_printing()
+ printer.cleanup()
+ return 0
+
+ last_unexpected_results = _gather_unexpected_results(options)
+ if options.print_last_failures:
+ printer.write("\n".join(last_unexpected_results) + "\n")
+ printer.cleanup()
+ return 0
+
+ # We wrap any parts of the run that are slow or likely to raise exceptions
+ # in a try/finally to ensure that we clean up the logging configuration.
+ num_unexpected_results = -1
+ try:
+ runner = test_runner.TestRunner(port, options, printer)
+ runner._print_config()
+
+ printer.print_update("Collecting tests ...")
+ try:
+ runner.collect_tests(args, last_unexpected_results)
+ except IOError, e:
+ if e.errno == errno.ENOENT:
+ return -1
+ raise
+
+ printer.print_update("Parsing expectations ...")
+ if options.lint_test_files:
+ return runner.lint()
+ runner.parse_expectations(port.test_platform_name(),
+ options.configuration == 'Debug')
+
+ printer.print_update("Checking build ...")
+ if not port.check_build(runner.needs_http()):
+ _log.error("Build check failed")
+ return -1
+
+ result_summary = runner.set_up_run()
+ if result_summary:
+ num_unexpected_results = runner.run(result_summary)
+ runner.clean_up_run()
+ _log.debug("Testing completed, Exit status: %d" %
+ num_unexpected_results)
+ finally:
+ printer.cleanup()
+
+ return num_unexpected_results
+
+
+def _set_up_derived_options(port_obj, options):
+ """Sets the options values that depend on other options values."""
+ # We return a list of warnings to print after the printer is initialized.
+ warnings = []
+
+ if options.worker_model == 'old-inline':
+ if options.child_processes and int(options.child_processes) > 1:
+ warnings.append("--worker-model=old-inline overrides --child-processes")
+ options.child_processes = "1"
+ if not options.child_processes:
+ options.child_processes = os.environ.get("WEBKIT_TEST_CHILD_PROCESSES",
+ str(port_obj.default_child_processes()))
+
+ if not options.configuration:
+ options.configuration = port_obj.default_configuration()
+
+ if options.pixel_tests is None:
+ options.pixel_tests = True
+
+ if not options.use_apache:
+ options.use_apache = sys.platform in ('darwin', 'linux2')
+
+ if not os.path.isabs(options.results_directory):
+ # This normalizes the path to the build dir.
+ # FIXME: how this happens is not at all obvious; this is a dumb
+ # interface and should be cleaned up.
+ options.results_directory = port_obj.results_directory()
+
+ if not options.time_out_ms:
+ if options.configuration == "Debug":
+ options.time_out_ms = str(2 * test_runner.TestRunner.DEFAULT_TEST_TIMEOUT_MS)
+ else:
+ options.time_out_ms = str(test_runner.TestRunner.DEFAULT_TEST_TIMEOUT_MS)
+
+ options.slow_time_out_ms = str(5 * int(options.time_out_ms))
+ return warnings
+
+
+def _gather_unexpected_results(options):
+ """Returns the unexpected results from the previous run, if any."""
+ last_unexpected_results = []
+ if options.print_last_failures or options.retest_last_failures:
+ unexpected_results_filename = os.path.join(
+ options.results_directory, "unexpected_results.json")
+ with codecs.open(unexpected_results_filename, "r", "utf-8") as file:
+ results = simplejson.load(file)
+ last_unexpected_results = results['tests'].keys()
+ return last_unexpected_results
+
+
+def _compat_shim_callback(option, opt_str, value, parser):
+ print "Ignoring unsupported option: %s" % opt_str
+
+
+def _compat_shim_option(option_name, **kwargs):
+ return optparse.make_option(option_name, action="callback",
+ callback=_compat_shim_callback,
+ help="Ignored, for old-run-webkit-tests compat only.", **kwargs)
+
+
+def parse_args(args=None):
+ """Provides a default set of command line args.
+
+ Returns a tuple of options, args from optparse"""
+
+ # FIXME: All of these options should be stored closer to the code which
+ # FIXME: actually uses them. configuration_options should move
+ # FIXME: to WebKitPort and be shared across all scripts.
+ configuration_options = [
+ optparse.make_option("-t", "--target", dest="configuration",
+ help="(DEPRECATED)"),
+ # FIXME: --help should display which configuration is default.
+ optparse.make_option('--debug', action='store_const', const='Debug',
+ dest="configuration",
+ help='Set the configuration to Debug'),
+ optparse.make_option('--release', action='store_const',
+ const='Release', dest="configuration",
+ help='Set the configuration to Release'),
+ # old-run-webkit-tests also accepts -c, --configuration CONFIGURATION.
+ ]
+
+ print_options = printing.print_options()
+
+ # FIXME: These options should move onto the ChromiumPort.
+ chromium_options = [
+ optparse.make_option("--chromium", action="store_true", default=False,
+ help="use the Chromium port"),
+ optparse.make_option("--startup-dialog", action="store_true",
+ default=False, help="create a dialog on DumpRenderTree startup"),
+ optparse.make_option("--gp-fault-error-box", action="store_true",
+ default=False, help="enable Windows GP fault error box"),
+ optparse.make_option("--multiple-loads",
+ type="int", help="turn on multiple loads of each test"),
+ optparse.make_option("--js-flags",
+ type="string", help="JavaScript flags to pass to tests"),
+ optparse.make_option("--nocheck-sys-deps", action="store_true",
+ default=False,
+ help="Don't check the system dependencies (themes)"),
+ optparse.make_option("--use-test-shell", action="store_true",
+ default=False,
+ help="Use test_shell instead of DRT"),
+ optparse.make_option("--accelerated-compositing",
+ action="store_true",
+ help="Use hardware-accelated compositing for rendering"),
+ optparse.make_option("--no-accelerated-compositing",
+ action="store_false",
+ dest="accelerated_compositing",
+ help="Don't use hardware-accelerated compositing for rendering"),
+ optparse.make_option("--accelerated-2d-canvas",
+ action="store_true",
+ help="Use hardware-accelerated 2D Canvas calls"),
+ optparse.make_option("--no-accelerated-2d-canvas",
+ action="store_false",
+ dest="accelerated_2d_canvas",
+ help="Don't use hardware-accelerated 2D Canvas calls"),
+ ]
+
+ # Missing Mac-specific old-run-webkit-tests options:
+ # FIXME: Need: -g, --guard for guard malloc support on Mac.
+ # FIXME: Need: -l --leaks Enable leaks checking.
+ # FIXME: Need: --sample-on-timeout Run sample on timeout
+
+ old_run_webkit_tests_compat = [
+ # NRWT doesn't generate results by default anyway.
+ _compat_shim_option("--no-new-test-results"),
+ # NRWT doesn't sample on timeout yet anyway.
+ _compat_shim_option("--no-sample-on-timeout"),
+ # FIXME: NRWT needs to support remote links eventually.
+ _compat_shim_option("--use-remote-links-to-tests"),
+ ]
+
+ results_options = [
+ # NEED for bots: --use-remote-links-to-tests Link to test files
+ # within the SVN repository in the results.
+ optparse.make_option("-p", "--pixel-tests", action="store_true",
+ dest="pixel_tests", help="Enable pixel-to-pixel PNG comparisons"),
+ optparse.make_option("--no-pixel-tests", action="store_false",
+ dest="pixel_tests", help="Disable pixel-to-pixel PNG comparisons"),
+ optparse.make_option("--tolerance",
+ help="Ignore image differences less than this percentage (some "
+ "ports may ignore this option)", type="float"),
+ optparse.make_option("--results-directory",
+ default="layout-test-results",
+ help="Output results directory source dir, relative to Debug or "
+ "Release"),
+ optparse.make_option("--new-baseline", action="store_true",
+ default=False, help="Save all generated results as new baselines "
+ "into the platform directory, overwriting whatever's "
+ "already there."),
+ optparse.make_option("--reset-results", action="store_true",
+ default=False, help="Reset any existing baselines to the "
+ "generated results"),
+ optparse.make_option("--no-show-results", action="store_false",
+ default=True, dest="show_results",
+ help="Don't launch a browser with results after the tests "
+ "are done"),
+ # FIXME: We should have a helper function to do this sort of
+ # deprectated mapping and automatically log, etc.
+ optparse.make_option("--noshow-results", action="store_false",
+ dest="show_results",
+ help="Deprecated, same as --no-show-results."),
+ optparse.make_option("--no-launch-safari", action="store_false",
+ dest="show_results",
+ help="old-run-webkit-tests compat, same as --noshow-results."),
+ # old-run-webkit-tests:
+ # --[no-]launch-safari Launch (or do not launch) Safari to display
+ # test results (default: launch)
+ optparse.make_option("--full-results-html", action="store_true",
+ default=False,
+ help="Show all failures in results.html, rather than only "
+ "regressions"),
+ optparse.make_option("--clobber-old-results", action="store_true",
+ default=False, help="Clobbers test results from previous runs."),
+ optparse.make_option("--platform",
+ help="Override the platform for expected results"),
+ optparse.make_option("--no-record-results", action="store_false",
+ default=True, dest="record_results",
+ help="Don't record the results."),
+ # old-run-webkit-tests also has HTTP toggle options:
+ # --[no-]http Run (or do not run) http tests
+ # (default: run)
+ ]
+
+ test_options = [
+ optparse.make_option("--build", dest="build",
+ action="store_true", default=True,
+ help="Check to ensure the DumpRenderTree build is up-to-date "
+ "(default)."),
+ optparse.make_option("--no-build", dest="build",
+ action="store_false", help="Don't check to see if the "
+ "DumpRenderTree build is up-to-date."),
+ optparse.make_option("-n", "--dry-run", action="store_true",
+ default=False,
+ help="Do everything but actually run the tests or upload results."),
+ # old-run-webkit-tests has --valgrind instead of wrapper.
+ optparse.make_option("--wrapper",
+ help="wrapper command to insert before invocations of "
+ "DumpRenderTree; option is split on whitespace before "
+ "running. (Example: --wrapper='valgrind --smc-check=all')"),
+ # old-run-webkit-tests:
+ # -i|--ignore-tests Comma-separated list of directories
+ # or tests to ignore
+ optparse.make_option("--test-list", action="append",
+ help="read list of tests to run from file", metavar="FILE"),
+ # old-run-webkit-tests uses --skipped==[default|ignore|only]
+ # instead of --force:
+ optparse.make_option("--force", action="store_true", default=False,
+ help="Run all tests, even those marked SKIP in the test list"),
+ optparse.make_option("--use-apache", action="store_true",
+ default=False, help="Whether to use apache instead of lighttpd."),
+ optparse.make_option("--time-out-ms",
+ help="Set the timeout for each test"),
+ # old-run-webkit-tests calls --randomize-order --random:
+ optparse.make_option("--randomize-order", action="store_true",
+ default=False, help=("Run tests in random order (useful "
+ "for tracking down corruption)")),
+ optparse.make_option("--run-chunk",
+ help=("Run a specified chunk (n:l), the nth of len l, "
+ "of the layout tests")),
+ optparse.make_option("--run-part", help=("Run a specified part (n:m), "
+ "the nth of m parts, of the layout tests")),
+ # old-run-webkit-tests calls --batch-size: --nthly n
+ # Restart DumpRenderTree every n tests (default: 1000)
+ optparse.make_option("--batch-size",
+ help=("Run a the tests in batches (n), after every n tests, "
+ "DumpRenderTree is relaunched."), type="int", default=0),
+ # old-run-webkit-tests calls --run-singly: -1|--singly
+ # Isolate each test case run (implies --nthly 1 --verbose)
+ optparse.make_option("--run-singly", action="store_true",
+ default=False, help="run a separate DumpRenderTree for each test"),
+ optparse.make_option("--child-processes",
+ help="Number of DumpRenderTrees to run in parallel."),
+ # FIXME: Display default number of child processes that will run.
+ optparse.make_option("--worker-model", action="store",
+ default="old-threads", help=("controls worker model. Valid values "
+ "are 'old-inline', 'old-threads'.")),
+ optparse.make_option("--experimental-fully-parallel",
+ action="store_true", default=False,
+ help="run all tests in parallel"),
+ optparse.make_option("--exit-after-n-failures", type="int", nargs=1,
+ help="Exit after the first N failures instead of running all "
+ "tests"),
+ optparse.make_option("--exit-after-n-crashes-or-timeouts", type="int",
+ nargs=1, help="Exit after the first N crashes instead of running "
+ "all tests"),
+ # FIXME: consider: --iterations n
+ # Number of times to run the set of tests (e.g. ABCABCABC)
+ optparse.make_option("--print-last-failures", action="store_true",
+ default=False, help="Print the tests in the last run that "
+ "had unexpected failures (or passes) and then exit."),
+ optparse.make_option("--retest-last-failures", action="store_true",
+ default=False, help="re-test the tests in the last run that "
+ "had unexpected failures (or passes)."),
+ optparse.make_option("--retry-failures", action="store_true",
+ default=True,
+ help="Re-try any tests that produce unexpected results (default)"),
+ optparse.make_option("--no-retry-failures", action="store_false",
+ dest="retry_failures",
+ help="Don't re-try any tests that produce unexpected results."),
+ ]
+
+ misc_options = [
+ optparse.make_option("--lint-test-files", action="store_true",
+ default=False, help=("Makes sure the test files parse for all "
+ "configurations. Does not run any tests.")),
+ ]
+
+ # FIXME: Move these into json_results_generator.py
+ results_json_options = [
+ optparse.make_option("--master-name", help="The name of the buildbot master."),
+ optparse.make_option("--builder-name", default="DUMMY_BUILDER_NAME",
+ help=("The name of the builder shown on the waterfall running "
+ "this script e.g. WebKit.")),
+ optparse.make_option("--build-name", default="DUMMY_BUILD_NAME",
+ help=("The name of the builder used in its path, e.g. "
+ "webkit-rel.")),
+ optparse.make_option("--build-number", default="DUMMY_BUILD_NUMBER",
+ help=("The build number of the builder running this script.")),
+ optparse.make_option("--test-results-server", default="",
+ help=("If specified, upload results json files to this appengine "
+ "server.")),
+ optparse.make_option("--upload-full-results",
+ action="store_true",
+ default=False,
+ help="If true, upload full json results to server."),
+ ]
+
+ option_list = (configuration_options + print_options +
+ chromium_options + results_options + test_options +
+ misc_options + results_json_options +
+ old_run_webkit_tests_compat)
+ option_parser = optparse.OptionParser(option_list=option_list)
+
+ return option_parser.parse_args(args)
+
+
+def main():
+ options, args = parse_args()
+ port_obj = port.get(options.platform, options)
+ return run(port_obj, options, args)
+
+
+if '__main__' == __name__:
+ try:
+ sys.exit(main())
+ except KeyboardInterrupt:
+ # this mirrors what the shell normally does
+ sys.exit(signal.SIGINT + 128)
diff --git a/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
new file mode 100644
index 0000000..2bfac2f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/run_webkit_tests_unittest.py
@@ -0,0 +1,545 @@
+#!/usr/bin/python
+# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2010 Gabor Rapcsanyi (rgabor@inf.u-szeged.hu), University of Szeged
+#
+# 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.
+
+"""Unit tests for run_webkit_tests."""
+
+import codecs
+import itertools
+import logging
+import os
+import Queue
+import shutil
+import sys
+import tempfile
+import thread
+import time
+import threading
+import unittest
+
+from webkitpy.common import array_stream
+from webkitpy.common.system import outputcapture
+from webkitpy.common.system import user
+from webkitpy.layout_tests import port
+from webkitpy.layout_tests import run_webkit_tests
+from webkitpy.layout_tests.layout_package import dump_render_tree_thread
+from webkitpy.layout_tests.port.test import TestPort, TestDriver
+from webkitpy.python24.versioning import compare_version
+from webkitpy.test.skip import skip_if
+
+from webkitpy.thirdparty.mock import Mock
+
+
+class MockUser():
+ def __init__(self):
+ self.url = None
+
+ def open_url(self, url):
+ self.url = url
+
+
+def parse_args(extra_args=None, record_results=False, tests_included=False,
+ print_nothing=True):
+ extra_args = extra_args or []
+ if print_nothing:
+ args = ['--print', 'nothing']
+ else:
+ args = []
+ if not '--platform' in extra_args:
+ args.extend(['--platform', 'test'])
+ if not record_results:
+ args.append('--no-record-results')
+ if not '--child-processes' in extra_args:
+ args.extend(['--worker-model', 'old-inline'])
+ args.extend(extra_args)
+ if not tests_included:
+ # We use the glob to test that globbing works.
+ args.extend(['passes',
+ 'http/tests',
+ 'websocket/tests',
+ 'failures/expected/*'])
+ return run_webkit_tests.parse_args(args)
+
+
+def passing_run(extra_args=None, port_obj=None, record_results=False,
+ tests_included=False):
+ options, parsed_args = parse_args(extra_args, record_results,
+ tests_included)
+ if not port_obj:
+ port_obj = port.get(port_name=options.platform, options=options,
+ user=MockUser())
+ res = run_webkit_tests.run(port_obj, options, parsed_args)
+ return res == 0
+
+
+def logging_run(extra_args=None, port_obj=None, tests_included=False):
+ options, parsed_args = parse_args(extra_args=extra_args,
+ record_results=False,
+ tests_included=tests_included,
+ print_nothing=False)
+ user = MockUser()
+ if not port_obj:
+ port_obj = port.get(port_name=options.platform, options=options,
+ user=user)
+
+ res, buildbot_output, regular_output = run_and_capture(port_obj, options,
+ parsed_args)
+ return (res, buildbot_output, regular_output, user)
+
+
+def run_and_capture(port_obj, options, parsed_args):
+ oc = outputcapture.OutputCapture()
+ try:
+ oc.capture_output()
+ buildbot_output = array_stream.ArrayStream()
+ regular_output = array_stream.ArrayStream()
+ res = run_webkit_tests.run(port_obj, options, parsed_args,
+ buildbot_output=buildbot_output,
+ regular_output=regular_output)
+ finally:
+ oc.restore_output()
+ return (res, buildbot_output, regular_output)
+
+
+def get_tests_run(extra_args=None, tests_included=False, flatten_batches=False):
+ extra_args = extra_args or []
+ if not tests_included:
+ # Not including http tests since they get run out of order (that
+ # behavior has its own test, see test_get_test_file_queue)
+ extra_args = ['passes', 'failures'] + extra_args
+ options, parsed_args = parse_args(extra_args, tests_included=True)
+
+ user = MockUser()
+
+ test_batches = []
+
+ class RecordingTestDriver(TestDriver):
+ def __init__(self, port, worker_number):
+ TestDriver.__init__(self, port, worker_number)
+ self._current_test_batch = None
+
+ def poll(self):
+ # So that we don't create a new driver for every test
+ return None
+
+ def stop(self):
+ self._current_test_batch = None
+
+ def run_test(self, test_input):
+ if self._current_test_batch is None:
+ self._current_test_batch = []
+ test_batches.append(self._current_test_batch)
+ test_name = self._port.relative_test_filename(test_input.filename)
+ self._current_test_batch.append(test_name)
+ return TestDriver.run_test(self, test_input)
+
+ class RecordingTestPort(TestPort):
+ def create_driver(self, worker_number):
+ return RecordingTestDriver(self, worker_number)
+
+ recording_port = RecordingTestPort(options=options, user=user)
+ run_and_capture(recording_port, options, parsed_args)
+
+ if flatten_batches:
+ return list(itertools.chain(*test_batches))
+
+ return test_batches
+
+
+class MainTest(unittest.TestCase):
+ def test_accelerated_compositing(self):
+ # This just tests that we recognize the command line args
+ self.assertTrue(passing_run(['--accelerated-compositing']))
+ self.assertTrue(passing_run(['--no-accelerated-compositing']))
+
+ def test_accelerated_2d_canvas(self):
+ # This just tests that we recognize the command line args
+ self.assertTrue(passing_run(['--accelerated-2d-canvas']))
+ self.assertTrue(passing_run(['--no-accelerated-2d-canvas']))
+
+ def test_basic(self):
+ self.assertTrue(passing_run())
+
+ def test_batch_size(self):
+ batch_tests_run = get_tests_run(['--batch-size', '2'])
+ for batch in batch_tests_run:
+ self.assertTrue(len(batch) <= 2, '%s had too many tests' % ', '.join(batch))
+
+ def test_child_process_1(self):
+ (res, buildbot_output, regular_output, user) = logging_run(
+ ['--print', 'config', '--child-processes', '1'])
+ self.assertTrue('Running one DumpRenderTree\n'
+ in regular_output.get())
+
+ def test_child_processes_2(self):
+ (res, buildbot_output, regular_output, user) = logging_run(
+ ['--print', 'config', '--child-processes', '2'])
+ self.assertTrue('Running 2 DumpRenderTrees in parallel\n'
+ in regular_output.get())
+
+ def test_dryrun(self):
+ batch_tests_run = get_tests_run(['--dry-run'])
+ self.assertEqual(batch_tests_run, [])
+
+ batch_tests_run = get_tests_run(['-n'])
+ self.assertEqual(batch_tests_run, [])
+
+ def test_exception_raised(self):
+ self.assertRaises(ValueError, logging_run,
+ ['failures/expected/exception.html'], tests_included=True)
+
+ def test_full_results_html(self):
+ # FIXME: verify html?
+ self.assertTrue(passing_run(['--full-results-html']))
+
+ def test_help_printing(self):
+ res, out, err, user = logging_run(['--help-printing'])
+ self.assertEqual(res, 0)
+ self.assertTrue(out.empty())
+ self.assertFalse(err.empty())
+
+ def test_hung_thread(self):
+ res, out, err, user = logging_run(['--run-singly', '--time-out-ms=50',
+ 'failures/expected/hang.html'],
+ tests_included=True)
+ self.assertEqual(res, 0)
+ self.assertFalse(out.empty())
+ self.assertFalse(err.empty())
+
+ def test_keyboard_interrupt(self):
+ # Note that this also tests running a test marked as SKIP if
+ # you specify it explicitly.
+ self.assertRaises(KeyboardInterrupt, logging_run,
+ ['failures/expected/keyboard.html'], tests_included=True)
+
+ def test_last_results(self):
+ passing_run(['--clobber-old-results'], record_results=True)
+ (res, buildbot_output, regular_output, user) = logging_run(
+ ['--print-last-failures'])
+ self.assertEqual(regular_output.get(), ['\n\n'])
+ self.assertEqual(buildbot_output.get(), [])
+
+ def test_lint_test_files(self):
+ res, out, err, user = logging_run(['--lint-test-files'])
+ self.assertEqual(res, 0)
+ self.assertTrue(out.empty())
+ self.assertTrue(any(['Lint succeeded' in msg for msg in err.get()]))
+
+ def test_lint_test_files__errors(self):
+ options, parsed_args = parse_args(['--lint-test-files'])
+ user = MockUser()
+ port_obj = port.get(options.platform, options=options, user=user)
+ port_obj.test_expectations = lambda: "# syntax error"
+ res, out, err = run_and_capture(port_obj, options, parsed_args)
+
+ self.assertEqual(res, -1)
+ self.assertTrue(out.empty())
+ self.assertTrue(any(['Lint failed' in msg for msg in err.get()]))
+
+ def test_no_tests_found(self):
+ res, out, err, user = logging_run(['resources'], tests_included=True)
+ self.assertEqual(res, -1)
+ self.assertTrue(out.empty())
+ self.assertTrue('No tests to run.\n' in err.get())
+
+ def test_no_tests_found_2(self):
+ res, out, err, user = logging_run(['foo'], tests_included=True)
+ self.assertEqual(res, -1)
+ self.assertTrue(out.empty())
+ self.assertTrue('No tests to run.\n' in err.get())
+
+ def test_randomize_order(self):
+ # FIXME: verify order was shuffled
+ self.assertTrue(passing_run(['--randomize-order']))
+
+ def test_run_chunk(self):
+ # Test that we actually select the right chunk
+ all_tests_run = get_tests_run(flatten_batches=True)
+ chunk_tests_run = get_tests_run(['--run-chunk', '1:4'], flatten_batches=True)
+ self.assertEquals(all_tests_run[4:8], chunk_tests_run)
+
+ # Test that we wrap around if the number of tests is not evenly divisible by the chunk size
+ tests_to_run = ['passes/error.html', 'passes/image.html', 'passes/platform_image.html', 'passes/text.html']
+ chunk_tests_run = get_tests_run(['--run-chunk', '1:3'] + tests_to_run, tests_included=True, flatten_batches=True)
+ self.assertEquals(['passes/text.html', 'passes/error.html', 'passes/image.html'], chunk_tests_run)
+
+ def test_run_force(self):
+ # This raises an exception because we run
+ # failures/expected/exception.html, which is normally SKIPped.
+ self.assertRaises(ValueError, logging_run, ['--force'])
+
+ def test_run_part(self):
+ # Test that we actually select the right part
+ tests_to_run = ['passes/error.html', 'passes/image.html', 'passes/platform_image.html', 'passes/text.html']
+ tests_run = get_tests_run(['--run-part', '1:2'] + tests_to_run, tests_included=True, flatten_batches=True)
+ self.assertEquals(['passes/error.html', 'passes/image.html'], tests_run)
+
+ # Test that we wrap around if the number of tests is not evenly divisible by the chunk size
+ # (here we end up with 3 parts, each with 2 tests, and we only have 4 tests total, so the
+ # last part repeats the first two tests).
+ chunk_tests_run = get_tests_run(['--run-part', '3:3'] + tests_to_run, tests_included=True, flatten_batches=True)
+ self.assertEquals(['passes/error.html', 'passes/image.html'], chunk_tests_run)
+
+ def test_run_singly(self):
+ batch_tests_run = get_tests_run(['--run-singly'])
+ for batch in batch_tests_run:
+ self.assertEquals(len(batch), 1, '%s had too many tests' % ', '.join(batch))
+
+ def test_single_file(self):
+ tests_run = get_tests_run(['passes/text.html'], tests_included=True, flatten_batches=True)
+ self.assertEquals(['passes/text.html'], tests_run)
+
+ def test_test_list(self):
+ filename = tempfile.mktemp()
+ tmpfile = file(filename, mode='w+')
+ tmpfile.write('passes/text.html')
+ tmpfile.close()
+ tests_run = get_tests_run(['--test-list=%s' % filename], tests_included=True, flatten_batches=True)
+ self.assertEquals(['passes/text.html'], tests_run)
+ os.remove(filename)
+ res, out, err, user = logging_run(['--test-list=%s' % filename],
+ tests_included=True)
+ self.assertEqual(res, -1)
+ self.assertFalse(err.empty())
+
+ def test_unexpected_failures(self):
+ # Run tests including the unexpected failures.
+ self._url_opened = None
+ res, out, err, user = logging_run(tests_included=True)
+ self.assertEqual(res, 3)
+ self.assertFalse(out.empty())
+ self.assertFalse(err.empty())
+ self.assertEqual(user.url, '/tmp/layout-test-results/results.html')
+
+ def test_exit_after_n_failures(self):
+ # Unexpected failures should result in tests stopping.
+ tests_run = get_tests_run([
+ 'failures/unexpected/text-image-checksum.html',
+ 'passes/text.html',
+ '--exit-after-n-failures', '1',
+ ],
+ tests_included=True,
+ flatten_batches=True)
+ self.assertEquals(['failures/unexpected/text-image-checksum.html'], tests_run)
+
+ # But we'll keep going for expected ones.
+ tests_run = get_tests_run([
+ 'failures/expected/text.html',
+ 'passes/text.html',
+ '--exit-after-n-failures', '1',
+ ],
+ tests_included=True,
+ flatten_batches=True)
+ self.assertEquals(['failures/expected/text.html', 'passes/text.html'], tests_run)
+
+ def test_exit_after_n_crashes(self):
+ # Unexpected crashes should result in tests stopping.
+ tests_run = get_tests_run([
+ 'failures/unexpected/crash.html',
+ 'passes/text.html',
+ '--exit-after-n-crashes-or-timeouts', '1',
+ ],
+ tests_included=True,
+ flatten_batches=True)
+ self.assertEquals(['failures/unexpected/crash.html'], tests_run)
+
+ # Same with timeouts.
+ tests_run = get_tests_run([
+ 'failures/unexpected/timeout.html',
+ 'passes/text.html',
+ '--exit-after-n-crashes-or-timeouts', '1',
+ ],
+ tests_included=True,
+ flatten_batches=True)
+ self.assertEquals(['failures/unexpected/timeout.html'], tests_run)
+
+ # But we'll keep going for expected ones.
+ tests_run = get_tests_run([
+ 'failures/expected/crash.html',
+ 'passes/text.html',
+ '--exit-after-n-crashes-or-timeouts', '1',
+ ],
+ tests_included=True,
+ flatten_batches=True)
+ self.assertEquals(['failures/expected/crash.html', 'passes/text.html'], tests_run)
+
+ def test_results_directory_absolute(self):
+ # We run a configuration that should fail, to generate output, then
+ # look for what the output results url was.
+
+ tmpdir = tempfile.mkdtemp()
+ res, out, err, user = logging_run(['--results-directory=' + tmpdir],
+ tests_included=True)
+ self.assertEqual(user.url, os.path.join(tmpdir, 'results.html'))
+ shutil.rmtree(tmpdir, ignore_errors=True)
+
+ def test_results_directory_default(self):
+ # We run a configuration that should fail, to generate output, then
+ # look for what the output results url was.
+
+ # This is the default location.
+ res, out, err, user = logging_run(tests_included=True)
+ self.assertEqual(user.url, '/tmp/layout-test-results/results.html')
+
+ def test_results_directory_relative(self):
+ # We run a configuration that should fail, to generate output, then
+ # look for what the output results url was.
+
+ res, out, err, user = logging_run(['--results-directory=foo'],
+ tests_included=True)
+ self.assertEqual(user.url, '/tmp/foo/results.html')
+
+ def test_tolerance(self):
+ class ImageDiffTestPort(TestPort):
+ def diff_image(self, expected_contents, actual_contents,
+ diff_filename=None):
+ self.tolerance_used_for_diff_image = self._options.tolerance
+ return True
+
+ def get_port_for_run(args):
+ options, parsed_args = run_webkit_tests.parse_args(args)
+ test_port = ImageDiffTestPort(options=options, user=MockUser())
+ passing_run(args, port_obj=test_port, tests_included=True)
+ return test_port
+
+ base_args = ['--pixel-tests', 'failures/expected/*']
+
+ # If we pass in an explicit tolerance argument, then that will be used.
+ test_port = get_port_for_run(base_args + ['--tolerance', '.1'])
+ self.assertEqual(0.1, test_port.tolerance_used_for_diff_image)
+ test_port = get_port_for_run(base_args + ['--tolerance', '0'])
+ self.assertEqual(0, test_port.tolerance_used_for_diff_image)
+
+ # Otherwise the port's default tolerance behavior (including ignoring it)
+ # should be used.
+ test_port = get_port_for_run(base_args)
+ self.assertEqual(None, test_port.tolerance_used_for_diff_image)
+
+ def test_worker_model__inline(self):
+ self.assertTrue(passing_run(['--worker-model', 'old-inline']))
+
+ def test_worker_model__threads(self):
+ self.assertTrue(passing_run(['--worker-model', 'old-threads']))
+
+ def test_worker_model__unknown(self):
+ self.assertRaises(ValueError, logging_run,
+ ['--worker-model', 'unknown'])
+
+MainTest = skip_if(MainTest, sys.platform == 'cygwin' and compare_version(sys, '2.6')[0] < 0, 'new-run-webkit-tests tests hang on Cygwin Python 2.5.2')
+
+
+
+def _mocked_open(original_open, file_list):
+ def _wrapper(name, mode, encoding):
+ if name.find("-expected.") != -1 and mode.find("w") != -1:
+ # we don't want to actually write new baselines, so stub these out
+ name.replace('\\', '/')
+ file_list.append(name)
+ return original_open(os.devnull, mode, encoding)
+ return original_open(name, mode, encoding)
+ return _wrapper
+
+
+class RebaselineTest(unittest.TestCase):
+ def assertBaselines(self, file_list, file):
+ "assert that the file_list contains the baselines."""
+ for ext in [".txt", ".png", ".checksum"]:
+ baseline = file + "-expected" + ext
+ self.assertTrue(any(f.find(baseline) != -1 for f in file_list))
+
+ # FIXME: Add tests to ensure that we're *not* writing baselines when we're not
+ # supposed to be.
+
+ def disabled_test_reset_results(self):
+ # FIXME: This test is disabled until we can rewrite it to use a
+ # mock filesystem.
+ #
+ # Test that we update expectations in place. If the expectation
+ # is missing, update the expected generic location.
+ file_list = []
+ passing_run(['--pixel-tests',
+ '--reset-results',
+ 'passes/image.html',
+ 'failures/expected/missing_image.html'],
+ tests_included=True)
+ self.assertEqual(len(file_list), 6)
+ self.assertBaselines(file_list,
+ "data/passes/image")
+ self.assertBaselines(file_list,
+ "data/failures/expected/missing_image")
+
+ def disabled_test_new_baseline(self):
+ # FIXME: This test is disabled until we can rewrite it to use a
+ # mock filesystem.
+ #
+ # Test that we update the platform expectations. If the expectation
+ # is mssing, then create a new expectation in the platform dir.
+ file_list = []
+ original_open = codecs.open
+ try:
+ # Test that we update the platform expectations. If the expectation
+ # is mssing, then create a new expectation in the platform dir.
+ file_list = []
+ codecs.open = _mocked_open(original_open, file_list)
+ passing_run(['--pixel-tests',
+ '--new-baseline',
+ 'passes/image.html',
+ 'failures/expected/missing_image.html'],
+ tests_included=True)
+ self.assertEqual(len(file_list), 6)
+ self.assertBaselines(file_list,
+ "data/platform/test/passes/image")
+ self.assertBaselines(file_list,
+ "data/platform/test/failures/expected/missing_image")
+ finally:
+ codecs.open = original_open
+
+
+class DryrunTest(unittest.TestCase):
+ # FIXME: it's hard to know which platforms are safe to test; the
+ # chromium platforms require a chromium checkout, and the mac platform
+ # requires fcntl, so it can't be tested on win32, etc. There is
+ # probably a better way of handling this.
+ def test_darwin(self):
+ if sys.platform != "darwin":
+ return
+
+ self.assertTrue(passing_run(['--platform', 'test']))
+ self.assertTrue(passing_run(['--platform', 'dryrun',
+ 'fast/html']))
+ self.assertTrue(passing_run(['--platform', 'dryrun-mac',
+ 'fast/html']))
+
+ def test_test(self):
+ self.assertTrue(passing_run(['--platform', 'dryrun-test',
+ '--pixel-tests']))
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/__init__.py b/Tools/Scripts/webkitpy/layout_tests/test_types/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/test_types/__init__.py
diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py b/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py
new file mode 100644
index 0000000..da466c8
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/test_types/image_diff.py
@@ -0,0 +1,146 @@
+#!/usr/bin/env python
+# 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.
+
+"""Compares the image output of a test to the expected image output.
+
+Compares hashes for the generated and expected images. If the output doesn't
+match, returns FailureImageHashMismatch and outputs both hashes into the layout
+test results directory.
+"""
+
+from __future__ import with_statement
+
+import codecs
+import errno
+import logging
+import os
+import shutil
+
+from webkitpy.layout_tests.layout_package import test_failures
+from webkitpy.layout_tests.test_types import test_type_base
+
+# Cache whether we have the image_diff executable available.
+_compare_available = True
+_compare_msg_printed = False
+
+_log = logging.getLogger("webkitpy.layout_tests.test_types.image_diff")
+
+
+class ImageDiff(test_type_base.TestTypeBase):
+
+ def _save_baseline_files(self, filename, image, image_hash,
+ generate_new_baseline):
+ """Saves new baselines for the PNG and checksum.
+
+ Args:
+ filename: test filename
+ image: a image output
+ image_hash: a checksum of the image
+ generate_new_baseline: whether to generate a new, platform-specific
+ baseline, or update the existing one
+ """
+ self._save_baseline_data(filename, image, ".png", encoding=None,
+ generate_new_baseline=generate_new_baseline)
+ self._save_baseline_data(filename, image_hash, ".checksum",
+ encoding="ascii",
+ generate_new_baseline=generate_new_baseline)
+
+ def _copy_image(self, filename, actual_image, expected_image):
+ self.write_output_files(filename, '.png',
+ output=actual_image, expected=expected_image,
+ encoding=None, print_text_diffs=False)
+
+ def _copy_image_hash(self, filename, actual_image_hash, expected_image_hash):
+ self.write_output_files(filename, '.checksum',
+ actual_image_hash, expected_image_hash,
+ encoding="ascii", print_text_diffs=False)
+
+ def _create_diff_image(self, port, filename, actual_image, expected_image):
+ """Creates the visual diff of the expected/actual PNGs.
+
+ Returns True if the images are different.
+ """
+ diff_filename = self.output_filename(filename,
+ self.FILENAME_SUFFIX_COMPARE)
+ return port.diff_image(actual_image, expected_image, diff_filename)
+
+ def compare_output(self, port, filename, test_args, actual_test_output,
+ expected_test_output):
+ """Implementation of CompareOutput that checks the output image and
+ checksum against the expected files from the LayoutTest directory.
+ """
+ failures = []
+
+ # If we didn't produce a hash file, this test must be text-only.
+ if actual_test_output.image_hash is None:
+ return failures
+
+ # If we're generating a new baseline, we pass.
+ if test_args.new_baseline or test_args.reset_results:
+ self._save_baseline_files(filename, actual_test_output.image,
+ actual_test_output.image_hash,
+ test_args.new_baseline)
+ return failures
+
+ if not expected_test_output.image:
+ # Report a missing expected PNG file.
+ self._copy_image(filename, actual_test_output.image, expected_image=None)
+ self._copy_image_hash(filename, actual_test_output.image_hash,
+ expected_test_output.image_hash)
+ failures.append(test_failures.FailureMissingImage())
+ return failures
+ if not expected_test_output.image_hash:
+ # Report a missing expected checksum file.
+ self._copy_image(filename, actual_test_output.image,
+ expected_test_output.image)
+ self._copy_image_hash(filename, actual_test_output.image_hash,
+ expected_image_hash=None)
+ failures.append(test_failures.FailureMissingImageHash())
+ return failures
+
+ if actual_test_output.image_hash == expected_test_output.image_hash:
+ # Hash matched (no diff needed, okay to return).
+ return failures
+
+ self._copy_image(filename, actual_test_output.image,
+ expected_test_output.image)
+ self._copy_image_hash(filename, actual_test_output.image_hash,
+ expected_test_output.image_hash)
+
+ # Even though we only use the result in one codepath below but we
+ # still need to call CreateImageDiff for other codepaths.
+ images_are_different = self._create_diff_image(port, filename,
+ actual_test_output.image,
+ expected_test_output.image)
+ if not images_are_different:
+ failures.append(test_failures.FailureImageHashIncorrect())
+ else:
+ failures.append(test_failures.FailureImageHashMismatch())
+
+ return failures
diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py b/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py
new file mode 100644
index 0000000..4b96b3a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base.py
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+# 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.
+
+"""Defines the interface TestTypeBase which other test types inherit from.
+
+Also defines the TestArguments "struct" to pass them additional arguments.
+"""
+
+from __future__ import with_statement
+
+import codecs
+import cgi
+import errno
+import logging
+import os.path
+
+_log = logging.getLogger("webkitpy.layout_tests.test_types.test_type_base")
+
+
+class TestArguments(object):
+ """Struct-like wrapper for additional arguments needed by
+ specific tests."""
+ # Whether to save new baseline results.
+ new_baseline = False
+
+ # Path to the actual PNG file generated by pixel tests
+ png_path = None
+
+ # Value of checksum generated by pixel tests.
+ hash = None
+
+ # Whether to use wdiff to generate by-word diffs.
+ wdiff = False
+
+# Python bug workaround. See the wdiff code in WriteOutputFiles for an
+# explanation.
+_wdiff_available = True
+
+
+class TestTypeBase(object):
+
+ # Filename pieces when writing failures to the test results directory.
+ FILENAME_SUFFIX_ACTUAL = "-actual"
+ FILENAME_SUFFIX_EXPECTED = "-expected"
+ FILENAME_SUFFIX_DIFF = "-diff"
+ FILENAME_SUFFIX_WDIFF = "-wdiff.html"
+ FILENAME_SUFFIX_PRETTY_PATCH = "-pretty-diff.html"
+ FILENAME_SUFFIX_COMPARE = "-diff.png"
+
+ def __init__(self, port, root_output_dir):
+ """Initialize a TestTypeBase object.
+
+ Args:
+ port: object implementing port-specific information and methods
+ root_output_dir: The unix style path to the output dir.
+ """
+ self._root_output_dir = root_output_dir
+ self._port = port
+
+ def _make_output_directory(self, filename):
+ """Creates the output directory (if needed) for a given test
+ filename."""
+ output_filename = os.path.join(self._root_output_dir,
+ self._port.relative_test_filename(filename))
+ self._port.maybe_make_directory(os.path.split(output_filename)[0])
+
+ def _save_baseline_data(self, filename, data, modifier, encoding,
+ generate_new_baseline=True):
+ """Saves a new baseline file into the port's baseline directory.
+
+ The file will be named simply "<test>-expected<modifier>", suitable for
+ use as the expected results in a later run.
+
+ Args:
+ filename: path to the test file
+ data: result to be saved as the new baseline
+ modifier: type of the result file, e.g. ".txt" or ".png"
+ encoding: file encoding (none, "utf-8", etc.)
+ generate_new_baseline: whether to enerate a new, platform-specific
+ baseline, or update the existing one
+ """
+
+ if generate_new_baseline:
+ relative_dir = os.path.dirname(
+ self._port.relative_test_filename(filename))
+ baseline_path = self._port.baseline_path()
+ output_dir = os.path.join(baseline_path, relative_dir)
+ output_file = os.path.basename(os.path.splitext(filename)[0] +
+ self.FILENAME_SUFFIX_EXPECTED + modifier)
+ self._port.maybe_make_directory(output_dir)
+ output_path = os.path.join(output_dir, output_file)
+ _log.debug('writing new baseline result "%s"' % (output_path))
+ else:
+ output_path = self._port.expected_filename(filename, modifier)
+ _log.debug('resetting baseline result "%s"' % output_path)
+
+ self._port.update_baseline(output_path, data, encoding)
+
+ def output_filename(self, filename, modifier):
+ """Returns a filename inside the output dir that contains modifier.
+
+ For example, if filename is c:/.../fast/dom/foo.html and modifier is
+ "-expected.txt", the return value is
+ c:/cygwin/tmp/layout-test-results/fast/dom/foo-expected.txt
+
+ Args:
+ filename: absolute filename to test file
+ modifier: a string to replace the extension of filename with
+
+ Return:
+ The absolute windows path to the output filename
+ """
+ output_filename = os.path.join(self._root_output_dir,
+ self._port.relative_test_filename(filename))
+ return os.path.splitext(output_filename)[0] + modifier
+
+ def compare_output(self, port, filename, test_args, actual_test_output,
+ expected_test_output):
+ """Method that compares the output from the test with the
+ expected value.
+
+ This is an abstract method to be implemented by all sub classes.
+
+ Args:
+ port: object implementing port-specific information and methods
+ filename: absolute filename to test file
+ test_args: a TestArguments object holding optional additional
+ arguments
+ actual_test_output: a TestOutput object which represents actual test
+ output
+ expected_test_output: a TestOutput object which represents a expected
+ test output
+
+ Return:
+ a list of TestFailure objects, empty if the test passes
+ """
+ raise NotImplementedError
+
+ def _write_into_file_at_path(self, file_path, contents, encoding):
+ """This method assumes that byte_array is already encoded
+ into the right format."""
+ open_mode = 'w'
+ if encoding is None:
+ open_mode = 'w+b'
+ with codecs.open(file_path, open_mode, encoding=encoding) as file:
+ file.write(contents)
+
+ def write_output_files(self, filename, file_type,
+ output, expected, encoding,
+ print_text_diffs=False):
+ """Writes the test output, the expected output and optionally the diff
+ between the two to files in the results directory.
+
+ The full output filename of the actual, for example, will be
+ <filename>-actual<file_type>
+ For instance,
+ my_test-actual.txt
+
+ Args:
+ filename: The test filename
+ file_type: A string describing the test output file type, e.g. ".txt"
+ output: A string containing the test output
+ expected: A string containing the expected test output
+ print_text_diffs: True for text diffs. (FIXME: We should be able to get this from the file type?)
+ """
+ self._make_output_directory(filename)
+ actual_filename = self.output_filename(filename, self.FILENAME_SUFFIX_ACTUAL + file_type)
+ expected_filename = self.output_filename(filename, self.FILENAME_SUFFIX_EXPECTED + file_type)
+ # FIXME: This function is poorly designed. We should be passing in some sort of
+ # encoding information from the callers.
+ if output:
+ self._write_into_file_at_path(actual_filename, output, encoding)
+ if expected:
+ self._write_into_file_at_path(expected_filename, expected, encoding)
+
+ if not output or not expected:
+ return
+
+ if not print_text_diffs:
+ return
+
+ # Note: We pass encoding=None for all diff writes, as we treat diff
+ # output as binary. Diff output may contain multiple files in
+ # conflicting encodings.
+ diff = self._port.diff_text(expected, output, expected_filename, actual_filename)
+ diff_filename = self.output_filename(filename, self.FILENAME_SUFFIX_DIFF + file_type)
+ self._write_into_file_at_path(diff_filename, diff, encoding=None)
+
+ # Shell out to wdiff to get colored inline diffs.
+ wdiff = self._port.wdiff_text(expected_filename, actual_filename)
+ wdiff_filename = self.output_filename(filename, self.FILENAME_SUFFIX_WDIFF)
+ self._write_into_file_at_path(wdiff_filename, wdiff, encoding=None)
+
+ # Use WebKit's PrettyPatch.rb to get an HTML diff.
+ pretty_patch = self._port.pretty_patch_text(diff_filename)
+ pretty_patch_filename = self.output_filename(filename, self.FILENAME_SUFFIX_PRETTY_PATCH)
+ self._write_into_file_at_path(pretty_patch_filename, pretty_patch, encoding=None)
diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py b/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py
new file mode 100644
index 0000000..5dbfcb6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/test_types/test_type_base_unittest.py
@@ -0,0 +1,47 @@
+# 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.
+
+""""Tests stray tests not covered by regular code paths."""
+
+import test_type_base
+import unittest
+
+from webkitpy.thirdparty.mock import Mock
+
+
+class Test(unittest.TestCase):
+
+ def test_compare_output_notimplemented(self):
+ test_type = test_type_base.TestTypeBase(None, None)
+ self.assertRaises(NotImplementedError, test_type.compare_output,
+ None, "foo.txt", '',
+ test_type_base.TestArguments(), 'Debug')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py b/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py
new file mode 100644
index 0000000..ad25262
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/test_types/text_diff.py
@@ -0,0 +1,93 @@
+#!/usr/bin/env python
+# 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.
+
+"""Compares the text output of a test to the expected text output.
+
+If the output doesn't match, returns FailureTextMismatch and outputs the diff
+files into the layout test results directory.
+"""
+
+from __future__ import with_statement
+
+import codecs
+import errno
+import logging
+import os.path
+
+from webkitpy.layout_tests.layout_package import test_failures
+from webkitpy.layout_tests.test_types import test_type_base
+
+_log = logging.getLogger("webkitpy.layout_tests.test_types.text_diff")
+
+
+class TestTextDiff(test_type_base.TestTypeBase):
+
+ def _get_normalized_output_text(self, output):
+ """Returns the normalized text output, i.e. the output in which
+ the end-of-line characters are normalized to "\n"."""
+ # Running tests on Windows produces "\r\n". The "\n" part is helpfully
+ # changed to "\r\n" by our system (Python/Cygwin), resulting in
+ # "\r\r\n", when, in fact, we wanted to compare the text output with
+ # the normalized text expectation files.
+ return output.replace("\r\r\n", "\r\n").replace("\r\n", "\n")
+
+ def compare_output(self, port, filename, test_args, actual_test_output,
+ expected_test_output):
+ """Implementation of CompareOutput that checks the output text against
+ the expected text from the LayoutTest directory."""
+ failures = []
+
+ # If we're generating a new baseline, we pass.
+ if test_args.new_baseline or test_args.reset_results:
+ # Although all test_shell/DumpRenderTree output should be utf-8,
+ # we do not ever decode it inside run-webkit-tests. For some tests
+ # DumpRenderTree may not output utf-8 text (e.g. webarchives).
+ self._save_baseline_data(filename, actual_test_output.text,
+ ".txt", encoding=None,
+ generate_new_baseline=test_args.new_baseline)
+ return failures
+
+ # Normalize text to diff
+ actual_text = self._get_normalized_output_text(actual_test_output.text)
+ # Assuming expected_text is already normalized.
+ expected_text = expected_test_output.text
+
+ # Write output files for new tests, too.
+ if port.compare_text(actual_text, expected_text):
+ # Text doesn't match, write output files.
+ self.write_output_files(filename, ".txt", actual_text,
+ expected_text, encoding=None,
+ print_text_diffs=True)
+
+ if expected_text == '':
+ failures.append(test_failures.FailureMissingResult())
+ else:
+ failures.append(test_failures.FailureTextMismatch())
+
+ return failures
diff --git a/Tools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests.py b/Tools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests.py
new file mode 100755
index 0000000..f4c8098
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests.py
@@ -0,0 +1,160 @@
+#!/usr/bin/env python
+
+# 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 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.
+
+from __future__ import with_statement
+
+import glob
+import logging
+import optparse
+import os
+import re
+import sys
+import webkitpy.common.checkout.scm as scm
+
+_log = logging.getLogger("webkitpy.layout_tests."
+ "update-webgl-conformance-tests")
+
+
+def remove_first_line_comment(text):
+ return re.compile(r'^<!--.*?-->\s*', re.DOTALL).sub('', text)
+
+
+def translate_includes(text):
+ # Mapping of single filename to relative path under WebKit root.
+ # Assumption: these filenames are globally unique.
+ include_mapping = {
+ "js-test-style.css": "../../js/resources",
+ "js-test-pre.js": "../../js/resources",
+ "js-test-post.js": "../../js/resources",
+ "desktop-gl-constants.js": "resources",
+ }
+
+ for filename, path in include_mapping.items():
+ search = r'(?:[^"\'= ]*/)?' + re.escape(filename)
+ replace = os.path.join(path, filename)
+ text = re.sub(search, replace, text)
+
+ return text
+
+
+def translate_khronos_test(text):
+ """
+ This method translates the contents of a Khronos test to a WebKit test.
+ """
+
+ translateFuncs = [
+ remove_first_line_comment,
+ translate_includes,
+ ]
+
+ for f in translateFuncs:
+ text = f(text)
+
+ return text
+
+
+def update_file(in_filename, out_dir):
+ # check in_filename exists
+ # check out_dir exists
+ out_filename = os.path.join(out_dir, os.path.basename(in_filename))
+
+ _log.debug("Processing " + in_filename)
+ with open(in_filename, 'r') as in_file:
+ with open(out_filename, 'w') as out_file:
+ out_file.write(translate_khronos_test(in_file.read()))
+
+
+def update_directory(in_dir, out_dir):
+ for filename in glob.glob(os.path.join(in_dir, '*.html')):
+ update_file(os.path.join(in_dir, filename), out_dir)
+
+
+def default_out_dir():
+ current_scm = scm.detect_scm_system(os.path.dirname(sys.argv[0]))
+ if not current_scm:
+ return os.getcwd()
+ root_dir = current_scm.checkout_root
+ if not root_dir:
+ return os.getcwd()
+ out_dir = os.path.join(root_dir, "LayoutTests/fast/canvas/webgl")
+ if os.path.isdir(out_dir):
+ return out_dir
+ return os.getcwd()
+
+
+def configure_logging(options):
+ """Configures the logging system."""
+ log_fmt = '%(levelname)s: %(message)s'
+ log_datefmt = '%y%m%d %H:%M:%S'
+ log_level = logging.INFO
+ if options.verbose:
+ log_fmt = ('%(asctime)s %(filename)s:%(lineno)-4d %(levelname)s '
+ '%(message)s')
+ log_level = logging.DEBUG
+ logging.basicConfig(level=log_level, format=log_fmt,
+ datefmt=log_datefmt)
+
+
+def option_parser():
+ usage = "usage: %prog [options] (input file or directory)"
+ parser = optparse.OptionParser(usage=usage)
+ parser.add_option('-v', '--verbose',
+ action='store_true',
+ default=False,
+ help='include debug-level logging')
+ parser.add_option('-o', '--output',
+ action='store',
+ type='string',
+ default=default_out_dir(),
+ metavar='DIR',
+ help='specify an output directory to place files '
+ 'in [default: %default]')
+ return parser
+
+
+def main():
+ parser = option_parser()
+ (options, args) = parser.parse_args()
+ configure_logging(options)
+
+ if len(args) == 0:
+ _log.error("Must specify an input directory or filename.")
+ parser.print_help()
+ return 1
+
+ in_name = args[0]
+ if os.path.isfile(in_name):
+ update_file(in_name, options.output)
+ elif os.path.isdir(in_name):
+ update_directory(in_name, options.output)
+ else:
+ _log.error("'%s' is not a directory or a file.", in_name)
+ return 2
+
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/Tools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests_unittest.py b/Tools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests_unittest.py
new file mode 100644
index 0000000..7393b70
--- /dev/null
+++ b/Tools/Scripts/webkitpy/layout_tests/update_webgl_conformance_tests_unittest.py
@@ -0,0 +1,102 @@
+#!/usr/bin/python
+# 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.
+
+"""Unit tests for update_webgl_conformance_tests."""
+
+import unittest
+from webkitpy.layout_tests import update_webgl_conformance_tests as webgl
+
+
+def construct_script(name):
+ return "<script src=\"" + name + "\"></script>\n"
+
+
+def construct_style(name):
+ return "<link rel=\"stylesheet\" href=\"" + name + "\">"
+
+
+class TestTranslation(unittest.TestCase):
+ def assert_unchanged(self, text):
+ self.assertEqual(text, webgl.translate_khronos_test(text))
+
+ def assert_translate(self, input, output):
+ self.assertEqual(output, webgl.translate_khronos_test(input))
+
+ def test_simple_unchanged(self):
+ self.assert_unchanged("")
+ self.assert_unchanged("<html></html>")
+
+ def test_header_strip(self):
+ single_line_header = "<!-- single line header. -->"
+ multi_line_header = """<!-- this is a multi-line
+ header. it should all be removed too.
+ -->"""
+ text = "<html></html>"
+ self.assert_translate(single_line_header, "")
+ self.assert_translate(single_line_header + text, text)
+ self.assert_translate(multi_line_header + text, text)
+
+ def dont_strip_other_headers(self):
+ self.assert_unchanged("<html>\n<!-- don't remove comments on other lines. -->\n</html>")
+
+ def test_include_rewriting(self):
+ # Mappings to None are unchanged
+ styles = {
+ "../resources/js-test-style.css": "../../js/resources/js-test-style.css",
+ "fail.css": None,
+ "resources/stylesheet.css": None,
+ "../resources/style.css": None,
+ }
+ scripts = {
+ "../resources/js-test-pre.js": "../../js/resources/js-test-pre.js",
+ "../resources/js-test-post.js": "../../js/resources/js-test-post.js",
+ "../resources/desktop-gl-constants.js": "resources/desktop-gl-constants.js",
+
+ "resources/shadow-offset.js": None,
+ "../resources/js-test-post-async.js": None,
+ }
+
+ input_text = ""
+ output_text = ""
+ for input, output in styles.items():
+ input_text += construct_style(input)
+ output_text += construct_style(output if output else input)
+ for input, output in scripts.items():
+ input_text += construct_script(input)
+ output_text += construct_script(output if output else input)
+
+ head = '<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">\n<html>\n<head>\n'
+ foot = '</head>\n<body>\n</body>\n</html>'
+ input_text = head + input_text + foot
+ output_text = head + output_text + foot
+ self.assert_translate(input_text, output_text)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/python24/__init__.py b/Tools/Scripts/webkitpy/python24/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/python24/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/python24/versioning.py b/Tools/Scripts/webkitpy/python24/versioning.py
new file mode 100644
index 0000000..8b1f21b
--- /dev/null
+++ b/Tools/Scripts/webkitpy/python24/versioning.py
@@ -0,0 +1,133 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Supports Python version checking."""
+
+import logging
+import sys
+
+_log = logging.getLogger("webkitpy.python24.versioning")
+
+# The minimum Python version the webkitpy package supports.
+_MINIMUM_SUPPORTED_PYTHON_VERSION = "2.5"
+
+
+def compare_version(sysmodule=None, target_version=None):
+ """Compare the current Python version with a target version.
+
+ Args:
+ sysmodule: An object with version and version_info data attributes
+ used to detect the current Python version. The attributes
+ should have the same semantics as sys.version and
+ sys.version_info. This parameter should only be used
+ for unit testing. Defaults to sys.
+ target_version: A string representing the Python version to compare
+ the current version against. The string should have
+ one of the following three forms: 2, 2.5, or 2.5.3.
+ Defaults to the minimum version that the webkitpy
+ package supports.
+
+ Returns:
+ A triple of (comparison, current_version, target_version).
+
+ comparison: An integer representing the result of comparing the
+ current version with the target version. A positive
+ number means the current version is greater than the
+ target, 0 means they are the same, and a negative number
+ means the current version is less than the target.
+ This method compares version information only up
+ to the precision of the given target version. For
+ example, if the target version is 2.6 and the current
+ version is 2.5.3, this method uses 2.5 for the purposes
+ of comparing with the target.
+ current_version: A string representing the current Python version, for
+ example 2.5.3.
+ target_version: A string representing the version that the current
+ version was compared against, for example 2.5.
+
+ """
+ if sysmodule is None:
+ sysmodule = sys
+ if target_version is None:
+ target_version = _MINIMUM_SUPPORTED_PYTHON_VERSION
+
+ # The number of version parts to compare.
+ precision = len(target_version.split("."))
+
+ # We use sys.version_info rather than sys.version since its first
+ # three elements are guaranteed to be integers.
+ current_version_info_to_compare = sysmodule.version_info[:precision]
+ # Convert integers to strings.
+ current_version_info_to_compare = map(str, current_version_info_to_compare)
+ current_version_to_compare = ".".join(current_version_info_to_compare)
+
+ # Compare version strings lexicographically.
+ if current_version_to_compare > target_version:
+ comparison = 1
+ elif current_version_to_compare == target_version:
+ comparison = 0
+ else:
+ comparison = -1
+
+ # The version number portion of the current version string, for
+ # example "2.6.4".
+ current_version = sysmodule.version.split()[0]
+
+ return (comparison, current_version, target_version)
+
+
+# FIXME: Add a logging level parameter to allow the version message
+# to be logged at levels other than WARNING, for example CRITICAL.
+def check_version(log=None, sysmodule=None, target_version=None):
+ """Check the current Python version against a target version.
+
+ Logs a warning message if the current version is less than the
+ target version.
+
+ Args:
+ log: A logging.logger instance to use when logging the version warning.
+ Defaults to the logger of this module.
+ sysmodule: See the compare_version() docstring.
+ target_version: See the compare_version() docstring.
+
+ Returns:
+ A boolean value of whether the current version is greater than
+ or equal to the target version.
+
+ """
+ if log is None:
+ log = _log
+
+ (comparison, current_version, target_version) = \
+ compare_version(sysmodule, target_version)
+
+ if comparison >= 0:
+ # Then the current version is at least the minimum version.
+ return True
+
+ message = ("WebKit Python scripts do not support your current Python "
+ "version (%s). The minimum supported version is %s.\n"
+ " See the following page to upgrade your Python version:\n\n"
+ " http://trac.webkit.org/wiki/PythonGuidelines\n"
+ % (current_version, target_version))
+ log.warn(message)
+ return False
diff --git a/Tools/Scripts/webkitpy/python24/versioning_unittest.py b/Tools/Scripts/webkitpy/python24/versioning_unittest.py
new file mode 100644
index 0000000..6939e2d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/python24/versioning_unittest.py
@@ -0,0 +1,134 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Contains unit tests for versioning.py."""
+
+import logging
+import unittest
+
+from webkitpy.common.system.logtesting import LogTesting
+from webkitpy.python24.versioning import check_version
+from webkitpy.python24.versioning import compare_version
+
+class MockSys(object):
+
+ """A mock sys module for passing to version-checking methods."""
+
+ def __init__(self, current_version):
+ """Create an instance.
+
+ current_version: A version string with major, minor, and micro
+ version parts.
+
+ """
+ version_info = current_version.split(".")
+ version_info = map(int, version_info)
+
+ self.version = current_version + " Version details."
+ self.version_info = version_info
+
+
+class CompareVersionTest(unittest.TestCase):
+
+ """Tests compare_version()."""
+
+ def _mock_sys(self, current_version):
+ return MockSys(current_version)
+
+ def test_default_minimum_version(self):
+ """Test the configured minimum version that webkitpy supports."""
+ (comparison, current_version, min_version) = compare_version()
+ self.assertEquals(min_version, "2.5")
+
+ def compare_version(self, target_version, current_version=None):
+ """Call compare_version()."""
+ if current_version is None:
+ current_version = "2.5.3"
+ mock_sys = self._mock_sys(current_version)
+ return compare_version(mock_sys, target_version)
+
+ def compare(self, target_version, current_version=None):
+ """Call compare_version(), and return the comparison."""
+ return self.compare_version(target_version, current_version)[0]
+
+ def test_returned_current_version(self):
+ """Test the current_version return value."""
+ current_version = self.compare_version("2.5")[1]
+ self.assertEquals(current_version, "2.5.3")
+
+ def test_returned_target_version(self):
+ """Test the current_version return value."""
+ target_version = self.compare_version("2.5")[2]
+ self.assertEquals(target_version, "2.5")
+
+ def test_target_version_major(self):
+ """Test major version for target."""
+ self.assertEquals(-1, self.compare("3"))
+ self.assertEquals(0, self.compare("2"))
+ self.assertEquals(1, self.compare("2", "3.0.0"))
+
+ def test_target_version_minor(self):
+ """Test minor version for target."""
+ self.assertEquals(-1, self.compare("2.6"))
+ self.assertEquals(0, self.compare("2.5"))
+ self.assertEquals(1, self.compare("2.4"))
+
+ def test_target_version_micro(self):
+ """Test minor version for target."""
+ self.assertEquals(-1, self.compare("2.5.4"))
+ self.assertEquals(0, self.compare("2.5.3"))
+ self.assertEquals(1, self.compare("2.5.2"))
+
+
+class CheckVersionTest(unittest.TestCase):
+
+ """Tests check_version()."""
+
+ def setUp(self):
+ self._log = LogTesting.setUp(self)
+
+ def tearDown(self):
+ self._log.tearDown()
+
+ def _check_version(self, minimum_version):
+ """Call check_version()."""
+ mock_sys = MockSys("2.5.3")
+ return check_version(sysmodule=mock_sys, target_version=minimum_version)
+
+ def test_true_return_value(self):
+ """Test the configured minimum version that webkitpy supports."""
+ is_current = self._check_version("2.4")
+ self.assertEquals(True, is_current)
+ self._log.assertMessages([]) # No warning was logged.
+
+ def test_false_return_value(self):
+ """Test the configured minimum version that webkitpy supports."""
+ is_current = self._check_version("2.6")
+ self.assertEquals(False, is_current)
+ expected_message = ('WARNING: WebKit Python scripts do not support '
+ 'your current Python version (2.5.3). '
+ 'The minimum supported version is 2.6.\n '
+ 'See the following page to upgrade your Python '
+ 'version:\n\n '
+ 'http://trac.webkit.org/wiki/PythonGuidelines\n\n')
+ self._log.assertMessages([expected_message])
+
diff --git a/Tools/Scripts/webkitpy/style/__init__.py b/Tools/Scripts/webkitpy/style/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/style/checker.py b/Tools/Scripts/webkitpy/style/checker.py
new file mode 100644
index 0000000..6f1beb0
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checker.py
@@ -0,0 +1,749 @@
+# Copyright (C) 2009 Google Inc. All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+# Copyright (C) 2010 ProFUSION embedded systems
+#
+# 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.
+
+"""Front end of some style-checker modules."""
+
+import logging
+import os.path
+import sys
+
+from checkers.common import categories as CommonCategories
+from checkers.common import CarriageReturnChecker
+from checkers.cpp import CppChecker
+from checkers.python import PythonChecker
+from checkers.test_expectations import TestExpectationsChecker
+from checkers.text import TextChecker
+from checkers.xml import XMLChecker
+from error_handlers import DefaultStyleErrorHandler
+from filter import FilterConfiguration
+from optparser import ArgumentParser
+from optparser import DefaultCommandOptionValues
+from webkitpy.style_references import configure_logging as _configure_logging
+
+_log = logging.getLogger("webkitpy.style.checker")
+
+# These are default option values for the command-line option parser.
+_DEFAULT_MIN_CONFIDENCE = 1
+_DEFAULT_OUTPUT_FORMAT = 'emacs'
+
+
+# FIXME: For style categories we will never want to have, remove them.
+# For categories for which we want to have similar functionality,
+# modify the implementation and enable them.
+#
+# Throughout this module, we use "filter rule" rather than "filter"
+# for an individual boolean filter flag like "+foo". This allows us to
+# reserve "filter" for what one gets by collectively applying all of
+# the filter rules.
+#
+# The base filter rules are the filter rules that begin the list of
+# filter rules used to check style. For example, these rules precede
+# any user-specified filter rules. Since by default all categories are
+# checked, this list should normally include only rules that begin
+# with a "-" sign.
+_BASE_FILTER_RULES = [
+ '-build/endif_comment',
+ '-build/include_what_you_use', # <string> for std::string
+ '-build/storage_class', # const static
+ '-legal/copyright',
+ '-readability/multiline_comment',
+ '-readability/braces', # int foo() {};
+ '-readability/fn_size',
+ '-readability/casting',
+ '-readability/function',
+ '-runtime/arrays', # variable length array
+ '-runtime/casting',
+ '-runtime/sizeof',
+ '-runtime/explicit', # explicit
+ '-runtime/virtual', # virtual dtor
+ '-runtime/printf',
+ '-runtime/threadsafe_fn',
+ '-runtime/rtti',
+ '-whitespace/blank_line',
+ '-whitespace/end_of_line',
+ '-whitespace/labels',
+ # List Python pep8 categories last.
+ #
+ # Because much of WebKit's Python code base does not abide by the
+ # PEP8 79 character limit, we ignore the 79-character-limit category
+ # pep8/E501 for now.
+ #
+ # FIXME: Consider bringing WebKit's Python code base into conformance
+ # with the 79 character limit, or some higher limit that is
+ # agreeable to the WebKit project.
+ '-pep8/E501',
+ ]
+
+
+# The path-specific filter rules.
+#
+# This list is order sensitive. Only the first path substring match
+# is used. See the FilterConfiguration documentation in filter.py
+# for more information on this list.
+#
+# Each string appearing in this nested list should have at least
+# one associated unit test assertion. These assertions are located,
+# for example, in the test_path_rules_specifier() unit test method of
+# checker_unittest.py.
+_PATH_RULES_SPECIFIER = [
+ # Files in these directories are consumers of the WebKit
+ # API and therefore do not follow the same header including
+ # discipline as WebCore.
+
+ ([# TestNetscapePlugIn has no config.h and uses funny names like
+ # NPP_SetWindow.
+ "Tools/DumpRenderTree/TestNetscapePlugIn/",
+ # The API test harnesses have no config.h and use funny macros like
+ # TEST_CLASS_NAME.
+ "Tools/WebKitAPITest/",
+ "Tools/TestWebKitAPI/"],
+ ["-build/include",
+ "-readability/naming"]),
+ ([# The EFL APIs use EFL naming style, which includes
+ # both lower-cased and camel-cased, underscore-sparated
+ # values.
+ "WebKit/efl/ewk/",
+ # There is no clean way to avoid "yy_*" names used by flex.
+ "WebCore/css/CSSParser.cpp",
+ # Qt code uses '_' in some places (such as private slots
+ # and on test xxx_data methos on tests)
+ "JavaScriptCore/qt/api/",
+ "WebKit/qt/Api/",
+ "WebKit/qt/tests/",
+ "WebKit/qt/declarative/",
+ "WebKit/qt/examples/"],
+ ["-readability/naming"]),
+ ([# The GTK+ APIs use GTK+ naming style, which includes
+ # lower-cased, underscore-separated values.
+ # Also, GTK+ allows the use of NULL.
+ "WebCore/bindings/scripts/test/GObject",
+ "WebKit/gtk/webkit/",
+ "Tools/DumpRenderTree/gtk/"],
+ ["-readability/naming",
+ "-readability/null"]),
+ ([# Header files in ForwardingHeaders have no header guards or
+ # exceptional header guards (e.g., WebCore_FWD_Debugger_h).
+ "/ForwardingHeaders/"],
+ ["-build/header_guard"]),
+ ([# assembler has lots of opcodes that use underscores, so
+ # we don't check for underscores in that directory.
+ "/JavaScriptCore/assembler/"],
+ ["-readability/naming"]),
+
+ # WebKit2 rules:
+ # WebKit2 doesn't use config.h, and certain directories have other
+ # idiosyncracies.
+ ([# NPAPI has function names with underscores.
+ "WebKit2/WebProcess/Plugins/Netscape"],
+ ["-build/include_order",
+ "-readability/naming"]),
+ ([# The WebKit2 C API has names with underscores and whitespace-aligned
+ # struct members.
+ "WebKit2/UIProcess/API/C/",
+ "WebKit2/WebProcess/InjectedBundle/API/c/"],
+ ["-build/include_order",
+ "-readability/naming",
+ "-whitespace/declaration"]),
+ ([# Nothing in WebKit2 uses config.h.
+ "WebKit2/"],
+ ["-build/include_order"]),
+
+ # For third-party Python code, keep only the following checks--
+ #
+ # No tabs: to avoid having to set the SVN allow-tabs property.
+ # No trailing white space: since this is easy to correct.
+ # No carriage-return line endings: since this is easy to correct.
+ #
+ (["webkitpy/thirdparty/"],
+ ["-",
+ "+pep8/W191", # Tabs
+ "+pep8/W291", # Trailing white space
+ "+whitespace/carriage_return"]),
+]
+
+
+_CPP_FILE_EXTENSIONS = [
+ 'c',
+ 'cpp',
+ 'h',
+ ]
+
+_PYTHON_FILE_EXTENSION = 'py'
+
+_TEXT_FILE_EXTENSIONS = [
+ 'ac',
+ 'cc',
+ 'cgi',
+ 'css',
+ 'exp',
+ 'flex',
+ 'gyp',
+ 'gypi',
+ 'html',
+ 'idl',
+ 'in',
+ 'js',
+ 'mm',
+ 'php',
+ 'pl',
+ 'pm',
+ 'pri',
+ 'pro',
+ 'rb',
+ 'sh',
+ 'txt',
+ 'wm',
+ 'xhtml',
+ 'y',
+ ]
+
+_XML_FILE_EXTENSIONS = [
+ 'vcproj',
+ 'vsprops',
+ ]
+
+# Files to skip that are less obvious.
+#
+# Some files should be skipped when checking style. For example,
+# WebKit maintains some files in Mozilla style on purpose to ease
+# future merges.
+_SKIPPED_FILES_WITH_WARNING = [
+ "gtk2drawing.c", # WebCore/platform/gtk/gtk2drawing.c
+ "gtkdrawing.h", # WebCore/platform/gtk/gtkdrawing.h
+ "WebKit/gtk/tests/",
+ # Soup API that is still being cooked, will be removed from WebKit
+ # in a few months when it is merged into soup proper. The style
+ # follows the libsoup style completely.
+ "WebCore/platform/network/soup/cache/",
+ ]
+
+
+# Files to skip that are more common or obvious.
+#
+# This list should be in addition to files with FileType.NONE. Files
+# with FileType.NONE are automatically skipped without warning.
+_SKIPPED_FILES_WITHOUT_WARNING = [
+ "LayoutTests/",
+ ]
+
+# Extensions of files which are allowed to contain carriage returns.
+_CARRIAGE_RETURN_ALLOWED_FILE_EXTENSIONS = [
+ 'vcproj',
+ 'vsprops',
+ ]
+
+# The maximum number of errors to report per file, per category.
+# If a category is not a key, then it has no maximum.
+_MAX_REPORTS_PER_CATEGORY = {
+ "whitespace/carriage_return": 1
+}
+
+
+def _all_categories():
+ """Return the set of all categories used by check-webkit-style."""
+ # Take the union across all checkers.
+ categories = CommonCategories.union(CppChecker.categories)
+ categories = categories.union(TestExpectationsChecker.categories)
+
+ # FIXME: Consider adding all of the pep8 categories. Since they
+ # are not too meaningful for documentation purposes, for
+ # now we add only the categories needed for the unit tests
+ # (which validate the consistency of the configuration
+ # settings against the known categories, etc).
+ categories = categories.union(["pep8/W191", "pep8/W291", "pep8/E501"])
+
+ return categories
+
+
+def _check_webkit_style_defaults():
+ """Return the default command-line options for check-webkit-style."""
+ return DefaultCommandOptionValues(min_confidence=_DEFAULT_MIN_CONFIDENCE,
+ output_format=_DEFAULT_OUTPUT_FORMAT)
+
+
+# This function assists in optparser not having to import from checker.
+def check_webkit_style_parser():
+ all_categories = _all_categories()
+ default_options = _check_webkit_style_defaults()
+ return ArgumentParser(all_categories=all_categories,
+ base_filter_rules=_BASE_FILTER_RULES,
+ default_options=default_options)
+
+
+def check_webkit_style_configuration(options):
+ """Return a StyleProcessorConfiguration instance for check-webkit-style.
+
+ Args:
+ options: A CommandOptionValues instance.
+
+ """
+ filter_configuration = FilterConfiguration(
+ base_rules=_BASE_FILTER_RULES,
+ path_specific=_PATH_RULES_SPECIFIER,
+ user_rules=options.filter_rules)
+
+ return StyleProcessorConfiguration(filter_configuration=filter_configuration,
+ max_reports_per_category=_MAX_REPORTS_PER_CATEGORY,
+ min_confidence=options.min_confidence,
+ output_format=options.output_format,
+ stderr_write=sys.stderr.write)
+
+
+def _create_log_handlers(stream):
+ """Create and return a default list of logging.Handler instances.
+
+ Format WARNING messages and above to display the logging level, and
+ messages strictly below WARNING not to display it.
+
+ Args:
+ stream: See the configure_logging() docstring.
+
+ """
+ # Handles logging.WARNING and above.
+ error_handler = logging.StreamHandler(stream)
+ error_handler.setLevel(logging.WARNING)
+ formatter = logging.Formatter("%(levelname)s: %(message)s")
+ error_handler.setFormatter(formatter)
+
+ # Create a logging.Filter instance that only accepts messages
+ # below WARNING (i.e. filters out anything WARNING or above).
+ non_error_filter = logging.Filter()
+ # The filter method accepts a logging.LogRecord instance.
+ non_error_filter.filter = lambda record: record.levelno < logging.WARNING
+
+ non_error_handler = logging.StreamHandler(stream)
+ non_error_handler.addFilter(non_error_filter)
+ formatter = logging.Formatter("%(message)s")
+ non_error_handler.setFormatter(formatter)
+
+ return [error_handler, non_error_handler]
+
+
+def _create_debug_log_handlers(stream):
+ """Create and return a list of logging.Handler instances for debugging.
+
+ Args:
+ stream: See the configure_logging() docstring.
+
+ """
+ handler = logging.StreamHandler(stream)
+ formatter = logging.Formatter("%(name)s: %(levelname)-8s %(message)s")
+ handler.setFormatter(formatter)
+
+ return [handler]
+
+
+def configure_logging(stream, logger=None, is_verbose=False):
+ """Configure logging, and return the list of handlers added.
+
+ Returns:
+ A list of references to the logging handlers added to the root
+ logger. This allows the caller to later remove the handlers
+ using logger.removeHandler. This is useful primarily during unit
+ testing where the caller may want to configure logging temporarily
+ and then undo the configuring.
+
+ Args:
+ stream: A file-like object to which to log. The stream must
+ define an "encoding" data attribute, or else logging
+ raises an error.
+ logger: A logging.logger instance to configure. This parameter
+ should be used only in unit tests. Defaults to the
+ root logger.
+ is_verbose: A boolean value of whether logging should be verbose.
+
+ """
+ # If the stream does not define an "encoding" data attribute, the
+ # logging module can throw an error like the following:
+ #
+ # Traceback (most recent call last):
+ # File "/System/Library/Frameworks/Python.framework/Versions/2.6/...
+ # lib/python2.6/logging/__init__.py", line 761, in emit
+ # self.stream.write(fs % msg.encode(self.stream.encoding))
+ # LookupError: unknown encoding: unknown
+ if logger is None:
+ logger = logging.getLogger()
+
+ if is_verbose:
+ logging_level = logging.DEBUG
+ handlers = _create_debug_log_handlers(stream)
+ else:
+ logging_level = logging.INFO
+ handlers = _create_log_handlers(stream)
+
+ handlers = _configure_logging(logging_level=logging_level, logger=logger,
+ handlers=handlers)
+
+ return handlers
+
+
+# Enum-like idiom
+class FileType:
+
+ NONE = 0 # FileType.NONE evaluates to False.
+ # Alphabetize remaining types
+ CPP = 1
+ PYTHON = 2
+ TEXT = 3
+ XML = 4
+
+
+class CheckerDispatcher(object):
+
+ """Supports determining whether and how to check style, based on path."""
+
+ def _file_extension(self, file_path):
+ """Return the file extension without the leading dot."""
+ return os.path.splitext(file_path)[1].lstrip(".")
+
+ def should_skip_with_warning(self, file_path):
+ """Return whether the given file should be skipped with a warning."""
+ for skipped_file in _SKIPPED_FILES_WITH_WARNING:
+ if file_path.find(skipped_file) >= 0:
+ return True
+ return False
+
+ def should_skip_without_warning(self, file_path):
+ """Return whether the given file should be skipped without a warning."""
+ if not self._file_type(file_path): # FileType.NONE.
+ return True
+ # Since "LayoutTests" is in _SKIPPED_FILES_WITHOUT_WARNING, make
+ # an exception to prevent files like "LayoutTests/ChangeLog" and
+ # "LayoutTests/ChangeLog-2009-06-16" from being skipped.
+ # Files like 'test_expectations.txt' and 'drt_expectations.txt'
+ # are also should not be skipped.
+ #
+ # FIXME: Figure out a good way to avoid having to add special logic
+ # for this special case.
+ basename = os.path.basename(file_path)
+ if basename.startswith('ChangeLog'):
+ return False
+ elif basename == 'test_expectations.txt' or basename == 'drt_expectations.txt':
+ return False
+ for skipped_file in _SKIPPED_FILES_WITHOUT_WARNING:
+ if file_path.find(skipped_file) >= 0:
+ return True
+ return False
+
+ def should_check_and_strip_carriage_returns(self, file_path):
+ return self._file_extension(file_path) not in _CARRIAGE_RETURN_ALLOWED_FILE_EXTENSIONS
+
+ def _file_type(self, file_path):
+ """Return the file type corresponding to the given file."""
+ file_extension = self._file_extension(file_path)
+
+ if (file_extension in _CPP_FILE_EXTENSIONS) or (file_path == '-'):
+ # FIXME: Do something about the comment below and the issue it
+ # raises since cpp_style already relies on the extension.
+ #
+ # Treat stdin as C++. Since the extension is unknown when
+ # reading from stdin, cpp_style tests should not rely on
+ # the extension.
+ return FileType.CPP
+ elif file_extension == _PYTHON_FILE_EXTENSION:
+ return FileType.PYTHON
+ elif file_extension in _XML_FILE_EXTENSIONS:
+ return FileType.XML
+ elif (os.path.basename(file_path).startswith('ChangeLog') or
+ (not file_extension and "Tools/Scripts/" in file_path) or
+ file_extension in _TEXT_FILE_EXTENSIONS):
+ return FileType.TEXT
+ else:
+ return FileType.NONE
+
+ def _create_checker(self, file_type, file_path, handle_style_error,
+ min_confidence):
+ """Instantiate and return a style checker based on file type."""
+ if file_type == FileType.NONE:
+ checker = None
+ elif file_type == FileType.CPP:
+ file_extension = self._file_extension(file_path)
+ checker = CppChecker(file_path, file_extension,
+ handle_style_error, min_confidence)
+ elif file_type == FileType.PYTHON:
+ checker = PythonChecker(file_path, handle_style_error)
+ elif file_type == FileType.XML:
+ checker = XMLChecker(file_path, handle_style_error)
+ elif file_type == FileType.TEXT:
+ basename = os.path.basename(file_path)
+ if basename == 'test_expectations.txt' or basename == 'drt_expectations.txt':
+ checker = TestExpectationsChecker(file_path, handle_style_error)
+ else:
+ checker = TextChecker(file_path, handle_style_error)
+ else:
+ raise ValueError('Invalid file type "%(file_type)s": the only valid file types '
+ "are %(NONE)s, %(CPP)s, and %(TEXT)s."
+ % {"file_type": file_type,
+ "NONE": FileType.NONE,
+ "CPP": FileType.CPP,
+ "TEXT": FileType.TEXT})
+
+ return checker
+
+ def dispatch(self, file_path, handle_style_error, min_confidence):
+ """Instantiate and return a style checker based on file path."""
+ file_type = self._file_type(file_path)
+
+ checker = self._create_checker(file_type,
+ file_path,
+ handle_style_error,
+ min_confidence)
+ return checker
+
+
+# FIXME: Remove the stderr_write attribute from this class and replace
+# its use with calls to a logging module logger.
+class StyleProcessorConfiguration(object):
+
+ """Stores configuration values for the StyleProcessor class.
+
+ Attributes:
+ min_confidence: An integer between 1 and 5 inclusive that is the
+ minimum confidence level of style errors to report.
+
+ max_reports_per_category: The maximum number of errors to report
+ per category, per file.
+
+ stderr_write: A function that takes a string as a parameter and
+ serves as stderr.write.
+
+ """
+
+ def __init__(self,
+ filter_configuration,
+ max_reports_per_category,
+ min_confidence,
+ output_format,
+ stderr_write):
+ """Create a StyleProcessorConfiguration instance.
+
+ Args:
+ filter_configuration: A FilterConfiguration instance. The default
+ is the "empty" filter configuration, which
+ means that all errors should be checked.
+
+ max_reports_per_category: The maximum number of errors to report
+ per category, per file.
+
+ min_confidence: An integer between 1 and 5 inclusive that is the
+ minimum confidence level of style errors to report.
+ The default is 1, which reports all style errors.
+
+ output_format: A string that is the output format. The supported
+ output formats are "emacs" which emacs can parse
+ and "vs7" which Microsoft Visual Studio 7 can parse.
+
+ stderr_write: A function that takes a string as a parameter and
+ serves as stderr.write.
+
+ """
+ self._filter_configuration = filter_configuration
+ self._output_format = output_format
+
+ self.max_reports_per_category = max_reports_per_category
+ self.min_confidence = min_confidence
+ self.stderr_write = stderr_write
+
+ def is_reportable(self, category, confidence_in_error, file_path):
+ """Return whether an error is reportable.
+
+ An error is reportable if both the confidence in the error is
+ at least the minimum confidence level and the current filter
+ says the category should be checked for the given path.
+
+ Args:
+ category: A string that is a style category.
+ confidence_in_error: An integer between 1 and 5 inclusive that is
+ the application's confidence in the error.
+ A higher number means greater confidence.
+ file_path: The path of the file being checked
+
+ """
+ if confidence_in_error < self.min_confidence:
+ return False
+
+ return self._filter_configuration.should_check(category, file_path)
+
+ def write_style_error(self,
+ category,
+ confidence_in_error,
+ file_path,
+ line_number,
+ message):
+ """Write a style error to the configured stderr."""
+ if self._output_format == 'vs7':
+ format_string = "%s(%s): %s [%s] [%d]\n"
+ else:
+ format_string = "%s:%s: %s [%s] [%d]\n"
+
+ self.stderr_write(format_string % (file_path,
+ line_number,
+ message,
+ category,
+ confidence_in_error))
+
+
+class ProcessorBase(object):
+
+ """The base class for processors of lists of lines."""
+
+ def should_process(self, file_path):
+ """Return whether the file at file_path should be processed.
+
+ The TextFileReader class calls this method prior to reading in
+ the lines of a file. Use this method, for example, to prevent
+ the style checker from reading binary files into memory.
+
+ """
+ raise NotImplementedError('Subclasses should implement.')
+
+ def process(self, lines, file_path, **kwargs):
+ """Process lines of text read from a file.
+
+ Args:
+ lines: A list of lines of text to process.
+ file_path: The path from which the lines were read.
+ **kwargs: This argument signifies that the process() method of
+ subclasses of ProcessorBase may support additional
+ keyword arguments.
+ For example, a style checker's check() method
+ may support a "reportable_lines" parameter that represents
+ the line numbers of the lines for which style errors
+ should be reported.
+
+ """
+ raise NotImplementedError('Subclasses should implement.')
+
+
+class StyleProcessor(ProcessorBase):
+
+ """A ProcessorBase for checking style.
+
+ Attributes:
+ error_count: An integer that is the total number of reported
+ errors for the lifetime of this instance.
+
+ """
+
+ def __init__(self, configuration, mock_dispatcher=None,
+ mock_increment_error_count=None,
+ mock_carriage_checker_class=None):
+ """Create an instance.
+
+ Args:
+ configuration: A StyleProcessorConfiguration instance.
+ mock_dispatcher: A mock CheckerDispatcher instance. This
+ parameter is for unit testing. Defaults to a
+ CheckerDispatcher instance.
+ mock_increment_error_count: A mock error-count incrementer.
+ mock_carriage_checker_class: A mock class for checking and
+ transforming carriage returns.
+ This parameter is for unit testing.
+ Defaults to CarriageReturnChecker.
+
+ """
+ if mock_dispatcher is None:
+ dispatcher = CheckerDispatcher()
+ else:
+ dispatcher = mock_dispatcher
+
+ if mock_increment_error_count is None:
+ # The following blank line is present to avoid flagging by pep8.py.
+
+ def increment_error_count():
+ """Increment the total count of reported errors."""
+ self.error_count += 1
+ else:
+ increment_error_count = mock_increment_error_count
+
+ if mock_carriage_checker_class is None:
+ # This needs to be a class rather than an instance since the
+ # process() method instantiates one using parameters.
+ carriage_checker_class = CarriageReturnChecker
+ else:
+ carriage_checker_class = mock_carriage_checker_class
+
+ self.error_count = 0
+
+ self._carriage_checker_class = carriage_checker_class
+ self._configuration = configuration
+ self._dispatcher = dispatcher
+ self._increment_error_count = increment_error_count
+
+ def should_process(self, file_path):
+ """Return whether the file should be checked for style."""
+ if self._dispatcher.should_skip_without_warning(file_path):
+ return False
+ if self._dispatcher.should_skip_with_warning(file_path):
+ _log.warn('File exempt from style guide. Skipping: "%s"'
+ % file_path)
+ return False
+ return True
+
+ def process(self, lines, file_path, line_numbers=None):
+ """Check the given lines for style.
+
+ Arguments:
+ lines: A list of all lines in the file to check.
+ file_path: The path of the file to process. If possible, the path
+ should be relative to the source root. Otherwise,
+ path-specific logic may not behave as expected.
+ line_numbers: A list of line numbers of the lines for which
+ style errors should be reported, or None if errors
+ for all lines should be reported. When not None, this
+ list normally contains the line numbers corresponding
+ to the modified lines of a patch.
+
+ """
+ _log.debug("Checking style: " + file_path)
+
+ style_error_handler = DefaultStyleErrorHandler(
+ configuration=self._configuration,
+ file_path=file_path,
+ increment_error_count=self._increment_error_count,
+ line_numbers=line_numbers)
+
+ carriage_checker = self._carriage_checker_class(style_error_handler)
+
+ # Check for and remove trailing carriage returns ("\r").
+ if self._dispatcher.should_check_and_strip_carriage_returns(file_path):
+ lines = carriage_checker.check(lines)
+
+ min_confidence = self._configuration.min_confidence
+ checker = self._dispatcher.dispatch(file_path,
+ style_error_handler,
+ min_confidence)
+
+ if checker is None:
+ raise AssertionError("File should not be checked: '%s'" % file_path)
+
+ _log.debug("Using class: " + checker.__class__.__name__)
+
+ checker.check(lines)
diff --git a/Tools/Scripts/webkitpy/style/checker_unittest.py b/Tools/Scripts/webkitpy/style/checker_unittest.py
new file mode 100755
index 0000000..d9057a8
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checker_unittest.py
@@ -0,0 +1,832 @@
+#!/usr/bin/python
+# -*- coding: utf-8; -*-
+#
+# Copyright (C) 2009 Google Inc. All rights reserved.
+# Copyright (C) 2009 Torch Mobile Inc.
+# Copyright (C) 2009 Apple Inc. All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+#
+# 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.
+
+"""Unit tests for style.py."""
+
+import logging
+import os
+import unittest
+
+import checker as style
+from webkitpy.style_references import LogTesting
+from webkitpy.style_references import TestLogStream
+from checker import _BASE_FILTER_RULES
+from checker import _MAX_REPORTS_PER_CATEGORY
+from checker import _PATH_RULES_SPECIFIER as PATH_RULES_SPECIFIER
+from checker import _all_categories
+from checker import check_webkit_style_configuration
+from checker import check_webkit_style_parser
+from checker import configure_logging
+from checker import CheckerDispatcher
+from checker import ProcessorBase
+from checker import StyleProcessor
+from checker import StyleProcessorConfiguration
+from checkers.cpp import CppChecker
+from checkers.python import PythonChecker
+from checkers.text import TextChecker
+from checkers.xml import XMLChecker
+from error_handlers import DefaultStyleErrorHandler
+from filter import validate_filter_rules
+from filter import FilterConfiguration
+from optparser import ArgumentParser
+from optparser import CommandOptionValues
+from webkitpy.common.system.logtesting import LoggingTestCase
+from webkitpy.style.filereader import TextFileReader
+
+
+class ConfigureLoggingTestBase(unittest.TestCase):
+
+ """Base class for testing configure_logging().
+
+ Sub-classes should implement:
+
+ is_verbose: The is_verbose value to pass to configure_logging().
+
+ """
+
+ def setUp(self):
+ is_verbose = self.is_verbose
+
+ log_stream = TestLogStream(self)
+
+ # Use a logger other than the root logger or one prefixed with
+ # webkit so as not to conflict with test-webkitpy logging.
+ logger = logging.getLogger("unittest")
+
+ # Configure the test logger not to pass messages along to the
+ # root logger. This prevents test messages from being
+ # propagated to loggers used by test-webkitpy logging (e.g.
+ # the root logger).
+ logger.propagate = False
+
+ self._handlers = configure_logging(stream=log_stream, logger=logger,
+ is_verbose=is_verbose)
+ self._log = logger
+ self._log_stream = log_stream
+
+ def tearDown(self):
+ """Reset logging to its original state.
+
+ This method ensures that the logging configuration set up
+ for a unit test does not affect logging in other unit tests.
+
+ """
+ logger = self._log
+ for handler in self._handlers:
+ logger.removeHandler(handler)
+
+ def assert_log_messages(self, messages):
+ """Assert that the logged messages equal the given messages."""
+ self._log_stream.assertMessages(messages)
+
+
+class ConfigureLoggingTest(ConfigureLoggingTestBase):
+
+ """Tests the configure_logging() function."""
+
+ is_verbose = False
+
+ def test_warning_message(self):
+ self._log.warn("test message")
+ self.assert_log_messages(["WARNING: test message\n"])
+
+ def test_below_warning_message(self):
+ # We test the boundary case of a logging level equal to 29.
+ # In practice, we will probably only be calling log.info(),
+ # which corresponds to a logging level of 20.
+ level = logging.WARNING - 1 # Equals 29.
+ self._log.log(level, "test message")
+ self.assert_log_messages(["test message\n"])
+
+ def test_debug_message(self):
+ self._log.debug("test message")
+ self.assert_log_messages([])
+
+ def test_two_messages(self):
+ self._log.info("message1")
+ self._log.info("message2")
+ self.assert_log_messages(["message1\n", "message2\n"])
+
+
+class ConfigureLoggingVerboseTest(ConfigureLoggingTestBase):
+
+ """Tests the configure_logging() function with is_verbose True."""
+
+ is_verbose = True
+
+ def test_debug_message(self):
+ self._log.debug("test message")
+ self.assert_log_messages(["unittest: DEBUG test message\n"])
+
+
+class GlobalVariablesTest(unittest.TestCase):
+
+ """Tests validity of the global variables."""
+
+ def _all_categories(self):
+ return _all_categories()
+
+ def defaults(self):
+ return style._check_webkit_style_defaults()
+
+ def test_webkit_base_filter_rules(self):
+ base_filter_rules = _BASE_FILTER_RULES
+ defaults = self.defaults()
+ already_seen = []
+ validate_filter_rules(base_filter_rules, self._all_categories())
+ # Also do some additional checks.
+ for rule in base_filter_rules:
+ # Check no leading or trailing white space.
+ self.assertEquals(rule, rule.strip())
+ # All categories are on by default, so defaults should
+ # begin with -.
+ self.assertTrue(rule.startswith('-'))
+ # Check no rule occurs twice.
+ self.assertFalse(rule in already_seen)
+ already_seen.append(rule)
+
+ def test_defaults(self):
+ """Check that default arguments are valid."""
+ default_options = self.defaults()
+
+ # FIXME: We should not need to call parse() to determine
+ # whether the default arguments are valid.
+ parser = ArgumentParser(all_categories=self._all_categories(),
+ base_filter_rules=[],
+ default_options=default_options)
+ # No need to test the return value here since we test parse()
+ # on valid arguments elsewhere.
+ #
+ # The default options are valid: no error or SystemExit.
+ parser.parse(args=[])
+
+ def test_path_rules_specifier(self):
+ all_categories = self._all_categories()
+ for (sub_paths, path_rules) in PATH_RULES_SPECIFIER:
+ validate_filter_rules(path_rules, self._all_categories())
+
+ config = FilterConfiguration(path_specific=PATH_RULES_SPECIFIER)
+
+ def assertCheck(path, category):
+ """Assert that the given category should be checked."""
+ message = ('Should check category "%s" for path "%s".'
+ % (category, path))
+ self.assertTrue(config.should_check(category, path))
+
+ def assertNoCheck(path, category):
+ """Assert that the given category should not be checked."""
+ message = ('Should not check category "%s" for path "%s".'
+ % (category, path))
+ self.assertFalse(config.should_check(category, path), message)
+
+ assertCheck("random_path.cpp",
+ "build/include")
+ assertNoCheck("Tools/WebKitAPITest/main.cpp",
+ "build/include")
+ assertCheck("random_path.cpp",
+ "readability/naming")
+ assertNoCheck("WebKit/gtk/webkit/webkit.h",
+ "readability/naming")
+ assertNoCheck("Tools/DumpRenderTree/gtk/DumpRenderTree.cpp",
+ "readability/null")
+ assertNoCheck("WebKit/efl/ewk/ewk_view.h",
+ "readability/naming")
+ assertNoCheck("WebCore/css/CSSParser.cpp",
+ "readability/naming")
+
+ # Test if Qt exceptions are indeed working
+ assertCheck("JavaScriptCore/qt/api/qscriptengine.cpp",
+ "readability/braces")
+ assertCheck("WebKit/qt/Api/qwebpage.cpp",
+ "readability/braces")
+ assertCheck("WebKit/qt/tests/qwebelement/tst_qwebelement.cpp",
+ "readability/braces")
+ assertCheck("WebKit/qt/declarative/platformplugin/WebPlugin.cpp",
+ "readability/braces")
+ assertCheck("WebKit/qt/examples/platformplugin/WebPlugin.cpp",
+ "readability/braces")
+ assertNoCheck("JavaScriptCore/qt/api/qscriptengine.cpp",
+ "readability/naming")
+ assertNoCheck("WebKit/qt/Api/qwebpage.cpp",
+ "readability/naming")
+ assertNoCheck("WebKit/qt/tests/qwebelement/tst_qwebelement.cpp",
+ "readability/naming")
+ assertNoCheck("WebKit/qt/declarative/platformplugin/WebPlugin.cpp",
+ "readability/naming")
+ assertNoCheck("WebKit/qt/examples/platformplugin/WebPlugin.cpp",
+ "readability/naming")
+
+ assertNoCheck("WebCore/ForwardingHeaders/debugger/Debugger.h",
+ "build/header_guard")
+
+ # Third-party Python code: webkitpy/thirdparty
+ path = "Tools/Scripts/webkitpy/thirdparty/mock.py"
+ assertNoCheck(path, "build/include")
+ assertNoCheck(path, "pep8/E401") # A random pep8 category.
+ assertCheck(path, "pep8/W191")
+ assertCheck(path, "pep8/W291")
+ assertCheck(path, "whitespace/carriage_return")
+
+ def test_max_reports_per_category(self):
+ """Check that _MAX_REPORTS_PER_CATEGORY is valid."""
+ all_categories = self._all_categories()
+ for category in _MAX_REPORTS_PER_CATEGORY.iterkeys():
+ self.assertTrue(category in all_categories,
+ 'Key "%s" is not a category' % category)
+
+
+class CheckWebKitStyleFunctionTest(unittest.TestCase):
+
+ """Tests the functions with names of the form check_webkit_style_*."""
+
+ def test_check_webkit_style_configuration(self):
+ # Exercise the code path to make sure the function does not error out.
+ option_values = CommandOptionValues()
+ configuration = check_webkit_style_configuration(option_values)
+
+ def test_check_webkit_style_parser(self):
+ # Exercise the code path to make sure the function does not error out.
+ parser = check_webkit_style_parser()
+
+
+class CheckerDispatcherSkipTest(unittest.TestCase):
+
+ """Tests the "should skip" methods of the CheckerDispatcher class."""
+
+ def setUp(self):
+ self._dispatcher = CheckerDispatcher()
+
+ def test_should_skip_with_warning(self):
+ """Test should_skip_with_warning()."""
+ # Check a non-skipped file.
+ self.assertFalse(self._dispatcher.should_skip_with_warning("foo.txt"))
+
+ # Check skipped files.
+ paths_to_skip = [
+ "gtk2drawing.c",
+ "gtkdrawing.h",
+ "WebCore/platform/gtk/gtk2drawing.c",
+ "WebCore/platform/gtk/gtkdrawing.h",
+ "WebKit/gtk/tests/testatk.c",
+ ]
+
+ for path in paths_to_skip:
+ self.assertTrue(self._dispatcher.should_skip_with_warning(path),
+ "Checking: " + path)
+
+ def _assert_should_skip_without_warning(self, path, is_checker_none,
+ expected):
+ # Check the file type before asserting the return value.
+ checker = self._dispatcher.dispatch(file_path=path,
+ handle_style_error=None,
+ min_confidence=3)
+ message = 'while checking: %s' % path
+ self.assertEquals(checker is None, is_checker_none, message)
+ self.assertEquals(self._dispatcher.should_skip_without_warning(path),
+ expected, message)
+
+ def test_should_skip_without_warning__true(self):
+ """Test should_skip_without_warning() for True return values."""
+ # Check a file with NONE file type.
+ path = 'foo.asdf' # Non-sensical file extension.
+ self._assert_should_skip_without_warning(path,
+ is_checker_none=True,
+ expected=True)
+
+ # Check files with non-NONE file type. These examples must be
+ # drawn from the _SKIPPED_FILES_WITHOUT_WARNING configuration
+ # variable.
+ path = os.path.join('LayoutTests', 'foo.txt')
+ self._assert_should_skip_without_warning(path,
+ is_checker_none=False,
+ expected=True)
+
+ def test_should_skip_without_warning__false(self):
+ """Test should_skip_without_warning() for False return values."""
+ paths = ['foo.txt',
+ os.path.join('LayoutTests', 'ChangeLog'),
+ ]
+
+ for path in paths:
+ self._assert_should_skip_without_warning(path,
+ is_checker_none=False,
+ expected=False)
+
+
+class CheckerDispatcherCarriageReturnTest(unittest.TestCase):
+ def test_should_check_and_strip_carriage_returns(self):
+ files = {
+ 'foo.txt': True,
+ 'foo.cpp': True,
+ 'foo.vcproj': False,
+ 'foo.vsprops': False,
+ }
+
+ dispatcher = CheckerDispatcher()
+ for file_path, expected_result in files.items():
+ self.assertEquals(dispatcher.should_check_and_strip_carriage_returns(file_path), expected_result, 'Checking: %s' % file_path)
+
+
+class CheckerDispatcherDispatchTest(unittest.TestCase):
+
+ """Tests dispatch() method of CheckerDispatcher class."""
+
+ def mock_handle_style_error(self):
+ pass
+
+ def dispatch(self, file_path):
+ """Call dispatch() with the given file path."""
+ dispatcher = CheckerDispatcher()
+ checker = dispatcher.dispatch(file_path,
+ self.mock_handle_style_error,
+ min_confidence=3)
+ return checker
+
+ def assert_checker_none(self, file_path):
+ """Assert that the dispatched checker is None."""
+ checker = self.dispatch(file_path)
+ self.assertTrue(checker is None, 'Checking: "%s"' % file_path)
+
+ def assert_checker(self, file_path, expected_class):
+ """Assert the type of the dispatched checker."""
+ checker = self.dispatch(file_path)
+ got_class = checker.__class__
+ self.assertEquals(got_class, expected_class,
+ 'For path "%(file_path)s" got %(got_class)s when '
+ "expecting %(expected_class)s."
+ % {"file_path": file_path,
+ "got_class": got_class,
+ "expected_class": expected_class})
+
+ def assert_checker_cpp(self, file_path):
+ """Assert that the dispatched checker is a CppChecker."""
+ self.assert_checker(file_path, CppChecker)
+
+ def assert_checker_python(self, file_path):
+ """Assert that the dispatched checker is a PythonChecker."""
+ self.assert_checker(file_path, PythonChecker)
+
+ def assert_checker_text(self, file_path):
+ """Assert that the dispatched checker is a TextChecker."""
+ self.assert_checker(file_path, TextChecker)
+
+ def assert_checker_xml(self, file_path):
+ """Assert that the dispatched checker is a XMLChecker."""
+ self.assert_checker(file_path, XMLChecker)
+
+ def test_cpp_paths(self):
+ """Test paths that should be checked as C++."""
+ paths = [
+ "-",
+ "foo.c",
+ "foo.cpp",
+ "foo.h",
+ ]
+
+ for path in paths:
+ self.assert_checker_cpp(path)
+
+ # Check checker attributes on a typical input.
+ file_base = "foo"
+ file_extension = "c"
+ file_path = file_base + "." + file_extension
+ self.assert_checker_cpp(file_path)
+ checker = self.dispatch(file_path)
+ self.assertEquals(checker.file_extension, file_extension)
+ self.assertEquals(checker.file_path, file_path)
+ self.assertEquals(checker.handle_style_error, self.mock_handle_style_error)
+ self.assertEquals(checker.min_confidence, 3)
+ # Check "-" for good measure.
+ file_base = "-"
+ file_extension = ""
+ file_path = file_base
+ self.assert_checker_cpp(file_path)
+ checker = self.dispatch(file_path)
+ self.assertEquals(checker.file_extension, file_extension)
+ self.assertEquals(checker.file_path, file_path)
+
+ def test_python_paths(self):
+ """Test paths that should be checked as Python."""
+ paths = [
+ "foo.py",
+ "Tools/Scripts/modules/text_style.py",
+ ]
+
+ for path in paths:
+ self.assert_checker_python(path)
+
+ # Check checker attributes on a typical input.
+ file_base = "foo"
+ file_extension = "css"
+ file_path = file_base + "." + file_extension
+ self.assert_checker_text(file_path)
+ checker = self.dispatch(file_path)
+ self.assertEquals(checker.file_path, file_path)
+ self.assertEquals(checker.handle_style_error,
+ self.mock_handle_style_error)
+
+ def test_text_paths(self):
+ """Test paths that should be checked as text."""
+ paths = [
+ "ChangeLog",
+ "ChangeLog-2009-06-16",
+ "foo.ac",
+ "foo.cc",
+ "foo.cgi",
+ "foo.css",
+ "foo.exp",
+ "foo.flex",
+ "foo.gyp",
+ "foo.gypi",
+ "foo.html",
+ "foo.idl",
+ "foo.in",
+ "foo.js",
+ "foo.mm",
+ "foo.php",
+ "foo.pl",
+ "foo.pm",
+ "foo.pri",
+ "foo.pro",
+ "foo.rb",
+ "foo.sh",
+ "foo.txt",
+ "foo.wm",
+ "foo.xhtml",
+ "foo.y",
+ os.path.join("WebCore", "ChangeLog"),
+ os.path.join("WebCore", "inspector", "front-end", "inspector.js"),
+ os.path.join("Tools", "Scripts", "check-webkit-style"),
+ ]
+
+ for path in paths:
+ self.assert_checker_text(path)
+
+ # Check checker attributes on a typical input.
+ file_base = "foo"
+ file_extension = "css"
+ file_path = file_base + "." + file_extension
+ self.assert_checker_text(file_path)
+ checker = self.dispatch(file_path)
+ self.assertEquals(checker.file_path, file_path)
+ self.assertEquals(checker.handle_style_error, self.mock_handle_style_error)
+
+ def test_xml_paths(self):
+ """Test paths that should be checked as XML."""
+ paths = [
+ "WebCore/WebCore.vcproj/WebCore.vcproj",
+ "WebKitLibraries/win/tools/vsprops/common.vsprops",
+ ]
+
+ for path in paths:
+ self.assert_checker_xml(path)
+
+ # Check checker attributes on a typical input.
+ file_base = "foo"
+ file_extension = "vcproj"
+ file_path = file_base + "." + file_extension
+ self.assert_checker_xml(file_path)
+ checker = self.dispatch(file_path)
+ self.assertEquals(checker.file_path, file_path)
+ self.assertEquals(checker.handle_style_error,
+ self.mock_handle_style_error)
+
+ def test_none_paths(self):
+ """Test paths that have no file type.."""
+ paths = [
+ "Makefile",
+ "foo.asdf", # Non-sensical file extension.
+ "foo.png",
+ "foo.exe",
+ ]
+
+ for path in paths:
+ self.assert_checker_none(path)
+
+
+class StyleProcessorConfigurationTest(unittest.TestCase):
+
+ """Tests the StyleProcessorConfiguration class."""
+
+ def setUp(self):
+ self._error_messages = []
+ """The messages written to _mock_stderr_write() of this class."""
+
+ def _mock_stderr_write(self, message):
+ self._error_messages.append(message)
+
+ def _style_checker_configuration(self, output_format="vs7"):
+ """Return a StyleProcessorConfiguration instance for testing."""
+ base_rules = ["-whitespace", "+whitespace/tab"]
+ filter_configuration = FilterConfiguration(base_rules=base_rules)
+
+ return StyleProcessorConfiguration(
+ filter_configuration=filter_configuration,
+ max_reports_per_category={"whitespace/newline": 1},
+ min_confidence=3,
+ output_format=output_format,
+ stderr_write=self._mock_stderr_write)
+
+ def test_init(self):
+ """Test the __init__() method."""
+ configuration = self._style_checker_configuration()
+
+ # Check that __init__ sets the "public" data attributes correctly.
+ self.assertEquals(configuration.max_reports_per_category,
+ {"whitespace/newline": 1})
+ self.assertEquals(configuration.stderr_write, self._mock_stderr_write)
+ self.assertEquals(configuration.min_confidence, 3)
+
+ def test_is_reportable(self):
+ """Test the is_reportable() method."""
+ config = self._style_checker_configuration()
+
+ self.assertTrue(config.is_reportable("whitespace/tab", 3, "foo.txt"))
+
+ # Test the confidence check code path by varying the confidence.
+ self.assertFalse(config.is_reportable("whitespace/tab", 2, "foo.txt"))
+
+ # Test the category check code path by varying the category.
+ self.assertFalse(config.is_reportable("whitespace/line", 4, "foo.txt"))
+
+ def _call_write_style_error(self, output_format):
+ config = self._style_checker_configuration(output_format=output_format)
+ config.write_style_error(category="whitespace/tab",
+ confidence_in_error=5,
+ file_path="foo.h",
+ line_number=100,
+ message="message")
+
+ def test_write_style_error_emacs(self):
+ """Test the write_style_error() method."""
+ self._call_write_style_error("emacs")
+ self.assertEquals(self._error_messages,
+ ["foo.h:100: message [whitespace/tab] [5]\n"])
+
+ def test_write_style_error_vs7(self):
+ """Test the write_style_error() method."""
+ self._call_write_style_error("vs7")
+ self.assertEquals(self._error_messages,
+ ["foo.h(100): message [whitespace/tab] [5]\n"])
+
+
+class StyleProcessor_EndToEndTest(LoggingTestCase):
+
+ """Test the StyleProcessor class with an emphasis on end-to-end tests."""
+
+ def setUp(self):
+ LoggingTestCase.setUp(self)
+ self._messages = []
+
+ def _mock_stderr_write(self, message):
+ """Save a message so it can later be asserted."""
+ self._messages.append(message)
+
+ def test_init(self):
+ """Test __init__ constructor."""
+ configuration = StyleProcessorConfiguration(
+ filter_configuration=FilterConfiguration(),
+ max_reports_per_category={},
+ min_confidence=3,
+ output_format="vs7",
+ stderr_write=self._mock_stderr_write)
+ processor = StyleProcessor(configuration)
+
+ self.assertEquals(processor.error_count, 0)
+ self.assertEquals(self._messages, [])
+
+ def test_process(self):
+ configuration = StyleProcessorConfiguration(
+ filter_configuration=FilterConfiguration(),
+ max_reports_per_category={},
+ min_confidence=3,
+ output_format="vs7",
+ stderr_write=self._mock_stderr_write)
+ processor = StyleProcessor(configuration)
+
+ processor.process(lines=['line1', 'Line with tab:\t'],
+ file_path='foo.txt')
+ self.assertEquals(processor.error_count, 1)
+ expected_messages = ['foo.txt(2): Line contains tab character. '
+ '[whitespace/tab] [5]\n']
+ self.assertEquals(self._messages, expected_messages)
+
+
+class StyleProcessor_CodeCoverageTest(LoggingTestCase):
+
+ """Test the StyleProcessor class with an emphasis on code coverage.
+
+ This class makes heavy use of mock objects.
+
+ """
+
+ class MockDispatchedChecker(object):
+
+ """A mock checker dispatched by the MockDispatcher."""
+
+ def __init__(self, file_path, min_confidence, style_error_handler):
+ self.file_path = file_path
+ self.min_confidence = min_confidence
+ self.style_error_handler = style_error_handler
+
+ def check(self, lines):
+ self.lines = lines
+
+ class MockDispatcher(object):
+
+ """A mock CheckerDispatcher class."""
+
+ def __init__(self):
+ self.dispatched_checker = None
+
+ def should_skip_with_warning(self, file_path):
+ return file_path.endswith('skip_with_warning.txt')
+
+ def should_skip_without_warning(self, file_path):
+ return file_path.endswith('skip_without_warning.txt')
+
+ def should_check_and_strip_carriage_returns(self, file_path):
+ return not file_path.endswith('carriage_returns_allowed.txt')
+
+ def dispatch(self, file_path, style_error_handler, min_confidence):
+ if file_path.endswith('do_not_process.txt'):
+ return None
+
+ checker = StyleProcessor_CodeCoverageTest.MockDispatchedChecker(
+ file_path,
+ min_confidence,
+ style_error_handler)
+
+ # Save the dispatched checker so the current test case has a
+ # way to access and check it.
+ self.dispatched_checker = checker
+
+ return checker
+
+ def setUp(self):
+ LoggingTestCase.setUp(self)
+ # We can pass an error-message swallower here because error message
+ # output is tested instead in the end-to-end test case above.
+ configuration = StyleProcessorConfiguration(
+ filter_configuration=FilterConfiguration(),
+ max_reports_per_category={"whitespace/newline": 1},
+ min_confidence=3,
+ output_format="vs7",
+ stderr_write=self._swallow_stderr_message)
+
+ mock_carriage_checker_class = self._create_carriage_checker_class()
+ mock_dispatcher = self.MockDispatcher()
+ # We do not need to use a real incrementer here because error-count
+ # incrementing is tested instead in the end-to-end test case above.
+ mock_increment_error_count = self._do_nothing
+
+ processor = StyleProcessor(configuration=configuration,
+ mock_carriage_checker_class=mock_carriage_checker_class,
+ mock_dispatcher=mock_dispatcher,
+ mock_increment_error_count=mock_increment_error_count)
+
+ self._configuration = configuration
+ self._mock_dispatcher = mock_dispatcher
+ self._processor = processor
+
+ def _do_nothing(self):
+ # We provide this function so the caller can pass it to the
+ # StyleProcessor constructor. This lets us assert the equality of
+ # the DefaultStyleErrorHandler instance generated by the process()
+ # method with an expected instance.
+ pass
+
+ def _swallow_stderr_message(self, message):
+ """Swallow a message passed to stderr.write()."""
+ # This is a mock stderr.write() for passing to the constructor
+ # of the StyleProcessorConfiguration class.
+ pass
+
+ def _create_carriage_checker_class(self):
+
+ # Create a reference to self with a new name so its name does not
+ # conflict with the self introduced below.
+ test_case = self
+
+ class MockCarriageChecker(object):
+
+ """A mock carriage-return checker."""
+
+ def __init__(self, style_error_handler):
+ self.style_error_handler = style_error_handler
+
+ # This gives the current test case access to the
+ # instantiated carriage checker.
+ test_case.carriage_checker = self
+
+ def check(self, lines):
+ # Save the lines so the current test case has a way to access
+ # and check them.
+ self.lines = lines
+
+ return lines
+
+ return MockCarriageChecker
+
+ def test_should_process__skip_without_warning(self):
+ """Test should_process() for a skip-without-warning file."""
+ file_path = "foo/skip_without_warning.txt"
+
+ self.assertFalse(self._processor.should_process(file_path))
+
+ def test_should_process__skip_with_warning(self):
+ """Test should_process() for a skip-with-warning file."""
+ file_path = "foo/skip_with_warning.txt"
+
+ self.assertFalse(self._processor.should_process(file_path))
+
+ self.assertLog(['WARNING: File exempt from style guide. '
+ 'Skipping: "foo/skip_with_warning.txt"\n'])
+
+ def test_should_process__true_result(self):
+ """Test should_process() for a file that should be processed."""
+ file_path = "foo/skip_process.txt"
+
+ self.assertTrue(self._processor.should_process(file_path))
+
+ def test_process__checker_dispatched(self):
+ """Test the process() method for a path with a dispatched checker."""
+ file_path = 'foo.txt'
+ lines = ['line1', 'line2']
+ line_numbers = [100]
+
+ expected_error_handler = DefaultStyleErrorHandler(
+ configuration=self._configuration,
+ file_path=file_path,
+ increment_error_count=self._do_nothing,
+ line_numbers=line_numbers)
+
+ self._processor.process(lines=lines,
+ file_path=file_path,
+ line_numbers=line_numbers)
+
+ # Check that the carriage-return checker was instantiated correctly
+ # and was passed lines correctly.
+ carriage_checker = self.carriage_checker
+ self.assertEquals(carriage_checker.style_error_handler,
+ expected_error_handler)
+ self.assertEquals(carriage_checker.lines, ['line1', 'line2'])
+
+ # Check that the style checker was dispatched correctly and was
+ # passed lines correctly.
+ checker = self._mock_dispatcher.dispatched_checker
+ self.assertEquals(checker.file_path, 'foo.txt')
+ self.assertEquals(checker.min_confidence, 3)
+ self.assertEquals(checker.style_error_handler, expected_error_handler)
+
+ self.assertEquals(checker.lines, ['line1', 'line2'])
+
+ def test_process__no_checker_dispatched(self):
+ """Test the process() method for a path with no dispatched checker."""
+ path = os.path.join('foo', 'do_not_process.txt')
+ self.assertRaises(AssertionError, self._processor.process,
+ lines=['line1', 'line2'], file_path=path,
+ line_numbers=[100])
+
+ def test_process__carriage_returns_not_stripped(self):
+ """Test that carriage returns aren't stripped from files that are allowed to contain them."""
+ file_path = 'carriage_returns_allowed.txt'
+ lines = ['line1\r', 'line2\r']
+ line_numbers = [100]
+ self._processor.process(lines=lines,
+ file_path=file_path,
+ line_numbers=line_numbers)
+ # The carriage return checker should never have been invoked, and so
+ # should not have saved off any lines.
+ self.assertFalse(hasattr(self.carriage_checker, 'lines'))
diff --git a/Tools/Scripts/webkitpy/style/checkers/__init__.py b/Tools/Scripts/webkitpy/style/checkers/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/style/checkers/common.py b/Tools/Scripts/webkitpy/style/checkers/common.py
new file mode 100644
index 0000000..76aa956
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/common.py
@@ -0,0 +1,74 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Supports style checking not specific to any one file type."""
+
+
+# FIXME: Test this list in the same way that the list of CppChecker
+# categories is tested, for example by checking that all of its
+# elements appear in the unit tests. This should probably be done
+# after moving the relevant cpp_unittest.ErrorCollector code
+# into a shared location and refactoring appropriately.
+categories = set([
+ "whitespace/carriage_return",
+ "whitespace/tab"])
+
+
+class CarriageReturnChecker(object):
+
+ """Supports checking for and handling carriage returns."""
+
+ def __init__(self, handle_style_error):
+ self._handle_style_error = handle_style_error
+
+ def check(self, lines):
+ """Check for and strip trailing carriage returns from lines."""
+ for line_number in range(len(lines)):
+ if not lines[line_number].endswith("\r"):
+ continue
+
+ self._handle_style_error(line_number + 1, # Correct for offset.
+ "whitespace/carriage_return",
+ 1,
+ "One or more unexpected \\r (^M) found; "
+ "better to use only a \\n")
+
+ lines[line_number] = lines[line_number].rstrip("\r")
+
+ return lines
+
+
+class TabChecker(object):
+
+ """Supports checking for and handling tabs."""
+
+ def __init__(self, file_path, handle_style_error):
+ self.file_path = file_path
+ self.handle_style_error = handle_style_error
+
+ def check(self, lines):
+ # FIXME: share with cpp_style.
+ for line_number, line in enumerate(lines):
+ if "\t" in line:
+ self.handle_style_error(line_number + 1,
+ "whitespace/tab", 5,
+ "Line contains tab character.")
diff --git a/Tools/Scripts/webkitpy/style/checkers/common_unittest.py b/Tools/Scripts/webkitpy/style/checkers/common_unittest.py
new file mode 100644
index 0000000..1fe1263
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/common_unittest.py
@@ -0,0 +1,124 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Unit tests for common.py."""
+
+import unittest
+
+from common import CarriageReturnChecker
+from common import TabChecker
+
+# FIXME: The unit tests for the cpp, text, and common checkers should
+# share supporting test code. This can include, for example, the
+# mock style error handling code and the code to check that all
+# of a checker's categories are covered by the unit tests.
+# Such shared code can be located in a shared test file, perhaps
+# even this file.
+class CarriageReturnCheckerTest(unittest.TestCase):
+
+ """Tests check_no_carriage_return()."""
+
+ _category = "whitespace/carriage_return"
+ _confidence = 1
+ _expected_message = ("One or more unexpected \\r (^M) found; "
+ "better to use only a \\n")
+
+ def setUp(self):
+ self._style_errors = [] # The list of accumulated style errors.
+
+ def _mock_style_error_handler(self, line_number, category, confidence,
+ message):
+ """Append the error information to the list of style errors."""
+ error = (line_number, category, confidence, message)
+ self._style_errors.append(error)
+
+ def assert_carriage_return(self, input_lines, expected_lines, error_lines):
+ """Process the given line and assert that the result is correct."""
+ handle_style_error = self._mock_style_error_handler
+
+ checker = CarriageReturnChecker(handle_style_error)
+ output_lines = checker.check(input_lines)
+
+ # Check both the return value and error messages.
+ self.assertEquals(output_lines, expected_lines)
+
+ expected_errors = [(line_number, self._category, self._confidence,
+ self._expected_message)
+ for line_number in error_lines]
+ self.assertEquals(self._style_errors, expected_errors)
+
+ def test_ends_with_carriage(self):
+ self.assert_carriage_return(["carriage return\r"],
+ ["carriage return"],
+ [1])
+
+ def test_ends_with_nothing(self):
+ self.assert_carriage_return(["no carriage return"],
+ ["no carriage return"],
+ [])
+
+ def test_ends_with_newline(self):
+ self.assert_carriage_return(["no carriage return\n"],
+ ["no carriage return\n"],
+ [])
+
+ def test_carriage_in_middle(self):
+ # The CarriageReturnChecker checks only the final character
+ # of each line.
+ self.assert_carriage_return(["carriage\r in a string"],
+ ["carriage\r in a string"],
+ [])
+
+ def test_multiple_errors(self):
+ self.assert_carriage_return(["line1", "line2\r", "line3\r"],
+ ["line1", "line2", "line3"],
+ [2, 3])
+
+
+class TabCheckerTest(unittest.TestCase):
+
+ """Tests for TabChecker."""
+
+ def assert_tab(self, input_lines, error_lines):
+ """Assert when the given lines contain tabs."""
+ self._error_lines = []
+
+ def style_error_handler(line_number, category, confidence, message):
+ self.assertEqual(category, 'whitespace/tab')
+ self.assertEqual(confidence, 5)
+ self.assertEqual(message, 'Line contains tab character.')
+ self._error_lines.append(line_number)
+
+ checker = TabChecker('', style_error_handler)
+ checker.check(input_lines)
+ self.assertEquals(self._error_lines, error_lines)
+
+ def test_notab(self):
+ self.assert_tab([''], [])
+ self.assert_tab(['foo', 'bar'], [])
+
+ def test_tab(self):
+ self.assert_tab(['\tfoo'], [1])
+ self.assert_tab(['line1', '\tline2', 'line3\t'], [2, 3])
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/style/checkers/cpp.py b/Tools/Scripts/webkitpy/style/checkers/cpp.py
new file mode 100644
index 0000000..94e5bdd
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/cpp.py
@@ -0,0 +1,3171 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2009 Google Inc. All rights reserved.
+# Copyright (C) 2009 Torch Mobile Inc.
+# Copyright (C) 2009 Apple Inc. All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.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 is the modified version of Google's cpplint. The original code is
+# http://google-styleguide.googlecode.com/svn/trunk/cpplint/cpplint.py
+
+"""Support for check-webkit-style."""
+
+import codecs
+import math # for log
+import os
+import os.path
+import re
+import sre_compile
+import string
+import sys
+import unicodedata
+
+# The key to use to provide a class to fake loading a header file.
+INCLUDE_IO_INJECTION_KEY = 'include_header_io'
+
+# Headers that we consider STL headers.
+_STL_HEADERS = frozenset([
+ 'algobase.h', 'algorithm', 'alloc.h', 'bitset', 'deque', 'exception',
+ 'function.h', 'functional', 'hash_map', 'hash_map.h', 'hash_set',
+ 'hash_set.h', 'iterator', 'list', 'list.h', 'map', 'memory', 'pair.h',
+ 'pthread_alloc', 'queue', 'set', 'set.h', 'sstream', 'stack',
+ 'stl_alloc.h', 'stl_relops.h', 'type_traits.h',
+ 'utility', 'vector', 'vector.h',
+ ])
+
+
+# Non-STL C++ system headers.
+_CPP_HEADERS = frozenset([
+ 'algo.h', 'builtinbuf.h', 'bvector.h', 'cassert', 'cctype',
+ 'cerrno', 'cfloat', 'ciso646', 'climits', 'clocale', 'cmath',
+ 'complex', 'complex.h', 'csetjmp', 'csignal', 'cstdarg', 'cstddef',
+ 'cstdio', 'cstdlib', 'cstring', 'ctime', 'cwchar', 'cwctype',
+ 'defalloc.h', 'deque.h', 'editbuf.h', 'exception', 'fstream',
+ 'fstream.h', 'hashtable.h', 'heap.h', 'indstream.h', 'iomanip',
+ 'iomanip.h', 'ios', 'iosfwd', 'iostream', 'iostream.h', 'istream.h',
+ 'iterator.h', 'limits', 'map.h', 'multimap.h', 'multiset.h',
+ 'numeric', 'ostream.h', 'parsestream.h', 'pfstream.h', 'PlotFile.h',
+ 'procbuf.h', 'pthread_alloc.h', 'rope', 'rope.h', 'ropeimpl.h',
+ 'SFile.h', 'slist', 'slist.h', 'stack.h', 'stdexcept',
+ 'stdiostream.h', 'streambuf.h', 'stream.h', 'strfile.h', 'string',
+ 'strstream', 'strstream.h', 'tempbuf.h', 'tree.h', 'typeinfo', 'valarray',
+ ])
+
+
+# Assertion macros. These are defined in base/logging.h and
+# testing/base/gunit.h. Note that the _M versions need to come first
+# for substring matching to work.
+_CHECK_MACROS = [
+ 'DCHECK', 'CHECK',
+ 'EXPECT_TRUE_M', 'EXPECT_TRUE',
+ 'ASSERT_TRUE_M', 'ASSERT_TRUE',
+ 'EXPECT_FALSE_M', 'EXPECT_FALSE',
+ 'ASSERT_FALSE_M', 'ASSERT_FALSE',
+ ]
+
+# Replacement macros for CHECK/DCHECK/EXPECT_TRUE/EXPECT_FALSE
+_CHECK_REPLACEMENT = dict([(m, {}) for m in _CHECK_MACROS])
+
+for op, replacement in [('==', 'EQ'), ('!=', 'NE'),
+ ('>=', 'GE'), ('>', 'GT'),
+ ('<=', 'LE'), ('<', 'LT')]:
+ _CHECK_REPLACEMENT['DCHECK'][op] = 'DCHECK_%s' % replacement
+ _CHECK_REPLACEMENT['CHECK'][op] = 'CHECK_%s' % replacement
+ _CHECK_REPLACEMENT['EXPECT_TRUE'][op] = 'EXPECT_%s' % replacement
+ _CHECK_REPLACEMENT['ASSERT_TRUE'][op] = 'ASSERT_%s' % replacement
+ _CHECK_REPLACEMENT['EXPECT_TRUE_M'][op] = 'EXPECT_%s_M' % replacement
+ _CHECK_REPLACEMENT['ASSERT_TRUE_M'][op] = 'ASSERT_%s_M' % replacement
+
+for op, inv_replacement in [('==', 'NE'), ('!=', 'EQ'),
+ ('>=', 'LT'), ('>', 'LE'),
+ ('<=', 'GT'), ('<', 'GE')]:
+ _CHECK_REPLACEMENT['EXPECT_FALSE'][op] = 'EXPECT_%s' % inv_replacement
+ _CHECK_REPLACEMENT['ASSERT_FALSE'][op] = 'ASSERT_%s' % inv_replacement
+ _CHECK_REPLACEMENT['EXPECT_FALSE_M'][op] = 'EXPECT_%s_M' % inv_replacement
+ _CHECK_REPLACEMENT['ASSERT_FALSE_M'][op] = 'ASSERT_%s_M' % inv_replacement
+
+
+# These constants define types of headers for use with
+# _IncludeState.check_next_include_order().
+_CONFIG_HEADER = 0
+_PRIMARY_HEADER = 1
+_OTHER_HEADER = 2
+_MOC_HEADER = 3
+
+
+# A dictionary of items customize behavior for unit test. For example,
+# INCLUDE_IO_INJECTION_KEY allows providing a custom io class which allows
+# for faking a header file.
+_unit_test_config = {}
+
+
+# The regexp compilation caching is inlined in all regexp functions for
+# performance reasons; factoring it out into a separate function turns out
+# to be noticeably expensive.
+_regexp_compile_cache = {}
+
+
+def match(pattern, s):
+ """Matches the string with the pattern, caching the compiled regexp."""
+ if not pattern in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].match(s)
+
+
+def search(pattern, s):
+ """Searches the string for the pattern, caching the compiled regexp."""
+ if not pattern in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].search(s)
+
+
+def sub(pattern, replacement, s):
+ """Substitutes occurrences of a pattern, caching the compiled regexp."""
+ if not pattern in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].sub(replacement, s)
+
+
+def subn(pattern, replacement, s):
+ """Substitutes occurrences of a pattern, caching the compiled regexp."""
+ if not pattern in _regexp_compile_cache:
+ _regexp_compile_cache[pattern] = sre_compile.compile(pattern)
+ return _regexp_compile_cache[pattern].subn(replacement, s)
+
+
+def iteratively_replace_matches_with_char(pattern, char_replacement, s):
+ """Returns the string with replacement done.
+
+ Every character in the match is replaced with char.
+ Due to the iterative nature, pattern should not match char or
+ there will be an infinite loop.
+
+ Example:
+ pattern = r'<[^>]>' # template parameters
+ char_replacement = '_'
+ s = 'A<B<C, D>>'
+ Returns 'A_________'
+
+ Args:
+ pattern: The regex to match.
+ char_replacement: The character to put in place of every
+ character of the match.
+ s: The string on which to do the replacements.
+
+ Returns:
+ True, if the given line is blank.
+ """
+ while True:
+ matched = search(pattern, s)
+ if not matched:
+ return s
+ start_match_index = matched.start(0)
+ end_match_index = matched.end(0)
+ match_length = end_match_index - start_match_index
+ s = s[:start_match_index] + char_replacement * match_length + s[end_match_index:]
+
+
+def up_to_unmatched_closing_paren(s):
+ """Splits a string into two parts up to first unmatched ')'.
+
+ Args:
+ s: a string which is a substring of line after '('
+ (e.g., "a == (b + c))").
+
+ Returns:
+ A pair of strings (prefix before first unmatched ')',
+ remainder of s after first unmatched ')'), e.g.,
+ up_to_unmatched_closing_paren("a == (b + c)) { ")
+ returns "a == (b + c)", " {".
+ Returns None, None if there is no unmatched ')'
+
+ """
+ i = 1
+ for pos, c in enumerate(s):
+ if c == '(':
+ i += 1
+ elif c == ')':
+ i -= 1
+ if i == 0:
+ return s[:pos], s[pos + 1:]
+ return None, None
+
+class _IncludeState(dict):
+ """Tracks line numbers for includes, and the order in which includes appear.
+
+ As a dict, an _IncludeState object serves as a mapping between include
+ filename and line number on which that file was included.
+
+ Call check_next_include_order() once for each header in the file, passing
+ in the type constants defined above. Calls in an illegal order will
+ raise an _IncludeError with an appropriate error message.
+
+ """
+ # self._section will move monotonically through this set. If it ever
+ # needs to move backwards, check_next_include_order will raise an error.
+ _INITIAL_SECTION = 0
+ _CONFIG_SECTION = 1
+ _PRIMARY_SECTION = 2
+ _OTHER_SECTION = 3
+
+ _TYPE_NAMES = {
+ _CONFIG_HEADER: 'WebCore config.h',
+ _PRIMARY_HEADER: 'header this file implements',
+ _OTHER_HEADER: 'other header',
+ _MOC_HEADER: 'moc file',
+ }
+ _SECTION_NAMES = {
+ _INITIAL_SECTION: "... nothing.",
+ _CONFIG_SECTION: "WebCore config.h.",
+ _PRIMARY_SECTION: 'a header this file implements.',
+ _OTHER_SECTION: 'other header.',
+ }
+
+ def __init__(self):
+ dict.__init__(self)
+ self._section = self._INITIAL_SECTION
+ self._visited_primary_section = False
+ self.header_types = dict();
+
+ def visited_primary_section(self):
+ return self._visited_primary_section
+
+ def check_next_include_order(self, header_type, file_is_header):
+ """Returns a non-empty error message if the next header is out of order.
+
+ This function also updates the internal state to be ready to check
+ the next include.
+
+ Args:
+ header_type: One of the _XXX_HEADER constants defined above.
+ file_is_header: Whether the file that owns this _IncludeState is itself a header
+
+ Returns:
+ The empty string if the header is in the right order, or an
+ error message describing what's wrong.
+
+ """
+ if header_type == _CONFIG_HEADER and file_is_header:
+ return 'Header file should not contain WebCore config.h.'
+ if header_type == _PRIMARY_HEADER and file_is_header:
+ return 'Header file should not contain itself.'
+ if header_type == _MOC_HEADER:
+ return ''
+
+ error_message = ''
+ if self._section != self._OTHER_SECTION:
+ before_error_message = ('Found %s before %s' %
+ (self._TYPE_NAMES[header_type],
+ self._SECTION_NAMES[self._section + 1]))
+ after_error_message = ('Found %s after %s' %
+ (self._TYPE_NAMES[header_type],
+ self._SECTION_NAMES[self._section]))
+
+ if header_type == _CONFIG_HEADER:
+ if self._section >= self._CONFIG_SECTION:
+ error_message = after_error_message
+ self._section = self._CONFIG_SECTION
+ elif header_type == _PRIMARY_HEADER:
+ if self._section >= self._PRIMARY_SECTION:
+ error_message = after_error_message
+ elif self._section < self._CONFIG_SECTION:
+ error_message = before_error_message
+ self._section = self._PRIMARY_SECTION
+ self._visited_primary_section = True
+ else:
+ assert header_type == _OTHER_HEADER
+ if not file_is_header and self._section < self._PRIMARY_SECTION:
+ error_message = before_error_message
+ self._section = self._OTHER_SECTION
+
+ return error_message
+
+
+class _FunctionState(object):
+ """Tracks current function name and the number of lines in its body.
+
+ Attributes:
+ min_confidence: The minimum confidence level to use while checking style.
+
+ """
+
+ _NORMAL_TRIGGER = 250 # for --v=0, 500 for --v=1, etc.
+ _TEST_TRIGGER = 400 # about 50% more than _NORMAL_TRIGGER.
+
+ def __init__(self, min_confidence):
+ self.min_confidence = min_confidence
+ self.current_function = ''
+ self.in_a_function = False
+ self.lines_in_function = 0
+ # Make sure these will not be mistaken for real lines (even when a
+ # small amount is added to them).
+ self.body_start_line_number = -1000
+ self.ending_line_number = -1000
+
+ def begin(self, function_name, body_start_line_number, ending_line_number, is_declaration):
+ """Start analyzing function body.
+
+ Args:
+ function_name: The name of the function being tracked.
+ body_start_line_number: The line number of the { or the ; for a protoype.
+ ending_line_number: The line number where the function ends.
+ is_declaration: True if this is a prototype.
+ """
+ self.in_a_function = True
+ self.lines_in_function = -1 # Don't count the open brace line.
+ self.current_function = function_name
+ self.body_start_line_number = body_start_line_number
+ self.ending_line_number = ending_line_number
+ self.is_declaration = is_declaration
+
+ def count(self, line_number):
+ """Count line in current function body."""
+ if self.in_a_function and line_number >= self.body_start_line_number:
+ self.lines_in_function += 1
+
+ def check(self, error, line_number):
+ """Report if too many lines in function body.
+
+ Args:
+ error: The function to call with any errors found.
+ line_number: The number of the line to check.
+ """
+ if match(r'T(EST|est)', self.current_function):
+ base_trigger = self._TEST_TRIGGER
+ else:
+ base_trigger = self._NORMAL_TRIGGER
+ trigger = base_trigger * 2 ** self.min_confidence
+
+ if self.lines_in_function > trigger:
+ error_level = int(math.log(self.lines_in_function / base_trigger, 2))
+ # 50 => 0, 100 => 1, 200 => 2, 400 => 3, 800 => 4, 1600 => 5, ...
+ if error_level > 5:
+ error_level = 5
+ error(line_number, 'readability/fn_size', error_level,
+ 'Small and focused functions are preferred:'
+ ' %s has %d non-comment lines'
+ ' (error triggered by exceeding %d lines).' % (
+ self.current_function, self.lines_in_function, trigger))
+
+ def end(self):
+ """Stop analyzing function body."""
+ self.in_a_function = False
+
+
+class _IncludeError(Exception):
+ """Indicates a problem with the include order in a file."""
+ pass
+
+
+class FileInfo:
+ """Provides utility functions for filenames.
+
+ FileInfo provides easy access to the components of a file's path
+ relative to the project root.
+ """
+
+ def __init__(self, filename):
+ self._filename = filename
+
+ def full_name(self):
+ """Make Windows paths like Unix."""
+ return os.path.abspath(self._filename).replace('\\', '/')
+
+ def repository_name(self):
+ """Full name after removing the local path to the repository.
+
+ If we have a real absolute path name here we can try to do something smart:
+ detecting the root of the checkout and truncating /path/to/checkout from
+ the name so that we get header guards that don't include things like
+ "C:\Documents and Settings\..." or "/home/username/..." in them and thus
+ people on different computers who have checked the source out to different
+ locations won't see bogus errors.
+ """
+ fullname = self.full_name()
+
+ if os.path.exists(fullname):
+ project_dir = os.path.dirname(fullname)
+
+ if os.path.exists(os.path.join(project_dir, ".svn")):
+ # If there's a .svn file in the current directory, we
+ # recursively look up the directory tree for the top
+ # of the SVN checkout
+ root_dir = project_dir
+ one_up_dir = os.path.dirname(root_dir)
+ while os.path.exists(os.path.join(one_up_dir, ".svn")):
+ root_dir = os.path.dirname(root_dir)
+ one_up_dir = os.path.dirname(one_up_dir)
+
+ prefix = os.path.commonprefix([root_dir, project_dir])
+ return fullname[len(prefix) + 1:]
+
+ # Not SVN? Try to find a git top level directory by
+ # searching up from the current path.
+ root_dir = os.path.dirname(fullname)
+ while (root_dir != os.path.dirname(root_dir)
+ and not os.path.exists(os.path.join(root_dir, ".git"))):
+ root_dir = os.path.dirname(root_dir)
+ if os.path.exists(os.path.join(root_dir, ".git")):
+ prefix = os.path.commonprefix([root_dir, project_dir])
+ return fullname[len(prefix) + 1:]
+
+ # Don't know what to do; header guard warnings may be wrong...
+ return fullname
+
+ def split(self):
+ """Splits the file into the directory, basename, and extension.
+
+ For 'chrome/browser/browser.cpp', Split() would
+ return ('chrome/browser', 'browser', '.cpp')
+
+ Returns:
+ A tuple of (directory, basename, extension).
+ """
+
+ googlename = self.repository_name()
+ project, rest = os.path.split(googlename)
+ return (project,) + os.path.splitext(rest)
+
+ def base_name(self):
+ """File base name - text after the final slash, before the final period."""
+ return self.split()[1]
+
+ def extension(self):
+ """File extension - text following the final period."""
+ return self.split()[2]
+
+ def no_extension(self):
+ """File has no source file extension."""
+ return '/'.join(self.split()[0:2])
+
+ def is_source(self):
+ """File has a source file extension."""
+ return self.extension()[1:] in ('c', 'cc', 'cpp', 'cxx')
+
+
+# Matches standard C++ escape esequences per 2.13.2.3 of the C++ standard.
+_RE_PATTERN_CLEANSE_LINE_ESCAPES = re.compile(
+ r'\\([abfnrtv?"\\\']|\d+|x[0-9a-fA-F]+)')
+# Matches strings. Escape codes should already be removed by ESCAPES.
+_RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES = re.compile(r'"[^"]*"')
+# Matches characters. Escape codes should already be removed by ESCAPES.
+_RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES = re.compile(r"'.'")
+# Matches multi-line C++ comments.
+# This RE is a little bit more complicated than one might expect, because we
+# have to take care of space removals tools so we can handle comments inside
+# statements better.
+# The current rule is: We only clear spaces from both sides when we're at the
+# end of the line. Otherwise, we try to remove spaces from the right side,
+# if this doesn't work we try on left side but only if there's a non-character
+# on the right.
+_RE_PATTERN_CLEANSE_LINE_C_COMMENTS = re.compile(
+ r"""(\s*/\*.*\*/\s*$|
+ /\*.*\*/\s+|
+ \s+/\*.*\*/(?=\W)|
+ /\*.*\*/)""", re.VERBOSE)
+
+
+def is_cpp_string(line):
+ """Does line terminate so, that the next symbol is in string constant.
+
+ This function does not consider single-line nor multi-line comments.
+
+ Args:
+ line: is a partial line of code starting from the 0..n.
+
+ Returns:
+ True, if next character appended to 'line' is inside a
+ string constant.
+ """
+
+ line = line.replace(r'\\', 'XX') # after this, \\" does not match to \"
+ return ((line.count('"') - line.count(r'\"') - line.count("'\"'")) & 1) == 1
+
+
+def find_next_multi_line_comment_start(lines, line_index):
+ """Find the beginning marker for a multiline comment."""
+ while line_index < len(lines):
+ if lines[line_index].strip().startswith('/*'):
+ # Only return this marker if the comment goes beyond this line
+ if lines[line_index].strip().find('*/', 2) < 0:
+ return line_index
+ line_index += 1
+ return len(lines)
+
+
+def find_next_multi_line_comment_end(lines, line_index):
+ """We are inside a comment, find the end marker."""
+ while line_index < len(lines):
+ if lines[line_index].strip().endswith('*/'):
+ return line_index
+ line_index += 1
+ return len(lines)
+
+
+def remove_multi_line_comments_from_range(lines, begin, end):
+ """Clears a range of lines for multi-line comments."""
+ # Having // dummy comments makes the lines non-empty, so we will not get
+ # unnecessary blank line warnings later in the code.
+ for i in range(begin, end):
+ lines[i] = '// dummy'
+
+
+def remove_multi_line_comments(lines, error):
+ """Removes multiline (c-style) comments from lines."""
+ line_index = 0
+ while line_index < len(lines):
+ line_index_begin = find_next_multi_line_comment_start(lines, line_index)
+ if line_index_begin >= len(lines):
+ return
+ line_index_end = find_next_multi_line_comment_end(lines, line_index_begin)
+ if line_index_end >= len(lines):
+ error(line_index_begin + 1, 'readability/multiline_comment', 5,
+ 'Could not find end of multi-line comment')
+ return
+ remove_multi_line_comments_from_range(lines, line_index_begin, line_index_end + 1)
+ line_index = line_index_end + 1
+
+
+def cleanse_comments(line):
+ """Removes //-comments and single-line C-style /* */ comments.
+
+ Args:
+ line: A line of C++ source.
+
+ Returns:
+ The line with single-line comments removed.
+ """
+ comment_position = line.find('//')
+ if comment_position != -1 and not is_cpp_string(line[:comment_position]):
+ line = line[:comment_position]
+ # get rid of /* ... */
+ return _RE_PATTERN_CLEANSE_LINE_C_COMMENTS.sub('', line)
+
+
+class CleansedLines(object):
+ """Holds 3 copies of all lines with different preprocessing applied to them.
+
+ 1) elided member contains lines without strings and comments,
+ 2) lines member contains lines without comments, and
+ 3) raw member contains all the lines without processing.
+ All these three members are of <type 'list'>, and of the same length.
+ """
+
+ def __init__(self, lines):
+ self.elided = []
+ self.lines = []
+ self.raw_lines = lines
+ self._num_lines = len(lines)
+ for line_number in range(len(lines)):
+ self.lines.append(cleanse_comments(lines[line_number]))
+ elided = self.collapse_strings(lines[line_number])
+ self.elided.append(cleanse_comments(elided))
+
+ def num_lines(self):
+ """Returns the number of lines represented."""
+ return self._num_lines
+
+ @staticmethod
+ def collapse_strings(elided):
+ """Collapses strings and chars on a line to simple "" or '' blocks.
+
+ We nix strings first so we're not fooled by text like '"http://"'
+
+ Args:
+ elided: The line being processed.
+
+ Returns:
+ The line with collapsed strings.
+ """
+ if not _RE_PATTERN_INCLUDE.match(elided):
+ # Remove escaped characters first to make quote/single quote collapsing
+ # basic. Things that look like escaped characters shouldn't occur
+ # outside of strings and chars.
+ elided = _RE_PATTERN_CLEANSE_LINE_ESCAPES.sub('', elided)
+ elided = _RE_PATTERN_CLEANSE_LINE_SINGLE_QUOTES.sub("''", elided)
+ elided = _RE_PATTERN_CLEANSE_LINE_DOUBLE_QUOTES.sub('""', elided)
+ return elided
+
+
+def close_expression(clean_lines, line_number, pos):
+ """If input points to ( or { or [, finds the position that closes it.
+
+ If clean_lines.elided[line_number][pos] points to a '(' or '{' or '[', finds
+ the line_number/pos that correspond to the closing of the expression.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ pos: A position on the line.
+
+ Returns:
+ A tuple (line, line_number, pos) pointer *past* the closing brace, or
+ ('', len(clean_lines.elided), -1) if we never find a close. Note we
+ ignore strings and comments when matching; and the line we return is the
+ 'cleansed' line at line_number.
+ """
+
+ line = clean_lines.elided[line_number]
+ start_character = line[pos]
+ if start_character not in '({[':
+ return (line, clean_lines.num_lines(), -1)
+ if start_character == '(':
+ end_character = ')'
+ if start_character == '[':
+ end_character = ']'
+ if start_character == '{':
+ end_character = '}'
+
+ num_open = line.count(start_character) - line.count(end_character)
+ while num_open > 0:
+ line_number += 1
+ if line_number >= clean_lines.num_lines():
+ return ('', len(clean_lines.elided), -1)
+ line = clean_lines.elided[line_number]
+ num_open += line.count(start_character) - line.count(end_character)
+ # OK, now find the end_character that actually got us back to even
+ endpos = len(line)
+ while num_open >= 0:
+ endpos = line.rfind(')', 0, endpos)
+ num_open -= 1 # chopped off another )
+ return (line, line_number, endpos + 1)
+
+
+def check_for_copyright(lines, error):
+ """Logs an error if no Copyright message appears at the top of the file."""
+
+ # We'll say it should occur by line 10. Don't forget there's a
+ # dummy line at the front.
+ for line in xrange(1, min(len(lines), 11)):
+ if re.search(r'Copyright', lines[line], re.I):
+ break
+ else: # means no copyright line was found
+ error(0, 'legal/copyright', 5,
+ 'No copyright message found. '
+ 'You should have a line: "Copyright [year] <Copyright Owner>"')
+
+
+def get_header_guard_cpp_variable(filename):
+ """Returns the CPP variable that should be used as a header guard.
+
+ Args:
+ filename: The name of a C++ header file.
+
+ Returns:
+ The CPP variable that should be used as a header guard in the
+ named file.
+
+ """
+
+ # Restores original filename in case that style checker is invoked from Emacs's
+ # flymake.
+ filename = re.sub(r'_flymake\.h$', '.h', filename)
+
+ standard_name = sub(r'[-.\s]', '_', os.path.basename(filename))
+
+ # Files under WTF typically have header guards that start with WTF_.
+ if filename.find('/wtf/'):
+ special_name = "WTF_" + standard_name
+ else:
+ special_name = standard_name
+ return (special_name, standard_name)
+
+
+def check_for_header_guard(filename, lines, error):
+ """Checks that the file contains a header guard.
+
+ Logs an error if no #ifndef header guard is present. For other
+ headers, checks that the full pathname is used.
+
+ Args:
+ filename: The name of the C++ header file.
+ lines: An array of strings, each representing a line of the file.
+ error: The function to call with any errors found.
+ """
+
+ cppvar = get_header_guard_cpp_variable(filename)
+
+ ifndef = None
+ ifndef_line_number = 0
+ define = None
+ for line_number, line in enumerate(lines):
+ line_split = line.split()
+ if len(line_split) >= 2:
+ # find the first occurrence of #ifndef and #define, save arg
+ if not ifndef and line_split[0] == '#ifndef':
+ # set ifndef to the header guard presented on the #ifndef line.
+ ifndef = line_split[1]
+ ifndef_line_number = line_number
+ if not define and line_split[0] == '#define':
+ define = line_split[1]
+ if define and ifndef:
+ break
+
+ if not ifndef or not define or ifndef != define:
+ error(0, 'build/header_guard', 5,
+ 'No #ifndef header guard found, suggested CPP variable is: %s' %
+ cppvar[0])
+ return
+
+ # The guard should be File_h.
+ if ifndef not in cppvar:
+ error(ifndef_line_number, 'build/header_guard', 5,
+ '#ifndef header guard has wrong style, please use: %s' % cppvar[0])
+
+
+def check_for_unicode_replacement_characters(lines, error):
+ """Logs an error for each line containing Unicode replacement characters.
+
+ These indicate that either the file contained invalid UTF-8 (likely)
+ or Unicode replacement characters (which it shouldn't). Note that
+ it's possible for this to throw off line numbering if the invalid
+ UTF-8 occurred adjacent to a newline.
+
+ Args:
+ lines: An array of strings, each representing a line of the file.
+ error: The function to call with any errors found.
+ """
+ for line_number, line in enumerate(lines):
+ if u'\ufffd' in line:
+ error(line_number, 'readability/utf8', 5,
+ 'Line contains invalid UTF-8 (or Unicode replacement character).')
+
+
+def check_for_new_line_at_eof(lines, error):
+ """Logs an error if there is no newline char at the end of the file.
+
+ Args:
+ lines: An array of strings, each representing a line of the file.
+ error: The function to call with any errors found.
+ """
+
+ # The array lines() was created by adding two newlines to the
+ # original file (go figure), then splitting on \n.
+ # To verify that the file ends in \n, we just have to make sure the
+ # last-but-two element of lines() exists and is empty.
+ if len(lines) < 3 or lines[-2]:
+ error(len(lines) - 2, 'whitespace/ending_newline', 5,
+ 'Could not find a newline character at the end of the file.')
+
+
+def check_for_multiline_comments_and_strings(clean_lines, line_number, error):
+ """Logs an error if we see /* ... */ or "..." that extend past one line.
+
+ /* ... */ comments are legit inside macros, for one line.
+ Otherwise, we prefer // comments, so it's ok to warn about the
+ other. Likewise, it's ok for strings to extend across multiple
+ lines, as long as a line continuation character (backslash)
+ terminates each line. Although not currently prohibited by the C++
+ style guide, it's ugly and unnecessary. We don't do well with either
+ in this lint program, so we warn about both.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[line_number]
+
+ # Remove all \\ (escaped backslashes) from the line. They are OK, and the
+ # second (escaped) slash may trigger later \" detection erroneously.
+ line = line.replace('\\\\', '')
+
+ if line.count('/*') > line.count('*/'):
+ error(line_number, 'readability/multiline_comment', 5,
+ 'Complex multi-line /*...*/-style comment found. '
+ 'Lint may give bogus warnings. '
+ 'Consider replacing these with //-style comments, '
+ 'with #if 0...#endif, '
+ 'or with more clearly structured multi-line comments.')
+
+ if (line.count('"') - line.count('\\"')) % 2:
+ error(line_number, 'readability/multiline_string', 5,
+ 'Multi-line string ("...") found. This lint script doesn\'t '
+ 'do well with such strings, and may give bogus warnings. They\'re '
+ 'ugly and unnecessary, and you should use concatenation instead".')
+
+
+_THREADING_LIST = (
+ ('asctime(', 'asctime_r('),
+ ('ctime(', 'ctime_r('),
+ ('getgrgid(', 'getgrgid_r('),
+ ('getgrnam(', 'getgrnam_r('),
+ ('getlogin(', 'getlogin_r('),
+ ('getpwnam(', 'getpwnam_r('),
+ ('getpwuid(', 'getpwuid_r('),
+ ('gmtime(', 'gmtime_r('),
+ ('localtime(', 'localtime_r('),
+ ('rand(', 'rand_r('),
+ ('readdir(', 'readdir_r('),
+ ('strtok(', 'strtok_r('),
+ ('ttyname(', 'ttyname_r('),
+ )
+
+
+def check_posix_threading(clean_lines, line_number, error):
+ """Checks for calls to thread-unsafe functions.
+
+ Much code has been originally written without consideration of
+ multi-threading. Also, engineers are relying on their old experience;
+ they have learned posix before threading extensions were added. These
+ tests guide the engineers to use thread-safe functions (when using
+ posix directly).
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[line_number]
+ for single_thread_function, multithread_safe_function in _THREADING_LIST:
+ index = line.find(single_thread_function)
+ # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
+ if index >= 0 and (index == 0 or (not line[index - 1].isalnum()
+ and line[index - 1] not in ('_', '.', '>'))):
+ error(line_number, 'runtime/threadsafe_fn', 2,
+ 'Consider using ' + multithread_safe_function +
+ '...) instead of ' + single_thread_function +
+ '...) for improved thread safety.')
+
+
+# Matches invalid increment: *count++, which moves pointer instead of
+# incrementing a value.
+_RE_PATTERN_INVALID_INCREMENT = re.compile(
+ r'^\s*\*\w+(\+\+|--);')
+
+
+def check_invalid_increment(clean_lines, line_number, error):
+ """Checks for invalid increment *count++.
+
+ For example following function:
+ void increment_counter(int* count) {
+ *count++;
+ }
+ is invalid, because it effectively does count++, moving pointer, and should
+ be replaced with ++*count, (*count)++ or *count += 1.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+ line = clean_lines.elided[line_number]
+ if _RE_PATTERN_INVALID_INCREMENT.match(line):
+ error(line_number, 'runtime/invalid_increment', 5,
+ 'Changing pointer instead of value (or unused value of operator*).')
+
+
+class _ClassInfo(object):
+ """Stores information about a class."""
+
+ def __init__(self, name, line_number):
+ self.name = name
+ self.line_number = line_number
+ self.seen_open_brace = False
+ self.is_derived = False
+ self.virtual_method_line_number = None
+ self.has_virtual_destructor = False
+ self.brace_depth = 0
+
+
+class _ClassState(object):
+ """Holds the current state of the parse relating to class declarations.
+
+ It maintains a stack of _ClassInfos representing the parser's guess
+ as to the current nesting of class declarations. The innermost class
+ is at the top (back) of the stack. Typically, the stack will either
+ be empty or have exactly one entry.
+ """
+
+ def __init__(self):
+ self.classinfo_stack = []
+
+ def check_finished(self, error):
+ """Checks that all classes have been completely parsed.
+
+ Call this when all lines in a file have been processed.
+ Args:
+ error: The function to call with any errors found.
+ """
+ if self.classinfo_stack:
+ # Note: This test can result in false positives if #ifdef constructs
+ # get in the way of brace matching. See the testBuildClass test in
+ # cpp_style_unittest.py for an example of this.
+ error(self.classinfo_stack[0].line_number, 'build/class', 5,
+ 'Failed to find complete declaration of class %s' %
+ self.classinfo_stack[0].name)
+
+
+class _FileState(object):
+ def __init__(self, clean_lines, file_extension):
+ self._did_inside_namespace_indent_warning = False
+ self._clean_lines = clean_lines
+ if file_extension in ['m', 'mm']:
+ self._is_objective_c = True
+ elif file_extension == 'h':
+ # In the case of header files, it is unknown if the file
+ # is objective c or not, so set this value to None and then
+ # if it is requested, use heuristics to guess the value.
+ self._is_objective_c = None
+ else:
+ self._is_objective_c = False
+ self._is_c = file_extension == 'c'
+
+ def set_did_inside_namespace_indent_warning(self):
+ self._did_inside_namespace_indent_warning = True
+
+ def did_inside_namespace_indent_warning(self):
+ return self._did_inside_namespace_indent_warning
+
+ def is_objective_c(self):
+ if self._is_objective_c is None:
+ for line in self._clean_lines.elided:
+ # Starting with @ or #import seem like the best indications
+ # that we have an Objective C file.
+ if line.startswith("@") or line.startswith("#import"):
+ self._is_objective_c = True
+ break
+ else:
+ self._is_objective_c = False
+ return self._is_objective_c
+
+ def is_c_or_objective_c(self):
+ """Return whether the file extension corresponds to C or Objective-C."""
+ return self._is_c or self.is_objective_c()
+
+
+def check_for_non_standard_constructs(clean_lines, line_number,
+ class_state, error):
+ """Logs an error if we see certain non-ANSI constructs ignored by gcc-2.
+
+ Complain about several constructs which gcc-2 accepts, but which are
+ not standard C++. Warning about these in lint is one way to ease the
+ transition to new compilers.
+ - put storage class first (e.g. "static const" instead of "const static").
+ - "%lld" instead of %qd" in printf-type functions.
+ - "%1$d" is non-standard in printf-type functions.
+ - "\%" is an undefined character escape sequence.
+ - text after #endif is not allowed.
+ - invalid inner-style forward declaration.
+ - >? and <? operators, and their >?= and <?= cousins.
+ - classes with virtual methods need virtual destructors (compiler warning
+ available, but not turned on yet.)
+
+ Additionally, check for constructor/destructor style violations as it
+ is very convenient to do so while checking for gcc-2 compliance.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ class_state: A _ClassState instance which maintains information about
+ the current stack of nested class declarations being parsed.
+ error: A callable to which errors are reported, which takes parameters:
+ line number, error level, and message
+ """
+
+ # Remove comments from the line, but leave in strings for now.
+ line = clean_lines.lines[line_number]
+
+ if search(r'printf\s*\(.*".*%[-+ ]?\d*q', line):
+ error(line_number, 'runtime/printf_format', 3,
+ '%q in format strings is deprecated. Use %ll instead.')
+
+ if search(r'printf\s*\(.*".*%\d+\$', line):
+ error(line_number, 'runtime/printf_format', 2,
+ '%N$ formats are unconventional. Try rewriting to avoid them.')
+
+ # Remove escaped backslashes before looking for undefined escapes.
+ line = line.replace('\\\\', '')
+
+ if search(r'("|\').*\\(%|\[|\(|{)', line):
+ error(line_number, 'build/printf_format', 3,
+ '%, [, (, and { are undefined character escapes. Unescape them.')
+
+ # For the rest, work with both comments and strings removed.
+ line = clean_lines.elided[line_number]
+
+ if search(r'\b(const|volatile|void|char|short|int|long'
+ r'|float|double|signed|unsigned'
+ r'|schar|u?int8|u?int16|u?int32|u?int64)'
+ r'\s+(auto|register|static|extern|typedef)\b',
+ line):
+ error(line_number, 'build/storage_class', 5,
+ 'Storage class (static, extern, typedef, etc) should be first.')
+
+ if match(r'\s*#\s*endif\s*[^/\s]+', line):
+ error(line_number, 'build/endif_comment', 5,
+ 'Uncommented text after #endif is non-standard. Use a comment.')
+
+ if match(r'\s*class\s+(\w+\s*::\s*)+\w+\s*;', line):
+ error(line_number, 'build/forward_decl', 5,
+ 'Inner-style forward declarations are invalid. Remove this line.')
+
+ if search(r'(\w+|[+-]?\d+(\.\d*)?)\s*(<|>)\?=?\s*(\w+|[+-]?\d+)(\.\d*)?', line):
+ error(line_number, 'build/deprecated', 3,
+ '>? and <? (max and min) operators are non-standard and deprecated.')
+
+ # Track class entry and exit, and attempt to find cases within the
+ # class declaration that don't meet the C++ style
+ # guidelines. Tracking is very dependent on the code matching Google
+ # style guidelines, but it seems to perform well enough in testing
+ # to be a worthwhile addition to the checks.
+ classinfo_stack = class_state.classinfo_stack
+ # Look for a class declaration
+ class_decl_match = match(
+ r'\s*(template\s*<[\w\s<>,:]*>\s*)?(class|struct)\s+(\w+(::\w+)*)', line)
+ if class_decl_match:
+ classinfo_stack.append(_ClassInfo(class_decl_match.group(3), line_number))
+
+ # Everything else in this function uses the top of the stack if it's
+ # not empty.
+ if not classinfo_stack:
+ return
+
+ classinfo = classinfo_stack[-1]
+
+ # If the opening brace hasn't been seen look for it and also
+ # parent class declarations.
+ if not classinfo.seen_open_brace:
+ # If the line has a ';' in it, assume it's a forward declaration or
+ # a single-line class declaration, which we won't process.
+ if line.find(';') != -1:
+ classinfo_stack.pop()
+ return
+ classinfo.seen_open_brace = (line.find('{') != -1)
+ # Look for a bare ':'
+ if search('(^|[^:]):($|[^:])', line):
+ classinfo.is_derived = True
+ if not classinfo.seen_open_brace:
+ return # Everything else in this function is for after open brace
+
+ # The class may have been declared with namespace or classname qualifiers.
+ # The constructor and destructor will not have those qualifiers.
+ base_classname = classinfo.name.split('::')[-1]
+
+ # Look for single-argument constructors that aren't marked explicit.
+ # Technically a valid construct, but against style.
+ args = match(r'(?<!explicit)\s+%s\s*\(([^,()]+)\)'
+ % re.escape(base_classname),
+ line)
+ if (args
+ and args.group(1) != 'void'
+ and not match(r'(const\s+)?%s\s*&' % re.escape(base_classname),
+ args.group(1).strip())):
+ error(line_number, 'runtime/explicit', 5,
+ 'Single-argument constructors should be marked explicit.')
+
+ # Look for methods declared virtual.
+ if search(r'\bvirtual\b', line):
+ classinfo.virtual_method_line_number = line_number
+ # Only look for a destructor declaration on the same line. It would
+ # be extremely unlikely for the destructor declaration to occupy
+ # more than one line.
+ if search(r'~%s\s*\(' % base_classname, line):
+ classinfo.has_virtual_destructor = True
+
+ # Look for class end.
+ brace_depth = classinfo.brace_depth
+ brace_depth = brace_depth + line.count('{') - line.count('}')
+ if brace_depth <= 0:
+ classinfo = classinfo_stack.pop()
+ # Try to detect missing virtual destructor declarations.
+ # For now, only warn if a non-derived class with virtual methods lacks
+ # a virtual destructor. This is to make it less likely that people will
+ # declare derived virtual destructors without declaring the base
+ # destructor virtual.
+ if ((classinfo.virtual_method_line_number is not None)
+ and (not classinfo.has_virtual_destructor)
+ and (not classinfo.is_derived)): # Only warn for base classes
+ error(classinfo.line_number, 'runtime/virtual', 4,
+ 'The class %s probably needs a virtual destructor due to '
+ 'having virtual method(s), one declared at line %d.'
+ % (classinfo.name, classinfo.virtual_method_line_number))
+ else:
+ classinfo.brace_depth = brace_depth
+
+
+def check_spacing_for_function_call(line, line_number, error):
+ """Checks for the correctness of various spacing around function calls.
+
+ Args:
+ line: The text of the line to check.
+ line_number: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ # Since function calls often occur inside if/for/foreach/while/switch
+ # expressions - which have their own, more liberal conventions - we
+ # first see if we should be looking inside such an expression for a
+ # function call, to which we can apply more strict standards.
+ function_call = line # if there's no control flow construct, look at whole line
+ for pattern in (r'\bif\s*\((.*)\)\s*{',
+ r'\bfor\s*\((.*)\)\s*{',
+ r'\bforeach\s*\((.*)\)\s*{',
+ r'\bwhile\s*\((.*)\)\s*[{;]',
+ r'\bswitch\s*\((.*)\)\s*{'):
+ matched = search(pattern, line)
+ if matched:
+ function_call = matched.group(1) # look inside the parens for function calls
+ break
+
+ # Except in if/for/foreach/while/switch, there should never be space
+ # immediately inside parens (eg "f( 3, 4 )"). We make an exception
+ # for nested parens ( (a+b) + c ). Likewise, there should never be
+ # a space before a ( when it's a function argument. I assume it's a
+ # function argument when the char before the whitespace is legal in
+ # a function name (alnum + _) and we're not starting a macro. Also ignore
+ # pointers and references to arrays and functions coz they're too tricky:
+ # we use a very simple way to recognize these:
+ # " (something)(maybe-something)" or
+ # " (something)(maybe-something," or
+ # " (something)[something]"
+ # Note that we assume the contents of [] to be short enough that
+ # they'll never need to wrap.
+ if ( # Ignore control structures.
+ not search(r'\b(if|for|foreach|while|switch|return|new|delete)\b', function_call)
+ # Ignore pointers/references to functions.
+ and not search(r' \([^)]+\)\([^)]*(\)|,$)', function_call)
+ # Ignore pointers/references to arrays.
+ and not search(r' \([^)]+\)\[[^\]]+\]', function_call)):
+ if search(r'\w\s*\([ \t](?!\s*\\$)', function_call): # a ( used for a fn call
+ error(line_number, 'whitespace/parens', 4,
+ 'Extra space after ( in function call')
+ elif search(r'\([ \t]+(?!(\s*\\)|\()', function_call):
+ error(line_number, 'whitespace/parens', 2,
+ 'Extra space after (')
+ if (search(r'\w\s+\(', function_call)
+ and not search(r'#\s*define|typedef', function_call)):
+ error(line_number, 'whitespace/parens', 4,
+ 'Extra space before ( in function call')
+ # If the ) is followed only by a newline or a { + newline, assume it's
+ # part of a control statement (if/while/etc), and don't complain
+ if search(r'[^)\s]\s+\)(?!\s*$|{\s*$)', function_call):
+ error(line_number, 'whitespace/parens', 2,
+ 'Extra space before )')
+
+
+def is_blank_line(line):
+ """Returns true if the given line is blank.
+
+ We consider a line to be blank if the line is empty or consists of
+ only white spaces.
+
+ Args:
+ line: A line of a string.
+
+ Returns:
+ True, if the given line is blank.
+ """
+ return not line or line.isspace()
+
+
+def detect_functions(clean_lines, line_number, function_state, error):
+ """Finds where functions start and end.
+
+ Uses a simplistic algorithm assuming other style guidelines
+ (especially spacing) are followed.
+ Trivial bodies are unchecked, so constructors with huge initializer lists
+ may be missed.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ function_state: Current function name and lines in body so far.
+ error: The function to call with any errors found.
+ """
+ # Are we now past the end of a function?
+ if function_state.ending_line_number + 1 == line_number:
+ function_state.end()
+
+ # If we're in a function, don't try to detect a new one.
+ if function_state.in_a_function:
+ return
+
+ lines = clean_lines.lines
+ line = lines[line_number]
+ raw = clean_lines.raw_lines
+ raw_line = raw[line_number]
+
+ regexp = r'\s*(\w(\w|::|\*|\&|\s|<|>|,|~)*)\(' # decls * & space::name( ...
+ match_result = match(regexp, line)
+ if not match_result:
+ return
+
+ # If the name is all caps and underscores, figure it's a macro and
+ # ignore it, unless it's TEST or TEST_F.
+ function_name = match_result.group(1).split()[-1]
+ if function_name != 'TEST' and function_name != 'TEST_F' and match(r'[A-Z_]+$', function_name):
+ return
+
+ joined_line = ''
+ for start_line_number in xrange(line_number, clean_lines.num_lines()):
+ start_line = clean_lines.elided[start_line_number]
+ joined_line += ' ' + start_line.lstrip()
+ if search(r'{|;', start_line):
+ # Replace template constructs with _ so that no spaces remain in the function name,
+ # while keeping the column numbers of other characters the same as "line".
+ line_with_no_templates = iteratively_replace_matches_with_char(r'<[^<>]*>', '_', line)
+ match_function = search(r'((\w|:|<|>|,|~)*)\(', line_with_no_templates)
+ if not match_function:
+ return # The '(' must have been inside of a template.
+
+ # Use the column numbers from the modified line to find the
+ # function name in the original line.
+ function = line[match_function.start(1):match_function.end(1)]
+
+ if match(r'TEST', function): # Handle TEST... macros
+ parameter_regexp = search(r'(\(.*\))', joined_line)
+ if parameter_regexp: # Ignore bad syntax
+ function += parameter_regexp.group(1)
+ else:
+ function += '()'
+ is_declaration = bool(search(r'^[^{]*;', start_line))
+ if is_declaration:
+ ending_line_number = start_line_number
+ else:
+ open_brace_index = start_line.find('{')
+ ending_line_number = close_expression(clean_lines, start_line_number, open_brace_index)[1]
+ function_state.begin(function, start_line_number, ending_line_number, is_declaration)
+ return
+
+ # No body for the function (or evidence of a non-function) was found.
+ error(line_number, 'readability/fn_size', 5,
+ 'Lint failed to find start of function body.')
+
+
+def check_for_function_lengths(clean_lines, line_number, function_state, error):
+ """Reports for long function bodies.
+
+ For an overview why this is done, see:
+ http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Write_Short_Functions
+
+ Blank/comment lines are not counted so as to avoid encouraging the removal
+ of vertical space and commments just to get through a lint check.
+ NOLINT *on the last line of a function* disables this check.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ function_state: Current function name and lines in body so far.
+ error: The function to call with any errors found.
+ """
+ lines = clean_lines.lines
+ line = lines[line_number]
+ raw = clean_lines.raw_lines
+ raw_line = raw[line_number]
+
+ if function_state.ending_line_number == line_number: # last line
+ if not search(r'\bNOLINT\b', raw_line):
+ function_state.check(error, line_number)
+ elif not match(r'^\s*$', line):
+ function_state.count(line_number) # Count non-blank/non-comment lines.
+
+
+def check_pass_ptr_usage(clean_lines, line_number, function_state, error):
+ """Check for proper usage of Pass*Ptr.
+
+ Currently this is limited to detecting declarations of Pass*Ptr
+ variables inside of functions.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ function_state: Current function name and lines in body so far.
+ error: The function to call with any errors found.
+ """
+ if not function_state.in_a_function:
+ return
+
+ lines = clean_lines.lines
+ line = lines[line_number]
+ if line_number > function_state.body_start_line_number:
+ matched_pass_ptr = match(r'^\s*Pass([A-Z][A-Za-z]*)Ptr<', line)
+ if matched_pass_ptr:
+ type_name = 'Pass%sPtr' % matched_pass_ptr.group(1)
+ error(line_number, 'readability/pass_ptr', 5,
+ 'Local variables should never be %s (see '
+ 'http://webkit.org/coding/RefPtr.html).' % type_name)
+
+
+def check_spacing(file_extension, clean_lines, line_number, error):
+ """Checks for the correctness of various spacing issues in the code.
+
+ Things we check for: spaces around operators, spaces after
+ if/for/while/switch, no spaces around parens in function calls, two
+ spaces between code and comment, don't start a block with a blank
+ line, don't end a function with a blank line, don't have too many
+ blank lines in a row.
+
+ Args:
+ file_extension: The current file extension, without the leading dot.
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ raw = clean_lines.raw_lines
+ line = raw[line_number]
+
+ # Before nixing comments, check if the line is blank for no good
+ # reason. This includes the first line after a block is opened, and
+ # blank lines at the end of a function (ie, right before a line like '}').
+ if is_blank_line(line):
+ elided = clean_lines.elided
+ previous_line = elided[line_number - 1]
+ previous_brace = previous_line.rfind('{')
+ # FIXME: Don't complain if line before blank line, and line after,
+ # both start with alnums and are indented the same amount.
+ # This ignores whitespace at the start of a namespace block
+ # because those are not usually indented.
+ if (previous_brace != -1 and previous_line[previous_brace:].find('}') == -1
+ and previous_line[:previous_brace].find('namespace') == -1):
+ # OK, we have a blank line at the start of a code block. Before we
+ # complain, we check if it is an exception to the rule: The previous
+ # non-empty line has the parameters of a function header that are indented
+ # 4 spaces (because they did not fit in a 80 column line when placed on
+ # the same line as the function name). We also check for the case where
+ # the previous line is indented 6 spaces, which may happen when the
+ # initializers of a constructor do not fit into a 80 column line.
+ exception = False
+ if match(r' {6}\w', previous_line): # Initializer list?
+ # We are looking for the opening column of initializer list, which
+ # should be indented 4 spaces to cause 6 space indentation afterwards.
+ search_position = line_number - 2
+ while (search_position >= 0
+ and match(r' {6}\w', elided[search_position])):
+ search_position -= 1
+ exception = (search_position >= 0
+ and elided[search_position][:5] == ' :')
+ else:
+ # Search for the function arguments or an initializer list. We use a
+ # simple heuristic here: If the line is indented 4 spaces; and we have a
+ # closing paren, without the opening paren, followed by an opening brace
+ # or colon (for initializer lists) we assume that it is the last line of
+ # a function header. If we have a colon indented 4 spaces, it is an
+ # initializer list.
+ exception = (match(r' {4}\w[^\(]*\)\s*(const\s*)?(\{\s*$|:)',
+ previous_line)
+ or match(r' {4}:', previous_line))
+
+ if not exception:
+ error(line_number, 'whitespace/blank_line', 2,
+ 'Blank line at the start of a code block. Is this needed?')
+ # This doesn't ignore whitespace at the end of a namespace block
+ # because that is too hard without pairing open/close braces;
+ # however, a special exception is made for namespace closing
+ # brackets which have a comment containing "namespace".
+ #
+ # Also, ignore blank lines at the end of a block in a long if-else
+ # chain, like this:
+ # if (condition1) {
+ # // Something followed by a blank line
+ #
+ # } else if (condition2) {
+ # // Something else
+ # }
+ if line_number + 1 < clean_lines.num_lines():
+ next_line = raw[line_number + 1]
+ if (next_line
+ and match(r'\s*}', next_line)
+ and next_line.find('namespace') == -1
+ and next_line.find('} else ') == -1):
+ error(line_number, 'whitespace/blank_line', 3,
+ 'Blank line at the end of a code block. Is this needed?')
+
+ # Next, we complain if there's a comment too near the text
+ comment_position = line.find('//')
+ if comment_position != -1:
+ # Check if the // may be in quotes. If so, ignore it
+ # Comparisons made explicit for clarity -- pylint: disable-msg=C6403
+ if (line.count('"', 0, comment_position) - line.count('\\"', 0, comment_position)) % 2 == 0: # not in quotes
+ # Allow one space before end of line comment.
+ if (not match(r'^\s*$', line[:comment_position])
+ and (comment_position >= 1
+ and ((line[comment_position - 1] not in string.whitespace)
+ or (comment_position >= 2
+ and line[comment_position - 2] in string.whitespace)))):
+ error(line_number, 'whitespace/comments', 5,
+ 'One space before end of line comments')
+ # There should always be a space between the // and the comment
+ commentend = comment_position + 2
+ if commentend < len(line) and not line[commentend] == ' ':
+ # but some lines are exceptions -- e.g. if they're big
+ # comment delimiters like:
+ # //----------------------------------------------------------
+ # or they begin with multiple slashes followed by a space:
+ # //////// Header comment
+ matched = (search(r'[=/-]{4,}\s*$', line[commentend:])
+ or search(r'^/+ ', line[commentend:]))
+ if not matched:
+ error(line_number, 'whitespace/comments', 4,
+ 'Should have a space between // and comment')
+
+ line = clean_lines.elided[line_number] # get rid of comments and strings
+
+ # Don't try to do spacing checks for operator methods
+ line = sub(r'operator(==|!=|<|<<|<=|>=|>>|>|\+=|-=|\*=|/=|%=|&=|\|=|^=|<<=|>>=)\(', 'operator\(', line)
+ # Don't try to do spacing checks for #include or #import statements at
+ # minimum because it messes up checks for spacing around /
+ if match(r'\s*#\s*(?:include|import)', line):
+ return
+ if search(r'[\w.]=[\w.]', line):
+ error(line_number, 'whitespace/operators', 4,
+ 'Missing spaces around =')
+
+ # FIXME: It's not ok to have spaces around binary operators like .
+
+ # You should always have whitespace around binary operators.
+ # Alas, we can't test < or > because they're legitimately used sans spaces
+ # (a->b, vector<int> a). The only time we can tell is a < with no >, and
+ # only if it's not template params list spilling into the next line.
+ matched = search(r'[^<>=!\s](==|!=|\+=|-=|\*=|/=|/|\|=|&=|<<=|>>=|<=|>=|\|\||\||&&|>>|<<)[^<>=!\s]', line)
+ if not matched:
+ # Note that while it seems that the '<[^<]*' term in the following
+ # regexp could be simplified to '<.*', which would indeed match
+ # the same class of strings, the [^<] means that searching for the
+ # regexp takes linear rather than quadratic time.
+ if not search(r'<[^<]*,\s*$', line): # template params spill
+ matched = search(r'[^<>=!\s](<)[^<>=!\s]([^>]|->)*$', line)
+ if matched:
+ error(line_number, 'whitespace/operators', 3,
+ 'Missing spaces around %s' % matched.group(1))
+
+ # There shouldn't be space around unary operators
+ matched = search(r'(!\s|~\s|[\s]--[\s;]|[\s]\+\+[\s;])', line)
+ if matched:
+ error(line_number, 'whitespace/operators', 4,
+ 'Extra space for operator %s' % matched.group(1))
+
+ # A pet peeve of mine: no spaces after an if, while, switch, or for
+ matched = search(r' (if\(|for\(|foreach\(|while\(|switch\()', line)
+ if matched:
+ error(line_number, 'whitespace/parens', 5,
+ 'Missing space before ( in %s' % matched.group(1))
+
+ # For if/for/foreach/while/switch, the left and right parens should be
+ # consistent about how many spaces are inside the parens, and
+ # there should either be zero or one spaces inside the parens.
+ # We don't want: "if ( foo)" or "if ( foo )".
+ # Exception: "for ( ; foo; bar)" and "for (foo; bar; )" are allowed.
+ matched = search(r'\b(?P<statement>if|for|foreach|while|switch)\s*\((?P<remainder>.*)$', line)
+ if matched:
+ statement = matched.group('statement')
+ condition, rest = up_to_unmatched_closing_paren(matched.group('remainder'))
+ if condition is not None:
+ condition_match = search(r'(?P<leading>[ ]*)(?P<separator>.).*[^ ]+(?P<trailing>[ ]*)', condition)
+ if condition_match:
+ n_leading = len(condition_match.group('leading'))
+ n_trailing = len(condition_match.group('trailing'))
+ if n_leading != 0:
+ for_exception = statement == 'for' and condition.startswith(' ;')
+ if not for_exception:
+ error(line_number, 'whitespace/parens', 5,
+ 'Extra space after ( in %s' % statement)
+ if n_trailing != 0:
+ for_exception = statement == 'for' and condition.endswith('; ')
+ if not for_exception:
+ error(line_number, 'whitespace/parens', 5,
+ 'Extra space before ) in %s' % statement)
+
+ # Do not check for more than one command in macros
+ in_preprocessor_directive = match(r'\s*#', line)
+ if not in_preprocessor_directive and not match(r'((\s*{\s*}?)|(\s*;?))\s*\\?$', rest):
+ error(line_number, 'whitespace/parens', 4,
+ 'More than one command on the same line in %s' % statement)
+
+ # You should always have a space after a comma (either as fn arg or operator)
+ if search(r',[^\s]', line):
+ error(line_number, 'whitespace/comma', 3,
+ 'Missing space after ,')
+
+ matched = search(r'^\s*(?P<token1>[a-zA-Z0-9_\*&]+)\s\s+(?P<token2>[a-zA-Z0-9_\*&]+)', line)
+ if matched:
+ error(line_number, 'whitespace/declaration', 3,
+ 'Extra space between %s and %s' % (matched.group('token1'), matched.group('token2')))
+
+ if file_extension == 'cpp':
+ # C++ should have the & or * beside the type not the variable name.
+ matched = match(r'\s*\w+(?<!\breturn|\bdelete)\s+(?P<pointer_operator>\*|\&)\w+', line)
+ if matched:
+ error(line_number, 'whitespace/declaration', 3,
+ 'Declaration has space between type name and %s in %s' % (matched.group('pointer_operator'), matched.group(0).strip()))
+
+ elif file_extension == 'c':
+ # C Pointer declaration should have the * beside the variable not the type name.
+ matched = search(r'^\s*\w+\*\s+\w+', line)
+ if matched:
+ error(line_number, 'whitespace/declaration', 3,
+ 'Declaration has space between * and variable name in %s' % matched.group(0).strip())
+
+ # Next we will look for issues with function calls.
+ check_spacing_for_function_call(line, line_number, error)
+
+ # Except after an opening paren, you should have spaces before your braces.
+ # And since you should never have braces at the beginning of a line, this is
+ # an easy test.
+ if search(r'[^ ({]{', line):
+ error(line_number, 'whitespace/braces', 5,
+ 'Missing space before {')
+
+ # Make sure '} else {' has spaces.
+ if search(r'}else', line):
+ error(line_number, 'whitespace/braces', 5,
+ 'Missing space before else')
+
+ # You shouldn't have spaces before your brackets, except maybe after
+ # 'delete []' or 'new char * []'.
+ if search(r'\w\s+\[', line) and not search(r'delete\s+\[', line):
+ error(line_number, 'whitespace/braces', 5,
+ 'Extra space before [')
+
+ # You shouldn't have a space before a semicolon at the end of the line.
+ # There's a special case for "for" since the style guide allows space before
+ # the semicolon there.
+ if search(r':\s*;\s*$', line):
+ error(line_number, 'whitespace/semicolon', 5,
+ 'Semicolon defining empty statement. Use { } instead.')
+ elif search(r'^\s*;\s*$', line):
+ error(line_number, 'whitespace/semicolon', 5,
+ 'Line contains only semicolon. If this should be an empty statement, '
+ 'use { } instead.')
+ elif (search(r'\s+;\s*$', line) and not search(r'\bfor\b', line)):
+ error(line_number, 'whitespace/semicolon', 5,
+ 'Extra space before last semicolon. If this should be an empty '
+ 'statement, use { } instead.')
+ elif (search(r'\b(for|while)\s*\(.*\)\s*;\s*$', line)
+ and line.count('(') == line.count(')')
+ # Allow do {} while();
+ and not search(r'}\s*while', line)):
+ error(line_number, 'whitespace/semicolon', 5,
+ 'Semicolon defining empty statement for this loop. Use { } instead.')
+
+
+def get_previous_non_blank_line(clean_lines, line_number):
+ """Return the most recent non-blank line and its line number.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file contents.
+ line_number: The number of the line to check.
+
+ Returns:
+ A tuple with two elements. The first element is the contents of the last
+ non-blank line before the current line, or the empty string if this is the
+ first non-blank line. The second is the line number of that line, or -1
+ if this is the first non-blank line.
+ """
+
+ previous_line_number = line_number - 1
+ while previous_line_number >= 0:
+ previous_line = clean_lines.elided[previous_line_number]
+ if not is_blank_line(previous_line): # if not a blank line...
+ return (previous_line, previous_line_number)
+ previous_line_number -= 1
+ return ('', -1)
+
+
+def check_namespace_indentation(clean_lines, line_number, file_extension, file_state, error):
+ """Looks for indentation errors inside of namespaces.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ file_extension: The extension (dot not included) of the file.
+ file_state: A _FileState instance which maintains information about
+ the state of things in the file.
+ error: The function to call with any errors found.
+ """
+
+ line = clean_lines.elided[line_number] # Get rid of comments and strings.
+
+ namespace_match = match(r'(?P<namespace_indentation>\s*)namespace\s+\S+\s*{\s*$', line)
+ if not namespace_match:
+ return
+
+ current_indentation_level = len(namespace_match.group('namespace_indentation'))
+ if current_indentation_level > 0:
+ # Don't warn about an indented namespace if we already warned about indented code.
+ if not file_state.did_inside_namespace_indent_warning():
+ error(line_number, 'whitespace/indent', 4,
+ 'namespace should never be indented.')
+ return
+ looking_for_semicolon = False;
+ line_offset = 0
+ in_preprocessor_directive = False;
+ for current_line in clean_lines.elided[line_number + 1:]:
+ line_offset += 1
+ if not current_line.strip():
+ continue
+ if not current_indentation_level:
+ if not (in_preprocessor_directive or looking_for_semicolon):
+ if not match(r'\S', current_line) and not file_state.did_inside_namespace_indent_warning():
+ file_state.set_did_inside_namespace_indent_warning()
+ error(line_number + line_offset, 'whitespace/indent', 4,
+ 'Code inside a namespace should not be indented.')
+ if in_preprocessor_directive or (current_line.strip()[0] == '#'): # This takes care of preprocessor directive syntax.
+ in_preprocessor_directive = current_line[-1] == '\\'
+ else:
+ looking_for_semicolon = ((current_line.find(';') == -1) and (current_line.strip()[-1] != '}')) or (current_line[-1] == '\\')
+ else:
+ looking_for_semicolon = False; # If we have a brace we may not need a semicolon.
+ current_indentation_level += current_line.count('{') - current_line.count('}')
+ if current_indentation_level < 0:
+ break;
+
+
+def check_using_std(clean_lines, line_number, file_state, error):
+ """Looks for 'using std::foo;' statements which should be replaced with 'using namespace std;'.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ file_state: A _FileState instance which maintains information about
+ the state of things in the file.
+ error: The function to call with any errors found.
+ """
+
+ # This check doesn't apply to C or Objective-C implementation files.
+ if file_state.is_c_or_objective_c():
+ return
+
+ line = clean_lines.elided[line_number] # Get rid of comments and strings.
+
+ using_std_match = match(r'\s*using\s+std::(?P<method_name>\S+)\s*;\s*$', line)
+ if not using_std_match:
+ return
+
+ method_name = using_std_match.group('method_name')
+ error(line_number, 'build/using_std', 4,
+ "Use 'using namespace std;' instead of 'using std::%s;'." % method_name)
+
+
+def check_max_min_macros(clean_lines, line_number, file_state, error):
+ """Looks use of MAX() and MIN() macros that should be replaced with std::max() and std::min().
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ file_state: A _FileState instance which maintains information about
+ the state of things in the file.
+ error: The function to call with any errors found.
+ """
+
+ # This check doesn't apply to C or Objective-C implementation files.
+ if file_state.is_c_or_objective_c():
+ return
+
+ line = clean_lines.elided[line_number] # Get rid of comments and strings.
+
+ max_min_macros_search = search(r'\b(?P<max_min_macro>(MAX|MIN))\s*\(', line)
+ if not max_min_macros_search:
+ return
+
+ max_min_macro = max_min_macros_search.group('max_min_macro')
+ max_min_macro_lower = max_min_macro.lower()
+ error(line_number, 'runtime/max_min_macros', 4,
+ 'Use std::%s() or std::%s<type>() instead of the %s() macro.'
+ % (max_min_macro_lower, max_min_macro_lower, max_min_macro))
+
+
+def check_switch_indentation(clean_lines, line_number, error):
+ """Looks for indentation errors inside of switch statements.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ line = clean_lines.elided[line_number] # Get rid of comments and strings.
+
+ switch_match = match(r'(?P<switch_indentation>\s*)switch\s*\(.+\)\s*{\s*$', line)
+ if not switch_match:
+ return
+
+ switch_indentation = switch_match.group('switch_indentation')
+ inner_indentation = switch_indentation + ' ' * 4
+ line_offset = 0
+ encountered_nested_switch = False
+
+ for current_line in clean_lines.elided[line_number + 1:]:
+ line_offset += 1
+
+ # Skip not only empty lines but also those with preprocessor directives.
+ if current_line.strip() == '' or current_line.startswith('#'):
+ continue
+
+ if match(r'\s*switch\s*\(.+\)\s*{\s*$', current_line):
+ # Complexity alarm - another switch statement nested inside the one
+ # that we're currently testing. We'll need to track the extent of
+ # that inner switch if the upcoming label tests are still supposed
+ # to work correctly. Let's not do that; instead, we'll finish
+ # checking this line, and then leave it like that. Assuming the
+ # indentation is done consistently (even if incorrectly), this will
+ # still catch all indentation issues in practice.
+ encountered_nested_switch = True
+
+ current_indentation_match = match(r'(?P<indentation>\s*)(?P<remaining_line>.*)$', current_line);
+ current_indentation = current_indentation_match.group('indentation')
+ remaining_line = current_indentation_match.group('remaining_line')
+
+ # End the check at the end of the switch statement.
+ if remaining_line.startswith('}') and current_indentation == switch_indentation:
+ break
+ # Case and default branches should not be indented. The regexp also
+ # catches single-line cases like "default: break;" but does not trigger
+ # on stuff like "Document::Foo();".
+ elif match(r'(default|case\s+.*)\s*:([^:].*)?$', remaining_line):
+ if current_indentation != switch_indentation:
+ error(line_number + line_offset, 'whitespace/indent', 4,
+ 'A case label should not be indented, but line up with its switch statement.')
+ # Don't throw an error for multiple badly indented labels,
+ # one should be enough to figure out the problem.
+ break
+ # We ignore goto labels at the very beginning of a line.
+ elif match(r'\w+\s*:\s*$', remaining_line):
+ continue
+ # It's not a goto label, so check if it's indented at least as far as
+ # the switch statement plus one more level of indentation.
+ elif not current_indentation.startswith(inner_indentation):
+ error(line_number + line_offset, 'whitespace/indent', 4,
+ 'Non-label code inside switch statements should be indented.')
+ # Don't throw an error for multiple badly indented statements,
+ # one should be enough to figure out the problem.
+ break
+
+ if encountered_nested_switch:
+ break
+
+
+def check_braces(clean_lines, line_number, error):
+ """Looks for misplaced braces (e.g. at the end of line).
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ line = clean_lines.elided[line_number] # Get rid of comments and strings.
+
+ if match(r'\s*{\s*$', line):
+ # We allow an open brace to start a line in the case where someone
+ # is using braces for function definition or in a block to
+ # explicitly create a new scope, which is commonly used to control
+ # the lifetime of stack-allocated variables. We don't detect this
+ # perfectly: we just don't complain if the last non-whitespace
+ # character on the previous non-blank line is ';', ':', '{', '}',
+ # ')', or ') const' and doesn't begin with 'if|for|while|switch|else'.
+ # We also allow '#' for #endif and '=' for array initialization.
+ previous_line = get_previous_non_blank_line(clean_lines, line_number)[0]
+ if ((not search(r'[;:}{)=]\s*$|\)\s*const\s*$', previous_line)
+ or search(r'\b(if|for|foreach|while|switch|else)\b', previous_line))
+ and previous_line.find('#') < 0):
+ error(line_number, 'whitespace/braces', 4,
+ 'This { should be at the end of the previous line')
+ elif (search(r'\)\s*(const\s*)?{\s*$', line)
+ and line.count('(') == line.count(')')
+ and not search(r'\b(if|for|foreach|while|switch)\b', line)
+ and not match(r'\s+[A-Z_][A-Z_0-9]+\b', line)):
+ error(line_number, 'whitespace/braces', 4,
+ 'Place brace on its own line for function definitions.')
+
+ if (match(r'\s*}\s*(else\s*({\s*)?)?$', line) and line_number > 1):
+ # We check if a closed brace has started a line to see if a
+ # one line control statement was previous.
+ previous_line = clean_lines.elided[line_number - 2]
+ if (previous_line.find('{') > 0 and previous_line.find('}') < 0
+ and search(r'\b(if|for|foreach|while|else)\b', previous_line)):
+ error(line_number, 'whitespace/braces', 4,
+ 'One line control clauses should not use braces.')
+
+ # An else clause should be on the same line as the preceding closing brace.
+ if match(r'\s*else\s*', line):
+ previous_line = get_previous_non_blank_line(clean_lines, line_number)[0]
+ if match(r'\s*}\s*$', previous_line):
+ error(line_number, 'whitespace/newline', 4,
+ 'An else should appear on the same line as the preceding }')
+
+ # Likewise, an else should never have the else clause on the same line
+ if search(r'\belse [^\s{]', line) and not search(r'\belse if\b', line):
+ error(line_number, 'whitespace/newline', 4,
+ 'Else clause should never be on same line as else (use 2 lines)')
+
+ # In the same way, a do/while should never be on one line
+ if match(r'\s*do [^\s{]', line):
+ error(line_number, 'whitespace/newline', 4,
+ 'do/while clauses should not be on a single line')
+
+ # Braces shouldn't be followed by a ; unless they're defining a struct
+ # or initializing an array.
+ # We can't tell in general, but we can for some common cases.
+ previous_line_number = line_number
+ while True:
+ (previous_line, previous_line_number) = get_previous_non_blank_line(clean_lines, previous_line_number)
+ if match(r'\s+{.*}\s*;', line) and not previous_line.count(';'):
+ line = previous_line + line
+ else:
+ break
+ if (search(r'{.*}\s*;', line)
+ and line.count('{') == line.count('}')
+ and not search(r'struct|class|enum|\s*=\s*{', line)):
+ error(line_number, 'readability/braces', 4,
+ "You don't need a ; after a }")
+
+
+def check_exit_statement_simplifications(clean_lines, line_number, error):
+ """Looks for else or else-if statements that should be written as an
+ if statement when the prior if concludes with a return, break, continue or
+ goto statement.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ line = clean_lines.elided[line_number] # Get rid of comments and strings.
+
+ else_match = match(r'(?P<else_indentation>\s*)(\}\s*)?else(\s+if\s*\(|(?P<else>\s*(\{\s*)?\Z))', line)
+ if not else_match:
+ return
+
+ else_indentation = else_match.group('else_indentation')
+ inner_indentation = else_indentation + ' ' * 4
+
+ previous_lines = clean_lines.elided[:line_number]
+ previous_lines.reverse()
+ line_offset = 0
+ encountered_exit_statement = False
+
+ for current_line in previous_lines:
+ line_offset -= 1
+
+ # Skip not only empty lines but also those with preprocessor directives
+ # and goto labels.
+ if current_line.strip() == '' or current_line.startswith('#') or match(r'\w+\s*:\s*$', current_line):
+ continue
+
+ # Skip lines with closing braces on the original indentation level.
+ # Even though the styleguide says they should be on the same line as
+ # the "else if" statement, we also want to check for instances where
+ # the current code does not comply with the coding style. Thus, ignore
+ # these lines and proceed to the line before that.
+ if current_line == else_indentation + '}':
+ continue
+
+ current_indentation_match = match(r'(?P<indentation>\s*)(?P<remaining_line>.*)$', current_line);
+ current_indentation = current_indentation_match.group('indentation')
+ remaining_line = current_indentation_match.group('remaining_line')
+
+ # As we're going up the lines, the first real statement to encounter
+ # has to be an exit statement (return, break, continue or goto) -
+ # otherwise, this check doesn't apply.
+ if not encountered_exit_statement:
+ # We only want to find exit statements if they are on exactly
+ # the same level of indentation as expected from the code inside
+ # the block. If the indentation doesn't strictly match then we
+ # might have a nested if or something, which must be ignored.
+ if current_indentation != inner_indentation:
+ break
+ if match(r'(return(\W+.*)|(break|continue)\s*;|goto\s*\w+;)$', remaining_line):
+ encountered_exit_statement = True
+ continue
+ break
+
+ # When code execution reaches this point, we've found an exit statement
+ # as last statement of the previous block. Now we only need to make
+ # sure that the block belongs to an "if", then we can throw an error.
+
+ # Skip lines with opening braces on the original indentation level,
+ # similar to the closing braces check above. ("if (condition)\n{")
+ if current_line == else_indentation + '{':
+ continue
+
+ # Skip everything that's further indented than our "else" or "else if".
+ if current_indentation.startswith(else_indentation) and current_indentation != else_indentation:
+ continue
+
+ # So we've got a line with same (or less) indentation. Is it an "if"?
+ # If yes: throw an error. If no: don't throw an error.
+ # Whatever the outcome, this is the end of our loop.
+ if match(r'if\s*\(', remaining_line):
+ if else_match.start('else') != -1:
+ error(line_number + line_offset, 'readability/control_flow', 4,
+ 'An else statement can be removed when the prior "if" '
+ 'concludes with a return, break, continue or goto statement.')
+ else:
+ error(line_number + line_offset, 'readability/control_flow', 4,
+ 'An else if statement should be written as an if statement '
+ 'when the prior "if" concludes with a return, break, '
+ 'continue or goto statement.')
+ break
+
+
+def replaceable_check(operator, macro, line):
+ """Determine whether a basic CHECK can be replaced with a more specific one.
+
+ For example suggest using CHECK_EQ instead of CHECK(a == b) and
+ similarly for CHECK_GE, CHECK_GT, CHECK_LE, CHECK_LT, CHECK_NE.
+
+ Args:
+ operator: The C++ operator used in the CHECK.
+ macro: The CHECK or EXPECT macro being called.
+ line: The current source line.
+
+ Returns:
+ True if the CHECK can be replaced with a more specific one.
+ """
+
+ # This matches decimal and hex integers, strings, and chars (in that order).
+ match_constant = r'([-+]?(\d+|0[xX][0-9a-fA-F]+)[lLuU]{0,3}|".*"|\'.*\')'
+
+ # Expression to match two sides of the operator with something that
+ # looks like a literal, since CHECK(x == iterator) won't compile.
+ # This means we can't catch all the cases where a more specific
+ # CHECK is possible, but it's less annoying than dealing with
+ # extraneous warnings.
+ match_this = (r'\s*' + macro + r'\((\s*' +
+ match_constant + r'\s*' + operator + r'[^<>].*|'
+ r'.*[^<>]' + operator + r'\s*' + match_constant +
+ r'\s*\))')
+
+ # Don't complain about CHECK(x == NULL) or similar because
+ # CHECK_EQ(x, NULL) won't compile (requires a cast).
+ # Also, don't complain about more complex boolean expressions
+ # involving && or || such as CHECK(a == b || c == d).
+ return match(match_this, line) and not search(r'NULL|&&|\|\|', line)
+
+
+def check_check(clean_lines, line_number, error):
+ """Checks the use of CHECK and EXPECT macros.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ error: The function to call with any errors found.
+ """
+
+ # Decide the set of replacement macros that should be suggested
+ raw_lines = clean_lines.raw_lines
+ current_macro = ''
+ for macro in _CHECK_MACROS:
+ if raw_lines[line_number].find(macro) >= 0:
+ current_macro = macro
+ break
+ if not current_macro:
+ # Don't waste time here if line doesn't contain 'CHECK' or 'EXPECT'
+ return
+
+ line = clean_lines.elided[line_number] # get rid of comments and strings
+
+ # Encourage replacing plain CHECKs with CHECK_EQ/CHECK_NE/etc.
+ for operator in ['==', '!=', '>=', '>', '<=', '<']:
+ if replaceable_check(operator, current_macro, line):
+ error(line_number, 'readability/check', 2,
+ 'Consider using %s instead of %s(a %s b)' % (
+ _CHECK_REPLACEMENT[current_macro][operator],
+ current_macro, operator))
+ break
+
+
+def check_for_comparisons_to_zero(clean_lines, line_number, error):
+ # Get the line without comments and strings.
+ line = clean_lines.elided[line_number]
+
+ # Include NULL here so that users don't have to convert NULL to 0 first and then get this error.
+ if search(r'[=!]=\s*(NULL|0|true|false)\W', line) or search(r'\W(NULL|0|true|false)\s*[=!]=', line):
+ error(line_number, 'readability/comparison_to_zero', 5,
+ 'Tests for true/false, null/non-null, and zero/non-zero should all be done without equality comparisons.')
+
+
+def check_for_null(clean_lines, line_number, file_state, error):
+ # This check doesn't apply to C or Objective-C implementation files.
+ if file_state.is_c_or_objective_c():
+ return
+
+ line = clean_lines.elided[line_number]
+
+ # Don't warn about NULL usage in g_*(). See Bug 32858 and 39372.
+ if search(r'\bg(_[a-z]+)+\b', line):
+ return
+
+ # Don't warn about NULL usage in gst_*_many(). See Bug 39740
+ if search(r'\bgst_\w+_many\b', line):
+ return
+
+ # Don't warn about NULL usage in g_str{join,concat}(). See Bug 34834
+ if search(r'\bg_str(join|concat)\b', line):
+ return
+
+ # Don't warn about NULL usage in gdk_pixbuf_save_to_*{join,concat}(). See Bug 43090.
+ if search(r'\bgdk_pixbuf_save_to\w+\b', line):
+ return
+
+ if search(r'\bNULL\b', line):
+ error(line_number, 'readability/null', 5, 'Use 0 instead of NULL.')
+ return
+
+ line = clean_lines.raw_lines[line_number]
+ # See if NULL occurs in any comments in the line. If the search for NULL using the raw line
+ # matches, then do the check with strings collapsed to avoid giving errors for
+ # NULLs occurring in strings.
+ if search(r'\bNULL\b', line) and search(r'\bNULL\b', CleansedLines.collapse_strings(line)):
+ error(line_number, 'readability/null', 4, 'Use 0 instead of NULL.')
+
+def get_line_width(line):
+ """Determines the width of the line in column positions.
+
+ Args:
+ line: A string, which may be a Unicode string.
+
+ Returns:
+ The width of the line in column positions, accounting for Unicode
+ combining characters and wide characters.
+ """
+ if isinstance(line, unicode):
+ width = 0
+ for c in unicodedata.normalize('NFC', line):
+ if unicodedata.east_asian_width(c) in ('W', 'F'):
+ width += 2
+ elif not unicodedata.combining(c):
+ width += 1
+ return width
+ return len(line)
+
+
+def check_style(clean_lines, line_number, file_extension, class_state, file_state, error):
+ """Checks rules from the 'C++ style rules' section of cppguide.html.
+
+ Most of these rules are hard to test (naming, comment style), but we
+ do what we can. In particular we check for 4-space indents, line lengths,
+ tab usage, spaces inside code, etc.
+
+ Args:
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ file_extension: The extension (without the dot) of the filename.
+ class_state: A _ClassState instance which maintains information about
+ the current stack of nested class declarations being parsed.
+ file_state: A _FileState instance which maintains information about
+ the state of things in the file.
+ error: The function to call with any errors found.
+ """
+
+ raw_lines = clean_lines.raw_lines
+ line = raw_lines[line_number]
+
+ if line.find('\t') != -1:
+ error(line_number, 'whitespace/tab', 1,
+ 'Tab found; better to use spaces')
+
+ # One or three blank spaces at the beginning of the line is weird; it's
+ # hard to reconcile that with 4-space indents.
+ # NOTE: here are the conditions rob pike used for his tests. Mine aren't
+ # as sophisticated, but it may be worth becoming so: RLENGTH==initial_spaces
+ # if(RLENGTH > 20) complain = 0;
+ # if(match($0, " +(error|private|public|protected):")) complain = 0;
+ # if(match(prev, "&& *$")) complain = 0;
+ # if(match(prev, "\\|\\| *$")) complain = 0;
+ # if(match(prev, "[\",=><] *$")) complain = 0;
+ # if(match($0, " <<")) complain = 0;
+ # if(match(prev, " +for \\(")) complain = 0;
+ # if(prevodd && match(prevprev, " +for \\(")) complain = 0;
+ initial_spaces = 0
+ cleansed_line = clean_lines.elided[line_number]
+ while initial_spaces < len(line) and line[initial_spaces] == ' ':
+ initial_spaces += 1
+ if line and line[-1].isspace():
+ error(line_number, 'whitespace/end_of_line', 4,
+ 'Line ends in whitespace. Consider deleting these extra spaces.')
+ # There are certain situations we allow one space, notably for labels
+ elif ((initial_spaces >= 1 and initial_spaces <= 3)
+ and not match(r'\s*\w+\s*:\s*$', cleansed_line)):
+ error(line_number, 'whitespace/indent', 3,
+ 'Weird number of spaces at line-start. '
+ 'Are you using a 4-space indent?')
+ # Labels should always be indented at least one space.
+ elif not initial_spaces and line[:2] != '//':
+ label_match = match(r'(?P<label>[^:]+):\s*$', line)
+
+ if label_match:
+ label = label_match.group('label')
+ # Only throw errors for stuff that is definitely not a goto label,
+ # because goto labels can in fact occur at the start of the line.
+ if label in ['public', 'private', 'protected'] or label.find(' ') != -1:
+ error(line_number, 'whitespace/labels', 4,
+ 'Labels should always be indented at least one space. '
+ 'If this is a member-initializer list in a constructor, '
+ 'the colon should be on the line after the definition header.')
+
+ if (cleansed_line.count(';') > 1
+ # for loops are allowed two ;'s (and may run over two lines).
+ and cleansed_line.find('for') == -1
+ and (get_previous_non_blank_line(clean_lines, line_number)[0].find('for') == -1
+ or get_previous_non_blank_line(clean_lines, line_number)[0].find(';') != -1)
+ # It's ok to have many commands in a switch case that fits in 1 line
+ and not ((cleansed_line.find('case ') != -1
+ or cleansed_line.find('default:') != -1)
+ and cleansed_line.find('break;') != -1)
+ # Also it's ok to have many commands in trivial single-line accessors in class definitions.
+ and not (match(r'.*\(.*\).*{.*.}', line)
+ and class_state.classinfo_stack
+ and line.count('{') == line.count('}'))
+ and not cleansed_line.startswith('#define ')):
+ error(line_number, 'whitespace/newline', 4,
+ 'More than one command on the same line')
+
+ if cleansed_line.strip().endswith('||') or cleansed_line.strip().endswith('&&'):
+ error(line_number, 'whitespace/operators', 4,
+ 'Boolean expressions that span multiple lines should have their '
+ 'operators on the left side of the line instead of the right side.')
+
+ # Some more style checks
+ check_namespace_indentation(clean_lines, line_number, file_extension, file_state, error)
+ check_using_std(clean_lines, line_number, file_state, error)
+ check_max_min_macros(clean_lines, line_number, file_state, error)
+ check_switch_indentation(clean_lines, line_number, error)
+ check_braces(clean_lines, line_number, error)
+ check_exit_statement_simplifications(clean_lines, line_number, error)
+ check_spacing(file_extension, clean_lines, line_number, error)
+ check_check(clean_lines, line_number, error)
+ check_for_comparisons_to_zero(clean_lines, line_number, error)
+ check_for_null(clean_lines, line_number, file_state, error)
+
+
+_RE_PATTERN_INCLUDE_NEW_STYLE = re.compile(r'#include +"[^/]+\.h"')
+_RE_PATTERN_INCLUDE = re.compile(r'^\s*#\s*include\s*([<"])([^>"]*)[>"].*$')
+# Matches the first component of a filename delimited by -s and _s. That is:
+# _RE_FIRST_COMPONENT.match('foo').group(0) == 'foo'
+# _RE_FIRST_COMPONENT.match('foo.cpp').group(0) == 'foo'
+# _RE_FIRST_COMPONENT.match('foo-bar_baz.cpp').group(0) == 'foo'
+# _RE_FIRST_COMPONENT.match('foo_bar-baz.cpp').group(0) == 'foo'
+_RE_FIRST_COMPONENT = re.compile(r'^[^-_.]+')
+
+
+def _drop_common_suffixes(filename):
+ """Drops common suffixes like _test.cpp or -inl.h from filename.
+
+ For example:
+ >>> _drop_common_suffixes('foo/foo-inl.h')
+ 'foo/foo'
+ >>> _drop_common_suffixes('foo/bar/foo.cpp')
+ 'foo/bar/foo'
+ >>> _drop_common_suffixes('foo/foo_internal.h')
+ 'foo/foo'
+ >>> _drop_common_suffixes('foo/foo_unusualinternal.h')
+ 'foo/foo_unusualinternal'
+
+ Args:
+ filename: The input filename.
+
+ Returns:
+ The filename with the common suffix removed.
+ """
+ for suffix in ('test.cpp', 'regtest.cpp', 'unittest.cpp',
+ 'inl.h', 'impl.h', 'internal.h'):
+ if (filename.endswith(suffix) and len(filename) > len(suffix)
+ and filename[-len(suffix) - 1] in ('-', '_')):
+ return filename[:-len(suffix) - 1]
+ return os.path.splitext(filename)[0]
+
+
+def _classify_include(filename, include, is_system, include_state):
+ """Figures out what kind of header 'include' is.
+
+ Args:
+ filename: The current file cpp_style is running over.
+ include: The path to a #included file.
+ is_system: True if the #include used <> rather than "".
+ include_state: An _IncludeState instance in which the headers are inserted.
+
+ Returns:
+ One of the _XXX_HEADER constants.
+
+ For example:
+ >>> _classify_include('foo.cpp', 'config.h', False)
+ _CONFIG_HEADER
+ >>> _classify_include('foo.cpp', 'foo.h', False)
+ _PRIMARY_HEADER
+ >>> _classify_include('foo.cpp', 'bar.h', False)
+ _OTHER_HEADER
+ """
+
+ # If it is a system header we know it is classified as _OTHER_HEADER.
+ if is_system:
+ return _OTHER_HEADER
+
+ # If the include is named config.h then this is WebCore/config.h.
+ if include == "config.h":
+ return _CONFIG_HEADER
+
+ # There cannot be primary includes in header files themselves. Only an
+ # include exactly matches the header filename will be is flagged as
+ # primary, so that it triggers the "don't include yourself" check.
+ if filename.endswith('.h') and filename != include:
+ return _OTHER_HEADER;
+
+ # Qt's moc files do not follow the naming and ordering rules, so they should be skipped
+ if include.startswith('moc_') and include.endswith('.cpp'):
+ return _MOC_HEADER
+
+ if include.endswith('.moc'):
+ return _MOC_HEADER
+
+ # If the target file basename starts with the include we're checking
+ # then we consider it the primary header.
+ target_base = FileInfo(filename).base_name()
+ include_base = FileInfo(include).base_name()
+
+ # If we haven't encountered a primary header, then be lenient in checking.
+ if not include_state.visited_primary_section() and target_base.find(include_base) != -1:
+ return _PRIMARY_HEADER
+ # If we already encountered a primary header, perform a strict comparison.
+ # In case the two filename bases are the same then the above lenient check
+ # probably was a false positive.
+ elif include_state.visited_primary_section() and target_base == include_base:
+ if include == "ResourceHandleWin.h":
+ # FIXME: Thus far, we've only seen one example of these, but if we
+ # start to see more, please consider generalizing this check
+ # somehow.
+ return _OTHER_HEADER
+ return _PRIMARY_HEADER
+
+ return _OTHER_HEADER
+
+
+def check_include_line(filename, file_extension, clean_lines, line_number, include_state, error):
+ """Check rules that are applicable to #include lines.
+
+ Strings on #include lines are NOT removed from elided line, to make
+ certain tasks easier. However, to prevent false positives, checks
+ applicable to #include lines in CheckLanguage must be put here.
+
+ Args:
+ filename: The name of the current file.
+ file_extension: The current file extension, without the leading dot.
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ include_state: An _IncludeState instance in which the headers are inserted.
+ error: The function to call with any errors found.
+ """
+ # FIXME: For readability or as a possible optimization, consider
+ # exiting early here by checking whether the "build/include"
+ # category should be checked for the given filename. This
+ # may involve having the error handler classes expose a
+ # should_check() method, in addition to the usual __call__
+ # method.
+ line = clean_lines.lines[line_number]
+
+ matched = _RE_PATTERN_INCLUDE.search(line)
+ if not matched:
+ return
+
+ include = matched.group(2)
+ is_system = (matched.group(1) == '<')
+
+ # Look for any of the stream classes that are part of standard C++.
+ if match(r'(f|ind|io|i|o|parse|pf|stdio|str|)?stream$', include):
+ error(line_number, 'readability/streams', 3,
+ 'Streams are highly discouraged.')
+
+ # Look for specific includes to fix.
+ if include.startswith('wtf/') and not is_system:
+ error(line_number, 'build/include', 4,
+ 'wtf includes should be <wtf/file.h> instead of "wtf/file.h".')
+
+ duplicate_header = include in include_state
+ if duplicate_header:
+ error(line_number, 'build/include', 4,
+ '"%s" already included at %s:%s' %
+ (include, filename, include_state[include]))
+ else:
+ include_state[include] = line_number
+
+ header_type = _classify_include(filename, include, is_system, include_state)
+ include_state.header_types[line_number] = header_type
+
+ # Only proceed if this isn't a duplicate header.
+ if duplicate_header:
+ return
+
+ # We want to ensure that headers appear in the right order:
+ # 1) for implementation files: config.h, primary header, blank line, alphabetically sorted
+ # 2) for header files: alphabetically sorted
+ # The include_state object keeps track of the last type seen
+ # and complains if the header types are out of order or missing.
+ error_message = include_state.check_next_include_order(header_type, file_extension == "h")
+
+ # Check to make sure we have a blank line after primary header.
+ if not error_message and header_type == _PRIMARY_HEADER:
+ next_line = clean_lines.raw_lines[line_number + 1]
+ if not is_blank_line(next_line):
+ error(line_number, 'build/include_order', 4,
+ 'You should add a blank line after implementation file\'s own header.')
+
+ # Check to make sure all headers besides config.h and the primary header are
+ # alphabetically sorted. Skip Qt's moc files.
+ if not error_message and header_type == _OTHER_HEADER:
+ previous_line_number = line_number - 1;
+ previous_line = clean_lines.lines[previous_line_number]
+ previous_match = _RE_PATTERN_INCLUDE.search(previous_line)
+ while (not previous_match and previous_line_number > 0
+ and not search(r'\A(#if|#ifdef|#ifndef|#else|#elif|#endif)', previous_line)):
+ previous_line_number -= 1;
+ previous_line = clean_lines.lines[previous_line_number]
+ previous_match = _RE_PATTERN_INCLUDE.search(previous_line)
+ if previous_match:
+ previous_header_type = include_state.header_types[previous_line_number]
+ if previous_header_type == _OTHER_HEADER and previous_line.strip() > line.strip():
+ error(line_number, 'build/include_order', 4,
+ 'Alphabetical sorting problem.')
+
+ if error_message:
+ if file_extension == 'h':
+ error(line_number, 'build/include_order', 4,
+ '%s Should be: alphabetically sorted.' %
+ error_message)
+ else:
+ error(line_number, 'build/include_order', 4,
+ '%s Should be: config.h, primary header, blank line, and then alphabetically sorted.' %
+ error_message)
+
+
+def check_language(filename, clean_lines, line_number, file_extension, include_state,
+ file_state, error):
+ """Checks rules from the 'C++ language rules' section of cppguide.html.
+
+ Some of these rules are hard to test (function overloading, using
+ uint32 inappropriately), but we do the best we can.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ line_number: The number of the line to check.
+ file_extension: The extension (without the dot) of the filename.
+ include_state: An _IncludeState instance in which the headers are inserted.
+ file_state: A _FileState instance which maintains information about
+ the state of things in the file.
+ error: The function to call with any errors found.
+ """
+ # If the line is empty or consists of entirely a comment, no need to
+ # check it.
+ line = clean_lines.elided[line_number]
+ if not line:
+ return
+
+ matched = _RE_PATTERN_INCLUDE.search(line)
+ if matched:
+ check_include_line(filename, file_extension, clean_lines, line_number, include_state, error)
+ return
+
+ # FIXME: figure out if they're using default arguments in fn proto.
+
+ # Check to see if they're using an conversion function cast.
+ # I just try to capture the most common basic types, though there are more.
+ # Parameterless conversion functions, such as bool(), are allowed as they are
+ # probably a member operator declaration or default constructor.
+ matched = search(
+ r'\b(int|float|double|bool|char|int32|uint32|int64|uint64)\([^)]', line)
+ if matched:
+ # gMock methods are defined using some variant of MOCK_METHODx(name, type)
+ # where type may be float(), int(string), etc. Without context they are
+ # virtually indistinguishable from int(x) casts.
+ if not match(r'^\s*MOCK_(CONST_)?METHOD\d+(_T)?\(', line):
+ error(line_number, 'readability/casting', 4,
+ 'Using deprecated casting style. '
+ 'Use static_cast<%s>(...) instead' %
+ matched.group(1))
+
+ check_c_style_cast(line_number, line, clean_lines.raw_lines[line_number],
+ 'static_cast',
+ r'\((int|float|double|bool|char|u?int(16|32|64))\)',
+ error)
+ # This doesn't catch all cases. Consider (const char * const)"hello".
+ check_c_style_cast(line_number, line, clean_lines.raw_lines[line_number],
+ 'reinterpret_cast', r'\((\w+\s?\*+\s?)\)', error)
+
+ # In addition, we look for people taking the address of a cast. This
+ # is dangerous -- casts can assign to temporaries, so the pointer doesn't
+ # point where you think.
+ if search(
+ r'(&\([^)]+\)[\w(])|(&(static|dynamic|reinterpret)_cast\b)', line):
+ error(line_number, 'runtime/casting', 4,
+ ('Are you taking an address of a cast? '
+ 'This is dangerous: could be a temp var. '
+ 'Take the address before doing the cast, rather than after'))
+
+ # Check for people declaring static/global STL strings at the top level.
+ # This is dangerous because the C++ language does not guarantee that
+ # globals with constructors are initialized before the first access.
+ matched = match(
+ r'((?:|static +)(?:|const +))string +([a-zA-Z0-9_:]+)\b(.*)',
+ line)
+ # Make sure it's not a function.
+ # Function template specialization looks like: "string foo<Type>(...".
+ # Class template definitions look like: "string Foo<Type>::Method(...".
+ if matched and not match(r'\s*(<.*>)?(::[a-zA-Z0-9_]+)?\s*\(([^"]|$)',
+ matched.group(3)):
+ error(line_number, 'runtime/string', 4,
+ 'For a static/global string constant, use a C style string instead: '
+ '"%schar %s[]".' %
+ (matched.group(1), matched.group(2)))
+
+ # Check that we're not using RTTI outside of testing code.
+ if search(r'\bdynamic_cast<', line):
+ error(line_number, 'runtime/rtti', 5,
+ 'Do not use dynamic_cast<>. If you need to cast within a class '
+ "hierarchy, use static_cast<> to upcast. Google doesn't support "
+ 'RTTI.')
+
+ if search(r'\b([A-Za-z0-9_]*_)\(\1\)', line):
+ error(line_number, 'runtime/init', 4,
+ 'You seem to be initializing a member variable with itself.')
+
+ if file_extension == 'h':
+ # FIXME: check that 1-arg constructors are explicit.
+ # How to tell it's a constructor?
+ # (handled in check_for_non_standard_constructs for now)
+ pass
+
+ # Check if people are using the verboten C basic types. The only exception
+ # we regularly allow is "unsigned short port" for port.
+ if search(r'\bshort port\b', line):
+ if not search(r'\bunsigned short port\b', line):
+ error(line_number, 'runtime/int', 4,
+ 'Use "unsigned short" for ports, not "short"')
+
+ # When snprintf is used, the second argument shouldn't be a literal.
+ matched = search(r'snprintf\s*\(([^,]*),\s*([0-9]*)\s*,', line)
+ if matched:
+ error(line_number, 'runtime/printf', 3,
+ 'If you can, use sizeof(%s) instead of %s as the 2nd arg '
+ 'to snprintf.' % (matched.group(1), matched.group(2)))
+
+ # Check if some verboten C functions are being used.
+ if search(r'\bsprintf\b', line):
+ error(line_number, 'runtime/printf', 5,
+ 'Never use sprintf. Use snprintf instead.')
+ matched = search(r'\b(strcpy|strcat)\b', line)
+ if matched:
+ error(line_number, 'runtime/printf', 4,
+ 'Almost always, snprintf is better than %s' % matched.group(1))
+
+ if search(r'\bsscanf\b', line):
+ error(line_number, 'runtime/printf', 1,
+ 'sscanf can be ok, but is slow and can overflow buffers.')
+
+ # Check for suspicious usage of "if" like
+ # } if (a == b) {
+ if search(r'\}\s*if\s*\(', line):
+ error(line_number, 'readability/braces', 4,
+ 'Did you mean "else if"? If not, start a new line for "if".')
+
+ # Check for potential format string bugs like printf(foo).
+ # We constrain the pattern not to pick things like DocidForPrintf(foo).
+ # Not perfect but it can catch printf(foo.c_str()) and printf(foo->c_str())
+ matched = re.search(r'\b((?:string)?printf)\s*\(([\w.\->()]+)\)', line, re.I)
+ if matched:
+ error(line_number, 'runtime/printf', 4,
+ 'Potential format string bug. Do %s("%%s", %s) instead.'
+ % (matched.group(1), matched.group(2)))
+
+ # Check for potential memset bugs like memset(buf, sizeof(buf), 0).
+ matched = search(r'memset\s*\(([^,]*),\s*([^,]*),\s*0\s*\)', line)
+ if matched and not match(r"^''|-?[0-9]+|0x[0-9A-Fa-f]$", matched.group(2)):
+ error(line_number, 'runtime/memset', 4,
+ 'Did you mean "memset(%s, 0, %s)"?'
+ % (matched.group(1), matched.group(2)))
+
+ # Detect variable-length arrays.
+ matched = match(r'\s*(.+::)?(\w+) [a-z]\w*\[(.+)];', line)
+ if (matched and matched.group(2) != 'return' and matched.group(2) != 'delete' and
+ matched.group(3).find(']') == -1):
+ # Split the size using space and arithmetic operators as delimiters.
+ # If any of the resulting tokens are not compile time constants then
+ # report the error.
+ tokens = re.split(r'\s|\+|\-|\*|\/|<<|>>]', matched.group(3))
+ is_const = True
+ skip_next = False
+ for tok in tokens:
+ if skip_next:
+ skip_next = False
+ continue
+
+ if search(r'sizeof\(.+\)', tok):
+ continue
+ if search(r'arraysize\(\w+\)', tok):
+ continue
+
+ tok = tok.lstrip('(')
+ tok = tok.rstrip(')')
+ if not tok:
+ continue
+ if match(r'\d+', tok):
+ continue
+ if match(r'0[xX][0-9a-fA-F]+', tok):
+ continue
+ if match(r'k[A-Z0-9]\w*', tok):
+ continue
+ if match(r'(.+::)?k[A-Z0-9]\w*', tok):
+ continue
+ if match(r'(.+::)?[A-Z][A-Z0-9_]*', tok):
+ continue
+ # A catch all for tricky sizeof cases, including 'sizeof expression',
+ # 'sizeof(*type)', 'sizeof(const type)', 'sizeof(struct StructName)'
+ # requires skipping the next token becasue we split on ' ' and '*'.
+ if tok.startswith('sizeof'):
+ skip_next = True
+ continue
+ is_const = False
+ break
+ if not is_const:
+ error(line_number, 'runtime/arrays', 1,
+ 'Do not use variable-length arrays. Use an appropriately named '
+ "('k' followed by CamelCase) compile-time constant for the size.")
+
+ # Check for use of unnamed namespaces in header files. Registration
+ # macros are typically OK, so we allow use of "namespace {" on lines
+ # that end with backslashes.
+ if (file_extension == 'h'
+ and search(r'\bnamespace\s*{', line)
+ and line[-1] != '\\'):
+ error(line_number, 'build/namespaces', 4,
+ 'Do not use unnamed namespaces in header files. See '
+ 'http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
+ ' for more information.')
+
+ check_identifier_name_in_declaration(filename, line_number, line, file_state, error)
+
+
+def check_identifier_name_in_declaration(filename, line_number, line, file_state, error):
+ """Checks if identifier names contain any underscores.
+
+ As identifiers in libraries we are using have a bunch of
+ underscores, we only warn about the declarations of identifiers
+ and don't check use of identifiers.
+
+ Args:
+ filename: The name of the current file.
+ line_number: The number of the line to check.
+ line: The line of code to check.
+ file_state: A _FileState instance which maintains information about
+ the state of things in the file.
+ error: The function to call with any errors found.
+ """
+ # We don't check a return statement.
+ if match(r'\s*(return|delete)\b', line):
+ return
+
+ # Basically, a declaration is a type name followed by whitespaces
+ # followed by an identifier. The type name can be complicated
+ # due to type adjectives and templates. We remove them first to
+ # simplify the process to find declarations of identifiers.
+
+ # Convert "long long", "long double", and "long long int" to
+ # simple types, but don't remove simple "long".
+ line = sub(r'long (long )?(?=long|double|int)', '', line)
+ # Convert unsigned/signed types to simple types, too.
+ line = sub(r'(unsigned|signed) (?=char|short|int|long)', '', line)
+ line = sub(r'\b(inline|using|static|const|volatile|auto|register|extern|typedef|restrict|struct|class|virtual)(?=\W)', '', line)
+
+ # Remove "new" and "new (expr)" to simplify, too.
+ line = sub(r'new\s*(\([^)]*\))?', '', line)
+
+ # Remove all template parameters by removing matching < and >.
+ # Loop until no templates are removed to remove nested templates.
+ while True:
+ line, number_of_replacements = subn(r'<([\w\s:]|::)+\s*[*&]*\s*>', '', line)
+ if not number_of_replacements:
+ break
+
+ # Declarations of local variables can be in condition expressions
+ # of control flow statements (e.g., "if (RenderObject* p = o->parent())").
+ # We remove the keywords and the first parenthesis.
+ #
+ # Declarations in "while", "if", and "switch" are different from
+ # other declarations in two aspects:
+ #
+ # - There can be only one declaration between the parentheses.
+ # (i.e., you cannot write "if (int i = 0, j = 1) {}")
+ # - The variable must be initialized.
+ # (i.e., you cannot write "if (int i) {}")
+ #
+ # and we will need different treatments for them.
+ line = sub(r'^\s*for\s*\(', '', line)
+ line, control_statement = subn(r'^\s*(while|else if|if|switch)\s*\(', '', line)
+
+ # Detect variable and functions.
+ type_regexp = r'\w([\w]|\s*[*&]\s*|::)+'
+ identifier_regexp = r'(?P<identifier>[\w:]+)'
+ maybe_bitfield_regexp = r'(:\s*\d+\s*)?'
+ character_after_identifier_regexp = r'(?P<character_after_identifier>[[;()=,])(?!=)'
+ declaration_without_type_regexp = r'\s*' + identifier_regexp + r'\s*' + maybe_bitfield_regexp + character_after_identifier_regexp
+ declaration_with_type_regexp = r'\s*' + type_regexp + r'\s' + declaration_without_type_regexp
+ is_function_arguments = False
+ number_of_identifiers = 0
+ while True:
+ # If we are seeing the first identifier or arguments of a
+ # function, there should be a type name before an identifier.
+ if not number_of_identifiers or is_function_arguments:
+ declaration_regexp = declaration_with_type_regexp
+ else:
+ declaration_regexp = declaration_without_type_regexp
+
+ matched = match(declaration_regexp, line)
+ if not matched:
+ return
+ identifier = matched.group('identifier')
+ character_after_identifier = matched.group('character_after_identifier')
+
+ # If we removed a non-for-control statement, the character after
+ # the identifier should be '='. With this rule, we can avoid
+ # warning for cases like "if (val & INT_MAX) {".
+ if control_statement and character_after_identifier != '=':
+ return
+
+ is_function_arguments = is_function_arguments or character_after_identifier == '('
+
+ # Remove "m_" and "s_" to allow them.
+ modified_identifier = sub(r'(^|(?<=::))[ms]_', '', identifier)
+ if not file_state.is_objective_c() and modified_identifier.find('_') >= 0:
+ # Various exceptions to the rule: JavaScript op codes functions, const_iterator.
+ if (not (filename.find('JavaScriptCore') >= 0 and modified_identifier.find('op_') >= 0)
+ and not modified_identifier.startswith('tst_')
+ and not modified_identifier.startswith('webkit_dom_object_')
+ and not modified_identifier.startswith('NPN_')
+ and not modified_identifier.startswith('NPP_')
+ and not modified_identifier.startswith('NP_')
+ and not modified_identifier.startswith('qt_')
+ and not modified_identifier.startswith('cairo_')
+ and not modified_identifier.find('::qt_') >= 0
+ and not modified_identifier == "const_iterator"
+ and not modified_identifier == "vm_throw"):
+ error(line_number, 'readability/naming', 4, identifier + " is incorrectly named. Don't use underscores in your identifier names.")
+
+ # Check for variables named 'l', these are too easy to confuse with '1' in some fonts
+ if modified_identifier == 'l':
+ error(line_number, 'readability/naming', 4, identifier + " is incorrectly named. Don't use the single letter 'l' as an identifier name.")
+
+ # There can be only one declaration in non-for-control statements.
+ if control_statement:
+ return
+ # We should continue checking if this is a function
+ # declaration because we need to check its arguments.
+ # Also, we need to check multiple declarations.
+ if character_after_identifier != '(' and character_after_identifier != ',':
+ return
+
+ number_of_identifiers += 1
+ line = line[matched.end():]
+
+def check_c_style_cast(line_number, line, raw_line, cast_type, pattern,
+ error):
+ """Checks for a C-style cast by looking for the pattern.
+
+ This also handles sizeof(type) warnings, due to similarity of content.
+
+ Args:
+ line_number: The number of the line to check.
+ line: The line of code to check.
+ raw_line: The raw line of code to check, with comments.
+ cast_type: The string for the C++ cast to recommend. This is either
+ reinterpret_cast or static_cast, depending.
+ pattern: The regular expression used to find C-style casts.
+ error: The function to call with any errors found.
+ """
+ matched = search(pattern, line)
+ if not matched:
+ return
+
+ # e.g., sizeof(int)
+ sizeof_match = match(r'.*sizeof\s*$', line[0:matched.start(1) - 1])
+ if sizeof_match:
+ error(line_number, 'runtime/sizeof', 1,
+ 'Using sizeof(type). Use sizeof(varname) instead if possible')
+ return
+
+ remainder = line[matched.end(0):]
+
+ # The close paren is for function pointers as arguments to a function.
+ # eg, void foo(void (*bar)(int));
+ # The semicolon check is a more basic function check; also possibly a
+ # function pointer typedef.
+ # eg, void foo(int); or void foo(int) const;
+ # The equals check is for function pointer assignment.
+ # eg, void *(*foo)(int) = ...
+ #
+ # Right now, this will only catch cases where there's a single argument, and
+ # it's unnamed. It should probably be expanded to check for multiple
+ # arguments with some unnamed.
+ function_match = match(r'\s*(\)|=|(const)?\s*(;|\{|throw\(\)))', remainder)
+ if function_match:
+ if (not function_match.group(3)
+ or function_match.group(3) == ';'
+ or raw_line.find('/*') < 0):
+ error(line_number, 'readability/function', 3,
+ 'All parameters should be named in a function')
+ return
+
+ # At this point, all that should be left is actual casts.
+ error(line_number, 'readability/casting', 4,
+ 'Using C-style cast. Use %s<%s>(...) instead' %
+ (cast_type, matched.group(1)))
+
+
+_HEADERS_CONTAINING_TEMPLATES = (
+ ('<deque>', ('deque',)),
+ ('<functional>', ('unary_function', 'binary_function',
+ 'plus', 'minus', 'multiplies', 'divides', 'modulus',
+ 'negate',
+ 'equal_to', 'not_equal_to', 'greater', 'less',
+ 'greater_equal', 'less_equal',
+ 'logical_and', 'logical_or', 'logical_not',
+ 'unary_negate', 'not1', 'binary_negate', 'not2',
+ 'bind1st', 'bind2nd',
+ 'pointer_to_unary_function',
+ 'pointer_to_binary_function',
+ 'ptr_fun',
+ 'mem_fun_t', 'mem_fun', 'mem_fun1_t', 'mem_fun1_ref_t',
+ 'mem_fun_ref_t',
+ 'const_mem_fun_t', 'const_mem_fun1_t',
+ 'const_mem_fun_ref_t', 'const_mem_fun1_ref_t',
+ 'mem_fun_ref',
+ )),
+ ('<limits>', ('numeric_limits',)),
+ ('<list>', ('list',)),
+ ('<map>', ('map', 'multimap',)),
+ ('<memory>', ('allocator',)),
+ ('<queue>', ('queue', 'priority_queue',)),
+ ('<set>', ('set', 'multiset',)),
+ ('<stack>', ('stack',)),
+ ('<string>', ('char_traits', 'basic_string',)),
+ ('<utility>', ('pair',)),
+ ('<vector>', ('vector',)),
+
+ # gcc extensions.
+ # Note: std::hash is their hash, ::hash is our hash
+ ('<hash_map>', ('hash_map', 'hash_multimap',)),
+ ('<hash_set>', ('hash_set', 'hash_multiset',)),
+ ('<slist>', ('slist',)),
+ )
+
+_HEADERS_ACCEPTED_BUT_NOT_PROMOTED = {
+ # We can trust with reasonable confidence that map gives us pair<>, too.
+ 'pair<>': ('map', 'multimap', 'hash_map', 'hash_multimap')
+}
+
+_RE_PATTERN_STRING = re.compile(r'\bstring\b')
+
+_re_pattern_algorithm_header = []
+for _template in ('copy', 'max', 'min', 'min_element', 'sort', 'swap',
+ 'transform'):
+ # Match max<type>(..., ...), max(..., ...), but not foo->max, foo.max or
+ # type::max().
+ _re_pattern_algorithm_header.append(
+ (re.compile(r'[^>.]\b' + _template + r'(<.*?>)?\([^\)]'),
+ _template,
+ '<algorithm>'))
+
+_re_pattern_templates = []
+for _header, _templates in _HEADERS_CONTAINING_TEMPLATES:
+ for _template in _templates:
+ _re_pattern_templates.append(
+ (re.compile(r'(\<|\b)' + _template + r'\s*\<'),
+ _template + '<>',
+ _header))
+
+
+def files_belong_to_same_module(filename_cpp, filename_h):
+ """Check if these two filenames belong to the same module.
+
+ The concept of a 'module' here is a as follows:
+ foo.h, foo-inl.h, foo.cpp, foo_test.cpp and foo_unittest.cpp belong to the
+ same 'module' if they are in the same directory.
+ some/path/public/xyzzy and some/path/internal/xyzzy are also considered
+ to belong to the same module here.
+
+ If the filename_cpp contains a longer path than the filename_h, for example,
+ '/absolute/path/to/base/sysinfo.cpp', and this file would include
+ 'base/sysinfo.h', this function also produces the prefix needed to open the
+ header. This is used by the caller of this function to more robustly open the
+ header file. We don't have access to the real include paths in this context,
+ so we need this guesswork here.
+
+ Known bugs: tools/base/bar.cpp and base/bar.h belong to the same module
+ according to this implementation. Because of this, this function gives
+ some false positives. This should be sufficiently rare in practice.
+
+ Args:
+ filename_cpp: is the path for the .cpp file
+ filename_h: is the path for the header path
+
+ Returns:
+ Tuple with a bool and a string:
+ bool: True if filename_cpp and filename_h belong to the same module.
+ string: the additional prefix needed to open the header file.
+ """
+
+ if not filename_cpp.endswith('.cpp'):
+ return (False, '')
+ filename_cpp = filename_cpp[:-len('.cpp')]
+ if filename_cpp.endswith('_unittest'):
+ filename_cpp = filename_cpp[:-len('_unittest')]
+ elif filename_cpp.endswith('_test'):
+ filename_cpp = filename_cpp[:-len('_test')]
+ filename_cpp = filename_cpp.replace('/public/', '/')
+ filename_cpp = filename_cpp.replace('/internal/', '/')
+
+ if not filename_h.endswith('.h'):
+ return (False, '')
+ filename_h = filename_h[:-len('.h')]
+ if filename_h.endswith('-inl'):
+ filename_h = filename_h[:-len('-inl')]
+ filename_h = filename_h.replace('/public/', '/')
+ filename_h = filename_h.replace('/internal/', '/')
+
+ files_belong_to_same_module = filename_cpp.endswith(filename_h)
+ common_path = ''
+ if files_belong_to_same_module:
+ common_path = filename_cpp[:-len(filename_h)]
+ return files_belong_to_same_module, common_path
+
+
+def update_include_state(filename, include_state, io=codecs):
+ """Fill up the include_state with new includes found from the file.
+
+ Args:
+ filename: the name of the header to read.
+ include_state: an _IncludeState instance in which the headers are inserted.
+ io: The io factory to use to read the file. Provided for testability.
+
+ Returns:
+ True if a header was succesfully added. False otherwise.
+ """
+ io = _unit_test_config.get(INCLUDE_IO_INJECTION_KEY, codecs)
+ header_file = None
+ try:
+ header_file = io.open(filename, 'r', 'utf8', 'replace')
+ except IOError:
+ return False
+ line_number = 0
+ for line in header_file:
+ line_number += 1
+ clean_line = cleanse_comments(line)
+ matched = _RE_PATTERN_INCLUDE.search(clean_line)
+ if matched:
+ include = matched.group(2)
+ # The value formatting is cute, but not really used right now.
+ # What matters here is that the key is in include_state.
+ include_state.setdefault(include, '%s:%d' % (filename, line_number))
+ return True
+
+
+def check_for_include_what_you_use(filename, clean_lines, include_state, error):
+ """Reports for missing stl includes.
+
+ This function will output warnings to make sure you are including the headers
+ necessary for the stl containers and functions that you use. We only give one
+ reason to include a header. For example, if you use both equal_to<> and
+ less<> in a .h file, only one (the latter in the file) of these will be
+ reported as a reason to include the <functional>.
+
+ Args:
+ filename: The name of the current file.
+ clean_lines: A CleansedLines instance containing the file.
+ include_state: An _IncludeState instance.
+ error: The function to call with any errors found.
+ """
+ required = {} # A map of header name to line_number and the template entity.
+ # Example of required: { '<functional>': (1219, 'less<>') }
+
+ for line_number in xrange(clean_lines.num_lines()):
+ line = clean_lines.elided[line_number]
+ if not line or line[0] == '#':
+ continue
+
+ # String is special -- it is a non-templatized type in STL.
+ if _RE_PATTERN_STRING.search(line):
+ required['<string>'] = (line_number, 'string')
+
+ for pattern, template, header in _re_pattern_algorithm_header:
+ if pattern.search(line):
+ required[header] = (line_number, template)
+
+ # The following function is just a speed up, no semantics are changed.
+ if not '<' in line: # Reduces the cpu time usage by skipping lines.
+ continue
+
+ for pattern, template, header in _re_pattern_templates:
+ if pattern.search(line):
+ required[header] = (line_number, template)
+
+ # The policy is that if you #include something in foo.h you don't need to
+ # include it again in foo.cpp. Here, we will look at possible includes.
+ # Let's copy the include_state so it is only messed up within this function.
+ include_state = include_state.copy()
+
+ # Did we find the header for this file (if any) and succesfully load it?
+ header_found = False
+
+ # Use the absolute path so that matching works properly.
+ abs_filename = os.path.abspath(filename)
+
+ # For Emacs's flymake.
+ # If cpp_style is invoked from Emacs's flymake, a temporary file is generated
+ # by flymake and that file name might end with '_flymake.cpp'. In that case,
+ # restore original file name here so that the corresponding header file can be
+ # found.
+ # e.g. If the file name is 'foo_flymake.cpp', we should search for 'foo.h'
+ # instead of 'foo_flymake.h'
+ abs_filename = re.sub(r'_flymake\.cpp$', '.cpp', abs_filename)
+
+ # include_state is modified during iteration, so we iterate over a copy of
+ # the keys.
+ for header in include_state.keys(): #NOLINT
+ (same_module, common_path) = files_belong_to_same_module(abs_filename, header)
+ fullpath = common_path + header
+ if same_module and update_include_state(fullpath, include_state):
+ header_found = True
+
+ # If we can't find the header file for a .cpp, assume it's because we don't
+ # know where to look. In that case we'll give up as we're not sure they
+ # didn't include it in the .h file.
+ # FIXME: Do a better job of finding .h files so we are confident that
+ # not having the .h file means there isn't one.
+ if filename.endswith('.cpp') and not header_found:
+ return
+
+ # All the lines have been processed, report the errors found.
+ for required_header_unstripped in required:
+ template = required[required_header_unstripped][1]
+ if template in _HEADERS_ACCEPTED_BUT_NOT_PROMOTED:
+ headers = _HEADERS_ACCEPTED_BUT_NOT_PROMOTED[template]
+ if [True for header in headers if header in include_state]:
+ continue
+ if required_header_unstripped.strip('<>"') not in include_state:
+ error(required[required_header_unstripped][0],
+ 'build/include_what_you_use', 4,
+ 'Add #include ' + required_header_unstripped + ' for ' + template)
+
+
+def process_line(filename, file_extension,
+ clean_lines, line, include_state, function_state,
+ class_state, file_state, error):
+ """Processes a single line in the file.
+
+ Args:
+ filename: Filename of the file that is being processed.
+ file_extension: The extension (dot not included) of the file.
+ clean_lines: An array of strings, each representing a line of the file,
+ with comments stripped.
+ line: Number of line being processed.
+ include_state: An _IncludeState instance in which the headers are inserted.
+ function_state: A _FunctionState instance which counts function lines, etc.
+ class_state: A _ClassState instance which maintains information about
+ the current stack of nested class declarations being parsed.
+ file_state: A _FileState instance which maintains information about
+ the state of things in the file.
+ error: A callable to which errors are reported, which takes arguments:
+ line number, error level, and message
+
+ """
+ raw_lines = clean_lines.raw_lines
+ detect_functions(clean_lines, line, function_state, error)
+ check_for_function_lengths(clean_lines, line, function_state, error)
+ if search(r'\bNOLINT\b', raw_lines[line]): # ignore nolint lines
+ return
+ check_pass_ptr_usage(clean_lines, line, function_state, error)
+ check_for_multiline_comments_and_strings(clean_lines, line, error)
+ check_style(clean_lines, line, file_extension, class_state, file_state, error)
+ check_language(filename, clean_lines, line, file_extension, include_state,
+ file_state, error)
+ check_for_non_standard_constructs(clean_lines, line, class_state, error)
+ check_posix_threading(clean_lines, line, error)
+ check_invalid_increment(clean_lines, line, error)
+
+
+def _process_lines(filename, file_extension, lines, error, min_confidence):
+ """Performs lint checks and reports any errors to the given error function.
+
+ Args:
+ filename: Filename of the file that is being processed.
+ file_extension: The extension (dot not included) of the file.
+ lines: An array of strings, each representing a line of the file, with the
+ last element being empty if the file is termined with a newline.
+ error: A callable to which errors are reported, which takes 4 arguments:
+ """
+ lines = (['// marker so line numbers and indices both start at 1'] + lines +
+ ['// marker so line numbers end in a known way'])
+
+ include_state = _IncludeState()
+ function_state = _FunctionState(min_confidence)
+ class_state = _ClassState()
+
+ check_for_copyright(lines, error)
+
+ if file_extension == 'h':
+ check_for_header_guard(filename, lines, error)
+
+ remove_multi_line_comments(lines, error)
+ clean_lines = CleansedLines(lines)
+ file_state = _FileState(clean_lines, file_extension)
+ for line in xrange(clean_lines.num_lines()):
+ process_line(filename, file_extension, clean_lines, line,
+ include_state, function_state, class_state, file_state, error)
+ class_state.check_finished(error)
+
+ check_for_include_what_you_use(filename, clean_lines, include_state, error)
+
+ # We check here rather than inside process_line so that we see raw
+ # lines rather than "cleaned" lines.
+ check_for_unicode_replacement_characters(lines, error)
+
+ check_for_new_line_at_eof(lines, error)
+
+
+class CppChecker(object):
+
+ """Processes C++ lines for checking style."""
+
+ # This list is used to--
+ #
+ # (1) generate an explicit list of all possible categories,
+ # (2) unit test that all checked categories have valid names, and
+ # (3) unit test that all categories are getting unit tested.
+ #
+ categories = set([
+ 'build/class',
+ 'build/deprecated',
+ 'build/endif_comment',
+ 'build/forward_decl',
+ 'build/header_guard',
+ 'build/include',
+ 'build/include_order',
+ 'build/include_what_you_use',
+ 'build/namespaces',
+ 'build/printf_format',
+ 'build/storage_class',
+ 'build/using_std',
+ 'legal/copyright',
+ 'readability/braces',
+ 'readability/casting',
+ 'readability/check',
+ 'readability/comparison_to_zero',
+ 'readability/constructors',
+ 'readability/control_flow',
+ 'readability/fn_size',
+ 'readability/function',
+ 'readability/multiline_comment',
+ 'readability/multiline_string',
+ 'readability/naming',
+ 'readability/null',
+ 'readability/pass_ptr',
+ 'readability/streams',
+ 'readability/todo',
+ 'readability/utf8',
+ 'runtime/arrays',
+ 'runtime/casting',
+ 'runtime/explicit',
+ 'runtime/init',
+ 'runtime/int',
+ 'runtime/invalid_increment',
+ 'runtime/max_min_macros',
+ 'runtime/memset',
+ 'runtime/printf',
+ 'runtime/printf_format',
+ 'runtime/references',
+ 'runtime/rtti',
+ 'runtime/sizeof',
+ 'runtime/string',
+ 'runtime/threadsafe_fn',
+ 'runtime/virtual',
+ 'whitespace/blank_line',
+ 'whitespace/braces',
+ 'whitespace/comma',
+ 'whitespace/comments',
+ 'whitespace/declaration',
+ 'whitespace/end_of_line',
+ 'whitespace/ending_newline',
+ 'whitespace/indent',
+ 'whitespace/labels',
+ 'whitespace/line_length',
+ 'whitespace/newline',
+ 'whitespace/operators',
+ 'whitespace/parens',
+ 'whitespace/semicolon',
+ 'whitespace/tab',
+ 'whitespace/todo',
+ ])
+
+ def __init__(self, file_path, file_extension, handle_style_error,
+ min_confidence):
+ """Create a CppChecker instance.
+
+ Args:
+ file_extension: A string that is the file extension, without
+ the leading dot.
+
+ """
+ self.file_extension = file_extension
+ self.file_path = file_path
+ self.handle_style_error = handle_style_error
+ self.min_confidence = min_confidence
+
+ # Useful for unit testing.
+ def __eq__(self, other):
+ """Return whether this CppChecker instance is equal to another."""
+ if self.file_extension != other.file_extension:
+ return False
+ if self.file_path != other.file_path:
+ return False
+ if self.handle_style_error != other.handle_style_error:
+ return False
+ if self.min_confidence != other.min_confidence:
+ return False
+
+ return True
+
+ # Useful for unit testing.
+ def __ne__(self, other):
+ # Python does not automatically deduce __ne__() from __eq__().
+ return not self.__eq__(other)
+
+ def check(self, lines):
+ _process_lines(self.file_path, self.file_extension, lines,
+ self.handle_style_error, self.min_confidence)
+
+
+# FIXME: Remove this function (requires refactoring unit tests).
+def process_file_data(filename, file_extension, lines, error, min_confidence, unit_test_config):
+ global _unit_test_config
+ _unit_test_config = unit_test_config
+ checker = CppChecker(filename, file_extension, error, min_confidence)
+ checker.check(lines)
+ _unit_test_config = {}
diff --git a/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py b/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
new file mode 100644
index 0000000..70df1ea
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/cpp_unittest.py
@@ -0,0 +1,3998 @@
+#!/usr/bin/python
+# -*- coding: utf-8; -*-
+#
+# Copyright (C) 2009 Google Inc. All rights reserved.
+# Copyright (C) 2009 Torch Mobile Inc.
+# Copyright (C) 2009 Apple Inc. All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.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.
+
+"""Unit test for cpp_style.py."""
+
+# FIXME: Add a good test that tests UpdateIncludeState.
+
+import codecs
+import os
+import random
+import re
+import unittest
+import cpp as cpp_style
+from cpp import CppChecker
+from ..filter import FilterConfiguration
+
+# This class works as an error collector and replaces cpp_style.Error
+# function for the unit tests. We also verify each category we see
+# is in STYLE_CATEGORIES, to help keep that list up to date.
+class ErrorCollector:
+ _all_style_categories = CppChecker.categories
+ # This is a list including all categories seen in any unit test.
+ _seen_style_categories = {}
+
+ def __init__(self, assert_fn, filter=None):
+ """assert_fn: a function to call when we notice a problem.
+ filter: filters the errors that we are concerned about."""
+ self._assert_fn = assert_fn
+ self._errors = []
+ if not filter:
+ filter = FilterConfiguration()
+ self._filter = filter
+
+ def __call__(self, unused_linenum, category, confidence, message):
+ self._assert_fn(category in self._all_style_categories,
+ 'Message "%s" has category "%s",'
+ ' which is not in STYLE_CATEGORIES' % (message, category))
+ if self._filter.should_check(category, ""):
+ self._seen_style_categories[category] = 1
+ self._errors.append('%s [%s] [%d]' % (message, category, confidence))
+
+ def results(self):
+ if len(self._errors) < 2:
+ return ''.join(self._errors) # Most tests expect to have a string.
+ else:
+ return self._errors # Let's give a list if there is more than one.
+
+ def result_list(self):
+ return self._errors
+
+ def verify_all_categories_are_seen(self):
+ """Fails if there's a category in _all_style_categories - _seen_style_categories.
+
+ This should only be called after all tests are run, so
+ _seen_style_categories has had a chance to fully populate. Since
+ this isn't called from within the normal unittest framework, we
+ can't use the normal unittest assert macros. Instead we just exit
+ when we see an error. Good thing this test is always run last!
+ """
+ for category in self._all_style_categories:
+ if category not in self._seen_style_categories:
+ import sys
+ sys.exit('FATAL ERROR: There are no tests for category "%s"' % category)
+
+
+# This class is a lame mock of codecs. We do not verify filename, mode, or
+# encoding, but for the current use case it is not needed.
+class MockIo:
+ def __init__(self, mock_file):
+ self.mock_file = mock_file
+
+ def open(self, unused_filename, unused_mode, unused_encoding, _): # NOLINT
+ # (lint doesn't like open as a method name)
+ return self.mock_file
+
+
+class CppFunctionsTest(unittest.TestCase):
+
+ """Supports testing functions that do not need CppStyleTestBase."""
+
+ def test_is_c_or_objective_c(self):
+ clean_lines = cpp_style.CleansedLines([''])
+ clean_objc_lines = cpp_style.CleansedLines(['#import "header.h"'])
+ self.assertTrue(cpp_style._FileState(clean_lines, 'c').is_c_or_objective_c())
+ self.assertTrue(cpp_style._FileState(clean_lines, 'm').is_c_or_objective_c())
+ self.assertFalse(cpp_style._FileState(clean_lines, 'cpp').is_c_or_objective_c())
+ self.assertFalse(cpp_style._FileState(clean_lines, 'cc').is_c_or_objective_c())
+ self.assertFalse(cpp_style._FileState(clean_lines, 'h').is_c_or_objective_c())
+ self.assertTrue(cpp_style._FileState(clean_objc_lines, 'h').is_c_or_objective_c())
+
+
+class CppStyleTestBase(unittest.TestCase):
+ """Provides some useful helper functions for cpp_style tests.
+
+ Attributes:
+ min_confidence: An integer that is the current minimum confidence
+ level for the tests.
+
+ """
+
+ # FIXME: Refactor the unit tests so the confidence level is passed
+ # explicitly, just like it is in the real code.
+ min_confidence = 1;
+
+ # Helper function to avoid needing to explicitly pass confidence
+ # in all the unit test calls to cpp_style.process_file_data().
+ def process_file_data(self, filename, file_extension, lines, error, unit_test_config={}):
+ """Call cpp_style.process_file_data() with the min_confidence."""
+ return cpp_style.process_file_data(filename, file_extension, lines,
+ error, self.min_confidence, unit_test_config)
+
+ def perform_lint(self, code, filename, basic_error_rules, unit_test_config={}):
+ error_collector = ErrorCollector(self.assert_, FilterConfiguration(basic_error_rules))
+ lines = code.split('\n')
+ extension = filename.split('.')[1]
+ self.process_file_data(filename, extension, lines, error_collector, unit_test_config)
+ return error_collector.results()
+
+ # Perform lint on single line of input and return the error message.
+ def perform_single_line_lint(self, code, filename):
+ basic_error_rules = ('-build/header_guard',
+ '-legal/copyright',
+ '-readability/fn_size',
+ '-whitespace/ending_newline')
+ return self.perform_lint(code, filename, basic_error_rules)
+
+ # Perform lint over multiple lines and return the error message.
+ def perform_multi_line_lint(self, code, file_extension):
+ basic_error_rules = ('-build/header_guard',
+ '-legal/copyright',
+ '-multi_line_filter',
+ '-whitespace/ending_newline')
+ return self.perform_lint(code, 'test.' + file_extension, basic_error_rules)
+
+ # Only keep some errors related to includes, namespaces and rtti.
+ def perform_language_rules_check(self, filename, code):
+ basic_error_rules = ('-',
+ '+build/include',
+ '+build/include_order',
+ '+build/namespaces',
+ '+runtime/rtti')
+ return self.perform_lint(code, filename, basic_error_rules)
+
+ # Only keep function length errors.
+ def perform_function_lengths_check(self, code):
+ basic_error_rules = ('-',
+ '+readability/fn_size')
+ return self.perform_lint(code, 'test.cpp', basic_error_rules)
+
+ # Only keep pass ptr errors.
+ def perform_pass_ptr_check(self, code):
+ basic_error_rules = ('-',
+ '+readability/pass_ptr')
+ return self.perform_lint(code, 'test.cpp', basic_error_rules)
+
+ # Only include what you use errors.
+ def perform_include_what_you_use(self, code, filename='foo.h', io=codecs):
+ basic_error_rules = ('-',
+ '+build/include_what_you_use')
+ unit_test_config = {cpp_style.INCLUDE_IO_INJECTION_KEY: io}
+ return self.perform_lint(code, filename, basic_error_rules, unit_test_config)
+
+ # Perform lint and compare the error message with "expected_message".
+ def assert_lint(self, code, expected_message, file_name='foo.cpp'):
+ self.assertEquals(expected_message, self.perform_single_line_lint(code, file_name))
+
+ def assert_lint_one_of_many_errors_re(self, code, expected_message_re, file_name='foo.cpp'):
+ messages = self.perform_single_line_lint(code, file_name)
+ for message in messages:
+ if re.search(expected_message_re, message):
+ return
+
+ self.assertEquals(expected_message_re, messages)
+
+ def assert_multi_line_lint(self, code, expected_message, file_name='foo.h'):
+ file_extension = file_name[file_name.rfind('.') + 1:]
+ self.assertEquals(expected_message, self.perform_multi_line_lint(code, file_extension))
+
+ def assert_multi_line_lint_re(self, code, expected_message_re, file_name='foo.h'):
+ file_extension = file_name[file_name.rfind('.') + 1:]
+ message = self.perform_multi_line_lint(code, file_extension)
+ if not re.search(expected_message_re, message):
+ self.fail('Message was:\n' + message + 'Expected match to "' + expected_message_re + '"')
+
+ def assert_language_rules_check(self, file_name, code, expected_message):
+ self.assertEquals(expected_message,
+ self.perform_language_rules_check(file_name, code))
+
+ def assert_include_what_you_use(self, code, expected_message):
+ self.assertEquals(expected_message,
+ self.perform_include_what_you_use(code))
+
+ def assert_blank_lines_check(self, lines, start_errors, end_errors):
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data('foo.cpp', 'cpp', lines, error_collector)
+ self.assertEquals(
+ start_errors,
+ error_collector.results().count(
+ 'Blank line at the start of a code block. Is this needed?'
+ ' [whitespace/blank_line] [2]'))
+ self.assertEquals(
+ end_errors,
+ error_collector.results().count(
+ 'Blank line at the end of a code block. Is this needed?'
+ ' [whitespace/blank_line] [3]'))
+
+
+class FunctionDetectionTest(CppStyleTestBase):
+ def perform_function_detection(self, lines, function_information):
+ clean_lines = cpp_style.CleansedLines(lines)
+ function_state = cpp_style._FunctionState(5)
+ error_collector = ErrorCollector(self.assert_)
+ cpp_style.detect_functions(clean_lines, 0, function_state, error_collector)
+ if not function_information:
+ self.assertEquals(function_state.in_a_function, False)
+ return
+ self.assertEquals(function_state.in_a_function, True)
+ self.assertEquals(function_state.current_function, function_information['name'] + '()')
+ self.assertEquals(function_state.body_start_line_number, function_information['body_start_line_number'])
+ self.assertEquals(function_state.ending_line_number, function_information['ending_line_number'])
+ self.assertEquals(function_state.is_declaration, function_information['is_declaration'])
+
+ def test_basic_function_detection(self):
+ self.perform_function_detection(
+ ['void theTestFunctionName(int) {',
+ '}'],
+ {'name': 'theTestFunctionName',
+ 'body_start_line_number': 0,
+ 'ending_line_number': 1,
+ 'is_declaration': False})
+
+ def test_function_declaration_detection(self):
+ self.perform_function_detection(
+ ['void aFunctionName(int);'],
+ {'name': 'aFunctionName',
+ 'body_start_line_number': 0,
+ 'ending_line_number': 0,
+ 'is_declaration': True})
+
+ def test_non_functions(self):
+ # This case exposed an error because the open brace was in quotes.
+ self.perform_function_detection(
+ ['asm(',
+ ' "stmdb sp!, {r1-r3}" "\n"',
+ ');'],
+ # This isn't a function but it looks like one to our simple
+ # algorithm and that is ok.
+ {'name': 'asm',
+ 'body_start_line_number': 2,
+ 'ending_line_number': 2,
+ 'is_declaration': True})
+
+ # Simple test case with something that is not a function.
+ self.perform_function_detection(['class Stuff;'], None)
+
+class CppStyleTest(CppStyleTestBase):
+
+ # Test get line width.
+ def test_get_line_width(self):
+ self.assertEquals(0, cpp_style.get_line_width(''))
+ self.assertEquals(10, cpp_style.get_line_width(u'x' * 10))
+ self.assertEquals(16, cpp_style.get_line_width(u'都|é“|府|県|支åº'))
+
+ def test_find_next_multi_line_comment_start(self):
+ self.assertEquals(1, cpp_style.find_next_multi_line_comment_start([''], 0))
+
+ lines = ['a', 'b', '/* c']
+ self.assertEquals(2, cpp_style.find_next_multi_line_comment_start(lines, 0))
+
+ lines = ['char a[] = "/*";'] # not recognized as comment.
+ self.assertEquals(1, cpp_style.find_next_multi_line_comment_start(lines, 0))
+
+ def test_find_next_multi_line_comment_end(self):
+ self.assertEquals(1, cpp_style.find_next_multi_line_comment_end([''], 0))
+ lines = ['a', 'b', ' c */']
+ self.assertEquals(2, cpp_style.find_next_multi_line_comment_end(lines, 0))
+
+ def test_remove_multi_line_comments_from_range(self):
+ lines = ['a', ' /* comment ', ' * still comment', ' comment */ ', 'b']
+ cpp_style.remove_multi_line_comments_from_range(lines, 1, 4)
+ self.assertEquals(['a', '// dummy', '// dummy', '// dummy', 'b'], lines)
+
+ def test_spaces_at_end_of_line(self):
+ self.assert_lint(
+ '// Hello there ',
+ 'Line ends in whitespace. Consider deleting these extra spaces.'
+ ' [whitespace/end_of_line] [4]')
+
+ # Test C-style cast cases.
+ def test_cstyle_cast(self):
+ self.assert_lint(
+ 'int a = (int)1.0;',
+ 'Using C-style cast. Use static_cast<int>(...) instead'
+ ' [readability/casting] [4]')
+ self.assert_lint(
+ 'int *a = (int *)DEFINED_VALUE;',
+ 'Using C-style cast. Use reinterpret_cast<int *>(...) instead'
+ ' [readability/casting] [4]', 'foo.c')
+ self.assert_lint(
+ 'uint16 a = (uint16)1.0;',
+ 'Using C-style cast. Use static_cast<uint16>(...) instead'
+ ' [readability/casting] [4]')
+ self.assert_lint(
+ 'int32 a = (int32)1.0;',
+ 'Using C-style cast. Use static_cast<int32>(...) instead'
+ ' [readability/casting] [4]')
+ self.assert_lint(
+ 'uint64 a = (uint64)1.0;',
+ 'Using C-style cast. Use static_cast<uint64>(...) instead'
+ ' [readability/casting] [4]')
+
+ # Test taking address of casts (runtime/casting)
+ def test_runtime_casting(self):
+ self.assert_lint(
+ 'int* x = &static_cast<int*>(foo);',
+ 'Are you taking an address of a cast? '
+ 'This is dangerous: could be a temp var. '
+ 'Take the address before doing the cast, rather than after'
+ ' [runtime/casting] [4]')
+
+ self.assert_lint(
+ 'int* x = &dynamic_cast<int *>(foo);',
+ ['Are you taking an address of a cast? '
+ 'This is dangerous: could be a temp var. '
+ 'Take the address before doing the cast, rather than after'
+ ' [runtime/casting] [4]',
+ 'Do not use dynamic_cast<>. If you need to cast within a class '
+ 'hierarchy, use static_cast<> to upcast. Google doesn\'t support '
+ 'RTTI. [runtime/rtti] [5]'])
+
+ self.assert_lint(
+ 'int* x = &reinterpret_cast<int *>(foo);',
+ 'Are you taking an address of a cast? '
+ 'This is dangerous: could be a temp var. '
+ 'Take the address before doing the cast, rather than after'
+ ' [runtime/casting] [4]')
+
+ # It's OK to cast an address.
+ self.assert_lint(
+ 'int* x = reinterpret_cast<int *>(&foo);',
+ '')
+
+ def test_runtime_selfinit(self):
+ self.assert_lint(
+ 'Foo::Foo(Bar r, Bel l) : r_(r_), l_(l_) { }',
+ 'You seem to be initializing a member variable with itself.'
+ ' [runtime/init] [4]')
+ self.assert_lint(
+ 'Foo::Foo(Bar r, Bel l) : r_(r), l_(l) { }',
+ '')
+ self.assert_lint(
+ 'Foo::Foo(Bar r) : r_(r), l_(r_), ll_(l_) { }',
+ '')
+
+ def test_runtime_rtti(self):
+ statement = 'int* x = dynamic_cast<int*>(&foo);'
+ error_message = (
+ 'Do not use dynamic_cast<>. If you need to cast within a class '
+ 'hierarchy, use static_cast<> to upcast. Google doesn\'t support '
+ 'RTTI. [runtime/rtti] [5]')
+ # dynamic_cast is disallowed in most files.
+ self.assert_language_rules_check('foo.cpp', statement, error_message)
+ self.assert_language_rules_check('foo.h', statement, error_message)
+
+ # We cannot test this functionality because of difference of
+ # function definitions. Anyway, we may never enable this.
+ #
+ # # Test for unnamed arguments in a method.
+ # def test_check_for_unnamed_params(self):
+ # message = ('All parameters should be named in a function'
+ # ' [readability/function] [3]')
+ # self.assert_lint('virtual void A(int*) const;', message)
+ # self.assert_lint('virtual void B(void (*fn)(int*));', message)
+ # self.assert_lint('virtual void C(int*);', message)
+ # self.assert_lint('void *(*f)(void *) = x;', message)
+ # self.assert_lint('void Method(char*) {', message)
+ # self.assert_lint('void Method(char*);', message)
+ # self.assert_lint('void Method(char* /*x*/);', message)
+ # self.assert_lint('typedef void (*Method)(int32);', message)
+ # self.assert_lint('static void operator delete[](void*) throw();', message)
+ #
+ # self.assert_lint('virtual void D(int* p);', '')
+ # self.assert_lint('void operator delete(void* x) throw();', '')
+ # self.assert_lint('void Method(char* x)\n{', '')
+ # self.assert_lint('void Method(char* /*x*/)\n{', '')
+ # self.assert_lint('void Method(char* x);', '')
+ # self.assert_lint('typedef void (*Method)(int32 x);', '')
+ # self.assert_lint('static void operator delete[](void* x) throw();', '')
+ # self.assert_lint('static void operator delete[](void* /*x*/) throw();', '')
+ #
+ # # This one should technically warn, but doesn't because the function
+ # # pointer is confusing.
+ # self.assert_lint('virtual void E(void (*fn)(int* p));', '')
+
+ # Test deprecated casts such as int(d)
+ def test_deprecated_cast(self):
+ self.assert_lint(
+ 'int a = int(2.2);',
+ 'Using deprecated casting style. '
+ 'Use static_cast<int>(...) instead'
+ ' [readability/casting] [4]')
+ # Checks for false positives...
+ self.assert_lint(
+ 'int a = int(); // Constructor, o.k.',
+ '')
+ self.assert_lint(
+ 'X::X() : a(int()) {} // default Constructor, o.k.',
+ '')
+ self.assert_lint(
+ 'operator bool(); // Conversion operator, o.k.',
+ '')
+
+ # The second parameter to a gMock method definition is a function signature
+ # that often looks like a bad cast but should not picked up by lint.
+ def test_mock_method(self):
+ self.assert_lint(
+ 'MOCK_METHOD0(method, int());',
+ '')
+ self.assert_lint(
+ 'MOCK_CONST_METHOD1(method, float(string));',
+ '')
+ self.assert_lint(
+ 'MOCK_CONST_METHOD2_T(method, double(float, float));',
+ '')
+
+ # Test sizeof(type) cases.
+ def test_sizeof_type(self):
+ self.assert_lint(
+ 'sizeof(int);',
+ 'Using sizeof(type). Use sizeof(varname) instead if possible'
+ ' [runtime/sizeof] [1]')
+ self.assert_lint(
+ 'sizeof(int *);',
+ 'Using sizeof(type). Use sizeof(varname) instead if possible'
+ ' [runtime/sizeof] [1]')
+
+ # Test typedef cases. There was a bug that cpp_style misidentified
+ # typedef for pointer to function as C-style cast and produced
+ # false-positive error messages.
+ def test_typedef_for_pointer_to_function(self):
+ self.assert_lint(
+ 'typedef void (*Func)(int x);',
+ '')
+ self.assert_lint(
+ 'typedef void (*Func)(int *x);',
+ '')
+ self.assert_lint(
+ 'typedef void Func(int x);',
+ '')
+ self.assert_lint(
+ 'typedef void Func(int *x);',
+ '')
+
+ def test_include_what_you_use_no_implementation_files(self):
+ code = 'std::vector<int> foo;'
+ self.assertEquals('Add #include <vector> for vector<>'
+ ' [build/include_what_you_use] [4]',
+ self.perform_include_what_you_use(code, 'foo.h'))
+ self.assertEquals('',
+ self.perform_include_what_you_use(code, 'foo.cpp'))
+
+ def test_include_what_you_use(self):
+ self.assert_include_what_you_use(
+ '''#include <vector>
+ std::vector<int> foo;
+ ''',
+ '')
+ self.assert_include_what_you_use(
+ '''#include <map>
+ std::pair<int,int> foo;
+ ''',
+ '')
+ self.assert_include_what_you_use(
+ '''#include <multimap>
+ std::pair<int,int> foo;
+ ''',
+ '')
+ self.assert_include_what_you_use(
+ '''#include <hash_map>
+ std::pair<int,int> foo;
+ ''',
+ '')
+ self.assert_include_what_you_use(
+ '''#include <utility>
+ std::pair<int,int> foo;
+ ''',
+ '')
+ self.assert_include_what_you_use(
+ '''#include <vector>
+ DECLARE_string(foobar);
+ ''',
+ '')
+ self.assert_include_what_you_use(
+ '''#include <vector>
+ DEFINE_string(foobar, "", "");
+ ''',
+ '')
+ self.assert_include_what_you_use(
+ '''#include <vector>
+ std::pair<int,int> foo;
+ ''',
+ 'Add #include <utility> for pair<>'
+ ' [build/include_what_you_use] [4]')
+ self.assert_include_what_you_use(
+ '''#include "base/foobar.h"
+ std::vector<int> foo;
+ ''',
+ 'Add #include <vector> for vector<>'
+ ' [build/include_what_you_use] [4]')
+ self.assert_include_what_you_use(
+ '''#include <vector>
+ std::set<int> foo;
+ ''',
+ 'Add #include <set> for set<>'
+ ' [build/include_what_you_use] [4]')
+ self.assert_include_what_you_use(
+ '''#include "base/foobar.h"
+ hash_map<int, int> foobar;
+ ''',
+ 'Add #include <hash_map> for hash_map<>'
+ ' [build/include_what_you_use] [4]')
+ self.assert_include_what_you_use(
+ '''#include "base/foobar.h"
+ bool foobar = std::less<int>(0,1);
+ ''',
+ 'Add #include <functional> for less<>'
+ ' [build/include_what_you_use] [4]')
+ self.assert_include_what_you_use(
+ '''#include "base/foobar.h"
+ bool foobar = min<int>(0,1);
+ ''',
+ 'Add #include <algorithm> for min [build/include_what_you_use] [4]')
+ self.assert_include_what_you_use(
+ 'void a(const string &foobar);',
+ 'Add #include <string> for string [build/include_what_you_use] [4]')
+ self.assert_include_what_you_use(
+ '''#include "base/foobar.h"
+ bool foobar = swap(0,1);
+ ''',
+ 'Add #include <algorithm> for swap [build/include_what_you_use] [4]')
+ self.assert_include_what_you_use(
+ '''#include "base/foobar.h"
+ bool foobar = transform(a.begin(), a.end(), b.start(), Foo);
+ ''',
+ 'Add #include <algorithm> for transform '
+ '[build/include_what_you_use] [4]')
+ self.assert_include_what_you_use(
+ '''#include "base/foobar.h"
+ bool foobar = min_element(a.begin(), a.end());
+ ''',
+ 'Add #include <algorithm> for min_element '
+ '[build/include_what_you_use] [4]')
+ self.assert_include_what_you_use(
+ '''foo->swap(0,1);
+ foo.swap(0,1);
+ ''',
+ '')
+ self.assert_include_what_you_use(
+ '''#include <string>
+ void a(const std::multimap<int,string> &foobar);
+ ''',
+ 'Add #include <map> for multimap<>'
+ ' [build/include_what_you_use] [4]')
+ self.assert_include_what_you_use(
+ '''#include <queue>
+ void a(const std::priority_queue<int> &foobar);
+ ''',
+ '')
+ self.assert_include_what_you_use(
+ '''#include "base/basictypes.h"
+ #include "base/port.h"
+ #include <assert.h>
+ #include <string>
+ #include <vector>
+ vector<string> hajoa;''', '')
+ self.assert_include_what_you_use(
+ '''#include <string>
+ int i = numeric_limits<int>::max()
+ ''',
+ 'Add #include <limits> for numeric_limits<>'
+ ' [build/include_what_you_use] [4]')
+ self.assert_include_what_you_use(
+ '''#include <limits>
+ int i = numeric_limits<int>::max()
+ ''',
+ '')
+
+ # Test the UpdateIncludeState code path.
+ mock_header_contents = ['#include "blah/foo.h"', '#include "blah/bar.h"']
+ message = self.perform_include_what_you_use(
+ '#include "config.h"\n'
+ '#include "blah/a.h"\n',
+ filename='blah/a.cpp',
+ io=MockIo(mock_header_contents))
+ self.assertEquals(message, '')
+
+ mock_header_contents = ['#include <set>']
+ message = self.perform_include_what_you_use(
+ '''#include "config.h"
+ #include "blah/a.h"
+
+ std::set<int> foo;''',
+ filename='blah/a.cpp',
+ io=MockIo(mock_header_contents))
+ self.assertEquals(message, '')
+
+ # If there's just a .cpp and the header can't be found then it's ok.
+ message = self.perform_include_what_you_use(
+ '''#include "config.h"
+ #include "blah/a.h"
+
+ std::set<int> foo;''',
+ filename='blah/a.cpp')
+ self.assertEquals(message, '')
+
+ # Make sure we find the headers with relative paths.
+ mock_header_contents = ['']
+ message = self.perform_include_what_you_use(
+ '''#include "config.h"
+ #include "%s/a.h"
+
+ std::set<int> foo;''' % os.path.basename(os.getcwd()),
+ filename='a.cpp',
+ io=MockIo(mock_header_contents))
+ self.assertEquals(message, 'Add #include <set> for set<> '
+ '[build/include_what_you_use] [4]')
+
+ def test_files_belong_to_same_module(self):
+ f = cpp_style.files_belong_to_same_module
+ self.assertEquals((True, ''), f('a.cpp', 'a.h'))
+ self.assertEquals((True, ''), f('base/google.cpp', 'base/google.h'))
+ self.assertEquals((True, ''), f('base/google_test.cpp', 'base/google.h'))
+ self.assertEquals((True, ''),
+ f('base/google_unittest.cpp', 'base/google.h'))
+ self.assertEquals((True, ''),
+ f('base/internal/google_unittest.cpp',
+ 'base/public/google.h'))
+ self.assertEquals((True, 'xxx/yyy/'),
+ f('xxx/yyy/base/internal/google_unittest.cpp',
+ 'base/public/google.h'))
+ self.assertEquals((True, 'xxx/yyy/'),
+ f('xxx/yyy/base/google_unittest.cpp',
+ 'base/public/google.h'))
+ self.assertEquals((True, ''),
+ f('base/google_unittest.cpp', 'base/google-inl.h'))
+ self.assertEquals((True, '/home/build/google3/'),
+ f('/home/build/google3/base/google.cpp', 'base/google.h'))
+
+ self.assertEquals((False, ''),
+ f('/home/build/google3/base/google.cpp', 'basu/google.h'))
+ self.assertEquals((False, ''), f('a.cpp', 'b.h'))
+
+ def test_cleanse_line(self):
+ self.assertEquals('int foo = 0; ',
+ cpp_style.cleanse_comments('int foo = 0; // danger!'))
+ self.assertEquals('int o = 0;',
+ cpp_style.cleanse_comments('int /* foo */ o = 0;'))
+ self.assertEquals('foo(int a, int b);',
+ cpp_style.cleanse_comments('foo(int a /* abc */, int b);'))
+ self.assertEqual('f(a, b);',
+ cpp_style.cleanse_comments('f(a, /* name */ b);'))
+ self.assertEqual('f(a, b);',
+ cpp_style.cleanse_comments('f(a /* name */, b);'))
+ self.assertEqual('f(a, b);',
+ cpp_style.cleanse_comments('f(a, /* name */b);'))
+
+ def test_multi_line_comments(self):
+ # missing explicit is bad
+ self.assert_multi_line_lint(
+ r'''int a = 0;
+ /* multi-liner
+ class Foo {
+ Foo(int f); // should cause a lint warning in code
+ }
+ */ ''',
+ '')
+ self.assert_multi_line_lint(
+ r'''/* int a = 0; multi-liner
+ static const int b = 0;''',
+ ['Could not find end of multi-line comment'
+ ' [readability/multiline_comment] [5]',
+ 'Complex multi-line /*...*/-style comment found. '
+ 'Lint may give bogus warnings. Consider replacing these with '
+ '//-style comments, with #if 0...#endif, or with more clearly '
+ 'structured multi-line comments. [readability/multiline_comment] [5]'])
+ self.assert_multi_line_lint(r''' /* multi-line comment''',
+ ['Could not find end of multi-line comment'
+ ' [readability/multiline_comment] [5]',
+ 'Complex multi-line /*...*/-style comment found. '
+ 'Lint may give bogus warnings. Consider replacing these with '
+ '//-style comments, with #if 0...#endif, or with more clearly '
+ 'structured multi-line comments. [readability/multiline_comment] [5]'])
+ self.assert_multi_line_lint(r''' // /* comment, but not multi-line''', '')
+
+ def test_multiline_strings(self):
+ multiline_string_error_message = (
+ 'Multi-line string ("...") found. This lint script doesn\'t '
+ 'do well with such strings, and may give bogus warnings. They\'re '
+ 'ugly and unnecessary, and you should use concatenation instead".'
+ ' [readability/multiline_string] [5]')
+
+ file_path = 'mydir/foo.cpp'
+
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data(file_path, 'cpp',
+ ['const char* str = "This is a\\',
+ ' multiline string.";'],
+ error_collector)
+ self.assertEquals(
+ 2, # One per line.
+ error_collector.result_list().count(multiline_string_error_message))
+
+ # Test non-explicit single-argument constructors
+ def test_explicit_single_argument_constructors(self):
+ # missing explicit is bad
+ self.assert_multi_line_lint(
+ '''class Foo {
+ Foo(int f);
+ };''',
+ 'Single-argument constructors should be marked explicit.'
+ ' [runtime/explicit] [5]')
+ # missing explicit is bad, even with whitespace
+ self.assert_multi_line_lint(
+ '''class Foo {
+ Foo (int f);
+ };''',
+ ['Extra space before ( in function call [whitespace/parens] [4]',
+ 'Single-argument constructors should be marked explicit.'
+ ' [runtime/explicit] [5]'])
+ # missing explicit, with distracting comment, is still bad
+ self.assert_multi_line_lint(
+ '''class Foo {
+ Foo(int f); // simpler than Foo(blargh, blarg)
+ };''',
+ 'Single-argument constructors should be marked explicit.'
+ ' [runtime/explicit] [5]')
+ # missing explicit, with qualified classname
+ self.assert_multi_line_lint(
+ '''class Qualifier::AnotherOne::Foo {
+ Foo(int f);
+ };''',
+ 'Single-argument constructors should be marked explicit.'
+ ' [runtime/explicit] [5]')
+ # structs are caught as well.
+ self.assert_multi_line_lint(
+ '''struct Foo {
+ Foo(int f);
+ };''',
+ 'Single-argument constructors should be marked explicit.'
+ ' [runtime/explicit] [5]')
+ # Templatized classes are caught as well.
+ self.assert_multi_line_lint(
+ '''template<typename T> class Foo {
+ Foo(int f);
+ };''',
+ 'Single-argument constructors should be marked explicit.'
+ ' [runtime/explicit] [5]')
+ # proper style is okay
+ self.assert_multi_line_lint(
+ '''class Foo {
+ explicit Foo(int f);
+ };''',
+ '')
+ # two argument constructor is okay
+ self.assert_multi_line_lint(
+ '''class Foo {
+ Foo(int f, int b);
+ };''',
+ '')
+ # two argument constructor, across two lines, is okay
+ self.assert_multi_line_lint(
+ '''class Foo {
+ Foo(int f,
+ int b);
+ };''',
+ '')
+ # non-constructor (but similar name), is okay
+ self.assert_multi_line_lint(
+ '''class Foo {
+ aFoo(int f);
+ };''',
+ '')
+ # constructor with void argument is okay
+ self.assert_multi_line_lint(
+ '''class Foo {
+ Foo(void);
+ };''',
+ '')
+ # single argument method is okay
+ self.assert_multi_line_lint(
+ '''class Foo {
+ Bar(int b);
+ };''',
+ '')
+ # comments should be ignored
+ self.assert_multi_line_lint(
+ '''class Foo {
+ // Foo(int f);
+ };''',
+ '')
+ # single argument function following class definition is okay
+ # (okay, it's not actually valid, but we don't want a false positive)
+ self.assert_multi_line_lint(
+ '''class Foo {
+ Foo(int f, int b);
+ };
+ Foo(int f);''',
+ '')
+ # single argument function is okay
+ self.assert_multi_line_lint(
+ '''static Foo(int f);''',
+ '')
+ # single argument copy constructor is okay.
+ self.assert_multi_line_lint(
+ '''class Foo {
+ Foo(const Foo&);
+ };''',
+ '')
+ self.assert_multi_line_lint(
+ '''class Foo {
+ Foo(Foo&);
+ };''',
+ '')
+
+ def test_slash_star_comment_on_single_line(self):
+ self.assert_multi_line_lint(
+ '''/* static */ Foo(int f);''',
+ '')
+ self.assert_multi_line_lint(
+ '''/*/ static */ Foo(int f);''',
+ '')
+ self.assert_multi_line_lint(
+ '''/*/ static Foo(int f);''',
+ 'Could not find end of multi-line comment'
+ ' [readability/multiline_comment] [5]')
+ self.assert_multi_line_lint(
+ ''' /*/ static Foo(int f);''',
+ 'Could not find end of multi-line comment'
+ ' [readability/multiline_comment] [5]')
+ self.assert_multi_line_lint(
+ ''' /**/ static Foo(int f);''',
+ '')
+
+ # Test suspicious usage of "if" like this:
+ # if (a == b) {
+ # DoSomething();
+ # } if (a == c) { // Should be "else if".
+ # DoSomething(); // This gets called twice if a == b && a == c.
+ # }
+ def test_suspicious_usage_of_if(self):
+ self.assert_lint(
+ ' if (a == b) {',
+ '')
+ self.assert_lint(
+ ' } if (a == b) {',
+ 'Did you mean "else if"? If not, start a new line for "if".'
+ ' [readability/braces] [4]')
+
+ # Test suspicious usage of memset. Specifically, a 0
+ # as the final argument is almost certainly an error.
+ def test_suspicious_usage_of_memset(self):
+ # Normal use is okay.
+ self.assert_lint(
+ ' memset(buf, 0, sizeof(buf))',
+ '')
+
+ # A 0 as the final argument is almost certainly an error.
+ self.assert_lint(
+ ' memset(buf, sizeof(buf), 0)',
+ 'Did you mean "memset(buf, 0, sizeof(buf))"?'
+ ' [runtime/memset] [4]')
+ self.assert_lint(
+ ' memset(buf, xsize * ysize, 0)',
+ 'Did you mean "memset(buf, 0, xsize * ysize)"?'
+ ' [runtime/memset] [4]')
+
+ # There is legitimate test code that uses this form.
+ # This is okay since the second argument is a literal.
+ self.assert_lint(
+ " memset(buf, 'y', 0)",
+ '')
+ self.assert_lint(
+ ' memset(buf, 4, 0)',
+ '')
+ self.assert_lint(
+ ' memset(buf, -1, 0)',
+ '')
+ self.assert_lint(
+ ' memset(buf, 0xF1, 0)',
+ '')
+ self.assert_lint(
+ ' memset(buf, 0xcd, 0)',
+ '')
+
+ def test_check_posix_threading(self):
+ self.assert_lint('sctime_r()', '')
+ self.assert_lint('strtok_r()', '')
+ self.assert_lint(' strtok_r(foo, ba, r)', '')
+ self.assert_lint('brand()', '')
+ self.assert_lint('_rand()', '')
+ self.assert_lint('.rand()', '')
+ self.assert_lint('>rand()', '')
+ self.assert_lint('rand()',
+ 'Consider using rand_r(...) instead of rand(...)'
+ ' for improved thread safety.'
+ ' [runtime/threadsafe_fn] [2]')
+ self.assert_lint('strtok()',
+ 'Consider using strtok_r(...) '
+ 'instead of strtok(...)'
+ ' for improved thread safety.'
+ ' [runtime/threadsafe_fn] [2]')
+
+ # Test potential format string bugs like printf(foo).
+ def test_format_strings(self):
+ self.assert_lint('printf("foo")', '')
+ self.assert_lint('printf("foo: %s", foo)', '')
+ self.assert_lint('DocidForPrintf(docid)', '') # Should not trigger.
+ self.assert_lint(
+ 'printf(foo)',
+ 'Potential format string bug. Do printf("%s", foo) instead.'
+ ' [runtime/printf] [4]')
+ self.assert_lint(
+ 'printf(foo.c_str())',
+ 'Potential format string bug. '
+ 'Do printf("%s", foo.c_str()) instead.'
+ ' [runtime/printf] [4]')
+ self.assert_lint(
+ 'printf(foo->c_str())',
+ 'Potential format string bug. '
+ 'Do printf("%s", foo->c_str()) instead.'
+ ' [runtime/printf] [4]')
+ self.assert_lint(
+ 'StringPrintf(foo)',
+ 'Potential format string bug. Do StringPrintf("%s", foo) instead.'
+ ''
+ ' [runtime/printf] [4]')
+
+ # Variable-length arrays are not permitted.
+ def test_variable_length_array_detection(self):
+ errmsg = ('Do not use variable-length arrays. Use an appropriately named '
+ "('k' followed by CamelCase) compile-time constant for the size."
+ ' [runtime/arrays] [1]')
+
+ self.assert_lint('int a[any_old_variable];', errmsg)
+ self.assert_lint('int doublesize[some_var * 2];', errmsg)
+ self.assert_lint('int a[afunction()];', errmsg)
+ self.assert_lint('int a[function(kMaxFooBars)];', errmsg)
+ self.assert_lint('bool aList[items_->size()];', errmsg)
+ self.assert_lint('namespace::Type buffer[len+1];', errmsg)
+
+ self.assert_lint('int a[64];', '')
+ self.assert_lint('int a[0xFF];', '')
+ self.assert_lint('int first[256], second[256];', '')
+ self.assert_lint('int arrayName[kCompileTimeConstant];', '')
+ self.assert_lint('char buf[somenamespace::kBufSize];', '')
+ self.assert_lint('int arrayName[ALL_CAPS];', '')
+ self.assert_lint('AClass array1[foo::bar::ALL_CAPS];', '')
+ self.assert_lint('int a[kMaxStrLen + 1];', '')
+ self.assert_lint('int a[sizeof(foo)];', '')
+ self.assert_lint('int a[sizeof(*foo)];', '')
+ self.assert_lint('int a[sizeof foo];', '')
+ self.assert_lint('int a[sizeof(struct Foo)];', '')
+ self.assert_lint('int a[128 - sizeof(const bar)];', '')
+ self.assert_lint('int a[(sizeof(foo) * 4)];', '')
+ self.assert_lint('int a[(arraysize(fixed_size_array)/2) << 1];', 'Missing spaces around / [whitespace/operators] [3]')
+ self.assert_lint('delete a[some_var];', '')
+ self.assert_lint('return a[some_var];', '')
+
+ # Brace usage
+ def test_braces(self):
+ # Braces shouldn't be followed by a ; unless they're defining a struct
+ # or initializing an array
+ self.assert_lint('int a[3] = { 1, 2, 3 };', '')
+ self.assert_lint(
+ '''const int foo[] =
+ {1, 2, 3 };''',
+ '')
+ # For single line, unmatched '}' with a ';' is ignored (not enough context)
+ self.assert_multi_line_lint(
+ '''int a[3] = { 1,
+ 2,
+ 3 };''',
+ '')
+ self.assert_multi_line_lint(
+ '''int a[2][3] = { { 1, 2 },
+ { 3, 4 } };''',
+ '')
+ self.assert_multi_line_lint(
+ '''int a[2][3] =
+ { { 1, 2 },
+ { 3, 4 } };''',
+ '')
+
+ # CHECK/EXPECT_TRUE/EXPECT_FALSE replacements
+ def test_check_check(self):
+ self.assert_lint('CHECK(x == 42)',
+ 'Consider using CHECK_EQ instead of CHECK(a == b)'
+ ' [readability/check] [2]')
+ self.assert_lint('CHECK(x != 42)',
+ 'Consider using CHECK_NE instead of CHECK(a != b)'
+ ' [readability/check] [2]')
+ self.assert_lint('CHECK(x >= 42)',
+ 'Consider using CHECK_GE instead of CHECK(a >= b)'
+ ' [readability/check] [2]')
+ self.assert_lint('CHECK(x > 42)',
+ 'Consider using CHECK_GT instead of CHECK(a > b)'
+ ' [readability/check] [2]')
+ self.assert_lint('CHECK(x <= 42)',
+ 'Consider using CHECK_LE instead of CHECK(a <= b)'
+ ' [readability/check] [2]')
+ self.assert_lint('CHECK(x < 42)',
+ 'Consider using CHECK_LT instead of CHECK(a < b)'
+ ' [readability/check] [2]')
+
+ self.assert_lint('DCHECK(x == 42)',
+ 'Consider using DCHECK_EQ instead of DCHECK(a == b)'
+ ' [readability/check] [2]')
+ self.assert_lint('DCHECK(x != 42)',
+ 'Consider using DCHECK_NE instead of DCHECK(a != b)'
+ ' [readability/check] [2]')
+ self.assert_lint('DCHECK(x >= 42)',
+ 'Consider using DCHECK_GE instead of DCHECK(a >= b)'
+ ' [readability/check] [2]')
+ self.assert_lint('DCHECK(x > 42)',
+ 'Consider using DCHECK_GT instead of DCHECK(a > b)'
+ ' [readability/check] [2]')
+ self.assert_lint('DCHECK(x <= 42)',
+ 'Consider using DCHECK_LE instead of DCHECK(a <= b)'
+ ' [readability/check] [2]')
+ self.assert_lint('DCHECK(x < 42)',
+ 'Consider using DCHECK_LT instead of DCHECK(a < b)'
+ ' [readability/check] [2]')
+
+ self.assert_lint(
+ 'EXPECT_TRUE("42" == x)',
+ 'Consider using EXPECT_EQ instead of EXPECT_TRUE(a == b)'
+ ' [readability/check] [2]')
+ self.assert_lint(
+ 'EXPECT_TRUE("42" != x)',
+ 'Consider using EXPECT_NE instead of EXPECT_TRUE(a != b)'
+ ' [readability/check] [2]')
+ self.assert_lint(
+ 'EXPECT_TRUE(+42 >= x)',
+ 'Consider using EXPECT_GE instead of EXPECT_TRUE(a >= b)'
+ ' [readability/check] [2]')
+ self.assert_lint(
+ 'EXPECT_TRUE_M(-42 > x)',
+ 'Consider using EXPECT_GT_M instead of EXPECT_TRUE_M(a > b)'
+ ' [readability/check] [2]')
+ self.assert_lint(
+ 'EXPECT_TRUE_M(42U <= x)',
+ 'Consider using EXPECT_LE_M instead of EXPECT_TRUE_M(a <= b)'
+ ' [readability/check] [2]')
+ self.assert_lint(
+ 'EXPECT_TRUE_M(42L < x)',
+ 'Consider using EXPECT_LT_M instead of EXPECT_TRUE_M(a < b)'
+ ' [readability/check] [2]')
+
+ self.assert_lint(
+ 'EXPECT_FALSE(x == 42)',
+ 'Consider using EXPECT_NE instead of EXPECT_FALSE(a == b)'
+ ' [readability/check] [2]')
+ self.assert_lint(
+ 'EXPECT_FALSE(x != 42)',
+ 'Consider using EXPECT_EQ instead of EXPECT_FALSE(a != b)'
+ ' [readability/check] [2]')
+ self.assert_lint(
+ 'EXPECT_FALSE(x >= 42)',
+ 'Consider using EXPECT_LT instead of EXPECT_FALSE(a >= b)'
+ ' [readability/check] [2]')
+ self.assert_lint(
+ 'ASSERT_FALSE(x > 42)',
+ 'Consider using ASSERT_LE instead of ASSERT_FALSE(a > b)'
+ ' [readability/check] [2]')
+ self.assert_lint(
+ 'ASSERT_FALSE(x <= 42)',
+ 'Consider using ASSERT_GT instead of ASSERT_FALSE(a <= b)'
+ ' [readability/check] [2]')
+ self.assert_lint(
+ 'ASSERT_FALSE_M(x < 42)',
+ 'Consider using ASSERT_GE_M instead of ASSERT_FALSE_M(a < b)'
+ ' [readability/check] [2]')
+
+ self.assert_lint('CHECK(some_iterator == obj.end())', '')
+ self.assert_lint('EXPECT_TRUE(some_iterator == obj.end())', '')
+ self.assert_lint('EXPECT_FALSE(some_iterator == obj.end())', '')
+
+ self.assert_lint('CHECK(CreateTestFile(dir, (1 << 20)));', '')
+ self.assert_lint('CHECK(CreateTestFile(dir, (1 >> 20)));', '')
+
+ self.assert_lint('CHECK(x<42)',
+ ['Missing spaces around <'
+ ' [whitespace/operators] [3]',
+ 'Consider using CHECK_LT instead of CHECK(a < b)'
+ ' [readability/check] [2]'])
+ self.assert_lint('CHECK(x>42)',
+ 'Consider using CHECK_GT instead of CHECK(a > b)'
+ ' [readability/check] [2]')
+
+ self.assert_lint(
+ ' EXPECT_TRUE(42 < x) // Random comment.',
+ 'Consider using EXPECT_LT instead of EXPECT_TRUE(a < b)'
+ ' [readability/check] [2]')
+ self.assert_lint(
+ 'EXPECT_TRUE( 42 < x )',
+ ['Extra space after ( in function call'
+ ' [whitespace/parens] [4]',
+ 'Consider using EXPECT_LT instead of EXPECT_TRUE(a < b)'
+ ' [readability/check] [2]'])
+ self.assert_lint(
+ 'CHECK("foo" == "foo")',
+ 'Consider using CHECK_EQ instead of CHECK(a == b)'
+ ' [readability/check] [2]')
+
+ self.assert_lint('CHECK_EQ("foo", "foo")', '')
+
+ def test_brace_at_begin_of_line(self):
+ self.assert_lint('{',
+ 'This { should be at the end of the previous line'
+ ' [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ '#endif\n'
+ '{\n'
+ '}\n',
+ '')
+ self.assert_multi_line_lint(
+ 'if (condition) {',
+ '')
+ self.assert_multi_line_lint(
+ ' MACRO1(macroArg) {',
+ '')
+ self.assert_multi_line_lint(
+ 'ACCESSOR_GETTER(MessageEventPorts) {',
+ 'Place brace on its own line for function definitions. [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'int foo() {',
+ 'Place brace on its own line for function definitions. [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'int foo() const {',
+ 'Place brace on its own line for function definitions. [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'int foo() const\n'
+ '{\n'
+ '}\n',
+ '')
+ self.assert_multi_line_lint(
+ 'if (condition\n'
+ ' && condition2\n'
+ ' && condition3) {\n'
+ '}\n',
+ '')
+
+ def test_mismatching_spaces_in_parens(self):
+ self.assert_lint('if (foo ) {', 'Extra space before ) in if'
+ ' [whitespace/parens] [5]')
+ self.assert_lint('switch ( foo) {', 'Extra space after ( in switch'
+ ' [whitespace/parens] [5]')
+ self.assert_lint('for (foo; ba; bar ) {', 'Extra space before ) in for'
+ ' [whitespace/parens] [5]')
+ self.assert_lint('for ((foo); (ba); (bar) ) {', 'Extra space before ) in for'
+ ' [whitespace/parens] [5]')
+ self.assert_lint('for (; foo; bar) {', '')
+ self.assert_lint('for (; (foo); (bar)) {', '')
+ self.assert_lint('for ( ; foo; bar) {', '')
+ self.assert_lint('for ( ; (foo); (bar)) {', '')
+ self.assert_lint('for ( ; foo; bar ) {', 'Extra space before ) in for'
+ ' [whitespace/parens] [5]')
+ self.assert_lint('for ( ; (foo); (bar) ) {', 'Extra space before ) in for'
+ ' [whitespace/parens] [5]')
+ self.assert_lint('for (foo; bar; ) {', '')
+ self.assert_lint('for ((foo); (bar); ) {', '')
+ self.assert_lint('foreach (foo, foos ) {', 'Extra space before ) in foreach'
+ ' [whitespace/parens] [5]')
+ self.assert_lint('foreach ( foo, foos) {', 'Extra space after ( in foreach'
+ ' [whitespace/parens] [5]')
+ self.assert_lint('while ( foo) {', 'Extra space after ( in while'
+ ' [whitespace/parens] [5]')
+
+ def test_spacing_for_fncall(self):
+ self.assert_lint('if (foo) {', '')
+ self.assert_lint('for (foo;bar;baz) {', '')
+ self.assert_lint('foreach (foo, foos) {', '')
+ self.assert_lint('while (foo) {', '')
+ self.assert_lint('switch (foo) {', '')
+ self.assert_lint('new (RenderArena()) RenderInline(document())', '')
+ self.assert_lint('foo( bar)', 'Extra space after ( in function call'
+ ' [whitespace/parens] [4]')
+ self.assert_lint('foobar( \\', '')
+ self.assert_lint('foobar( \\', '')
+ self.assert_lint('( a + b)', 'Extra space after ('
+ ' [whitespace/parens] [2]')
+ self.assert_lint('((a+b))', '')
+ self.assert_lint('foo (foo)', 'Extra space before ( in function call'
+ ' [whitespace/parens] [4]')
+ self.assert_lint('typedef foo (*foo)(foo)', '')
+ self.assert_lint('typedef foo (*foo12bar_)(foo)', '')
+ self.assert_lint('typedef foo (Foo::*bar)(foo)', '')
+ self.assert_lint('foo (Foo::*bar)(',
+ 'Extra space before ( in function call'
+ ' [whitespace/parens] [4]')
+ self.assert_lint('typedef foo (Foo::*bar)(', '')
+ self.assert_lint('(foo)(bar)', '')
+ self.assert_lint('Foo (*foo)(bar)', '')
+ self.assert_lint('Foo (*foo)(Bar bar,', '')
+ self.assert_lint('char (*p)[sizeof(foo)] = &foo', '')
+ self.assert_lint('char (&ref)[sizeof(foo)] = &foo', '')
+ self.assert_lint('const char32 (*table[])[6];', '')
+
+ def test_spacing_before_braces(self):
+ self.assert_lint('if (foo){', 'Missing space before {'
+ ' [whitespace/braces] [5]')
+ self.assert_lint('for{', 'Missing space before {'
+ ' [whitespace/braces] [5]')
+ self.assert_lint('for {', '')
+ self.assert_lint('EXPECT_DEBUG_DEATH({', '')
+
+ def test_spacing_around_else(self):
+ self.assert_lint('}else {', 'Missing space before else'
+ ' [whitespace/braces] [5]')
+ self.assert_lint('} else{', 'Missing space before {'
+ ' [whitespace/braces] [5]')
+ self.assert_lint('} else {', '')
+ self.assert_lint('} else if', '')
+
+ def test_spacing_for_binary_ops(self):
+ self.assert_lint('if (foo<=bar) {', 'Missing spaces around <='
+ ' [whitespace/operators] [3]')
+ self.assert_lint('if (foo<bar) {', 'Missing spaces around <'
+ ' [whitespace/operators] [3]')
+ self.assert_lint('if (foo<bar->baz) {', 'Missing spaces around <'
+ ' [whitespace/operators] [3]')
+ self.assert_lint('if (foo<bar->bar) {', 'Missing spaces around <'
+ ' [whitespace/operators] [3]')
+ self.assert_lint('typedef hash_map<Foo, Bar', 'Missing spaces around <'
+ ' [whitespace/operators] [3]')
+ self.assert_lint('typedef hash_map<FoooooType, BaaaaarType,', '')
+ self.assert_lint('a<Foo> t+=b;', 'Missing spaces around +='
+ ' [whitespace/operators] [3]')
+ self.assert_lint('a<Foo> t-=b;', 'Missing spaces around -='
+ ' [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t*=b;', 'Missing spaces around *='
+ ' [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t/=b;', 'Missing spaces around /='
+ ' [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t|=b;', 'Missing spaces around |='
+ ' [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t&=b;', 'Missing spaces around &='
+ ' [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t<<=b;', 'Missing spaces around <<='
+ ' [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t>>=b;', 'Missing spaces around >>='
+ ' [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t>>=&b|c;', 'Missing spaces around >>='
+ ' [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t<<=*b/c;', 'Missing spaces around <<='
+ ' [whitespace/operators] [3]')
+ self.assert_lint('a<Foo> t -= b;', '')
+ self.assert_lint('a<Foo> t += b;', '')
+ self.assert_lint('a<Foo*> t *= b;', '')
+ self.assert_lint('a<Foo*> t /= b;', '')
+ self.assert_lint('a<Foo*> t |= b;', '')
+ self.assert_lint('a<Foo*> t &= b;', '')
+ self.assert_lint('a<Foo*> t <<= b;', '')
+ self.assert_lint('a<Foo*> t >>= b;', '')
+ self.assert_lint('a<Foo*> t >>= &b|c;', 'Missing spaces around |'
+ ' [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t <<= *b/c;', 'Missing spaces around /'
+ ' [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t <<= b/c; //Test', [
+ 'Should have a space between // and comment '
+ '[whitespace/comments] [4]', 'Missing'
+ ' spaces around / [whitespace/operators] [3]'])
+ self.assert_lint('a<Foo*> t <<= b||c; //Test', ['One space before end'
+ ' of line comments [whitespace/comments] [5]',
+ 'Should have a space between // and comment '
+ '[whitespace/comments] [4]',
+ 'Missing spaces around || [whitespace/operators] [3]'])
+ self.assert_lint('a<Foo*> t <<= b&&c; // Test', 'Missing spaces around'
+ ' && [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t <<= b&&&c; // Test', 'Missing spaces around'
+ ' && [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t <<= b&&*c; // Test', 'Missing spaces around'
+ ' && [whitespace/operators] [3]')
+ self.assert_lint('a<Foo*> t <<= b && *c; // Test', '')
+ self.assert_lint('a<Foo*> t <<= b && &c; // Test', '')
+ self.assert_lint('a<Foo*> t <<= b || &c; /*Test', 'Complex multi-line '
+ '/*...*/-style comment found. Lint may give bogus '
+ 'warnings. Consider replacing these with //-style'
+ ' comments, with #if 0...#endif, or with more clearly'
+ ' structured multi-line comments. [readability/multiline_comment] [5]')
+ self.assert_lint('a<Foo&> t <<= &b | &c;', '')
+ self.assert_lint('a<Foo*> t <<= &b & &c; // Test', '')
+ self.assert_lint('a<Foo*> t <<= *b / &c; // Test', '')
+ self.assert_lint('if (a=b == 1)', 'Missing spaces around = [whitespace/operators] [4]')
+ self.assert_lint('a = 1<<20', 'Missing spaces around << [whitespace/operators] [3]')
+ self.assert_lint('if (a = b == 1)', '')
+ self.assert_lint('a = 1 << 20', '')
+ self.assert_multi_line_lint('#include <sys/io.h>\n', '')
+ self.assert_multi_line_lint('#import <foo/bar.h>\n', '')
+
+ def test_operator_methods(self):
+ self.assert_lint('String operator+(const String&, const String&);', '')
+ self.assert_lint('bool operator==(const String&, const String&);', '')
+ self.assert_lint('String& operator-=(const String&, const String&);', '')
+ self.assert_lint('String& operator+=(const String&, const String&);', '')
+ self.assert_lint('String& operator*=(const String&, const String&);', '')
+ self.assert_lint('String& operator%=(const String&, const String&);', '')
+ self.assert_lint('String& operator&=(const String&, const String&);', '')
+ self.assert_lint('String& operator<<=(const String&, const String&);', '')
+ self.assert_lint('String& operator>>=(const String&, const String&);', '')
+ self.assert_lint('String& operator|=(const String&, const String&);', '')
+ self.assert_lint('String& operator^=(const String&, const String&);', '')
+
+ def test_spacing_before_last_semicolon(self):
+ self.assert_lint('call_function() ;',
+ 'Extra space before last semicolon. If this should be an '
+ 'empty statement, use { } instead.'
+ ' [whitespace/semicolon] [5]')
+ self.assert_lint('while (true) ;',
+ 'Extra space before last semicolon. If this should be an '
+ 'empty statement, use { } instead.'
+ ' [whitespace/semicolon] [5]')
+ self.assert_lint('default:;',
+ 'Semicolon defining empty statement. Use { } instead.'
+ ' [whitespace/semicolon] [5]')
+ self.assert_lint(' ;',
+ 'Line contains only semicolon. If this should be an empty '
+ 'statement, use { } instead.'
+ ' [whitespace/semicolon] [5]')
+ self.assert_lint('for (int i = 0; ;', '')
+
+ # Static or global STL strings.
+ def test_static_or_global_stlstrings(self):
+ self.assert_lint('string foo;',
+ 'For a static/global string constant, use a C style '
+ 'string instead: "char foo[]".'
+ ' [runtime/string] [4]')
+ self.assert_lint('string kFoo = "hello"; // English',
+ 'For a static/global string constant, use a C style '
+ 'string instead: "char kFoo[]".'
+ ' [runtime/string] [4]')
+ self.assert_lint('static string foo;',
+ 'For a static/global string constant, use a C style '
+ 'string instead: "static char foo[]".'
+ ' [runtime/string] [4]')
+ self.assert_lint('static const string foo;',
+ 'For a static/global string constant, use a C style '
+ 'string instead: "static const char foo[]".'
+ ' [runtime/string] [4]')
+ self.assert_lint('string Foo::bar;',
+ 'For a static/global string constant, use a C style '
+ 'string instead: "char Foo::bar[]".'
+ ' [runtime/string] [4]')
+ # Rare case.
+ self.assert_lint('string foo("foobar");',
+ 'For a static/global string constant, use a C style '
+ 'string instead: "char foo[]".'
+ ' [runtime/string] [4]')
+ # Should not catch local or member variables.
+ self.assert_lint(' string foo', '')
+ # Should not catch functions.
+ self.assert_lint('string EmptyString() { return ""; }', '')
+ self.assert_lint('string EmptyString () { return ""; }', '')
+ self.assert_lint('string VeryLongNameFunctionSometimesEndsWith(\n'
+ ' VeryLongNameType veryLongNameVariable) {}', '')
+ self.assert_lint('template<>\n'
+ 'string FunctionTemplateSpecialization<SomeType>(\n'
+ ' int x) { return ""; }', '')
+ self.assert_lint('template<>\n'
+ 'string FunctionTemplateSpecialization<vector<A::B>* >(\n'
+ ' int x) { return ""; }', '')
+
+ # should not catch methods of template classes.
+ self.assert_lint('string Class<Type>::Method() const\n'
+ '{\n'
+ ' return "";\n'
+ '}\n', '')
+ self.assert_lint('string Class<Type>::Method(\n'
+ ' int arg) const\n'
+ '{\n'
+ ' return "";\n'
+ '}\n', '')
+
+ def test_no_spaces_in_function_calls(self):
+ self.assert_lint('TellStory(1, 3);',
+ '')
+ self.assert_lint('TellStory(1, 3 );',
+ 'Extra space before )'
+ ' [whitespace/parens] [2]')
+ self.assert_lint('TellStory(1 /* wolf */, 3 /* pigs */);',
+ '')
+ self.assert_multi_line_lint('#endif\n );',
+ '')
+
+ def test_two_spaces_between_code_and_comments(self):
+ self.assert_lint('} // namespace foo',
+ '')
+ self.assert_lint('}// namespace foo',
+ 'One space before end of line comments'
+ ' [whitespace/comments] [5]')
+ self.assert_lint('printf("foo"); // Outside quotes.',
+ '')
+ self.assert_lint('int i = 0; // Having one space is fine.','')
+ self.assert_lint('int i = 0; // Having two spaces is bad.',
+ 'One space before end of line comments'
+ ' [whitespace/comments] [5]')
+ self.assert_lint('int i = 0; // Having three spaces is bad.',
+ 'One space before end of line comments'
+ ' [whitespace/comments] [5]')
+ self.assert_lint('// Top level comment', '')
+ self.assert_lint(' // Line starts with four spaces.', '')
+ self.assert_lint('foo();\n'
+ '{ // A scope is opening.', '')
+ self.assert_lint(' foo();\n'
+ ' { // An indented scope is opening.', '')
+ self.assert_lint('if (foo) { // not a pure scope',
+ '')
+ self.assert_lint('printf("// In quotes.")', '')
+ self.assert_lint('printf("\\"%s // In quotes.")', '')
+ self.assert_lint('printf("%s", "// In quotes.")', '')
+
+ def test_space_after_comment_marker(self):
+ self.assert_lint('//', '')
+ self.assert_lint('//x', 'Should have a space between // and comment'
+ ' [whitespace/comments] [4]')
+ self.assert_lint('// x', '')
+ self.assert_lint('//----', '')
+ self.assert_lint('//====', '')
+ self.assert_lint('//////', '')
+ self.assert_lint('////// x', '')
+ self.assert_lint('/// x', '')
+ self.assert_lint('////x', 'Should have a space between // and comment'
+ ' [whitespace/comments] [4]')
+
+ def test_newline_at_eof(self):
+ def do_test(self, data, is_missing_eof):
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data('foo.cpp', 'cpp', data.split('\n'),
+ error_collector)
+ # The warning appears only once.
+ self.assertEquals(
+ int(is_missing_eof),
+ error_collector.results().count(
+ 'Could not find a newline character at the end of the file.'
+ ' [whitespace/ending_newline] [5]'))
+
+ do_test(self, '// Newline\n// at EOF\n', False)
+ do_test(self, '// No newline\n// at EOF', True)
+
+ def test_invalid_utf8(self):
+ def do_test(self, raw_bytes, has_invalid_utf8):
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data('foo.cpp', 'cpp',
+ unicode(raw_bytes, 'utf8', 'replace').split('\n'),
+ error_collector)
+ # The warning appears only once.
+ self.assertEquals(
+ int(has_invalid_utf8),
+ error_collector.results().count(
+ 'Line contains invalid UTF-8'
+ ' (or Unicode replacement character).'
+ ' [readability/utf8] [5]'))
+
+ do_test(self, 'Hello world\n', False)
+ do_test(self, '\xe9\x8e\xbd\n', False)
+ do_test(self, '\xe9x\x8e\xbd\n', True)
+ # This is the encoding of the replacement character itself (which
+ # you can see by evaluating codecs.getencoder('utf8')(u'\ufffd')).
+ do_test(self, '\xef\xbf\xbd\n', True)
+
+ def test_is_blank_line(self):
+ self.assert_(cpp_style.is_blank_line(''))
+ self.assert_(cpp_style.is_blank_line(' '))
+ self.assert_(cpp_style.is_blank_line(' \t\r\n'))
+ self.assert_(not cpp_style.is_blank_line('int a;'))
+ self.assert_(not cpp_style.is_blank_line('{'))
+
+ def test_blank_lines_check(self):
+ self.assert_blank_lines_check(['{\n', '\n', '\n', '}\n'], 1, 1)
+ self.assert_blank_lines_check([' if (foo) {\n', '\n', ' }\n'], 1, 1)
+ self.assert_blank_lines_check(
+ ['\n', '// {\n', '\n', '\n', '// Comment\n', '{\n', '}\n'], 0, 0)
+ self.assert_blank_lines_check(['\n', 'run("{");\n', '\n'], 0, 0)
+ self.assert_blank_lines_check(['\n', ' if (foo) { return 0; }\n', '\n'], 0, 0)
+
+ def test_allow_blank_line_before_closing_namespace(self):
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data('foo.cpp', 'cpp',
+ ['namespace {', '', '} // namespace'],
+ error_collector)
+ self.assertEquals(0, error_collector.results().count(
+ 'Blank line at the end of a code block. Is this needed?'
+ ' [whitespace/blank_line] [3]'))
+
+ def test_allow_blank_line_before_if_else_chain(self):
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data('foo.cpp', 'cpp',
+ ['if (hoge) {',
+ '', # No warning
+ '} else if (piyo) {',
+ '', # No warning
+ '} else if (piyopiyo) {',
+ ' hoge = true;', # No warning
+ '} else {',
+ '', # Warning on this line
+ '}'],
+ error_collector)
+ self.assertEquals(1, error_collector.results().count(
+ 'Blank line at the end of a code block. Is this needed?'
+ ' [whitespace/blank_line] [3]'))
+
+ def test_else_on_same_line_as_closing_braces(self):
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data('foo.cpp', 'cpp',
+ ['if (hoge) {',
+ '',
+ '}',
+ ' else {' # Warning on this line
+ '',
+ '}'],
+ error_collector)
+ self.assertEquals(1, error_collector.results().count(
+ 'An else should appear on the same line as the preceding }'
+ ' [whitespace/newline] [4]'))
+
+ def test_else_clause_not_on_same_line_as_else(self):
+ self.assert_lint(' else DoSomethingElse();',
+ 'Else clause should never be on same line as else '
+ '(use 2 lines) [whitespace/newline] [4]')
+ self.assert_lint(' else ifDoSomethingElse();',
+ 'Else clause should never be on same line as else '
+ '(use 2 lines) [whitespace/newline] [4]')
+ self.assert_lint(' else if (blah) {', '')
+ self.assert_lint(' variable_ends_in_else = true;', '')
+
+ def test_comma(self):
+ self.assert_lint('a = f(1,2);',
+ 'Missing space after , [whitespace/comma] [3]')
+ self.assert_lint('int tmp=a,a=b,b=tmp;',
+ ['Missing spaces around = [whitespace/operators] [4]',
+ 'Missing space after , [whitespace/comma] [3]'])
+ self.assert_lint('f(a, /* name */ b);', '')
+ self.assert_lint('f(a, /* name */b);', '')
+
+ def test_declaration(self):
+ self.assert_lint('int a;', '')
+ self.assert_lint('int a;', 'Extra space between int and a [whitespace/declaration] [3]')
+ self.assert_lint('int* a;', 'Extra space between int* and a [whitespace/declaration] [3]')
+ self.assert_lint('else if { }', '')
+ self.assert_lint('else if { }', 'Extra space between else and if [whitespace/declaration] [3]')
+
+ def test_pointer_reference_marker_location(self):
+ self.assert_lint('int* b;', '', 'foo.cpp')
+ self.assert_lint('int *b;',
+ 'Declaration has space between type name and * in int *b [whitespace/declaration] [3]',
+ 'foo.cpp')
+ self.assert_lint('return *b;', '', 'foo.cpp')
+ self.assert_lint('delete *b;', '', 'foo.cpp')
+ self.assert_lint('int *b;', '', 'foo.c')
+ self.assert_lint('int* b;',
+ 'Declaration has space between * and variable name in int* b [whitespace/declaration] [3]',
+ 'foo.c')
+ self.assert_lint('int& b;', '', 'foo.cpp')
+ self.assert_lint('int &b;',
+ 'Declaration has space between type name and & in int &b [whitespace/declaration] [3]',
+ 'foo.cpp')
+ self.assert_lint('return &b;', '', 'foo.cpp')
+
+ def test_indent(self):
+ self.assert_lint('static int noindent;', '')
+ self.assert_lint(' int fourSpaceIndent;', '')
+ self.assert_lint(' int oneSpaceIndent;',
+ 'Weird number of spaces at line-start. '
+ 'Are you using a 4-space indent? [whitespace/indent] [3]')
+ self.assert_lint(' int threeSpaceIndent;',
+ 'Weird number of spaces at line-start. '
+ 'Are you using a 4-space indent? [whitespace/indent] [3]')
+ self.assert_lint(' char* oneSpaceIndent = "public:";',
+ 'Weird number of spaces at line-start. '
+ 'Are you using a 4-space indent? [whitespace/indent] [3]')
+ self.assert_lint(' public:', '')
+ self.assert_lint(' public:', '')
+ self.assert_lint(' public:', '')
+
+ def test_label(self):
+ self.assert_lint('public:',
+ 'Labels should always be indented at least one space. '
+ 'If this is a member-initializer list in a constructor, '
+ 'the colon should be on the line after the definition '
+ 'header. [whitespace/labels] [4]')
+ self.assert_lint(' public:', '')
+ self.assert_lint(' public:', '')
+ self.assert_lint(' public:', '')
+ self.assert_lint(' public:', '')
+ self.assert_lint(' public:', '')
+
+ def test_not_alabel(self):
+ self.assert_lint('MyVeryLongNamespace::MyVeryLongClassName::', '')
+
+ def test_tab(self):
+ self.assert_lint('\tint a;',
+ 'Tab found; better to use spaces [whitespace/tab] [1]')
+ self.assert_lint('int a = 5;\t// set a to 5',
+ 'Tab found; better to use spaces [whitespace/tab] [1]')
+
+ def test_unnamed_namespaces_in_headers(self):
+ self.assert_language_rules_check(
+ 'foo.h', 'namespace {',
+ 'Do not use unnamed namespaces in header files. See'
+ ' http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Namespaces'
+ ' for more information. [build/namespaces] [4]')
+ # namespace registration macros are OK.
+ self.assert_language_rules_check('foo.h', 'namespace { \\', '')
+ # named namespaces are OK.
+ self.assert_language_rules_check('foo.h', 'namespace foo {', '')
+ self.assert_language_rules_check('foo.h', 'namespace foonamespace {', '')
+ self.assert_language_rules_check('foo.cpp', 'namespace {', '')
+ self.assert_language_rules_check('foo.cpp', 'namespace foo {', '')
+
+ def test_build_class(self):
+ # Test that the linter can parse to the end of class definitions,
+ # and that it will report when it can't.
+ # Use multi-line linter because it performs the ClassState check.
+ self.assert_multi_line_lint(
+ 'class Foo {',
+ 'Failed to find complete declaration of class Foo'
+ ' [build/class] [5]')
+ # Don't warn on forward declarations of various types.
+ self.assert_multi_line_lint(
+ 'class Foo;',
+ '')
+ self.assert_multi_line_lint(
+ '''struct Foo*
+ foo = NewFoo();''',
+ '')
+ # Here is an example where the linter gets confused, even though
+ # the code doesn't violate the style guide.
+ self.assert_multi_line_lint(
+ '''class Foo
+ #ifdef DERIVE_FROM_GOO
+ : public Goo {
+ #else
+ : public Hoo {
+ #endif
+ };''',
+ 'Failed to find complete declaration of class Foo'
+ ' [build/class] [5]')
+
+ def test_build_end_comment(self):
+ # The crosstool compiler we currently use will fail to compile the
+ # code in this test, so we might consider removing the lint check.
+ self.assert_lint('#endif Not a comment',
+ 'Uncommented text after #endif is non-standard.'
+ ' Use a comment.'
+ ' [build/endif_comment] [5]')
+
+ def test_build_forward_decl(self):
+ # The crosstool compiler we currently use will fail to compile the
+ # code in this test, so we might consider removing the lint check.
+ self.assert_lint('class Foo::Goo;',
+ 'Inner-style forward declarations are invalid.'
+ ' Remove this line.'
+ ' [build/forward_decl] [5]')
+
+ def test_build_header_guard(self):
+ file_path = 'mydir/Foo.h'
+
+ # We can't rely on our internal stuff to get a sane path on the open source
+ # side of things, so just parse out the suggested header guard. This
+ # doesn't allow us to test the suggested header guard, but it does let us
+ # test all the other header tests.
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data(file_path, 'h', [], error_collector)
+ expected_guard = ''
+ matcher = re.compile(
+ 'No \#ifndef header guard found\, suggested CPP variable is\: ([A-Za-z_0-9]+) ')
+ for error in error_collector.result_list():
+ matches = matcher.match(error)
+ if matches:
+ expected_guard = matches.group(1)
+ break
+
+ # Make sure we extracted something for our header guard.
+ self.assertNotEqual(expected_guard, '')
+
+ # Wrong guard
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data(file_path, 'h',
+ ['#ifndef FOO_H', '#define FOO_H'], error_collector)
+ self.assertEquals(
+ 1,
+ error_collector.result_list().count(
+ '#ifndef header guard has wrong style, please use: %s'
+ ' [build/header_guard] [5]' % expected_guard),
+ error_collector.result_list())
+
+ # No define
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data(file_path, 'h',
+ ['#ifndef %s' % expected_guard], error_collector)
+ self.assertEquals(
+ 1,
+ error_collector.result_list().count(
+ 'No #ifndef header guard found, suggested CPP variable is: %s'
+ ' [build/header_guard] [5]' % expected_guard),
+ error_collector.result_list())
+
+ # Mismatched define
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data(file_path, 'h',
+ ['#ifndef %s' % expected_guard,
+ '#define FOO_H'],
+ error_collector)
+ self.assertEquals(
+ 1,
+ error_collector.result_list().count(
+ 'No #ifndef header guard found, suggested CPP variable is: %s'
+ ' [build/header_guard] [5]' % expected_guard),
+ error_collector.result_list())
+
+ # No header guard errors
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data(file_path, 'h',
+ ['#ifndef %s' % expected_guard,
+ '#define %s' % expected_guard,
+ '#endif // %s' % expected_guard],
+ error_collector)
+ for line in error_collector.result_list():
+ if line.find('build/header_guard') != -1:
+ self.fail('Unexpected error: %s' % line)
+
+ # Completely incorrect header guard
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data(file_path, 'h',
+ ['#ifndef FOO',
+ '#define FOO',
+ '#endif // FOO'],
+ error_collector)
+ self.assertEquals(
+ 1,
+ error_collector.result_list().count(
+ '#ifndef header guard has wrong style, please use: %s'
+ ' [build/header_guard] [5]' % expected_guard),
+ error_collector.result_list())
+
+ # Special case for flymake
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data('mydir/Foo_flymake.h', 'h',
+ ['#ifndef %s' % expected_guard,
+ '#define %s' % expected_guard,
+ '#endif // %s' % expected_guard],
+ error_collector)
+ for line in error_collector.result_list():
+ if line.find('build/header_guard') != -1:
+ self.fail('Unexpected error: %s' % line)
+
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data('mydir/Foo_flymake.h', 'h', [], error_collector)
+ self.assertEquals(
+ 1,
+ error_collector.result_list().count(
+ 'No #ifndef header guard found, suggested CPP variable is: %s'
+ ' [build/header_guard] [5]' % expected_guard),
+ error_collector.result_list())
+
+ # Allow the WTF_ prefix for files in that directory.
+ header_guard_filter = FilterConfiguration(('-', '+build/header_guard'))
+ error_collector = ErrorCollector(self.assert_, header_guard_filter)
+ self.process_file_data('JavaScriptCore/wtf/TestName.h', 'h',
+ ['#ifndef WTF_TestName_h', '#define WTF_TestName_h'],
+ error_collector)
+ self.assertEquals(0, len(error_collector.result_list()),
+ error_collector.result_list())
+
+ # Also allow the non WTF_ prefix for files in that directory.
+ error_collector = ErrorCollector(self.assert_, header_guard_filter)
+ self.process_file_data('JavaScriptCore/wtf/TestName.h', 'h',
+ ['#ifndef TestName_h', '#define TestName_h'],
+ error_collector)
+ self.assertEquals(0, len(error_collector.result_list()),
+ error_collector.result_list())
+
+ # Verify that we suggest the WTF prefix version.
+ error_collector = ErrorCollector(self.assert_, header_guard_filter)
+ self.process_file_data('JavaScriptCore/wtf/TestName.h', 'h',
+ ['#ifndef BAD_TestName_h', '#define BAD_TestName_h'],
+ error_collector)
+ self.assertEquals(
+ 1,
+ error_collector.result_list().count(
+ '#ifndef header guard has wrong style, please use: WTF_TestName_h'
+ ' [build/header_guard] [5]'),
+ error_collector.result_list())
+
+ def test_build_printf_format(self):
+ self.assert_lint(
+ r'printf("\%%d", value);',
+ '%, [, (, and { are undefined character escapes. Unescape them.'
+ ' [build/printf_format] [3]')
+
+ self.assert_lint(
+ r'snprintf(buffer, sizeof(buffer), "\[%d", value);',
+ '%, [, (, and { are undefined character escapes. Unescape them.'
+ ' [build/printf_format] [3]')
+
+ self.assert_lint(
+ r'fprintf(file, "\(%d", value);',
+ '%, [, (, and { are undefined character escapes. Unescape them.'
+ ' [build/printf_format] [3]')
+
+ self.assert_lint(
+ r'vsnprintf(buffer, sizeof(buffer), "\\\{%d", ap);',
+ '%, [, (, and { are undefined character escapes. Unescape them.'
+ ' [build/printf_format] [3]')
+
+ # Don't warn if double-slash precedes the symbol
+ self.assert_lint(r'printf("\\%%%d", value);',
+ '')
+
+ def test_runtime_printf_format(self):
+ self.assert_lint(
+ r'fprintf(file, "%q", value);',
+ '%q in format strings is deprecated. Use %ll instead.'
+ ' [runtime/printf_format] [3]')
+
+ self.assert_lint(
+ r'aprintf(file, "The number is %12q", value);',
+ '%q in format strings is deprecated. Use %ll instead.'
+ ' [runtime/printf_format] [3]')
+
+ self.assert_lint(
+ r'printf(file, "The number is" "%-12q", value);',
+ '%q in format strings is deprecated. Use %ll instead.'
+ ' [runtime/printf_format] [3]')
+
+ self.assert_lint(
+ r'printf(file, "The number is" "%+12q", value);',
+ '%q in format strings is deprecated. Use %ll instead.'
+ ' [runtime/printf_format] [3]')
+
+ self.assert_lint(
+ r'printf(file, "The number is" "% 12q", value);',
+ '%q in format strings is deprecated. Use %ll instead.'
+ ' [runtime/printf_format] [3]')
+
+ self.assert_lint(
+ r'snprintf(file, "Never mix %d and %1$d parmaeters!", value);',
+ '%N$ formats are unconventional. Try rewriting to avoid them.'
+ ' [runtime/printf_format] [2]')
+
+ def assert_lintLogCodeOnError(self, code, expected_message):
+ # Special assert_lint which logs the input code on error.
+ result = self.perform_single_line_lint(code, 'foo.cpp')
+ if result != expected_message:
+ self.fail('For code: "%s"\nGot: "%s"\nExpected: "%s"'
+ % (code, result, expected_message))
+
+ def test_build_storage_class(self):
+ qualifiers = [None, 'const', 'volatile']
+ signs = [None, 'signed', 'unsigned']
+ types = ['void', 'char', 'int', 'float', 'double',
+ 'schar', 'int8', 'uint8', 'int16', 'uint16',
+ 'int32', 'uint32', 'int64', 'uint64']
+ storage_classes = ['auto', 'extern', 'register', 'static', 'typedef']
+
+ build_storage_class_error_message = (
+ 'Storage class (static, extern, typedef, etc) should be first.'
+ ' [build/storage_class] [5]')
+
+ # Some explicit cases. Legal in C++, deprecated in C99.
+ self.assert_lint('const int static foo = 5;',
+ build_storage_class_error_message)
+
+ self.assert_lint('char static foo;',
+ build_storage_class_error_message)
+
+ self.assert_lint('double const static foo = 2.0;',
+ build_storage_class_error_message)
+
+ self.assert_lint('uint64 typedef unsignedLongLong;',
+ build_storage_class_error_message)
+
+ self.assert_lint('int register foo = 0;',
+ build_storage_class_error_message)
+
+ # Since there are a very large number of possibilities, randomly
+ # construct declarations.
+ # Make sure that the declaration is logged if there's an error.
+ # Seed generator with an integer for absolute reproducibility.
+ random.seed(25)
+ for unused_i in range(10):
+ # Build up random list of non-storage-class declaration specs.
+ other_decl_specs = [random.choice(qualifiers), random.choice(signs),
+ random.choice(types)]
+ # remove None
+ other_decl_specs = filter(lambda x: x is not None, other_decl_specs)
+
+ # shuffle
+ random.shuffle(other_decl_specs)
+
+ # insert storage class after the first
+ storage_class = random.choice(storage_classes)
+ insertion_point = random.randint(1, len(other_decl_specs))
+ decl_specs = (other_decl_specs[0:insertion_point]
+ + [storage_class]
+ + other_decl_specs[insertion_point:])
+
+ self.assert_lintLogCodeOnError(
+ ' '.join(decl_specs) + ';',
+ build_storage_class_error_message)
+
+ # but no error if storage class is first
+ self.assert_lintLogCodeOnError(
+ storage_class + ' ' + ' '.join(other_decl_specs),
+ '')
+
+ def test_legal_copyright(self):
+ legal_copyright_message = (
+ 'No copyright message found. '
+ 'You should have a line: "Copyright [year] <Copyright Owner>"'
+ ' [legal/copyright] [5]')
+
+ copyright_line = '// Copyright 2008 Google Inc. All Rights Reserved.'
+
+ file_path = 'mydir/googleclient/foo.cpp'
+
+ # There should be a copyright message in the first 10 lines
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data(file_path, 'cpp', [], error_collector)
+ self.assertEquals(
+ 1,
+ error_collector.result_list().count(legal_copyright_message))
+
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data(
+ file_path, 'cpp',
+ ['' for unused_i in range(10)] + [copyright_line],
+ error_collector)
+ self.assertEquals(
+ 1,
+ error_collector.result_list().count(legal_copyright_message))
+
+ # Test that warning isn't issued if Copyright line appears early enough.
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data(file_path, 'cpp', [copyright_line], error_collector)
+ for message in error_collector.result_list():
+ if message.find('legal/copyright') != -1:
+ self.fail('Unexpected error: %s' % message)
+
+ error_collector = ErrorCollector(self.assert_)
+ self.process_file_data(
+ file_path, 'cpp',
+ ['' for unused_i in range(9)] + [copyright_line],
+ error_collector)
+ for message in error_collector.result_list():
+ if message.find('legal/copyright') != -1:
+ self.fail('Unexpected error: %s' % message)
+
+ def test_invalid_increment(self):
+ self.assert_lint('*count++;',
+ 'Changing pointer instead of value (or unused value of '
+ 'operator*). [runtime/invalid_increment] [5]')
+
+
+class CleansedLinesTest(unittest.TestCase):
+ def test_init(self):
+ lines = ['Line 1',
+ 'Line 2',
+ 'Line 3 // Comment test',
+ 'Line 4 "foo"']
+
+ clean_lines = cpp_style.CleansedLines(lines)
+ self.assertEquals(lines, clean_lines.raw_lines)
+ self.assertEquals(4, clean_lines.num_lines())
+
+ self.assertEquals(['Line 1',
+ 'Line 2',
+ 'Line 3 ',
+ 'Line 4 "foo"'],
+ clean_lines.lines)
+
+ self.assertEquals(['Line 1',
+ 'Line 2',
+ 'Line 3 ',
+ 'Line 4 ""'],
+ clean_lines.elided)
+
+ def test_init_empty(self):
+ clean_lines = cpp_style.CleansedLines([])
+ self.assertEquals([], clean_lines.raw_lines)
+ self.assertEquals(0, clean_lines.num_lines())
+
+ def test_collapse_strings(self):
+ collapse = cpp_style.CleansedLines.collapse_strings
+ self.assertEquals('""', collapse('""')) # "" (empty)
+ self.assertEquals('"""', collapse('"""')) # """ (bad)
+ self.assertEquals('""', collapse('"xyz"')) # "xyz" (string)
+ self.assertEquals('""', collapse('"\\\""')) # "\"" (string)
+ self.assertEquals('""', collapse('"\'"')) # "'" (string)
+ self.assertEquals('"\"', collapse('"\"')) # "\" (bad)
+ self.assertEquals('""', collapse('"\\\\"')) # "\\" (string)
+ self.assertEquals('"', collapse('"\\\\\\"')) # "\\\" (bad)
+ self.assertEquals('""', collapse('"\\\\\\\\"')) # "\\\\" (string)
+
+ self.assertEquals('\'\'', collapse('\'\'')) # '' (empty)
+ self.assertEquals('\'\'', collapse('\'a\'')) # 'a' (char)
+ self.assertEquals('\'\'', collapse('\'\\\'\'')) # '\'' (char)
+ self.assertEquals('\'', collapse('\'\\\'')) # '\' (bad)
+ self.assertEquals('', collapse('\\012')) # '\012' (char)
+ self.assertEquals('', collapse('\\xfF0')) # '\xfF0' (char)
+ self.assertEquals('', collapse('\\n')) # '\n' (char)
+ self.assertEquals('\#', collapse('\\#')) # '\#' (bad)
+
+ self.assertEquals('StringReplace(body, "", "");',
+ collapse('StringReplace(body, "\\\\", "\\\\\\\\");'))
+ self.assertEquals('\'\' ""',
+ collapse('\'"\' "foo"'))
+
+
+class OrderOfIncludesTest(CppStyleTestBase):
+ def setUp(self):
+ self.include_state = cpp_style._IncludeState()
+
+ # Cheat os.path.abspath called in FileInfo class.
+ self.os_path_abspath_orig = os.path.abspath
+ os.path.abspath = lambda value: value
+
+ def tearDown(self):
+ os.path.abspath = self.os_path_abspath_orig
+
+ def test_try_drop_common_suffixes(self):
+ self.assertEqual('foo/foo', cpp_style._drop_common_suffixes('foo/foo-inl.h'))
+ self.assertEqual('foo/bar/foo',
+ cpp_style._drop_common_suffixes('foo/bar/foo_inl.h'))
+ self.assertEqual('foo/foo', cpp_style._drop_common_suffixes('foo/foo.cpp'))
+ self.assertEqual('foo/foo_unusualinternal',
+ cpp_style._drop_common_suffixes('foo/foo_unusualinternal.h'))
+ self.assertEqual('',
+ cpp_style._drop_common_suffixes('_test.cpp'))
+ self.assertEqual('test',
+ cpp_style._drop_common_suffixes('test.cpp'))
+
+
+class OrderOfIncludesTest(CppStyleTestBase):
+ def setUp(self):
+ self.include_state = cpp_style._IncludeState()
+
+ # Cheat os.path.abspath called in FileInfo class.
+ self.os_path_abspath_orig = os.path.abspath
+ os.path.abspath = lambda value: value
+
+ def tearDown(self):
+ os.path.abspath = self.os_path_abspath_orig
+
+ def test_check_next_include_order__no_config(self):
+ self.assertEqual('Header file should not contain WebCore config.h.',
+ self.include_state.check_next_include_order(cpp_style._CONFIG_HEADER, True))
+
+ def test_check_next_include_order__no_self(self):
+ self.assertEqual('Header file should not contain itself.',
+ self.include_state.check_next_include_order(cpp_style._PRIMARY_HEADER, True))
+ # Test actual code to make sure that header types are correctly assigned.
+ self.assert_language_rules_check('Foo.h',
+ '#include "Foo.h"\n',
+ 'Header file should not contain itself. Should be: alphabetically sorted.'
+ ' [build/include_order] [4]')
+ self.assert_language_rules_check('FooBar.h',
+ '#include "Foo.h"\n',
+ '')
+
+ def test_check_next_include_order__likely_then_config(self):
+ self.assertEqual('Found header this file implements before WebCore config.h.',
+ self.include_state.check_next_include_order(cpp_style._PRIMARY_HEADER, False))
+ self.assertEqual('Found WebCore config.h after a header this file implements.',
+ self.include_state.check_next_include_order(cpp_style._CONFIG_HEADER, False))
+
+ def test_check_next_include_order__other_then_config(self):
+ self.assertEqual('Found other header before WebCore config.h.',
+ self.include_state.check_next_include_order(cpp_style._OTHER_HEADER, False))
+ self.assertEqual('Found WebCore config.h after other header.',
+ self.include_state.check_next_include_order(cpp_style._CONFIG_HEADER, False))
+
+ def test_check_next_include_order__config_then_other_then_likely(self):
+ self.assertEqual('', self.include_state.check_next_include_order(cpp_style._CONFIG_HEADER, False))
+ self.assertEqual('Found other header before a header this file implements.',
+ self.include_state.check_next_include_order(cpp_style._OTHER_HEADER, False))
+ self.assertEqual('Found header this file implements after other header.',
+ self.include_state.check_next_include_order(cpp_style._PRIMARY_HEADER, False))
+
+ def test_check_alphabetical_include_order(self):
+ self.assert_language_rules_check('foo.h',
+ '#include "a.h"\n'
+ '#include "c.h"\n'
+ '#include "b.h"\n',
+ 'Alphabetical sorting problem. [build/include_order] [4]')
+
+ self.assert_language_rules_check('foo.h',
+ '#include "a.h"\n'
+ '#include "b.h"\n'
+ '#include "c.h"\n',
+ '')
+
+ self.assert_language_rules_check('foo.h',
+ '#include <assert.h>\n'
+ '#include "bar.h"\n',
+ 'Alphabetical sorting problem. [build/include_order] [4]')
+
+ self.assert_language_rules_check('foo.h',
+ '#include "bar.h"\n'
+ '#include <assert.h>\n',
+ '')
+
+ def test_check_line_break_after_own_header(self):
+ self.assert_language_rules_check('foo.cpp',
+ '#include "config.h"\n'
+ '#include "foo.h"\n'
+ '#include "bar.h"\n',
+ 'You should add a blank line after implementation file\'s own header. [build/include_order] [4]')
+
+ self.assert_language_rules_check('foo.cpp',
+ '#include "config.h"\n'
+ '#include "foo.h"\n'
+ '\n'
+ '#include "bar.h"\n',
+ '')
+
+ def test_check_preprocessor_in_include_section(self):
+ self.assert_language_rules_check('foo.cpp',
+ '#include "config.h"\n'
+ '#include "foo.h"\n'
+ '\n'
+ '#ifdef BAZ\n'
+ '#include "baz.h"\n'
+ '#else\n'
+ '#include "foobar.h"\n'
+ '#endif"\n'
+ '#include "bar.h"\n', # No flag because previous is in preprocessor section
+ '')
+
+ self.assert_language_rules_check('foo.cpp',
+ '#include "config.h"\n'
+ '#include "foo.h"\n'
+ '\n'
+ '#ifdef BAZ\n'
+ '#include "baz.h"\n'
+ '#endif"\n'
+ '#include "bar.h"\n'
+ '#include "a.h"\n', # Should still flag this.
+ 'Alphabetical sorting problem. [build/include_order] [4]')
+
+ self.assert_language_rules_check('foo.cpp',
+ '#include "config.h"\n'
+ '#include "foo.h"\n'
+ '\n'
+ '#ifdef BAZ\n'
+ '#include "baz.h"\n'
+ '#include "bar.h"\n' #Should still flag this
+ '#endif"\n',
+ 'Alphabetical sorting problem. [build/include_order] [4]')
+
+ self.assert_language_rules_check('foo.cpp',
+ '#include "config.h"\n'
+ '#include "foo.h"\n'
+ '\n'
+ '#ifdef BAZ\n'
+ '#include "baz.h"\n'
+ '#endif"\n'
+ '#ifdef FOOBAR\n'
+ '#include "foobar.h"\n'
+ '#endif"\n'
+ '#include "bar.h"\n'
+ '#include "a.h"\n', # Should still flag this.
+ 'Alphabetical sorting problem. [build/include_order] [4]')
+
+ # Check that after an already included error, the sorting rules still work.
+ self.assert_language_rules_check('foo.cpp',
+ '#include "config.h"\n'
+ '#include "foo.h"\n'
+ '\n'
+ '#include "foo.h"\n'
+ '#include "g.h"\n',
+ '"foo.h" already included at foo.cpp:2 [build/include] [4]')
+
+ def test_check_wtf_includes(self):
+ self.assert_language_rules_check('foo.cpp',
+ '#include "config.h"\n'
+ '#include "foo.h"\n'
+ '\n'
+ '#include <wtf/Assertions.h>\n',
+ '')
+ self.assert_language_rules_check('foo.cpp',
+ '#include "config.h"\n'
+ '#include "foo.h"\n'
+ '\n'
+ '#include "wtf/Assertions.h"\n',
+ 'wtf includes should be <wtf/file.h> instead of "wtf/file.h".'
+ ' [build/include] [4]')
+
+ def test_classify_include(self):
+ classify_include = cpp_style._classify_include
+ include_state = cpp_style._IncludeState()
+ self.assertEqual(cpp_style._CONFIG_HEADER,
+ classify_include('foo/foo.cpp',
+ 'config.h',
+ False, include_state))
+ self.assertEqual(cpp_style._PRIMARY_HEADER,
+ classify_include('foo/internal/foo.cpp',
+ 'foo/public/foo.h',
+ False, include_state))
+ self.assertEqual(cpp_style._PRIMARY_HEADER,
+ classify_include('foo/internal/foo.cpp',
+ 'foo/other/public/foo.h',
+ False, include_state))
+ self.assertEqual(cpp_style._OTHER_HEADER,
+ classify_include('foo/internal/foo.cpp',
+ 'foo/other/public/foop.h',
+ False, include_state))
+ self.assertEqual(cpp_style._OTHER_HEADER,
+ classify_include('foo/foo.cpp',
+ 'string',
+ True, include_state))
+ self.assertEqual(cpp_style._PRIMARY_HEADER,
+ classify_include('fooCustom.cpp',
+ 'foo.h',
+ False, include_state))
+ self.assertEqual(cpp_style._PRIMARY_HEADER,
+ classify_include('PrefixFooCustom.cpp',
+ 'Foo.h',
+ False, include_state))
+ self.assertEqual(cpp_style._MOC_HEADER,
+ classify_include('foo.cpp',
+ 'foo.moc',
+ False, include_state))
+ self.assertEqual(cpp_style._MOC_HEADER,
+ classify_include('foo.cpp',
+ 'moc_foo.cpp',
+ False, include_state))
+ # Tricky example where both includes might be classified as primary.
+ self.assert_language_rules_check('ScrollbarThemeWince.cpp',
+ '#include "config.h"\n'
+ '#include "ScrollbarThemeWince.h"\n'
+ '\n'
+ '#include "Scrollbar.h"\n',
+ '')
+ self.assert_language_rules_check('ScrollbarThemeWince.cpp',
+ '#include "config.h"\n'
+ '#include "Scrollbar.h"\n'
+ '\n'
+ '#include "ScrollbarThemeWince.h"\n',
+ 'Found header this file implements after a header this file implements.'
+ ' Should be: config.h, primary header, blank line, and then alphabetically sorted.'
+ ' [build/include_order] [4]')
+ self.assert_language_rules_check('ResourceHandleWin.cpp',
+ '#include "config.h"\n'
+ '#include "ResourceHandle.h"\n'
+ '\n'
+ '#include "ResourceHandleWin.h"\n',
+ '')
+
+ def test_try_drop_common_suffixes(self):
+ self.assertEqual('foo/foo', cpp_style._drop_common_suffixes('foo/foo-inl.h'))
+ self.assertEqual('foo/bar/foo',
+ cpp_style._drop_common_suffixes('foo/bar/foo_inl.h'))
+ self.assertEqual('foo/foo', cpp_style._drop_common_suffixes('foo/foo.cpp'))
+ self.assertEqual('foo/foo_unusualinternal',
+ cpp_style._drop_common_suffixes('foo/foo_unusualinternal.h'))
+ self.assertEqual('',
+ cpp_style._drop_common_suffixes('_test.cpp'))
+ self.assertEqual('test',
+ cpp_style._drop_common_suffixes('test.cpp'))
+ self.assertEqual('test',
+ cpp_style._drop_common_suffixes('test.cpp'))
+
+class CheckForFunctionLengthsTest(CppStyleTestBase):
+ def setUp(self):
+ # Reducing these thresholds for the tests speeds up tests significantly.
+ self.old_normal_trigger = cpp_style._FunctionState._NORMAL_TRIGGER
+ self.old_test_trigger = cpp_style._FunctionState._TEST_TRIGGER
+
+ cpp_style._FunctionState._NORMAL_TRIGGER = 10
+ cpp_style._FunctionState._TEST_TRIGGER = 25
+
+ def tearDown(self):
+ cpp_style._FunctionState._NORMAL_TRIGGER = self.old_normal_trigger
+ cpp_style._FunctionState._TEST_TRIGGER = self.old_test_trigger
+
+ # FIXME: Eliminate the need for this function.
+ def set_min_confidence(self, min_confidence):
+ """Set new test confidence and return old test confidence."""
+ old_min_confidence = self.min_confidence
+ self.min_confidence = min_confidence
+ return old_min_confidence
+
+ def assert_function_lengths_check(self, code, expected_message):
+ """Check warnings for long function bodies are as expected.
+
+ Args:
+ code: C++ source code expected to generate a warning message.
+ expected_message: Message expected to be generated by the C++ code.
+ """
+ self.assertEquals(expected_message,
+ self.perform_function_lengths_check(code))
+
+ def trigger_lines(self, error_level):
+ """Return number of lines needed to trigger a function length warning.
+
+ Args:
+ error_level: --v setting for cpp_style.
+
+ Returns:
+ Number of lines needed to trigger a function length warning.
+ """
+ return cpp_style._FunctionState._NORMAL_TRIGGER * 2 ** error_level
+
+ def trigger_test_lines(self, error_level):
+ """Return number of lines needed to trigger a test function length warning.
+
+ Args:
+ error_level: --v setting for cpp_style.
+
+ Returns:
+ Number of lines needed to trigger a test function length warning.
+ """
+ return cpp_style._FunctionState._TEST_TRIGGER * 2 ** error_level
+
+ def assert_function_length_check_definition(self, lines, error_level):
+ """Generate long function definition and check warnings are as expected.
+
+ Args:
+ lines: Number of lines to generate.
+ error_level: --v setting for cpp_style.
+ """
+ trigger_level = self.trigger_lines(self.min_confidence)
+ self.assert_function_lengths_check(
+ 'void test(int x)' + self.function_body(lines),
+ ('Small and focused functions are preferred: '
+ 'test() has %d non-comment lines '
+ '(error triggered by exceeding %d lines).'
+ ' [readability/fn_size] [%d]'
+ % (lines, trigger_level, error_level)))
+
+ def assert_function_length_check_definition_ok(self, lines):
+ """Generate shorter function definition and check no warning is produced.
+
+ Args:
+ lines: Number of lines to generate.
+ """
+ self.assert_function_lengths_check(
+ 'void test(int x)' + self.function_body(lines),
+ '')
+
+ def assert_function_length_check_at_error_level(self, error_level):
+ """Generate and check function at the trigger level for --v setting.
+
+ Args:
+ error_level: --v setting for cpp_style.
+ """
+ self.assert_function_length_check_definition(self.trigger_lines(error_level),
+ error_level)
+
+ def assert_function_length_check_below_error_level(self, error_level):
+ """Generate and check function just below the trigger level for --v setting.
+
+ Args:
+ error_level: --v setting for cpp_style.
+ """
+ self.assert_function_length_check_definition(self.trigger_lines(error_level) - 1,
+ error_level - 1)
+
+ def assert_function_length_check_above_error_level(self, error_level):
+ """Generate and check function just above the trigger level for --v setting.
+
+ Args:
+ error_level: --v setting for cpp_style.
+ """
+ self.assert_function_length_check_definition(self.trigger_lines(error_level) + 1,
+ error_level)
+
+ def function_body(self, number_of_lines):
+ return ' {\n' + ' this_is_just_a_test();\n' * number_of_lines + '}'
+
+ def function_body_with_blank_lines(self, number_of_lines):
+ return ' {\n' + ' this_is_just_a_test();\n\n' * number_of_lines + '}'
+
+ def function_body_with_no_lints(self, number_of_lines):
+ return ' {\n' + ' this_is_just_a_test(); // NOLINT\n' * number_of_lines + '}'
+
+ # Test line length checks.
+ def test_function_length_check_declaration(self):
+ self.assert_function_lengths_check(
+ 'void test();', # Not a function definition
+ '')
+
+ def test_function_length_check_declaration_with_block_following(self):
+ self.assert_function_lengths_check(
+ ('void test();\n'
+ + self.function_body(66)), # Not a function definition
+ '')
+
+ def test_function_length_check_class_definition(self):
+ self.assert_function_lengths_check( # Not a function definition
+ 'class Test' + self.function_body(66) + ';',
+ '')
+
+ def test_function_length_check_trivial(self):
+ self.assert_function_lengths_check(
+ 'void test() {}', # Not counted
+ '')
+
+ def test_function_length_check_empty(self):
+ self.assert_function_lengths_check(
+ 'void test() {\n}',
+ '')
+
+ def test_function_length_check_definition_below_severity0(self):
+ old_min_confidence = self.set_min_confidence(0)
+ self.assert_function_length_check_definition_ok(self.trigger_lines(0) - 1)
+ self.set_min_confidence(old_min_confidence)
+
+ def test_function_length_check_definition_at_severity0(self):
+ old_min_confidence = self.set_min_confidence(0)
+ self.assert_function_length_check_definition_ok(self.trigger_lines(0))
+ self.set_min_confidence(old_min_confidence)
+
+ def test_function_length_check_definition_above_severity0(self):
+ old_min_confidence = self.set_min_confidence(0)
+ self.assert_function_length_check_above_error_level(0)
+ self.set_min_confidence(old_min_confidence)
+
+ def test_function_length_check_definition_below_severity1v0(self):
+ old_min_confidence = self.set_min_confidence(0)
+ self.assert_function_length_check_below_error_level(1)
+ self.set_min_confidence(old_min_confidence)
+
+ def test_function_length_check_definition_at_severity1v0(self):
+ old_min_confidence = self.set_min_confidence(0)
+ self.assert_function_length_check_at_error_level(1)
+ self.set_min_confidence(old_min_confidence)
+
+ def test_function_length_check_definition_below_severity1(self):
+ self.assert_function_length_check_definition_ok(self.trigger_lines(1) - 1)
+
+ def test_function_length_check_definition_at_severity1(self):
+ self.assert_function_length_check_definition_ok(self.trigger_lines(1))
+
+ def test_function_length_check_definition_above_severity1(self):
+ self.assert_function_length_check_above_error_level(1)
+
+ def test_function_length_check_definition_severity1_plus_indented(self):
+ error_level = 1
+ error_lines = self.trigger_lines(error_level) + 1
+ trigger_level = self.trigger_lines(self.min_confidence)
+ indent_spaces = ' '
+ self.assert_function_lengths_check(
+ re.sub(r'(?m)^(.)', indent_spaces + r'\1',
+ 'void test_indent(int x)\n' + self.function_body(error_lines)),
+ ('Small and focused functions are preferred: '
+ 'test_indent() has %d non-comment lines '
+ '(error triggered by exceeding %d lines).'
+ ' [readability/fn_size] [%d]')
+ % (error_lines, trigger_level, error_level))
+
+ def test_function_length_check_definition_severity1_plus_blanks(self):
+ error_level = 1
+ error_lines = self.trigger_lines(error_level) + 1
+ trigger_level = self.trigger_lines(self.min_confidence)
+ self.assert_function_lengths_check(
+ 'void test_blanks(int x)' + self.function_body(error_lines),
+ ('Small and focused functions are preferred: '
+ 'test_blanks() has %d non-comment lines '
+ '(error triggered by exceeding %d lines).'
+ ' [readability/fn_size] [%d]')
+ % (error_lines, trigger_level, error_level))
+
+ def test_function_length_check_complex_definition_severity1(self):
+ error_level = 1
+ error_lines = self.trigger_lines(error_level) + 1
+ trigger_level = self.trigger_lines(self.min_confidence)
+ self.assert_function_lengths_check(
+ ('my_namespace::my_other_namespace::MyVeryLongTypeName<Type1, bool func(const Element*)>*\n'
+ 'my_namespace::my_other_namespace<Type3, Type4>::~MyFunction<Type5<Type6, Type7> >(int arg1, char* arg2)'
+ + self.function_body(error_lines)),
+ ('Small and focused functions are preferred: '
+ 'my_namespace::my_other_namespace<Type3, Type4>::~MyFunction<Type5<Type6, Type7> >()'
+ ' has %d non-comment lines '
+ '(error triggered by exceeding %d lines).'
+ ' [readability/fn_size] [%d]')
+ % (error_lines, trigger_level, error_level))
+
+ def test_function_length_check_definition_severity1_for_test(self):
+ error_level = 1
+ error_lines = self.trigger_test_lines(error_level) + 1
+ trigger_level = self.trigger_test_lines(self.min_confidence)
+ self.assert_function_lengths_check(
+ 'TEST_F(Test, Mutator)' + self.function_body(error_lines),
+ ('Small and focused functions are preferred: '
+ 'TEST_F(Test, Mutator) has %d non-comment lines '
+ '(error triggered by exceeding %d lines).'
+ ' [readability/fn_size] [%d]')
+ % (error_lines, trigger_level, error_level))
+
+ def test_function_length_check_definition_severity1_for_split_line_test(self):
+ error_level = 1
+ error_lines = self.trigger_test_lines(error_level) + 1
+ trigger_level = self.trigger_test_lines(self.min_confidence)
+ self.assert_function_lengths_check(
+ ('TEST_F(GoogleUpdateRecoveryRegistryProtectedTest,\n'
+ ' FixGoogleUpdate_AllValues_MachineApp)' # note: 4 spaces
+ + self.function_body(error_lines)),
+ ('Small and focused functions are preferred: '
+ 'TEST_F(GoogleUpdateRecoveryRegistryProtectedTest, ' # 1 space
+ 'FixGoogleUpdate_AllValues_MachineApp) has %d non-comment lines '
+ '(error triggered by exceeding %d lines).'
+ ' [readability/fn_size] [%d]')
+ % (error_lines, trigger_level, error_level))
+
+ def test_function_length_check_definition_severity1_for_bad_test_doesnt_break(self):
+ error_level = 1
+ error_lines = self.trigger_test_lines(error_level) + 1
+ trigger_level = self.trigger_test_lines(self.min_confidence)
+ self.assert_function_lengths_check(
+ ('TEST_F('
+ + self.function_body(error_lines)),
+ ('Small and focused functions are preferred: '
+ 'TEST_F has %d non-comment lines '
+ '(error triggered by exceeding %d lines).'
+ ' [readability/fn_size] [%d]')
+ % (error_lines, trigger_level, error_level))
+
+ def test_function_length_check_definition_severity1_with_embedded_no_lints(self):
+ error_level = 1
+ error_lines = self.trigger_lines(error_level) + 1
+ trigger_level = self.trigger_lines(self.min_confidence)
+ self.assert_function_lengths_check(
+ 'void test(int x)' + self.function_body_with_no_lints(error_lines),
+ ('Small and focused functions are preferred: '
+ 'test() has %d non-comment lines '
+ '(error triggered by exceeding %d lines).'
+ ' [readability/fn_size] [%d]')
+ % (error_lines, trigger_level, error_level))
+
+ def test_function_length_check_definition_severity1_with_no_lint(self):
+ self.assert_function_lengths_check(
+ ('void test(int x)' + self.function_body(self.trigger_lines(1))
+ + ' // NOLINT -- long function'),
+ '')
+
+ def test_function_length_check_definition_below_severity2(self):
+ self.assert_function_length_check_below_error_level(2)
+
+ def test_function_length_check_definition_severity2(self):
+ self.assert_function_length_check_at_error_level(2)
+
+ def test_function_length_check_definition_above_severity2(self):
+ self.assert_function_length_check_above_error_level(2)
+
+ def test_function_length_check_definition_below_severity3(self):
+ self.assert_function_length_check_below_error_level(3)
+
+ def test_function_length_check_definition_severity3(self):
+ self.assert_function_length_check_at_error_level(3)
+
+ def test_function_length_check_definition_above_severity3(self):
+ self.assert_function_length_check_above_error_level(3)
+
+ def test_function_length_check_definition_below_severity4(self):
+ self.assert_function_length_check_below_error_level(4)
+
+ def test_function_length_check_definition_severity4(self):
+ self.assert_function_length_check_at_error_level(4)
+
+ def test_function_length_check_definition_above_severity4(self):
+ self.assert_function_length_check_above_error_level(4)
+
+ def test_function_length_check_definition_below_severity5(self):
+ self.assert_function_length_check_below_error_level(5)
+
+ def test_function_length_check_definition_at_severity5(self):
+ self.assert_function_length_check_at_error_level(5)
+
+ def test_function_length_check_definition_above_severity5(self):
+ self.assert_function_length_check_above_error_level(5)
+
+ def test_function_length_check_definition_huge_lines(self):
+ # 5 is the limit
+ self.assert_function_length_check_definition(self.trigger_lines(10), 5)
+
+ def test_function_length_not_determinable(self):
+ # Macro invocation without terminating semicolon.
+ self.assert_function_lengths_check(
+ 'MACRO(arg)',
+ '')
+
+ # Macro with underscores
+ self.assert_function_lengths_check(
+ 'MACRO_WITH_UNDERSCORES(arg1, arg2, arg3)',
+ '')
+
+ self.assert_function_lengths_check(
+ 'NonMacro(arg)',
+ 'Lint failed to find start of function body.'
+ ' [readability/fn_size] [5]')
+
+
+class NoNonVirtualDestructorsTest(CppStyleTestBase):
+
+ def test_no_error(self):
+ self.assert_multi_line_lint(
+ '''class Foo {
+ virtual ~Foo();
+ virtual void foo();
+ };''',
+ '')
+
+ self.assert_multi_line_lint(
+ '''class Foo {
+ virtual inline ~Foo();
+ virtual void foo();
+ };''',
+ '')
+
+ self.assert_multi_line_lint(
+ '''class Foo {
+ inline virtual ~Foo();
+ virtual void foo();
+ };''',
+ '')
+
+ self.assert_multi_line_lint(
+ '''class Foo::Goo {
+ virtual ~Goo();
+ virtual void goo();
+ };''',
+ '')
+ self.assert_multi_line_lint(
+ 'class Foo { void foo(); };',
+ 'More than one command on the same line [whitespace/newline] [4]')
+ self.assert_multi_line_lint(
+ 'class MyClass {\n'
+ ' int getIntValue() { ASSERT(m_ptr); return *m_ptr; }\n'
+ '};\n',
+ '')
+ self.assert_multi_line_lint(
+ 'class MyClass {\n'
+ ' int getIntValue()\n'
+ ' {\n'
+ ' ASSERT(m_ptr); return *m_ptr;\n'
+ ' }\n'
+ '};\n',
+ 'More than one command on the same line [whitespace/newline] [4]')
+
+ self.assert_multi_line_lint(
+ '''class Qualified::Goo : public Foo {
+ virtual void goo();
+ };''',
+ '')
+
+ self.assert_multi_line_lint(
+ # Line-ending :
+ '''class Goo :
+ public Foo {
+ virtual void goo();
+ };''',
+ 'Labels should always be indented at least one space. If this is a '
+ 'member-initializer list in a constructor, the colon should be on the '
+ 'line after the definition header. [whitespace/labels] [4]')
+
+ def test_no_destructor_when_virtual_needed(self):
+ self.assert_multi_line_lint_re(
+ '''class Foo {
+ virtual void foo();
+ };''',
+ 'The class Foo probably needs a virtual destructor')
+
+ def test_destructor_non_virtual_when_virtual_needed(self):
+ self.assert_multi_line_lint_re(
+ '''class Foo {
+ ~Foo();
+ virtual void foo();
+ };''',
+ 'The class Foo probably needs a virtual destructor')
+
+ def test_no_warn_when_derived(self):
+ self.assert_multi_line_lint(
+ '''class Foo : public Goo {
+ virtual void foo();
+ };''',
+ '')
+
+ def test_internal_braces(self):
+ self.assert_multi_line_lint_re(
+ '''class Foo {
+ enum Goo {
+ GOO
+ };
+ virtual void foo();
+ };''',
+ 'The class Foo probably needs a virtual destructor')
+
+ def test_inner_class_needs_virtual_destructor(self):
+ self.assert_multi_line_lint_re(
+ '''class Foo {
+ class Goo {
+ virtual void goo();
+ };
+ };''',
+ 'The class Goo probably needs a virtual destructor')
+
+ def test_outer_class_needs_virtual_destructor(self):
+ self.assert_multi_line_lint_re(
+ '''class Foo {
+ class Goo {
+ };
+ virtual void foo();
+ };''',
+ 'The class Foo probably needs a virtual destructor')
+
+ def test_qualified_class_needs_virtual_destructor(self):
+ self.assert_multi_line_lint_re(
+ '''class Qualified::Foo {
+ virtual void foo();
+ };''',
+ 'The class Qualified::Foo probably needs a virtual destructor')
+
+ def test_multi_line_declaration_no_error(self):
+ self.assert_multi_line_lint_re(
+ '''class Foo
+ : public Goo {
+ virtual void foo();
+ };''',
+ '')
+
+ def test_multi_line_declaration_with_error(self):
+ self.assert_multi_line_lint(
+ '''class Foo
+ {
+ virtual void foo();
+ };''',
+ ['This { should be at the end of the previous line '
+ '[whitespace/braces] [4]',
+ 'The class Foo probably needs a virtual destructor due to having '
+ 'virtual method(s), one declared at line 3. [runtime/virtual] [4]'])
+
+
+class PassPtrTest(CppStyleTestBase):
+ # For http://webkit.org/coding/RefPtr.html
+
+ def assert_pass_ptr_check(self, code, expected_message):
+ """Check warnings for Pass*Ptr are as expected.
+
+ Args:
+ code: C++ source code expected to generate a warning message.
+ expected_message: Message expected to be generated by the C++ code.
+ """
+ self.assertEquals(expected_message,
+ self.perform_pass_ptr_check(code))
+
+ def test_pass_ref_ptr_in_function(self):
+ # Local variables should never be PassRefPtr.
+ self.assert_pass_ptr_check(
+ 'int myFunction()\n'
+ '{\n'
+ ' PassRefPtr<Type1> variable = variable2;\n'
+ '}',
+ 'Local variables should never be PassRefPtr (see '
+ 'http://webkit.org/coding/RefPtr.html). [readability/pass_ptr] [5]')
+
+ def test_pass_own_ptr_in_function(self):
+ # Local variables should never be PassRefPtr.
+ self.assert_pass_ptr_check(
+ 'int myFunction()\n'
+ '{\n'
+ ' PassOwnPtr<Type1> variable = variable2;\n'
+ '}',
+ 'Local variables should never be PassOwnPtr (see '
+ 'http://webkit.org/coding/RefPtr.html). [readability/pass_ptr] [5]')
+
+ def test_pass_other_type_ptr_in_function(self):
+ # Local variables should never be PassRefPtr.
+ self.assert_pass_ptr_check(
+ 'int myFunction()\n'
+ '{\n'
+ ' PassOtherTypePtr<Type1> variable;\n'
+ '}',
+ 'Local variables should never be PassOtherTypePtr (see '
+ 'http://webkit.org/coding/RefPtr.html). [readability/pass_ptr] [5]')
+
+ def test_pass_ref_ptr_return_value(self):
+ self.assert_pass_ptr_check(
+ 'PassRefPtr<Type1>\n'
+ 'myFunction(int)\n'
+ '{\n'
+ '}',
+ '')
+ self.assert_pass_ptr_check(
+ 'PassRefPtr<Type1> myFunction(int)\n'
+ '{\n'
+ '}',
+ '')
+ self.assert_pass_ptr_check(
+ 'PassRefPtr<Type1> myFunction();\n',
+ '')
+
+ def test_pass_ref_ptr_parameter_value(self):
+ self.assert_pass_ptr_check(
+ 'int myFunction(PassRefPtr<Type1>)\n'
+ '{\n'
+ '}',
+ '')
+
+ def test_ref_ptr_member_variable(self):
+ self.assert_pass_ptr_check(
+ 'class Foo {'
+ ' RefPtr<Type1> m_other;\n'
+ '};\n',
+ '')
+
+
+class WebKitStyleTest(CppStyleTestBase):
+
+ # for http://webkit.org/coding/coding-style.html
+ def test_indentation(self):
+ # 1. Use spaces, not tabs. Tabs should only appear in files that
+ # require them for semantic meaning, like Makefiles.
+ self.assert_multi_line_lint(
+ 'class Foo {\n'
+ ' int goo;\n'
+ '};',
+ '')
+ self.assert_multi_line_lint(
+ 'class Foo {\n'
+ '\tint goo;\n'
+ '};',
+ 'Tab found; better to use spaces [whitespace/tab] [1]')
+
+ # 2. The indent size is 4 spaces.
+ self.assert_multi_line_lint(
+ 'class Foo {\n'
+ ' int goo;\n'
+ '};',
+ '')
+ self.assert_multi_line_lint(
+ 'class Foo {\n'
+ ' int goo;\n'
+ '};',
+ 'Weird number of spaces at line-start. Are you using a 4-space indent? [whitespace/indent] [3]')
+ # FIXME: No tests for 8-spaces.
+
+ # 3. In a header, code inside a namespace should not be indented.
+ self.assert_multi_line_lint(
+ 'namespace WebCore {\n\n'
+ 'class Document {\n'
+ ' int myVariable;\n'
+ '};\n'
+ '}',
+ '',
+ 'foo.h')
+ self.assert_multi_line_lint(
+ 'namespace OuterNamespace {\n'
+ ' namespace InnerNamespace {\n'
+ ' class Document {\n'
+ '};\n'
+ '};\n'
+ '}',
+ 'Code inside a namespace should not be indented. [whitespace/indent] [4]',
+ 'foo.h')
+ self.assert_multi_line_lint(
+ 'namespace OuterNamespace {\n'
+ ' class Document {\n'
+ ' namespace InnerNamespace {\n'
+ '};\n'
+ '};\n'
+ '}',
+ 'Code inside a namespace should not be indented. [whitespace/indent] [4]',
+ 'foo.h')
+ self.assert_multi_line_lint(
+ 'namespace WebCore {\n'
+ '#if 0\n'
+ ' class Document {\n'
+ '};\n'
+ '#endif\n'
+ '}',
+ 'Code inside a namespace should not be indented. [whitespace/indent] [4]',
+ 'foo.h')
+ self.assert_multi_line_lint(
+ 'namespace WebCore {\n'
+ 'class Document {\n'
+ '};\n'
+ '}',
+ '',
+ 'foo.h')
+
+ # 4. In an implementation file (files with the extension .cpp, .c
+ # or .mm), code inside a namespace should not be indented.
+ self.assert_multi_line_lint(
+ 'namespace WebCore {\n\n'
+ 'Document::Foo()\n'
+ ' : foo(bar)\n'
+ ' , boo(far)\n'
+ '{\n'
+ ' stuff();\n'
+ '}',
+ '',
+ 'foo.cpp')
+ self.assert_multi_line_lint(
+ 'namespace OuterNamespace {\n'
+ 'namespace InnerNamespace {\n'
+ 'Document::Foo() { }\n'
+ ' void* p;\n'
+ '}\n'
+ '}\n',
+ 'Code inside a namespace should not be indented. [whitespace/indent] [4]',
+ 'foo.cpp')
+ self.assert_multi_line_lint(
+ 'namespace OuterNamespace {\n'
+ 'namespace InnerNamespace {\n'
+ 'Document::Foo() { }\n'
+ '}\n'
+ ' void* p;\n'
+ '}\n',
+ 'Code inside a namespace should not be indented. [whitespace/indent] [4]',
+ 'foo.cpp')
+ self.assert_multi_line_lint(
+ 'namespace WebCore {\n\n'
+ ' const char* foo = "start:;"\n'
+ ' "dfsfsfs";\n'
+ '}\n',
+ 'Code inside a namespace should not be indented. [whitespace/indent] [4]',
+ 'foo.cpp')
+ self.assert_multi_line_lint(
+ 'namespace WebCore {\n\n'
+ 'const char* foo(void* a = ";", // ;\n'
+ ' void* b);\n'
+ ' void* p;\n'
+ '}\n',
+ 'Code inside a namespace should not be indented. [whitespace/indent] [4]',
+ 'foo.cpp')
+ self.assert_multi_line_lint(
+ 'namespace WebCore {\n\n'
+ 'const char* foo[] = {\n'
+ ' "void* b);", // ;\n'
+ ' "asfdf",\n'
+ ' }\n'
+ ' void* p;\n'
+ '}\n',
+ 'Code inside a namespace should not be indented. [whitespace/indent] [4]',
+ 'foo.cpp')
+ self.assert_multi_line_lint(
+ 'namespace WebCore {\n\n'
+ 'const char* foo[] = {\n'
+ ' "void* b);", // }\n'
+ ' "asfdf",\n'
+ ' }\n'
+ '}\n',
+ '',
+ 'foo.cpp')
+ self.assert_multi_line_lint(
+ ' namespace WebCore {\n\n'
+ ' void Document::Foo()\n'
+ ' {\n'
+ 'start: // infinite loops are fun!\n'
+ ' goto start;\n'
+ ' }',
+ 'namespace should never be indented. [whitespace/indent] [4]',
+ 'foo.cpp')
+ self.assert_multi_line_lint(
+ 'namespace WebCore {\n'
+ ' Document::Foo() { }\n'
+ '}',
+ 'Code inside a namespace should not be indented.'
+ ' [whitespace/indent] [4]',
+ 'foo.cpp')
+ self.assert_multi_line_lint(
+ 'namespace WebCore {\n'
+ '#define abc(x) x; \\\n'
+ ' x\n'
+ '}',
+ '',
+ 'foo.cpp')
+ self.assert_multi_line_lint(
+ 'namespace WebCore {\n'
+ '#define abc(x) x; \\\n'
+ ' x\n'
+ ' void* x;'
+ '}',
+ 'Code inside a namespace should not be indented. [whitespace/indent] [4]',
+ 'foo.cpp')
+
+ # 5. A case label should line up with its switch statement. The
+ # case statement is indented.
+ self.assert_multi_line_lint(
+ ' switch (condition) {\n'
+ ' case fooCondition:\n'
+ ' case barCondition:\n'
+ ' i++;\n'
+ ' break;\n'
+ ' default:\n'
+ ' i--;\n'
+ ' }\n',
+ '')
+ self.assert_multi_line_lint(
+ ' switch (condition) {\n'
+ ' case fooCondition:\n'
+ ' switch (otherCondition) {\n'
+ ' default:\n'
+ ' return;\n'
+ ' }\n'
+ ' default:\n'
+ ' i--;\n'
+ ' }\n',
+ '')
+ self.assert_multi_line_lint(
+ ' switch (condition) {\n'
+ ' case fooCondition: break;\n'
+ ' default: return;\n'
+ ' }\n',
+ '')
+ self.assert_multi_line_lint(
+ ' switch (condition) {\n'
+ ' case fooCondition:\n'
+ ' case barCondition:\n'
+ ' i++;\n'
+ ' break;\n'
+ ' default:\n'
+ ' i--;\n'
+ ' }\n',
+ 'A case label should not be indented, but line up with its switch statement.'
+ ' [whitespace/indent] [4]')
+ self.assert_multi_line_lint(
+ ' switch (condition) {\n'
+ ' case fooCondition:\n'
+ ' break;\n'
+ ' default:\n'
+ ' i--;\n'
+ ' }\n',
+ 'A case label should not be indented, but line up with its switch statement.'
+ ' [whitespace/indent] [4]')
+ self.assert_multi_line_lint(
+ ' switch (condition) {\n'
+ ' case fooCondition:\n'
+ ' case barCondition:\n'
+ ' switch (otherCondition) {\n'
+ ' default:\n'
+ ' return;\n'
+ ' }\n'
+ ' default:\n'
+ ' i--;\n'
+ ' }\n',
+ 'A case label should not be indented, but line up with its switch statement.'
+ ' [whitespace/indent] [4]')
+ self.assert_multi_line_lint(
+ ' switch (condition) {\n'
+ ' case fooCondition:\n'
+ ' case barCondition:\n'
+ ' i++;\n'
+ ' break;\n\n'
+ ' default:\n'
+ ' i--;\n'
+ ' }\n',
+ 'Non-label code inside switch statements should be indented.'
+ ' [whitespace/indent] [4]')
+ self.assert_multi_line_lint(
+ ' switch (condition) {\n'
+ ' case fooCondition:\n'
+ ' case barCondition:\n'
+ ' switch (otherCondition) {\n'
+ ' default:\n'
+ ' return;\n'
+ ' }\n'
+ ' default:\n'
+ ' i--;\n'
+ ' }\n',
+ 'Non-label code inside switch statements should be indented.'
+ ' [whitespace/indent] [4]')
+
+ # 6. Boolean expressions at the same nesting level that span
+ # multiple lines should have their operators on the left side of
+ # the line instead of the right side.
+ self.assert_multi_line_lint(
+ ' return attr->name() == srcAttr\n'
+ ' || attr->name() == lowsrcAttr;\n',
+ '')
+ self.assert_multi_line_lint(
+ ' return attr->name() == srcAttr ||\n'
+ ' attr->name() == lowsrcAttr;\n',
+ 'Boolean expressions that span multiple lines should have their '
+ 'operators on the left side of the line instead of the right side.'
+ ' [whitespace/operators] [4]')
+
+ def test_spacing(self):
+ # 1. Do not place spaces around unary operators.
+ self.assert_multi_line_lint(
+ 'i++;',
+ '')
+ self.assert_multi_line_lint(
+ 'i ++;',
+ 'Extra space for operator ++; [whitespace/operators] [4]')
+
+ # 2. Do place spaces around binary and ternary operators.
+ self.assert_multi_line_lint(
+ 'y = m * x + b;',
+ '')
+ self.assert_multi_line_lint(
+ 'f(a, b);',
+ '')
+ self.assert_multi_line_lint(
+ 'c = a | b;',
+ '')
+ self.assert_multi_line_lint(
+ 'return condition ? 1 : 0;',
+ '')
+ self.assert_multi_line_lint(
+ 'y=m*x+b;',
+ 'Missing spaces around = [whitespace/operators] [4]')
+ self.assert_multi_line_lint(
+ 'f(a,b);',
+ 'Missing space after , [whitespace/comma] [3]')
+ self.assert_multi_line_lint(
+ 'c = a|b;',
+ 'Missing spaces around | [whitespace/operators] [3]')
+ # FIXME: We cannot catch this lint error.
+ # self.assert_multi_line_lint(
+ # 'return condition ? 1:0;',
+ # '')
+
+ # 3. Place spaces between control statements and their parentheses.
+ self.assert_multi_line_lint(
+ ' if (condition)\n'
+ ' doIt();\n',
+ '')
+ self.assert_multi_line_lint(
+ ' if(condition)\n'
+ ' doIt();\n',
+ 'Missing space before ( in if( [whitespace/parens] [5]')
+
+ # 4. Do not place spaces between a function and its parentheses,
+ # or between a parenthesis and its content.
+ self.assert_multi_line_lint(
+ 'f(a, b);',
+ '')
+ self.assert_multi_line_lint(
+ 'f (a, b);',
+ 'Extra space before ( in function call [whitespace/parens] [4]')
+ self.assert_multi_line_lint(
+ 'f( a, b );',
+ ['Extra space after ( in function call [whitespace/parens] [4]',
+ 'Extra space before ) [whitespace/parens] [2]'])
+
+ def test_line_breaking(self):
+ # 1. Each statement should get its own line.
+ self.assert_multi_line_lint(
+ ' x++;\n'
+ ' y++;\n'
+ ' if (condition);\n'
+ ' doIt();\n',
+ '')
+ self.assert_multi_line_lint(
+ ' if (condition) \\\n'
+ ' doIt();\n',
+ '')
+ self.assert_multi_line_lint(
+ ' x++; y++;',
+ 'More than one command on the same line [whitespace/newline] [4]')
+ self.assert_multi_line_lint(
+ ' if (condition) doIt();\n',
+ 'More than one command on the same line in if [whitespace/parens] [4]')
+ # Ensure that having a # in the line doesn't hide the error.
+ self.assert_multi_line_lint(
+ ' x++; char a[] = "#";',
+ 'More than one command on the same line [whitespace/newline] [4]')
+ # Ignore preprocessor if's.
+ self.assert_multi_line_lint(
+ ' #if (condition) || (condition2)\n',
+ '')
+
+ # 2. An else statement should go on the same line as a preceding
+ # close brace if one is present, else it should line up with the
+ # if statement.
+ self.assert_multi_line_lint(
+ 'if (condition) {\n'
+ ' doSomething();\n'
+ ' doSomethingAgain();\n'
+ '} else {\n'
+ ' doSomethingElse();\n'
+ ' doSomethingElseAgain();\n'
+ '}\n',
+ '')
+ self.assert_multi_line_lint(
+ 'if (condition)\n'
+ ' doSomething();\n'
+ 'else\n'
+ ' doSomethingElse();\n',
+ '')
+ self.assert_multi_line_lint(
+ 'if (condition)\n'
+ ' doSomething();\n'
+ 'else {\n'
+ ' doSomethingElse();\n'
+ ' doSomethingElseAgain();\n'
+ '}\n',
+ '')
+ self.assert_multi_line_lint(
+ '#define TEST_ASSERT(expression) do { if (!(expression)) { TestsController::shared().testFailed(__FILE__, __LINE__, #expression); return; } } while (0)\n',
+ '')
+ self.assert_multi_line_lint(
+ '#define TEST_ASSERT(expression) do { if ( !(expression)) { TestsController::shared().testFailed(__FILE__, __LINE__, #expression); return; } } while (0)\n',
+ 'Extra space after ( in if [whitespace/parens] [5]')
+ # FIXME: currently we only check first conditional, so we cannot detect errors in next ones.
+ # self.assert_multi_line_lint(
+ # '#define TEST_ASSERT(expression) do { if (!(expression)) { TestsController::shared().testFailed(__FILE__, __LINE__, #expression); return; } } while (0 )\n',
+ # 'Mismatching spaces inside () in if [whitespace/parens] [5]')
+ self.assert_multi_line_lint(
+ 'if (condition) {\n'
+ ' doSomething();\n'
+ ' doSomethingAgain();\n'
+ '}\n'
+ 'else {\n'
+ ' doSomethingElse();\n'
+ ' doSomethingElseAgain();\n'
+ '}\n',
+ 'An else should appear on the same line as the preceding } [whitespace/newline] [4]')
+ self.assert_multi_line_lint(
+ 'if (condition) doSomething(); else doSomethingElse();\n',
+ ['More than one command on the same line [whitespace/newline] [4]',
+ 'Else clause should never be on same line as else (use 2 lines) [whitespace/newline] [4]',
+ 'More than one command on the same line in if [whitespace/parens] [4]'])
+ self.assert_multi_line_lint(
+ 'if (condition) doSomething(); else {\n'
+ ' doSomethingElse();\n'
+ '}\n',
+ ['More than one command on the same line in if [whitespace/parens] [4]',
+ 'One line control clauses should not use braces. [whitespace/braces] [4]'])
+ self.assert_multi_line_lint(
+ 'void func()\n'
+ '{\n'
+ ' while (condition) { }\n'
+ ' return 0;\n'
+ '}\n',
+ '')
+ self.assert_multi_line_lint(
+ 'void func()\n'
+ '{\n'
+ ' for (i = 0; i < 42; i++) { foobar(); }\n'
+ ' return 0;\n'
+ '}\n',
+ 'More than one command on the same line in for [whitespace/parens] [4]')
+
+ # 3. An else if statement should be written as an if statement
+ # when the prior if concludes with a return statement.
+ self.assert_multi_line_lint(
+ 'if (motivated) {\n'
+ ' if (liquid)\n'
+ ' return money;\n'
+ '} else if (tired)\n'
+ ' break;\n',
+ '')
+ self.assert_multi_line_lint(
+ 'if (condition)\n'
+ ' doSomething();\n'
+ 'else if (otherCondition)\n'
+ ' doSomethingElse();\n',
+ '')
+ self.assert_multi_line_lint(
+ 'if (condition)\n'
+ ' doSomething();\n'
+ 'else\n'
+ ' doSomethingElse();\n',
+ '')
+ self.assert_multi_line_lint(
+ 'if (condition)\n'
+ ' returnValue = foo;\n'
+ 'else if (otherCondition)\n'
+ ' returnValue = bar;\n',
+ '')
+ self.assert_multi_line_lint(
+ 'if (condition)\n'
+ ' returnValue = foo;\n'
+ 'else\n'
+ ' returnValue = bar;\n',
+ '')
+ self.assert_multi_line_lint(
+ 'if (condition)\n'
+ ' doSomething();\n'
+ 'else if (liquid)\n'
+ ' return money;\n'
+ 'else if (broke)\n'
+ ' return favor;\n'
+ 'else\n'
+ ' sleep(28800);\n',
+ '')
+ self.assert_multi_line_lint(
+ 'if (liquid) {\n'
+ ' prepare();\n'
+ ' return money;\n'
+ '} else if (greedy) {\n'
+ ' keep();\n'
+ ' return nothing;\n'
+ '}\n',
+ 'An else if statement should be written as an if statement when the '
+ 'prior "if" concludes with a return, break, continue or goto statement.'
+ ' [readability/control_flow] [4]')
+ self.assert_multi_line_lint(
+ ' if (stupid) {\n'
+ 'infiniteLoop:\n'
+ ' goto infiniteLoop;\n'
+ ' } else if (evil)\n'
+ ' goto hell;\n',
+ 'An else if statement should be written as an if statement when the '
+ 'prior "if" concludes with a return, break, continue or goto statement.'
+ ' [readability/control_flow] [4]')
+ self.assert_multi_line_lint(
+ 'if (liquid)\n'
+ '{\n'
+ ' prepare();\n'
+ ' return money;\n'
+ '}\n'
+ 'else if (greedy)\n'
+ ' keep();\n',
+ ['This { should be at the end of the previous line [whitespace/braces] [4]',
+ 'An else should appear on the same line as the preceding } [whitespace/newline] [4]',
+ 'An else if statement should be written as an if statement when the '
+ 'prior "if" concludes with a return, break, continue or goto statement.'
+ ' [readability/control_flow] [4]'])
+ self.assert_multi_line_lint(
+ 'if (gone)\n'
+ ' return;\n'
+ 'else if (here)\n'
+ ' go();\n',
+ 'An else if statement should be written as an if statement when the '
+ 'prior "if" concludes with a return, break, continue or goto statement.'
+ ' [readability/control_flow] [4]')
+ self.assert_multi_line_lint(
+ 'if (gone)\n'
+ ' return;\n'
+ 'else\n'
+ ' go();\n',
+ 'An else statement can be removed when the prior "if" concludes '
+ 'with a return, break, continue or goto statement.'
+ ' [readability/control_flow] [4]')
+ self.assert_multi_line_lint(
+ 'if (motivated) {\n'
+ ' prepare();\n'
+ ' continue;\n'
+ '} else {\n'
+ ' cleanUp();\n'
+ ' break;\n'
+ '}\n',
+ 'An else statement can be removed when the prior "if" concludes '
+ 'with a return, break, continue or goto statement.'
+ ' [readability/control_flow] [4]')
+ self.assert_multi_line_lint(
+ 'if (tired)\n'
+ ' break;\n'
+ 'else {\n'
+ ' prepare();\n'
+ ' continue;\n'
+ '}\n',
+ 'An else statement can be removed when the prior "if" concludes '
+ 'with a return, break, continue or goto statement.'
+ ' [readability/control_flow] [4]')
+
+ def test_braces(self):
+ # 1. Function definitions: place each brace on its own line.
+ self.assert_multi_line_lint(
+ 'int main()\n'
+ '{\n'
+ ' doSomething();\n'
+ '}\n',
+ '')
+ self.assert_multi_line_lint(
+ 'int main() {\n'
+ ' doSomething();\n'
+ '}\n',
+ 'Place brace on its own line for function definitions. [whitespace/braces] [4]')
+
+ # 2. Other braces: place the open brace on the line preceding the
+ # code block; place the close brace on its own line.
+ self.assert_multi_line_lint(
+ 'class MyClass {\n'
+ ' int foo;\n'
+ '};\n',
+ '')
+ self.assert_multi_line_lint(
+ 'namespace WebCore {\n'
+ 'int foo;\n'
+ '};\n',
+ '')
+ self.assert_multi_line_lint(
+ 'for (int i = 0; i < 10; i++) {\n'
+ ' DoSomething();\n'
+ '};\n',
+ '')
+ self.assert_multi_line_lint(
+ 'class MyClass\n'
+ '{\n'
+ ' int foo;\n'
+ '};\n',
+ 'This { should be at the end of the previous line [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'if (condition)\n'
+ '{\n'
+ ' int foo;\n'
+ '}\n',
+ 'This { should be at the end of the previous line [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'for (int i = 0; i < 10; i++)\n'
+ '{\n'
+ ' int foo;\n'
+ '}\n',
+ 'This { should be at the end of the previous line [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'while (true)\n'
+ '{\n'
+ ' int foo;\n'
+ '}\n',
+ 'This { should be at the end of the previous line [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'foreach (Foo* foo, foos)\n'
+ '{\n'
+ ' int bar;\n'
+ '}\n',
+ 'This { should be at the end of the previous line [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'switch (type)\n'
+ '{\n'
+ 'case foo: return;\n'
+ '}\n',
+ 'This { should be at the end of the previous line [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'if (condition)\n'
+ '{\n'
+ ' int foo;\n'
+ '}\n',
+ 'This { should be at the end of the previous line [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'for (int i = 0; i < 10; i++)\n'
+ '{\n'
+ ' int foo;\n'
+ '}\n',
+ 'This { should be at the end of the previous line [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'while (true)\n'
+ '{\n'
+ ' int foo;\n'
+ '}\n',
+ 'This { should be at the end of the previous line [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'switch (type)\n'
+ '{\n'
+ 'case foo: return;\n'
+ '}\n',
+ 'This { should be at the end of the previous line [whitespace/braces] [4]')
+ self.assert_multi_line_lint(
+ 'else if (type)\n'
+ '{\n'
+ 'case foo: return;\n'
+ '}\n',
+ 'This { should be at the end of the previous line [whitespace/braces] [4]')
+
+ # 3. One-line control clauses should not use braces unless
+ # comments are included or a single statement spans multiple
+ # lines.
+ self.assert_multi_line_lint(
+ 'if (true) {\n'
+ ' int foo;\n'
+ '}\n',
+ 'One line control clauses should not use braces. [whitespace/braces] [4]')
+
+ self.assert_multi_line_lint(
+ 'for (; foo; bar) {\n'
+ ' int foo;\n'
+ '}\n',
+ 'One line control clauses should not use braces. [whitespace/braces] [4]')
+
+ self.assert_multi_line_lint(
+ 'foreach (foo, foos) {\n'
+ ' int bar;\n'
+ '}\n',
+ 'One line control clauses should not use braces. [whitespace/braces] [4]')
+
+ self.assert_multi_line_lint(
+ 'while (true) {\n'
+ ' int foo;\n'
+ '}\n',
+ 'One line control clauses should not use braces. [whitespace/braces] [4]')
+
+ self.assert_multi_line_lint(
+ 'if (true)\n'
+ ' int foo;\n'
+ 'else {\n'
+ ' int foo;\n'
+ '}\n',
+ 'One line control clauses should not use braces. [whitespace/braces] [4]')
+
+ self.assert_multi_line_lint(
+ 'if (true) {\n'
+ ' int foo;\n'
+ '} else\n'
+ ' int foo;\n',
+ 'One line control clauses should not use braces. [whitespace/braces] [4]')
+
+ self.assert_multi_line_lint(
+ 'if (true) {\n'
+ ' // Some comment\n'
+ ' int foo;\n'
+ '}\n',
+ '')
+
+ self.assert_multi_line_lint(
+ 'if (true) {\n'
+ ' myFunction(reallyLongParam1, reallyLongParam2,\n'
+ ' reallyLongParam3);\n'
+ '}\n',
+ '')
+
+ # 4. Control clauses without a body should use empty braces.
+ self.assert_multi_line_lint(
+ 'for ( ; current; current = current->next) { }\n',
+ '')
+ self.assert_multi_line_lint(
+ 'for ( ; current;\n'
+ ' current = current->next) {}\n',
+ '')
+ self.assert_multi_line_lint(
+ 'for ( ; current; current = current->next);\n',
+ 'Semicolon defining empty statement for this loop. Use { } instead. [whitespace/semicolon] [5]')
+ self.assert_multi_line_lint(
+ 'while (true);\n',
+ 'Semicolon defining empty statement for this loop. Use { } instead. [whitespace/semicolon] [5]')
+ self.assert_multi_line_lint(
+ '} while (true);\n',
+ '')
+
+ def test_null_false_zero(self):
+ # 1. In C++, the null pointer value should be written as 0. In C,
+ # it should be written as NULL. In Objective-C and Objective-C++,
+ # follow the guideline for C or C++, respectively, but use nil to
+ # represent a null Objective-C object.
+ self.assert_lint(
+ 'functionCall(NULL)',
+ 'Use 0 instead of NULL.'
+ ' [readability/null] [5]',
+ 'foo.cpp')
+ self.assert_lint(
+ "// Don't use NULL in comments since it isn't in code.",
+ 'Use 0 instead of NULL.'
+ ' [readability/null] [4]',
+ 'foo.cpp')
+ self.assert_lint(
+ '"A string with NULL" // and a comment with NULL is tricky to flag correctly in cpp_style.',
+ 'Use 0 instead of NULL.'
+ ' [readability/null] [4]',
+ 'foo.cpp')
+ self.assert_lint(
+ '"A string containing NULL is ok"',
+ '',
+ 'foo.cpp')
+ self.assert_lint(
+ 'if (aboutNULL)',
+ '',
+ 'foo.cpp')
+ self.assert_lint(
+ 'myVariable = NULLify',
+ '',
+ 'foo.cpp')
+ # Make sure that the NULL check does not apply to C and Objective-C files.
+ self.assert_lint(
+ 'functionCall(NULL)',
+ '',
+ 'foo.c')
+ self.assert_lint(
+ 'functionCall(NULL)',
+ '',
+ 'foo.m')
+
+ # Make sure that the NULL check does not apply to g_object_{set,get} and
+ # g_str{join,concat}
+ self.assert_lint(
+ 'g_object_get(foo, "prop", &bar, NULL);',
+ '')
+ self.assert_lint(
+ 'g_object_set(foo, "prop", bar, NULL);',
+ '')
+ self.assert_lint(
+ 'g_build_filename(foo, bar, NULL);',
+ '')
+ self.assert_lint(
+ 'gst_bin_add_many(foo, bar, boo, NULL);',
+ '')
+ self.assert_lint(
+ 'gst_bin_remove_many(foo, bar, boo, NULL);',
+ '')
+ self.assert_lint(
+ 'gst_element_link_many(foo, bar, boo, NULL);',
+ '')
+ self.assert_lint(
+ 'gst_element_unlink_many(foo, bar, boo, NULL);',
+ '')
+ self.assert_lint(
+ 'gchar* result = g_strconcat("part1", "part2", "part3", NULL);',
+ '')
+ self.assert_lint(
+ 'gchar* result = g_strconcat("part1", NULL);',
+ '')
+ self.assert_lint(
+ 'gchar* result = g_strjoin(",", "part1", "part2", "part3", NULL);',
+ '')
+ self.assert_lint(
+ 'gchar* result = g_strjoin(",", "part1", NULL);',
+ '')
+ self.assert_lint(
+ 'gchar* result = gdk_pixbuf_save_to_callback(pixbuf, function, data, type, error, NULL);',
+ '')
+ self.assert_lint(
+ 'gchar* result = gdk_pixbuf_save_to_buffer(pixbuf, function, data, type, error, NULL);',
+ '')
+ self.assert_lint(
+ 'gchar* result = gdk_pixbuf_save_to_stream(pixbuf, function, data, type, error, NULL);',
+ '')
+
+ # 2. C++ and C bool values should be written as true and
+ # false. Objective-C BOOL values should be written as YES and NO.
+ # FIXME: Implement this.
+
+ # 3. Tests for true/false, null/non-null, and zero/non-zero should
+ # all be done without equality comparisons.
+ self.assert_lint(
+ 'if (count == 0)',
+ 'Tests for true/false, null/non-null, and zero/non-zero should all be done without equality comparisons.'
+ ' [readability/comparison_to_zero] [5]')
+ self.assert_lint_one_of_many_errors_re(
+ 'if (string != NULL)',
+ r'Tests for true/false, null/non-null, and zero/non-zero should all be done without equality comparisons\.')
+ self.assert_lint(
+ 'if (condition == true)',
+ 'Tests for true/false, null/non-null, and zero/non-zero should all be done without equality comparisons.'
+ ' [readability/comparison_to_zero] [5]')
+ self.assert_lint(
+ 'if (myVariable != /* Why would anyone put a comment here? */ false)',
+ 'Tests for true/false, null/non-null, and zero/non-zero should all be done without equality comparisons.'
+ ' [readability/comparison_to_zero] [5]')
+
+ self.assert_lint(
+ 'if (0 /* This comment also looks odd to me. */ != aLongerVariableName)',
+ 'Tests for true/false, null/non-null, and zero/non-zero should all be done without equality comparisons.'
+ ' [readability/comparison_to_zero] [5]')
+ self.assert_lint_one_of_many_errors_re(
+ 'if (NULL == thisMayBeNull)',
+ r'Tests for true/false, null/non-null, and zero/non-zero should all be done without equality comparisons\.')
+ self.assert_lint(
+ 'if (true != anotherCondition)',
+ 'Tests for true/false, null/non-null, and zero/non-zero should all be done without equality comparisons.'
+ ' [readability/comparison_to_zero] [5]')
+ self.assert_lint(
+ 'if (false == myBoolValue)',
+ 'Tests for true/false, null/non-null, and zero/non-zero should all be done without equality comparisons.'
+ ' [readability/comparison_to_zero] [5]')
+
+ self.assert_lint(
+ 'if (fontType == trueType)',
+ '')
+ self.assert_lint(
+ 'if (othertrue == fontType)',
+ '')
+
+ def test_using_std(self):
+ self.assert_lint(
+ 'using std::min;',
+ "Use 'using namespace std;' instead of 'using std::min;'."
+ " [build/using_std] [4]",
+ 'foo.cpp')
+
+ def test_max_macro(self):
+ self.assert_lint(
+ 'int i = MAX(0, 1);',
+ '',
+ 'foo.c')
+
+ self.assert_lint(
+ 'int i = MAX(0, 1);',
+ 'Use std::max() or std::max<type>() instead of the MAX() macro.'
+ ' [runtime/max_min_macros] [4]',
+ 'foo.cpp')
+
+ self.assert_lint(
+ 'inline int foo() { return MAX(0, 1); }',
+ 'Use std::max() or std::max<type>() instead of the MAX() macro.'
+ ' [runtime/max_min_macros] [4]',
+ 'foo.h')
+
+ def test_min_macro(self):
+ self.assert_lint(
+ 'int i = MIN(0, 1);',
+ '',
+ 'foo.c')
+
+ self.assert_lint(
+ 'int i = MIN(0, 1);',
+ 'Use std::min() or std::min<type>() instead of the MIN() macro.'
+ ' [runtime/max_min_macros] [4]',
+ 'foo.cpp')
+
+ self.assert_lint(
+ 'inline int foo() { return MIN(0, 1); }',
+ 'Use std::min() or std::min<type>() instead of the MIN() macro.'
+ ' [runtime/max_min_macros] [4]',
+ 'foo.h')
+
+ def test_names(self):
+ name_underscore_error_message = " is incorrectly named. Don't use underscores in your identifier names. [readability/naming] [4]"
+ name_tooshort_error_message = " is incorrectly named. Don't use the single letter 'l' as an identifier name. [readability/naming] [4]"
+
+ # Basic cases from WebKit style guide.
+ self.assert_lint('struct Data;', '')
+ self.assert_lint('size_t bufferSize;', '')
+ self.assert_lint('class HTMLDocument;', '')
+ self.assert_lint('String mimeType();', '')
+ self.assert_lint('size_t buffer_size;',
+ 'buffer_size' + name_underscore_error_message)
+ self.assert_lint('short m_length;', '')
+ self.assert_lint('short _length;',
+ '_length' + name_underscore_error_message)
+ self.assert_lint('short length_;',
+ 'length_' + name_underscore_error_message)
+ self.assert_lint('unsigned _length;',
+ '_length' + name_underscore_error_message)
+ self.assert_lint('unsigned int _length;',
+ '_length' + name_underscore_error_message)
+ self.assert_lint('unsigned long long _length;',
+ '_length' + name_underscore_error_message)
+
+ # Allow underscores in Objective C files.
+ self.assert_lint('unsigned long long _length;',
+ '',
+ 'foo.m')
+ self.assert_lint('unsigned long long _length;',
+ '',
+ 'foo.mm')
+ self.assert_lint('#import "header_file.h"\n'
+ 'unsigned long long _length;',
+ '',
+ 'foo.h')
+ self.assert_lint('unsigned long long _length;\n'
+ '@interface WebFullscreenWindow;',
+ '',
+ 'foo.h')
+ self.assert_lint('unsigned long long _length;\n'
+ '@implementation WebFullscreenWindow;',
+ '',
+ 'foo.h')
+ self.assert_lint('unsigned long long _length;\n'
+ '@class WebWindowFadeAnimation;',
+ '',
+ 'foo.h')
+
+ # Variable name 'l' is easy to confuse with '1'
+ self.assert_lint('int l;', 'l' + name_tooshort_error_message)
+ self.assert_lint('size_t l;', 'l' + name_tooshort_error_message)
+ self.assert_lint('long long l;', 'l' + name_tooshort_error_message)
+
+ # Pointers, references, functions, templates, and adjectives.
+ self.assert_lint('char* under_score;',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('const int UNDER_SCORE;',
+ 'UNDER_SCORE' + name_underscore_error_message)
+ self.assert_lint('static inline const char const& const under_score;',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('WebCore::RenderObject* under_score;',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('int func_name();',
+ 'func_name' + name_underscore_error_message)
+ self.assert_lint('RefPtr<RenderObject*> under_score;',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('WTF::Vector<WTF::RefPtr<const RenderObject* const> > under_score;',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('int under_score[];',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('struct dirent* under_score;',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('long under_score;',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('long long under_score;',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('long double under_score;',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('long long int under_score;',
+ 'under_score' + name_underscore_error_message)
+
+ # Declarations in control statement.
+ self.assert_lint('if (int under_score = 42) {',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('else if (int under_score = 42) {',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('for (int under_score = 42; cond; i++) {',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('while (foo & under_score = bar) {',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('for (foo * under_score = p; cond; i++) {',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('for (foo * under_score; cond; i++) {',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('while (foo & value_in_thirdparty_library) {', '')
+ self.assert_lint('while (foo * value_in_thirdparty_library) {', '')
+ self.assert_lint('if (mli && S_OK == mli->foo()) {', '')
+
+ # More member variables and functions.
+ self.assert_lint('int SomeClass::s_validName', '')
+ self.assert_lint('int m_under_score;',
+ 'm_under_score' + name_underscore_error_message)
+ self.assert_lint('int SomeClass::s_under_score = 0;',
+ 'SomeClass::s_under_score' + name_underscore_error_message)
+ self.assert_lint('int SomeClass::under_score = 0;',
+ 'SomeClass::under_score' + name_underscore_error_message)
+
+ # Other statements.
+ self.assert_lint('return INT_MAX;', '')
+ self.assert_lint('return_t under_score;',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('goto under_score;',
+ 'under_score' + name_underscore_error_message)
+ self.assert_lint('delete static_cast<Foo*>(p);', '')
+
+ # Multiple variables in one line.
+ self.assert_lint('void myFunction(int variable1, int another_variable);',
+ 'another_variable' + name_underscore_error_message)
+ self.assert_lint('int variable1, another_variable;',
+ 'another_variable' + name_underscore_error_message)
+ self.assert_lint('int first_variable, secondVariable;',
+ 'first_variable' + name_underscore_error_message)
+ self.assert_lint('void my_function(int variable_1, int variable_2);',
+ ['my_function' + name_underscore_error_message,
+ 'variable_1' + name_underscore_error_message,
+ 'variable_2' + name_underscore_error_message])
+ self.assert_lint('for (int variable_1, variable_2;;) {',
+ ['variable_1' + name_underscore_error_message,
+ 'variable_2' + name_underscore_error_message])
+
+ # There is an exception for op code functions but only in the JavaScriptCore directory.
+ self.assert_lint('void this_op_code(int var1, int var2)', '', 'JavaScriptCore/foo.cpp')
+ self.assert_lint('void op_code(int var1, int var2)', '', 'JavaScriptCore/foo.cpp')
+ self.assert_lint('void this_op_code(int var1, int var2)', 'this_op_code' + name_underscore_error_message)
+
+ # GObject requires certain magical names in class declarations.
+ self.assert_lint('void webkit_dom_object_init();', '')
+ self.assert_lint('void webkit_dom_object_class_init();', '')
+
+ # There is an exception for some unit tests that begin with "tst_".
+ self.assert_lint('void tst_QWebFrame::arrayObjectEnumerable(int var1, int var2)', '')
+
+ # The Qt API uses names that begin with "qt_".
+ self.assert_lint('void QTFrame::qt_drt_is_awesome(int var1, int var2)', '')
+ self.assert_lint('void qt_drt_is_awesome(int var1, int var2);', '')
+
+ # Cairo forward-declarations should not be a failure.
+ self.assert_lint('typedef struct _cairo cairo_t;', '')
+ self.assert_lint('typedef struct _cairo_surface cairo_surface_t;', '')
+ self.assert_lint('typedef struct _cairo_scaled_font cairo_scaled_font_t;', '')
+
+ # NPAPI functions that start with NPN_, NPP_ or NP_ are allowed.
+ self.assert_lint('void NPN_Status(NPP, const char*)', '')
+ self.assert_lint('NPError NPP_SetWindow(NPP instance, NPWindow *window)', '')
+ self.assert_lint('NPObject* NP_Allocate(NPP, NPClass*)', '')
+
+ # const_iterator is allowed as well.
+ self.assert_lint('typedef VectorType::const_iterator const_iterator;', '')
+
+ # vm_throw is allowed as well.
+ self.assert_lint('int vm_throw;', '')
+
+ # Bitfields.
+ self.assert_lint('unsigned _fillRule : 1;',
+ '_fillRule' + name_underscore_error_message)
+
+ # new operators in initialization.
+ self.assert_lint('OwnPtr<uint32_t> variable(new uint32_t);', '')
+ self.assert_lint('OwnPtr<uint32_t> variable(new (expr) uint32_t);', '')
+ self.assert_lint('OwnPtr<uint32_t> under_score(new uint32_t);',
+ 'under_score' + name_underscore_error_message)
+
+
+ def test_comments(self):
+ # A comment at the beginning of a line is ok.
+ self.assert_lint('// comment', '')
+ self.assert_lint(' // comment', '')
+
+ self.assert_lint('} // namespace WebCore',
+ 'One space before end of line comments'
+ ' [whitespace/comments] [5]')
+
+ def test_other(self):
+ # FIXME: Implement this.
+ pass
+
+
+class CppCheckerTest(unittest.TestCase):
+
+ """Tests CppChecker class."""
+
+ def mock_handle_style_error(self):
+ pass
+
+ def _checker(self):
+ return CppChecker("foo", "h", self.mock_handle_style_error, 3)
+
+ def test_init(self):
+ """Test __init__ constructor."""
+ checker = self._checker()
+ self.assertEquals(checker.file_extension, "h")
+ self.assertEquals(checker.file_path, "foo")
+ self.assertEquals(checker.handle_style_error, self.mock_handle_style_error)
+ self.assertEquals(checker.min_confidence, 3)
+
+ def test_eq(self):
+ """Test __eq__ equality function."""
+ checker1 = self._checker()
+ checker2 = self._checker()
+
+ # == calls __eq__.
+ self.assertTrue(checker1 == checker2)
+
+ def mock_handle_style_error2(self):
+ pass
+
+ # Verify that a difference in any argument cause equality to fail.
+ checker = CppChecker("foo", "h", self.mock_handle_style_error, 3)
+ self.assertFalse(checker == CppChecker("bar", "h", self.mock_handle_style_error, 3))
+ self.assertFalse(checker == CppChecker("foo", "c", self.mock_handle_style_error, 3))
+ self.assertFalse(checker == CppChecker("foo", "h", mock_handle_style_error2, 3))
+ self.assertFalse(checker == CppChecker("foo", "h", self.mock_handle_style_error, 4))
+
+ def test_ne(self):
+ """Test __ne__ inequality function."""
+ checker1 = self._checker()
+ checker2 = self._checker()
+
+ # != calls __ne__.
+ # By default, __ne__ always returns true on different objects.
+ # Thus, just check the distinguishing case to verify that the
+ # code defines __ne__.
+ self.assertFalse(checker1 != checker2)
+
+
+def tearDown():
+ """A global check to make sure all error-categories have been tested.
+
+ The main tearDown() routine is the only code we can guarantee will be
+ run after all other tests have been executed.
+ """
+ try:
+ if _run_verifyallcategoriesseen:
+ ErrorCollector(None).verify_all_categories_are_seen()
+ except NameError:
+ # If nobody set the global _run_verifyallcategoriesseen, then
+ # we assume we shouldn't run the test
+ pass
+
+if __name__ == '__main__':
+ import sys
+ # We don't want to run the verify_all_categories_are_seen() test unless
+ # we're running the full test suite: if we only run one test,
+ # obviously we're not going to see all the error categories. So we
+ # only run verify_all_categories_are_seen() when no commandline flags
+ # are passed in.
+ global _run_verifyallcategoriesseen
+ _run_verifyallcategoriesseen = (len(sys.argv) == 1)
+
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/style/checkers/python.py b/Tools/Scripts/webkitpy/style/checkers/python.py
new file mode 100644
index 0000000..70d4450
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/python.py
@@ -0,0 +1,56 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Supports checking WebKit style in Python files."""
+
+from ...style_references import pep8
+
+
+class PythonChecker(object):
+
+ """Processes text lines for checking style."""
+
+ def __init__(self, file_path, handle_style_error):
+ self._file_path = file_path
+ self._handle_style_error = handle_style_error
+
+ def check(self, lines):
+ # Initialize pep8.options, which is necessary for
+ # Checker.check_all() to execute.
+ pep8.process_options(arglist=[self._file_path])
+
+ checker = pep8.Checker(self._file_path)
+
+ def _pep8_handle_error(line_number, offset, text, check):
+ # FIXME: Incorporate the character offset into the error output.
+ # This will require updating the error handler __call__
+ # signature to include an optional "offset" parameter.
+ pep8_code = text[:4]
+ pep8_message = text[5:]
+
+ category = "pep8/" + pep8_code
+
+ self._handle_style_error(line_number, category, 5, pep8_message)
+
+ checker.report_error = _pep8_handle_error
+
+ errors = checker.check_all()
diff --git a/Tools/Scripts/webkitpy/style/checkers/python_unittest.py b/Tools/Scripts/webkitpy/style/checkers/python_unittest.py
new file mode 100644
index 0000000..e003eb8
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/python_unittest.py
@@ -0,0 +1,62 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Unit tests for python.py."""
+
+import os
+import unittest
+
+from python import PythonChecker
+
+
+class PythonCheckerTest(unittest.TestCase):
+
+ """Tests the PythonChecker class."""
+
+ def test_init(self):
+ """Test __init__() method."""
+ def _mock_handle_style_error(self):
+ pass
+
+ checker = PythonChecker("foo.txt", _mock_handle_style_error)
+ self.assertEquals(checker._file_path, "foo.txt")
+ self.assertEquals(checker._handle_style_error,
+ _mock_handle_style_error)
+
+ def test_check(self):
+ """Test check() method."""
+ errors = []
+
+ def _mock_handle_style_error(line_number, category, confidence,
+ message):
+ error = (line_number, category, confidence, message)
+ errors.append(error)
+
+ current_dir = os.path.dirname(__file__)
+ file_path = os.path.join(current_dir, "python_unittest_input.py")
+
+ checker = PythonChecker(file_path, _mock_handle_style_error)
+ checker.check(lines=[])
+
+ self.assertEquals(len(errors), 1)
+ self.assertEquals(errors[0],
+ (2, "pep8/W291", 5, "trailing whitespace"))
diff --git a/Tools/Scripts/webkitpy/style/checkers/python_unittest_input.py b/Tools/Scripts/webkitpy/style/checkers/python_unittest_input.py
new file mode 100644
index 0000000..9f1d118
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/python_unittest_input.py
@@ -0,0 +1,2 @@
+# This file is sample input for python_unittest.py and includes a single
+# error which is an extra space at the end of this line.
diff --git a/Tools/Scripts/webkitpy/style/checkers/test_expectations.py b/Tools/Scripts/webkitpy/style/checkers/test_expectations.py
new file mode 100644
index 0000000..c86b32c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/test_expectations.py
@@ -0,0 +1,120 @@
+# 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.
+
+"""Checks WebKit style for test_expectations files."""
+
+import logging
+import os
+import re
+import sys
+
+from common import TabChecker
+from webkitpy.style_references import port
+from webkitpy.style_references import test_expectations
+
+_log = logging.getLogger("webkitpy.style.checkers.test_expectations")
+
+
+class ChromiumOptions(object):
+ """A mock object for creating chromium port object.
+
+ port.get() requires an options object which has 'chromium' attribute to create
+ chromium port object for each platform. This class mocks such object.
+ """
+ def __init__(self):
+ self.chromium = True
+
+
+class TestExpectationsChecker(object):
+ """Processes test_expectations.txt lines for validating the syntax."""
+
+ categories = set(['test/expectations'])
+
+ def __init__(self, file_path, handle_style_error):
+ self._file_path = file_path
+ self._handle_style_error = handle_style_error
+ self._tab_checker = TabChecker(file_path, handle_style_error)
+ self._output_regex = re.compile('Line:(?P<line>\d+)\s*(?P<message>.+)')
+ # Determining the port of this expectations.
+ try:
+ port_name = self._file_path.split(os.sep)[-2]
+ if port_name == "chromium":
+ options = ChromiumOptions()
+ self._port_obj = port.get(port_name=None, options=options)
+ else:
+ self._port_obj = port.get(port_name=port_name)
+ except:
+ # Using 'test' port when we couldn't determine the port for this
+ # expectations.
+ _log.warn("Could not determine the port for %s. "
+ "Using 'test' port, but platform-specific expectations "
+ "will fail the check." % self._file_path)
+ self._port_obj = port.get('test')
+ self._port_to_check = self._port_obj.test_platform_name()
+ # Suppress error messages of test_expectations module since they will be
+ # reported later.
+ log = logging.getLogger("webkitpy.layout_tests.layout_package."
+ "test_expectations")
+ log.setLevel(logging.CRITICAL)
+
+ def _handle_error_message(self, lineno, message, confidence):
+ pass
+
+ def check_test_expectations(self, expectations_str, tests=None, overrides=None):
+ err = None
+ expectations = None
+ try:
+ expectations = test_expectations.TestExpectationsFile(
+ port=self._port_obj, expectations=expectations_str, full_test_list=tests,
+ test_platform_name=self._port_to_check, is_debug_mode=False,
+ is_lint_mode=True, overrides=overrides)
+ except test_expectations.ParseError, error:
+ err = error
+
+ if err:
+ level = 2
+ if err.fatal:
+ level = 5
+ for error in err.errors:
+ matched = self._output_regex.match(error)
+ if matched:
+ lineno, message = matched.group('line', 'message')
+ self._handle_style_error(int(lineno), 'test/expectations', level, message)
+
+
+ def check_tabs(self, lines):
+ self._tab_checker.check(lines)
+
+ def check(self, lines):
+ overrides = self._port_obj.test_expectations_overrides()
+ expectations = '\n'.join(lines)
+ self.check_test_expectations(expectations_str=expectations,
+ tests=None,
+ overrides=overrides)
+ # Warn tabs in lines as well
+ self.check_tabs(lines)
diff --git a/Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py b/Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py
new file mode 100644
index 0000000..9817c5d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/test_expectations_unittest.py
@@ -0,0 +1,173 @@
+#!/usr/bin/python
+# 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.
+
+"""Unit tests for test_expectations.py."""
+
+import os
+import sys
+import unittest
+
+# We need following workaround hack to run this unit tests in stand-alone.
+try:
+ d = os.path.dirname(__file__)
+except NameError:
+ d = os.path.dirname(sys.argv[0])
+sys.path.append(os.path.abspath(os.path.join(d, '../../../')))
+
+from test_expectations import TestExpectationsChecker
+from webkitpy.style_references import port
+from webkitpy.style_references import test_expectations as test_expectations_style
+
+
+class ErrorCollector(object):
+ """An error handler class for unit tests."""
+
+ def __init__(self):
+ self._errors = []
+
+ def __call__(self, lineno, category, confidence, message):
+ self._errors.append('%s [%s] [%d]' % (message, category, confidence))
+
+ def get_errors(self):
+ return ''.join(self._errors)
+
+ def reset_errors(self):
+ self._errors = []
+
+
+class TestExpectationsTestCase(unittest.TestCase):
+ """TestCase for test_expectations.py"""
+
+ def setUp(self):
+ self._error_collector = ErrorCollector()
+ port_obj = port.get('test')
+ self._test_file = os.path.join(port_obj.layout_tests_dir(), 'passes/text.html')
+
+ def process_expectations(self, expectations, overrides=None):
+ self._checker = TestExpectationsChecker()
+
+ def assert_lines_lint(self, lines, expected):
+ self._error_collector.reset_errors()
+ checker = TestExpectationsChecker('test/test_expectations.txt',
+ self._error_collector)
+ checker.check_test_expectations(expectations_str='\n'.join(lines),
+ tests=[self._test_file],
+ overrides=None)
+ checker.check_tabs(lines)
+ self.assertEqual(expected, self._error_collector.get_errors())
+
+ def test_valid_expectations(self):
+ self.assert_lines_lint(
+ ["passes/text.html = PASS"],
+ "")
+ self.assert_lines_lint(
+ ["passes/text.html = FAIL PASS"],
+ "")
+ self.assert_lines_lint(
+ ["passes/text.html = CRASH TIMEOUT FAIL PASS"],
+ "")
+ self.assert_lines_lint(
+ ["BUGCR1234 MAC : passes/text.html = PASS FAIL"],
+ "")
+ self.assert_lines_lint(
+ ["SKIP BUGCR1234 : passes/text.html = TIMEOUT PASS"],
+ "")
+ self.assert_lines_lint(
+ ["BUGCR1234 DEBUG : passes/text.html = TIMEOUT PASS"],
+ "")
+ self.assert_lines_lint(
+ ["BUGCR1234 DEBUG SKIP : passes/text.html = TIMEOUT PASS"],
+ "")
+ self.assert_lines_lint(
+ ["BUGCR1234 MAC DEBUG SKIP : passes/text.html = TIMEOUT PASS"],
+ "")
+ self.assert_lines_lint(
+ ["BUGCR1234 DEBUG MAC : passes/text.html = TIMEOUT PASS"],
+ "")
+ self.assert_lines_lint(
+ ["SLOW BUGCR1234 : passes/text.html = PASS"],
+ "")
+ self.assert_lines_lint(
+ ["WONTFIX SKIP : passes/text.html = TIMEOUT"],
+ "")
+
+ def test_modifier_errors(self):
+ self.assert_lines_lint(
+ ["BUG1234 : passes/text.html = FAIL"],
+ 'Bug must be either BUGCR, BUGWK, or BUGV8_ for test: bug1234 passes/text.html [test/expectations] [5]')
+
+ def test_valid_modifiers(self):
+ self.assert_lines_lint(
+ ["INVALID-MODIFIER : passes/text.html = PASS"],
+ "Invalid modifier for test: invalid-modifier "
+ "passes/text.html [test/expectations] [5]")
+ self.assert_lines_lint(
+ ["SKIP : passes/text.html = PASS"],
+ "Test lacks BUG modifier. "
+ "passes/text.html [test/expectations] [2]")
+
+ def test_expectation_errors(self):
+ self.assert_lines_lint(
+ ["missing expectations"],
+ "Missing expectations. ['missing expectations'] [test/expectations] [5]")
+ self.assert_lines_lint(
+ ["SLOW : passes/text.html = TIMEOUT"],
+ "A test can not be both slow and timeout. "
+ "If it times out indefinitely, then it should be just timeout. "
+ "passes/text.html [test/expectations] [5]")
+ self.assert_lines_lint(
+ ["does/not/exist.html = FAIL"],
+ "Path does not exist. does/not/exist.html [test/expectations] [2]")
+
+ def test_parse_expectations(self):
+ self.assert_lines_lint(
+ ["passes/text.html = PASS"],
+ "")
+ self.assert_lines_lint(
+ ["passes/text.html = UNSUPPORTED"],
+ "Unsupported expectation: unsupported "
+ "passes/text.html [test/expectations] [5]")
+ self.assert_lines_lint(
+ ["passes/text.html = PASS UNSUPPORTED"],
+ "Unsupported expectation: unsupported "
+ "passes/text.html [test/expectations] [5]")
+
+ def test_already_seen_test(self):
+ self.assert_lines_lint(
+ ["passes/text.html = PASS",
+ "passes/text.html = TIMEOUT"],
+ "Duplicate expectation. %s [test/expectations] [5]" % self._test_file)
+
+ def test_tab(self):
+ self.assert_lines_lint(
+ ["\tpasses/text.html = PASS"],
+ "Line contains tab character. [whitespace/tab] [5]")
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/style/checkers/text.py b/Tools/Scripts/webkitpy/style/checkers/text.py
new file mode 100644
index 0000000..1147658
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/text.py
@@ -0,0 +1,51 @@
+# Copyright (C) 2009 Google Inc. All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@webkit.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.
+
+"""Checks WebKit style for text files."""
+
+from common import TabChecker
+
+class TextChecker(object):
+
+ """Processes text lines for checking style."""
+
+ def __init__(self, file_path, handle_style_error):
+ self.file_path = file_path
+ self.handle_style_error = handle_style_error
+ self._tab_checker = TabChecker(file_path, handle_style_error)
+
+ def check(self, lines):
+ self._tab_checker.check(lines)
+
+
+# FIXME: Remove this function (requires refactoring unit tests).
+def process_file_data(filename, lines, error):
+ checker = TextChecker(filename, error)
+ checker.check(lines)
+
diff --git a/Tools/Scripts/webkitpy/style/checkers/text_unittest.py b/Tools/Scripts/webkitpy/style/checkers/text_unittest.py
new file mode 100644
index 0000000..ced49a9
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/text_unittest.py
@@ -0,0 +1,94 @@
+#!/usr/bin/python
+# 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.
+
+"""Unit test for text_style.py."""
+
+import unittest
+
+import text as text_style
+from text import TextChecker
+
+class TextStyleTestCase(unittest.TestCase):
+ """TestCase for text_style.py"""
+
+ def assertNoError(self, lines):
+ """Asserts that the specified lines has no errors."""
+ self.had_error = False
+
+ def error_for_test(line_number, category, confidence, message):
+ """Records if an error occurs."""
+ self.had_error = True
+
+ text_style.process_file_data('', lines, error_for_test)
+ self.assert_(not self.had_error, '%s should not have any errors.' % lines)
+
+ def assertError(self, lines, expected_line_number):
+ """Asserts that the specified lines has an error."""
+ self.had_error = False
+
+ def error_for_test(line_number, category, confidence, message):
+ """Checks if the expected error occurs."""
+ self.assertEquals(expected_line_number, line_number)
+ self.assertEquals('whitespace/tab', category)
+ self.had_error = True
+
+ text_style.process_file_data('', lines, error_for_test)
+ self.assert_(self.had_error, '%s should have an error [whitespace/tab].' % lines)
+
+
+ def test_no_error(self):
+ """Tests for no error cases."""
+ self.assertNoError([''])
+ self.assertNoError(['abc def', 'ggg'])
+
+
+ def test_error(self):
+ """Tests for error cases."""
+ self.assertError(['2009-12-16\tKent Tamura\t<tkent@chromium.org>'], 1)
+ self.assertError(['2009-12-16 Kent Tamura <tkent@chromium.org>',
+ '',
+ '\tReviewed by NOBODY.'], 3)
+
+
+class TextCheckerTest(unittest.TestCase):
+
+ """Tests TextChecker class."""
+
+ def mock_handle_style_error(self):
+ pass
+
+ def test_init(self):
+ """Test __init__ constructor."""
+ checker = TextChecker("foo.txt", self.mock_handle_style_error)
+ self.assertEquals(checker.file_path, "foo.txt")
+ self.assertEquals(checker.handle_style_error, self.mock_handle_style_error)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/style/checkers/xml.py b/Tools/Scripts/webkitpy/style/checkers/xml.py
new file mode 100644
index 0000000..2f7c0ce
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/xml.py
@@ -0,0 +1,45 @@
+# 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.
+
+"""Checks WebKit style for XML files."""
+
+from __future__ import absolute_import
+
+from xml.parsers import expat
+
+
+class XMLChecker(object):
+ """Processes XML lines for checking style."""
+
+ def __init__(self, file_path, handle_style_error):
+ self.file_path = file_path
+ self.handle_style_error = handle_style_error
+
+ def check(self, lines):
+ parser = expat.ParserCreate()
+ try:
+ for line in lines:
+ parser.Parse(line)
+ parser.Parse('\n')
+ parser.Parse('', True)
+ except expat.ExpatError, error:
+ self.handle_style_error(error.lineno, 'xml/syntax', 5, expat.ErrorString(error.code))
diff --git a/Tools/Scripts/webkitpy/style/checkers/xml_unittest.py b/Tools/Scripts/webkitpy/style/checkers/xml_unittest.py
new file mode 100644
index 0000000..3825660
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/checkers/xml_unittest.py
@@ -0,0 +1,72 @@
+#!/usr/bin/env python
+#
+# 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.
+
+"""Unit test for xml.py."""
+
+import unittest
+
+import xml
+
+
+class XMLCheckerTest(unittest.TestCase):
+ """Tests XMLChecker class."""
+
+ def assert_no_error(self, xml_data):
+ def handle_style_error(line_number, category, confidence, message):
+ self.fail('Unexpected error: %d %s %d %s' % (line_number, category, confidence, message))
+ checker = xml.XMLChecker('foo.xml', handle_style_error)
+ checker.check(xml_data.split('\n'))
+
+ def assert_error(self, expected_line_number, expected_category, xml_data):
+ def handle_style_error(line_number, category, confidence, message):
+ self.had_error = True
+ self.assertEquals(expected_line_number, line_number)
+ self.assertEquals(expected_category, category)
+ checker = xml.XMLChecker('foo.xml', handle_style_error)
+ checker.check(xml_data.split('\n'))
+ self.assertTrue(self.had_error)
+
+ def mock_handle_style_error(self):
+ pass
+
+ def test_conflict_marker(self):
+ self.assert_error(1, 'xml/syntax', '<<<<<<< HEAD\n<foo>\n</foo>\n')
+
+ def test_extra_closing_tag(self):
+ self.assert_error(3, 'xml/syntax', '<foo>\n</foo>\n</foo>\n')
+
+ def test_init(self):
+ checker = xml.XMLChecker('foo.xml', self.mock_handle_style_error)
+ self.assertEquals(checker.file_path, 'foo.xml')
+ self.assertEquals(checker.handle_style_error, self.mock_handle_style_error)
+
+ def test_missing_closing_tag(self):
+ self.assert_error(3, 'xml/syntax', '<foo>\n<bar>\n</foo>\n')
+
+ def test_no_error(self):
+ checker = xml.XMLChecker('foo.xml', self.assert_no_error)
+ checker.check(['<foo>', '</foo>'])
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/style/error_handlers.py b/Tools/Scripts/webkitpy/style/error_handlers.py
new file mode 100644
index 0000000..0bede24
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/error_handlers.py
@@ -0,0 +1,159 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Defines style error handler classes.
+
+A style error handler is a function to call when a style error is
+found. Style error handlers can also have state. A class that represents
+a style error handler should implement the following methods.
+
+Methods:
+
+ __call__(self, line_number, category, confidence, message):
+
+ Handle the occurrence of a style error.
+
+ Check whether the error is reportable. If so, increment the total
+ error count and report the details. Note that error reporting can
+ be suppressed after reaching a certain number of reports.
+
+ Args:
+ line_number: The integer line number of the line containing the error.
+ category: The name of the category of the error, for example
+ "whitespace/newline".
+ confidence: An integer between 1 and 5 inclusive that represents the
+ application's level of confidence in the error. The value
+ 5 means that we are certain of the problem, and the
+ value 1 means that it could be a legitimate construct.
+ message: The error message to report.
+
+"""
+
+
+import sys
+
+
+class DefaultStyleErrorHandler(object):
+
+ """The default style error handler."""
+
+ def __init__(self, file_path, configuration, increment_error_count,
+ line_numbers=None):
+ """Create a default style error handler.
+
+ Args:
+ file_path: The path to the file containing the error. This
+ is used for reporting to the user.
+ configuration: A StyleProcessorConfiguration instance.
+ increment_error_count: A function that takes no arguments and
+ increments the total count of reportable
+ errors.
+ line_numbers: An array of line numbers of the lines for which
+ style errors should be reported, or None if errors
+ for all lines should be reported. When it is not
+ None, this array normally contains the line numbers
+ corresponding to the modified lines of a patch.
+
+ """
+ if line_numbers is not None:
+ line_numbers = set(line_numbers)
+
+ self._file_path = file_path
+ self._configuration = configuration
+ self._increment_error_count = increment_error_count
+ self._line_numbers = line_numbers
+
+ # A string to integer dictionary cache of the number of reportable
+ # errors per category passed to this instance.
+ self._category_totals = {}
+
+ # Useful for unit testing.
+ def __eq__(self, other):
+ """Return whether this instance is equal to another."""
+ if self._configuration != other._configuration:
+ return False
+ if self._file_path != other._file_path:
+ return False
+ if self._increment_error_count != other._increment_error_count:
+ return False
+ if self._line_numbers != other._line_numbers:
+ return False
+
+ return True
+
+ # Useful for unit testing.
+ def __ne__(self, other):
+ # Python does not automatically deduce __ne__ from __eq__.
+ return not self.__eq__(other)
+
+ def _add_reportable_error(self, category):
+ """Increment the error count and return the new category total."""
+ self._increment_error_count() # Increment the total.
+
+ # Increment the category total.
+ if not category in self._category_totals:
+ self._category_totals[category] = 1
+ else:
+ self._category_totals[category] += 1
+
+ return self._category_totals[category]
+
+ def _max_reports(self, category):
+ """Return the maximum number of errors to report."""
+ if not category in self._configuration.max_reports_per_category:
+ return None
+ return self._configuration.max_reports_per_category[category]
+
+ def __call__(self, line_number, category, confidence, message):
+ """Handle the occurrence of a style error.
+
+ See the docstring of this module for more information.
+
+ """
+ if (self._line_numbers is not None and
+ line_number not in self._line_numbers):
+ # Then the error occurred in a line that was not modified, so
+ # the error is not reportable.
+ return
+
+ if not self._configuration.is_reportable(category=category,
+ confidence_in_error=confidence,
+ file_path=self._file_path):
+ return
+
+ category_total = self._add_reportable_error(category)
+
+ max_reports = self._max_reports(category)
+
+ if (max_reports is not None) and (category_total > max_reports):
+ # Then suppress displaying the error.
+ return
+
+ self._configuration.write_style_error(category=category,
+ confidence_in_error=confidence,
+ file_path=self._file_path,
+ line_number=line_number,
+ message=message)
+
+ if category_total == max_reports:
+ self._configuration.stderr_write("Suppressing further [%s] reports "
+ "for this file.\n" % category)
diff --git a/Tools/Scripts/webkitpy/style/error_handlers_unittest.py b/Tools/Scripts/webkitpy/style/error_handlers_unittest.py
new file mode 100644
index 0000000..23619cc
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/error_handlers_unittest.py
@@ -0,0 +1,187 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Unit tests for error_handlers.py."""
+
+
+import unittest
+
+from checker import StyleProcessorConfiguration
+from error_handlers import DefaultStyleErrorHandler
+from filter import FilterConfiguration
+
+
+class DefaultStyleErrorHandlerTest(unittest.TestCase):
+
+ """Tests the DefaultStyleErrorHandler class."""
+
+ def setUp(self):
+ self._error_messages = []
+ self._error_count = 0
+
+ _category = "whitespace/tab"
+ """The category name for the tests in this class."""
+
+ _file_path = "foo.h"
+ """The file path for the tests in this class."""
+
+ def _mock_increment_error_count(self):
+ self._error_count += 1
+
+ def _mock_stderr_write(self, message):
+ self._error_messages.append(message)
+
+ def _style_checker_configuration(self):
+ """Return a StyleProcessorConfiguration instance for testing."""
+ base_rules = ["-whitespace", "+whitespace/tab"]
+ filter_configuration = FilterConfiguration(base_rules=base_rules)
+
+ return StyleProcessorConfiguration(
+ filter_configuration=filter_configuration,
+ max_reports_per_category={"whitespace/tab": 2},
+ min_confidence=3,
+ output_format="vs7",
+ stderr_write=self._mock_stderr_write)
+
+ def _error_handler(self, configuration, line_numbers=None):
+ return DefaultStyleErrorHandler(configuration=configuration,
+ file_path=self._file_path,
+ increment_error_count=self._mock_increment_error_count,
+ line_numbers=line_numbers)
+
+ def _check_initialized(self):
+ """Check that count and error messages are initialized."""
+ self.assertEquals(0, self._error_count)
+ self.assertEquals(0, len(self._error_messages))
+
+ def _call_error_handler(self, handle_error, confidence, line_number=100):
+ """Call the given error handler with a test error."""
+ handle_error(line_number=line_number,
+ category=self._category,
+ confidence=confidence,
+ message="message")
+
+ def test_eq__true_return_value(self):
+ """Test the __eq__() method for the return value of True."""
+ handler1 = self._error_handler(configuration=None)
+ handler2 = self._error_handler(configuration=None)
+
+ self.assertTrue(handler1.__eq__(handler2))
+
+ def test_eq__false_return_value(self):
+ """Test the __eq__() method for the return value of False."""
+ def make_handler(configuration=self._style_checker_configuration(),
+ file_path='foo.txt', increment_error_count=lambda: True,
+ line_numbers=[100]):
+ return DefaultStyleErrorHandler(configuration=configuration,
+ file_path=file_path,
+ increment_error_count=increment_error_count,
+ line_numbers=line_numbers)
+
+ handler = make_handler()
+
+ # Establish a baseline for our comparisons below.
+ self.assertTrue(handler.__eq__(make_handler()))
+
+ # Verify that a difference in any argument causes equality to fail.
+ self.assertFalse(handler.__eq__(make_handler(configuration=None)))
+ self.assertFalse(handler.__eq__(make_handler(file_path='bar.txt')))
+ self.assertFalse(handler.__eq__(make_handler(increment_error_count=None)))
+ self.assertFalse(handler.__eq__(make_handler(line_numbers=[50])))
+
+ def test_ne(self):
+ """Test the __ne__() method."""
+ # By default, __ne__ always returns true on different objects.
+ # Thus, check just the distinguishing case to verify that the
+ # code defines __ne__.
+ handler1 = self._error_handler(configuration=None)
+ handler2 = self._error_handler(configuration=None)
+
+ self.assertFalse(handler1.__ne__(handler2))
+
+ def test_non_reportable_error(self):
+ """Test __call__() with a non-reportable error."""
+ self._check_initialized()
+ configuration = self._style_checker_configuration()
+
+ confidence = 1
+ # Confirm the error is not reportable.
+ self.assertFalse(configuration.is_reportable(self._category,
+ confidence,
+ self._file_path))
+ error_handler = self._error_handler(configuration)
+ self._call_error_handler(error_handler, confidence)
+
+ self.assertEquals(0, self._error_count)
+ self.assertEquals([], self._error_messages)
+
+ # Also serves as a reportable error test.
+ def test_max_reports_per_category(self):
+ """Test error report suppression in __call__() method."""
+ self._check_initialized()
+ configuration = self._style_checker_configuration()
+ error_handler = self._error_handler(configuration)
+
+ confidence = 5
+
+ # First call: usual reporting.
+ self._call_error_handler(error_handler, confidence)
+ self.assertEquals(1, self._error_count)
+ self.assertEquals(1, len(self._error_messages))
+ self.assertEquals(self._error_messages,
+ ["foo.h(100): message [whitespace/tab] [5]\n"])
+
+ # Second call: suppression message reported.
+ self._call_error_handler(error_handler, confidence)
+ # The "Suppressing further..." message counts as an additional
+ # message (but not as an addition to the error count).
+ self.assertEquals(2, self._error_count)
+ self.assertEquals(3, len(self._error_messages))
+ self.assertEquals(self._error_messages[-2],
+ "foo.h(100): message [whitespace/tab] [5]\n")
+ self.assertEquals(self._error_messages[-1],
+ "Suppressing further [whitespace/tab] reports "
+ "for this file.\n")
+
+ # Third call: no report.
+ self._call_error_handler(error_handler, confidence)
+ self.assertEquals(3, self._error_count)
+ self.assertEquals(3, len(self._error_messages))
+
+ def test_line_numbers(self):
+ """Test the line_numbers parameter."""
+ self._check_initialized()
+ configuration = self._style_checker_configuration()
+ error_handler = self._error_handler(configuration,
+ line_numbers=[50])
+ confidence = 5
+
+ # Error on non-modified line: no error.
+ self._call_error_handler(error_handler, confidence, line_number=60)
+ self.assertEquals(0, self._error_count)
+ self.assertEquals([], self._error_messages)
+
+ # Error on modified line: error.
+ self._call_error_handler(error_handler, confidence, line_number=50)
+ self.assertEquals(1, self._error_count)
+ self.assertEquals(self._error_messages,
+ ["foo.h(50): message [whitespace/tab] [5]\n"])
diff --git a/Tools/Scripts/webkitpy/style/filereader.py b/Tools/Scripts/webkitpy/style/filereader.py
new file mode 100644
index 0000000..1a24cb5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/filereader.py
@@ -0,0 +1,162 @@
+# Copyright (C) 2009 Google Inc. All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+# Copyright (C) 2010 ProFUSION embedded systems
+#
+# 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.
+
+"""Supports reading and processing text files."""
+
+import codecs
+import logging
+import os
+import sys
+
+
+_log = logging.getLogger(__name__)
+
+
+class TextFileReader(object):
+
+ """Supports reading and processing text files.
+
+ Attributes:
+ file_count: The total number of files passed to this instance
+ for processing, including non-text files and files
+ that should be skipped.
+ delete_only_file_count: The total number of files that are not
+ processed this instance actually because
+ the files don't have any modified lines
+ but should be treated as processed.
+
+ """
+
+ def __init__(self, processor):
+ """Create an instance.
+
+ Arguments:
+ processor: A ProcessorBase instance.
+
+ """
+ self._processor = processor
+ self.file_count = 0
+ self.delete_only_file_count = 0
+
+ def _read_lines(self, file_path):
+ """Read the file at a path, and return its lines.
+
+ Raises:
+ IOError: If the file does not exist or cannot be read.
+
+ """
+ # Support the UNIX convention of using "-" for stdin.
+ if file_path == '-':
+ file = codecs.StreamReaderWriter(sys.stdin,
+ codecs.getreader('utf8'),
+ codecs.getwriter('utf8'),
+ 'replace')
+ else:
+ # We do not open the file with universal newline support
+ # (codecs does not support it anyway), so the resulting
+ # lines contain trailing "\r" characters if we are reading
+ # a file with CRLF endings.
+ file = codecs.open(file_path, 'r', 'utf8', 'replace')
+
+ try:
+ contents = file.read()
+ finally:
+ file.close()
+
+ lines = contents.split('\n')
+ return lines
+
+ def process_file(self, file_path, **kwargs):
+ """Process the given file by calling the processor's process() method.
+
+ Args:
+ file_path: The path of the file to process.
+ **kwargs: Any additional keyword parameters that should be passed
+ to the processor's process() method. The process()
+ method should support these keyword arguments.
+
+ Raises:
+ SystemExit: If no file at file_path exists.
+
+ """
+ self.file_count += 1
+
+ if not os.path.exists(file_path) and file_path != "-":
+ _log.error("File does not exist: '%s'" % file_path)
+ sys.exit(1)
+
+ if not self._processor.should_process(file_path):
+ _log.debug("Skipping file: '%s'" % file_path)
+ return
+ _log.debug("Processing file: '%s'" % file_path)
+
+ try:
+ lines = self._read_lines(file_path)
+ except IOError, err:
+ message = ("Could not read file. Skipping: '%s'\n %s"
+ % (file_path, err))
+ _log.warn(message)
+ return
+
+ self._processor.process(lines, file_path, **kwargs)
+
+ def _process_directory(self, directory):
+ """Process all files in the given directory, recursively.
+
+ Args:
+ directory: A directory path.
+
+ """
+ for dir_path, dir_names, file_names in os.walk(directory):
+ for file_name in file_names:
+ file_path = os.path.join(dir_path, file_name)
+ self.process_file(file_path)
+
+ def process_paths(self, paths):
+ """Process the given file and directory paths.
+
+ Args:
+ paths: A list of file and directory paths.
+
+ """
+ for path in paths:
+ if os.path.isdir(path):
+ self._process_directory(directory=path)
+ else:
+ self.process_file(path)
+
+ def count_delete_only_file(self):
+ """Count up files that contains only deleted lines.
+
+ Files which has no modified or newly-added lines don't need
+ to check style, but should be treated as checked. For that
+ purpose, we just count up the number of such files.
+ """
+ self.delete_only_file_count += 1
diff --git a/Tools/Scripts/webkitpy/style/filereader_unittest.py b/Tools/Scripts/webkitpy/style/filereader_unittest.py
new file mode 100644
index 0000000..6328337
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/filereader_unittest.py
@@ -0,0 +1,166 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Contains unit tests for filereader.py."""
+
+from __future__ import with_statement
+
+import codecs
+import os
+import shutil
+import tempfile
+import unittest
+
+from webkitpy.common.system.logtesting import LoggingTestCase
+from webkitpy.style.checker import ProcessorBase
+from webkitpy.style.filereader import TextFileReader
+
+
+class TextFileReaderTest(LoggingTestCase):
+
+ class MockProcessor(ProcessorBase):
+
+ """A processor for test purposes.
+
+ This processor simply records the parameters passed to its process()
+ method for later checking by the unittest test methods.
+
+ """
+
+ def __init__(self):
+ self.processed = []
+ """The parameters passed for all calls to the process() method."""
+
+ def should_process(self, file_path):
+ return not file_path.endswith('should_not_process.txt')
+
+ def process(self, lines, file_path, test_kwarg=None):
+ self.processed.append((lines, file_path, test_kwarg))
+
+ def setUp(self):
+ LoggingTestCase.setUp(self)
+ processor = TextFileReaderTest.MockProcessor()
+
+ temp_dir = tempfile.mkdtemp()
+
+ self._file_reader = TextFileReader(processor)
+ self._processor = processor
+ self._temp_dir = temp_dir
+
+ def tearDown(self):
+ LoggingTestCase.tearDown(self)
+ shutil.rmtree(self._temp_dir)
+
+ def _create_file(self, rel_path, text, encoding="utf-8"):
+ """Create a file with given text and return the path to the file."""
+ # FIXME: There are better/more secure APIs for creatin tmp file paths.
+ file_path = os.path.join(self._temp_dir, rel_path)
+ with codecs.open(file_path, "w", encoding) as file:
+ file.write(text)
+ return file_path
+
+ def _passed_to_processor(self):
+ """Return the parameters passed to MockProcessor.process()."""
+ return self._processor.processed
+
+ def _assert_file_reader(self, passed_to_processor, file_count):
+ """Assert the state of the file reader."""
+ self.assertEquals(passed_to_processor, self._passed_to_processor())
+ self.assertEquals(file_count, self._file_reader.file_count)
+
+ def test_process_file__does_not_exist(self):
+ try:
+ self._file_reader.process_file('does_not_exist.txt')
+ except SystemExit, err:
+ self.assertEquals(str(err), '1')
+ else:
+ self.fail('No Exception raised.')
+ self._assert_file_reader([], 1)
+ self.assertLog(["ERROR: File does not exist: 'does_not_exist.txt'\n"])
+
+ def test_process_file__is_dir(self):
+ temp_dir = os.path.join(self._temp_dir, 'test_dir')
+ os.mkdir(temp_dir)
+
+ self._file_reader.process_file(temp_dir)
+
+ # Because the log message below contains exception text, it is
+ # possible that the text varies across platforms. For this reason,
+ # we check only the portion of the log message that we control,
+ # namely the text at the beginning.
+ log_messages = self.logMessages()
+ # We remove the message we are looking at to prevent the tearDown()
+ # from raising an exception when it asserts that no log messages
+ # remain.
+ message = log_messages.pop()
+
+ self.assertTrue(message.startswith('WARNING: Could not read file. '
+ "Skipping: '%s'\n " % temp_dir))
+
+ self._assert_file_reader([], 1)
+
+ def test_process_file__should_not_process(self):
+ file_path = self._create_file('should_not_process.txt', 'contents')
+
+ self._file_reader.process_file(file_path)
+ self._assert_file_reader([], 1)
+
+ def test_process_file__multiple_lines(self):
+ file_path = self._create_file('foo.txt', 'line one\r\nline two\n')
+
+ self._file_reader.process_file(file_path)
+ processed = [(['line one\r', 'line two', ''], file_path, None)]
+ self._assert_file_reader(processed, 1)
+
+ def test_process_file__file_stdin(self):
+ file_path = self._create_file('-', 'file contents')
+
+ self._file_reader.process_file(file_path=file_path, test_kwarg='foo')
+ processed = [(['file contents'], file_path, 'foo')]
+ self._assert_file_reader(processed, 1)
+
+ def test_process_file__with_kwarg(self):
+ file_path = self._create_file('foo.txt', 'file contents')
+
+ self._file_reader.process_file(file_path=file_path, test_kwarg='foo')
+ processed = [(['file contents'], file_path, 'foo')]
+ self._assert_file_reader(processed, 1)
+
+ def test_process_paths(self):
+ # We test a list of paths that contains both a file and a directory.
+ dir = os.path.join(self._temp_dir, 'foo_dir')
+ os.mkdir(dir)
+
+ file_path1 = self._create_file('file1.txt', 'foo')
+
+ rel_path = os.path.join('foo_dir', 'file2.txt')
+ file_path2 = self._create_file(rel_path, 'bar')
+
+ self._file_reader.process_paths([dir, file_path1])
+ processed = [(['bar'], file_path2, None),
+ (['foo'], file_path1, None)]
+ self._assert_file_reader(processed, 2)
+
+ def test_count_delete_only_file(self):
+ self._file_reader.count_delete_only_file()
+ delete_only_file_count = self._file_reader.delete_only_file_count
+ self.assertEquals(delete_only_file_count, 1)
diff --git a/Tools/Scripts/webkitpy/style/filter.py b/Tools/Scripts/webkitpy/style/filter.py
new file mode 100644
index 0000000..608a9e6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/filter.py
@@ -0,0 +1,278 @@
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@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.
+#
+# 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.
+
+"""Contains filter-related code."""
+
+
+def validate_filter_rules(filter_rules, all_categories):
+ """Validate the given filter rules, and raise a ValueError if not valid.
+
+ Args:
+ filter_rules: A list of boolean filter rules, for example--
+ ["-whitespace", "+whitespace/braces"]
+ all_categories: A list of all available category names, for example--
+ ["whitespace/tabs", "whitespace/braces"]
+
+ Raises:
+ ValueError: An error occurs if a filter rule does not begin
+ with "+" or "-" or if a filter rule does not match
+ the beginning of some category name in the list
+ of all available categories.
+
+ """
+ for rule in filter_rules:
+ if not (rule.startswith('+') or rule.startswith('-')):
+ raise ValueError('Invalid filter rule "%s": every rule '
+ "must start with + or -." % rule)
+
+ for category in all_categories:
+ if category.startswith(rule[1:]):
+ break
+ else:
+ raise ValueError('Suspected incorrect filter rule "%s": '
+ "the rule does not match the beginning "
+ "of any category name." % rule)
+
+
+class _CategoryFilter(object):
+
+ """Filters whether to check style categories."""
+
+ def __init__(self, filter_rules=None):
+ """Create a category filter.
+
+ Args:
+ filter_rules: A list of strings that are filter rules, which
+ are strings beginning with the plus or minus
+ symbol (+/-). The list should include any
+ default filter rules at the beginning.
+ Defaults to the empty list.
+
+ Raises:
+ ValueError: Invalid filter rule if a rule does not start with
+ plus ("+") or minus ("-").
+
+ """
+ if filter_rules is None:
+ filter_rules = []
+
+ self._filter_rules = filter_rules
+ self._should_check_category = {} # Cached dictionary of category to True/False
+
+ def __str__(self):
+ return ",".join(self._filter_rules)
+
+ # Useful for unit testing.
+ def __eq__(self, other):
+ """Return whether this CategoryFilter instance is equal to another."""
+ return self._filter_rules == other._filter_rules
+
+ # Useful for unit testing.
+ def __ne__(self, other):
+ # Python does not automatically deduce from __eq__().
+ return not (self == other)
+
+ def should_check(self, category):
+ """Return whether the category should be checked.
+
+ The rules for determining whether a category should be checked
+ are as follows. By default all categories should be checked.
+ Then apply the filter rules in order from first to last, with
+ later flags taking precedence.
+
+ A filter rule applies to a category if the string after the
+ leading plus/minus (+/-) matches the beginning of the category
+ name. A plus (+) means the category should be checked, while a
+ minus (-) means the category should not be checked.
+
+ """
+ if category in self._should_check_category:
+ return self._should_check_category[category]
+
+ should_check = True # All categories checked by default.
+ for rule in self._filter_rules:
+ if not category.startswith(rule[1:]):
+ continue
+ should_check = rule.startswith('+')
+ self._should_check_category[category] = should_check # Update cache.
+ return should_check
+
+
+class FilterConfiguration(object):
+
+ """Supports filtering with path-specific and user-specified rules."""
+
+ def __init__(self, base_rules=None, path_specific=None, user_rules=None):
+ """Create a FilterConfiguration instance.
+
+ Args:
+ base_rules: The starting list of filter rules to use for
+ processing. The default is the empty list, which
+ by itself would mean that all categories should be
+ checked.
+
+ path_specific: A list of (sub_paths, path_rules) pairs
+ that stores the path-specific filter rules for
+ appending to the base rules.
+ The "sub_paths" value is a list of path
+ substrings. If a file path contains one of the
+ substrings, then the corresponding path rules
+ are appended. The first substring match takes
+ precedence, i.e. only the first match triggers
+ an append.
+ The "path_rules" value is a list of filter
+ rules that can be appended to the base rules.
+
+ user_rules: A list of filter rules that is always appended
+ to the base rules and any path rules. In other
+ words, the user rules take precedence over the
+ everything. In practice, the user rules are
+ provided by the user from the command line.
+
+ """
+ if base_rules is None:
+ base_rules = []
+ if path_specific is None:
+ path_specific = []
+ if user_rules is None:
+ user_rules = []
+
+ self._base_rules = base_rules
+ self._path_specific = path_specific
+ self._path_specific_lower = None
+ """The backing store for self._get_path_specific_lower()."""
+
+ self._user_rules = user_rules
+
+ self._path_rules_to_filter = {}
+ """Cached dictionary of path rules to CategoryFilter instance."""
+
+ # The same CategoryFilter instance can be shared across
+ # multiple keys in this dictionary. This allows us to take
+ # greater advantage of the caching done by
+ # CategoryFilter.should_check().
+ self._path_to_filter = {}
+ """Cached dictionary of file path to CategoryFilter instance."""
+
+ # Useful for unit testing.
+ def __eq__(self, other):
+ """Return whether this FilterConfiguration is equal to another."""
+ if self._base_rules != other._base_rules:
+ return False
+ if self._path_specific != other._path_specific:
+ return False
+ if self._user_rules != other._user_rules:
+ return False
+
+ return True
+
+ # Useful for unit testing.
+ def __ne__(self, other):
+ # Python does not automatically deduce this from __eq__().
+ return not self.__eq__(other)
+
+ # We use the prefix "_get" since the name "_path_specific_lower"
+ # is already taken up by the data attribute backing store.
+ def _get_path_specific_lower(self):
+ """Return a copy of self._path_specific with the paths lower-cased."""
+ if self._path_specific_lower is None:
+ self._path_specific_lower = []
+ for (sub_paths, path_rules) in self._path_specific:
+ sub_paths = map(str.lower, sub_paths)
+ self._path_specific_lower.append((sub_paths, path_rules))
+ return self._path_specific_lower
+
+ def _path_rules_from_path(self, path):
+ """Determine the path-specific rules to use, and return as a tuple.
+
+ This method returns a tuple rather than a list so the return
+ value can be passed to _filter_from_path_rules() without change.
+
+ """
+ path = path.lower()
+ for (sub_paths, path_rules) in self._get_path_specific_lower():
+ for sub_path in sub_paths:
+ if path.find(sub_path) > -1:
+ return tuple(path_rules)
+ return () # Default to the empty tuple.
+
+ def _filter_from_path_rules(self, path_rules):
+ """Return the CategoryFilter associated to the given path rules.
+
+ Args:
+ path_rules: A tuple of path rules. We require a tuple rather
+ than a list so the value can be used as a dictionary
+ key in self._path_rules_to_filter.
+
+ """
+ # We reuse the same CategoryFilter where possible to take
+ # advantage of the caching they do.
+ if path_rules not in self._path_rules_to_filter:
+ rules = list(self._base_rules) # Make a copy
+ rules.extend(path_rules)
+ rules.extend(self._user_rules)
+ self._path_rules_to_filter[path_rules] = _CategoryFilter(rules)
+
+ return self._path_rules_to_filter[path_rules]
+
+ def _filter_from_path(self, path):
+ """Return the CategoryFilter associated to a path."""
+ if path not in self._path_to_filter:
+ path_rules = self._path_rules_from_path(path)
+ filter = self._filter_from_path_rules(path_rules)
+ self._path_to_filter[path] = filter
+
+ return self._path_to_filter[path]
+
+ def should_check(self, category, path):
+ """Return whether the given category should be checked.
+
+ This method determines whether a category should be checked
+ by checking the category name against the filter rules for
+ the given path.
+
+ For a given path, the filter rules are the combination of
+ the base rules, the path-specific rules, and the user-provided
+ rules -- in that order. As we will describe below, later rules
+ in the list take precedence. The path-specific rules are the
+ rules corresponding to the first element of the "path_specific"
+ parameter that contains a string case-insensitively matching
+ some substring of the path. If there is no such element,
+ there are no path-specific rules for that path.
+
+ Given a list of filter rules, the logic for determining whether
+ a category should be checked is as follows. By default all
+ categories should be checked. Then apply the filter rules in
+ order from first to last, with later flags taking precedence.
+
+ A filter rule applies to a category if the string after the
+ leading plus/minus (+/-) matches the beginning of the category
+ name. A plus (+) means the category should be checked, while a
+ minus (-) means the category should not be checked.
+
+ Args:
+ category: The category name.
+ path: The path of the file being checked.
+
+ """
+ return self._filter_from_path(path).should_check(category)
+
diff --git a/Tools/Scripts/webkitpy/style/filter_unittest.py b/Tools/Scripts/webkitpy/style/filter_unittest.py
new file mode 100644
index 0000000..7b8a5402
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/filter_unittest.py
@@ -0,0 +1,256 @@
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@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.
+#
+# 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.
+
+"""Unit tests for filter.py."""
+
+import unittest
+
+from filter import _CategoryFilter as CategoryFilter
+from filter import validate_filter_rules
+from filter import FilterConfiguration
+
+# On Testing __eq__() and __ne__():
+#
+# In the tests below, we deliberately do not use assertEquals() or
+# assertNotEquals() to test __eq__() or __ne__(). We do this to be
+# very explicit about what we are testing, especially in the case
+# of assertNotEquals().
+#
+# Part of the reason is that it is not immediately clear what
+# expression the unittest module uses to assert "not equals" -- the
+# negation of __eq__() or __ne__(), which are not necessarily
+# equivalent expresions in Python. For example, from Python's "Data
+# Model" documentation--
+#
+# "There are no implied relationships among the comparison
+# operators. The truth of x==y does not imply that x!=y is
+# false. Accordingly, when defining __eq__(), one should
+# also define __ne__() so that the operators will behave as
+# expected."
+#
+# (from http://docs.python.org/reference/datamodel.html#object.__ne__ )
+
+class ValidateFilterRulesTest(unittest.TestCase):
+
+ """Tests validate_filter_rules() function."""
+
+ def test_validate_filter_rules(self):
+ all_categories = ["tabs", "whitespace", "build/include"]
+
+ bad_rules = [
+ "tabs",
+ "*tabs",
+ " tabs",
+ " +tabs",
+ "+whitespace/newline",
+ "+xxx",
+ ]
+
+ good_rules = [
+ "+tabs",
+ "-tabs",
+ "+build"
+ ]
+
+ for rule in bad_rules:
+ self.assertRaises(ValueError, validate_filter_rules,
+ [rule], all_categories)
+
+ for rule in good_rules:
+ # This works: no error.
+ validate_filter_rules([rule], all_categories)
+
+
+class CategoryFilterTest(unittest.TestCase):
+
+ """Tests CategoryFilter class."""
+
+ def test_init(self):
+ """Test __init__ method."""
+ # Test that the attributes are getting set correctly.
+ filter = CategoryFilter(["+"])
+ self.assertEquals(["+"], filter._filter_rules)
+
+ def test_init_default_arguments(self):
+ """Test __init__ method default arguments."""
+ filter = CategoryFilter()
+ self.assertEquals([], filter._filter_rules)
+
+ def test_str(self):
+ """Test __str__ "to string" operator."""
+ filter = CategoryFilter(["+a", "-b"])
+ self.assertEquals(str(filter), "+a,-b")
+
+ def test_eq(self):
+ """Test __eq__ equality function."""
+ filter1 = CategoryFilter(["+a", "+b"])
+ filter2 = CategoryFilter(["+a", "+b"])
+ filter3 = CategoryFilter(["+b", "+a"])
+
+ # See the notes at the top of this module about testing
+ # __eq__() and __ne__().
+ self.assertTrue(filter1.__eq__(filter2))
+ self.assertFalse(filter1.__eq__(filter3))
+
+ def test_ne(self):
+ """Test __ne__ inequality function."""
+ # By default, __ne__ always returns true on different objects.
+ # Thus, just check the distinguishing case to verify that the
+ # code defines __ne__.
+ #
+ # Also, see the notes at the top of this module about testing
+ # __eq__() and __ne__().
+ self.assertFalse(CategoryFilter().__ne__(CategoryFilter()))
+
+ def test_should_check(self):
+ """Test should_check() method."""
+ filter = CategoryFilter()
+ self.assertTrue(filter.should_check("everything"))
+ # Check a second time to exercise cache.
+ self.assertTrue(filter.should_check("everything"))
+
+ filter = CategoryFilter(["-"])
+ self.assertFalse(filter.should_check("anything"))
+ # Check a second time to exercise cache.
+ self.assertFalse(filter.should_check("anything"))
+
+ filter = CategoryFilter(["-", "+ab"])
+ self.assertTrue(filter.should_check("abc"))
+ self.assertFalse(filter.should_check("a"))
+
+ filter = CategoryFilter(["+", "-ab"])
+ self.assertFalse(filter.should_check("abc"))
+ self.assertTrue(filter.should_check("a"))
+
+
+class FilterConfigurationTest(unittest.TestCase):
+
+ """Tests FilterConfiguration class."""
+
+ def _config(self, base_rules, path_specific, user_rules):
+ """Return a FilterConfiguration instance."""
+ return FilterConfiguration(base_rules=base_rules,
+ path_specific=path_specific,
+ user_rules=user_rules)
+
+ def test_init(self):
+ """Test __init__ method."""
+ # Test that the attributes are getting set correctly.
+ # We use parameter values that are different from the defaults.
+ base_rules = ["-"]
+ path_specific = [(["path"], ["+a"])]
+ user_rules = ["+"]
+
+ config = self._config(base_rules, path_specific, user_rules)
+
+ self.assertEquals(base_rules, config._base_rules)
+ self.assertEquals(path_specific, config._path_specific)
+ self.assertEquals(user_rules, config._user_rules)
+
+ def test_default_arguments(self):
+ # Test that the attributes are getting set correctly to the defaults.
+ config = FilterConfiguration()
+
+ self.assertEquals([], config._base_rules)
+ self.assertEquals([], config._path_specific)
+ self.assertEquals([], config._user_rules)
+
+ def test_eq(self):
+ """Test __eq__ method."""
+ # See the notes at the top of this module about testing
+ # __eq__() and __ne__().
+ self.assertTrue(FilterConfiguration().__eq__(FilterConfiguration()))
+
+ # Verify that a difference in any argument causes equality to fail.
+ config = FilterConfiguration()
+
+ # These parameter values are different from the defaults.
+ base_rules = ["-"]
+ path_specific = [(["path"], ["+a"])]
+ user_rules = ["+"]
+
+ self.assertFalse(config.__eq__(FilterConfiguration(
+ base_rules=base_rules)))
+ self.assertFalse(config.__eq__(FilterConfiguration(
+ path_specific=path_specific)))
+ self.assertFalse(config.__eq__(FilterConfiguration(
+ user_rules=user_rules)))
+
+ def test_ne(self):
+ """Test __ne__ method."""
+ # By default, __ne__ always returns true on different objects.
+ # Thus, just check the distinguishing case to verify that the
+ # code defines __ne__.
+ #
+ # Also, see the notes at the top of this module about testing
+ # __eq__() and __ne__().
+ self.assertFalse(FilterConfiguration().__ne__(FilterConfiguration()))
+
+ def test_base_rules(self):
+ """Test effect of base_rules on should_check()."""
+ base_rules = ["-b"]
+ path_specific = []
+ user_rules = []
+
+ config = self._config(base_rules, path_specific, user_rules)
+
+ self.assertTrue(config.should_check("a", "path"))
+ self.assertFalse(config.should_check("b", "path"))
+
+ def test_path_specific(self):
+ """Test effect of path_rules_specifier on should_check()."""
+ base_rules = ["-"]
+ path_specific = [(["path1"], ["+b"]),
+ (["path2"], ["+c"])]
+ user_rules = []
+
+ config = self._config(base_rules, path_specific, user_rules)
+
+ self.assertFalse(config.should_check("c", "path1"))
+ self.assertTrue(config.should_check("c", "path2"))
+ # Test that first match takes precedence.
+ self.assertFalse(config.should_check("c", "path2/path1"))
+
+ def test_path_with_different_case(self):
+ """Test a path that differs only in case."""
+ base_rules = ["-"]
+ path_specific = [(["Foo/"], ["+whitespace"])]
+ user_rules = []
+
+ config = self._config(base_rules, path_specific, user_rules)
+
+ self.assertFalse(config.should_check("whitespace", "Fooo/bar.txt"))
+ self.assertTrue(config.should_check("whitespace", "Foo/bar.txt"))
+ # Test different case.
+ self.assertTrue(config.should_check("whitespace", "FOO/bar.txt"))
+
+ def test_user_rules(self):
+ """Test effect of user_rules on should_check()."""
+ base_rules = ["-"]
+ path_specific = []
+ user_rules = ["+b"]
+
+ config = self._config(base_rules, path_specific, user_rules)
+
+ self.assertFalse(config.should_check("a", "path"))
+ self.assertTrue(config.should_check("b", "path"))
+
diff --git a/Tools/Scripts/webkitpy/style/main.py b/Tools/Scripts/webkitpy/style/main.py
new file mode 100644
index 0000000..83c0323
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/main.py
@@ -0,0 +1,130 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+import logging
+import os
+import sys
+
+from webkitpy.common.system.ospath import relpath as _relpath
+
+
+_log = logging.getLogger(__name__)
+
+
+def change_directory(checkout_root, paths, mock_os=None):
+ """Change the working directory to the WebKit checkout root, if possible.
+
+ If every path in the paths parameter is below the checkout root (or if
+ the paths parameter is empty or None), this method changes the current
+ working directory to the checkout root and converts the paths parameter
+ as described below.
+ This allows the paths being checked to be displayed relative to the
+ checkout root, and for path-specific style checks to work as expected.
+ Path-specific checks include whether files should be skipped, whether
+ custom style rules should apply to certain files, etc.
+ If the checkout root is None or the empty string, this method returns
+ the paths parameter unchanged.
+
+ Returns:
+ paths: A copy of the paths parameter -- possibly converted, as follows.
+ If this method changed the current working directory to the
+ checkout root, then the list is the paths parameter converted to
+ normalized paths relative to the checkout root. Otherwise, the
+ paths are not converted.
+
+ Args:
+ paths: A list of paths to the files that should be checked for style.
+ This argument can be None or the empty list if a git commit
+ or all changes under the checkout root should be checked.
+ checkout_root: The path to the root of the WebKit checkout, or None or
+ the empty string if no checkout could be detected.
+ mock_os: A replacement module for unit testing. Defaults to os.
+
+ """
+ os_module = os if mock_os is None else mock_os
+
+ if paths is not None:
+ paths = list(paths)
+
+ if not checkout_root:
+ if not paths:
+ raise Exception("The paths parameter must be non-empty if "
+ "there is no checkout root.")
+
+ # FIXME: Consider trying to detect the checkout root for each file
+ # being checked rather than only trying to detect the checkout
+ # root for the current working directory. This would allow
+ # files to be checked correctly even if the script is being
+ # run from outside any WebKit checkout.
+ #
+ # Moreover, try to find the "source root" for each file
+ # using path-based heuristics rather than using only the
+ # presence of a WebKit checkout. For example, we could
+ # examine parent directories until a directory is found
+ # containing JavaScriptCore, WebCore, WebKit, Websites,
+ # and Tools.
+ # Then log an INFO message saying that a source root not
+ # in a WebKit checkout was found. This will allow us to check
+ # the style of non-scm copies of the source tree (e.g.
+ # nightlies).
+ _log.warn("WebKit checkout root not found:\n"
+ " Path-dependent style checks may not work correctly.\n"
+ " See the help documentation for more info.")
+
+ return paths
+
+ if paths:
+ # Then try converting all of the paths to paths relative to
+ # the checkout root.
+ rel_paths = []
+ for path in paths:
+ rel_path = _relpath(path, checkout_root)
+ if rel_path is None:
+ # Then the path is not below the checkout root. Since all
+ # paths should be interpreted relative to the same root,
+ # do not interpret any of the paths as relative to the
+ # checkout root. Interpret all of them relative to the
+ # current working directory, and do not change the current
+ # working directory.
+ _log.warn(
+"""Path-dependent style checks may not work correctly:
+
+ One of the given paths is outside the WebKit checkout of the current
+ working directory:
+
+ Path: %s
+ Checkout root: %s
+
+ Pass only files below the checkout root to ensure correct results.
+ See the help documentation for more info.
+"""
+ % (path, checkout_root))
+
+ return paths
+ rel_paths.append(rel_path)
+ # If we got here, the conversion was successful.
+ paths = rel_paths
+
+ _log.debug("Changing to checkout root: " + checkout_root)
+ os_module.chdir(checkout_root)
+
+ return paths
diff --git a/Tools/Scripts/webkitpy/style/main_unittest.py b/Tools/Scripts/webkitpy/style/main_unittest.py
new file mode 100644
index 0000000..fe448f5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/main_unittest.py
@@ -0,0 +1,124 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Unit tests for main.py."""
+
+import os
+import unittest
+
+from main import change_directory
+from webkitpy.style_references import LogTesting
+
+
+class ChangeDirectoryTest(unittest.TestCase):
+
+ """Tests change_directory()."""
+
+ _original_directory = "/original"
+ _checkout_root = "/WebKit"
+
+ class _MockOs(object):
+
+ """A mock os module for unit testing."""
+
+ def __init__(self, test_case):
+ self._test_case = test_case
+ self._current_directory = \
+ ChangeDirectoryTest._original_directory
+
+ def chdir(self, current_directory):
+ self._current_directory = current_directory
+
+ def assertCurrentDirectory(self, expected_directory):
+ self._test_case.assertEquals(expected_directory,
+ self._current_directory)
+
+ def setUp(self):
+ self._log = LogTesting.setUp(self)
+ self._mock_os = self._MockOs(self)
+
+ def tearDown(self):
+ self._log.tearDown()
+
+ # This method is a convenient wrapper for change_working_directory() that
+ # passes the mock_os for this unit testing class.
+ def _change_directory(self, paths, checkout_root):
+ return change_directory(paths=paths,
+ checkout_root=checkout_root,
+ mock_os=self._mock_os)
+
+ def _assert_result(self, actual_return_value, expected_return_value,
+ expected_log_messages, expected_current_directory):
+ self.assertEquals(actual_return_value, expected_return_value)
+ self._log.assertMessages(expected_log_messages)
+ self._mock_os.assertCurrentDirectory(expected_current_directory)
+
+ def test_checkout_root_none_paths_none(self):
+ self.assertRaises(Exception, self._change_directory,
+ checkout_root=None, paths=None)
+ self._log.assertMessages([])
+ self._mock_os.assertCurrentDirectory(self._original_directory)
+
+ def test_checkout_root_none(self):
+ paths = self._change_directory(checkout_root=None,
+ paths=["path1"])
+ log_messages = [
+"""WARNING: WebKit checkout root not found:
+ Path-dependent style checks may not work correctly.
+ See the help documentation for more info.
+"""]
+ self._assert_result(paths, ["path1"], log_messages,
+ self._original_directory)
+
+ def test_paths_none(self):
+ paths = self._change_directory(checkout_root=self._checkout_root,
+ paths=None)
+ self._assert_result(paths, None, [], self._checkout_root)
+
+ def test_paths_convertible(self):
+ paths=["/WebKit/foo1.txt",
+ "/WebKit/foo2.txt"]
+ paths = self._change_directory(checkout_root=self._checkout_root,
+ paths=paths)
+ self._assert_result(paths, ["foo1.txt", "foo2.txt"], [],
+ self._checkout_root)
+
+ def test_with_scm_paths_unconvertible(self):
+ paths=["/WebKit/foo1.txt",
+ "/outside/foo2.txt"]
+ paths = self._change_directory(checkout_root=self._checkout_root,
+ paths=paths)
+ log_messages = [
+"""WARNING: Path-dependent style checks may not work correctly:
+
+ One of the given paths is outside the WebKit checkout of the current
+ working directory:
+
+ Path: /outside/foo2.txt
+ Checkout root: /WebKit
+
+ Pass only files below the checkout root to ensure correct results.
+ See the help documentation for more info.
+
+"""]
+ self._assert_result(paths, paths, log_messages,
+ self._original_directory)
diff --git a/Tools/Scripts/webkitpy/style/optparser.py b/Tools/Scripts/webkitpy/style/optparser.py
new file mode 100644
index 0000000..f4e9923
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/optparser.py
@@ -0,0 +1,457 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Supports the parsing of command-line options for check-webkit-style."""
+
+import logging
+from optparse import OptionParser
+import os.path
+import sys
+
+from filter import validate_filter_rules
+# This module should not import anything from checker.py.
+
+_log = logging.getLogger(__name__)
+
+_USAGE = """usage: %prog [--help] [options] [path1] [path2] ...
+
+Overview:
+ Check coding style according to WebKit style guidelines:
+
+ http://webkit.org/coding/coding-style.html
+
+ Path arguments can be files and directories. If neither a git commit nor
+ paths are passed, then all changes in your source control working directory
+ are checked.
+
+Style errors:
+ This script assigns to every style error a confidence score from 1-5 and
+ a category name. A confidence score of 5 means the error is certainly
+ a problem, and 1 means it could be fine.
+
+ Category names appear in error messages in brackets, for example
+ [whitespace/indent]. See the options section below for an option that
+ displays all available categories and which are reported by default.
+
+Filters:
+ Use filters to configure what errors to report. Filters are specified using
+ a comma-separated list of boolean filter rules. The script reports errors
+ in a category if the category passes the filter, as described below.
+
+ All categories start out passing. Boolean filter rules are then evaluated
+ from left to right, with later rules taking precedence. For example, the
+ rule "+foo" passes any category that starts with "foo", and "-foo" fails
+ any such category. The filter input "-whitespace,+whitespace/braces" fails
+ the category "whitespace/tab" and passes "whitespace/braces".
+
+ Examples: --filter=-whitespace,+whitespace/braces
+ --filter=-whitespace,-runtime/printf,+runtime/printf_format
+ --filter=-,+build/include_what_you_use
+
+Paths:
+ Certain style-checking behavior depends on the paths relative to
+ the WebKit source root of the files being checked. For example,
+ certain types of errors may be handled differently for files in
+ WebKit/gtk/webkit/ (e.g. by suppressing "readability/naming" errors
+ for files in this directory).
+
+ Consequently, if the path relative to the source root cannot be
+ determined for a file being checked, then style checking may not
+ work correctly for that file. This can occur, for example, if no
+ WebKit checkout can be found, or if the source root can be detected,
+ but one of the files being checked lies outside the source tree.
+
+ If a WebKit checkout can be detected and all files being checked
+ are in the source tree, then all paths will automatically be
+ converted to paths relative to the source root prior to checking.
+ This is also useful for display purposes.
+
+ Currently, this command can detect the source root only if the
+ command is run from within a WebKit checkout (i.e. if the current
+ working directory is below the root of a checkout). In particular,
+ it is not recommended to run this script from a directory outside
+ a checkout.
+
+ Running this script from a top-level WebKit source directory and
+ checking only files in the source tree will ensure that all style
+ checking behaves correctly -- whether or not a checkout can be
+ detected. This is because all file paths will already be relative
+ to the source root and so will not need to be converted."""
+
+_EPILOG = ("This script can miss errors and does not substitute for "
+ "code review.")
+
+
+# This class should not have knowledge of the flag key names.
+class DefaultCommandOptionValues(object):
+
+ """Stores the default check-webkit-style command-line options.
+
+ Attributes:
+ output_format: A string that is the default output format.
+ min_confidence: An integer that is the default minimum confidence level.
+
+ """
+
+ def __init__(self, min_confidence, output_format):
+ self.min_confidence = min_confidence
+ self.output_format = output_format
+
+
+# This class should not have knowledge of the flag key names.
+class CommandOptionValues(object):
+
+ """Stores the option values passed by the user via the command line.
+
+ Attributes:
+ is_verbose: A boolean value of whether verbose logging is enabled.
+
+ filter_rules: The list of filter rules provided by the user.
+ These rules are appended to the base rules and
+ path-specific rules and so take precedence over
+ the base filter rules, etc.
+
+ git_commit: A string representing the git commit to check.
+ The default is None.
+
+ min_confidence: An integer between 1 and 5 inclusive that is the
+ minimum confidence level of style errors to report.
+ The default is 1, which reports all errors.
+
+ output_format: A string that is the output format. The supported
+ output formats are "emacs" which emacs can parse
+ and "vs7" which Microsoft Visual Studio 7 can parse.
+
+ """
+ def __init__(self,
+ filter_rules=None,
+ git_commit=None,
+ diff_files=None,
+ is_verbose=False,
+ min_confidence=1,
+ output_format="emacs"):
+ if filter_rules is None:
+ filter_rules = []
+
+ if (min_confidence < 1) or (min_confidence > 5):
+ raise ValueError('Invalid "min_confidence" parameter: value '
+ "must be an integer between 1 and 5 inclusive. "
+ 'Value given: "%s".' % min_confidence)
+
+ if output_format not in ("emacs", "vs7"):
+ raise ValueError('Invalid "output_format" parameter: '
+ 'value must be "emacs" or "vs7". '
+ 'Value given: "%s".' % output_format)
+
+ self.filter_rules = filter_rules
+ self.git_commit = git_commit
+ self.diff_files = diff_files
+ self.is_verbose = is_verbose
+ self.min_confidence = min_confidence
+ self.output_format = output_format
+
+ # Useful for unit testing.
+ def __eq__(self, other):
+ """Return whether this instance is equal to another."""
+ if self.filter_rules != other.filter_rules:
+ return False
+ if self.git_commit != other.git_commit:
+ return False
+ if self.diff_files != other.diff_files:
+ return False
+ if self.is_verbose != other.is_verbose:
+ return False
+ if self.min_confidence != other.min_confidence:
+ return False
+ if self.output_format != other.output_format:
+ return False
+
+ return True
+
+ # Useful for unit testing.
+ def __ne__(self, other):
+ # Python does not automatically deduce this from __eq__().
+ return not self.__eq__(other)
+
+
+class ArgumentPrinter(object):
+
+ """Supports the printing of check-webkit-style command arguments."""
+
+ def _flag_pair_to_string(self, flag_key, flag_value):
+ return '--%(key)s=%(val)s' % {'key': flag_key, 'val': flag_value }
+
+ def to_flag_string(self, options):
+ """Return a flag string of the given CommandOptionValues instance.
+
+ This method orders the flag values alphabetically by the flag key.
+
+ Args:
+ options: A CommandOptionValues instance.
+
+ """
+ flags = {}
+ flags['min-confidence'] = options.min_confidence
+ flags['output'] = options.output_format
+ # Only include the filter flag if user-provided rules are present.
+ filter_rules = options.filter_rules
+ if filter_rules:
+ flags['filter'] = ",".join(filter_rules)
+ if options.git_commit:
+ flags['git-commit'] = options.git_commit
+ if options.diff_files:
+ flags['diff_files'] = options.diff_files
+
+ flag_string = ''
+ # Alphabetizing lets us unit test this method.
+ for key in sorted(flags.keys()):
+ flag_string += self._flag_pair_to_string(key, flags[key]) + ' '
+
+ return flag_string.strip()
+
+
+class ArgumentParser(object):
+
+ # FIXME: Move the documentation of the attributes to the __init__
+ # docstring after making the attributes internal.
+ """Supports the parsing of check-webkit-style command arguments.
+
+ Attributes:
+ create_usage: A function that accepts a DefaultCommandOptionValues
+ instance and returns a string of usage instructions.
+ Defaults to the function that generates the usage
+ string for check-webkit-style.
+ default_options: A DefaultCommandOptionValues instance that provides
+ the default values for options not explicitly
+ provided by the user.
+ stderr_write: A function that takes a string as a parameter and
+ serves as stderr.write. Defaults to sys.stderr.write.
+ This parameter should be specified only for unit tests.
+
+ """
+
+ def __init__(self,
+ all_categories,
+ default_options,
+ base_filter_rules=None,
+ mock_stderr=None,
+ usage=None):
+ """Create an ArgumentParser instance.
+
+ Args:
+ all_categories: The set of all available style categories.
+ default_options: See the corresponding attribute in the class
+ docstring.
+ Keyword Args:
+ base_filter_rules: The list of filter rules at the beginning of
+ the list of rules used to check style. This
+ list has the least precedence when checking
+ style and precedes any user-provided rules.
+ The class uses this parameter only for display
+ purposes to the user. Defaults to the empty list.
+ create_usage: See the documentation of the corresponding
+ attribute in the class docstring.
+ stderr_write: See the documentation of the corresponding
+ attribute in the class docstring.
+
+ """
+ if base_filter_rules is None:
+ base_filter_rules = []
+ stderr = sys.stderr if mock_stderr is None else mock_stderr
+ if usage is None:
+ usage = _USAGE
+
+ self._all_categories = all_categories
+ self._base_filter_rules = base_filter_rules
+
+ # FIXME: Rename these to reflect that they are internal.
+ self.default_options = default_options
+ self.stderr_write = stderr.write
+
+ self._parser = self._create_option_parser(stderr=stderr,
+ usage=usage,
+ default_min_confidence=self.default_options.min_confidence,
+ default_output_format=self.default_options.output_format)
+
+ def _create_option_parser(self, stderr, usage,
+ default_min_confidence, default_output_format):
+ # Since the epilog string is short, it is not necessary to replace
+ # the epilog string with a mock epilog string when testing.
+ # For this reason, we use _EPILOG directly rather than passing it
+ # as an argument like we do for the usage string.
+ parser = OptionParser(usage=usage, epilog=_EPILOG)
+
+ filter_help = ('set a filter to control what categories of style '
+ 'errors to report. Specify a filter using a comma-'
+ 'delimited list of boolean filter rules, for example '
+ '"--filter -whitespace,+whitespace/braces". To display '
+ 'all categories and which are enabled by default, pass '
+ """no value (e.g. '-f ""' or '--filter=').""")
+ parser.add_option("-f", "--filter-rules", metavar="RULES",
+ dest="filter_value", help=filter_help)
+
+ git_commit_help = ("check all changes in the given commit. "
+ "Use 'commit_id..' to check all changes after commmit_id")
+ parser.add_option("-g", "--git-diff", "--git-commit",
+ metavar="COMMIT", dest="git_commit", help=git_commit_help,)
+
+ diff_files_help = "diff the files passed on the command line rather than checking the style of every line"
+ parser.add_option("--diff-files", action="store_true", dest="diff_files", default=False, help=diff_files_help)
+
+ min_confidence_help = ("set the minimum confidence of style errors "
+ "to report. Can be an integer 1-5, with 1 "
+ "displaying all errors. Defaults to %default.")
+ parser.add_option("-m", "--min-confidence", metavar="INT",
+ type="int", dest="min_confidence",
+ default=default_min_confidence,
+ help=min_confidence_help)
+
+ output_format_help = ('set the output format, which can be "emacs" '
+ 'or "vs7" (for Visual Studio). '
+ 'Defaults to "%default".')
+ parser.add_option("-o", "--output-format", metavar="FORMAT",
+ choices=["emacs", "vs7"],
+ dest="output_format", default=default_output_format,
+ help=output_format_help)
+
+ verbose_help = "enable verbose logging."
+ parser.add_option("-v", "--verbose", dest="is_verbose", default=False,
+ action="store_true", help=verbose_help)
+
+ # Override OptionParser's error() method so that option help will
+ # also display when an error occurs. Normally, just the usage
+ # string displays and not option help.
+ parser.error = self._parse_error
+
+ # Override OptionParser's print_help() method so that help output
+ # does not render to the screen while running unit tests.
+ print_help = parser.print_help
+ parser.print_help = lambda: print_help(file=stderr)
+
+ return parser
+
+ def _parse_error(self, error_message):
+ """Print the help string and an error message, and exit."""
+ # The method format_help() includes both the usage string and
+ # the flag options.
+ help = self._parser.format_help()
+ # Separate help from the error message with a single blank line.
+ self.stderr_write(help + "\n")
+ if error_message:
+ _log.error(error_message)
+
+ # Since we are using this method to replace/override the Python
+ # module optparse's OptionParser.error() method, we match its
+ # behavior and exit with status code 2.
+ #
+ # As additional background, Python documentation says--
+ #
+ # "Unix programs generally use 2 for command line syntax errors
+ # and 1 for all other kind of errors."
+ #
+ # (from http://docs.python.org/library/sys.html#sys.exit )
+ sys.exit(2)
+
+ def _exit_with_categories(self):
+ """Exit and print the style categories and default filter rules."""
+ self.stderr_write('\nAll categories:\n')
+ for category in sorted(self._all_categories):
+ self.stderr_write(' ' + category + '\n')
+
+ self.stderr_write('\nDefault filter rules**:\n')
+ for filter_rule in sorted(self._base_filter_rules):
+ self.stderr_write(' ' + filter_rule + '\n')
+ self.stderr_write('\n**The command always evaluates the above rules, '
+ 'and before any --filter flag.\n\n')
+
+ sys.exit(0)
+
+ def _parse_filter_flag(self, flag_value):
+ """Parse the --filter flag, and return a list of filter rules.
+
+ Args:
+ flag_value: A string of comma-separated filter rules, for
+ example "-whitespace,+whitespace/indent".
+
+ """
+ filters = []
+ for uncleaned_filter in flag_value.split(','):
+ filter = uncleaned_filter.strip()
+ if not filter:
+ continue
+ filters.append(filter)
+ return filters
+
+ def parse(self, args):
+ """Parse the command line arguments to check-webkit-style.
+
+ Args:
+ args: A list of command-line arguments as returned by sys.argv[1:].
+
+ Returns:
+ A tuple of (paths, options)
+
+ paths: The list of paths to check.
+ options: A CommandOptionValues instance.
+
+ """
+ (options, paths) = self._parser.parse_args(args=args)
+
+ filter_value = options.filter_value
+ git_commit = options.git_commit
+ diff_files = options.diff_files
+ is_verbose = options.is_verbose
+ min_confidence = options.min_confidence
+ output_format = options.output_format
+
+ if filter_value is not None and not filter_value:
+ # Then the user explicitly passed no filter, for
+ # example "-f ''" or "--filter=".
+ self._exit_with_categories()
+
+ # Validate user-provided values.
+
+ min_confidence = int(min_confidence)
+ if (min_confidence < 1) or (min_confidence > 5):
+ self._parse_error('option --min-confidence: invalid integer: '
+ '%s: value must be between 1 and 5'
+ % min_confidence)
+
+ if filter_value:
+ filter_rules = self._parse_filter_flag(filter_value)
+ else:
+ filter_rules = []
+
+ try:
+ validate_filter_rules(filter_rules, self._all_categories)
+ except ValueError, err:
+ self._parse_error(err)
+
+ options = CommandOptionValues(filter_rules=filter_rules,
+ git_commit=git_commit,
+ diff_files=diff_files,
+ is_verbose=is_verbose,
+ min_confidence=min_confidence,
+ output_format=output_format)
+
+ return (paths, options)
+
diff --git a/Tools/Scripts/webkitpy/style/optparser_unittest.py b/Tools/Scripts/webkitpy/style/optparser_unittest.py
new file mode 100644
index 0000000..a6b64da
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/optparser_unittest.py
@@ -0,0 +1,258 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Unit tests for parser.py."""
+
+import unittest
+
+from webkitpy.common.system.logtesting import LoggingTestCase
+from webkitpy.style.optparser import ArgumentParser
+from webkitpy.style.optparser import ArgumentPrinter
+from webkitpy.style.optparser import CommandOptionValues as ProcessorOptions
+from webkitpy.style.optparser import DefaultCommandOptionValues
+
+
+class ArgumentPrinterTest(unittest.TestCase):
+
+ """Tests the ArgumentPrinter class."""
+
+ _printer = ArgumentPrinter()
+
+ def _create_options(self,
+ output_format='emacs',
+ min_confidence=3,
+ filter_rules=[],
+ git_commit=None):
+ return ProcessorOptions(filter_rules=filter_rules,
+ git_commit=git_commit,
+ min_confidence=min_confidence,
+ output_format=output_format)
+
+ def test_to_flag_string(self):
+ options = self._create_options('vs7', 5, ['+foo', '-bar'], 'git')
+ self.assertEquals('--filter=+foo,-bar --git-commit=git '
+ '--min-confidence=5 --output=vs7',
+ self._printer.to_flag_string(options))
+
+ # This is to check that --filter and --git-commit do not
+ # show up when not user-specified.
+ options = self._create_options()
+ self.assertEquals('--min-confidence=3 --output=emacs',
+ self._printer.to_flag_string(options))
+
+
+class ArgumentParserTest(LoggingTestCase):
+
+ """Test the ArgumentParser class."""
+
+ class _MockStdErr(object):
+
+ def write(self, message):
+ # We do not want the usage string or style categories
+ # to print during unit tests, so print nothing.
+ return
+
+ def _parse(self, args):
+ """Call a test parser.parse()."""
+ parser = self._create_parser()
+ return parser.parse(args)
+
+ def _create_defaults(self):
+ """Return a DefaultCommandOptionValues instance for testing."""
+ base_filter_rules = ["-", "+whitespace"]
+ return DefaultCommandOptionValues(min_confidence=3,
+ output_format="vs7")
+
+ def _create_parser(self):
+ """Return an ArgumentParser instance for testing."""
+ default_options = self._create_defaults()
+
+ all_categories = ["build" ,"whitespace"]
+
+ mock_stderr = self._MockStdErr()
+
+ return ArgumentParser(all_categories=all_categories,
+ base_filter_rules=[],
+ default_options=default_options,
+ mock_stderr=mock_stderr,
+ usage="test usage")
+
+ def test_parse_documentation(self):
+ parse = self._parse
+
+ # FIXME: Test both the printing of the usage string and the
+ # filter categories help.
+
+ # Request the usage string.
+ self.assertRaises(SystemExit, parse, ['--help'])
+ # Request default filter rules and available style categories.
+ self.assertRaises(SystemExit, parse, ['--filter='])
+
+ def test_parse_bad_values(self):
+ parse = self._parse
+
+ # Pass an unsupported argument.
+ self.assertRaises(SystemExit, parse, ['--bad'])
+ self.assertLog(['ERROR: no such option: --bad\n'])
+
+ self.assertRaises(SystemExit, parse, ['--min-confidence=bad'])
+ self.assertLog(['ERROR: option --min-confidence: '
+ "invalid integer value: 'bad'\n"])
+ self.assertRaises(SystemExit, parse, ['--min-confidence=0'])
+ self.assertLog(['ERROR: option --min-confidence: invalid integer: 0: '
+ 'value must be between 1 and 5\n'])
+ self.assertRaises(SystemExit, parse, ['--min-confidence=6'])
+ self.assertLog(['ERROR: option --min-confidence: invalid integer: 6: '
+ 'value must be between 1 and 5\n'])
+ parse(['--min-confidence=1']) # works
+ parse(['--min-confidence=5']) # works
+
+ self.assertRaises(SystemExit, parse, ['--output=bad'])
+ self.assertLog(['ERROR: option --output-format: invalid choice: '
+ "'bad' (choose from 'emacs', 'vs7')\n"])
+ parse(['--output=vs7']) # works
+
+ # Pass a filter rule not beginning with + or -.
+ self.assertRaises(SystemExit, parse, ['--filter=build'])
+ self.assertLog(['ERROR: Invalid filter rule "build": '
+ 'every rule must start with + or -.\n'])
+ parse(['--filter=+build']) # works
+
+ def test_parse_default_arguments(self):
+ parse = self._parse
+
+ (files, options) = parse([])
+
+ self.assertEquals(files, [])
+
+ self.assertEquals(options.filter_rules, [])
+ self.assertEquals(options.git_commit, None)
+ self.assertEquals(options.diff_files, False)
+ self.assertEquals(options.is_verbose, False)
+ self.assertEquals(options.min_confidence, 3)
+ self.assertEquals(options.output_format, 'vs7')
+
+ def test_parse_explicit_arguments(self):
+ parse = self._parse
+
+ # Pass non-default explicit values.
+ (files, options) = parse(['--min-confidence=4'])
+ self.assertEquals(options.min_confidence, 4)
+ (files, options) = parse(['--output=emacs'])
+ self.assertEquals(options.output_format, 'emacs')
+ (files, options) = parse(['-g', 'commit'])
+ self.assertEquals(options.git_commit, 'commit')
+ (files, options) = parse(['--git-commit=commit'])
+ self.assertEquals(options.git_commit, 'commit')
+ (files, options) = parse(['--git-diff=commit'])
+ self.assertEquals(options.git_commit, 'commit')
+ (files, options) = parse(['--verbose'])
+ self.assertEquals(options.is_verbose, True)
+ (files, options) = parse(['--diff-files', 'file.txt'])
+ self.assertEquals(options.diff_files, True)
+
+ # Pass user_rules.
+ (files, options) = parse(['--filter=+build,-whitespace'])
+ self.assertEquals(options.filter_rules,
+ ["+build", "-whitespace"])
+
+ # Pass spurious white space in user rules.
+ (files, options) = parse(['--filter=+build, -whitespace'])
+ self.assertEquals(options.filter_rules,
+ ["+build", "-whitespace"])
+
+ def test_parse_files(self):
+ parse = self._parse
+
+ (files, options) = parse(['foo.cpp'])
+ self.assertEquals(files, ['foo.cpp'])
+
+ # Pass multiple files.
+ (files, options) = parse(['--output=emacs', 'foo.cpp', 'bar.cpp'])
+ self.assertEquals(files, ['foo.cpp', 'bar.cpp'])
+
+
+class CommandOptionValuesTest(unittest.TestCase):
+
+ """Tests CommandOptionValues class."""
+
+ def test_init(self):
+ """Test __init__ constructor."""
+ # Check default parameters.
+ options = ProcessorOptions()
+ self.assertEquals(options.filter_rules, [])
+ self.assertEquals(options.git_commit, None)
+ self.assertEquals(options.is_verbose, False)
+ self.assertEquals(options.min_confidence, 1)
+ self.assertEquals(options.output_format, "emacs")
+
+ # Check argument validation.
+ self.assertRaises(ValueError, ProcessorOptions, output_format="bad")
+ ProcessorOptions(output_format="emacs") # No ValueError: works
+ ProcessorOptions(output_format="vs7") # works
+ self.assertRaises(ValueError, ProcessorOptions, min_confidence=0)
+ self.assertRaises(ValueError, ProcessorOptions, min_confidence=6)
+ ProcessorOptions(min_confidence=1) # works
+ ProcessorOptions(min_confidence=5) # works
+
+ # Check attributes.
+ options = ProcessorOptions(filter_rules=["+"],
+ git_commit="commit",
+ is_verbose=True,
+ min_confidence=3,
+ output_format="vs7")
+ self.assertEquals(options.filter_rules, ["+"])
+ self.assertEquals(options.git_commit, "commit")
+ self.assertEquals(options.is_verbose, True)
+ self.assertEquals(options.min_confidence, 3)
+ self.assertEquals(options.output_format, "vs7")
+
+ def test_eq(self):
+ """Test __eq__ equality function."""
+ self.assertTrue(ProcessorOptions().__eq__(ProcessorOptions()))
+
+ # Also verify that a difference in any argument causes equality to fail.
+
+ # Explicitly create a ProcessorOptions instance with all default
+ # values. We do this to be sure we are assuming the right default
+ # values in our self.assertFalse() calls below.
+ options = ProcessorOptions(filter_rules=[],
+ git_commit=None,
+ is_verbose=False,
+ min_confidence=1,
+ output_format="emacs")
+ # Verify that we created options correctly.
+ self.assertTrue(options.__eq__(ProcessorOptions()))
+
+ self.assertFalse(options.__eq__(ProcessorOptions(filter_rules=["+"])))
+ self.assertFalse(options.__eq__(ProcessorOptions(git_commit="commit")))
+ self.assertFalse(options.__eq__(ProcessorOptions(is_verbose=True)))
+ self.assertFalse(options.__eq__(ProcessorOptions(min_confidence=2)))
+ self.assertFalse(options.__eq__(ProcessorOptions(output_format="vs7")))
+
+ def test_ne(self):
+ """Test __ne__ inequality function."""
+ # By default, __ne__ always returns true on different objects.
+ # Thus, just check the distinguishing case to verify that the
+ # code defines __ne__.
+ self.assertFalse(ProcessorOptions().__ne__(ProcessorOptions()))
+
diff --git a/Tools/Scripts/webkitpy/style/patchreader.py b/Tools/Scripts/webkitpy/style/patchreader.py
new file mode 100644
index 0000000..f44839d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/patchreader.py
@@ -0,0 +1,66 @@
+# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+# Copyright (C) 2010 ProFUSION embedded systems
+#
+# 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 logging
+
+from webkitpy.common.checkout.diff_parser import DiffParser
+
+
+_log = logging.getLogger("webkitpy.style.patchreader")
+
+
+class PatchReader(object):
+ """Supports checking style in patches."""
+
+ def __init__(self, text_file_reader):
+ """Create a PatchReader instance.
+
+ Args:
+ text_file_reader: A TextFileReader instance.
+
+ """
+ self._text_file_reader = text_file_reader
+
+ def check(self, patch_string):
+ """Check style in the given patch."""
+ patch_files = DiffParser(patch_string.splitlines()).files
+
+ for path, diff_file in patch_files.iteritems():
+ line_numbers = diff_file.added_or_modified_line_numbers()
+ _log.debug('Found %s new or modified lines in: %s' % (len(line_numbers), path))
+
+ if not line_numbers:
+ # Don't check files which contain only deleted lines
+ # as they can never add style errors. However, mark them as
+ # processed so that we count up number of such files.
+ self._text_file_reader.count_delete_only_file()
+ continue
+
+ self._text_file_reader.process_file(file_path=path, line_numbers=line_numbers)
diff --git a/Tools/Scripts/webkitpy/style/patchreader_unittest.py b/Tools/Scripts/webkitpy/style/patchreader_unittest.py
new file mode 100644
index 0000000..b121082
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style/patchreader_unittest.py
@@ -0,0 +1,92 @@
+#!/usr/bin/python
+#
+# Copyright (C) 2010 Google Inc. All rights reserved.
+# Copyright (C) 2009 Torch Mobile Inc.
+# Copyright (C) 2009 Apple Inc. All rights reserved.
+# Copyright (C) 2010 Chris Jerdonek (chris.jerdonek@gmail.com)
+#
+# 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 unittest
+
+from webkitpy.style.patchreader import PatchReader
+
+
+class PatchReaderTest(unittest.TestCase):
+
+ """Test the PatchReader class."""
+
+ class MockTextFileReader(object):
+
+ def __init__(self):
+ self.passed_to_process_file = []
+ """A list of (file_path, line_numbers) pairs."""
+ self.delete_only_file_count = 0
+ """A number of times count_delete_only_file() called"""
+
+ def process_file(self, file_path, line_numbers):
+ self.passed_to_process_file.append((file_path, line_numbers))
+
+ def count_delete_only_file(self):
+ self.delete_only_file_count += 1
+
+ def setUp(self):
+ file_reader = self.MockTextFileReader()
+ self._file_reader = file_reader
+ self._patch_checker = PatchReader(file_reader)
+
+ def _call_check_patch(self, patch_string):
+ self._patch_checker.check(patch_string)
+
+ def _assert_checked(self, passed_to_process_file, delete_only_file_count):
+ self.assertEquals(self._file_reader.passed_to_process_file,
+ passed_to_process_file)
+ self.assertEquals(self._file_reader.delete_only_file_count,
+ delete_only_file_count)
+
+ def test_check_patch(self):
+ # The modified line_numbers array for this patch is: [2].
+ self._call_check_patch("""diff --git a/__init__.py b/__init__.py
+index ef65bee..e3db70e 100644
+--- a/__init__.py
++++ b/__init__.py
+@@ -1,1 +1,2 @@
+ # Required for Python to search this directory for module files
++# New line
+""")
+ self._assert_checked([("__init__.py", [2])], 0)
+
+ def test_check_patch_with_deletion(self):
+ self._call_check_patch("""Index: __init__.py
+===================================================================
+--- __init__.py (revision 3593)
++++ __init__.py (working copy)
+@@ -1 +0,0 @@
+-foobar
+""")
+ # _mock_check_file should not be called for the deletion patch.
+ self._assert_checked([], 1)
diff --git a/Tools/Scripts/webkitpy/style_references.py b/Tools/Scripts/webkitpy/style_references.py
new file mode 100644
index 0000000..a21e931
--- /dev/null
+++ b/Tools/Scripts/webkitpy/style_references.py
@@ -0,0 +1,74 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""References to non-style modules used by the style package."""
+
+# This module is a simple facade to the functionality used by the
+# style package that comes from WebKit modules outside the style
+# package.
+#
+# With this module, the only intra-package references (i.e.
+# references to webkitpy modules outside the style folder) that
+# the style package needs to make are relative references to
+# this module. For example--
+#
+# > from .. style_references import parse_patch
+#
+# Similarly, people maintaining non-style code are not beholden
+# to the contents of the style package when refactoring or
+# otherwise changing non-style code. They only have to be aware
+# of this module.
+
+import os
+
+from webkitpy.common.checkout.diff_parser import DiffParser
+from webkitpy.common.system.logtesting import LogTesting
+from webkitpy.common.system.logtesting import TestLogStream
+from webkitpy.common.system.logutils import configure_logging
+from webkitpy.common.checkout.scm import detect_scm_system
+from webkitpy.layout_tests import port
+from webkitpy.layout_tests.layout_package import test_expectations
+from webkitpy.thirdparty.autoinstalled import pep8
+
+
+def detect_checkout():
+ """Return a WebKitCheckout instance, or None if it cannot be found."""
+ cwd = os.path.abspath(os.curdir)
+ scm = detect_scm_system(cwd)
+
+ return None if scm is None else WebKitCheckout(scm)
+
+
+class WebKitCheckout(object):
+
+ """Simple facade to the SCM class for use by style package."""
+
+ def __init__(self, scm):
+ self._scm = scm
+
+ def root_path(self):
+ """Return the checkout root as an absolute path."""
+ return self._scm.checkout_root
+
+ def create_patch(self, git_commit, changed_files=None):
+ # FIXME: SCM.create_patch should understand how to handle None.
+ return self._scm.create_patch(git_commit, changed_files=changed_files or [])
diff --git a/Tools/Scripts/webkitpy/test/__init__.py b/Tools/Scripts/webkitpy/test/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/test/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/test/cat.py b/Tools/Scripts/webkitpy/test/cat.py
new file mode 100644
index 0000000..ae1e143
--- /dev/null
+++ b/Tools/Scripts/webkitpy/test/cat.py
@@ -0,0 +1,42 @@
+# 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.
+
+import os.path
+import sys
+
+# Add WebKitTools/Scripts to the path to ensure we can find webkitpy.
+sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
+
+from webkitpy.common.system import fileutils
+
+
+def command_arguments(*args):
+ return ['python', __file__] + list(args)
+
+
+def main():
+ fileutils.make_stdout_binary()
+ sys.stdout.write(sys.stdin.read())
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/Tools/Scripts/webkitpy/test/cat_unittest.py b/Tools/Scripts/webkitpy/test/cat_unittest.py
new file mode 100644
index 0000000..4ed1f67
--- /dev/null
+++ b/Tools/Scripts/webkitpy/test/cat_unittest.py
@@ -0,0 +1,52 @@
+# 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.
+
+import StringIO
+import os.path
+import sys
+import unittest
+
+from webkitpy.common.system import executive, outputcapture
+from webkitpy.test import cat
+
+
+class CatTest(outputcapture.OutputCaptureTestCaseBase):
+ def assert_cat(self, input):
+ saved_stdin = sys.stdin
+ sys.stdin = StringIO.StringIO(input)
+ cat.main()
+ self.assertStdout(input)
+ sys.stdin = saved_stdin
+
+ def test_basic(self):
+ self.assert_cat('foo bar baz\n')
+
+ def test_no_newline(self):
+ self.assert_cat('foo bar baz')
+
+ def test_unicode(self):
+ self.assert_cat(u'WebKit \u2661 Tor Arne Vestb\u00F8!')
+
+ def test_as_command(self):
+ input = 'foo bar baz\n'
+ output = executive.Executive().run_command(cat.command_arguments(), input=input)
+ self.assertEqual(input, output)
diff --git a/Tools/Scripts/webkitpy/test/echo.py b/Tools/Scripts/webkitpy/test/echo.py
new file mode 100644
index 0000000..f7468f7
--- /dev/null
+++ b/Tools/Scripts/webkitpy/test/echo.py
@@ -0,0 +1,52 @@
+# 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.
+
+import os.path
+import sys
+
+# Add WebKitTools/Scripts to the path to ensure we can find webkitpy.
+sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
+
+from webkitpy.common.system import fileutils
+
+
+def command_arguments(*args):
+ return ['python', __file__] + list(args)
+
+
+def main(args=None):
+ if args is None:
+ args = sys.argv[1:]
+
+ fileutils.make_stdout_binary()
+
+ print_newline = True
+ if len(args) and args[0] == '-n':
+ print_newline = False
+ del args[0]
+ sys.stdout.write(' '.join(args))
+ if print_newline:
+ sys.stdout.write('\n')
+ return 0
+
+if __name__ == '__main__':
+ sys.exit(main())
diff --git a/Tools/Scripts/webkitpy/test/echo_unittest.py b/Tools/Scripts/webkitpy/test/echo_unittest.py
new file mode 100644
index 0000000..bc13b5e
--- /dev/null
+++ b/Tools/Scripts/webkitpy/test/echo_unittest.py
@@ -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.
+
+import os.path
+import sys
+import unittest
+
+from webkitpy.common.system import executive, outputcapture
+from webkitpy.test import echo
+
+
+class EchoTest(outputcapture.OutputCaptureTestCaseBase):
+ def test_basic(self):
+ echo.main(['foo', 'bar', 'baz'])
+ self.assertStdout('foo bar baz\n')
+
+ def test_no_newline(self):
+ echo.main(['-n', 'foo', 'bar', 'baz'])
+ self.assertStdout('foo bar baz')
+
+ def test_unicode(self):
+ echo.main([u'WebKit \u2661', 'Tor Arne', u'Vestb\u00F8!'])
+ self.assertStdout(u'WebKit \u2661 Tor Arne Vestb\u00F8!\n')
+
+ def test_argument_order(self):
+ echo.main(['foo', '-n', 'bar'])
+ self.assertStdout('foo -n bar\n')
+
+ def test_empty_arguments(self):
+ old_argv = sys.argv
+ sys.argv = ['echo.py', 'foo', 'bar', 'baz']
+ echo.main([])
+ self.assertStdout('\n')
+ sys.argv = old_argv
+
+ def test_no_arguments(self):
+ old_argv = sys.argv
+ sys.argv = ['echo.py', 'foo', 'bar', 'baz']
+ echo.main()
+ self.assertStdout('foo bar baz\n')
+ sys.argv = old_argv
+
+ def test_as_command(self):
+ output = executive.Executive().run_command(echo.command_arguments('foo', 'bar', 'baz'))
+ self.assertEqual(output, 'foo bar baz\n')
diff --git a/Tools/Scripts/webkitpy/test/main.py b/Tools/Scripts/webkitpy/test/main.py
new file mode 100644
index 0000000..1038d82
--- /dev/null
+++ b/Tools/Scripts/webkitpy/test/main.py
@@ -0,0 +1,140 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+"""Contains the entry method for test-webkitpy."""
+
+import logging
+import os
+import sys
+import unittest
+
+import webkitpy
+
+
+_log = logging.getLogger(__name__)
+
+
+class Tester(object):
+
+ """Discovers and runs webkitpy unit tests."""
+
+ def _find_unittest_files(self, webkitpy_dir):
+ """Return a list of paths to all unit-test files."""
+ unittest_paths = [] # Return value.
+
+ for dir_path, dir_names, file_names in os.walk(webkitpy_dir):
+ for file_name in file_names:
+ if not file_name.endswith("_unittest.py"):
+ continue
+ unittest_path = os.path.join(dir_path, file_name)
+ unittest_paths.append(unittest_path)
+
+ return unittest_paths
+
+ def _modules_from_paths(self, package_root, paths):
+ """Return a list of fully-qualified module names given paths."""
+ package_path = os.path.abspath(package_root)
+ root_package_name = os.path.split(package_path)[1] # Equals "webkitpy".
+
+ prefix_length = len(package_path)
+
+ modules = []
+ for path in paths:
+ path = os.path.abspath(path)
+ # This gives us, for example: /common/config/ports_unittest.py
+ rel_path = path[prefix_length:]
+ # This gives us, for example: /common/config/ports_unittest
+ rel_path = os.path.splitext(rel_path)[0]
+
+ parts = []
+ while True:
+ (rel_path, tail) = os.path.split(rel_path)
+ if not tail:
+ break
+ parts.insert(0, tail)
+ # We now have, for example: common.config.ports_unittest
+ # FIXME: This is all a hack around the fact that we always prefix webkitpy includes with "webkitpy."
+ parts.insert(0, root_package_name) # Put "webkitpy" at the beginning.
+ module = ".".join(parts)
+ modules.append(module)
+
+ return modules
+
+ def run_tests(self, sys_argv, external_package_paths=None):
+ """Run the unit tests in all *_unittest.py modules in webkitpy.
+
+ This method excludes "webkitpy.common.checkout.scm_unittest" unless
+ the --all option is the second element of sys_argv.
+
+ Args:
+ sys_argv: A reference to sys.argv.
+
+ """
+ if external_package_paths is None:
+ external_package_paths = []
+ else:
+ # FIXME: We should consider moving webkitpy off of using "webkitpy." to prefix
+ # all includes. If we did that, then this would use path instead of dirname(path).
+ # QueueStatusServer.__init__ has a sys.path import hack due to this code.
+ sys.path.extend(set(os.path.dirname(path) for path in external_package_paths))
+
+ if len(sys_argv) > 1 and not sys_argv[-1].startswith("-"):
+ # Then explicit modules or test names were provided, which
+ # the unittest module is equipped to handle.
+ unittest.main(argv=sys_argv, module=None)
+ # No need to return since unitttest.main() exits.
+
+ # Otherwise, auto-detect all unit tests.
+
+ # FIXME: This should be combined with the external_package_paths code above.
+ webkitpy_dir = os.path.dirname(webkitpy.__file__)
+
+ modules = []
+ for path in [webkitpy_dir] + external_package_paths:
+ modules.extend(self._modules_from_paths(path, self._find_unittest_files(path)))
+ modules.sort()
+
+ # This is a sanity check to ensure that the unit-test discovery
+ # methods are working.
+ if len(modules) < 1:
+ raise Exception("No unit-test modules found.")
+
+ for module in modules:
+ _log.debug("Found: %s" % module)
+
+ # FIXME: This is a hack, but I'm tired of commenting out the test.
+ # See https://bugs.webkit.org/show_bug.cgi?id=31818
+ if len(sys_argv) > 1 and sys.argv[1] == "--all":
+ sys.argv.remove("--all")
+ else:
+ excluded_module = "webkitpy.common.checkout.scm_unittest"
+ _log.info("Excluding: %s (use --all to include)" % excluded_module)
+ modules.remove(excluded_module)
+
+ sys_argv.extend(modules)
+
+ # We pass None for the module because we do not want the unittest
+ # module to resolve module names relative to a given module.
+ # (This would require importing all of the unittest modules from
+ # this module.) See the loadTestsFromName() method of the
+ # unittest.TestLoader class for more details on this parameter.
+ unittest.main(argv=sys_argv, module=None)
diff --git a/Tools/Scripts/webkitpy/test/skip.py b/Tools/Scripts/webkitpy/test/skip.py
new file mode 100644
index 0000000..8587d56
--- /dev/null
+++ b/Tools/Scripts/webkitpy/test/skip.py
@@ -0,0 +1,52 @@
+# 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.
+
+import logging
+
+_log = logging.getLogger(__name__)
+
+
+def skip_if(klass, condition, message=None, logger=None):
+ """Makes all test_* methods in a given class no-ops if the given condition
+ is False. Backported from Python 3.1+'s unittest.skipIf decorator."""
+ if not logger:
+ logger = _log
+ if not condition:
+ return klass
+ for name in dir(klass):
+ attr = getattr(klass, name)
+ if not callable(attr):
+ continue
+ if not name.startswith('test_'):
+ continue
+ setattr(klass, name, _skipped_method(attr, message, logger))
+ klass._printed_skipped_message = False
+ return klass
+
+
+def _skipped_method(method, message, logger):
+ def _skip(*args):
+ if method.im_class._printed_skipped_message:
+ return
+ method.im_class._printed_skipped_message = True
+ logger.info('Skipping %s.%s: %s' % (method.__module__, method.im_class.__name__, message))
+ return _skip
diff --git a/Tools/Scripts/webkitpy/test/skip_unittest.py b/Tools/Scripts/webkitpy/test/skip_unittest.py
new file mode 100644
index 0000000..f61a1bb
--- /dev/null
+++ b/Tools/Scripts/webkitpy/test/skip_unittest.py
@@ -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 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.
+
+import StringIO
+import logging
+import unittest
+
+from webkitpy.test.skip import skip_if
+
+
+class SkipTest(unittest.TestCase):
+ def setUp(self):
+ self.logger = logging.getLogger(__name__)
+
+ self.old_level = self.logger.level
+ self.logger.setLevel(logging.INFO)
+
+ self.old_propagate = self.logger.propagate
+ self.logger.propagate = False
+
+ self.log_stream = StringIO.StringIO()
+ self.handler = logging.StreamHandler(self.log_stream)
+ self.logger.addHandler(self.handler)
+
+ self.foo_was_called = False
+
+ def tearDown(self):
+ self.logger.removeHandler(self.handler)
+ self.propagate = self.old_propagate
+ self.logger.setLevel(self.old_level)
+
+ def create_fixture_class(self):
+ class TestSkipFixture(object):
+ def __init__(self, callback):
+ self.callback = callback
+
+ def test_foo(self):
+ self.callback()
+
+ return TestSkipFixture
+
+ def foo_callback(self):
+ self.foo_was_called = True
+
+ def test_skip_if_false(self):
+ klass = skip_if(self.create_fixture_class(), False, 'Should not see this message.', logger=self.logger)
+ klass(self.foo_callback).test_foo()
+ self.assertEqual(self.log_stream.getvalue(), '')
+ self.assertTrue(self.foo_was_called)
+
+ def test_skip_if_true(self):
+ klass = skip_if(self.create_fixture_class(), True, 'Should see this message.', logger=self.logger)
+ klass(self.foo_callback).test_foo()
+ self.assertEqual(self.log_stream.getvalue(), 'Skipping webkitpy.test.skip_unittest.TestSkipFixture: Should see this message.\n')
+ self.assertFalse(self.foo_was_called)
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/thirdparty/BeautifulSoup.py b/Tools/Scripts/webkitpy/thirdparty/BeautifulSoup.py
new file mode 100644
index 0000000..34204e7
--- /dev/null
+++ b/Tools/Scripts/webkitpy/thirdparty/BeautifulSoup.py
@@ -0,0 +1,2000 @@
+"""Beautiful Soup
+Elixir and Tonic
+"The Screen-Scraper's Friend"
+http://www.crummy.com/software/BeautifulSoup/
+
+Beautiful Soup parses a (possibly invalid) XML or HTML document into a
+tree representation. It provides methods and Pythonic idioms that make
+it easy to navigate, search, and modify the tree.
+
+A well-formed XML/HTML document yields a well-formed data
+structure. An ill-formed XML/HTML document yields a correspondingly
+ill-formed data structure. If your document is only locally
+well-formed, you can use this library to find and process the
+well-formed part of it.
+
+Beautiful Soup works with Python 2.2 and up. It has no external
+dependencies, but you'll have more success at converting data to UTF-8
+if you also install these three packages:
+
+* chardet, for auto-detecting character encodings
+ http://chardet.feedparser.org/
+* cjkcodecs and iconv_codec, which add more encodings to the ones supported
+ by stock Python.
+ http://cjkpython.i18n.org/
+
+Beautiful Soup defines classes for two main parsing strategies:
+
+ * BeautifulStoneSoup, for parsing XML, SGML, or your domain-specific
+ language that kind of looks like XML.
+
+ * BeautifulSoup, for parsing run-of-the-mill HTML code, be it valid
+ or invalid. This class has web browser-like heuristics for
+ obtaining a sensible parse tree in the face of common HTML errors.
+
+Beautiful Soup also defines a class (UnicodeDammit) for autodetecting
+the encoding of an HTML or XML document, and converting it to
+Unicode. Much of this code is taken from Mark Pilgrim's Universal Feed Parser.
+
+For more than you ever wanted to know about Beautiful Soup, see the
+documentation:
+http://www.crummy.com/software/BeautifulSoup/documentation.html
+
+Here, have some legalese:
+
+Copyright (c) 2004-2009, Leonard Richardson
+
+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 the the Beautiful Soup Consortium and All
+ Night Kosher Bakery 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, DAMMIT.
+
+"""
+from __future__ import generators
+
+__author__ = "Leonard Richardson (leonardr@segfault.org)"
+__version__ = "3.1.0.1"
+__copyright__ = "Copyright (c) 2004-2009 Leonard Richardson"
+__license__ = "New-style BSD"
+
+import codecs
+import markupbase
+import types
+import re
+from HTMLParser import HTMLParser, HTMLParseError
+try:
+ from htmlentitydefs import name2codepoint
+except ImportError:
+ name2codepoint = {}
+try:
+ set
+except NameError:
+ from sets import Set as set
+
+#These hacks make Beautiful Soup able to parse XML with namespaces
+markupbase._declname_match = re.compile(r'[a-zA-Z][-_.:a-zA-Z0-9]*\s*').match
+
+DEFAULT_OUTPUT_ENCODING = "utf-8"
+
+# First, the classes that represent markup elements.
+
+def sob(unicode, encoding):
+ """Returns either the given Unicode string or its encoding."""
+ if encoding is None:
+ return unicode
+ else:
+ return unicode.encode(encoding)
+
+class PageElement:
+ """Contains the navigational information for some part of the page
+ (either a tag or a piece of text)"""
+
+ def setup(self, parent=None, previous=None):
+ """Sets up the initial relations between this element and
+ other elements."""
+ self.parent = parent
+ self.previous = previous
+ self.next = None
+ self.previousSibling = None
+ self.nextSibling = None
+ if self.parent and self.parent.contents:
+ self.previousSibling = self.parent.contents[-1]
+ self.previousSibling.nextSibling = self
+
+ def replaceWith(self, replaceWith):
+ oldParent = self.parent
+ myIndex = self.parent.contents.index(self)
+ if hasattr(replaceWith, 'parent') and replaceWith.parent == self.parent:
+ # We're replacing this element with one of its siblings.
+ index = self.parent.contents.index(replaceWith)
+ if index and index < myIndex:
+ # Furthermore, it comes before this element. That
+ # means that when we extract it, the index of this
+ # element will change.
+ myIndex = myIndex - 1
+ self.extract()
+ oldParent.insert(myIndex, replaceWith)
+
+ def extract(self):
+ """Destructively rips this element out of the tree."""
+ if self.parent:
+ try:
+ self.parent.contents.remove(self)
+ except ValueError:
+ pass
+
+ #Find the two elements that would be next to each other if
+ #this element (and any children) hadn't been parsed. Connect
+ #the two.
+ lastChild = self._lastRecursiveChild()
+ nextElement = lastChild.next
+
+ if self.previous:
+ self.previous.next = nextElement
+ if nextElement:
+ nextElement.previous = self.previous
+ self.previous = None
+ lastChild.next = None
+
+ self.parent = None
+ if self.previousSibling:
+ self.previousSibling.nextSibling = self.nextSibling
+ if self.nextSibling:
+ self.nextSibling.previousSibling = self.previousSibling
+ self.previousSibling = self.nextSibling = None
+ return self
+
+ def _lastRecursiveChild(self):
+ "Finds the last element beneath this object to be parsed."
+ lastChild = self
+ while hasattr(lastChild, 'contents') and lastChild.contents:
+ lastChild = lastChild.contents[-1]
+ return lastChild
+
+ def insert(self, position, newChild):
+ if (isinstance(newChild, basestring)
+ or isinstance(newChild, unicode)) \
+ and not isinstance(newChild, NavigableString):
+ newChild = NavigableString(newChild)
+
+ position = min(position, len(self.contents))
+ if hasattr(newChild, 'parent') and newChild.parent != None:
+ # We're 'inserting' an element that's already one
+ # of this object's children.
+ if newChild.parent == self:
+ index = self.find(newChild)
+ if index and index < position:
+ # Furthermore we're moving it further down the
+ # list of this object's children. That means that
+ # when we extract this element, our target index
+ # will jump down one.
+ position = position - 1
+ newChild.extract()
+
+ newChild.parent = self
+ previousChild = None
+ if position == 0:
+ newChild.previousSibling = None
+ newChild.previous = self
+ else:
+ previousChild = self.contents[position-1]
+ newChild.previousSibling = previousChild
+ newChild.previousSibling.nextSibling = newChild
+ newChild.previous = previousChild._lastRecursiveChild()
+ if newChild.previous:
+ newChild.previous.next = newChild
+
+ newChildsLastElement = newChild._lastRecursiveChild()
+
+ if position >= len(self.contents):
+ newChild.nextSibling = None
+
+ parent = self
+ parentsNextSibling = None
+ while not parentsNextSibling:
+ parentsNextSibling = parent.nextSibling
+ parent = parent.parent
+ if not parent: # This is the last element in the document.
+ break
+ if parentsNextSibling:
+ newChildsLastElement.next = parentsNextSibling
+ else:
+ newChildsLastElement.next = None
+ else:
+ nextChild = self.contents[position]
+ newChild.nextSibling = nextChild
+ if newChild.nextSibling:
+ newChild.nextSibling.previousSibling = newChild
+ newChildsLastElement.next = nextChild
+
+ if newChildsLastElement.next:
+ newChildsLastElement.next.previous = newChildsLastElement
+ self.contents.insert(position, newChild)
+
+ def append(self, tag):
+ """Appends the given tag to the contents of this tag."""
+ self.insert(len(self.contents), tag)
+
+ def findNext(self, name=None, attrs={}, text=None, **kwargs):
+ """Returns the first item that matches the given criteria and
+ appears after this Tag in the document."""
+ return self._findOne(self.findAllNext, name, attrs, text, **kwargs)
+
+ def findAllNext(self, name=None, attrs={}, text=None, limit=None,
+ **kwargs):
+ """Returns all items that match the given criteria and appear
+ after this Tag in the document."""
+ return self._findAll(name, attrs, text, limit, self.nextGenerator,
+ **kwargs)
+
+ def findNextSibling(self, name=None, attrs={}, text=None, **kwargs):
+ """Returns the closest sibling to this Tag that matches the
+ given criteria and appears after this Tag in the document."""
+ return self._findOne(self.findNextSiblings, name, attrs, text,
+ **kwargs)
+
+ def findNextSiblings(self, name=None, attrs={}, text=None, limit=None,
+ **kwargs):
+ """Returns the siblings of this Tag that match the given
+ criteria and appear after this Tag in the document."""
+ return self._findAll(name, attrs, text, limit,
+ self.nextSiblingGenerator, **kwargs)
+ fetchNextSiblings = findNextSiblings # Compatibility with pre-3.x
+
+ def findPrevious(self, name=None, attrs={}, text=None, **kwargs):
+ """Returns the first item that matches the given criteria and
+ appears before this Tag in the document."""
+ return self._findOne(self.findAllPrevious, name, attrs, text, **kwargs)
+
+ def findAllPrevious(self, name=None, attrs={}, text=None, limit=None,
+ **kwargs):
+ """Returns all items that match the given criteria and appear
+ before this Tag in the document."""
+ return self._findAll(name, attrs, text, limit, self.previousGenerator,
+ **kwargs)
+ fetchPrevious = findAllPrevious # Compatibility with pre-3.x
+
+ def findPreviousSibling(self, name=None, attrs={}, text=None, **kwargs):
+ """Returns the closest sibling to this Tag that matches the
+ given criteria and appears before this Tag in the document."""
+ return self._findOne(self.findPreviousSiblings, name, attrs, text,
+ **kwargs)
+
+ def findPreviousSiblings(self, name=None, attrs={}, text=None,
+ limit=None, **kwargs):
+ """Returns the siblings of this Tag that match the given
+ criteria and appear before this Tag in the document."""
+ return self._findAll(name, attrs, text, limit,
+ self.previousSiblingGenerator, **kwargs)
+ fetchPreviousSiblings = findPreviousSiblings # Compatibility with pre-3.x
+
+ def findParent(self, name=None, attrs={}, **kwargs):
+ """Returns the closest parent of this Tag that matches the given
+ criteria."""
+ # NOTE: We can't use _findOne because findParents takes a different
+ # set of arguments.
+ r = None
+ l = self.findParents(name, attrs, 1)
+ if l:
+ r = l[0]
+ return r
+
+ def findParents(self, name=None, attrs={}, limit=None, **kwargs):
+ """Returns the parents of this Tag that match the given
+ criteria."""
+
+ return self._findAll(name, attrs, None, limit, self.parentGenerator,
+ **kwargs)
+ fetchParents = findParents # Compatibility with pre-3.x
+
+ #These methods do the real heavy lifting.
+
+ def _findOne(self, method, name, attrs, text, **kwargs):
+ r = None
+ l = method(name, attrs, text, 1, **kwargs)
+ if l:
+ r = l[0]
+ return r
+
+ def _findAll(self, name, attrs, text, limit, generator, **kwargs):
+ "Iterates over a generator looking for things that match."
+
+ if isinstance(name, SoupStrainer):
+ strainer = name
+ else:
+ # Build a SoupStrainer
+ strainer = SoupStrainer(name, attrs, text, **kwargs)
+ results = ResultSet(strainer)
+ g = generator()
+ while True:
+ try:
+ i = g.next()
+ except StopIteration:
+ break
+ if i:
+ found = strainer.search(i)
+ if found:
+ results.append(found)
+ if limit and len(results) >= limit:
+ break
+ return results
+
+ #These Generators can be used to navigate starting from both
+ #NavigableStrings and Tags.
+ def nextGenerator(self):
+ i = self
+ while i:
+ i = i.next
+ yield i
+
+ def nextSiblingGenerator(self):
+ i = self
+ while i:
+ i = i.nextSibling
+ yield i
+
+ def previousGenerator(self):
+ i = self
+ while i:
+ i = i.previous
+ yield i
+
+ def previousSiblingGenerator(self):
+ i = self
+ while i:
+ i = i.previousSibling
+ yield i
+
+ def parentGenerator(self):
+ i = self
+ while i:
+ i = i.parent
+ yield i
+
+ # Utility methods
+ def substituteEncoding(self, str, encoding=None):
+ encoding = encoding or "utf-8"
+ return str.replace("%SOUP-ENCODING%", encoding)
+
+ def toEncoding(self, s, encoding=None):
+ """Encodes an object to a string in some encoding, or to Unicode.
+ ."""
+ if isinstance(s, unicode):
+ if encoding:
+ s = s.encode(encoding)
+ elif isinstance(s, str):
+ if encoding:
+ s = s.encode(encoding)
+ else:
+ s = unicode(s)
+ else:
+ if encoding:
+ s = self.toEncoding(str(s), encoding)
+ else:
+ s = unicode(s)
+ return s
+
+class NavigableString(unicode, PageElement):
+
+ def __new__(cls, value):
+ """Create a new NavigableString.
+
+ When unpickling a NavigableString, this method is called with
+ the string in DEFAULT_OUTPUT_ENCODING. That encoding needs to be
+ passed in to the superclass's __new__ or the superclass won't know
+ how to handle non-ASCII characters.
+ """
+ if isinstance(value, unicode):
+ return unicode.__new__(cls, value)
+ return unicode.__new__(cls, value, DEFAULT_OUTPUT_ENCODING)
+
+ def __getnewargs__(self):
+ return (unicode(self),)
+
+ def __getattr__(self, attr):
+ """text.string gives you text. This is for backwards
+ compatibility for Navigable*String, but for CData* it lets you
+ get the string without the CData wrapper."""
+ if attr == 'string':
+ return self
+ else:
+ raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__.__name__, attr)
+
+ def encode(self, encoding=DEFAULT_OUTPUT_ENCODING):
+ return self.decode().encode(encoding)
+
+ def decodeGivenEventualEncoding(self, eventualEncoding):
+ return self
+
+class CData(NavigableString):
+
+ def decodeGivenEventualEncoding(self, eventualEncoding):
+ return u'<![CDATA[' + self + u']]>'
+
+class ProcessingInstruction(NavigableString):
+
+ def decodeGivenEventualEncoding(self, eventualEncoding):
+ output = self
+ if u'%SOUP-ENCODING%' in output:
+ output = self.substituteEncoding(output, eventualEncoding)
+ return u'<?' + output + u'?>'
+
+class Comment(NavigableString):
+ def decodeGivenEventualEncoding(self, eventualEncoding):
+ return u'<!--' + self + u'-->'
+
+class Declaration(NavigableString):
+ def decodeGivenEventualEncoding(self, eventualEncoding):
+ return u'<!' + self + u'>'
+
+class Tag(PageElement):
+
+ """Represents a found HTML tag with its attributes and contents."""
+
+ def _invert(h):
+ "Cheap function to invert a hash."
+ i = {}
+ for k,v in h.items():
+ i[v] = k
+ return i
+
+ XML_ENTITIES_TO_SPECIAL_CHARS = { "apos" : "'",
+ "quot" : '"',
+ "amp" : "&",
+ "lt" : "<",
+ "gt" : ">" }
+
+ XML_SPECIAL_CHARS_TO_ENTITIES = _invert(XML_ENTITIES_TO_SPECIAL_CHARS)
+
+ def _convertEntities(self, match):
+ """Used in a call to re.sub to replace HTML, XML, and numeric
+ entities with the appropriate Unicode characters. If HTML
+ entities are being converted, any unrecognized entities are
+ escaped."""
+ x = match.group(1)
+ if self.convertHTMLEntities and x in name2codepoint:
+ return unichr(name2codepoint[x])
+ elif x in self.XML_ENTITIES_TO_SPECIAL_CHARS:
+ if self.convertXMLEntities:
+ return self.XML_ENTITIES_TO_SPECIAL_CHARS[x]
+ else:
+ return u'&%s;' % x
+ elif len(x) > 0 and x[0] == '#':
+ # Handle numeric entities
+ if len(x) > 1 and x[1] == 'x':
+ return unichr(int(x[2:], 16))
+ else:
+ return unichr(int(x[1:]))
+
+ elif self.escapeUnrecognizedEntities:
+ return u'&amp;%s;' % x
+ else:
+ return u'&%s;' % x
+
+ def __init__(self, parser, name, attrs=None, parent=None,
+ previous=None):
+ "Basic constructor."
+
+ # We don't actually store the parser object: that lets extracted
+ # chunks be garbage-collected
+ self.parserClass = parser.__class__
+ self.isSelfClosing = parser.isSelfClosingTag(name)
+ self.name = name
+ if attrs == None:
+ attrs = []
+ self.attrs = attrs
+ self.contents = []
+ self.setup(parent, previous)
+ self.hidden = False
+ self.containsSubstitutions = False
+ self.convertHTMLEntities = parser.convertHTMLEntities
+ self.convertXMLEntities = parser.convertXMLEntities
+ self.escapeUnrecognizedEntities = parser.escapeUnrecognizedEntities
+
+ def convert(kval):
+ "Converts HTML, XML and numeric entities in the attribute value."
+ k, val = kval
+ if val is None:
+ return kval
+ return (k, re.sub("&(#\d+|#x[0-9a-fA-F]+|\w+);",
+ self._convertEntities, val))
+ self.attrs = map(convert, self.attrs)
+
+ def get(self, key, default=None):
+ """Returns the value of the 'key' attribute for the tag, or
+ the value given for 'default' if it doesn't have that
+ attribute."""
+ return self._getAttrMap().get(key, default)
+
+ def has_key(self, key):
+ return self._getAttrMap().has_key(key)
+
+ def __getitem__(self, key):
+ """tag[key] returns the value of the 'key' attribute for the tag,
+ and throws an exception if it's not there."""
+ return self._getAttrMap()[key]
+
+ def __iter__(self):
+ "Iterating over a tag iterates over its contents."
+ return iter(self.contents)
+
+ def __len__(self):
+ "The length of a tag is the length of its list of contents."
+ return len(self.contents)
+
+ def __contains__(self, x):
+ return x in self.contents
+
+ def __nonzero__(self):
+ "A tag is non-None even if it has no contents."
+ return True
+
+ def __setitem__(self, key, value):
+ """Setting tag[key] sets the value of the 'key' attribute for the
+ tag."""
+ self._getAttrMap()
+ self.attrMap[key] = value
+ found = False
+ for i in range(0, len(self.attrs)):
+ if self.attrs[i][0] == key:
+ self.attrs[i] = (key, value)
+ found = True
+ if not found:
+ self.attrs.append((key, value))
+ self._getAttrMap()[key] = value
+
+ def __delitem__(self, key):
+ "Deleting tag[key] deletes all 'key' attributes for the tag."
+ for item in self.attrs:
+ if item[0] == key:
+ self.attrs.remove(item)
+ #We don't break because bad HTML can define the same
+ #attribute multiple times.
+ self._getAttrMap()
+ if self.attrMap.has_key(key):
+ del self.attrMap[key]
+
+ def __call__(self, *args, **kwargs):
+ """Calling a tag like a function is the same as calling its
+ findAll() method. Eg. tag('a') returns a list of all the A tags
+ found within this tag."""
+ return apply(self.findAll, args, kwargs)
+
+ def __getattr__(self, tag):
+ #print "Getattr %s.%s" % (self.__class__, tag)
+ if len(tag) > 3 and tag.rfind('Tag') == len(tag)-3:
+ return self.find(tag[:-3])
+ elif tag.find('__') != 0:
+ return self.find(tag)
+ raise AttributeError, "'%s' object has no attribute '%s'" % (self.__class__, tag)
+
+ def __eq__(self, other):
+ """Returns true iff this tag has the same name, the same attributes,
+ and the same contents (recursively) as the given tag.
+
+ NOTE: right now this will return false if two tags have the
+ same attributes in a different order. Should this be fixed?"""
+ if not hasattr(other, 'name') or not hasattr(other, 'attrs') or not hasattr(other, 'contents') or self.name != other.name or self.attrs != other.attrs or len(self) != len(other):
+ return False
+ for i in range(0, len(self.contents)):
+ if self.contents[i] != other.contents[i]:
+ return False
+ return True
+
+ def __ne__(self, other):
+ """Returns true iff this tag is not identical to the other tag,
+ as defined in __eq__."""
+ return not self == other
+
+ def __repr__(self, encoding=DEFAULT_OUTPUT_ENCODING):
+ """Renders this tag as a string."""
+ return self.decode(eventualEncoding=encoding)
+
+ BARE_AMPERSAND_OR_BRACKET = re.compile("([<>]|"
+ + "&(?!#\d+;|#x[0-9a-fA-F]+;|\w+;)"
+ + ")")
+
+ def _sub_entity(self, x):
+ """Used with a regular expression to substitute the
+ appropriate XML entity for an XML special character."""
+ return "&" + self.XML_SPECIAL_CHARS_TO_ENTITIES[x.group(0)[0]] + ";"
+
+ def __unicode__(self):
+ return self.decode()
+
+ def __str__(self):
+ return self.encode()
+
+ def encode(self, encoding=DEFAULT_OUTPUT_ENCODING,
+ prettyPrint=False, indentLevel=0):
+ return self.decode(prettyPrint, indentLevel, encoding).encode(encoding)
+
+ def decode(self, prettyPrint=False, indentLevel=0,
+ eventualEncoding=DEFAULT_OUTPUT_ENCODING):
+ """Returns a string or Unicode representation of this tag and
+ its contents. To get Unicode, pass None for encoding."""
+
+ attrs = []
+ if self.attrs:
+ for key, val in self.attrs:
+ fmt = '%s="%s"'
+ if isString(val):
+ if (self.containsSubstitutions
+ and eventualEncoding is not None
+ and '%SOUP-ENCODING%' in val):
+ val = self.substituteEncoding(val, eventualEncoding)
+
+ # The attribute value either:
+ #
+ # * Contains no embedded double quotes or single quotes.
+ # No problem: we enclose it in double quotes.
+ # * Contains embedded single quotes. No problem:
+ # double quotes work here too.
+ # * Contains embedded double quotes. No problem:
+ # we enclose it in single quotes.
+ # * Embeds both single _and_ double quotes. This
+ # can't happen naturally, but it can happen if
+ # you modify an attribute value after parsing
+ # the document. Now we have a bit of a
+ # problem. We solve it by enclosing the
+ # attribute in single quotes, and escaping any
+ # embedded single quotes to XML entities.
+ if '"' in val:
+ fmt = "%s='%s'"
+ if "'" in val:
+ # TODO: replace with apos when
+ # appropriate.
+ val = val.replace("'", "&squot;")
+
+ # Now we're okay w/r/t quotes. But the attribute
+ # value might also contain angle brackets, or
+ # ampersands that aren't part of entities. We need
+ # to escape those to XML entities too.
+ val = self.BARE_AMPERSAND_OR_BRACKET.sub(self._sub_entity, val)
+ if val is None:
+ # Handle boolean attributes.
+ decoded = key
+ else:
+ decoded = fmt % (key, val)
+ attrs.append(decoded)
+ close = ''
+ closeTag = ''
+ if self.isSelfClosing:
+ close = ' /'
+ else:
+ closeTag = '</%s>' % self.name
+
+ indentTag, indentContents = 0, 0
+ if prettyPrint:
+ indentTag = indentLevel
+ space = (' ' * (indentTag-1))
+ indentContents = indentTag + 1
+ contents = self.decodeContents(prettyPrint, indentContents,
+ eventualEncoding)
+ if self.hidden:
+ s = contents
+ else:
+ s = []
+ attributeString = ''
+ if attrs:
+ attributeString = ' ' + ' '.join(attrs)
+ if prettyPrint:
+ s.append(space)
+ s.append('<%s%s%s>' % (self.name, attributeString, close))
+ if prettyPrint:
+ s.append("\n")
+ s.append(contents)
+ if prettyPrint and contents and contents[-1] != "\n":
+ s.append("\n")
+ if prettyPrint and closeTag:
+ s.append(space)
+ s.append(closeTag)
+ if prettyPrint and closeTag and self.nextSibling:
+ s.append("\n")
+ s = ''.join(s)
+ return s
+
+ def decompose(self):
+ """Recursively destroys the contents of this tree."""
+ contents = [i for i in self.contents]
+ for i in contents:
+ if isinstance(i, Tag):
+ i.decompose()
+ else:
+ i.extract()
+ self.extract()
+
+ def prettify(self, encoding=DEFAULT_OUTPUT_ENCODING):
+ return self.encode(encoding, True)
+
+ def encodeContents(self, encoding=DEFAULT_OUTPUT_ENCODING,
+ prettyPrint=False, indentLevel=0):
+ return self.decodeContents(prettyPrint, indentLevel).encode(encoding)
+
+ def decodeContents(self, prettyPrint=False, indentLevel=0,
+ eventualEncoding=DEFAULT_OUTPUT_ENCODING):
+ """Renders the contents of this tag as a string in the given
+ encoding. If encoding is None, returns a Unicode string.."""
+ s=[]
+ for c in self:
+ text = None
+ if isinstance(c, NavigableString):
+ text = c.decodeGivenEventualEncoding(eventualEncoding)
+ elif isinstance(c, Tag):
+ s.append(c.decode(prettyPrint, indentLevel, eventualEncoding))
+ if text and prettyPrint:
+ text = text.strip()
+ if text:
+ if prettyPrint:
+ s.append(" " * (indentLevel-1))
+ s.append(text)
+ if prettyPrint:
+ s.append("\n")
+ return ''.join(s)
+
+ #Soup methods
+
+ def find(self, name=None, attrs={}, recursive=True, text=None,
+ **kwargs):
+ """Return only the first child of this Tag matching the given
+ criteria."""
+ r = None
+ l = self.findAll(name, attrs, recursive, text, 1, **kwargs)
+ if l:
+ r = l[0]
+ return r
+ findChild = find
+
+ def findAll(self, name=None, attrs={}, recursive=True, text=None,
+ limit=None, **kwargs):
+ """Extracts a list of Tag objects that match the given
+ criteria. You can specify the name of the Tag and any
+ attributes you want the Tag to have.
+
+ The value of a key-value pair in the 'attrs' map can be a
+ string, a list of strings, a regular expression object, or a
+ callable that takes a string and returns whether or not the
+ string matches for some custom definition of 'matches'. The
+ same is true of the tag name."""
+ generator = self.recursiveChildGenerator
+ if not recursive:
+ generator = self.childGenerator
+ return self._findAll(name, attrs, text, limit, generator, **kwargs)
+ findChildren = findAll
+
+ # Pre-3.x compatibility methods. Will go away in 4.0.
+ first = find
+ fetch = findAll
+
+ def fetchText(self, text=None, recursive=True, limit=None):
+ return self.findAll(text=text, recursive=recursive, limit=limit)
+
+ def firstText(self, text=None, recursive=True):
+ return self.find(text=text, recursive=recursive)
+
+ # 3.x compatibility methods. Will go away in 4.0.
+ def renderContents(self, encoding=DEFAULT_OUTPUT_ENCODING,
+ prettyPrint=False, indentLevel=0):
+ if encoding is None:
+ return self.decodeContents(prettyPrint, indentLevel, encoding)
+ else:
+ return self.encodeContents(encoding, prettyPrint, indentLevel)
+
+
+ #Private methods
+
+ def _getAttrMap(self):
+ """Initializes a map representation of this tag's attributes,
+ if not already initialized."""
+ if not getattr(self, 'attrMap'):
+ self.attrMap = {}
+ for (key, value) in self.attrs:
+ self.attrMap[key] = value
+ return self.attrMap
+
+ #Generator methods
+ def recursiveChildGenerator(self):
+ if not len(self.contents):
+ raise StopIteration
+ stopNode = self._lastRecursiveChild().next
+ current = self.contents[0]
+ while current is not stopNode:
+ yield current
+ current = current.next
+
+ def childGenerator(self):
+ if not len(self.contents):
+ raise StopIteration
+ current = self.contents[0]
+ while current:
+ yield current
+ current = current.nextSibling
+ raise StopIteration
+
+# Next, a couple classes to represent queries and their results.
+class SoupStrainer:
+ """Encapsulates a number of ways of matching a markup element (tag or
+ text)."""
+
+ def __init__(self, name=None, attrs={}, text=None, **kwargs):
+ self.name = name
+ if isString(attrs):
+ kwargs['class'] = attrs
+ attrs = None
+ if kwargs:
+ if attrs:
+ attrs = attrs.copy()
+ attrs.update(kwargs)
+ else:
+ attrs = kwargs
+ self.attrs = attrs
+ self.text = text
+
+ def __str__(self):
+ if self.text:
+ return self.text
+ else:
+ return "%s|%s" % (self.name, self.attrs)
+
+ def searchTag(self, markupName=None, markupAttrs={}):
+ found = None
+ markup = None
+ if isinstance(markupName, Tag):
+ markup = markupName
+ markupAttrs = markup
+ callFunctionWithTagData = callable(self.name) \
+ and not isinstance(markupName, Tag)
+
+ if (not self.name) \
+ or callFunctionWithTagData \
+ or (markup and self._matches(markup, self.name)) \
+ or (not markup and self._matches(markupName, self.name)):
+ if callFunctionWithTagData:
+ match = self.name(markupName, markupAttrs)
+ else:
+ match = True
+ markupAttrMap = None
+ for attr, matchAgainst in self.attrs.items():
+ if not markupAttrMap:
+ if hasattr(markupAttrs, 'get'):
+ markupAttrMap = markupAttrs
+ else:
+ markupAttrMap = {}
+ for k,v in markupAttrs:
+ markupAttrMap[k] = v
+ attrValue = markupAttrMap.get(attr)
+ if not self._matches(attrValue, matchAgainst):
+ match = False
+ break
+ if match:
+ if markup:
+ found = markup
+ else:
+ found = markupName
+ return found
+
+ def search(self, markup):
+ #print 'looking for %s in %s' % (self, markup)
+ found = None
+ # If given a list of items, scan it for a text element that
+ # matches.
+ if isList(markup) and not isinstance(markup, Tag):
+ for element in markup:
+ if isinstance(element, NavigableString) \
+ and self.search(element):
+ found = element
+ break
+ # If it's a Tag, make sure its name or attributes match.
+ # Don't bother with Tags if we're searching for text.
+ elif isinstance(markup, Tag):
+ if not self.text:
+ found = self.searchTag(markup)
+ # If it's text, make sure the text matches.
+ elif isinstance(markup, NavigableString) or \
+ isString(markup):
+ if self._matches(markup, self.text):
+ found = markup
+ else:
+ raise Exception, "I don't know how to match against a %s" \
+ % markup.__class__
+ return found
+
+ def _matches(self, markup, matchAgainst):
+ #print "Matching %s against %s" % (markup, matchAgainst)
+ result = False
+ if matchAgainst == True and type(matchAgainst) == types.BooleanType:
+ result = markup != None
+ elif callable(matchAgainst):
+ result = matchAgainst(markup)
+ else:
+ #Custom match methods take the tag as an argument, but all
+ #other ways of matching match the tag name as a string.
+ if isinstance(markup, Tag):
+ markup = markup.name
+ if markup is not None and not isString(markup):
+ markup = unicode(markup)
+ #Now we know that chunk is either a string, or None.
+ if hasattr(matchAgainst, 'match'):
+ # It's a regexp object.
+ result = markup and matchAgainst.search(markup)
+ elif (isList(matchAgainst)
+ and (markup is not None or not isString(matchAgainst))):
+ result = markup in matchAgainst
+ elif hasattr(matchAgainst, 'items'):
+ result = markup.has_key(matchAgainst)
+ elif matchAgainst and isString(markup):
+ if isinstance(markup, unicode):
+ matchAgainst = unicode(matchAgainst)
+ else:
+ matchAgainst = str(matchAgainst)
+
+ if not result:
+ result = matchAgainst == markup
+ return result
+
+class ResultSet(list):
+ """A ResultSet is just a list that keeps track of the SoupStrainer
+ that created it."""
+ def __init__(self, source):
+ list.__init__([])
+ self.source = source
+
+# Now, some helper functions.
+
+def isList(l):
+ """Convenience method that works with all 2.x versions of Python
+ to determine whether or not something is listlike."""
+ return ((hasattr(l, '__iter__') and not isString(l))
+ or (type(l) in (types.ListType, types.TupleType)))
+
+def isString(s):
+ """Convenience method that works with all 2.x versions of Python
+ to determine whether or not something is stringlike."""
+ try:
+ return isinstance(s, unicode) or isinstance(s, basestring)
+ except NameError:
+ return isinstance(s, str)
+
+def buildTagMap(default, *args):
+ """Turns a list of maps, lists, or scalars into a single map.
+ Used to build the SELF_CLOSING_TAGS, NESTABLE_TAGS, and
+ NESTING_RESET_TAGS maps out of lists and partial maps."""
+ built = {}
+ for portion in args:
+ if hasattr(portion, 'items'):
+ #It's a map. Merge it.
+ for k,v in portion.items():
+ built[k] = v
+ elif isList(portion) and not isString(portion):
+ #It's a list. Map each item to the default.
+ for k in portion:
+ built[k] = default
+ else:
+ #It's a scalar. Map it to the default.
+ built[portion] = default
+ return built
+
+# Now, the parser classes.
+
+class HTMLParserBuilder(HTMLParser):
+
+ def __init__(self, soup):
+ HTMLParser.__init__(self)
+ self.soup = soup
+
+ # We inherit feed() and reset().
+
+ def handle_starttag(self, name, attrs):
+ if name == 'meta':
+ self.soup.extractCharsetFromMeta(attrs)
+ else:
+ self.soup.unknown_starttag(name, attrs)
+
+ def handle_endtag(self, name):
+ self.soup.unknown_endtag(name)
+
+ def handle_data(self, content):
+ self.soup.handle_data(content)
+
+ def _toStringSubclass(self, text, subclass):
+ """Adds a certain piece of text to the tree as a NavigableString
+ subclass."""
+ self.soup.endData()
+ self.handle_data(text)
+ self.soup.endData(subclass)
+
+ def handle_pi(self, text):
+ """Handle a processing instruction as a ProcessingInstruction
+ object, possibly one with a %SOUP-ENCODING% slot into which an
+ encoding will be plugged later."""
+ if text[:3] == "xml":
+ text = u"xml version='1.0' encoding='%SOUP-ENCODING%'"
+ self._toStringSubclass(text, ProcessingInstruction)
+
+ def handle_comment(self, text):
+ "Handle comments as Comment objects."
+ self._toStringSubclass(text, Comment)
+
+ def handle_charref(self, ref):
+ "Handle character references as data."
+ if self.soup.convertEntities:
+ data = unichr(int(ref))
+ else:
+ data = '&#%s;' % ref
+ self.handle_data(data)
+
+ def handle_entityref(self, ref):
+ """Handle entity references as data, possibly converting known
+ HTML and/or XML entity references to the corresponding Unicode
+ characters."""
+ data = None
+ if self.soup.convertHTMLEntities:
+ try:
+ data = unichr(name2codepoint[ref])
+ except KeyError:
+ pass
+
+ if not data and self.soup.convertXMLEntities:
+ data = self.soup.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref)
+
+ if not data and self.soup.convertHTMLEntities and \
+ not self.soup.XML_ENTITIES_TO_SPECIAL_CHARS.get(ref):
+ # TODO: We've got a problem here. We're told this is
+ # an entity reference, but it's not an XML entity
+ # reference or an HTML entity reference. Nonetheless,
+ # the logical thing to do is to pass it through as an
+ # unrecognized entity reference.
+ #
+ # Except: when the input is "&carol;" this function
+ # will be called with input "carol". When the input is
+ # "AT&T", this function will be called with input
+ # "T". We have no way of knowing whether a semicolon
+ # was present originally, so we don't know whether
+ # this is an unknown entity or just a misplaced
+ # ampersand.
+ #
+ # The more common case is a misplaced ampersand, so I
+ # escape the ampersand and omit the trailing semicolon.
+ data = "&amp;%s" % ref
+ if not data:
+ # This case is different from the one above, because we
+ # haven't already gone through a supposedly comprehensive
+ # mapping of entities to Unicode characters. We might not
+ # have gone through any mapping at all. So the chances are
+ # very high that this is a real entity, and not a
+ # misplaced ampersand.
+ data = "&%s;" % ref
+ self.handle_data(data)
+
+ def handle_decl(self, data):
+ "Handle DOCTYPEs and the like as Declaration objects."
+ self._toStringSubclass(data, Declaration)
+
+ def parse_declaration(self, i):
+ """Treat a bogus SGML declaration as raw data. Treat a CDATA
+ declaration as a CData object."""
+ j = None
+ if self.rawdata[i:i+9] == '<![CDATA[':
+ k = self.rawdata.find(']]>', i)
+ if k == -1:
+ k = len(self.rawdata)
+ data = self.rawdata[i+9:k]
+ j = k+3
+ self._toStringSubclass(data, CData)
+ else:
+ try:
+ j = HTMLParser.parse_declaration(self, i)
+ except HTMLParseError:
+ toHandle = self.rawdata[i:]
+ self.handle_data(toHandle)
+ j = i + len(toHandle)
+ return j
+
+
+class BeautifulStoneSoup(Tag):
+
+ """This class contains the basic parser and search code. It defines
+ a parser that knows nothing about tag behavior except for the
+ following:
+
+ You can't close a tag without closing all the tags it encloses.
+ That is, "<foo><bar></foo>" actually means
+ "<foo><bar></bar></foo>".
+
+ [Another possible explanation is "<foo><bar /></foo>", but since
+ this class defines no SELF_CLOSING_TAGS, it will never use that
+ explanation.]
+
+ This class is useful for parsing XML or made-up markup languages,
+ or when BeautifulSoup makes an assumption counter to what you were
+ expecting."""
+
+ SELF_CLOSING_TAGS = {}
+ NESTABLE_TAGS = {}
+ RESET_NESTING_TAGS = {}
+ QUOTE_TAGS = {}
+ PRESERVE_WHITESPACE_TAGS = []
+
+ MARKUP_MASSAGE = [(re.compile('(<[^<>]*)/>'),
+ lambda x: x.group(1) + ' />'),
+ (re.compile('<!\s+([^<>]*)>'),
+ lambda x: '<!' + x.group(1) + '>')
+ ]
+
+ ROOT_TAG_NAME = u'[document]'
+
+ HTML_ENTITIES = "html"
+ XML_ENTITIES = "xml"
+ XHTML_ENTITIES = "xhtml"
+ # TODO: This only exists for backwards-compatibility
+ ALL_ENTITIES = XHTML_ENTITIES
+
+ # Used when determining whether a text node is all whitespace and
+ # can be replaced with a single space. A text node that contains
+ # fancy Unicode spaces (usually non-breaking) should be left
+ # alone.
+ STRIP_ASCII_SPACES = { 9: None, 10: None, 12: None, 13: None, 32: None, }
+
+ def __init__(self, markup="", parseOnlyThese=None, fromEncoding=None,
+ markupMassage=True, smartQuotesTo=XML_ENTITIES,
+ convertEntities=None, selfClosingTags=None, isHTML=False,
+ builder=HTMLParserBuilder):
+ """The Soup object is initialized as the 'root tag', and the
+ provided markup (which can be a string or a file-like object)
+ is fed into the underlying parser.
+
+ HTMLParser will process most bad HTML, and the BeautifulSoup
+ class has some tricks for dealing with some HTML that kills
+ HTMLParser, but Beautiful Soup can nonetheless choke or lose data
+ if your data uses self-closing tags or declarations
+ incorrectly.
+
+ By default, Beautiful Soup uses regexes to sanitize input,
+ avoiding the vast majority of these problems. If the problems
+ don't apply to you, pass in False for markupMassage, and
+ you'll get better performance.
+
+ The default parser massage techniques fix the two most common
+ instances of invalid HTML that choke HTMLParser:
+
+ <br/> (No space between name of closing tag and tag close)
+ <! --Comment--> (Extraneous whitespace in declaration)
+
+ You can pass in a custom list of (RE object, replace method)
+ tuples to get Beautiful Soup to scrub your input the way you
+ want."""
+
+ self.parseOnlyThese = parseOnlyThese
+ self.fromEncoding = fromEncoding
+ self.smartQuotesTo = smartQuotesTo
+ self.convertEntities = convertEntities
+ # Set the rules for how we'll deal with the entities we
+ # encounter
+ if self.convertEntities:
+ # It doesn't make sense to convert encoded characters to
+ # entities even while you're converting entities to Unicode.
+ # Just convert it all to Unicode.
+ self.smartQuotesTo = None
+ if convertEntities == self.HTML_ENTITIES:
+ self.convertXMLEntities = False
+ self.convertHTMLEntities = True
+ self.escapeUnrecognizedEntities = True
+ elif convertEntities == self.XHTML_ENTITIES:
+ self.convertXMLEntities = True
+ self.convertHTMLEntities = True
+ self.escapeUnrecognizedEntities = False
+ elif convertEntities == self.XML_ENTITIES:
+ self.convertXMLEntities = True
+ self.convertHTMLEntities = False
+ self.escapeUnrecognizedEntities = False
+ else:
+ self.convertXMLEntities = False
+ self.convertHTMLEntities = False
+ self.escapeUnrecognizedEntities = False
+
+ self.instanceSelfClosingTags = buildTagMap(None, selfClosingTags)
+ self.builder = builder(self)
+ self.reset()
+
+ if hasattr(markup, 'read'): # It's a file-type object.
+ markup = markup.read()
+ self.markup = markup
+ self.markupMassage = markupMassage
+ try:
+ self._feed(isHTML=isHTML)
+ except StopParsing:
+ pass
+ self.markup = None # The markup can now be GCed.
+ self.builder = None # So can the builder.
+
+ def _feed(self, inDocumentEncoding=None, isHTML=False):
+ # Convert the document to Unicode.
+ markup = self.markup
+ if isinstance(markup, unicode):
+ if not hasattr(self, 'originalEncoding'):
+ self.originalEncoding = None
+ else:
+ dammit = UnicodeDammit\
+ (markup, [self.fromEncoding, inDocumentEncoding],
+ smartQuotesTo=self.smartQuotesTo, isHTML=isHTML)
+ markup = dammit.unicode
+ self.originalEncoding = dammit.originalEncoding
+ self.declaredHTMLEncoding = dammit.declaredHTMLEncoding
+ if markup:
+ if self.markupMassage:
+ if not isList(self.markupMassage):
+ self.markupMassage = self.MARKUP_MASSAGE
+ for fix, m in self.markupMassage:
+ markup = fix.sub(m, markup)
+ # TODO: We get rid of markupMassage so that the
+ # soup object can be deepcopied later on. Some
+ # Python installations can't copy regexes. If anyone
+ # was relying on the existence of markupMassage, this
+ # might cause problems.
+ del(self.markupMassage)
+ self.builder.reset()
+
+ self.builder.feed(markup)
+ # Close out any unfinished strings and close all the open tags.
+ self.endData()
+ while self.currentTag.name != self.ROOT_TAG_NAME:
+ self.popTag()
+
+ def isSelfClosingTag(self, name):
+ """Returns true iff the given string is the name of a
+ self-closing tag according to this parser."""
+ return self.SELF_CLOSING_TAGS.has_key(name) \
+ or self.instanceSelfClosingTags.has_key(name)
+
+ def reset(self):
+ Tag.__init__(self, self, self.ROOT_TAG_NAME)
+ self.hidden = 1
+ self.builder.reset()
+ self.currentData = []
+ self.currentTag = None
+ self.tagStack = []
+ self.quoteStack = []
+ self.pushTag(self)
+
+ def popTag(self):
+ tag = self.tagStack.pop()
+ # Tags with just one string-owning child get the child as a
+ # 'string' property, so that soup.tag.string is shorthand for
+ # soup.tag.contents[0]
+ if len(self.currentTag.contents) == 1 and \
+ isinstance(self.currentTag.contents[0], NavigableString):
+ self.currentTag.string = self.currentTag.contents[0]
+
+ #print "Pop", tag.name
+ if self.tagStack:
+ self.currentTag = self.tagStack[-1]
+ return self.currentTag
+
+ def pushTag(self, tag):
+ #print "Push", tag.name
+ if self.currentTag:
+ self.currentTag.contents.append(tag)
+ self.tagStack.append(tag)
+ self.currentTag = self.tagStack[-1]
+
+ def endData(self, containerClass=NavigableString):
+ if self.currentData:
+ currentData = u''.join(self.currentData)
+ if (currentData.translate(self.STRIP_ASCII_SPACES) == '' and
+ not set([tag.name for tag in self.tagStack]).intersection(
+ self.PRESERVE_WHITESPACE_TAGS)):
+ if '\n' in currentData:
+ currentData = '\n'
+ else:
+ currentData = ' '
+ self.currentData = []
+ if self.parseOnlyThese and len(self.tagStack) <= 1 and \
+ (not self.parseOnlyThese.text or \
+ not self.parseOnlyThese.search(currentData)):
+ return
+ o = containerClass(currentData)
+ o.setup(self.currentTag, self.previous)
+ if self.previous:
+ self.previous.next = o
+ self.previous = o
+ self.currentTag.contents.append(o)
+
+
+ def _popToTag(self, name, inclusivePop=True):
+ """Pops the tag stack up to and including the most recent
+ instance of the given tag. If inclusivePop is false, pops the tag
+ stack up to but *not* including the most recent instqance of
+ the given tag."""
+ #print "Popping to %s" % name
+ if name == self.ROOT_TAG_NAME:
+ return
+
+ numPops = 0
+ mostRecentTag = None
+ for i in range(len(self.tagStack)-1, 0, -1):
+ if name == self.tagStack[i].name:
+ numPops = len(self.tagStack)-i
+ break
+ if not inclusivePop:
+ numPops = numPops - 1
+
+ for i in range(0, numPops):
+ mostRecentTag = self.popTag()
+ return mostRecentTag
+
+ def _smartPop(self, name):
+
+ """We need to pop up to the previous tag of this type, unless
+ one of this tag's nesting reset triggers comes between this
+ tag and the previous tag of this type, OR unless this tag is a
+ generic nesting trigger and another generic nesting trigger
+ comes between this tag and the previous tag of this type.
+
+ Examples:
+ <p>Foo<b>Bar *<p>* should pop to 'p', not 'b'.
+ <p>Foo<table>Bar *<p>* should pop to 'table', not 'p'.
+ <p>Foo<table><tr>Bar *<p>* should pop to 'tr', not 'p'.
+
+ <li><ul><li> *<li>* should pop to 'ul', not the first 'li'.
+ <tr><table><tr> *<tr>* should pop to 'table', not the first 'tr'
+ <td><tr><td> *<td>* should pop to 'tr', not the first 'td'
+ """
+
+ nestingResetTriggers = self.NESTABLE_TAGS.get(name)
+ isNestable = nestingResetTriggers != None
+ isResetNesting = self.RESET_NESTING_TAGS.has_key(name)
+ popTo = None
+ inclusive = True
+ for i in range(len(self.tagStack)-1, 0, -1):
+ p = self.tagStack[i]
+ if (not p or p.name == name) and not isNestable:
+ #Non-nestable tags get popped to the top or to their
+ #last occurance.
+ popTo = name
+ break
+ if (nestingResetTriggers != None
+ and p.name in nestingResetTriggers) \
+ or (nestingResetTriggers == None and isResetNesting
+ and self.RESET_NESTING_TAGS.has_key(p.name)):
+
+ #If we encounter one of the nesting reset triggers
+ #peculiar to this tag, or we encounter another tag
+ #that causes nesting to reset, pop up to but not
+ #including that tag.
+ popTo = p.name
+ inclusive = False
+ break
+ p = p.parent
+ if popTo:
+ self._popToTag(popTo, inclusive)
+
+ def unknown_starttag(self, name, attrs, selfClosing=0):
+ #print "Start tag %s: %s" % (name, attrs)
+ if self.quoteStack:
+ #This is not a real tag.
+ #print "<%s> is not real!" % name
+ attrs = ''.join(map(lambda(x, y): ' %s="%s"' % (x, y), attrs))
+ self.handle_data('<%s%s>' % (name, attrs))
+ return
+ self.endData()
+
+ if not self.isSelfClosingTag(name) and not selfClosing:
+ self._smartPop(name)
+
+ if self.parseOnlyThese and len(self.tagStack) <= 1 \
+ and (self.parseOnlyThese.text or not self.parseOnlyThese.searchTag(name, attrs)):
+ return
+
+ tag = Tag(self, name, attrs, self.currentTag, self.previous)
+ if self.previous:
+ self.previous.next = tag
+ self.previous = tag
+ self.pushTag(tag)
+ if selfClosing or self.isSelfClosingTag(name):
+ self.popTag()
+ if name in self.QUOTE_TAGS:
+ #print "Beginning quote (%s)" % name
+ self.quoteStack.append(name)
+ self.literal = 1
+ return tag
+
+ def unknown_endtag(self, name):
+ #print "End tag %s" % name
+ if self.quoteStack and self.quoteStack[-1] != name:
+ #This is not a real end tag.
+ #print "</%s> is not real!" % name
+ self.handle_data('</%s>' % name)
+ return
+ self.endData()
+ self._popToTag(name)
+ if self.quoteStack and self.quoteStack[-1] == name:
+ self.quoteStack.pop()
+ self.literal = (len(self.quoteStack) > 0)
+
+ def handle_data(self, data):
+ self.currentData.append(data)
+
+ def extractCharsetFromMeta(self, attrs):
+ self.unknown_starttag('meta', attrs)
+
+
+class BeautifulSoup(BeautifulStoneSoup):
+
+ """This parser knows the following facts about HTML:
+
+ * Some tags have no closing tag and should be interpreted as being
+ closed as soon as they are encountered.
+
+ * The text inside some tags (ie. 'script') may contain tags which
+ are not really part of the document and which should be parsed
+ as text, not tags. If you want to parse the text as tags, you can
+ always fetch it and parse it explicitly.
+
+ * Tag nesting rules:
+
+ Most tags can't be nested at all. For instance, the occurance of
+ a <p> tag should implicitly close the previous <p> tag.
+
+ <p>Para1<p>Para2
+ should be transformed into:
+ <p>Para1</p><p>Para2
+
+ Some tags can be nested arbitrarily. For instance, the occurance
+ of a <blockquote> tag should _not_ implicitly close the previous
+ <blockquote> tag.
+
+ Alice said: <blockquote>Bob said: <blockquote>Blah
+ should NOT be transformed into:
+ Alice said: <blockquote>Bob said: </blockquote><blockquote>Blah
+
+ Some tags can be nested, but the nesting is reset by the
+ interposition of other tags. For instance, a <tr> tag should
+ implicitly close the previous <tr> tag within the same <table>,
+ but not close a <tr> tag in another table.
+
+ <table><tr>Blah<tr>Blah
+ should be transformed into:
+ <table><tr>Blah</tr><tr>Blah
+ but,
+ <tr>Blah<table><tr>Blah
+ should NOT be transformed into
+ <tr>Blah<table></tr><tr>Blah
+
+ Differing assumptions about tag nesting rules are a major source
+ of problems with the BeautifulSoup class. If BeautifulSoup is not
+ treating as nestable a tag your page author treats as nestable,
+ try ICantBelieveItsBeautifulSoup, MinimalSoup, or
+ BeautifulStoneSoup before writing your own subclass."""
+
+ def __init__(self, *args, **kwargs):
+ if not kwargs.has_key('smartQuotesTo'):
+ kwargs['smartQuotesTo'] = self.HTML_ENTITIES
+ kwargs['isHTML'] = True
+ BeautifulStoneSoup.__init__(self, *args, **kwargs)
+
+ SELF_CLOSING_TAGS = buildTagMap(None,
+ ['br' , 'hr', 'input', 'img', 'meta',
+ 'spacer', 'link', 'frame', 'base'])
+
+ PRESERVE_WHITESPACE_TAGS = set(['pre', 'textarea'])
+
+ QUOTE_TAGS = {'script' : None, 'textarea' : None}
+
+ #According to the HTML standard, each of these inline tags can
+ #contain another tag of the same type. Furthermore, it's common
+ #to actually use these tags this way.
+ NESTABLE_INLINE_TAGS = ['span', 'font', 'q', 'object', 'bdo', 'sub', 'sup',
+ 'center']
+
+ #According to the HTML standard, these block tags can contain
+ #another tag of the same type. Furthermore, it's common
+ #to actually use these tags this way.
+ NESTABLE_BLOCK_TAGS = ['blockquote', 'div', 'fieldset', 'ins', 'del']
+
+ #Lists can contain other lists, but there are restrictions.
+ NESTABLE_LIST_TAGS = { 'ol' : [],
+ 'ul' : [],
+ 'li' : ['ul', 'ol'],
+ 'dl' : [],
+ 'dd' : ['dl'],
+ 'dt' : ['dl'] }
+
+ #Tables can contain other tables, but there are restrictions.
+ NESTABLE_TABLE_TAGS = {'table' : [],
+ 'tr' : ['table', 'tbody', 'tfoot', 'thead'],
+ 'td' : ['tr'],
+ 'th' : ['tr'],
+ 'thead' : ['table'],
+ 'tbody' : ['table'],
+ 'tfoot' : ['table'],
+ }
+
+ NON_NESTABLE_BLOCK_TAGS = ['address', 'form', 'p', 'pre']
+
+ #If one of these tags is encountered, all tags up to the next tag of
+ #this type are popped.
+ RESET_NESTING_TAGS = buildTagMap(None, NESTABLE_BLOCK_TAGS, 'noscript',
+ NON_NESTABLE_BLOCK_TAGS,
+ NESTABLE_LIST_TAGS,
+ NESTABLE_TABLE_TAGS)
+
+ NESTABLE_TAGS = buildTagMap([], NESTABLE_INLINE_TAGS, NESTABLE_BLOCK_TAGS,
+ NESTABLE_LIST_TAGS, NESTABLE_TABLE_TAGS)
+
+ # Used to detect the charset in a META tag; see start_meta
+ CHARSET_RE = re.compile("((^|;)\s*charset=)([^;]*)", re.M)
+
+ def extractCharsetFromMeta(self, attrs):
+ """Beautiful Soup can detect a charset included in a META tag,
+ try to convert the document to that charset, and re-parse the
+ document from the beginning."""
+ httpEquiv = None
+ contentType = None
+ contentTypeIndex = None
+ tagNeedsEncodingSubstitution = False
+
+ for i in range(0, len(attrs)):
+ key, value = attrs[i]
+ key = key.lower()
+ if key == 'http-equiv':
+ httpEquiv = value
+ elif key == 'content':
+ contentType = value
+ contentTypeIndex = i
+
+ if httpEquiv and contentType: # It's an interesting meta tag.
+ match = self.CHARSET_RE.search(contentType)
+ if match:
+ if (self.declaredHTMLEncoding is not None or
+ self.originalEncoding == self.fromEncoding):
+ # An HTML encoding was sniffed while converting
+ # the document to Unicode, or an HTML encoding was
+ # sniffed during a previous pass through the
+ # document, or an encoding was specified
+ # explicitly and it worked. Rewrite the meta tag.
+ def rewrite(match):
+ return match.group(1) + "%SOUP-ENCODING%"
+ newAttr = self.CHARSET_RE.sub(rewrite, contentType)
+ attrs[contentTypeIndex] = (attrs[contentTypeIndex][0],
+ newAttr)
+ tagNeedsEncodingSubstitution = True
+ else:
+ # This is our first pass through the document.
+ # Go through it again with the encoding information.
+ newCharset = match.group(3)
+ if newCharset and newCharset != self.originalEncoding:
+ self.declaredHTMLEncoding = newCharset
+ self._feed(self.declaredHTMLEncoding)
+ raise StopParsing
+ pass
+ tag = self.unknown_starttag("meta", attrs)
+ if tag and tagNeedsEncodingSubstitution:
+ tag.containsSubstitutions = True
+
+
+class StopParsing(Exception):
+ pass
+
+class ICantBelieveItsBeautifulSoup(BeautifulSoup):
+
+ """The BeautifulSoup class is oriented towards skipping over
+ common HTML errors like unclosed tags. However, sometimes it makes
+ errors of its own. For instance, consider this fragment:
+
+ <b>Foo<b>Bar</b></b>
+
+ This is perfectly valid (if bizarre) HTML. However, the
+ BeautifulSoup class will implicitly close the first b tag when it
+ encounters the second 'b'. It will think the author wrote
+ "<b>Foo<b>Bar", and didn't close the first 'b' tag, because
+ there's no real-world reason to bold something that's already
+ bold. When it encounters '</b></b>' it will close two more 'b'
+ tags, for a grand total of three tags closed instead of two. This
+ can throw off the rest of your document structure. The same is
+ true of a number of other tags, listed below.
+
+ It's much more common for someone to forget to close a 'b' tag
+ than to actually use nested 'b' tags, and the BeautifulSoup class
+ handles the common case. This class handles the not-co-common
+ case: where you can't believe someone wrote what they did, but
+ it's valid HTML and BeautifulSoup screwed up by assuming it
+ wouldn't be."""
+
+ I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS = \
+ ['em', 'big', 'i', 'small', 'tt', 'abbr', 'acronym', 'strong',
+ 'cite', 'code', 'dfn', 'kbd', 'samp', 'strong', 'var', 'b',
+ 'big']
+
+ I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS = ['noscript']
+
+ NESTABLE_TAGS = buildTagMap([], BeautifulSoup.NESTABLE_TAGS,
+ I_CANT_BELIEVE_THEYRE_NESTABLE_BLOCK_TAGS,
+ I_CANT_BELIEVE_THEYRE_NESTABLE_INLINE_TAGS)
+
+class MinimalSoup(BeautifulSoup):
+ """The MinimalSoup class is for parsing HTML that contains
+ pathologically bad markup. It makes no assumptions about tag
+ nesting, but it does know which tags are self-closing, that
+ <script> tags contain Javascript and should not be parsed, that
+ META tags may contain encoding information, and so on.
+
+ This also makes it better for subclassing than BeautifulStoneSoup
+ or BeautifulSoup."""
+
+ RESET_NESTING_TAGS = buildTagMap('noscript')
+ NESTABLE_TAGS = {}
+
+class BeautifulSOAP(BeautifulStoneSoup):
+ """This class will push a tag with only a single string child into
+ the tag's parent as an attribute. The attribute's name is the tag
+ name, and the value is the string child. An example should give
+ the flavor of the change:
+
+ <foo><bar>baz</bar></foo>
+ =>
+ <foo bar="baz"><bar>baz</bar></foo>
+
+ You can then access fooTag['bar'] instead of fooTag.barTag.string.
+
+ This is, of course, useful for scraping structures that tend to
+ use subelements instead of attributes, such as SOAP messages. Note
+ that it modifies its input, so don't print the modified version
+ out.
+
+ I'm not sure how many people really want to use this class; let me
+ know if you do. Mainly I like the name."""
+
+ def popTag(self):
+ if len(self.tagStack) > 1:
+ tag = self.tagStack[-1]
+ parent = self.tagStack[-2]
+ parent._getAttrMap()
+ if (isinstance(tag, Tag) and len(tag.contents) == 1 and
+ isinstance(tag.contents[0], NavigableString) and
+ not parent.attrMap.has_key(tag.name)):
+ parent[tag.name] = tag.contents[0]
+ BeautifulStoneSoup.popTag(self)
+
+#Enterprise class names! It has come to our attention that some people
+#think the names of the Beautiful Soup parser classes are too silly
+#and "unprofessional" for use in enterprise screen-scraping. We feel
+#your pain! For such-minded folk, the Beautiful Soup Consortium And
+#All-Night Kosher Bakery recommends renaming this file to
+#"RobustParser.py" (or, in cases of extreme enterprisiness,
+#"RobustParserBeanInterface.class") and using the following
+#enterprise-friendly class aliases:
+class RobustXMLParser(BeautifulStoneSoup):
+ pass
+class RobustHTMLParser(BeautifulSoup):
+ pass
+class RobustWackAssHTMLParser(ICantBelieveItsBeautifulSoup):
+ pass
+class RobustInsanelyWackAssHTMLParser(MinimalSoup):
+ pass
+class SimplifyingSOAPParser(BeautifulSOAP):
+ pass
+
+######################################################
+#
+# Bonus library: Unicode, Dammit
+#
+# This class forces XML data into a standard format (usually to UTF-8
+# or Unicode). It is heavily based on code from Mark Pilgrim's
+# Universal Feed Parser. It does not rewrite the XML or HTML to
+# reflect a new encoding: that happens in BeautifulStoneSoup.handle_pi
+# (XML) and BeautifulSoup.start_meta (HTML).
+
+# Autodetects character encodings.
+# Download from http://chardet.feedparser.org/
+try:
+ import chardet
+# import chardet.constants
+# chardet.constants._debug = 1
+except ImportError:
+ chardet = None
+
+# cjkcodecs and iconv_codec make Python know about more character encodings.
+# Both are available from http://cjkpython.i18n.org/
+# They're built in if you use Python 2.4.
+try:
+ import cjkcodecs.aliases
+except ImportError:
+ pass
+try:
+ import iconv_codec
+except ImportError:
+ pass
+
+class UnicodeDammit:
+ """A class for detecting the encoding of a *ML document and
+ converting it to a Unicode string. If the source encoding is
+ windows-1252, can replace MS smart quotes with their HTML or XML
+ equivalents."""
+
+ # This dictionary maps commonly seen values for "charset" in HTML
+ # meta tags to the corresponding Python codec names. It only covers
+ # values that aren't in Python's aliases and can't be determined
+ # by the heuristics in find_codec.
+ CHARSET_ALIASES = { "macintosh" : "mac-roman",
+ "x-sjis" : "shift-jis" }
+
+ def __init__(self, markup, overrideEncodings=[],
+ smartQuotesTo='xml', isHTML=False):
+ self.declaredHTMLEncoding = None
+ self.markup, documentEncoding, sniffedEncoding = \
+ self._detectEncoding(markup, isHTML)
+ self.smartQuotesTo = smartQuotesTo
+ self.triedEncodings = []
+ if markup == '' or isinstance(markup, unicode):
+ self.originalEncoding = None
+ self.unicode = unicode(markup)
+ return
+
+ u = None
+ for proposedEncoding in overrideEncodings:
+ u = self._convertFrom(proposedEncoding)
+ if u: break
+ if not u:
+ for proposedEncoding in (documentEncoding, sniffedEncoding):
+ u = self._convertFrom(proposedEncoding)
+ if u: break
+
+ # If no luck and we have auto-detection library, try that:
+ if not u and chardet and not isinstance(self.markup, unicode):
+ u = self._convertFrom(chardet.detect(self.markup)['encoding'])
+
+ # As a last resort, try utf-8 and windows-1252:
+ if not u:
+ for proposed_encoding in ("utf-8", "windows-1252"):
+ u = self._convertFrom(proposed_encoding)
+ if u: break
+
+ self.unicode = u
+ if not u: self.originalEncoding = None
+
+ def _subMSChar(self, match):
+ """Changes a MS smart quote character to an XML or HTML
+ entity."""
+ orig = match.group(1)
+ sub = self.MS_CHARS.get(orig)
+ if type(sub) == types.TupleType:
+ if self.smartQuotesTo == 'xml':
+ sub = '&#x'.encode() + sub[1].encode() + ';'.encode()
+ else:
+ sub = '&'.encode() + sub[0].encode() + ';'.encode()
+ else:
+ sub = sub.encode()
+ return sub
+
+ def _convertFrom(self, proposed):
+ proposed = self.find_codec(proposed)
+ if not proposed or proposed in self.triedEncodings:
+ return None
+ self.triedEncodings.append(proposed)
+ markup = self.markup
+
+ # Convert smart quotes to HTML if coming from an encoding
+ # that might have them.
+ if self.smartQuotesTo and proposed.lower() in("windows-1252",
+ "iso-8859-1",
+ "iso-8859-2"):
+ smart_quotes_re = "([\x80-\x9f])"
+ smart_quotes_compiled = re.compile(smart_quotes_re)
+ markup = smart_quotes_compiled.sub(self._subMSChar, markup)
+
+ try:
+ # print "Trying to convert document to %s" % proposed
+ u = self._toUnicode(markup, proposed)
+ self.markup = u
+ self.originalEncoding = proposed
+ except Exception, e:
+ # print "That didn't work!"
+ # print e
+ return None
+ #print "Correct encoding: %s" % proposed
+ return self.markup
+
+ def _toUnicode(self, data, encoding):
+ '''Given a string and its encoding, decodes the string into Unicode.
+ %encoding is a string recognized by encodings.aliases'''
+
+ # strip Byte Order Mark (if present)
+ if (len(data) >= 4) and (data[:2] == '\xfe\xff') \
+ and (data[2:4] != '\x00\x00'):
+ encoding = 'utf-16be'
+ data = data[2:]
+ elif (len(data) >= 4) and (data[:2] == '\xff\xfe') \
+ and (data[2:4] != '\x00\x00'):
+ encoding = 'utf-16le'
+ data = data[2:]
+ elif data[:3] == '\xef\xbb\xbf':
+ encoding = 'utf-8'
+ data = data[3:]
+ elif data[:4] == '\x00\x00\xfe\xff':
+ encoding = 'utf-32be'
+ data = data[4:]
+ elif data[:4] == '\xff\xfe\x00\x00':
+ encoding = 'utf-32le'
+ data = data[4:]
+ newdata = unicode(data, encoding)
+ return newdata
+
+ def _detectEncoding(self, xml_data, isHTML=False):
+ """Given a document, tries to detect its XML encoding."""
+ xml_encoding = sniffed_xml_encoding = None
+ try:
+ if xml_data[:4] == '\x4c\x6f\xa7\x94':
+ # EBCDIC
+ xml_data = self._ebcdic_to_ascii(xml_data)
+ elif xml_data[:4] == '\x00\x3c\x00\x3f':
+ # UTF-16BE
+ sniffed_xml_encoding = 'utf-16be'
+ xml_data = unicode(xml_data, 'utf-16be').encode('utf-8')
+ elif (len(xml_data) >= 4) and (xml_data[:2] == '\xfe\xff') \
+ and (xml_data[2:4] != '\x00\x00'):
+ # UTF-16BE with BOM
+ sniffed_xml_encoding = 'utf-16be'
+ xml_data = unicode(xml_data[2:], 'utf-16be').encode('utf-8')
+ elif xml_data[:4] == '\x3c\x00\x3f\x00':
+ # UTF-16LE
+ sniffed_xml_encoding = 'utf-16le'
+ xml_data = unicode(xml_data, 'utf-16le').encode('utf-8')
+ elif (len(xml_data) >= 4) and (xml_data[:2] == '\xff\xfe') and \
+ (xml_data[2:4] != '\x00\x00'):
+ # UTF-16LE with BOM
+ sniffed_xml_encoding = 'utf-16le'
+ xml_data = unicode(xml_data[2:], 'utf-16le').encode('utf-8')
+ elif xml_data[:4] == '\x00\x00\x00\x3c':
+ # UTF-32BE
+ sniffed_xml_encoding = 'utf-32be'
+ xml_data = unicode(xml_data, 'utf-32be').encode('utf-8')
+ elif xml_data[:4] == '\x3c\x00\x00\x00':
+ # UTF-32LE
+ sniffed_xml_encoding = 'utf-32le'
+ xml_data = unicode(xml_data, 'utf-32le').encode('utf-8')
+ elif xml_data[:4] == '\x00\x00\xfe\xff':
+ # UTF-32BE with BOM
+ sniffed_xml_encoding = 'utf-32be'
+ xml_data = unicode(xml_data[4:], 'utf-32be').encode('utf-8')
+ elif xml_data[:4] == '\xff\xfe\x00\x00':
+ # UTF-32LE with BOM
+ sniffed_xml_encoding = 'utf-32le'
+ xml_data = unicode(xml_data[4:], 'utf-32le').encode('utf-8')
+ elif xml_data[:3] == '\xef\xbb\xbf':
+ # UTF-8 with BOM
+ sniffed_xml_encoding = 'utf-8'
+ xml_data = unicode(xml_data[3:], 'utf-8').encode('utf-8')
+ else:
+ sniffed_xml_encoding = 'ascii'
+ pass
+ except:
+ xml_encoding_match = None
+ xml_encoding_re = '^<\?.*encoding=[\'"](.*?)[\'"].*\?>'.encode()
+ xml_encoding_match = re.compile(xml_encoding_re).match(xml_data)
+ if not xml_encoding_match and isHTML:
+ meta_re = '<\s*meta[^>]+charset=([^>]*?)[;\'">]'.encode()
+ regexp = re.compile(meta_re, re.I)
+ xml_encoding_match = regexp.search(xml_data)
+ if xml_encoding_match is not None:
+ xml_encoding = xml_encoding_match.groups()[0].decode(
+ 'ascii').lower()
+ if isHTML:
+ self.declaredHTMLEncoding = xml_encoding
+ if sniffed_xml_encoding and \
+ (xml_encoding in ('iso-10646-ucs-2', 'ucs-2', 'csunicode',
+ 'iso-10646-ucs-4', 'ucs-4', 'csucs4',
+ 'utf-16', 'utf-32', 'utf_16', 'utf_32',
+ 'utf16', 'u16')):
+ xml_encoding = sniffed_xml_encoding
+ return xml_data, xml_encoding, sniffed_xml_encoding
+
+
+ def find_codec(self, charset):
+ return self._codec(self.CHARSET_ALIASES.get(charset, charset)) \
+ or (charset and self._codec(charset.replace("-", ""))) \
+ or (charset and self._codec(charset.replace("-", "_"))) \
+ or charset
+
+ def _codec(self, charset):
+ if not charset: return charset
+ codec = None
+ try:
+ codecs.lookup(charset)
+ codec = charset
+ except (LookupError, ValueError):
+ pass
+ return codec
+
+ EBCDIC_TO_ASCII_MAP = None
+ def _ebcdic_to_ascii(self, s):
+ c = self.__class__
+ if not c.EBCDIC_TO_ASCII_MAP:
+ emap = (0,1,2,3,156,9,134,127,151,141,142,11,12,13,14,15,
+ 16,17,18,19,157,133,8,135,24,25,146,143,28,29,30,31,
+ 128,129,130,131,132,10,23,27,136,137,138,139,140,5,6,7,
+ 144,145,22,147,148,149,150,4,152,153,154,155,20,21,158,26,
+ 32,160,161,162,163,164,165,166,167,168,91,46,60,40,43,33,
+ 38,169,170,171,172,173,174,175,176,177,93,36,42,41,59,94,
+ 45,47,178,179,180,181,182,183,184,185,124,44,37,95,62,63,
+ 186,187,188,189,190,191,192,193,194,96,58,35,64,39,61,34,
+ 195,97,98,99,100,101,102,103,104,105,196,197,198,199,200,
+ 201,202,106,107,108,109,110,111,112,113,114,203,204,205,
+ 206,207,208,209,126,115,116,117,118,119,120,121,122,210,
+ 211,212,213,214,215,216,217,218,219,220,221,222,223,224,
+ 225,226,227,228,229,230,231,123,65,66,67,68,69,70,71,72,
+ 73,232,233,234,235,236,237,125,74,75,76,77,78,79,80,81,
+ 82,238,239,240,241,242,243,92,159,83,84,85,86,87,88,89,
+ 90,244,245,246,247,248,249,48,49,50,51,52,53,54,55,56,57,
+ 250,251,252,253,254,255)
+ import string
+ c.EBCDIC_TO_ASCII_MAP = string.maketrans( \
+ ''.join(map(chr, range(256))), ''.join(map(chr, emap)))
+ return s.translate(c.EBCDIC_TO_ASCII_MAP)
+
+ MS_CHARS = { '\x80' : ('euro', '20AC'),
+ '\x81' : ' ',
+ '\x82' : ('sbquo', '201A'),
+ '\x83' : ('fnof', '192'),
+ '\x84' : ('bdquo', '201E'),
+ '\x85' : ('hellip', '2026'),
+ '\x86' : ('dagger', '2020'),
+ '\x87' : ('Dagger', '2021'),
+ '\x88' : ('circ', '2C6'),
+ '\x89' : ('permil', '2030'),
+ '\x8A' : ('Scaron', '160'),
+ '\x8B' : ('lsaquo', '2039'),
+ '\x8C' : ('OElig', '152'),
+ '\x8D' : '?',
+ '\x8E' : ('#x17D', '17D'),
+ '\x8F' : '?',
+ '\x90' : '?',
+ '\x91' : ('lsquo', '2018'),
+ '\x92' : ('rsquo', '2019'),
+ '\x93' : ('ldquo', '201C'),
+ '\x94' : ('rdquo', '201D'),
+ '\x95' : ('bull', '2022'),
+ '\x96' : ('ndash', '2013'),
+ '\x97' : ('mdash', '2014'),
+ '\x98' : ('tilde', '2DC'),
+ '\x99' : ('trade', '2122'),
+ '\x9a' : ('scaron', '161'),
+ '\x9b' : ('rsaquo', '203A'),
+ '\x9c' : ('oelig', '153'),
+ '\x9d' : '?',
+ '\x9e' : ('#x17E', '17E'),
+ '\x9f' : ('Yuml', ''),}
+
+#######################################################################
+
+
+#By default, act as an HTML pretty-printer.
+if __name__ == '__main__':
+ import sys
+ soup = BeautifulSoup(sys.stdin)
+ print soup.prettify()
diff --git a/Tools/Scripts/webkitpy/thirdparty/__init__.py b/Tools/Scripts/webkitpy/thirdparty/__init__.py
new file mode 100644
index 0000000..c2249c2
--- /dev/null
+++ b/Tools/Scripts/webkitpy/thirdparty/__init__.py
@@ -0,0 +1,98 @@
+# Copyright (C) 2010 Chris Jerdonek (cjerdonek@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.
+#
+# 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.
+
+# This module is required for Python to treat this directory as a package.
+
+"""Autoinstalls third-party code required by WebKit."""
+
+from __future__ import with_statement
+
+import codecs
+import os
+
+from webkitpy.common.system.autoinstall import AutoInstaller
+
+# Putting the autoinstall code into webkitpy/thirdparty/__init__.py
+# ensures that no autoinstalling occurs until a caller imports from
+# webkitpy.thirdparty. This is useful if the caller wants to configure
+# logging prior to executing autoinstall code.
+
+# FIXME: Ideally, a package should be autoinstalled only if the caller
+# attempts to import from that individual package. This would
+# make autoinstalling lazier than it is currently. This can
+# perhaps be done using Python's import hooks as the original
+# autoinstall implementation did.
+
+# FIXME: If any of these servers is offline, webkit-patch breaks (and maybe
+# other scripts do, too). See <http://webkit.org/b/42080>.
+
+# We put auto-installed third-party modules in this directory--
+#
+# webkitpy/thirdparty/autoinstalled
+thirdparty_dir = os.path.dirname(__file__)
+autoinstalled_dir = os.path.join(thirdparty_dir, "autoinstalled")
+
+# We need to download ClientForm since the mechanize package that we download
+# below requires it. The mechanize package uses ClientForm, for example,
+# in _html.py. Since mechanize imports ClientForm in the following way,
+#
+# > import sgmllib, ClientForm
+#
+# the search path needs to include ClientForm. We put ClientForm in
+# its own directory so that we can include it in the search path without
+# including other modules as a side effect.
+clientform_dir = os.path.join(autoinstalled_dir, "clientform")
+installer = AutoInstaller(append_to_search_path=True,
+ target_dir=clientform_dir)
+installer.install(url="http://pypi.python.org/packages/source/C/ClientForm/ClientForm-0.2.10.zip",
+ url_subpath="ClientForm.py")
+
+# The remaining packages do not need to be in the search path, so we create
+# a new AutoInstaller instance that does not append to the search path.
+installer = AutoInstaller(target_dir=autoinstalled_dir)
+
+installer.install(url="http://pypi.python.org/packages/source/m/mechanize/mechanize-0.1.11.zip",
+ url_subpath="mechanize")
+installer.install(url="http://pypi.python.org/packages/source/p/pep8/pep8-0.5.0.tar.gz#md5=512a818af9979290cd619cce8e9c2e2b",
+ url_subpath="pep8-0.5.0/pep8.py")
+installer.install(url="http://www.adambarth.com/webkit/eliza",
+ target_name="eliza.py")
+
+# Since irclib and ircbot are two top-level packages, we need to import
+# them separately. We group them into an irc package for better
+# organization purposes.
+irc_dir = os.path.join(autoinstalled_dir, "irc")
+installer = AutoInstaller(target_dir=irc_dir)
+installer.install(url="http://downloads.sourceforge.net/project/python-irclib/python-irclib/0.4.8/python-irclib-0.4.8.zip", url_subpath="irclib.py")
+installer.install(url="http://downloads.sourceforge.net/project/python-irclib/python-irclib/0.4.8/python-irclib-0.4.8.zip", url_subpath="ircbot.py")
+
+pywebsocket_dir = os.path.join(autoinstalled_dir, "pywebsocket")
+installer = AutoInstaller(target_dir=pywebsocket_dir)
+installer.install(url="http://pywebsocket.googlecode.com/files/mod_pywebsocket-0.5.2.tar.gz",
+ url_subpath="pywebsocket-0.5.2/src/mod_pywebsocket")
+
+readme_path = os.path.join(autoinstalled_dir, "README")
+if not os.path.exists(readme_path):
+ with codecs.open(readme_path, "w", "ascii") as file:
+ file.write("This directory is auto-generated by WebKit and is "
+ "safe to delete.\nIt contains needed third-party Python "
+ "packages automatically downloaded from the web.")
diff --git a/Tools/Scripts/webkitpy/thirdparty/mock.py b/Tools/Scripts/webkitpy/thirdparty/mock.py
new file mode 100644
index 0000000..015c19e
--- /dev/null
+++ b/Tools/Scripts/webkitpy/thirdparty/mock.py
@@ -0,0 +1,309 @@
+# mock.py
+# Test tools for mocking and patching.
+# Copyright (C) 2007-2009 Michael Foord
+# E-mail: fuzzyman AT voidspace DOT org DOT uk
+
+# mock 0.6.0
+# http://www.voidspace.org.uk/python/mock/
+
+# Released subject to the BSD License
+# Please see http://www.voidspace.org.uk/python/license.shtml
+
+# 2009-11-25: Licence downloaded from above URL.
+# BEGIN DOWNLOADED LICENSE
+#
+# Copyright (c) 2003-2009, Michael Foord
+# All rights reserved.
+# E-mail : fuzzyman AT voidspace DOT org DOT uk
+#
+# 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 Michael Foord nor the name of Voidspace
+# 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.
+#
+# END DOWNLOADED LICENSE
+
+# Scripts maintained at http://www.voidspace.org.uk/python/index.shtml
+# Comments, suggestions and bug reports welcome.
+
+
+__all__ = (
+ 'Mock',
+ 'patch',
+ 'patch_object',
+ 'sentinel',
+ 'DEFAULT'
+)
+
+__version__ = '0.6.0'
+
+class SentinelObject(object):
+ def __init__(self, name):
+ self.name = name
+
+ def __repr__(self):
+ return '<SentinelObject "%s">' % self.name
+
+
+class Sentinel(object):
+ def __init__(self):
+ self._sentinels = {}
+
+ def __getattr__(self, name):
+ return self._sentinels.setdefault(name, SentinelObject(name))
+
+
+sentinel = Sentinel()
+
+DEFAULT = sentinel.DEFAULT
+
+class OldStyleClass:
+ pass
+ClassType = type(OldStyleClass)
+
+def _is_magic(name):
+ return '__%s__' % name[2:-2] == name
+
+def _copy(value):
+ if type(value) in (dict, list, tuple, set):
+ return type(value)(value)
+ return value
+
+
+class Mock(object):
+
+ def __init__(self, spec=None, side_effect=None, return_value=DEFAULT,
+ name=None, parent=None, wraps=None):
+ self._parent = parent
+ self._name = name
+ if spec is not None and not isinstance(spec, list):
+ spec = [member for member in dir(spec) if not _is_magic(member)]
+
+ self._methods = spec
+ self._children = {}
+ self._return_value = return_value
+ self.side_effect = side_effect
+ self._wraps = wraps
+
+ self.reset_mock()
+
+
+ def reset_mock(self):
+ self.called = False
+ self.call_args = None
+ self.call_count = 0
+ self.call_args_list = []
+ self.method_calls = []
+ for child in self._children.itervalues():
+ child.reset_mock()
+ if isinstance(self._return_value, Mock):
+ self._return_value.reset_mock()
+
+
+ def __get_return_value(self):
+ if self._return_value is DEFAULT:
+ self._return_value = Mock()
+ return self._return_value
+
+ def __set_return_value(self, value):
+ self._return_value = value
+
+ return_value = property(__get_return_value, __set_return_value)
+
+
+ def __call__(self, *args, **kwargs):
+ self.called = True
+ self.call_count += 1
+ self.call_args = (args, kwargs)
+ self.call_args_list.append((args, kwargs))
+
+ parent = self._parent
+ name = self._name
+ while parent is not None:
+ parent.method_calls.append((name, args, kwargs))
+ if parent._parent is None:
+ break
+ name = parent._name + '.' + name
+ parent = parent._parent
+
+ ret_val = DEFAULT
+ if self.side_effect is not None:
+ if (isinstance(self.side_effect, Exception) or
+ isinstance(self.side_effect, (type, ClassType)) and
+ issubclass(self.side_effect, Exception)):
+ raise self.side_effect
+
+ ret_val = self.side_effect(*args, **kwargs)
+ if ret_val is DEFAULT:
+ ret_val = self.return_value
+
+ if self._wraps is not None and self._return_value is DEFAULT:
+ return self._wraps(*args, **kwargs)
+ if ret_val is DEFAULT:
+ ret_val = self.return_value
+ return ret_val
+
+
+ def __getattr__(self, name):
+ if self._methods is not None:
+ if name not in self._methods:
+ raise AttributeError("Mock object has no attribute '%s'" % name)
+ elif _is_magic(name):
+ raise AttributeError(name)
+
+ if name not in self._children:
+ wraps = None
+ if self._wraps is not None:
+ wraps = getattr(self._wraps, name)
+ self._children[name] = Mock(parent=self, name=name, wraps=wraps)
+
+ return self._children[name]
+
+
+ def assert_called_with(self, *args, **kwargs):
+ assert self.call_args == (args, kwargs), 'Expected: %s\nCalled with: %s' % ((args, kwargs), self.call_args)
+
+
+def _dot_lookup(thing, comp, import_path):
+ try:
+ return getattr(thing, comp)
+ except AttributeError:
+ __import__(import_path)
+ return getattr(thing, comp)
+
+
+def _importer(target):
+ components = target.split('.')
+ import_path = components.pop(0)
+ thing = __import__(import_path)
+
+ for comp in components:
+ import_path += ".%s" % comp
+ thing = _dot_lookup(thing, comp, import_path)
+ return thing
+
+
+class _patch(object):
+ def __init__(self, target, attribute, new, spec, create):
+ self.target = target
+ self.attribute = attribute
+ self.new = new
+ self.spec = spec
+ self.create = create
+ self.has_local = False
+
+
+ def __call__(self, func):
+ if hasattr(func, 'patchings'):
+ func.patchings.append(self)
+ return func
+
+ def patched(*args, **keywargs):
+ # don't use a with here (backwards compatability with 2.5)
+ extra_args = []
+ for patching in patched.patchings:
+ arg = patching.__enter__()
+ if patching.new is DEFAULT:
+ extra_args.append(arg)
+ args += tuple(extra_args)
+ try:
+ return func(*args, **keywargs)
+ finally:
+ for patching in getattr(patched, 'patchings', []):
+ patching.__exit__()
+
+ patched.patchings = [self]
+ patched.__name__ = func.__name__
+ patched.compat_co_firstlineno = getattr(func, "compat_co_firstlineno",
+ func.func_code.co_firstlineno)
+ return patched
+
+
+ def get_original(self):
+ target = self.target
+ name = self.attribute
+ create = self.create
+
+ original = DEFAULT
+ if _has_local_attr(target, name):
+ try:
+ original = target.__dict__[name]
+ except AttributeError:
+ # for instances of classes with slots, they have no __dict__
+ original = getattr(target, name)
+ elif not create and not hasattr(target, name):
+ raise AttributeError("%s does not have the attribute %r" % (target, name))
+ return original
+
+
+ def __enter__(self):
+ new, spec, = self.new, self.spec
+ original = self.get_original()
+ if new is DEFAULT:
+ # XXXX what if original is DEFAULT - shouldn't use it as a spec
+ inherit = False
+ if spec == True:
+ # set spec to the object we are replacing
+ spec = original
+ if isinstance(spec, (type, ClassType)):
+ inherit = True
+ new = Mock(spec=spec)
+ if inherit:
+ new.return_value = Mock(spec=spec)
+ self.temp_original = original
+ setattr(self.target, self.attribute, new)
+ return new
+
+
+ def __exit__(self, *_):
+ if self.temp_original is not DEFAULT:
+ setattr(self.target, self.attribute, self.temp_original)
+ else:
+ delattr(self.target, self.attribute)
+ del self.temp_original
+
+
+def patch_object(target, attribute, new=DEFAULT, spec=None, create=False):
+ return _patch(target, attribute, new, spec, create)
+
+
+def patch(target, new=DEFAULT, spec=None, create=False):
+ try:
+ target, attribute = target.rsplit('.', 1)
+ except (TypeError, ValueError):
+ raise TypeError("Need a valid target to patch. You supplied: %r" % (target,))
+ target = _importer(target)
+ return _patch(target, attribute, new, spec, create)
+
+
+
+def _has_local_attr(obj, name):
+ try:
+ return name in vars(obj)
+ except TypeError:
+ # objects without a __dict__
+ return hasattr(obj, name)
diff --git a/Tools/Scripts/webkitpy/thirdparty/simplejson/LICENSE.txt b/Tools/Scripts/webkitpy/thirdparty/simplejson/LICENSE.txt
new file mode 100644
index 0000000..ad95f29
--- /dev/null
+++ b/Tools/Scripts/webkitpy/thirdparty/simplejson/LICENSE.txt
@@ -0,0 +1,19 @@
+Copyright (c) 2006 Bob Ippolito
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+of the Software, and to permit persons to whom the Software is furnished to do
+so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/Tools/Scripts/webkitpy/thirdparty/simplejson/README.txt b/Tools/Scripts/webkitpy/thirdparty/simplejson/README.txt
new file mode 100644
index 0000000..7f726ce
--- /dev/null
+++ b/Tools/Scripts/webkitpy/thirdparty/simplejson/README.txt
@@ -0,0 +1,11 @@
+URL: http://undefined.org/python/#simplejson
+Version: 1.7.3
+License: MIT
+License File: LICENSE.txt
+
+Description:
+simplejson is a JSON encoder and decoder for Python.
+
+
+Local Modifications:
+Removed unit tests from current distribution.
diff --git a/Tools/Scripts/webkitpy/thirdparty/simplejson/__init__.py b/Tools/Scripts/webkitpy/thirdparty/simplejson/__init__.py
new file mode 100644
index 0000000..38d6229
--- /dev/null
+++ b/Tools/Scripts/webkitpy/thirdparty/simplejson/__init__.py
@@ -0,0 +1,287 @@
+r"""
+A simple, fast, extensible JSON encoder and decoder
+
+JSON (JavaScript Object Notation) <http://json.org> is a subset of
+JavaScript syntax (ECMA-262 3rd edition) used as a lightweight data
+interchange format.
+
+simplejson exposes an API familiar to uses of the standard library
+marshal and pickle modules.
+
+Encoding basic Python object hierarchies::
+
+ >>> import simplejson
+ >>> simplejson.dumps(['foo', {'bar': ('baz', None, 1.0, 2)}])
+ '["foo", {"bar": ["baz", null, 1.0, 2]}]'
+ >>> print simplejson.dumps("\"foo\bar")
+ "\"foo\bar"
+ >>> print simplejson.dumps(u'\u1234')
+ "\u1234"
+ >>> print simplejson.dumps('\\')
+ "\\"
+ >>> print simplejson.dumps({"c": 0, "b": 0, "a": 0}, sort_keys=True)
+ {"a": 0, "b": 0, "c": 0}
+ >>> from StringIO import StringIO
+ >>> io = StringIO()
+ >>> simplejson.dump(['streaming API'], io)
+ >>> io.getvalue()
+ '["streaming API"]'
+
+Compact encoding::
+
+ >>> import simplejson
+ >>> simplejson.dumps([1,2,3,{'4': 5, '6': 7}], separators=(',',':'))
+ '[1,2,3,{"4":5,"6":7}]'
+
+Pretty printing::
+
+ >>> import simplejson
+ >>> print simplejson.dumps({'4': 5, '6': 7}, sort_keys=True, indent=4)
+ {
+ "4": 5,
+ "6": 7
+ }
+
+Decoding JSON::
+
+ >>> import simplejson
+ >>> simplejson.loads('["foo", {"bar":["baz", null, 1.0, 2]}]')
+ [u'foo', {u'bar': [u'baz', None, 1.0, 2]}]
+ >>> simplejson.loads('"\\"foo\\bar"')
+ u'"foo\x08ar'
+ >>> from StringIO import StringIO
+ >>> io = StringIO('["streaming API"]')
+ >>> simplejson.load(io)
+ [u'streaming API']
+
+Specializing JSON object decoding::
+
+ >>> import simplejson
+ >>> def as_complex(dct):
+ ... if '__complex__' in dct:
+ ... return complex(dct['real'], dct['imag'])
+ ... return dct
+ ...
+ >>> simplejson.loads('{"__complex__": true, "real": 1, "imag": 2}',
+ ... object_hook=as_complex)
+ (1+2j)
+
+Extending JSONEncoder::
+
+ >>> import simplejson
+ >>> class ComplexEncoder(simplejson.JSONEncoder):
+ ... def default(self, obj):
+ ... if isinstance(obj, complex):
+ ... return [obj.real, obj.imag]
+ ... return simplejson.JSONEncoder.default(self, obj)
+ ...
+ >>> dumps(2 + 1j, cls=ComplexEncoder)
+ '[2.0, 1.0]'
+ >>> ComplexEncoder().encode(2 + 1j)
+ '[2.0, 1.0]'
+ >>> list(ComplexEncoder().iterencode(2 + 1j))
+ ['[', '2.0', ', ', '1.0', ']']
+
+
+Note that the JSON produced by this module's default settings
+is a subset of YAML, so it may be used as a serializer for that as well.
+"""
+__version__ = '1.7.3'
+__all__ = [
+ 'dump', 'dumps', 'load', 'loads',
+ 'JSONDecoder', 'JSONEncoder',
+]
+
+from decoder import JSONDecoder
+from encoder import JSONEncoder
+
+_default_encoder = JSONEncoder(
+ skipkeys=False,
+ ensure_ascii=True,
+ check_circular=True,
+ allow_nan=True,
+ indent=None,
+ separators=None,
+ encoding='utf-8'
+)
+
+def dump(obj, fp, skipkeys=False, ensure_ascii=True, check_circular=True,
+ allow_nan=True, cls=None, indent=None, separators=None,
+ encoding='utf-8', **kw):
+ """
+ Serialize ``obj`` as a JSON formatted stream to ``fp`` (a
+ ``.write()``-supporting file-like object).
+
+ If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types
+ (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
+ will be skipped instead of raising a ``TypeError``.
+
+ If ``ensure_ascii`` is ``False``, then the some chunks written to ``fp``
+ may be ``unicode`` instances, subject to normal Python ``str`` to
+ ``unicode`` coercion rules. Unless ``fp.write()`` explicitly
+ understands ``unicode`` (as in ``codecs.getwriter()``) this is likely
+ to cause an error.
+
+ If ``check_circular`` is ``False``, then the circular reference check
+ for container types will be skipped and a circular reference will
+ result in an ``OverflowError`` (or worse).
+
+ If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to
+ serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``)
+ in strict compliance of the JSON specification, instead of using the
+ JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
+
+ If ``indent`` is a non-negative integer, then JSON array elements and object
+ members will be pretty-printed with that indent level. An indent level
+ of 0 will only insert newlines. ``None`` is the most compact representation.
+
+ If ``separators`` is an ``(item_separator, dict_separator)`` tuple
+ then it will be used instead of the default ``(', ', ': ')`` separators.
+ ``(',', ':')`` is the most compact JSON representation.
+
+ ``encoding`` is the character encoding for str instances, default is UTF-8.
+
+ To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
+ ``.default()`` method to serialize additional types), specify it with
+ the ``cls`` kwarg.
+ """
+ # cached encoder
+ if (skipkeys is False and ensure_ascii is True and
+ check_circular is True and allow_nan is True and
+ cls is None and indent is None and separators is None and
+ encoding == 'utf-8' and not kw):
+ iterable = _default_encoder.iterencode(obj)
+ else:
+ if cls is None:
+ cls = JSONEncoder
+ iterable = cls(skipkeys=skipkeys, ensure_ascii=ensure_ascii,
+ check_circular=check_circular, allow_nan=allow_nan, indent=indent,
+ separators=separators, encoding=encoding, **kw).iterencode(obj)
+ # could accelerate with writelines in some versions of Python, at
+ # a debuggability cost
+ for chunk in iterable:
+ fp.write(chunk)
+
+
+def dumps(obj, skipkeys=False, ensure_ascii=True, check_circular=True,
+ allow_nan=True, cls=None, indent=None, separators=None,
+ encoding='utf-8', **kw):
+ """
+ Serialize ``obj`` to a JSON formatted ``str``.
+
+ If ``skipkeys`` is ``True`` then ``dict`` keys that are not basic types
+ (``str``, ``unicode``, ``int``, ``long``, ``float``, ``bool``, ``None``)
+ will be skipped instead of raising a ``TypeError``.
+
+ If ``ensure_ascii`` is ``False``, then the return value will be a
+ ``unicode`` instance subject to normal Python ``str`` to ``unicode``
+ coercion rules instead of being escaped to an ASCII ``str``.
+
+ If ``check_circular`` is ``False``, then the circular reference check
+ for container types will be skipped and a circular reference will
+ result in an ``OverflowError`` (or worse).
+
+ If ``allow_nan`` is ``False``, then it will be a ``ValueError`` to
+ serialize out of range ``float`` values (``nan``, ``inf``, ``-inf``) in
+ strict compliance of the JSON specification, instead of using the
+ JavaScript equivalents (``NaN``, ``Infinity``, ``-Infinity``).
+
+ If ``indent`` is a non-negative integer, then JSON array elements and
+ object members will be pretty-printed with that indent level. An indent
+ level of 0 will only insert newlines. ``None`` is the most compact
+ representation.
+
+ If ``separators`` is an ``(item_separator, dict_separator)`` tuple
+ then it will be used instead of the default ``(', ', ': ')`` separators.
+ ``(',', ':')`` is the most compact JSON representation.
+
+ ``encoding`` is the character encoding for str instances, default is UTF-8.
+
+ To use a custom ``JSONEncoder`` subclass (e.g. one that overrides the
+ ``.default()`` method to serialize additional types), specify it with
+ the ``cls`` kwarg.
+ """
+ # cached encoder
+ if (skipkeys is False and ensure_ascii is True and
+ check_circular is True and allow_nan is True and
+ cls is None and indent is None and separators is None and
+ encoding == 'utf-8' and not kw):
+ return _default_encoder.encode(obj)
+ if cls is None:
+ cls = JSONEncoder
+ return cls(
+ skipkeys=skipkeys, ensure_ascii=ensure_ascii,
+ check_circular=check_circular, allow_nan=allow_nan, indent=indent,
+ separators=separators, encoding=encoding,
+ **kw).encode(obj)
+
+_default_decoder = JSONDecoder(encoding=None, object_hook=None)
+
+def load(fp, encoding=None, cls=None, object_hook=None, **kw):
+ """
+ Deserialize ``fp`` (a ``.read()``-supporting file-like object containing
+ a JSON document) to a Python object.
+
+ If the contents of ``fp`` is encoded with an ASCII based encoding other
+ than utf-8 (e.g. latin-1), then an appropriate ``encoding`` name must
+ be specified. Encodings that are not ASCII based (such as UCS-2) are
+ not allowed, and should be wrapped with
+ ``codecs.getreader(fp)(encoding)``, or simply decoded to a ``unicode``
+ object and passed to ``loads()``
+
+ ``object_hook`` is an optional function that will be called with the
+ result of any object literal decode (a ``dict``). The return value of
+ ``object_hook`` will be used instead of the ``dict``. This feature
+ can be used to implement custom decoders (e.g. JSON-RPC class hinting).
+
+ To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
+ kwarg.
+ """
+ return loads(fp.read(),
+ encoding=encoding, cls=cls, object_hook=object_hook, **kw)
+
+def loads(s, encoding=None, cls=None, object_hook=None, **kw):
+ """
+ Deserialize ``s`` (a ``str`` or ``unicode`` instance containing a JSON
+ document) to a Python object.
+
+ If ``s`` is a ``str`` instance and is encoded with an ASCII based encoding
+ other than utf-8 (e.g. latin-1) then an appropriate ``encoding`` name
+ must be specified. Encodings that are not ASCII based (such as UCS-2)
+ are not allowed and should be decoded to ``unicode`` first.
+
+ ``object_hook`` is an optional function that will be called with the
+ result of any object literal decode (a ``dict``). The return value of
+ ``object_hook`` will be used instead of the ``dict``. This feature
+ can be used to implement custom decoders (e.g. JSON-RPC class hinting).
+
+ To use a custom ``JSONDecoder`` subclass, specify it with the ``cls``
+ kwarg.
+ """
+ if cls is None and encoding is None and object_hook is None and not kw:
+ return _default_decoder.decode(s)
+ if cls is None:
+ cls = JSONDecoder
+ if object_hook is not None:
+ kw['object_hook'] = object_hook
+ return cls(encoding=encoding, **kw).decode(s)
+
+def read(s):
+ """
+ json-py API compatibility hook. Use loads(s) instead.
+ """
+ import warnings
+ warnings.warn("simplejson.loads(s) should be used instead of read(s)",
+ DeprecationWarning)
+ return loads(s)
+
+def write(obj):
+ """
+ json-py API compatibility hook. Use dumps(s) instead.
+ """
+ import warnings
+ warnings.warn("simplejson.dumps(s) should be used instead of write(s)",
+ DeprecationWarning)
+ return dumps(obj)
+
+
diff --git a/Tools/Scripts/webkitpy/thirdparty/simplejson/_speedups.c b/Tools/Scripts/webkitpy/thirdparty/simplejson/_speedups.c
new file mode 100644
index 0000000..8f290bb
--- /dev/null
+++ b/Tools/Scripts/webkitpy/thirdparty/simplejson/_speedups.c
@@ -0,0 +1,215 @@
+#include "Python.h"
+#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN)
+typedef int Py_ssize_t;
+#define PY_SSIZE_T_MAX INT_MAX
+#define PY_SSIZE_T_MIN INT_MIN
+#endif
+
+static Py_ssize_t
+ascii_escape_char(Py_UNICODE c, char *output, Py_ssize_t chars);
+static PyObject *
+ascii_escape_unicode(PyObject *pystr);
+static PyObject *
+ascii_escape_str(PyObject *pystr);
+static PyObject *
+py_encode_basestring_ascii(PyObject* self __attribute__((__unused__)), PyObject *pystr);
+void init_speedups(void);
+
+#define S_CHAR(c) (c >= ' ' && c <= '~' && c != '\\' && c != '/' && c != '"')
+
+#define MIN_EXPANSION 6
+#ifdef Py_UNICODE_WIDE
+#define MAX_EXPANSION (2 * MIN_EXPANSION)
+#else
+#define MAX_EXPANSION MIN_EXPANSION
+#endif
+
+static Py_ssize_t
+ascii_escape_char(Py_UNICODE c, char *output, Py_ssize_t chars) {
+ Py_UNICODE x;
+ output[chars++] = '\\';
+ switch (c) {
+ case '/': output[chars++] = (char)c; break;
+ case '\\': output[chars++] = (char)c; break;
+ case '"': output[chars++] = (char)c; break;
+ case '\b': output[chars++] = 'b'; break;
+ case '\f': output[chars++] = 'f'; break;
+ case '\n': output[chars++] = 'n'; break;
+ case '\r': output[chars++] = 'r'; break;
+ case '\t': output[chars++] = 't'; break;
+ default:
+#ifdef Py_UNICODE_WIDE
+ if (c >= 0x10000) {
+ /* UTF-16 surrogate pair */
+ Py_UNICODE v = c - 0x10000;
+ c = 0xd800 | ((v >> 10) & 0x3ff);
+ output[chars++] = 'u';
+ x = (c & 0xf000) >> 12;
+ output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10);
+ x = (c & 0x0f00) >> 8;
+ output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10);
+ x = (c & 0x00f0) >> 4;
+ output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10);
+ x = (c & 0x000f);
+ output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10);
+ c = 0xdc00 | (v & 0x3ff);
+ output[chars++] = '\\';
+ }
+#endif
+ output[chars++] = 'u';
+ x = (c & 0xf000) >> 12;
+ output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10);
+ x = (c & 0x0f00) >> 8;
+ output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10);
+ x = (c & 0x00f0) >> 4;
+ output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10);
+ x = (c & 0x000f);
+ output[chars++] = (x < 10) ? '0' + x : 'a' + (x - 10);
+ }
+ return chars;
+}
+
+static PyObject *
+ascii_escape_unicode(PyObject *pystr) {
+ Py_ssize_t i;
+ Py_ssize_t input_chars;
+ Py_ssize_t output_size;
+ Py_ssize_t chars;
+ PyObject *rval;
+ char *output;
+ Py_UNICODE *input_unicode;
+
+ input_chars = PyUnicode_GET_SIZE(pystr);
+ input_unicode = PyUnicode_AS_UNICODE(pystr);
+ /* One char input can be up to 6 chars output, estimate 4 of these */
+ output_size = 2 + (MIN_EXPANSION * 4) + input_chars;
+ rval = PyString_FromStringAndSize(NULL, output_size);
+ if (rval == NULL) {
+ return NULL;
+ }
+ output = PyString_AS_STRING(rval);
+ chars = 0;
+ output[chars++] = '"';
+ for (i = 0; i < input_chars; i++) {
+ Py_UNICODE c = input_unicode[i];
+ if (S_CHAR(c)) {
+ output[chars++] = (char)c;
+ } else {
+ chars = ascii_escape_char(c, output, chars);
+ }
+ if (output_size - chars < (1 + MAX_EXPANSION)) {
+ /* There's more than four, so let's resize by a lot */
+ output_size *= 2;
+ /* This is an upper bound */
+ if (output_size > 2 + (input_chars * MAX_EXPANSION)) {
+ output_size = 2 + (input_chars * MAX_EXPANSION);
+ }
+ if (_PyString_Resize(&rval, output_size) == -1) {
+ return NULL;
+ }
+ output = PyString_AS_STRING(rval);
+ }
+ }
+ output[chars++] = '"';
+ if (_PyString_Resize(&rval, chars) == -1) {
+ return NULL;
+ }
+ return rval;
+}
+
+static PyObject *
+ascii_escape_str(PyObject *pystr) {
+ Py_ssize_t i;
+ Py_ssize_t input_chars;
+ Py_ssize_t output_size;
+ Py_ssize_t chars;
+ PyObject *rval;
+ char *output;
+ char *input_str;
+
+ input_chars = PyString_GET_SIZE(pystr);
+ input_str = PyString_AS_STRING(pystr);
+ /* One char input can be up to 6 chars output, estimate 4 of these */
+ output_size = 2 + (MIN_EXPANSION * 4) + input_chars;
+ rval = PyString_FromStringAndSize(NULL, output_size);
+ if (rval == NULL) {
+ return NULL;
+ }
+ output = PyString_AS_STRING(rval);
+ chars = 0;
+ output[chars++] = '"';
+ for (i = 0; i < input_chars; i++) {
+ Py_UNICODE c = (Py_UNICODE)input_str[i];
+ if (S_CHAR(c)) {
+ output[chars++] = (char)c;
+ } else if (c > 0x7F) {
+ /* We hit a non-ASCII character, bail to unicode mode */
+ PyObject *uni;
+ Py_DECREF(rval);
+ uni = PyUnicode_DecodeUTF8(input_str, input_chars, "strict");
+ if (uni == NULL) {
+ return NULL;
+ }
+ rval = ascii_escape_unicode(uni);
+ Py_DECREF(uni);
+ return rval;
+ } else {
+ chars = ascii_escape_char(c, output, chars);
+ }
+ /* An ASCII char can't possibly expand to a surrogate! */
+ if (output_size - chars < (1 + MIN_EXPANSION)) {
+ /* There's more than four, so let's resize by a lot */
+ output_size *= 2;
+ if (output_size > 2 + (input_chars * MIN_EXPANSION)) {
+ output_size = 2 + (input_chars * MIN_EXPANSION);
+ }
+ if (_PyString_Resize(&rval, output_size) == -1) {
+ return NULL;
+ }
+ output = PyString_AS_STRING(rval);
+ }
+ }
+ output[chars++] = '"';
+ if (_PyString_Resize(&rval, chars) == -1) {
+ return NULL;
+ }
+ return rval;
+}
+
+PyDoc_STRVAR(pydoc_encode_basestring_ascii,
+ "encode_basestring_ascii(basestring) -> str\n"
+ "\n"
+ "..."
+);
+
+static PyObject *
+py_encode_basestring_ascii(PyObject* self __attribute__((__unused__)), PyObject *pystr) {
+ /* METH_O */
+ if (PyString_Check(pystr)) {
+ return ascii_escape_str(pystr);
+ } else if (PyUnicode_Check(pystr)) {
+ return ascii_escape_unicode(pystr);
+ }
+ PyErr_SetString(PyExc_TypeError, "first argument must be a string");
+ return NULL;
+}
+
+#define DEFN(n, k) \
+ { \
+ #n, \
+ (PyCFunction)py_ ##n, \
+ k, \
+ pydoc_ ##n \
+ }
+static PyMethodDef speedups_methods[] = {
+ DEFN(encode_basestring_ascii, METH_O),
+ {}
+};
+#undef DEFN
+
+void
+init_speedups(void)
+{
+ PyObject *m;
+ m = Py_InitModule4("_speedups", speedups_methods, NULL, NULL, PYTHON_API_VERSION);
+}
diff --git a/Tools/Scripts/webkitpy/thirdparty/simplejson/decoder.py b/Tools/Scripts/webkitpy/thirdparty/simplejson/decoder.py
new file mode 100644
index 0000000..63f70cb
--- /dev/null
+++ b/Tools/Scripts/webkitpy/thirdparty/simplejson/decoder.py
@@ -0,0 +1,273 @@
+"""
+Implementation of JSONDecoder
+"""
+import re
+
+from scanner import Scanner, pattern
+
+FLAGS = re.VERBOSE | re.MULTILINE | re.DOTALL
+
+def _floatconstants():
+ import struct
+ import sys
+ _BYTES = '7FF80000000000007FF0000000000000'.decode('hex')
+ if sys.byteorder != 'big':
+ _BYTES = _BYTES[:8][::-1] + _BYTES[8:][::-1]
+ nan, inf = struct.unpack('dd', _BYTES)
+ return nan, inf, -inf
+
+NaN, PosInf, NegInf = _floatconstants()
+
+def linecol(doc, pos):
+ lineno = doc.count('\n', 0, pos) + 1
+ if lineno == 1:
+ colno = pos
+ else:
+ colno = pos - doc.rindex('\n', 0, pos)
+ return lineno, colno
+
+def errmsg(msg, doc, pos, end=None):
+ lineno, colno = linecol(doc, pos)
+ if end is None:
+ return '%s: line %d column %d (char %d)' % (msg, lineno, colno, pos)
+ endlineno, endcolno = linecol(doc, end)
+ return '%s: line %d column %d - line %d column %d (char %d - %d)' % (
+ msg, lineno, colno, endlineno, endcolno, pos, end)
+
+_CONSTANTS = {
+ '-Infinity': NegInf,
+ 'Infinity': PosInf,
+ 'NaN': NaN,
+ 'true': True,
+ 'false': False,
+ 'null': None,
+}
+
+def JSONConstant(match, context, c=_CONSTANTS):
+ return c[match.group(0)], None
+pattern('(-?Infinity|NaN|true|false|null)')(JSONConstant)
+
+def JSONNumber(match, context):
+ match = JSONNumber.regex.match(match.string, *match.span())
+ integer, frac, exp = match.groups()
+ if frac or exp:
+ res = float(integer + (frac or '') + (exp or ''))
+ else:
+ res = int(integer)
+ return res, None
+pattern(r'(-?(?:0|[1-9]\d*))(\.\d+)?([eE][-+]?\d+)?')(JSONNumber)
+
+STRINGCHUNK = re.compile(r'(.*?)(["\\])', FLAGS)
+BACKSLASH = {
+ '"': u'"', '\\': u'\\', '/': u'/',
+ 'b': u'\b', 'f': u'\f', 'n': u'\n', 'r': u'\r', 't': u'\t',
+}
+
+DEFAULT_ENCODING = "utf-8"
+
+def scanstring(s, end, encoding=None, _b=BACKSLASH, _m=STRINGCHUNK.match):
+ if encoding is None:
+ encoding = DEFAULT_ENCODING
+ chunks = []
+ _append = chunks.append
+ begin = end - 1
+ while 1:
+ chunk = _m(s, end)
+ if chunk is None:
+ raise ValueError(
+ errmsg("Unterminated string starting at", s, begin))
+ end = chunk.end()
+ content, terminator = chunk.groups()
+ if content:
+ if not isinstance(content, unicode):
+ content = unicode(content, encoding)
+ _append(content)
+ if terminator == '"':
+ break
+ try:
+ esc = s[end]
+ except IndexError:
+ raise ValueError(
+ errmsg("Unterminated string starting at", s, begin))
+ if esc != 'u':
+ try:
+ m = _b[esc]
+ except KeyError:
+ raise ValueError(
+ errmsg("Invalid \\escape: %r" % (esc,), s, end))
+ end += 1
+ else:
+ esc = s[end + 1:end + 5]
+ try:
+ m = unichr(int(esc, 16))
+ if len(esc) != 4 or not esc.isalnum():
+ raise ValueError
+ except ValueError:
+ raise ValueError(errmsg("Invalid \\uXXXX escape", s, end))
+ end += 5
+ _append(m)
+ return u''.join(chunks), end
+
+def JSONString(match, context):
+ encoding = getattr(context, 'encoding', None)
+ return scanstring(match.string, match.end(), encoding)
+pattern(r'"')(JSONString)
+
+WHITESPACE = re.compile(r'\s*', FLAGS)
+
+def JSONObject(match, context, _w=WHITESPACE.match):
+ pairs = {}
+ s = match.string
+ end = _w(s, match.end()).end()
+ nextchar = s[end:end + 1]
+ # trivial empty object
+ if nextchar == '}':
+ return pairs, end + 1
+ if nextchar != '"':
+ raise ValueError(errmsg("Expecting property name", s, end))
+ end += 1
+ encoding = getattr(context, 'encoding', None)
+ iterscan = JSONScanner.iterscan
+ while True:
+ key, end = scanstring(s, end, encoding)
+ end = _w(s, end).end()
+ if s[end:end + 1] != ':':
+ raise ValueError(errmsg("Expecting : delimiter", s, end))
+ end = _w(s, end + 1).end()
+ try:
+ value, end = iterscan(s, idx=end, context=context).next()
+ except StopIteration:
+ raise ValueError(errmsg("Expecting object", s, end))
+ pairs[key] = value
+ end = _w(s, end).end()
+ nextchar = s[end:end + 1]
+ end += 1
+ if nextchar == '}':
+ break
+ if nextchar != ',':
+ raise ValueError(errmsg("Expecting , delimiter", s, end - 1))
+ end = _w(s, end).end()
+ nextchar = s[end:end + 1]
+ end += 1
+ if nextchar != '"':
+ raise ValueError(errmsg("Expecting property name", s, end - 1))
+ object_hook = getattr(context, 'object_hook', None)
+ if object_hook is not None:
+ pairs = object_hook(pairs)
+ return pairs, end
+pattern(r'{')(JSONObject)
+
+def JSONArray(match, context, _w=WHITESPACE.match):
+ values = []
+ s = match.string
+ end = _w(s, match.end()).end()
+ # look-ahead for trivial empty array
+ nextchar = s[end:end + 1]
+ if nextchar == ']':
+ return values, end + 1
+ iterscan = JSONScanner.iterscan
+ while True:
+ try:
+ value, end = iterscan(s, idx=end, context=context).next()
+ except StopIteration:
+ raise ValueError(errmsg("Expecting object", s, end))
+ values.append(value)
+ end = _w(s, end).end()
+ nextchar = s[end:end + 1]
+ end += 1
+ if nextchar == ']':
+ break
+ if nextchar != ',':
+ raise ValueError(errmsg("Expecting , delimiter", s, end))
+ end = _w(s, end).end()
+ return values, end
+pattern(r'\[')(JSONArray)
+
+ANYTHING = [
+ JSONObject,
+ JSONArray,
+ JSONString,
+ JSONConstant,
+ JSONNumber,
+]
+
+JSONScanner = Scanner(ANYTHING)
+
+class JSONDecoder(object):
+ """
+ Simple JSON <http://json.org> decoder
+
+ Performs the following translations in decoding:
+
+ +---------------+-------------------+
+ | JSON | Python |
+ +===============+===================+
+ | object | dict |
+ +---------------+-------------------+
+ | array | list |
+ +---------------+-------------------+
+ | string | unicode |
+ +---------------+-------------------+
+ | number (int) | int, long |
+ +---------------+-------------------+
+ | number (real) | float |
+ +---------------+-------------------+
+ | true | True |
+ +---------------+-------------------+
+ | false | False |
+ +---------------+-------------------+
+ | null | None |
+ +---------------+-------------------+
+
+ It also understands ``NaN``, ``Infinity``, and ``-Infinity`` as
+ their corresponding ``float`` values, which is outside the JSON spec.
+ """
+
+ _scanner = Scanner(ANYTHING)
+ __all__ = ['__init__', 'decode', 'raw_decode']
+
+ def __init__(self, encoding=None, object_hook=None):
+ """
+ ``encoding`` determines the encoding used to interpret any ``str``
+ objects decoded by this instance (utf-8 by default). It has no
+ effect when decoding ``unicode`` objects.
+
+ Note that currently only encodings that are a superset of ASCII work,
+ strings of other encodings should be passed in as ``unicode``.
+
+ ``object_hook``, if specified, will be called with the result
+ of every JSON object decoded and its return value will be used in
+ place of the given ``dict``. This can be used to provide custom
+ deserializations (e.g. to support JSON-RPC class hinting).
+ """
+ self.encoding = encoding
+ self.object_hook = object_hook
+
+ def decode(self, s, _w=WHITESPACE.match):
+ """
+ Return the Python representation of ``s`` (a ``str`` or ``unicode``
+ instance containing a JSON document)
+ """
+ obj, end = self.raw_decode(s, idx=_w(s, 0).end())
+ end = _w(s, end).end()
+ if end != len(s):
+ raise ValueError(errmsg("Extra data", s, end, len(s)))
+ return obj
+
+ def raw_decode(self, s, **kw):
+ """
+ Decode a JSON document from ``s`` (a ``str`` or ``unicode`` beginning
+ with a JSON document) and return a 2-tuple of the Python
+ representation and the index in ``s`` where the document ended.
+
+ This can be used to decode a JSON document from a string that may
+ have extraneous data at the end.
+ """
+ kw.setdefault('context', self)
+ try:
+ obj, end = self._scanner.iterscan(s, **kw).next()
+ except StopIteration:
+ raise ValueError("No JSON object could be decoded")
+ return obj, end
+
+__all__ = ['JSONDecoder']
diff --git a/Tools/Scripts/webkitpy/thirdparty/simplejson/encoder.py b/Tools/Scripts/webkitpy/thirdparty/simplejson/encoder.py
new file mode 100644
index 0000000..d29919a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/thirdparty/simplejson/encoder.py
@@ -0,0 +1,371 @@
+"""
+Implementation of JSONEncoder
+"""
+import re
+try:
+ from simplejson import _speedups
+except ImportError:
+ _speedups = None
+
+ESCAPE = re.compile(r'[\x00-\x19\\"\b\f\n\r\t]')
+ESCAPE_ASCII = re.compile(r'([\\"/]|[^\ -~])')
+ESCAPE_DCT = {
+ # escape all forward slashes to prevent </script> attack
+ '/': '\\/',
+ '\\': '\\\\',
+ '"': '\\"',
+ '\b': '\\b',
+ '\f': '\\f',
+ '\n': '\\n',
+ '\r': '\\r',
+ '\t': '\\t',
+}
+for i in range(0x20):
+ ESCAPE_DCT.setdefault(chr(i), '\\u%04x' % (i,))
+
+# assume this produces an infinity on all machines (probably not guaranteed)
+INFINITY = float('1e66666')
+
+def floatstr(o, allow_nan=True):
+ # Check for specials. Note that this type of test is processor- and/or
+ # platform-specific, so do tests which don't depend on the internals.
+
+ if o != o:
+ text = 'NaN'
+ elif o == INFINITY:
+ text = 'Infinity'
+ elif o == -INFINITY:
+ text = '-Infinity'
+ else:
+ return repr(o)
+
+ if not allow_nan:
+ raise ValueError("Out of range float values are not JSON compliant: %r"
+ % (o,))
+
+ return text
+
+
+def encode_basestring(s):
+ """
+ Return a JSON representation of a Python string
+ """
+ def replace(match):
+ return ESCAPE_DCT[match.group(0)]
+ return '"' + ESCAPE.sub(replace, s) + '"'
+
+def encode_basestring_ascii(s):
+ def replace(match):
+ s = match.group(0)
+ try:
+ return ESCAPE_DCT[s]
+ except KeyError:
+ n = ord(s)
+ if n < 0x10000:
+ return '\\u%04x' % (n,)
+ else:
+ # surrogate pair
+ n -= 0x10000
+ s1 = 0xd800 | ((n >> 10) & 0x3ff)
+ s2 = 0xdc00 | (n & 0x3ff)
+ return '\\u%04x\\u%04x' % (s1, s2)
+ return '"' + str(ESCAPE_ASCII.sub(replace, s)) + '"'
+
+try:
+ encode_basestring_ascii = _speedups.encode_basestring_ascii
+ _need_utf8 = True
+except AttributeError:
+ _need_utf8 = False
+
+class JSONEncoder(object):
+ """
+ Extensible JSON <http://json.org> encoder for Python data structures.
+
+ Supports the following objects and types by default:
+
+ +-------------------+---------------+
+ | Python | JSON |
+ +===================+===============+
+ | dict | object |
+ +-------------------+---------------+
+ | list, tuple | array |
+ +-------------------+---------------+
+ | str, unicode | string |
+ +-------------------+---------------+
+ | int, long, float | number |
+ +-------------------+---------------+
+ | True | true |
+ +-------------------+---------------+
+ | False | false |
+ +-------------------+---------------+
+ | None | null |
+ +-------------------+---------------+
+
+ To extend this to recognize other objects, subclass and implement a
+ ``.default()`` method with another method that returns a serializable
+ object for ``o`` if possible, otherwise it should call the superclass
+ implementation (to raise ``TypeError``).
+ """
+ __all__ = ['__init__', 'default', 'encode', 'iterencode']
+ item_separator = ', '
+ key_separator = ': '
+ def __init__(self, skipkeys=False, ensure_ascii=True,
+ check_circular=True, allow_nan=True, sort_keys=False,
+ indent=None, separators=None, encoding='utf-8'):
+ """
+ Constructor for JSONEncoder, with sensible defaults.
+
+ If skipkeys is False, then it is a TypeError to attempt
+ encoding of keys that are not str, int, long, float or None. If
+ skipkeys is True, such items are simply skipped.
+
+ If ensure_ascii is True, the output is guaranteed to be str
+ objects with all incoming unicode characters escaped. If
+ ensure_ascii is false, the output will be unicode object.
+
+ If check_circular is True, then lists, dicts, and custom encoded
+ objects will be checked for circular references during encoding to
+ prevent an infinite recursion (which would cause an OverflowError).
+ Otherwise, no such check takes place.
+
+ If allow_nan is True, then NaN, Infinity, and -Infinity will be
+ encoded as such. This behavior is not JSON specification compliant,
+ but is consistent with most JavaScript based encoders and decoders.
+ Otherwise, it will be a ValueError to encode such floats.
+
+ If sort_keys is True, then the output of dictionaries will be
+ sorted by key; this is useful for regression tests to ensure
+ that JSON serializations can be compared on a day-to-day basis.
+
+ If indent is a non-negative integer, then JSON array
+ elements and object members will be pretty-printed with that
+ indent level. An indent level of 0 will only insert newlines.
+ None is the most compact representation.
+
+ If specified, separators should be a (item_separator, key_separator)
+ tuple. The default is (', ', ': '). To get the most compact JSON
+ representation you should specify (',', ':') to eliminate whitespace.
+
+ If encoding is not None, then all input strings will be
+ transformed into unicode using that encoding prior to JSON-encoding.
+ The default is UTF-8.
+ """
+
+ self.skipkeys = skipkeys
+ self.ensure_ascii = ensure_ascii
+ self.check_circular = check_circular
+ self.allow_nan = allow_nan
+ self.sort_keys = sort_keys
+ self.indent = indent
+ self.current_indent_level = 0
+ if separators is not None:
+ self.item_separator, self.key_separator = separators
+ self.encoding = encoding
+
+ def _newline_indent(self):
+ return '\n' + (' ' * (self.indent * self.current_indent_level))
+
+ def _iterencode_list(self, lst, markers=None):
+ if not lst:
+ yield '[]'
+ return
+ if markers is not None:
+ markerid = id(lst)
+ if markerid in markers:
+ raise ValueError("Circular reference detected")
+ markers[markerid] = lst
+ yield '['
+ if self.indent is not None:
+ self.current_indent_level += 1
+ newline_indent = self._newline_indent()
+ separator = self.item_separator + newline_indent
+ yield newline_indent
+ else:
+ newline_indent = None
+ separator = self.item_separator
+ first = True
+ for value in lst:
+ if first:
+ first = False
+ else:
+ yield separator
+ for chunk in self._iterencode(value, markers):
+ yield chunk
+ if newline_indent is not None:
+ self.current_indent_level -= 1
+ yield self._newline_indent()
+ yield ']'
+ if markers is not None:
+ del markers[markerid]
+
+ def _iterencode_dict(self, dct, markers=None):
+ if not dct:
+ yield '{}'
+ return
+ if markers is not None:
+ markerid = id(dct)
+ if markerid in markers:
+ raise ValueError("Circular reference detected")
+ markers[markerid] = dct
+ yield '{'
+ key_separator = self.key_separator
+ if self.indent is not None:
+ self.current_indent_level += 1
+ newline_indent = self._newline_indent()
+ item_separator = self.item_separator + newline_indent
+ yield newline_indent
+ else:
+ newline_indent = None
+ item_separator = self.item_separator
+ first = True
+ if self.ensure_ascii:
+ encoder = encode_basestring_ascii
+ else:
+ encoder = encode_basestring
+ allow_nan = self.allow_nan
+ if self.sort_keys:
+ keys = dct.keys()
+ keys.sort()
+ items = [(k, dct[k]) for k in keys]
+ else:
+ items = dct.iteritems()
+ _encoding = self.encoding
+ _do_decode = (_encoding is not None
+ and not (_need_utf8 and _encoding == 'utf-8'))
+ for key, value in items:
+ if isinstance(key, str):
+ if _do_decode:
+ key = key.decode(_encoding)
+ elif isinstance(key, basestring):
+ pass
+ # JavaScript is weakly typed for these, so it makes sense to
+ # also allow them. Many encoders seem to do something like this.
+ elif isinstance(key, float):
+ key = floatstr(key, allow_nan)
+ elif isinstance(key, (int, long)):
+ key = str(key)
+ elif key is True:
+ key = 'true'
+ elif key is False:
+ key = 'false'
+ elif key is None:
+ key = 'null'
+ elif self.skipkeys:
+ continue
+ else:
+ raise TypeError("key %r is not a string" % (key,))
+ if first:
+ first = False
+ else:
+ yield item_separator
+ yield encoder(key)
+ yield key_separator
+ for chunk in self._iterencode(value, markers):
+ yield chunk
+ if newline_indent is not None:
+ self.current_indent_level -= 1
+ yield self._newline_indent()
+ yield '}'
+ if markers is not None:
+ del markers[markerid]
+
+ def _iterencode(self, o, markers=None):
+ if isinstance(o, basestring):
+ if self.ensure_ascii:
+ encoder = encode_basestring_ascii
+ else:
+ encoder = encode_basestring
+ _encoding = self.encoding
+ if (_encoding is not None and isinstance(o, str)
+ and not (_need_utf8 and _encoding == 'utf-8')):
+ o = o.decode(_encoding)
+ yield encoder(o)
+ elif o is None:
+ yield 'null'
+ elif o is True:
+ yield 'true'
+ elif o is False:
+ yield 'false'
+ elif isinstance(o, (int, long)):
+ yield str(o)
+ elif isinstance(o, float):
+ yield floatstr(o, self.allow_nan)
+ elif isinstance(o, (list, tuple)):
+ for chunk in self._iterencode_list(o, markers):
+ yield chunk
+ elif isinstance(o, dict):
+ for chunk in self._iterencode_dict(o, markers):
+ yield chunk
+ else:
+ if markers is not None:
+ markerid = id(o)
+ if markerid in markers:
+ raise ValueError("Circular reference detected")
+ markers[markerid] = o
+ for chunk in self._iterencode_default(o, markers):
+ yield chunk
+ if markers is not None:
+ del markers[markerid]
+
+ def _iterencode_default(self, o, markers=None):
+ newobj = self.default(o)
+ return self._iterencode(newobj, markers)
+
+ def default(self, o):
+ """
+ Implement this method in a subclass such that it returns
+ a serializable object for ``o``, or calls the base implementation
+ (to raise a ``TypeError``).
+
+ For example, to support arbitrary iterators, you could
+ implement default like this::
+
+ def default(self, o):
+ try:
+ iterable = iter(o)
+ except TypeError:
+ pass
+ else:
+ return list(iterable)
+ return JSONEncoder.default(self, o)
+ """
+ raise TypeError("%r is not JSON serializable" % (o,))
+
+ def encode(self, o):
+ """
+ Return a JSON string representation of a Python data structure.
+
+ >>> JSONEncoder().encode({"foo": ["bar", "baz"]})
+ '{"foo":["bar", "baz"]}'
+ """
+ # This is for extremely simple cases and benchmarks...
+ if isinstance(o, basestring):
+ if isinstance(o, str):
+ _encoding = self.encoding
+ if (_encoding is not None
+ and not (_encoding == 'utf-8' and _need_utf8)):
+ o = o.decode(_encoding)
+ return encode_basestring_ascii(o)
+ # This doesn't pass the iterator directly to ''.join() because it
+ # sucks at reporting exceptions. It's going to do this internally
+ # anyway because it uses PySequence_Fast or similar.
+ chunks = list(self.iterencode(o))
+ return ''.join(chunks)
+
+ def iterencode(self, o):
+ """
+ Encode the given object and yield each string
+ representation as available.
+
+ For example::
+
+ for chunk in JSONEncoder().iterencode(bigobject):
+ mysocket.write(chunk)
+ """
+ if self.check_circular:
+ markers = {}
+ else:
+ markers = None
+ return self._iterencode(o, markers)
+
+__all__ = ['JSONEncoder']
diff --git a/Tools/Scripts/webkitpy/thirdparty/simplejson/jsonfilter.py b/Tools/Scripts/webkitpy/thirdparty/simplejson/jsonfilter.py
new file mode 100644
index 0000000..01ca21d
--- /dev/null
+++ b/Tools/Scripts/webkitpy/thirdparty/simplejson/jsonfilter.py
@@ -0,0 +1,40 @@
+import simplejson
+import cgi
+
+class JSONFilter(object):
+ def __init__(self, app, mime_type='text/x-json'):
+ self.app = app
+ self.mime_type = mime_type
+
+ def __call__(self, environ, start_response):
+ # Read JSON POST input to jsonfilter.json if matching mime type
+ response = {'status': '200 OK', 'headers': []}
+ def json_start_response(status, headers):
+ response['status'] = status
+ response['headers'].extend(headers)
+ environ['jsonfilter.mime_type'] = self.mime_type
+ if environ.get('REQUEST_METHOD', '') == 'POST':
+ if environ.get('CONTENT_TYPE', '') == self.mime_type:
+ args = [_ for _ in [environ.get('CONTENT_LENGTH')] if _]
+ data = environ['wsgi.input'].read(*map(int, args))
+ environ['jsonfilter.json'] = simplejson.loads(data)
+ res = simplejson.dumps(self.app(environ, json_start_response))
+ jsonp = cgi.parse_qs(environ.get('QUERY_STRING', '')).get('jsonp')
+ if jsonp:
+ content_type = 'text/javascript'
+ res = ''.join(jsonp + ['(', res, ')'])
+ elif 'Opera' in environ.get('HTTP_USER_AGENT', ''):
+ # Opera has bunk XMLHttpRequest support for most mime types
+ content_type = 'text/plain'
+ else:
+ content_type = self.mime_type
+ headers = [
+ ('Content-type', content_type),
+ ('Content-length', len(res)),
+ ]
+ headers.extend(response['headers'])
+ start_response(response['status'], headers)
+ return [res]
+
+def factory(app, global_conf, **kw):
+ return JSONFilter(app, **kw)
diff --git a/Tools/Scripts/webkitpy/thirdparty/simplejson/scanner.py b/Tools/Scripts/webkitpy/thirdparty/simplejson/scanner.py
new file mode 100644
index 0000000..64f4999
--- /dev/null
+++ b/Tools/Scripts/webkitpy/thirdparty/simplejson/scanner.py
@@ -0,0 +1,63 @@
+"""
+Iterator based sre token scanner
+"""
+import sre_parse, sre_compile, sre_constants
+from sre_constants import BRANCH, SUBPATTERN
+from re import VERBOSE, MULTILINE, DOTALL
+import re
+
+__all__ = ['Scanner', 'pattern']
+
+FLAGS = (VERBOSE | MULTILINE | DOTALL)
+class Scanner(object):
+ def __init__(self, lexicon, flags=FLAGS):
+ self.actions = [None]
+ # combine phrases into a compound pattern
+ s = sre_parse.Pattern()
+ s.flags = flags
+ p = []
+ for idx, token in enumerate(lexicon):
+ phrase = token.pattern
+ try:
+ subpattern = sre_parse.SubPattern(s,
+ [(SUBPATTERN, (idx + 1, sre_parse.parse(phrase, flags)))])
+ except sre_constants.error:
+ raise
+ p.append(subpattern)
+ self.actions.append(token)
+
+ p = sre_parse.SubPattern(s, [(BRANCH, (None, p))])
+ self.scanner = sre_compile.compile(p)
+
+
+ def iterscan(self, string, idx=0, context=None):
+ """
+ Yield match, end_idx for each match
+ """
+ match = self.scanner.scanner(string, idx).match
+ actions = self.actions
+ lastend = idx
+ end = len(string)
+ while True:
+ m = match()
+ if m is None:
+ break
+ matchbegin, matchend = m.span()
+ if lastend == matchend:
+ break
+ action = actions[m.lastindex]
+ if action is not None:
+ rval, next_pos = action(m, context)
+ if next_pos is not None and next_pos != matchend:
+ # "fast forward" the scanner
+ matchend = next_pos
+ match = self.scanner.scanner(string, matchend).match
+ yield rval, matchend
+ lastend = matchend
+
+def pattern(pattern, flags=FLAGS):
+ def decorator(fn):
+ fn.pattern = pattern
+ fn.regex = re.compile(pattern, flags)
+ return fn
+ return decorator
diff --git a/Tools/Scripts/webkitpy/tool/__init__.py b/Tools/Scripts/webkitpy/tool/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/tool/bot/__init__.py b/Tools/Scripts/webkitpy/tool/bot/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py
new file mode 100644
index 0000000..1d82ea8
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask.py
@@ -0,0 +1,220 @@
+# 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.
+
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.common.net.layouttestresults import LayoutTestResults
+
+
+class CommitQueueTaskDelegate(object):
+ def run_command(self, command):
+ raise NotImplementedError("subclasses must implement")
+
+ def command_passed(self, message, patch):
+ raise NotImplementedError("subclasses must implement")
+
+ def command_failed(self, message, script_error, patch):
+ raise NotImplementedError("subclasses must implement")
+
+ def refetch_patch(self, patch):
+ raise NotImplementedError("subclasses must implement")
+
+ def layout_test_results(self):
+ raise NotImplementedError("subclasses must implement")
+
+ def report_flaky_tests(self, patch, flaky_tests):
+ raise NotImplementedError("subclasses must implement")
+
+
+class CommitQueueTask(object):
+ def __init__(self, delegate, patch):
+ self._delegate = delegate
+ self._patch = patch
+ self._script_error = None
+
+ def _validate(self):
+ # Bugs might get closed, or patches might be obsoleted or r-'d while the
+ # commit-queue is processing.
+ self._patch = self._delegate.refetch_patch(self._patch)
+ if self._patch.is_obsolete():
+ return False
+ if self._patch.bug().is_closed():
+ return False
+ if not self._patch.committer():
+ return False
+ # Reviewer is not required. Missing reviewers will be caught during
+ # the ChangeLog check during landing.
+ return True
+
+ def _run_command(self, command, success_message, failure_message):
+ try:
+ self._delegate.run_command(command)
+ self._delegate.command_passed(success_message, patch=self._patch)
+ return True
+ except ScriptError, e:
+ self._script_error = e
+ self.failure_status_id = self._delegate.command_failed(failure_message, script_error=self._script_error, patch=self._patch)
+ return False
+
+ def _clean(self):
+ return self._run_command([
+ "clean",
+ ],
+ "Cleaned working directory",
+ "Unable to clean working directory")
+
+ def _update(self):
+ # FIXME: Ideally the status server log message should include which revision we updated to.
+ return self._run_command([
+ "update",
+ ],
+ "Updated working directory",
+ "Unable to update working directory")
+
+ def _apply(self):
+ return self._run_command([
+ "apply-attachment",
+ "--no-update",
+ "--non-interactive",
+ self._patch.id(),
+ ],
+ "Applied patch",
+ "Patch does not apply")
+
+ def _build(self):
+ return self._run_command([
+ "build",
+ "--no-clean",
+ "--no-update",
+ "--build-style=both",
+ ],
+ "Built patch",
+ "Patch does not build")
+
+ def _build_without_patch(self):
+ return self._run_command([
+ "build",
+ "--force-clean",
+ "--no-update",
+ "--build-style=both",
+ ],
+ "Able to build without patch",
+ "Unable to build without patch")
+
+ def _test(self):
+ return self._run_command([
+ "build-and-test",
+ "--no-clean",
+ "--no-update",
+ # Notice that we don't pass --build, which means we won't build!
+ "--test",
+ "--non-interactive",
+ ],
+ "Passed tests",
+ "Patch does not pass tests")
+
+ def _build_and_test_without_patch(self):
+ return self._run_command([
+ "build-and-test",
+ "--force-clean",
+ "--no-update",
+ "--build",
+ "--test",
+ "--non-interactive",
+ ],
+ "Able to pass tests without patch",
+ "Unable to pass tests without patch (tree is red?)")
+
+ def _failing_tests_from_last_run(self):
+ results = self._delegate.layout_test_results()
+ if not results:
+ return None
+ return results.failing_tests()
+
+ def _land(self):
+ # Unclear if this should pass --quiet or not. If --parent-command always does the reporting, then it should.
+ return self._run_command([
+ "land-attachment",
+ "--force-clean",
+ "--ignore-builders",
+ "--non-interactive",
+ "--parent-command=commit-queue",
+ self._patch.id(),
+ ],
+ "Landed patch",
+ "Unable to land patch")
+
+ def _report_flaky_tests(self, flaky_tests):
+ self._delegate.report_flaky_tests(self._patch, flaky_tests)
+
+ def _test_patch(self):
+ if self._patch.is_rollout():
+ return True
+ if self._test():
+ return True
+
+ first_failing_tests = self._failing_tests_from_last_run()
+ if self._test():
+ self._report_flaky_tests(first_failing_tests)
+ return True
+
+ second_failing_tests = self._failing_tests_from_last_run()
+ if first_failing_tests != second_failing_tests:
+ # We could report flaky tests here, but since run-webkit-tests
+ # is run with --exit-after-N-failures=1, we would need to
+ # be careful not to report constant failures as flaky due to earlier
+ # flaky test making them not fail (no results) in one of the runs.
+ # See https://bugs.webkit.org/show_bug.cgi?id=51272
+ return False
+
+ if self._build_and_test_without_patch():
+ raise self._script_error # The error from the previous ._test() run is real, report it.
+ return False # Tree must be red, just retry later.
+
+ def run(self):
+ if not self._validate():
+ return False
+ if not self._clean():
+ return False
+ if not self._update():
+ return False
+ if not self._apply():
+ raise self._script_error
+ if not self._build():
+ if not self._build_without_patch():
+ return False
+ raise self._script_error
+ if not self._test_patch():
+ return False
+ # Make sure the patch is still valid before landing (e.g., make sure
+ # no one has set commit-queue- since we started working on the patch.)
+ if not self._validate():
+ return False
+ # FIXME: We should understand why the land failure occured and retry if possible.
+ if not self._land():
+ raise self._script_error
+ return True
diff --git a/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py
new file mode 100644
index 0000000..376f407
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/commitqueuetask_unittest.py
@@ -0,0 +1,316 @@
+# 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.
+
+from datetime import datetime
+import unittest
+
+from webkitpy.common.system.deprecated_logging import error, log
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.tool.bot.commitqueuetask import *
+from webkitpy.tool.mocktool import MockTool
+
+
+class MockCommitQueue(CommitQueueTaskDelegate):
+ def __init__(self, error_plan):
+ self._error_plan = error_plan
+
+ def run_command(self, command):
+ log("run_webkit_patch: %s" % command)
+ if self._error_plan:
+ error = self._error_plan.pop(0)
+ if error:
+ raise error
+
+ def command_passed(self, success_message, patch):
+ log("command_passed: success_message='%s' patch='%s'" % (
+ success_message, patch.id()))
+
+ def command_failed(self, failure_message, script_error, patch):
+ log("command_failed: failure_message='%s' script_error='%s' patch='%s'" % (
+ failure_message, script_error, patch.id()))
+ return 3947
+
+ def refetch_patch(self, patch):
+ return patch
+
+ def layout_test_results(self):
+ return None
+
+ def report_flaky_tests(self, patch, flaky_tests):
+ log("report_flaky_tests: patch='%s' flaky_tests='%s'" % (patch.id(), flaky_tests))
+
+
+class CommitQueueTaskTest(unittest.TestCase):
+ def _run_through_task(self, commit_queue, expected_stderr, expected_exception=None, expect_retry=False):
+ tool = MockTool(log_executive=True)
+ patch = tool.bugs.fetch_attachment(197)
+ task = CommitQueueTask(commit_queue, patch)
+ success = OutputCapture().assert_outputs(self, task.run, expected_stderr=expected_stderr, expected_exception=expected_exception)
+ if not expected_exception:
+ self.assertEqual(success, not expect_retry)
+
+ def test_success_case(self):
+ commit_queue = MockCommitQueue([])
+ expected_stderr = """run_webkit_patch: ['clean']
+command_passed: success_message='Cleaned working directory' patch='197'
+run_webkit_patch: ['update']
+command_passed: success_message='Updated working directory' patch='197'
+run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 197]
+command_passed: success_message='Applied patch' patch='197'
+run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=both']
+command_passed: success_message='Built patch' patch='197'
+run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+command_passed: success_message='Passed tests' patch='197'
+run_webkit_patch: ['land-attachment', '--force-clean', '--ignore-builders', '--non-interactive', '--parent-command=commit-queue', 197]
+command_passed: success_message='Landed patch' patch='197'
+"""
+ self._run_through_task(commit_queue, expected_stderr)
+
+ def test_clean_failure(self):
+ commit_queue = MockCommitQueue([
+ ScriptError("MOCK clean failure"),
+ ])
+ expected_stderr = """run_webkit_patch: ['clean']
+command_failed: failure_message='Unable to clean working directory' script_error='MOCK clean failure' patch='197'
+"""
+ self._run_through_task(commit_queue, expected_stderr, expect_retry=True)
+
+ def test_update_failure(self):
+ commit_queue = MockCommitQueue([
+ None,
+ ScriptError("MOCK update failure"),
+ ])
+ expected_stderr = """run_webkit_patch: ['clean']
+command_passed: success_message='Cleaned working directory' patch='197'
+run_webkit_patch: ['update']
+command_failed: failure_message='Unable to update working directory' script_error='MOCK update failure' patch='197'
+"""
+ self._run_through_task(commit_queue, expected_stderr, expect_retry=True)
+
+ def test_apply_failure(self):
+ commit_queue = MockCommitQueue([
+ None,
+ None,
+ ScriptError("MOCK apply failure"),
+ ])
+ expected_stderr = """run_webkit_patch: ['clean']
+command_passed: success_message='Cleaned working directory' patch='197'
+run_webkit_patch: ['update']
+command_passed: success_message='Updated working directory' patch='197'
+run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 197]
+command_failed: failure_message='Patch does not apply' script_error='MOCK apply failure' patch='197'
+"""
+ self._run_through_task(commit_queue, expected_stderr, ScriptError)
+
+ def test_build_failure(self):
+ commit_queue = MockCommitQueue([
+ None,
+ None,
+ None,
+ ScriptError("MOCK build failure"),
+ ])
+ expected_stderr = """run_webkit_patch: ['clean']
+command_passed: success_message='Cleaned working directory' patch='197'
+run_webkit_patch: ['update']
+command_passed: success_message='Updated working directory' patch='197'
+run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 197]
+command_passed: success_message='Applied patch' patch='197'
+run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=both']
+command_failed: failure_message='Patch does not build' script_error='MOCK build failure' patch='197'
+run_webkit_patch: ['build', '--force-clean', '--no-update', '--build-style=both']
+command_passed: success_message='Able to build without patch' patch='197'
+"""
+ self._run_through_task(commit_queue, expected_stderr, ScriptError)
+
+ def test_red_build_failure(self):
+ commit_queue = MockCommitQueue([
+ None,
+ None,
+ None,
+ ScriptError("MOCK build failure"),
+ ScriptError("MOCK clean build failure"),
+ ])
+ expected_stderr = """run_webkit_patch: ['clean']
+command_passed: success_message='Cleaned working directory' patch='197'
+run_webkit_patch: ['update']
+command_passed: success_message='Updated working directory' patch='197'
+run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 197]
+command_passed: success_message='Applied patch' patch='197'
+run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=both']
+command_failed: failure_message='Patch does not build' script_error='MOCK build failure' patch='197'
+run_webkit_patch: ['build', '--force-clean', '--no-update', '--build-style=both']
+command_failed: failure_message='Unable to build without patch' script_error='MOCK clean build failure' patch='197'
+"""
+ self._run_through_task(commit_queue, expected_stderr, expect_retry=True)
+
+ def test_flaky_test_failure(self):
+ commit_queue = MockCommitQueue([
+ None,
+ None,
+ None,
+ None,
+ ScriptError("MOCK tests failure"),
+ ])
+ expected_stderr = """run_webkit_patch: ['clean']
+command_passed: success_message='Cleaned working directory' patch='197'
+run_webkit_patch: ['update']
+command_passed: success_message='Updated working directory' patch='197'
+run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 197]
+command_passed: success_message='Applied patch' patch='197'
+run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=both']
+command_passed: success_message='Built patch' patch='197'
+run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+command_failed: failure_message='Patch does not pass tests' script_error='MOCK tests failure' patch='197'
+run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+command_passed: success_message='Passed tests' patch='197'
+report_flaky_tests: patch='197' flaky_tests='None'
+run_webkit_patch: ['land-attachment', '--force-clean', '--ignore-builders', '--non-interactive', '--parent-command=commit-queue', 197]
+command_passed: success_message='Landed patch' patch='197'
+"""
+ self._run_through_task(commit_queue, expected_stderr)
+
+ _double_flaky_test_counter = 0
+
+ def test_double_flaky_test_failure(self):
+ commit_queue = MockCommitQueue([
+ None,
+ None,
+ None,
+ None,
+ ScriptError("MOCK test failure"),
+ ScriptError("MOCK test failure again"),
+ ])
+ # The (subtle) point of this test is that report_flaky_tests does not appear
+ # in the expected_stderr for this run.
+ # Note also that there is no attempt to run the tests w/o the patch.
+ expected_stderr = """run_webkit_patch: ['clean']
+command_passed: success_message='Cleaned working directory' patch='197'
+run_webkit_patch: ['update']
+command_passed: success_message='Updated working directory' patch='197'
+run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 197]
+command_passed: success_message='Applied patch' patch='197'
+run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=both']
+command_passed: success_message='Built patch' patch='197'
+run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+command_failed: failure_message='Patch does not pass tests' script_error='MOCK test failure' patch='197'
+run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+command_failed: failure_message='Patch does not pass tests' script_error='MOCK test failure again' patch='197'
+"""
+ tool = MockTool(log_executive=True)
+ patch = tool.bugs.fetch_attachment(197)
+ task = CommitQueueTask(commit_queue, patch)
+ self._double_flaky_test_counter = 0
+
+ def mock_failing_tests_from_last_run():
+ CommitQueueTaskTest._double_flaky_test_counter += 1
+ if CommitQueueTaskTest._double_flaky_test_counter % 2:
+ return ['foo.html']
+ return ['bar.html']
+
+ task._failing_tests_from_last_run = mock_failing_tests_from_last_run
+ success = OutputCapture().assert_outputs(self, task.run, expected_stderr=expected_stderr)
+ self.assertEqual(success, False)
+
+ def test_test_failure(self):
+ commit_queue = MockCommitQueue([
+ None,
+ None,
+ None,
+ None,
+ ScriptError("MOCK test failure"),
+ ScriptError("MOCK test failure again"),
+ ])
+ expected_stderr = """run_webkit_patch: ['clean']
+command_passed: success_message='Cleaned working directory' patch='197'
+run_webkit_patch: ['update']
+command_passed: success_message='Updated working directory' patch='197'
+run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 197]
+command_passed: success_message='Applied patch' patch='197'
+run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=both']
+command_passed: success_message='Built patch' patch='197'
+run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+command_failed: failure_message='Patch does not pass tests' script_error='MOCK test failure' patch='197'
+run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+command_failed: failure_message='Patch does not pass tests' script_error='MOCK test failure again' patch='197'
+run_webkit_patch: ['build-and-test', '--force-clean', '--no-update', '--build', '--test', '--non-interactive']
+command_passed: success_message='Able to pass tests without patch' patch='197'
+"""
+ self._run_through_task(commit_queue, expected_stderr, ScriptError)
+
+ def test_red_test_failure(self):
+ commit_queue = MockCommitQueue([
+ None,
+ None,
+ None,
+ None,
+ ScriptError("MOCK test failure"),
+ ScriptError("MOCK test failure again"),
+ ScriptError("MOCK clean test failure"),
+ ])
+ expected_stderr = """run_webkit_patch: ['clean']
+command_passed: success_message='Cleaned working directory' patch='197'
+run_webkit_patch: ['update']
+command_passed: success_message='Updated working directory' patch='197'
+run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 197]
+command_passed: success_message='Applied patch' patch='197'
+run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=both']
+command_passed: success_message='Built patch' patch='197'
+run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+command_failed: failure_message='Patch does not pass tests' script_error='MOCK test failure' patch='197'
+run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+command_failed: failure_message='Patch does not pass tests' script_error='MOCK test failure again' patch='197'
+run_webkit_patch: ['build-and-test', '--force-clean', '--no-update', '--build', '--test', '--non-interactive']
+command_failed: failure_message='Unable to pass tests without patch (tree is red?)' script_error='MOCK clean test failure' patch='197'
+"""
+ self._run_through_task(commit_queue, expected_stderr, expect_retry=True)
+
+ def test_land_failure(self):
+ commit_queue = MockCommitQueue([
+ None,
+ None,
+ None,
+ None,
+ None,
+ ScriptError("MOCK land failure"),
+ ])
+ expected_stderr = """run_webkit_patch: ['clean']
+command_passed: success_message='Cleaned working directory' patch='197'
+run_webkit_patch: ['update']
+command_passed: success_message='Updated working directory' patch='197'
+run_webkit_patch: ['apply-attachment', '--no-update', '--non-interactive', 197]
+command_passed: success_message='Applied patch' patch='197'
+run_webkit_patch: ['build', '--no-clean', '--no-update', '--build-style=both']
+command_passed: success_message='Built patch' patch='197'
+run_webkit_patch: ['build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+command_passed: success_message='Passed tests' patch='197'
+run_webkit_patch: ['land-attachment', '--force-clean', '--ignore-builders', '--non-interactive', '--parent-command=commit-queue', 197]
+command_failed: failure_message='Unable to land patch' script_error='MOCK land failure' patch='197'
+"""
+ # FIXME: This should really be expect_retry=True for a better user experiance.
+ self._run_through_task(commit_queue, expected_stderr, ScriptError)
diff --git a/Tools/Scripts/webkitpy/tool/bot/feeders.py b/Tools/Scripts/webkitpy/tool/bot/feeders.py
new file mode 100644
index 0000000..046c4c1
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/feeders.py
@@ -0,0 +1,90 @@
+# 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.
+
+from webkitpy.common.config.committervalidator import CommitterValidator
+from webkitpy.common.system.deprecated_logging import log
+from webkitpy.tool.grammar import pluralize
+
+
+class AbstractFeeder(object):
+ def __init__(self, tool):
+ self._tool = tool
+
+ def feed(self):
+ raise NotImplementedError("subclasses must implement")
+
+
+class CommitQueueFeeder(AbstractFeeder):
+ queue_name = "commit-queue"
+
+ def __init__(self, tool):
+ AbstractFeeder.__init__(self, tool)
+ self.committer_validator = CommitterValidator(self._tool.bugs)
+
+ def _update_work_items(self, item_ids):
+ # FIXME: This is the last use of update_work_items, the commit-queue
+ # should move to feeding patches one at a time like the EWS does.
+ self._tool.status_server.update_work_items(self.queue_name, item_ids)
+ log("Feeding %s items %s" % (self.queue_name, item_ids))
+
+ def feed(self):
+ patches = self._validate_patches()
+ patches = sorted(patches, self._patch_cmp)
+ patch_ids = [patch.id() for patch in patches]
+ self._update_work_items(patch_ids)
+
+ def _patches_for_bug(self, bug_id):
+ return self._tool.bugs.fetch_bug(bug_id).commit_queued_patches(include_invalid=True)
+
+ def _validate_patches(self):
+ # Not using BugzillaQueries.fetch_patches_from_commit_queue() so we can reject patches with invalid committers/reviewers.
+ bug_ids = self._tool.bugs.queries.fetch_bug_ids_from_commit_queue()
+ all_patches = sum([self._patches_for_bug(bug_id) for bug_id in bug_ids], [])
+ return self.committer_validator.patches_after_rejecting_invalid_commiters_and_reviewers(all_patches)
+
+ def _patch_cmp(self, a, b):
+ # Sort first by is_rollout, then by attach_date.
+ # Reversing the order so that is_rollout is first.
+ rollout_cmp = cmp(b.is_rollout(), a.is_rollout())
+ if rollout_cmp != 0:
+ return rollout_cmp
+ return cmp(a.attach_date(), b.attach_date())
+
+
+class EWSFeeder(AbstractFeeder):
+ def __init__(self, tool):
+ self._ids_sent_to_server = set()
+ AbstractFeeder.__init__(self, tool)
+
+ def feed(self):
+ ids_needing_review = set(self._tool.bugs.queries.fetch_attachment_ids_from_review_queue())
+ new_ids = ids_needing_review.difference(self._ids_sent_to_server)
+ log("Feeding EWS (%s, %s new)" % (pluralize("r? patch", len(ids_needing_review)), len(new_ids)))
+ for attachment_id in new_ids: # Order doesn't really matter for the EWS.
+ self._tool.status_server.submit_to_ews(attachment_id)
+ self._ids_sent_to_server.add(attachment_id)
diff --git a/Tools/Scripts/webkitpy/tool/bot/feeders_unittest.py b/Tools/Scripts/webkitpy/tool/bot/feeders_unittest.py
new file mode 100644
index 0000000..580f840
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/feeders_unittest.py
@@ -0,0 +1,70 @@
+# 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.
+
+from datetime import datetime
+import unittest
+
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.tool.bot.feeders import *
+from webkitpy.tool.mocktool import MockTool
+
+
+class FeedersTest(unittest.TestCase):
+ def test_commit_queue_feeder(self):
+ feeder = CommitQueueFeeder(MockTool())
+ expected_stderr = u"""Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)
+Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)
+MOCK setting flag 'commit-queue' to '-' on attachment '128' with comment 'Rejecting attachment 128 from commit-queue.' and additional comment 'non-committer@example.com does not have committer permissions according to http://trac.webkit.org/browser/trunk/Tools/Scripts/webkitpy/common/config/committers.py.
+
+- If you do not have committer rights please read http://webkit.org/coding/contributing.html for instructions on how to use bugzilla flags.
+
+- If you have committer rights please correct the error in Tools/Scripts/webkitpy/common/config/committers.py by adding yourself to the file (no review needed). The commit-queue restarts itself every 2 hours. After restart the commit-queue will correctly respect your committer rights.'
+MOCK: update_work_items: commit-queue [106, 197]
+Feeding commit-queue items [106, 197]
+"""
+ OutputCapture().assert_outputs(self, feeder.feed, expected_stderr=expected_stderr)
+
+ def _mock_attachment(self, is_rollout, attach_date):
+ attachment = Mock()
+ attachment.is_rollout = lambda: is_rollout
+ attachment.attach_date = lambda: attach_date
+ return attachment
+
+ def test_patch_cmp(self):
+ long_ago_date = datetime(1900, 1, 21)
+ recent_date = datetime(2010, 1, 21)
+ attachment1 = self._mock_attachment(is_rollout=False, attach_date=recent_date)
+ attachment2 = self._mock_attachment(is_rollout=False, attach_date=long_ago_date)
+ attachment3 = self._mock_attachment(is_rollout=True, attach_date=recent_date)
+ attachment4 = self._mock_attachment(is_rollout=True, attach_date=long_ago_date)
+ attachments = [attachment1, attachment2, attachment3, attachment4]
+ expected_sort = [attachment4, attachment3, attachment2, attachment1]
+ queue = CommitQueueFeeder(MockTool())
+ attachments.sort(queue._patch_cmp)
+ self.assertEqual(attachments, expected_sort)
diff --git a/Tools/Scripts/webkitpy/tool/bot/flakytestreporter.py b/Tools/Scripts/webkitpy/tool/bot/flakytestreporter.py
new file mode 100644
index 0000000..01cbf39
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/flakytestreporter.py
@@ -0,0 +1,181 @@
+# 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 codecs
+import logging
+import platform
+import os.path
+
+from webkitpy.common.net.layouttestresults import path_for_layout_test, LayoutTestResults
+from webkitpy.common.config import urls
+from webkitpy.tool.grammar import plural, pluralize, join_with_separators
+
+_log = logging.getLogger(__name__)
+
+
+class FlakyTestReporter(object):
+ def __init__(self, tool, bot_name):
+ self._tool = tool
+ self._bot_name = bot_name
+
+ def _author_emails_for_test(self, flaky_test):
+ test_path = path_for_layout_test(flaky_test)
+ commit_infos = self._tool.checkout().recent_commit_infos_for_files([test_path])
+ # This ignores authors which are not committers because we don't have their bugzilla_email.
+ return set([commit_info.author().bugzilla_email() for commit_info in commit_infos if commit_info.author()])
+
+ def _bugzilla_email(self):
+ # FIXME: This is kinda a funny way to get the bugzilla email,
+ # we could also just create a Credentials object directly
+ # but some of the Credentials logic is in bugzilla.py too...
+ self._tool.bugs.authenticate()
+ return self._tool.bugs.username
+
+ # FIXME: This should move into common.config
+ _bot_emails = set([
+ "commit-queue@webkit.org", # commit-queue
+ "eseidel@chromium.org", # old commit-queue
+ "webkit.review.bot@gmail.com", # style-queue, sheriff-bot, CrLx/Gtk EWS
+ "buildbot@hotmail.com", # Win EWS
+ # Mac EWS currently uses eric@webkit.org, but that's not normally a bot
+ ])
+
+ def _lookup_bug_for_flaky_test(self, flaky_test):
+ bugs = self._tool.bugs.queries.fetch_bugs_matching_search(search_string=flaky_test)
+ if not bugs:
+ return None
+ # Match any bugs which are from known bots or the email this bot is using.
+ allowed_emails = self._bot_emails | set([self._bugzilla_email])
+ bugs = filter(lambda bug: bug.reporter_email() in allowed_emails, bugs)
+ if not bugs:
+ return None
+ if len(bugs) > 1:
+ # FIXME: There are probably heuristics we could use for finding
+ # the right bug instead of the first, like open vs. closed.
+ _log.warn("Found %s %s matching '%s' filed by a bot, using the first." % (pluralize('bug', len(bugs)), [bug.id() for bug in bugs], flaky_test))
+ return bugs[0]
+
+ def _view_source_url_for_test(self, test_path):
+ return urls.view_source_url("LayoutTests/%s" % test_path)
+
+ def _create_bug_for_flaky_test(self, flaky_test, author_emails, latest_flake_message):
+ format_values = {
+ 'test': flaky_test,
+ 'authors': join_with_separators(sorted(author_emails)),
+ 'flake_message': latest_flake_message,
+ 'test_url': self._view_source_url_for_test(flaky_test),
+ 'bot_name': self._bot_name,
+ }
+ title = "Flaky Test: %(test)s" % format_values
+ description = """This is an automatically generated bug from the %(bot_name)s.
+%(test)s has been flaky on the %(bot_name)s.
+
+%(test)s was authored by %(authors)s.
+%(test_url)s
+
+%(flake_message)s
+
+The bots will update this with information from each new failure.
+
+If you would like to track this test fix with another bug, please close this bug as a duplicate.
+""" % format_values
+
+ master_flake_bug = 50856 # MASTER: Flaky tests found by the commit-queue
+ return self._tool.bugs.create_bug(title, description,
+ component="Tools / Tests",
+ cc=",".join(author_emails),
+ blocked="50856")
+
+ # This is over-engineered, but it makes for pretty bug messages.
+ def _optional_author_string(self, author_emails):
+ if not author_emails:
+ return ""
+ heading_string = plural('author') if len(author_emails) > 1 else 'author'
+ authors_string = join_with_separators(sorted(author_emails))
+ return " (%s: %s)" % (heading_string, authors_string)
+
+ def _bot_information(self):
+ bot_id = self._tool.status_server.bot_id
+ bot_id_string = "Bot: %s " % (bot_id) if bot_id else ""
+ return "%sPort: %s Platform: %s" % (bot_id_string, self._tool.port().name(), self._tool.platform.display_name())
+
+ def _latest_flake_message(self, flaky_test, patch):
+ flake_message = "The %s just saw %s flake while processing attachment %s on bug %s." % (self._bot_name, flaky_test, patch.id(), patch.bug_id())
+ return "%s\n%s" % (flake_message, self._bot_information())
+
+ def _results_diff_path_for_test(self, flaky_test):
+ # FIXME: This is a big hack. We should get this path from results.json
+ # except that old-run-webkit-tests doesn't produce a results.json
+ # so we just guess at the file path.
+ results_path = self._tool.port().layout_tests_results_path()
+ results_directory = os.path.dirname(results_path)
+ test_path = os.path.join(results_directory, flaky_test)
+ (test_path_root, _) = os.path.splitext(test_path)
+ return "%s-diffs.txt" % test_path_root
+
+ def _follow_duplicate_chain(self, bug):
+ while bug.is_closed() and bug.duplicate_of():
+ bug = self._tool.bugs.fetch_bug(bug.duplicate_of())
+ return bug
+
+ # Maybe this logic should move into Bugzilla? a reopen=True arg to post_comment?
+ def _update_bug_for_flaky_test(self, bug, latest_flake_message):
+ if bug.is_closed():
+ self._tool.bugs.reopen_bug(bug.id(), latest_flake_message)
+ else:
+ self._tool.bugs.post_comment_to_bug(bug.id(), latest_flake_message)
+
+ def report_flaky_tests(self, flaky_tests, patch):
+ message = "The %s encountered the following flaky tests while processing attachment %s:\n\n" % (self._bot_name, patch.id())
+ for flaky_test in flaky_tests:
+ bug = self._lookup_bug_for_flaky_test(flaky_test)
+ latest_flake_message = self._latest_flake_message(flaky_test, patch)
+ author_emails = self._author_emails_for_test(flaky_test)
+ if not bug:
+ _log.info("Bug does not already exist for %s, creating." % flaky_test)
+ flake_bug_id = self._create_bug_for_flaky_test(flaky_test, author_emails, latest_flake_message)
+ else:
+ bug = self._follow_duplicate_chain(bug)
+ self._update_bug_for_flaky_test(bug, latest_flake_message)
+ flake_bug_id = bug.id()
+ # FIXME: Ideally we'd only make one comment per flake, not two. But that's not possible
+ # in all cases (e.g. when reopening), so for now we do the attachment in a second step.
+ results_diff_path = self._results_diff_path_for_test(flaky_test)
+ # Check to make sure that the path makes sense.
+ # Since we're not actually getting this path from the results.html
+ # there is a high probaility it's totally wrong.
+ if self._tool.filesystem.exists(results_diff_path):
+ results_diff = self._tool.filesystem.read_binary_file(results_diff_path)
+ bot_id = self._tool.status_server.bot_id or "bot"
+ self._tool.bugs.add_attachment_to_bug(flake_bug_id, results_diff, "Failure diff from %s" % bot_id, filename="failure.diff")
+ else:
+ _log.error("%s does not exist as expected, not uploading." % results_diff_path)
+ message += "%s bug %s%s\n" % (flaky_test, flake_bug_id, self._optional_author_string(author_emails))
+
+ message += "The %s is continuing to process your patch." % self._bot_name
+ self._tool.bugs.post_comment_to_bug(patch.bug_id(), message)
diff --git a/Tools/Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py b/Tools/Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py
new file mode 100644
index 0000000..f72fb28
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/flakytestreporter_unittest.py
@@ -0,0 +1,145 @@
+# 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 unittest
+
+from webkitpy.common.config.committers import Committer
+from webkitpy.common.system.filesystem_mock import MockFileSystem
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.bot.flakytestreporter import FlakyTestReporter
+from webkitpy.tool.mocktool import MockTool, MockStatusServer
+
+
+# Creating fake CommitInfos is a pain, so we use a mock one here.
+class MockCommitInfo(object):
+ def __init__(self, author_email):
+ self._author_email = author_email
+
+ def author(self):
+ # It's definitely possible to have commits with authors who
+ # are not in our committers.py list.
+ if not self._author_email:
+ return None
+ return Committer("Mock Committer", self._author_email)
+
+
+class FlakyTestReporterTest(unittest.TestCase):
+ def _assert_emails_for_test(self, emails):
+ tool = MockTool()
+ reporter = FlakyTestReporter(tool, 'dummy-queue')
+ commit_infos = [MockCommitInfo(email) for email in emails]
+ tool.checkout().recent_commit_infos_for_files = lambda paths: set(commit_infos)
+ self.assertEqual(reporter._author_emails_for_test([]), set(emails))
+
+ def test_author_emails_for_test(self):
+ self._assert_emails_for_test([])
+ self._assert_emails_for_test(["test1@test.com", "test1@test.com"])
+ self._assert_emails_for_test(["test1@test.com", "test2@test.com"])
+
+ def test_create_bug_for_flaky_test(self):
+ reporter = FlakyTestReporter(MockTool(), 'dummy-queue')
+ expected_stderr = """MOCK create_bug
+bug_title: Flaky Test: foo/bar.html
+bug_description: This is an automatically generated bug from the dummy-queue.
+foo/bar.html has been flaky on the dummy-queue.
+
+foo/bar.html was authored by test@test.com.
+http://trac.webkit.org/browser/trunk/LayoutTests/foo/bar.html
+
+FLAKE_MESSAGE
+
+The bots will update this with information from each new failure.
+
+If you would like to track this test fix with another bug, please close this bug as a duplicate.
+
+component: Tools / Tests
+cc: test@test.com
+blocked: 50856
+"""
+ OutputCapture().assert_outputs(self, reporter._create_bug_for_flaky_test, ['foo/bar.html', ['test@test.com'], 'FLAKE_MESSAGE'], expected_stderr=expected_stderr)
+
+ def test_follow_duplicate_chain(self):
+ tool = MockTool()
+ reporter = FlakyTestReporter(tool, 'dummy-queue')
+ bug = tool.bugs.fetch_bug(78)
+ self.assertEqual(reporter._follow_duplicate_chain(bug).id(), 76)
+
+ def test_bot_information(self):
+ tool = MockTool()
+ tool.status_server = MockStatusServer("MockBotId")
+ reporter = FlakyTestReporter(tool, 'dummy-queue')
+ self.assertEqual(reporter._bot_information(), "Bot: MockBotId Port: MockPort Platform: MockPlatform 1.0")
+
+ def test_report_flaky_tests_creating_bug(self):
+ tool = MockTool()
+ tool.filesystem = MockFileSystem({"/mock/foo/bar-diffs.txt": "mock"})
+ tool.status_server = MockStatusServer(bot_id="mock-bot-id")
+ reporter = FlakyTestReporter(tool, 'dummy-queue')
+ reporter._lookup_bug_for_flaky_test = lambda bug_id: None
+ patch = tool.bugs.fetch_attachment(197)
+ expected_stderr = """MOCK create_bug
+bug_title: Flaky Test: foo/bar.html
+bug_description: This is an automatically generated bug from the dummy-queue.
+foo/bar.html has been flaky on the dummy-queue.
+
+foo/bar.html was authored by abarth@webkit.org.
+http://trac.webkit.org/browser/trunk/LayoutTests/foo/bar.html
+
+The dummy-queue just saw foo/bar.html flake while processing attachment 197 on bug 42.
+Bot: mock-bot-id Port: MockPort Platform: MockPlatform 1.0
+
+The bots will update this with information from each new failure.
+
+If you would like to track this test fix with another bug, please close this bug as a duplicate.
+
+component: Tools / Tests
+cc: abarth@webkit.org
+blocked: 50856
+MOCK add_attachment_to_bug: bug_id=78, description=Failure diff from mock-bot-id filename=failure.diff
+MOCK bug comment: bug_id=42, cc=None
+--- Begin comment ---
+The dummy-queue encountered the following flaky tests while processing attachment 197:
+
+foo/bar.html bug 78 (author: abarth@webkit.org)
+The dummy-queue is continuing to process your patch.
+--- End comment ---
+
+"""
+ OutputCapture().assert_outputs(self, reporter.report_flaky_tests, [['foo/bar.html'], patch], expected_stderr=expected_stderr)
+
+ def test_optional_author_string(self):
+ reporter = FlakyTestReporter(MockTool(), 'dummy-queue')
+ self.assertEqual(reporter._optional_author_string([]), "")
+ self.assertEqual(reporter._optional_author_string(["foo@bar.com"]), " (author: foo@bar.com)")
+ self.assertEqual(reporter._optional_author_string(["a@b.com", "b@b.com"]), " (authors: a@b.com and b@b.com)")
+
+ def test_results_diff_path_for_test(self):
+ reporter = FlakyTestReporter(MockTool(), 'dummy-queue')
+ self.assertEqual(reporter._results_diff_path_for_test("test.html"), "/mock/test-diffs.txt")
+
+ # report_flaky_tests is also tested by queues_unittest
diff --git a/Tools/Scripts/webkitpy/tool/bot/irc_command.py b/Tools/Scripts/webkitpy/tool/bot/irc_command.py
new file mode 100644
index 0000000..0c17c9f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/irc_command.py
@@ -0,0 +1,109 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import random
+import webkitpy.common.config.irc as config_irc
+
+from webkitpy.common.config import urls
+from webkitpy.tool.bot.queueengine import TerminateQueue
+from webkitpy.common.net.bugzilla import parse_bug_id
+from webkitpy.common.system.executive import ScriptError
+
+# FIXME: Merge with Command?
+class IRCCommand(object):
+ def execute(self, nick, args, tool, sheriff):
+ raise NotImplementedError, "subclasses must implement"
+
+
+class LastGreenRevision(IRCCommand):
+ def execute(self, nick, args, tool, sheriff):
+ return "%s: %s" % (nick,
+ urls.view_revision_url(tool.buildbot.last_green_revision()))
+
+
+class Restart(IRCCommand):
+ def execute(self, nick, args, tool, sheriff):
+ tool.irc().post("Restarting...")
+ raise TerminateQueue()
+
+
+class Rollout(IRCCommand):
+ def execute(self, nick, args, tool, sheriff):
+ if len(args) < 2:
+ tool.irc().post("%s: Usage: SVN_REVISION REASON" % nick)
+ return
+ svn_revision = args[0].lstrip("r")
+ rollout_reason = " ".join(args[1:])
+ tool.irc().post("Preparing rollout for r%s..." % svn_revision)
+ try:
+ complete_reason = "%s (Requested by %s on %s)." % (
+ rollout_reason, nick, config_irc.channel)
+ bug_id = sheriff.post_rollout_patch(svn_revision, complete_reason)
+ bug_url = tool.bugs.bug_url_for_bug_id(bug_id)
+ tool.irc().post("%s: Created rollout: %s" % (nick, bug_url))
+ except ScriptError, e:
+ tool.irc().post("%s: Failed to create rollout patch:" % nick)
+ tool.irc().post("%s" % e)
+ bug_id = parse_bug_id(e.output)
+ if bug_id:
+ tool.irc().post("Ugg... Might have created %s" %
+ tool.bugs.bug_url_for_bug_id(bug_id))
+
+
+class Help(IRCCommand):
+ def execute(self, nick, args, tool, sheriff):
+ return "%s: Available commands: %s" % (nick, ", ".join(commands.keys()))
+
+
+class Hi(IRCCommand):
+ def execute(self, nick, args, tool, sheriff):
+ quips = tool.bugs.quips()
+ quips.append('"Only you can prevent forest fires." -- Smokey the Bear')
+ return random.choice(quips)
+
+
+class Eliza(IRCCommand):
+ therapist = None
+
+ def __init__(self):
+ if not self.therapist:
+ import webkitpy.thirdparty.autoinstalled.eliza as eliza
+ Eliza.therapist = eliza.eliza()
+
+ def execute(self, nick, args, tool, sheriff):
+ return "%s: %s" % (nick, self.therapist.respond(" ".join(args)))
+
+
+# FIXME: Lame. We should have an auto-registering CommandCenter.
+commands = {
+ "last-green-revision": LastGreenRevision,
+ "restart": Restart,
+ "rollout": Rollout,
+ "help": Help,
+ "hi": Hi,
+}
diff --git a/Tools/Scripts/webkitpy/tool/bot/irc_command_unittest.py b/Tools/Scripts/webkitpy/tool/bot/irc_command_unittest.py
new file mode 100644
index 0000000..7aeb6a0
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/irc_command_unittest.py
@@ -0,0 +1,38 @@
+# 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 unittest
+
+from webkitpy.tool.bot.irc_command import *
+
+
+class IRCCommandTest(unittest.TestCase):
+ def test_eliza(self):
+ eliza = Eliza()
+ eliza.execute("tom", "hi", None, None)
+ eliza.execute("tom", "bye", None, None)
diff --git a/Tools/Scripts/webkitpy/tool/bot/queueengine.py b/Tools/Scripts/webkitpy/tool/bot/queueengine.py
new file mode 100644
index 0000000..8b016e8
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/queueengine.py
@@ -0,0 +1,165 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# 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:
+#
+# * 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 os
+import time
+import traceback
+
+from datetime import datetime, timedelta
+
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.common.system.deprecated_logging import log, OutputTee
+
+
+class TerminateQueue(Exception):
+ pass
+
+
+class QueueEngineDelegate:
+ def queue_log_path(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def work_item_log_path(self, work_item):
+ raise NotImplementedError, "subclasses must implement"
+
+ def begin_work_queue(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def should_continue_work_queue(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def next_work_item(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def should_proceed_with_work_item(self, work_item):
+ # returns (safe_to_proceed, waiting_message, patch)
+ raise NotImplementedError, "subclasses must implement"
+
+ def process_work_item(self, work_item):
+ raise NotImplementedError, "subclasses must implement"
+
+ def handle_unexpected_error(self, work_item, message):
+ raise NotImplementedError, "subclasses must implement"
+
+
+class QueueEngine:
+ def __init__(self, name, delegate, wakeup_event):
+ self._name = name
+ self._delegate = delegate
+ self._wakeup_event = wakeup_event
+ self._output_tee = OutputTee()
+
+ log_date_format = "%Y-%m-%d %H:%M:%S"
+ sleep_duration_text = "2 mins" # This could be generated from seconds_to_sleep
+ seconds_to_sleep = 120
+ handled_error_code = 2
+
+ # Child processes exit with a special code to the parent queue process can detect the error was handled.
+ @classmethod
+ def exit_after_handled_error(cls, error):
+ log(error)
+ exit(cls.handled_error_code)
+
+ def run(self):
+ self._begin_logging()
+
+ self._delegate.begin_work_queue()
+ while (self._delegate.should_continue_work_queue()):
+ try:
+ self._ensure_work_log_closed()
+ work_item = self._delegate.next_work_item()
+ if not work_item:
+ self._sleep("No work item.")
+ continue
+ if not self._delegate.should_proceed_with_work_item(work_item):
+ self._sleep("Not proceeding with work item.")
+ continue
+
+ # FIXME: Work logs should not depend on bug_id specificaly.
+ # This looks fixed, no?
+ self._open_work_log(work_item)
+ try:
+ if not self._delegate.process_work_item(work_item):
+ log("Unable to process work item.")
+ continue
+ except ScriptError, e:
+ # Use a special exit code to indicate that the error was already
+ # handled in the child process and we should just keep looping.
+ if e.exit_code == self.handled_error_code:
+ continue
+ message = "Unexpected failure when processing patch! Please file a bug against webkit-patch.\n%s" % e.message_with_output()
+ self._delegate.handle_unexpected_error(work_item, message)
+ except TerminateQueue, e:
+ self._stopping("TerminateQueue exception received.")
+ return 0
+ except KeyboardInterrupt, e:
+ self._stopping("User terminated queue.")
+ return 1
+ except Exception, e:
+ traceback.print_exc()
+ # Don't try tell the status bot, in case telling it causes an exception.
+ self._sleep("Exception while preparing queue")
+ self._stopping("Delegate terminated queue.")
+ return 0
+
+ def _stopping(self, message):
+ log("\n%s" % message)
+ self._delegate.stop_work_queue(message)
+ # Be careful to shut down our OutputTee or the unit tests will be unhappy.
+ self._ensure_work_log_closed()
+ self._output_tee.remove_log(self._queue_log)
+
+ def _begin_logging(self):
+ self._queue_log = self._output_tee.add_log(self._delegate.queue_log_path())
+ self._work_log = None
+
+ def _open_work_log(self, work_item):
+ work_item_log_path = self._delegate.work_item_log_path(work_item)
+ if not work_item_log_path:
+ return
+ self._work_log = self._output_tee.add_log(work_item_log_path)
+
+ def _ensure_work_log_closed(self):
+ # If we still have a bug log open, close it.
+ if self._work_log:
+ self._output_tee.remove_log(self._work_log)
+ self._work_log = None
+
+ def _now(self):
+ """Overriden by the unit tests to allow testing _sleep_message"""
+ return datetime.now()
+
+ def _sleep_message(self, message):
+ wake_time = self._now() + timedelta(seconds=self.seconds_to_sleep)
+ return "%s Sleeping until %s (%s)." % (message, wake_time.strftime(self.log_date_format), self.sleep_duration_text)
+
+ def _sleep(self, message):
+ log(self._sleep_message(message))
+ self._wakeup_event.wait(self.seconds_to_sleep)
+ self._wakeup_event.clear()
diff --git a/Tools/Scripts/webkitpy/tool/bot/queueengine_unittest.py b/Tools/Scripts/webkitpy/tool/bot/queueengine_unittest.py
new file mode 100644
index 0000000..37d8502
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/queueengine_unittest.py
@@ -0,0 +1,209 @@
+# 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 datetime
+import os
+import shutil
+import tempfile
+import threading
+import unittest
+
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.bot.queueengine import QueueEngine, QueueEngineDelegate, TerminateQueue
+
+
+class LoggingDelegate(QueueEngineDelegate):
+ def __init__(self, test):
+ self._test = test
+ self._callbacks = []
+ self._run_before = False
+ self.stop_message = None
+
+ expected_callbacks = [
+ 'queue_log_path',
+ 'begin_work_queue',
+ 'should_continue_work_queue',
+ 'next_work_item',
+ 'should_proceed_with_work_item',
+ 'work_item_log_path',
+ 'process_work_item',
+ 'should_continue_work_queue',
+ 'stop_work_queue',
+ ]
+
+ def record(self, method_name):
+ self._callbacks.append(method_name)
+
+ def queue_log_path(self):
+ self.record("queue_log_path")
+ return os.path.join(self._test.temp_dir, "queue_log_path")
+
+ def work_item_log_path(self, work_item):
+ self.record("work_item_log_path")
+ return os.path.join(self._test.temp_dir, "work_log_path", "%s.log" % work_item)
+
+ def begin_work_queue(self):
+ self.record("begin_work_queue")
+
+ def should_continue_work_queue(self):
+ self.record("should_continue_work_queue")
+ if not self._run_before:
+ self._run_before = True
+ return True
+ return False
+
+ def next_work_item(self):
+ self.record("next_work_item")
+ return "work_item"
+
+ def should_proceed_with_work_item(self, work_item):
+ self.record("should_proceed_with_work_item")
+ self._test.assertEquals(work_item, "work_item")
+ fake_patch = { 'bug_id' : 42 }
+ return (True, "waiting_message", fake_patch)
+
+ def process_work_item(self, work_item):
+ self.record("process_work_item")
+ self._test.assertEquals(work_item, "work_item")
+ return True
+
+ def handle_unexpected_error(self, work_item, message):
+ self.record("handle_unexpected_error")
+ self._test.assertEquals(work_item, "work_item")
+
+ def stop_work_queue(self, message):
+ self.record("stop_work_queue")
+ self.stop_message = message
+
+
+class RaisingDelegate(LoggingDelegate):
+ def __init__(self, test, exception):
+ LoggingDelegate.__init__(self, test)
+ self._exception = exception
+
+ def process_work_item(self, work_item):
+ self.record("process_work_item")
+ raise self._exception
+
+
+class NotSafeToProceedDelegate(LoggingDelegate):
+ def should_proceed_with_work_item(self, work_item):
+ self.record("should_proceed_with_work_item")
+ self._test.assertEquals(work_item, "work_item")
+ return False
+
+
+class FastQueueEngine(QueueEngine):
+ def __init__(self, delegate):
+ QueueEngine.__init__(self, "fast-queue", delegate, threading.Event())
+
+ # No sleep for the wicked.
+ seconds_to_sleep = 0
+
+ def _sleep(self, message):
+ pass
+
+
+class QueueEngineTest(unittest.TestCase):
+ def test_trivial(self):
+ delegate = LoggingDelegate(self)
+ self._run_engine(delegate)
+ self.assertEquals(delegate.stop_message, "Delegate terminated queue.")
+ self.assertEquals(delegate._callbacks, LoggingDelegate.expected_callbacks)
+ self.assertTrue(os.path.exists(os.path.join(self.temp_dir, "queue_log_path")))
+ self.assertTrue(os.path.exists(os.path.join(self.temp_dir, "work_log_path", "work_item.log")))
+
+ def test_unexpected_error(self):
+ delegate = RaisingDelegate(self, ScriptError(exit_code=3))
+ self._run_engine(delegate)
+ expected_callbacks = LoggingDelegate.expected_callbacks[:]
+ work_item_index = expected_callbacks.index('process_work_item')
+ # The unexpected error should be handled right after process_work_item starts
+ # but before any other callback. Otherwise callbacks should be normal.
+ expected_callbacks.insert(work_item_index + 1, 'handle_unexpected_error')
+ self.assertEquals(delegate._callbacks, expected_callbacks)
+
+ def test_handled_error(self):
+ delegate = RaisingDelegate(self, ScriptError(exit_code=QueueEngine.handled_error_code))
+ self._run_engine(delegate)
+ self.assertEquals(delegate._callbacks, LoggingDelegate.expected_callbacks)
+
+ def _run_engine(self, delegate, engine=None, termination_message=None):
+ if not engine:
+ engine = QueueEngine("test-queue", delegate, threading.Event())
+ if not termination_message:
+ termination_message = "Delegate terminated queue."
+ expected_stderr = "\n%s\n" % termination_message
+ OutputCapture().assert_outputs(self, engine.run, [], expected_stderr=expected_stderr)
+
+ def _test_terminating_queue(self, exception, termination_message):
+ work_item_index = LoggingDelegate.expected_callbacks.index('process_work_item')
+ # The terminating error should be handled right after process_work_item.
+ # There should be no other callbacks after stop_work_queue.
+ expected_callbacks = LoggingDelegate.expected_callbacks[:work_item_index + 1]
+ expected_callbacks.append("stop_work_queue")
+
+ delegate = RaisingDelegate(self, exception)
+ self._run_engine(delegate, termination_message=termination_message)
+
+ self.assertEquals(delegate._callbacks, expected_callbacks)
+ self.assertEquals(delegate.stop_message, termination_message)
+
+ def test_terminating_error(self):
+ self._test_terminating_queue(KeyboardInterrupt(), "User terminated queue.")
+ self._test_terminating_queue(TerminateQueue(), "TerminateQueue exception received.")
+
+ def test_not_safe_to_proceed(self):
+ delegate = NotSafeToProceedDelegate(self)
+ self._run_engine(delegate, engine=FastQueueEngine(delegate))
+ expected_callbacks = LoggingDelegate.expected_callbacks[:]
+ expected_callbacks.remove('work_item_log_path')
+ expected_callbacks.remove('process_work_item')
+ self.assertEquals(delegate._callbacks, expected_callbacks)
+
+ def test_now(self):
+ """Make sure there are no typos in the QueueEngine.now() method."""
+ engine = QueueEngine("test", None, None)
+ self.assertTrue(isinstance(engine._now(), datetime.datetime))
+
+ def test_sleep_message(self):
+ engine = QueueEngine("test", None, None)
+ engine._now = lambda: datetime.datetime(2010, 1, 1)
+ expected_sleep_message = "MESSAGE Sleeping until 2010-01-01 00:02:00 (2 mins)."
+ self.assertEqual(engine._sleep_message("MESSAGE"), expected_sleep_message)
+
+ def setUp(self):
+ self.temp_dir = tempfile.mkdtemp(suffix="work_queue_test_logs")
+
+ def tearDown(self):
+ shutil.rmtree(self.temp_dir)
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/tool/bot/sheriff.py b/Tools/Scripts/webkitpy/tool/bot/sheriff.py
new file mode 100644
index 0000000..43f3221
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/sheriff.py
@@ -0,0 +1,91 @@
+# 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.
+
+from webkitpy.common.config import urls
+from webkitpy.common.net.bugzilla import parse_bug_id
+from webkitpy.common.system.deprecated_logging import log
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.tool.grammar import join_with_separators
+
+
+class Sheriff(object):
+ def __init__(self, tool, sheriffbot):
+ self._tool = tool
+ self._sheriffbot = sheriffbot
+
+ def post_irc_warning(self, commit_info, builders):
+ irc_nicknames = sorted([party.irc_nickname for
+ party in commit_info.responsible_parties()
+ if party.irc_nickname])
+ irc_prefix = ": " if irc_nicknames else ""
+ irc_message = "%s%s%s might have broken %s" % (
+ ", ".join(irc_nicknames),
+ irc_prefix,
+ urls.view_revision_url(commit_info.revision()),
+ join_with_separators([builder.name() for builder in builders]))
+
+ self._tool.irc().post(irc_message)
+
+ def post_rollout_patch(self, svn_revision, rollout_reason):
+ # Ensure that svn_revision is a number (and not an option to
+ # create-rollout).
+ try:
+ svn_revision = int(svn_revision)
+ except:
+ raise ScriptError(message="Invalid svn revision number \"%s\"."
+ % svn_revision)
+
+ if rollout_reason.startswith("-"):
+ raise ScriptError(message="The rollout reason may not begin "
+ "with - (\"%s\")." % rollout_reason)
+
+ output = self._sheriffbot.run_webkit_patch([
+ "create-rollout",
+ "--force-clean",
+ # In principle, we should pass --non-interactive here, but it
+ # turns out that create-rollout doesn't need it yet. We can't
+ # pass it prophylactically because we reject unrecognized command
+ # line switches.
+ "--parent-command=sheriff-bot",
+ svn_revision,
+ rollout_reason,
+ ])
+ return parse_bug_id(output)
+
+ def post_blame_comment_on_bug(self, commit_info, builders, tests):
+ if not commit_info.bug_id():
+ return
+ comment = "%s might have broken %s" % (
+ urls.view_revision_url(commit_info.revision()),
+ join_with_separators([builder.name() for builder in builders]))
+ if tests:
+ comment += "\nThe following tests are not passing:\n"
+ comment += "\n".join(tests)
+ self._tool.bugs.post_comment_to_bug(commit_info.bug_id(),
+ comment,
+ cc=self._sheriffbot.watchers)
diff --git a/Tools/Scripts/webkitpy/tool/bot/sheriff_unittest.py b/Tools/Scripts/webkitpy/tool/bot/sheriff_unittest.py
new file mode 100644
index 0000000..690af1f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/sheriff_unittest.py
@@ -0,0 +1,90 @@
+# 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 os
+import unittest
+
+from webkitpy.common.net.buildbot import Builder
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.tool.bot.sheriff import Sheriff
+from webkitpy.tool.mocktool import MockTool
+
+
+class MockSheriffBot(object):
+ name = "mock-sheriff-bot"
+ watchers = [
+ "watcher@example.com",
+ ]
+
+ def run_webkit_patch(self, args):
+ return "Created bug https://bugs.webkit.org/show_bug.cgi?id=36936\n"
+
+
+class SheriffTest(unittest.TestCase):
+ def test_post_blame_comment_on_bug(self):
+ def run():
+ sheriff = Sheriff(MockTool(), MockSheriffBot())
+ builders = [
+ Builder("Foo", None),
+ Builder("Bar", None),
+ ]
+ commit_info = Mock()
+ commit_info.bug_id = lambda: None
+ commit_info.revision = lambda: 4321
+ # Should do nothing with no bug_id
+ sheriff.post_blame_comment_on_bug(commit_info, builders, [])
+ sheriff.post_blame_comment_on_bug(commit_info, builders, ["mock-test-1", "mock-test-2"])
+ # Should try to post a comment to the bug, but MockTool.bugs does nothing.
+ commit_info.bug_id = lambda: 1234
+ sheriff.post_blame_comment_on_bug(commit_info, builders, [])
+ sheriff.post_blame_comment_on_bug(commit_info, builders, ["mock-test-1"])
+ sheriff.post_blame_comment_on_bug(commit_info, builders, ["mock-test-1", "mock-test-2"])
+
+ expected_stderr = u"""MOCK bug comment: bug_id=1234, cc=['watcher@example.com']
+--- Begin comment ---
+http://trac.webkit.org/changeset/4321 might have broken Foo and Bar
+--- End comment ---
+
+MOCK bug comment: bug_id=1234, cc=['watcher@example.com']
+--- Begin comment ---
+http://trac.webkit.org/changeset/4321 might have broken Foo and Bar
+The following tests are not passing:
+mock-test-1
+--- End comment ---
+
+MOCK bug comment: bug_id=1234, cc=['watcher@example.com']
+--- Begin comment ---
+http://trac.webkit.org/changeset/4321 might have broken Foo and Bar
+The following tests are not passing:
+mock-test-1
+mock-test-2
+--- End comment ---
+
+"""
+ OutputCapture().assert_outputs(self, run, expected_stderr=expected_stderr)
diff --git a/Tools/Scripts/webkitpy/tool/bot/sheriffircbot.py b/Tools/Scripts/webkitpy/tool/bot/sheriffircbot.py
new file mode 100644
index 0000000..de77222
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/sheriffircbot.py
@@ -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.
+
+import webkitpy.tool.bot.irc_command as irc_command
+
+from webkitpy.common.net.irc.ircbot import IRCBotDelegate
+from webkitpy.common.thread.threadedmessagequeue import ThreadedMessageQueue
+
+
+class _IRCThreadTearoff(IRCBotDelegate):
+ def __init__(self, password, message_queue, wakeup_event):
+ self._password = password
+ self._message_queue = message_queue
+ self._wakeup_event = wakeup_event
+
+ # IRCBotDelegate methods
+
+ def irc_message_received(self, nick, message):
+ self._message_queue.post([nick, message])
+ self._wakeup_event.set()
+
+ def irc_nickname(self):
+ return "sheriffbot"
+
+ def irc_password(self):
+ return self._password
+
+
+class SheriffIRCBot(object):
+ def __init__(self, tool, sheriff):
+ self._tool = tool
+ self._sheriff = sheriff
+ self._message_queue = ThreadedMessageQueue()
+
+ def irc_delegate(self):
+ return _IRCThreadTearoff(self._tool.irc_password,
+ self._message_queue,
+ self._tool.wakeup_event)
+
+ def process_message(self, message):
+ (nick, request) = message
+ tokenized_request = request.strip().split(" ")
+ if not tokenized_request:
+ return
+ command = irc_command.commands.get(tokenized_request[0])
+ args = tokenized_request[1:]
+ if not command:
+ # Give the peoples someone to talk with.
+ command = irc_command.Eliza
+ args = tokenized_request
+ response = command().execute(nick, args, self._tool, self._sheriff)
+ if response:
+ self._tool.irc().post(response)
+
+ def process_pending_messages(self):
+ (messages, is_running) = self._message_queue.take_all()
+ for message in messages:
+ self.process_message(message)
diff --git a/Tools/Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py b/Tools/Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py
new file mode 100644
index 0000000..08023bd
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/bot/sheriffircbot_unittest.py
@@ -0,0 +1,95 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+import unittest
+import random
+
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.bot.sheriff import Sheriff
+from webkitpy.tool.bot.sheriffircbot import SheriffIRCBot
+from webkitpy.tool.bot.sheriff_unittest import MockSheriffBot
+from webkitpy.tool.mocktool import MockTool
+
+
+def run(message):
+ tool = MockTool()
+ tool.ensure_irc_connected(None)
+ bot = SheriffIRCBot(tool, Sheriff(tool, MockSheriffBot()))
+ bot._message_queue.post(["mock_nick", message])
+ bot.process_pending_messages()
+
+
+class SheriffIRCBotTest(unittest.TestCase):
+ def test_hi(self):
+ random.seed(23324)
+ expected_stderr = 'MOCK: irc.post: "Only you can prevent forest fires." -- Smokey the Bear\n'
+ OutputCapture().assert_outputs(self, run, args=["hi"], expected_stderr=expected_stderr)
+
+ def test_help(self):
+ expected_stderr = "MOCK: irc.post: mock_nick: Available commands: rollout, hi, help, restart, last-green-revision\n"
+ OutputCapture().assert_outputs(self, run, args=["help"], expected_stderr=expected_stderr)
+
+ def test_lgr(self):
+ expected_stderr = "MOCK: irc.post: mock_nick: http://trac.webkit.org/changeset/9479\n"
+ OutputCapture().assert_outputs(self, run, args=["last-green-revision"], expected_stderr=expected_stderr)
+
+ def test_rollout(self):
+ expected_stderr = "MOCK: irc.post: Preparing rollout for r21654...\nMOCK: irc.post: mock_nick: Created rollout: http://example.com/36936\n"
+ OutputCapture().assert_outputs(self, run, args=["rollout 21654 This patch broke the world"], expected_stderr=expected_stderr)
+
+ def test_rollout_with_r_in_svn_revision(self):
+ expected_stderr = "MOCK: irc.post: Preparing rollout for r21654...\nMOCK: irc.post: mock_nick: Created rollout: http://example.com/36936\n"
+ OutputCapture().assert_outputs(self, run, args=["rollout r21654 This patch broke the world"], expected_stderr=expected_stderr)
+
+ def test_rollout_bananas(self):
+ expected_stderr = "MOCK: irc.post: mock_nick: Usage: SVN_REVISION REASON\n"
+ OutputCapture().assert_outputs(self, run, args=["rollout bananas"], expected_stderr=expected_stderr)
+
+ def test_rollout_invalidate_revision(self):
+ expected_stderr = ("MOCK: irc.post: Preparing rollout for r--component=Tools...\n"
+ "MOCK: irc.post: mock_nick: Failed to create rollout patch:\n"
+ "MOCK: irc.post: Invalid svn revision number \"--component=Tools\".\n")
+ OutputCapture().assert_outputs(self, run,
+ args=["rollout "
+ "--component=Tools 21654"],
+ expected_stderr=expected_stderr)
+
+ def test_rollout_invalidate_reason(self):
+ expected_stderr = ("MOCK: irc.post: Preparing rollout for "
+ "r21654...\nMOCK: irc.post: mock_nick: Failed to "
+ "create rollout patch:\nMOCK: irc.post: The rollout"
+ " reason may not begin with - (\"-bad (Requested "
+ "by mock_nick on #webkit).\").\n")
+ OutputCapture().assert_outputs(self, run,
+ args=["rollout "
+ "21654 -bad"],
+ expected_stderr=expected_stderr)
+
+ def test_rollout_no_reason(self):
+ expected_stderr = "MOCK: irc.post: mock_nick: Usage: SVN_REVISION REASON\n"
+ OutputCapture().assert_outputs(self, run, args=["rollout 21654"], expected_stderr=expected_stderr)
diff --git a/Tools/Scripts/webkitpy/tool/commands/__init__.py b/Tools/Scripts/webkitpy/tool/commands/__init__.py
new file mode 100644
index 0000000..a974b67
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/__init__.py
@@ -0,0 +1,14 @@
+# Required for Python to search this directory for module files
+
+from webkitpy.tool.commands.bugsearch import BugSearch
+from webkitpy.tool.commands.bugfortest import BugForTest
+from webkitpy.tool.commands.download import *
+from webkitpy.tool.commands.earlywarningsystem import *
+from webkitpy.tool.commands.openbugs import OpenBugs
+from webkitpy.tool.commands.prettydiff import PrettyDiff
+from webkitpy.tool.commands.queries import *
+from webkitpy.tool.commands.queues import *
+from webkitpy.tool.commands.rebaseline import Rebaseline
+from webkitpy.tool.commands.rebaselineserver import RebaselineServer
+from webkitpy.tool.commands.sheriffbot import *
+from webkitpy.tool.commands.upload import *
diff --git a/Tools/Scripts/webkitpy/tool/commands/abstractsequencedcommand.py b/Tools/Scripts/webkitpy/tool/commands/abstractsequencedcommand.py
new file mode 100644
index 0000000..fd10890
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/abstractsequencedcommand.py
@@ -0,0 +1,51 @@
+# 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.
+
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.common.system.deprecated_logging import log
+from webkitpy.tool.commands.stepsequence import StepSequence
+from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
+
+
+class AbstractSequencedCommand(AbstractDeclarativeCommand):
+ steps = None
+ def __init__(self):
+ self._sequence = StepSequence(self.steps)
+ AbstractDeclarativeCommand.__init__(self, self._sequence.options())
+
+ def _prepare_state(self, options, args, tool):
+ return None
+
+ def execute(self, options, args, tool):
+ try:
+ state = self._prepare_state(options, args, tool)
+ except ScriptError, e:
+ log(e.message_with_output())
+ exit(e.exit_code or 2)
+
+ self._sequence.run_and_handle_errors(tool, options, state)
diff --git a/Tools/Scripts/webkitpy/tool/commands/bugfortest.py b/Tools/Scripts/webkitpy/tool/commands/bugfortest.py
new file mode 100644
index 0000000..36aa6b5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/bugfortest.py
@@ -0,0 +1,48 @@
+# 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.
+
+from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
+from webkitpy.tool.bot.flakytestreporter import FlakyTestReporter
+
+
+# This is mostly a command for testing FlakyTestReporter, however
+# it could be easily expanded to auto-create bugs, etc. if another
+# command outside of webkitpy wanted to use it.
+class BugForTest(AbstractDeclarativeCommand):
+ name = "bug-for-test"
+ help_text = "Finds the bugzilla bug for a given test"
+
+ def execute(self, options, args, tool):
+ reporter = FlakyTestReporter(tool, "webkitpy")
+ search_string = args[0]
+ bug = reporter._lookup_bug_for_flaky_test(search_string)
+ if bug:
+ bug = reporter._follow_duplicate_chain(bug)
+ print "%5s %s" % (bug.id(), bug.title())
+ else:
+ print "No bugs found matching '%s'" % search_string
diff --git a/Tools/Scripts/webkitpy/tool/commands/bugsearch.py b/Tools/Scripts/webkitpy/tool/commands/bugsearch.py
new file mode 100644
index 0000000..5cbc1a0
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/bugsearch.py
@@ -0,0 +1,42 @@
+# 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.
+
+from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
+
+
+class BugSearch(AbstractDeclarativeCommand):
+ name = "bug-search"
+ help_text = "List bugs matching a query"
+
+ def execute(self, options, args, tool):
+ search_string = args[0]
+ bugs = tool.bugs.queries.fetch_bugs_matching_quicksearch(search_string)
+ for bug in bugs:
+ print "%5s %s" % (bug.id(), bug.title())
+ if not bugs:
+ print "No bugs found matching '%s'" % search_string
diff --git a/Tools/Scripts/webkitpy/tool/commands/commandtest.py b/Tools/Scripts/webkitpy/tool/commands/commandtest.py
new file mode 100644
index 0000000..c0efa50
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/commandtest.py
@@ -0,0 +1,48 @@
+# 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 unittest
+
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.mocktool import MockOptions, MockTool
+
+class CommandsTest(unittest.TestCase):
+ def assert_execute_outputs(self, command, args, expected_stdout="", expected_stderr="", options=MockOptions(), tool=MockTool()):
+ options.blocks = None
+ options.cc = 'MOCK cc'
+ options.component = 'MOCK component'
+ options.confirm = True
+ options.email = 'MOCK email'
+ options.git_commit = 'MOCK git commit'
+ options.obsolete_patches = True
+ options.open_bug = True
+ options.port = 'MOCK port'
+ options.quiet = True
+ options.reviewer = 'MOCK reviewer'
+ command.bind_to_tool(tool)
+ OutputCapture().assert_outputs(self, command.execute, [options, args, tool], expected_stdout=expected_stdout, expected_stderr=expected_stderr)
diff --git a/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html b/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html
new file mode 100644
index 0000000..8bdf7c2
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/index.html
@@ -0,0 +1,180 @@
+<!DOCTYPE html>
+<!--
+ 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.
+-->
+<html>
+<head>
+ <title>Layout Test Rebaseline Server</title>
+ <link rel="stylesheet" href="/main.css" type="text/css">
+ <script src="/util.js"></script>
+ <script src="/loupe.js"></script>
+ <script src="/main.js"></script>
+ <script src="/queue.js"></script>
+</head>
+<body class="loading">
+
+<pre id="log" style="display: none"></pre>
+<div id="queue" style="display: none">
+ Queue:
+ <select id="queue-select" size="10"></select>
+ <button id="remove-queue-selection">Remove selection</button>
+ <button id="rebaseline-queue">Rebaseline queue</button>
+</div>
+
+<div id="header">
+ <div id="controls">
+ <!-- Add a dummy <select> node so that this lines up with the text on the left -->
+ <select style="visibility: hidden"></select>
+ <span id="toggle-log" class="link">Log</span>
+ <span class="divider">|</span>
+ <a href="/quitquitquit">Exit</a>
+ </div>
+
+ <span id="selectors">
+ <label>
+ Failure type:
+ <select id="failure-type-selector"></select>
+ </label>
+
+ <label>
+ Directory:
+ <select id="directory-selector"></select>
+ </label>
+
+ <label>
+ Test:
+ <select id="test-selector"></select>
+ </label>
+ </span>
+
+ <a id="test-link" target="_blank">View test</a>
+
+ <span id="nav-buttons">
+ <button id="previous-test">&laquo;</button>
+ <span id="test-index"></span> of <span id="test-count"></span>
+ <button id="next-test">&raquo;</button>
+ </span>
+</div>
+
+<table id="test-output">
+ <thead id="labels">
+ <tr>
+ <th>Expected</th>
+ <th>Actual</th>
+ <th>Diff</th>
+ </tr>
+ </thead>
+ <tbody id="image-outputs" style="display: none">
+ <tr>
+ <td colspan="3"><h2>Image</h2></td>
+ </tr>
+ <tr>
+ <td><img id="expected-image"></td>
+ <td><img id="actual-image"></td>
+ <td>
+ <canvas id="diff-canvas" width="800" height="600"></canvas>
+ <div id="diff-checksum" style="display: none">
+ <h3>Checksum mismatch</h3>
+ Expected: <span id="expected-checksum"></span><br>
+ Actual: <span id="actual-checksum"></span>
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ <tbody id="text-outputs" style="display: none">
+ <tr>
+ <td colspan="3"><h2>Text</h2></td>
+ </tr>
+ <tr>
+ <td><pre id="expected-text" class="text-output"></pre></td>
+ <td><pre id="actual-text" class="text-output"></pre></td>
+ <td><div id="diff-text-pretty" class="text-output"></div></td>
+ </tr>
+ </tbody>
+</table>
+
+<div id="footer">
+ <label>State: <span id="state"></span></label>
+ <label>Existing baselines: <span id="current-baselines"></span></label>
+ <label>
+ Baseline target:
+ <select id="baseline-target"></select>
+ </label>
+ <label>
+ Move current baselines to:
+ <select id="baseline-move-to">
+ <option value="none">Nowhere (replace)</option>
+ </select>
+ </label>
+
+ <!-- Add a dummy <button> node so that this lines up with the text on the right -->
+ <button style="visibility: hidden; padding-left: 0; padding-right: 0;"></button>
+
+ <div id="action-buttons">
+ <span id="toggle-queue" class="link">Queue</span>
+ <button id="add-to-rebaseline-queue">Add to rebaseline queue</button>
+ </div>
+</div>
+
+<table id="loupe" style="display: none">
+ <tr>
+ <td colspan="3" id="loupe-info">
+ <span id="loupe-close" class="link">Close</span>
+ <label>Coordinate: <span id="loupe-coordinate"></span></label>
+ </td>
+ </tr>
+ <tr>
+ <td>
+ <div class="loupe-container">
+ <canvas id="expected-loupe" width="210" height="210"></canvas>
+ <div class="center-highlight"></div>
+ </div>
+ </td>
+ <td>
+ <div class="loupe-container">
+ <canvas id="actual-loupe" width="210" height="210"></canvas>
+ <div class="center-highlight"></div>
+ </div>
+ </td>
+ <td>
+ <div class="loupe-container">
+ <canvas id="diff-loupe" width="210" height="210"></canvas>
+ <div class="center-highlight"></div>
+ </div>
+ </td>
+ </tr>
+ <tr id="loupe-colors">
+ <td><label>Exp. color: <span id="expected-loupe-color"></span></label></td>
+ <td><label>Actual color: <span id="actual-loupe-color"></span></label></td>
+ <td><label>Diff color: <span id="diff-loupe-color"></span></label></td>
+ </tr>
+</table>
+
+</body>
+</html>
diff --git a/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js b/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js
new file mode 100644
index 0000000..41f977a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/loupe.js
@@ -0,0 +1,144 @@
+/*
+ * 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.
+ */
+
+var LOUPE_MAGNIFICATION_FACTOR = 10;
+
+function Loupe()
+{
+ this._node = $('loupe');
+ this._currentCornerX = -1;
+ this._currentCornerY = -1;
+
+ var self = this;
+
+ function handleOutputClick(event) { self._handleOutputClick(event); }
+ $('expected-image').addEventListener('click', handleOutputClick);
+ $('actual-image').addEventListener('click', handleOutputClick);
+ $('diff-canvas').addEventListener('click', handleOutputClick);
+
+ function handleLoupeClick(event) { self._handleLoupeClick(event); }
+ $('expected-loupe').addEventListener('click', handleLoupeClick);
+ $('actual-loupe').addEventListener('click', handleLoupeClick);
+ $('diff-loupe').addEventListener('click', handleLoupeClick);
+
+ function hide(event) { self.hide(); }
+ $('loupe-close').addEventListener('click', hide);
+}
+
+Loupe.prototype._handleOutputClick = function(event)
+{
+ // The -1 compensates for the border around the image/canvas.
+ this._showFor(event.offsetX - 1, event.offsetY - 1);
+};
+
+Loupe.prototype._handleLoupeClick = function(event)
+{
+ var deltaX = Math.floor(event.offsetX/LOUPE_MAGNIFICATION_FACTOR);
+ var deltaY = Math.floor(event.offsetY/LOUPE_MAGNIFICATION_FACTOR);
+
+ this._showFor(
+ this._currentCornerX + deltaX, this._currentCornerY + deltaY);
+}
+
+Loupe.prototype.hide = function()
+{
+ this._node.style.display = 'none';
+};
+
+Loupe.prototype._showFor = function(x, y)
+{
+ this._fillFromImage(x, y, 'expected', $('expected-image'));
+ this._fillFromImage(x, y, 'actual', $('actual-image'));
+ this._fillFromCanvas(x, y, 'diff', $('diff-canvas'));
+
+ this._node.style.display = '';
+};
+
+Loupe.prototype._fillFromImage = function(x, y, type, sourceImage)
+{
+ var tempCanvas = document.createElement('canvas');
+ tempCanvas.width = sourceImage.width;
+ tempCanvas.height = sourceImage.height;
+ var tempContext = tempCanvas.getContext('2d');
+
+ tempContext.drawImage(sourceImage, 0, 0);
+
+ this._fillFromCanvas(x, y, type, tempCanvas);
+};
+
+Loupe.prototype._fillFromCanvas = function(x, y, type, canvas)
+{
+ var context = canvas.getContext('2d');
+ var sourceImageData =
+ context.getImageData(0, 0, canvas.width, canvas.height);
+
+ var targetCanvas = $(type + '-loupe');
+ var targetContext = targetCanvas.getContext('2d');
+ targetContext.fillStyle = 'rgba(255, 255, 255, 1)';
+ targetContext.fillRect(0, 0, targetCanvas.width, targetCanvas.height);
+
+ var sourceXOffset = (targetCanvas.width/LOUPE_MAGNIFICATION_FACTOR - 1)/2;
+ var sourceYOffset = (targetCanvas.height/LOUPE_MAGNIFICATION_FACTOR - 1)/2;
+
+ function readPixelComponent(x, y, component) {
+ var offset = (y * sourceImageData.width + x) * 4 + component;
+ return sourceImageData.data[offset];
+ }
+
+ for (var i = -sourceXOffset; i <= sourceXOffset; i++) {
+ for (var j = -sourceYOffset; j <= sourceYOffset; j++) {
+ var sourceX = x + i;
+ var sourceY = y + j;
+
+ var sourceR = readPixelComponent(sourceX, sourceY, 0);
+ var sourceG = readPixelComponent(sourceX, sourceY, 1);
+ var sourceB = readPixelComponent(sourceX, sourceY, 2);
+ var sourceA = readPixelComponent(sourceX, sourceY, 3)/255;
+ sourceA = Math.round(sourceA * 10)/10;
+
+ var targetX = (i + sourceXOffset) * LOUPE_MAGNIFICATION_FACTOR;
+ var targetY = (j + sourceYOffset) * LOUPE_MAGNIFICATION_FACTOR;
+ var colorString =
+ sourceR + ', ' + sourceG + ', ' + sourceB + ', ' + sourceA;
+ targetContext.fillStyle = 'rgba(' + colorString + ')';
+ targetContext.fillRect(
+ targetX, targetY,
+ LOUPE_MAGNIFICATION_FACTOR, LOUPE_MAGNIFICATION_FACTOR);
+
+ if (i == 0 && j == 0) {
+ $('loupe-coordinate').textContent = sourceX + ', ' + sourceY;
+ $(type + '-loupe-color').textContent = colorString;
+ }
+ }
+ }
+
+ this._currentCornerX = x - sourceXOffset;
+ this._currentCornerY = y - sourceYOffset;
+};
diff --git a/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css b/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css
new file mode 100644
index 0000000..76643c5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.css
@@ -0,0 +1,309 @@
+/*
+ * Copyright (c) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+body {
+ font-size: 12px;
+ font-family: Helvetica, Arial, sans-serif;
+ padding: 0;
+ margin: 0;
+}
+
+.loading {
+ opacity: 0.5;
+}
+
+div {
+ margin: 0;
+}
+
+a, .link {
+ color: #aaf;
+ text-decoration: underline;
+ cursor: pointer;
+}
+
+.link.selected {
+ color: #fff;
+ font-weight: bold;
+ text-decoration: none;
+}
+
+#log,
+#queue {
+ padding: .25em 0 0 .25em;
+ position: absolute;
+ right: 0;
+ height: 200px;
+ overflow: auto;
+ background: #fff;
+ -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, .5);
+}
+
+#log {
+ top: 2em;
+ width: 500px;
+}
+
+#queue {
+ bottom: 3em;
+ width: 400px;
+}
+
+#queue-select {
+ display: block;
+ width: 390px;
+}
+
+#header,
+#footer {
+ padding: .5em 1em;
+ background: #333;
+ color: #fff;
+ -webkit-box-shadow: 0 1px 5px rgba(0, 0, 0, 0.5);
+}
+
+#header {
+ margin-bottom: 1em;
+}
+
+#header .divider,
+#footer .divider {
+ opacity: .3;
+ padding: 0 .5em;
+}
+
+#header label,
+#footer label {
+ padding-right: 1em;
+ color: #ccc;
+}
+
+#test-link {
+ margin-right: 1em;
+}
+
+#header label span,
+#footer label span {
+ color: #fff;
+ font-weight: bold;
+}
+
+#nav-buttons {
+ white-space: nowrap;
+}
+
+#nav-buttons button {
+ background: #fff;
+ border: 0;
+ border-radius: 10px;
+}
+
+#nav-buttons button:active {
+ -webkit-box-shadow: 0 0 5px #33f inset;
+ background: #aaa;
+}
+
+#nav-buttons button[disabled] {
+ opacity: .5;
+}
+
+#controls {
+ float: right;
+}
+
+#test-output {
+ border-spacing: 0;
+ border-collapse: collapse;
+ margin: 0 auto;
+ width: 100%;
+}
+
+#test-output td,
+#test-output th {
+ padding: 0;
+ vertical-align: top;
+}
+
+#image-outputs img,
+#image-outputs canvas,
+#image-outputs #diff-checksum {
+ width: 800px;
+ height: 600px;
+ border: solid 1px #ddd;
+ -webkit-user-select: none;
+ -webkit-user-drag: none;
+}
+
+#image-outputs img,
+#image-outputs canvas {
+ cursor: crosshair;
+}
+
+#image-outputs img.loading,
+#image-outputs canvas.loading {
+ opacity: .5;
+}
+
+#image-outputs #actual-image {
+ margin: 0 1em;
+}
+
+#test-output #labels th {
+ text-align: center;
+ color: #666;
+}
+
+#text-outputs .text-output {
+ height: 600px;
+ width: 800px;
+ overflow: auto;
+}
+
+#test-output h2 {
+ border-bottom: solid 1px #ccc;
+ font-weight: bold;
+ margin: 0;
+ background: #eee;
+}
+
+#footer {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ margin-top: 1em;
+}
+
+#state.needs_rebaseline {
+ color: yellow;
+}
+
+#state.rebaseline_failed {
+ color: red;
+}
+
+#state.rebaseline_succeeded {
+ color: green;
+}
+
+#state.in_queue {
+ color: gray;
+}
+
+#current-baselines {
+ font-weight: normal !important;
+}
+
+#current-baselines .platform {
+ font-weight: bold;
+}
+
+#current-baselines a {
+ color: #ddf;
+}
+
+#current-baselines .was-used-for-test {
+ color: #aaf;
+ font-weight: bold;
+}
+
+#action-buttons {
+ float: right;
+}
+
+#action-buttons .link {
+ margin-right: 1em;
+}
+
+#footer button {
+ padding: 1em;
+}
+
+#loupe {
+ -webkit-box-shadow: 2px 2px 5px rgba(0, 0, 0, .5);
+ position: absolute;
+ width: 634px;
+ top: 50%;
+ left: 50%;
+ margin-left: -151px;
+ margin-top: -50px;
+ background: #fff;
+ border-spacing: 0;
+ border-collapse: collapse;
+}
+
+#loupe td {
+ padding: 0;
+ border: solid 1px #ccc;
+}
+
+#loupe label {
+ color: #999;
+ padding-right: 1em;
+}
+
+#loupe span {
+ color: #000;
+ font-weight: bold;
+}
+
+#loupe canvas {
+ cursor: crosshair;
+}
+
+#loupe #loupe-close {
+ float: right;
+}
+
+#loupe #loupe-info {
+ background: #eee;
+ padding: .3em .5em;
+}
+
+#loupe #loupe-colors td {
+ text-align: center;
+}
+
+#loupe .loupe-container {
+ position: relative;
+ width: 210px;
+ height: 210px;
+}
+
+#loupe .center-highlight {
+ position: absolute;
+ width: 10px;
+ height: 10px;
+ top: 50%;
+ left: 50%;
+ margin-left: -5px;
+ margin-top: -5px;
+ outline: solid 1px #999;
+}
diff --git a/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js b/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js
new file mode 100644
index 0000000..aeaac04
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/main.js
@@ -0,0 +1,543 @@
+/*
+ * Copyright (c) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+var ALL_DIRECTORY_PATH = '[all]';
+
+var STATE_NEEDS_REBASELINE = 'needs_rebaseline';
+var STATE_REBASELINE_FAILED = 'rebaseline_failed';
+var STATE_REBASELINE_SUCCEEDED = 'rebaseline_succeeded';
+var STATE_IN_QUEUE = 'in_queue';
+var STATE_TO_DISPLAY_STATE = {};
+STATE_TO_DISPLAY_STATE[STATE_NEEDS_REBASELINE] = 'Needs rebaseline';
+STATE_TO_DISPLAY_STATE[STATE_REBASELINE_FAILED] = 'Rebaseline failed';
+STATE_TO_DISPLAY_STATE[STATE_REBASELINE_SUCCEEDED] = 'Rebaseline succeeded';
+STATE_TO_DISPLAY_STATE[STATE_IN_QUEUE] = 'In queue';
+
+var results;
+var testsByFailureType = {};
+var testsByDirectory = {};
+var selectedTests = [];
+var loupe;
+var queue;
+
+function main()
+{
+ $('failure-type-selector').addEventListener('change', selectFailureType);
+ $('directory-selector').addEventListener('change', selectDirectory);
+ $('test-selector').addEventListener('change', selectTest);
+ $('next-test').addEventListener('click', nextTest);
+ $('previous-test').addEventListener('click', previousTest);
+
+ $('toggle-log').addEventListener('click', function() { toggle('log'); });
+
+ loupe = new Loupe();
+ queue = new RebaselineQueue();
+
+ document.addEventListener('keydown', function(event) {
+ if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey) {
+ return;
+ }
+
+ switch (event.keyIdentifier) {
+ case 'Left':
+ event.preventDefault();
+ previousTest();
+ break;
+ case 'Right':
+ event.preventDefault();
+ nextTest();
+ break;
+ case 'U+0051': // q
+ queue.addCurrentTest();
+ break;
+ case 'U+0058': // x
+ queue.removeCurrentTest();
+ break;
+ case 'U+0052': // r
+ queue.rebaseline();
+ break;
+ }
+ });
+
+ loadText('/platforms.json', function(text) {
+ var platforms = JSON.parse(text);
+ platforms.platforms.forEach(function(platform) {
+ var platformOption = document.createElement('option');
+ platformOption.value = platform;
+ platformOption.textContent = platform;
+
+ var targetOption = platformOption.cloneNode(true);
+ targetOption.selected = platform == platforms.defaultPlatform;
+ $('baseline-target').appendChild(targetOption);
+ $('baseline-move-to').appendChild(platformOption.cloneNode(true));
+ });
+ });
+
+ loadText('/results.json', function(text) {
+ results = JSON.parse(text);
+ displayResults();
+ });
+}
+
+/**
+ * Groups test results by failure type.
+ */
+function displayResults()
+{
+ var failureTypeSelector = $('failure-type-selector');
+ var failureTypes = [];
+
+ for (var testName in results.tests) {
+ var test = results.tests[testName];
+ if (test.actual == 'PASS') {
+ continue;
+ }
+ var failureType = test.actual + ' (expected ' + test.expected + ')';
+ if (!(failureType in testsByFailureType)) {
+ testsByFailureType[failureType] = [];
+ failureTypes.push(failureType);
+ }
+ testsByFailureType[failureType].push(testName);
+ }
+
+ // Sort by number of failures
+ failureTypes.sort(function(a, b) {
+ return testsByFailureType[b].length - testsByFailureType[a].length;
+ });
+
+ for (var i = 0, failureType; failureType = failureTypes[i]; i++) {
+ var failureTypeOption = document.createElement('option');
+ failureTypeOption.value = failureType;
+ failureTypeOption.textContent = failureType + ' - ' + testsByFailureType[failureType].length + ' tests';
+ failureTypeSelector.appendChild(failureTypeOption);
+ }
+
+ selectFailureType();
+
+ document.body.className = '';
+}
+
+/**
+ * For a given failure type, gets all the tests and groups them by directory
+ * (populating the directory selector with them).
+ */
+function selectFailureType()
+{
+ var selectedFailureType = getSelectValue('failure-type-selector');
+ var tests = testsByFailureType[selectedFailureType];
+
+ testsByDirectory = {}
+ var displayDirectoryNamesByDirectory = {};
+ var directories = [];
+
+ // Include a special option for all tests
+ testsByDirectory[ALL_DIRECTORY_PATH] = tests;
+ displayDirectoryNamesByDirectory[ALL_DIRECTORY_PATH] = 'all';
+ directories.push(ALL_DIRECTORY_PATH);
+
+ // Roll up tests by ancestor directories
+ tests.forEach(function(test) {
+ var pathPieces = test.split('/');
+ var pathDirectories = pathPieces.slice(0, pathPieces.length -1);
+ var ancestorDirectory = '';
+
+ pathDirectories.forEach(function(pathDirectory, index) {
+ ancestorDirectory += pathDirectory + '/';
+ if (!(ancestorDirectory in testsByDirectory)) {
+ testsByDirectory[ancestorDirectory] = [];
+ var displayDirectoryName = new Array(index * 6).join('&nbsp;') + pathDirectory;
+ displayDirectoryNamesByDirectory[ancestorDirectory] = displayDirectoryName;
+ directories.push(ancestorDirectory);
+ }
+
+ testsByDirectory[ancestorDirectory].push(test);
+ });
+ });
+
+ directories.sort();
+
+ var directorySelector = $('directory-selector');
+ directorySelector.innerHTML = '';
+
+ directories.forEach(function(directory) {
+ var directoryOption = document.createElement('option');
+ directoryOption.value = directory;
+ directoryOption.innerHTML =
+ displayDirectoryNamesByDirectory[directory] + ' - ' +
+ testsByDirectory[directory].length + ' tests';
+ directorySelector.appendChild(directoryOption);
+ });
+
+ selectDirectory();
+}
+
+/**
+ * For a given failure type and directory and failure type, gets all the tests
+ * in that directory and populatest the test selector with them.
+ */
+function selectDirectory()
+{
+ var previouslySelectedTest = getSelectedTest();
+
+ var selectedDirectory = getSelectValue('directory-selector');
+ selectedTests = testsByDirectory[selectedDirectory];
+ selectedTests.sort();
+
+ var testsByState = {};
+ selectedTests.forEach(function(testName) {
+ var state = results.tests[testName].state;
+ if (state == STATE_IN_QUEUE) {
+ state = STATE_NEEDS_REBASELINE;
+ }
+ if (!(state in testsByState)) {
+ testsByState[state] = [];
+ }
+ testsByState[state].push(testName);
+ });
+
+ var optionIndexByTest = {};
+
+ var testSelector = $('test-selector');
+ testSelector.innerHTML = '';
+
+ for (var state in testsByState) {
+ var stateOption = document.createElement('option');
+ stateOption.textContent = STATE_TO_DISPLAY_STATE[state];
+ stateOption.disabled = true;
+ testSelector.appendChild(stateOption);
+
+ testsByState[state].forEach(function(testName) {
+ var testOption = document.createElement('option');
+ testOption.value = testName;
+ var testDisplayName = testName;
+ if (testName.lastIndexOf(selectedDirectory) == 0) {
+ testDisplayName = testName.substring(selectedDirectory.length);
+ }
+ testOption.innerHTML = '&nbsp;&nbsp;' + testDisplayName;
+ optionIndexByTest[testName] = testSelector.options.length;
+ testSelector.appendChild(testOption);
+ });
+ }
+
+ if (previouslySelectedTest in optionIndexByTest) {
+ testSelector.selectedIndex = optionIndexByTest[previouslySelectedTest];
+ } else if (STATE_NEEDS_REBASELINE in testsByState) {
+ testSelector.selectedIndex =
+ optionIndexByTest[testsByState[STATE_NEEDS_REBASELINE][0]];
+ selectTest();
+ } else {
+ testSelector.selectedIndex = 1;
+ selectTest();
+ }
+
+ selectTest();
+}
+
+function getSelectedTest()
+{
+ return getSelectValue('test-selector');
+}
+
+function selectTest()
+{
+ var selectedTest = getSelectedTest();
+
+ if (results.tests[selectedTest].actual.indexOf('IMAGE') != -1) {
+ $('image-outputs').style.display = '';
+ displayImageResults(selectedTest);
+ } else {
+ $('image-outputs').style.display = 'none';
+ }
+
+ if (results.tests[selectedTest].actual.indexOf('TEXT') != -1) {
+ $('text-outputs').style.display = '';
+ displayTextResults(selectedTest);
+ } else {
+ $('text-outputs').style.display = 'none';
+ }
+
+ var currentBaselines = $('current-baselines');
+ currentBaselines.textContent = '';
+ var baselines = results.tests[selectedTest].baselines;
+ var testName = selectedTest.split('.').slice(0, -1).join('.');
+ getSortedKeys(baselines).forEach(function(platform, i) {
+ if (i != 0) {
+ currentBaselines.appendChild(document.createTextNode('; '));
+ }
+ var platformName = document.createElement('span');
+ platformName.className = 'platform';
+ platformName.textContent = platform;
+ currentBaselines.appendChild(platformName);
+ currentBaselines.appendChild(document.createTextNode(' ('));
+ getSortedKeys(baselines[platform]).forEach(function(extension, j) {
+ if (j != 0) {
+ currentBaselines.appendChild(document.createTextNode(', '));
+ }
+ var link = document.createElement('a');
+ var baselinePath = '';
+ if (platform != 'base') {
+ baselinePath += 'platform/' + platform + '/';
+ }
+ baselinePath += testName + '-expected' + extension;
+ link.href = getTracUrl(baselinePath);
+ if (extension == '.checksum') {
+ link.textContent = 'chk';
+ } else {
+ link.textContent = extension.substring(1);
+ }
+ link.target = '_blank';
+ if (baselines[platform][extension]) {
+ link.className = 'was-used-for-test';
+ }
+ currentBaselines.appendChild(link);
+ });
+ currentBaselines.appendChild(document.createTextNode(')'));
+ });
+
+ updateState();
+ loupe.hide();
+
+ prefetchNextImageTest();
+}
+
+function prefetchNextImageTest()
+{
+ var testSelector = $('test-selector');
+ if (testSelector.selectedIndex == testSelector.options.length - 1) {
+ return;
+ }
+ var nextTest = testSelector.options[testSelector.selectedIndex + 1].value;
+ if (results.tests[nextTest].actual.indexOf('IMAGE') != -1) {
+ new Image().src = getTestResultUrl(nextTest, 'expected-image');
+ new Image().src = getTestResultUrl(nextTest, 'actual-image');
+ }
+}
+
+function updateState()
+{
+ var testName = getSelectedTest();
+ var testIndex = selectedTests.indexOf(testName);
+ var testCount = selectedTests.length
+ $('test-index').textContent = testIndex + 1;
+ $('test-count').textContent = testCount;
+
+ $('next-test').disabled = testIndex == testCount - 1;
+ $('previous-test').disabled = testIndex == 0;
+
+ $('test-link').href = getTracUrl(testName);
+
+ var state = results.tests[testName].state;
+ $('state').className = state;
+ $('state').innerHTML = STATE_TO_DISPLAY_STATE[state];
+
+ queue.updateState();
+}
+
+function getTestResultUrl(testName, mode)
+{
+ return '/test_result?test=' + testName + '&mode=' + mode;
+}
+
+var currentExpectedImageTest;
+var currentActualImageTest;
+
+function displayImageResults(testName)
+{
+ if (currentExpectedImageTest == currentActualImageTest
+ && currentExpectedImageTest == testName) {
+ return;
+ }
+
+ function displayImageResult(mode, callback) {
+ var image = $(mode);
+ image.className = 'loading';
+ image.src = getTestResultUrl(testName, mode);
+ image.onload = function() {
+ image.className = '';
+ callback();
+ updateImageDiff();
+ };
+ }
+
+ displayImageResult(
+ 'expected-image',
+ function() { currentExpectedImageTest = testName; });
+ displayImageResult(
+ 'actual-image',
+ function() { currentActualImageTest = testName; });
+
+ $('diff-canvas').className = 'loading';
+ $('diff-canvas').style.display = '';
+ $('diff-checksum').style.display = 'none';
+}
+
+/**
+ * Computes a graphical a diff between the expected and actual images by
+ * rendering each to a canvas, getting the image data, and comparing the RGBA
+ * components of each pixel. The output is put into the diff canvas, with
+ * identical pixels appearing at 12.5% opacity and different pixels being
+ * highlighted in red.
+ */
+function updateImageDiff() {
+ if (currentExpectedImageTest != currentActualImageTest)
+ return;
+
+ var expectedImage = $('expected-image');
+ var actualImage = $('actual-image');
+
+ function getImageData(image) {
+ var imageCanvas = document.createElement('canvas');
+ imageCanvas.width = image.width;
+ imageCanvas.height = image.height;
+ imageCanvasContext = imageCanvas.getContext('2d');
+
+ imageCanvasContext.fillStyle = 'rgba(255, 255, 255, 1)';
+ imageCanvasContext.fillRect(
+ 0, 0, image.width, image.height);
+
+ imageCanvasContext.drawImage(image, 0, 0);
+ return imageCanvasContext.getImageData(
+ 0, 0, image.width, image.height);
+ }
+
+ var expectedImageData = getImageData(expectedImage);
+ var actualImageData = getImageData(actualImage);
+
+ var diffCanvas = $('diff-canvas');
+ var diffCanvasContext = diffCanvas.getContext('2d');
+ var diffImageData =
+ diffCanvasContext.createImageData(diffCanvas.width, diffCanvas.height);
+
+ // Avoiding property lookups for all these during the per-pixel loop below
+ // provides a significant performance benefit.
+ var expectedWidth = expectedImage.width;
+ var expectedHeight = expectedImage.height;
+ var expected = expectedImageData.data;
+
+ var actualWidth = actualImage.width;
+ var actual = actualImageData.data;
+
+ var diffWidth = diffImageData.width;
+ var diff = diffImageData.data;
+
+ var hadDiff = false;
+ for (var x = 0; x < expectedWidth; x++) {
+ for (var y = 0; y < expectedHeight; y++) {
+ var expectedOffset = (y * expectedWidth + x) * 4;
+ var actualOffset = (y * actualWidth + x) * 4;
+ var diffOffset = (y * diffWidth + x) * 4;
+ if (expected[expectedOffset] != actual[actualOffset] ||
+ expected[expectedOffset + 1] != actual[actualOffset + 1] ||
+ expected[expectedOffset + 2] != actual[actualOffset + 2] ||
+ expected[expectedOffset + 3] != actual[actualOffset + 3]) {
+ hadDiff = true;
+ diff[diffOffset] = 255;
+ diff[diffOffset + 1] = 0;
+ diff[diffOffset + 2] = 0;
+ diff[diffOffset + 3] = 255;
+ } else {
+ diff[diffOffset] = expected[expectedOffset];
+ diff[diffOffset + 1] = expected[expectedOffset + 1];
+ diff[diffOffset + 2] = expected[expectedOffset + 2];
+ diff[diffOffset + 3] = 32;
+ }
+ }
+ }
+
+ diffCanvasContext.putImageData(
+ diffImageData,
+ 0, 0,
+ 0, 0,
+ diffImageData.width, diffImageData.height);
+ diffCanvas.className = '';
+
+ if (!hadDiff) {
+ diffCanvas.style.display = 'none';
+ $('diff-checksum').style.display = '';
+ loadTextResult(currentExpectedImageTest, 'expected-checksum');
+ loadTextResult(currentExpectedImageTest, 'actual-checksum');
+ }
+}
+
+function loadTextResult(testName, mode, responseIsHtml)
+{
+ loadText(getTestResultUrl(testName, mode), function(text) {
+ if (responseIsHtml) {
+ $(mode).innerHTML = text;
+ } else {
+ $(mode).textContent = text;
+ }
+ });
+}
+
+function displayTextResults(testName)
+{
+ loadTextResult(testName, 'expected-text');
+ loadTextResult(testName, 'actual-text');
+ loadTextResult(testName, 'diff-text-pretty', true);
+}
+
+function nextTest()
+{
+ var testSelector = $('test-selector');
+ var nextTestIndex = testSelector.selectedIndex + 1;
+ while (true) {
+ if (nextTestIndex == testSelector.options.length) {
+ return;
+ }
+ if (testSelector.options[nextTestIndex].disabled) {
+ nextTestIndex++;
+ } else {
+ testSelector.selectedIndex = nextTestIndex;
+ selectTest();
+ return;
+ }
+ }
+}
+
+function previousTest()
+{
+ var testSelector = $('test-selector');
+ var previousTestIndex = testSelector.selectedIndex - 1;
+ while (true) {
+ if (previousTestIndex == -1) {
+ return;
+ }
+ if (testSelector.options[previousTestIndex].disabled) {
+ previousTestIndex--;
+ } else {
+ testSelector.selectedIndex = previousTestIndex;
+ selectTest();
+ return
+ }
+ }
+}
+
+window.addEventListener('DOMContentLoaded', main);
diff --git a/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js b/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js
new file mode 100644
index 0000000..338e28f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/queue.js
@@ -0,0 +1,186 @@
+/*
+ * Copyright (c) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+function RebaselineQueue()
+{
+ this._selectNode = $('queue-select');
+ this._rebaselineButtonNode = $('rebaseline-queue');
+ this._toggleNode = $('toggle-queue');
+ this._removeSelectionButtonNode = $('remove-queue-selection');
+
+ this._inProgressRebaselineCount = 0;
+
+ var self = this;
+ $('add-to-rebaseline-queue').addEventListener(
+ 'click', function() { self.addCurrentTest(); });
+ this._selectNode.addEventListener('change', updateState);
+ this._removeSelectionButtonNode.addEventListener(
+ 'click', function() { self._removeSelection(); });
+ this._rebaselineButtonNode.addEventListener(
+ 'click', function() { self.rebaseline(); });
+ this._toggleNode.addEventListener(
+ 'click', function() { toggle('queue'); });
+}
+
+RebaselineQueue.prototype.updateState = function()
+{
+ var testName = getSelectedTest();
+
+ var state = results.tests[testName].state;
+ $('add-to-rebaseline-queue').disabled = state != STATE_NEEDS_REBASELINE;
+
+ var queueLength = this._selectNode.options.length;
+ if (this._inProgressRebaselineCount > 0) {
+ this._rebaselineButtonNode.disabled = true;
+ this._rebaselineButtonNode.textContent =
+ 'Rebaseline in progress (' + this._inProgressRebaselineCount +
+ ' tests left)';
+ } else if (queueLength == 0) {
+ this._rebaselineButtonNode.disabled = true;
+ this._rebaselineButtonNode.textContent = 'Rebaseline queue';
+ this._toggleNode.textContent = 'Queue';
+ } else {
+ this._rebaselineButtonNode.disabled = false;
+ this._rebaselineButtonNode.textContent =
+ 'Rebaseline queue (' + queueLength + ' tests)';
+ this._toggleNode.textContent = 'Queue (' + queueLength + ' tests)';
+ }
+ this._removeSelectionButtonNode.disabled =
+ this._selectNode.selectedIndex == -1;
+};
+
+RebaselineQueue.prototype.addCurrentTest = function()
+{
+ var testName = getSelectedTest();
+ var test = results.tests[testName];
+
+ if (test.state != STATE_NEEDS_REBASELINE) {
+ log('Cannot add test with state "' + test.state + '" to queue.',
+ log.WARNING);
+ return;
+ }
+
+ var queueOption = document.createElement('option');
+ queueOption.value = testName;
+ queueOption.textContent = testName;
+ this._selectNode.appendChild(queueOption);
+ test.state = STATE_IN_QUEUE;
+ updateState();
+};
+
+RebaselineQueue.prototype.removeCurrentTest = function()
+{
+ this._removeTest(getSelectedTest());
+};
+
+RebaselineQueue.prototype._removeSelection = function()
+{
+ if (this._selectNode.selectedIndex == -1)
+ return;
+
+ this._removeTest(
+ this._selectNode.options[this._selectNode.selectedIndex].value);
+};
+
+RebaselineQueue.prototype._removeTest = function(testName)
+{
+ var queueOption = this._selectNode.firstChild;
+
+ while (queueOption && queueOption.value != testName) {
+ queueOption = queueOption.nextSibling;
+ }
+
+ if (!queueOption)
+ return;
+
+ this._selectNode.removeChild(queueOption);
+ var test = results.tests[testName];
+ test.state = STATE_NEEDS_REBASELINE;
+ updateState();
+};
+
+RebaselineQueue.prototype.rebaseline = function()
+{
+ var testNames = [];
+ for (var queueOption = this._selectNode.firstChild;
+ queueOption;
+ queueOption = queueOption.nextSibling) {
+ testNames.push(queueOption.value);
+ }
+
+ this._inProgressRebaselineCount = testNames.length;
+ updateState();
+
+ testNames.forEach(this._rebaselineTest, this);
+};
+
+RebaselineQueue.prototype._rebaselineTest = function(testName)
+{
+ var baselineTarget = getSelectValue('baseline-target');
+ var baselineMoveTo = getSelectValue('baseline-move-to');
+
+ var xhr = new XMLHttpRequest();
+ xhr.open('POST',
+ '/rebaseline?test=' + encodeURIComponent(testName) +
+ '&baseline-target=' + encodeURIComponent(baselineTarget) +
+ '&baseline-move-to=' + encodeURIComponent(baselineMoveTo));
+
+ var self = this;
+ function handleResponse(logType, newState) {
+ log(xhr.responseText, logType);
+ self._removeTest(testName);
+ self._inProgressRebaselineCount--;
+ results.tests[testName].state = newState;
+ updateState();
+ // If we're done with a set of rebaselines, regenerate the test menu
+ // (which is grouped by state) since test states have changed.
+ if (self._inProgressRebaselineCount == 0) {
+ selectDirectory();
+ }
+ }
+
+ function handleSuccess() {
+ handleResponse(log.SUCCESS, STATE_REBASELINE_SUCCEEDED);
+ }
+ function handleFailure() {
+ handleResponse(log.ERROR, STATE_REBASELINE_FAILED);
+ }
+
+ xhr.addEventListener('load', function() {
+ if (xhr.status < 400) {
+ handleSuccess();
+ } else {
+ handleFailure();
+ }
+ });
+ xhr.addEventListener('error', handleFailure);
+
+ xhr.send();
+};
diff --git a/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/util.js b/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/util.js
new file mode 100644
index 0000000..5ad7612
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/data/rebaselineserver/util.js
@@ -0,0 +1,104 @@
+/*
+ * 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.
+ */
+
+var results;
+var testsByFailureType = {};
+var testsByDirectory = {};
+var selectedTests = [];
+
+function $(id)
+{
+ return document.getElementById(id);
+}
+
+function getSelectValue(id)
+{
+ var select = $(id);
+ if (select.selectedIndex == -1) {
+ return null;
+ } else {
+ return select.options[select.selectedIndex].value;
+ }
+}
+
+function loadText(url, callback)
+{
+ var xhr = new XMLHttpRequest();
+ xhr.open('GET', url);
+ xhr.addEventListener('load', function() { callback(xhr.responseText); });
+ xhr.send();
+}
+
+function log(text, type)
+{
+ var node = $('log');
+
+ if (type) {
+ var typeNode = document.createElement('span');
+ typeNode.textContent = type.text;
+ typeNode.style.color = type.color;
+ node.appendChild(typeNode);
+ }
+
+ node.appendChild(document.createTextNode(text + '\n'));
+ node.scrollTop = node.scrollHeight;
+}
+
+log.WARNING = {text: 'Warning: ', color: '#aa3'};
+log.SUCCESS = {text: 'Success: ', color: 'green'};
+log.ERROR = {text: 'Error: ', color: 'red'};
+
+function toggle(id)
+{
+ var element = $(id);
+ var toggler = $('toggle-' + id);
+ if (element.style.display == 'none') {
+ element.style.display = '';
+ toggler.className = 'link selected';
+ } else {
+ element.style.display = 'none';
+ toggler.className = 'link';
+ }
+}
+
+function getTracUrl(layoutTestPath)
+{
+ return 'http://trac.webkit.org/browser/trunk/LayoutTests/' + layoutTestPath;
+}
+
+function getSortedKeys(obj)
+{
+ var keys = [];
+ for (var key in obj) {
+ keys.push(key);
+ }
+ keys.sort();
+ return keys;
+} \ No newline at end of file
diff --git a/Tools/Scripts/webkitpy/tool/commands/download.py b/Tools/Scripts/webkitpy/tool/commands/download.py
new file mode 100644
index 0000000..020f339
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/download.py
@@ -0,0 +1,405 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# 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:
+#
+# * 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 os
+
+import webkitpy.tool.steps as steps
+
+from webkitpy.common.checkout.changelog import ChangeLog
+from webkitpy.common.config import urls
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.tool.commands.abstractsequencedcommand import AbstractSequencedCommand
+from webkitpy.tool.commands.stepsequence import StepSequence
+from webkitpy.tool.comments import bug_comment_from_commit_text
+from webkitpy.tool.grammar import pluralize
+from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
+from webkitpy.common.system.deprecated_logging import error, log
+
+
+class Clean(AbstractSequencedCommand):
+ name = "clean"
+ help_text = "Clean the working copy"
+ steps = [
+ steps.CleanWorkingDirectory,
+ ]
+
+ def _prepare_state(self, options, args, tool):
+ options.force_clean = True
+
+
+class Update(AbstractSequencedCommand):
+ name = "update"
+ help_text = "Update working copy (used internally)"
+ steps = [
+ steps.CleanWorkingDirectory,
+ steps.Update,
+ ]
+
+
+class Build(AbstractSequencedCommand):
+ name = "build"
+ help_text = "Update working copy and build"
+ steps = [
+ steps.CleanWorkingDirectory,
+ steps.Update,
+ steps.Build,
+ ]
+
+ def _prepare_state(self, options, args, tool):
+ options.build = True
+
+
+class BuildAndTest(AbstractSequencedCommand):
+ name = "build-and-test"
+ help_text = "Update working copy, build, and run the tests"
+ steps = [
+ steps.CleanWorkingDirectory,
+ steps.Update,
+ steps.Build,
+ steps.RunTests,
+ ]
+
+
+class Land(AbstractSequencedCommand):
+ name = "land"
+ help_text = "Land the current working directory diff and updates the associated bug if any"
+ argument_names = "[BUGID]"
+ show_in_main_help = True
+ steps = [
+ steps.EnsureBuildersAreGreen,
+ steps.UpdateChangeLogsWithReviewer,
+ steps.ValidateReviewer,
+ steps.Build,
+ steps.RunTests,
+ steps.Commit,
+ steps.CloseBugForLandDiff,
+ ]
+ long_help = """land commits the current working copy diff (just as svn or git commit would).
+land will NOT build and run the tests before committing, but you can use the --build option for that.
+If a bug id is provided, or one can be found in the ChangeLog land will update the bug after committing."""
+
+ def _prepare_state(self, options, args, tool):
+ changed_files = self._tool.scm().changed_files(options.git_commit)
+ return {
+ "changed_files": changed_files,
+ "bug_id": (args and args[0]) or tool.checkout().bug_id_for_this_commit(options.git_commit, changed_files),
+ }
+
+
+class LandCowboy(AbstractSequencedCommand):
+ name = "land-cowboy"
+ help_text = "Prepares a ChangeLog and lands the current working directory diff."
+ steps = [
+ steps.PrepareChangeLog,
+ steps.EditChangeLog,
+ steps.ConfirmDiff,
+ steps.Build,
+ steps.RunTests,
+ steps.Commit,
+ ]
+
+
+class AbstractPatchProcessingCommand(AbstractDeclarativeCommand):
+ # Subclasses must implement the methods below. We don't declare them here
+ # because we want to be able to implement them with mix-ins.
+ #
+ # def _fetch_list_of_patches_to_process(self, options, args, tool):
+ # def _prepare_to_process(self, options, args, tool):
+
+ @staticmethod
+ def _collect_patches_by_bug(patches):
+ bugs_to_patches = {}
+ for patch in patches:
+ bugs_to_patches[patch.bug_id()] = bugs_to_patches.get(patch.bug_id(), []) + [patch]
+ return bugs_to_patches
+
+ def execute(self, options, args, tool):
+ self._prepare_to_process(options, args, tool)
+ patches = self._fetch_list_of_patches_to_process(options, args, tool)
+
+ # It's nice to print out total statistics.
+ bugs_to_patches = self._collect_patches_by_bug(patches)
+ log("Processing %s from %s." % (pluralize("patch", len(patches)), pluralize("bug", len(bugs_to_patches))))
+
+ for patch in patches:
+ self._process_patch(patch, options, args, tool)
+
+
+class AbstractPatchSequencingCommand(AbstractPatchProcessingCommand):
+ prepare_steps = None
+ main_steps = None
+
+ def __init__(self):
+ options = []
+ self._prepare_sequence = StepSequence(self.prepare_steps)
+ self._main_sequence = StepSequence(self.main_steps)
+ options = sorted(set(self._prepare_sequence.options() + self._main_sequence.options()))
+ AbstractPatchProcessingCommand.__init__(self, options)
+
+ def _prepare_to_process(self, options, args, tool):
+ self._prepare_sequence.run_and_handle_errors(tool, options)
+
+ def _process_patch(self, patch, options, args, tool):
+ state = { "patch" : patch }
+ self._main_sequence.run_and_handle_errors(tool, options, state)
+
+
+class ProcessAttachmentsMixin(object):
+ def _fetch_list_of_patches_to_process(self, options, args, tool):
+ return map(lambda patch_id: tool.bugs.fetch_attachment(patch_id), args)
+
+
+class ProcessBugsMixin(object):
+ def _fetch_list_of_patches_to_process(self, options, args, tool):
+ all_patches = []
+ for bug_id in args:
+ patches = tool.bugs.fetch_bug(bug_id).reviewed_patches()
+ log("%s found on bug %s." % (pluralize("reviewed patch", len(patches)), bug_id))
+ all_patches += patches
+ return all_patches
+
+
+class CheckStyle(AbstractPatchSequencingCommand, ProcessAttachmentsMixin):
+ name = "check-style"
+ help_text = "Run check-webkit-style on the specified attachments"
+ argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
+ main_steps = [
+ steps.CleanWorkingDirectory,
+ steps.Update,
+ steps.ApplyPatch,
+ steps.CheckStyle,
+ ]
+
+
+class BuildAttachment(AbstractPatchSequencingCommand, ProcessAttachmentsMixin):
+ name = "build-attachment"
+ help_text = "Apply and build patches from bugzilla"
+ argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
+ main_steps = [
+ steps.CleanWorkingDirectory,
+ steps.Update,
+ steps.ApplyPatch,
+ steps.Build,
+ ]
+
+
+class BuildAndTestAttachment(AbstractPatchSequencingCommand, ProcessAttachmentsMixin):
+ name = "build-and-test-attachment"
+ help_text = "Apply, build, and test patches from bugzilla"
+ argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
+ main_steps = [
+ steps.CleanWorkingDirectory,
+ steps.Update,
+ steps.ApplyPatch,
+ steps.Build,
+ steps.RunTests,
+ ]
+
+
+class AbstractPatchApplyingCommand(AbstractPatchSequencingCommand):
+ prepare_steps = [
+ steps.EnsureLocalCommitIfNeeded,
+ steps.CleanWorkingDirectoryWithLocalCommits,
+ steps.Update,
+ ]
+ main_steps = [
+ steps.ApplyPatchWithLocalCommit,
+ ]
+ long_help = """Updates the working copy.
+Downloads and applies the patches, creating local commits if necessary."""
+
+
+class ApplyAttachment(AbstractPatchApplyingCommand, ProcessAttachmentsMixin):
+ name = "apply-attachment"
+ help_text = "Apply an attachment to the local working directory"
+ argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
+ show_in_main_help = True
+
+
+class ApplyFromBug(AbstractPatchApplyingCommand, ProcessBugsMixin):
+ name = "apply-from-bug"
+ help_text = "Apply reviewed patches from provided bugs to the local working directory"
+ argument_names = "BUGID [BUGIDS]"
+ show_in_main_help = True
+
+
+class AbstractPatchLandingCommand(AbstractPatchSequencingCommand):
+ prepare_steps = [
+ steps.EnsureBuildersAreGreen,
+ ]
+ main_steps = [
+ steps.CleanWorkingDirectory,
+ steps.Update,
+ steps.ApplyPatch,
+ steps.ValidateReviewer,
+ steps.Build,
+ steps.RunTests,
+ steps.Commit,
+ steps.ClosePatch,
+ steps.CloseBug,
+ ]
+ long_help = """Checks to make sure builders are green.
+Updates the working copy.
+Applies the patch.
+Builds.
+Runs the layout tests.
+Commits the patch.
+Clears the flags on the patch.
+Closes the bug if no patches are marked for review."""
+
+
+class LandAttachment(AbstractPatchLandingCommand, ProcessAttachmentsMixin):
+ name = "land-attachment"
+ help_text = "Land patches from bugzilla, optionally building and testing them first"
+ argument_names = "ATTACHMENT_ID [ATTACHMENT_IDS]"
+ show_in_main_help = True
+
+
+class LandFromBug(AbstractPatchLandingCommand, ProcessBugsMixin):
+ name = "land-from-bug"
+ help_text = "Land all patches on the given bugs, optionally building and testing them first"
+ argument_names = "BUGID [BUGIDS]"
+ show_in_main_help = True
+
+
+class AbstractRolloutPrepCommand(AbstractSequencedCommand):
+ argument_names = "REVISION [REVISIONS] REASON"
+
+ def _commit_info(self, revision):
+ commit_info = self._tool.checkout().commit_info_for_revision(revision)
+ if commit_info and commit_info.bug_id():
+ # Note: Don't print a bug URL here because it will confuse the
+ # SheriffBot because the SheriffBot just greps the output
+ # of create-rollout for bug URLs. It should do better
+ # parsing instead.
+ log("Preparing rollout for bug %s." % commit_info.bug_id())
+ else:
+ log("Unable to parse bug number from diff.")
+ return commit_info
+
+ def _prepare_state(self, options, args, tool):
+ revision_list = []
+ for revision in str(args[0]).split():
+ if revision.isdigit():
+ revision_list.append(int(revision))
+ else:
+ raise ScriptError(message="Invalid svn revision number: " + revision)
+ revision_list.sort()
+
+ # We use the earliest revision for the bug info
+ earliest_revision = revision_list[0]
+ commit_info = self._commit_info(earliest_revision)
+ cc_list = sorted([party.bugzilla_email()
+ for party in commit_info.responsible_parties()
+ if party.bugzilla_email()])
+ return {
+ "revision": earliest_revision,
+ "revision_list": revision_list,
+ "bug_id": commit_info.bug_id(),
+ # FIXME: We should used the list as the canonical representation.
+ "bug_cc": ",".join(cc_list),
+ "reason": args[1],
+ }
+
+
+class PrepareRollout(AbstractRolloutPrepCommand):
+ name = "prepare-rollout"
+ help_text = "Revert the given revision(s) in the working copy and prepare ChangeLogs with revert reason"
+ long_help = """Updates the working copy.
+Applies the inverse diff for the provided revision(s).
+Creates an appropriate rollout ChangeLog, including a trac link and bug link.
+"""
+ steps = [
+ steps.CleanWorkingDirectory,
+ steps.Update,
+ steps.RevertRevision,
+ steps.PrepareChangeLogForRevert,
+ ]
+
+
+class CreateRollout(AbstractRolloutPrepCommand):
+ name = "create-rollout"
+ help_text = "Creates a bug to track the broken SVN revision(s) and uploads a rollout patch."
+ steps = [
+ steps.CleanWorkingDirectory,
+ steps.Update,
+ steps.RevertRevision,
+ steps.CreateBug,
+ steps.PrepareChangeLogForRevert,
+ steps.PostDiffForRevert,
+ ]
+
+ def _prepare_state(self, options, args, tool):
+ state = AbstractRolloutPrepCommand._prepare_state(self, options, args, tool)
+ # Currently, state["bug_id"] points to the bug that caused the
+ # regression. We want to create a new bug that blocks the old bug
+ # so we move state["bug_id"] to state["bug_blocked"] and delete the
+ # old state["bug_id"] so that steps.CreateBug will actually create
+ # the new bug that we want (and subsequently store its bug id into
+ # state["bug_id"])
+ state["bug_blocked"] = state["bug_id"]
+ del state["bug_id"]
+ state["bug_title"] = "REGRESSION(r%s): %s" % (state["revision"], state["reason"])
+ state["bug_description"] = "%s broke the build:\n%s" % (urls.view_revision_url(state["revision"]), state["reason"])
+ # FIXME: If we had more context here, we could link to other open bugs
+ # that mention the test that regressed.
+ if options.parent_command == "sheriff-bot":
+ state["bug_description"] += """
+
+This is an automatic bug report generated by the sheriff-bot. If this bug
+report was created because of a flaky test, please file a bug for the flaky
+test (if we don't already have one on file) and dup this bug against that bug
+so that we can track how often these flaky tests case pain.
+
+"Only you can prevent forest fires." -- Smokey the Bear
+"""
+ return state
+
+
+class Rollout(AbstractRolloutPrepCommand):
+ name = "rollout"
+ show_in_main_help = True
+ help_text = "Revert the given revision(s) in the working copy and optionally commit the revert and re-open the original bug"
+ long_help = """Updates the working copy.
+Applies the inverse diff for the provided revision.
+Creates an appropriate rollout ChangeLog, including a trac link and bug link.
+Opens the generated ChangeLogs in $EDITOR.
+Shows the prepared diff for confirmation.
+Commits the revert and updates the bug (including re-opening the bug if necessary)."""
+ steps = [
+ steps.CleanWorkingDirectory,
+ steps.Update,
+ steps.RevertRevision,
+ steps.PrepareChangeLogForRevert,
+ steps.EditChangeLog,
+ steps.ConfirmDiff,
+ steps.Build,
+ steps.Commit,
+ steps.ReopenBugAfterRollout,
+ ]
diff --git a/Tools/Scripts/webkitpy/tool/commands/download_unittest.py b/Tools/Scripts/webkitpy/tool/commands/download_unittest.py
new file mode 100644
index 0000000..3748a8f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/download_unittest.py
@@ -0,0 +1,206 @@
+# 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 unittest
+
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.tool.commands.commandtest import CommandsTest
+from webkitpy.tool.commands.download import *
+from webkitpy.tool.mocktool import MockCheckout, MockOptions, MockTool
+
+
+class AbstractRolloutPrepCommandTest(unittest.TestCase):
+ def test_commit_info(self):
+ command = AbstractRolloutPrepCommand()
+ tool = MockTool()
+ command.bind_to_tool(tool)
+ output = OutputCapture()
+
+ expected_stderr = "Preparing rollout for bug 42.\n"
+ commit_info = output.assert_outputs(self, command._commit_info, [1234], expected_stderr=expected_stderr)
+ self.assertTrue(commit_info)
+
+ mock_commit_info = Mock()
+ mock_commit_info.bug_id = lambda: None
+ tool._checkout.commit_info_for_revision = lambda revision: mock_commit_info
+ expected_stderr = "Unable to parse bug number from diff.\n"
+ commit_info = output.assert_outputs(self, command._commit_info, [1234], expected_stderr=expected_stderr)
+ self.assertEqual(commit_info, mock_commit_info)
+
+ def test_prepare_state(self):
+ command = AbstractRolloutPrepCommand()
+ mock_commit_info = MockCheckout().commit_info_for_revision(123)
+ command._commit_info = lambda revision: mock_commit_info
+
+ state = command._prepare_state(None, ["124 123 125", "Reason"], None)
+ self.assertEqual(123, state["revision"])
+ self.assertEqual([123, 124, 125], state["revision_list"])
+
+ self.assertRaises(ScriptError, command._prepare_state, options=None, args=["125 r122 123", "Reason"], tool=None)
+ self.assertRaises(ScriptError, command._prepare_state, options=None, args=["125 foo 123", "Reason"], tool=None)
+
+
+class DownloadCommandsTest(CommandsTest):
+ def _default_options(self):
+ options = MockOptions()
+ options.build = True
+ options.build_style = True
+ options.check_builders = True
+ options.check_style = True
+ options.clean = True
+ options.close_bug = True
+ options.force_clean = False
+ options.force_patch = True
+ options.non_interactive = False
+ options.parent_command = 'MOCK parent command'
+ options.quiet = False
+ options.test = True
+ options.update = True
+ return options
+
+ def test_build(self):
+ expected_stderr = "Updating working directory\nBuilding WebKit\n"
+ self.assert_execute_outputs(Build(), [], options=self._default_options(), expected_stderr=expected_stderr)
+
+ def test_build_and_test(self):
+ expected_stderr = "Updating working directory\nBuilding WebKit\nRunning Python unit tests\nRunning Perl unit tests\nRunning JavaScriptCore tests\nRunning run-webkit-tests\n"
+ self.assert_execute_outputs(BuildAndTest(), [], options=self._default_options(), expected_stderr=expected_stderr)
+
+ def test_apply_attachment(self):
+ options = self._default_options()
+ options.update = True
+ options.local_commit = True
+ expected_stderr = "Updating working directory\nProcessing 1 patch from 1 bug.\nProcessing patch 197 from bug 42.\n"
+ self.assert_execute_outputs(ApplyAttachment(), [197], options=options, expected_stderr=expected_stderr)
+
+ def test_apply_patches(self):
+ options = self._default_options()
+ options.update = True
+ options.local_commit = True
+ expected_stderr = "Updating working directory\n2 reviewed patches found on bug 42.\nProcessing 2 patches from 1 bug.\nProcessing patch 197 from bug 42.\nProcessing patch 128 from bug 42.\n"
+ self.assert_execute_outputs(ApplyFromBug(), [42], options=options, expected_stderr=expected_stderr)
+
+ def test_land_diff(self):
+ expected_stderr = "Building WebKit\nRunning Python unit tests\nRunning Perl unit tests\nRunning JavaScriptCore tests\nRunning run-webkit-tests\nCommitted r49824: <http://trac.webkit.org/changeset/49824>\nUpdating bug 42\n"
+ mock_tool = MockTool()
+ mock_tool.scm().create_patch = Mock()
+ mock_tool.checkout().modified_changelogs = Mock(return_value=[])
+ self.assert_execute_outputs(Land(), [42], options=self._default_options(), expected_stderr=expected_stderr, tool=mock_tool)
+ # Make sure we're not calling expensive calls too often.
+ self.assertEqual(mock_tool.scm().create_patch.call_count, 0)
+ self.assertEqual(mock_tool.checkout().modified_changelogs.call_count, 1)
+
+ def test_land_red_builders(self):
+ expected_stderr = '\nWARNING: Builders ["Builder2"] are red, please watch your commit carefully.\nSee http://dummy_buildbot_host/console?category=core\n\nBuilding WebKit\nRunning Python unit tests\nRunning Perl unit tests\nRunning JavaScriptCore tests\nRunning run-webkit-tests\nCommitted r49824: <http://trac.webkit.org/changeset/49824>\nUpdating bug 42\n'
+ mock_tool = MockTool()
+ mock_tool.buildbot.light_tree_on_fire()
+ self.assert_execute_outputs(Land(), [42], options=self._default_options(), expected_stderr=expected_stderr, tool=mock_tool)
+
+ def test_check_style(self):
+ expected_stderr = "Processing 1 patch from 1 bug.\nUpdating working directory\nProcessing patch 197 from bug 42.\nRunning check-webkit-style\n"
+ self.assert_execute_outputs(CheckStyle(), [197], options=self._default_options(), expected_stderr=expected_stderr)
+
+ def test_build_attachment(self):
+ expected_stderr = "Processing 1 patch from 1 bug.\nUpdating working directory\nProcessing patch 197 from bug 42.\nBuilding WebKit\n"
+ self.assert_execute_outputs(BuildAttachment(), [197], options=self._default_options(), expected_stderr=expected_stderr)
+
+ def test_land_attachment(self):
+ # FIXME: This expected result is imperfect, notice how it's seeing the same patch as still there after it thought it would have cleared the flags.
+ expected_stderr = """Processing 1 patch from 1 bug.
+Updating working directory
+Processing patch 197 from bug 42.
+Building WebKit
+Running Python unit tests
+Running Perl unit tests
+Running JavaScriptCore tests
+Running run-webkit-tests
+Committed r49824: <http://trac.webkit.org/changeset/49824>
+Not closing bug 42 as attachment 197 has review=+. Assuming there are more patches to land from this bug.
+"""
+ self.assert_execute_outputs(LandAttachment(), [197], options=self._default_options(), expected_stderr=expected_stderr)
+
+ def test_land_patches(self):
+ # FIXME: This expected result is imperfect, notice how it's seeing the same patch as still there after it thought it would have cleared the flags.
+ expected_stderr = """2 reviewed patches found on bug 42.
+Processing 2 patches from 1 bug.
+Updating working directory
+Processing patch 197 from bug 42.
+Building WebKit
+Running Python unit tests
+Running Perl unit tests
+Running JavaScriptCore tests
+Running run-webkit-tests
+Committed r49824: <http://trac.webkit.org/changeset/49824>
+Not closing bug 42 as attachment 197 has review=+. Assuming there are more patches to land from this bug.
+Updating working directory
+Processing patch 128 from bug 42.
+Building WebKit
+Running Python unit tests
+Running Perl unit tests
+Running JavaScriptCore tests
+Running run-webkit-tests
+Committed r49824: <http://trac.webkit.org/changeset/49824>
+Not closing bug 42 as attachment 197 has review=+. Assuming there are more patches to land from this bug.
+"""
+ self.assert_execute_outputs(LandFromBug(), [42], options=self._default_options(), expected_stderr=expected_stderr)
+
+ def test_prepare_rollout(self):
+ expected_stderr = "Preparing rollout for bug 42.\nUpdating working directory\nRunning prepare-ChangeLog\n"
+ self.assert_execute_outputs(PrepareRollout(), [852, "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
+
+ def test_create_rollout(self):
+ expected_stderr = """Preparing rollout for bug 42.
+Updating working directory
+MOCK create_bug
+bug_title: REGRESSION(r852): Reason
+bug_description: http://trac.webkit.org/changeset/852 broke the build:
+Reason
+component: MOCK component
+cc: MOCK cc
+blocked: 42
+Running prepare-ChangeLog
+MOCK add_patch_to_bug: bug_id=78, description=ROLLOUT of r852, mark_for_review=False, mark_for_commit_queue=True, mark_for_landing=False
+-- Begin comment --
+Any committer can land this patch automatically by marking it commit-queue+. The commit-queue will build and test the patch before landing to ensure that the rollout will be successful. This process takes approximately 15 minutes.
+
+If you would like to land the rollout faster, you can use the following command:
+
+ webkit-patch land-attachment ATTACHMENT_ID --ignore-builders
+
+where ATTACHMENT_ID is the ID of this attachment.
+-- End comment --
+"""
+ self.assert_execute_outputs(CreateRollout(), [852, "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
+ self.assert_execute_outputs(CreateRollout(), ["855 852 854", "Reason"], options=self._default_options(), expected_stderr=expected_stderr)
+
+ def test_rollout(self):
+ expected_stderr = "Preparing rollout for bug 42.\nUpdating working directory\nRunning prepare-ChangeLog\nMOCK: user.open_url: file://...\nBuilding WebKit\nCommitted r49824: <http://trac.webkit.org/changeset/49824>\n"
+ expected_stdout = "Was that diff correct?\n"
+ self.assert_execute_outputs(Rollout(), [852, "Reason"], options=self._default_options(), expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+
diff --git a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py
new file mode 100644
index 0000000..3b53d1a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem.py
@@ -0,0 +1,182 @@
+# 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.
+
+from webkitpy.tool.commands.queues import AbstractReviewQueue
+from webkitpy.common.config.committers import CommitterList
+from webkitpy.common.config.ports import WebKitPort
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.tool.bot.queueengine import QueueEngine
+
+
+class AbstractEarlyWarningSystem(AbstractReviewQueue):
+ _build_style = "release"
+
+ def __init__(self):
+ AbstractReviewQueue.__init__(self)
+ self.port = WebKitPort.port(self.port_name)
+
+ def should_proceed_with_work_item(self, patch):
+ return True
+
+ def _can_build(self):
+ try:
+ self.run_webkit_patch([
+ "build",
+ self.port.flag(),
+ "--build-style=%s" % self._build_style,
+ "--force-clean",
+ "--no-update"])
+ return True
+ except ScriptError, e:
+ failure_log = self._log_from_script_error_for_upload(e)
+ self._update_status("Unable to perform a build", results_file=failure_log)
+ return False
+
+ def _build(self, patch, first_run=False):
+ try:
+ args = [
+ "build-attachment",
+ self.port.flag(),
+ "--build",
+ "--build-style=%s" % self._build_style,
+ "--force-clean",
+ "--quiet",
+ "--non-interactive",
+ patch.id()]
+ if not first_run:
+ # See commit-queue for an explanation of what we're doing here.
+ args.append("--no-update")
+ args.append("--parent-command=%s" % self.name)
+ self.run_webkit_patch(args)
+ return True
+ except ScriptError, e:
+ if first_run:
+ return False
+ raise
+
+ def review_patch(self, patch):
+ if patch.is_obsolete():
+ self._did_error(patch, "%s does not process obsolete patches." % self.name)
+ return False
+
+ if patch.bug().is_closed():
+ self._did_error(patch, "%s does not process patches on closed bugs." % self.name)
+ return False
+
+ if not self._build(patch, first_run=True):
+ if not self._can_build():
+ return False
+ self._build(patch)
+ return True
+
+ @classmethod
+ def handle_script_error(cls, tool, state, script_error):
+ is_svn_apply = script_error.command_name() == "svn-apply"
+ status_id = cls._update_status_for_script_error(tool, state, script_error, is_error=is_svn_apply)
+ if is_svn_apply:
+ QueueEngine.exit_after_handled_error(script_error)
+ results_link = tool.status_server.results_url_for_status(status_id)
+ message = "Attachment %s did not build on %s:\nBuild output: %s" % (state["patch"].id(), cls.port_name, results_link)
+ tool.bugs.post_comment_to_bug(state["patch"].bug_id(), message, cc=cls.watchers)
+ exit(1)
+
+
+class GtkEWS(AbstractEarlyWarningSystem):
+ name = "gtk-ews"
+ port_name = "gtk"
+ watchers = AbstractEarlyWarningSystem.watchers + [
+ "gns@gnome.org",
+ "xan.lopez@gmail.com",
+ ]
+
+
+class EflEWS(AbstractEarlyWarningSystem):
+ name = "efl-ews"
+ port_name = "efl"
+ watchers = AbstractEarlyWarningSystem.watchers + [
+ "leandro@profusion.mobi",
+ "antognolli@profusion.mobi",
+ "lucas.demarchi@profusion.mobi",
+ ]
+
+
+class QtEWS(AbstractEarlyWarningSystem):
+ name = "qt-ews"
+ port_name = "qt"
+
+
+class WinEWS(AbstractEarlyWarningSystem):
+ name = "win-ews"
+ port_name = "win"
+ # Use debug, the Apple Win port fails to link Release on 32-bit Windows.
+ # https://bugs.webkit.org/show_bug.cgi?id=39197
+ _build_style = "debug"
+
+
+class AbstractChromiumEWS(AbstractEarlyWarningSystem):
+ port_name = "chromium"
+ watchers = AbstractEarlyWarningSystem.watchers + [
+ "dglazkov@chromium.org",
+ ]
+
+
+class ChromiumLinuxEWS(AbstractChromiumEWS):
+ # FIXME: We should rename this command to cr-linux-ews, but that requires
+ # a database migration. :(
+ name = "chromium-ews"
+
+
+class ChromiumWindowsEWS(AbstractChromiumEWS):
+ name = "cr-win-ews"
+
+
+# For platforms that we can't run inside a VM (like Mac OS X), we require
+# patches to be uploaded by committers, who are generally trustworthy folk. :)
+class AbstractCommitterOnlyEWS(AbstractEarlyWarningSystem):
+ def __init__(self, committers=CommitterList()):
+ AbstractEarlyWarningSystem.__init__(self)
+ self._committers = committers
+
+ def process_work_item(self, patch):
+ if not self._committers.committer_by_email(patch.attacher_email()):
+ self._did_error(patch, "%s cannot process patches from non-committers :(" % self.name)
+ return False
+ return AbstractEarlyWarningSystem.process_work_item(self, patch)
+
+
+# FIXME: Inheriting from AbstractCommitterOnlyEWS is kinda a hack, but it
+# happens to work because AbstractChromiumEWS and AbstractCommitterOnlyEWS
+# provide disjoint sets of functionality, and Python is otherwise smart
+# enough to handle the diamond inheritance.
+class ChromiumMacEWS(AbstractChromiumEWS, AbstractCommitterOnlyEWS):
+ name = "cr-mac-ews"
+
+
+class MacEWS(AbstractCommitterOnlyEWS):
+ name = "mac-ews"
+ port_name = "mac"
diff --git a/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py
new file mode 100644
index 0000000..830e11c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/earlywarningsystem_unittest.py
@@ -0,0 +1,132 @@
+# 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 os
+
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.bot.queueengine import QueueEngine
+from webkitpy.tool.commands.earlywarningsystem import *
+from webkitpy.tool.commands.queuestest import QueuesTest
+from webkitpy.tool.mocktool import MockTool, MockOptions
+
+
+class AbstractEarlyWarningSystemTest(QueuesTest):
+ def test_can_build(self):
+ # Needed to define port_name, used in AbstractEarlyWarningSystem.__init__
+ class TestEWS(AbstractEarlyWarningSystem):
+ port_name = "win" # Needs to be a port which port/factory understands.
+
+ queue = TestEWS()
+ queue.bind_to_tool(MockTool(log_executive=True))
+ queue._options = MockOptions(port=None)
+ expected_stderr = "MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'build', '--port=win', '--build-style=release', '--force-clean', '--no-update']\n"
+ OutputCapture().assert_outputs(self, queue._can_build, [], expected_stderr=expected_stderr)
+
+ def mock_run_webkit_patch(args):
+ raise ScriptError("MOCK script error")
+
+ queue.run_webkit_patch = mock_run_webkit_patch
+ expected_stderr = "MOCK: update_status: None Unable to perform a build\n"
+ OutputCapture().assert_outputs(self, queue._can_build, [], expected_stderr=expected_stderr)
+
+ # FIXME: This belongs on an AbstractReviewQueueTest object in queues_unittest.py
+ def test_subprocess_handled_error(self):
+ queue = AbstractReviewQueue()
+ queue.bind_to_tool(MockTool())
+
+ def mock_review_patch(patch):
+ raise ScriptError('MOCK script error', exit_code=QueueEngine.handled_error_code)
+
+ queue.review_patch = mock_review_patch
+ mock_patch = queue._tool.bugs.fetch_attachment(197)
+ expected_stderr = "MOCK: release_work_item: None 197\n"
+ OutputCapture().assert_outputs(self, queue.process_work_item, [mock_patch], expected_stderr=expected_stderr, expected_exception=ScriptError)
+
+
+class EarlyWarningSytemTest(QueuesTest):
+ def test_failed_builds(self):
+ ews = ChromiumLinuxEWS()
+ ews.bind_to_tool(MockTool())
+ ews._build = lambda patch, first_run=False: False
+ ews._can_build = lambda: True
+ mock_patch = ews._tool.bugs.fetch_attachment(197)
+ ews.review_patch(mock_patch)
+
+ def _default_expected_stderr(self, ews):
+ string_replacemnts = {
+ "name": ews.name,
+ "port": ews.port_name,
+ "watchers": ews.watchers,
+ }
+ expected_stderr = {
+ "begin_work_queue": self._default_begin_work_queue_stderr(ews.name, ews._tool.scm().checkout_root),
+ "handle_unexpected_error": "Mock error message\n",
+ "next_work_item": "",
+ "process_work_item": "MOCK: update_status: %(name)s Pass\nMOCK: release_work_item: %(name)s 197\n" % string_replacemnts,
+ "handle_script_error": "MOCK: update_status: %(name)s ScriptError error message\nMOCK bug comment: bug_id=42, cc=%(watchers)s\n--- Begin comment ---\nAttachment 197 did not build on %(port)s:\nBuild output: http://dummy_url\n--- End comment ---\n\n" % string_replacemnts,
+ }
+ return expected_stderr
+
+ def _test_ews(self, ews):
+ ews.bind_to_tool(MockTool())
+ expected_exceptions = {
+ "handle_script_error": SystemExit,
+ }
+ self.assert_queue_outputs(ews, expected_stderr=self._default_expected_stderr(ews), expected_exceptions=expected_exceptions)
+
+ def _test_committer_only_ews(self, ews):
+ ews.bind_to_tool(MockTool())
+ expected_stderr = self._default_expected_stderr(ews)
+ string_replacemnts = {"name": ews.name}
+ expected_stderr["process_work_item"] = "MOCK: update_status: %(name)s Error: %(name)s cannot process patches from non-committers :(\nMOCK: release_work_item: %(name)s 197\n" % string_replacemnts
+ expected_exceptions = {"handle_script_error": SystemExit}
+ self.assert_queue_outputs(ews, expected_stderr=expected_stderr, expected_exceptions=expected_exceptions)
+
+ # FIXME: If all EWSes are going to output the same text, we
+ # could test them all in one method with a for loop over an array.
+ def test_chromium_linux_ews(self):
+ self._test_ews(ChromiumLinuxEWS())
+
+ def test_chromium_windows_ews(self):
+ self._test_ews(ChromiumWindowsEWS())
+
+ def test_qt_ews(self):
+ self._test_ews(QtEWS())
+
+ def test_gtk_ews(self):
+ self._test_ews(GtkEWS())
+
+ def test_efl_ews(self):
+ self._test_ews(EflEWS())
+
+ def test_mac_ews(self):
+ self._test_committer_only_ews(MacEWS())
+
+ def test_chromium_mac_ews(self):
+ self._test_committer_only_ews(ChromiumMacEWS())
diff --git a/Tools/Scripts/webkitpy/tool/commands/openbugs.py b/Tools/Scripts/webkitpy/tool/commands/openbugs.py
new file mode 100644
index 0000000..1b51c9f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/openbugs.py
@@ -0,0 +1,63 @@
+# 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 re
+import sys
+
+from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
+from webkitpy.common.system.deprecated_logging import log
+
+
+class OpenBugs(AbstractDeclarativeCommand):
+ name = "open-bugs"
+ help_text = "Finds all bug numbers passed in arguments (or stdin if no args provided) and opens them in a web browser"
+
+ bug_number_regexp = re.compile(r"\b\d{4,6}\b")
+
+ def _open_bugs(self, bug_ids):
+ for bug_id in bug_ids:
+ bug_url = self._tool.bugs.bug_url_for_bug_id(bug_id)
+ self._tool.user.open_url(bug_url)
+
+ # _find_bugs_in_string mostly exists for easy unit testing.
+ def _find_bugs_in_string(self, string):
+ return self.bug_number_regexp.findall(string)
+
+ def _find_bugs_in_iterable(self, iterable):
+ return sum([self._find_bugs_in_string(string) for string in iterable], [])
+
+ def execute(self, options, args, tool):
+ if args:
+ bug_ids = self._find_bugs_in_iterable(args)
+ else:
+ # This won't open bugs until stdin is closed but could be made to easily. That would just make unit testing slightly harder.
+ bug_ids = self._find_bugs_in_iterable(sys.stdin)
+
+ log("%s bugs found in input." % len(bug_ids))
+
+ self._open_bugs(bug_ids)
diff --git a/Tools/Scripts/webkitpy/tool/commands/openbugs_unittest.py b/Tools/Scripts/webkitpy/tool/commands/openbugs_unittest.py
new file mode 100644
index 0000000..40a6e1b
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/openbugs_unittest.py
@@ -0,0 +1,50 @@
+# 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.
+
+from webkitpy.tool.commands.commandtest import CommandsTest
+from webkitpy.tool.commands.openbugs import OpenBugs
+
+class OpenBugsTest(CommandsTest):
+
+ find_bugs_in_string_expectations = [
+ ["123", []],
+ ["1234", ["1234"]],
+ ["12345", ["12345"]],
+ ["123456", ["123456"]],
+ ["1234567", []],
+ [" 123456 234567", ["123456", "234567"]],
+ ]
+
+ def test_find_bugs_in_string(self):
+ openbugs = OpenBugs()
+ for expectation in self.find_bugs_in_string_expectations:
+ self.assertEquals(openbugs._find_bugs_in_string(expectation[0]), expectation[1])
+
+ def test_args_parsing(self):
+ expected_stderr = "2 bugs found in input.\nMOCK: user.open_url: http://example.com/12345\nMOCK: user.open_url: http://example.com/23456\n"
+ self.assert_execute_outputs(OpenBugs(), ["12345\n23456"], expected_stderr=expected_stderr)
diff --git a/Tools/Scripts/webkitpy/tool/commands/prettydiff.py b/Tools/Scripts/webkitpy/tool/commands/prettydiff.py
new file mode 100644
index 0000000..e3fc00c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/prettydiff.py
@@ -0,0 +1,38 @@
+# 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.
+
+from webkitpy.tool.commands.abstractsequencedcommand import AbstractSequencedCommand
+import webkitpy.tool.steps as steps
+
+
+class PrettyDiff(AbstractSequencedCommand):
+ name = "pretty-diff"
+ help_text = "Shows the pretty diff in the default browser"
+ steps = [
+ steps.ConfirmDiff,
+ ]
diff --git a/Tools/Scripts/webkitpy/tool/commands/queries.py b/Tools/Scripts/webkitpy/tool/commands/queries.py
new file mode 100644
index 0000000..f04f384
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/queries.py
@@ -0,0 +1,389 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# 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:
+#
+# * 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.
+
+
+from optparse import make_option
+
+import webkitpy.tool.steps as steps
+
+from webkitpy.common.checkout.commitinfo import CommitInfo
+from webkitpy.common.config.committers import CommitterList
+from webkitpy.common.net.buildbot import BuildBot
+from webkitpy.common.net.regressionwindow import RegressionWindow
+from webkitpy.common.system.user import User
+from webkitpy.tool.grammar import pluralize
+from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
+from webkitpy.common.system.deprecated_logging import log
+from webkitpy.layout_tests import port
+
+
+class SuggestReviewers(AbstractDeclarativeCommand):
+ name = "suggest-reviewers"
+ help_text = "Suggest reviewers for a patch based on recent changes to the modified files."
+
+ def __init__(self):
+ options = [
+ steps.Options.git_commit,
+ ]
+ AbstractDeclarativeCommand.__init__(self, options=options)
+
+ def execute(self, options, args, tool):
+ reviewers = tool.checkout().suggested_reviewers(options.git_commit)
+ print "\n".join([reviewer.full_name for reviewer in reviewers])
+
+
+class BugsToCommit(AbstractDeclarativeCommand):
+ name = "bugs-to-commit"
+ help_text = "List bugs in the commit-queue"
+
+ def execute(self, options, args, tool):
+ # FIXME: This command is poorly named. It's fetching the commit-queue list here. The name implies it's fetching pending-commit (all r+'d patches).
+ bug_ids = tool.bugs.queries.fetch_bug_ids_from_commit_queue()
+ for bug_id in bug_ids:
+ print "%s" % bug_id
+
+
+class PatchesInCommitQueue(AbstractDeclarativeCommand):
+ name = "patches-in-commit-queue"
+ help_text = "List patches in the commit-queue"
+
+ def execute(self, options, args, tool):
+ patches = tool.bugs.queries.fetch_patches_from_commit_queue()
+ log("Patches in commit queue:")
+ for patch in patches:
+ print patch.url()
+
+
+class PatchesToCommitQueue(AbstractDeclarativeCommand):
+ name = "patches-to-commit-queue"
+ help_text = "Patches which should be added to the commit queue"
+ def __init__(self):
+ options = [
+ make_option("--bugs", action="store_true", dest="bugs", help="Output bug links instead of patch links"),
+ ]
+ AbstractDeclarativeCommand.__init__(self, options=options)
+
+ @staticmethod
+ def _needs_commit_queue(patch):
+ if patch.commit_queue() == "+": # If it's already cq+, ignore the patch.
+ log("%s already has cq=%s" % (patch.id(), patch.commit_queue()))
+ return False
+
+ # We only need to worry about patches from contributers who are not yet committers.
+ committer_record = CommitterList().committer_by_email(patch.attacher_email())
+ if committer_record:
+ log("%s committer = %s" % (patch.id(), committer_record))
+ return not committer_record
+
+ def execute(self, options, args, tool):
+ patches = tool.bugs.queries.fetch_patches_from_pending_commit_list()
+ patches_needing_cq = filter(self._needs_commit_queue, patches)
+ if options.bugs:
+ bugs_needing_cq = map(lambda patch: patch.bug_id(), patches_needing_cq)
+ bugs_needing_cq = sorted(set(bugs_needing_cq))
+ for bug_id in bugs_needing_cq:
+ print "%s" % tool.bugs.bug_url_for_bug_id(bug_id)
+ else:
+ for patch in patches_needing_cq:
+ print "%s" % tool.bugs.attachment_url_for_id(patch.id(), action="edit")
+
+
+class PatchesToReview(AbstractDeclarativeCommand):
+ name = "patches-to-review"
+ help_text = "List patches that are pending review"
+
+ def execute(self, options, args, tool):
+ patch_ids = tool.bugs.queries.fetch_attachment_ids_from_review_queue()
+ log("Patches pending review:")
+ for patch_id in patch_ids:
+ print patch_id
+
+
+class LastGreenRevision(AbstractDeclarativeCommand):
+ name = "last-green-revision"
+ help_text = "Prints the last known good revision"
+
+ def execute(self, options, args, tool):
+ print self._tool.buildbot.last_green_revision()
+
+
+class WhatBroke(AbstractDeclarativeCommand):
+ name = "what-broke"
+ help_text = "Print failing buildbots (%s) and what revisions broke them" % BuildBot.default_host
+
+ def _print_builder_line(self, builder_name, max_name_width, status_message):
+ print "%s : %s" % (builder_name.ljust(max_name_width), status_message)
+
+ def _print_blame_information_for_builder(self, builder_status, name_width, avoid_flakey_tests=True):
+ builder = self._tool.buildbot.builder_with_name(builder_status["name"])
+ red_build = builder.build(builder_status["build_number"])
+ regression_window = builder.find_regression_window(red_build)
+ if not regression_window.failing_build():
+ self._print_builder_line(builder.name(), name_width, "FAIL (error loading build information)")
+ return
+ if not regression_window.build_before_failure():
+ self._print_builder_line(builder.name(), name_width, "FAIL (blame-list: sometime before %s?)" % regression_window.failing_build().revision())
+ return
+
+ revisions = regression_window.revisions()
+ first_failure_message = ""
+ if (regression_window.failing_build() == builder.build(builder_status["build_number"])):
+ first_failure_message = " FIRST FAILURE, possibly a flaky test"
+ self._print_builder_line(builder.name(), name_width, "FAIL (blame-list: %s%s)" % (revisions, first_failure_message))
+ for revision in revisions:
+ commit_info = self._tool.checkout().commit_info_for_revision(revision)
+ if commit_info:
+ print commit_info.blame_string(self._tool.bugs)
+ else:
+ print "FAILED to fetch CommitInfo for r%s, likely missing ChangeLog" % revision
+
+ def execute(self, options, args, tool):
+ builder_statuses = tool.buildbot.builder_statuses()
+ longest_builder_name = max(map(len, map(lambda builder: builder["name"], builder_statuses)))
+ failing_builders = 0
+ for builder_status in builder_statuses:
+ # If the builder is green, print OK, exit.
+ if builder_status["is_green"]:
+ continue
+ self._print_blame_information_for_builder(builder_status, name_width=longest_builder_name)
+ failing_builders += 1
+ if failing_builders:
+ print "%s of %s are failing" % (failing_builders, pluralize("builder", len(builder_statuses)))
+ else:
+ print "All builders are passing!"
+
+
+class ResultsFor(AbstractDeclarativeCommand):
+ name = "results-for"
+ help_text = "Print a list of failures for the passed revision from bots on %s" % BuildBot.default_host
+ argument_names = "REVISION"
+
+ def _print_layout_test_results(self, results):
+ if not results:
+ print " No results."
+ return
+ for title, files in results.parsed_results().items():
+ print " %s" % title
+ for filename in files:
+ print " %s" % filename
+
+ def execute(self, options, args, tool):
+ builders = self._tool.buildbot.builders()
+ for builder in builders:
+ print "%s:" % builder.name()
+ build = builder.build_for_revision(args[0], allow_failed_lookups=True)
+ self._print_layout_test_results(build.layout_test_results())
+
+
+class FailureReason(AbstractDeclarativeCommand):
+ name = "failure-reason"
+ help_text = "Lists revisions where individual test failures started at %s" % BuildBot.default_host
+
+ def _blame_line_for_revision(self, revision):
+ try:
+ commit_info = self._tool.checkout().commit_info_for_revision(revision)
+ except Exception, e:
+ return "FAILED to fetch CommitInfo for r%s, exception: %s" % (revision, e)
+ if not commit_info:
+ return "FAILED to fetch CommitInfo for r%s, likely missing ChangeLog" % revision
+ return commit_info.blame_string(self._tool.bugs)
+
+ def _print_blame_information_for_transition(self, regression_window, failing_tests):
+ red_build = regression_window.failing_build()
+ print "SUCCESS: Build %s (r%s) was the first to show failures: %s" % (red_build._number, red_build.revision(), failing_tests)
+ print "Suspect revisions:"
+ for revision in regression_window.revisions():
+ print self._blame_line_for_revision(revision)
+
+ def _explain_failures_for_builder(self, builder, start_revision):
+ print "Examining failures for \"%s\", starting at r%s" % (builder.name(), start_revision)
+ revision_to_test = start_revision
+ build = builder.build_for_revision(revision_to_test, allow_failed_lookups=True)
+ layout_test_results = build.layout_test_results()
+ if not layout_test_results:
+ # FIXME: This could be made more user friendly.
+ print "Failed to load layout test results; can't continue. (start revision = r%s)" % start_revision
+ return 1
+
+ results_to_explain = set(layout_test_results.failing_tests())
+ last_build_with_results = build
+ print "Starting at %s" % revision_to_test
+ while results_to_explain:
+ revision_to_test -= 1
+ new_build = builder.build_for_revision(revision_to_test, allow_failed_lookups=True)
+ if not new_build:
+ print "No build for %s" % revision_to_test
+ continue
+ build = new_build
+ latest_results = build.layout_test_results()
+ if not latest_results:
+ print "No results build %s (r%s)" % (build._number, build.revision())
+ continue
+ failures = set(latest_results.failing_tests())
+ if len(failures) >= 20:
+ # FIXME: We may need to move this logic into the LayoutTestResults class.
+ # The buildbot stops runs after 20 failures so we don't have full results to work with here.
+ print "Too many failures in build %s (r%s), ignoring." % (build._number, build.revision())
+ continue
+ fixed_results = results_to_explain - failures
+ if not fixed_results:
+ print "No change in build %s (r%s), %s unexplained failures (%s in this build)" % (build._number, build.revision(), len(results_to_explain), len(failures))
+ last_build_with_results = build
+ continue
+ regression_window = RegressionWindow(build, last_build_with_results)
+ self._print_blame_information_for_transition(regression_window, fixed_results)
+ last_build_with_results = build
+ results_to_explain -= fixed_results
+ if results_to_explain:
+ print "Failed to explain failures: %s" % results_to_explain
+ return 1
+ print "Explained all results for %s" % builder.name()
+ return 0
+
+ def _builder_to_explain(self):
+ builder_statuses = self._tool.buildbot.builder_statuses()
+ red_statuses = [status for status in builder_statuses if not status["is_green"]]
+ print "%s failing" % (pluralize("builder", len(red_statuses)))
+ builder_choices = [status["name"] for status in red_statuses]
+ # We could offer an "All" choice here.
+ chosen_name = User.prompt_with_list("Which builder to diagnose:", builder_choices)
+ # FIXME: prompt_with_list should really take a set of objects and a set of names and then return the object.
+ for status in red_statuses:
+ if status["name"] == chosen_name:
+ return (self._tool.buildbot.builder_with_name(chosen_name), status["built_revision"])
+
+ def execute(self, options, args, tool):
+ (builder, latest_revision) = self._builder_to_explain()
+ start_revision = self._tool.user.prompt("Revision to walk backwards from? [%s] " % latest_revision) or latest_revision
+ if not start_revision:
+ print "Revision required."
+ return 1
+ return self._explain_failures_for_builder(builder, start_revision=int(start_revision))
+
+
+class FindFlakyTests(AbstractDeclarativeCommand):
+ name = "find-flaky-tests"
+ help_text = "Lists tests that often fail for a single build at %s" % BuildBot.default_host
+
+ def _find_failures(self, builder, revision):
+ build = builder.build_for_revision(revision, allow_failed_lookups=True)
+ if not build:
+ print "No build for %s" % revision
+ return (None, None)
+ results = build.layout_test_results()
+ if not results:
+ print "No results build %s (r%s)" % (build._number, build.revision())
+ return (None, None)
+ failures = set(results.failing_tests())
+ if len(failures) >= 20:
+ # FIXME: We may need to move this logic into the LayoutTestResults class.
+ # The buildbot stops runs after 20 failures so we don't have full results to work with here.
+ print "Too many failures in build %s (r%s), ignoring." % (build._number, build.revision())
+ return (None, None)
+ return (build, failures)
+
+ def _increment_statistics(self, flaky_tests, flaky_test_statistics):
+ for test in flaky_tests:
+ count = flaky_test_statistics.get(test, 0)
+ flaky_test_statistics[test] = count + 1
+
+ def _print_statistics(self, statistics):
+ print "=== Results ==="
+ print "Occurances Test name"
+ for value, key in sorted([(value, key) for key, value in statistics.items()]):
+ print "%10d %s" % (value, key)
+
+ def _walk_backwards_from(self, builder, start_revision, limit):
+ flaky_test_statistics = {}
+ all_previous_failures = set([])
+ one_time_previous_failures = set([])
+ previous_build = None
+ for i in range(limit):
+ revision = start_revision - i
+ print "Analyzing %s ... " % revision,
+ (build, failures) = self._find_failures(builder, revision)
+ if failures == None:
+ # Notice that we don't loop on the empty set!
+ continue
+ print "has %s failures" % len(failures)
+ flaky_tests = one_time_previous_failures - failures
+ if flaky_tests:
+ print "Flaky tests: %s %s" % (sorted(flaky_tests),
+ previous_build.results_url())
+ self._increment_statistics(flaky_tests, flaky_test_statistics)
+ one_time_previous_failures = failures - all_previous_failures
+ all_previous_failures = failures
+ previous_build = build
+ self._print_statistics(flaky_test_statistics)
+
+ def _builder_to_analyze(self):
+ statuses = self._tool.buildbot.builder_statuses()
+ choices = [status["name"] for status in statuses]
+ chosen_name = User.prompt_with_list("Which builder to analyze:", choices)
+ for status in statuses:
+ if status["name"] == chosen_name:
+ return (self._tool.buildbot.builder_with_name(chosen_name), status["built_revision"])
+
+ def execute(self, options, args, tool):
+ (builder, latest_revision) = self._builder_to_analyze()
+ limit = self._tool.user.prompt("How many revisions to look through? [10000] ") or 10000
+ return self._walk_backwards_from(builder, latest_revision, limit=int(limit))
+
+
+class TreeStatus(AbstractDeclarativeCommand):
+ name = "tree-status"
+ help_text = "Print the status of the %s buildbots" % BuildBot.default_host
+ long_help = """Fetches build status from http://build.webkit.org/one_box_per_builder
+and displayes the status of each builder."""
+
+ def execute(self, options, args, tool):
+ for builder in tool.buildbot.builder_statuses():
+ status_string = "ok" if builder["is_green"] else "FAIL"
+ print "%s : %s" % (status_string.ljust(4), builder["name"])
+
+
+class SkippedPorts(AbstractDeclarativeCommand):
+ name = "skipped-ports"
+ help_text = "Print the list of ports skipping the given layout test(s)"
+ long_help = """Scans the the Skipped file of each port and figure
+out what ports are skipping the test(s). Categories are taken in account too."""
+ argument_names = "TEST_NAME"
+
+ def execute(self, options, args, tool):
+ results = dict([(test_name, []) for test_name in args])
+ for port_name, port_object in tool.port_factory.get_all().iteritems():
+ for test_name in args:
+ if port_object.skips_layout_test(test_name):
+ results[test_name].append(port_name)
+
+ for test_name, ports in results.iteritems():
+ if ports:
+ print "Ports skipping test %r: %s" % (test_name, ', '.join(ports))
+ else:
+ print "Test %r is not skipped by any port." % test_name
diff --git a/Tools/Scripts/webkitpy/tool/commands/queries_unittest.py b/Tools/Scripts/webkitpy/tool/commands/queries_unittest.py
new file mode 100644
index 0000000..05a4a5c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/queries_unittest.py
@@ -0,0 +1,90 @@
+# 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 unittest
+
+from webkitpy.common.net.bugzilla import Bugzilla
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.tool.commands.commandtest import CommandsTest
+from webkitpy.tool.commands.queries import *
+from webkitpy.tool.mocktool import MockTool
+
+
+class QueryCommandsTest(CommandsTest):
+ def test_bugs_to_commit(self):
+ expected_stderr = "Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)\n"
+ self.assert_execute_outputs(BugsToCommit(), None, "42\n77\n", expected_stderr)
+
+ def test_patches_in_commit_queue(self):
+ expected_stdout = "http://example.com/197\nhttp://example.com/103\n"
+ expected_stderr = "Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)\nPatches in commit queue:\n"
+ self.assert_execute_outputs(PatchesInCommitQueue(), None, expected_stdout, expected_stderr)
+
+ def test_patches_to_commit_queue(self):
+ expected_stdout = "http://example.com/104&action=edit\n"
+ expected_stderr = "197 already has cq=+\n128 already has cq=+\n105 committer = \"Eric Seidel\" <eric@webkit.org>\n"
+ options = Mock()
+ options.bugs = False
+ self.assert_execute_outputs(PatchesToCommitQueue(), None, expected_stdout, expected_stderr, options=options)
+
+ expected_stdout = "http://example.com/77\n"
+ options.bugs = True
+ self.assert_execute_outputs(PatchesToCommitQueue(), None, expected_stdout, expected_stderr, options=options)
+
+ def test_patches_to_review(self):
+ expected_stdout = "103\n"
+ expected_stderr = "Patches pending review:\n"
+ self.assert_execute_outputs(PatchesToReview(), None, expected_stdout, expected_stderr)
+
+ def test_tree_status(self):
+ expected_stdout = "ok : Builder1\nok : Builder2\n"
+ self.assert_execute_outputs(TreeStatus(), None, expected_stdout)
+
+ def test_skipped_ports(self):
+ expected_stdout = "Ports skipping test 'media/foo/bar.html': test_port1, test_port2\n"
+ self.assert_execute_outputs(SkippedPorts(), ("media/foo/bar.html",), expected_stdout)
+
+ expected_stdout = "Ports skipping test 'foo': test_port1\n"
+ self.assert_execute_outputs(SkippedPorts(), ("foo",), expected_stdout)
+
+ expected_stdout = "Test 'media' is not skipped by any port.\n"
+ self.assert_execute_outputs(SkippedPorts(), ("media",), expected_stdout)
+
+
+class FailureReasonTest(unittest.TestCase):
+ def test_blame_line_for_revision(self):
+ tool = MockTool()
+ command = FailureReason()
+ command.bind_to_tool(tool)
+ # This is an artificial example, mostly to test the CommitInfo lookup failure case.
+ self.assertEquals(command._blame_line_for_revision(None), "FAILED to fetch CommitInfo for rNone, likely missing ChangeLog")
+
+ def raising_mock(self):
+ raise Exception("MESSAGE")
+ tool.checkout().commit_info_for_revision = raising_mock
+ self.assertEquals(command._blame_line_for_revision(None), "FAILED to fetch CommitInfo for rNone, exception: MESSAGE")
diff --git a/Tools/Scripts/webkitpy/tool/commands/queues.py b/Tools/Scripts/webkitpy/tool/commands/queues.py
new file mode 100644
index 0000000..e15555f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/queues.py
@@ -0,0 +1,406 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# 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:
+#
+# * 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.
+
+from __future__ import with_statement
+
+import codecs
+import time
+import traceback
+import os
+
+from datetime import datetime
+from optparse import make_option
+from StringIO import StringIO
+
+from webkitpy.common.config.committervalidator import CommitterValidator
+from webkitpy.common.net.bugzilla import Attachment
+from webkitpy.common.net.layouttestresults import LayoutTestResults
+from webkitpy.common.net.statusserver import StatusServer
+from webkitpy.common.system.deprecated_logging import error, log
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.tool.bot.commitqueuetask import CommitQueueTask, CommitQueueTaskDelegate
+from webkitpy.tool.bot.feeders import CommitQueueFeeder, EWSFeeder
+from webkitpy.tool.bot.queueengine import QueueEngine, QueueEngineDelegate
+from webkitpy.tool.bot.flakytestreporter import FlakyTestReporter
+from webkitpy.tool.commands.stepsequence import StepSequenceErrorHandler
+from webkitpy.tool.multicommandtool import Command, TryAgain
+
+
+class AbstractQueue(Command, QueueEngineDelegate):
+ watchers = [
+ ]
+
+ _pass_status = "Pass"
+ _fail_status = "Fail"
+ _retry_status = "Retry"
+ _error_status = "Error"
+
+ def __init__(self, options=None): # Default values should never be collections (like []) as default values are shared between invocations
+ options_list = (options or []) + [
+ make_option("--no-confirm", action="store_false", dest="confirm", default=True, help="Do not ask the user for confirmation before running the queue. Dangerous!"),
+ make_option("--exit-after-iteration", action="store", type="int", dest="iterations", default=None, help="Stop running the queue after iterating this number of times."),
+ ]
+ Command.__init__(self, "Run the %s" % self.name, options=options_list)
+ self._iteration_count = 0
+
+ def _cc_watchers(self, bug_id):
+ try:
+ self._tool.bugs.add_cc_to_bug(bug_id, self.watchers)
+ except Exception, e:
+ traceback.print_exc()
+ log("Failed to CC watchers.")
+
+ def run_webkit_patch(self, args):
+ webkit_patch_args = [self._tool.path()]
+ # FIXME: This is a hack, we should have a more general way to pass global options.
+ # FIXME: We must always pass global options and their value in one argument
+ # because our global option code looks for the first argument which does
+ # not begin with "-" and assumes that is the command name.
+ webkit_patch_args += ["--status-host=%s" % self._tool.status_server.host]
+ if self._tool.status_server.bot_id:
+ webkit_patch_args += ["--bot-id=%s" % self._tool.status_server.bot_id]
+ if self._options.port:
+ webkit_patch_args += ["--port=%s" % self._options.port]
+ webkit_patch_args.extend(args)
+ # FIXME: There is probably no reason to use run_and_throw_if_fail anymore.
+ # run_and_throw_if_fail was invented to support tee'd output
+ # (where we write both to a log file and to the console at once),
+ # but the queues don't need live-progress, a dump-of-output at the
+ # end should be sufficient.
+ return self._tool.executive.run_and_throw_if_fail(webkit_patch_args)
+
+ def _log_directory(self):
+ return "%s-logs" % self.name
+
+ # QueueEngineDelegate methods
+
+ def queue_log_path(self):
+ return os.path.join(self._log_directory(), "%s.log" % self.name)
+
+ def work_item_log_path(self, work_item):
+ raise NotImplementedError, "subclasses must implement"
+
+ def begin_work_queue(self):
+ log("CAUTION: %s will discard all local changes in \"%s\"" % (self.name, self._tool.scm().checkout_root))
+ if self._options.confirm:
+ response = self._tool.user.prompt("Are you sure? Type \"yes\" to continue: ")
+ if (response != "yes"):
+ error("User declined.")
+ log("Running WebKit %s." % self.name)
+ self._tool.status_server.update_status(self.name, "Starting Queue")
+
+ def stop_work_queue(self, reason):
+ self._tool.status_server.update_status(self.name, "Stopping Queue, reason: %s" % reason)
+
+ def should_continue_work_queue(self):
+ self._iteration_count += 1
+ return not self._options.iterations or self._iteration_count <= self._options.iterations
+
+ def next_work_item(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def should_proceed_with_work_item(self, work_item):
+ raise NotImplementedError, "subclasses must implement"
+
+ def process_work_item(self, work_item):
+ raise NotImplementedError, "subclasses must implement"
+
+ def handle_unexpected_error(self, work_item, message):
+ raise NotImplementedError, "subclasses must implement"
+
+ # Command methods
+
+ def execute(self, options, args, tool, engine=QueueEngine):
+ self._options = options # FIXME: This code is wrong. Command.options is a list, this assumes an Options element!
+ self._tool = tool # FIXME: This code is wrong too! Command.bind_to_tool handles this!
+ return engine(self.name, self, self._tool.wakeup_event).run()
+
+ @classmethod
+ def _log_from_script_error_for_upload(cls, script_error, output_limit=None):
+ # We have seen request timeouts with app engine due to large
+ # log uploads. Trying only the last 512k.
+ if not output_limit:
+ output_limit = 512 * 1024 # 512k
+ output = script_error.message_with_output(output_limit=output_limit)
+ # We pre-encode the string to a byte array before passing it
+ # to status_server, because ClientForm (part of mechanize)
+ # wants a file-like object with pre-encoded data.
+ return StringIO(output.encode("utf-8"))
+
+ @classmethod
+ def _update_status_for_script_error(cls, tool, state, script_error, is_error=False):
+ message = str(script_error)
+ if is_error:
+ message = "Error: %s" % message
+ failure_log = cls._log_from_script_error_for_upload(script_error)
+ return tool.status_server.update_status(cls.name, message, state["patch"], failure_log)
+
+
+class FeederQueue(AbstractQueue):
+ name = "feeder-queue"
+
+ _sleep_duration = 30 # seconds
+
+ # AbstractPatchQueue methods
+
+ def begin_work_queue(self):
+ AbstractQueue.begin_work_queue(self)
+ self.feeders = [
+ CommitQueueFeeder(self._tool),
+ EWSFeeder(self._tool),
+ ]
+
+ def next_work_item(self):
+ # This really show inherit from some more basic class that doesn't
+ # understand work items, but the base class in the heirarchy currently
+ # understands work items.
+ return "synthetic-work-item"
+
+ def should_proceed_with_work_item(self, work_item):
+ return True
+
+ def process_work_item(self, work_item):
+ for feeder in self.feeders:
+ feeder.feed()
+ time.sleep(self._sleep_duration)
+ return True
+
+ def work_item_log_path(self, work_item):
+ return None
+
+ def handle_unexpected_error(self, work_item, message):
+ log(message)
+
+
+class AbstractPatchQueue(AbstractQueue):
+ def _update_status(self, message, patch=None, results_file=None):
+ return self._tool.status_server.update_status(self.name, message, patch, results_file)
+
+ def _next_patch(self):
+ patch_id = self._tool.status_server.next_work_item(self.name)
+ if not patch_id:
+ return None
+ patch = self._tool.bugs.fetch_attachment(patch_id)
+ if not patch:
+ # FIXME: Using a fake patch because release_work_item has the wrong API.
+ # We also don't really need to release the lock (although that's fine),
+ # mostly we just need to remove this bogus patch from our queue.
+ # If for some reason bugzilla is just down, then it will be re-fed later.
+ patch = Attachment({'id': patch_id}, None)
+ self._release_work_item(patch)
+ return None
+ return patch
+
+ def _release_work_item(self, patch):
+ self._tool.status_server.release_work_item(self.name, patch)
+
+ def _did_pass(self, patch):
+ self._update_status(self._pass_status, patch)
+ self._release_work_item(patch)
+
+ def _did_fail(self, patch):
+ self._update_status(self._fail_status, patch)
+ self._release_work_item(patch)
+
+ def _did_retry(self, patch):
+ self._update_status(self._retry_status, patch)
+ self._release_work_item(patch)
+
+ def _did_error(self, patch, reason):
+ message = "%s: %s" % (self._error_status, reason)
+ self._update_status(message, patch)
+ self._release_work_item(patch)
+
+ def work_item_log_path(self, patch):
+ return os.path.join(self._log_directory(), "%s.log" % patch.bug_id())
+
+
+class CommitQueue(AbstractPatchQueue, StepSequenceErrorHandler, CommitQueueTaskDelegate):
+ name = "commit-queue"
+
+ # AbstractPatchQueue methods
+
+ def begin_work_queue(self):
+ AbstractPatchQueue.begin_work_queue(self)
+ self.committer_validator = CommitterValidator(self._tool.bugs)
+
+ def next_work_item(self):
+ return self._next_patch()
+
+ def should_proceed_with_work_item(self, patch):
+ patch_text = "rollout patch" if patch.is_rollout() else "patch"
+ self._update_status("Processing %s" % patch_text, patch)
+ return True
+
+ def process_work_item(self, patch):
+ self._cc_watchers(patch.bug_id())
+ task = CommitQueueTask(self, patch)
+ try:
+ if task.run():
+ self._did_pass(patch)
+ return True
+ self._did_retry(patch)
+ except ScriptError, e:
+ validator = CommitterValidator(self._tool.bugs)
+ validator.reject_patch_from_commit_queue(patch.id(), self._error_message_for_bug(task.failure_status_id, e))
+ self._did_fail(patch)
+
+ def _error_message_for_bug(self, status_id, script_error):
+ if not script_error.output:
+ return script_error.message_with_output()
+ results_link = self._tool.status_server.results_url_for_status(status_id)
+ return "%s\nFull output: %s" % (script_error.message_with_output(), results_link)
+
+ def handle_unexpected_error(self, patch, message):
+ self.committer_validator.reject_patch_from_commit_queue(patch.id(), message)
+
+ # CommitQueueTaskDelegate methods
+
+ def run_command(self, command):
+ self.run_webkit_patch(command)
+
+ def command_passed(self, message, patch):
+ self._update_status(message, patch=patch)
+
+ def command_failed(self, message, script_error, patch):
+ failure_log = self._log_from_script_error_for_upload(script_error)
+ return self._update_status(message, patch=patch, results_file=failure_log)
+
+ # FIXME: This exists for mocking, but should instead be mocked via
+ # tool.filesystem.read_text_file. They have different error handling at the moment.
+ def _read_file_contents(self, path):
+ try:
+ with codecs.open(path, "r", "utf-8") as open_file:
+ return open_file.read()
+ except OSError, e: # File does not exist or can't be read.
+ return None
+
+ # FIXME: This may belong on the Port object.
+ def layout_test_results(self):
+ results_path = self._tool.port().layout_tests_results_path()
+ results_html = self._read_file_contents(results_path)
+ if not results_html:
+ return None
+ return LayoutTestResults.results_from_string(results_html)
+
+ def refetch_patch(self, patch):
+ return self._tool.bugs.fetch_attachment(patch.id())
+
+ def report_flaky_tests(self, patch, flaky_tests):
+ reporter = FlakyTestReporter(self._tool, self.name)
+ reporter.report_flaky_tests(flaky_tests, patch)
+
+ # StepSequenceErrorHandler methods
+
+ def handle_script_error(cls, tool, state, script_error):
+ # Hitting this error handler should be pretty rare. It does occur,
+ # however, when a patch no longer applies to top-of-tree in the final
+ # land step.
+ log(script_error.message_with_output())
+
+ @classmethod
+ def handle_checkout_needs_update(cls, tool, state, options, error):
+ message = "Tests passed, but commit failed (checkout out of date). Updating, then landing without building or re-running tests."
+ tool.status_server.update_status(cls.name, message, state["patch"])
+ # The only time when we find out that out checkout needs update is
+ # when we were ready to actually pull the trigger and land the patch.
+ # Rather than spinning in the master process, we retry without
+ # building or testing, which is much faster.
+ options.build = False
+ options.test = False
+ options.update = True
+ raise TryAgain()
+
+
+class AbstractReviewQueue(AbstractPatchQueue, StepSequenceErrorHandler):
+ """This is the base-class for the EWS queues and the style-queue."""
+ def __init__(self, options=None):
+ AbstractPatchQueue.__init__(self, options)
+
+ def review_patch(self, patch):
+ raise NotImplementedError("subclasses must implement")
+
+ # AbstractPatchQueue methods
+
+ def begin_work_queue(self):
+ AbstractPatchQueue.begin_work_queue(self)
+
+ def next_work_item(self):
+ return self._next_patch()
+
+ def should_proceed_with_work_item(self, patch):
+ raise NotImplementedError("subclasses must implement")
+
+ def process_work_item(self, patch):
+ try:
+ if not self.review_patch(patch):
+ return False
+ self._did_pass(patch)
+ return True
+ except ScriptError, e:
+ if e.exit_code != QueueEngine.handled_error_code:
+ self._did_fail(patch)
+ else:
+ # The subprocess handled the error, but won't have released the patch, so we do.
+ # FIXME: We need to simplify the rules by which _release_work_item is called.
+ self._release_work_item(patch)
+ raise e
+
+ def handle_unexpected_error(self, patch, message):
+ log(message)
+
+ # StepSequenceErrorHandler methods
+
+ @classmethod
+ def handle_script_error(cls, tool, state, script_error):
+ log(script_error.message_with_output())
+
+
+class StyleQueue(AbstractReviewQueue):
+ name = "style-queue"
+ def __init__(self):
+ AbstractReviewQueue.__init__(self)
+
+ def should_proceed_with_work_item(self, patch):
+ self._update_status("Checking style", patch)
+ return True
+
+ def review_patch(self, patch):
+ self.run_webkit_patch(["check-style", "--force-clean", "--non-interactive", "--parent-command=style-queue", patch.id()])
+ return True
+
+ @classmethod
+ def handle_script_error(cls, tool, state, script_error):
+ is_svn_apply = script_error.command_name() == "svn-apply"
+ status_id = cls._update_status_for_script_error(tool, state, script_error, is_error=is_svn_apply)
+ if is_svn_apply:
+ QueueEngine.exit_after_handled_error(script_error)
+ message = "Attachment %s did not pass %s:\n\n%s\n\nIf any of these errors are false positives, please file a bug against check-webkit-style." % (state["patch"].id(), cls.name, script_error.message_with_output(output_limit=3*1024))
+ tool.bugs.post_comment_to_bug(state["patch"].bug_id(), message, cc=cls.watchers)
+ exit(1)
diff --git a/Tools/Scripts/webkitpy/tool/commands/queues_unittest.py b/Tools/Scripts/webkitpy/tool/commands/queues_unittest.py
new file mode 100644
index 0000000..d793213
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/queues_unittest.py
@@ -0,0 +1,380 @@
+# 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 os
+
+from webkitpy.common.checkout.scm import CheckoutNeedsUpdate
+from webkitpy.common.net.bugzilla import Attachment
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.tool.commands.commandtest import CommandsTest
+from webkitpy.tool.commands.queues import *
+from webkitpy.tool.commands.queuestest import QueuesTest
+from webkitpy.tool.commands.stepsequence import StepSequence
+from webkitpy.tool.mocktool import MockTool, MockSCM, MockStatusServer
+
+
+class TestQueue(AbstractPatchQueue):
+ name = "test-queue"
+
+
+class TestReviewQueue(AbstractReviewQueue):
+ name = "test-review-queue"
+
+
+class TestFeederQueue(FeederQueue):
+ _sleep_duration = 0
+
+
+class AbstractQueueTest(CommandsTest):
+ def test_log_directory(self):
+ self.assertEquals(TestQueue()._log_directory(), "test-queue-logs")
+
+ def _assert_run_webkit_patch(self, run_args, port=None):
+ queue = TestQueue()
+ tool = MockTool()
+ tool.status_server.bot_id = "gort"
+ tool.executive = Mock()
+ queue.bind_to_tool(tool)
+ queue._options = Mock()
+ queue._options.port = port
+
+ queue.run_webkit_patch(run_args)
+ expected_run_args = ["echo", "--status-host=example.com", "--bot-id=gort"]
+ if port:
+ expected_run_args.append("--port=%s" % port)
+ expected_run_args.extend(run_args)
+ tool.executive.run_and_throw_if_fail.assert_called_with(expected_run_args)
+
+ def test_run_webkit_patch(self):
+ self._assert_run_webkit_patch([1])
+ self._assert_run_webkit_patch(["one", 2])
+ self._assert_run_webkit_patch([1], port="mockport")
+
+ def test_iteration_count(self):
+ queue = TestQueue()
+ queue._options = Mock()
+ queue._options.iterations = 3
+ self.assertTrue(queue.should_continue_work_queue())
+ self.assertTrue(queue.should_continue_work_queue())
+ self.assertTrue(queue.should_continue_work_queue())
+ self.assertFalse(queue.should_continue_work_queue())
+
+ def test_no_iteration_count(self):
+ queue = TestQueue()
+ queue._options = Mock()
+ self.assertTrue(queue.should_continue_work_queue())
+ self.assertTrue(queue.should_continue_work_queue())
+ self.assertTrue(queue.should_continue_work_queue())
+ self.assertTrue(queue.should_continue_work_queue())
+
+ def _assert_log_message(self, script_error, log_message):
+ failure_log = AbstractQueue._log_from_script_error_for_upload(script_error, output_limit=10)
+ self.assertTrue(failure_log.read(), log_message)
+
+ def test_log_from_script_error_for_upload(self):
+ self._assert_log_message(ScriptError("test"), "test")
+ # In python 2.5 unicode(Exception) is busted. See:
+ # http://bugs.python.org/issue2517
+ # With no good workaround, we just ignore these tests.
+ if not hasattr(Exception, "__unicode__"):
+ return
+
+ unicode_tor = u"WebKit \u2661 Tor Arne Vestb\u00F8!"
+ utf8_tor = unicode_tor.encode("utf-8")
+ self._assert_log_message(ScriptError(unicode_tor), utf8_tor)
+ script_error = ScriptError(unicode_tor, output=unicode_tor)
+ expected_output = "%s\nLast %s characters of output:\n%s" % (utf8_tor, 10, utf8_tor[-10:])
+ self._assert_log_message(script_error, expected_output)
+
+
+class FeederQueueTest(QueuesTest):
+ def test_feeder_queue(self):
+ queue = TestFeederQueue()
+ tool = MockTool(log_executive=True)
+ expected_stderr = {
+ "begin_work_queue": self._default_begin_work_queue_stderr("feeder-queue", MockSCM.fake_checkout_root),
+ "should_proceed_with_work_item": "",
+ "next_work_item": "",
+ "process_work_item": """Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)
+Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)
+MOCK setting flag 'commit-queue' to '-' on attachment '128' with comment 'Rejecting attachment 128 from commit-queue.' and additional comment 'non-committer@example.com does not have committer permissions according to http://trac.webkit.org/browser/trunk/Tools/Scripts/webkitpy/common/config/committers.py.
+
+- If you do not have committer rights please read http://webkit.org/coding/contributing.html for instructions on how to use bugzilla flags.
+
+- If you have committer rights please correct the error in Tools/Scripts/webkitpy/common/config/committers.py by adding yourself to the file (no review needed). The commit-queue restarts itself every 2 hours. After restart the commit-queue will correctly respect your committer rights.'
+MOCK: update_work_items: commit-queue [106, 197]
+Feeding commit-queue items [106, 197]
+Feeding EWS (1 r? patch, 1 new)
+MOCK: submit_to_ews: 103
+""",
+ "handle_unexpected_error": "Mock error message\n",
+ }
+ self.assert_queue_outputs(queue, tool=tool, expected_stderr=expected_stderr)
+
+
+class AbstractPatchQueueTest(CommandsTest):
+ def test_next_patch(self):
+ queue = AbstractPatchQueue()
+ tool = MockTool()
+ queue.bind_to_tool(tool)
+ queue._options = Mock()
+ queue._options.port = None
+ self.assertEquals(queue._next_patch(), None)
+ tool.status_server = MockStatusServer(work_items=[2, 197])
+ expected_stdout = "MOCK: fetch_attachment: 2 is not a known attachment id\n" # A mock-only message to prevent us from making mistakes.
+ expected_stderr = "MOCK: release_work_item: None 2\n"
+ patch_id = OutputCapture().assert_outputs(self, queue._next_patch, [], expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+ self.assertEquals(patch_id, None) # 2 is an invalid patch id
+ self.assertEquals(queue._next_patch().id(), 197)
+
+
+class NeedsUpdateSequence(StepSequence):
+ def _run(self, tool, options, state):
+ raise CheckoutNeedsUpdate([], 1, "", None)
+
+
+class AlwaysCommitQueueTool(object):
+ def __init__(self):
+ self.status_server = MockStatusServer()
+
+ def command_by_name(self, name):
+ return CommitQueue
+
+
+class SecondThoughtsCommitQueue(CommitQueue):
+ def __init__(self):
+ self._reject_patch = False
+ CommitQueue.__init__(self)
+
+ def run_command(self, command):
+ # We want to reject the patch after the first validation,
+ # so wait to reject it until after some other command has run.
+ self._reject_patch = True
+ return CommitQueue.run_command(self, command)
+
+ def refetch_patch(self, patch):
+ if not self._reject_patch:
+ return self._tool.bugs.fetch_attachment(patch.id())
+
+ attachment_dictionary = {
+ "id": patch.id(),
+ "bug_id": patch.bug_id(),
+ "name": "Rejected",
+ "is_obsolete": True,
+ "is_patch": False,
+ "review": "-",
+ "reviewer_email": "foo@bar.com",
+ "commit-queue": "-",
+ "committer_email": "foo@bar.com",
+ "attacher_email": "Contributer1",
+ }
+ return Attachment(attachment_dictionary, None)
+
+
+class CommitQueueTest(QueuesTest):
+ def test_commit_queue(self):
+ expected_stderr = {
+ "begin_work_queue": self._default_begin_work_queue_stderr("commit-queue", MockSCM.fake_checkout_root),
+ "should_proceed_with_work_item": "MOCK: update_status: commit-queue Processing patch\n",
+ "next_work_item": "",
+ "process_work_item": """MOCK: update_status: commit-queue Cleaned working directory
+MOCK: update_status: commit-queue Updated working directory
+MOCK: update_status: commit-queue Applied patch
+MOCK: update_status: commit-queue Built patch
+MOCK: update_status: commit-queue Passed tests
+MOCK: update_status: commit-queue Landed patch
+MOCK: update_status: commit-queue Pass
+MOCK: release_work_item: commit-queue 197
+""",
+ "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '197' with comment 'Rejecting attachment 197 from commit-queue.' and additional comment 'Mock error message'\n",
+ "handle_script_error": "ScriptError error message\n",
+ }
+ self.assert_queue_outputs(CommitQueue(), expected_stderr=expected_stderr)
+
+ def test_commit_queue_failure(self):
+ expected_stderr = {
+ "begin_work_queue": self._default_begin_work_queue_stderr("commit-queue", MockSCM.fake_checkout_root),
+ "should_proceed_with_work_item": "MOCK: update_status: commit-queue Processing patch\n",
+ "next_work_item": "",
+ "process_work_item": """MOCK: update_status: commit-queue Cleaned working directory
+MOCK: update_status: commit-queue Updated working directory
+MOCK: update_status: commit-queue Patch does not apply
+MOCK setting flag 'commit-queue' to '-' on attachment '197' with comment 'Rejecting attachment 197 from commit-queue.' and additional comment 'MOCK script error'
+MOCK: update_status: commit-queue Fail
+MOCK: release_work_item: commit-queue 197
+""",
+ "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '197' with comment 'Rejecting attachment 197 from commit-queue.' and additional comment 'Mock error message'\n",
+ "handle_script_error": "ScriptError error message\n",
+ }
+ queue = CommitQueue()
+
+ def mock_run_webkit_patch(command):
+ if command == ['clean'] or command == ['update']:
+ # We want cleaning to succeed so we can error out on a step
+ # that causes the commit-queue to reject the patch.
+ return
+ raise ScriptError('MOCK script error')
+
+ queue.run_webkit_patch = mock_run_webkit_patch
+ self.assert_queue_outputs(queue, expected_stderr=expected_stderr)
+
+ def test_rollout(self):
+ tool = MockTool(log_executive=True)
+ tool.buildbot.light_tree_on_fire()
+ expected_stderr = {
+ "begin_work_queue": self._default_begin_work_queue_stderr("commit-queue", MockSCM.fake_checkout_root),
+ "should_proceed_with_work_item": "MOCK: update_status: commit-queue Processing patch\n",
+ "next_work_item": "",
+ "process_work_item": """MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'clean']
+MOCK: update_status: commit-queue Cleaned working directory
+MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'update']
+MOCK: update_status: commit-queue Updated working directory
+MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'apply-attachment', '--no-update', '--non-interactive', 197]
+MOCK: update_status: commit-queue Applied patch
+MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'build', '--no-clean', '--no-update', '--build-style=both']
+MOCK: update_status: commit-queue Built patch
+MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'build-and-test', '--no-clean', '--no-update', '--test', '--non-interactive']
+MOCK: update_status: commit-queue Passed tests
+MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'land-attachment', '--force-clean', '--ignore-builders', '--non-interactive', '--parent-command=commit-queue', 197]
+MOCK: update_status: commit-queue Landed patch
+MOCK: update_status: commit-queue Pass
+MOCK: release_work_item: commit-queue 197
+""",
+ "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '197' with comment 'Rejecting attachment 197 from commit-queue.' and additional comment 'Mock error message'\n",
+ "handle_script_error": "ScriptError error message\n",
+ }
+ self.assert_queue_outputs(CommitQueue(), tool=tool, expected_stderr=expected_stderr)
+
+ def test_rollout_lands(self):
+ tool = MockTool(log_executive=True)
+ tool.buildbot.light_tree_on_fire()
+ rollout_patch = tool.bugs.fetch_attachment(106) # _patch6, a rollout patch.
+ assert(rollout_patch.is_rollout())
+ expected_stderr = {
+ "begin_work_queue": self._default_begin_work_queue_stderr("commit-queue", MockSCM.fake_checkout_root),
+ "should_proceed_with_work_item": "MOCK: update_status: commit-queue Processing rollout patch\n",
+ "next_work_item": "",
+ "process_work_item": """MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'clean']
+MOCK: update_status: commit-queue Cleaned working directory
+MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'update']
+MOCK: update_status: commit-queue Updated working directory
+MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'apply-attachment', '--no-update', '--non-interactive', 106]
+MOCK: update_status: commit-queue Applied patch
+MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'build', '--no-clean', '--no-update', '--build-style=both']
+MOCK: update_status: commit-queue Built patch
+MOCK run_and_throw_if_fail: ['echo', '--status-host=example.com', 'land-attachment', '--force-clean', '--ignore-builders', '--non-interactive', '--parent-command=commit-queue', 106]
+MOCK: update_status: commit-queue Landed patch
+MOCK: update_status: commit-queue Pass
+MOCK: release_work_item: commit-queue 106
+""",
+ "handle_unexpected_error": "MOCK setting flag 'commit-queue' to '-' on attachment '106' with comment 'Rejecting attachment 106 from commit-queue.' and additional comment 'Mock error message'\n",
+ "handle_script_error": "ScriptError error message\n",
+ }
+ self.assert_queue_outputs(CommitQueue(), tool=tool, work_item=rollout_patch, expected_stderr=expected_stderr)
+
+ def test_auto_retry(self):
+ queue = CommitQueue()
+ options = Mock()
+ options.parent_command = "commit-queue"
+ tool = AlwaysCommitQueueTool()
+ sequence = NeedsUpdateSequence(None)
+
+ expected_stderr = "Commit failed because the checkout is out of date. Please update and try again.\nMOCK: update_status: commit-queue Tests passed, but commit failed (checkout out of date). Updating, then landing without building or re-running tests.\n"
+ state = {'patch': None}
+ OutputCapture().assert_outputs(self, sequence.run_and_handle_errors, [tool, options, state], expected_exception=TryAgain, expected_stderr=expected_stderr)
+
+ self.assertEquals(options.update, True)
+ self.assertEquals(options.build, False)
+ self.assertEquals(options.test, False)
+
+ def test_manual_reject_during_processing(self):
+ queue = SecondThoughtsCommitQueue()
+ queue.bind_to_tool(MockTool())
+ queue._options = Mock()
+ queue._options.port = None
+ expected_stderr = """MOCK: update_status: commit-queue Cleaned working directory
+MOCK: update_status: commit-queue Updated working directory
+MOCK: update_status: commit-queue Applied patch
+MOCK: update_status: commit-queue Built patch
+MOCK: update_status: commit-queue Passed tests
+MOCK: update_status: commit-queue Retry
+MOCK: release_work_item: commit-queue 197
+"""
+ OutputCapture().assert_outputs(self, queue.process_work_item, [QueuesTest.mock_work_item], expected_stderr=expected_stderr)
+
+ def test_report_flaky_tests(self):
+ queue = CommitQueue()
+ queue.bind_to_tool(MockTool())
+ expected_stderr = """MOCK bug comment: bug_id=76, cc=None
+--- Begin comment ---
+The commit-queue just saw foo/bar.html flake while processing attachment 197 on bug 42.
+Port: MockPort Platform: MockPlatform 1.0
+--- End comment ---
+
+MOCK bug comment: bug_id=76, cc=None
+--- Begin comment ---
+The commit-queue just saw bar/baz.html flake while processing attachment 197 on bug 42.
+Port: MockPort Platform: MockPlatform 1.0
+--- End comment ---
+
+MOCK bug comment: bug_id=42, cc=None
+--- Begin comment ---
+The commit-queue encountered the following flaky tests while processing attachment 197:
+
+foo/bar.html bug 76 (author: abarth@webkit.org)
+bar/baz.html bug 76 (author: abarth@webkit.org)
+The commit-queue is continuing to process your patch.
+--- End comment ---
+
+"""
+ OutputCapture().assert_outputs(self, queue.report_flaky_tests, [QueuesTest.mock_work_item, ["foo/bar.html", "bar/baz.html"]], expected_stderr=expected_stderr)
+
+ def test_layout_test_results(self):
+ queue = CommitQueue()
+ queue.bind_to_tool(MockTool())
+ queue._read_file_contents = lambda path: None
+ self.assertEquals(queue.layout_test_results(), None)
+ queue._read_file_contents = lambda path: ""
+ self.assertEquals(queue.layout_test_results(), None)
+
+
+class StyleQueueTest(QueuesTest):
+ def test_style_queue(self):
+ expected_stderr = {
+ "begin_work_queue": self._default_begin_work_queue_stderr("style-queue", MockSCM.fake_checkout_root),
+ "next_work_item": "",
+ "should_proceed_with_work_item": "MOCK: update_status: style-queue Checking style\n",
+ "process_work_item": "MOCK: update_status: style-queue Pass\nMOCK: release_work_item: style-queue 197\n",
+ "handle_unexpected_error": "Mock error message\n",
+ "handle_script_error": "MOCK: update_status: style-queue ScriptError error message\nMOCK bug comment: bug_id=42, cc=[]\n--- Begin comment ---\nAttachment 197 did not pass style-queue:\n\nScriptError error message\n\nIf any of these errors are false positives, please file a bug against check-webkit-style.\n--- End comment ---\n\n",
+ }
+ expected_exceptions = {
+ "handle_script_error": SystemExit,
+ }
+ self.assert_queue_outputs(StyleQueue(), expected_stderr=expected_stderr, expected_exceptions=expected_exceptions)
diff --git a/Tools/Scripts/webkitpy/tool/commands/queuestest.py b/Tools/Scripts/webkitpy/tool/commands/queuestest.py
new file mode 100644
index 0000000..6455617
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/queuestest.py
@@ -0,0 +1,95 @@
+# 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 unittest
+
+from webkitpy.common.net.bugzilla import Attachment
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.tool.commands.stepsequence import StepSequenceErrorHandler
+from webkitpy.tool.mocktool import MockTool
+
+
+class MockQueueEngine(object):
+ def __init__(self, name, queue, wakeup_event):
+ pass
+
+ def run(self):
+ pass
+
+
+class QueuesTest(unittest.TestCase):
+ # This is _patch1 in mocktool.py
+ mock_work_item = MockTool().bugs.fetch_attachment(197)
+
+ def assert_outputs(self, func, func_name, args, expected_stdout, expected_stderr, expected_exceptions):
+ exception = None
+ if expected_exceptions and func_name in expected_exceptions:
+ exception = expected_exceptions[func_name]
+
+ OutputCapture().assert_outputs(self,
+ func,
+ args=args,
+ expected_stdout=expected_stdout.get(func_name, ""),
+ expected_stderr=expected_stderr.get(func_name, ""),
+ expected_exception=exception)
+
+ def _default_begin_work_queue_stderr(self, name, checkout_dir):
+ string_replacements = {"name": name, 'checkout_dir': checkout_dir}
+ return "CAUTION: %(name)s will discard all local changes in \"%(checkout_dir)s\"\nRunning WebKit %(name)s.\nMOCK: update_status: %(name)s Starting Queue\n" % string_replacements
+
+ def assert_queue_outputs(self, queue, args=None, work_item=None, expected_stdout=None, expected_stderr=None, expected_exceptions=None, options=None, tool=None):
+ if not tool:
+ tool = MockTool()
+ if not expected_stdout:
+ expected_stdout = {}
+ if not expected_stderr:
+ expected_stderr = {}
+ if not args:
+ args = []
+ if not options:
+ options = Mock()
+ options.port = None
+ if not work_item:
+ work_item = self.mock_work_item
+ tool.user.prompt = lambda message: "yes"
+
+ queue.execute(options, args, tool, engine=MockQueueEngine)
+
+ self.assert_outputs(queue.queue_log_path, "queue_log_path", [], expected_stdout, expected_stderr, expected_exceptions)
+ self.assert_outputs(queue.work_item_log_path, "work_item_log_path", [work_item], expected_stdout, expected_stderr, expected_exceptions)
+ self.assert_outputs(queue.begin_work_queue, "begin_work_queue", [], expected_stdout, expected_stderr, expected_exceptions)
+ self.assert_outputs(queue.should_continue_work_queue, "should_continue_work_queue", [], expected_stdout, expected_stderr, expected_exceptions)
+ self.assert_outputs(queue.next_work_item, "next_work_item", [], expected_stdout, expected_stderr, expected_exceptions)
+ self.assert_outputs(queue.should_proceed_with_work_item, "should_proceed_with_work_item", [work_item], expected_stdout, expected_stderr, expected_exceptions)
+ self.assert_outputs(queue.process_work_item, "process_work_item", [work_item], expected_stdout, expected_stderr, expected_exceptions)
+ self.assert_outputs(queue.handle_unexpected_error, "handle_unexpected_error", [work_item, "Mock error message"], expected_stdout, expected_stderr, expected_exceptions)
+ # Should we have a different function for testing StepSequenceErrorHandlers?
+ if isinstance(queue, StepSequenceErrorHandler):
+ self.assert_outputs(queue.handle_script_error, "handle_script_error", [tool, {"patch": self.mock_work_item}, ScriptError(message="ScriptError error message", script_args="MockErrorCommand")], expected_stdout, expected_stderr, expected_exceptions)
diff --git a/Tools/Scripts/webkitpy/tool/commands/rebaseline.py b/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
new file mode 100644
index 0000000..8c4b997
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/rebaseline.py
@@ -0,0 +1,112 @@
+# 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 os.path
+import re
+import shutil
+import urllib
+
+from webkitpy.common.net.buildbot import BuildBot
+from webkitpy.common.net.layouttestresults import LayoutTestResults
+from webkitpy.common.system.user import User
+from webkitpy.layout_tests.port import factory
+from webkitpy.tool.grammar import pluralize
+from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
+
+
+# FIXME: I'm not sure where this logic should go in the end.
+# For now it's here, until we have a second need for it.
+class BuilderToPort(object):
+ _builder_name_to_port_name = {
+ r"SnowLeopard": "mac-snowleopard",
+ r"Leopard": "mac-leopard",
+ r"Tiger": "mac-tiger",
+ r"Windows": "win",
+ r"GTK": "gtk",
+ r"Qt": "qt",
+ r"Chromium Mac": "chromium-mac",
+ r"Chromium Linux": "chromium-linux",
+ r"Chromium Win": "chromium-win",
+ }
+
+ def _port_name_for_builder_name(self, builder_name):
+ for regexp, port_name in self._builder_name_to_port_name.items():
+ if re.match(regexp, builder_name):
+ return port_name
+
+ def port_for_builder(self, builder_name):
+ port_name = self._port_name_for_builder_name(builder_name)
+ assert(port_name) # Need to update _builder_name_to_port_name
+ port = factory.get(port_name)
+ assert(port) # Need to update _builder_name_to_port_name
+ return port
+
+
+class Rebaseline(AbstractDeclarativeCommand):
+ name = "rebaseline"
+ help_text = "Replaces local expected.txt files with new results from build bots"
+
+ # FIXME: This should share more code with FailureReason._builder_to_explain
+ def _builder_to_pull_from(self):
+ builder_statuses = self._tool.buildbot.builder_statuses()
+ red_statuses = [status for status in builder_statuses if not status["is_green"]]
+ print "%s failing" % (pluralize("builder", len(red_statuses)))
+ builder_choices = [status["name"] for status in red_statuses]
+ chosen_name = self._tool.user.prompt_with_list("Which builder to pull results from:", builder_choices)
+ # FIXME: prompt_with_list should really take a set of objects and a set of names and then return the object.
+ for status in red_statuses:
+ if status["name"] == chosen_name:
+ return (self._tool.buildbot.builder_with_name(chosen_name), status["build_number"])
+
+ def _replace_expectation_with_remote_result(self, local_file, remote_file):
+ (downloaded_file, headers) = urllib.urlretrieve(remote_file)
+ shutil.move(downloaded_file, local_file)
+
+ def _tests_to_update(self, build):
+ failing_tests = build.layout_test_results().results_matching_keys([LayoutTestResults.fail_key])
+ return self._tool.user.prompt_with_list("Which test(s) to rebaseline:", failing_tests, can_choose_multiple=True)
+
+ def _results_url_for_test(self, build, test):
+ test_base = os.path.splitext(test)[0]
+ actual_path = test_base + "-actual.txt"
+ return build.results_url() + "/" + actual_path
+
+ def execute(self, options, args, tool):
+ builder, build_number = self._builder_to_pull_from()
+ build = builder.build(build_number)
+ port = BuilderToPort().port_for_builder(builder.name())
+
+ for test in self._tests_to_update(build):
+ results_url = self._results_url_for_test(build, test)
+ # Port operates with absolute paths.
+ absolute_path = os.path.join(port.layout_tests_dir(), test)
+ expected_file = port.expected_filename(absolute_path, ".txt")
+ print test
+ self._replace_expectation_with_remote_result(expected_file, results_url)
+
+ # FIXME: We should handle new results too.
diff --git a/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py b/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
new file mode 100644
index 0000000..d6582a7
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/rebaseline_unittest.py
@@ -0,0 +1,38 @@
+# 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 unittest
+
+from webkitpy.tool.commands.rebaseline import BuilderToPort
+
+
+class BuilderToPortTest(unittest.TestCase):
+ def test_port_for_builder(self):
+ converter = BuilderToPort()
+ port = converter.port_for_builder("Leopard Intel Debug (Tests)")
+ self.assertEqual(port.name(), "mac-leopard")
diff --git a/Tools/Scripts/webkitpy/tool/commands/rebaselineserver.py b/Tools/Scripts/webkitpy/tool/commands/rebaselineserver.py
new file mode 100644
index 0000000..56780b5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/rebaselineserver.py
@@ -0,0 +1,457 @@
+# 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.
+
+"""Starts a local HTTP server which displays layout test failures (given a test
+results directory), provides comparisons of expected and actual results (both
+images and text) and allows one-click rebaselining of tests."""
+from __future__ import with_statement
+
+import codecs
+import datetime
+import fnmatch
+import mimetypes
+import os
+import os.path
+import shutil
+import threading
+import time
+import urlparse
+import BaseHTTPServer
+
+from optparse import make_option
+from wsgiref.handlers import format_date_time
+
+from webkitpy.common import system
+from webkitpy.layout_tests.port import factory
+from webkitpy.layout_tests.port.webkit import WebKitPort
+from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
+from webkitpy.thirdparty import simplejson
+
+STATE_NEEDS_REBASELINE = 'needs_rebaseline'
+STATE_REBASELINE_FAILED = 'rebaseline_failed'
+STATE_REBASELINE_SUCCEEDED = 'rebaseline_succeeded'
+
+class RebaselineHTTPServer(BaseHTTPServer.HTTPServer):
+ def __init__(self, httpd_port, test_config, results_json, platforms_json):
+ BaseHTTPServer.HTTPServer.__init__(self, ("", httpd_port), RebaselineHTTPRequestHandler)
+ self.test_config = test_config
+ self.results_json = results_json
+ self.platforms_json = platforms_json
+
+
+class RebaselineHTTPRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+ STATIC_FILE_NAMES = frozenset([
+ "index.html",
+ "loupe.js",
+ "main.js",
+ "main.css",
+ "queue.js",
+ "util.js",
+ ])
+
+ STATIC_FILE_DIRECTORY = os.path.join(
+ os.path.dirname(__file__), "data", "rebaselineserver")
+
+ def do_GET(self):
+ self._handle_request()
+
+ def do_POST(self):
+ self._handle_request()
+
+ def _handle_request(self):
+ # Parse input.
+ if "?" in self.path:
+ path, query_string = self.path.split("?", 1)
+ self.query = urlparse.parse_qs(query_string)
+ else:
+ path = self.path
+ self.query = {}
+ function_or_file_name = path[1:] or "index.html"
+
+ # See if a static file matches.
+ if function_or_file_name in RebaselineHTTPRequestHandler.STATIC_FILE_NAMES:
+ self._serve_static_file(function_or_file_name)
+ return
+
+ # See if a class method matches.
+ function_name = function_or_file_name.replace(".", "_")
+ if not hasattr(self, function_name):
+ self.send_error(404, "Unknown function %s" % function_name)
+ return
+ if function_name[0] == "_":
+ self.send_error(
+ 401, "Not allowed to invoke private or protected methods")
+ return
+ function = getattr(self, function_name)
+ function()
+
+ def _serve_static_file(self, static_path):
+ self._serve_file(os.path.join(
+ RebaselineHTTPRequestHandler.STATIC_FILE_DIRECTORY, static_path))
+
+ def rebaseline(self):
+ test = self.query['test'][0]
+ baseline_target = self.query['baseline-target'][0]
+ baseline_move_to = self.query['baseline-move-to'][0]
+ test_json = self.server.results_json['tests'][test]
+
+ if test_json['state'] != STATE_NEEDS_REBASELINE:
+ self.send_error(400, "Test %s is in unexpected state: %s" %
+ (test, test_json["state"]))
+ return
+
+ log = []
+ success = _rebaseline_test(
+ test,
+ baseline_target,
+ baseline_move_to,
+ self.server.test_config,
+ log=lambda l: log.append(l))
+
+ if success:
+ test_json['state'] = STATE_REBASELINE_SUCCEEDED
+ self.send_response(200)
+ else:
+ test_json['state'] = STATE_REBASELINE_FAILED
+ self.send_response(500)
+
+ self.send_header('Content-type', 'text/plain')
+ self.end_headers()
+ self.wfile.write('\n'.join(log))
+
+ def quitquitquit(self):
+ self.send_response(200)
+ self.send_header("Content-type", "text/plain")
+ self.end_headers()
+ self.wfile.write("Quit.\n")
+
+ # Shutdown has to happen on another thread from the server's thread,
+ # otherwise there's a deadlock
+ threading.Thread(target=lambda: self.server.shutdown()).start()
+
+ def test_result(self):
+ test_name, _ = os.path.splitext(self.query['test'][0])
+ mode = self.query['mode'][0]
+ if mode == 'expected-image':
+ file_name = test_name + '-expected.png'
+ elif mode == 'actual-image':
+ file_name = test_name + '-actual.png'
+ if mode == 'expected-checksum':
+ file_name = test_name + '-expected.checksum'
+ elif mode == 'actual-checksum':
+ file_name = test_name + '-actual.checksum'
+ elif mode == 'diff-image':
+ file_name = test_name + '-diff.png'
+ if mode == 'expected-text':
+ file_name = test_name + '-expected.txt'
+ elif mode == 'actual-text':
+ file_name = test_name + '-actual.txt'
+ elif mode == 'diff-text':
+ file_name = test_name + '-diff.txt'
+ elif mode == 'diff-text-pretty':
+ file_name = test_name + '-pretty-diff.html'
+
+ file_path = os.path.join(self.server.test_config.results_directory, file_name)
+
+ # Let results be cached for 60 seconds, so that they can be pre-fetched
+ # by the UI
+ self._serve_file(file_path, cacheable_seconds=60)
+
+ def results_json(self):
+ self._serve_json(self.server.results_json)
+
+ def platforms_json(self):
+ self._serve_json(self.server.platforms_json)
+
+ def _serve_json(self, json):
+ self.send_response(200)
+ self.send_header('Content-type', 'application/json')
+ self.end_headers()
+ simplejson.dump(json, self.wfile)
+
+ def _serve_file(self, file_path, cacheable_seconds=0):
+ if not os.path.exists(file_path):
+ self.send_error(404, "File not found")
+ return
+ with codecs.open(file_path, "rb") as static_file:
+ self.send_response(200)
+ self.send_header("Content-Length", os.path.getsize(file_path))
+ mime_type, encoding = mimetypes.guess_type(file_path)
+ if mime_type:
+ self.send_header("Content-type", mime_type)
+
+ if cacheable_seconds:
+ expires_time = (datetime.datetime.now() +
+ datetime.timedelta(0, cacheable_seconds))
+ expires_formatted = format_date_time(
+ time.mktime(expires_time.timetuple()))
+ self.send_header("Expires", expires_formatted)
+ self.end_headers()
+
+ shutil.copyfileobj(static_file, self.wfile)
+
+
+class TestConfig(object):
+ def __init__(self, test_port, layout_tests_directory, results_directory, platforms, filesystem, scm):
+ self.test_port = test_port
+ self.layout_tests_directory = layout_tests_directory
+ self.results_directory = results_directory
+ self.platforms = platforms
+ self.filesystem = filesystem
+ self.scm = scm
+
+
+def _get_actual_result_files(test_file, test_config):
+ test_name, _ = os.path.splitext(test_file)
+ test_directory = os.path.dirname(test_file)
+
+ test_results_directory = test_config.filesystem.join(
+ test_config.results_directory, test_directory)
+ actual_pattern = os.path.basename(test_name) + '-actual.*'
+ actual_files = []
+ for filename in test_config.filesystem.listdir(test_results_directory):
+ if fnmatch.fnmatch(filename, actual_pattern):
+ actual_files.append(filename)
+ actual_files.sort()
+ return tuple(actual_files)
+
+
+def _rebaseline_test(test_file, baseline_target, baseline_move_to, test_config, log):
+ test_name, _ = os.path.splitext(test_file)
+ test_directory = os.path.dirname(test_name)
+
+ log('Rebaselining %s...' % test_name)
+
+ actual_result_files = _get_actual_result_files(test_file, test_config)
+ filesystem = test_config.filesystem
+ scm = test_config.scm
+ layout_tests_directory = test_config.layout_tests_directory
+ results_directory = test_config.results_directory
+ target_expectations_directory = filesystem.join(
+ layout_tests_directory, 'platform', baseline_target, test_directory)
+ test_results_directory = test_config.filesystem.join(
+ test_config.results_directory, test_directory)
+
+ # If requested, move current baselines out
+ current_baselines = _get_test_baselines(test_file, test_config)
+ if baseline_target in current_baselines and baseline_move_to != 'none':
+ log(' Moving current %s baselines to %s' %
+ (baseline_target, baseline_move_to))
+
+ # See which ones we need to move (only those that are about to be
+ # updated), and make sure we're not clobbering any files in the
+ # destination.
+ current_extensions = set(current_baselines[baseline_target].keys())
+ actual_result_extensions = [
+ os.path.splitext(f)[1] for f in actual_result_files]
+ extensions_to_move = current_extensions.intersection(
+ actual_result_extensions)
+
+ if extensions_to_move.intersection(
+ current_baselines.get(baseline_move_to, {}).keys()):
+ log(' Already had baselines in %s, could not move existing '
+ '%s ones' % (baseline_move_to, baseline_target))
+ return False
+
+ # Do the actual move.
+ if extensions_to_move:
+ if not _move_test_baselines(
+ test_file,
+ list(extensions_to_move),
+ baseline_target,
+ baseline_move_to,
+ test_config,
+ log):
+ return False
+ else:
+ log(' No current baselines to move')
+
+ log(' Updating baselines for %s' % baseline_target)
+ filesystem.maybe_make_directory(target_expectations_directory)
+ for source_file in actual_result_files:
+ source_path = filesystem.join(test_results_directory, source_file)
+ destination_file = source_file.replace('-actual', '-expected')
+ destination_path = filesystem.join(
+ target_expectations_directory, destination_file)
+ filesystem.copyfile(source_path, destination_path)
+ exit_code = scm.add(destination_path, return_exit_code=True)
+ if exit_code:
+ log(' Could not update %s in SCM, exit code %d' %
+ (destination_file, exit_code))
+ return False
+ else:
+ log(' Updated %s' % destination_file)
+
+ return True
+
+
+def _move_test_baselines(test_file, extensions_to_move, source_platform, destination_platform, test_config, log):
+ test_file_name = os.path.splitext(os.path.basename(test_file))[0]
+ test_directory = os.path.dirname(test_file)
+ filesystem = test_config.filesystem
+
+ # Want predictable output order for unit tests.
+ extensions_to_move.sort()
+
+ source_directory = os.path.join(
+ test_config.layout_tests_directory,
+ 'platform',
+ source_platform,
+ test_directory)
+ destination_directory = os.path.join(
+ test_config.layout_tests_directory,
+ 'platform',
+ destination_platform,
+ test_directory)
+ filesystem.maybe_make_directory(destination_directory)
+
+ for extension in extensions_to_move:
+ file_name = test_file_name + '-expected' + extension
+ source_path = filesystem.join(source_directory, file_name)
+ destination_path = filesystem.join(destination_directory, file_name)
+ filesystem.copyfile(source_path, destination_path)
+ exit_code = test_config.scm.add(destination_path, return_exit_code=True)
+ if exit_code:
+ log(' Could not update %s in SCM, exit code %d' %
+ (file_name, exit_code))
+ return False
+ else:
+ log(' Moved %s' % file_name)
+
+ return True
+
+def _get_test_baselines(test_file, test_config):
+ class AllPlatformsPort(WebKitPort):
+ def __init__(self):
+ WebKitPort.__init__(self, filesystem=test_config.filesystem)
+ self._platforms_by_directory = dict(
+ [(self._webkit_baseline_path(p), p) for p in test_config.platforms])
+
+ def baseline_search_path(self):
+ return self._platforms_by_directory.keys()
+
+ def platform_from_directory(self, directory):
+ return self._platforms_by_directory[directory]
+
+ test_path = test_config.filesystem.join(
+ test_config.layout_tests_directory, test_file)
+
+ all_platforms_port = AllPlatformsPort()
+
+ all_test_baselines = {}
+ for baseline_extension in ('.txt', '.checksum', '.png'):
+ test_baselines = test_config.test_port.expected_baselines(
+ test_path, baseline_extension)
+ baselines = all_platforms_port.expected_baselines(
+ test_path, baseline_extension, all_baselines=True)
+ for platform_directory, expected_filename in baselines:
+ if not platform_directory:
+ continue
+ if platform_directory == test_config.layout_tests_directory:
+ platform = 'base'
+ else:
+ platform = all_platforms_port.platform_from_directory(
+ platform_directory)
+ platform_baselines = all_test_baselines.setdefault(platform, {})
+ was_used_for_test = (
+ platform_directory, expected_filename) in test_baselines
+ platform_baselines[baseline_extension] = was_used_for_test
+
+ return all_test_baselines
+
+
+class RebaselineServer(AbstractDeclarativeCommand):
+ name = "rebaseline-server"
+ help_text = __doc__
+ argument_names = "/path/to/results/directory"
+
+ def __init__(self):
+ options = [
+ make_option("--httpd-port", action="store", type="int", default=8127, help="Port to use for the the rebaseline HTTP server"),
+ ]
+ AbstractDeclarativeCommand.__init__(self, options=options)
+
+ def execute(self, options, args, tool):
+ results_directory = args[0]
+ filesystem = system.filesystem.FileSystem()
+ scm = self._tool.scm()
+
+ if options.dry_run:
+
+ def no_op_copyfile(src, dest):
+ pass
+
+ def no_op_add(path, return_exit_code=False):
+ if return_exit_code:
+ return 0
+
+ filesystem.copyfile = no_op_copyfile
+ scm.add = no_op_add
+
+ print 'Parsing unexpected_results.json...'
+ results_json_path = filesystem.join(
+ results_directory, 'unexpected_results.json')
+ with codecs.open(results_json_path, "r") as results_json_file:
+ results_json_file = file(results_json_path)
+ results_json = simplejson.load(results_json_file)
+
+ port = factory.get()
+ layout_tests_directory = port.layout_tests_dir()
+ platforms = filesystem.listdir(
+ filesystem.join(layout_tests_directory, 'platform'))
+ test_config = TestConfig(
+ port,
+ layout_tests_directory,
+ results_directory,
+ platforms,
+ filesystem,
+ scm)
+
+ print 'Gathering current baselines...'
+ for test_file, test_json in results_json['tests'].items():
+ test_json['state'] = STATE_NEEDS_REBASELINE
+ test_path = filesystem.join(layout_tests_directory, test_file)
+ test_json['baselines'] = _get_test_baselines(test_file, test_config)
+
+ server_url = "http://localhost:%d/" % options.httpd_port
+ print "Starting server at %s" % server_url
+ print ("Use the 'Exit' link in the UI, %squitquitquit "
+ "or Ctrl-C to stop") % server_url
+
+ threading.Timer(
+ .1, lambda: self._tool.user.open_url(server_url)).start()
+
+ httpd = RebaselineHTTPServer(
+ httpd_port=options.httpd_port,
+ test_config=test_config,
+ results_json=results_json,
+ platforms_json={
+ 'platforms': platforms,
+ 'defaultPlatform': port.name(),
+ })
+ httpd.serve_forever()
diff --git a/Tools/Scripts/webkitpy/tool/commands/rebaselineserver_unittest.py b/Tools/Scripts/webkitpy/tool/commands/rebaselineserver_unittest.py
new file mode 100644
index 0000000..f4371f4
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/rebaselineserver_unittest.py
@@ -0,0 +1,304 @@
+# 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 unittest
+
+from webkitpy.common.system import filesystem_mock
+from webkitpy.layout_tests.port import base
+from webkitpy.layout_tests.port.webkit import WebKitPort
+from webkitpy.tool.commands import rebaselineserver
+from webkitpy.tool.mocktool import MockSCM
+
+
+class RebaselineTestTest(unittest.TestCase):
+ def test_text_rebaseline_update(self):
+ self._assertRebaseline(
+ test_files=(
+ 'fast/text-expected.txt',
+ 'platform/mac/fast/text-expected.txt',
+ ),
+ results_files=(
+ 'fast/text-actual.txt',
+ ),
+ test_name='fast/text.html',
+ baseline_target='mac',
+ baseline_move_to='none',
+ expected_success=True,
+ expected_log=[
+ 'Rebaselining fast/text...',
+ ' Updating baselines for mac',
+ ' Updated text-expected.txt',
+ ])
+
+ def test_text_rebaseline_new(self):
+ self._assertRebaseline(
+ test_files=(
+ 'fast/text-expected.txt',
+ ),
+ results_files=(
+ 'fast/text-actual.txt',
+ ),
+ test_name='fast/text.html',
+ baseline_target='mac',
+ baseline_move_to='none',
+ expected_success=True,
+ expected_log=[
+ 'Rebaselining fast/text...',
+ ' Updating baselines for mac',
+ ' Updated text-expected.txt',
+ ])
+
+ def test_text_rebaseline_move_no_op_1(self):
+ self._assertRebaseline(
+ test_files=(
+ 'fast/text-expected.txt',
+ 'platform/win/fast/text-expected.txt',
+ ),
+ results_files=(
+ 'fast/text-actual.txt',
+ ),
+ test_name='fast/text.html',
+ baseline_target='mac',
+ baseline_move_to='mac-leopard',
+ expected_success=True,
+ expected_log=[
+ 'Rebaselining fast/text...',
+ ' Updating baselines for mac',
+ ' Updated text-expected.txt',
+ ])
+
+ def test_text_rebaseline_move_no_op_2(self):
+ self._assertRebaseline(
+ test_files=(
+ 'fast/text-expected.txt',
+ 'platform/mac/fast/text-expected.checksum',
+ ),
+ results_files=(
+ 'fast/text-actual.txt',
+ ),
+ test_name='fast/text.html',
+ baseline_target='mac',
+ baseline_move_to='mac-leopard',
+ expected_success=True,
+ expected_log=[
+ 'Rebaselining fast/text...',
+ ' Moving current mac baselines to mac-leopard',
+ ' No current baselines to move',
+ ' Updating baselines for mac',
+ ' Updated text-expected.txt',
+ ])
+
+ def test_text_rebaseline_move(self):
+ self._assertRebaseline(
+ test_files=(
+ 'fast/text-expected.txt',
+ 'platform/mac/fast/text-expected.txt',
+ ),
+ results_files=(
+ 'fast/text-actual.txt',
+ ),
+ test_name='fast/text.html',
+ baseline_target='mac',
+ baseline_move_to='mac-leopard',
+ expected_success=True,
+ expected_log=[
+ 'Rebaselining fast/text...',
+ ' Moving current mac baselines to mac-leopard',
+ ' Moved text-expected.txt',
+ ' Updating baselines for mac',
+ ' Updated text-expected.txt',
+ ])
+
+ def test_text_rebaseline_move_only_images(self):
+ self._assertRebaseline(
+ test_files=(
+ 'fast/image-expected.txt',
+ 'platform/mac/fast/image-expected.txt',
+ 'platform/mac/fast/image-expected.png',
+ 'platform/mac/fast/image-expected.checksum',
+ ),
+ results_files=(
+ 'fast/image-actual.png',
+ 'fast/image-actual.checksum',
+ ),
+ test_name='fast/image.html',
+ baseline_target='mac',
+ baseline_move_to='mac-leopard',
+ expected_success=True,
+ expected_log=[
+ 'Rebaselining fast/image...',
+ ' Moving current mac baselines to mac-leopard',
+ ' Moved image-expected.checksum',
+ ' Moved image-expected.png',
+ ' Updating baselines for mac',
+ ' Updated image-expected.checksum',
+ ' Updated image-expected.png',
+ ])
+
+ def test_text_rebaseline_move_already_exist(self):
+ self._assertRebaseline(
+ test_files=(
+ 'fast/text-expected.txt',
+ 'platform/mac-leopard/fast/text-expected.txt',
+ 'platform/mac/fast/text-expected.txt',
+ ),
+ results_files=(
+ 'fast/text-actual.txt',
+ ),
+ test_name='fast/text.html',
+ baseline_target='mac',
+ baseline_move_to='mac-leopard',
+ expected_success=False,
+ expected_log=[
+ 'Rebaselining fast/text...',
+ ' Moving current mac baselines to mac-leopard',
+ ' Already had baselines in mac-leopard, could not move existing mac ones',
+ ])
+
+ def test_image_rebaseline(self):
+ self._assertRebaseline(
+ test_files=(
+ 'fast/image-expected.txt',
+ 'platform/mac/fast/image-expected.png',
+ 'platform/mac/fast/image-expected.checksum',
+ ),
+ results_files=(
+ 'fast/image-actual.png',
+ 'fast/image-actual.checksum',
+ ),
+ test_name='fast/image.html',
+ baseline_target='mac',
+ baseline_move_to='none',
+ expected_success=True,
+ expected_log=[
+ 'Rebaselining fast/image...',
+ ' Updating baselines for mac',
+ ' Updated image-expected.checksum',
+ ' Updated image-expected.png',
+ ])
+
+ def _assertRebaseline(self, test_files, results_files, test_name, baseline_target, baseline_move_to, expected_success, expected_log):
+ log = []
+ test_config = get_test_config(test_files, results_files)
+ success = rebaselineserver._rebaseline_test(
+ test_name,
+ baseline_target,
+ baseline_move_to,
+ test_config,
+ log=lambda l: log.append(l))
+ self.assertEqual(expected_log, log)
+ self.assertEqual(expected_success, success)
+
+
+class GetActualResultFilesTest(unittest.TestCase):
+ def test(self):
+ test_config = get_test_config(result_files=(
+ 'fast/text-actual.txt',
+ 'fast2/text-actual.txt',
+ 'fast/text2-actual.txt',
+ 'fast/text-notactual.txt',
+ ))
+ self.assertEqual(
+ ('text-actual.txt',),
+ rebaselineserver._get_actual_result_files(
+ 'fast/text.html', test_config))
+
+
+class GetBaselinesTest(unittest.TestCase):
+ def test_no_baselines(self):
+ self._assertBaselines(
+ test_files=(),
+ test_name='fast/missing.html',
+ expected_baselines={})
+
+ def test_text_baselines(self):
+ self._assertBaselines(
+ test_files=(
+ 'fast/text-expected.txt',
+ 'platform/mac/fast/text-expected.txt',
+ ),
+ test_name='fast/text.html',
+ expected_baselines={
+ 'mac': {'.txt': True},
+ 'base': {'.txt': False},
+ })
+
+ def test_image_and_text_baselines(self):
+ self._assertBaselines(
+ test_files=(
+ 'fast/image-expected.txt',
+ 'platform/mac/fast/image-expected.png',
+ 'platform/mac/fast/image-expected.checksum',
+ 'platform/win/fast/image-expected.png',
+ 'platform/win/fast/image-expected.checksum',
+ ),
+ test_name='fast/image.html',
+ expected_baselines={
+ 'base': {'.txt': True},
+ 'mac': {'.checksum': True, '.png': True},
+ 'win': {'.checksum': False, '.png': False},
+ })
+
+ def test_extra_baselines(self):
+ self._assertBaselines(
+ test_files=(
+ 'fast/text-expected.txt',
+ 'platform/nosuchplatform/fast/text-expected.txt',
+ ),
+ test_name='fast/text.html',
+ expected_baselines={'base': {'.txt': True}})
+
+ def _assertBaselines(self, test_files, test_name, expected_baselines):
+ actual_baselines = rebaselineserver._get_test_baselines(
+ test_name, get_test_config(test_files))
+ self.assertEqual(expected_baselines, actual_baselines)
+
+
+def get_test_config(test_files=[], result_files=[]):
+ layout_tests_directory = base.Port().layout_tests_dir()
+ results_directory = '/WebKitBuild/Debug/layout-test-results'
+ mock_filesystem = filesystem_mock.MockFileSystem()
+ for file in test_files:
+ file_path = mock_filesystem.join(layout_tests_directory, file)
+ mock_filesystem.files[file_path] = ''
+ for file in result_files:
+ file_path = mock_filesystem.join(results_directory, file)
+ mock_filesystem.files[file_path] = ''
+
+ class TestMacPort(WebKitPort):
+ def __init__(self):
+ WebKitPort.__init__(self, filesystem=mock_filesystem)
+ self._name = 'mac'
+
+ return rebaselineserver.TestConfig(
+ TestMacPort(),
+ layout_tests_directory,
+ results_directory,
+ ('mac', 'mac-leopard', 'win', 'linux'),
+ mock_filesystem,
+ MockSCM())
diff --git a/Tools/Scripts/webkitpy/tool/commands/sheriffbot.py b/Tools/Scripts/webkitpy/tool/commands/sheriffbot.py
new file mode 100644
index 0000000..145f485
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/sheriffbot.py
@@ -0,0 +1,106 @@
+# 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 os
+
+from webkitpy.common.system.deprecated_logging import log
+from webkitpy.common.config.ports import WebKitPort
+from webkitpy.tool.bot.sheriff import Sheriff
+from webkitpy.tool.bot.sheriffircbot import SheriffIRCBot
+from webkitpy.tool.commands.queues import AbstractQueue
+from webkitpy.tool.commands.stepsequence import StepSequenceErrorHandler
+
+
+class SheriffBot(AbstractQueue, StepSequenceErrorHandler):
+ name = "sheriff-bot"
+ watchers = AbstractQueue.watchers + [
+ "abarth@webkit.org",
+ "eric@webkit.org",
+ ]
+
+ def _update(self):
+ self.run_webkit_patch(["update", "--force-clean", "--quiet"])
+
+ # AbstractQueue methods
+
+ def begin_work_queue(self):
+ AbstractQueue.begin_work_queue(self)
+ self._sheriff = Sheriff(self._tool, self)
+ self._irc_bot = SheriffIRCBot(self._tool, self._sheriff)
+ self._tool.ensure_irc_connected(self._irc_bot.irc_delegate())
+
+ def work_item_log_path(self, failure_map):
+ return None
+
+ def _is_old_failure(self, revision):
+ return self._tool.status_server.svn_revision(revision)
+
+ def next_work_item(self):
+ self._irc_bot.process_pending_messages()
+ self._update()
+
+ # FIXME: We need to figure out how to provoke_flaky_builders.
+
+ failure_map = self._tool.buildbot.failure_map()
+ failure_map.filter_out_old_failures(self._is_old_failure)
+ if failure_map.is_empty():
+ return None
+ return failure_map
+
+ def should_proceed_with_work_item(self, failure_map):
+ # Currently, we don't have any reasons not to proceed with work items.
+ return True
+
+ def process_work_item(self, failure_map):
+ failing_revisions = failure_map.failing_revisions()
+ for revision in failing_revisions:
+ builders = failure_map.builders_failing_for(revision)
+ tests = failure_map.tests_failing_for(revision)
+ try:
+ commit_info = self._tool.checkout().commit_info_for_revision(revision)
+ if not commit_info:
+ print "FAILED to fetch CommitInfo for r%s, likely missing ChangeLog" % revision
+ continue
+ self._sheriff.post_irc_warning(commit_info, builders)
+ self._sheriff.post_blame_comment_on_bug(commit_info, builders, tests)
+
+ finally:
+ for builder in builders:
+ self._tool.status_server.update_svn_revision(revision, builder.name())
+ return True
+
+ def handle_unexpected_error(self, failure_map, message):
+ log(message)
+
+ # StepSequenceErrorHandler methods
+
+ @classmethod
+ def handle_script_error(cls, tool, state, script_error):
+ # Ideally we would post some information to IRC about what went wrong
+ # here, but we don't have the IRC password in the child process.
+ pass
diff --git a/Tools/Scripts/webkitpy/tool/commands/sheriffbot_unittest.py b/Tools/Scripts/webkitpy/tool/commands/sheriffbot_unittest.py
new file mode 100644
index 0000000..4db463e
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/sheriffbot_unittest.py
@@ -0,0 +1,57 @@
+# 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 os
+
+from webkitpy.tool.commands.queuestest import QueuesTest
+from webkitpy.tool.commands.sheriffbot import SheriffBot
+from webkitpy.tool.mocktool import *
+
+
+class SheriffBotTest(QueuesTest):
+ builder1 = MockBuilder("Builder1")
+ builder2 = MockBuilder("Builder2")
+
+ def test_sheriff_bot(self):
+ tool = MockTool()
+ mock_work_item = MockFailureMap(tool.buildbot)
+ expected_stderr = {
+ "begin_work_queue": self._default_begin_work_queue_stderr("sheriff-bot", tool.scm().checkout_root),
+ "next_work_item": "",
+ "process_work_item": """MOCK: irc.post: abarth, darin, eseidel: http://trac.webkit.org/changeset/29837 might have broken Builder1
+MOCK bug comment: bug_id=42, cc=['abarth@webkit.org', 'eric@webkit.org']
+--- Begin comment ---
+http://trac.webkit.org/changeset/29837 might have broken Builder1
+The following tests are not passing:
+mock-test-1
+--- End comment ---
+
+""",
+ "handle_unexpected_error": "Mock error message\n"
+ }
+ self.assert_queue_outputs(SheriffBot(), work_item=mock_work_item, expected_stderr=expected_stderr)
diff --git a/Tools/Scripts/webkitpy/tool/commands/stepsequence.py b/Tools/Scripts/webkitpy/tool/commands/stepsequence.py
new file mode 100644
index 0000000..be2ed4c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/stepsequence.py
@@ -0,0 +1,83 @@
+# 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 webkitpy.tool.steps as steps
+
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.common.checkout.scm import CheckoutNeedsUpdate
+from webkitpy.tool.bot.queueengine import QueueEngine
+from webkitpy.common.system.deprecated_logging import log
+
+
+class StepSequenceErrorHandler():
+ @classmethod
+ def handle_script_error(cls, tool, patch, script_error):
+ raise NotImplementedError, "subclasses must implement"
+
+ @classmethod
+ def handle_checkout_needs_update(cls, tool, state, options, error):
+ raise NotImplementedError, "subclasses must implement"
+
+
+class StepSequence(object):
+ def __init__(self, steps):
+ self._steps = steps or []
+
+ def options(self):
+ collected_options = [
+ steps.Options.parent_command,
+ steps.Options.quiet,
+ ]
+ for step in self._steps:
+ collected_options = collected_options + step.options()
+ # Remove duplicates.
+ collected_options = sorted(set(collected_options))
+ return collected_options
+
+ def _run(self, tool, options, state):
+ for step in self._steps:
+ step(tool, options).run(state)
+
+ def run_and_handle_errors(self, tool, options, state=None):
+ if not state:
+ state = {}
+ try:
+ self._run(tool, options, state)
+ except CheckoutNeedsUpdate, e:
+ log("Commit failed because the checkout is out of date. Please update and try again.")
+ if options.parent_command:
+ command = tool.command_by_name(options.parent_command)
+ command.handle_checkout_needs_update(tool, state, options, e)
+ QueueEngine.exit_after_handled_error(e)
+ except ScriptError, e:
+ if not options.quiet:
+ log(e.message_with_output())
+ if options.parent_command:
+ command = tool.command_by_name(options.parent_command)
+ command.handle_script_error(tool, state, e)
+ QueueEngine.exit_after_handled_error(e)
diff --git a/Tools/Scripts/webkitpy/tool/commands/upload.py b/Tools/Scripts/webkitpy/tool/commands/upload.py
new file mode 100644
index 0000000..e12c8e2
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/upload.py
@@ -0,0 +1,483 @@
+#!/usr/bin/env python
+# Copyright (c) 2009, 2010 Google Inc. All rights reserved.
+# 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:
+#
+# * 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 os
+import re
+import sys
+
+from optparse import make_option
+
+import webkitpy.tool.steps as steps
+
+from webkitpy.common.config.committers import CommitterList
+from webkitpy.common.net.bugzilla import parse_bug_id
+from webkitpy.common.system.user import User
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.tool.commands.abstractsequencedcommand import AbstractSequencedCommand
+from webkitpy.tool.grammar import pluralize, join_with_separators
+from webkitpy.tool.comments import bug_comment_from_svn_revision
+from webkitpy.tool.multicommandtool import AbstractDeclarativeCommand
+from webkitpy.common.system.deprecated_logging import error, log
+
+
+class CommitMessageForCurrentDiff(AbstractDeclarativeCommand):
+ name = "commit-message"
+ help_text = "Print a commit message suitable for the uncommitted changes"
+
+ def __init__(self):
+ options = [
+ steps.Options.git_commit,
+ ]
+ AbstractDeclarativeCommand.__init__(self, options=options)
+
+ def execute(self, options, args, tool):
+ # This command is a useful test to make sure commit_message_for_this_commit
+ # always returns the right value regardless of the current working directory.
+ print "%s" % tool.checkout().commit_message_for_this_commit(options.git_commit).message()
+
+
+class CleanPendingCommit(AbstractDeclarativeCommand):
+ name = "clean-pending-commit"
+ help_text = "Clear r+ on obsolete patches so they do not appear in the pending-commit list."
+
+ # NOTE: This was designed to be generic, but right now we're only processing patches from the pending-commit list, so only r+ matters.
+ def _flags_to_clear_on_patch(self, patch):
+ if not patch.is_obsolete():
+ return None
+ what_was_cleared = []
+ if patch.review() == "+":
+ if patch.reviewer():
+ what_was_cleared.append("%s's review+" % patch.reviewer().full_name)
+ else:
+ what_was_cleared.append("review+")
+ return join_with_separators(what_was_cleared)
+
+ def execute(self, options, args, tool):
+ committers = CommitterList()
+ for bug_id in tool.bugs.queries.fetch_bug_ids_from_pending_commit_list():
+ bug = self._tool.bugs.fetch_bug(bug_id)
+ patches = bug.patches(include_obsolete=True)
+ for patch in patches:
+ flags_to_clear = self._flags_to_clear_on_patch(patch)
+ if not flags_to_clear:
+ continue
+ message = "Cleared %s from obsolete attachment %s so that this bug does not appear in http://webkit.org/pending-commit." % (flags_to_clear, patch.id())
+ self._tool.bugs.obsolete_attachment(patch.id(), message)
+
+
+# FIXME: This should be share more logic with AssignToCommitter and CleanPendingCommit
+class CleanReviewQueue(AbstractDeclarativeCommand):
+ name = "clean-review-queue"
+ help_text = "Clear r? on obsolete patches so they do not appear in the pending-commit list."
+
+ def execute(self, options, args, tool):
+ queue_url = "http://webkit.org/pending-review"
+ # We do this inefficient dance to be more like webkit.org/pending-review
+ # bugs.queries.fetch_bug_ids_from_review_queue() doesn't return
+ # closed bugs, but folks using /pending-review will see them. :(
+ for patch_id in tool.bugs.queries.fetch_attachment_ids_from_review_queue():
+ patch = self._tool.bugs.fetch_attachment(patch_id)
+ if not patch.review() == "?":
+ continue
+ attachment_obsolete_modifier = ""
+ if patch.is_obsolete():
+ attachment_obsolete_modifier = "obsolete "
+ elif patch.bug().is_closed():
+ bug_closed_explanation = " If you would like this patch reviewed, please attach it to a new bug (or re-open this bug before marking it for review again)."
+ else:
+ # Neither the patch was obsolete or the bug was closed, next patch...
+ continue
+ message = "Cleared review? from %sattachment %s so that this bug does not appear in %s.%s" % (attachment_obsolete_modifier, patch.id(), queue_url, bug_closed_explanation)
+ self._tool.bugs.obsolete_attachment(patch.id(), message)
+
+
+class AssignToCommitter(AbstractDeclarativeCommand):
+ name = "assign-to-committer"
+ help_text = "Assign bug to whoever attached the most recent r+'d patch"
+
+ def _patches_have_commiters(self, reviewed_patches):
+ for patch in reviewed_patches:
+ if not patch.committer():
+ return False
+ return True
+
+ def _assign_bug_to_last_patch_attacher(self, bug_id):
+ committers = CommitterList()
+ bug = self._tool.bugs.fetch_bug(bug_id)
+ if not bug.is_unassigned():
+ assigned_to_email = bug.assigned_to_email()
+ log("Bug %s is already assigned to %s (%s)." % (bug_id, assigned_to_email, committers.committer_by_email(assigned_to_email)))
+ return
+
+ reviewed_patches = bug.reviewed_patches()
+ if not reviewed_patches:
+ log("Bug %s has no non-obsolete patches, ignoring." % bug_id)
+ return
+
+ # We only need to do anything with this bug if one of the r+'d patches does not have a valid committer (cq+ set).
+ if self._patches_have_commiters(reviewed_patches):
+ log("All reviewed patches on bug %s already have commit-queue+, ignoring." % bug_id)
+ return
+
+ latest_patch = reviewed_patches[-1]
+ attacher_email = latest_patch.attacher_email()
+ committer = committers.committer_by_email(attacher_email)
+ if not committer:
+ log("Attacher %s is not a committer. Bug %s likely needs commit-queue+." % (attacher_email, bug_id))
+ return
+
+ reassign_message = "Attachment %s was posted by a committer and has review+, assigning to %s for commit." % (latest_patch.id(), committer.full_name)
+ self._tool.bugs.reassign_bug(bug_id, committer.bugzilla_email(), reassign_message)
+
+ def execute(self, options, args, tool):
+ for bug_id in tool.bugs.queries.fetch_bug_ids_from_pending_commit_list():
+ self._assign_bug_to_last_patch_attacher(bug_id)
+
+
+class ObsoleteAttachments(AbstractSequencedCommand):
+ name = "obsolete-attachments"
+ help_text = "Mark all attachments on a bug as obsolete"
+ argument_names = "BUGID"
+ steps = [
+ steps.ObsoletePatches,
+ ]
+
+ def _prepare_state(self, options, args, tool):
+ return { "bug_id" : args[0] }
+
+
+class AbstractPatchUploadingCommand(AbstractSequencedCommand):
+ def _bug_id(self, options, args, tool, state):
+ # Perfer a bug id passed as an argument over a bug url in the diff (i.e. ChangeLogs).
+ bug_id = args and args[0]
+ if not bug_id:
+ changed_files = self._tool.scm().changed_files(options.git_commit)
+ state["changed_files"] = changed_files
+ bug_id = tool.checkout().bug_id_for_this_commit(options.git_commit, changed_files)
+ return bug_id
+
+ def _prepare_state(self, options, args, tool):
+ state = {}
+ state["bug_id"] = self._bug_id(options, args, tool, state)
+ if not state["bug_id"]:
+ error("No bug id passed and no bug url found in ChangeLogs.")
+ return state
+
+
+class Post(AbstractPatchUploadingCommand):
+ name = "post"
+ help_text = "Attach the current working directory diff to a bug as a patch file"
+ argument_names = "[BUGID]"
+ steps = [
+ steps.CheckStyle,
+ steps.ConfirmDiff,
+ steps.ObsoletePatches,
+ steps.SuggestReviewers,
+ steps.PostDiff,
+ ]
+
+
+class LandSafely(AbstractPatchUploadingCommand):
+ name = "land-safely"
+ help_text = "Land the current diff via the commit-queue"
+ argument_names = "[BUGID]"
+ long_help = """land-safely updates the ChangeLog with the reviewer listed
+ in bugs.webkit.org for BUGID (or the bug ID detected from the ChangeLog).
+ The command then uploads the current diff to the bug and marks it for
+ commit by the commit-queue."""
+ show_in_main_help = True
+ steps = [
+ steps.UpdateChangeLogsWithReviewer,
+ steps.ObsoletePatches,
+ steps.PostDiffForCommit,
+ ]
+
+
+class Prepare(AbstractSequencedCommand):
+ name = "prepare"
+ help_text = "Creates a bug (or prompts for an existing bug) and prepares the ChangeLogs"
+ argument_names = "[BUGID]"
+ steps = [
+ steps.PromptForBugOrTitle,
+ steps.CreateBug,
+ steps.PrepareChangeLog,
+ ]
+
+ def _prepare_state(self, options, args, tool):
+ bug_id = args and args[0]
+ return { "bug_id" : bug_id }
+
+
+class Upload(AbstractPatchUploadingCommand):
+ name = "upload"
+ help_text = "Automates the process of uploading a patch for review"
+ argument_names = "[BUGID]"
+ show_in_main_help = True
+ steps = [
+ steps.CheckStyle,
+ steps.PromptForBugOrTitle,
+ steps.CreateBug,
+ steps.PrepareChangeLog,
+ steps.EditChangeLog,
+ steps.ConfirmDiff,
+ steps.ObsoletePatches,
+ steps.SuggestReviewers,
+ steps.PostDiff,
+ ]
+ long_help = """upload uploads the current diff to bugs.webkit.org.
+ If no bug id is provided, upload will create a bug.
+ If the current diff does not have a ChangeLog, upload
+ will prepare a ChangeLog. Once a patch is read, upload
+ will open the ChangeLogs for editing using the command in the
+ EDITOR environment variable and will display the diff using the
+ command in the PAGER environment variable."""
+
+ def _prepare_state(self, options, args, tool):
+ state = {}
+ state["bug_id"] = self._bug_id(options, args, tool, state)
+ return state
+
+
+class EditChangeLogs(AbstractSequencedCommand):
+ name = "edit-changelogs"
+ help_text = "Opens modified ChangeLogs in $EDITOR"
+ show_in_main_help = True
+ steps = [
+ steps.EditChangeLog,
+ ]
+
+
+class PostCommits(AbstractDeclarativeCommand):
+ name = "post-commits"
+ help_text = "Attach a range of local commits to bugs as patch files"
+ argument_names = "COMMITISH"
+
+ def __init__(self):
+ options = [
+ make_option("-b", "--bug-id", action="store", type="string", dest="bug_id", help="Specify bug id if no URL is provided in the commit log."),
+ make_option("--add-log-as-comment", action="store_true", dest="add_log_as_comment", default=False, help="Add commit log message as a comment when uploading the patch."),
+ make_option("-m", "--description", action="store", type="string", dest="description", help="Description string for the attachment (default: description from commit message)"),
+ steps.Options.obsolete_patches,
+ steps.Options.review,
+ steps.Options.request_commit,
+ ]
+ AbstractDeclarativeCommand.__init__(self, options=options, requires_local_commits=True)
+
+ def _comment_text_for_commit(self, options, commit_message, tool, commit_id):
+ comment_text = None
+ if (options.add_log_as_comment):
+ comment_text = commit_message.body(lstrip=True)
+ comment_text += "---\n"
+ comment_text += tool.scm().files_changed_summary_for_commit(commit_id)
+ return comment_text
+
+ def execute(self, options, args, tool):
+ commit_ids = tool.scm().commit_ids_from_commitish_arguments(args)
+ if len(commit_ids) > 10: # We could lower this limit, 10 is too many for one bug as-is.
+ error("webkit-patch does not support attaching %s at once. Are you sure you passed the right commit range?" % (pluralize("patch", len(commit_ids))))
+
+ have_obsoleted_patches = set()
+ for commit_id in commit_ids:
+ commit_message = tool.scm().commit_message_for_local_commit(commit_id)
+
+ # Prefer --bug-id=, then a bug url in the commit message, then a bug url in the entire commit diff (i.e. ChangeLogs).
+ bug_id = options.bug_id or parse_bug_id(commit_message.message()) or parse_bug_id(tool.scm().create_patch(git_commit=commit_id))
+ if not bug_id:
+ log("Skipping %s: No bug id found in commit or specified with --bug-id." % commit_id)
+ continue
+
+ if options.obsolete_patches and bug_id not in have_obsoleted_patches:
+ state = { "bug_id": bug_id }
+ steps.ObsoletePatches(tool, options).run(state)
+ have_obsoleted_patches.add(bug_id)
+
+ diff = tool.scm().create_patch(git_commit=commit_id)
+ description = options.description or commit_message.description(lstrip=True, strip_url=True)
+ comment_text = self._comment_text_for_commit(options, commit_message, tool, commit_id)
+ tool.bugs.add_patch_to_bug(bug_id, diff, description, comment_text, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
+
+
+# FIXME: This command needs to be brought into the modern age with steps and CommitInfo.
+class MarkBugFixed(AbstractDeclarativeCommand):
+ name = "mark-bug-fixed"
+ help_text = "Mark the specified bug as fixed"
+ argument_names = "[SVN_REVISION]"
+ def __init__(self):
+ options = [
+ make_option("--bug-id", action="store", type="string", dest="bug_id", help="Specify bug id if no URL is provided in the commit log."),
+ make_option("--comment", action="store", type="string", dest="comment", help="Text to include in bug comment."),
+ make_option("--open", action="store_true", default=False, dest="open_bug", help="Open bug in default web browser (Mac only)."),
+ make_option("--update-only", action="store_true", default=False, dest="update_only", help="Add comment to the bug, but do not close it."),
+ ]
+ AbstractDeclarativeCommand.__init__(self, options=options)
+
+ # FIXME: We should be using checkout().changelog_entries_for_revision(...) instead here.
+ def _fetch_commit_log(self, tool, svn_revision):
+ if not svn_revision:
+ return tool.scm().last_svn_commit_log()
+ return tool.scm().svn_commit_log(svn_revision)
+
+ def _determine_bug_id_and_svn_revision(self, tool, bug_id, svn_revision):
+ commit_log = self._fetch_commit_log(tool, svn_revision)
+
+ if not bug_id:
+ bug_id = parse_bug_id(commit_log)
+
+ if not svn_revision:
+ match = re.search("^r(?P<svn_revision>\d+) \|", commit_log, re.MULTILINE)
+ if match:
+ svn_revision = match.group('svn_revision')
+
+ if not bug_id or not svn_revision:
+ not_found = []
+ if not bug_id:
+ not_found.append("bug id")
+ if not svn_revision:
+ not_found.append("svn revision")
+ error("Could not find %s on command-line or in %s."
+ % (" or ".join(not_found), "r%s" % svn_revision if svn_revision else "last commit"))
+
+ return (bug_id, svn_revision)
+
+ def execute(self, options, args, tool):
+ bug_id = options.bug_id
+
+ svn_revision = args and args[0]
+ if svn_revision:
+ if re.match("^r[0-9]+$", svn_revision, re.IGNORECASE):
+ svn_revision = svn_revision[1:]
+ if not re.match("^[0-9]+$", svn_revision):
+ error("Invalid svn revision: '%s'" % svn_revision)
+
+ needs_prompt = False
+ if not bug_id or not svn_revision:
+ needs_prompt = True
+ (bug_id, svn_revision) = self._determine_bug_id_and_svn_revision(tool, bug_id, svn_revision)
+
+ log("Bug: <%s> %s" % (tool.bugs.bug_url_for_bug_id(bug_id), tool.bugs.fetch_bug_dictionary(bug_id)["title"]))
+ log("Revision: %s" % svn_revision)
+
+ if options.open_bug:
+ tool.user.open_url(tool.bugs.bug_url_for_bug_id(bug_id))
+
+ if needs_prompt:
+ if not tool.user.confirm("Is this correct?"):
+ exit(1)
+
+ bug_comment = bug_comment_from_svn_revision(svn_revision)
+ if options.comment:
+ bug_comment = "%s\n\n%s" % (options.comment, bug_comment)
+
+ if options.update_only:
+ log("Adding comment to Bug %s." % bug_id)
+ tool.bugs.post_comment_to_bug(bug_id, bug_comment)
+ else:
+ log("Adding comment to Bug %s and marking as Resolved/Fixed." % bug_id)
+ tool.bugs.close_bug_as_fixed(bug_id, bug_comment)
+
+
+# FIXME: Requires unit test. Blocking issue: too complex for now.
+class CreateBug(AbstractDeclarativeCommand):
+ name = "create-bug"
+ help_text = "Create a bug from local changes or local commits"
+ argument_names = "[COMMITISH]"
+
+ def __init__(self):
+ options = [
+ steps.Options.cc,
+ steps.Options.component,
+ make_option("--no-prompt", action="store_false", dest="prompt", default=True, help="Do not prompt for bug title and comment; use commit log instead."),
+ make_option("--no-review", action="store_false", dest="review", default=True, help="Do not mark the patch for review."),
+ make_option("--request-commit", action="store_true", dest="request_commit", default=False, help="Mark the patch as needing auto-commit after review."),
+ ]
+ AbstractDeclarativeCommand.__init__(self, options=options)
+
+ def create_bug_from_commit(self, options, args, tool):
+ commit_ids = tool.scm().commit_ids_from_commitish_arguments(args)
+ if len(commit_ids) > 3:
+ error("Are you sure you want to create one bug with %s patches?" % len(commit_ids))
+
+ commit_id = commit_ids[0]
+
+ bug_title = ""
+ comment_text = ""
+ if options.prompt:
+ (bug_title, comment_text) = self.prompt_for_bug_title_and_comment()
+ else:
+ commit_message = tool.scm().commit_message_for_local_commit(commit_id)
+ bug_title = commit_message.description(lstrip=True, strip_url=True)
+ comment_text = commit_message.body(lstrip=True)
+ comment_text += "---\n"
+ comment_text += tool.scm().files_changed_summary_for_commit(commit_id)
+
+ diff = tool.scm().create_patch(git_commit=commit_id)
+ bug_id = tool.bugs.create_bug(bug_title, comment_text, options.component, diff, "Patch", cc=options.cc, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
+
+ if bug_id and len(commit_ids) > 1:
+ options.bug_id = bug_id
+ options.obsolete_patches = False
+ # FIXME: We should pass through --no-comment switch as well.
+ PostCommits.execute(self, options, commit_ids[1:], tool)
+
+ def create_bug_from_patch(self, options, args, tool):
+ bug_title = ""
+ comment_text = ""
+ if options.prompt:
+ (bug_title, comment_text) = self.prompt_for_bug_title_and_comment()
+ else:
+ commit_message = tool.checkout().commit_message_for_this_commit(options.git_commit)
+ bug_title = commit_message.description(lstrip=True, strip_url=True)
+ comment_text = commit_message.body(lstrip=True)
+
+ diff = tool.scm().create_patch(options.git_commit)
+ bug_id = tool.bugs.create_bug(bug_title, comment_text, options.component, diff, "Patch", cc=options.cc, mark_for_review=options.review, mark_for_commit_queue=options.request_commit)
+
+ def prompt_for_bug_title_and_comment(self):
+ bug_title = User.prompt("Bug title: ")
+ print "Bug comment (hit ^D on blank line to end):"
+ lines = sys.stdin.readlines()
+ try:
+ sys.stdin.seek(0, os.SEEK_END)
+ except IOError:
+ # Cygwin raises an Illegal Seek (errno 29) exception when the above
+ # seek() call is made. Ignoring it seems to cause no harm.
+ # FIXME: Figure out a way to get avoid the exception in the first
+ # place.
+ pass
+ comment_text = "".join(lines)
+ return (bug_title, comment_text)
+
+ def execute(self, options, args, tool):
+ if len(args):
+ if (not tool.scm().supports_local_commits()):
+ error("Extra arguments not supported; patch is taken from working directory.")
+ self.create_bug_from_commit(options, args, tool)
+ else:
+ self.create_bug_from_patch(options, args, tool)
diff --git a/Tools/Scripts/webkitpy/tool/commands/upload_unittest.py b/Tools/Scripts/webkitpy/tool/commands/upload_unittest.py
new file mode 100644
index 0000000..a347b00
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/commands/upload_unittest.py
@@ -0,0 +1,122 @@
+# 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.
+
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.tool.commands.commandtest import CommandsTest
+from webkitpy.tool.commands.upload import *
+from webkitpy.tool.mocktool import MockOptions, MockTool
+
+class UploadCommandsTest(CommandsTest):
+ def test_commit_message_for_current_diff(self):
+ tool = MockTool()
+ expected_stdout = "This is a fake commit message that is at least 50 characters.\n"
+ self.assert_execute_outputs(CommitMessageForCurrentDiff(), [], expected_stdout=expected_stdout, tool=tool)
+
+ def test_clean_pending_commit(self):
+ self.assert_execute_outputs(CleanPendingCommit(), [])
+
+ def test_assign_to_committer(self):
+ tool = MockTool()
+ expected_stderr = "Warning, attachment 128 on bug 42 has invalid committer (non-committer@example.com)\nBug 77 is already assigned to foo@foo.com (None).\nBug 76 has no non-obsolete patches, ignoring.\n"
+ self.assert_execute_outputs(AssignToCommitter(), [], expected_stderr=expected_stderr, tool=tool)
+ tool.bugs.reassign_bug.assert_called_with(42, "eric@webkit.org", "Attachment 128 was posted by a committer and has review+, assigning to Eric Seidel for commit.")
+
+ def test_obsolete_attachments(self):
+ expected_stderr = "Obsoleting 2 old patches on bug 42\n"
+ self.assert_execute_outputs(ObsoleteAttachments(), [42], expected_stderr=expected_stderr)
+
+ def test_post(self):
+ options = MockOptions()
+ options.cc = None
+ options.check_style = True
+ options.comment = None
+ options.description = "MOCK description"
+ options.request_commit = False
+ options.review = True
+ options.suggest_reviewers = False
+ expected_stderr = """Running check-webkit-style
+MOCK: user.open_url: file://...
+Obsoleting 2 old patches on bug 42
+MOCK add_patch_to_bug: bug_id=42, description=MOCK description, mark_for_review=True, mark_for_commit_queue=False, mark_for_landing=False
+MOCK: user.open_url: http://example.com/42
+"""
+ expected_stdout = "Was that diff correct?\n"
+ self.assert_execute_outputs(Post(), [42], options=options, expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+
+ def test_land_safely(self):
+ expected_stderr = "Obsoleting 2 old patches on bug 42\nMOCK add_patch_to_bug: bug_id=42, description=Patch for landing, mark_for_review=False, mark_for_commit_queue=False, mark_for_landing=True\n"
+ self.assert_execute_outputs(LandSafely(), [42], expected_stderr=expected_stderr)
+
+ def test_prepare_diff_with_arg(self):
+ self.assert_execute_outputs(Prepare(), [42])
+
+ def test_prepare(self):
+ expected_stderr = "MOCK create_bug\nbug_title: Mock user response\nbug_description: Mock user response\ncomponent: MOCK component\ncc: MOCK cc\n"
+ self.assert_execute_outputs(Prepare(), [], expected_stderr=expected_stderr)
+
+ def test_upload(self):
+ options = MockOptions()
+ options.cc = None
+ options.check_style = True
+ options.comment = None
+ options.description = "MOCK description"
+ options.request_commit = False
+ options.review = True
+ options.suggest_reviewers = False
+ expected_stderr = """Running check-webkit-style
+MOCK: user.open_url: file://...
+Obsoleting 2 old patches on bug 42
+MOCK add_patch_to_bug: bug_id=42, description=MOCK description, mark_for_review=True, mark_for_commit_queue=False, mark_for_landing=False
+MOCK: user.open_url: http://example.com/42
+"""
+ expected_stdout = "Was that diff correct?\n"
+ self.assert_execute_outputs(Upload(), [42], options=options, expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+
+ def test_mark_bug_fixed(self):
+ tool = MockTool()
+ tool._scm.last_svn_commit_log = lambda: "r9876 |"
+ options = Mock()
+ options.bug_id = 42
+ options.comment = "MOCK comment"
+ expected_stderr = """Bug: <http://example.com/42> Bug with two r+'d and cq+'d patches, one of which has an invalid commit-queue setter.
+Revision: 9876
+MOCK: user.open_url: http://example.com/42
+Adding comment to Bug 42.
+MOCK bug comment: bug_id=42, cc=None
+--- Begin comment ---
+MOCK comment
+
+Committed r9876: <http://trac.webkit.org/changeset/9876>
+--- End comment ---
+
+"""
+ expected_stdout = "Is this correct?\n"
+ self.assert_execute_outputs(MarkBugFixed(), [], expected_stdout=expected_stdout, expected_stderr=expected_stderr, tool=tool, options=options)
+
+ def test_edit_changelog(self):
+ self.assert_execute_outputs(EditChangeLogs(), [])
diff --git a/Tools/Scripts/webkitpy/tool/comments.py b/Tools/Scripts/webkitpy/tool/comments.py
new file mode 100755
index 0000000..771953e
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/comments.py
@@ -0,0 +1,42 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# 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:
+#
+# * 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.
+#
+# A tool for automating dealing with bugzilla, posting patches, committing
+# patches, etc.
+
+from webkitpy.common.config import urls
+
+
+def bug_comment_from_svn_revision(svn_revision):
+ return "Committed r%s: <%s>" % (svn_revision, urls.view_revision_url(svn_revision))
+
+
+def bug_comment_from_commit_text(scm, commit_text):
+ svn_revision = scm.svn_revision_from_commit_text(commit_text)
+ return bug_comment_from_svn_revision(svn_revision)
diff --git a/Tools/Scripts/webkitpy/tool/grammar.py b/Tools/Scripts/webkitpy/tool/grammar.py
new file mode 100644
index 0000000..8db9826
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/grammar.py
@@ -0,0 +1,54 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# 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:
+#
+# * 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 re
+
+
+def plural(noun):
+ # This is a dumb plural() implementation that is just enough for our uses.
+ if re.search("h$", noun):
+ return noun + "es"
+ else:
+ return noun + "s"
+
+
+def pluralize(noun, count):
+ if count != 1:
+ noun = plural(noun)
+ return "%d %s" % (count, noun)
+
+
+def join_with_separators(list_of_strings, separator=', ', only_two_separator=" and ", last_separator=', and '):
+ if not list_of_strings:
+ return ""
+ if len(list_of_strings) == 1:
+ return list_of_strings[0]
+ if len(list_of_strings) == 2:
+ return only_two_separator.join(list_of_strings)
+ return "%s%s%s" % (separator.join(list_of_strings[:-1]), last_separator, list_of_strings[-1])
diff --git a/Tools/Scripts/webkitpy/tool/grammar_unittest.py b/Tools/Scripts/webkitpy/tool/grammar_unittest.py
new file mode 100644
index 0000000..cab71db
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/grammar_unittest.py
@@ -0,0 +1,41 @@
+# 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 unittest
+
+from webkitpy.tool.grammar import join_with_separators
+
+class GrammarTest(unittest.TestCase):
+
+ def test_join_with_separators(self):
+ self.assertEqual(join_with_separators(["one"]), "one")
+ self.assertEqual(join_with_separators(["one", "two"]), "one and two")
+ self.assertEqual(join_with_separators(["one", "two", "three"]), "one, two, and three")
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/tool/main.py b/Tools/Scripts/webkitpy/tool/main.py
new file mode 100755
index 0000000..0006e87
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/main.py
@@ -0,0 +1,141 @@
+# Copyright (c) 2010 Google Inc. All rights reserved.
+# 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:
+#
+# * 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.
+#
+# A tool for automating dealing with bugzilla, posting patches, committing patches, etc.
+
+from optparse import make_option
+import os
+import threading
+
+from webkitpy.common.checkout.api import Checkout
+from webkitpy.common.checkout.scm import default_scm
+from webkitpy.common.config.ports import WebKitPort
+from webkitpy.common.net.bugzilla import Bugzilla
+from webkitpy.common.net.buildbot import BuildBot
+from webkitpy.common.net.irc.ircproxy import IRCProxy
+from webkitpy.common.net.statusserver import StatusServer
+from webkitpy.common.system.executive import Executive
+from webkitpy.common.system.filesystem import FileSystem
+from webkitpy.common.system.platforminfo import PlatformInfo
+from webkitpy.common.system.user import User
+from webkitpy.layout_tests import port
+from webkitpy.tool.multicommandtool import MultiCommandTool
+import webkitpy.tool.commands as commands
+
+
+class WebKitPatch(MultiCommandTool):
+ global_options = [
+ make_option("-v", "--verbose", action="store_true", dest="verbose", default=False, help="enable all logging"),
+ make_option("--dry-run", action="store_true", dest="dry_run", default=False, help="do not touch remote servers"),
+ make_option("--status-host", action="store", dest="status_host", type="string", help="Hostname (e.g. localhost or commit.webkit.org) where status updates should be posted."),
+ make_option("--bot-id", action="store", dest="bot_id", type="string", help="Identifier for this bot (if multiple bots are running for a queue)"),
+ make_option("--irc-password", action="store", dest="irc_password", type="string", help="Password to use when communicating via IRC."),
+ make_option("--port", action="store", dest="port", default=None, help="Specify a port (e.g., mac, qt, gtk, ...)."),
+ ]
+
+ def __init__(self, path):
+ MultiCommandTool.__init__(self)
+
+ self._path = path
+ self.wakeup_event = threading.Event()
+ # FIXME: All of these shared objects should move off onto a
+ # separate "Tool" object. WebKitPatch should inherit from
+ # "Tool" and all these objects should use getters/setters instead of
+ # manual getter functions (e.g. scm()).
+ self.bugs = Bugzilla()
+ self.buildbot = BuildBot()
+ self.executive = Executive()
+ self._irc = None
+ self.filesystem = FileSystem()
+ self._port = None
+ self.user = User()
+ self._scm = None
+ self._checkout = None
+ self.status_server = StatusServer()
+ self.port_factory = port.factory
+ self.platform = PlatformInfo()
+
+ def scm(self):
+ # Lazily initialize SCM to not error-out before command line parsing (or when running non-scm commands).
+ if not self._scm:
+ self._scm = default_scm()
+ return self._scm
+
+ def checkout(self):
+ if not self._checkout:
+ self._checkout = Checkout(self.scm())
+ return self._checkout
+
+ def port(self):
+ return self._port
+
+ def ensure_irc_connected(self, irc_delegate):
+ if not self._irc:
+ self._irc = IRCProxy(irc_delegate)
+
+ def irc(self):
+ # We don't automatically construct IRCProxy here because constructing
+ # IRCProxy actually connects to IRC. We want clients to explicitly
+ # connect to IRC.
+ return self._irc
+
+ def path(self):
+ return self._path
+
+ def command_completed(self):
+ if self._irc:
+ self._irc.disconnect()
+
+ def should_show_in_main_help(self, command):
+ if not command.show_in_main_help:
+ return False
+ if command.requires_local_commits:
+ return self.scm().supports_local_commits()
+ return True
+
+ # FIXME: This may be unnecessary since we pass global options to all commands during execute() as well.
+ def handle_global_options(self, options):
+ self._options = options
+ if options.dry_run:
+ self.scm().dryrun = True
+ self.bugs.dryrun = True
+ if options.status_host:
+ self.status_server.set_host(options.status_host)
+ if options.bot_id:
+ self.status_server.set_bot_id(options.bot_id)
+ if options.irc_password:
+ self.irc_password = options.irc_password
+ # If options.port is None, we'll get the default port for this platform.
+ self._port = WebKitPort.port(options.port)
+
+ def should_execute_command(self, command):
+ if command.requires_local_commits and not self.scm().supports_local_commits():
+ failure_reason = "%s requires local commits using %s in %s." % (command.name, self.scm().display_name(), self.scm().checkout_root)
+ return (False, failure_reason)
+ return (True, None)
diff --git a/Tools/Scripts/webkitpy/tool/mocktool.py b/Tools/Scripts/webkitpy/tool/mocktool.py
new file mode 100644
index 0000000..30a4bc3
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/mocktool.py
@@ -0,0 +1,735 @@
+# 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 os
+import threading
+
+from webkitpy.common.config.committers import CommitterList, Reviewer
+from webkitpy.common.checkout.commitinfo import CommitInfo
+from webkitpy.common.checkout.scm import CommitMessage
+from webkitpy.common.net.bugzilla import Bug, Attachment
+from webkitpy.common.system.deprecated_logging import log
+from webkitpy.common.system.filesystem_mock import MockFileSystem
+from webkitpy.thirdparty.mock import Mock
+
+
+def _id_to_object_dictionary(*objects):
+ dictionary = {}
+ for thing in objects:
+ dictionary[thing["id"]] = thing
+ return dictionary
+
+# Testing
+
+# FIXME: The ids should be 1, 2, 3 instead of crazy numbers.
+
+
+_patch1 = {
+ "id": 197,
+ "bug_id": 42,
+ "url": "http://example.com/197",
+ "name": "Patch1",
+ "is_obsolete": False,
+ "is_patch": True,
+ "review": "+",
+ "reviewer_email": "foo@bar.com",
+ "commit-queue": "+",
+ "committer_email": "foo@bar.com",
+ "attacher_email": "Contributer1",
+}
+
+
+_patch2 = {
+ "id": 128,
+ "bug_id": 42,
+ "url": "http://example.com/128",
+ "name": "Patch2",
+ "is_obsolete": False,
+ "is_patch": True,
+ "review": "+",
+ "reviewer_email": "foo@bar.com",
+ "commit-queue": "+",
+ "committer_email": "non-committer@example.com",
+ "attacher_email": "eric@webkit.org",
+}
+
+
+_patch3 = {
+ "id": 103,
+ "bug_id": 75,
+ "url": "http://example.com/103",
+ "name": "Patch3",
+ "is_obsolete": False,
+ "is_patch": True,
+ "review": "?",
+ "attacher_email": "eric@webkit.org",
+}
+
+
+_patch4 = {
+ "id": 104,
+ "bug_id": 77,
+ "url": "http://example.com/103",
+ "name": "Patch3",
+ "is_obsolete": False,
+ "is_patch": True,
+ "review": "+",
+ "commit-queue": "?",
+ "reviewer_email": "foo@bar.com",
+ "attacher_email": "Contributer2",
+}
+
+
+_patch5 = {
+ "id": 105,
+ "bug_id": 77,
+ "url": "http://example.com/103",
+ "name": "Patch5",
+ "is_obsolete": False,
+ "is_patch": True,
+ "review": "+",
+ "reviewer_email": "foo@bar.com",
+ "attacher_email": "eric@webkit.org",
+}
+
+
+_patch6 = { # Valid committer, but no reviewer.
+ "id": 106,
+ "bug_id": 77,
+ "url": "http://example.com/103",
+ "name": "ROLLOUT of r3489",
+ "is_obsolete": False,
+ "is_patch": True,
+ "commit-queue": "+",
+ "committer_email": "foo@bar.com",
+ "attacher_email": "eric@webkit.org",
+}
+
+
+_patch7 = { # Valid review, patch is marked obsolete.
+ "id": 107,
+ "bug_id": 76,
+ "url": "http://example.com/103",
+ "name": "Patch7",
+ "is_obsolete": True,
+ "is_patch": True,
+ "review": "+",
+ "reviewer_email": "foo@bar.com",
+ "attacher_email": "eric@webkit.org",
+}
+
+
+# This matches one of Bug.unassigned_emails
+_unassigned_email = "webkit-unassigned@lists.webkit.org"
+# This is needed for the FlakyTestReporter to believe the bug
+# was filed by one of the webkitpy bots.
+_commit_queue_email = "commit-queue@webkit.org"
+
+
+# FIXME: The ids should be 1, 2, 3 instead of crazy numbers.
+
+
+_bug1 = {
+ "id": 42,
+ "title": "Bug with two r+'d and cq+'d patches, one of which has an "
+ "invalid commit-queue setter.",
+ "reporter_email": "foo@foo.com",
+ "assigned_to_email": _unassigned_email,
+ "attachments": [_patch1, _patch2],
+ "bug_status": "UNCONFIRMED",
+}
+
+
+_bug2 = {
+ "id": 75,
+ "title": "Bug with a patch needing review.",
+ "reporter_email": "foo@foo.com",
+ "assigned_to_email": "foo@foo.com",
+ "attachments": [_patch3],
+ "bug_status": "ASSIGNED",
+}
+
+
+_bug3 = {
+ "id": 76,
+ "title": "The third bug",
+ "reporter_email": "foo@foo.com",
+ "assigned_to_email": _unassigned_email,
+ "attachments": [_patch7],
+ "bug_status": "NEW",
+}
+
+
+_bug4 = {
+ "id": 77,
+ "title": "The fourth bug",
+ "reporter_email": "foo@foo.com",
+ "assigned_to_email": "foo@foo.com",
+ "attachments": [_patch4, _patch5, _patch6],
+ "bug_status": "REOPENED",
+}
+
+
+_bug5 = {
+ "id": 78,
+ "title": "The fifth bug",
+ "reporter_email": _commit_queue_email,
+ "assigned_to_email": "foo@foo.com",
+ "attachments": [],
+ "bug_status": "RESOLVED",
+ "dup_id": 76,
+}
+
+
+# FIXME: This should not inherit from Mock
+class MockBugzillaQueries(Mock):
+
+ def __init__(self, bugzilla):
+ Mock.__init__(self)
+ self._bugzilla = bugzilla
+
+ def _all_bugs(self):
+ return map(lambda bug_dictionary: Bug(bug_dictionary, self._bugzilla),
+ self._bugzilla.bug_cache.values())
+
+ def fetch_bug_ids_from_commit_queue(self):
+ bugs_with_commit_queued_patches = filter(
+ lambda bug: bug.commit_queued_patches(),
+ self._all_bugs())
+ return map(lambda bug: bug.id(), bugs_with_commit_queued_patches)
+
+ def fetch_attachment_ids_from_review_queue(self):
+ unreviewed_patches = sum([bug.unreviewed_patches()
+ for bug in self._all_bugs()], [])
+ return map(lambda patch: patch.id(), unreviewed_patches)
+
+ def fetch_patches_from_commit_queue(self):
+ return sum([bug.commit_queued_patches()
+ for bug in self._all_bugs()], [])
+
+ def fetch_bug_ids_from_pending_commit_list(self):
+ bugs_with_reviewed_patches = filter(lambda bug: bug.reviewed_patches(),
+ self._all_bugs())
+ bug_ids = map(lambda bug: bug.id(), bugs_with_reviewed_patches)
+ # NOTE: This manual hack here is to allow testing logging in
+ # test_assign_to_committer the real pending-commit query on bugzilla
+ # will return bugs with patches which have r+, but are also obsolete.
+ return bug_ids + [76]
+
+ def fetch_patches_from_pending_commit_list(self):
+ return sum([bug.reviewed_patches() for bug in self._all_bugs()], [])
+
+ def fetch_bugs_matching_search(self, search_string, author_email=None):
+ return [self._bugzilla.fetch_bug(78), self._bugzilla.fetch_bug(77)]
+
+_mock_reviewer = Reviewer("Foo Bar", "foo@bar.com")
+
+
+# FIXME: Bugzilla is the wrong Mock-point. Once we have a BugzillaNetwork
+# class we should mock that instead.
+# Most of this class is just copy/paste from Bugzilla.
+# FIXME: This should not inherit from Mock
+class MockBugzilla(Mock):
+
+ bug_server_url = "http://example.com"
+
+ bug_cache = _id_to_object_dictionary(_bug1, _bug2, _bug3, _bug4, _bug5)
+
+ attachment_cache = _id_to_object_dictionary(_patch1,
+ _patch2,
+ _patch3,
+ _patch4,
+ _patch5,
+ _patch6,
+ _patch7)
+
+ def __init__(self):
+ Mock.__init__(self)
+ self.queries = MockBugzillaQueries(self)
+ self.committers = CommitterList(reviewers=[_mock_reviewer])
+ self._override_patch = None
+
+ def create_bug(self,
+ bug_title,
+ bug_description,
+ component=None,
+ diff=None,
+ patch_description=None,
+ cc=None,
+ blocked=None,
+ mark_for_review=False,
+ mark_for_commit_queue=False):
+ log("MOCK create_bug")
+ log("bug_title: %s" % bug_title)
+ log("bug_description: %s" % bug_description)
+ if component:
+ log("component: %s" % component)
+ if cc:
+ log("cc: %s" % cc)
+ if blocked:
+ log("blocked: %s" % blocked)
+ return 78
+
+ def quips(self):
+ return ["Good artists copy. Great artists steal. - Pablo Picasso"]
+
+ def fetch_bug(self, bug_id):
+ return Bug(self.bug_cache.get(bug_id), self)
+
+ def set_override_patch(self, patch):
+ self._override_patch = patch
+
+ def fetch_attachment(self, attachment_id):
+ if self._override_patch:
+ return self._override_patch
+
+ attachment_dictionary = self.attachment_cache.get(attachment_id)
+ if not attachment_dictionary:
+ print "MOCK: fetch_attachment: %s is not a known attachment id" % attachment_id
+ return None
+ bug = self.fetch_bug(attachment_dictionary["bug_id"])
+ for attachment in bug.attachments(include_obsolete=True):
+ if attachment.id() == int(attachment_id):
+ return attachment
+
+ def bug_url_for_bug_id(self, bug_id):
+ return "%s/%s" % (self.bug_server_url, bug_id)
+
+ def fetch_bug_dictionary(self, bug_id):
+ return self.bug_cache.get(bug_id)
+
+ def attachment_url_for_id(self, attachment_id, action="view"):
+ action_param = ""
+ if action and action != "view":
+ action_param = "&action=%s" % action
+ return "%s/%s%s" % (self.bug_server_url, attachment_id, action_param)
+
+ def set_flag_on_attachment(self,
+ attachment_id,
+ flag_name,
+ flag_value,
+ comment_text=None,
+ additional_comment_text=None):
+ log("MOCK setting flag '%s' to '%s' on attachment '%s' with comment '%s' and additional comment '%s'" % (
+ flag_name, flag_value, attachment_id, comment_text, additional_comment_text))
+
+ def post_comment_to_bug(self, bug_id, comment_text, cc=None):
+ log("MOCK bug comment: bug_id=%s, cc=%s\n--- Begin comment ---\n%s\n--- End comment ---\n" % (
+ bug_id, cc, comment_text))
+
+ def add_attachment_to_bug(self,
+ bug_id,
+ file_or_string,
+ description,
+ filename=None,
+ comment_text=None):
+ log("MOCK add_attachment_to_bug: bug_id=%s, description=%s filename=%s" % (bug_id, description, filename))
+ if comment_text:
+ log("-- Begin comment --")
+ log(comment_text)
+ log("-- End comment --")
+
+ def add_patch_to_bug(self,
+ bug_id,
+ diff,
+ description,
+ comment_text=None,
+ mark_for_review=False,
+ mark_for_commit_queue=False,
+ mark_for_landing=False):
+ log("MOCK add_patch_to_bug: bug_id=%s, description=%s, mark_for_review=%s, mark_for_commit_queue=%s, mark_for_landing=%s" %
+ (bug_id, description, mark_for_review, mark_for_commit_queue, mark_for_landing))
+ if comment_text:
+ log("-- Begin comment --")
+ log(comment_text)
+ log("-- End comment --")
+
+
+class MockBuilder(object):
+ def __init__(self, name):
+ self._name = name
+
+ def name(self):
+ return self._name
+
+ def results_url(self):
+ return "http://example.com/builders/%s/results/" % self.name()
+
+ def force_build(self, username, comments):
+ log("MOCK: force_build: name=%s, username=%s, comments=%s" % (
+ self._name, username, comments))
+
+
+class MockFailureMap(object):
+ def __init__(self, buildbot):
+ self._buildbot = buildbot
+
+ def is_empty(self):
+ return False
+
+ def filter_out_old_failures(self, is_old_revision):
+ pass
+
+ def failing_revisions(self):
+ return [29837]
+
+ def builders_failing_for(self, revision):
+ return [self._buildbot.builder_with_name("Builder1")]
+
+ def tests_failing_for(self, revision):
+ return ["mock-test-1"]
+
+
+class MockBuildBot(object):
+ buildbot_host = "dummy_buildbot_host"
+ def __init__(self):
+ self._mock_builder1_status = {
+ "name": "Builder1",
+ "is_green": True,
+ "activity": "building",
+ }
+ self._mock_builder2_status = {
+ "name": "Builder2",
+ "is_green": True,
+ "activity": "idle",
+ }
+
+ def builder_with_name(self, name):
+ return MockBuilder(name)
+
+ def builder_statuses(self):
+ return [
+ self._mock_builder1_status,
+ self._mock_builder2_status,
+ ]
+
+ def red_core_builders_names(self):
+ if not self._mock_builder2_status["is_green"]:
+ return [self._mock_builder2_status["name"]]
+ return []
+
+ def red_core_builders(self):
+ if not self._mock_builder2_status["is_green"]:
+ return [self._mock_builder2_status]
+ return []
+
+ def idle_red_core_builders(self):
+ if not self._mock_builder2_status["is_green"]:
+ return [self._mock_builder2_status]
+ return []
+
+ def last_green_revision(self):
+ return 9479
+
+ def light_tree_on_fire(self):
+ self._mock_builder2_status["is_green"] = False
+
+ def failure_map(self):
+ return MockFailureMap(self)
+
+
+# FIXME: This should not inherit from Mock
+class MockSCM(Mock):
+
+ fake_checkout_root = os.path.realpath("/tmp") # realpath is needed to allow for Mac OS X's /private/tmp
+
+ def __init__(self):
+ Mock.__init__(self)
+ # FIXME: We should probably use real checkout-root detection logic here.
+ # os.getcwd() can't work here because other parts of the code assume that "checkout_root"
+ # will actually be the root. Since getcwd() is wrong, use a globally fake root for now.
+ self.checkout_root = self.fake_checkout_root
+
+ def changed_files(self, git_commit=None):
+ return ["MockFile1"]
+
+ def create_patch(self, git_commit, changed_files=None):
+ return "Patch1"
+
+ def commit_ids_from_commitish_arguments(self, args):
+ return ["Commitish1", "Commitish2"]
+
+ def commit_message_for_local_commit(self, commit_id):
+ if commit_id == "Commitish1":
+ return CommitMessage("CommitMessage1\n" \
+ "https://bugs.example.org/show_bug.cgi?id=42\n")
+ if commit_id == "Commitish2":
+ return CommitMessage("CommitMessage2\n" \
+ "https://bugs.example.org/show_bug.cgi?id=75\n")
+ raise Exception("Bogus commit_id in commit_message_for_local_commit.")
+
+ def diff_for_revision(self, revision):
+ return "DiffForRevision%s\n" \
+ "http://bugs.webkit.org/show_bug.cgi?id=12345" % revision
+
+ def svn_revision_from_commit_text(self, commit_text):
+ return "49824"
+
+ def add(self, destination_path, return_exit_code=False):
+ if return_exit_code:
+ return 0
+
+
+class MockCheckout(object):
+
+ _committer_list = CommitterList()
+
+ def commit_info_for_revision(self, svn_revision):
+ # The real Checkout would probably throw an exception, but this is the only way tests have to get None back at the moment.
+ if not svn_revision:
+ return None
+ return CommitInfo(svn_revision, "eric@webkit.org", {
+ "bug_id": 42,
+ "author_name": "Adam Barth",
+ "author_email": "abarth@webkit.org",
+ "author": self._committer_list.committer_by_email("abarth@webkit.org"),
+ "reviewer_text": "Darin Adler",
+ "reviewer": self._committer_list.committer_by_name("Darin Adler"),
+ })
+
+ def bug_id_for_revision(self, svn_revision):
+ return 12345
+
+ def recent_commit_infos_for_files(self, paths):
+ return [self.commit_info_for_revision(32)]
+
+ def modified_changelogs(self, git_commit, changed_files=None):
+ # Ideally we'd return something more interesting here. The problem is
+ # that LandDiff will try to actually read the patch from disk!
+ return []
+
+ def commit_message_for_this_commit(self, git_commit, changed_files=None):
+ commit_message = Mock()
+ commit_message.message = lambda:"This is a fake commit message that is at least 50 characters."
+ return commit_message
+
+ def apply_patch(self, patch, force=False):
+ pass
+
+ def apply_reverse_diffs(self, revision):
+ pass
+
+ def suggested_reviewers(self, git_commit, changed_files=None):
+ return [_mock_reviewer]
+
+
+class MockUser(object):
+
+ @staticmethod
+ def prompt(message, repeat=1, raw_input=raw_input):
+ return "Mock user response"
+
+ def edit(self, files):
+ pass
+
+ def edit_changelog(self, files):
+ pass
+
+ def page(self, message):
+ pass
+
+ def confirm(self, message=None, default='y'):
+ print message
+ return default == 'y'
+
+ def can_open_url(self):
+ return True
+
+ def open_url(self, url):
+ if url.startswith("file://"):
+ log("MOCK: user.open_url: file://...")
+ return
+ log("MOCK: user.open_url: %s" % url)
+
+
+class MockIRC(object):
+
+ def post(self, message):
+ log("MOCK: irc.post: %s" % message)
+
+ def disconnect(self):
+ log("MOCK: irc.disconnect")
+
+
+class MockStatusServer(object):
+
+ def __init__(self, bot_id=None, work_items=None):
+ self.host = "example.com"
+ self.bot_id = bot_id
+ self._work_items = work_items or []
+
+ def patch_status(self, queue_name, patch_id):
+ return None
+
+ def svn_revision(self, svn_revision):
+ return None
+
+ def next_work_item(self, queue_name):
+ if not self._work_items:
+ return None
+ return self._work_items.pop(0)
+
+ def release_work_item(self, queue_name, patch):
+ log("MOCK: release_work_item: %s %s" % (queue_name, patch.id()))
+
+ def update_work_items(self, queue_name, work_items):
+ self._work_items = work_items
+ log("MOCK: update_work_items: %s %s" % (queue_name, work_items))
+
+ def submit_to_ews(self, patch_id):
+ log("MOCK: submit_to_ews: %s" % (patch_id))
+
+ def update_status(self, queue_name, status, patch=None, results_file=None):
+ log("MOCK: update_status: %s %s" % (queue_name, status))
+ return 187
+
+ def update_svn_revision(self, svn_revision, broken_bot):
+ return 191
+
+ def results_url_for_status(self, status_id):
+ return "http://dummy_url"
+
+
+# FIXME: This should not inherit from Mock
+# FIXME: Unify with common.system.executive_mock.MockExecutive.
+class MockExecutive(Mock):
+ def __init__(self, should_log):
+ self._should_log = should_log
+
+ def run_and_throw_if_fail(self, args, quiet=False):
+ if self._should_log:
+ log("MOCK run_and_throw_if_fail: %s" % args)
+ return "MOCK output of child process"
+
+ def run_command(self,
+ args,
+ cwd=None,
+ input=None,
+ error_handler=None,
+ return_exit_code=False,
+ return_stderr=True,
+ decode_output=False):
+ if self._should_log:
+ log("MOCK run_command: %s" % args)
+ return "MOCK output of child process"
+
+
+class MockOptions(object):
+ """Mock implementation of optparse.Values."""
+
+ def __init__(self, **kwargs):
+ # The caller can set option values using keyword arguments. We don't
+ # set any values by default because we don't know how this
+ # object will be used. Generally speaking unit tests should
+ # subclass this or provider wrapper functions that set a common
+ # set of options.
+ for key, value in kwargs.items():
+ self.__dict__[key] = value
+
+
+class MockPort(Mock):
+ def name(self):
+ return "MockPort"
+
+ def layout_tests_results_path(self):
+ return "/mock/results.html"
+
+class MockTestPort1(object):
+
+ def skips_layout_test(self, test_name):
+ return test_name in ["media/foo/bar.html", "foo"]
+
+
+class MockTestPort2(object):
+
+ def skips_layout_test(self, test_name):
+ return test_name == "media/foo/bar.html"
+
+
+class MockPortFactory(object):
+
+ def get_all(self, options=None):
+ return {"test_port1": MockTestPort1(), "test_port2": MockTestPort2()}
+
+
+class MockPlatformInfo(object):
+ def display_name(self):
+ return "MockPlatform 1.0"
+
+
+class MockTool(object):
+
+ def __init__(self, log_executive=False):
+ self.wakeup_event = threading.Event()
+ self.bugs = MockBugzilla()
+ self.buildbot = MockBuildBot()
+ self.executive = MockExecutive(should_log=log_executive)
+ self.filesystem = MockFileSystem()
+ self._irc = None
+ self.user = MockUser()
+ self._scm = MockSCM()
+ self._checkout = MockCheckout()
+ self.status_server = MockStatusServer()
+ self.irc_password = "MOCK irc password"
+ self.port_factory = MockPortFactory()
+ self.platform = MockPlatformInfo()
+
+ def scm(self):
+ return self._scm
+
+ def checkout(self):
+ return self._checkout
+
+ def ensure_irc_connected(self, delegate):
+ if not self._irc:
+ self._irc = MockIRC()
+
+ def irc(self):
+ return self._irc
+
+ def path(self):
+ return "echo"
+
+ def port(self):
+ return MockPort()
+
+
+class MockBrowser(object):
+ params = {}
+
+ def open(self, url):
+ pass
+
+ def select_form(self, name):
+ pass
+
+ def __setitem__(self, key, value):
+ self.params[key] = value
+
+ def submit(self):
+ return Mock(file)
diff --git a/Tools/Scripts/webkitpy/tool/mocktool_unittest.py b/Tools/Scripts/webkitpy/tool/mocktool_unittest.py
new file mode 100644
index 0000000..cceaa2e
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/mocktool_unittest.py
@@ -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:
+#
+# * 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 unittest
+
+from mocktool import MockOptions
+
+
+class MockOptionsTest(unittest.TestCase):
+ # MockOptions() should implement the same semantics that
+ # optparse.Values does.
+
+ def test_get__set(self):
+ # Test that we can still set options after we construct the
+ # object.
+ options = MockOptions()
+ options.foo = 'bar'
+ self.assertEqual(options.foo, 'bar')
+
+ def test_get__unset(self):
+ # Test that unset options raise an exception (regular Mock
+ # objects return an object and hence are different from
+ # optparse.Values()).
+ options = MockOptions()
+ self.assertRaises(AttributeError, lambda: options.foo)
+
+ def test_kwarg__set(self):
+ # Test that keyword arguments work in the constructor.
+ options = MockOptions(foo='bar')
+ self.assertEqual(options.foo, 'bar')
+
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/tool/multicommandtool.py b/Tools/Scripts/webkitpy/tool/multicommandtool.py
new file mode 100644
index 0000000..4848ae5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/multicommandtool.py
@@ -0,0 +1,314 @@
+# Copyright (c) 2009 Google Inc. All rights reserved.
+# 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:
+#
+# * 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.
+#
+# MultiCommandTool provides a framework for writing svn-like/git-like tools
+# which are called with the following format:
+# tool-name [global options] command-name [command options]
+
+import sys
+
+from optparse import OptionParser, IndentedHelpFormatter, SUPPRESS_USAGE, make_option
+
+from webkitpy.tool.grammar import pluralize
+from webkitpy.common.system.deprecated_logging import log
+
+
+class TryAgain(Exception):
+ pass
+
+
+class Command(object):
+ name = None
+ show_in_main_help = False
+ def __init__(self, help_text, argument_names=None, options=None, long_help=None, requires_local_commits=False):
+ self.help_text = help_text
+ self.long_help = long_help
+ self.argument_names = argument_names
+ self.required_arguments = self._parse_required_arguments(argument_names)
+ self.options = options
+ self.requires_local_commits = requires_local_commits
+ self._tool = None
+ # option_parser can be overriden by the tool using set_option_parser
+ # This default parser will be used for standalone_help printing.
+ self.option_parser = HelpPrintingOptionParser(usage=SUPPRESS_USAGE, add_help_option=False, option_list=self.options)
+
+ # This design is slightly awkward, but we need the
+ # the tool to be able to create and modify the option_parser
+ # before it knows what Command to run.
+ def set_option_parser(self, option_parser):
+ self.option_parser = option_parser
+ self._add_options_to_parser()
+
+ def _add_options_to_parser(self):
+ options = self.options or []
+ for option in options:
+ self.option_parser.add_option(option)
+
+ # The tool calls bind_to_tool on each Command after adding it to its list.
+ def bind_to_tool(self, tool):
+ # Command instances can only be bound to one tool at a time.
+ if self._tool and tool != self._tool:
+ raise Exception("Command already bound to tool!")
+ self._tool = tool
+
+ @staticmethod
+ def _parse_required_arguments(argument_names):
+ required_args = []
+ if not argument_names:
+ return required_args
+ split_args = argument_names.split(" ")
+ for argument in split_args:
+ if argument[0] == '[':
+ # For now our parser is rather dumb. Do some minimal validation that
+ # we haven't confused it.
+ if argument[-1] != ']':
+ raise Exception("Failure to parse argument string %s. Argument %s is missing ending ]" % (argument_names, argument))
+ else:
+ required_args.append(argument)
+ return required_args
+
+ def name_with_arguments(self):
+ usage_string = self.name
+ if self.options:
+ usage_string += " [options]"
+ if self.argument_names:
+ usage_string += " " + self.argument_names
+ return usage_string
+
+ def parse_args(self, args):
+ return self.option_parser.parse_args(args)
+
+ def check_arguments_and_execute(self, options, args, tool=None):
+ if len(args) < len(self.required_arguments):
+ log("%s required, %s provided. Provided: %s Required: %s\nSee '%s help %s' for usage." % (
+ pluralize("argument", len(self.required_arguments)),
+ pluralize("argument", len(args)),
+ "'%s'" % " ".join(args),
+ " ".join(self.required_arguments),
+ tool.name(),
+ self.name))
+ return 1
+ return self.execute(options, args, tool) or 0
+
+ def standalone_help(self):
+ help_text = self.name_with_arguments().ljust(len(self.name_with_arguments()) + 3) + self.help_text + "\n\n"
+ if self.long_help:
+ help_text += "%s\n\n" % self.long_help
+ help_text += self.option_parser.format_option_help(IndentedHelpFormatter())
+ return help_text
+
+ def execute(self, options, args, tool):
+ raise NotImplementedError, "subclasses must implement"
+
+ # main() exists so that Commands can be turned into stand-alone scripts.
+ # Other parts of the code will likely require modification to work stand-alone.
+ def main(self, args=sys.argv):
+ (options, args) = self.parse_args(args)
+ # Some commands might require a dummy tool
+ return self.check_arguments_and_execute(options, args)
+
+
+# FIXME: This should just be rolled into Command. help_text and argument_names do not need to be instance variables.
+class AbstractDeclarativeCommand(Command):
+ help_text = None
+ argument_names = None
+ long_help = None
+ def __init__(self, options=None, **kwargs):
+ Command.__init__(self, self.help_text, self.argument_names, options=options, long_help=self.long_help, **kwargs)
+
+
+class HelpPrintingOptionParser(OptionParser):
+ def __init__(self, epilog_method=None, *args, **kwargs):
+ self.epilog_method = epilog_method
+ OptionParser.__init__(self, *args, **kwargs)
+
+ def error(self, msg):
+ self.print_usage(sys.stderr)
+ error_message = "%s: error: %s\n" % (self.get_prog_name(), msg)
+ # This method is overriden to add this one line to the output:
+ error_message += "\nType \"%s --help\" to see usage.\n" % self.get_prog_name()
+ self.exit(1, error_message)
+
+ # We override format_epilog to avoid the default formatting which would paragraph-wrap the epilog
+ # and also to allow us to compute the epilog lazily instead of in the constructor (allowing it to be context sensitive).
+ def format_epilog(self, epilog):
+ if self.epilog_method:
+ return "\n%s\n" % self.epilog_method()
+ return ""
+
+
+class HelpCommand(AbstractDeclarativeCommand):
+ name = "help"
+ help_text = "Display information about this program or its subcommands"
+ argument_names = "[COMMAND]"
+
+ def __init__(self):
+ options = [
+ make_option("-a", "--all-commands", action="store_true", dest="show_all_commands", help="Print all available commands"),
+ ]
+ AbstractDeclarativeCommand.__init__(self, options)
+ self.show_all_commands = False # A hack used to pass --all-commands to _help_epilog even though it's called by the OptionParser.
+
+ def _help_epilog(self):
+ # Only show commands which are relevant to this checkout's SCM system. Might this be confusing to some users?
+ if self.show_all_commands:
+ epilog = "All %prog commands:\n"
+ relevant_commands = self._tool.commands[:]
+ else:
+ epilog = "Common %prog commands:\n"
+ relevant_commands = filter(self._tool.should_show_in_main_help, self._tool.commands)
+ longest_name_length = max(map(lambda command: len(command.name), relevant_commands))
+ relevant_commands.sort(lambda a, b: cmp(a.name, b.name))
+ command_help_texts = map(lambda command: " %s %s\n" % (command.name.ljust(longest_name_length), command.help_text), relevant_commands)
+ epilog += "%s\n" % "".join(command_help_texts)
+ epilog += "See '%prog help --all-commands' to list all commands.\n"
+ epilog += "See '%prog help COMMAND' for more information on a specific command.\n"
+ return epilog.replace("%prog", self._tool.name()) # Use of %prog here mimics OptionParser.expand_prog_name().
+
+ # FIXME: This is a hack so that we don't show --all-commands as a global option:
+ def _remove_help_options(self):
+ for option in self.options:
+ self.option_parser.remove_option(option.get_opt_string())
+
+ def execute(self, options, args, tool):
+ if args:
+ command = self._tool.command_by_name(args[0])
+ if command:
+ print command.standalone_help()
+ return 0
+
+ self.show_all_commands = options.show_all_commands
+ self._remove_help_options()
+ self.option_parser.print_help()
+ return 0
+
+
+class MultiCommandTool(object):
+ global_options = None
+
+ def __init__(self, name=None, commands=None):
+ self._name = name or OptionParser(prog=name).get_prog_name() # OptionParser has nice logic for fetching the name.
+ # Allow the unit tests to disable command auto-discovery.
+ self.commands = commands or [cls() for cls in self._find_all_commands() if cls.name]
+ self.help_command = self.command_by_name(HelpCommand.name)
+ # Require a help command, even if the manual test list doesn't include one.
+ if not self.help_command:
+ self.help_command = HelpCommand()
+ self.commands.append(self.help_command)
+ for command in self.commands:
+ command.bind_to_tool(self)
+
+ @classmethod
+ def _add_all_subclasses(cls, class_to_crawl, seen_classes):
+ for subclass in class_to_crawl.__subclasses__():
+ if subclass not in seen_classes:
+ seen_classes.add(subclass)
+ cls._add_all_subclasses(subclass, seen_classes)
+
+ @classmethod
+ def _find_all_commands(cls):
+ commands = set()
+ cls._add_all_subclasses(Command, commands)
+ return sorted(commands)
+
+ def name(self):
+ return self._name
+
+ def _create_option_parser(self):
+ usage = "Usage: %prog [options] COMMAND [ARGS]"
+ return HelpPrintingOptionParser(epilog_method=self.help_command._help_epilog, prog=self.name(), usage=usage)
+
+ @staticmethod
+ def _split_command_name_from_args(args):
+ # Assume the first argument which doesn't start with "-" is the command name.
+ command_index = 0
+ for arg in args:
+ if arg[0] != "-":
+ break
+ command_index += 1
+ else:
+ return (None, args[:])
+
+ command = args[command_index]
+ return (command, args[:command_index] + args[command_index + 1:])
+
+ def command_by_name(self, command_name):
+ for command in self.commands:
+ if command_name == command.name:
+ return command
+ return None
+
+ def path(self):
+ raise NotImplementedError, "subclasses must implement"
+
+ def command_completed(self):
+ pass
+
+ def should_show_in_main_help(self, command):
+ return command.show_in_main_help
+
+ def should_execute_command(self, command):
+ return True
+
+ def _add_global_options(self, option_parser):
+ global_options = self.global_options or []
+ for option in global_options:
+ option_parser.add_option(option)
+
+ def handle_global_options(self, options):
+ pass
+
+ def main(self, argv=sys.argv):
+ (command_name, args) = self._split_command_name_from_args(argv[1:])
+
+ option_parser = self._create_option_parser()
+ self._add_global_options(option_parser)
+
+ command = self.command_by_name(command_name) or self.help_command
+ if not command:
+ option_parser.error("%s is not a recognized command" % command_name)
+
+ command.set_option_parser(option_parser)
+ (options, args) = command.parse_args(args)
+ self.handle_global_options(options)
+
+ (should_execute, failure_reason) = self.should_execute_command(command)
+ if not should_execute:
+ log(failure_reason)
+ return 0 # FIXME: Should this really be 0?
+
+ while True:
+ try:
+ result = command.check_arguments_and_execute(options, args, self)
+ break
+ except TryAgain, e:
+ pass
+
+ self.command_completed()
+ return result
diff --git a/Tools/Scripts/webkitpy/tool/multicommandtool_unittest.py b/Tools/Scripts/webkitpy/tool/multicommandtool_unittest.py
new file mode 100644
index 0000000..c19095c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/multicommandtool_unittest.py
@@ -0,0 +1,177 @@
+# 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 sys
+import unittest
+
+from optparse import make_option
+
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.multicommandtool import MultiCommandTool, Command, TryAgain
+
+
+class TrivialCommand(Command):
+ name = "trivial"
+ show_in_main_help = True
+ def __init__(self, **kwargs):
+ Command.__init__(self, "help text", **kwargs)
+
+ def execute(self, options, args, tool):
+ pass
+
+
+class UncommonCommand(TrivialCommand):
+ name = "uncommon"
+ show_in_main_help = False
+
+
+class LikesToRetry(Command):
+ name = "likes-to-retry"
+ show_in_main_help = True
+
+ def __init__(self, **kwargs):
+ Command.__init__(self, "help text", **kwargs)
+ self.execute_count = 0
+
+ def execute(self, options, args, tool):
+ self.execute_count += 1
+ if self.execute_count < 2:
+ raise TryAgain()
+
+
+class CommandTest(unittest.TestCase):
+ def test_name_with_arguments(self):
+ command_with_args = TrivialCommand(argument_names="ARG1 ARG2")
+ self.assertEqual(command_with_args.name_with_arguments(), "trivial ARG1 ARG2")
+
+ command_with_args = TrivialCommand(options=[make_option("--my_option")])
+ self.assertEqual(command_with_args.name_with_arguments(), "trivial [options]")
+
+ def test_parse_required_arguments(self):
+ self.assertEqual(Command._parse_required_arguments("ARG1 ARG2"), ["ARG1", "ARG2"])
+ self.assertEqual(Command._parse_required_arguments("[ARG1] [ARG2]"), [])
+ self.assertEqual(Command._parse_required_arguments("[ARG1] ARG2"), ["ARG2"])
+ # Note: We might make our arg parsing smarter in the future and allow this type of arguments string.
+ self.assertRaises(Exception, Command._parse_required_arguments, "[ARG1 ARG2]")
+
+ def test_required_arguments(self):
+ two_required_arguments = TrivialCommand(argument_names="ARG1 ARG2 [ARG3]")
+ expected_missing_args_error = "2 arguments required, 1 argument provided. Provided: 'foo' Required: ARG1 ARG2\nSee 'trivial-tool help trivial' for usage.\n"
+ exit_code = OutputCapture().assert_outputs(self, two_required_arguments.check_arguments_and_execute, [None, ["foo"], TrivialTool()], expected_stderr=expected_missing_args_error)
+ self.assertEqual(exit_code, 1)
+
+
+class TrivialTool(MultiCommandTool):
+ def __init__(self, commands=None):
+ MultiCommandTool.__init__(self, name="trivial-tool", commands=commands)
+
+ def path(self):
+ return __file__
+
+ def should_execute_command(self, command):
+ return (True, None)
+
+
+class MultiCommandToolTest(unittest.TestCase):
+ def _assert_split(self, args, expected_split):
+ self.assertEqual(MultiCommandTool._split_command_name_from_args(args), expected_split)
+
+ def test_split_args(self):
+ # MultiCommandToolTest._split_command_name_from_args returns: (command, args)
+ full_args = ["--global-option", "command", "--option", "arg"]
+ full_args_expected = ("command", ["--global-option", "--option", "arg"])
+ self._assert_split(full_args, full_args_expected)
+
+ full_args = []
+ full_args_expected = (None, [])
+ self._assert_split(full_args, full_args_expected)
+
+ full_args = ["command", "arg"]
+ full_args_expected = ("command", ["arg"])
+ self._assert_split(full_args, full_args_expected)
+
+ def test_command_by_name(self):
+ # This also tests Command auto-discovery.
+ tool = TrivialTool()
+ self.assertEqual(tool.command_by_name("trivial").name, "trivial")
+ self.assertEqual(tool.command_by_name("bar"), None)
+
+ def _assert_tool_main_outputs(self, tool, main_args, expected_stdout, expected_stderr = "", expected_exit_code=0):
+ exit_code = OutputCapture().assert_outputs(self, tool.main, [main_args], expected_stdout=expected_stdout, expected_stderr=expected_stderr)
+ self.assertEqual(exit_code, expected_exit_code)
+
+ def test_retry(self):
+ likes_to_retry = LikesToRetry()
+ tool = TrivialTool(commands=[likes_to_retry])
+ tool.main(["tool", "likes-to-retry"])
+ self.assertEqual(likes_to_retry.execute_count, 2)
+
+ def test_global_help(self):
+ tool = TrivialTool(commands=[TrivialCommand(), UncommonCommand()])
+ expected_common_commands_help = """Usage: trivial-tool [options] COMMAND [ARGS]
+
+Options:
+ -h, --help show this help message and exit
+
+Common trivial-tool commands:
+ trivial help text
+
+See 'trivial-tool help --all-commands' to list all commands.
+See 'trivial-tool help COMMAND' for more information on a specific command.
+
+"""
+ self._assert_tool_main_outputs(tool, ["tool"], expected_common_commands_help)
+ self._assert_tool_main_outputs(tool, ["tool", "help"], expected_common_commands_help)
+ expected_all_commands_help = """Usage: trivial-tool [options] COMMAND [ARGS]
+
+Options:
+ -h, --help show this help message and exit
+
+All trivial-tool commands:
+ help Display information about this program or its subcommands
+ trivial help text
+ uncommon help text
+
+See 'trivial-tool help --all-commands' to list all commands.
+See 'trivial-tool help COMMAND' for more information on a specific command.
+
+"""
+ self._assert_tool_main_outputs(tool, ["tool", "help", "--all-commands"], expected_all_commands_help)
+ # Test that arguments can be passed before commands as well
+ self._assert_tool_main_outputs(tool, ["tool", "--all-commands", "help"], expected_all_commands_help)
+
+
+ def test_command_help(self):
+ command_with_options = TrivialCommand(options=[make_option("--my_option")], long_help="LONG HELP")
+ tool = TrivialTool(commands=[command_with_options])
+ expected_subcommand_help = "trivial [options] help text\n\nLONG HELP\n\nOptions:\n --my_option=MY_OPTION\n\n"
+ self._assert_tool_main_outputs(tool, ["tool", "help", "trivial"], expected_subcommand_help)
+
+
+if __name__ == "__main__":
+ unittest.main()
diff --git a/Tools/Scripts/webkitpy/tool/steps/__init__.py b/Tools/Scripts/webkitpy/tool/steps/__init__.py
new file mode 100644
index 0000000..64d9d05
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/__init__.py
@@ -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:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above
+# copyright notice, this list of conditions and the following disclaimer
+# in the documentation and/or other materials provided with the
+# distribution.
+# * Neither the name of Google Inc. nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+# FIXME: Is this the right way to do this?
+from webkitpy.tool.steps.applypatch import ApplyPatch
+from webkitpy.tool.steps.applypatchwithlocalcommit import ApplyPatchWithLocalCommit
+from webkitpy.tool.steps.build import Build
+from webkitpy.tool.steps.checkstyle import CheckStyle
+from webkitpy.tool.steps.cleanworkingdirectory import CleanWorkingDirectory
+from webkitpy.tool.steps.cleanworkingdirectorywithlocalcommits import CleanWorkingDirectoryWithLocalCommits
+from webkitpy.tool.steps.closebug import CloseBug
+from webkitpy.tool.steps.closebugforlanddiff import CloseBugForLandDiff
+from webkitpy.tool.steps.closepatch import ClosePatch
+from webkitpy.tool.steps.commit import Commit
+from webkitpy.tool.steps.confirmdiff import ConfirmDiff
+from webkitpy.tool.steps.createbug import CreateBug
+from webkitpy.tool.steps.editchangelog import EditChangeLog
+from webkitpy.tool.steps.ensurebuildersaregreen import EnsureBuildersAreGreen
+from webkitpy.tool.steps.ensurelocalcommitifneeded import EnsureLocalCommitIfNeeded
+from webkitpy.tool.steps.obsoletepatches import ObsoletePatches
+from webkitpy.tool.steps.options import Options
+from webkitpy.tool.steps.postdiff import PostDiff
+from webkitpy.tool.steps.postdiffforcommit import PostDiffForCommit
+from webkitpy.tool.steps.postdiffforrevert import PostDiffForRevert
+from webkitpy.tool.steps.preparechangelogforrevert import PrepareChangeLogForRevert
+from webkitpy.tool.steps.preparechangelog import PrepareChangeLog
+from webkitpy.tool.steps.promptforbugortitle import PromptForBugOrTitle
+from webkitpy.tool.steps.reopenbugafterrollout import ReopenBugAfterRollout
+from webkitpy.tool.steps.revertrevision import RevertRevision
+from webkitpy.tool.steps.runtests import RunTests
+from webkitpy.tool.steps.suggestreviewers import SuggestReviewers
+from webkitpy.tool.steps.updatechangelogswithreviewer import UpdateChangeLogsWithReviewer
+from webkitpy.tool.steps.update import Update
+from webkitpy.tool.steps.validatereviewer import ValidateReviewer
diff --git a/Tools/Scripts/webkitpy/tool/steps/abstractstep.py b/Tools/Scripts/webkitpy/tool/steps/abstractstep.py
new file mode 100644
index 0000000..5525ea0
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/abstractstep.py
@@ -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.
+
+from webkitpy.common.system.deprecated_logging import log
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.common.config.ports import WebKitPort
+from webkitpy.tool.steps.options import Options
+
+
+class AbstractStep(object):
+ def __init__(self, tool, options):
+ self._tool = tool
+ self._options = options
+
+ # FIXME: This should use tool.port()
+ def _run_script(self, script_name, args=None, quiet=False, port=WebKitPort):
+ log("Running %s" % script_name)
+ command = [port.script_path(script_name)]
+ if args:
+ command.extend(args)
+ self._tool.executive.run_and_throw_if_fail(command, quiet)
+
+ def _changed_files(self, state):
+ return self.cached_lookup(state, "changed_files")
+
+ _well_known_keys = {
+ "bug_title": lambda self, state: self._tool.bugs.fetch_bug(state["bug_id"]).title(),
+ "changed_files": lambda self, state: self._tool.scm().changed_files(self._options.git_commit),
+ "diff": lambda self, state: self._tool.scm().create_patch(self._options.git_commit, changed_files=self._changed_files(state)),
+ "changelogs": lambda self, state: self._tool.checkout().modified_changelogs(self._options.git_commit, changed_files=self._changed_files(state)),
+ }
+
+ def cached_lookup(self, state, key, promise=None):
+ if state.get(key):
+ return state[key]
+ if not promise:
+ promise = self._well_known_keys.get(key)
+ state[key] = promise(self, state)
+ return state[key]
+
+ def did_modify_checkout(self, state):
+ state["diff"] = None
+ state["changelogs"] = None
+ state["changed_files"] = None
+
+ @classmethod
+ def options(cls):
+ return [
+ # We need this option here because cached_lookup uses it. :(
+ Options.git_commit,
+ ]
+
+ def run(self, state):
+ raise NotImplementedError, "subclasses must implement"
diff --git a/Tools/Scripts/webkitpy/tool/steps/applypatch.py b/Tools/Scripts/webkitpy/tool/steps/applypatch.py
new file mode 100644
index 0000000..327ac09
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/applypatch.py
@@ -0,0 +1,43 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import log
+
+class ApplyPatch(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.non_interactive,
+ Options.force_patch,
+ ]
+
+ def run(self, state):
+ log("Processing patch %s from bug %s." % (state["patch"].id(), state["patch"].bug_id()))
+ self._tool.checkout().apply_patch(state["patch"], force=self._options.non_interactive or self._options.force_patch)
diff --git a/Tools/Scripts/webkitpy/tool/steps/applypatchwithlocalcommit.py b/Tools/Scripts/webkitpy/tool/steps/applypatchwithlocalcommit.py
new file mode 100644
index 0000000..3dcd8d9
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/applypatchwithlocalcommit.py
@@ -0,0 +1,43 @@
+# 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.
+
+from webkitpy.tool.steps.applypatch import ApplyPatch
+from webkitpy.tool.steps.options import Options
+
+class ApplyPatchWithLocalCommit(ApplyPatch):
+ @classmethod
+ def options(cls):
+ return ApplyPatch.options() + [
+ Options.local_commit,
+ ]
+
+ def run(self, state):
+ ApplyPatch.run(self, state)
+ if self._options.local_commit:
+ commit_message = self._tool.checkout().commit_message_for_this_commit(git_commit=None)
+ self._tool.scm().commit_locally_with_message(commit_message.message() or state["patch"].name())
diff --git a/Tools/Scripts/webkitpy/tool/steps/build.py b/Tools/Scripts/webkitpy/tool/steps/build.py
new file mode 100644
index 0000000..0990b8b
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/build.py
@@ -0,0 +1,54 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import log
+
+
+class Build(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.build,
+ Options.quiet,
+ Options.build_style,
+ ]
+
+ def build(self, build_style):
+ self._tool.executive.run_and_throw_if_fail(self._tool.port().build_webkit_command(build_style=build_style), self._options.quiet)
+
+ def run(self, state):
+ if not self._options.build:
+ return
+ log("Building WebKit")
+ if self._options.build_style == "both":
+ self.build("debug")
+ self.build("release")
+ else:
+ self.build(self._options.build_style)
diff --git a/Tools/Scripts/webkitpy/tool/steps/checkstyle.py b/Tools/Scripts/webkitpy/tool/steps/checkstyle.py
new file mode 100644
index 0000000..af66c50
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/checkstyle.py
@@ -0,0 +1,66 @@
+# 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 os
+
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import error
+
+class CheckStyle(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.non_interactive,
+ Options.check_style,
+ Options.git_commit,
+ ]
+
+ def run(self, state):
+ if not self._options.check_style:
+ return
+ os.chdir(self._tool.scm().checkout_root)
+
+ args = []
+ if self._options.git_commit:
+ args.append("--git-commit")
+ args.append(self._options.git_commit)
+
+ args.append("--diff-files")
+ args.extend(self._changed_files(state))
+
+ try:
+ self._run_script("check-webkit-style", args)
+ except ScriptError, e:
+ if self._options.non_interactive:
+ # We need to re-raise the exception here to have the
+ # style-queue do the right thing.
+ raise e
+ if not self._tool.user.confirm("Are you sure you want to continue?"):
+ exit(1)
diff --git a/Tools/Scripts/webkitpy/tool/steps/cleanworkingdirectory.py b/Tools/Scripts/webkitpy/tool/steps/cleanworkingdirectory.py
new file mode 100644
index 0000000..9c16242
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/cleanworkingdirectory.py
@@ -0,0 +1,54 @@
+# 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 os
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+
+
+class CleanWorkingDirectory(AbstractStep):
+ def __init__(self, tool, options, allow_local_commits=False):
+ AbstractStep.__init__(self, tool, options)
+ self._allow_local_commits = allow_local_commits
+
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.force_clean,
+ Options.clean,
+ ]
+
+ def run(self, state):
+ if not self._options.clean:
+ return
+ # FIXME: This chdir should not be necessary.
+ os.chdir(self._tool.scm().checkout_root)
+ if not self._allow_local_commits:
+ self._tool.scm().ensure_no_local_commits(self._options.force_clean)
+ self._tool.scm().ensure_clean_working_directory(force_clean=self._options.force_clean)
diff --git a/Tools/Scripts/webkitpy/tool/steps/cleanworkingdirectory_unittest.py b/Tools/Scripts/webkitpy/tool/steps/cleanworkingdirectory_unittest.py
new file mode 100644
index 0000000..36a3d2b
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/cleanworkingdirectory_unittest.py
@@ -0,0 +1,49 @@
+# 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 unittest
+
+from webkitpy.thirdparty.mock import Mock
+from webkitpy.tool.mocktool import MockOptions, MockTool
+from webkitpy.tool.steps.cleanworkingdirectory import CleanWorkingDirectory
+
+
+class CleanWorkingDirectoryTest(unittest.TestCase):
+ def test_run(self):
+ tool = MockTool()
+ step = CleanWorkingDirectory(tool, MockOptions(clean=True, force_clean=False))
+ step.run({})
+ self.assertEqual(tool._scm.ensure_no_local_commits.call_count, 1)
+ self.assertEqual(tool._scm.ensure_clean_working_directory.call_count, 1)
+
+ def test_no_clean(self):
+ tool = MockTool()
+ step = CleanWorkingDirectory(tool, MockOptions(clean=False))
+ step.run({})
+ self.assertEqual(tool._scm.ensure_no_local_commits.call_count, 0)
+ self.assertEqual(tool._scm.ensure_clean_working_directory.call_count, 0)
diff --git a/Tools/Scripts/webkitpy/tool/steps/cleanworkingdirectorywithlocalcommits.py b/Tools/Scripts/webkitpy/tool/steps/cleanworkingdirectorywithlocalcommits.py
new file mode 100644
index 0000000..f06f94e
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/cleanworkingdirectorywithlocalcommits.py
@@ -0,0 +1,34 @@
+# 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.
+
+from webkitpy.tool.steps.cleanworkingdirectory import CleanWorkingDirectory
+
+class CleanWorkingDirectoryWithLocalCommits(CleanWorkingDirectory):
+ def __init__(self, tool, options):
+ # FIXME: This a bit of a hack. Consider doing this more cleanly.
+ CleanWorkingDirectory.__init__(self, tool, options, allow_local_commits=True)
diff --git a/Tools/Scripts/webkitpy/tool/steps/closebug.py b/Tools/Scripts/webkitpy/tool/steps/closebug.py
new file mode 100644
index 0000000..e77bc24
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/closebug.py
@@ -0,0 +1,51 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import log
+
+
+class CloseBug(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.close_bug,
+ ]
+
+ def run(self, state):
+ if not self._options.close_bug:
+ return
+ # Check to make sure there are no r? or r+ patches on the bug before closing.
+ # Assume that r- patches are just previous patches someone forgot to obsolete.
+ patches = self._tool.bugs.fetch_bug(state["patch"].bug_id()).patches()
+ for patch in patches:
+ if patch.review() == "?" or patch.review() == "+":
+ log("Not closing bug %s as attachment %s has review=%s. Assuming there are more patches to land from this bug." % (patch.bug_id(), patch.id(), patch.review()))
+ return
+ self._tool.bugs.close_bug_as_fixed(state["patch"].bug_id(), "All reviewed patches have been landed. Closing bug.")
diff --git a/Tools/Scripts/webkitpy/tool/steps/closebugforlanddiff.py b/Tools/Scripts/webkitpy/tool/steps/closebugforlanddiff.py
new file mode 100644
index 0000000..e5a68db
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/closebugforlanddiff.py
@@ -0,0 +1,58 @@
+# 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.
+
+from webkitpy.tool.comments import bug_comment_from_commit_text
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import log
+
+
+class CloseBugForLandDiff(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.close_bug,
+ ]
+
+ def run(self, state):
+ comment_text = bug_comment_from_commit_text(self._tool.scm(), state["commit_text"])
+ bug_id = state.get("bug_id")
+ if not bug_id and state.get("patch"):
+ bug_id = state.get("patch").bug_id()
+
+ if bug_id:
+ log("Updating bug %s" % bug_id)
+ if self._options.close_bug:
+ self._tool.bugs.close_bug_as_fixed(bug_id, comment_text)
+ else:
+ # FIXME: We should a smart way to figure out if the patch is attached
+ # to the bug, and if so obsolete it.
+ self._tool.bugs.post_comment_to_bug(bug_id, comment_text)
+ else:
+ log(comment_text)
+ log("No bug id provided.")
diff --git a/Tools/Scripts/webkitpy/tool/steps/closebugforlanddiff_unittest.py b/Tools/Scripts/webkitpy/tool/steps/closebugforlanddiff_unittest.py
new file mode 100644
index 0000000..0a56564
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/closebugforlanddiff_unittest.py
@@ -0,0 +1,40 @@
+# 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 unittest
+
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.mocktool import MockOptions, MockTool
+from webkitpy.tool.steps.closebugforlanddiff import CloseBugForLandDiff
+
+class CloseBugForLandDiffTest(unittest.TestCase):
+ def test_empty_state(self):
+ capture = OutputCapture()
+ step = CloseBugForLandDiff(MockTool(), MockOptions())
+ expected_stderr = "Committed r49824: <http://trac.webkit.org/changeset/49824>\nNo bug id provided.\n"
+ capture.assert_outputs(self, step.run, [{"commit_text" : "Mock commit text"}], expected_stderr=expected_stderr)
diff --git a/Tools/Scripts/webkitpy/tool/steps/closepatch.py b/Tools/Scripts/webkitpy/tool/steps/closepatch.py
new file mode 100644
index 0000000..ff94df8
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/closepatch.py
@@ -0,0 +1,36 @@
+# 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.
+
+from webkitpy.tool.comments import bug_comment_from_commit_text
+from webkitpy.tool.steps.abstractstep import AbstractStep
+
+
+class ClosePatch(AbstractStep):
+ def run(self, state):
+ comment_text = bug_comment_from_commit_text(self._tool.scm(), state["commit_text"])
+ self._tool.bugs.clear_attachment_flags(state["patch"].id(), comment_text)
diff --git a/Tools/Scripts/webkitpy/tool/steps/commit.py b/Tools/Scripts/webkitpy/tool/steps/commit.py
new file mode 100644
index 0000000..5aa6b51
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/commit.py
@@ -0,0 +1,81 @@
+# 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.
+
+from webkitpy.common.checkout.scm import AuthenticationError, AmbiguousCommitError
+from webkitpy.common.config import urls
+from webkitpy.common.system.deprecated_logging import log
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.common.system.user import User
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+
+
+class Commit(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.git_commit,
+ ]
+
+ def _commit_warning(self, error):
+ working_directory_message = "" if error.working_directory_is_clean else " and working copy changes"
+ return ('There are %s local commits%s. Everything will be committed as a single commit. '
+ 'To avoid this prompt, set "git config webkit-patch.commit-should-always-squash true".' % (
+ error.num_local_commits, working_directory_message))
+
+ def run(self, state):
+ self._commit_message = self._tool.checkout().commit_message_for_this_commit(self._options.git_commit).message()
+ if len(self._commit_message) < 50:
+ raise Exception("Attempted to commit with a commit message shorter than 50 characters. Either your patch is missing a ChangeLog or webkit-patch may have a bug.")
+
+ self._state = state
+
+ username = None
+ force_squash = False
+
+ num_tries = 0
+ while num_tries < 3:
+ num_tries += 1
+
+ try:
+ scm = self._tool.scm()
+ commit_text = scm.commit_with_message(self._commit_message, git_commit=self._options.git_commit, username=username, force_squash=force_squash)
+ svn_revision = scm.svn_revision_from_commit_text(commit_text)
+ log("Committed r%s: <%s>" % (svn_revision, urls.view_revision_url(svn_revision)))
+ self._state["commit_text"] = commit_text
+ break;
+ except AmbiguousCommitError, e:
+ if self._tool.user.confirm(self._commit_warning(e)):
+ force_squash = True
+ else:
+ # This will correctly interrupt the rest of the commit process.
+ raise ScriptError(message="Did not commit")
+ except AuthenticationError, e:
+ username = self._tool.user.prompt("%s login: " % e.server_host, repeat=5)
+ if not username:
+ raise ScriptError("You need to specify the username on %s to perform the commit as." % self.svn_server_host)
diff --git a/Tools/Scripts/webkitpy/tool/steps/confirmdiff.py b/Tools/Scripts/webkitpy/tool/steps/confirmdiff.py
new file mode 100644
index 0000000..7e8e348
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/confirmdiff.py
@@ -0,0 +1,77 @@
+# 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 urllib
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.prettypatch import PrettyPatch
+from webkitpy.common.system import logutils
+from webkitpy.common.system.executive import ScriptError
+
+
+_log = logutils.get_logger(__file__)
+
+
+class ConfirmDiff(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.confirm,
+ ]
+
+ def _show_pretty_diff(self, diff):
+ if not self._tool.user.can_open_url():
+ return None
+
+ try:
+ pretty_patch = PrettyPatch(self._tool.executive,
+ self._tool.scm().checkout_root)
+ pretty_diff_file = pretty_patch.pretty_diff_file(diff)
+ url = "file://%s" % urllib.quote(pretty_diff_file.name)
+ self._tool.user.open_url(url)
+ # We return the pretty_diff_file here because we need to keep the
+ # file alive until the user has had a chance to confirm the diff.
+ return pretty_diff_file
+ except ScriptError, e:
+ _log.warning("PrettyPatch failed. :(")
+ except OSError, e:
+ _log.warning("PrettyPatch unavailable.")
+
+ def run(self, state):
+ if not self._options.confirm:
+ return
+ diff = self.cached_lookup(state, "diff")
+ pretty_diff_file = self._show_pretty_diff(diff)
+ if not pretty_diff_file:
+ self._tool.user.page(diff)
+ diff_correct = self._tool.user.confirm("Was that diff correct?")
+ if pretty_diff_file:
+ pretty_diff_file.close()
+ if not diff_correct:
+ exit(1)
diff --git a/Tools/Scripts/webkitpy/tool/steps/createbug.py b/Tools/Scripts/webkitpy/tool/steps/createbug.py
new file mode 100644
index 0000000..0ab6f68
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/createbug.py
@@ -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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+
+
+class CreateBug(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.cc,
+ Options.component,
+ Options.blocks,
+ ]
+
+ def run(self, state):
+ # No need to create a bug if we already have one.
+ if state.get("bug_id"):
+ return
+ cc = self._options.cc
+ if not cc:
+ cc = state.get("bug_cc")
+ blocks = self._options.blocks
+ if not blocks:
+ blocks = state.get("bug_blocked")
+ state["bug_id"] = self._tool.bugs.create_bug(state["bug_title"], state["bug_description"], blocked=blocks, component=self._options.component, cc=cc)
diff --git a/Tools/Scripts/webkitpy/tool/steps/editchangelog.py b/Tools/Scripts/webkitpy/tool/steps/editchangelog.py
new file mode 100644
index 0000000..4d9646f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/editchangelog.py
@@ -0,0 +1,38 @@
+# 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 os
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+
+
+class EditChangeLog(AbstractStep):
+ def run(self, state):
+ os.chdir(self._tool.scm().checkout_root)
+ self._tool.user.edit_changelog(self.cached_lookup(state, "changelogs"))
+ self.did_modify_checkout(state)
diff --git a/Tools/Scripts/webkitpy/tool/steps/ensurebuildersaregreen.py b/Tools/Scripts/webkitpy/tool/steps/ensurebuildersaregreen.py
new file mode 100644
index 0000000..a4fc174
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/ensurebuildersaregreen.py
@@ -0,0 +1,48 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import log, error
+
+
+class EnsureBuildersAreGreen(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.check_builders,
+ ]
+
+ def run(self, state):
+ if not self._options.check_builders:
+ return
+ red_builders_names = self._tool.buildbot.red_core_builders_names()
+ if not red_builders_names:
+ return
+ red_builders_names = map(lambda name: "\"%s\"" % name, red_builders_names) # Add quotes around the names.
+ log("\nWARNING: Builders [%s] are red, please watch your commit carefully.\nSee http://%s/console?category=core\n" % (", ".join(red_builders_names), self._tool.buildbot.buildbot_host))
diff --git a/Tools/Scripts/webkitpy/tool/steps/ensurelocalcommitifneeded.py b/Tools/Scripts/webkitpy/tool/steps/ensurelocalcommitifneeded.py
new file mode 100644
index 0000000..d0cda46
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/ensurelocalcommitifneeded.py
@@ -0,0 +1,43 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import error
+
+
+class EnsureLocalCommitIfNeeded(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.local_commit,
+ ]
+
+ def run(self, state):
+ if self._options.local_commit and not self._tool.scm().supports_local_commits():
+ error("--local-commit passed, but %s does not support local commits" % self._tool.scm.display_name())
diff --git a/Tools/Scripts/webkitpy/tool/steps/metastep.py b/Tools/Scripts/webkitpy/tool/steps/metastep.py
new file mode 100644
index 0000000..7cbd1c5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/metastep.py
@@ -0,0 +1,54 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+
+
+# FIXME: Unify with StepSequence? I'm not sure yet which is the better design.
+class MetaStep(AbstractStep):
+ substeps = [] # Override in subclasses
+ def __init__(self, tool, options):
+ AbstractStep.__init__(self, tool, options)
+ self._step_instances = []
+ for step_class in self.substeps:
+ self._step_instances.append(step_class(tool, options))
+
+ @staticmethod
+ def _collect_options_from_steps(steps):
+ collected_options = []
+ for step in steps:
+ collected_options = collected_options + step.options()
+ return collected_options
+
+ @classmethod
+ def options(cls):
+ return cls._collect_options_from_steps(cls.substeps)
+
+ def run(self, state):
+ for step in self._step_instances:
+ step.run(state)
diff --git a/Tools/Scripts/webkitpy/tool/steps/obsoletepatches.py b/Tools/Scripts/webkitpy/tool/steps/obsoletepatches.py
new file mode 100644
index 0000000..de508c6
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/obsoletepatches.py
@@ -0,0 +1,51 @@
+# 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.
+
+from webkitpy.tool.grammar import pluralize
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import log
+
+
+class ObsoletePatches(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.obsolete_patches,
+ ]
+
+ def run(self, state):
+ if not self._options.obsolete_patches:
+ return
+ bug_id = state["bug_id"]
+ patches = self._tool.bugs.fetch_bug(bug_id).patches()
+ if not patches:
+ return
+ log("Obsoleting %s on bug %s" % (pluralize("old patch", len(patches)), bug_id))
+ for patch in patches:
+ self._tool.bugs.obsolete_attachment(patch.id())
diff --git a/Tools/Scripts/webkitpy/tool/steps/options.py b/Tools/Scripts/webkitpy/tool/steps/options.py
new file mode 100644
index 0000000..5b8baf0
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/options.py
@@ -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:
+#
+# * 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.
+
+from optparse import make_option
+
+class Options(object):
+ blocks = make_option("--blocks", action="store", type="string", dest="blocks", default=None, help="Bug number which the created bug blocks.")
+ build = make_option("--build", action="store_true", dest="build", default=False, help="Build and run run-webkit-tests before committing.")
+ build_style = make_option("--build-style", action="store", dest="build_style", default=None, help="Whether to build debug, release, or both.")
+ cc = make_option("--cc", action="store", type="string", dest="cc", help="Comma-separated list of email addresses to carbon-copy.")
+ check_builders = make_option("--ignore-builders", action="store_false", dest="check_builders", default=True, help="Don't check to see if the build.webkit.org builders are green before landing.")
+ check_style = make_option("--ignore-style", action="store_false", dest="check_style", default=True, help="Don't check to see if the patch has proper style before uploading.")
+ clean = make_option("--no-clean", action="store_false", dest="clean", default=True, help="Don't check if the working directory is clean before applying patches")
+ close_bug = make_option("--no-close", action="store_false", dest="close_bug", default=True, help="Leave bug open after landing.")
+ comment = make_option("--comment", action="store", type="string", dest="comment", help="Comment to post to bug.")
+ component = make_option("--component", action="store", type="string", dest="component", help="Component for the new bug.")
+ confirm = make_option("--no-confirm", action="store_false", dest="confirm", default=True, help="Skip confirmation steps.")
+ description = make_option("-m", "--description", action="store", type="string", dest="description", help="Description string for the attachment (default: \"patch\")")
+ email = make_option("--email", action="store", type="string", dest="email", help="Email address to use in ChangeLogs.")
+ force_clean = make_option("--force-clean", action="store_true", dest="force_clean", default=False, help="Clean working directory before applying patches (removes local changes and commits)")
+ force_patch = make_option("--force-patch", action="store_true", dest="force_patch", default=False, help="Forcefully applies the patch, continuing past errors.")
+ git_commit = make_option("-g", "--git-commit", action="store", dest="git_commit", help="Operate on a local commit. If a range, the commits are squashed into one. HEAD.. operates on working copy changes only.")
+ local_commit = make_option("--local-commit", action="store_true", dest="local_commit", default=False, help="Make a local commit for each applied patch")
+ non_interactive = make_option("--non-interactive", action="store_true", dest="non_interactive", default=False, help="Never prompt the user, fail as fast as possible.")
+ obsolete_patches = make_option("--no-obsolete", action="store_false", dest="obsolete_patches", default=True, help="Do not obsolete old patches before posting this one.")
+ open_bug = make_option("--open-bug", action="store_true", dest="open_bug", default=False, help="Opens the associated bug in a browser.")
+ parent_command = make_option("--parent-command", action="store", dest="parent_command", default=None, help="(Internal) The command that spawned this instance.")
+ quiet = make_option("--quiet", action="store_true", dest="quiet", default=False, help="Produce less console output.")
+ request_commit = make_option("--request-commit", action="store_true", dest="request_commit", default=False, help="Mark the patch as needing auto-commit after review.")
+ review = make_option("--no-review", action="store_false", dest="review", default=True, help="Do not mark the patch for review.")
+ reviewer = make_option("-r", "--reviewer", action="store", type="string", dest="reviewer", help="Update ChangeLogs to say Reviewed by REVIEWER.")
+ suggest_reviewers = make_option("--suggest-reviewers", action="store_true", default=False, help="Offer to CC appropriate reviewers.")
+ test = make_option("--test", action="store_true", dest="test", default=False, help="Run run-webkit-tests before committing.")
+ update = make_option("--no-update", action="store_false", dest="update", default=True, help="Don't update the working directory.")
diff --git a/Tools/Scripts/webkitpy/tool/steps/postdiff.py b/Tools/Scripts/webkitpy/tool/steps/postdiff.py
new file mode 100644
index 0000000..c40b6ff
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/postdiff.py
@@ -0,0 +1,50 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+
+
+class PostDiff(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.description,
+ Options.comment,
+ Options.review,
+ Options.request_commit,
+ Options.open_bug,
+ ]
+
+ def run(self, state):
+ diff = self.cached_lookup(state, "diff")
+ description = self._options.description or "Patch"
+ comment_text = self._options.comment
+ self._tool.bugs.add_patch_to_bug(state["bug_id"], diff, description, comment_text=comment_text, mark_for_review=self._options.review, mark_for_commit_queue=self._options.request_commit)
+ if self._options.open_bug:
+ self._tool.user.open_url(self._tool.bugs.bug_url_for_bug_id(state["bug_id"]))
diff --git a/Tools/Scripts/webkitpy/tool/steps/postdiffforcommit.py b/Tools/Scripts/webkitpy/tool/steps/postdiffforcommit.py
new file mode 100644
index 0000000..13bc00c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/postdiffforcommit.py
@@ -0,0 +1,39 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+
+
+class PostDiffForCommit(AbstractStep):
+ def run(self, state):
+ self._tool.bugs.add_patch_to_bug(
+ state["bug_id"],
+ self.cached_lookup(state, "diff"),
+ "Patch for landing",
+ mark_for_review=False,
+ mark_for_landing=True)
diff --git a/Tools/Scripts/webkitpy/tool/steps/postdiffforrevert.py b/Tools/Scripts/webkitpy/tool/steps/postdiffforrevert.py
new file mode 100644
index 0000000..bfa631f
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/postdiffforrevert.py
@@ -0,0 +1,49 @@
+# 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.
+
+from webkitpy.common.net.bugzilla import Attachment
+from webkitpy.tool.steps.abstractstep import AbstractStep
+
+
+class PostDiffForRevert(AbstractStep):
+ def run(self, state):
+ comment_text = "Any committer can land this patch automatically by \
+marking it commit-queue+. The commit-queue will build and test \
+the patch before landing to ensure that the rollout will be \
+successful. This process takes approximately 15 minutes.\n\n\
+If you would like to land the rollout faster, you can use the \
+following command:\n\n\
+ webkit-patch land-attachment ATTACHMENT_ID --ignore-builders\n\n\
+where ATTACHMENT_ID is the ID of this attachment."
+ self._tool.bugs.add_patch_to_bug(
+ state["bug_id"],
+ self.cached_lookup(state, "diff"),
+ "%s%s" % (Attachment.rollout_preamble, state["revision"]),
+ comment_text=comment_text,
+ mark_for_review=False,
+ mark_for_commit_queue=True)
diff --git a/Tools/Scripts/webkitpy/tool/steps/preparechangelog.py b/Tools/Scripts/webkitpy/tool/steps/preparechangelog.py
new file mode 100644
index 0000000..099dfe3
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/preparechangelog.py
@@ -0,0 +1,77 @@
+# 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 os
+
+from webkitpy.common.checkout.changelog import ChangeLog
+from webkitpy.common.system.executive import ScriptError
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import error
+
+
+class PrepareChangeLog(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.quiet,
+ Options.email,
+ Options.git_commit,
+ ]
+
+ def _ensure_bug_url(self, state):
+ if not state.get("bug_id"):
+ return
+ bug_id = state.get("bug_id")
+ changelogs = self.cached_lookup(state, "changelogs")
+ for changelog_path in changelogs:
+ changelog = ChangeLog(changelog_path)
+ if not changelog.latest_entry().bug_id():
+ changelog.set_short_description_and_bug_url(
+ self.cached_lookup(state, "bug_title"),
+ self._tool.bugs.bug_url_for_bug_id(bug_id))
+
+ def run(self, state):
+ if self.cached_lookup(state, "changelogs"):
+ self._ensure_bug_url(state)
+ return
+ os.chdir(self._tool.scm().checkout_root)
+ args = [self._tool.port().script_path("prepare-ChangeLog")]
+ if state.get("bug_id"):
+ args.append("--bug=%s" % state["bug_id"])
+ if self._options.email:
+ args.append("--email=%s" % self._options.email)
+
+ if self._tool.scm().supports_local_commits():
+ args.append("--merge-base=%s" % self._tool.scm().merge_base(self._options.git_commit))
+
+ try:
+ self._tool.executive.run_and_throw_if_fail(args, self._options.quiet)
+ except ScriptError, e:
+ error("Unable to prepare ChangeLogs.")
+ self.did_modify_checkout(state)
diff --git a/Tools/Scripts/webkitpy/tool/steps/preparechangelog_unittest.py b/Tools/Scripts/webkitpy/tool/steps/preparechangelog_unittest.py
new file mode 100644
index 0000000..eceffdf
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/preparechangelog_unittest.py
@@ -0,0 +1,54 @@
+# 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 os
+import unittest
+
+from webkitpy.common.checkout.changelog_unittest import ChangeLogTest
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.mocktool import MockOptions, MockTool
+from webkitpy.tool.steps.preparechangelog import PrepareChangeLog
+
+
+class PrepareChangeLogTest(ChangeLogTest):
+ def test_ensure_bug_url(self):
+ capture = OutputCapture()
+ step = PrepareChangeLog(MockTool(), MockOptions())
+ changelog_contents = u"%s\n%s" % (self._new_entry_boilerplate, self._example_changelog)
+ changelog_path = self._write_tmp_file_with_contents(changelog_contents.encode("utf-8"))
+ state = {
+ "bug_title": "Example title",
+ "bug_id": 1234,
+ "changelogs": [changelog_path],
+ }
+ capture.assert_outputs(self, step.run, [state])
+ actual_contents = self._read_file_contents(changelog_path, "utf-8")
+ expected_message = "Example title\n http://example.com/1234"
+ expected_contents = changelog_contents.replace("Need a short description and bug URL (OOPS!)", expected_message)
+ os.remove(changelog_path)
+ self.assertEquals(actual_contents, expected_contents)
diff --git a/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py b/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py
new file mode 100644
index 0000000..1e47a6a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/preparechangelogforrevert.py
@@ -0,0 +1,44 @@
+# 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 os
+
+from webkitpy.common.checkout.changelog import ChangeLog
+from webkitpy.tool.steps.abstractstep import AbstractStep
+
+
+class PrepareChangeLogForRevert(AbstractStep):
+ def run(self, state):
+ # This could move to prepare-ChangeLog by adding a --revert= option.
+ self._run_script("prepare-ChangeLog")
+ changelog_paths = self._tool.checkout().modified_changelogs(git_commit=None)
+ bug_url = self._tool.bugs.bug_url_for_bug_id(state["bug_id"]) if state["bug_id"] else None
+ for changelog_path in changelog_paths:
+ # FIXME: Seems we should prepare the message outside of changelogs.py and then just pass in
+ # text that we want to use to replace the reviewed by line.
+ ChangeLog(changelog_path).update_for_revert(state["revision_list"], state["reason"], bug_url)
diff --git a/Tools/Scripts/webkitpy/tool/steps/promptforbugortitle.py b/Tools/Scripts/webkitpy/tool/steps/promptforbugortitle.py
new file mode 100644
index 0000000..31c913c
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/promptforbugortitle.py
@@ -0,0 +1,45 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+
+
+class PromptForBugOrTitle(AbstractStep):
+ def run(self, state):
+ # No need to prompt if we alrady have the bug_id.
+ if state.get("bug_id"):
+ return
+ user_response = self._tool.user.prompt("Please enter a bug number or a title for a new bug:\n")
+ # If the user responds with a number, we assume it's bug number.
+ # Otherwise we assume it's a bug subject.
+ try:
+ state["bug_id"] = int(user_response)
+ except ValueError, TypeError:
+ state["bug_title"] = user_response
+ # FIXME: This is kind of a lame description.
+ state["bug_description"] = user_response
diff --git a/Tools/Scripts/webkitpy/tool/steps/reopenbugafterrollout.py b/Tools/Scripts/webkitpy/tool/steps/reopenbugafterrollout.py
new file mode 100644
index 0000000..f369ca9
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/reopenbugafterrollout.py
@@ -0,0 +1,44 @@
+# 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.
+
+from webkitpy.tool.comments import bug_comment_from_commit_text
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.common.system.deprecated_logging import log
+
+
+class ReopenBugAfterRollout(AbstractStep):
+ def run(self, state):
+ commit_comment = bug_comment_from_commit_text(self._tool.scm(), state["commit_text"])
+ comment_text = "Reverted r%s for reason:\n\n%s\n\n%s" % (state["revision"], state["reason"], commit_comment)
+
+ bug_id = state["bug_id"]
+ if not bug_id:
+ log(comment_text)
+ log("No bugs were updated.")
+ return
+ self._tool.bugs.reopen_bug(bug_id, comment_text)
diff --git a/Tools/Scripts/webkitpy/tool/steps/revertrevision.py b/Tools/Scripts/webkitpy/tool/steps/revertrevision.py
new file mode 100644
index 0000000..8016be5
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/revertrevision.py
@@ -0,0 +1,35 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+
+
+class RevertRevision(AbstractStep):
+ def run(self, state):
+ self._tool.checkout().apply_reverse_diffs(state["revision_list"])
+ self.did_modify_checkout(state)
diff --git a/Tools/Scripts/webkitpy/tool/steps/runtests.py b/Tools/Scripts/webkitpy/tool/steps/runtests.py
new file mode 100644
index 0000000..282e381
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/runtests.py
@@ -0,0 +1,81 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import log
+
+class RunTests(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.test,
+ Options.non_interactive,
+ Options.quiet,
+ ]
+
+ def run(self, state):
+ if not self._options.test:
+ return
+
+ # Run the scripting unit tests first because they're quickest.
+ log("Running Python unit tests")
+ self._tool.executive.run_and_throw_if_fail(self._tool.port().run_python_unittests_command())
+ log("Running Perl unit tests")
+ self._tool.executive.run_and_throw_if_fail(self._tool.port().run_perl_unittests_command())
+
+ javascriptcore_tests_command = self._tool.port().run_javascriptcore_tests_command()
+ if javascriptcore_tests_command:
+ log("Running JavaScriptCore tests")
+ self._tool.executive.run_and_throw_if_fail(javascriptcore_tests_command, quiet=True)
+
+ log("Running run-webkit-tests")
+ args = self._tool.port().run_webkit_tests_command()
+ if self._options.non_interactive:
+ args.append("--no-new-test-results")
+ args.append("--no-launch-safari")
+ args.append("--exit-after-n-failures=1")
+ args.append("--wait-for-httpd")
+ # FIXME: Hack to work around https://bugs.webkit.org/show_bug.cgi?id=38912
+ # when running the commit-queue on a mac leopard machine since compositing
+ # does not work reliably on Leopard due to various graphics driver/system bugs.
+ if self._tool.port().name() == "Mac" and self._tool.port().is_leopard():
+ tests_to_ignore = []
+ tests_to_ignore.append("compositing")
+
+ # media tests are also broken on mac leopard due to
+ # a separate CoreVideo bug which causes random crashes/hangs
+ # https://bugs.webkit.org/show_bug.cgi?id=38912
+ tests_to_ignore.append("media")
+
+ args.extend(["--ignore-tests", ",".join(tests_to_ignore)])
+
+ if self._options.quiet:
+ args.append("--quiet")
+ self._tool.executive.run_and_throw_if_fail(args)
+
diff --git a/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py b/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py
new file mode 100644
index 0000000..783ae29
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/steps_unittest.py
@@ -0,0 +1,92 @@
+# 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 unittest
+
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.common.config.ports import WebKitPort
+from webkitpy.tool.mocktool import MockOptions, MockTool
+from webkitpy.tool.steps.update import Update
+from webkitpy.tool.steps.runtests import RunTests
+from webkitpy.tool.steps.promptforbugortitle import PromptForBugOrTitle
+
+
+class StepsTest(unittest.TestCase):
+ def _step_options(self):
+ options = MockOptions()
+ options.non_interactive = True
+ options.port = 'MOCK port'
+ options.quiet = True
+ options.test = True
+ return options
+
+ def _run_step(self, step, tool=None, options=None, state=None):
+ if not tool:
+ tool = MockTool()
+ if not options:
+ options = self._step_options()
+ if not state:
+ state = {}
+ step(tool, options).run(state)
+
+ def test_update_step(self):
+ tool = MockTool()
+ options = self._step_options()
+ options.update = True
+ expected_stderr = "Updating working directory\n"
+ OutputCapture().assert_outputs(self, self._run_step, [Update, tool, options], expected_stderr=expected_stderr)
+
+ def test_prompt_for_bug_or_title_step(self):
+ tool = MockTool()
+ tool.user.prompt = lambda message: 42
+ self._run_step(PromptForBugOrTitle, tool=tool)
+
+ def test_runtests_leopard_commit_queue_hack_step(self):
+ expected_stderr = "Running Python unit tests\nRunning Perl unit tests\nRunning JavaScriptCore tests\nRunning run-webkit-tests\n"
+ OutputCapture().assert_outputs(self, self._run_step, [RunTests], expected_stderr=expected_stderr)
+
+ def test_runtests_leopard_commit_queue_hack_command(self):
+ mock_options = self._step_options()
+ step = RunTests(MockTool(log_executive=True), mock_options)
+ # FIXME: We shouldn't use a real port-object here, but there is too much to mock at the moment.
+ mock_port = WebKitPort()
+ mock_port.name = lambda: "Mac"
+ mock_port.is_leopard = lambda: True
+ tool = MockTool(log_executive=True)
+ tool.port = lambda: mock_port
+ step = RunTests(tool, mock_options)
+ expected_stderr = """Running Python unit tests
+MOCK run_and_throw_if_fail: ['Tools/Scripts/test-webkitpy']
+Running Perl unit tests
+MOCK run_and_throw_if_fail: ['Tools/Scripts/test-webkitperl']
+Running JavaScriptCore tests
+MOCK run_and_throw_if_fail: ['Tools/Scripts/run-javascriptcore-tests']
+Running run-webkit-tests
+MOCK run_and_throw_if_fail: ['Tools/Scripts/run-webkit-tests', '--no-new-test-results', '--no-launch-safari', '--exit-after-n-failures=1', '--wait-for-httpd', '--ignore-tests', 'compositing,media', '--quiet']
+"""
+ OutputCapture().assert_outputs(self, step.run, [{}], expected_stderr=expected_stderr)
diff --git a/Tools/Scripts/webkitpy/tool/steps/suggestreviewers.py b/Tools/Scripts/webkitpy/tool/steps/suggestreviewers.py
new file mode 100644
index 0000000..76bef35
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/suggestreviewers.py
@@ -0,0 +1,51 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+
+
+class SuggestReviewers(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.git_commit,
+ Options.suggest_reviewers,
+ ]
+
+ def run(self, state):
+ if not self._options.suggest_reviewers:
+ return
+
+ reviewers = self._tool.checkout().suggested_reviewers(self._options.git_commit, self._changed_files(state))
+ print "The following reviewers have recently modified files in your patch:"
+ print "\n".join([reviewer.full_name for reviewer in reviewers])
+ if not self._tool.user.confirm("Would you like to CC them?"):
+ return
+ reviewer_emails = [reviewer.bugzilla_email() for reviewer in reviewers]
+ self._tool.bugs.add_cc_to_bug(state['bug_id'], reviewer_emails)
diff --git a/Tools/Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py b/Tools/Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py
new file mode 100644
index 0000000..0c86535
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/suggestreviewers_unittest.py
@@ -0,0 +1,45 @@
+# 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 unittest
+
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.mocktool import MockOptions, MockTool
+from webkitpy.tool.steps.suggestreviewers import SuggestReviewers
+
+
+class SuggestReviewersTest(unittest.TestCase):
+ def test_disabled(self):
+ step = SuggestReviewers(MockTool(), MockOptions(suggest_reviewers=False))
+ OutputCapture().assert_outputs(self, step.run, [{}])
+
+ def test_basic(self):
+ capture = OutputCapture()
+ step = SuggestReviewers(MockTool(), MockOptions(suggest_reviewers=True, git_commit=None))
+ expected_stdout = "The following reviewers have recently modified files in your patch:\nFoo Bar\nWould you like to CC them?\n"
+ capture.assert_outputs(self, step.run, [{"bug_id": "123"}], expected_stdout=expected_stdout)
diff --git a/Tools/Scripts/webkitpy/tool/steps/update.py b/Tools/Scripts/webkitpy/tool/steps/update.py
new file mode 100644
index 0000000..cd1d4d8
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/update.py
@@ -0,0 +1,45 @@
+# 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.
+
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import log
+
+
+class Update(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.update,
+ ]
+
+ def run(self, state):
+ if not self._options.update:
+ return
+ log("Updating working directory")
+ self._tool.executive.run_and_throw_if_fail(self._tool.port().update_webkit_command(), quiet=True)
diff --git a/Tools/Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittest.py b/Tools/Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittest.py
new file mode 100644
index 0000000..b475378
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/updatechangelogswithreview_unittest.py
@@ -0,0 +1,48 @@
+# 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 unittest
+
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.mocktool import MockOptions, MockTool
+from webkitpy.tool.steps.updatechangelogswithreviewer import UpdateChangeLogsWithReviewer
+
+class UpdateChangeLogsWithReviewerTest(unittest.TestCase):
+ def test_guess_reviewer_from_bug(self):
+ capture = OutputCapture()
+ step = UpdateChangeLogsWithReviewer(MockTool(), MockOptions())
+ expected_stderr = "0 reviewed patches on bug 75, cannot infer reviewer.\n"
+ capture.assert_outputs(self, step._guess_reviewer_from_bug, [75], expected_stderr=expected_stderr)
+
+ def test_empty_state(self):
+ capture = OutputCapture()
+ options = MockOptions()
+ options.reviewer = 'MOCK reviewer'
+ options.git_commit = 'MOCK git commit'
+ step = UpdateChangeLogsWithReviewer(MockTool(), options)
+ capture.assert_outputs(self, step.run, [{}])
diff --git a/Tools/Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py b/Tools/Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py
new file mode 100644
index 0000000..e46b790
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/updatechangelogswithreviewer.py
@@ -0,0 +1,72 @@
+# 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 os
+
+from webkitpy.common.checkout.changelog import ChangeLog
+from webkitpy.tool.grammar import pluralize
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import log, error
+
+class UpdateChangeLogsWithReviewer(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.git_commit,
+ Options.reviewer,
+ ]
+
+ def _guess_reviewer_from_bug(self, bug_id):
+ patches = self._tool.bugs.fetch_bug(bug_id).reviewed_patches()
+ if len(patches) != 1:
+ log("%s on bug %s, cannot infer reviewer." % (pluralize("reviewed patch", len(patches)), bug_id))
+ return None
+ patch = patches[0]
+ log("Guessing \"%s\" as reviewer from attachment %s on bug %s." % (patch.reviewer().full_name, patch.id(), bug_id))
+ return patch.reviewer().full_name
+
+ def run(self, state):
+ bug_id = state.get("bug_id")
+ if not bug_id and state.get("patch"):
+ bug_id = state.get("patch").bug_id()
+
+ reviewer = self._options.reviewer
+ if not reviewer:
+ if not bug_id:
+ log("No bug id provided and --reviewer= not provided. Not updating ChangeLogs with reviewer.")
+ return
+ reviewer = self._guess_reviewer_from_bug(bug_id)
+
+ if not reviewer:
+ log("Failed to guess reviewer from bug %s and --reviewer= not provided. Not updating ChangeLogs with reviewer." % bug_id)
+ return
+
+ os.chdir(self._tool.scm().checkout_root)
+ for changelog_path in self.cached_lookup(state, "changelogs"):
+ ChangeLog(changelog_path).set_reviewer(reviewer)
diff --git a/Tools/Scripts/webkitpy/tool/steps/validatereviewer.py b/Tools/Scripts/webkitpy/tool/steps/validatereviewer.py
new file mode 100644
index 0000000..bdf729e
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/validatereviewer.py
@@ -0,0 +1,71 @@
+# 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 os
+import re
+
+from webkitpy.common.checkout.changelog import ChangeLog
+from webkitpy.tool.steps.abstractstep import AbstractStep
+from webkitpy.tool.steps.options import Options
+from webkitpy.common.system.deprecated_logging import error, log
+
+
+# FIXME: Some of this logic should probably be unified with CommitterValidator?
+class ValidateReviewer(AbstractStep):
+ @classmethod
+ def options(cls):
+ return AbstractStep.options() + [
+ Options.git_commit,
+ ]
+
+ # FIXME: This should probably move onto ChangeLogEntry
+ def _has_valid_reviewer(self, changelog_entry):
+ if changelog_entry.reviewer():
+ return True
+ if re.search("unreviewed", changelog_entry.contents(), re.IGNORECASE):
+ return True
+ if re.search("rubber[ -]stamp", changelog_entry.contents(), re.IGNORECASE):
+ return True
+ return False
+
+ def run(self, state):
+ # FIXME: For now we disable this check when a user is driving the script
+ # this check is too draconian (and too poorly tested) to foist upon users.
+ if not self._options.non_interactive:
+ return
+ # FIXME: We should figure out how to handle the current working
+ # directory issue more globally.
+ os.chdir(self._tool.scm().checkout_root)
+ for changelog_path in self.cached_lookup(state, "changelogs"):
+ changelog_entry = ChangeLog(changelog_path).latest_entry()
+ if self._has_valid_reviewer(changelog_entry):
+ continue
+ reviewer_text = changelog_entry.reviewer_text()
+ if reviewer_text:
+ log("%s found in %s does not appear to be a valid reviewer according to committers.py." % (reviewer_text, changelog_path))
+ error('%s neither lists a valid reviewer nor contains the string "Unreviewed" or "Rubber stamp" (case insensitive).' % changelog_path)
diff --git a/Tools/Scripts/webkitpy/tool/steps/validatereviewer_unittest.py b/Tools/Scripts/webkitpy/tool/steps/validatereviewer_unittest.py
new file mode 100644
index 0000000..d9b856a
--- /dev/null
+++ b/Tools/Scripts/webkitpy/tool/steps/validatereviewer_unittest.py
@@ -0,0 +1,57 @@
+# 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 unittest
+
+from webkitpy.common.checkout.changelog import ChangeLogEntry
+from webkitpy.common.system.outputcapture import OutputCapture
+from webkitpy.tool.mocktool import MockOptions, MockTool
+from webkitpy.tool.steps.validatereviewer import ValidateReviewer
+
+class ValidateReviewerTest(unittest.TestCase):
+ _boilerplate_entry = '''2009-08-19 Eric Seidel <eric@webkit.org>
+
+ REVIEW_LINE
+
+ * Scripts/bugzilla-tool:
+'''
+
+ def _test_review_text(self, step, text, expected):
+ contents = self._boilerplate_entry.replace("REVIEW_LINE", text)
+ entry = ChangeLogEntry(contents)
+ self.assertEqual(step._has_valid_reviewer(entry), expected)
+
+ def test_has_valid_reviewer(self):
+ step = ValidateReviewer(MockTool(), MockOptions())
+ self._test_review_text(step, "Reviewed by Eric Seidel.", True)
+ self._test_review_text(step, "Reviewed by Eric Seidel", True) # Not picky about the '.'
+ self._test_review_text(step, "Reviewed by Eric.", False)
+ self._test_review_text(step, "Reviewed by Eric C Seidel.", False)
+ self._test_review_text(step, "Rubber-stamped by Eric.", True)
+ self._test_review_text(step, "Rubber stamped by Eric.", True)
+ self._test_review_text(step, "Unreviewed build fix.", True)
diff --git a/Tools/Scripts/wkstyle b/Tools/Scripts/wkstyle
new file mode 100755
index 0000000..4b3447f
--- /dev/null
+++ b/Tools/Scripts/wkstyle
@@ -0,0 +1,89 @@
+
+# Copyright (C) 2006 Michael Emmel<mike.emmel@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.
+# 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.
+
+cmdcpp="astyle \
+--unpad=paren \
+--style=linux \
+--brackets=linux \
+--indent=spaces=4 \
+--indent-switches \
+--convert-tabs"
+
+cmdh="astyle \
+--unpad=paren \
+--style=linux \
+--brackets=break \
+--indent=spaces=4 \
+--convert-tabs"
+
+#astyle does not support unpadding so we use sed
+for i in $@
+do
+echo $i
+
+ext=`echo $i|awk -F . '{print $NF}'`
+
+cmd=$cmdcpp
+
+if [ $ext == "h" ] ; then
+ cmd=$cmdh
+fi
+
+$cmd $i
+
+#first print the changes we are making
+sed -n -e '
+/( .*/p
+s/( /(/gp
+/*. )/p
+s/ )/)/gp
+#supress printing this
+#/^namespace WebCore/{
+#N
+#s/\n{/ {/p
+#}
+' $i
+
+#do it for real
+sed -e '
+#unpad leading spaces
+s/( /(/g
+#unpad traling spaces
+s/ )/)/g
+#fixup the namspec decl
+/^namespace WebCore/{
+N
+s/\n{/ {/
+}
+#fixup extra tab in constructor initalizer
+/^ \+,/{s/^ //}
+/^ \+:/{s/^ //}
+' $i > $i.sed
+mv $i.sed $i
+done
+
+
diff --git a/Tools/TestResultServer/app.yaml b/Tools/TestResultServer/app.yaml
new file mode 100644
index 0000000..e51af84
--- /dev/null
+++ b/Tools/TestResultServer/app.yaml
@@ -0,0 +1,19 @@
+application: test-results
+version: 1
+runtime: python
+api_version: 1
+
+handlers:
+- url: /stylesheets
+ static_dir: stylesheets
+
+- url: /testfile/delete
+ script: main.py
+ login: admin
+
+- url: /dashboards/delete
+ script: main.py
+ login: admin
+
+- url: /.*
+ script: main.py
diff --git a/Tools/TestResultServer/handlers/__init__.py b/Tools/TestResultServer/handlers/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/TestResultServer/handlers/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/TestResultServer/handlers/dashboardhandler.py b/Tools/TestResultServer/handlers/dashboardhandler.py
new file mode 100644
index 0000000..c8b5ace
--- /dev/null
+++ b/Tools/TestResultServer/handlers/dashboardhandler.py
@@ -0,0 +1,123 @@
+# 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 logging
+import mimetypes
+import urllib2
+
+from google.appengine.api import users
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+from model.dashboardfile import DashboardFile
+
+PARAM_FILE = "file"
+
+
+def get_content_type(filename):
+ return mimetypes.guess_type(filename)[0] or "application/octet-stream"
+
+
+class GetDashboardFile(webapp.RequestHandler):
+ def get(self, resource):
+ if not resource:
+ logging.debug("Getting dashboard file list.")
+ return self._get_file_list()
+
+ filename = str(urllib2.unquote(resource))
+
+ logging.debug("Getting dashboard file: %s", filename)
+
+ files = DashboardFile.get_files(filename)
+ if not files:
+ logging.error("Failed to find dashboard file: %s, request: %s",
+ filename, self.request)
+ self.response.set_status(404)
+ return
+
+ content_type = "%s; charset=utf-8" % get_content_type(filename)
+ logging.info("content type: %s", content_type)
+ self.response.headers["Content-Type"] = content_type
+ self.response.out.write(files[0].data)
+
+ def _get_file_list(self):
+ logging.info("getting dashboard file list.")
+
+ files = DashboardFile.get_files("", 100)
+ if not files:
+ logging.info("Failed to find dashboard files.")
+ self.response.set_status(404)
+ return
+
+ template_values = {
+ "admin": users.is_current_user_admin(),
+ "files": files,
+ }
+ self.response.out.write(
+ template.render("templates/dashboardfilelist.html",
+ template_values))
+
+
+class UpdateDashboardFile(webapp.RequestHandler):
+ def get(self):
+ files = self.request.get_all(PARAM_FILE)
+ if not files:
+ files = ["flakiness_dashboard.html",
+ "dashboard_base.js",
+ "aggregate_results.html",
+ "dygraph-combined.js",
+ "timeline_explorer.html"]
+
+ errors = []
+ for file in files:
+ if not DashboardFile.update_file(file):
+ errors.append("Failed to update file: %s" % file)
+
+ if errors:
+ messages = "; ".join(errors)
+ logging.warning(messages)
+ self.response.set_status(500, messages)
+ self.response.out.write("FAIL")
+ else:
+ self.response.set_status(200)
+ self.response.out.write("OK")
+
+
+class DeleteDashboardFile(webapp.RequestHandler):
+ def get(self):
+ files = self.request.get_all(PARAM_FILE)
+ if not files:
+ logging.warning("No dashboard file to delete.")
+ self.response.set_status(400)
+ return
+
+ for file in files:
+ DashboardFile.delete_file(file)
+
+ # Display dashboard file list after deleting the file.
+ self.redirect("/dashboards/")
diff --git a/Tools/TestResultServer/handlers/menu.py b/Tools/TestResultServer/handlers/menu.py
new file mode 100644
index 0000000..f2f3855
--- /dev/null
+++ b/Tools/TestResultServer/handlers/menu.py
@@ -0,0 +1,63 @@
+# 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.
+
+from google.appengine.api import users
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+menu = [
+ ["List of test files", "/testfile"],
+ ["List of results.json files", "/testfile?name=results.json"],
+ ["List of expectations.json files", "/testfile?name=expectations.json"],
+ ["Upload test file", "/testfile/uploadform"],
+ ["List of dashboard files", "/dashboards/"],
+ ["Update dashboard files", "/dashboards/update"],
+]
+
+
+class Menu(webapp.RequestHandler):
+ def get(self):
+ user = users.get_current_user()
+ if user:
+ user_email = user.email()
+ login_text = "Sign out"
+ login_url = users.create_logout_url(self.request.uri)
+ else:
+ user_email = ""
+ login_text = "Sign in"
+ login_url = users.create_login_url(self.request.uri)
+
+ template_values = {
+ "user_email": user_email,
+ "login_text": login_text,
+ "login_url": login_url,
+ "menu": menu,
+ }
+
+ self.response.out.write(
+ template.render("templates/menu.html", template_values))
diff --git a/Tools/TestResultServer/handlers/testfilehandler.py b/Tools/TestResultServer/handlers/testfilehandler.py
new file mode 100644
index 0000000..6f0ca44
--- /dev/null
+++ b/Tools/TestResultServer/handlers/testfilehandler.py
@@ -0,0 +1,230 @@
+# 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 logging
+import urllib
+
+from google.appengine.api import users
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp import template
+
+from model.jsonresults import JsonResults
+from model.testfile import TestFile
+
+PARAM_MASTER = "master"
+PARAM_BUILDER = "builder"
+PARAM_DIR = "dir"
+PARAM_FILE = "file"
+PARAM_NAME = "name"
+PARAM_KEY = "key"
+PARAM_TEST_TYPE = "testtype"
+PARAM_INCREMENTAL = "incremental"
+PARAM_TEST_LIST_JSON = "testlistjson"
+
+
+class DeleteFile(webapp.RequestHandler):
+ """Delete test file for a given builder and name from datastore."""
+
+ def get(self):
+ key = self.request.get(PARAM_KEY)
+ master = self.request.get(PARAM_MASTER)
+ builder = self.request.get(PARAM_BUILDER)
+ test_type = self.request.get(PARAM_TEST_TYPE)
+ name = self.request.get(PARAM_NAME)
+
+ logging.debug(
+ "Deleting File, master: %s, builder: %s, test_type: %s, name: %s, key: %s.",
+ master, builder, test_type, name, key)
+
+ TestFile.delete_file(key, master, builder, test_type, name, 100)
+
+ # Display file list after deleting the file.
+ self.redirect("/testfile?master=%s&builder=%s&testtype=%s&name=%s"
+ % (master, builder, test_type, name))
+
+
+class GetFile(webapp.RequestHandler):
+ """Get file content or list of files for given builder and name."""
+
+ def _get_file_list(self, master, builder, test_type, name):
+ """Get and display a list of files that matches builder and file name.
+
+ Args:
+ builder: builder name
+ test_type: type of the test
+ name: file name
+ """
+
+ files = TestFile.get_files(
+ master, builder, test_type, name, load_data=False, limit=100)
+ if not files:
+ logging.info("File not found, master: %s, builder: %s, test_type: %s, name: %s.",
+ master, builder, test_type, name)
+ self.response.out.write("File not found")
+ return
+
+ template_values = {
+ "admin": users.is_current_user_admin(),
+ "master": master,
+ "builder": builder,
+ "test_type": test_type,
+ "name": name,
+ "files": files,
+ }
+ self.response.out.write(template.render("templates/showfilelist.html",
+ template_values))
+
+ def _get_file_content(self, master, builder, test_type, name):
+ """Return content of the file that matches builder and file name.
+
+ Args:
+ builder: builder name
+ test_type: type of the test
+ name: file name
+ """
+
+ files = TestFile.get_files(
+ master, builder, test_type, name, load_data=True, limit=1)
+ if not files:
+ logging.info("File not found, master %s, builder: %s, test_type: %s, name: %s.",
+ master, builder, test_type, name)
+ return None
+
+ return files[0].data
+
+ def _get_test_list_json(self, master, builder, test_type):
+ """Return json file with test name list only, do not include test
+ results and other non-test-data .
+
+ Args:
+ builder: builder name.
+ test_type: type of test results.
+ """
+
+ json = self._get_file_content(master, builder, test_type, "results.json")
+ if not json:
+ return None
+
+ return JsonResults.get_test_list(builder, json)
+
+ def get(self):
+ master = self.request.get(PARAM_MASTER)
+ builder = self.request.get(PARAM_BUILDER)
+ test_type = self.request.get(PARAM_TEST_TYPE)
+ name = self.request.get(PARAM_NAME)
+ dir = self.request.get(PARAM_DIR)
+ test_list_json = self.request.get(PARAM_TEST_LIST_JSON)
+
+ logging.debug(
+ "Getting files, master %s, builder: %s, test_type: %s, name: %s.",
+ master, builder, test_type, name)
+
+ # If parameter "dir" is specified or there is no builder or filename
+ # specified in the request, return list of files, otherwise, return
+ # file content.
+ if dir or not builder or not name:
+ return self._get_file_list(master, builder, test_type, name)
+
+ if name == "results.json" and test_list_json:
+ json = self._get_test_list_json(master, builder, test_type)
+ else:
+ json = self._get_file_content(master, builder, test_type, name)
+
+ if json:
+ self.response.headers["Content-Type"] = "text/plain; charset=utf-8"
+ self.response.out.write(json)
+ else:
+ self.error(404)
+
+class Upload(webapp.RequestHandler):
+ """Upload test results file to datastore."""
+
+ def post(self):
+ file_params = self.request.POST.getall(PARAM_FILE)
+ if not file_params:
+ self.response.out.write("FAIL: missing upload file field.")
+ return
+
+ builder = self.request.get(PARAM_BUILDER)
+ if not builder:
+ self.response.out.write("FAIL: missing builder parameter.")
+ return
+
+ master = self.request.get(PARAM_MASTER)
+ test_type = self.request.get(PARAM_TEST_TYPE)
+ incremental = self.request.get(PARAM_INCREMENTAL)
+
+ logging.debug(
+ "Processing upload request, master: %s, builder: %s, test_type: %s.",
+ master, builder, test_type)
+
+ # There are two possible types of each file_params in the request:
+ # one file item or a list of file items.
+ # Normalize file_params to a file item list.
+ files = []
+ logging.debug("test: %s, type:%s", file_params, type(file_params))
+ for item in file_params:
+ if not isinstance(item, list) and not isinstance(item, tuple):
+ item = [item]
+ files.extend(item)
+
+ errors = []
+ for file in files:
+ filename = file.filename.lower()
+ if ((incremental and filename == "results.json") or
+ (filename == "incremental_results.json")):
+ # Merge incremental json results.
+ update_succeeded = JsonResults.update(master, builder, test_type, file.value)
+ else:
+ update_succeeded = TestFile.update(
+ master, builder, test_type, file.filename, file.value)
+
+ if not update_succeeded:
+ errors.append(
+ "Upload failed, master: %s, builder: %s, test_type: %s, name: %s." %
+ (master, builder, test_type, file.filename))
+
+ if errors:
+ messages = "FAIL: " + "; ".join(errors)
+ logging.warning(messages)
+ self.response.set_status(500, messages)
+ self.response.out.write("FAIL")
+ else:
+ self.response.set_status(200)
+ self.response.out.write("OK")
+
+
+class UploadForm(webapp.RequestHandler):
+ """Show a form so user can upload a file."""
+
+ def get(self):
+ template_values = {
+ "upload_url": "/testfile/upload",
+ }
+ self.response.out.write(template.render("templates/uploadform.html",
+ template_values))
diff --git a/Tools/TestResultServer/index.yaml b/Tools/TestResultServer/index.yaml
new file mode 100644
index 0000000..a7d3e48
--- /dev/null
+++ b/Tools/TestResultServer/index.yaml
@@ -0,0 +1,65 @@
+indexes:
+
+# AUTOGENERATED
+
+# This index.yaml is automatically updated whenever the dev_appserver
+# detects that a new type of query is run. If you want to manage the
+# index.yaml file manually, remove the above marker line (the line
+# saying "# AUTOGENERATED"). If you want to manage some indexes
+# manually, move them above the marker line. The index.yaml file is
+# automatically uploaded to the admin console when you next deploy
+# your application using appcfg.py.
+
+- kind: DashboardFile
+ properties:
+ - name: name
+ - name: date
+ direction: desc
+
+- kind: TestFile
+ properties:
+ - name: builder
+ - name: date
+ direction: desc
+
+- kind: TestFile
+ properties:
+ - name: builder
+ - name: master
+ - name: name
+ - name: test_type
+ - name: date
+ direction: desc
+
+- kind: TestFile
+ properties:
+ - name: builder
+ - name: name
+ - name: date
+ direction: desc
+
+- kind: TestFile
+ properties:
+ - name: builder
+ - name: name
+ - name: test_type
+ - name: date
+ direction: desc
+
+- kind: TestFile
+ properties:
+ - name: master
+ - name: date
+ direction: desc
+
+- kind: TestFile
+ properties:
+ - name: name
+ - name: date
+ direction: desc
+
+- kind: TestFile
+ properties:
+ - name: test_type
+ - name: date
+ direction: desc
diff --git a/Tools/TestResultServer/main.py b/Tools/TestResultServer/main.py
new file mode 100644
index 0000000..aa6e432
--- /dev/null
+++ b/Tools/TestResultServer/main.py
@@ -0,0 +1,58 @@
+# 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.
+
+# Request a modern Django
+from google.appengine.dist import use_library
+use_library('django', '1.1')
+
+from google.appengine.ext import webapp
+from google.appengine.ext.webapp.util import run_wsgi_app
+
+from handlers import dashboardhandler
+from handlers import menu
+from handlers import testfilehandler
+
+routes = [
+ ('/dashboards/delete', dashboardhandler.DeleteDashboardFile),
+ ('/dashboards/update', dashboardhandler.UpdateDashboardFile),
+ ('/dashboards/([^?]+)?', dashboardhandler.GetDashboardFile),
+ ('/testfile/delete', testfilehandler.DeleteFile),
+ ('/testfile/upload', testfilehandler.Upload),
+ ('/testfile/uploadform', testfilehandler.UploadForm),
+ ('/testfile/?', testfilehandler.GetFile),
+ ('/*|/menu', menu.Menu),
+]
+
+application = webapp.WSGIApplication(routes, debug=True)
+
+
+def main():
+ run_wsgi_app(application)
+
+if __name__ == "__main__":
+ main()
diff --git a/Tools/TestResultServer/model/__init__.py b/Tools/TestResultServer/model/__init__.py
new file mode 100644
index 0000000..ef65bee
--- /dev/null
+++ b/Tools/TestResultServer/model/__init__.py
@@ -0,0 +1 @@
+# Required for Python to search this directory for module files
diff --git a/Tools/TestResultServer/model/dashboardfile.py b/Tools/TestResultServer/model/dashboardfile.py
new file mode 100644
index 0000000..aad6d50
--- /dev/null
+++ b/Tools/TestResultServer/model/dashboardfile.py
@@ -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.
+
+from datetime import datetime
+import logging
+import urllib
+import urllib2
+
+from google.appengine.ext import db
+
+SVN_PATH_DASHBOARD = ("http://src.chromium.org/viewvc/chrome/trunk/tools/"
+ "dashboards/")
+
+
+class DashboardFile(db.Model):
+ name = db.StringProperty()
+ data = db.BlobProperty()
+ date = db.DateTimeProperty(auto_now_add=True)
+
+ @classmethod
+ def get_files(cls, name, limit=1):
+ query = DashboardFile.all()
+ if name:
+ query = query.filter("name =", name)
+ return query.order("-date").fetch(limit)
+
+ @classmethod
+ def add_file(cls, name, data):
+ file = DashboardFile()
+ file.name = name
+ file.data = db.Blob(data)
+ file.put()
+
+ logging.debug("Dashboard file saved, name: %s.", name)
+
+ return file
+
+ @classmethod
+ def grab_file_from_svn(cls, name):
+ logging.debug("Grab file from SVN, name: %s.", name)
+
+ url = SVN_PATH_DASHBOARD + urllib.quote_plus(name)
+
+ logging.info("Grab file from SVN, url: %s.", url)
+ try:
+ file = urllib2.urlopen(url)
+ if not file:
+ logging.error("Failed to grab dashboard file: %s.", url)
+ return None
+
+ return file.read()
+ except urllib2.HTTPError, e:
+ logging.error("Failed to grab dashboard file: %s", str(e))
+ except urllib2.URLError, e:
+ logging.error("Failed to grab dashboard file: %s", str(e))
+
+ return None
+
+ @classmethod
+ def update_file(cls, name):
+ data = cls.grab_file_from_svn(name)
+ if not data:
+ return False
+
+ logging.info("Got file from SVN.")
+
+ files = cls.get_files(name)
+ if not files:
+ logging.info("No existing file, added as new file.")
+ if cls.add_file(name, data):
+ return True
+ return False
+
+ logging.debug("Updating existing file.")
+ file = files[0]
+ file.data = data
+ file.date = datetime.now()
+ file.put()
+
+ logging.info("Dashboard file replaced, name: %s.", name)
+
+ return True
+
+ @classmethod
+ def delete_file(cls, name):
+ files = cls.get_files(name)
+ if not files:
+ logging.warning("File not found, name: %s.", name)
+ return False
+
+ for file in files:
+ file.delete()
+
+ return True
diff --git a/Tools/TestResultServer/model/datastorefile.py b/Tools/TestResultServer/model/datastorefile.py
new file mode 100755
index 0000000..ac28d64
--- /dev/null
+++ b/Tools/TestResultServer/model/datastorefile.py
@@ -0,0 +1,150 @@
+# 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.
+
+from datetime import datetime
+import logging
+
+from google.appengine.ext import db
+
+MAX_DATA_ENTRY_PER_FILE = 10
+MAX_ENTRY_LEN = 1000 * 1000
+
+
+class DataEntry(db.Model):
+ """Datastore entry that stores one segmant of file data
+ (<1000*1000 bytes).
+ """
+
+ data = db.BlobProperty()
+
+ @classmethod
+ def get(cls, key):
+ return db.get(key)
+
+ def get_data(self, key):
+ return db.get(key)
+
+
+class DataStoreFile(db.Model):
+ """This class stores file in datastore.
+ If a file is oversize (>1000*1000 bytes), the file is split into
+ multiple segments and stored in multiple datastore entries.
+ """
+
+ name = db.StringProperty()
+ data_keys = db.ListProperty(db.Key)
+ # keys to the data store entries that can be reused for new data.
+ # If it is emtpy, create new DataEntry.
+ new_data_keys = db.ListProperty(db.Key)
+ date = db.DateTimeProperty(auto_now_add=True)
+
+ data = None
+
+ def delete_data(self, keys=None):
+ if not keys:
+ keys = self.data_keys
+
+ for key in keys:
+ data_entry = DataEntry.get(key)
+ if data_entry:
+ data_entry.delete()
+
+ def save_data(self, data):
+ if not data:
+ logging.warning("No data to save.")
+ return False
+
+ if len(data) > (MAX_DATA_ENTRY_PER_FILE * MAX_ENTRY_LEN):
+ logging.error("File too big, can't save to datastore: %dK",
+ len(data) / 1024)
+ return False
+
+ start = 0
+ # Use the new_data_keys to store new data. If all new data are saved
+ # successfully, swap new_data_keys and data_keys so we can reuse the
+ # data_keys entries in next run. If unable to save new data for any
+ # reason, only the data pointed by new_data_keys may be corrupted,
+ # the existing data_keys data remains untouched. The corrupted data
+ # in new_data_keys will be overwritten in next update.
+ keys = self.new_data_keys
+ self.new_data_keys = []
+
+ while start < len(data):
+ if keys:
+ key = keys[0]
+ data_entry = DataEntry.get(key)
+ if not data_entry:
+ logging.warning("Found key, but no data entry: %s", key)
+ data_entry = DataEntry()
+ else:
+ data_entry = DataEntry()
+
+ data_entry.data = db.Blob(data[start: start + MAX_ENTRY_LEN])
+ try:
+ data_entry.put()
+ except Exception, err:
+ logging.error("Failed to save data store entry: %s", err)
+ if keys:
+ self.delete_data(keys)
+ return False
+
+ logging.info("Data saved: %s.", data_entry.key())
+ self.new_data_keys.append(data_entry.key())
+ if keys:
+ keys.pop(0)
+
+ start = start + MAX_ENTRY_LEN
+
+ if keys:
+ self.delete_data(keys)
+
+ temp_keys = self.data_keys
+ self.data_keys = self.new_data_keys
+ self.new_data_keys = temp_keys
+ self.data = data
+
+ return True
+
+ def load_data(self):
+ if not self.data_keys:
+ logging.warning("No data to load.")
+ return None
+
+ data = []
+ for key in self.data_keys:
+ logging.info("Loading data for key: %s.", key)
+ data_entry = DataEntry.get(key)
+ if not data_entry:
+ logging.error("No data found for key: %s.", key)
+ return None
+
+ data.append(data_entry.data)
+
+ self.data = "".join(data)
+
+ return self.data
diff --git a/Tools/TestResultServer/model/jsonresults.py b/Tools/TestResultServer/model/jsonresults.py
new file mode 100755
index 0000000..f5a0fde
--- /dev/null
+++ b/Tools/TestResultServer/model/jsonresults.py
@@ -0,0 +1,466 @@
+# 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.
+
+from datetime import datetime
+from django.utils import simplejson
+import logging
+
+from model.testfile import TestFile
+
+JSON_RESULTS_FILE = "results.json"
+JSON_RESULTS_FILE_SMALL = "results-small.json"
+JSON_RESULTS_PREFIX = "ADD_RESULTS("
+JSON_RESULTS_SUFFIX = ");"
+JSON_RESULTS_VERSION_KEY = "version"
+JSON_RESULTS_BUILD_NUMBERS = "buildNumbers"
+JSON_RESULTS_TESTS = "tests"
+JSON_RESULTS_RESULTS = "results"
+JSON_RESULTS_TIMES = "times"
+JSON_RESULTS_PASS = "P"
+JSON_RESULTS_NO_DATA = "N"
+JSON_RESULTS_MIN_TIME = 1
+JSON_RESULTS_VERSION = 3
+JSON_RESULTS_MAX_BUILDS = 750
+JSON_RESULTS_MAX_BUILDS_SMALL = 200
+
+
+class JsonResults(object):
+ @classmethod
+ def _strip_prefix_suffix(cls, data):
+ """Strip out prefix and suffix of json results string.
+
+ Args:
+ data: json file content.
+
+ Returns:
+ json string without prefix and suffix.
+ """
+
+ assert(data.startswith(JSON_RESULTS_PREFIX))
+ assert(data.endswith(JSON_RESULTS_SUFFIX))
+
+ return data[len(JSON_RESULTS_PREFIX):
+ len(data) - len(JSON_RESULTS_SUFFIX)]
+
+ @classmethod
+ def _generate_file_data(cls, json, sort_keys=False):
+ """Given json string, generate file content data by adding
+ prefix and suffix.
+
+ Args:
+ json: json string without prefix and suffix.
+
+ Returns:
+ json file data.
+ """
+
+ data = simplejson.dumps(json, separators=(',', ':'),
+ sort_keys=sort_keys)
+ return JSON_RESULTS_PREFIX + data + JSON_RESULTS_SUFFIX
+
+ @classmethod
+ def _load_json(cls, file_data):
+ """Load json file to a python object.
+
+ Args:
+ file_data: json file content.
+
+ Returns:
+ json object or
+ None on failure.
+ """
+
+ json_results_str = cls._strip_prefix_suffix(file_data)
+ if not json_results_str:
+ logging.warning("No json results data.")
+ return None
+
+ try:
+ return simplejson.loads(json_results_str)
+ except Exception, err:
+ logging.debug(json_results_str)
+ logging.error("Failed to load json results: %s", str(err))
+ return None
+
+ @classmethod
+ def _merge_json(cls, aggregated_json, incremental_json, num_runs):
+ """Merge incremental json into aggregated json results.
+
+ Args:
+ aggregated_json: aggregated json object.
+ incremental_json: incremental json object.
+
+ Returns:
+ True if merge succeeds or
+ False on failure.
+ """
+
+ # Merge non tests property data.
+ # Tests properties are merged in _merge_tests.
+ if not cls._merge_non_test_data(aggregated_json, incremental_json, num_runs):
+ return False
+
+ # Merge tests results and times
+ incremental_tests = incremental_json[JSON_RESULTS_TESTS]
+ if incremental_tests:
+ aggregated_tests = aggregated_json[JSON_RESULTS_TESTS]
+ cls._merge_tests(aggregated_tests, incremental_tests, num_runs)
+
+ return True
+
+ @classmethod
+ def _merge_non_test_data(cls, aggregated_json, incremental_json, num_runs):
+ """Merge incremental non tests property data into aggregated json results.
+
+ Args:
+ aggregated_json: aggregated json object.
+ incremental_json: incremental json object.
+
+ Returns:
+ True if merge succeeds or
+ False on failure.
+ """
+
+ incremental_builds = incremental_json[JSON_RESULTS_BUILD_NUMBERS]
+ aggregated_builds = aggregated_json[JSON_RESULTS_BUILD_NUMBERS]
+ aggregated_build_number = int(aggregated_builds[0])
+ # Loop through all incremental builds, start from the oldest run.
+ for index in reversed(range(len(incremental_builds))):
+ build_number = int(incremental_builds[index])
+ logging.debug("Merging build %s, incremental json index: %d.",
+ build_number, index)
+
+ # Return if not all build numbers in the incremental json results
+ # are newer than the most recent build in the aggregated results.
+ # FIXME: make this case work.
+ if build_number < aggregated_build_number:
+ logging.warning(("Build %d in incremental json is older than "
+ "the most recent build in aggregated results: %d"),
+ build_number, aggregated_build_number)
+ return False
+
+ # Return if the build number is duplicated.
+ # FIXME: skip the duplicated build and merge rest of the results.
+ # Need to be careful on skiping the corresponding value in
+ # _merge_tests because the property data for each test could
+ # be accumulated.
+ if build_number == aggregated_build_number:
+ logging.warning("Duplicate build %d in incremental json",
+ build_number)
+ return False
+
+ # Merge this build into aggreagated results.
+ cls._merge_one_build(aggregated_json, incremental_json, index, num_runs)
+
+ return True
+
+ @classmethod
+ def _merge_one_build(cls, aggregated_json, incremental_json,
+ incremental_index, num_runs):
+ """Merge one build of incremental json into aggregated json results.
+
+ Args:
+ aggregated_json: aggregated json object.
+ incremental_json: incremental json object.
+ incremental_index: index of the incremental json results to merge.
+ """
+
+ for key in incremental_json.keys():
+ # Merge json results except "tests" properties (results, times etc).
+ # "tests" properties will be handled separately.
+ if key == JSON_RESULTS_TESTS:
+ continue
+
+ if key in aggregated_json:
+ aggregated_json[key].insert(
+ 0, incremental_json[key][incremental_index])
+ aggregated_json[key] = \
+ aggregated_json[key][:num_runs]
+ else:
+ aggregated_json[key] = incremental_json[key]
+
+ @classmethod
+ def _merge_tests(cls, aggregated_json, incremental_json, num_runs):
+ """Merge "tests" properties:results, times.
+
+ Args:
+ aggregated_json: aggregated json object.
+ incremental_json: incremental json object.
+ """
+
+ all_tests = (set(aggregated_json.iterkeys()) |
+ set(incremental_json.iterkeys()))
+ for test_name in all_tests:
+ if test_name in aggregated_json:
+ aggregated_test = aggregated_json[test_name]
+ if test_name in incremental_json:
+ incremental_test = incremental_json[test_name]
+ results = incremental_test[JSON_RESULTS_RESULTS]
+ times = incremental_test[JSON_RESULTS_TIMES]
+ else:
+ results = [[1, JSON_RESULTS_NO_DATA]]
+ times = [[1, 0]]
+
+ cls._insert_item_run_length_encoded(
+ results, aggregated_test[JSON_RESULTS_RESULTS], num_runs)
+ cls._insert_item_run_length_encoded(
+ times, aggregated_test[JSON_RESULTS_TIMES], num_runs)
+ cls._normalize_results_json(test_name, aggregated_json)
+ else:
+ aggregated_json[test_name] = incremental_json[test_name]
+
+ @classmethod
+ def _insert_item_run_length_encoded(cls, incremental_item, aggregated_item, num_runs):
+ """Inserts the incremental run-length encoded results into the aggregated
+ run-length encoded results.
+
+ Args:
+ incremental_item: incremental run-length encoded results.
+ aggregated_item: aggregated run-length encoded results.
+ """
+
+ for item in incremental_item:
+ if len(aggregated_item) and item[1] == aggregated_item[0][1]:
+ aggregated_item[0][0] = min(
+ aggregated_item[0][0] + item[0], num_runs)
+ else:
+ aggregated_item.insert(0, item)
+
+ @classmethod
+ def _normalize_results_json(cls, test_name, aggregated_json):
+ """ Prune tests where all runs pass or tests that no longer exist and
+ truncate all results to JSON_RESULTS_MAX_BUILDS.
+
+ Args:
+ test_name: Name of the test.
+ aggregated_json: The JSON object with all the test results for
+ this builder.
+ """
+
+ aggregated_test = aggregated_json[test_name]
+ aggregated_test[JSON_RESULTS_RESULTS] = \
+ cls._remove_items_over_max_number_of_builds(
+ aggregated_test[JSON_RESULTS_RESULTS])
+ aggregated_test[JSON_RESULTS_TIMES] = \
+ cls._remove_items_over_max_number_of_builds(
+ aggregated_test[JSON_RESULTS_TIMES])
+
+ is_all_pass = cls._is_results_all_of_type(
+ aggregated_test[JSON_RESULTS_RESULTS], JSON_RESULTS_PASS)
+ is_all_no_data = cls._is_results_all_of_type(
+ aggregated_test[JSON_RESULTS_RESULTS], JSON_RESULTS_NO_DATA)
+
+ max_time = max(
+ [time[1] for time in aggregated_test[JSON_RESULTS_TIMES]])
+ # Remove all passes/no-data from the results to reduce noise and
+ # filesize. If a test passes every run, but
+ # takes >= JSON_RESULTS_MIN_TIME to run, don't throw away the data.
+ if (is_all_no_data or
+ (is_all_pass and max_time < JSON_RESULTS_MIN_TIME)):
+ del aggregated_json[test_name]
+
+ @classmethod
+ def _remove_items_over_max_number_of_builds(cls, encoded_list):
+ """Removes items from the run-length encoded list after the final
+ item that exceeds the max number of builds to track.
+
+ Args:
+ encoded_results: run-length encoded results. An array of arrays, e.g.
+ [[3,'A'],[1,'Q']] encodes AAAQ.
+ """
+ num_builds = 0
+ index = 0
+ for result in encoded_list:
+ num_builds = num_builds + result[0]
+ index = index + 1
+ if num_builds > JSON_RESULTS_MAX_BUILDS:
+ return encoded_list[:index]
+
+ return encoded_list
+
+ @classmethod
+ def _is_results_all_of_type(cls, results, type):
+ """Returns whether all the results are of the given type
+ (e.g. all passes).
+ """
+
+ return len(results) == 1 and results[0][1] == type
+
+ @classmethod
+ def _check_json(cls, builder, json):
+ """Check whether the given json is valid.
+
+ Args:
+ builder: builder name this json is for.
+ json: json object to check.
+
+ Returns:
+ True if the json is valid or
+ False otherwise.
+ """
+
+ version = json[JSON_RESULTS_VERSION_KEY]
+ if version > JSON_RESULTS_VERSION:
+ logging.error("Results JSON version '%s' is not supported.",
+ version)
+ return False
+
+ if not builder in json:
+ logging.error("Builder '%s' is not in json results.", builder)
+ return False
+
+ results_for_builder = json[builder]
+ if not JSON_RESULTS_BUILD_NUMBERS in results_for_builder:
+ logging.error("Missing build number in json results.")
+ return False
+
+ return True
+
+ @classmethod
+ def merge(cls, builder, aggregated, incremental, num_runs, sort_keys=False):
+ """Merge incremental json file data with aggregated json file data.
+
+ Args:
+ builder: builder name.
+ aggregated: aggregated json file data.
+ incremental: incremental json file data.
+ sort_key: whether or not to sort key when dumping json results.
+
+ Returns:
+ Merged json file data if merge succeeds or
+ None on failure.
+ """
+
+ if not incremental:
+ logging.warning("Nothing to merge.")
+ return None
+
+ logging.info("Loading incremental json...")
+ incremental_json = cls._load_json(incremental)
+ if not incremental_json:
+ return None
+
+ logging.info("Checking incremental json...")
+ if not cls._check_json(builder, incremental_json):
+ return None
+
+ logging.info("Loading existing aggregated json...")
+ aggregated_json = cls._load_json(aggregated)
+ if not aggregated_json:
+ return incremental
+
+ logging.info("Checking existing aggregated json...")
+ if not cls._check_json(builder, aggregated_json):
+ return incremental
+
+ logging.info("Merging json results...")
+ try:
+ if not cls._merge_json(aggregated_json[builder], incremental_json[builder], num_runs):
+ return None
+ except Exception, err:
+ logging.error("Failed to merge json results: %s", str(err))
+ return None
+
+ aggregated_json[JSON_RESULTS_VERSION_KEY] = JSON_RESULTS_VERSION
+
+ return cls._generate_file_data(aggregated_json, sort_keys)
+
+ @classmethod
+ def update(cls, master, builder, test_type, incremental):
+ """Update datastore json file data by merging it with incremental json
+ file. Writes the large file and a small file. The small file just stores
+ fewer runs.
+
+ Args:
+ master: master name.
+ builder: builder name.
+ test_type: type of test results.
+ incremental: incremental json file data to merge.
+
+ Returns:
+ Large TestFile object if update succeeds or
+ None on failure.
+ """
+ small_file_updated = cls.update_file(master, builder, test_type, incremental, JSON_RESULTS_FILE_SMALL, JSON_RESULTS_MAX_BUILDS_SMALL)
+ large_file_updated = cls.update_file(master, builder, test_type, incremental, JSON_RESULTS_FILE, JSON_RESULTS_MAX_BUILDS)
+
+ return small_file_updated and large_file_updated
+
+ @classmethod
+ def update_file(cls, master, builder, test_type, incremental, filename, num_runs):
+ files = TestFile.get_files(master, builder, test_type, filename)
+ if files:
+ file = files[0]
+ new_results = cls.merge(builder, file.data, incremental, num_runs)
+ else:
+ # Use the incremental data if there is no aggregated file to merge.
+ file = TestFile()
+ file.master = master
+ file.builder = builder
+ file.test_type = test_type
+ file.name = filename
+ new_results = incremental
+ logging.info("No existing json results, incremental json is saved.")
+
+ if not new_results or not file.save(new_results):
+ logging.info(
+ "Update failed, master: %s, builder: %s, test_type: %s, name: %s." %
+ (master, builder, test_type, filename))
+ return False
+
+ return True
+
+ @classmethod
+ def get_test_list(cls, builder, json_file_data):
+ """Get list of test names from aggregated json file data.
+
+ Args:
+ json_file_data: json file data that has all test-data and
+ non-test-data.
+
+ Returns:
+ json file with test name list only. The json format is the same
+ as the one saved in datastore, but all non-test-data and test detail
+ results are removed.
+ """
+
+ logging.debug("Loading test results json...")
+ json = cls._load_json(json_file_data)
+ if not json:
+ return None
+
+ logging.debug("Checking test results json...")
+ if not cls._check_json(builder, json):
+ return None
+
+ test_list_json = {}
+ tests = json[builder][JSON_RESULTS_TESTS]
+ test_list_json[builder] = {
+ "tests": dict.fromkeys(tests, {})}
+
+ return cls._generate_file_data(test_list_json)
diff --git a/Tools/TestResultServer/model/jsonresults_unittest.py b/Tools/TestResultServer/model/jsonresults_unittest.py
new file mode 100755
index 0000000..c70b90c
--- /dev/null
+++ b/Tools/TestResultServer/model/jsonresults_unittest.py
@@ -0,0 +1,322 @@
+# 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.
+
+try:
+ import jsonresults
+ from jsonresults import JsonResults
+except ImportError:
+ print "ERROR: Add the TestResultServer, google_appengine and yaml/lib directories to your PYTHONPATH"
+
+import unittest
+
+
+JSON_RESULTS_TEMPLATE = (
+ '{"Webkit":{'
+ '"allFixableCount":[[TESTDATA_COUNT]],'
+ '"buildNumbers":[[TESTDATA_BUILDNUMBERS]],'
+ '"chromeRevision":[[TESTDATA_CHROMEREVISION]],'
+ '"deferredCounts":[[TESTDATA_COUNTS]],'
+ '"fixableCount":[[TESTDATA_COUNT]],'
+ '"fixableCounts":[[TESTDATA_COUNTS]],'
+ '"secondsSinceEpoch":[[TESTDATA_TIMES]],'
+ '"tests":{[TESTDATA_TESTS]},'
+ '"webkitRevision":[[TESTDATA_WEBKITREVISION]],'
+ '"wontfixCounts":[[TESTDATA_COUNTS]]'
+ '},'
+ '"version":3'
+ '}')
+
+JSON_RESULTS_COUNTS_TEMPLATE = (
+ '{'
+ '"C":[TESTDATA],'
+ '"F":[TESTDATA],'
+ '"I":[TESTDATA],'
+ '"O":[TESTDATA],'
+ '"P":[TESTDATA],'
+ '"T":[TESTDATA],'
+ '"X":[TESTDATA],'
+ '"Z":[TESTDATA]}')
+
+JSON_RESULTS_TESTS_TEMPLATE = (
+ '"[TESTDATA_TEST_NAME]":{'
+ '"results":[[TESTDATA_TEST_RESULTS]],'
+ '"times":[[TESTDATA_TEST_TIMES]]}')
+
+JSON_RESULTS_PREFIX = "ADD_RESULTS("
+JSON_RESULTS_SUFFIX = ");"
+
+JSON_RESULTS_TEST_LIST_TEMPLATE = (
+ '{"Webkit":{"tests":{[TESTDATA_TESTS]}}}')
+
+
+class JsonResultsTest(unittest.TestCase):
+ def setUp(self):
+ self._builder = "Webkit"
+
+ def _make_test_json(self, test_data):
+ if not test_data:
+ return JSON_RESULTS_PREFIX + JSON_RESULTS_SUFFIX
+
+ (builds, tests) = test_data
+ if not builds or not tests:
+ return JSON_RESULTS_PREFIX + JSON_RESULTS_SUFFIX
+
+ json = JSON_RESULTS_TEMPLATE
+
+ counts = []
+ build_numbers = []
+ webkit_revision = []
+ chrome_revision = []
+ times = []
+ for build in builds:
+ counts.append(JSON_RESULTS_COUNTS_TEMPLATE.replace("[TESTDATA]", build))
+ build_numbers.append("1000%s" % build)
+ webkit_revision.append("2000%s" % build)
+ chrome_revision.append("3000%s" % build)
+ times.append("100000%s000" % build)
+
+ json = json.replace("[TESTDATA_COUNTS]", ",".join(counts))
+ json = json.replace("[TESTDATA_COUNT]", ",".join(builds))
+ json = json.replace("[TESTDATA_BUILDNUMBERS]", ",".join(build_numbers))
+ json = json.replace("[TESTDATA_WEBKITREVISION]", ",".join(webkit_revision))
+ json = json.replace("[TESTDATA_CHROMEREVISION]", ",".join(chrome_revision))
+ json = json.replace("[TESTDATA_TIMES]", ",".join(times))
+
+ json_tests = []
+ for test in tests:
+ t = JSON_RESULTS_TESTS_TEMPLATE.replace("[TESTDATA_TEST_NAME]", test[0])
+ t = t.replace("[TESTDATA_TEST_RESULTS]", test[1])
+ t = t.replace("[TESTDATA_TEST_TIMES]", test[2])
+ json_tests.append(t)
+
+ json = json.replace("[TESTDATA_TESTS]", ",".join(json_tests))
+
+ return JSON_RESULTS_PREFIX + json + JSON_RESULTS_SUFFIX
+
+ def _test_merge(self, aggregated_data, incremental_data, expected_data):
+ aggregated_results = self._make_test_json(aggregated_data)
+ incremental_results = self._make_test_json(incremental_data)
+ merged_results = JsonResults.merge(self._builder,
+ aggregated_results, incremental_results, jsonresults.JSON_RESULTS_MAX_BUILDS,
+ sort_keys=True)
+
+ if expected_data:
+ expected_results = self._make_test_json(expected_data)
+ self.assertEquals(merged_results, expected_results)
+ else:
+ self.assertFalse(merged_results)
+
+ def _test_get_test_list(self, input_data, expected_data):
+ input_results = self._make_test_json(input_data)
+
+ json_tests = []
+ for test in expected_data:
+ json_tests.append("\"" + test + "\":{}")
+
+ expected_results = JSON_RESULTS_PREFIX + \
+ JSON_RESULTS_TEST_LIST_TEMPLATE.replace(
+ "[TESTDATA_TESTS]", ",".join(json_tests)) + \
+ JSON_RESULTS_SUFFIX
+
+ actual_results = JsonResults.get_test_list(self._builder, input_results)
+ self.assertEquals(actual_results, expected_results)
+
+ def test(self):
+ # Empty incremental results json.
+ # Nothing to merge.
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]),
+ # Incremental results
+ None,
+ # Expect no merge happens.
+ None)
+
+ # No actual incremental test results (only prefix and suffix) to merge.
+ # Nothing to merge.
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]),
+ # Incremental results
+ ([], []),
+ # Expected no merge happens.
+ None)
+
+ # No existing aggregated results.
+ # Merged results == new incremental results.
+ self._test_merge(
+ # Aggregated results
+ None,
+ # Incremental results
+ (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]),
+ # Expected results
+ (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]))
+
+ # Single test for single run.
+ # Incremental results has the latest build and same test results for
+ # that run.
+ # Insert the incremental results at the first place and sum number
+ # of runs for "P" (200 + 1) to get merged results.
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]),
+ # Incremental results
+ (["3"], [["001.html", "[1,\"F\"]", "[1,0]"]]),
+ # Expected results
+ (["3", "2", "1"], [["001.html", "[201,\"F\"]", "[201,0]"]]))
+
+ # Single test for single run.
+ # Incremental results has the latest build but different test results
+ # for that run.
+ # Insert the incremental results at the first place.
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]),
+ # Incremental results
+ (["3"], [["001.html", "[1, \"I\"]", "[1,1]"]]),
+ # Expected results
+ (["3", "2", "1"], [["001.html", "[1,\"I\"],[200,\"F\"]", "[1,1],[200,0]"]]))
+
+ # Single test for single run.
+ # Incremental results has the latest build but different test results
+ # for that run.
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"F\"],[10,\"I\"]", "[200,0],[10,1]"]]),
+ # Incremental results
+ (["3"], [["001.html", "[1,\"I\"]", "[1,1]"]]),
+ # Expected results
+ (["3", "2", "1"], [["001.html", "[1,\"I\"],[200,\"F\"],[10,\"I\"]", "[1,1],[200,0],[10,1]"]]))
+
+ # Multiple tests for single run.
+ # All tests have incremental updates.
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"], ["002.html", "[100,\"I\"]", "[100,1]"]]),
+ # Incremental results
+ (["3"], [["001.html", "[1,\"F\"]", "[1,0]"], ["002.html", "[1,\"I\"]", "[1,1]"]]),
+ # Expected results
+ (["3", "2", "1"], [["001.html", "[201,\"F\"]", "[201,0]"], ["002.html", "[101,\"I\"]", "[101,1]"]]))
+
+ # Multiple tests for single run.
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"], ["002.html", "[100,\"I\"]", "[100,1]"]]),
+ # Incremental results
+ (["3"], [["002.html", "[1,\"I\"]", "[1,1]"]]),
+ # Expected results
+ (["3", "2", "1"], [["001.html", "[1,\"N\"],[200,\"F\"]", "[201,0]"], ["002.html", "[101,\"I\"]", "[101,1]"]]))
+
+ # Single test for multiple runs.
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]),
+ # Incremental results
+ (["4", "3"], [["001.html", "[2, \"I\"]", "[2,2]"]]),
+ # Expected results
+ (["4", "3", "2", "1"], [["001.html", "[2,\"I\"],[200,\"F\"]", "[2,2],[200,0]"]]))
+
+ # Multiple tests for multiple runs.
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"], ["002.html", "[10,\"Z\"]", "[10,0]"]]),
+ # Incremental results
+ (["4", "3"], [["001.html", "[2, \"I\"]", "[2,2]"], ["002.html", "[1,\"C\"]", "[1,1]"]]),
+ # Expected results
+ (["4", "3", "2", "1"], [["001.html", "[2,\"I\"],[200,\"F\"]", "[2,2],[200,0]"], ["002.html", "[1,\"C\"],[10,\"Z\"]", "[1,1],[10,0]"]]))
+
+ # Test the build in incremental results is older than the most recent
+ # build in aggregated results.
+ # The incremental results should be dropped and no merge happens.
+ self._test_merge(
+ # Aggregated results
+ (["3", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]),
+ # Incremental results
+ (["2"], [["001.html", "[1, \"F\"]", "[1,0]"]]),
+ # Expected no merge happens.
+ None)
+
+ # Test the build in incremental results is same as the build in
+ # aggregated results.
+ # The incremental results should be dropped and no merge happens.
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"F\"]", "[200,0]"]]),
+ # Incremental results
+ (["3", "2"], [["001.html", "[2, \"F\"]", "[2,0]"]]),
+ # Expected no merge happens.
+ None)
+
+ # Remove test where there is no data in all runs.
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"N\"]", "[200,0]"], ["002.html", "[10,\"F\"]", "[10,0]"]]),
+ # Incremental results
+ (["3"], [["001.html", "[1,\"N\"]", "[1,0]"], ["002.html", "[1,\"P\"]", "[1,0]"]]),
+ # Expected results
+ (["3", "2", "1"], [["002.html", "[1,\"P\"],[10,\"F\"]", "[11,0]"]]))
+
+ # Remove test where all run pass and max running time < 1 seconds
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"P\"]", "[200,0]"], ["002.html", "[10,\"F\"]", "[10,0]"]]),
+ # Incremental results
+ (["3"], [["001.html", "[1,\"P\"]", "[1,0]"], ["002.html", "[1,\"P\"]", "[1,0]"]]),
+ # Expected results
+ (["3", "2", "1"], [["002.html", "[1,\"P\"],[10,\"F\"]", "[11,0]"]]))
+
+ # Do not remove test where all run pass but max running time >= 1 seconds
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[200,\"P\"]", "[200,0]"], ["002.html", "[10,\"F\"]", "[10,0]"]]),
+ # Incremental results
+ (["3"], [["001.html", "[1,\"P\"]", "[1,1]"], ["002.html", "[1,\"P\"]", "[1,0]"]]),
+ # Expected results
+ (["3", "2", "1"], [["001.html", "[201,\"P\"]", "[1,1],[200,0]"], ["002.html", "[1,\"P\"],[10,\"F\"]", "[11,0]"]]))
+
+ # Remove items from test results and times that exceeds the max number
+ # of builds to track.
+ max_builds = str(jsonresults.JSON_RESULTS_MAX_BUILDS)
+ self._test_merge(
+ # Aggregated results
+ (["2", "1"], [["001.html", "[" + max_builds + ",\"F\"],[1,\"I\"]", "[" + max_builds + ",0],[1,1]"]]),
+ # Incremental results
+ (["3"], [["001.html", "[1,\"T\"]", "[1,1]"]]),
+ # Expected results
+ (["3", "2", "1"], [["001.html", "[1,\"T\"],[" + max_builds + ",\"F\"]", "[1,1],[" + max_builds + ",0]"]]))
+
+ # Get test name list only. Don't include non-test-list data and
+ # of test result details.
+ self._test_get_test_list(
+ # Input results
+ (["3", "2", "1"], [["001.html", "[200,\"P\"]", "[200,0]"], ["002.html", "[10,\"F\"]", "[10,0]"]]),
+ # Expected results
+ ["001.html", "002.html"])
+
+if __name__ == '__main__':
+ unittest.main()
diff --git a/Tools/TestResultServer/model/testfile.py b/Tools/TestResultServer/model/testfile.py
new file mode 100644
index 0000000..e600c99
--- /dev/null
+++ b/Tools/TestResultServer/model/testfile.py
@@ -0,0 +1,127 @@
+# 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.
+
+from datetime import datetime
+import logging
+
+from google.appengine.ext import db
+
+from model.datastorefile import DataStoreFile
+
+
+class TestFile(DataStoreFile):
+ master = db.StringProperty()
+ builder = db.StringProperty()
+ test_type = db.StringProperty()
+
+ @classmethod
+ def delete_file(cls, key, master, builder, test_type, name, limit):
+ if key:
+ file = db.get(key)
+ if not file:
+ logging.warning("File not found, key: %s.", key)
+ return False
+
+ file._delete_all()
+ else:
+ files = cls.get_files(master, builder, test_type, name, limit)
+ if not files:
+ logging.warning(
+ "File not found, master: %s, builder: %s, test_type:%s, name: %s.",
+ builder, test_type, name)
+ return False
+
+ for file in files:
+ file._delete_all()
+
+ return True
+
+ @classmethod
+ def get_files(cls, master, builder, test_type, name, load_data=True, limit=1):
+ query = TestFile.all()
+ if master:
+ query = query.filter("master =", master)
+ if builder:
+ query = query.filter("builder =", builder)
+ if test_type:
+ query = query.filter("test_type =", test_type)
+ if name:
+ query = query.filter("name =", name)
+
+ files = query.order("-date").fetch(limit)
+ if load_data:
+ for file in files:
+ file.load_data()
+
+ return files
+
+ @classmethod
+ def add_file(cls, master, builder, test_type, name, data):
+ file = TestFile()
+ file.master = master
+ file.builder = builder
+ file.test_type = test_type
+ file.name = name
+
+ if not file.save(data):
+ return None
+
+ logging.info(
+ "File saved, master: %s, builder: %s, test_type: %s, name: %s, key: %s.",
+ master, builder, test_type, file.name, str(file.data_keys))
+
+ return file
+
+ @classmethod
+ def update(cls, master, builder, test_type, name, data):
+ files = cls.get_files(master, builder, test_type, name)
+ if not files:
+ return cls.add_file(master, builder, test_type, name, data)
+
+ file = files[0]
+ if not file.save(data):
+ return None
+
+ logging.info(
+ "File replaced, master: %s, builder: %s, test_type: %s, name: %s, data key: %s.",
+ master, builder, test_type, file.name, str(file.data_keys))
+
+ return file
+
+ def save(self, data):
+ if not self.save_data(data):
+ return False
+
+ self.date = datetime.now()
+ self.put()
+
+ return True
+
+ def _delete_all(self):
+ self.delete_data()
+ self.delete()
diff --git a/Tools/TestResultServer/stylesheets/dashboardfile.css b/Tools/TestResultServer/stylesheets/dashboardfile.css
new file mode 100644
index 0000000..1b0921c
--- /dev/null
+++ b/Tools/TestResultServer/stylesheets/dashboardfile.css
@@ -0,0 +1,30 @@
+body {
+ font-family: Verdana, Helvetica, sans-serif;
+ padding: 0px;
+ color: #444;
+}
+h1 {
+ color: #444;
+ font-size: 14pt;
+ font-style: italic;
+ margin: 0px;
+ padding: 5px;
+}
+table {
+ border-spacing: 0px;
+}
+th {
+ background-color: #AAA;
+ color: white;
+ text-align: left;
+ padding: 5px;
+ font-size: 12pt;
+}
+td {
+ font-size: 11pt;
+ padding: 3px;
+ text-align: left;
+}
+tr:hover {
+ background-color: #EEE;
+}
diff --git a/Tools/TestResultServer/stylesheets/form.css b/Tools/TestResultServer/stylesheets/form.css
new file mode 100644
index 0000000..b8f367d
--- /dev/null
+++ b/Tools/TestResultServer/stylesheets/form.css
@@ -0,0 +1,26 @@
+body {
+ font-family: Verdana;
+ padding: 0px;
+ color: #444;
+}
+h1 {
+ color: #444;
+ font-size: 14pt;
+ font-style: italic;
+ margin: 0px;
+ padding: 5px;
+}
+.label {
+ margin: 1px;
+ padding: 5px;
+ font-size: 11pt;
+ width: 90px;
+}
+.inputtext {
+ font-size: 11pt;
+}
+.button {
+ margin: 1px;
+ padding: 1px;
+ font-size: 11pt;
+}
diff --git a/Tools/TestResultServer/stylesheets/menu.css b/Tools/TestResultServer/stylesheets/menu.css
new file mode 100644
index 0000000..9948605
--- /dev/null
+++ b/Tools/TestResultServer/stylesheets/menu.css
@@ -0,0 +1,28 @@
+body {
+ font-family: Verdana, Helvetica, sans-serif;
+}
+h1 {
+ background-color: #EEE;
+ color: #444;
+ font-size: 14pt;
+ font-style: italic;
+ margin: 0px;
+ padding: 5px;
+}
+ul {
+ margin: 0px;
+ padding: 20px;
+ list-style: none;
+}
+li {
+ padding: 5px;
+}
+li:hover {
+ background-color: #EEE;
+}
+.login {
+ font-size: 8pt;
+ text-align: right;
+ width: 100%;
+}
+
diff --git a/Tools/TestResultServer/stylesheets/testfile.css b/Tools/TestResultServer/stylesheets/testfile.css
new file mode 100644
index 0000000..1b0921c
--- /dev/null
+++ b/Tools/TestResultServer/stylesheets/testfile.css
@@ -0,0 +1,30 @@
+body {
+ font-family: Verdana, Helvetica, sans-serif;
+ padding: 0px;
+ color: #444;
+}
+h1 {
+ color: #444;
+ font-size: 14pt;
+ font-style: italic;
+ margin: 0px;
+ padding: 5px;
+}
+table {
+ border-spacing: 0px;
+}
+th {
+ background-color: #AAA;
+ color: white;
+ text-align: left;
+ padding: 5px;
+ font-size: 12pt;
+}
+td {
+ font-size: 11pt;
+ padding: 3px;
+ text-align: left;
+}
+tr:hover {
+ background-color: #EEE;
+}
diff --git a/Tools/TestResultServer/templates/dashboardfilelist.html b/Tools/TestResultServer/templates/dashboardfilelist.html
new file mode 100644
index 0000000..818cb91
--- /dev/null
+++ b/Tools/TestResultServer/templates/dashboardfilelist.html
@@ -0,0 +1,38 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Dashboard Files</title>
+<link type="text/css" rel="stylesheet" href="/stylesheets/dashboardfile.css" />
+</head>
+<body>
+<h1>Dashboard Files
+</h1>
+<div>
+ <table>
+ <tr>
+ <th>File</th>
+ <th>Date</th>
+ {% if admin %}
+ <th></th>
+ {% endif %}
+ {% for file in files %}
+ <tr>{% if file.name %}
+ <td><a href="/dashboards/{{ file.name }}" >
+ {{ file.name }}
+ </a>
+ </td>
+ <td>{{ file.date|date:"d-M-Y H:i:s" }}
+ </td>
+ {% if admin %}
+ <td><a href="/dashboards/delete?file={{ file.name }}" >
+ Delete
+ </a>
+ </td>
+ {% endif %}
+ {% endif %}
+ </tr>
+ {% endfor %}
+ </table>
+</div>
+</body>
+</html>
diff --git a/Tools/TestResultServer/templates/menu.html b/Tools/TestResultServer/templates/menu.html
new file mode 100644
index 0000000..1ad9f4d
--- /dev/null
+++ b/Tools/TestResultServer/templates/menu.html
@@ -0,0 +1,27 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Test Result Server</title>
+<table class=login>
+ <tr>
+ <td>
+ {% if user_email %}
+ <span>{{ user_email }}</span>
+ {% endif %}
+ <span><a href="{{ login_url }}">{{ login_text }}</a></span>
+ </td>
+ </tr>
+</table>
+<link type="text/css" rel="stylesheet" href="/stylesheets/menu.css" />
+</head>
+<body>
+<h1>Test Result Server</h1>
+<div>
+ <ul>{% for title,link in menu %}
+ <li>
+ <a href="{{ link }}" >{{ title }}</a>
+ </li>{% endfor %}
+ </ul>
+</div>
+</body>
+</html>
diff --git a/Tools/TestResultServer/templates/showfilelist.html b/Tools/TestResultServer/templates/showfilelist.html
new file mode 100644
index 0000000..d292fe2
--- /dev/null
+++ b/Tools/TestResultServer/templates/showfilelist.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Test Results</title>
+<link type="text/css" rel="stylesheet" href="/stylesheets/testfile.css" />
+</head>
+<body>
+<h1>Test Results
+{% if builder or test_type or name %}
+- {{ builder }} {{test_type }} {{ name }}
+{% endif %}
+</h1>
+<div>
+ <table>
+ <tr>
+ <th>Master</th>
+ <th>Builder</th>
+ <th>Test Type</th>
+ <th>File</th>
+ <th>Date</th>
+ {% if admin %}
+ <th></th>
+ {% endif %}
+ {% for file in files %}
+ <tr>{% if file.builder and file.name %}
+ <td><a href="/testfile?master={{ file.master }}" >
+ {{ file.master }}
+ </a>
+ </td>
+ <td><a href="/testfile?builder={{ file.builder }}" >
+ {{ file.builder }}
+ </a>
+ </td>
+ <td>{% if file.test_type %}
+ <a href="/testfile?testtype={{ file.test_type }}" >
+ {{ file.test_type }}
+ </a>
+ {% endif %}
+ </td>
+ <td><a href="/testfile?builder={{ file.builder }}&name={{ file.name }}" >
+ {{ file.name }}
+ </a>
+ </td>
+ <td>{{ file.date|date:"d-M-Y H:i:s" }}
+ </td>
+ {% if admin %}
+ <td><a href="/testfile/delete?key={{ file.key }}&builder={{ builder }}&name={{ name }}" >
+ Delete
+ </a>
+ </td>
+ {% endif %}
+ {% endif %}
+ </tr>
+ {% endfor %}
+ </table>
+</div>
+</body>
+</html>
diff --git a/Tools/TestResultServer/templates/uploadform.html b/Tools/TestResultServer/templates/uploadform.html
new file mode 100644
index 0000000..9974a24
--- /dev/null
+++ b/Tools/TestResultServer/templates/uploadform.html
@@ -0,0 +1,33 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Upload Test Result File</title>
+<link type="text/css" rel="stylesheet" href="/stylesheets/form.css" />
+</head>
+<body>
+<h1>Upload Test Result File</h1>
+<form id="uploadForm" name="test_result_upload" accept="text/html" action="{{ upload_url }}" enctype="multipart/form-data" method="post">
+ <br>
+ <table>
+ <tr>
+ <td class=label><label>Master:</label></td>
+ <td><input class=inputtext type="text" name="master" placeholder="Chromium"/></td>
+ </tr>
+ <tr>
+ <td class=label><label>Builder:</label></td>
+ <td><input class=inputtext type="text" name="builder" placeholder="Webkit"/></td>
+ </tr>
+ <tr>
+ <td class=label><label>Test Type:</label></td>
+ <td><input class=inputtext type="text" name="testtype" placeholder="layout-tests"/></td>
+ </tr>
+ </table>
+ <br>
+ <div><input class=button type="checkbox" name="incremental">Incremental results, merge with server file.</div>
+ <br>
+ <div><input class=button type="file" name="file" multiple></div>
+ <br>
+ <div><input class=button type="submit" value="Upload"></div>
+</form>
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Configurations/Base.xcconfig b/Tools/TestWebKitAPI/Configurations/Base.xcconfig
new file mode 100644
index 0000000..feb7c5e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Configurations/Base.xcconfig
@@ -0,0 +1,72 @@
+// 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.
+
+HEADER_SEARCH_PATHS = $(WEBCORE_PRIVATE_HEADERS_DIR)/ForwardingHeaders;
+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_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;
+VALID_ARCHS = i386 x86_64;
+
+
+TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR);
+
+
+// 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_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+TARGET_GCC_VERSION_ = $(TARGET_GCC_VERSION_1040);
+TARGET_GCC_VERSION_1040 = GCC_40;
+TARGET_GCC_VERSION_1050 = $(TARGET_GCC_VERSION_1050_$(XCODE_VERSION_MINOR));
+TARGET_GCC_VERSION_1050_ = $(TARGET_GCC_VERSION_1050_$(XCODE_VERSION_ACTUAL));
+TARGET_GCC_VERSION_1050_0310 = GCC_42;
+TARGET_GCC_VERSION_1050_0320 = GCC_42;
+TARGET_GCC_VERSION_1060 = GCC_42;
+TARGET_GCC_VERSION_1070 = LLVM_GCC_42;
+
+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;
+
+// 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_1050_1040 = macosx10.4;
+SDKROOT_1060_1040 = macosx10.4;
+SDKROOT_1060_1050 = macosx10.5;
+SDKROOT_1070_1040 = macosx10.4;
+SDKROOT_1070_1050 = macosx10.5;
+SDKROOT_1070_1060 = macosx10.6;
+
+WEBKIT_UMBRELLA_FRAMEWORKS_DIR = $(NEXT_ROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/WebKit.framework/Versions/A/Frameworks;
+WEBCORE_PRIVATE_HEADERS_DIR = $(WEBKIT_UMBRELLA_FRAMEWORKS_DIR)/WebCore.framework/PrivateHeaders;
diff --git a/Tools/TestWebKitAPI/Configurations/DebugRelease.xcconfig b/Tools/TestWebKitAPI/Configurations/DebugRelease.xcconfig
new file mode 100644
index 0000000..41600b1
--- /dev/null
+++ b/Tools/TestWebKitAPI/Configurations/DebugRelease.xcconfig
@@ -0,0 +1,42 @@
+// 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 "Base.xcconfig"
+
+ARCHS = $(ARCHS_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+ARCHS_ = $(ARCHS_1040);
+ARCHS_1040 = $(NATIVE_ARCH);
+ARCHS_1050 = $(NATIVE_ARCH);
+ARCHS_1060 = $(ARCHS_STANDARD_32_64_BIT);
+ARCHS_1070 = $(ARCHS_STANDARD_32_64_BIT);
+
+ONLY_ACTIVE_ARCH = YES;
+
+MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(TARGET_MAC_OS_X_VERSION_MAJOR))
+MACOSX_DEPLOYMENT_TARGET_ = 10.4;
+MACOSX_DEPLOYMENT_TARGET_1040 = 10.4;
+MACOSX_DEPLOYMENT_TARGET_1050 = 10.5;
+MACOSX_DEPLOYMENT_TARGET_1060 = 10.6;
+MACOSX_DEPLOYMENT_TARGET_1070 = 10.7;
+
+WEBKIT_UMBRELLA_FRAMEWORKS_DIR = $(BUILT_PRODUCTS_DIR);
diff --git a/Tools/TestWebKitAPI/Configurations/InjectedBundle.xcconfig b/Tools/TestWebKitAPI/Configurations/InjectedBundle.xcconfig
new file mode 100644
index 0000000..6bf31b2
--- /dev/null
+++ b/Tools/TestWebKitAPI/Configurations/InjectedBundle.xcconfig
@@ -0,0 +1,24 @@
+// 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.
+
+PRODUCT_NAME = InjectedBundleTestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig b/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig
new file mode 100644
index 0000000..5e69d0e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Configurations/TestWebKitAPI.xcconfig
@@ -0,0 +1,26 @@
+// 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.
+
+PRODUCT_NAME = TestWebKitAPI
+GCC_ENABLE_OBJC_EXCEPTIONS = YES
+GCC_PREFIX_HEADER = TestWebKitAPIPrefix.h
diff --git a/Tools/TestWebKitAPI/Configurations/TestWebKitAPICFLite.vsprops b/Tools/TestWebKitAPI/Configurations/TestWebKitAPICFLite.vsprops
new file mode 100644
index 0000000..cfbcfad
--- /dev/null
+++ b/Tools/TestWebKitAPI/Configurations/TestWebKitAPICFLite.vsprops
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestWebKitAPICFLite"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="CFLite$(LibraryConfigSuffix).lib"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/TestWebKitAPI/Configurations/TestWebKitAPICommon.vsprops b/Tools/TestWebKitAPI/Configurations/TestWebKitAPICommon.vsprops
new file mode 100644
index 0000000..43927f2
--- /dev/null
+++ b/Tools/TestWebKitAPI/Configurations/TestWebKitAPICommon.vsprops
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestWebKitAPICommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)&quot;;&quot;$(ProjectDir)\..&quot;;&quot;$(WebKitOutputDir)\include&quot;;&quot;$(WebKitOutputDir)\include\WebCore\ForwardingHeaders&quot;;&quot;$(WebKitOutputDir)\include\private&quot;;&quot;$(WebKitLibrariesDir)\include&quot;"
+ ForcedIncludeFiles="TestWebKitAPIPrefix.h"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="WebKit$(WebKitDLLConfigSuffix).lib JavaScriptCore$(WebKitDLLConfigSuffix).lib"
+ SubSystem="1"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/TestWebKitAPI/Configurations/TestWebKitAPICoreFoundation.vsprops b/Tools/TestWebKitAPI/Configurations/TestWebKitAPICoreFoundation.vsprops
new file mode 100644
index 0000000..1260b1a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Configurations/TestWebKitAPICoreFoundation.vsprops
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestWebKitAPICoreFoundation"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="CoreFoundation$(LibraryConfigSuffix).lib"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/TestWebKitAPI/InjectedBundle-Info.plist b/Tools/TestWebKitAPI/InjectedBundle-Info.plist
new file mode 100644
index 0000000..c285a47
--- /dev/null
+++ b/Tools/TestWebKitAPI/InjectedBundle-Info.plist
@@ -0,0 +1,22 @@
+<?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>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.yourcompany.${PRODUCT_NAME:rfc1034identifier}</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>
diff --git a/Tools/TestWebKitAPI/InjectedBundleController.cpp b/Tools/TestWebKitAPI/InjectedBundleController.cpp
new file mode 100644
index 0000000..e438afd
--- /dev/null
+++ b/Tools/TestWebKitAPI/InjectedBundleController.cpp
@@ -0,0 +1,126 @@
+/*
+ * 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 "InjectedBundleController.h"
+
+#include "InjectedBundleTest.h"
+#include "PlatformUtilities.h"
+#include <WebKit2/WebKit2.h>
+#include <algorithm>
+#include <assert.h>
+
+namespace TestWebKitAPI {
+
+InjectedBundleController& InjectedBundleController::shared()
+{
+ static InjectedBundleController& shared = *new InjectedBundleController;
+ return shared;
+}
+
+InjectedBundleController::InjectedBundleController()
+ : m_bundle(0)
+ , m_currentTest(0)
+{
+}
+
+void InjectedBundleController::initialize(WKBundleRef bundle, WKTypeRef initializationUserData)
+{
+ m_bundle = bundle;
+
+ WKBundleClient client = {
+ 0,
+ this,
+ didCreatePage,
+ willDestroyPage,
+ didInitializePageGroup,
+ didReceiveMessage
+ };
+ WKBundleSetClient(m_bundle, &client);
+
+ // Initialize the test from the "initializationUserData".
+
+ assert(WKGetTypeID(initializationUserData) == WKDictionaryGetTypeID());
+ WKDictionaryRef initializationDictionary = static_cast<WKDictionaryRef>(initializationUserData);
+
+ WKStringRef testName = static_cast<WKStringRef>(WKDictionaryGetItemForKey(initializationDictionary, WKStringCreateWithUTF8CString("TestName")));
+ WKTypeRef userData = WKDictionaryGetItemForKey(initializationDictionary, WKStringCreateWithUTF8CString("UserData"));
+
+ initializeTestNamed(bundle, Util::toSTD(testName), userData);
+}
+
+void InjectedBundleController::didCreatePage(WKBundleRef bundle, WKBundlePageRef page, const void* clientInfo)
+{
+ InjectedBundleController* self = static_cast<InjectedBundleController*>(const_cast<void*>(clientInfo));
+ assert(self->m_currentTest);
+ self->m_currentTest->didCreatePage(bundle, page);
+}
+
+void InjectedBundleController::willDestroyPage(WKBundleRef bundle, WKBundlePageRef page, const void* clientInfo)
+{
+ InjectedBundleController* self = static_cast<InjectedBundleController*>(const_cast<void*>(clientInfo));
+ assert(self->m_currentTest);
+ self->m_currentTest->willDestroyPage(bundle, page);
+}
+
+void InjectedBundleController::didInitializePageGroup(WKBundleRef bundle, WKBundlePageGroupRef pageGroup, const void* clientInfo)
+{
+ InjectedBundleController* self = static_cast<InjectedBundleController*>(const_cast<void*>(clientInfo));
+ assert(self->m_currentTest);
+ self->m_currentTest->didInitializePageGroup(bundle, pageGroup);
+}
+
+void InjectedBundleController::didReceiveMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
+{
+ InjectedBundleController* self = static_cast<InjectedBundleController*>(const_cast<void*>(clientInfo));
+ assert(self->m_currentTest);
+ self->m_currentTest->didReceiveMessage(bundle, messageName, messageBody);
+}
+
+void InjectedBundleController::dumpTestNames()
+{
+ std::map<std::string, CreateInjectedBundleTestFunction>::const_iterator it = m_createInjectedBundleTestFunctions.begin();
+ std::map<std::string, CreateInjectedBundleTestFunction>::const_iterator end = m_createInjectedBundleTestFunctions.end();
+ for (; it != end; ++it)
+ printf("%s\n", (*it).first.c_str());
+}
+
+void InjectedBundleController::initializeTestNamed(WKBundleRef bundle, const std::string& identifier, WKTypeRef userData)
+{
+ CreateInjectedBundleTestFunction createTestFunction = m_createInjectedBundleTestFunctions[identifier];
+ if (!createTestFunction) {
+ printf("ERROR: InjectedBundle test not found - %s\n", identifier.c_str());
+ exit(1);
+ }
+
+ m_currentTest = createTestFunction(identifier);
+ m_currentTest->initialize(bundle, userData);
+}
+
+void InjectedBundleController::registerCreateInjectedBundleTestFunction(const std::string& identifier, CreateInjectedBundleTestFunction function)
+{
+ m_createInjectedBundleTestFunctions[identifier] = function;
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/InjectedBundleController.h b/Tools/TestWebKitAPI/InjectedBundleController.h
new file mode 100644
index 0000000..b84be4b
--- /dev/null
+++ b/Tools/TestWebKitAPI/InjectedBundleController.h
@@ -0,0 +1,65 @@
+/*
+ * 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 InjectedBundleController_h
+#define InjectedBundleController_h
+
+#include <WebKit2/WKBundle.h>
+#include <map>
+#include <string>
+
+namespace TestWebKitAPI {
+
+class InjectedBundleTest;
+
+class InjectedBundleController {
+public:
+ static InjectedBundleController& shared();
+
+ void initialize(WKBundleRef, WKTypeRef);
+
+ void dumpTestNames();
+ void initializeTestNamed(WKBundleRef bundle, const std::string&, WKTypeRef userData);
+
+ typedef InjectedBundleTest* (*CreateInjectedBundleTestFunction)(const std::string&);
+ void registerCreateInjectedBundleTestFunction(const std::string&, CreateInjectedBundleTestFunction);
+
+private:
+ InjectedBundleController();
+ ~InjectedBundleController();
+
+ static void didCreatePage(WKBundleRef, WKBundlePageRef, const void* clientInfo);
+ static void willDestroyPage(WKBundleRef, WKBundlePageRef, const void* clientInfo);
+ static void didInitializePageGroup(WKBundleRef, WKBundlePageGroupRef, const void* clientInfo);
+ static void didReceiveMessage(WKBundleRef, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo);
+
+ std::map<std::string, CreateInjectedBundleTestFunction> m_createInjectedBundleTestFunctions;
+ WKBundleRef m_bundle;
+ InjectedBundleTest* m_currentTest;
+};
+
+} // namespace TestWebKitAPI
+
+#endif // InjectedBundleController_h
diff --git a/Tools/TestWebKitAPI/InjectedBundleMain.cpp b/Tools/TestWebKitAPI/InjectedBundleMain.cpp
new file mode 100644
index 0000000..355c35b
--- /dev/null
+++ b/Tools/TestWebKitAPI/InjectedBundleMain.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "InjectedBundleController.h"
+#include <WebKit2/WKBundleInitialize.h>
+
+#if defined(WIN32) || defined(_WIN32)
+extern "C" __declspec(dllexport)
+#else
+extern "C"
+#endif
+void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData)
+{
+ TestWebKitAPI::InjectedBundleController::shared().initialize(bundle, initializationUserData);
+}
diff --git a/Tools/TestWebKitAPI/InjectedBundleTest.h b/Tools/TestWebKitAPI/InjectedBundleTest.h
new file mode 100644
index 0000000..5285cdf
--- /dev/null
+++ b/Tools/TestWebKitAPI/InjectedBundleTest.h
@@ -0,0 +1,71 @@
+/*
+ * 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 InjectedBundleTest_h
+#define InjectedBundleTest_h
+
+#include "InjectedBundleController.h"
+
+namespace TestWebKitAPI {
+
+class InjectedBundleTest {
+public:
+ virtual ~InjectedBundleTest() { }
+
+ virtual void initialize(WKBundleRef, WKTypeRef) { }
+
+ virtual void didCreatePage(WKBundleRef, WKBundlePageRef) { }
+ virtual void willDestroyPage(WKBundleRef, WKBundlePageRef) { }
+ virtual void didInitializePageGroup(WKBundleRef, WKBundlePageGroupRef) { }
+ virtual void didReceiveMessage(WKBundleRef, WKStringRef messageName, WKTypeRef messageBody) { }
+
+ std::string name() const { return m_identifier; }
+
+ template<typename TestClassTy> class Register {
+ public:
+ Register(const std::string& test)
+ {
+ InjectedBundleController::shared().registerCreateInjectedBundleTestFunction(test, Register::create);
+ }
+
+ private:
+ static InjectedBundleTest* create(const std::string& identifier)
+ {
+ return new TestClassTy(identifier);
+ }
+ };
+
+protected:
+ InjectedBundleTest(const std::string& identifier)
+ : m_identifier(identifier)
+ {
+ }
+
+ std::string m_identifier;
+};
+
+} // namespace TestWebKitAPI
+
+#endif // InjectedBundleTest_h
diff --git a/Tools/TestWebKitAPI/Makefile b/Tools/TestWebKitAPI/Makefile
new file mode 100644
index 0000000..ed01cce
--- /dev/null
+++ b/Tools/TestWebKitAPI/Makefile
@@ -0,0 +1,21 @@
+# Build TestWebKitAPI only on Snow Leopard and later.
+
+OSX_VERSION ?= $(shell sw_vers -productVersion | cut -d. -f 2)
+BUILD_TESTWEBKITAPI = $(shell (( $(OSX_VERSION) >= 6 )) && echo "YES" )
+
+ifeq "$(BUILD_TESTWEBKITAPI)" "YES"
+
+SCRIPTS_PATH = ../Scripts
+include ../../Makefile.shared
+
+else
+
+all: ;
+
+debug d development dev develop: ;
+
+release r deployment dep deploy: ;
+
+clean: ;
+
+endif
diff --git a/Tools/TestWebKitAPI/PlatformUtilities.cpp b/Tools/TestWebKitAPI/PlatformUtilities.cpp
new file mode 100644
index 0000000..2353975
--- /dev/null
+++ b/Tools/TestWebKitAPI/PlatformUtilities.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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 "PlatformUtilities.h"
+
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/PassOwnArrayPtr.h>
+
+namespace TestWebKitAPI {
+namespace Util {
+
+WKContextRef createContextForInjectedBundleTest(const std::string& testName, WKTypeRef userData)
+{
+ WKRetainPtr<WKStringRef> injectedBundlePath(AdoptWK, createInjectedBundlePath());
+ WKContextRef context = WKContextCreateWithInjectedBundlePath(injectedBundlePath.get());
+
+ WKRetainPtr<WKMutableDictionaryRef> initializationDictionary(AdoptWK, WKMutableDictionaryCreate());
+
+ WKRetainPtr<WKStringRef> testNameKey(AdoptWK, WKStringCreateWithUTF8CString("TestName"));
+ WKRetainPtr<WKStringRef> testNameString(AdoptWK, WKStringCreateWithUTF8CString(testName.c_str()));
+ WKDictionaryAddItem(initializationDictionary.get(), testNameKey.get(), testNameString.get());
+
+ WKRetainPtr<WKStringRef> userDataKey(AdoptWK, WKStringCreateWithUTF8CString("UserData"));
+ WKDictionaryAddItem(initializationDictionary.get(), userDataKey.get(), userData);
+
+ WKContextSetInitializationUserDataForInjectedBundle(context, initializationDictionary.get());
+
+ return context;
+}
+
+std::string toSTD(WKStringRef string)
+{
+ size_t bufferSize = WKStringGetMaximumUTF8CStringSize(string);
+ OwnArrayPtr<char> buffer = adoptArrayPtr(new char[bufferSize]);
+ size_t stringLength = WKStringGetUTF8CString(string, buffer.get(), bufferSize);
+ return std::string(buffer.get(), stringLength - 1);
+}
+
+WKRetainPtr<WKStringRef> toWK(const char* utf8String)
+{
+ return WKRetainPtr<WKStringRef>(AdoptWK, WKStringCreateWithUTF8CString(utf8String));
+}
+
+} // namespace Util
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/PlatformUtilities.h b/Tools/TestWebKitAPI/PlatformUtilities.h
new file mode 100644
index 0000000..9fecdd5
--- /dev/null
+++ b/Tools/TestWebKitAPI/PlatformUtilities.h
@@ -0,0 +1,59 @@
+/*
+ * 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 PlatformUtilities_h
+#define PlatformUtilities_h
+
+#include <WebKit2/WebKit2.h>
+#include <WebKit2/WKRetainPtr.h>
+#include <string>
+
+namespace TestWebKitAPI {
+namespace Util {
+
+// Runs a platform runloop until the 'done' is true.
+void run(bool* done);
+
+WKContextRef createContextForInjectedBundleTest(const std::string&, WKTypeRef userData = 0);
+
+WKStringRef createInjectedBundlePath();
+WKURLRef createURLForResource(const char* resource, const char* extension);
+WKURLRef URLForNonExistentResource();
+
+bool isKeyDown(WKNativeEventPtr);
+
+std::string toSTD(WKStringRef string);
+WKRetainPtr<WKStringRef> toWK(const char* utf8String);
+
+
+template<typename T> static inline WKRetainPtr<T> adoptWK(T item)
+{
+ return WKRetainPtr<T>(AdoptWK, item);
+}
+
+} // namespace Util
+} // namespace TestWebKitAPI
+
+#endif // PlatformUtilities_h
diff --git a/Tools/TestWebKitAPI/PlatformWebView.h b/Tools/TestWebKitAPI/PlatformWebView.h
new file mode 100644
index 0000000..43e329b
--- /dev/null
+++ b/Tools/TestWebKitAPI/PlatformWebView.h
@@ -0,0 +1,85 @@
+/*
+ * 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 PlatformWebView_h
+#define PlatformWebView_h
+
+#include <wtf/Platform.h>
+
+#ifdef __APPLE__
+#ifdef __OBJC__
+@class WKView;
+@class NSWindow;
+#else
+class WKView;
+class NSWindow;
+#endif
+typedef WKView *PlatformWKView;
+typedef NSWindow *PlatformWindow;
+#elif defined(WIN32) || defined(_WIN32)
+typedef WKViewRef PlatformWKView;
+typedef HWND PlatformWindow;
+#endif
+
+namespace TestWebKitAPI {
+
+#if PLATFORM(WIN)
+class WindowMessageObserver;
+#endif
+
+class PlatformWebView {
+public:
+ PlatformWebView(WKContextRef, WKPageGroupRef = 0);
+ ~PlatformWebView();
+
+ WKPageRef page();
+ PlatformWKView platformView() const { return m_view; }
+ void resizeTo(unsigned width, unsigned height);
+ void focus();
+
+ void simulateSpacebarKeyPress();
+ void simulateAltKeyPress();
+
+#if PLATFORM(WIN)
+ void setParentWindowMessageObserver(WindowMessageObserver* observer) { m_parentWindowMessageObserver = observer; }
+#endif
+
+private:
+#if PLATFORM(WIN)
+ static void registerWindowClass();
+ static LRESULT CALLBACK wndProc(HWND, UINT message, WPARAM, LPARAM);
+#endif
+
+ PlatformWKView m_view;
+ PlatformWindow m_window;
+
+#if PLATFORM(WIN)
+ WindowMessageObserver* m_parentWindowMessageObserver;
+#endif
+};
+
+} // namespace TestWebKitAPI
+
+#endif // PlatformWebView_h
diff --git a/Tools/TestWebKitAPI/Test.h b/Tools/TestWebKitAPI/Test.h
new file mode 100644
index 0000000..93bfd8b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Test.h
@@ -0,0 +1,86 @@
+/*
+ * 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 Test_h
+#define Test_h
+
+#include "TestsController.h"
+
+namespace TestWebKitAPI {
+
+// Abstract base class that all tests inherit from.
+class Test {
+public:
+ virtual ~Test() { }
+
+ virtual void run() = 0;
+ std::string name() const { return m_identifier; }
+
+ template<typename TestClassTy> class Register {
+ public:
+ Register(const std::string& testSuite, const std::string& testCase)
+ {
+ TestsController::shared().registerCreateTestFunction(testSuite + "/" + testCase, Register::create);
+ }
+
+ private:
+ static Test* create(const std::string& identifier)
+ {
+ return new TestClassTy(identifier);
+ }
+ };
+
+protected:
+ Test(const std::string& identifier)
+ : m_identifier(identifier)
+ {
+ }
+
+ std::string m_identifier;
+};
+
+#define TEST_CLASS_NAME(testSuite, testCaseName) testSuite##testCaseName##_Test
+#define TEST_REGISTRAR_NAME(testSuite, testCaseName) testSuite##testCaseName##_Registrar
+
+// Use this to define a new test.
+#define TEST(testSuite, testCaseName) \
+ class TEST_CLASS_NAME(testSuite, testCaseName) : public Test { \
+ public: \
+ TEST_CLASS_NAME(testSuite, testCaseName)(const std::string& identifier) \
+ : Test(identifier) \
+ { \
+ } \
+ virtual void run(); \
+ }; \
+ \
+ static Test::Register<TEST_CLASS_NAME(testSuite, testCaseName)> TEST_REGISTRAR_NAME(testSuite, testCaseName)(#testSuite, #testCaseName); \
+ \
+ void TEST_CLASS_NAME(testSuite, testCaseName)::run()
+
+#define TEST_ASSERT(expression) do { if (!(expression)) { TestsController::shared().testFailed(__FILE__, __LINE__, #expression); return; } } while (0)
+
+} // namespace TestWebKitAPI
+
+#endif // Test_h
diff --git a/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..0aca686
--- /dev/null
+++ b/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj
@@ -0,0 +1,501 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 1A02C84F125D4A8400E3F4BD /* Find.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A02C84E125D4A8400E3F4BD /* Find.cpp */; };
+ 1A02C870125D4CFD00E3F4BD /* find.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = 1A02C84B125D4A5E00E3F4BD /* find.html */; };
+ 1A5FEFDD1270E2A3000E2921 /* EvaluateJavaScript.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1A5FEFDC1270E2A3000E2921 /* EvaluateJavaScript.cpp */; };
+ 333B9CE21277F23100FEFCE3 /* PreventEmptyUserAgent.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 333B9CE11277F23100FEFCE3 /* PreventEmptyUserAgent.cpp */; };
+ BC131885117114B600B69727 /* PlatformUtilitiesMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC131884117114B600B69727 /* PlatformUtilitiesMac.mm */; };
+ BC131A9B1171316900B69727 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC131A9A1171316900B69727 /* main.mm */; };
+ BC131AA9117131FC00B69727 /* TestsController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC131AA8117131FC00B69727 /* TestsController.cpp */; };
+ BC2D004912A9FDFA00E732A3 /* PageLoadDidChangeLocationWithinPageForFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC2D004812A9FDFA00E732A3 /* PageLoadDidChangeLocationWithinPageForFrame.cpp */; };
+ BC2D006412AA04CE00E732A3 /* file-with-anchor.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = BC2D004A12A9FEB300E732A3 /* file-with-anchor.html */; };
+ BC575A90126E74D3006F0F12 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BCB9E9F011235BDE00A137E0 /* Cocoa.framework */; };
+ BC575A91126E74D3006F0F12 /* WebKit2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BCA61DB411700EFD00460D1E /* WebKit2.framework */; };
+ BC575A92126E74D3006F0F12 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC90964D1255620C00083756 /* JavaScriptCore.framework */; };
+ BC575A97126E74F1006F0F12 /* InjectedBundleMain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC575946126E7351006F0F12 /* InjectedBundleMain.cpp */; };
+ BC575AA2126E7660006F0F12 /* InjectedBundleController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC575AA0126E7657006F0F12 /* InjectedBundleController.cpp */; };
+ BC575AAD126E83B9006F0F12 /* InjectedBundleBasic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC575AAC126E83B9006F0F12 /* InjectedBundleBasic.cpp */; };
+ BC575AB0126E83C8006F0F12 /* InjectedBundleBasic_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC575AAF126E83C8006F0F12 /* InjectedBundleBasic_Bundle.cpp */; };
+ BC575BC0126F5752006F0F12 /* PlatformUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC575BBF126F5752006F0F12 /* PlatformUtilities.cpp */; };
+ BC575BD9126F58E2006F0F12 /* PlatformUtilities.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC575BBF126F5752006F0F12 /* PlatformUtilities.cpp */; };
+ BC575BE0126F590D006F0F12 /* PlatformUtilitiesMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC131884117114B600B69727 /* PlatformUtilitiesMac.mm */; };
+ BC7B61AA129A038700D174A4 /* WKPreferences.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC7B619A1299FE9E00D174A4 /* WKPreferences.cpp */; };
+ BC90955D125548AA00083756 /* PlatformWebViewMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC90955C125548AA00083756 /* PlatformWebViewMac.mm */; };
+ BC90964C125561BF00083756 /* VectorBasic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC90964B125561BF00083756 /* VectorBasic.cpp */; };
+ BC90964E1255620C00083756 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC90964D1255620C00083756 /* JavaScriptCore.framework */; };
+ BC90977A125571AB00083756 /* PageLoadBasic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC909779125571AB00083756 /* PageLoadBasic.cpp */; };
+ BC909784125571CF00083756 /* simple.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = BC909778125571AB00083756 /* simple.html */; };
+ BC90995E12567BC100083756 /* WKString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC90995D12567BC100083756 /* WKString.cpp */; };
+ BC9099941256ACF100083756 /* WKStringJSString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC9099931256ACF100083756 /* WKStringJSString.cpp */; };
+ BCA61DB511700EFD00460D1E /* WebKit2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BCA61DB411700EFD00460D1E /* WebKit2.framework */; };
+ BCB68040126FBFE100642A61 /* DocumentStartUserScriptAlertCrash.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCB6803F126FBFE100642A61 /* DocumentStartUserScriptAlertCrash.cpp */; };
+ BCB68042126FBFF100642A61 /* DocumentStartUserScriptAlertCrash_Bundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCB68041126FBFF100642A61 /* DocumentStartUserScriptAlertCrash_Bundle.cpp */; };
+ BCB9E9F111235BDE00A137E0 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BCB9E9F011235BDE00A137E0 /* Cocoa.framework */; };
+ BCBD3710125AA2EB00D2C29F /* FrameMIMETypeHTML.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCBD370F125AA2EB00D2C29F /* FrameMIMETypeHTML.cpp */; };
+ BCBD3737125ABBEB00D2C29F /* icon.png in Copy Resources */ = {isa = PBXBuildFile; fileRef = BCBD372E125ABBE600D2C29F /* icon.png */; };
+ BCBD3761125ABCFE00D2C29F /* FrameMIMETypePNG.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCBD3760125ABCFE00D2C29F /* FrameMIMETypePNG.cpp */; };
+ BCC8B95B12611F4700DE46A4 /* FailedLoad.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCC8B95A12611F4700DE46A4 /* FailedLoad.cpp */; };
+ C01A23F21266156700C9ED55 /* spacebar-scrolling.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = C02B7882126615410026BF0F /* spacebar-scrolling.html */; };
+ C02B77F2126612140026BF0F /* SpacebarScrolling.cpp in Sources */ = {isa = PBXBuildFile; fileRef = C02B77F1126612140026BF0F /* SpacebarScrolling.cpp */; };
+ C02B7854126613AE0026BF0F /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C02B7853126613AE0026BF0F /* Carbon.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ BC575A95126E74E7006F0F12 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BC57597F126E74AF006F0F12;
+ remoteInfo = InjectedBundle;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 8DD76F9E0486AA7600D96B5E /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+ BCB9F4FB112384C000A137E0 /* Copy Resources */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 7;
+ files = (
+ BCBD3737125ABBEB00D2C29F /* icon.png in Copy Resources */,
+ 1A02C870125D4CFD00E3F4BD /* find.html in Copy Resources */,
+ BC909784125571CF00083756 /* simple.html in Copy Resources */,
+ C01A23F21266156700C9ED55 /* spacebar-scrolling.html in Copy Resources */,
+ BC2D006412AA04CE00E732A3 /* file-with-anchor.html in Copy Resources */,
+ );
+ name = "Copy Resources";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 1A02C84B125D4A5E00E3F4BD /* find.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = find.html; sourceTree = "<group>"; };
+ 1A02C84E125D4A8400E3F4BD /* Find.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Find.cpp; sourceTree = "<group>"; };
+ 1A5FEFDC1270E2A3000E2921 /* EvaluateJavaScript.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EvaluateJavaScript.cpp; sourceTree = "<group>"; };
+ 333B9CE11277F23100FEFCE3 /* PreventEmptyUserAgent.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PreventEmptyUserAgent.cpp; sourceTree = "<group>"; };
+ 8DD76FA10486AA7600D96B5E /* TestWebKitAPI */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = TestWebKitAPI; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC131883117114A800B69727 /* PlatformUtilities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformUtilities.h; sourceTree = "<group>"; };
+ BC131884117114B600B69727 /* PlatformUtilitiesMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformUtilitiesMac.mm; sourceTree = "<group>"; };
+ BC131A9A1171316900B69727 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
+ BC131A9E1171317C00B69727 /* TestWebKitAPIPrefix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestWebKitAPIPrefix.h; sourceTree = "<group>"; };
+ BC131AA8117131FC00B69727 /* TestsController.cpp */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.cpp; fileEncoding = 4; path = TestsController.cpp; sourceTree = "<group>"; };
+ BC2D004812A9FDFA00E732A3 /* PageLoadDidChangeLocationWithinPageForFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageLoadDidChangeLocationWithinPageForFrame.cpp; sourceTree = "<group>"; };
+ BC2D004A12A9FEB300E732A3 /* file-with-anchor.html */ = {isa = PBXFileReference; explicitFileType = text.html; fileEncoding = 4; path = "file-with-anchor.html"; sourceTree = "<group>"; };
+ BC575946126E7351006F0F12 /* InjectedBundleMain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundleMain.cpp; sourceTree = "<group>"; };
+ BC575980126E74AF006F0F12 /* InjectedBundleTestWebKitAPI.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = InjectedBundleTestWebKitAPI.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC575981126E74AF006F0F12 /* InjectedBundle-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "InjectedBundle-Info.plist"; sourceTree = "<group>"; };
+ BC575A9E126E75FB006F0F12 /* InjectedBundleTest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedBundleTest.h; sourceTree = "<group>"; };
+ BC575A9F126E7657006F0F12 /* InjectedBundleController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedBundleController.h; sourceTree = "<group>"; };
+ BC575AA0126E7657006F0F12 /* InjectedBundleController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundleController.cpp; sourceTree = "<group>"; };
+ BC575AAC126E83B9006F0F12 /* InjectedBundleBasic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundleBasic.cpp; sourceTree = "<group>"; };
+ BC575AAF126E83C8006F0F12 /* InjectedBundleBasic_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundleBasic_Bundle.cpp; sourceTree = "<group>"; };
+ BC575AE2126E88B1006F0F12 /* InjectedBundle.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = InjectedBundle.xcconfig; sourceTree = "<group>"; };
+ BC575BBF126F5752006F0F12 /* PlatformUtilities.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PlatformUtilities.cpp; sourceTree = "<group>"; };
+ BC7B619A1299FE9E00D174A4 /* WKPreferences.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKPreferences.cpp; sourceTree = "<group>"; };
+ BC90951B125533D700083756 /* PlatformWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformWebView.h; sourceTree = "<group>"; };
+ BC90955C125548AA00083756 /* PlatformWebViewMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformWebViewMac.mm; sourceTree = "<group>"; };
+ BC90957E12554CF900083756 /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; };
+ BC90957F12554CF900083756 /* DebugRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugRelease.xcconfig; sourceTree = "<group>"; };
+ BC90958012554CF900083756 /* TestWebKitAPI.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = TestWebKitAPI.xcconfig; sourceTree = "<group>"; };
+ BC90964B125561BF00083756 /* VectorBasic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = VectorBasic.cpp; path = WTF/VectorBasic.cpp; sourceTree = "<group>"; };
+ BC90964D1255620C00083756 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = JavaScriptCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC909778125571AB00083756 /* simple.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = simple.html; sourceTree = "<group>"; };
+ BC909779125571AB00083756 /* PageLoadBasic.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PageLoadBasic.cpp; sourceTree = "<group>"; };
+ BC90995D12567BC100083756 /* WKString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKString.cpp; sourceTree = "<group>"; };
+ BC9099931256ACF100083756 /* WKStringJSString.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WKStringJSString.cpp; sourceTree = "<group>"; };
+ BCA61DB411700EFD00460D1E /* WebKit2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = WebKit2.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ BCB6803F126FBFE100642A61 /* DocumentStartUserScriptAlertCrash.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentStartUserScriptAlertCrash.cpp; sourceTree = "<group>"; };
+ BCB68041126FBFF100642A61 /* DocumentStartUserScriptAlertCrash_Bundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DocumentStartUserScriptAlertCrash_Bundle.cpp; sourceTree = "<group>"; };
+ BCB9E7C711234E3A00A137E0 /* TestsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestsController.h; sourceTree = "<group>"; };
+ BCB9E7FA112359A300A137E0 /* Test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Test.h; sourceTree = "<group>"; };
+ BCB9E9F011235BDE00A137E0 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
+ BCBD370F125AA2EB00D2C29F /* FrameMIMETypeHTML.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameMIMETypeHTML.cpp; sourceTree = "<group>"; };
+ BCBD372E125ABBE600D2C29F /* icon.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = icon.png; sourceTree = "<group>"; };
+ BCBD3760125ABCFE00D2C29F /* FrameMIMETypePNG.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FrameMIMETypePNG.cpp; sourceTree = "<group>"; };
+ BCC8B95A12611F4700DE46A4 /* FailedLoad.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FailedLoad.cpp; sourceTree = "<group>"; };
+ C02B77F1126612140026BF0F /* SpacebarScrolling.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = SpacebarScrolling.cpp; sourceTree = "<group>"; };
+ C02B7853126613AE0026BF0F /* Carbon.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; name = Carbon.framework; sourceTree = SDKROOT; };
+ C02B7882126615410026BF0F /* spacebar-scrolling.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "spacebar-scrolling.html"; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8DD76F9B0486AA7600D96B5E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BCB9E9F111235BDE00A137E0 /* Cocoa.framework in Frameworks */,
+ BCA61DB511700EFD00460D1E /* WebKit2.framework in Frameworks */,
+ BC90964E1255620C00083756 /* JavaScriptCore.framework in Frameworks */,
+ C02B7854126613AE0026BF0F /* Carbon.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BC57597E126E74AF006F0F12 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BC575A90126E74D3006F0F12 /* Cocoa.framework in Frameworks */,
+ BC575A91126E74D3006F0F12 /* WebKit2.framework in Frameworks */,
+ BC575A92126E74D3006F0F12 /* JavaScriptCore.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* TestWebKitAPI */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB7795FE84155DC02AAC07 /* Source */,
+ BCB9EB66112366D800A137E0 /* Tests */,
+ BC90957D12554CEA00083756 /* Configurations */,
+ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
+ 1AB674ADFE9D54B511CA2CBB /* Products */,
+ BC575981126E74AF006F0F12 /* InjectedBundle-Info.plist */,
+ );
+ name = TestWebKitAPI;
+ sourceTree = "<group>";
+ };
+ 08FB7795FE84155DC02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ BCA61C3A11700B9400460D1E /* mac */,
+ BC575944126E733C006F0F12 /* InjectedBundle */,
+ BC131A9E1171317C00B69727 /* TestWebKitAPIPrefix.h */,
+ BC575BBF126F5752006F0F12 /* PlatformUtilities.cpp */,
+ BC131883117114A800B69727 /* PlatformUtilities.h */,
+ BC90951B125533D700083756 /* PlatformWebView.h */,
+ BCB9E7FA112359A300A137E0 /* Test.h */,
+ BC131AA8117131FC00B69727 /* TestsController.cpp */,
+ BCB9E7C711234E3A00A137E0 /* TestsController.h */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ BCB9E9F011235BDE00A137E0 /* Cocoa.framework */,
+ BC90964D1255620C00083756 /* JavaScriptCore.framework */,
+ BCA61DB411700EFD00460D1E /* WebKit2.framework */,
+ C02B7853126613AE0026BF0F /* Carbon.framework */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 1AB674ADFE9D54B511CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8DD76FA10486AA7600D96B5E /* TestWebKitAPI */,
+ BC575980126E74AF006F0F12 /* InjectedBundleTestWebKitAPI.bundle */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ BC575944126E733C006F0F12 /* InjectedBundle */ = {
+ isa = PBXGroup;
+ children = (
+ BC575946126E7351006F0F12 /* InjectedBundleMain.cpp */,
+ BC575A9E126E75FB006F0F12 /* InjectedBundleTest.h */,
+ BC575A9F126E7657006F0F12 /* InjectedBundleController.h */,
+ BC575AA0126E7657006F0F12 /* InjectedBundleController.cpp */,
+ );
+ name = InjectedBundle;
+ sourceTree = "<group>";
+ };
+ BC90957D12554CEA00083756 /* Configurations */ = {
+ isa = PBXGroup;
+ children = (
+ BC90957E12554CF900083756 /* Base.xcconfig */,
+ BC90957F12554CF900083756 /* DebugRelease.xcconfig */,
+ BC575AE2126E88B1006F0F12 /* InjectedBundle.xcconfig */,
+ BC90958012554CF900083756 /* TestWebKitAPI.xcconfig */,
+ );
+ path = Configurations;
+ sourceTree = "<group>";
+ };
+ BC9096411255616000083756 /* WebKit2 */ = {
+ isa = PBXGroup;
+ children = (
+ BC90977B125571AE00083756 /* Resources */,
+ BCB6803F126FBFE100642A61 /* DocumentStartUserScriptAlertCrash.cpp */,
+ BCB68041126FBFF100642A61 /* DocumentStartUserScriptAlertCrash_Bundle.cpp */,
+ 1A5FEFDC1270E2A3000E2921 /* EvaluateJavaScript.cpp */,
+ BCC8B95A12611F4700DE46A4 /* FailedLoad.cpp */,
+ 1A02C84E125D4A8400E3F4BD /* Find.cpp */,
+ BCBD370F125AA2EB00D2C29F /* FrameMIMETypeHTML.cpp */,
+ BCBD3760125ABCFE00D2C29F /* FrameMIMETypePNG.cpp */,
+ BC575AAC126E83B9006F0F12 /* InjectedBundleBasic.cpp */,
+ BC575AAF126E83C8006F0F12 /* InjectedBundleBasic_Bundle.cpp */,
+ BC909779125571AB00083756 /* PageLoadBasic.cpp */,
+ BC2D004812A9FDFA00E732A3 /* PageLoadDidChangeLocationWithinPageForFrame.cpp */,
+ 333B9CE11277F23100FEFCE3 /* PreventEmptyUserAgent.cpp */,
+ C02B77F1126612140026BF0F /* SpacebarScrolling.cpp */,
+ BC7B619A1299FE9E00D174A4 /* WKPreferences.cpp */,
+ BC90995D12567BC100083756 /* WKString.cpp */,
+ BC9099931256ACF100083756 /* WKStringJSString.cpp */,
+ );
+ path = WebKit2;
+ sourceTree = "<group>";
+ };
+ BC9096461255618900083756 /* WTF */ = {
+ isa = PBXGroup;
+ children = (
+ BC90964B125561BF00083756 /* VectorBasic.cpp */,
+ );
+ name = WTF;
+ sourceTree = "<group>";
+ };
+ BC90977B125571AE00083756 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ BC2D004A12A9FEB300E732A3 /* file-with-anchor.html */,
+ 1A02C84B125D4A5E00E3F4BD /* find.html */,
+ BCBD372E125ABBE600D2C29F /* icon.png */,
+ BC909778125571AB00083756 /* simple.html */,
+ C02B7882126615410026BF0F /* spacebar-scrolling.html */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ BCA61C3A11700B9400460D1E /* mac */ = {
+ isa = PBXGroup;
+ children = (
+ BC131A9A1171316900B69727 /* main.mm */,
+ BC131884117114B600B69727 /* PlatformUtilitiesMac.mm */,
+ BC90955C125548AA00083756 /* PlatformWebViewMac.mm */,
+ );
+ path = mac;
+ sourceTree = "<group>";
+ };
+ BCB9EB66112366D800A137E0 /* Tests */ = {
+ isa = PBXGroup;
+ children = (
+ BC9096411255616000083756 /* WebKit2 */,
+ BC9096461255618900083756 /* WTF */,
+ );
+ path = Tests;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 8DD76F960486AA7600D96B5E /* TestWebKitAPI */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "TestWebKitAPI" */;
+ buildPhases = (
+ 8DD76F990486AA7600D96B5E /* Sources */,
+ 8DD76F9B0486AA7600D96B5E /* Frameworks */,
+ 8DD76F9E0486AA7600D96B5E /* CopyFiles */,
+ BCB9F4FB112384C000A137E0 /* Copy Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ BC575A96126E74E7006F0F12 /* PBXTargetDependency */,
+ );
+ name = TestWebKitAPI;
+ productInstallPath = "$(HOME)/bin";
+ productName = TestWebKitAPI;
+ productReference = 8DD76FA10486AA7600D96B5E /* TestWebKitAPI */;
+ productType = "com.apple.product-type.tool";
+ };
+ BC57597F126E74AF006F0F12 /* InjectedBundleTestWebKitAPI */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BC575986126E74AF006F0F12 /* Build configuration list for PBXNativeTarget "InjectedBundleTestWebKitAPI" */;
+ buildPhases = (
+ BC57597C126E74AF006F0F12 /* Resources */,
+ BC57597D126E74AF006F0F12 /* Sources */,
+ BC57597E126E74AF006F0F12 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = InjectedBundleTestWebKitAPI;
+ productName = InjectedBundle;
+ productReference = BC575980126E74AF006F0F12 /* InjectedBundleTestWebKitAPI.bundle */;
+ productType = "com.apple.product-type.bundle";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "TestWebKitAPI" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 08FB7794FE84155DC02AAC07 /* TestWebKitAPI */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8DD76F960486AA7600D96B5E /* TestWebKitAPI */,
+ BC57597F126E74AF006F0F12 /* InjectedBundleTestWebKitAPI */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ BC57597C126E74AF006F0F12 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8DD76F990486AA7600D96B5E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BC131885117114B600B69727 /* PlatformUtilitiesMac.mm in Sources */,
+ BC131A9B1171316900B69727 /* main.mm in Sources */,
+ BC131AA9117131FC00B69727 /* TestsController.cpp in Sources */,
+ BC90955D125548AA00083756 /* PlatformWebViewMac.mm in Sources */,
+ BC90964C125561BF00083756 /* VectorBasic.cpp in Sources */,
+ BC90977A125571AB00083756 /* PageLoadBasic.cpp in Sources */,
+ BC90995E12567BC100083756 /* WKString.cpp in Sources */,
+ BC9099941256ACF100083756 /* WKStringJSString.cpp in Sources */,
+ BCBD3710125AA2EB00D2C29F /* FrameMIMETypeHTML.cpp in Sources */,
+ BCBD3761125ABCFE00D2C29F /* FrameMIMETypePNG.cpp in Sources */,
+ 1A02C84F125D4A8400E3F4BD /* Find.cpp in Sources */,
+ BCC8B95B12611F4700DE46A4 /* FailedLoad.cpp in Sources */,
+ C02B77F2126612140026BF0F /* SpacebarScrolling.cpp in Sources */,
+ BC575AAD126E83B9006F0F12 /* InjectedBundleBasic.cpp in Sources */,
+ BC575BC0126F5752006F0F12 /* PlatformUtilities.cpp in Sources */,
+ BCB68040126FBFE100642A61 /* DocumentStartUserScriptAlertCrash.cpp in Sources */,
+ 1A5FEFDD1270E2A3000E2921 /* EvaluateJavaScript.cpp in Sources */,
+ 333B9CE21277F23100FEFCE3 /* PreventEmptyUserAgent.cpp in Sources */,
+ BC7B61AA129A038700D174A4 /* WKPreferences.cpp in Sources */,
+ BC2D004912A9FDFA00E732A3 /* PageLoadDidChangeLocationWithinPageForFrame.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BC57597D126E74AF006F0F12 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BC575A97126E74F1006F0F12 /* InjectedBundleMain.cpp in Sources */,
+ BC575AA2126E7660006F0F12 /* InjectedBundleController.cpp in Sources */,
+ BC575AB0126E83C8006F0F12 /* InjectedBundleBasic_Bundle.cpp in Sources */,
+ BC575BD9126F58E2006F0F12 /* PlatformUtilities.cpp in Sources */,
+ BC575BE0126F590D006F0F12 /* PlatformUtilitiesMac.mm in Sources */,
+ BCB68042126FBFF100642A61 /* DocumentStartUserScriptAlertCrash_Bundle.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ BC575A96126E74E7006F0F12 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BC57597F126E74AF006F0F12 /* InjectedBundleTestWebKitAPI */;
+ targetProxy = BC575A95126E74E7006F0F12 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB927508733DD40010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC90958012554CF900083756 /* TestWebKitAPI.xcconfig */;
+ buildSettings = {
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
+ };
+ name = Debug;
+ };
+ 1DEB927608733DD40010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC90958012554CF900083756 /* TestWebKitAPI.xcconfig */;
+ buildSettings = {
+ FRAMEWORK_SEARCH_PATHS = "$(inherited)";
+ };
+ name = Release;
+ };
+ 1DEB927908733DD40010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC90957F12554CF900083756 /* DebugRelease.xcconfig */;
+ buildSettings = {
+ GCC_OPTIMIZATION_LEVEL = 0;
+ };
+ name = Debug;
+ };
+ 1DEB927A08733DD40010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC90957F12554CF900083756 /* DebugRelease.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ BC575984126E74AF006F0F12 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC575AE2126E88B1006F0F12 /* InjectedBundle.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ BC575985126E74AF006F0F12 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC575AE2126E88B1006F0F12 /* InjectedBundle.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "TestWebKitAPI" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB927508733DD40010E9CD /* Debug */,
+ 1DEB927608733DD40010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "TestWebKitAPI" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB927908733DD40010E9CD /* Debug */,
+ 1DEB927A08733DD40010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BC575986126E74AF006F0F12 /* Build configuration list for PBXNativeTarget "InjectedBundleTestWebKitAPI" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BC575984126E74AF006F0F12 /* Debug */,
+ BC575985126E74AF006F0F12 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
diff --git a/Tools/TestWebKitAPI/TestWebKitAPIPrefix.h b/Tools/TestWebKitAPI/TestWebKitAPIPrefix.h
new file mode 100644
index 0000000..00e14ad
--- /dev/null
+++ b/Tools/TestWebKitAPI/TestWebKitAPIPrefix.h
@@ -0,0 +1,41 @@
+/*
+ * 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.
+ */
+
+
+#if __APPLE__
+
+#ifdef __OBJC__
+#import <Cocoa/Cocoa.h>
+#endif
+
+#elif defined(WIN32) || defined(_WIN32)
+
+#define NOMINMAX
+
+#endif
+
+#include <stdint.h>
+
+#include <WebKit2/WebKit2.h>
diff --git a/Tools/TestWebKitAPI/Tests/WTF/VectorBasic.cpp b/Tools/TestWebKitAPI/Tests/WTF/VectorBasic.cpp
new file mode 100644
index 0000000..012fa27
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WTF/VectorBasic.cpp
@@ -0,0 +1,40 @@
+/*
+ * 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 "Test.h"
+
+#include <JavaScriptCore/Vector.h>
+
+namespace TestWebKitAPI {
+
+TEST(WTF, VectorBasic)
+{
+ Vector<int> intVector;
+ TEST_ASSERT(intVector.isEmpty());
+ TEST_ASSERT(intVector.size() == 0);
+ TEST_ASSERT(intVector.capacity() == 0);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp
new file mode 100644
index 0000000..fdda8c7
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash.cpp
@@ -0,0 +1,66 @@
+/*
+ * 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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WebKit2.h>
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool done;
+
+static void runJavaScriptAlert(WKPageRef page, WKStringRef alertText, WKFrameRef frame, const void* clientInfo)
+{
+ TEST_ASSERT(frame);
+ TEST_ASSERT(WKFrameGetPage(frame) == page);
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(alertText, "an alert"));
+
+ done = true;
+}
+
+TEST(WebKit2, DocumentStartUserScriptAlertCrashTest)
+{
+ WKRetainPtr<WKPageGroupRef> pageGroup(AdoptWK, WKPageGroupCreateWithIdentifier(WKStringCreateWithUTF8CString("DocumentStartUserScriptAlertCrashTestPageGroup")));
+
+ WKRetainPtr<WKContextRef> context(AdoptWK, Util::createContextForInjectedBundleTest("DocumentStartUserScriptAlertCrashTest", pageGroup.get()));
+ PlatformWebView webView(context.get(), pageGroup.get());
+
+ WKPageUIClient uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+ uiClient.version = 0;
+ uiClient.clientInfo = 0;
+ uiClient.runJavaScriptAlert = runJavaScriptAlert;
+ WKPageSetPageUIClient(webView.page(), &uiClient);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("simple", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&done);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp
new file mode 100644
index 0000000..dbd5d21
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/DocumentStartUserScriptAlertCrash_Bundle.cpp
@@ -0,0 +1,58 @@
+/*
+ * 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 "InjectedBundleTest.h"
+#include <WebKit2/WKBundlePageGroup.h>
+#include <WebKit2/WKBundlePrivate.h>
+#include <WebKit2/WKBundleScriptWorld.h>
+#include <WebKit2/WKRetainPtr.h>
+#include <WebKit2/WebKit2.h>
+#include <assert.h>
+
+namespace TestWebKitAPI {
+
+class DocumentStartUserScriptAlertCrashTest : public InjectedBundleTest {
+public:
+ DocumentStartUserScriptAlertCrashTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
+ {
+ }
+
+ virtual void initialize(WKBundleRef bundle, WKTypeRef userData)
+ {
+ assert(WKGetTypeID(userData) == WKBundlePageGroupGetTypeID());
+ WKBundlePageGroupRef pageGroup = static_cast<WKBundlePageGroupRef>(userData);
+
+ WKRetainPtr<WKStringRef> source(AdoptWK, WKStringCreateWithUTF8CString("alert('an alert');"));
+ WKBundleAddUserScript(bundle, pageGroup, WKBundleScriptWorldNormalWorld(), source.get(), 0, 0, 0, kWKInjectAtDocumentStart, kWKInjectInAllFrames);
+ }
+
+private:
+ WKBundlePageGroupRef m_pageGroup;
+};
+
+static InjectedBundleTest::Register<DocumentStartUserScriptAlertCrashTest> registrar("DocumentStartUserScriptAlertCrashTest");
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/EvaluateJavaScript.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/EvaluateJavaScript.cpp
new file mode 100644
index 0000000..32bd563
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/EvaluateJavaScript.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WKRetainPtr.h>
+#include <WebKit2/WebKit2.h>
+
+namespace TestWebKitAPI {
+
+static bool testDone;
+
+static void didRunJavaScript(WKStringRef resultString, WKErrorRef error, void* context)
+{
+ TEST_ASSERT(context == reinterpret_cast<void*>(0x1234578));
+ TEST_ASSERT(WKStringIsEmpty(resultString));
+
+ // FIXME: We should also check the error, but right now it's always null.
+ // Assert that it's null so we can revisit when this changes.
+ TEST_ASSERT(!error);
+
+ testDone = true;
+}
+
+TEST(WebKit2, EvaluateJavaScriptThatThrowsAnException)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKRetainPtr<WKStringRef> javaScriptString(AdoptWK, WKStringCreateWithUTF8CString("throw 'Hello'"));
+ WKPageRunJavaScriptInMainFrame(webView.page(), javaScriptString.get(), reinterpret_cast<void*>(0x1234578), didRunJavaScript);
+
+ Util::run(&testDone);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/FailedLoad.cpp
new file mode 100644
index 0000000..fdb3693
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/FailedLoad.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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WebKit2.h>
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+// FIXME: This should also test the that the load state after didFailLoadWithErrorForFrame is kWKFrameLoadStateFinished
+
+static bool testDone;
+
+static void didFailProvisionalLoadWithErrorForFrame(WKPageRef page, WKFrameRef frame, WKErrorRef error, WKTypeRef userData, const void* clientInfo)
+{
+ TEST_ASSERT(WKFrameGetFrameLoadState(frame) == kWKFrameLoadStateFinished);
+
+ WKURLRef url = WKFrameCopyProvisionalURL(frame);
+ TEST_ASSERT(!url);
+
+ testDone = true;
+}
+
+TEST(WebKit2, FailedLoad)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClient loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.version = 0;
+ loaderClient.clientInfo = 0;
+ loaderClient.didFailProvisionalLoadWithErrorForFrame = didFailProvisionalLoadWithErrorForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::URLForNonExistentResource());
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&testDone);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/Find.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/Find.cpp
new file mode 100644
index 0000000..f22c44d
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/Find.cpp
@@ -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. 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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WKRetainPtr.h>
+#include <WebKit2/WebKit2.h>
+
+namespace TestWebKitAPI {
+
+static bool didFinishLoad = false;
+static bool didCallCountStringMatches = false;
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ didFinishLoad = true;
+}
+
+static void didCountStringMatches(WKPageRef page, WKStringRef string, unsigned numMatches, const void* clientInfo)
+{
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(string, "Hello"));
+ TEST_ASSERT(numMatches == 3);
+
+ didCallCountStringMatches = true;
+}
+
+TEST(WebKit2, Find)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClient loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient);
+
+ WKPageFindClient findClient;
+ memset(&findClient, 0, sizeof(findClient));
+
+ findClient.version = 0;
+ findClient.didCountStringMatches = didCountStringMatches;
+ WKPageSetPageFindClient(webView.page(), &findClient);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("find", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&didFinishLoad);
+
+ WKRetainPtr<WKStringRef> findString(AdoptWK, WKStringCreateWithUTF8CString("Hello"));
+ WKPageCountStringMatches(webView.page(), findString.get(), true, 100);
+
+ Util::run(&didCallCountStringMatches);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.cpp
new file mode 100644
index 0000000..1188bb2
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypeHTML.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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WebKit2.h>
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool testDone;
+
+static void didStartProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ WKRetainPtr<WKStringRef> wkMIME(AdoptWK, WKFrameCopyMIMEType(frame));
+ TEST_ASSERT(WKStringIsEmpty(wkMIME.get()));
+}
+
+static void didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ WKRetainPtr<WKStringRef> wkMIME(AdoptWK, WKFrameCopyMIMEType(frame));
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(wkMIME.get(), "text/html"));
+}
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ WKRetainPtr<WKStringRef> wkMIME(AdoptWK, WKFrameCopyMIMEType(frame));
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(wkMIME.get(), "text/html"));
+
+ testDone = true;
+}
+
+TEST(WebKit2, FrameMIMETypeHTML)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClient loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.version = 0;
+ loaderClient.clientInfo = 0;
+ loaderClient.didStartProvisionalLoadForFrame = didStartProvisionalLoadForFrame;
+ loaderClient.didCommitLoadForFrame = didCommitLoadForFrame;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("simple", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&testDone);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.cpp
new file mode 100644
index 0000000..1b56bae
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/FrameMIMETypePNG.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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WebKit2.h>
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool testDone;
+
+static void didStartProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ WKRetainPtr<WKStringRef> wkMIME(AdoptWK, WKFrameCopyMIMEType(frame));
+ TEST_ASSERT(WKStringIsEmpty(wkMIME.get()));
+}
+
+static void didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ WKRetainPtr<WKStringRef> wkMIME(AdoptWK, WKFrameCopyMIMEType(frame));
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(wkMIME.get(), "image/png"));
+}
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ WKRetainPtr<WKStringRef> wkMIME(AdoptWK, WKFrameCopyMIMEType(frame));
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(wkMIME.get(), "image/png"));
+
+ testDone = true;
+}
+
+TEST(WebKit2, FrameMIMETypePNG)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClient loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.version = 0;
+ loaderClient.clientInfo = 0;
+ loaderClient.didStartProvisionalLoadForFrame = didStartProvisionalLoadForFrame;
+ loaderClient.didCommitLoadForFrame = didCommitLoadForFrame;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("icon", "png"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&testDone);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic.cpp
new file mode 100644
index 0000000..f28971d
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WebKit2.h>
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool done;
+static bool loadDone;
+static bool messageReceived;
+
+void didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
+{
+ messageReceived = true;
+ if (loadDone)
+ done = true;
+}
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ loadDone = true;
+ if (messageReceived)
+ done = true;
+}
+
+TEST(WebKit2, InjectedBundleBasic)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, Util::createContextForInjectedBundleTest("InjectedBundleBasicTest"));
+
+ WKContextInjectedBundleClient injectedBundleClient;
+ memset(&injectedBundleClient, 0, sizeof(injectedBundleClient));
+ injectedBundleClient.version = 0;
+ injectedBundleClient.clientInfo = 0;
+ injectedBundleClient.didReceiveMessageFromInjectedBundle = didReceiveMessageFromInjectedBundle;
+ WKContextSetInjectedBundleClient(context.get(), &injectedBundleClient);
+
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClient loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+ loaderClient.version = 0;
+ loaderClient.clientInfo = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("simple", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&done);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic_Bundle.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic_Bundle.cpp
new file mode 100644
index 0000000..67c062b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/InjectedBundleBasic_Bundle.cpp
@@ -0,0 +1,49 @@
+/*
+ * 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 "InjectedBundleTest.h"
+#include <WebKit2/WebKit2.h>
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+class InjectedBundleBasicTest : public InjectedBundleTest {
+public:
+ InjectedBundleBasicTest(const std::string& identifier)
+ : InjectedBundleTest(identifier)
+ {
+ }
+
+ virtual void didCreatePage(WKBundleRef bundle, WKBundlePageRef page)
+ {
+ WKRetainPtr<WKStringRef> doneMessageName(AdoptWK, WKStringCreateWithUTF8CString("DoneMessageName"));
+ WKRetainPtr<WKStringRef> doneMessageBody(AdoptWK, WKStringCreateWithUTF8CString("DoneMessageBody"));
+ WKBundlePostMessage(bundle, doneMessageName.get(), doneMessageBody.get());
+ }
+};
+
+static InjectedBundleTest::Register<InjectedBundleBasicTest> registrar("InjectedBundleBasicTest");
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp
new file mode 100644
index 0000000..98a636c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadBasic.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WebKit2.h>
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool test1Done;
+
+struct State {
+ State()
+ : didDecidePolicyForNavigationAction(false)
+ , didStartProvisionalLoadForFrame(false)
+ , didCommitLoadForFrame(false)
+ {
+ }
+
+ bool didDecidePolicyForNavigationAction;
+ bool didStartProvisionalLoadForFrame;
+ bool didCommitLoadForFrame;
+};
+
+static void didStartProvisionalLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ State* state = reinterpret_cast<State*>(const_cast<void*>(clientInfo));
+ TEST_ASSERT(state->didDecidePolicyForNavigationAction);
+ TEST_ASSERT(!state->didCommitLoadForFrame);
+
+ // The commited URL should be null.
+ TEST_ASSERT(!WKFrameCopyURL(frame));
+
+ TEST_ASSERT(!state->didStartProvisionalLoadForFrame);
+
+
+ state->didStartProvisionalLoadForFrame = true;
+}
+
+static void didCommitLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ State* state = reinterpret_cast<State*>(const_cast<void*>(clientInfo));
+ TEST_ASSERT(state->didDecidePolicyForNavigationAction);
+ TEST_ASSERT(state->didStartProvisionalLoadForFrame);
+
+ // The provisional URL should be null.
+ TEST_ASSERT(!WKFrameCopyProvisionalURL(frame));
+
+ state->didCommitLoadForFrame = true;
+}
+
+static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void* clientInfo)
+{
+ State* state = reinterpret_cast<State*>(const_cast<void*>(clientInfo));
+ TEST_ASSERT(state->didDecidePolicyForNavigationAction);
+ TEST_ASSERT(state->didStartProvisionalLoadForFrame);
+ TEST_ASSERT(state->didCommitLoadForFrame);
+
+ // The provisional URL should be null.
+ TEST_ASSERT(!WKFrameCopyProvisionalURL(frame));
+
+ test1Done = true;
+}
+
+static void decidePolicyForNavigationAction(WKPageRef page, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void* clientInfo)
+{
+ State* state = reinterpret_cast<State*>(const_cast<void*>(clientInfo));
+ TEST_ASSERT(!state->didStartProvisionalLoadForFrame);
+ TEST_ASSERT(!state->didCommitLoadForFrame);
+
+ state->didDecidePolicyForNavigationAction = true;
+
+ WKFramePolicyListenerUse(listener);
+}
+
+static void decidePolicyForNewWindowAction(WKPageRef page, WKFrameNavigationType navigationType, WKEventModifiers modifiers, WKEventMouseButton mouseButton, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void* clientInfo)
+{
+ WKFramePolicyListenerUse(listener);
+}
+
+static void decidePolicyForMIMEType(WKPageRef page, WKStringRef MIMEType, WKURLRef url, WKFrameRef frame, WKFramePolicyListenerRef listener, const void* clientInfo)
+{
+ WKFramePolicyListenerUse(listener);
+}
+
+TEST(WebKit2, PageLoadBasic)
+{
+ State state;
+
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClient loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.version = 0;
+ loaderClient.clientInfo = &state;
+ loaderClient.didStartProvisionalLoadForFrame = didStartProvisionalLoadForFrame;
+ loaderClient.didCommitLoadForFrame = didCommitLoadForFrame;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient);
+
+ WKPagePolicyClient policyClient;
+ memset(&policyClient, 0, sizeof(policyClient));
+
+ policyClient.version = 0;
+ policyClient.clientInfo = &state;
+ policyClient.decidePolicyForNavigationAction = decidePolicyForNavigationAction;
+ policyClient.decidePolicyForNewWindowAction = decidePolicyForNewWindowAction;
+ policyClient.decidePolicyForMIMEType = decidePolicyForMIMEType;
+ WKPageSetPagePolicyClient(webView.page(), &policyClient);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("simple", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+
+ Util::run(&test1Done);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp
new file mode 100644
index 0000000..3cbe113
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/PageLoadDidChangeLocationWithinPageForFrame.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WebKit2.h>
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static void nullJavaScriptCallback(WKStringRef, WKErrorRef error, void*)
+{
+}
+
+static bool didFinishLoad;
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+ didFinishLoad = true;
+}
+
+static bool didPopStateWithinPage;
+static bool didChangeLocationWithinPage;
+static void didSameDocumentNavigationForFrame(WKPageRef, WKFrameRef, WKSameDocumentNavigationType type, WKTypeRef, const void*)
+{
+ if (!didPopStateWithinPage) {
+ TEST_ASSERT(type == kWKSameDocumentNavigationSessionStatePop);
+ TEST_ASSERT(!didChangeLocationWithinPage);
+ didPopStateWithinPage = true;
+ return;
+ }
+
+ TEST_ASSERT(type == kWKSameDocumentNavigationAnchorNavigation);
+ didChangeLocationWithinPage = true;
+}
+
+TEST(WebKit2, PageLoadDidChangeLocationWithinPageForFrame)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClient loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ loaderClient.didSameDocumentNavigationForFrame = didSameDocumentNavigationForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("file-with-anchor", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+ Util::run(&didFinishLoad);
+
+ WKRetainPtr<WKURLRef> initialURL = Util::adoptWK(WKFrameCopyURL(WKPageGetMainFrame(webView.page())));
+
+ WKPageRunJavaScriptInMainFrame(webView.page(), Util::toWK("clickLink()").get(), 0, nullJavaScriptCallback);
+ Util::run(&didChangeLocationWithinPage);
+
+ WKRetainPtr<WKURLRef> urlAfterAnchorClick = Util::adoptWK(WKFrameCopyURL(WKPageGetMainFrame(webView.page())));
+
+ TEST_ASSERT(!WKURLIsEqual(initialURL.get(), urlAfterAnchorClick.get()));
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/PreventEmptyUserAgent.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/PreventEmptyUserAgent.cpp
new file mode 100644
index 0000000..306174a
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/PreventEmptyUserAgent.cpp
@@ -0,0 +1,60 @@
+/*
+ * 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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WKRetainPtr.h>
+#include <WebKit2/WebKit2.h>
+
+namespace TestWebKitAPI {
+
+static bool testDone;
+
+static void didRunJavaScript(WKStringRef resultString, WKErrorRef error, void* context)
+{
+ TEST_ASSERT(context == reinterpret_cast<void*>(0x1234578));
+
+ // Make sure that the result of navigator.userAgent isn't empty, even if we set the custom
+ // user agent to the empty string.
+ TEST_ASSERT(!WKStringIsEmpty(resultString));
+
+ testDone = true;
+}
+
+TEST(WebKit2, PreventEmptyUserAgent)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageSetCustomUserAgent(webView.page(), WKStringCreateWithUTF8CString(""));
+ WKRetainPtr<WKStringRef> javaScriptString(AdoptWK, WKStringCreateWithUTF8CString("navigator.userAgent"));
+ WKPageRunJavaScriptInMainFrame(webView.page(), javaScriptString.get(), reinterpret_cast<void*>(0x1234578), didRunJavaScript);
+
+ Util::run(&testDone);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp
new file mode 100644
index 0000000..6d4783c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/SpacebarScrolling.cpp
@@ -0,0 +1,132 @@
+/*
+ * 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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+struct JavaScriptCallbackContext {
+ JavaScriptCallbackContext(const char* expectedString) : didFinish(false), expectedString(expectedString), didMatchExpectedString(false) { }
+
+ bool didFinish;
+ const char* expectedString;
+ bool didMatchExpectedString;
+};
+
+static bool didFinishLoad;
+static bool didNotHandleKeyDownEvent;
+
+static void didFinishLoadForFrame(WKPageRef, WKFrameRef, WKTypeRef, const void*)
+{
+ didFinishLoad = true;
+}
+
+static void didNotHandleKeyEventCallback(WKPageRef, WKNativeEventPtr event, const void*)
+{
+ if (Util::isKeyDown(event))
+ didNotHandleKeyDownEvent = true;
+}
+
+static void javaScriptCallback(WKStringRef string, WKErrorRef error, void* ctx)
+{
+ JavaScriptCallbackContext* context = static_cast<JavaScriptCallbackContext*>(ctx);
+
+ context->didFinish = true;
+ context->didMatchExpectedString = WKStringIsEqualToUTF8CString(string, context->expectedString);
+
+ TEST_ASSERT(!error);
+}
+
+static WKRetainPtr<WKStringRef> wk(const char* utf8String)
+{
+ return WKRetainPtr<WKStringRef>(AdoptWK, WKStringCreateWithUTF8CString(utf8String));
+}
+
+static bool runJSTest(WKPageRef page, const char* script, const char* expectedResult)
+{
+ JavaScriptCallbackContext context(expectedResult);
+ WKPageRunJavaScriptInMainFrame(page, wk(script).get(), &context, javaScriptCallback);
+ Util::run(&context.didFinish);
+ return context.didMatchExpectedString;
+}
+
+TEST(WebKit2, SpacebarScrolling)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageLoaderClient loaderClient;
+ memset(&loaderClient, 0, sizeof(loaderClient));
+
+ loaderClient.version = 0;
+ loaderClient.didFinishLoadForFrame = didFinishLoadForFrame;
+ WKPageSetPageLoaderClient(webView.page(), &loaderClient);
+
+ WKPageUIClient uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+
+ uiClient.didNotHandleKeyEvent = didNotHandleKeyEventCallback;
+ WKPageSetPageUIClient(webView.page(), &uiClient);
+
+ WKRetainPtr<WKURLRef> url(AdoptWK, Util::createURLForResource("spacebar-scrolling", "html"));
+ WKPageLoadURL(webView.page(), url.get());
+ Util::run(&didFinishLoad);
+
+ TEST_ASSERT(runJSTest(webView.page(), "isDocumentScrolled()", "false"));
+ TEST_ASSERT(runJSTest(webView.page(), "textFieldContainsSpace()", "false"));
+
+ webView.simulateSpacebarKeyPress();
+
+ TEST_ASSERT(runJSTest(webView.page(), "isDocumentScrolled()", "false"));
+ TEST_ASSERT(runJSTest(webView.page(), "textFieldContainsSpace()", "true"));
+
+ // On Mac, a key down event represents both a raw key down and a key press. On Windows, a key
+ // down event only represents a raw key down. We expect the key press to be handled (because it
+ // inserts text into the text field). But the raw key down should not be handled.
+#if PLATFORM(MAC)
+ TEST_ASSERT(!didNotHandleKeyDownEvent);
+#elif PLATFORM(WIN)
+ TEST_ASSERT(didNotHandleKeyDownEvent);
+#endif
+
+ TEST_ASSERT(runJSTest(webView.page(), "blurTextField()", "undefined"));
+
+ didNotHandleKeyDownEvent = false;
+ webView.simulateSpacebarKeyPress();
+
+ TEST_ASSERT(runJSTest(webView.page(), "isDocumentScrolled()", "true"));
+ TEST_ASSERT(runJSTest(webView.page(), "textFieldContainsSpace()", "true"));
+#if PLATFORM(MAC)
+ TEST_ASSERT(!didNotHandleKeyDownEvent);
+#elif PLATFORM(WIN)
+ TEST_ASSERT(didNotHandleKeyDownEvent);
+#endif
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp
new file mode 100644
index 0000000..f27131c
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKPreferences.cpp
@@ -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. 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 "Test.h"
+
+#include <WebKit2/WKPreferences.h>
+#include <WebKit2/WKPreferencesPrivate.h>
+#include <WebKit2/WKRetainPtr.h>
+#include <WebKit2/WKString.h>
+#include <wtf/Platform.h>
+
+namespace TestWebKitAPI {
+
+TEST(WebKit2, WKPreferencesBasic)
+{
+ WKPreferencesRef preference = WKPreferencesCreate();
+
+ TEST_ASSERT(WKGetTypeID(preference) == WKPreferencesGetTypeID());
+
+ WKRelease(preference);
+}
+
+TEST(WebKit2, WKPreferencesDefaults)
+{
+#if PLATFORM(WIN)
+ static const char* expectedStandardFontFamily = "Times New Roman";
+ static const char* expectedFixedFontFamily = "Courier New";
+ static const char* expectedSerifFontFamily = "Times New Roman";
+ static const char* expectedSansSerifFontFamily = "Arial";
+ static const char* expectedCursiveFontFamily = "Comic Sans MS";
+ static const char* expectedFantasyFontFamily = "Comic Sans MS";
+#elif PLATFORM(MAC)
+ static const char* expectedStandardFontFamily = "Times";
+ static const char* expectedFixedFontFamily = "Courier";
+ static const char* expectedSerifFontFamily = "Times";
+ static const char* expectedSansSerifFontFamily = "Helvetica";
+ static const char* expectedCursiveFontFamily = "Apple Chancery";
+ static const char* expectedFantasyFontFamily = "Papyrus";
+#endif
+
+ WKPreferencesRef preference = WKPreferencesCreate();
+
+ TEST_ASSERT(WKPreferencesGetJavaScriptEnabled(preference) == true);
+ TEST_ASSERT(WKPreferencesGetLoadsImagesAutomatically(preference) == true);
+ TEST_ASSERT(WKPreferencesGetOfflineWebApplicationCacheEnabled(preference) == false);
+ TEST_ASSERT(WKPreferencesGetLocalStorageEnabled(preference) == true);
+ TEST_ASSERT(WKPreferencesGetXSSAuditorEnabled(preference) == true);
+ TEST_ASSERT(WKPreferencesGetFrameFlatteningEnabled(preference) == false);
+ TEST_ASSERT(WKPreferencesGetPluginsEnabled(preference) == true);
+ TEST_ASSERT(WKPreferencesGetJavaEnabled(preference) == true);
+ TEST_ASSERT(WKPreferencesGetJavaScriptCanOpenWindowsAutomatically(preference) == true);
+ TEST_ASSERT(WKPreferencesGetHyperlinkAuditingEnabled(preference) == true);
+ WKRetainPtr<WKStringRef> standardFontFamily(AdoptWK, WKPreferencesCopyStandardFontFamily(preference));
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(standardFontFamily.get(), expectedStandardFontFamily));
+ WKRetainPtr<WKStringRef> fixedFontFamily(AdoptWK, WKPreferencesCopyFixedFontFamily(preference));
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(fixedFontFamily.get(), expectedFixedFontFamily));
+ WKRetainPtr<WKStringRef> serifFontFamily(AdoptWK, WKPreferencesCopySerifFontFamily(preference));
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(serifFontFamily.get(), expectedSerifFontFamily));
+ WKRetainPtr<WKStringRef> sansSerifFontFamily(AdoptWK, WKPreferencesCopySansSerifFontFamily(preference));
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(sansSerifFontFamily.get(), expectedSansSerifFontFamily));
+ WKRetainPtr<WKStringRef> cursiveFontFamily(AdoptWK, WKPreferencesCopyCursiveFontFamily(preference));
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(cursiveFontFamily.get(), expectedCursiveFontFamily));
+ WKRetainPtr<WKStringRef> fantasyFontFamily(AdoptWK, WKPreferencesCopyFantasyFontFamily(preference));
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(fantasyFontFamily.get(), expectedFantasyFontFamily));
+ TEST_ASSERT(WKPreferencesGetMinimumFontSize(preference) == 0);
+ TEST_ASSERT(WKPreferencesGetPrivateBrowsingEnabled(preference) == false);
+ TEST_ASSERT(WKPreferencesGetDeveloperExtrasEnabled(preference) == false);
+ TEST_ASSERT(WKPreferencesGetTextAreasAreResizable(preference) == true);
+ TEST_ASSERT(WKPreferencesGetFontSmoothingLevel(preference) == kWKFontSmoothingLevelMedium);
+ TEST_ASSERT(WKPreferencesGetAcceleratedCompositingEnabled(preference) == true);
+ TEST_ASSERT(WKPreferencesGetCompositingBordersVisible(preference) == false);
+ TEST_ASSERT(WKPreferencesGetCompositingRepaintCountersVisible(preference) == false);
+ TEST_ASSERT(WKPreferencesGetNeedsSiteSpecificQuirks(preference) == false);
+
+ WKRelease(preference);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp
new file mode 100644
index 0000000..b0b133d
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKString.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "Test.h"
+
+#include <WebKit2/WKString.h>
+
+namespace TestWebKitAPI {
+
+TEST(WebKit2, WKString)
+{
+ WKStringRef string = WKStringCreateWithUTF8CString("hello");
+ TEST_ASSERT(!WKStringIsEmpty(string));
+ TEST_ASSERT(WKStringIsEqual(string, string));
+ TEST_ASSERT(WKStringIsEqualToUTF8CString(string, "hello"));
+ TEST_ASSERT(WKStringGetMaximumUTF8CStringSize(string) == 16);
+
+ size_t maxSize = WKStringGetMaximumUTF8CStringSize(string);
+ char* buffer = new char[maxSize];
+
+ size_t actualSize = WKStringGetUTF8CString(string, buffer, maxSize);
+ TEST_ASSERT(actualSize == 6);
+ TEST_ASSERT(strcmp(buffer, "hello") == 0);
+
+ delete[] buffer;
+
+ WKRelease(string);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/WKStringJSString.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/WKStringJSString.cpp
new file mode 100644
index 0000000..0d6eca3
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/WKStringJSString.cpp
@@ -0,0 +1,52 @@
+/*
+ * 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 "Test.h"
+
+#include <WebKit2/WKString.h>
+#include <WebKit2/WKStringPrivate.h>
+#include <JavaScriptCore/JSStringRef.h>
+
+namespace TestWebKitAPI {
+
+TEST(WebKit2, WKStringJSString)
+{
+ WKStringRef wkString = WKStringCreateWithUTF8CString("hello");
+ JSStringRef jsString = JSStringCreateWithUTF8CString("hello");
+
+ WKStringRef convertedJSString = WKStringCreateWithJSString(jsString);
+ TEST_ASSERT(WKStringIsEqual(wkString, convertedJSString));
+
+ JSStringRef convertedWKString = WKStringCopyJSString(wkString);
+ TEST_ASSERT(JSStringIsEqual(jsString, convertedWKString));
+
+ WKRelease(wkString);
+ WKRelease(convertedJSString);
+
+ JSStringRelease(jsString);
+ JSStringRelease(convertedWKString);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/file-with-anchor.html b/Tools/TestWebKitAPI/Tests/WebKit2/file-with-anchor.html
new file mode 100644
index 0000000..8ea866b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/file-with-anchor.html
@@ -0,0 +1,19 @@
+<html>
+<head>
+ <script>
+ function clickLink()
+ {
+ var evt = document.createEvent("MouseEvent");
+ evt.initMouseEvent("click", true, true, window, 0, 0, 0, 0, 0, false, false, false, false, 0, null);
+ var link = document.querySelector('a');
+ link.dispatchEvent(evt);
+ }
+ </script>
+</head>
+<body>
+ <a href="#anchor">Link to anchor</a><br>
+ In between.<br>
+ <span id="anchor">Anchor</span><br>
+ After the anchor.<br>
+ </body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/find.html b/Tools/TestWebKitAPI/Tests/WebKit2/find.html
new file mode 100644
index 0000000..d965911
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/find.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+ Test search. Hello Hello Hello!
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/icon.png b/Tools/TestWebKitAPI/Tests/WebKit2/icon.png
new file mode 100644
index 0000000..79e4598
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/icon.png
Binary files differ
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/simple.html b/Tools/TestWebKitAPI/Tests/WebKit2/simple.html
new file mode 100644
index 0000000..12cf873
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/simple.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+ Simple HTML file.
+</body>
+</html>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/spacebar-scrolling.html b/Tools/TestWebKitAPI/Tests/WebKit2/spacebar-scrolling.html
new file mode 100644
index 0000000..8da08b3
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/spacebar-scrolling.html
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<script>
+ function textFieldContainsSpace()
+ {
+ return document.querySelector("input").value === " ";
+ }
+
+ function blurTextField()
+ {
+ document.querySelector("input").blur();
+ }
+
+ function isDocumentScrolled()
+ {
+ return scrollY !== 0;
+ }
+
+ function loaded()
+ {
+ document.querySelector("input").focus();
+ }
+
+ addEventListener("load", loaded);
+</script>
+<input>
+<div style="height: 3000px;"></div>
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/win/AltKeyGeneratesWMSysCommand.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/win/AltKeyGeneratesWMSysCommand.cpp
new file mode 100644
index 0000000..1bca89b
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/win/AltKeyGeneratesWMSysCommand.cpp
@@ -0,0 +1,86 @@
+/*
+ * 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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include "WindowMessageObserver.h"
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+class WMSysCommandObserver : public WindowMessageObserver {
+public:
+ WMSysCommandObserver() : m_windowDidReceiveWMSysCommand(false) { }
+
+ bool windowDidReceiveWMSysCommand() const { return m_windowDidReceiveWMSysCommand; }
+
+private:
+ virtual void windowReceivedMessage(HWND, UINT message, WPARAM, LPARAM)
+ {
+ if (message == WM_SYSCOMMAND)
+ m_windowDidReceiveWMSysCommand = true;
+ }
+
+ bool m_windowDidReceiveWMSysCommand;
+};
+
+static bool didNotHandleWMSysKeyUp;
+
+static void didNotHandleKeyEventCallback(WKPageRef, WKNativeEventPtr event, const void*)
+{
+ if (event->message != WM_SYSKEYUP)
+ return;
+
+ didNotHandleWMSysKeyUp = true;
+}
+
+TEST(WebKit2, AltKeyGeneratesWMSysCommand)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageUIClient uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+
+ uiClient.didNotHandleKeyEvent = didNotHandleKeyEventCallback;
+ WKPageSetPageUIClient(webView.page(), &uiClient);
+
+ WMSysCommandObserver observer;
+ webView.setParentWindowMessageObserver(&observer);
+
+ webView.simulateAltKeyPress();
+
+ Util::run(&didNotHandleWMSysKeyUp);
+
+ webView.setParentWindowMessageObserver(0);
+
+ // The WM_SYSKEYUP message should have generated a WM_SYSCOMMAND message that was sent to the
+ // WKView's parent window.
+ TEST_ASSERT(observer.windowDidReceiveWMSysCommand());
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/Tests/WebKit2/win/WMCloseCallsUIClientClose.cpp b/Tools/TestWebKitAPI/Tests/WebKit2/win/WMCloseCallsUIClientClose.cpp
new file mode 100644
index 0000000..56e619e
--- /dev/null
+++ b/Tools/TestWebKitAPI/Tests/WebKit2/win/WMCloseCallsUIClientClose.cpp
@@ -0,0 +1,57 @@
+/*
+ * 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 "Test.h"
+
+#include "PlatformUtilities.h"
+#include "PlatformWebView.h"
+#include <WebKit2/WKRetainPtr.h>
+
+namespace TestWebKitAPI {
+
+static bool didReceiveClose;
+
+static void close(WKPageRef, const void*)
+{
+ didReceiveClose = true;
+}
+
+TEST(WebKit2, WMCloseCallsUIClientClose)
+{
+ WKRetainPtr<WKContextRef> context(AdoptWK, WKContextCreate());
+ PlatformWebView webView(context.get());
+
+ WKPageUIClient uiClient;
+ memset(&uiClient, 0, sizeof(uiClient));
+
+ uiClient.close = close;
+ WKPageSetPageUIClient(webView.page(), &uiClient);
+
+ ::SendMessageW(WKViewGetWindow(webView.platformView()), WM_CLOSE, 0, 0);
+
+ Util::run(&didReceiveClose);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/TestsController.cpp b/Tools/TestWebKitAPI/TestsController.cpp
new file mode 100644
index 0000000..3499f2c
--- /dev/null
+++ b/Tools/TestWebKitAPI/TestsController.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 "TestsController.h"
+
+#include "Test.h"
+#include <algorithm>
+#include <assert.h>
+
+namespace TestWebKitAPI {
+
+TestsController& TestsController::shared()
+{
+ static TestsController& shared = *new TestsController;
+ return shared;
+}
+
+TestsController::TestsController()
+ : m_testFailed(false)
+ , m_currentTest(0)
+{
+}
+
+void TestsController::dumpTestNames()
+{
+ std::map<std::string, CreateTestFunction>::const_iterator it = m_createTestFunctions.begin();
+ std::map<std::string, CreateTestFunction>::const_iterator end = m_createTestFunctions.end();
+ for (; it != end; ++it)
+ printf("%s\n", (*it).first.c_str());
+}
+
+bool TestsController::runTestNamed(const std::string& identifier)
+{
+ CreateTestFunction createTestFunction = m_createTestFunctions[identifier];
+ if (!createTestFunction) {
+ printf("ERROR: Test not found - %s\n", identifier.c_str());
+ return false;
+ }
+
+ m_currentTest = createTestFunction(identifier);
+ m_currentTest->run();
+
+ delete m_currentTest;
+ m_currentTest = 0;
+
+ return !m_testFailed;
+}
+
+void TestsController::testFailed(const char* file, int line, const char* message)
+{
+ m_testFailed = true;
+ printf("FAIL: %s\n\t%s (%s:%d)\n", m_currentTest->name().c_str(), message, file, line);
+}
+
+void TestsController::registerCreateTestFunction(const std::string& identifier, CreateTestFunction createTestFunction)
+{
+ m_createTestFunctions[identifier] = createTestFunction;
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/TestsController.h b/Tools/TestWebKitAPI/TestsController.h
new file mode 100644
index 0000000..0ff1fc7
--- /dev/null
+++ b/Tools/TestWebKitAPI/TestsController.h
@@ -0,0 +1,61 @@
+/*
+ * 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 TestsController_h
+#define TestsController_h
+
+#include <map>
+#include <string>
+
+namespace TestWebKitAPI {
+
+class Test;
+
+class TestsController {
+public:
+ static TestsController& shared();
+
+ void dumpTestNames();
+ bool runTestNamed(const std::string&);
+
+ // Called by the tests themselves.
+ void testFailed(const char* file, int line, const char* message);
+
+ typedef Test* (*CreateTestFunction)(const std::string&);
+ void registerCreateTestFunction(const std::string&, CreateTestFunction);
+
+private:
+ TestsController();
+ ~TestsController();
+
+ bool m_testFailed;
+ Test* m_currentTest;
+
+ std::map<std::string, CreateTestFunction> m_createTestFunctions;
+};
+
+} // namespace TestWebKitAPI
+
+#endif // TestsController_h
diff --git a/Tools/TestWebKitAPI/mac/PlatformUtilitiesMac.mm b/Tools/TestWebKitAPI/mac/PlatformUtilitiesMac.mm
new file mode 100644
index 0000000..474278f
--- /dev/null
+++ b/Tools/TestWebKitAPI/mac/PlatformUtilitiesMac.mm
@@ -0,0 +1,66 @@
+/*
+ * 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 "PlatformUtilities.h"
+
+#include <WebKit2/WKRetainPtr.h>
+#include <WebKit2/WKStringCF.h>
+#include <WebKit2/WKURLCF.h>
+#include <WebKit2/WebKit2.h>
+
+namespace TestWebKitAPI {
+namespace Util {
+
+void run(bool* done)
+{
+ while (!*done)
+ [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
+}
+
+WKStringRef createInjectedBundlePath()
+{
+ NSString *nsString = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"InjectedBundleTestWebKitAPI.bundle"];
+ return WKStringCreateWithCFString((CFStringRef)nsString);
+}
+
+WKURLRef createURLForResource(const char* resource, const char* extension)
+{
+ NSURL *nsURL = [[NSBundle mainBundle] URLForResource:[NSString stringWithUTF8String:resource] withExtension:[NSString stringWithUTF8String:extension]];
+ return WKURLCreateWithCFURL((CFURLRef)nsURL);
+}
+
+WKURLRef URLForNonExistentResource()
+{
+ NSURL *nsURL = [NSURL URLWithString:@"file:///does-not-exist.html"];
+ return WKURLCreateWithCFURL((CFURLRef)nsURL);
+}
+
+bool isKeyDown(WKNativeEventPtr event)
+{
+ return [event type] == NSKeyDown;
+}
+
+} // namespace Util
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/mac/PlatformWebViewMac.mm b/Tools/TestWebKitAPI/mac/PlatformWebViewMac.mm
new file mode 100644
index 0000000..c4f2d72
--- /dev/null
+++ b/Tools/TestWebKitAPI/mac/PlatformWebViewMac.mm
@@ -0,0 +1,97 @@
+/*
+ * 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 "PlatformWebView.h"
+
+#import <Carbon/Carbon.h>
+
+namespace TestWebKitAPI {
+
+PlatformWebView::PlatformWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
+{
+ NSRect rect = NSMakeRect(0, 0, 800, 600);
+ m_view = [[WKView alloc] initWithFrame:rect contextRef:contextRef pageGroupRef:pageGroupRef];
+
+ NSRect windowRect = NSOffsetRect(rect, -10000, [[[NSScreen screens] objectAtIndex:0] frame].size.height - rect.size.height + 10000);
+ m_window = [[NSWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
+ [m_window setColorSpace:[[NSScreen mainScreen] colorSpace]];
+ [[m_window contentView] addSubview:m_view];
+ [m_window orderBack:nil];
+ [m_window setAutodisplay:NO];
+ [m_window setReleasedWhenClosed:NO];
+}
+
+void PlatformWebView::resizeTo(unsigned width, unsigned height)
+{
+ [m_view setFrame:NSMakeRect(0, 0, width, height)];
+}
+
+PlatformWebView::~PlatformWebView()
+{
+ [m_window close];
+ [m_window release];
+ [m_view release];
+}
+
+WKPageRef PlatformWebView::page()
+{
+ return [m_view pageRef];
+}
+
+void PlatformWebView::focus()
+{
+ // Implement.
+}
+
+void PlatformWebView::simulateSpacebarKeyPress()
+{
+ NSEvent *event = [NSEvent keyEventWithType:NSKeyDown
+ location:NSMakePoint(5, 5)
+ modifierFlags:0
+ timestamp:GetCurrentEventTime()
+ windowNumber:[m_window windowNumber]
+ context:[NSGraphicsContext currentContext]
+ characters:@" "
+ charactersIgnoringModifiers:@" "
+ isARepeat:NO
+ keyCode:0x31];
+
+ [m_view keyDown:event];
+
+ event = [NSEvent keyEventWithType:NSKeyUp
+ location:NSMakePoint(5, 5)
+ modifierFlags:0
+ timestamp:GetCurrentEventTime()
+ windowNumber:[m_window windowNumber]
+ context:[NSGraphicsContext currentContext]
+ characters:@" "
+ charactersIgnoringModifiers:@" "
+ isARepeat:NO
+ keyCode:0x31];
+
+ [m_view keyUp:event];
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/mac/main.mm b/Tools/TestWebKitAPI/mac/main.mm
new file mode 100644
index 0000000..e6dd4a6
--- /dev/null
+++ b/Tools/TestWebKitAPI/mac/main.mm
@@ -0,0 +1,45 @@
+/*
+ * 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.
+ */
+
+#import "TestsController.h"
+
+int main(int argc, const char* argv[])
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ [NSApplication sharedApplication];
+
+ bool passed = true;
+
+ std::string argument(argv[1]);
+ if (argument == "--dump-tests")
+ TestWebKitAPI::TestsController::shared().dumpTestNames();
+ else
+ passed = TestWebKitAPI::TestsController::shared().runTestNamed(argument);
+
+ [pool drain];
+
+ return passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/Tools/TestWebKitAPI/win/PlatformUtilitiesWin.cpp b/Tools/TestWebKitAPI/win/PlatformUtilitiesWin.cpp
new file mode 100644
index 0000000..6efc9ea
--- /dev/null
+++ b/Tools/TestWebKitAPI/win/PlatformUtilitiesWin.cpp
@@ -0,0 +1,85 @@
+/*
+ * 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 "PlatformUtilities.h"
+
+#include <WebKit2/WKStringCF.h>
+#include <WebKit2/WKURLCF.h>
+#include <wtf/RetainPtr.h>
+
+namespace TestWebKitAPI {
+namespace Util {
+
+#ifdef DEBUG_ALL
+const char* injectedBundleDLL = "\\InjectedBundle_debug.dll";
+#else
+const char* injectedBundleDLL = "\\InjectedBundle.dll";
+#endif
+
+void run(bool* done)
+{
+ while (!*done) {
+ MSG msg;
+ BOOL result = ::GetMessageW(&msg, 0, 0, 0);
+ if (!result || result == -1)
+ break;
+ ::TranslateMessage(&msg);
+ ::DispatchMessage(&msg);
+ }
+}
+
+RetainPtr<CFStringRef> cf(const char* utf8String)
+{
+ return RetainPtr<CFStringRef>(AdoptCF, CFStringCreateWithCString(kCFAllocatorDefault, utf8String, kCFStringEncodingUTF8));
+}
+
+WKStringRef createInjectedBundlePath()
+{
+ RetainPtr<CFURLRef> executableURL(AdoptCF, CFBundleCopyExecutableURL(CFBundleGetMainBundle()));
+ RetainPtr<CFURLRef> executableContainerURL(AdoptCF, CFURLCreateCopyDeletingLastPathComponent(0, executableURL.get()));
+ RetainPtr<CFStringRef> dllFilename(AdoptCF, CFStringCreateWithCStringNoCopy(0, injectedBundleDLL, kCFStringEncodingWindowsLatin1, 0));
+ RetainPtr<CFURLRef> bundleURL(AdoptCF, CFURLCreateCopyAppendingPathComponent(0, executableContainerURL.get(), dllFilename.get(), false));
+ RetainPtr<CFStringRef> bundlePath(AdoptCF, CFURLCopyFileSystemPath(bundleURL.get(), kCFURLWindowsPathStyle));
+ return WKStringCreateWithCFString(bundlePath.get());
+}
+
+WKURLRef createURLForResource(const char* resource, const char* extension)
+{
+ RetainPtr<CFURLRef> url(AdoptCF, CFBundleCopyResourceURL(CFBundleGetMainBundle(), cf(resource).get(), cf(extension).get(), 0));
+ return WKURLCreateWithCFURL(url.get());
+}
+
+WKURLRef URLForNonExistentResource()
+{
+ return WKURLCreateWithUTF8CString("file:///does-not-exist.html");
+}
+
+bool isKeyDown(WKNativeEventPtr event)
+{
+ return event->message == WM_KEYDOWN;
+}
+
+} // namespace Util
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/win/PlatformWebViewWin.cpp b/Tools/TestWebKitAPI/win/PlatformWebViewWin.cpp
new file mode 100644
index 0000000..dede4b2
--- /dev/null
+++ b/Tools/TestWebKitAPI/win/PlatformWebViewWin.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 "PlatformWebView.h"
+
+#include "WindowMessageObserver.h"
+
+namespace TestWebKitAPI {
+
+static const wchar_t* hostWindowClassName = L"org.WebKit.TestWebKitAPI.PlatformWebViewHostWindow";
+static const wchar_t* webViewPointerProperty = L"org.WebKit.TestWebKitAPI.PlatformWebView.InstancePointer";
+
+// These offsets come from rom <http://msdn.microsoft.com/en-us/library/ms646280(VS.85).aspx>.
+static const size_t repeatCountBitOffset = 0;
+static const size_t scanCodeBitOffset = 16;
+static const size_t contextCodeBitOffset = 29;
+static const size_t previousStateBitOffset = 30;
+static const size_t transitionStateBitOffset = 31;
+
+void PlatformWebView::registerWindowClass()
+{
+ static bool initialized;
+ if (initialized)
+ return;
+ initialized = true;
+
+ WNDCLASSEXW wndClass = {0};
+ wndClass.cbSize = sizeof(wndClass);
+ wndClass.style = CS_HREDRAW | CS_VREDRAW;
+ wndClass.lpfnWndProc = wndProc;
+ wndClass.hCursor = LoadCursor(0, IDC_ARROW);
+ wndClass.lpszClassName = hostWindowClassName;
+
+ ::RegisterClassExW(&wndClass);
+}
+
+PlatformWebView::PlatformWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
+ : m_parentWindowMessageObserver(0)
+{
+ registerWindowClass();
+
+ RECT viewRect = {0, 0, 800, 600};
+ m_window = CreateWindowExW(0, hostWindowClassName, L"TestWebKitAPI", WS_OVERLAPPEDWINDOW, viewRect.left, viewRect.top, viewRect.right, viewRect.bottom, 0, 0, 0, this);
+ m_view = WKViewCreate(viewRect, contextRef, pageGroupRef, m_window);
+}
+
+PlatformWebView::~PlatformWebView()
+{
+ ::DestroyWindow(m_window);
+ WKRelease(m_view);
+}
+
+WKPageRef PlatformWebView::page()
+{
+ return WKViewGetPage(m_view);
+}
+
+void PlatformWebView::simulateSpacebarKeyPress()
+{
+ HWND window = WKViewGetWindow(m_view);
+
+ // These values match what happens when you press the spacebar in Notepad, as observed by Spy++.
+ ::SendMessageW(window, WM_KEYDOWN, VK_SPACE, (1 << repeatCountBitOffset) | (39 << scanCodeBitOffset));
+ ::SendMessageW(window, WM_CHAR, ' ', (1 << repeatCountBitOffset) | (39 << scanCodeBitOffset));
+ ::SendMessageW(window, WM_KEYUP, VK_SPACE, (1 << repeatCountBitOffset) | (39 << scanCodeBitOffset) | (1 << previousStateBitOffset) | (1 << transitionStateBitOffset));
+}
+
+void PlatformWebView::simulateAltKeyPress()
+{
+ HWND window = WKViewGetWindow(m_view);
+
+ // These values match what happens when you press the Alt key in Notepad, as observed by Spy++.
+ ::SendMessageW(window, WM_SYSKEYDOWN, VK_MENU, (1 << repeatCountBitOffset) | (38 << scanCodeBitOffset) | (1 << contextCodeBitOffset));
+ ::SendMessageW(window, WM_SYSKEYUP, VK_MENU, (1 << repeatCountBitOffset) | (38 << scanCodeBitOffset) | (1 << previousStateBitOffset) | (1 << transitionStateBitOffset));
+}
+
+LRESULT PlatformWebView::wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ PlatformWebView* webView;
+ if (message == WM_CREATE) {
+ CREATESTRUCT* createStruct = reinterpret_cast<CREATESTRUCT*>(lParam);
+ webView = static_cast<PlatformWebView*>(createStruct->lpCreateParams);
+ ::SetPropW(hWnd, webViewPointerProperty, webView);
+ } else
+ webView = reinterpret_cast<PlatformWebView*>(::GetPropW(hWnd, webViewPointerProperty));
+
+ if (webView && webView->m_parentWindowMessageObserver)
+ webView->m_parentWindowMessageObserver->windowReceivedMessage(hWnd, message, wParam, lParam);
+
+ if (message == WM_NCDESTROY)
+ ::RemovePropW(hWnd, webViewPointerProperty);
+
+ return ::DefWindowProcW(hWnd, message, wParam, lParam);
+}
+
+} // namespace TestWebKitAPI
diff --git a/Tools/TestWebKitAPI/win/TestWebKitAPI.sln b/Tools/TestWebKitAPI/win/TestWebKitAPI.sln
new file mode 100644
index 0000000..5354271
--- /dev/null
+++ b/Tools/TestWebKitAPI/win/TestWebKitAPI.sln
@@ -0,0 +1,54 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestWebKitAPI", "TestWebKitAPI.vcproj", "{3E48AB23-D249-488F-A1C4-43CDF52FBD28}"
+ ProjectSection(ProjectDependencies) = postProject
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86} = {45C45411-7F0E-404D-919A-4EE9BB60BE86}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestWebKitAPIGenerated", "TestWebKitAPIGenerated.vcproj", "{45C45411-7F0E-404D-919A-4EE9BB60BE86}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ all|Win32 = all|Win32
+ Debug_All|Win32 = Debug_All|Win32
+ Debug_Cairo_CFLite|Win32 = Debug_Cairo_CFLite|Win32
+ Debug|Win32 = Debug|Win32
+ Release_Cairo_CFLite|Win32 = Release_Cairo_CFLite|Win32
+ Release_LTCG|Win32 = Release_LTCG|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.all|Win32.ActiveCfg = Release_Cairo_CFLite|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.all|Win32.Build.0 = Release_Cairo_CFLite|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.Debug_All|Win32.Build.0 = Debug_All|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.Debug|Win32.Build.0 = Debug|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.Release_LTCG|Win32.ActiveCfg = Release_LTCG|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.Release_LTCG|Win32.Build.0 = Release_LTCG|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.Release|Win32.ActiveCfg = Release|Win32
+ {3E48AB23-D249-488F-A1C4-43CDF52FBD28}.Release|Win32.Build.0 = Release|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.all|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.all|Win32.Build.0 = Debug_Cairo_CFLite|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.Debug_All|Win32.Build.0 = Debug_All|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.Debug_Cairo_CFLite|Win32.ActiveCfg = Debug_Cairo_CFLite|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.Debug_Cairo_CFLite|Win32.Build.0 = Debug_Cairo_CFLite|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.Debug|Win32.ActiveCfg = Debug|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.Debug|Win32.Build.0 = Debug|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.Release_Cairo_CFLite|Win32.ActiveCfg = Release_Cairo_CFLite|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.Release_Cairo_CFLite|Win32.Build.0 = Release_Cairo_CFLite|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.Release_LTCG|Win32.ActiveCfg = Release_LTCG|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.Release_LTCG|Win32.Build.0 = Release_LTCG|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.Release|Win32.ActiveCfg = Release|Win32
+ {45C45411-7F0E-404D-919A-4EE9BB60BE86}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj b/Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj
new file mode 100644
index 0000000..a2412ef
--- /dev/null
+++ b/Tools/TestWebKitAPI/win/TestWebKitAPI.vcproj
@@ -0,0 +1,535 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestWebKitAPI"
+ ProjectGUID="{3E48AB23-D249-488F-A1C4-43CDF52FBD28}"
+ RootNamespace="TestWebKitAPI"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;..\Configurations\TestWebKitAPICommon.vsprops;..\Configurations\TestWebKitAPICoreFoundation.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="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;..\Configurations\TestWebKitAPICommon.vsprops;..\Configurations\TestWebKitAPICoreFoundation.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="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;..\Configurations\TestWebKitAPICommon.vsprops;..\Configurations\TestWebKitAPICoreFoundation.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="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;..\Configurations\TestWebKitAPICommon.vsprops;..\Configurations\TestWebKitAPICFLite.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="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;..\Configurations\TestWebKitAPICommon.vsprops;..\Configurations\TestWebKitAPICFLite.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_LTCG|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;..\Configurations\TestWebKitAPICommon.vsprops;..\Configurations\TestWebKitAPICoreFoundation.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="win"
+ >
+ <File
+ RelativePath=".\main.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\PlatformUtilitiesWin.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\PlatformWebViewWin.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\WindowMessageObserver.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Tests"
+ >
+ <Filter
+ Name="WebKit2"
+ >
+ <File
+ RelativePath="..\Tests\WebKit2\EvaluateJavaScript.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\FailedLoad.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\file-with-anchor.html"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\Find.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\find.html"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\FrameMIMETypeHTML.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\FrameMIMETypePNG.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\icon.png"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\PageLoadBasic.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\PageLoadDidChangeLocationWithinPageForFrame.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\PreventEmptyUserAgent.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\simple.html"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\spacebar-scrolling.html"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\SpacebarScrolling.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\WKPreferences.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\WKString.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\WKStringJSString.cpp"
+ >
+ </File>
+ <Filter
+ Name="win"
+ >
+ <File
+ RelativePath="..\Tests\WebKit2\win\AltKeyGeneratesWMSysCommand.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\Tests\WebKit2\win\WMCloseCallsUIClientClose.cpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <Filter
+ Name="WTF"
+ >
+ <File
+ RelativePath="..\Tests\WTF\VectorBasic.cpp"
+ >
+ </File>
+ </Filter>
+ </Filter>
+ <File
+ RelativePath="..\PlatformUtilities.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\PlatformUtilities.h"
+ >
+ </File>
+ <File
+ RelativePath="..\PlatformWebView.h"
+ >
+ </File>
+ <File
+ RelativePath="..\Test.h"
+ >
+ </File>
+ <File
+ RelativePath="..\TestsController.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\TestsController.h"
+ >
+ </File>
+ <File
+ RelativePath="..\TestWebKitAPIPrefix.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/TestWebKitAPI/win/TestWebKitAPIGenerated.vcproj b/Tools/TestWebKitAPI/win/TestWebKitAPIGenerated.vcproj
new file mode 100644
index 0000000..3f30a05
--- /dev/null
+++ b/Tools/TestWebKitAPI/win/TestWebKitAPIGenerated.vcproj
@@ -0,0 +1,82 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestWebKitAPIGenerated"
+ ProjectGUID="{45C45411-7F0E-404D-919A-4EE9BB60BE86}"
+ Keyword="MakeFileProj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="0"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;.\TestWebKitAPIGeneratedCommon.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="0"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;.\TestWebKitAPIGeneratedCommon.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_All|Win32"
+ ConfigurationType="0"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;.\TestWebKitAPIGeneratedCommon.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_LTCG|Win32"
+ ConfigurationType="0"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;.\TestWebKitAPIGeneratedCommon.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_Cairo_CFLite|Win32"
+ ConfigurationType="0"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;.\TestWebKitAPIGeneratedCommon.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_Cairo_CFLite|Win32"
+ ConfigurationType="0"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;.\TestWebKitAPIGeneratedCommon.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\copy-resources.cmd"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/TestWebKitAPI/win/TestWebKitAPIGeneratedCommon.vsprops b/Tools/TestWebKitAPI/win/TestWebKitAPIGeneratedCommon.vsprops
new file mode 100644
index 0000000..7e1587b
--- /dev/null
+++ b/Tools/TestWebKitAPI/win/TestWebKitAPIGeneratedCommon.vsprops
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="TestWebKitAPIGeneratedCommon"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="copy-resources.cmd"
+ ReBuildCommandLine="copy-resources.cmd rebuild"
+ CleanCommandLine="copy-resources.cmd clean"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/TestWebKitAPI/win/TestWebKitAPIPostBuild.cmd b/Tools/TestWebKitAPI/win/TestWebKitAPIPostBuild.cmd
new file mode 100644
index 0000000..f011495
--- /dev/null
+++ b/Tools/TestWebKitAPI/win/TestWebKitAPIPostBuild.cmd
@@ -0,0 +1 @@
+if exist "%WEBKITOUTPUTDIR%\buildfailed" del "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/TestWebKitAPI/win/TestWebKitAPIPreBuild.cmd b/Tools/TestWebKitAPI/win/TestWebKitAPIPreBuild.cmd
new file mode 100644
index 0000000..3a84c26
--- /dev/null
+++ b/Tools/TestWebKitAPI/win/TestWebKitAPIPreBuild.cmd
@@ -0,0 +1,6 @@
+%SystemDrive%\cygwin\bin\which.exe bash
+if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
+cmd /c
+if exist "%WEBKITOUTPUTDIR%\buildfailed" grep XX%PROJECTNAME%XX "%WEBKITOUTPUTDIR%\buildfailed"
+if errorlevel 1 exit 1
+echo XX%PROJECTNAME%XX > "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/TestWebKitAPI/win/WindowMessageObserver.h b/Tools/TestWebKitAPI/win/WindowMessageObserver.h
new file mode 100644
index 0000000..3388816
--- /dev/null
+++ b/Tools/TestWebKitAPI/win/WindowMessageObserver.h
@@ -0,0 +1,41 @@
+/*
+ * 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 WindowMessageObserver_h
+#define WindowMessageObserver_h
+
+namespace TestWebKitAPI {
+
+class WindowMessageObserver {
+public:
+ virtual void windowReceivedMessage(HWND, UINT message, WPARAM, LPARAM) = 0;
+
+protected:
+ virtual ~WindowMessageObserver() { }
+};
+
+} // namespace TestWebKitAPI
+
+#endif // WindowMessageObserver_h
diff --git a/Tools/TestWebKitAPI/win/copy-resources.cmd b/Tools/TestWebKitAPI/win/copy-resources.cmd
new file mode 100755
index 0000000..4b209d4
--- /dev/null
+++ b/Tools/TestWebKitAPI/win/copy-resources.cmd
@@ -0,0 +1,25 @@
+@echo off
+
+set ResourcesDirectory=%WebKitOutputDir%\bin\TestWebKitAPI.resources
+
+if "%1" EQU "clean" goto :clean
+if "%1" EQU "rebuild" call :clean
+
+echo Copying resources...
+mkdir 2>NUL "%ResourcesDirectory%"
+for %%f in (
+ ..\Tests\WebKit2\file-with-anchor.html
+ ..\Tests\WebKit2\find.html
+ ..\Tests\WebKit2\icon.png
+ ..\Tests\WebKit2\simple.html
+ ..\Tests\WebKit2\spacebar-scrolling.html
+) do (
+ xcopy /y /d %%f "%ResourcesDirectory%"
+)
+
+goto :EOF
+
+:clean
+
+echo Deleting resources...
+del /s /q "%ResourcesDirectory%"
diff --git a/Tools/TestWebKitAPI/win/main.cpp b/Tools/TestWebKitAPI/win/main.cpp
new file mode 100644
index 0000000..3091819
--- /dev/null
+++ b/Tools/TestWebKitAPI/win/main.cpp
@@ -0,0 +1,39 @@
+/*
+ * 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 "TestsController.h"
+
+int main(int argc, const char* argv[])
+{
+ bool passed = true;
+
+ std::string argument(argv[1]);
+ if (argument == "--dump-tests")
+ TestWebKitAPI::TestsController::shared().dumpTestNames();
+ else
+ passed = TestWebKitAPI::TestsController::shared().runTestNamed(argument);
+
+ return passed ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/Tools/WebKitAPITest/HostWindow.cpp b/Tools/WebKitAPITest/HostWindow.cpp
new file mode 100644
index 0000000..b364831
--- /dev/null
+++ b/Tools/WebKitAPITest/HostWindow.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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 "HostWindow.h"
+
+namespace WebKitAPITest {
+
+static LPCWSTR hostWindowClassName = L"HostWindow";
+
+HostWindow::HostWindow()
+ : m_window(0)
+{
+}
+
+bool HostWindow::initialize()
+{
+ registerWindowClass();
+ m_window = CreateWindowExW(0, hostWindowClassName, L"WebKitAPITest", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, GetModuleHandle(0), 0);
+ return m_window;
+}
+
+HostWindow::~HostWindow()
+{
+ if (!IsWindow(m_window))
+ return;
+ DestroyWindow(m_window);
+}
+
+RECT HostWindow::clientRect() const
+{
+ RECT rect = {0};
+ if (!GetClientRect(m_window, &rect)) {
+ RECT emptyRect = {0};
+ return emptyRect;
+ }
+ return rect;
+}
+
+void HostWindow::registerWindowClass()
+{
+ static bool initialized;
+ if (initialized)
+ return;
+ initialized = true;
+
+ WNDCLASSEXW wndClass = {0};
+ wndClass.cbSize = sizeof(wndClass);
+ wndClass.style = CS_HREDRAW | CS_VREDRAW;
+ wndClass.lpfnWndProc = wndProc;
+ wndClass.hCursor = LoadCursor(0, IDC_ARROW);
+ wndClass.hInstance = GetModuleHandle(0);
+ wndClass.lpszClassName = hostWindowClassName;
+
+ RegisterClassExW(&wndClass);
+}
+
+LRESULT HostWindow::wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+}
+
+} // namespace WebKitAPITest
diff --git a/Tools/WebKitAPITest/HostWindow.h b/Tools/WebKitAPITest/HostWindow.h
new file mode 100644
index 0000000..a2734ed
--- /dev/null
+++ b/Tools/WebKitAPITest/HostWindow.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 HostWindow_h
+#define HostWindow_h
+
+#include <windows.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebKitAPITest {
+
+class HostWindow : public Noncopyable {
+public:
+ HostWindow();
+ ~HostWindow();
+ bool initialize();
+
+ RECT clientRect() const;
+ HWND window() const { return m_window; }
+
+private:
+ static void registerWindowClass();
+ static LRESULT CALLBACK wndProc(HWND, UINT uMsg, WPARAM, LPARAM);
+
+ HWND m_window;
+};
+
+} // namespace WebKitAPITest
+
+#endif // HostWindow_h
diff --git a/Tools/WebKitAPITest/Test.h b/Tools/WebKitAPITest/Test.h
new file mode 100644
index 0000000..33b07c9
--- /dev/null
+++ b/Tools/WebKitAPITest/Test.h
@@ -0,0 +1,59 @@
+/*
+ * 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 Test_h
+#define Test_h
+
+#include "TestsController.h"
+
+namespace WebKitAPITest {
+
+// Abstract base class that all tests inherit from.
+class Test {
+public:
+ ~Test() { }
+ virtual const char* name() const = 0;
+ virtual void run() = 0;
+};
+
+#define TEST_CLASS_NAME(testCaseName, testName) testCaseName##_##testName##_Test
+
+// Use this to define a new test.
+#define TEST(testCaseName, testName) \
+ class TEST_CLASS_NAME(testCaseName, testName) : public Test { \
+ public: \
+ virtual const char* name() const { return #testCaseName ": " #testName; } \
+ virtual void run(); \
+ static const bool initialized; \
+ }; \
+ \
+ const bool TEST_CLASS_NAME(testCaseName, testName)::initialized = (TestsController::shared().addTest(new TEST_CLASS_NAME(testCaseName, testName)), true); \
+ \
+ void TEST_CLASS_NAME(testCaseName, testName)::run()
+
+#define TEST_ASSERT(expression) do { if (!(expression)) { TestsController::shared().testFailed(__FILE__, __LINE__, #expression); return; } } while (0)
+
+} // namespace WebKitAPITest
+
+#endif // Test_h
diff --git a/Tools/WebKitAPITest/TestsController.cpp b/Tools/WebKitAPITest/TestsController.cpp
new file mode 100644
index 0000000..08b193a
--- /dev/null
+++ b/Tools/WebKitAPITest/TestsController.cpp
@@ -0,0 +1,147 @@
+/*
+ * 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 "TestsController.h"
+
+#include "Test.h"
+#include <wtf/PassOwnPtr.h>
+
+using namespace std;
+
+namespace WebKitAPITest {
+
+static const LPCWSTR testsControllerWindowClassName = L"TestsControllerWindowClass";
+
+enum { runNextTestTimerID = 1 };
+
+inline TestsController::TestsController()
+ : m_testFailed(false)
+ , m_anyTestFailed(false)
+{
+ registerWindowClass();
+ m_window = CreateWindowExW(0, testsControllerWindowClassName, 0, WS_CHILD, 0, 0, 0, 0, HWND_MESSAGE, 0, GetModuleHandle(0), 0);
+}
+
+TestsController& TestsController::shared()
+{
+ static TestsController& shared = *new TestsController;
+ return shared;
+}
+
+bool TestsController::runAllTests()
+{
+ if (m_tests.isEmpty())
+ return true;
+
+ MSG msg;
+ BOOL result;
+ while ((result = GetMessage(&msg, 0, 0, 0))) {
+ if (result == -1)
+ break;
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ if (msg.message != WM_QUIT)
+ return false;
+
+ return !m_anyTestFailed;
+}
+
+void TestsController::addTest(PassOwnPtr<Test> test)
+{
+ m_tests.append(test.leakPtr());
+ runNextTestSoon();
+}
+
+void TestsController::testFailed(const char* file, int line, const char* message)
+{
+ ASSERT(!m_tests.isEmpty());
+
+ m_testFailed = true;
+ m_anyTestFailed = true;
+
+ printf("FAIL: %s\n\t%s (%s:%d)\n", m_tests.first()->name(), message, file, line);
+ fflush(stdout);
+}
+
+void TestsController::runNextTest()
+{
+ if (m_tests.isEmpty()) {
+ PostQuitMessage(0);
+ return;
+ }
+
+ Test* test = m_tests.first();
+
+ m_testFailed = false;
+ printf("RUN: %s\n", test->name());
+ fflush(stdout);
+ test->run();
+
+ if (!m_testFailed) {
+ printf("PASS: %s\n", test->name());
+ fflush(stdout);
+ }
+
+ m_tests.removeFirst();
+ delete test;
+
+ runNextTestSoon();
+}
+
+void TestsController::runNextTestSoon()
+{
+ SetTimer(m_window, runNextTestTimerID, 0, 0);
+}
+
+void TestsController::registerWindowClass()
+{
+ static bool initialized;
+ if (initialized)
+ return;
+ initialized = true;
+
+ WNDCLASSEXW wndClass = {0};
+ wndClass.cbSize = sizeof(wndClass);
+ wndClass.lpfnWndProc = wndProc;
+ wndClass.hCursor = LoadCursor(0, IDC_ARROW);
+ wndClass.hInstance = GetModuleHandle(0);
+ wndClass.lpszClassName = testsControllerWindowClassName;
+
+ RegisterClassExW(&wndClass);
+}
+
+LRESULT TestsController::wndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
+{
+ if (uMsg == WM_TIMER && wParam == runNextTestTimerID) {
+ KillTimer(hWnd, runNextTestTimerID);
+ TestsController::shared().runNextTest();
+ return 0;
+ }
+
+ return DefWindowProcW(hWnd, uMsg, wParam, lParam);
+}
+
+} // namespace WebKitAPITest
diff --git a/Tools/WebKitAPITest/TestsController.h b/Tools/WebKitAPITest/TestsController.h
new file mode 100644
index 0000000..11b457d
--- /dev/null
+++ b/Tools/WebKitAPITest/TestsController.h
@@ -0,0 +1,65 @@
+/*
+ * 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 TestsController_h
+#define TestsController_h
+
+#include <windows.h>
+#include <wtf/Forward.h>
+#include <wtf/Deque.h>
+#include <wtf/Noncopyable.h>
+
+namespace WebKitAPITest {
+
+class Test;
+
+class TestsController : public Noncopyable {
+public:
+ static TestsController& shared();
+
+ // Returns true if all the tests passed, false otherwise.
+ bool runAllTests();
+
+ void addTest(PassOwnPtr<Test>);
+ void testFailed(const char* file, int line, const char* message);
+
+private:
+ TestsController();
+ ~TestsController();
+
+ void runNextTest();
+ void runNextTestSoon();
+
+ static void registerWindowClass();
+ static LRESULT CALLBACK wndProc(HWND, UINT uMsg, WPARAM, LPARAM);
+
+ HWND m_window;
+ Deque<Test*> m_tests;
+ bool m_testFailed;
+ bool m_anyTestFailed;
+};
+
+} // namespace WebKitAPITest
+
+#endif // TestsController_h
diff --git a/Tools/WebKitAPITest/WebKitAPITest.vcproj b/Tools/WebKitAPITest/WebKitAPITest.vcproj
new file mode 100644
index 0000000..e3d8171
--- /dev/null
+++ b/Tools/WebKitAPITest/WebKitAPITest.vcproj
@@ -0,0 +1,418 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="WebKitAPITest"
+ ProjectGUID="{626089A3-25D3-4883-A96C-B8C66E036397}"
+ RootNamespace="WebKitAPITest"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug_All|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\WebKitAPITestCommon.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|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\WebKitAPITestCommon.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;.\WebKitAPITestCommon.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\WebKitAPITestCommon.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_LTCG|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\WebKitAPITestCommon.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="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;.\WebKitAPITestCommon.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=".\HostWindow.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\HostWindow.h"
+ >
+ </File>
+ <File
+ RelativePath=".\main.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\Test.h"
+ >
+ </File>
+ <File
+ RelativePath=".\TestsController.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\TestsController.h"
+ >
+ </File>
+ <File
+ RelativePath=".\tests\WebViewDestruction.cpp"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/WebKitAPITest/WebKitAPITestCommon.vsprops b/Tools/WebKitAPITest/WebKitAPITestCommon.vsprops
new file mode 100644
index 0000000..f57f53c
--- /dev/null
+++ b/Tools/WebKitAPITest/WebKitAPITestCommon.vsprops
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="WebKitAPITestCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)&quot;;&quot;$(WebKitOutputDir)\include&quot;;&quot;$(WebKitOutputDir)\include\private&quot;;&quot;$(WebKitOutputDir)\include\WebCore\ForwardingHeaders&quot;;&quot;$(WebKitLibrariesDir)\include&quot;;&quot;$(WebKitLibrariesDir)\include\private&quot;;&quot;$(WebKitLibrariesDir)\include\WebCore\ForwardingHeaders&quot;"
+ PreprocessorDefinitions="_CONSOLE;NOMINMAX"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="user32.lib ole32.lib JavaScriptCore$(WebKitDLLConfigSuffix).lib WebKit$(WebKitDLLConfigSuffix).lib"
+ SubSystem="1"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/NXCOMPAT"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/WebKitAPITest/WebKitAPITestPostBuild.cmd b/Tools/WebKitAPITest/WebKitAPITestPostBuild.cmd
new file mode 100644
index 0000000..f011495
--- /dev/null
+++ b/Tools/WebKitAPITest/WebKitAPITestPostBuild.cmd
@@ -0,0 +1 @@
+if exist "%WEBKITOUTPUTDIR%\buildfailed" del "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/WebKitAPITest/WebKitAPITestPreBuild.cmd b/Tools/WebKitAPITest/WebKitAPITestPreBuild.cmd
new file mode 100644
index 0000000..3a84c26
--- /dev/null
+++ b/Tools/WebKitAPITest/WebKitAPITestPreBuild.cmd
@@ -0,0 +1,6 @@
+%SystemDrive%\cygwin\bin\which.exe bash
+if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
+cmd /c
+if exist "%WEBKITOUTPUTDIR%\buildfailed" grep XX%PROJECTNAME%XX "%WEBKITOUTPUTDIR%\buildfailed"
+if errorlevel 1 exit 1
+echo XX%PROJECTNAME%XX > "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/WebKitAPITest/main.cpp b/Tools/WebKitAPITest/main.cpp
new file mode 100644
index 0000000..a941c30
--- /dev/null
+++ b/Tools/WebKitAPITest/main.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 "TestsController.h"
+
+using namespace WebKitAPITest;
+
+int main(int, char*[])
+{
+ // FIXME: Remove this line once <http://webkit.org/b/32867> is fixed.
+ OleInitialize(0);
+
+ return !TestsController::shared().runAllTests();
+}
diff --git a/Tools/WebKitAPITest/tests/WebViewDestruction.cpp b/Tools/WebKitAPITest/tests/WebViewDestruction.cpp
new file mode 100644
index 0000000..6c09e6f
--- /dev/null
+++ b/Tools/WebKitAPITest/tests/WebViewDestruction.cpp
@@ -0,0 +1,230 @@
+/*
+ * 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 "HostWindow.h"
+#include "Test.h"
+#include <WebCore/COMPtr.h>
+#include <WebKit/WebKit.h>
+#include <WebKit/WebKitCOMAPI.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WebKitAPITest {
+
+template <typename T>
+static HRESULT WebKitCreateInstance(REFCLSID clsid, T** object)
+{
+ return WebKitCreateInstance(clsid, 0, __uuidof(T), reinterpret_cast<void**>(object));
+}
+
+static int webViewCount()
+{
+ COMPtr<IWebKitStatistics> statistics;
+ if (FAILED(WebKitCreateInstance(__uuidof(WebKitStatistics), &statistics)))
+ return -1;
+ int count;
+ if (FAILED(statistics->webViewCount(&count)))
+ return -1;
+ return count;
+}
+
+static void createAndInitializeWebView(COMPtr<IWebView>& outWebView, HostWindow& window, HWND& viewWindow)
+{
+ COMPtr<IWebView> webView;
+ TEST_ASSERT(SUCCEEDED(WebKitCreateInstance(__uuidof(WebView), &webView)));
+
+ TEST_ASSERT(window.initialize());
+ TEST_ASSERT(SUCCEEDED(webView->setHostWindow(reinterpret_cast<OLE_HANDLE>(window.window()))));
+ TEST_ASSERT(SUCCEEDED(webView->initWithFrame(window.clientRect(), 0, 0)));
+
+ COMPtr<IWebViewPrivate> viewPrivate(Query, webView);
+ TEST_ASSERT(viewPrivate);
+ TEST_ASSERT(SUCCEEDED(viewPrivate->viewWindow(reinterpret_cast<OLE_HANDLE*>(&viewWindow))));
+ TEST_ASSERT(IsWindow(viewWindow));
+
+ outWebView.adoptRef(webView.releaseRef());
+}
+
+static void runMessagePump(DWORD timeoutMilliseconds)
+{
+ DWORD startTickCount = GetTickCount();
+ MSG msg;
+ BOOL result;
+ while ((result = PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) && GetTickCount() - startTickCount <= timeoutMilliseconds) {
+ if (result == -1)
+ break;
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+}
+
+static void finishWebViewDestructionTest(COMPtr<IWebView>& webView, HWND viewWindow)
+{
+ // Allow window messages to be processed, because in some cases that would trigger a crash (e.g., <http://webkit.org/b/32827>).
+ runMessagePump(50);
+
+ // We haven't crashed. Release the WebView and ensure that its view window has been destroyed and the WebView doesn't leak.
+ int currentWebViewCount = webViewCount();
+ TEST_ASSERT(currentWebViewCount > 0);
+
+ webView = 0;
+
+ TEST_ASSERT(webViewCount() == currentWebViewCount - 1);
+ TEST_ASSERT(!IsWindow(viewWindow));
+}
+
+// Tests that releasing a WebView without calling IWebView::initWithFrame works.
+TEST(WebViewDestruction, NoInitWithFrame)
+{
+ COMPtr<IWebView> webView;
+ TEST_ASSERT(SUCCEEDED(WebKitCreateInstance(__uuidof(WebView), &webView)));
+
+ finishWebViewDestructionTest(webView, 0);
+}
+
+TEST(WebViewDestruction, CloseWithoutInitWithFrame)
+{
+ COMPtr<IWebView> webView;
+ TEST_ASSERT(SUCCEEDED(WebKitCreateInstance(__uuidof(WebView), &webView)));
+
+ TEST_ASSERT(SUCCEEDED(webView->close()));
+
+ finishWebViewDestructionTest(webView, 0);
+}
+
+// Tests that releasing a WebView without calling IWebView::close or DestroyWindow doesn't leak. <http://webkit.org/b/33162>
+TEST(WebViewDestruction, NoCloseOrDestroyViewWindow)
+{
+ COMPtr<IWebView> webView;
+ HostWindow window;
+ HWND viewWindow;
+ createAndInitializeWebView(webView, window, viewWindow);
+
+ finishWebViewDestructionTest(webView, viewWindow);
+}
+
+// Tests that calling IWebView::close without calling DestroyWindow, then releasing a WebView doesn't crash. <http://webkit.org/b/32827>
+TEST(WebViewDestruction, CloseWithoutDestroyViewWindow)
+{
+ COMPtr<IWebView> webView;
+ HostWindow window;
+ HWND viewWindow;
+ createAndInitializeWebView(webView, window, viewWindow);
+
+ TEST_ASSERT(SUCCEEDED(webView->close()));
+
+ finishWebViewDestructionTest(webView, viewWindow);
+}
+
+TEST(WebViewDestruction, DestroyViewWindowWithoutClose)
+{
+ COMPtr<IWebView> webView;
+ HostWindow window;
+ HWND viewWindow;
+ createAndInitializeWebView(webView, window, viewWindow);
+
+ DestroyWindow(viewWindow);
+
+ finishWebViewDestructionTest(webView, viewWindow);
+}
+
+TEST(WebViewDestruction, CloseThenDestroyViewWindow)
+{
+ COMPtr<IWebView> webView;
+ HostWindow window;
+ HWND viewWindow;
+ createAndInitializeWebView(webView, window, viewWindow);
+
+ TEST_ASSERT(SUCCEEDED(webView->close()));
+ DestroyWindow(viewWindow);
+
+ finishWebViewDestructionTest(webView, viewWindow);
+}
+
+TEST(WebViewDestruction, DestroyViewWindowThenClose)
+{
+ COMPtr<IWebView> webView;
+ HostWindow window;
+ HWND viewWindow;
+ createAndInitializeWebView(webView, window, viewWindow);
+
+ DestroyWindow(viewWindow);
+ TEST_ASSERT(SUCCEEDED(webView->close()));
+
+ finishWebViewDestructionTest(webView, viewWindow);
+}
+
+TEST(WebViewDestruction, DestroyHostWindow)
+{
+ COMPtr<IWebView> webView;
+ HostWindow window;
+ HWND viewWindow;
+ createAndInitializeWebView(webView, window, viewWindow);
+
+ DestroyWindow(window.window());
+
+ finishWebViewDestructionTest(webView, viewWindow);
+}
+
+TEST(WebViewDestruction, DestroyHostWindowThenClose)
+{
+ COMPtr<IWebView> webView;
+ HostWindow window;
+ HWND viewWindow;
+ createAndInitializeWebView(webView, window, viewWindow);
+
+ DestroyWindow(window.window());
+ TEST_ASSERT(SUCCEEDED(webView->close()));
+
+ finishWebViewDestructionTest(webView, viewWindow);
+}
+
+TEST(WebViewDestruction, CloseThenDestroyHostWindow)
+{
+ COMPtr<IWebView> webView;
+ HostWindow window;
+ HWND viewWindow;
+ createAndInitializeWebView(webView, window, viewWindow);
+
+ TEST_ASSERT(SUCCEEDED(webView->close()));
+ DestroyWindow(window.window());
+
+ finishWebViewDestructionTest(webView, viewWindow);
+}
+
+// Tests that calling IWebView::mainFrame after calling IWebView::close doesn't crash. <http://webkit.org/b/32868>
+TEST(WebViewDestruction, MainFrameAfterClose)
+{
+ COMPtr<IWebView> webView;
+ HostWindow window;
+ HWND viewWindow;
+ createAndInitializeWebView(webView, window, viewWindow);
+
+ TEST_ASSERT(SUCCEEDED(webView->close()));
+ COMPtr<IWebFrame> mainFrame;
+ TEST_ASSERT(SUCCEEDED(webView->mainFrame(&mainFrame)));
+
+ finishWebViewDestructionTest(webView, viewWindow);
+}
+
+} // namespace WebKitAPITest
diff --git a/Tools/WebKitLauncher/Configurations/Base.xcconfig b/Tools/WebKitLauncher/Configurations/Base.xcconfig
new file mode 100644
index 0000000..0a4dc2e
--- /dev/null
+++ b/Tools/WebKitLauncher/Configurations/Base.xcconfig
@@ -0,0 +1,39 @@
+// 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.
+
+ARCHS = $(ARCHS_STANDARD_32_64_BIT);
+DEAD_CODE_STRIPPING = YES;
+DEBUG_INFORMATION_FORMAT = dwarf;
+GCC_DEBUGGING_SYMBOLS = full;
+GCC_MODEL_TUNING = G5;
+GCC_PREPROCESSOR_DEFINITIONS = ENABLE_SPARKLE=$(ENABLE_SPARKLE);
+GCC_TREAT_WARNINGS_AS_ERRORS = YES;
+GCC_VERSION = 4.0;
+GCC_VERSION[arch=x86_64] = 4.2;
+MACOSX_DEPLOYMENT_TARGET = 10.4;
+MACOSX_DEPLOYMENT_TARGET[arch=x86_64] = 10.5;
+PREBINDING = NO;
+SDKROOT = macosx10.5;
+WARNING_CFLAGS = -Wall;
+
+ENABLE_SPARKLE = 0;
diff --git a/Tools/WebKitLauncher/Configurations/WebKitLauncher.xcconfig b/Tools/WebKitLauncher/Configurations/WebKitLauncher.xcconfig
new file mode 100644
index 0000000..c4dde36
--- /dev/null
+++ b/Tools/WebKitLauncher/Configurations/WebKitLauncher.xcconfig
@@ -0,0 +1,27 @@
+// 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.
+
+INFOPLIST_FILE = Info.plist;
+PRODUCT_NAME = WebKit;
+WRAPPER_EXTENSION = app;
+MACOSX_DEPLOYMENT_TARGET[arch=ppc] = 10.2;
diff --git a/Tools/WebKitLauncher/Configurations/WebKitNightlyEnabler.xcconfig b/Tools/WebKitLauncher/Configurations/WebKitNightlyEnabler.xcconfig
new file mode 100644
index 0000000..ff352e6
--- /dev/null
+++ b/Tools/WebKitLauncher/Configurations/WebKitNightlyEnabler.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 = WebKitNightlyEnabler;
+INSTALL_PATH = @executable_path/../Resources;
+
+OTHER_LDFLAGS = $(OTHER_LDFLAGS_$(ENABLE_SPARKLE));
+OTHER_LDFLAGS_0 = ;
+OTHER_LDFLAGS_1 = -framework Sparkle;
diff --git a/Tools/WebKitLauncher/Info.plist b/Tools/WebKitLauncher/Info.plist
new file mode 100644
index 0000000..83564a7
--- /dev/null
+++ b/Tools/WebKitLauncher/Info.plist
@@ -0,0 +1,493 @@
+<?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>CFBundleDocumentTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>css</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>text/css</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>CSS style sheet</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>pdf</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>application/pdf</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>PDF document</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>webarchive</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>webarchive.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>application/x-webarchive</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Web archive</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>syndarticle</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeName</key>
+ <string>RSS article</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>webbookmark</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeName</key>
+ <string>Safari bookmark</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>webloc</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeName</key>
+ <string>Web internet location</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>ilht</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>download</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>download10.icns</string>
+ <key>CFBundleTypeName</key>
+ <string>Safari download</string>
+ <key>CFBundleTypeRole</key>
+ <string>Editor</string>
+ <key>LSTypeIsPackage</key>
+ <true/>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>gif</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>image/gif</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>GIF image</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>GIFf</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>html</string>
+ <string>htm</string>
+ <string>shtml</string>
+ <string>jhtml</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>text/html</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>HTML document</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>HTML</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>js</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>application/x-javascript</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>JavaScript script</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>jpg</string>
+ <string>jpeg</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>image/jpeg</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>JPEG image</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>JPEG</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>jp2</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>image/jp2</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>JPEG 2000 image</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>jp2 </string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>txt</string>
+ <string>text</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>text/plain</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Plain text document</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>TEXT</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>png</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>image/png</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>PNG image</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>PNGf</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>rtf</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>application/rtf</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Rich Text Format (RTF) document</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>RTF </string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>tiff</string>
+ <string>tif</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>image/tiff</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>TIFF image</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>TIFF</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>url</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeName</key>
+ <string>Web site location</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>LINK</string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>ico</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>image/x-icon</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>Windows icon image</string>
+ <key>CFBundleTypeOSTypes</key>
+ <array>
+ <string>ICO </string>
+ </array>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>xhtml</string>
+ <string>xhtm</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>application/xhtml+xml</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>XHTML document</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ <dict>
+ <key>CFBundleTypeExtensions</key>
+ <array>
+ <string>xml</string>
+ <string>xbl</string>
+ <string>xsl</string>
+ <string>xslt</string>
+ </array>
+ <key>CFBundleTypeIconFile</key>
+ <string>document.icns</string>
+ <key>CFBundleTypeMIMETypes</key>
+ <array>
+ <string>application/xml</string>
+ <string>text/xml</string>
+ </array>
+ <key>CFBundleTypeName</key>
+ <string>XML document</string>
+ <key>CFBundleTypeRole</key>
+ <string>Viewer</string>
+ <key>NSDocumentClass</key>
+ <string>BrowserDocument</string>
+ </dict>
+ </array>
+ <key>CFBundleExecutable</key>
+ <string>${EXECUTABLE_NAME}</string>
+ <key>CFBundleGetInfoString</key>
+ <string>rVERSION, Copyright 2005-2009 Apple Inc.</string>
+ <key>CFBundleIconFile</key>
+ <string>webkit.icns</string>
+ <key>CFBundleIdentifier</key>
+ <string>org.webkit.nightly.WebKit</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundleName</key>
+ <string>${PRODUCT_NAME}</string>
+ <key>CFBundlePackageType</key>
+ <string>APPL</string>
+ <key>CFBundleSignature</key>
+ <string>wbkt</string>
+ <key>CFBundleVersion</key>
+ <string>VERSION</string>
+ <key>CFBundleShortVersionString</key>
+ <string>rVERSION</string>
+ <key>LSArchitecturePriority</key>
+ <array>
+ <string>x86_64</string>
+ <string>i386</string>
+ <string>ppc</string>
+ </array>
+ <key>LSMinimumSystemVersionByArchitecture</key>
+ <dict>
+ <key>x86_64</key>
+ <string>10.6</string>
+ </dict>
+ <key>SUFeedURL</key>
+ <string>http://nightly.webkit.org/builds/trunk/mac/rss</string>
+ <key>SUShowReleaseNotes</key>
+ <false/>
+ <key>SUAllowsAutomaticUpdates</key>
+ <false/>
+ <key>SUPublicDSAKeyFile</key>
+ <string>nightly.webkit.org.public.pem</string>
+ <key>NSPrincipalClass</key>
+ <string>BrowserApplication</string>
+ <key>CFBundleHelpBookFolder</key>
+ <string>SafariHelp</string>
+ <key>CFBundleHelpBookName</key>
+ <string>Safari Help</string>
+ <key>CFBundleURLTypes</key>
+ <array>
+ <dict>
+ <key>CFBundleURLName</key>
+ <string>Web site URL</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>http</string>
+ <string>https</string>
+ </array>
+ </dict>
+ <dict>
+ <key>CFBundleURLName</key>
+ <string>local file URL</string>
+ <key>CFBundleURLSchemes</key>
+ <array>
+ <string>file</string>
+ </array>
+ </dict>
+ </array>
+ <key>NSAppleScriptEnabled</key>
+ <string>Yes</string>
+ <key>UTExportedTypeDeclarations</key>
+ <array>
+ <dict>
+ <key>UTTypeConformsTo</key>
+ <string>public.data</string>
+ <key>UTTypeDescription</key>
+ <string>Safari bookmark</string>
+ <key>UTTypeIdentifier</key>
+ <string>com.apple.safari.bookmark</string>
+ <key>UTTypeTagSpecification</key>
+ <dict>
+ <key>public.filename-extension</key>
+ <array>
+ <string>webbookmark</string>
+ </array>
+ </dict>
+ </dict>
+ </array>
+</dict>
+</plist>
diff --git a/Tools/WebKitLauncher/VERSION b/Tools/WebKitLauncher/VERSION
new file mode 100644
index 0000000..fd85e30
--- /dev/null
+++ b/Tools/WebKitLauncher/VERSION
@@ -0,0 +1 @@
+VERSION
diff --git a/Tools/WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj b/Tools/WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..c130f45
--- /dev/null
+++ b/Tools/WebKitLauncher/WebKitLauncher.xcodeproj/project.pbxproj
@@ -0,0 +1,448 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ 5DE79BC30F1C62450067BE08 /* Extract Sparkle */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = 5DE79BD80F1C629B0067BE08 /* Build configuration list for PBXAggregateTarget "Extract Sparkle" */;
+ buildPhases = (
+ 5DE79BC20F1C62450067BE08 /* ShellScript */,
+ );
+ dependencies = (
+ );
+ name = "Extract Sparkle";
+ productName = "Extract Sparkle";
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 5D1067640FE63758002A2868 /* WebKitLauncherURLProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = 5D1067620FE63758002A2868 /* WebKitLauncherURLProtocol.h */; };
+ 5D1067650FE63758002A2868 /* WebKitLauncherURLProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D1067630FE63758002A2868 /* WebKitLauncherURLProtocol.m */; };
+ 5D18A1FF103FE255006CA7C7 /* nightly.webkit.org.public.pem in Resources */ = {isa = PBXBuildFile; fileRef = 5D18A1FE103FE255006CA7C7 /* nightly.webkit.org.public.pem */; };
+ 5D41141C0A50A9DE00C84CF0 /* VERSION in Resources */ = {isa = PBXBuildFile; fileRef = 5D41141B0A50A9DE00C84CF0 /* VERSION */; };
+ 5D4DF982097F89FB0083D5E5 /* start.html in Resources */ = {isa = PBXBuildFile; fileRef = 5D4DF981097F89FB0083D5E5 /* start.html */; };
+ 5D650F3609DB8B370075E9A8 /* WebKitNightlyEnabler.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D650F3509DB8B370075E9A8 /* WebKitNightlyEnabler.m */; };
+ 5D650F3A09DB8B410075E9A8 /* WebKitNightlyEnabler.dylib in Resources */ = {isa = PBXBuildFile; fileRef = 5D650F3409DB8B280075E9A8 /* WebKitNightlyEnabler.dylib */; };
+ 5D877FCD0A5795F200D0C67B /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
+ 5DA88F6D0FC8136000AB2F62 /* WebKitNightlyEnablerSparkle.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DA88F6B0FC8136000AB2F62 /* WebKitNightlyEnablerSparkle.h */; };
+ 5DA88F6E0FC8136000AB2F62 /* WebKitNightlyEnablerSparkle.m in Sources */ = {isa = PBXBuildFile; fileRef = 5DA88F6C0FC8136000AB2F62 /* WebKitNightlyEnablerSparkle.m */; };
+ 5DA88F7A0FC813EB00AB2F62 /* WebKitNightlyEnabler.h in Headers */ = {isa = PBXBuildFile; fileRef = 5DA88F790FC813EB00AB2F62 /* WebKitNightlyEnabler.h */; };
+ 5DB70525097B94CD009875EC /* webkit.icns in Resources */ = {isa = PBXBuildFile; fileRef = 5DB70524097B94CD009875EC /* webkit.icns */; };
+ 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; };
+ 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 5D650F4409DB8B830075E9A8 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5D650F3309DB8B280075E9A8;
+ remoteInfo = WebKitNightlyEnabler;
+ };
+ 5DE79BC90F1C62850067BE08 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5DE79BC30F1C62450067BE08;
+ remoteInfo = "Extract Sparkle";
+ };
+ 5DE79BCB0F1C62890067BE08 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 29B97313FDCFA39411CA2CEA /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 5DE79BC30F1C62450067BE08;
+ remoteInfo = "Extract Sparkle";
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = "<absolute>"; };
+ 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
+ 5D1067620FE63758002A2868 /* WebKitLauncherURLProtocol.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitLauncherURLProtocol.h; sourceTree = "<group>"; };
+ 5D1067630FE63758002A2868 /* WebKitLauncherURLProtocol.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebKitLauncherURLProtocol.m; sourceTree = "<group>"; };
+ 5D18A1FE103FE255006CA7C7 /* nightly.webkit.org.public.pem */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = nightly.webkit.org.public.pem; sourceTree = "<group>"; };
+ 5D41141B0A50A9DE00C84CF0 /* VERSION */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = VERSION; sourceTree = "<group>"; };
+ 5D4DF981097F89FB0083D5E5 /* start.html */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.html; path = start.html; sourceTree = "<group>"; };
+ 5D650F3409DB8B280075E9A8 /* WebKitNightlyEnabler.dylib */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.dylib"; includeInIndex = 0; path = WebKitNightlyEnabler.dylib; sourceTree = BUILT_PRODUCTS_DIR; };
+ 5D650F3509DB8B370075E9A8 /* WebKitNightlyEnabler.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebKitNightlyEnabler.m; sourceTree = "<group>"; };
+ 5DA88F6B0FC8136000AB2F62 /* WebKitNightlyEnablerSparkle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitNightlyEnablerSparkle.h; sourceTree = "<group>"; };
+ 5DA88F6C0FC8136000AB2F62 /* WebKitNightlyEnablerSparkle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebKitNightlyEnablerSparkle.m; sourceTree = "<group>"; };
+ 5DA88F790FC813EB00AB2F62 /* WebKitNightlyEnabler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitNightlyEnabler.h; sourceTree = "<group>"; };
+ 5DA88F7E0FC8176100AB2F62 /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; };
+ 5DA88F7F0FC8176100AB2F62 /* WebKitLauncher.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = WebKitLauncher.xcconfig; sourceTree = "<group>"; };
+ 5DA88F800FC8176100AB2F62 /* WebKitNightlyEnabler.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = WebKitNightlyEnabler.xcconfig; sourceTree = "<group>"; };
+ 5DB70524097B94CD009875EC /* webkit.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = webkit.icns; sourceTree = "<group>"; };
+ 5DE79BEB0F1C63CC0067BE08 /* Sparkle.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = Sparkle.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8D1107310486CEB800E47090 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
+ 8D1107320486CEB800E47090 /* WebKit.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WebKit.app; sourceTree = BUILT_PRODUCTS_DIR; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 5D650F3209DB8B280075E9A8 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5D877FCD0A5795F200D0C67B /* Cocoa.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D11072E0486CEB800E47090 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */,
+ );
+ name = "Linked Frameworks";
+ sourceTree = "<group>";
+ };
+ 19C28FACFE9D520D11CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 5DE79BEB0F1C63CC0067BE08 /* Sparkle.framework */,
+ 8D1107320486CEB800E47090 /* WebKit.app */,
+ 5D650F3409DB8B280075E9A8 /* WebKitNightlyEnabler.dylib */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 29B97314FDCFA39411CA2CEA /* WebKit */ = {
+ isa = PBXGroup;
+ children = (
+ 29B97315FDCFA39411CA2CEA /* Source */,
+ 5DA88F7D0FC8174E00AB2F62 /* Configurations */,
+ 29B97317FDCFA39411CA2CEA /* Resources */,
+ 29B97323FDCFA39411CA2CEA /* Frameworks */,
+ 19C28FACFE9D520D11CA2CBB /* Products */,
+ );
+ name = WebKit;
+ sourceTree = "<group>";
+ };
+ 29B97315FDCFA39411CA2CEA /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ 29B97316FDCFA39411CA2CEA /* main.m */,
+ 5D1067620FE63758002A2868 /* WebKitLauncherURLProtocol.h */,
+ 5D1067630FE63758002A2868 /* WebKitLauncherURLProtocol.m */,
+ 5DA88F790FC813EB00AB2F62 /* WebKitNightlyEnabler.h */,
+ 5D650F3509DB8B370075E9A8 /* WebKitNightlyEnabler.m */,
+ 5DA88F6B0FC8136000AB2F62 /* WebKitNightlyEnablerSparkle.h */,
+ 5DA88F6C0FC8136000AB2F62 /* WebKitNightlyEnablerSparkle.m */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 29B97317FDCFA39411CA2CEA /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ 8D1107310486CEB800E47090 /* Info.plist */,
+ 5D18A1FE103FE255006CA7C7 /* nightly.webkit.org.public.pem */,
+ 5D4DF981097F89FB0083D5E5 /* start.html */,
+ 5D41141B0A50A9DE00C84CF0 /* VERSION */,
+ 5DB70524097B94CD009875EC /* webkit.icns */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ 29B97323FDCFA39411CA2CEA /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */,
+ );
+ name = Frameworks;
+ sourceTree = "<group>";
+ };
+ 5DA88F7D0FC8174E00AB2F62 /* Configurations */ = {
+ isa = PBXGroup;
+ children = (
+ 5DA88F7E0FC8176100AB2F62 /* Base.xcconfig */,
+ 5DA88F7F0FC8176100AB2F62 /* WebKitLauncher.xcconfig */,
+ 5DA88F800FC8176100AB2F62 /* WebKitNightlyEnabler.xcconfig */,
+ );
+ path = Configurations;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 5D650F3009DB8B280075E9A8 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5D1067640FE63758002A2868 /* WebKitLauncherURLProtocol.h in Headers */,
+ 5DA88F7A0FC813EB00AB2F62 /* WebKitNightlyEnabler.h in Headers */,
+ 5DA88F6D0FC8136000AB2F62 /* WebKitNightlyEnablerSparkle.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 5D650F3309DB8B280075E9A8 /* WebKitNightlyEnabler */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 5D650F3709DB8B370075E9A8 /* Build configuration list for PBXNativeTarget "WebKitNightlyEnabler" */;
+ buildPhases = (
+ 5D650F3009DB8B280075E9A8 /* Headers */,
+ 5D650F3109DB8B280075E9A8 /* Sources */,
+ 5D650F3209DB8B280075E9A8 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 5DE79BCC0F1C62890067BE08 /* PBXTargetDependency */,
+ );
+ name = WebKitNightlyEnabler;
+ productName = WebKitNightlyEnabler;
+ productReference = 5D650F3409DB8B280075E9A8 /* WebKitNightlyEnabler.dylib */;
+ productType = "com.apple.product-type.library.dynamic";
+ };
+ 8D1107260486CEB800E47090 /* WebKit */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "WebKit" */;
+ buildPhases = (
+ 8D1107290486CEB800E47090 /* Resources */,
+ 8D11072C0486CEB800E47090 /* Sources */,
+ 8D11072E0486CEB800E47090 /* Frameworks */,
+ 5DA892AC0FC8E3A100AB2F62 /* Copy Sparkle in to Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 5D650F4509DB8B830075E9A8 /* PBXTargetDependency */,
+ 5DE79BCA0F1C62850067BE08 /* PBXTargetDependency */,
+ );
+ name = WebKit;
+ productInstallPath = "$(HOME)/Applications";
+ productName = WebKit;
+ productReference = 8D1107320486CEB800E47090 /* WebKit.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 29B97313FDCFA39411CA2CEA /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "WebKitLauncher" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 29B97314FDCFA39411CA2CEA /* WebKit */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8D1107260486CEB800E47090 /* WebKit */,
+ 5D650F3309DB8B280075E9A8 /* WebKitNightlyEnabler */,
+ 5DE79BC30F1C62450067BE08 /* Extract Sparkle */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8D1107290486CEB800E47090 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5D4DF982097F89FB0083D5E5 /* start.html in Resources */,
+ 5D41141C0A50A9DE00C84CF0 /* VERSION in Resources */,
+ 5DB70525097B94CD009875EC /* webkit.icns in Resources */,
+ 5D650F3A09DB8B410075E9A8 /* WebKitNightlyEnabler.dylib in Resources */,
+ 5D18A1FF103FE255006CA7C7 /* nightly.webkit.org.public.pem in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ 5DA892AC0FC8E3A100AB2F62 /* Copy Sparkle in to Frameworks */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Copy Sparkle in to Frameworks";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "if [[ \"${ENABLE_SPARKLE}\" == \"1\" ]]\nthen\n ditto \"${CONFIGURATION_BUILD_DIR}/Sparkle.framework\" \"${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sparkle.framework\"\n cd \"${CONFIGURATION_BUILD_DIR}/Sparkle.framework/Resources\"\n find . -name '*lproj' -not -name 'en.lproj' -print0 | xargs -0 rm -rf\nelse\n rm -rf \"${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Sparkle.framework\"\nfi\n";
+ };
+ 5DE79BC20F1C62450067BE08 /* ShellScript */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ "$(SRCROOT)/Sparkle.framework.tar.gz",
+ );
+ outputPaths = (
+ "$(CONFIGURATION_BUILD_DIR)/Sparkle.framework",
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "if [[ \"${ENABLE_SPARKLE}\" == \"1\" ]]\nthen\n tar -C \"${CONFIGURATION_BUILD_DIR}\" -xvzf \"${SRCROOT}/Sparkle.framework.tar.gz\"\n cd \"${CONFIGURATION_BUILD_DIR}/Sparkle.framework/Resources\"\n find . -name '*lproj' -not -name 'en.lproj' -print0 | xargs -0 rm -rf\nelse\n rm -rf \"${CONFIGURATION_BUILD_DIR}/Sparkle.framework\"\nfi\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 5D650F3109DB8B280075E9A8 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 5D1067650FE63758002A2868 /* WebKitLauncherURLProtocol.m in Sources */,
+ 5D650F3609DB8B370075E9A8 /* WebKitNightlyEnabler.m in Sources */,
+ 5DA88F6E0FC8136000AB2F62 /* WebKitNightlyEnablerSparkle.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8D11072C0486CEB800E47090 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8D11072D0486CEB800E47090 /* main.m in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 5D650F4509DB8B830075E9A8 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5D650F3309DB8B280075E9A8 /* WebKitNightlyEnabler */;
+ targetProxy = 5D650F4409DB8B830075E9A8 /* PBXContainerItemProxy */;
+ };
+ 5DE79BCA0F1C62850067BE08 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5DE79BC30F1C62450067BE08 /* Extract Sparkle */;
+ targetProxy = 5DE79BC90F1C62850067BE08 /* PBXContainerItemProxy */;
+ };
+ 5DE79BCC0F1C62890067BE08 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 5DE79BC30F1C62450067BE08 /* Extract Sparkle */;
+ targetProxy = 5DE79BCB0F1C62890067BE08 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 5D650F3809DB8B370075E9A8 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5DA88F800FC8176100AB2F62 /* WebKitNightlyEnabler.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ 5D650F3909DB8B370075E9A8 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5DA88F800FC8176100AB2F62 /* WebKitNightlyEnabler.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ 5DE79BC40F1C62450067BE08 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "Extract Sparkle";
+ };
+ name = Debug;
+ };
+ 5DE79BC50F1C62450067BE08 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ PRODUCT_NAME = "Extract Sparkle";
+ };
+ name = Release;
+ };
+ C01FCF4B08A954540054247B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5DA88F7F0FC8176100AB2F62 /* WebKitLauncher.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ C01FCF4C08A954540054247B /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5DA88F7F0FC8176100AB2F62 /* WebKitLauncher.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ C01FCF4F08A954540054247B /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5DA88F7E0FC8176100AB2F62 /* Base.xcconfig */;
+ buildSettings = {
+ GCC_OPTIMIZATION_LEVEL = 0;
+ ONLY_ACTIVE_ARCH = YES;
+ };
+ name = Debug;
+ };
+ C01FCF5008A954540054247B /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = 5DA88F7E0FC8176100AB2F62 /* Base.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 5D650F3709DB8B370075E9A8 /* Build configuration list for PBXNativeTarget "WebKitNightlyEnabler" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5D650F3809DB8B370075E9A8 /* Debug */,
+ 5D650F3909DB8B370075E9A8 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 5DE79BD80F1C629B0067BE08 /* Build configuration list for PBXAggregateTarget "Extract Sparkle" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 5DE79BC40F1C62450067BE08 /* Debug */,
+ 5DE79BC50F1C62450067BE08 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "WebKit" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C01FCF4B08A954540054247B /* Debug */,
+ C01FCF4C08A954540054247B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ C01FCF4E08A954540054247B /* Build configuration list for PBXProject "WebKitLauncher" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ C01FCF4F08A954540054247B /* Debug */,
+ C01FCF5008A954540054247B /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 29B97313FDCFA39411CA2CEA /* Project object */;
+}
diff --git a/Tools/WebKitLauncher/WebKitLauncherURLProtocol.h b/Tools/WebKitLauncher/WebKitLauncherURLProtocol.h
new file mode 100644
index 0000000..9159f5d
--- /dev/null
+++ b/Tools/WebKitLauncher/WebKitLauncherURLProtocol.h
@@ -0,0 +1,33 @@
+/*
+ * 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 <Foundation/Foundation.h>
+
+@interface WebKitLauncherURLProtocol : NSURLProtocol
+{
+
+}
+
+@end
diff --git a/Tools/WebKitLauncher/WebKitLauncherURLProtocol.m b/Tools/WebKitLauncher/WebKitLauncherURLProtocol.m
new file mode 100644
index 0000000..9e56857
--- /dev/null
+++ b/Tools/WebKitLauncher/WebKitLauncherURLProtocol.m
@@ -0,0 +1,123 @@
+/*
+ * 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 "WebKitLauncherURLProtocol.h"
+#import "WebKitNightlyEnabler.h"
+
+#if ENABLE_SPARKLE
+#import <AppKit/AppKit.h>
+#import <Sparkle/Sparkle.h>
+#endif
+
+@interface WebKitLauncherURLProtocol (ImplementationDetails)
+-(void)handleIsWebKitLauncherAvailableJS;
+-(void)handleCheckForUpdates;
+-(void)resourceNotFound;
+@end
+
+@implementation WebKitLauncherURLProtocol
+
++(void)load
+{
+ [NSURLProtocol registerClass:self];
+}
+
++(BOOL)canInitWithRequest:(NSURLRequest *)request
+{
+ if (![[[request URL] scheme] isEqualToString:@"x-webkit-launcher"])
+ return NO;
+
+ NSURL *mainDocumentURL = [request mainDocumentURL];
+ if (!mainDocumentURL)
+ return NO;
+
+ NSString *mainDocumentHost = [mainDocumentURL host];
+ if (![mainDocumentHost isEqualToString:@"webkit.org"] && ![mainDocumentHost hasSuffix:@".webkit.org"])
+ return NO;
+
+ return YES;
+}
+
++(NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request
+{
+ return request;
+}
+
+-(void)startLoading
+{
+ NSURLRequest *request = [self request];
+ NSString *resourceSpecifier = [[request URL] resourceSpecifier];
+ if ([resourceSpecifier isEqualToString:@"is-x-webkit-launcher-available.js"]) {
+ [self handleIsWebKitLauncherAvailableJS];
+ return;
+ }
+#if ENABLE_SPARKLE
+ if ([resourceSpecifier isEqualToString:@"check-for-updates"]) {
+ [self handleCheckForUpdates];
+ return;
+ }
+#endif
+ [self resourceNotFound];
+}
+
+-(void)stopLoading
+{
+}
+
+-(void)handleIsWebKitLauncherAvailableJS
+{
+ id client = [self client];
+ NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[[self request] URL] MIMEType:@"text/javascript" expectedContentLength:0 textEncodingName:@"utf-8"];
+ [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageAllowed];
+ [response release];
+
+ NSData *data = [@"var isWebKitLauncherAvailable = true;" dataUsingEncoding:NSUTF8StringEncoding];
+ [client URLProtocol:self didLoadData:data];
+ [client URLProtocolDidFinishLoading:self];
+}
+
+#if ENABLE_SPARKLE
+-(void)handleCheckForUpdates
+{
+ id client = [self client];
+ NSURLResponse *response = [[NSURLResponse alloc] initWithURL:[[self request] URL] MIMEType:@"text/plain" expectedContentLength:0 textEncodingName:@"utf-8"];
+ [client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
+ [response release];
+
+ SUUpdater *updater = [SUUpdater updaterForBundle:webKitLauncherBundle()];
+ [updater performSelectorOnMainThread:@selector(checkForUpdates:) withObject:self waitUntilDone:NO];
+ [client URLProtocolDidFinishLoading:self];
+}
+#endif
+
+-(void)resourceNotFound
+{
+ id client = [self client];
+ NSDictionary *infoDictionary = [NSDictionary dictionaryWithObject:NSErrorFailingURLStringKey forKey:[[self request] URL]];
+ NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorFileDoesNotExist userInfo:infoDictionary];
+ [client URLProtocol:self didFailWithError:error];
+}
+
+@end
diff --git a/Tools/WebKitLauncher/WebKitNightlyEnabler.h b/Tools/WebKitLauncher/WebKitNightlyEnabler.h
new file mode 100644
index 0000000..2fe1444
--- /dev/null
+++ b/Tools/WebKitLauncher/WebKitNightlyEnabler.h
@@ -0,0 +1,31 @@
+/*
+ * 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.
+ */
+#ifndef WebKitNightlyEnabler_h
+#define WebKitNightlyEnabler_h
+
+@class NSBundle;
+extern NSBundle *webKitLauncherBundle();
+
+#endif // WebKitNightlyEnabler_h
diff --git a/Tools/WebKitLauncher/WebKitNightlyEnabler.m b/Tools/WebKitLauncher/WebKitNightlyEnabler.m
new file mode 100644
index 0000000..eef0f8c
--- /dev/null
+++ b/Tools/WebKitLauncher/WebKitNightlyEnabler.m
@@ -0,0 +1,236 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Graham Dennis. 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 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 "WebKitNightlyEnablerSparkle.h"
+
+static void enableWebKitNightlyBehaviour() __attribute__ ((constructor));
+
+static NSString *WKNERunState = @"WKNERunState";
+static NSString *WKNEShouldMonitorShutdowns = @"WKNEShouldMonitorShutdowns";
+
+typedef enum {
+ RunStateShutDown,
+ RunStateInitializing,
+ RunStateRunning
+} WKNERunStates;
+
+static char *webKitAppPath;
+static bool extensionBundlesWereLoaded = NO;
+static NSSet *extensionPaths = nil;
+
+static int32_t systemVersion()
+{
+ static SInt32 version = 0;
+ if (!version)
+ Gestalt(gestaltSystemVersion, &version);
+
+ return version;
+}
+
+
+static void myBundleDidLoad(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
+{
+ NSBundle *bundle = (NSBundle *)object;
+ NSString *bundlePath = [[bundle bundlePath] stringByAbbreviatingWithTildeInPath];
+ NSString *bundleFileName = [bundlePath lastPathComponent];
+
+ // Explicitly ignore SIMBL.bundle, as its only purpose is to load extensions
+ // on a per-application basis. It's presence indicates a user has application
+ // extensions, but not that any will be loaded into Safari
+ if ([bundleFileName isEqualToString:@"SIMBL.bundle"])
+ return;
+
+ // If the bundle lives inside a known extension path, flag it as an extension
+ NSEnumerator *e = [extensionPaths objectEnumerator];
+ NSString *path = nil;
+ while ((path = [e nextObject])) {
+ if ([bundlePath length] < [path length])
+ continue;
+
+ if ([[bundlePath substringToIndex:[path length]] isEqualToString:path]) {
+ NSLog(@"Extension detected: %@", bundlePath);
+ extensionBundlesWereLoaded = YES;
+ break;
+ }
+ }
+}
+
+static void myApplicationWillFinishLaunching(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
+{
+ CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), &myApplicationWillFinishLaunching, NULL, NULL);
+ CFNotificationCenterRemoveObserver(CFNotificationCenterGetLocalCenter(), &myBundleDidLoad, NULL, NULL);
+ [extensionPaths release];
+ extensionPaths = nil;
+
+ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+ [userDefaults setInteger:RunStateRunning forKey:WKNERunState];
+ [userDefaults synchronize];
+
+ if (extensionBundlesWereLoaded)
+ NSRunInformationalAlertPanel(@"Safari extensions detected",
+ @"Safari extensions were detected on your system. Extensions are incompatible with nightly builds of WebKit, and may cause crashes or incorrect behavior. Please disable them if you experience such behavior.", @"Continue",
+ nil, nil);
+
+ initializeSparkle();
+}
+
+static void myApplicationWillTerminate(CFNotificationCenterRef center, void *observer, CFStringRef name, const void *object, CFDictionaryRef userInfo)
+{
+ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+ [userDefaults setInteger:RunStateShutDown forKey:WKNERunState];
+ [userDefaults synchronize];
+}
+
+NSBundle *webKitLauncherBundle()
+{
+ NSString *executablePath = [NSString stringWithUTF8String:webKitAppPath];
+ NSRange appLocation = [executablePath rangeOfString:@".app/" options:NSBackwardsSearch];
+ NSString *appPath = [executablePath substringToIndex:appLocation.location + appLocation.length];
+ return [NSBundle bundleWithPath:appPath];
+}
+
+extern char **_CFGetProcessPath() __attribute__((weak));
+extern OSStatus _RegisterApplication(CFDictionaryRef additionalAppInfoRef, ProcessSerialNumber* myPSN) __attribute__((weak));
+
+static void poseAsWebKitApp()
+{
+ webKitAppPath = strdup(getenv("WebKitAppPath"));
+ if (!webKitAppPath)
+ return;
+
+ unsetenv("WebKitAppPath");
+
+ // Set up the main bundle early so it points at Safari.app
+ CFBundleGetMainBundle();
+
+ if (systemVersion() < 0x1060) {
+ if (!_CFGetProcessPath)
+ return;
+
+ // Fiddle with CoreFoundation to have it pick up the executable path as being within WebKit.app
+ char **processPath = _CFGetProcessPath();
+ *processPath = NULL;
+ setenv("CFProcessPath", webKitAppPath, 1);
+ _CFGetProcessPath();
+ unsetenv("CFProcessPath");
+ } else {
+ if (!_RegisterApplication)
+ return;
+
+ // Register the application with LaunchServices, passing a customized registration dictionary that
+ // uses the WebKit launcher as the application bundle.
+ NSBundle *bundle = webKitLauncherBundle();
+ NSMutableDictionary *checkInDictionary = [[bundle infoDictionary] mutableCopy];
+ [checkInDictionary setObject:[bundle bundlePath] forKey:@"LSBundlePath"];
+ [checkInDictionary setObject:[checkInDictionary objectForKey:(NSString *)kCFBundleNameKey] forKey:@"LSDisplayName"];
+ _RegisterApplication((CFDictionaryRef)checkInDictionary, 0);
+ [checkInDictionary release];
+ }
+}
+
+static BOOL insideSafari4OnTigerTrampoline()
+{
+ // If we're not on Tiger then we can't be in the trampoline state.
+ if ((systemVersion() & 0xFFF0) != 0x1040)
+ return NO;
+
+ // If we're running Safari < 4.0 then we can't be in the trampoline state.
+ CFBundleRef safariBundle = CFBundleGetMainBundle();
+ CFStringRef safariVersion = CFBundleGetValueForInfoDictionaryKey(safariBundle, CFSTR("CFBundleShortVersionString"));
+ if ([(NSString *)safariVersion intValue] < 4)
+ return NO;
+
+ const char* frameworkPath = getenv("DYLD_FRAMEWORK_PATH");
+ if (!frameworkPath)
+ frameworkPath = "";
+
+ // If the framework search path is empty or otherwise does not contain the Safari
+ // framework's Frameworks directory then we are in the trampoline state.
+ const char safariFrameworkSearchPath[] = "/System/Library/PrivateFrameworks/Safari.framework/Frameworks";
+ return strstr(frameworkPath, safariFrameworkSearchPath) == 0;
+}
+
+static void enableWebKitNightlyBehaviour()
+{
+ // If we're inside Safari in its trampoline state, it will very shortly relaunch itself.
+ // We bail out here so that we'll be called again in the freshly-launched Safari process.
+ if (insideSafari4OnTigerTrampoline())
+ return;
+
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ unsetenv("DYLD_INSERT_LIBRARIES");
+ poseAsWebKitApp();
+
+ extensionPaths = [[NSSet alloc] initWithObjects:@"~/Library/InputManagers/", @"/Library/InputManagers/",
+ @"~/Library/Application Support/SIMBL/Plugins/", @"/Library/Application Support/SIMBL/Plugins/",
+ @"~/Library/Application Enhancers/", @"/Library/Application Enhancers/",
+ nil];
+
+ // As of 2008-11 attempting to load Saft would cause a crash on launch, so prevent it from being loaded.
+ NSArray *disabledInputManagers = [NSArray arrayWithObjects:@"Saft", nil];
+
+ NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
+ NSDictionary *defaultPrefs = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:RunStateShutDown], WKNERunState,
+ [NSNumber numberWithBool:YES], WKNEShouldMonitorShutdowns,
+ disabledInputManagers, @"NSDisabledInputManagers", nil];
+ [userDefaults registerDefaults:defaultPrefs];
+ if ([userDefaults boolForKey:WKNEShouldMonitorShutdowns]) {
+ WKNERunStates savedState = (WKNERunStates)[userDefaults integerForKey:WKNERunState];
+ if (savedState == RunStateInitializing) {
+ // Use CoreFoundation here as AppKit hasn't been initialized at this stage of Safari's lifetime
+ CFOptionFlags responseFlags;
+ CFUserNotificationDisplayAlert(0, kCFUserNotificationCautionAlertLevel,
+ NULL, NULL, NULL,
+ CFSTR("WebKit failed to open correctly"),
+ CFSTR("WebKit failed to open correctly on your previous attempt. Please disable any Safari extensions that you may have installed. If the problem continues to occur, please file a bug report at http://webkit.org/quality/reporting.html"),
+ CFSTR("Continue"), NULL, NULL, &responseFlags);
+ }
+ else if (savedState == RunStateRunning) {
+ NSLog(@"WebKit failed to shut down cleanly. Checking for Safari extensions.");
+ CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), &myBundleDidLoad,
+ myBundleDidLoad, (CFStringRef) NSBundleDidLoadNotification,
+ NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
+ }
+ }
+ [userDefaults setInteger:RunStateInitializing forKey:WKNERunState];
+ [userDefaults synchronize];
+
+ CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), &myApplicationWillFinishLaunching,
+ myApplicationWillFinishLaunching, (CFStringRef) NSApplicationWillFinishLaunchingNotification,
+ NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
+ CFNotificationCenterAddObserver(CFNotificationCenterGetLocalCenter(), &myApplicationWillTerminate,
+ myApplicationWillTerminate, (CFStringRef) NSApplicationWillTerminateNotification,
+ NULL, CFNotificationSuspensionBehaviorDeliverImmediately);
+
+ NSLog(@"WebKit %@ initialized.", [webKitLauncherBundle() objectForInfoDictionaryKey:@"CFBundleShortVersionString"]);
+
+ [pool release];
+}
diff --git a/Tools/WebKitLauncher/WebKitNightlyEnablerSparkle.h b/Tools/WebKitLauncher/WebKitNightlyEnablerSparkle.h
new file mode 100644
index 0000000..7ff4fef
--- /dev/null
+++ b/Tools/WebKitLauncher/WebKitNightlyEnablerSparkle.h
@@ -0,0 +1,30 @@
+/*
+ * 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.
+ */
+#ifndef WebKitNightlyEnablerSparkle_h
+#define WebKitNightlyEnablerSparkle_h
+
+extern void initializeSparkle();
+
+#endif // WebKitNightlyEnablerSparkle_h
diff --git a/Tools/WebKitLauncher/WebKitNightlyEnablerSparkle.m b/Tools/WebKitLauncher/WebKitNightlyEnablerSparkle.m
new file mode 100644
index 0000000..8b13ab8
--- /dev/null
+++ b/Tools/WebKitLauncher/WebKitNightlyEnablerSparkle.m
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ */
+
+#if !ENABLE_SPARKLE
+
+void initializeSparkle()
+{
+ // No-op.
+}
+
+#else // ENABLE_SPARKLE
+
+#import <Cocoa/Cocoa.h>
+#import <Sparkle/SUUpdater.h>
+#import <objc/objc-runtime.h>
+#import "WebKitNightlyEnabler.h"
+
+// We need to tweak the wording of the prompt to make sense in the context of WebKit and Safari.
+static NSString* updatePermissionPromptDescription(id self, SEL _cmd)
+{
+ return @"Should WebKit automatically check for updates? You can always check for updates manually from the Safari menu.";
+}
+
+static NSPanel *updateAlertPanel(id updateItem, id host)
+{
+ NSString *hostName = objc_msgSend(host, @selector(name));
+ NSPanel *panel = NSGetInformationalAlertPanel([NSString stringWithFormat:@"Would you like to download and install %@ %@ now?", hostName, objc_msgSend(updateItem, @selector(displayVersionString))],
+ [NSString stringWithFormat:@"You are currently running %@ %@.", hostName, objc_msgSend(host, @selector(displayVersion))],
+ @"Install Update", @"Skip This Version", @"Remind Me Later");
+ NSArray *subviews = [[panel contentView] subviews];
+ NSEnumerator *e = [subviews objectEnumerator];
+ NSView *view;
+ while ((view = [e nextObject])) {
+ if (![view isKindOfClass:[NSButton class]])
+ continue;
+
+ NSButton *button = (NSButton *)view;
+ [button setAction:@selector(webKitHandleButtonPress:)];
+ if ([button tag] == NSAlertOtherReturn)
+ [button setKeyEquivalent:@"\033"];
+ }
+ [panel center];
+ return panel;
+}
+
+// Sparkle's udpate alert panel looks odd with the release notes hidden, so we
+// swap it out with a standard NSAlert-style panel instead.
+static id updateAlertInitForAlertPanel(id self, SEL _cmd, id updateItem, id host)
+{
+ NSPanel *panel = updateAlertPanel(updateItem, host);
+ [panel setDelegate:self];
+
+ self = [self initWithWindow:panel];
+ if (!self)
+ return nil;
+
+ [updateItem retain];
+ [host retain];
+
+ object_setInstanceVariable(self, "updateItem", (void*)updateItem);
+ object_setInstanceVariable(self, "host", (void*)host);
+
+ [self setShouldCascadeWindows:NO];
+
+ return self;
+}
+
+@implementation NSAlert (WebKitLauncherExtensions)
+
+- (void)webKitHandleButtonPress:(id)sender
+{
+ // We rely on the fact that NSAlertOtherReturn == -1, NSAlertAlternateReturn == 0 and NSAlertDefaultReturn == 1
+ // to map the button tag to the corresponding selector
+ SEL selectors[] = { @selector(remindMeLater:), @selector(skipThisVersion:), @selector(installUpdate:) };
+ SEL selector = selectors[[sender tag] + 1];
+
+ id delegate = [[sender window] delegate];
+ objc_msgSend(delegate, selector, sender);
+}
+
+@end
+
+#if __LP64__
+
+#define setMethodImplementation method_setImplementation
+
+#else
+
+static void setMethodImplementation(Method m, IMP imp)
+{
+ m->method_imp = imp;
+}
+
+#endif
+
+static NSString *userAgentStringForSparkle()
+{
+ NSBundle *safariBundle = [NSBundle mainBundle];
+ NSString *safariVersion = [[safariBundle localizedInfoDictionary] valueForKey:@"CFBundleShortVersionString"];
+ NSString *safariBuild = [[[safariBundle infoDictionary] valueForKey:(NSString *)kCFBundleVersionKey] substringFromIndex:1];
+ NSString *webKitRevision = [[webKitLauncherBundle() infoDictionary] valueForKey:(NSString *)kCFBundleVersionKey];
+ NSString *applicationName = [NSString stringWithFormat:@"Version/%@ Safari/%@ WebKitRevision/%@", safariVersion, safariBuild, webKitRevision];
+ Class WebView = objc_lookUpClass("WebView");
+ return objc_msgSend(WebView, @selector(_standardUserAgentWithApplicationName:), applicationName);
+}
+
+void initializeSparkle()
+{
+ // Override some Sparkle behaviour
+ Method methodToPatch = class_getInstanceMethod(objc_getRequiredClass("SUUpdatePermissionPrompt"), @selector(promptDescription));
+ setMethodImplementation(methodToPatch, (IMP)updatePermissionPromptDescription);
+
+ methodToPatch = class_getInstanceMethod(objc_getRequiredClass("SUUpdateAlert"), @selector(initWithAppcastItem:host:));
+ setMethodImplementation(methodToPatch, (IMP)updateAlertInitForAlertPanel);
+
+ SUUpdater *updater = [SUUpdater updaterForBundle:webKitLauncherBundle()];
+ [updater setUserAgentString:userAgentStringForSparkle()];
+
+ // Find the first separator on the Safari menu…
+ NSMenu *applicationSubmenu = [[[NSApp mainMenu] itemAtIndex:0] submenu];
+ int i = 0;
+ for (; i < [applicationSubmenu numberOfItems]; i++) {
+ if ([[applicationSubmenu itemAtIndex:i] isSeparatorItem])
+ break;
+ }
+
+ // … and insert a menu item that can be used to manually trigger update checks.
+ NSMenuItem *updateMenuItem = [[NSMenuItem alloc] initWithTitle:@"Check for WebKit Updates…" action:@selector(checkForUpdates:) keyEquivalent:@""];
+ [updateMenuItem setTarget:updater];
+ [applicationSubmenu insertItem:updateMenuItem atIndex:i];
+ [updateMenuItem release];
+}
+
+#endif // ENABLE_SPARKLE
diff --git a/Tools/WebKitLauncher/main.m b/Tools/WebKitLauncher/main.m
new file mode 100644
index 0000000..4fee68a
--- /dev/null
+++ b/Tools/WebKitLauncher/main.m
@@ -0,0 +1,248 @@
+/*
+ * Copyright (C) 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 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 <CoreFoundation/CoreFoundation.h>
+
+// We need to weak-import posix_spawn and friends as they're not available on Tiger.
+// The BSD-level system headers do not have availability macros, so we redeclare the
+// functions ourselves with the "weak" attribute.
+
+#define WEAK_IMPORT __attribute__((weak))
+
+#define POSIX_SPAWN_SETEXEC 0x0040
+typedef void *posix_spawnattr_t;
+typedef void *posix_spawn_file_actions_t;
+int posix_spawnattr_init(posix_spawnattr_t *) WEAK_IMPORT;
+int posix_spawn(pid_t * __restrict, const char * __restrict, const posix_spawn_file_actions_t *, const posix_spawnattr_t * __restrict, char *const __argv[ __restrict], char *const __envp[ __restrict]) WEAK_IMPORT;
+int posix_spawnattr_setbinpref_np(posix_spawnattr_t * __restrict, size_t, cpu_type_t *__restrict, size_t *__restrict) WEAK_IMPORT;
+int posix_spawnattr_setflags(posix_spawnattr_t *, short) WEAK_IMPORT;
+
+
+static void displayErrorAndQuit(NSString *title, NSString *message)
+{
+ NSApplicationLoad();
+ NSRunCriticalAlertPanel(title, message, @"Quit", nil, nil);
+ exit(0);
+}
+
+static int getLastVersionShown()
+{
+ [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObject:@"-1" forKey:@"StartPageShownInVersion"]];
+ return [[NSUserDefaults standardUserDefaults] integerForKey:@"StartPageShownInVersion"];
+}
+
+static void saveLastVersionShown(int lastVersion)
+{
+ [[NSUserDefaults standardUserDefaults] setInteger:lastVersion forKey:@"StartPageShownInVersion"];
+ [[NSUserDefaults standardUserDefaults] synchronize];
+}
+
+static NSString *getPathForStartPage()
+{
+ return [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"start.html"];
+}
+
+static int getCurrentVersion()
+{
+ return [[[[NSBundle mainBundle] infoDictionary] valueForKey:(NSString *)kCFBundleVersionKey] intValue];
+}
+
+static int getShowStartPageVersion()
+{
+ return getCurrentVersion() + 1;
+}
+
+static BOOL startPageDisabled()
+{
+ return [[NSUserDefaults standardUserDefaults] boolForKey:@"StartPageDisabled"];
+}
+
+static void addStartPageToArgumentsIfNeeded(NSMutableArray *arguments)
+{
+ if (startPageDisabled())
+ return;
+
+ if (getLastVersionShown() < getShowStartPageVersion()) {
+ saveLastVersionShown(getCurrentVersion());
+ NSString *startPagePath = getPathForStartPage();
+ if (startPagePath)
+ [arguments addObject:startPagePath];
+ }
+}
+
+static cpu_type_t preferredArchitecture()
+{
+#if defined(__ppc__)
+ return CPU_TYPE_POWERPC;
+#elif defined(__LP64__)
+ return CPU_TYPE_X86_64;
+#else
+ return CPU_TYPE_X86;
+#endif
+}
+
+static void myExecve(NSString *executable, NSArray *args, NSDictionary *environment)
+{
+ char **argv = (char **)calloc(sizeof(char *), [args count] + 1);
+ char **env = (char **)calloc(sizeof(char *), [environment count] + 1);
+
+ NSEnumerator *e = [args objectEnumerator];
+ NSString *s;
+ int i = 0;
+ while ((s = [e nextObject]))
+ argv[i++] = (char *) [s UTF8String];
+
+ e = [environment keyEnumerator];
+ i = 0;
+ while ((s = [e nextObject]))
+ env[i++] = (char *) [[NSString stringWithFormat:@"%@=%@", s, [environment objectForKey:s]] UTF8String];
+
+ if (posix_spawnattr_init && posix_spawn && posix_spawnattr_setbinpref_np && posix_spawnattr_setflags) {
+ posix_spawnattr_t attr;
+ posix_spawnattr_init(&attr);
+ cpu_type_t architecturePreference[] = { preferredArchitecture(), CPU_TYPE_X86 };
+ posix_spawnattr_setbinpref_np(&attr, 2, architecturePreference, 0);
+ short flags = POSIX_SPAWN_SETEXEC;
+ posix_spawnattr_setflags(&attr, flags);
+ posix_spawn(NULL, [executable fileSystemRepresentation], NULL, &attr, argv, env);
+ } else
+ execve([executable fileSystemRepresentation], argv, env);
+}
+
+static NSBundle *locateSafariBundle()
+{
+ NSArray *applicationDirectories = NSSearchPathForDirectoriesInDomains(NSApplicationDirectory, NSAllDomainsMask, YES);
+ NSEnumerator *e = [applicationDirectories objectEnumerator];
+ NSString *applicationDirectory;
+ while ((applicationDirectory = [e nextObject])) {
+ NSString *possibleSafariPath = [applicationDirectory stringByAppendingPathComponent:@"Safari.app"];
+ NSBundle *possibleSafariBundle = [NSBundle bundleWithPath:possibleSafariPath];
+ if ([[possibleSafariBundle bundleIdentifier] isEqualToString:@"com.apple.Safari"])
+ return possibleSafariBundle;
+ }
+
+ CFURLRef safariURL = nil;
+ OSStatus err = LSFindApplicationForInfo(kLSUnknownCreator, CFSTR("com.apple.Safari"), nil, nil, &safariURL);
+ if (err != noErr)
+ displayErrorAndQuit(@"Unable to locate Safari", @"Nightly builds of WebKit require Safari to run. Please check that it is available and then try again.");
+
+ NSBundle *safariBundle = [NSBundle bundleWithPath:[(NSURL *)safariURL path]];
+ CFRelease(safariURL);
+ return safariBundle;
+}
+
+static NSString *currentMacOSXVersion()
+{
+ SInt32 version;
+ if (Gestalt(gestaltSystemVersion, &version) != noErr)
+ return @"10.4";
+
+ return [NSString stringWithFormat:@"%x.%x", (version & 0xFF00) >> 8, (version & 0x00F0) >> 4];
+}
+
+static NSString *fallbackMacOSXVersion(NSString *systemVersion)
+{
+ NSDictionary *fallbackVersionMap = [[NSUserDefaults standardUserDefaults] dictionaryForKey:@"FallbackSystemVersions"];
+ if (!fallbackVersionMap)
+ return nil;
+ NSString *fallbackSystemVersion = [fallbackVersionMap objectForKey:systemVersion];
+ if (!fallbackSystemVersion || ![fallbackSystemVersion isKindOfClass:[NSString class]])
+ return nil;
+ return fallbackSystemVersion;
+}
+
+static BOOL checkFrameworkPath(NSString *frameworkPath)
+{
+ BOOL isDirectory = NO;
+ return [[NSFileManager defaultManager] fileExistsAtPath:frameworkPath isDirectory:&isDirectory] && isDirectory;
+}
+
+static BOOL checkSafariVersion(NSBundle *safariBundle)
+{
+ NSString *safariBundleVersion = [[safariBundle infoDictionary] objectForKey:(NSString *)kCFBundleVersionKey];
+ NSString *majorComponent = [[safariBundleVersion componentsSeparatedByString:@"."] objectAtIndex:0];
+ NSString *majorVersion = [majorComponent substringFromIndex:[majorComponent length] - 3];
+ return [majorVersion intValue] >= 530;
+}
+
+int main(int argc, char *argv[])
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+
+ NSString *systemVersion = currentMacOSXVersion();
+ NSString *frameworkPath = [[[NSBundle mainBundle] privateFrameworksPath] stringByAppendingPathComponent:systemVersion];
+
+ BOOL frameworkPathIsUsable = checkFrameworkPath(frameworkPath);
+
+ if (!frameworkPathIsUsable) {
+ NSString *fallbackSystemVersion = fallbackMacOSXVersion(systemVersion);
+ if (fallbackSystemVersion) {
+ frameworkPath = [[[NSBundle mainBundle] privateFrameworksPath] stringByAppendingPathComponent:fallbackSystemVersion];
+ frameworkPathIsUsable = checkFrameworkPath(frameworkPath);
+ }
+ }
+
+ if (!frameworkPathIsUsable)
+ displayErrorAndQuit([NSString stringWithFormat:@"Mac OS X %@ is not supported", systemVersion],
+ [NSString stringWithFormat:@"Nightly builds of WebKit are not supported on Mac OS X %@ at this time.", systemVersion]);
+
+ NSString *pathToEnablerLib = [[NSBundle mainBundle] pathForResource:@"WebKitNightlyEnabler" ofType:@"dylib"];
+
+ NSBundle *safariBundle = locateSafariBundle();
+ NSString *executablePath = [safariBundle executablePath];
+
+ if (!checkSafariVersion(safariBundle)) {
+ NSString *safariVersion = [[safariBundle localizedInfoDictionary] objectForKey:@"CFBundleShortVersionString"];
+ displayErrorAndQuit([NSString stringWithFormat:@"Safari %@ is not supported", safariVersion],
+ [NSString stringWithFormat:@"Nightly builds of WebKit are not supported with Safari %@ at this time. Please update to a newer version of Safari.", safariVersion]);
+ }
+
+ if ([frameworkPath rangeOfString:@":"].location != NSNotFound ||
+ [pathToEnablerLib rangeOfString:@":"].location != NSNotFound)
+ displayErrorAndQuit(@"Unable to launch Safari",
+ @"WebKit is located at a path containing an unsupported character. Please move WebKit to a different location and try again.");
+
+ NSMutableArray *arguments = [NSMutableArray arrayWithObject:executablePath];
+ NSMutableDictionary *environment = [[[NSDictionary dictionaryWithObjectsAndKeys:frameworkPath, @"DYLD_FRAMEWORK_PATH", @"YES", @"WEBKIT_UNSET_DYLD_FRAMEWORK_PATH",
+ pathToEnablerLib, @"DYLD_INSERT_LIBRARIES", [[NSBundle mainBundle] executablePath], @"WebKitAppPath", nil] mutableCopy] autorelease];
+ [environment addEntriesFromDictionary:[[NSProcessInfo processInfo] environment]];
+ addStartPageToArgumentsIfNeeded(arguments);
+
+ while (*++argv)
+ [arguments addObject:[NSString stringWithUTF8String:*argv]];
+
+ myExecve(executablePath, arguments, environment);
+
+ char *error = strerror(errno);
+ NSString *errorMessage = [NSString stringWithFormat:@"Launching Safari at %@ failed with the error '%s' (%d)", [safariBundle bundlePath], error, errno];
+ displayErrorAndQuit(@"Unable to launch Safari", errorMessage);
+
+ [pool release];
+ return 0;
+}
diff --git a/Tools/WebKitLauncher/nightly.webkit.org.public.pem b/Tools/WebKitLauncher/nightly.webkit.org.public.pem
new file mode 100644
index 0000000..174c1e4
--- /dev/null
+++ b/Tools/WebKitLauncher/nightly.webkit.org.public.pem
@@ -0,0 +1,20 @@
+-----BEGIN PUBLIC KEY-----
+MIIDOjCCAi0GByqGSM44BAEwggIgAoIBAQCkQLoVjuu3dPn1dO8N6xIFf4riPVuJ
+XOVpx+QlFMno+qzqGJcJxqhfqZhIRwLq62eHpeuYKIuuPG8fqXY/hquHQIjrtEFZ
+euCW8cxqC7iBg3PlX6RsKUXHD+WY82HJ5Hdkd+5G3jD9qO+Ka7RXgOnL7fTRcbkW
+rtBjL7lVAlMBSVG54+zvti/h1CmdfpO83JAnoGl8c+WGgKlwt5nR7jxp4PgBdAw2
+aJt+UqrMkZOr4Npik1a8IzW+KTlBn96DbF5M6PP6Uh9TblnYtt0ic/Vnr6MKS60X
+WNCb/2/HFjQYaINYtJfXpBaGUMZ0dsAyMxn/Sf1vApmVWh2t0TRMgI4JAhUAtL7E
+pauM+spqaZnAxcMNMP0uFaECggEAe1lF6yZHJh89QdPQvmwROKFHOXYvEX5/IFRw
+pFJDdJJdw53nS/yXWKy8o/wBqESzeVCbktYRqQE84ApO/KJs4KdwiL2LU32FiMD0
+c4UCkRf/RxSLxE4/FGKQzTaBB5TGMfuNLn6C/4aoNXnxcB399QxKF2slBp1GQgsC
+6/4KZZYN+kxGxqAfA1UqrleVtv9OwmaCJwMYYqq20zxYhryuBjTSAD+VN6ncerUf
+IxUceX83mWriBMtXHHR0x12WUDfnFQZg583MeMguFc8qESqZX7mWtzSnblsGmez3
+pD028APHFWJSdruT2YI1NJf08S7A9GLdkLRaUNQTABygANviQwOCAQUAAoIBAGDn
+SFRJ3o/wKBm1PwQyaMfE8dtFt1NVOqTA2/VL3CVfqPV6tizRSvto45HSBn96R6nC
+cxZCi3knJy/9V9ITtlCw1UtqeYOW7sp0PRAgct93XuzlMpOFQr5Q8jydvqMEymOD
+c55QE2vbSgHYbQH362uNXsyMWN1xRVSlT13MBi+fmZ86Z5CkRWvIPWg2NRO16bnx
+jK6l0LGvBKiU79HIrH7DlEfX0zVJBYi6NnJqvFSDeoKyiOMWaCAquWDgu00k3NOl
+gndPnl+mVzEEgNvvN0H6KGVTf55H7KR1LqtWFWCw0VXy5oFgRB359hrLvxe91U4M
+iN3jD7YxuENTOTefu9c=
+-----END PUBLIC KEY-----
diff --git a/Tools/WebKitLauncher/start.html b/Tools/WebKitLauncher/start.html
new file mode 100644
index 0000000..2c94e79
--- /dev/null
+++ b/Tools/WebKitLauncher/start.html
@@ -0,0 +1,33 @@
+<html>
+ <head>
+ <title>Loading WebKit...</title>
+ <meta http-equiv="refresh" content="1;URL=http://nightly.webkit.org/start/" />
+ <script type="text/javascript">
+ function getWebKitRevision()
+ {
+ var request = new XMLHttpRequest();
+ request.open("GET", "VERSION", false);
+ request.send();
+ var revision = parseInt(request.responseText);
+ if (isNaN(revision))
+ return "";
+
+ return revision;
+ }
+
+ function getWebKitBranch()
+ {
+ var request = new XMLHttpRequest();
+ request.open("GET", "BRANCH", false);
+ request.send();
+ return (request.responseText || "trunk").replace(/\s/g, '')
+ }
+
+ var revision = getWebKitRevision();
+ var branch = getWebKitBranch();
+ document.location = "http://nightly.webkit.org/start/" + branch + "/" + revision;
+ </script>
+ </head>
+ <body>
+ </body>
+</html>
diff --git a/Tools/WebKitLauncher/webkit.icns b/Tools/WebKitLauncher/webkit.icns
new file mode 100644
index 0000000..b1e1017
--- /dev/null
+++ b/Tools/WebKitLauncher/webkit.icns
Binary files differ
diff --git a/Tools/WebKitLauncherWin/Resource.h b/Tools/WebKitLauncherWin/Resource.h
new file mode 100644
index 0000000..f0c38ab
--- /dev/null
+++ b/Tools/WebKitLauncherWin/Resource.h
@@ -0,0 +1,19 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by WebKitLauncherWin.rc
+//
+
+#define IDI_WEBKITLAUNCHERWIN 107
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+
+#define _APS_NO_MFC 130
+#define _APS_NEXT_RESOURCE_VALUE 129
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
diff --git a/Tools/WebKitLauncherWin/WebKitLauncherWin.cpp b/Tools/WebKitLauncherWin/WebKitLauncherWin.cpp
new file mode 100644
index 0000000..f59050d
--- /dev/null
+++ b/Tools/WebKitLauncherWin/WebKitLauncherWin.cpp
@@ -0,0 +1,95 @@
+/*
+ * 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 "resource.h"
+#include <shlwapi.h>
+#include <tchar.h>
+#include <windows.h>
+
+static LPTSTR getStringValue(HKEY key, LPCTSTR valueName)
+{
+ DWORD type = 0;
+ DWORD bufferSize = 0;
+ if (RegQueryValueEx(key, valueName, 0, &type, 0, &bufferSize) != ERROR_SUCCESS || type != REG_SZ)
+ return 0;
+
+ LPTSTR buffer = static_cast<LPTSTR>(malloc(bufferSize));
+ if (RegQueryValueEx(key, valueName, 0, &type, reinterpret_cast<LPBYTE>(buffer), &bufferSize) != ERROR_SUCCESS) {
+ free(buffer);
+ return 0;
+ }
+
+ return buffer;
+}
+
+static LPTSTR applePathFromRegistry(LPCTSTR key, LPCTSTR value)
+{
+ HKEY applePathKey = 0;
+ LONG error = RegOpenKeyEx(HKEY_LOCAL_MACHINE, key, 0, KEY_READ, &applePathKey);
+ if (error != ERROR_SUCCESS)
+ return 0;
+ LPTSTR path = getStringValue(applePathKey, value);
+ RegCloseKey(applePathKey);
+ return path;
+}
+
+static LPTSTR safariInstallDir()
+{
+ return applePathFromRegistry(TEXT("SOFTWARE\\Apple Computer, Inc.\\Safari"), TEXT("InstallDir"));
+}
+
+static LPTSTR safariBrowserExe()
+{
+ return applePathFromRegistry(TEXT("SOFTWARE\\Apple Computer, Inc.\\Safari"), TEXT("BrowserExe"));
+}
+
+int APIENTRY _tWinMain(HINSTANCE instance, HINSTANCE, LPTSTR commandLine, int)
+{
+ LPTSTR path = safariInstallDir();
+ LPTSTR browserExe = safariBrowserExe();
+ if (!path || !browserExe) {
+ MessageBox(0, TEXT("Safari must be installed to run a WebKit nightly. You can download Safari from http://www.apple.com/safari/download"), TEXT("Safari not found"), MB_ICONSTOP);
+ return 1;
+ }
+
+ // Set WEBKITNIGHTLY environment variable to point to the nightly bits
+ TCHAR exePath[MAX_PATH];
+ if (!GetModuleFileName(0, exePath, ARRAYSIZE(exePath)))
+ return 1;
+ if (!PathRemoveFileSpec(exePath))
+ return 1;
+ SetEnvironmentVariable(TEXT("WEBKITNIGHTLY"), exePath);
+
+ // Launch Safari as a child process
+ STARTUPINFO startupInfo = {0};
+ startupInfo.cb = sizeof(startupInfo);
+ PROCESS_INFORMATION processInfo = {0};
+ if (!CreateProcess(browserExe, commandLine, 0, 0, FALSE, NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT, 0, path, &startupInfo, &processInfo))
+ MessageBox(0, TEXT("Safari could not be launched. Please make sure you have the latest version of Safari installed and try again. You can download Safari from http://www.apple.com/safari/download"), TEXT("Safari launch failed"), MB_ICONSTOP);
+
+ free(browserExe);
+ free(path);
+ return 0;
+}
diff --git a/Tools/WebKitLauncherWin/WebKitLauncherWin.rc b/Tools/WebKitLauncherWin/WebKitLauncherWin.rc
new file mode 100644
index 0000000..65a2dfa
--- /dev/null
+++ b/Tools/WebKitLauncherWin/WebKitLauncherWin.rc
@@ -0,0 +1,70 @@
+//Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)
+LANGUAGE 9, 1
+#pragma code_page(1252)
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+
+IDI_WEBKITLAUNCHERWIN ICON "webkit.ico"
+
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+#endif
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
diff --git a/Tools/WebKitLauncherWin/WebKitLauncherWin.vcproj b/Tools/WebKitLauncherWin/WebKitLauncherWin.vcproj
new file mode 100644
index 0000000..f0038e6
--- /dev/null
+++ b/Tools/WebKitLauncherWin/WebKitLauncherWin.vcproj
@@ -0,0 +1,426 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="WebKitLauncherWin"
+ ProjectGUID="{D09806DB-E58B-4646-8C9B-61101906C1E2}"
+ RootNamespace="WebKitLauncherWin"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\WebKitLauncherWinCommon.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_LTCG|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\WebKitLauncherWinCommon.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="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\WebKitLauncherWinCommon.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\WebKitLauncherWinCommon.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="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;.\WebKitLauncherWinCommon.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;.\WebKitLauncherWinCommon.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="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\WebKitLauncherWin.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\Resource.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\webkit.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\WebKitLauncherWin.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/WebKitLauncherWin/WebKitLauncherWinCommon.vsprops b/Tools/WebKitLauncherWin/WebKitLauncherWinCommon.vsprops
new file mode 100644
index 0000000..9b6419c
--- /dev/null
+++ b/Tools/WebKitLauncherWin/WebKitLauncherWinCommon.vsprops
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="WebKitLauncherWinCommon"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="shlwapi.lib"
+ OutputFile="$(OutDir)\WebKit$(WebKitConfigSuffix).exe"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/WebKitLauncherWin/webkit.ico b/Tools/WebKitLauncherWin/webkit.ico
new file mode 100644
index 0000000..b86c9bb
--- /dev/null
+++ b/Tools/WebKitLauncherWin/webkit.ico
Binary files differ
diff --git a/Tools/WebKitTestRunner/Configurations/Base.xcconfig b/Tools/WebKitTestRunner/Configurations/Base.xcconfig
new file mode 100644
index 0000000..feb7c5e
--- /dev/null
+++ b/Tools/WebKitTestRunner/Configurations/Base.xcconfig
@@ -0,0 +1,72 @@
+// 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.
+
+HEADER_SEARCH_PATHS = $(WEBCORE_PRIVATE_HEADERS_DIR)/ForwardingHeaders;
+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_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;
+VALID_ARCHS = i386 x86_64;
+
+
+TARGET_MAC_OS_X_VERSION_MAJOR = $(MAC_OS_X_VERSION_MAJOR);
+
+
+// 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_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+TARGET_GCC_VERSION_ = $(TARGET_GCC_VERSION_1040);
+TARGET_GCC_VERSION_1040 = GCC_40;
+TARGET_GCC_VERSION_1050 = $(TARGET_GCC_VERSION_1050_$(XCODE_VERSION_MINOR));
+TARGET_GCC_VERSION_1050_ = $(TARGET_GCC_VERSION_1050_$(XCODE_VERSION_ACTUAL));
+TARGET_GCC_VERSION_1050_0310 = GCC_42;
+TARGET_GCC_VERSION_1050_0320 = GCC_42;
+TARGET_GCC_VERSION_1060 = GCC_42;
+TARGET_GCC_VERSION_1070 = LLVM_GCC_42;
+
+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;
+
+// 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_1050_1040 = macosx10.4;
+SDKROOT_1060_1040 = macosx10.4;
+SDKROOT_1060_1050 = macosx10.5;
+SDKROOT_1070_1040 = macosx10.4;
+SDKROOT_1070_1050 = macosx10.5;
+SDKROOT_1070_1060 = macosx10.6;
+
+WEBKIT_UMBRELLA_FRAMEWORKS_DIR = $(NEXT_ROOT)$(SYSTEM_LIBRARY_DIR)/Frameworks/WebKit.framework/Versions/A/Frameworks;
+WEBCORE_PRIVATE_HEADERS_DIR = $(WEBKIT_UMBRELLA_FRAMEWORKS_DIR)/WebCore.framework/PrivateHeaders;
diff --git a/Tools/WebKitTestRunner/Configurations/DebugRelease.xcconfig b/Tools/WebKitTestRunner/Configurations/DebugRelease.xcconfig
new file mode 100644
index 0000000..41600b1
--- /dev/null
+++ b/Tools/WebKitTestRunner/Configurations/DebugRelease.xcconfig
@@ -0,0 +1,42 @@
+// 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 "Base.xcconfig"
+
+ARCHS = $(ARCHS_$(TARGET_MAC_OS_X_VERSION_MAJOR));
+ARCHS_ = $(ARCHS_1040);
+ARCHS_1040 = $(NATIVE_ARCH);
+ARCHS_1050 = $(NATIVE_ARCH);
+ARCHS_1060 = $(ARCHS_STANDARD_32_64_BIT);
+ARCHS_1070 = $(ARCHS_STANDARD_32_64_BIT);
+
+ONLY_ACTIVE_ARCH = YES;
+
+MACOSX_DEPLOYMENT_TARGET = $(MACOSX_DEPLOYMENT_TARGET_$(TARGET_MAC_OS_X_VERSION_MAJOR))
+MACOSX_DEPLOYMENT_TARGET_ = 10.4;
+MACOSX_DEPLOYMENT_TARGET_1040 = 10.4;
+MACOSX_DEPLOYMENT_TARGET_1050 = 10.5;
+MACOSX_DEPLOYMENT_TARGET_1060 = 10.6;
+MACOSX_DEPLOYMENT_TARGET_1070 = 10.7;
+
+WEBKIT_UMBRELLA_FRAMEWORKS_DIR = $(BUILT_PRODUCTS_DIR);
diff --git a/Tools/WebKitTestRunner/Configurations/InjectedBundle.xcconfig b/Tools/WebKitTestRunner/Configurations/InjectedBundle.xcconfig
new file mode 100644
index 0000000..dcf4be0
--- /dev/null
+++ b/Tools/WebKitTestRunner/Configurations/InjectedBundle.xcconfig
@@ -0,0 +1,24 @@
+// 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.
+
+PRODUCT_NAME = WebKitTestRunnerInjectedBundle
diff --git a/Tools/WebKitTestRunner/Configurations/InjectedBundleCFLite.vsprops b/Tools/WebKitTestRunner/Configurations/InjectedBundleCFLite.vsprops
new file mode 100644
index 0000000..094599f
--- /dev/null
+++ b/Tools/WebKitTestRunner/Configurations/InjectedBundleCFLite.vsprops
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="InjectedBundleCFLite"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib WebKit$(WebKitDLLConfigSuffix).lib CFLite$(LibraryConfigSuffix).lib"
+ OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix).dll"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/WebKitTestRunner/Configurations/InjectedBundleCommon.vsprops b/Tools/WebKitTestRunner/Configurations/InjectedBundleCommon.vsprops
new file mode 100644
index 0000000..540fc7a
--- /dev/null
+++ b/Tools/WebKitTestRunner/Configurations/InjectedBundleCommon.vsprops
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="InjectedBundleCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)\..&quot;;&quot;$(ProjectDir)\..\InjectedBundle\&quot;;&quot;$(ProjectDir)\..\InjectedBundle\Bindings&quot;;&quot;$(WebKitOutputDir)\Include&quot;;&quot;$(WebKitOutputDir)\Include\private&quot;;&quot;$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders&quot;;&quot;$(WebKitLibrariesDir)\include&quot;;&quot;$(WebKitOutputDir)\obj\InjectedBundle\DerivedSources\&quot;"
+ ForcedIncludeFiles="WebKitTestRunnerPrefix.h"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/WebKitTestRunner/Configurations/InjectedBundleCoreFoundation.vsprops b/Tools/WebKitTestRunner/Configurations/InjectedBundleCoreFoundation.vsprops
new file mode 100644
index 0000000..d2addc6
--- /dev/null
+++ b/Tools/WebKitTestRunner/Configurations/InjectedBundleCoreFoundation.vsprops
@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="InjectedBundleCoreFoundation"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib WebKit$(WebKitDLLConfigSuffix).lib CoreFoundation$(LibraryConfigSuffix).lib"
+ OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix).dll"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/WebKitTestRunner/Configurations/WebKitTestRunner.xcconfig b/Tools/WebKitTestRunner/Configurations/WebKitTestRunner.xcconfig
new file mode 100644
index 0000000..e90edba
--- /dev/null
+++ b/Tools/WebKitTestRunner/Configurations/WebKitTestRunner.xcconfig
@@ -0,0 +1,26 @@
+// 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.
+
+PRODUCT_NAME = WebKitTestRunner
+GCC_ENABLE_OBJC_EXCEPTIONS = YES
+GCC_PREFIX_HEADER = WebKitTestRunnerPrefix.h
diff --git a/Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCFLite.vsprops b/Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCFLite.vsprops
new file mode 100644
index 0000000..a739f1d
--- /dev/null
+++ b/Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCFLite.vsprops
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="WebKitTestRunnerCFLite"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="CFLite$(LibraryConfigSuffix).lib"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCommon.vsprops b/Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCommon.vsprops
new file mode 100644
index 0000000..4233b55
--- /dev/null
+++ b/Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCommon.vsprops
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="WebKitTestRunnerCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(ProjectDir)\..&quot;;&quot;$(WebKitOutputDir)\Include&quot;;&quot;$(WebKitOutputDir)\Include\private&quot;;&quot;$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders&quot;;&quot;$(WebKitLibrariesDir)\Include&quot;"
+ PreprocessorDefinitions="__WIN32__;_CONSOLE"
+ DisableSpecificWarnings="4146"
+ ForcedIncludeFiles="WebKitTestRunnerPrefix.h"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalOptions="/NXCOMPAT"
+ AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib WebKit$(WebKitDLLConfigSuffix).lib shlwapi.lib"
+ SubSystem="1"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCoreFoundation.vsprops b/Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCoreFoundation.vsprops
new file mode 100644
index 0000000..11e031a
--- /dev/null
+++ b/Tools/WebKitTestRunner/Configurations/WebKitTestRunnerCoreFoundation.vsprops
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="WebKitTestRunnerCoreFoundation"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="CoreFoundation$(LibraryConfigSuffix).lib"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/WebKitTestRunner/DerivedSources.make b/Tools/WebKitTestRunner/DerivedSources.make
new file mode 100644
index 0000000..c308a8a
--- /dev/null
+++ b/Tools/WebKitTestRunner/DerivedSources.make
@@ -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.
+
+VPATH = \
+ $(WebKitTestRunner)/InjectedBundle/Bindings \
+#
+
+INTERFACES = \
+ EventSendingController \
+ GCController \
+ LayoutTestController \
+#
+
+SCRIPTS = \
+ $(WebCoreScripts)/CodeGenerator.pm \
+ $(WebKitTestRunner)/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm \
+ $(WebCoreScripts)/IDLParser.pm \
+ $(WebCoreScripts)/IDLStructure.pm \
+ $(WebCoreScripts)/generate-bindings.pl \
+#
+
+.PHONY : all
+
+JS%.h JS%.cpp : %.idl $(SCRIPTS)
+ @echo Generating bindings for $*...
+ @perl -I $(WebCoreScripts) -I $(WebKitTestRunner)/InjectedBundle/Bindings $(WebCoreScripts)/generate-bindings.pl --defines "" --include InjectedBundle/Bindings --outputDir . --generator TestRunner $<
+
+all : \
+ $(INTERFACES:%=JS%.h) \
+ $(INTERFACES:%=JS%.cpp) \
+#
diff --git a/Tools/WebKitTestRunner/DerivedSources.pro b/Tools/WebKitTestRunner/DerivedSources.pro
new file mode 100644
index 0000000..96f2a90
--- /dev/null
+++ b/Tools/WebKitTestRunner/DerivedSources.pro
@@ -0,0 +1,57 @@
+# DerivedSources - qmake build info
+
+CONFIG -= debug_and_release
+
+TEMPLATE = lib
+TARGET = dummy
+
+QMAKE_EXTRA_TARGETS += generated_files
+
+GENERATED_SOURCES_DIR = generated
+
+IDL_BINDINGS += \
+ InjectedBundle/Bindings/EventSendingController.idl \
+ InjectedBundle/Bindings/GCController.idl \
+ InjectedBundle/Bindings/LayoutTestController.idl \
+
+defineTest(addExtraCompiler) {
+ eval($${1}.CONFIG = target_predeps no_link)
+ eval($${1}.variable_out =)
+ eval($${1}.dependency_type = TYPE_C)
+
+ wkScript = $$eval($${1}.wkScript)
+ eval($${1}.depends += $$wkScript)
+
+ export($${1}.CONFIG)
+ export($${1}.variable_out)
+ export($${1}.dependency_type)
+ export($${1}.depends)
+
+ QMAKE_EXTRA_COMPILERS += $$1
+ generated_files.depends += compiler_$${1}_make_all
+ export(QMAKE_EXTRA_COMPILERS)
+ export(generated_files.depends)
+ return(true)
+}
+
+SRC_ROOT_DIR = $$replace(PWD, /Tools/WebKitTestRunner, /)
+
+# Make sure forwarded headers needed by this project are present
+fwheader_generator.commands = perl $${SRC_ROOT_DIR}/WebKit2/Scripts/generate-forwarding-headers.pl $${SRC_ROOT_DIR}/Tools/WebKitTestRunner $${OUTPUT_DIR}/include qt
+fwheader_generator.depends = $${SRC_ROOT_DIR}/WebKit2/Scripts/generate-forwarding-headers.pl
+generated_files.depends += fwheader_generator
+QMAKE_EXTRA_TARGETS += fwheader_generator
+
+# GENERATOR 1: IDL compiler
+idl.output = $${GENERATED_SOURCES_DIR}/JS${QMAKE_FILE_BASE}.cpp
+idl.input = IDL_BINDINGS
+idl.wkScript = $$PWD/../../WebCore/bindings/scripts/generate-bindings.pl
+idl.commands = perl -I$$PWD/../../WebCore/bindings/scripts -I$$PWD/InjectedBundle/Bindings $$idl.wkScript --defines \"\" --generator TestRunner --include $$PWD/InjectedBundle/Bindings --outputDir $$GENERATED_SOURCES_DIR --preprocessor \"$${QMAKE_MOC} -E\" ${QMAKE_FILE_NAME}
+idl.depends = $$PWD/../../WebCore/bindings/scripts/CodeGenerator.pm \
+ $$PWD/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm \
+ $$PWD/../../WebCore/bindings/scripts/IDLParser.pm \
+ $$PWD/../../WebCore/bindings/scripts/IDLStructure.pm \
+ $$PWD/../../WebCore/bindings/scripts/InFilesParser.pm \
+ $$PWD/../../WebCore/bindings/scripts/generate-bindings.pl
+addExtraCompiler(idl)
+
diff --git a/Tools/WebKitTestRunner/InjectedBundle-Info.plist b/Tools/WebKitTestRunner/InjectedBundle-Info.plist
new file mode 100644
index 0000000..a21fbde
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle-Info.plist
@@ -0,0 +1,22 @@
+<?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>${EXECUTABLE_NAME}</string>
+ <key>CFBundleIdentifier</key>
+ <string>com.apple.WebKitTestRunner.InjectedBundle</string>
+ <key>CFBundleInfoDictionaryVersion</key>
+ <string>6.0</string>
+ <key>CFBundlePackageType</key>
+ <string>BNDL</string>
+ <key>CFBundleShortVersionString</key>
+ <string>1.0</string>
+ <key>CFBundleSignature</key>
+ <string>????</string>
+ <key>CFBundleVersion</key>
+ <string>1</string>
+</dict>
+</plist>
diff --git a/Tools/WebKitTestRunner/InjectedBundle/ActivateFonts.h b/Tools/WebKitTestRunner/InjectedBundle/ActivateFonts.h
new file mode 100644
index 0000000..5ee1276
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/ActivateFonts.h
@@ -0,0 +1,35 @@
+/*
+ * 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 ActivateFonts_h
+#define ActivateFonts_h
+
+namespace WTR {
+
+void activateFonts();
+
+} // namespace WTR
+
+#endif // ActivateFonts_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm b/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm
new file mode 100644
index 0000000..0de2fd0
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/CodeGeneratorTestRunner.pm
@@ -0,0 +1,530 @@
+# 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.
+
+use strict;
+use warnings;
+use File::Spec;
+
+package CodeGeneratorTestRunner;
+
+sub new
+{
+ my ($class, $codeGenerator, $outputDir) = @_;
+
+ my $reference = {
+ codeGenerator => $codeGenerator,
+ outputDir => $outputDir,
+ };
+
+ bless($reference, $class);
+ return $reference;
+}
+
+sub GenerateModule
+{
+}
+
+sub GenerateInterface
+{
+ my ($self, $interface, $defines) = @_;
+
+ foreach my $file ($self->_generateHeaderFile($interface), $self->_generateImplementationFile($interface)) {
+ open(FILE, ">", File::Spec->catfile($$self{outputDir}, $$file{name})) or die "Failed to open $$file{name} for writing: $!";
+ print FILE @{$$file{contents}};
+ close(FILE) or die "Failed to close $$file{name} after writing: $!";
+ }
+}
+
+sub finish
+{
+}
+
+sub _className
+{
+ my ($idlType) = @_;
+
+ return "JS" . _implementationClassName($idlType);
+}
+
+sub _classRefGetter
+{
+ my ($self, $idlType) = @_;
+ return $$self{codeGenerator}->WK_lcfirst(_implementationClassName($idlType)) . "Class";
+}
+
+sub _fileHeaderString
+{
+ my ($filename) = @_;
+
+ # FIXME: We should pull header out of the IDL file to get the copyright
+ # year(s) right.
+ return <<EOF;
+/*
+ * 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.
+ */
+EOF
+}
+
+sub _generateHeaderFile
+{
+ my ($self, $interface) = @_;
+
+ my @contents = ();
+
+ my $idlType = $interface->name;
+ my $className = _className($idlType);
+ my $implementationClassName = _implementationClassName($idlType);
+ my $filename = $className . ".h";
+
+ push(@contents, _fileHeaderString($filename));
+
+ my $parentClassName = _parentClassName($interface);
+
+ push(@contents, <<EOF);
+
+#ifndef ${className}_h
+#define ${className}_h
+
+#include "${parentClassName}.h"
+EOF
+ push(@contents, <<EOF);
+
+namespace WTR {
+
+class ${implementationClassName};
+
+class ${className} : public ${parentClassName} {
+public:
+ static JSClassRef @{[$self->_classRefGetter($idlType)]}();
+
+private:
+ static const JSStaticFunction* staticFunctions();
+ static const JSStaticValue* staticValues();
+EOF
+
+ if (my @functions = @{$interface->functions}) {
+ push(@contents, "\n // Functions\n\n");
+ foreach my $function (@functions) {
+ push(@contents, " static JSValueRef @{[$function->signature->name]}(JSContextRef, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef*);\n");
+ }
+ }
+
+ if (my @attributes = @{$interface->attributes}) {
+ push(@contents, "\n // Attributes\n\n");
+ foreach my $attribute (@attributes) {
+ push(@contents, " static JSValueRef @{[$self->_getterName($attribute)]}(JSContextRef, JSObjectRef, JSStringRef, JSValueRef*);\n");
+ push(@contents, " static bool @{[$self->_setterName($attribute)]}(JSContextRef, JSObjectRef, JSStringRef, JSValueRef, JSValueRef*);\n") unless $attribute->type =~ /^readonly/;
+ }
+ }
+
+ push(@contents, <<EOF);
+};
+
+${implementationClassName}* to${implementationClassName}(JSContextRef, JSValueRef);
+
+} // namespace WTR
+
+#endif // ${className}_h
+EOF
+
+ return { name => $filename, contents => \@contents };
+}
+
+sub _generateImplementationFile
+{
+ my ($self, $interface) = @_;
+
+ my @contentsPrefix = ();
+ my %contentsIncludes = ();
+ my @contents = ();
+
+ my $idlType = $interface->name;
+ my $className = _className($idlType);
+ my $implementationClassName = _implementationClassName($idlType);
+ my $filename = $className . ".cpp";
+
+ push(@contentsPrefix, _fileHeaderString($filename));
+
+ my $classRefGetter = $self->_classRefGetter($idlType);
+ my $parentClassName = _parentClassName($interface);
+
+ $contentsIncludes{"${className}.h"} = 1;
+ $contentsIncludes{"${implementationClassName}.h"} = 1;
+
+ push(@contentsPrefix, <<EOF);
+
+EOF
+
+ push(@contents, <<EOF);
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <wtf/GetPtr.h>
+
+namespace WTR {
+
+${implementationClassName}* to${implementationClassName}(JSContextRef context, JSValueRef value)
+{
+ if (!context || !value || !${className}::${classRefGetter}() || !JSValueIsObjectOfClass(context, value, ${className}::${classRefGetter}()))
+ return 0;
+ return static_cast<${implementationClassName}*>(JSWrapper::unwrap(context, value));
+}
+
+JSClassRef ${className}::${classRefGetter}()
+{
+ static JSClassRef jsClass;
+ if (!jsClass) {
+ JSClassDefinition definition = kJSClassDefinitionEmpty;
+ definition.className = "${idlType}";
+ definition.parentClass = @{[$self->_parentClassRefGetterExpression($interface)]};
+ definition.staticValues = staticValues();
+ definition.staticFunctions = staticFunctions();
+EOF
+
+ push(@contents, " definition.initialize = initialize;\n") unless _parentInterface($interface);
+ push(@contents, " definition.finalize = finalize;\n") unless _parentInterface($interface);
+
+ push(@contents, <<EOF);
+ jsClass = JSClassCreate(&definition);
+ }
+ return jsClass;
+}
+
+EOF
+
+ push(@contents, $self->_staticFunctionsGetterImplementation($interface), "\n");
+ push(@contents, $self->_staticValuesGetterImplementation($interface));
+
+ if (my @functions = @{$interface->functions}) {
+ push(@contents, "\n// Functions\n");
+
+ foreach my $function (@functions) {
+ push(@contents, <<EOF);
+
+JSValueRef ${className}::@{[$function->signature->name]}(JSContextRef context, JSObjectRef, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ ${implementationClassName}* impl = to${implementationClassName}(context, thisObject);
+ if (!impl)
+ return JSValueMakeUndefined(context);
+
+EOF
+ my $functionCall;
+ if ($function->signature->extendedAttributes->{"CustomArgumentHandling"}) {
+ $functionCall = "impl->" . $function->signature->name . "(context, argumentCount, arguments, exception)";
+ } else {
+ my @parameters = ();
+ my @specifiedParameters = @{$function->parameters};
+
+ $self->_includeHeaders(\%contentsIncludes, $function->signature->type, $function->signature);
+
+ foreach my $i (0..$#specifiedParameters) {
+ my $parameter = $specifiedParameters[$i];
+
+ $self->_includeHeaders(\%contentsIncludes, $idlType, $parameter);
+
+ push(@contents, " " . $self->_platformTypeVariableDeclaration($parameter, $parameter->name, "arguments[$i]", "argumentCount > $i") . "\n");
+
+ push(@parameters, $self->_parameterExpression($parameter));
+ }
+
+ $functionCall = "impl->" . $function->signature->name . "(" . join(", ", @parameters) . ")";
+ }
+
+ push(@contents, " ${functionCall};\n\n") if $function->signature->type eq "void";
+ push(@contents, " return " . $self->_returnExpression($function->signature, $functionCall) . ";\n}\n");
+ }
+ }
+
+ if (my @attributes = @{$interface->attributes}) {
+ push(@contents, "\n// Attributes\n");
+ foreach my $attribute (@attributes) {
+ $self->_includeHeaders(\%contentsIncludes, $attribute->signature->type, $attribute->signature);
+
+ my $getterName = $self->_getterName($attribute);
+ my $getterExpression = "impl->${getterName}()";
+
+ push(@contents, <<EOF);
+
+JSValueRef ${className}::${getterName}(JSContextRef context, JSObjectRef object, JSStringRef, JSValueRef* exception)
+{
+ ${implementationClassName}* impl = to${implementationClassName}(context, object);
+ if (!impl)
+ return JSValueMakeUndefined(context);
+
+ return @{[$self->_returnExpression($attribute->signature, $getterExpression)]};
+}
+EOF
+
+ unless ($attribute->type =~ /^readonly/) {
+ push(@contents, <<EOF);
+
+bool ${className}::@{[$self->_setterName($attribute)]}(JSContextRef context, JSObjectRef object, JSStringRef, JSValueRef value, JSValueRef* exception)
+{
+ ${implementationClassName}* impl = to${implementationClassName}(context, object);
+ if (!impl)
+ return false;
+
+EOF
+
+ my $platformValue = $self->_platformTypeConstructor($attribute->signature, "value");
+
+ push(@contents, <<EOF);
+ impl->@{[$self->_setterName($attribute)]}(${platformValue});
+
+ return true;
+}
+EOF
+ }
+ }
+ }
+
+ push(@contents, <<EOF);
+
+} // namespace WTR
+
+EOF
+
+ unshift(@contents, map { "#include \"$_\"\n" } sort keys(%contentsIncludes));
+ unshift(@contents, @contentsPrefix);
+
+ return { name => $filename, contents => \@contents };
+}
+
+sub _getterName
+{
+ my ($self, $attribute) = @_;
+
+ my $signature = $attribute->signature;
+ my $name = $signature->name;
+
+ return $name;
+}
+
+sub _includeHeaders
+{
+ my ($self, $headers, $idlType, $signature) = @_;
+
+ return unless defined $idlType;
+ return if $idlType eq "boolean";
+ return if $idlType eq "object";
+ return if $$self{codeGenerator}->IsNonPointerType($idlType);
+ return if $$self{codeGenerator}->IsStringType($idlType);
+
+ $$headers{_className($idlType) . ".h"} = 1;
+ $$headers{_implementationClassName($idlType) . ".h"} = 1;
+}
+
+sub _implementationClassName
+{
+ my ($idlType) = @_;
+
+ return $idlType;
+}
+
+sub _parentClassName
+{
+ my ($interface) = @_;
+
+ my $parentInterface = _parentInterface($interface);
+ return $parentInterface ? _className($parentInterface) : "JSWrapper";
+}
+
+sub _parentClassRefGetterExpression
+{
+ my ($self, $interface) = @_;
+
+ my $parentInterface = _parentInterface($interface);
+ return $parentInterface ? $self->_classRefGetter($parentInterface) . "()" : "0";
+}
+
+sub _parentInterface
+{
+ my ($interface) = @_;
+ return $interface->parents->[0];
+}
+
+sub _platformType
+{
+ my ($self, $idlType, $signature) = @_;
+
+ return undef unless defined $idlType;
+
+ return "bool" if $idlType eq "boolean";
+ return "JSValueRef" if $idlType eq "object";
+ return "JSRetainPtr<JSStringRef>" if $$self{codeGenerator}->IsStringType($idlType);
+ return "double" if $$self{codeGenerator}->IsNonPointerType($idlType);
+ return _implementationClassName($idlType);
+}
+
+sub _platformTypeConstructor
+{
+ my ($self, $signature, $argumentName) = @_;
+
+ my $idlType = $signature->type;
+
+ return "JSValueToBoolean(context, $argumentName)" if $idlType eq "boolean";
+ return "$argumentName" if $idlType eq "object";
+ return "JSRetainPtr<JSStringRef>(Adopt, JSValueToStringCopy(context, $argumentName, 0))" if $$self{codeGenerator}->IsStringType($idlType);
+ return "JSValueToNumber(context, $argumentName, 0)" if $$self{codeGenerator}->IsNonPointerType($idlType);
+ return "to" . _implementationClassName($idlType) . "(context, $argumentName)";
+}
+
+sub _platformTypeVariableDeclaration
+{
+ my ($self, $signature, $variableName, $argumentName, $condition) = @_;
+
+ my $platformType = $self->_platformType($signature->type, $signature);
+ my $constructor = $self->_platformTypeConstructor($signature, $argumentName);
+
+ my %nonPointerTypes = (
+ "bool" => 1,
+ "double" => 1,
+ "JSRetainPtr<JSStringRef>" => 1,
+ "JSValueRef" => 1,
+ );
+
+ my $nullValue = "0";
+ $nullValue = "$platformType()" if defined $nonPointerTypes{$platformType} && $platformType ne "double";
+
+ $platformType .= "*" unless defined $nonPointerTypes{$platformType};
+
+ return "$platformType $variableName = $condition && $constructor;" if $condition && $platformType eq "bool";
+ return "$platformType $variableName = $condition ? $constructor : $nullValue;" if $condition;
+ return "$platformType $variableName = $constructor;";
+}
+
+sub _returnExpression
+{
+ my ($self, $signature, $expression) = @_;
+
+ my $returnIDLType = $signature->type;
+
+ return "JSValueMakeUndefined(context)" if $returnIDLType eq "void";
+ return "JSValueMakeBoolean(context, ${expression})" if $returnIDLType eq "boolean";
+ return "${expression}" if $returnIDLType eq "object";
+ return "JSValueMakeNumber(context, ${expression})" if $$self{codeGenerator}->IsNonPointerType($returnIDLType);
+ return "JSValueMakeStringOrNull(context, ${expression}.get())" if $$self{codeGenerator}->IsStringType($returnIDLType);
+ return "toJS(context, WTF::getPtr(${expression}))";
+}
+
+sub _parameterExpression
+{
+ my ($self, $parameter) = @_;
+
+ my $idlType = $parameter->type;
+ my $name = $parameter->name;
+
+ return "${name}.get()" if $$self{codeGenerator}->IsStringType($idlType);
+ return $name;
+}
+
+sub _setterName
+{
+ my ($self, $attribute) = @_;
+
+ my $name = $attribute->signature->name;
+
+ return "set" . $$self{codeGenerator}->WK_ucfirst($name);
+}
+
+sub _staticFunctionsGetterImplementation
+{
+ my ($self, $interface) = @_;
+
+ my $mapFunction = sub {
+ my $name = $_->signature->name;
+ my @attributes = qw(kJSPropertyAttributeDontDelete kJSPropertyAttributeReadOnly);
+ push(@attributes, "kJSPropertyAttributeDontEnum") if $_->signature->extendedAttributes->{"DontEnum"};
+
+ return "{ \"$name\", $name, " . join(" | ", @attributes) . " }";
+ };
+
+ return $self->_staticFunctionsOrValuesGetterImplementation($interface, "function", "{ 0, 0, 0 }", $mapFunction, $interface->functions);
+}
+
+sub _staticFunctionsOrValuesGetterImplementation
+{
+ my ($self, $interface, $functionOrValue, $arrayTerminator, $mapFunction, $functionsOrAttributes) = @_;
+
+ my $className = _className($interface->name);
+ my $uppercaseFunctionOrValue = $$self{codeGenerator}->WK_ucfirst($functionOrValue);
+
+ my $result = <<EOF;
+const JSStatic${uppercaseFunctionOrValue}* ${className}::static${uppercaseFunctionOrValue}s()
+{
+EOF
+
+ my @initializers = map(&$mapFunction, @{$functionsOrAttributes});
+ return $result . " return 0;\n}\n" unless @initializers;
+
+ $result .= <<EOF
+ static const JSStatic${uppercaseFunctionOrValue} ${functionOrValue}s[] = {
+ @{[join(",\n ", @initializers)]},
+ ${arrayTerminator}
+ };
+ return ${functionOrValue}s;
+}
+EOF
+}
+
+sub _staticValuesGetterImplementation
+{
+ my ($self, $interface) = @_;
+
+ my $mapFunction = sub {
+ return if $_->signature->extendedAttributes->{"NoImplementation"};
+
+ my $attributeName = $_->signature->name;
+ my $attributeIsReadonly = $_->type =~ /^readonly/;
+ my $getterName = $self->_getterName($_);
+ my $setterName = $attributeIsReadonly ? "0" : $self->_setterName($_);
+ my @attributes = qw(kJSPropertyAttributeDontDelete);
+ push(@attributes, "kJSPropertyAttributeReadOnly") if $attributeIsReadonly;
+ push(@attributes, "kJSPropertyAttributeDontEnum") if $_->signature->extendedAttributes->{"DontEnum"};
+
+ return "{ \"$attributeName\", $getterName, $setterName, " . join(" | ", @attributes) . " }";
+ };
+
+ return $self->_staticFunctionsOrValuesGetterImplementation($interface, "value", "{ 0, 0, 0, 0 }", $mapFunction, $interface->attributes);
+}
+
+1;
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl
new file mode 100644
index 0000000..1e47772
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/EventSendingController.idl
@@ -0,0 +1,43 @@
+/*
+ * 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.
+ */
+
+module WTR {
+
+ interface EventSendingController {
+ [CustomArgumentHandling] void mouseDown();
+ [CustomArgumentHandling] void mouseUp();
+ [CustomArgumentHandling] void mouseMoveTo();
+ [CustomArgumentHandling] void keyDown();
+ [CustomArgumentHandling] void contextClick(); // CustomArgumentHandling only to throw exception while not implemented.
+ [CustomArgumentHandling] void leapForward(/*in unsigned long delay*/); // CustomArgumentHandling only to throw exception while not implemented.
+
+ // Zoom functions.
+ void textZoomIn();
+ void textZoomOut();
+ void zoomPageIn();
+ void zoomPageOut();
+ };
+
+}
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/GCController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/GCController.idl
new file mode 100644
index 0000000..eb3ddee
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/GCController.idl
@@ -0,0 +1,34 @@
+/*
+ * 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.
+ */
+
+module WTR {
+
+ interface GCController {
+ void collect();
+ void collectOnAlternateThread(in boolean waitUntilDone);
+ unsigned long long getJSObjectCount();
+ };
+
+}
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h b/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.h
new file mode 100644
index 0000000..5ec7197
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrappable.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. 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 JSWrappable_h
+#define JSWrappable_h
+
+#include <JavaScriptCore/JavaScript.h>
+#include <wtf/RefCounted.h>
+
+namespace WTR {
+
+class JSWrappable : public RefCounted<JSWrappable> {
+public:
+ virtual ~JSWrappable() { }
+ virtual JSClassRef wrapperClass() = 0;
+};
+
+inline JSValueRef JSValueMakeStringOrNull(JSContextRef context, JSStringRef stringOrNull)
+{
+ return stringOrNull ? JSValueMakeString(context, stringOrNull) : JSValueMakeNull(context);
+}
+
+} // namespace WTR
+
+#endif // JSWrappable_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp b/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp
new file mode 100644
index 0000000..a62cb2e
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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 "JSWrapper.h"
+
+#include <JavaScriptCore/JSContextRefPrivate.h>
+
+namespace WTR {
+
+JSValueRef JSWrapper::wrap(JSContextRef context, JSWrappable* object)
+{
+ ASSERT_ARG(context, context);
+
+ if (!object)
+ return JSValueMakeNull(context);
+
+ JSClassRef objectClass = object->wrapperClass();
+ ASSERT(objectClass);
+ JSObjectRef wrapperObject = JSObjectMake(context, objectClass, object);
+ ASSERT(wrapperObject);
+
+ return wrapperObject;
+}
+
+JSWrappable* JSWrapper::unwrap(JSContextRef context, JSValueRef value)
+{
+ ASSERT_ARG(context, context);
+ ASSERT_ARG(value, value);
+ if (!context || !value)
+ return 0;
+ return static_cast<JSWrappable*>(JSObjectGetPrivate(JSValueToObject(context, value, 0)));
+}
+
+static JSWrappable* unwrapObject(JSObjectRef object)
+{
+ JSWrappable* wrappable = static_cast<JSWrappable*>(JSObjectGetPrivate(object));
+ ASSERT(wrappable);
+ return wrappable;
+}
+
+void JSWrapper::initialize(JSContextRef ctx, JSObjectRef object)
+{
+ JSWrappable* wrappable = unwrapObject(object);
+ if (!wrappable)
+ return;
+ wrappable->ref();
+}
+
+void JSWrapper::finalize(JSObjectRef object)
+{
+ JSWrappable* wrappable = unwrapObject(object);
+ if (!wrappable)
+ return;
+ wrappable->deref();
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h b/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h
new file mode 100644
index 0000000..d885801
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/JSWrapper.h
@@ -0,0 +1,57 @@
+/*
+ * 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 JSWrapper_h
+#define JSWrapper_h
+
+#include "JSWrappable.h"
+#include <JavaScriptCore/JSRetainPtr.h>
+
+namespace WTR {
+
+// FIXME: If necessary, we can do wrapper caching here.
+class JSWrapper {
+public:
+ static JSValueRef wrap(JSContextRef context, JSWrappable* object);
+ static JSWrappable* unwrap(JSContextRef context, JSValueRef value);
+
+ static void initialize(JSContextRef, JSObjectRef);
+ static void finalize(JSObjectRef);
+};
+
+inline JSValueRef toJS(JSContextRef context, JSWrappable* impl)
+{
+ return JSWrapper::wrap(context, impl);
+}
+
+inline void setProperty(JSContextRef context, JSObjectRef object, const char* propertyName, JSWrappable* value, JSPropertyAttributes attributes, JSValueRef* exception)
+{
+ JSRetainPtr<JSStringRef> propertyNameString(Adopt, JSStringCreateWithUTF8CString(propertyName));
+ JSObjectSetProperty(context, object, propertyNameString.get(), JSWrapper::wrap(context, value), attributes, exception);
+}
+
+} // namespace WTR
+
+#endif // JSWrapper_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl b/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl
new file mode 100644
index 0000000..acc2f47
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/Bindings/LayoutTestController.idl
@@ -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. 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.
+ */
+
+module WTR {
+
+ interface LayoutTestController {
+ // The basics.
+ void dumpAsText();
+ void dumpChildFramesAsText();
+ void waitUntilDone();
+ void notifyDone();
+
+ // Other dumping.
+ void dumpBackForwardList();
+ void dumpChildFrameScrollPositions();
+ void dumpEditingCallbacks();
+ void dumpSelectionRect();
+ void dumpStatusCallbacks();
+ void dumpTitleChanges();
+
+ // Special options.
+ void keepWebHistory();
+ void setAcceptsEditing(in boolean value);
+ void setCanOpenWindows(in boolean value);
+ void setCloseRemainingWindowsWhenComplete(in boolean value);
+ void setXSSAuditorEnabled(in boolean value);
+
+ // Special DOM functions.
+ void clearBackForwardList();
+ object computedStyleIncludingVisitedInfo(in object element);
+ DOMString counterValueForElementById(in DOMString elementId);
+ void execCommand(in DOMString name, in DOMString argument);
+ boolean isCommandEnabled(in DOMString name);
+ DOMString markerTextForListItem(in object element);
+ unsigned long windowCount();
+
+ // Repaint testing.
+ void testRepaint();
+ void repaintSweepHorizontally();
+ void display();
+
+ // Animation testing.
+ int numberOfActiveAnimations();
+ boolean pauseAnimationAtTimeOnElementWithId(in DOMString animationName, in double time, in DOMString elementId);
+ void suspendAnimations();
+ void resumeAnimations();
+
+ // UserContent testing.
+ void addUserScript(in DOMString source, in boolean runAtStart, in boolean allFrames);
+ void addUserStyleSheet(in DOMString source, in boolean allFrames);
+
+ // Compositing testing.
+ DOMString layerTreeAsText();
+
+ // Text search testing.
+ boolean findString(in DOMString target, in object optionsArray);
+ };
+
+}
diff --git a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp
new file mode 100644
index 0000000..73de45b
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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 "EventSendingController.h"
+
+#include "InjectedBundle.h"
+#include "InjectedBundlePage.h"
+#include "JSEventSendingController.h"
+#include <WebKit2/WKBundlePage.h>
+#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit2/WKBundlePrivate.h>
+
+namespace WTR {
+
+static const float ZoomMultiplierRatio = 1.2f;
+
+PassRefPtr<EventSendingController> EventSendingController::create()
+{
+ return adoptRef(new EventSendingController);
+}
+
+EventSendingController::EventSendingController()
+{
+}
+
+EventSendingController::~EventSendingController()
+{
+}
+
+JSClassRef EventSendingController::wrapperClass()
+{
+ return JSEventSendingController::eventSendingControllerClass();
+}
+
+static void setExceptionForString(JSContextRef context, JSValueRef* exception, const char* string)
+{
+ JSRetainPtr<JSStringRef> exceptionString(Adopt, JSStringCreateWithUTF8CString(string));
+ *exception = JSValueMakeString(context, exceptionString.get());
+}
+
+void EventSendingController::mouseDown(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ setExceptionForString(context, exception, "EventSender.mouseDown is not yet supported.");
+}
+
+void EventSendingController::mouseUp(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ setExceptionForString(context, exception, "EventSender.mouseUp is not yet supported.");
+}
+
+void EventSendingController::mouseMoveTo(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ setExceptionForString(context, exception, "EventSender.mouseMoveTo is not yet supported.");
+}
+
+void EventSendingController::keyDown(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ setExceptionForString(context, exception, "EventSender.keyDown is not yet supported.");
+}
+
+void EventSendingController::contextClick(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ setExceptionForString(context, exception, "EventSender.contextClick is not yet supported.");
+}
+
+void EventSendingController::leapForward(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception)
+{
+ setExceptionForString(context, exception, "EventSender.leapForward is not yet supported.");
+}
+
+void EventSendingController::textZoomIn()
+{
+ // Ensure page zoom is reset.
+ WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1);
+
+ double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page());
+ WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio);
+}
+
+void EventSendingController::textZoomOut()
+{
+ // Ensure page zoom is reset.
+ WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), 1);
+
+ double zoomFactor = WKBundlePageGetTextZoomFactor(InjectedBundle::shared().page()->page());
+ WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio);
+}
+
+void EventSendingController::zoomPageIn()
+{
+ // Ensure text zoom is reset.
+ WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1);
+
+ double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page());
+ WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor * ZoomMultiplierRatio);
+}
+
+void EventSendingController::zoomPageOut()
+{
+ // Ensure text zoom is reset.
+ WKBundlePageSetTextZoomFactor(InjectedBundle::shared().page()->page(), 1);
+
+ double zoomFactor = WKBundlePageGetPageZoomFactor(InjectedBundle::shared().page()->page());
+ WKBundlePageSetPageZoomFactor(InjectedBundle::shared().page()->page(), zoomFactor / ZoomMultiplierRatio);
+}
+
+// Object Creation
+
+void EventSendingController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
+{
+ setProperty(context, windowObject, "eventSender", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h
new file mode 100644
index 0000000..400f60d
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/EventSendingController.h
@@ -0,0 +1,63 @@
+/*
+ * 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 EventSendingController_h
+#define EventSendingController_h
+
+#include "JSWrappable.h"
+#include <wtf/PassRefPtr.h>
+
+namespace WTR {
+
+class EventSendingController : public JSWrappable {
+public:
+ static PassRefPtr<EventSendingController> create();
+ virtual ~EventSendingController();
+
+ void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception);
+
+ // JSWrappable
+ virtual JSClassRef wrapperClass();
+
+ void mouseDown(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+ void mouseUp(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+ void mouseMoveTo(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+ void keyDown(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+ void contextClick(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+ void leapForward(JSContextRef context, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception);
+
+ // Zoom functions.
+ void textZoomIn();
+ void textZoomOut();
+ void zoomPageIn();
+ void zoomPageOut();
+
+private:
+ EventSendingController();
+};
+
+} // namespace WTR
+
+#endif // EventSendingController_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/GCController.cpp b/Tools/WebKitTestRunner/InjectedBundle/GCController.cpp
new file mode 100644
index 0000000..0eba2df
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/GCController.cpp
@@ -0,0 +1,74 @@
+/*
+ * 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 "GCController.h"
+
+#include "InjectedBundle.h"
+#include "JSGCController.h"
+#include <WebKit2/WKBundlePrivate.h>
+
+namespace WTR {
+
+PassRefPtr<GCController> GCController::create()
+{
+ return adoptRef(new GCController);
+}
+
+GCController::GCController()
+{
+}
+
+GCController::~GCController()
+{
+}
+
+JSClassRef GCController::wrapperClass()
+{
+ return JSGCController::gCControllerClass();
+}
+
+void GCController::collect()
+{
+ WKBundleGarbageCollectJavaScriptObjects(InjectedBundle::shared().bundle());
+}
+
+void GCController::collectOnAlternateThread(bool waitUntilDone)
+{
+ WKBundleGarbageCollectJavaScriptObjectsOnAlternateThreadForDebugging(InjectedBundle::shared().bundle(), waitUntilDone);
+}
+
+size_t GCController::getJSObjectCount()
+{
+ return WKBundleGetJavaScriptObjectsCount(InjectedBundle::shared().bundle());
+}
+
+// Object Creation
+
+void GCController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
+{
+ setProperty(context, windowObject, "GCController", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/GCController.h b/Tools/WebKitTestRunner/InjectedBundle/GCController.h
new file mode 100644
index 0000000..760fbb1
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/GCController.h
@@ -0,0 +1,54 @@
+/*
+ * 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 GCController_h
+#define GCController_h
+
+#include "JSWrappable.h"
+#include <wtf/PassRefPtr.h>
+
+namespace WTR {
+
+class GCController : public JSWrappable {
+public:
+ static PassRefPtr<GCController> create();
+ virtual ~GCController();
+
+ void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception);
+
+ // JSWrappable
+ virtual JSClassRef wrapperClass();
+
+ void collect();
+ void collectOnAlternateThread(bool waitUntilDone);
+ size_t getJSObjectCount();
+
+private:
+ GCController();
+};
+
+} // namespace WTR
+
+#endif // GCController_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.cpp
new file mode 100644
index 0000000..49d9db6
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.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 "InjectedBundle.h"
+
+#include "ActivateFonts.h"
+#include "InjectedBundlePage.h"
+#include "StringFunctions.h"
+#include <WebKit2/WKBundle.h>
+#include <WebKit2/WKBundlePage.h>
+#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit2/WKBundlePrivate.h>
+#include <WebKit2/WKRetainPtr.h>
+#include <WebKit2/WebKit2.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+namespace WTR {
+
+InjectedBundle& InjectedBundle::shared()
+{
+ static InjectedBundle& shared = *new InjectedBundle;
+ return shared;
+}
+
+InjectedBundle::InjectedBundle()
+ : m_bundle(0)
+ , m_state(Idle)
+{
+}
+
+void InjectedBundle::didCreatePage(WKBundleRef bundle, WKBundlePageRef page, const void* clientInfo)
+{
+ static_cast<InjectedBundle*>(const_cast<void*>(clientInfo))->didCreatePage(page);
+}
+
+void InjectedBundle::willDestroyPage(WKBundleRef bundle, WKBundlePageRef page, const void* clientInfo)
+{
+ static_cast<InjectedBundle*>(const_cast<void*>(clientInfo))->willDestroyPage(page);
+}
+
+void InjectedBundle::didInitializePageGroup(WKBundleRef bundle, WKBundlePageGroupRef pageGroup, const void* clientInfo)
+{
+ static_cast<InjectedBundle*>(const_cast<void*>(clientInfo))->didInitializePageGroup(pageGroup);
+}
+
+void InjectedBundle::didReceiveMessage(WKBundleRef bundle, WKStringRef messageName, WKTypeRef messageBody, const void *clientInfo)
+{
+ static_cast<InjectedBundle*>(const_cast<void*>(clientInfo))->didReceiveMessage(messageName, messageBody);
+}
+
+void InjectedBundle::initialize(WKBundleRef bundle)
+{
+ m_bundle = bundle;
+
+ WKBundleClient client = {
+ 0,
+ this,
+ didCreatePage,
+ willDestroyPage,
+ didInitializePageGroup,
+ didReceiveMessage
+ };
+ WKBundleSetClient(m_bundle, &client);
+
+ activateFonts();
+ WKBundleActivateMacFontAscentHack(m_bundle);
+}
+
+void InjectedBundle::didCreatePage(WKBundlePageRef page)
+{
+ m_pages.append(adoptPtr(new InjectedBundlePage(page)));
+}
+
+void InjectedBundle::willDestroyPage(WKBundlePageRef page)
+{
+ size_t size = m_pages.size();
+ for (size_t i = 0; i < size; ++i) {
+ if (m_pages[i]->page() == page) {
+ m_pages.remove(i);
+ break;
+ }
+ }
+}
+
+void InjectedBundle::didInitializePageGroup(WKBundlePageGroupRef pageGroup)
+{
+ m_pageGroup = pageGroup;
+}
+
+InjectedBundlePage* InjectedBundle::page() const
+{
+ // It might be better to have the UI process send over a reference to the main
+ // page instead of just assuming it's the first one.
+ return m_pages[0].get();
+}
+
+void InjectedBundle::didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody)
+{
+ if (WKStringIsEqualToUTF8CString(messageName, "BeginTest")) {
+ ASSERT(!messageBody);
+
+ WKRetainPtr<WKStringRef> ackMessageName(AdoptWK, WKStringCreateWithUTF8CString("Ack"));
+ WKRetainPtr<WKStringRef> ackMessageBody(AdoptWK, WKStringCreateWithUTF8CString("BeginTest"));
+ WKBundlePostMessage(m_bundle, ackMessageName.get(), ackMessageBody.get());
+
+ beginTesting();
+ return;
+ }
+
+ WKRetainPtr<WKStringRef> errorMessageName(AdoptWK, WKStringCreateWithUTF8CString("Error"));
+ WKRetainPtr<WKStringRef> errorMessageBody(AdoptWK, WKStringCreateWithUTF8CString("Unknown"));
+ WKBundlePostMessage(m_bundle, errorMessageName.get(), errorMessageBody.get());
+}
+
+void InjectedBundle::beginTesting()
+{
+ m_state = Testing;
+
+ m_outputStream.str("");
+
+ m_layoutTestController = LayoutTestController::create();
+ m_gcController = GCController::create();
+ m_eventSendingController = EventSendingController::create();
+
+ WKBundleSetShouldTrackVisitedLinks(m_bundle, false);
+ WKBundleRemoveAllVisitedLinks(m_bundle);
+
+ WKBundleRemoveAllUserContent(m_bundle, m_pageGroup);
+
+ page()->reset();
+}
+
+void InjectedBundle::done()
+{
+ m_state = Stopping;
+
+ page()->stopLoading();
+
+ WKRetainPtr<WKStringRef> doneMessageName(AdoptWK, WKStringCreateWithUTF8CString("Done"));
+ WKRetainPtr<WKStringRef> doneMessageBody(AdoptWK, WKStringCreateWithUTF8CString(m_outputStream.str().c_str()));
+
+ WKBundlePostMessage(m_bundle, doneMessageName.get(), doneMessageBody.get());
+
+ m_state = Idle;
+}
+
+void InjectedBundle::closeOtherPages()
+{
+ Vector<WKBundlePageRef> pagesToClose;
+ size_t size = m_pages.size();
+ for (size_t i = 1; i < size; ++i)
+ pagesToClose.append(m_pages[i]->page());
+ size = pagesToClose.size();
+ for (size_t i = 0; i < size; ++i)
+ WKBundlePageClose(pagesToClose[i]);
+}
+
+void InjectedBundle::dumpBackForwardListsForAllPages()
+{
+ size_t size = m_pages.size();
+ for (size_t i = 0; i < size; ++i)
+ m_pages[i]->dumpBackForwardList();
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h
new file mode 100644
index 0000000..c1d8b37
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundle.h
@@ -0,0 +1,104 @@
+/*
+ * 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 InjectedBundle_h
+#define InjectedBundle_h
+
+#include "EventSendingController.h"
+#include "GCController.h"
+#include "LayoutTestController.h"
+#include <WebKit2/WKBase.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+#include <sstream>
+
+namespace WTR {
+
+class InjectedBundlePage;
+
+class InjectedBundle {
+public:
+ static InjectedBundle& shared();
+
+ // Initialize the InjectedBundle.
+ void initialize(WKBundleRef);
+
+ WKBundleRef bundle() const { return m_bundle; }
+ WKBundlePageGroupRef pageGroup() const { return m_pageGroup; }
+
+ LayoutTestController* layoutTestController() { return m_layoutTestController.get(); }
+ GCController* gcController() { return m_gcController.get(); }
+ EventSendingController* eventSendingController() { return m_eventSendingController.get(); }
+
+ InjectedBundlePage* page() const;
+ size_t pageCount() const { return m_pages.size(); }
+ void closeOtherPages();
+
+ void dumpBackForwardListsForAllPages();
+
+ void done();
+ std::ostringstream& os() { return m_outputStream; }
+
+ bool isTestRunning() { return m_state == Testing; }
+
+private:
+ InjectedBundle();
+ ~InjectedBundle();
+
+ static void didCreatePage(WKBundleRef, WKBundlePageRef, const void* clientInfo);
+ static void willDestroyPage(WKBundleRef, WKBundlePageRef, const void* clientInfo);
+ static void didInitializePageGroup(WKBundleRef, WKBundlePageGroupRef, const void* clientInfo);
+ static void didReceiveMessage(WKBundleRef, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo);
+
+ void didCreatePage(WKBundlePageRef);
+ void willDestroyPage(WKBundlePageRef);
+ void didInitializePageGroup(WKBundlePageGroupRef);
+ void didReceiveMessage(WKStringRef messageName, WKTypeRef messageBody);
+
+ void beginTesting();
+
+ WKBundleRef m_bundle;
+ WKBundlePageGroupRef m_pageGroup;
+ Vector<OwnPtr<InjectedBundlePage> > m_pages;
+
+ RefPtr<LayoutTestController> m_layoutTestController;
+ RefPtr<GCController> m_gcController;
+ RefPtr<EventSendingController> m_eventSendingController;
+
+ std::ostringstream m_outputStream;
+
+ enum State {
+ Idle,
+ Testing,
+ Stopping
+ };
+ State m_state;
+};
+
+} // namespace WTR
+
+#endif // InjectedBundle_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp
new file mode 100644
index 0000000..c4cf892
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundleMain.cpp
@@ -0,0 +1,37 @@
+/*
+ * 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 "InjectedBundle.h"
+#include <WebKit2/WKBundleInitialize.h>
+
+#if defined(WIN32) || defined(_WIN32)
+extern "C" __declspec(dllexport)
+#else
+extern "C"
+#endif
+void WKBundleInitialize(WKBundleRef bundle, WKTypeRef initializationUserData)
+{
+ WTR::InjectedBundle::shared().initialize(bundle);
+}
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp
new file mode 100644
index 0000000..da79b19
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.cpp
@@ -0,0 +1,901 @@
+/*
+ * 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 "InjectedBundlePage.h"
+
+#include "InjectedBundle.h"
+#include "StringFunctions.h"
+#include <cmath>
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <WebKit2/WKArray.h>
+#include <WebKit2/WKBundle.h>
+#include <WebKit2/WKBundleBackForwardList.h>
+#include <WebKit2/WKBundleBackForwardListItem.h>
+#include <WebKit2/WKBundleFrame.h>
+#include <WebKit2/WKBundleFramePrivate.h>
+#include <WebKit2/WKBundlePagePrivate.h>
+
+using namespace std;
+
+namespace WTR {
+
+template<typename T> static inline WKRetainPtr<T> adoptWK(T item)
+{
+ return WKRetainPtr<T>(AdoptWK, item);
+}
+
+static bool hasPrefix(const string& searchString, const string& prefix)
+{
+ return searchString.length() >= prefix.length() && searchString.substr(0, prefix.length()) == prefix;
+}
+
+static JSValueRef propertyValue(JSContextRef context, JSObjectRef object, const char* propertyName)
+{
+ if (!object)
+ return 0;
+ JSRetainPtr<JSStringRef> propertyNameString(Adopt, JSStringCreateWithUTF8CString(propertyName));
+ return JSObjectGetProperty(context, object, propertyNameString.get(), 0);
+}
+
+static double propertyValueDouble(JSContextRef context, JSObjectRef object, const char* propertyName)
+{
+ JSValueRef value = propertyValue(context, object, propertyName);
+ if (!value)
+ return 0;
+ return JSValueToNumber(context, value, 0);
+}
+
+static int propertyValueInt(JSContextRef context, JSObjectRef object, const char* propertyName)
+{
+ return static_cast<int>(propertyValueDouble(context, object, propertyName));
+}
+
+static double numericWindowPropertyValue(WKBundleFrameRef frame, const char* propertyName)
+{
+ JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
+ return propertyValueDouble(context, JSContextGetGlobalObject(context), propertyName);
+}
+
+static string dumpPath(JSGlobalContextRef context, JSObjectRef nodeValue)
+{
+ JSValueRef nodeNameValue = propertyValue(context, nodeValue, "nodeName");
+ JSRetainPtr<JSStringRef> jsStringNodeName(Adopt, JSValueToStringCopy(context, nodeNameValue, 0));
+ WKRetainPtr<WKStringRef> nodeName = toWK(jsStringNodeName);
+
+ JSValueRef parentNode = propertyValue(context, nodeValue, "parentNode");
+
+ ostringstream out;
+ out << nodeName;
+
+ if (parentNode && JSValueIsObject(context, parentNode))
+ out << " > " << dumpPath(context, (JSObjectRef)parentNode);
+
+ return out.str();
+}
+
+static string dumpPath(WKBundlePageRef page, WKBundleScriptWorldRef world, WKBundleNodeHandleRef node)
+{
+ if (!node)
+ return "(null)";
+
+ WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
+
+ JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world);
+ JSValueRef nodeValue = WKBundleFrameGetJavaScriptWrapperForNodeForWorld(frame, node, world);
+ ASSERT(JSValueIsObject(context, nodeValue));
+ JSObjectRef nodeObject = (JSObjectRef)nodeValue;
+
+ return dumpPath(context, nodeObject);
+}
+
+static string toStr(WKBundlePageRef page, WKBundleScriptWorldRef world, WKBundleRangeHandleRef rangeRef)
+{
+ if (!rangeRef)
+ return "(null)";
+
+ WKBundleFrameRef frame = WKBundlePageGetMainFrame(page);
+
+ JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world);
+ JSValueRef rangeValue = WKBundleFrameGetJavaScriptWrapperForRangeForWorld(frame, rangeRef, world);
+ ASSERT(JSValueIsObject(context, rangeValue));
+ JSObjectRef rangeObject = (JSObjectRef)rangeValue;
+
+ JSValueRef startNodeValue = propertyValue(context, rangeObject, "startContainer");
+ ASSERT(JSValueIsObject(context, startNodeValue));
+ JSObjectRef startNodeObject = (JSObjectRef)startNodeValue;
+
+ JSValueRef endNodeValue = propertyValue(context, rangeObject, "endContainer");
+ ASSERT(JSValueIsObject(context, endNodeValue));
+ JSObjectRef endNodeObject = (JSObjectRef)endNodeValue;
+
+ int startOffset = propertyValueInt(context, rangeObject, "startOffset");
+ int endOffset = propertyValueInt(context, rangeObject, "endOffset");
+
+ ostringstream out;
+ out << "range from " << startOffset << " of " << dumpPath(context, startNodeObject) << " to " << endOffset << " of " << dumpPath(context, endNodeObject);
+ return out.str();
+}
+
+static ostream& operator<<(ostream& out, WKBundleCSSStyleDeclarationRef style)
+{
+ // DumpRenderTree calls -[DOMCSSStyleDeclaration description], which just dumps class name and object address.
+ // No existing tests actually hit this code path at the time of this writing, because WebCore doesn't call
+ // the editing client if the styling operation source is CommandFromDOM or CommandFromDOMWithUserInterface.
+ out << "<DOMCSSStyleDeclaration ADDRESS>";
+ return out;
+}
+
+static ostream& operator<<(ostream& out, WKBundleFrameRef frame)
+{
+ WKRetainPtr<WKStringRef> name(AdoptWK, WKBundleFrameCopyName(frame));
+ if (WKBundleFrameIsMainFrame(frame)) {
+ if (!WKStringIsEmpty(name.get()))
+ out << "main frame \"" << name << "\"";
+ else
+ out << "main frame";
+ } else {
+ if (!WKStringIsEmpty(name.get()))
+ out << "frame \"" << name << "\"";
+ else
+ out << "frame (anonymous)";
+ }
+
+ return out;
+}
+
+InjectedBundlePage::InjectedBundlePage(WKBundlePageRef page)
+ : m_page(page)
+ , m_world(AdoptWK, WKBundleScriptWorldCreateWorld())
+ , m_isLoading(false)
+{
+ WKBundlePageLoaderClient loaderClient = {
+ 0,
+ this,
+ didStartProvisionalLoadForFrame,
+ didReceiveServerRedirectForProvisionalLoadForFrame,
+ didFailProvisionalLoadWithErrorForFrame,
+ didCommitLoadForFrame,
+ didFinishDocumentLoadForFrame,
+ didFinishLoadForFrame,
+ didFailLoadWithErrorForFrame,
+ didSameDocumentNavigationForFrame,
+ didReceiveTitleForFrame,
+ 0,
+ 0,
+ 0,
+ didDisplayInsecureContentForFrame,
+ didRunInsecureContentForFrame,
+ didClearWindowForFrame,
+ didCancelClientRedirectForFrame,
+ willPerformClientRedirectForFrame,
+ didHandleOnloadEventsForFrame
+ };
+ WKBundlePageSetLoaderClient(m_page, &loaderClient);
+
+ WKBundlePageUIClient uiClient = {
+ 0,
+ this,
+ willAddMessageToConsole,
+ willSetStatusbarText,
+ willRunJavaScriptAlert,
+ willRunJavaScriptConfirm,
+ willRunJavaScriptPrompt,
+ 0, /*mouseDidMoveOverElement*/
+ 0, /*pageDidScroll*/
+ };
+ WKBundlePageSetUIClient(m_page, &uiClient);
+
+ WKBundlePageEditorClient editorClient = {
+ 0,
+ this,
+ shouldBeginEditing,
+ shouldEndEditing,
+ shouldInsertNode,
+ shouldInsertText,
+ shouldDeleteRange,
+ shouldChangeSelectedRange,
+ shouldApplyStyle,
+ didBeginEditing,
+ didEndEditing,
+ didChange,
+ didChangeSelection
+ };
+ WKBundlePageSetEditorClient(m_page, &editorClient);
+}
+
+InjectedBundlePage::~InjectedBundlePage()
+{
+}
+
+void InjectedBundlePage::stopLoading()
+{
+ WKBundlePageStopLoading(m_page);
+ m_isLoading = false;
+}
+
+void InjectedBundlePage::reset()
+{
+ WKBundlePageClearMainFrameName(m_page);
+
+ WKBundlePageSetPageZoomFactor(m_page, 1);
+ WKBundlePageSetTextZoomFactor(m_page, 1);
+
+ m_previousTestBackForwardListItem = adoptWK(WKBundleBackForwardListCopyItemAtIndex(WKBundlePageGetBackForwardList(m_page), 0));
+}
+
+// Loader Client Callbacks
+
+void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didStartProvisionalLoadForFrame(frame);
+}
+
+void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveServerRedirectForProvisionalLoadForFrame(frame);
+}
+
+void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef error, WKTypeRef*, const void *clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFailProvisionalLoadWithErrorForFrame(frame, error);
+}
+
+void InjectedBundlePage::didCommitLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didCommitLoadForFrame(frame);
+}
+
+void InjectedBundlePage::didFinishLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(frame);
+}
+
+void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFinishDocumentLoadForFrame(frame);
+}
+
+void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKErrorRef error, WKTypeRef*, const void *clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didFailLoadWithErrorForFrame(frame, error);
+}
+
+void InjectedBundlePage::didReceiveTitleForFrame(WKBundlePageRef page, WKStringRef title, WKBundleFrameRef frame, WKTypeRef*, const void *clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didReceiveTitleForFrame(title, frame);
+}
+
+void InjectedBundlePage::didClearWindowForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKBundleScriptWorldRef world, const void *clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didClearWindowForFrame(frame, world);
+}
+
+void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didCancelClientRedirectForFrame(frame);
+}
+
+void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKURLRef url, double delay, double date, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willPerformClientRedirectForFrame(frame, url, delay, date);
+}
+
+void InjectedBundlePage::didSameDocumentNavigationForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKSameDocumentNavigationType type, WKTypeRef*, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didSameDocumentNavigationForFrame(frame, type);
+}
+
+void InjectedBundlePage::didHandleOnloadEventsForFrame(WKBundlePageRef page, WKBundleFrameRef frame, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didHandleOnloadEventsForFrame(frame);
+}
+
+void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didDisplayInsecureContentForFrame(frame);
+}
+
+void InjectedBundlePage::didRunInsecureContentForFrame(WKBundlePageRef page, WKBundleFrameRef frame, WKTypeRef*, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didRunInsecureContentForFrame(frame);
+}
+
+
+void InjectedBundlePage::didStartProvisionalLoadForFrame(WKBundleFrameRef frame)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ if (frame == WKBundlePageGetMainFrame(m_page))
+ m_isLoading = true;
+}
+
+void InjectedBundlePage::didReceiveServerRedirectForProvisionalLoadForFrame(WKBundleFrameRef frame)
+{
+}
+
+void InjectedBundlePage::didFailProvisionalLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef error)
+{
+}
+
+void InjectedBundlePage::didCommitLoadForFrame(WKBundleFrameRef frame)
+{
+}
+
+enum FrameNamePolicy { ShouldNotIncludeFrameName, ShouldIncludeFrameName };
+
+static void dumpFrameScrollPosition(WKBundleFrameRef frame, FrameNamePolicy shouldIncludeFrameName = ShouldNotIncludeFrameName)
+{
+ double x = numericWindowPropertyValue(frame, "pageXOffset");
+ double y = numericWindowPropertyValue(frame, "pageYOffset");
+ if (fabs(x) > 0.00000001 || fabs(y) > 0.00000001) {
+ if (shouldIncludeFrameName) {
+ WKRetainPtr<WKStringRef> name(AdoptWK, WKBundleFrameCopyName(frame));
+ InjectedBundle::shared().os() << "frame '" << name << "' ";
+ }
+ InjectedBundle::shared().os() << "scrolled to " << x << "," << y << "\n";
+ }
+}
+
+static void dumpDescendantFrameScrollPositions(WKBundleFrameRef frame)
+{
+ WKRetainPtr<WKArrayRef> childFrames(AdoptWK, WKBundleFrameCopyChildFrames(frame));
+ size_t size = WKArrayGetSize(childFrames.get());
+ for (size_t i = 0; i < size; ++i) {
+ WKBundleFrameRef subframe = static_cast<WKBundleFrameRef>(WKArrayGetItemAtIndex(childFrames.get(), i));
+ dumpFrameScrollPosition(subframe, ShouldIncludeFrameName);
+ dumpDescendantFrameScrollPositions(subframe);
+ }
+}
+
+void InjectedBundlePage::dumpAllFrameScrollPositions()
+{
+ WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
+ dumpFrameScrollPosition(frame);
+ dumpDescendantFrameScrollPositions(frame);
+}
+
+static JSRetainPtr<JSStringRef> toJS(const char* string)
+{
+ return JSRetainPtr<JSStringRef>(Adopt, JSStringCreateWithUTF8CString(string));
+}
+
+static bool hasDocumentElement(WKBundleFrameRef frame)
+{
+ JSGlobalContextRef context = WKBundleFrameGetJavaScriptContext(frame);
+ JSObjectRef globalObject = JSContextGetGlobalObject(context);
+
+ JSValueRef documentValue = JSObjectGetProperty(context, globalObject, toJS("document").get(), 0);
+ if (!documentValue)
+ return false;
+
+ ASSERT(JSValueIsObject(context, documentValue));
+ JSObjectRef document = JSValueToObject(context, documentValue, 0);
+
+ JSValueRef documentElementValue = JSObjectGetProperty(context, document, toJS("documentElement").get(), 0);
+ if (!documentElementValue)
+ return false;
+
+ return JSValueToBoolean(context, documentElementValue);
+}
+
+static void dumpFrameText(WKBundleFrameRef frame)
+{
+ // If the frame doesn't have a document element, its inner text will be an empty string, so
+ // we'll end up just appending a single newline below. But DumpRenderTree doesn't append
+ // anything in this case, so we shouldn't either.
+ if (!hasDocumentElement(frame))
+ return;
+
+ WKRetainPtr<WKStringRef> text(AdoptWK, WKBundleFrameCopyInnerText(frame));
+ InjectedBundle::shared().os() << text << "\n";
+}
+
+static void dumpDescendantFramesText(WKBundleFrameRef frame)
+{
+ WKRetainPtr<WKArrayRef> childFrames(AdoptWK, WKBundleFrameCopyChildFrames(frame));
+ size_t size = WKArrayGetSize(childFrames.get());
+ for (size_t i = 0; i < size; ++i) {
+ WKBundleFrameRef subframe = static_cast<WKBundleFrameRef>(WKArrayGetItemAtIndex(childFrames.get(), i));
+ WKRetainPtr<WKStringRef> subframeName(AdoptWK, WKBundleFrameCopyName(subframe));
+ InjectedBundle::shared().os() << "\n--------\nFrame: '" << subframeName << "'\n--------\n";
+ dumpFrameText(subframe);
+ dumpDescendantFramesText(subframe);
+ }
+}
+
+void InjectedBundlePage::dumpAllFramesText()
+{
+ WKBundleFrameRef frame = WKBundlePageGetMainFrame(m_page);
+ dumpFrameText(frame);
+ dumpDescendantFramesText(frame);
+}
+
+void InjectedBundlePage::dump()
+{
+ ASSERT(InjectedBundle::shared().isTestRunning());
+
+ InjectedBundle::shared().layoutTestController()->invalidateWaitToDumpWatchdogTimer();
+
+ switch (InjectedBundle::shared().layoutTestController()->whatToDump()) {
+ case LayoutTestController::RenderTree: {
+ WKRetainPtr<WKStringRef> text(AdoptWK, WKBundlePageCopyRenderTreeExternalRepresentation(m_page));
+ InjectedBundle::shared().os() << text;
+ break;
+ }
+ case LayoutTestController::MainFrameText:
+ dumpFrameText(WKBundlePageGetMainFrame(m_page));
+ break;
+ case LayoutTestController::AllFramesText:
+ dumpAllFramesText();
+ break;
+ }
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpAllFrameScrollPositions())
+ dumpAllFrameScrollPositions();
+ else if (InjectedBundle::shared().layoutTestController()->shouldDumpMainFrameScrollPosition())
+ dumpFrameScrollPosition(WKBundlePageGetMainFrame(m_page));
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpBackForwardListsForAllWindows())
+ InjectedBundle::shared().dumpBackForwardListsForAllPages();
+
+ InjectedBundle::shared().done();
+}
+
+void InjectedBundlePage::didFinishLoadForFrame(WKBundleFrameRef frame)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ if (!WKBundleFrameIsMainFrame(frame))
+ return;
+
+ m_isLoading = false;
+
+ if (this != InjectedBundle::shared().page())
+ return;
+
+ if (InjectedBundle::shared().layoutTestController()->waitToDump())
+ return;
+
+ dump();
+}
+
+void InjectedBundlePage::didFailLoadWithErrorForFrame(WKBundleFrameRef frame, WKErrorRef)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ if (!WKBundleFrameIsMainFrame(frame))
+ return;
+
+ m_isLoading = false;
+
+ if (this != InjectedBundle::shared().page())
+ return;
+
+ InjectedBundle::shared().done();
+}
+
+void InjectedBundlePage::didReceiveTitleForFrame(WKStringRef title, WKBundleFrameRef frame)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ if (!InjectedBundle::shared().layoutTestController()->shouldDumpTitleChanges())
+ return;
+
+ InjectedBundle::shared().os() << "TITLE CHANGED: " << title << "\n";
+}
+
+void InjectedBundlePage::didClearWindowForFrame(WKBundleFrameRef frame, WKBundleScriptWorldRef world)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ if (WKBundleScriptWorldNormalWorld() != world)
+ return;
+
+ JSGlobalContextRef context = WKBundleFrameGetJavaScriptContextForWorld(frame, world);
+ JSObjectRef window = JSContextGetGlobalObject(context);
+
+ JSValueRef exception = 0;
+ InjectedBundle::shared().layoutTestController()->makeWindowObject(context, window, &exception);
+ InjectedBundle::shared().gcController()->makeWindowObject(context, window, &exception);
+ InjectedBundle::shared().eventSendingController()->makeWindowObject(context, window, &exception);
+}
+
+void InjectedBundlePage::didCancelClientRedirectForFrame(WKBundleFrameRef frame)
+{
+}
+
+void InjectedBundlePage::willPerformClientRedirectForFrame(WKBundleFrameRef frame, WKURLRef url, double delay, double date)
+{
+}
+
+void InjectedBundlePage::didSameDocumentNavigationForFrame(WKBundleFrameRef frame, WKSameDocumentNavigationType type)
+{
+}
+
+void InjectedBundlePage::didFinishDocumentLoadForFrame(WKBundleFrameRef frame)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ unsigned pendingFrameUnloadEvents = WKBundleFrameGetPendingUnloadCount(frame);
+ if (pendingFrameUnloadEvents)
+ InjectedBundle::shared().os() << frame << " - has " << pendingFrameUnloadEvents << " onunload handler(s)\n";
+}
+
+void InjectedBundlePage::didHandleOnloadEventsForFrame(WKBundleFrameRef frame)
+{
+}
+
+void InjectedBundlePage::didDisplayInsecureContentForFrame(WKBundleFrameRef frame)
+{
+}
+
+void InjectedBundlePage::didRunInsecureContentForFrame(WKBundleFrameRef frame)
+{
+}
+
+// UI Client Callbacks
+
+void InjectedBundlePage::willAddMessageToConsole(WKBundlePageRef page, WKStringRef message, uint32_t lineNumber, const void *clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willAddMessageToConsole(message, lineNumber);
+}
+
+void InjectedBundlePage::willSetStatusbarText(WKBundlePageRef page, WKStringRef statusbarText, const void *clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willSetStatusbarText(statusbarText);
+}
+
+void InjectedBundlePage::willRunJavaScriptAlert(WKBundlePageRef page, WKStringRef message, WKBundleFrameRef frame, const void *clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptAlert(message, frame);
+}
+
+void InjectedBundlePage::willRunJavaScriptConfirm(WKBundlePageRef page, WKStringRef message, WKBundleFrameRef frame, const void *clientInfo)
+{
+ return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptConfirm(message, frame);
+}
+
+void InjectedBundlePage::willRunJavaScriptPrompt(WKBundlePageRef page, WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef frame, const void *clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->willRunJavaScriptPrompt(message, defaultValue, frame);
+}
+
+void InjectedBundlePage::willAddMessageToConsole(WKStringRef message, uint32_t lineNumber)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ // FIXME: Strip file: urls.
+ InjectedBundle::shared().os() << "CONSOLE MESSAGE: line " << lineNumber << ": " << message << "\n";
+}
+
+void InjectedBundlePage::willSetStatusbarText(WKStringRef statusbarText)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ if (!InjectedBundle::shared().layoutTestController()->shouldDumpStatusCallbacks())
+ return;
+
+ InjectedBundle::shared().os() << "UI DELEGATE STATUS CALLBACK: setStatusText:" << statusbarText << "\n";
+}
+
+void InjectedBundlePage::willRunJavaScriptAlert(WKStringRef message, WKBundleFrameRef)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ InjectedBundle::shared().os() << "ALERT: " << message << "\n";
+}
+
+void InjectedBundlePage::willRunJavaScriptConfirm(WKStringRef message, WKBundleFrameRef)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ InjectedBundle::shared().os() << "CONFIRM: " << message << "\n";
+}
+
+void InjectedBundlePage::willRunJavaScriptPrompt(WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef)
+{
+ InjectedBundle::shared().os() << "PROMPT: " << message << ", default text: " << defaultValue << "\n";
+}
+
+// Editor Client Callbacks
+
+bool InjectedBundlePage::shouldBeginEditing(WKBundlePageRef page, WKBundleRangeHandleRef range, const void* clientInfo)
+{
+ return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldBeginEditing(range);
+}
+
+bool InjectedBundlePage::shouldEndEditing(WKBundlePageRef page, WKBundleRangeHandleRef range, const void* clientInfo)
+{
+ return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldEndEditing(range);
+}
+
+bool InjectedBundlePage::shouldInsertNode(WKBundlePageRef page, WKBundleNodeHandleRef node, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action, const void* clientInfo)
+{
+ return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldInsertNode(node, rangeToReplace, action);
+}
+
+bool InjectedBundlePage::shouldInsertText(WKBundlePageRef page, WKStringRef text, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action, const void* clientInfo)
+{
+ return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldInsertText(text, rangeToReplace, action);
+}
+
+bool InjectedBundlePage::shouldDeleteRange(WKBundlePageRef page, WKBundleRangeHandleRef range, const void* clientInfo)
+{
+ return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldDeleteRange(range);
+}
+
+bool InjectedBundlePage::shouldChangeSelectedRange(WKBundlePageRef page, WKBundleRangeHandleRef fromRange, WKBundleRangeHandleRef toRange, WKAffinityType affinity, bool stillSelecting, const void* clientInfo)
+{
+ return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldChangeSelectedRange(fromRange, toRange, affinity, stillSelecting);
+}
+
+bool InjectedBundlePage::shouldApplyStyle(WKBundlePageRef page, WKBundleCSSStyleDeclarationRef style, WKBundleRangeHandleRef range, const void* clientInfo)
+{
+ return static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->shouldApplyStyle(style, range);
+}
+
+void InjectedBundlePage::didBeginEditing(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didBeginEditing(notificationName);
+}
+
+void InjectedBundlePage::didEndEditing(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didEndEditing(notificationName);
+}
+
+void InjectedBundlePage::didChange(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didChange(notificationName);
+}
+
+void InjectedBundlePage::didChangeSelection(WKBundlePageRef page, WKStringRef notificationName, const void* clientInfo)
+{
+ static_cast<InjectedBundlePage*>(const_cast<void*>(clientInfo))->didChangeSelection(notificationName);
+}
+
+bool InjectedBundlePage::shouldBeginEditing(WKBundleRangeHandleRef range)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return true;
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
+ InjectedBundle::shared().os() << "EDITING DELEGATE: shouldBeginEditingInDOMRange:" << toStr(m_page, m_world.get(), range) << "\n";
+ return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
+}
+
+bool InjectedBundlePage::shouldEndEditing(WKBundleRangeHandleRef range)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return true;
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
+ InjectedBundle::shared().os() << "EDITING DELEGATE: shouldEndEditingInDOMRange:" << toStr(m_page, m_world.get(), range) << "\n";
+ return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
+}
+
+bool InjectedBundlePage::shouldInsertNode(WKBundleNodeHandleRef node, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return true;
+
+ static const char* insertactionstring[] = {
+ "WebViewInsertActionTyped",
+ "WebViewInsertActionPasted",
+ "WebViewInsertActionDropped",
+ };
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
+ InjectedBundle::shared().os() << "EDITING DELEGATE: shouldInsertNode:" << dumpPath(m_page, m_world.get(), node) << " replacingDOMRange:" << toStr(m_page, m_world.get(), rangeToReplace) << " givenAction:" << insertactionstring[action] << "\n";
+ return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
+}
+
+bool InjectedBundlePage::shouldInsertText(WKStringRef text, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType action)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return true;
+
+ static const char *insertactionstring[] = {
+ "WebViewInsertActionTyped",
+ "WebViewInsertActionPasted",
+ "WebViewInsertActionDropped",
+ };
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
+ InjectedBundle::shared().os() << "EDITING DELEGATE: shouldInsertText:" << text << " replacingDOMRange:" << toStr(m_page, m_world.get(), rangeToReplace) << " givenAction:" << insertactionstring[action] << "\n";
+ return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
+}
+
+bool InjectedBundlePage::shouldDeleteRange(WKBundleRangeHandleRef range)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return true;
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
+ InjectedBundle::shared().os() << "EDITING DELEGATE: shouldDeleteDOMRange:" << toStr(m_page, m_world.get(), range) << "\n";
+ return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
+}
+
+bool InjectedBundlePage::shouldChangeSelectedRange(WKBundleRangeHandleRef fromRange, WKBundleRangeHandleRef toRange, WKAffinityType affinity, bool stillSelecting)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return true;
+
+ static const char *affinitystring[] = {
+ "NSSelectionAffinityUpstream",
+ "NSSelectionAffinityDownstream"
+ };
+ static const char *boolstring[] = {
+ "FALSE",
+ "TRUE"
+ };
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
+ InjectedBundle::shared().os() << "EDITING DELEGATE: shouldChangeSelectedDOMRange:" << toStr(m_page, m_world.get(), fromRange) << " toDOMRange:" << toStr(m_page, m_world.get(), toRange) << " affinity:" << affinitystring[affinity] << " stillSelecting:" << boolstring[stillSelecting] << "\n";
+ return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
+}
+
+bool InjectedBundlePage::shouldApplyStyle(WKBundleCSSStyleDeclarationRef style, WKBundleRangeHandleRef range)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return true;
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
+ InjectedBundle::shared().os() << "EDITING DELEGATE: shouldApplyStyle:" << style << " toElementsInDOMRange:" << toStr(m_page, m_world.get(), range) << "\n";
+ return InjectedBundle::shared().layoutTestController()->shouldAllowEditing();
+}
+
+void InjectedBundlePage::didBeginEditing(WKStringRef notificationName)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
+ InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidBeginEditing:" << notificationName << "\n";
+}
+
+void InjectedBundlePage::didEndEditing(WKStringRef notificationName)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
+ InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidEndEditing:" << notificationName << "\n";
+}
+
+void InjectedBundlePage::didChange(WKStringRef notificationName)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
+ InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidChange:" << notificationName << "\n";
+}
+
+void InjectedBundlePage::didChangeSelection(WKStringRef notificationName)
+{
+ if (!InjectedBundle::shared().isTestRunning())
+ return;
+
+ if (InjectedBundle::shared().layoutTestController()->shouldDumpEditingCallbacks())
+ InjectedBundle::shared().os() << "EDITING DELEGATE: webViewDidChangeSelection:" << notificationName << "\n";
+}
+
+static bool compareByTargetName(WKBundleBackForwardListItemRef item1, WKBundleBackForwardListItemRef item2)
+{
+ return toSTD(adoptWK(WKBundleBackForwardListItemCopyTarget(item1))) < toSTD(adoptWK(WKBundleBackForwardListItemCopyTarget(item2)));
+}
+
+static void dumpBackForwardListItem(WKBundleBackForwardListItemRef item, unsigned indent, bool isCurrentItem)
+{
+ unsigned column = 0;
+ if (isCurrentItem) {
+ InjectedBundle::shared().os() << "curr->";
+ column = 6;
+ }
+ for (unsigned i = column; i < indent; i++)
+ InjectedBundle::shared().os() << ' ';
+
+ string url = toSTD(adoptWK(WKURLCopyString(adoptWK(WKBundleBackForwardListItemCopyURL(item)).get())));
+ if (hasPrefix(url, "file:")) {
+ string directoryName = "/LayoutTests/";
+ size_t start = url.find(directoryName);
+ if (start == string::npos)
+ start = 0;
+ else
+ start += directoryName.size();
+ InjectedBundle::shared().os() << "(file test):" << url.substr(start);
+ } else
+ InjectedBundle::shared().os() << url;
+
+ string target = toSTD(adoptWK(WKBundleBackForwardListItemCopyTarget(item)));
+ if (target.length())
+ InjectedBundle::shared().os() << " (in frame \"" << target << "\")";
+
+ // FIXME: Need WKBackForwardListItemIsTargetItem.
+ if (WKBundleBackForwardListItemIsTargetItem(item))
+ InjectedBundle::shared().os() << " **nav target**";
+
+ InjectedBundle::shared().os() << '\n';
+
+ if (WKRetainPtr<WKArrayRef> kids = adoptWK(WKBundleBackForwardListItemCopyChildren(item))) {
+ // Sort to eliminate arbitrary result ordering which defeats reproducible testing.
+ size_t size = WKArrayGetSize(kids.get());
+ Vector<WKBundleBackForwardListItemRef> sortedKids(size);
+ for (size_t i = 0; i < size; ++i)
+ sortedKids[i] = static_cast<WKBundleBackForwardListItemRef>(WKArrayGetItemAtIndex(kids.get(), i));
+ stable_sort(sortedKids.begin(), sortedKids.end(), compareByTargetName);
+ for (size_t i = 0; i < size; ++i)
+ dumpBackForwardListItem(sortedKids[i], indent + 4, false);
+ }
+}
+
+void InjectedBundlePage::dumpBackForwardList()
+{
+ InjectedBundle::shared().os() << "\n============== Back Forward List ==============\n";
+
+ WKBundleBackForwardListRef list = WKBundlePageGetBackForwardList(m_page);
+
+ // Print out all items in the list after m_previousTestBackForwardListItem.
+ // Gather items from the end of the list, then print them out from oldest to newest.
+ Vector<WKRetainPtr<WKBundleBackForwardListItemRef> > itemsToPrint;
+ for (unsigned i = WKBundleBackForwardListGetForwardListCount(list); i; --i) {
+ WKRetainPtr<WKBundleBackForwardListItemRef> item = adoptWK(WKBundleBackForwardListCopyItemAtIndex(list, i));
+ // Something is wrong if the item from the last test is in the forward part of the list.
+ ASSERT(!WKBundleBackForwardListItemIsSame(item.get(), m_previousTestBackForwardListItem.get()));
+ itemsToPrint.append(item);
+ }
+
+ ASSERT(!WKBundleBackForwardListItemIsSame(adoptWK(WKBundleBackForwardListCopyItemAtIndex(list, 0)).get(), m_previousTestBackForwardListItem.get()));
+
+ itemsToPrint.append(adoptWK(WKBundleBackForwardListCopyItemAtIndex(list, 0)));
+
+ int currentItemIndex = itemsToPrint.size() - 1;
+
+ int backListCount = WKBundleBackForwardListGetBackListCount(list);
+ for (int i = -1; i >= -backListCount; --i) {
+ WKRetainPtr<WKBundleBackForwardListItemRef> item = adoptWK(WKBundleBackForwardListCopyItemAtIndex(list, i));
+ if (WKBundleBackForwardListItemIsSame(item.get(), m_previousTestBackForwardListItem.get()))
+ break;
+ itemsToPrint.append(item);
+ }
+
+ for (int i = itemsToPrint.size() - 1; i >= 0; i--)
+ dumpBackForwardListItem(itemsToPrint[i].get(), 8, i == currentItemIndex);
+
+ InjectedBundle::shared().os() << "===============================================\n";
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h
new file mode 100644
index 0000000..cb1c27b
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/InjectedBundlePage.h
@@ -0,0 +1,130 @@
+/*
+ * 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 InjectedBundlePage_h
+#define InjectedBundlePage_h
+
+#include <WebKit2/WKBundlePage.h>
+#include <WebKit2/WKBundleScriptWorld.h>
+#include <WebKit2/WKRetainPtr.h>
+
+namespace WTR {
+
+class InjectedBundlePage {
+public:
+ InjectedBundlePage(WKBundlePageRef);
+ ~InjectedBundlePage();
+
+ WKBundlePageRef page() const { return m_page; }
+ void dump();
+
+ void stopLoading();
+ bool isLoading() { return m_isLoading; }
+
+ void reset();
+
+ void dumpBackForwardList();
+
+private:
+ // Loader Client
+ static void didStartProvisionalLoadForFrame(WKBundlePageRef, WKBundleFrameRef, WKTypeRef*, const void*);
+ static void didReceiveServerRedirectForProvisionalLoadForFrame(WKBundlePageRef, WKBundleFrameRef, WKTypeRef*, const void*);
+ static void didFailProvisionalLoadWithErrorForFrame(WKBundlePageRef, WKBundleFrameRef, WKErrorRef, WKTypeRef*, const void*);
+ static void didCommitLoadForFrame(WKBundlePageRef, WKBundleFrameRef, WKTypeRef*, const void*);
+ static void didFinishLoadForFrame(WKBundlePageRef, WKBundleFrameRef, WKTypeRef*, const void*);
+ static void didFinishDocumentLoadForFrame(WKBundlePageRef, WKBundleFrameRef, WKTypeRef*, const void*);
+ static void didFailLoadWithErrorForFrame(WKBundlePageRef, WKBundleFrameRef, WKErrorRef, WKTypeRef*, const void*);
+ static void didReceiveTitleForFrame(WKBundlePageRef, WKStringRef title, WKBundleFrameRef, WKTypeRef*, const void*);
+ static void didClearWindowForFrame(WKBundlePageRef, WKBundleFrameRef, WKBundleScriptWorldRef, const void*);
+ static void didCancelClientRedirectForFrame(WKBundlePageRef, WKBundleFrameRef, const void*);
+ static void willPerformClientRedirectForFrame(WKBundlePageRef, WKBundleFrameRef, WKURLRef url, double delay, double date, const void*);
+ static void didSameDocumentNavigationForFrame(WKBundlePageRef, WKBundleFrameRef, WKSameDocumentNavigationType, WKTypeRef*, const void*);
+ static void didHandleOnloadEventsForFrame(WKBundlePageRef, WKBundleFrameRef, const void*);
+ static void didDisplayInsecureContentForFrame(WKBundlePageRef, WKBundleFrameRef, WKTypeRef*, const void*);
+ static void didRunInsecureContentForFrame(WKBundlePageRef, WKBundleFrameRef, WKTypeRef*, const void*);
+ void didStartProvisionalLoadForFrame(WKBundleFrameRef);
+ void didReceiveServerRedirectForProvisionalLoadForFrame(WKBundleFrameRef);
+ void didFailProvisionalLoadWithErrorForFrame(WKBundleFrameRef, WKErrorRef);
+ void didCommitLoadForFrame(WKBundleFrameRef);
+ void didFinishLoadForFrame(WKBundleFrameRef);
+ void didFailLoadWithErrorForFrame(WKBundleFrameRef, WKErrorRef);
+ void didReceiveTitleForFrame(WKStringRef title, WKBundleFrameRef);
+ void didClearWindowForFrame(WKBundleFrameRef, WKBundleScriptWorldRef);
+ void didCancelClientRedirectForFrame(WKBundleFrameRef);
+ void willPerformClientRedirectForFrame(WKBundleFrameRef, WKURLRef url, double delay, double date);
+ void didSameDocumentNavigationForFrame(WKBundleFrameRef, WKSameDocumentNavigationType);
+ void didFinishDocumentLoadForFrame(WKBundleFrameRef);
+ void didHandleOnloadEventsForFrame(WKBundleFrameRef);
+ void didDisplayInsecureContentForFrame(WKBundleFrameRef);
+ void didRunInsecureContentForFrame(WKBundleFrameRef);
+
+ // UI Client
+ static void willAddMessageToConsole(WKBundlePageRef, WKStringRef message, uint32_t lineNumber, const void* clientInfo);
+ static void willSetStatusbarText(WKBundlePageRef, WKStringRef statusbarText, const void* clientInfo);
+ static void willRunJavaScriptAlert(WKBundlePageRef, WKStringRef message, WKBundleFrameRef frame, const void* clientInfo);
+ static void willRunJavaScriptConfirm(WKBundlePageRef, WKStringRef message, WKBundleFrameRef frame, const void* clientInfo);
+ static void willRunJavaScriptPrompt(WKBundlePageRef, WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef frame, const void* clientInfo);
+ void willAddMessageToConsole(WKStringRef message, uint32_t lineNumber);
+ void willSetStatusbarText(WKStringRef statusbarText);
+ void willRunJavaScriptAlert(WKStringRef message, WKBundleFrameRef);
+ void willRunJavaScriptConfirm(WKStringRef message, WKBundleFrameRef);
+ void willRunJavaScriptPrompt(WKStringRef message, WKStringRef defaultValue, WKBundleFrameRef);
+
+ // Editor client
+ static bool shouldBeginEditing(WKBundlePageRef, WKBundleRangeHandleRef, const void* clientInfo);
+ static bool shouldEndEditing(WKBundlePageRef, WKBundleRangeHandleRef, const void* clientInfo);
+ static bool shouldInsertNode(WKBundlePageRef, WKBundleNodeHandleRef, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType, const void* clientInfo);
+ static bool shouldInsertText(WKBundlePageRef, WKStringRef, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType, const void* clientInfo);
+ static bool shouldDeleteRange(WKBundlePageRef, WKBundleRangeHandleRef, const void* clientInfo);
+ static bool shouldChangeSelectedRange(WKBundlePageRef, WKBundleRangeHandleRef fromRange, WKBundleRangeHandleRef toRange, WKAffinityType, bool stillSelecting, const void* clientInfo);
+ static bool shouldApplyStyle(WKBundlePageRef, WKBundleCSSStyleDeclarationRef style, WKBundleRangeHandleRef range, const void* clientInfo);
+ static void didBeginEditing(WKBundlePageRef, WKStringRef notificationName, const void* clientInfo);
+ static void didEndEditing(WKBundlePageRef, WKStringRef notificationName, const void* clientInfo);
+ static void didChange(WKBundlePageRef, WKStringRef notificationName, const void* clientInfo);
+ static void didChangeSelection(WKBundlePageRef, WKStringRef notificationName, const void* clientInfo);
+ bool shouldBeginEditing(WKBundleRangeHandleRef);
+ bool shouldEndEditing(WKBundleRangeHandleRef);
+ bool shouldInsertNode(WKBundleNodeHandleRef, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType);
+ bool shouldInsertText(WKStringRef, WKBundleRangeHandleRef rangeToReplace, WKInsertActionType);
+ bool shouldDeleteRange(WKBundleRangeHandleRef);
+ bool shouldChangeSelectedRange(WKBundleRangeHandleRef fromRange, WKBundleRangeHandleRef toRange, WKAffinityType, bool stillSelecting);
+ bool shouldApplyStyle(WKBundleCSSStyleDeclarationRef style, WKBundleRangeHandleRef range);
+ void didBeginEditing(WKStringRef notificationName);
+ void didEndEditing(WKStringRef notificationName);
+ void didChange(WKStringRef notificationName);
+ void didChangeSelection(WKStringRef notificationName);
+
+ void dumpAllFramesText();
+ void dumpAllFrameScrollPositions();
+
+ WKBundlePageRef m_page;
+ WKRetainPtr<WKBundleScriptWorldRef> m_world;
+ WKRetainPtr<WKBundleBackForwardListItemRef> m_previousTestBackForwardListItem;
+ bool m_isLoading;
+};
+
+} // namespace WTR
+
+#endif // InjectedBundlePage_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp
new file mode 100644
index 0000000..60e3130
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.cpp
@@ -0,0 +1,307 @@
+/*
+ * 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 "LayoutTestController.h"
+
+#include "InjectedBundle.h"
+#include "InjectedBundlePage.h"
+#include "JSLayoutTestController.h"
+#include "StringFunctions.h"
+#include <WebKit2/WKBundleBackForwardList.h>
+#include <WebKit2/WKBundleFrame.h>
+#include <WebKit2/WKBundleFramePrivate.h>
+#include <WebKit2/WKBundlePagePrivate.h>
+#include <WebKit2/WKBundleScriptWorld.h>
+#include <WebKit2/WKBundlePrivate.h>
+#include <WebKit2/WKRetainPtr.h>
+#include <WebKit2/WebKit2.h>
+
+namespace WTR {
+
+// This is lower than DumpRenderTree's timeout, to make it easier to work through the failures
+// Eventually it should be changed to match.
+const double LayoutTestController::waitToDumpWatchdogTimerInterval = 6;
+
+static JSValueRef propertyValue(JSContextRef context, JSObjectRef object, const char* propertyName)
+{
+ if (!object)
+ return 0;
+ JSRetainPtr<JSStringRef> propertyNameString(Adopt, JSStringCreateWithUTF8CString(propertyName));
+ JSValueRef exception;
+ return JSObjectGetProperty(context, object, propertyNameString.get(), &exception);
+}
+
+static JSObjectRef propertyObject(JSContextRef context, JSObjectRef object, const char* propertyName)
+{
+ JSValueRef value = propertyValue(context, object, propertyName);
+ if (!value || !JSValueIsObject(context, value))
+ return 0;
+ return const_cast<JSObjectRef>(value);
+}
+
+static JSObjectRef getElementById(WKBundleFrameRef frame, JSStringRef elementId)
+{
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(frame);
+ JSObjectRef document = propertyObject(context, JSContextGetGlobalObject(context), "document");
+ if (!document)
+ return 0;
+ JSValueRef getElementById = propertyObject(context, document, "getElementById");
+ if (!getElementById || !JSValueIsObject(context, getElementById))
+ return 0;
+ JSValueRef elementIdValue = JSValueMakeString(context, elementId);
+ JSValueRef exception;
+ JSValueRef element = JSObjectCallAsFunction(context, const_cast<JSObjectRef>(getElementById), document, 1, &elementIdValue, &exception);
+ if (!element || !JSValueIsObject(context, element))
+ return 0;
+ return const_cast<JSObjectRef>(element);
+}
+
+PassRefPtr<LayoutTestController> LayoutTestController::create()
+{
+ return adoptRef(new LayoutTestController);
+}
+
+LayoutTestController::LayoutTestController()
+ : m_whatToDump(RenderTree)
+ , m_shouldDumpAllFrameScrollPositions(false)
+ , m_shouldDumpBackForwardListsForAllWindows(false)
+ , m_shouldAllowEditing(true)
+ , m_shouldCloseExtraWindows(false)
+ , m_dumpEditingCallbacks(false)
+ , m_dumpStatusCallbacks(false)
+ , m_dumpTitleChanges(false)
+ , m_waitToDump(false)
+ , m_testRepaint(false)
+ , m_testRepaintSweepHorizontally(false)
+{
+ platformInitialize();
+}
+
+LayoutTestController::~LayoutTestController()
+{
+}
+
+JSClassRef LayoutTestController::wrapperClass()
+{
+ return JSLayoutTestController::layoutTestControllerClass();
+}
+
+void LayoutTestController::display()
+{
+ // FIXME: actually implement, once we want pixel tests
+}
+
+void LayoutTestController::waitUntilDone()
+{
+ m_waitToDump = true;
+ initializeWaitToDumpWatchdogTimerIfNeeded();
+}
+
+void LayoutTestController::waitToDumpWatchdogTimerFired()
+{
+ invalidateWaitToDumpWatchdogTimer();
+ const char* message = "FAIL: Timed out waiting for notifyDone to be called\n";
+ InjectedBundle::shared().os() << message << "\n";
+ InjectedBundle::shared().done();
+}
+
+void LayoutTestController::notifyDone()
+{
+ if (m_waitToDump && !InjectedBundle::shared().page()->isLoading())
+ InjectedBundle::shared().page()->dump();
+ m_waitToDump = false;
+}
+
+unsigned LayoutTestController::numberOfActiveAnimations() const
+{
+ // FIXME: Is it OK this works only for the main frame?
+ // FIXME: If this is needed only for the main frame, then why is the function on WKBundleFrame instead of WKBundlePage?
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ return WKBundleFrameGetNumberOfActiveAnimations(mainFrame);
+}
+
+bool LayoutTestController::pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId)
+{
+ // FIXME: Is it OK this works only for the main frame?
+ // FIXME: If this is needed only for the main frame, then why is the function on WKBundleFrame instead of WKBundlePage?
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ return WKBundleFramePauseAnimationOnElementWithId(mainFrame, toWK(animationName).get(), toWK(elementId).get(), time);
+}
+
+void LayoutTestController::suspendAnimations()
+{
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ WKBundleFrameSuspendAnimations(mainFrame);
+}
+
+void LayoutTestController::resumeAnimations()
+{
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ WKBundleFrameResumeAnimations(mainFrame);
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::layerTreeAsText() const
+{
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ WKRetainPtr<WKStringRef> text(AdoptWK, WKBundleFrameCopyLayerTreeAsText(mainFrame));
+ return toJS(text);
+}
+
+void LayoutTestController::addUserScript(JSStringRef source, bool runAtStart, bool allFrames)
+{
+ WKRetainPtr<WKStringRef> sourceWK = toWK(source);
+ WKRetainPtr<WKBundleScriptWorldRef> scriptWorld(AdoptWK, WKBundleScriptWorldCreateWorld());
+
+ WKBundleAddUserScript(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), scriptWorld.get(), sourceWK.get(), 0, 0, 0,
+ (runAtStart ? kWKInjectAtDocumentStart : kWKInjectAtDocumentEnd),
+ (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
+}
+
+void LayoutTestController::addUserStyleSheet(JSStringRef source, bool allFrames)
+{
+ WKRetainPtr<WKStringRef> sourceWK = toWK(source);
+ WKRetainPtr<WKBundleScriptWorldRef> scriptWorld(AdoptWK, WKBundleScriptWorldCreateWorld());
+
+ WKBundleAddUserStyleSheet(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), scriptWorld.get(), sourceWK.get(), 0, 0, 0,
+ (allFrames ? kWKInjectInAllFrames : kWKInjectInTopFrameOnly));
+}
+
+void LayoutTestController::keepWebHistory()
+{
+ WKBundleSetShouldTrackVisitedLinks(InjectedBundle::shared().bundle(), true);
+}
+
+JSValueRef LayoutTestController::computedStyleIncludingVisitedInfo(JSValueRef element)
+{
+ // FIXME: Is it OK this works only for the main frame?
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+ if (!JSValueIsObject(context, element))
+ return JSValueMakeUndefined(context);
+ JSValueRef value = WKBundleFrameGetComputedStyleIncludingVisitedInfo(mainFrame, const_cast<JSObjectRef>(element));
+ if (!value)
+ return JSValueMakeUndefined(context);
+ return value;
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::counterValueForElementById(JSStringRef elementId)
+{
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ JSObjectRef element = getElementById(mainFrame, elementId);
+ if (!element)
+ return 0;
+ WKRetainPtr<WKStringRef> value(AdoptWK, WKBundleFrameCopyCounterValue(mainFrame, const_cast<JSObjectRef>(element)));
+ return toJS(value);
+}
+
+JSRetainPtr<JSStringRef> LayoutTestController::markerTextForListItem(JSValueRef element)
+{
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+ if (!element || !JSValueIsObject(context, element))
+ return 0;
+ WKRetainPtr<WKStringRef> text(AdoptWK, WKBundleFrameCopyMarkerText(mainFrame, const_cast<JSObjectRef>(element)));
+ if (WKStringIsEmpty(text.get()))
+ return 0;
+ return toJS(text);
+}
+
+void LayoutTestController::execCommand(JSStringRef name, JSStringRef argument)
+{
+ WKBundlePageExecuteEditingCommand(InjectedBundle::shared().page()->page(), toWK(name).get(), toWK(argument).get());
+}
+
+bool LayoutTestController::findString(JSStringRef target, JSValueRef optionsArrayAsValue)
+{
+ WKFindOptions options = 0;
+
+ WKBundleFrameRef mainFrame = WKBundlePageGetMainFrame(InjectedBundle::shared().page()->page());
+ JSContextRef context = WKBundleFrameGetJavaScriptContext(mainFrame);
+ JSRetainPtr<JSStringRef> lengthPropertyName(Adopt, JSStringCreateWithUTF8CString("length"));
+ JSObjectRef optionsArray = JSValueToObject(context, optionsArrayAsValue, 0);
+ JSValueRef lengthValue = JSObjectGetProperty(context, optionsArray, lengthPropertyName.get(), 0);
+ if (!JSValueIsNumber(context, lengthValue))
+ return false;
+
+ 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 |= kWKFindOptionsCaseInsensitive;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "AtWordStarts"))
+ options |= kWKFindOptionsAtWordStarts;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "TreatMedialCapitalAsWordStart"))
+ options |= kWKFindOptionsTreatMedialCapitalAsWordStart;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "Backwards"))
+ options |= kWKFindOptionsBackwards;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "WrapAround"))
+ options |= kWKFindOptionsWrapAround;
+ else if (JSStringIsEqualToUTF8CString(optionName.get(), "StartInSelection")) {
+ // FIXME: No kWKFindOptionsStartInSelection.
+ }
+ }
+
+ return WKBundlePageFindString(InjectedBundle::shared().page()->page(), toWK(target).get(), options);
+}
+
+bool LayoutTestController::isCommandEnabled(JSStringRef name)
+{
+ return WKBundlePageIsEditingCommandEnabled(InjectedBundle::shared().page()->page(), toWK(name).get());
+}
+
+void LayoutTestController::setCanOpenWindows(bool)
+{
+ // It's not clear if or why any tests require opening windows be forbidden.
+ // For now, just ignore this setting, and if we find later it's needed we can add it.
+}
+
+void LayoutTestController::setXSSAuditorEnabled(bool enabled)
+{
+ WKBundleOverrideXSSAuditorEnabledForTestRunner(InjectedBundle::shared().bundle(), InjectedBundle::shared().pageGroup(), true);
+}
+
+unsigned LayoutTestController::windowCount()
+{
+ return InjectedBundle::shared().pageCount();
+}
+
+void LayoutTestController::clearBackForwardList()
+{
+ WKBundleBackForwardListClear(WKBundlePageGetBackForwardList(InjectedBundle::shared().page()->page()));
+}
+
+// Object Creation
+
+void LayoutTestController::makeWindowObject(JSContextRef context, JSObjectRef windowObject, JSValueRef* exception)
+{
+ setProperty(context, windowObject, "layoutTestController", this, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete, exception);
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h
new file mode 100644
index 0000000..2aaad08
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/LayoutTestController.h
@@ -0,0 +1,152 @@
+/*
+ * 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 LayoutTestController_h
+#define LayoutTestController_h
+
+#include "JSWrappable.h"
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <string>
+#include <wtf/PassRefPtr.h>
+
+#if PLATFORM(MAC)
+#include <wtf/RetainPtr.h>
+typedef RetainPtr<CFRunLoopTimerRef> PlatformTimerRef;
+#elif PLATFORM(WIN)
+typedef UINT_PTR PlatformTimerRef;
+#elif PLATFORM(QT)
+#include <QTimer>
+typedef QTimer PlatformTimerRef;
+#endif
+
+namespace WTR {
+
+class LayoutTestController : public JSWrappable {
+public:
+ static PassRefPtr<LayoutTestController> create();
+ virtual ~LayoutTestController();
+
+ // JSWrappable
+ virtual JSClassRef wrapperClass();
+
+ void makeWindowObject(JSContextRef, JSObjectRef windowObject, JSValueRef* exception);
+
+ // The basics.
+ void dumpAsText() { m_whatToDump = MainFrameText; }
+ void dumpChildFramesAsText() { m_whatToDump = AllFramesText; }
+ void waitUntilDone();
+ void notifyDone();
+
+ // Other dumping.
+ void dumpBackForwardList() { m_shouldDumpBackForwardListsForAllWindows = true; }
+ void dumpChildFrameScrollPositions() { m_shouldDumpAllFrameScrollPositions = true; }
+ void dumpEditingCallbacks() { m_dumpEditingCallbacks = true; }
+ void dumpSelectionRect() { } // Will need to do something when we support pixel tests.
+ void dumpStatusCallbacks() { m_dumpStatusCallbacks = true; }
+ void dumpTitleChanges() { m_dumpTitleChanges = true; }
+
+ // Special options.
+ void keepWebHistory();
+ void setAcceptsEditing(bool value) { m_shouldAllowEditing = value; }
+ void setCanOpenWindows(bool);
+ void setCloseRemainingWindowsWhenComplete(bool value) { m_shouldCloseExtraWindows = value; }
+ void setXSSAuditorEnabled(bool);
+
+ // Special DOM functions.
+ JSValueRef computedStyleIncludingVisitedInfo(JSValueRef element);
+ JSRetainPtr<JSStringRef> counterValueForElementById(JSStringRef elementId);
+ void clearBackForwardList();
+ void execCommand(JSStringRef name, JSStringRef argument);
+ bool isCommandEnabled(JSStringRef name);
+ JSRetainPtr<JSStringRef> markerTextForListItem(JSValueRef element);
+ unsigned windowCount();
+
+ // Repaint testing.
+ void testRepaint() { m_testRepaint = true; }
+ void repaintSweepHorizontally() { m_testRepaintSweepHorizontally = true; }
+ void display();
+
+ // Animation testing.
+ unsigned numberOfActiveAnimations() const;
+ bool pauseAnimationAtTimeOnElementWithId(JSStringRef animationName, double time, JSStringRef elementId);
+ void suspendAnimations();
+ void resumeAnimations();
+
+ // Compositing testing.
+ JSRetainPtr<JSStringRef> layerTreeAsText() const;
+
+ // UserContent testing.
+ void addUserScript(JSStringRef source, bool runAtStart, bool allFrames);
+ void addUserStyleSheet(JSStringRef source, bool allFrames);
+
+ // Text search testing.
+ bool findString(JSStringRef, JSValueRef optionsArray);
+
+ enum WhatToDump { RenderTree, MainFrameText, AllFramesText };
+ WhatToDump whatToDump() const { return m_whatToDump; }
+
+ bool shouldDumpAllFrameScrollPositions() const { return m_shouldDumpAllFrameScrollPositions; }
+ bool shouldDumpBackForwardListsForAllWindows() const { return m_shouldDumpBackForwardListsForAllWindows; }
+ bool shouldDumpEditingCallbacks() const { return m_dumpEditingCallbacks; }
+ bool shouldDumpMainFrameScrollPosition() const { return m_whatToDump == RenderTree; }
+ bool shouldDumpStatusCallbacks() const { return m_dumpStatusCallbacks; }
+ bool shouldDumpTitleChanges() const { return m_dumpTitleChanges; }
+
+ bool waitToDump() const { return m_waitToDump; }
+ void waitToDumpWatchdogTimerFired();
+ void invalidateWaitToDumpWatchdogTimer();
+
+ bool shouldAllowEditing() const { return m_shouldAllowEditing; }
+
+ bool shouldCloseExtraWindowsAfterRunningTest() const { return m_shouldCloseExtraWindows; }
+
+private:
+ static const double waitToDumpWatchdogTimerInterval;
+
+ LayoutTestController();
+
+ void platformInitialize();
+ void initializeWaitToDumpWatchdogTimerIfNeeded();
+
+ WhatToDump m_whatToDump;
+ bool m_shouldDumpAllFrameScrollPositions;
+ bool m_shouldDumpBackForwardListsForAllWindows;
+
+ bool m_shouldAllowEditing;
+ bool m_shouldCloseExtraWindows;
+
+ bool m_dumpEditingCallbacks;
+ bool m_dumpStatusCallbacks;
+ bool m_dumpTitleChanges;
+ bool m_waitToDump; // True if waitUntilDone() has been called, but notifyDone() has not yet been called.
+ bool m_testRepaint;
+ bool m_testRepaintSweepHorizontally;
+
+ PlatformTimerRef m_waitToDumpWatchdogTimer;
+};
+
+} // namespace WTR
+
+#endif // LayoutTestController_h
diff --git a/Tools/WebKitTestRunner/InjectedBundle/mac/ActivateFonts.mm b/Tools/WebKitTestRunner/InjectedBundle/mac/ActivateFonts.mm
new file mode 100644
index 0000000..b5bc4a1
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/mac/ActivateFonts.mm
@@ -0,0 +1,75 @@
+/*
+ * 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 "ActivateFonts.h"
+
+#import <AppKit/AppKit.h>
+#import <CoreFoundation/CoreFoundation.h>
+#import <Foundation/Foundation.h>
+
+@interface WKTRFontActivatorDummyClass : NSObject
+@end
+
+@implementation WKTRFontActivatorDummyClass
+@end
+
+namespace WTR {
+
+void activateFonts()
+{
+ // Work around <rdar://problem/6698023> by activating fonts from disk
+
+ static const char* fontFileNames[] = {
+ "AHEM____.TTF",
+ "ColorBits.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 = [[NSBundle bundleForClass:[WKTRFontActivatorDummyClass class]] resourceURL];
+ 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);
+ }
+}
+
+}
+
diff --git a/Tools/WebKitTestRunner/InjectedBundle/mac/LayoutTestControllerMac.mm b/Tools/WebKitTestRunner/InjectedBundle/mac/LayoutTestControllerMac.mm
new file mode 100644
index 0000000..2eb4d5b
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/mac/LayoutTestControllerMac.mm
@@ -0,0 +1,59 @@
+/*
+ * 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 "LayoutTestController.h"
+
+#include "InjectedBundle.h"
+
+namespace WTR {
+
+void LayoutTestController::platformInitialize()
+{
+}
+
+void LayoutTestController::invalidateWaitToDumpWatchdogTimer()
+{
+ if (!m_waitToDumpWatchdogTimer)
+ return;
+
+ CFRunLoopTimerInvalidate(m_waitToDumpWatchdogTimer.get());
+ m_waitToDumpWatchdogTimer = 0;
+}
+
+static void waitUntilDoneWatchdogTimerFired(CFRunLoopTimerRef timer, void* info)
+{
+ InjectedBundle::shared().layoutTestController()->waitToDumpWatchdogTimerFired();
+}
+
+void LayoutTestController::initializeWaitToDumpWatchdogTimerIfNeeded()
+{
+ if (m_waitToDumpWatchdogTimer)
+ return;
+
+ m_waitToDumpWatchdogTimer.adoptCF(CFRunLoopTimerCreate(kCFAllocatorDefault, CFAbsoluteTimeGetCurrent() + waitToDumpWatchdogTimerInterval, 0, 0, 0, WTR::waitUntilDoneWatchdogTimerFired, NULL));
+ CFRunLoopAddTimer(CFRunLoopGetCurrent(), m_waitToDumpWatchdogTimer.get(), kCFRunLoopCommonModes);
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp b/Tools/WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp
new file mode 100644
index 0000000..d8166d0
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/qt/ActivateFontsQt.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2005, 2006 Apple Computer, Inc. All rights reserved.
+ * 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 "ActivateFonts.h"
+
+#include <QByteArray>
+#include <QDir>
+
+#ifdef Q_WS_X11
+#include <fontconfig/fontconfig.h>
+#endif
+
+#include <limits.h>
+
+namespace WTR {
+
+void activateFonts()
+{
+#if defined(Q_WS_X11)
+ static int numFonts = -1;
+
+ // 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/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro b/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro
new file mode 100644
index 0000000..f7d0989
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/qt/InjectedBundle.pro
@@ -0,0 +1,77 @@
+TEMPLATE = lib
+
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../../..
+
+CONFIG(standalone_package) {
+ isEmpty(WC_GENERATED_SOURCES_DIR):WC_GENERATED_SOURCES_DIR = $$PWD/../../../../WebCore/generated
+} else {
+ isEmpty(WC_GENERATED_SOURCES_DIR):WC_GENERATED_SOURCES_DIR = ../../../../WebCore/generated
+}
+
+GENERATED_SOURCES_DIR = ../../generated
+
+SOURCES += \
+ ../InjectedBundle.cpp \
+ ../InjectedBundle.h \
+ ../InjectedBundleMain.cpp \
+ ../InjectedBundlePage.cpp \
+ ../InjectedBundlePage.h \
+ ../EventSendingController.cpp \
+ ../EventSendingController.h \
+ ../GCController.cpp \
+ ../GCController.h \
+ ../LayoutTestController.cpp \
+ ../LayoutTestController.h \
+ ../Bindings/JSWrapper.cpp \
+ ActivateFontsQt.cpp \
+ LayoutTestControllerQt.cpp \
+ $$GENERATED_SOURCES_DIR/JSEventSendingController.cpp \
+ $$GENERATED_SOURCES_DIR/JSGCController.cpp \
+ $$GENERATED_SOURCES_DIR/JSLayoutTestController.cpp \
+
+HEADERS += \
+ ../ActivateFonts.h \
+ ../EventSendingController.h \
+ ../GCController.h \
+ ../InjectedBundle.h \
+ ../InjectedBundlePage.h \
+ ../LayoutTestController.h \
+
+!CONFIG(release, debug|release) {
+ OBJECTS_DIR = obj/debug
+} else { # Release
+ OBJECTS_DIR = obj/release
+}
+
+include(../../../../WebKit.pri)
+include(../../../../JavaScriptCore/JavaScriptCore.pri)
+addJavaScriptCoreLib(../../../../JavaScriptCore)
+include(../../../../WebKit2/WebKit2.pri)
+addWebKit2Lib(../../../../WebKit2)
+
+INCLUDEPATH += \
+ $$PWD \
+ $$PWD/.. \
+ $$PWD/../.. \
+ $$PWD/../Bindings \
+ $$PWD/../../../../JavaScriptCore \
+ $$PWD/../../../../JavaScriptCore/wtf \
+ $$PWD/../../../../WebKit2 \
+ $$PWD/../../../../WebKit2/Shared \
+ $$GENERATED_SOURCES_DIR
+
+INCLUDEPATH += \
+ $$OUTPUT_DIR/include \
+ $$WC_GENERATED_SOURCES_DIR
+
+PREFIX_HEADER = $$PWD/../../WebKitTestRunnerPrefix.h
+QMAKE_CXXFLAGS += "-include $$PREFIX_HEADER"
+
+unix:!mac:!symbian {
+ CONFIG += link_pkgconfig
+ PKGCONFIG += fontconfig
+}
+
+TARGET = WTRInjectedBundle
+DESTDIR = $$OUTPUT_DIR/lib
+!CONFIG(standalone_package): CONFIG -= app_bundle
diff --git a/Tools/WebKitTestRunner/InjectedBundle/qt/LayoutTestControllerQt.cpp b/Tools/WebKitTestRunner/InjectedBundle/qt/LayoutTestControllerQt.cpp
new file mode 100644
index 0000000..b515326
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/qt/LayoutTestControllerQt.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 University of Szeged. 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 "LayoutTestController.h"
+
+#include "InjectedBundle.h"
+#include <QObject>
+
+namespace WTR {
+
+class WatchdogTimerHelper : public QObject {
+ Q_OBJECT
+
+public:
+ static WatchdogTimerHelper* instance()
+ {
+ static WatchdogTimerHelper* theInstance = new WatchdogTimerHelper;
+ return theInstance;
+ }
+
+public slots:
+ void timerFired()
+ {
+ InjectedBundle::shared().layoutTestController()->waitToDumpWatchdogTimerFired();
+ }
+
+private:
+ WatchdogTimerHelper() {}
+};
+
+void LayoutTestController::platformInitialize()
+{
+ QObject::connect(&m_waitToDumpWatchdogTimer, SIGNAL(timeout()), WatchdogTimerHelper::instance(), SLOT(timerFired()));
+}
+
+void LayoutTestController::invalidateWaitToDumpWatchdogTimer()
+{
+ m_waitToDumpWatchdogTimer.stop();
+}
+
+void LayoutTestController::initializeWaitToDumpWatchdogTimerIfNeeded()
+{
+ if (m_waitToDumpWatchdogTimer.isActive())
+ return;
+
+ m_waitToDumpWatchdogTimer.start(waitToDumpWatchdogTimerInterval * 1000);
+}
+
+} // namespace WTR
+
+#include "LayoutTestControllerQt.moc"
diff --git a/Tools/WebKitTestRunner/InjectedBundle/win/ActivateFonts.cpp b/Tools/WebKitTestRunner/InjectedBundle/win/ActivateFonts.cpp
new file mode 100644
index 0000000..d9f08c9
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/win/ActivateFonts.cpp
@@ -0,0 +1,107 @@
+/*
+ * 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 "ActivateFonts.h"
+
+#include <string>
+#include <wtf/Vector.h>
+
+static LPCWSTR fontsEnvironmentVariable = L"WEBKIT_TESTFONTS";
+
+namespace WTR {
+
+using namespace std;
+
+static const wstring& fontsPath()
+{
+ static wstring path;
+ static bool initialized;
+
+ if (initialized)
+ return path;
+ initialized = true;
+
+ DWORD size = ::GetEnvironmentVariableW(fontsEnvironmentVariable, 0, 0);
+ Vector<WCHAR> buffer(size);
+ if (!::GetEnvironmentVariableW(fontsEnvironmentVariable, buffer.data(), buffer.size()))
+ return path;
+
+ path = buffer.data();
+ if (path[path.length() - 1] != '\\')
+ path.append(L"\\");
+
+ return path;
+}
+
+
+void activateFonts()
+{
+ static LPCWSTR 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();
+
+ for (unsigned i = 0; i < ARRAYSIZE(fontsToInstall); ++i)
+ ::AddFontResourceExW(wstring(resourcesPath + fontsToInstall[i]).c_str(), FR_PRIVATE, 0);
+}
+
+}
diff --git a/Tools/WebKitTestRunner/InjectedBundle/win/LayoutTestControllerWin.cpp b/Tools/WebKitTestRunner/InjectedBundle/win/LayoutTestControllerWin.cpp
new file mode 100644
index 0000000..39cd727
--- /dev/null
+++ b/Tools/WebKitTestRunner/InjectedBundle/win/LayoutTestControllerWin.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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 "LayoutTestController.h"
+
+#include "InjectedBundle.h"
+
+namespace WTR {
+
+void LayoutTestController::platformInitialize()
+{
+ m_waitToDumpWatchdogTimer = 0;
+}
+
+void LayoutTestController::invalidateWaitToDumpWatchdogTimer()
+{
+ if (!m_waitToDumpWatchdogTimer)
+ return;
+
+ ::KillTimer(0, m_waitToDumpWatchdogTimer);
+ m_waitToDumpWatchdogTimer = 0;
+}
+
+static void CALLBACK waitToDumpWatchdogTimerFired(HWND, UINT, UINT_PTR, DWORD)
+{
+ InjectedBundle::shared().layoutTestController()->waitToDumpWatchdogTimerFired();
+}
+
+static const UINT_PTR waitToDumpWatchdogTimerIdentifier = 1;
+
+void LayoutTestController::initializeWaitToDumpWatchdogTimerIfNeeded()
+{
+ if (m_waitToDumpWatchdogTimer)
+ return;
+
+ m_waitToDumpWatchdogTimer = ::SetTimer(0, waitToDumpWatchdogTimerIdentifier, waitToDumpWatchdogTimerInterval * 1000, WTR::waitToDumpWatchdogTimerFired);
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/Makefile b/Tools/WebKitTestRunner/Makefile
new file mode 100644
index 0000000..4648f98
--- /dev/null
+++ b/Tools/WebKitTestRunner/Makefile
@@ -0,0 +1,21 @@
+# Build WebKitTestRunner only on Snow Leopard and later.
+
+OSX_VERSION ?= $(shell sw_vers -productVersion | cut -d. -f 2)
+BUILD_WEBKITTESTRUNNER = $(shell (( $(OSX_VERSION) >= 6 )) && echo "YES" )
+
+ifeq "$(BUILD_WEBKITTESTRUNNER)" "YES"
+
+SCRIPTS_PATH = ../Scripts
+include ../../Makefile.shared
+
+else
+
+all: ;
+
+debug d development dev develop: ;
+
+release r deployment dep deploy: ;
+
+clean: ;
+
+endif
diff --git a/Tools/WebKitTestRunner/PlatformWebView.h b/Tools/WebKitTestRunner/PlatformWebView.h
new file mode 100644
index 0000000..9739d42
--- /dev/null
+++ b/Tools/WebKitTestRunner/PlatformWebView.h
@@ -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.
+ */
+
+#ifndef PlatformWebView_h
+#define PlatformWebView_h
+
+#if defined(BUILDING_QT__)
+namespace WTR {
+class WebView;
+}
+typedef WTR::WebView* PlatformWKView;
+class QMainWindow;
+typedef QMainWindow* PlatformWindow;
+#elif defined(__APPLE__) && __APPLE__
+#if __OBJC__
+@class WKView;
+@class NSWindow;
+#else
+class WKView;
+class NSWindow;
+#endif
+typedef WKView* PlatformWKView;
+typedef NSWindow* PlatformWindow;
+#elif defined(WIN32) || defined(_WIN32)
+typedef WKViewRef PlatformWKView;
+typedef HWND PlatformWindow;
+#endif
+
+namespace WTR {
+
+class PlatformWebView {
+public:
+ PlatformWebView(WKContextRef, WKPageGroupRef);
+ ~PlatformWebView();
+
+ WKPageRef page();
+ PlatformWKView platformView() { return m_view; }
+ void resizeTo(unsigned width, unsigned height);
+ void focus();
+
+ WKRect windowFrame();
+ void setWindowFrame(WKRect);
+
+private:
+ PlatformWKView m_view;
+ PlatformWindow m_window;
+};
+
+} // namespace WTR
+
+#endif // PlatformWebView_h
diff --git a/Tools/WebKitTestRunner/StringFunctions.h b/Tools/WebKitTestRunner/StringFunctions.h
new file mode 100644
index 0000000..2d0ca72
--- /dev/null
+++ b/Tools/WebKitTestRunner/StringFunctions.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 University of Szeged. 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 StringFunctions_h
+#define StringFunctions_h
+
+#include <JavaScriptCore/JSRetainPtr.h>
+#include <JavaScriptCore/JavaScript.h>
+#include <sstream>
+#include <string>
+#include <WebKit2/WKRetainPtr.h>
+#include <WebKit2/WKString.h>
+#include <WebKit2/WKStringPrivate.h>
+#include <WebKit2/WKURL.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/PassOwnArrayPtr.h>
+#include <wtf/Platform.h>
+#include <wtf/Vector.h>
+
+namespace WTR {
+
+// Conversion functions
+
+inline WKRetainPtr<WKStringRef> toWK(JSStringRef string)
+{
+ return WKRetainPtr<WKStringRef>(AdoptWK, WKStringCreateWithJSString(string));
+}
+
+inline WKRetainPtr<WKStringRef> toWK(JSRetainPtr<JSStringRef> string)
+{
+ return toWK(string.get());
+}
+
+inline JSRetainPtr<JSStringRef> toJS(WKStringRef string)
+{
+ return JSRetainPtr<JSStringRef>(Adopt, WKStringCopyJSString(string));
+}
+
+inline JSRetainPtr<JSStringRef> toJS(const WKRetainPtr<WKStringRef>& string)
+{
+ return toJS(string.get());
+}
+
+inline std::string toSTD(WKStringRef string)
+{
+ size_t bufferSize = WKStringGetMaximumUTF8CStringSize(string);
+ OwnArrayPtr<char> buffer = adoptArrayPtr(new char[bufferSize]);
+ size_t stringLength = WKStringGetUTF8CString(string, buffer.get(), bufferSize);
+ return std::string(buffer.get(), stringLength - 1);
+}
+
+inline std::string toSTD(const WKRetainPtr<WKStringRef>& string)
+{
+ return toSTD(string.get());
+}
+
+// Streaming functions
+
+inline std::ostream& operator<<(std::ostream& out, WKStringRef stringRef)
+{
+ if (!stringRef)
+ return out;
+
+ return out << toSTD(stringRef);
+}
+
+inline std::ostream& operator<<(std::ostream& out, const WKRetainPtr<WKStringRef>& stringRef)
+{
+ return out << stringRef.get();
+}
+
+} // namespace WTR
+
+#endif // StringFunctions_h
diff --git a/Tools/WebKitTestRunner/TestController.cpp b/Tools/WebKitTestRunner/TestController.cpp
new file mode 100644
index 0000000..77213a2
--- /dev/null
+++ b/Tools/WebKitTestRunner/TestController.cpp
@@ -0,0 +1,408 @@
+/*
+ * 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 "TestController.h"
+
+#include "PlatformWebView.h"
+#include "StringFunctions.h"
+#include "TestInvocation.h"
+#include <cstdio>
+#include <WebKit2/WKPageGroup.h>
+#include <WebKit2/WKContextPrivate.h>
+#include <WebKit2/WKPreferencesPrivate.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace WTR {
+
+static const double defaultLongTimeout = 30;
+static const double defaultShortTimeout = 5;
+
+static WKURLRef blankURL()
+{
+ static WKURLRef staticBlankURL = WKURLCreateWithUTF8CString("about:blank");
+ return staticBlankURL;
+}
+
+static TestController* controller;
+
+TestController& TestController::shared()
+{
+ ASSERT(controller);
+ return *controller;
+}
+
+TestController::TestController(int argc, const char* argv[])
+ : m_dumpPixels(false)
+ , m_verbose(false)
+ , m_printSeparators(false)
+ , m_usingServerMode(false)
+ , m_state(Initial)
+ , m_doneResetting(false)
+ , m_longTimeout(defaultLongTimeout)
+ , m_shortTimeout(defaultShortTimeout)
+{
+ initialize(argc, argv);
+ controller = this;
+ run();
+ controller = 0;
+}
+
+TestController::~TestController()
+{
+}
+
+static WKRect getWindowFrameMainPage(WKPageRef page, const void* clientInfo)
+{
+ PlatformWebView* view = static_cast<TestController*>(const_cast<void*>(clientInfo))->mainWebView();
+ return view->windowFrame();
+}
+
+static void setWindowFrameMainPage(WKPageRef page, WKRect frame, const void* clientInfo)
+{
+ PlatformWebView* view = static_cast<TestController*>(const_cast<void*>(clientInfo))->mainWebView();
+ view->setWindowFrame(frame);
+}
+
+static WKRect getWindowFrameOtherPage(WKPageRef page, const void* clientInfo)
+{
+ PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
+ return view->windowFrame();
+}
+
+static void setWindowFrameOtherPage(WKPageRef page, WKRect frame, const void* clientInfo)
+{
+ PlatformWebView* view = static_cast<PlatformWebView*>(const_cast<void*>(clientInfo));
+ view->setWindowFrame(frame);
+}
+
+static void closeOtherPage(WKPageRef page, const void* clientInfo)
+{
+ WKPageClose(page);
+ const PlatformWebView* view = static_cast<const PlatformWebView*>(clientInfo);
+ delete view;
+}
+
+static WKPageRef createOtherPage(WKPageRef oldPage, WKDictionaryRef, WKEventModifiers, WKEventMouseButton, const void*)
+{
+ PlatformWebView* view = new PlatformWebView(WKPageGetContext(oldPage), WKPageGetPageGroup(oldPage));
+ WKPageRef newPage = view->page();
+
+ view->resizeTo(800, 600);
+
+ WKPageUIClient otherPageUIClient = {
+ 0,
+ view,
+ createOtherPage,
+ 0, // showPage
+ closeOtherPage,
+ 0, // runJavaScriptAlert
+ 0, // runJavaScriptConfirm
+ 0, // runJavaScriptPrompt
+ 0, // setStatusText
+ 0, // mouseDidMoveOverElement
+ 0, // missingPluginButtonClicked
+ 0, // didNotHandleKeyEvent
+ 0, // toolbarsAreVisible
+ 0, // setToolbarsAreVisible
+ 0, // menuBarIsVisible
+ 0, // setMenuBarIsVisible
+ 0, // statusBarIsVisible
+ 0, // setStatusBarIsVisible
+ 0, // isResizable
+ 0, // setIsResizable
+ getWindowFrameOtherPage,
+ setWindowFrameOtherPage,
+ 0, // runBeforeUnloadConfirmPanel
+ 0, // didDraw
+ 0, // pageDidScroll
+ 0, // exceededDatabaseQuota
+ 0 // runOpenPanel
+ };
+ WKPageSetPageUIClient(newPage, &otherPageUIClient);
+
+ WKRetain(newPage);
+ return newPage;
+}
+
+void TestController::initialize(int argc, const char* argv[])
+{
+ platformInitialize();
+
+ bool printSupportedFeatures = false;
+
+ for (int i = 1; i < argc; ++i) {
+ std::string argument(argv[i]);
+
+ if (argument == "--timeout" && i + 1 < argc) {
+ m_longTimeout = atoi(argv[++i]);
+ // Scale up the short timeout to match.
+ m_shortTimeout = defaultShortTimeout * m_longTimeout / defaultLongTimeout;
+ continue;
+ }
+ if (argument == "--pixel-tests") {
+ m_dumpPixels = true;
+ continue;
+ }
+ if (argument == "--verbose") {
+ m_verbose = true;
+ continue;
+ }
+ if (argument == "--print-supported-features") {
+ printSupportedFeatures = true;
+ break;
+ }
+
+ // Skip any other arguments that begin with '--'.
+ if (argument.length() >= 2 && argument[0] == '-' && argument[1] == '-')
+ continue;
+
+ m_paths.push_back(argument);
+ }
+
+ if (printSupportedFeatures) {
+ // FIXME: On Windows, DumpRenderTree uses this to expose whether it supports 3d
+ // transforms and accelerated compositing. When we support those features, we
+ // should match DRT's behavior.
+ exit(0);
+ }
+
+ m_usingServerMode = (m_paths.size() == 1 && m_paths[0] == "-");
+ if (m_usingServerMode)
+ m_printSeparators = true;
+ else
+ m_printSeparators = m_paths.size() > 1;
+
+ initializeInjectedBundlePath();
+ initializeTestPluginDirectory();
+
+ WKRetainPtr<WKStringRef> pageGroupIdentifier(AdoptWK, WKStringCreateWithUTF8CString("WebKitTestRunnerPageGroup"));
+ m_pageGroup.adopt(WKPageGroupCreateWithIdentifier(pageGroupIdentifier.get()));
+
+ m_context.adopt(WKContextCreateWithInjectedBundlePath(injectedBundlePath()));
+ platformInitializeContext();
+
+ WKContextInjectedBundleClient injectedBundleClient = {
+ 0,
+ this,
+ didReceiveMessageFromInjectedBundle,
+ didReceiveSynchronousMessageFromInjectedBundle
+ };
+ WKContextSetInjectedBundleClient(m_context.get(), &injectedBundleClient);
+
+ _WKContextSetAdditionalPluginsDirectory(m_context.get(), testPluginDirectory());
+
+ m_mainWebView = adoptPtr(new PlatformWebView(m_context.get(), m_pageGroup.get()));
+
+ WKPageUIClient pageUIClient = {
+ 0,
+ this,
+ createOtherPage,
+ 0, // showPage
+ 0, // close
+ 0, // runJavaScriptAlert
+ 0, // runJavaScriptConfirm
+ 0, // runJavaScriptPrompt
+ 0, // setStatusText
+ 0, // mouseDidMoveOverElement
+ 0, // missingPluginButtonClicked
+ 0, // didNotHandleKeyEvent
+ 0, // toolbarsAreVisible
+ 0, // setToolbarsAreVisible
+ 0, // menuBarIsVisible
+ 0, // setMenuBarIsVisible
+ 0, // statusBarIsVisible
+ 0, // setStatusBarIsVisible
+ 0, // isResizable
+ 0, // setIsResizable
+ getWindowFrameMainPage,
+ setWindowFrameMainPage,
+ 0, // runBeforeUnloadConfirmPanel
+ 0, // didDraw
+ 0, // pageDidScroll
+ 0, // exceededDatabaseQuota
+ 0 // runOpenPanel
+ };
+ WKPageSetPageUIClient(m_mainWebView->page(), &pageUIClient);
+
+ WKPageLoaderClient pageLoaderClient = {
+ 0,
+ this,
+ 0, // didStartProvisionalLoadForFrame
+ 0, // didReceiveServerRedirectForProvisionalLoadForFrame
+ 0, // didFailProvisionalLoadWithErrorForFrame
+ 0, // didCommitLoadForFrame
+ 0, // didFinishDocumentLoadForFrame
+ didFinishLoadForFrame,
+ 0, // didFailLoadWithErrorForFrame
+ 0, // didSameDocumentNavigationForFrame
+ 0, // didReceiveTitleForFrame
+ 0, // didFirstLayoutForFrame
+ 0, // didFirstVisuallyNonEmptyLayoutForFrame
+ 0, // didRemoveFrameFromHierarchy
+ 0, // didDisplayInsecureContentForFrame
+ 0, // didRunInsecureContentForFrame
+ 0, // canAuthenticateAgainstProtectionSpaceInFrame
+ 0, // didReceiveAuthenticationChallengeInFrame
+ 0, // didStartProgress
+ 0, // didChangeProgress
+ 0, // didFinishProgress
+ 0, // didBecomeUnresponsive
+ 0, // didBecomeResponsive
+ 0, // processDidExit
+ 0 // didChangeBackForwardList
+ };
+ WKPageSetPageLoaderClient(m_mainWebView->page(), &pageLoaderClient);
+}
+
+bool TestController::resetStateToConsistentValues()
+{
+ m_state = Resetting;
+
+ // FIXME: This function should also ensure that there is only one page open.
+
+ // Reset preferences
+ WKPreferencesRef preferences = WKPageGroupGetPreferences(m_pageGroup.get());
+ WKPreferencesSetOfflineWebApplicationCacheEnabled(preferences, true);
+ WKPreferencesSetFontSmoothingLevel(preferences, kWKFontSmoothingLevelNoSubpixelAntiAliasing);
+ WKPreferencesSetXSSAuditorEnabled(preferences, false);
+ WKPreferencesSetDeveloperExtrasEnabled(preferences, true);
+ WKPreferencesSetJavaScriptCanOpenWindowsAutomatically(preferences, true);
+
+ static WKStringRef standardFontFamily = WKStringCreateWithUTF8CString("Times");
+ static WKStringRef cursiveFontFamily = WKStringCreateWithUTF8CString("Apple Chancery");
+ static WKStringRef fantasyFontFamily = WKStringCreateWithUTF8CString("Papyrus");
+ static WKStringRef fixedFontFamily = WKStringCreateWithUTF8CString("Courier");
+ static WKStringRef sansSerifFontFamily = WKStringCreateWithUTF8CString("Helvetica");
+ static WKStringRef serifFontFamily = WKStringCreateWithUTF8CString("Times");
+
+ WKPreferencesSetStandardFontFamily(preferences, standardFontFamily);
+ WKPreferencesSetCursiveFontFamily(preferences, cursiveFontFamily);
+ WKPreferencesSetFantasyFontFamily(preferences, fantasyFontFamily);
+ WKPreferencesSetFixedFontFamily(preferences, fixedFontFamily);
+ WKPreferencesSetSansSerifFontFamily(preferences, sansSerifFontFamily);
+ WKPreferencesSetSerifFontFamily(preferences, serifFontFamily);
+
+ m_mainWebView->focus();
+
+ // Reset main page back to about:blank
+ m_doneResetting = false;
+
+ WKPageLoadURL(m_mainWebView->page(), blankURL());
+ runUntil(m_doneResetting, ShortTimeout);
+ return m_doneResetting;
+}
+
+bool TestController::runTest(const char* test)
+{
+ if (!resetStateToConsistentValues())
+ return false;
+
+ m_state = RunningTest;
+ m_currentInvocation.set(new TestInvocation(test));
+ m_currentInvocation->invoke();
+ m_currentInvocation.clear();
+
+ return true;
+}
+
+void TestController::runTestingServerLoop()
+{
+ char filenameBuffer[2048];
+ while (fgets(filenameBuffer, sizeof(filenameBuffer), stdin)) {
+ char *newLineCharacter = strchr(filenameBuffer, '\n');
+ if (newLineCharacter)
+ *newLineCharacter = '\0';
+
+ if (strlen(filenameBuffer) == 0)
+ continue;
+
+ if (!runTest(filenameBuffer))
+ break;
+ }
+}
+
+void TestController::run()
+{
+ if (m_usingServerMode)
+ runTestingServerLoop();
+ else {
+ for (size_t i = 0; i < m_paths.size(); ++i) {
+ if (!runTest(m_paths[i].c_str()))
+ break;
+ }
+ }
+}
+
+void TestController::runUntil(bool& done, TimeoutDuration timeoutDuration)
+{
+ platformRunUntil(done, timeoutDuration == ShortTimeout ? m_shortTimeout : m_longTimeout);
+}
+
+// WKContextInjectedBundleClient
+
+void TestController::didReceiveMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, const void* clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveMessageFromInjectedBundle(messageName, messageBody);
+}
+
+void TestController::didReceiveSynchronousMessageFromInjectedBundle(WKContextRef context, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void* clientInfo)
+{
+ *returnData = static_cast<TestController*>(const_cast<void*>(clientInfo))->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody).leakRef();
+}
+
+void TestController::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
+{
+ m_currentInvocation->didReceiveMessageFromInjectedBundle(messageName, messageBody);
+}
+
+WKRetainPtr<WKTypeRef> TestController::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
+{
+ return m_currentInvocation->didReceiveSynchronousMessageFromInjectedBundle(messageName, messageBody);
+}
+
+// WKPageLoaderClient
+
+void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef, const void* clientInfo)
+{
+ static_cast<TestController*>(const_cast<void*>(clientInfo))->didFinishLoadForFrame(page, frame);
+}
+
+void TestController::didFinishLoadForFrame(WKPageRef page, WKFrameRef frame)
+{
+ if (m_state != Resetting)
+ return;
+
+ if (!WKFrameIsMainFrame(frame))
+ return;
+
+ WKRetainPtr<WKURLRef> wkURL(AdoptWK, WKFrameCopyURL(frame));
+ if (!WKURLIsEqual(wkURL.get(), blankURL()))
+ return;
+
+ m_doneResetting = true;
+ shared().notifyDone();
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/TestController.h b/Tools/WebKitTestRunner/TestController.h
new file mode 100644
index 0000000..ef41314
--- /dev/null
+++ b/Tools/WebKitTestRunner/TestController.h
@@ -0,0 +1,114 @@
+/*
+ * 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 TestController_h
+#define TestController_h
+
+#include <WebKit2/WKRetainPtr.h>
+#include <string>
+#include <vector>
+#include <wtf/OwnPtr.h>
+
+namespace WTR {
+
+class TestInvocation;
+class PlatformWebView;
+
+// FIXME: Rename this TestRunner?
+class TestController {
+public:
+ static TestController& shared();
+
+ TestController(int argc, const char* argv[]);
+ ~TestController();
+
+ bool verbose() const { return m_verbose; }
+
+ WKStringRef injectedBundlePath() { return m_injectedBundlePath.get(); }
+ WKStringRef testPluginDirectory() { return m_testPluginDirectory.get(); }
+
+ PlatformWebView* mainWebView() { return m_mainWebView.get(); }
+ WKContextRef context() { return m_context.get(); }
+
+ // Runs the run loop until `done` is true or the timeout elapses.
+ enum TimeoutDuration { ShortTimeout, LongTimeout };
+ void runUntil(bool& done, TimeoutDuration);
+ void notifyDone();
+
+private:
+ void initialize(int argc, const char* argv[]);
+ void run();
+
+ void runTestingServerLoop();
+ bool runTest(const char* pathOrURL);
+
+ void platformInitialize();
+ void platformInitializeContext();
+ void platformRunUntil(bool& done, double timeout);
+ void initializeInjectedBundlePath();
+ void initializeTestPluginDirectory();
+
+ bool resetStateToConsistentValues();
+
+ // WKContextInjectedBundleClient
+ static void didReceiveMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, const void*);
+ static void didReceiveSynchronousMessageFromInjectedBundle(WKContextRef, WKStringRef messageName, WKTypeRef messageBody, WKTypeRef* returnData, const void*);
+ void didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody);
+ WKRetainPtr<WKTypeRef> didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody);
+
+ // WKPageLoaderClient
+ static void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame, WKTypeRef userData, const void*);
+ void didFinishLoadForFrame(WKPageRef page, WKFrameRef frame);
+
+
+ OwnPtr<TestInvocation> m_currentInvocation;
+
+ bool m_dumpPixels;
+ bool m_verbose;
+ bool m_printSeparators;
+ bool m_usingServerMode;
+ std::vector<std::string> m_paths;
+ WKRetainPtr<WKStringRef> m_injectedBundlePath;
+ WKRetainPtr<WKStringRef> m_testPluginDirectory;
+
+ OwnPtr<PlatformWebView> m_mainWebView;
+ WKRetainPtr<WKContextRef> m_context;
+ WKRetainPtr<WKPageGroupRef> m_pageGroup;
+
+ enum State {
+ Initial,
+ Resetting,
+ RunningTest
+ };
+ State m_state;
+ bool m_doneResetting;
+
+ double m_longTimeout;
+ double m_shortTimeout;
+};
+
+} // namespace WTR
+
+#endif // TestController_h
diff --git a/Tools/WebKitTestRunner/TestInvocation.cpp b/Tools/WebKitTestRunner/TestInvocation.cpp
new file mode 100644
index 0000000..26ecfc0
--- /dev/null
+++ b/Tools/WebKitTestRunner/TestInvocation.cpp
@@ -0,0 +1,202 @@
+/*
+ * 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 "TestInvocation.h"
+
+#include "PlatformWebView.h"
+#include "StringFunctions.h"
+#include "TestController.h"
+#include <climits>
+#include <cstdio>
+#include <WebKit2/WKContextPrivate.h>
+#include <WebKit2/WKRetainPtr.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/PassOwnArrayPtr.h>
+
+#if OS(WINDOWS)
+#include <direct.h> // For _getcwd.
+#define getcwd _getcwd // MSDN says getcwd is deprecated.
+#define PATH_MAX _MAX_PATH
+#endif
+
+using namespace WebKit;
+using namespace std;
+
+namespace WTR {
+
+static WKURLRef createWKURL(const char* pathOrURL)
+{
+ if (strstr(pathOrURL, "http://") || strstr(pathOrURL, "https://") || strstr(pathOrURL, "file://"))
+ return WKURLCreateWithUTF8CString(pathOrURL);
+
+ // Creating from filesytem path.
+ size_t length = strlen(pathOrURL);
+ if (!length)
+ return 0;
+
+ const char* filePrefix = "file://";
+ static const size_t prefixLength = strlen(filePrefix);
+#if OS(WINDOWS)
+ const char separator = '\\';
+ bool isAbsolutePath = length >= 3 && pathOrURL[1] == ':' && pathOrURL[2] == separator;
+#else
+ const char separator = '/';
+ bool isAbsolutePath = pathOrURL[0] == separator;
+#endif
+
+ OwnArrayPtr<char> buffer;
+ if (isAbsolutePath) {
+ buffer = adoptArrayPtr(new char[prefixLength + length + 1]);
+ strcpy(buffer.get(), filePrefix);
+ strcpy(buffer.get() + prefixLength, pathOrURL);
+ } else {
+ buffer = adoptArrayPtr(new char[prefixLength + PATH_MAX + length + 2]); // 1 for the separator
+ strcpy(buffer.get(), filePrefix);
+ if (!getcwd(buffer.get() + prefixLength, PATH_MAX))
+ return 0;
+ size_t numCharacters = strlen(buffer.get());
+ buffer[numCharacters] = separator;
+ strcpy(buffer.get() + numCharacters + 1, pathOrURL);
+ }
+
+ return WKURLCreateWithUTF8CString(buffer.get());
+}
+
+TestInvocation::TestInvocation(const char* pathOrURL)
+ : m_url(AdoptWK, createWKURL(pathOrURL))
+ , m_pathOrURL(fastStrDup(pathOrURL))
+ , m_gotInitialResponse(false)
+ , m_gotFinalMessage(false)
+ , m_error(false)
+{
+}
+
+TestInvocation::~TestInvocation()
+{
+ fastFree(m_pathOrURL);
+}
+
+static const unsigned w3cSVGWidth = 480;
+static const unsigned w3cSVGHeight = 360;
+static const unsigned normalWidth = 800;
+static const unsigned normalHeight = 600;
+
+static void sizeWebViewForCurrentTest(char* pathOrURL)
+{
+ bool isSVGW3CTest = strstr(pathOrURL, "svg/W3C-SVG-1.1") || strstr(pathOrURL, "svg\\W3C-SVG-1.1");
+
+ if (isSVGW3CTest)
+ TestController::shared().mainWebView()->resizeTo(w3cSVGWidth, w3cSVGHeight);
+ else
+ TestController::shared().mainWebView()->resizeTo(normalWidth, normalHeight);
+}
+
+void TestInvocation::invoke()
+{
+ sizeWebViewForCurrentTest(m_pathOrURL);
+
+ WKRetainPtr<WKStringRef> messageName(AdoptWK, WKStringCreateWithUTF8CString("BeginTest"));
+ WKContextPostMessageToInjectedBundle(TestController::shared().context(), messageName.get(), 0);
+
+ TestController::shared().runUntil(m_gotInitialResponse, TestController::ShortTimeout);
+ if (!m_gotInitialResponse) {
+ dump("Timed out waiting for initial response from web process\n");
+ return;
+ }
+ if (m_error) {
+ dump("FAIL\n");
+ return;
+ }
+
+ WKPageLoadURL(TestController::shared().mainWebView()->page(), m_url.get());
+
+ TestController::shared().runUntil(m_gotFinalMessage, TestController::LongTimeout);
+ if (!m_gotFinalMessage) {
+ dump("Timed out waiting for final message from web process\n");
+ return;
+ }
+ if (m_error) {
+ dump("FAIL\n");
+ return;
+ }
+}
+
+void TestInvocation::dump(const char* stringToDump)
+{
+ printf("Content-Type: text/plain\n");
+ printf("%s", stringToDump);
+
+ fputs("#EOF\n", stdout);
+ fputs("#EOF\n", stdout);
+ fputs("#EOF\n", stderr);
+
+ fflush(stdout);
+ fflush(stderr);
+}
+
+void TestInvocation::didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody)
+{
+ if (WKStringIsEqualToUTF8CString(messageName, "Error")) {
+ // Set all states to true to stop spinning the runloop.
+ m_gotInitialResponse = true;
+ m_gotFinalMessage = true;
+ m_error = true;
+ TestController::shared().notifyDone();
+ return;
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "Ack")) {
+ ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
+ WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody);
+ if (WKStringIsEqualToUTF8CString(messageBodyString, "BeginTest")) {
+ m_gotInitialResponse = true;
+ TestController::shared().notifyDone();
+ return;
+ }
+
+ ASSERT_NOT_REACHED();
+ }
+
+ if (WKStringIsEqualToUTF8CString(messageName, "Done")) {
+ ASSERT(WKGetTypeID(messageBody) == WKStringGetTypeID());
+ WKStringRef messageBodyString = static_cast<WKStringRef>(messageBody);
+
+ dump(toSTD(messageBodyString).c_str());
+
+ m_gotFinalMessage = true;
+ TestController::shared().notifyDone();
+ return;
+ }
+
+ ASSERT_NOT_REACHED();
+}
+
+WKRetainPtr<WKTypeRef> TestInvocation::didReceiveSynchronousMessageFromInjectedBundle(WKStringRef /*messageName*/, WKTypeRef /*messageBody*/)
+{
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/TestInvocation.h b/Tools/WebKitTestRunner/TestInvocation.h
new file mode 100644
index 0000000..fec1f7a
--- /dev/null
+++ b/Tools/WebKitTestRunner/TestInvocation.h
@@ -0,0 +1,57 @@
+/*
+ * 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 TestInvocation_h
+#define TestInvocation_h
+
+#include <WebKit2/WKRetainPtr.h>
+#include <wtf/Noncopyable.h>
+
+namespace WTR {
+
+class TestInvocation : public Noncopyable {
+public:
+ TestInvocation(const char*);
+ ~TestInvocation();
+
+ void invoke();
+ void didReceiveMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody);
+ WKRetainPtr<WKTypeRef> didReceiveSynchronousMessageFromInjectedBundle(WKStringRef messageName, WKTypeRef messageBody);
+
+private:
+ void dump(const char*);
+
+ WKRetainPtr<WKURLRef> m_url;
+ char* m_pathOrURL;
+
+ // Invocation state
+ bool m_gotInitialResponse;
+ bool m_gotFinalMessage;
+ bool m_error;
+};
+
+} // namespace WTR
+
+#endif // TestInvocation_h
diff --git a/Tools/WebKitTestRunner/WebKitTestRunner.pro b/Tools/WebKitTestRunner/WebKitTestRunner.pro
new file mode 100644
index 0000000..677abb3
--- /dev/null
+++ b/Tools/WebKitTestRunner/WebKitTestRunner.pro
@@ -0,0 +1,5 @@
+TEMPLATE = subdirs
+
+SUBDIRS = qt/WebKitTestRunner.pro \
+ InjectedBundle/qt/InjectedBundle.pro \
+
diff --git a/Tools/WebKitTestRunner/WebKitTestRunner.sln b/Tools/WebKitTestRunner/WebKitTestRunner.sln
new file mode 100644
index 0000000..3384503
--- /dev/null
+++ b/Tools/WebKitTestRunner/WebKitTestRunner.sln
@@ -0,0 +1,91 @@
+
+Microsoft Visual Studio Solution File, Format Version 9.00
+# Visual Studio 2005
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WebKitTestRunner", "win\WebKitTestRunner.vcproj", "{3B99669B-1817-443B-BCBE-835580146668}"
+ ProjectSection(ProjectDependencies) = postProject
+ {CBC3391C-F060-4BF5-A66E-81404168816B} = {CBC3391C-F060-4BF5-A66E-81404168816B}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InjectedBundleGenerated", "win\InjectedBundleGenerated.vcproj", "{4343BC0B-A2E0-4B48-8277-F33CFBFA83CD}"
+ ProjectSection(ProjectDependencies) = postProject
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C} = {C0737398-3565-439E-A2B8-AB2BE4D5430C}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FindSafari", "..\FindSafari\FindSafari.vcproj", "{DA31DA52-6675-48D4-89E0-333A7144397C}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ImageDiff", "..\DumpRenderTree\win\ImageDiff.vcproj", "{59CC0547-70AC-499C-9B19-EC01C6F61137}"
+ ProjectSection(ProjectDependencies) = postProject
+ {DA31DA52-6675-48D4-89E0-333A7144397C} = {DA31DA52-6675-48D4-89E0-333A7144397C}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "InjectedBundle", "win\InjectedBundle.vcproj", "{CBC3391C-F060-4BF5-A66E-81404168816B}"
+ ProjectSection(ProjectDependencies) = postProject
+ {4343BC0B-A2E0-4B48-8277-F33CFBFA83CD} = {4343BC0B-A2E0-4B48-8277-F33CFBFA83CD}
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "TestNetscapePlugin", "..\DumpRenderTree\TestNetscapePlugIn\win\TestNetscapePlugin.vcproj", "{C0737398-3565-439E-A2B8-AB2BE4D5430C}"
+ 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|Win32 = Debug|Win32
+ Release_LTCG|Win32 = Release_LTCG|Win32
+ Release|Win32 = Release|Win32
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {3B99669B-1817-443B-BCBE-835580146668}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {3B99669B-1817-443B-BCBE-835580146668}.Debug_All|Win32.Build.0 = Debug_All|Win32
+ {3B99669B-1817-443B-BCBE-835580146668}.Debug|Win32.ActiveCfg = Debug|Win32
+ {3B99669B-1817-443B-BCBE-835580146668}.Debug|Win32.Build.0 = Debug|Win32
+ {3B99669B-1817-443B-BCBE-835580146668}.Release_LTCG|Win32.ActiveCfg = Release_LTCG|Win32
+ {3B99669B-1817-443B-BCBE-835580146668}.Release_LTCG|Win32.Build.0 = Release_LTCG|Win32
+ {3B99669B-1817-443B-BCBE-835580146668}.Release|Win32.ActiveCfg = Release|Win32
+ {3B99669B-1817-443B-BCBE-835580146668}.Release|Win32.Build.0 = Release|Win32
+ {4343BC0B-A2E0-4B48-8277-F33CFBFA83CD}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {4343BC0B-A2E0-4B48-8277-F33CFBFA83CD}.Debug_All|Win32.Build.0 = Debug_All|Win32
+ {4343BC0B-A2E0-4B48-8277-F33CFBFA83CD}.Debug|Win32.ActiveCfg = Debug|Win32
+ {4343BC0B-A2E0-4B48-8277-F33CFBFA83CD}.Debug|Win32.Build.0 = Debug|Win32
+ {4343BC0B-A2E0-4B48-8277-F33CFBFA83CD}.Release_LTCG|Win32.ActiveCfg = Release_LTCG|Win32
+ {4343BC0B-A2E0-4B48-8277-F33CFBFA83CD}.Release_LTCG|Win32.Build.0 = Release_LTCG|Win32
+ {4343BC0B-A2E0-4B48-8277-F33CFBFA83CD}.Release|Win32.ActiveCfg = Release|Win32
+ {4343BC0B-A2E0-4B48-8277-F33CFBFA83CD}.Release|Win32.Build.0 = Release|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug_All|Win32.Build.0 = Debug_All|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug|Win32.ActiveCfg = Debug|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug|Win32.Build.0 = Debug|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_LTCG|Win32.ActiveCfg = Release_LTCG|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_LTCG|Win32.Build.0 = Release_LTCG|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release|Win32.ActiveCfg = Release|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.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|Win32.ActiveCfg = Debug|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Debug|Win32.Build.0 = Debug|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release_LTCG|Win32.ActiveCfg = Release_LTCG|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release_LTCG|Win32.Build.0 = Release_LTCG|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release|Win32.ActiveCfg = Release|Win32
+ {59CC0547-70AC-499C-9B19-EC01C6F61137}.Release|Win32.Build.0 = Release|Win32
+ {CBC3391C-F060-4BF5-A66E-81404168816B}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {CBC3391C-F060-4BF5-A66E-81404168816B}.Debug_All|Win32.Build.0 = Debug_All|Win32
+ {CBC3391C-F060-4BF5-A66E-81404168816B}.Debug|Win32.ActiveCfg = Debug|Win32
+ {CBC3391C-F060-4BF5-A66E-81404168816B}.Debug|Win32.Build.0 = Debug|Win32
+ {CBC3391C-F060-4BF5-A66E-81404168816B}.Release_LTCG|Win32.ActiveCfg = Release_LTCG|Win32
+ {CBC3391C-F060-4BF5-A66E-81404168816B}.Release_LTCG|Win32.Build.0 = Release_LTCG|Win32
+ {CBC3391C-F060-4BF5-A66E-81404168816B}.Release|Win32.ActiveCfg = Release|Win32
+ {CBC3391C-F060-4BF5-A66E-81404168816B}.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|Win32.ActiveCfg = Debug|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Debug|Win32.Build.0 = Debug|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release_LTCG|Win32.ActiveCfg = Release_LTCG|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release_LTCG|Win32.Build.0 = Release_LTCG|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release|Win32.ActiveCfg = Release|Win32
+ {C0737398-3565-439E-A2B8-AB2BE4D5430C}.Release|Win32.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj b/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..a15fe41
--- /dev/null
+++ b/Tools/WebKitTestRunner/WebKitTestRunner.xcodeproj/project.pbxproj
@@ -0,0 +1,582 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 45;
+ objects = {
+
+/* Begin PBXAggregateTarget section */
+ BC952D7711F3BF5D003398B4 /* Derived Sources */ = {
+ isa = PBXAggregateTarget;
+ buildConfigurationList = BC952D7D11F3BF6A003398B4 /* Build configuration list for PBXAggregateTarget "Derived Sources" */;
+ buildPhases = (
+ BC952D8211F3BF78003398B4 /* Generate Derived Sources */,
+ );
+ dependencies = (
+ );
+ name = "Derived Sources";
+ productName = "Derived Sources";
+ };
+/* End PBXAggregateTarget section */
+
+/* Begin PBXBuildFile section */
+ 6510A78211EC643800410867 /* AHEM____.TTF in Resources */ = {isa = PBXBuildFile; fileRef = 6510A77711EC643800410867 /* AHEM____.TTF */; };
+ 6510A78311EC643800410867 /* ColorBits.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A77811EC643800410867 /* ColorBits.ttf */; };
+ 6510A78411EC643800410867 /* WebKitWeightWatcher100.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A77911EC643800410867 /* WebKitWeightWatcher100.ttf */; };
+ 6510A78511EC643800410867 /* WebKitWeightWatcher200.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A77A11EC643800410867 /* WebKitWeightWatcher200.ttf */; };
+ 6510A78611EC643800410867 /* WebKitWeightWatcher300.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A77B11EC643800410867 /* WebKitWeightWatcher300.ttf */; };
+ 6510A78711EC643800410867 /* WebKitWeightWatcher400.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A77C11EC643800410867 /* WebKitWeightWatcher400.ttf */; };
+ 6510A78811EC643800410867 /* WebKitWeightWatcher500.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A77D11EC643800410867 /* WebKitWeightWatcher500.ttf */; };
+ 6510A78911EC643800410867 /* WebKitWeightWatcher600.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A77E11EC643800410867 /* WebKitWeightWatcher600.ttf */; };
+ 6510A78A11EC643800410867 /* WebKitWeightWatcher700.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A77F11EC643800410867 /* WebKitWeightWatcher700.ttf */; };
+ 6510A78B11EC643800410867 /* WebKitWeightWatcher800.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A78011EC643800410867 /* WebKitWeightWatcher800.ttf */; };
+ 6510A78C11EC643800410867 /* WebKitWeightWatcher900.ttf in Resources */ = {isa = PBXBuildFile; fileRef = 6510A78111EC643800410867 /* WebKitWeightWatcher900.ttf */; };
+ 65EB85A011EC67CC0034D300 /* ActivateFonts.mm in Sources */ = {isa = PBXBuildFile; fileRef = 65EB859F11EC67CC0034D300 /* ActivateFonts.mm */; };
+ BC14E4DB120E02D000826C0C /* GCController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC14E4D9120E02D000826C0C /* GCController.cpp */; };
+ BC14E4EA120E03D800826C0C /* JSGCController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC14E4E8120E03D800826C0C /* JSGCController.cpp */; };
+ BC25193E11D15D8B002EBC01 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC7934A411906584005EA8E2 /* Cocoa.framework */; };
+ BC25193F11D15D8B002EBC01 /* WebKit2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC7934AB1190658C005EA8E2 /* WebKit2.framework */; };
+ BC25194011D15D8B002EBC01 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BCDA2B991191051F00C3BC47 /* JavaScriptCore.framework */; };
+ BC251A3E11D16831002EBC01 /* InjectedBundleMain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC25184611D15767002EBC01 /* InjectedBundleMain.cpp */; };
+ BC793400118F7C84005EA8E2 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC7933FF118F7C84005EA8E2 /* main.mm */; };
+ BC793431118F7F19005EA8E2 /* TestController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC793430118F7F19005EA8E2 /* TestController.cpp */; };
+ BC7934A511906584005EA8E2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC7934A411906584005EA8E2 /* Cocoa.framework */; };
+ BC7934AC1190658C005EA8E2 /* WebKit2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BC7934AB1190658C005EA8E2 /* WebKit2.framework */; };
+ BC7934E811906846005EA8E2 /* PlatformWebViewMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC7934E711906846005EA8E2 /* PlatformWebViewMac.mm */; };
+ BC8C795C11D2785D004535A1 /* TestControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = BC8C795B11D2785D004535A1 /* TestControllerMac.mm */; };
+ BC8FD8CA120E527F00F3E71A /* EventSendingController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC8FD8C9120E527F00F3E71A /* EventSendingController.cpp */; };
+ BC8FD8D2120E545B00F3E71A /* JSEventSendingController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC8FD8D0120E545B00F3E71A /* JSEventSendingController.cpp */; };
+ BC952C0D11F3B965003398B4 /* JSWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC952C0C11F3B965003398B4 /* JSWrapper.cpp */; };
+ BC952F1F11F3C652003398B4 /* JSLayoutTestController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC952F1D11F3C652003398B4 /* JSLayoutTestController.cpp */; };
+ BCC997A411D3C8F60017BCA2 /* InjectedBundle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCC997A011D3C8F60017BCA2 /* InjectedBundle.cpp */; };
+ BCC997A511D3C8F60017BCA2 /* InjectedBundlePage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCC997A211D3C8F60017BCA2 /* InjectedBundlePage.cpp */; };
+ BCC9981811D3F51E0017BCA2 /* LayoutTestController.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCC9981711D3F51E0017BCA2 /* LayoutTestController.cpp */; };
+ BCD7D2F811921278006DB7EE /* TestInvocation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCD7D2F711921278006DB7EE /* TestInvocation.cpp */; };
+ BCDA2B9A1191051F00C3BC47 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BCDA2B991191051F00C3BC47 /* JavaScriptCore.framework */; };
+ C0CE720B1247C93300BC0EC4 /* LayoutTestControllerMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = C0CE720A1247C93300BC0EC4 /* LayoutTestControllerMac.mm */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ BC25194111D15D94002EBC01 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BC25186111D15D54002EBC01;
+ remoteInfo = InjectedBundle;
+ };
+ BC952ED611F3C38B003398B4 /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 08FB7793FE84155DC02AAC07 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = BC952D7711F3BF5D003398B4;
+ remoteInfo = "Derived Sources";
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXFileReference section */
+ 6510A77711EC643800410867 /* AHEM____.TTF */ = {isa = PBXFileReference; lastKnownFileType = file; name = "AHEM____.TTF"; path = "fonts/AHEM____.TTF"; sourceTree = "<group>"; };
+ 6510A77811EC643800410867 /* ColorBits.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = ColorBits.ttf; path = fonts/ColorBits.ttf; sourceTree = "<group>"; };
+ 6510A77911EC643800410867 /* WebKitWeightWatcher100.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher100.ttf; path = fonts/WebKitWeightWatcher100.ttf; sourceTree = "<group>"; };
+ 6510A77A11EC643800410867 /* WebKitWeightWatcher200.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher200.ttf; path = fonts/WebKitWeightWatcher200.ttf; sourceTree = "<group>"; };
+ 6510A77B11EC643800410867 /* WebKitWeightWatcher300.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher300.ttf; path = fonts/WebKitWeightWatcher300.ttf; sourceTree = "<group>"; };
+ 6510A77C11EC643800410867 /* WebKitWeightWatcher400.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher400.ttf; path = fonts/WebKitWeightWatcher400.ttf; sourceTree = "<group>"; };
+ 6510A77D11EC643800410867 /* WebKitWeightWatcher500.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher500.ttf; path = fonts/WebKitWeightWatcher500.ttf; sourceTree = "<group>"; };
+ 6510A77E11EC643800410867 /* WebKitWeightWatcher600.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher600.ttf; path = fonts/WebKitWeightWatcher600.ttf; sourceTree = "<group>"; };
+ 6510A77F11EC643800410867 /* WebKitWeightWatcher700.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher700.ttf; path = fonts/WebKitWeightWatcher700.ttf; sourceTree = "<group>"; };
+ 6510A78011EC643800410867 /* WebKitWeightWatcher800.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher800.ttf; path = fonts/WebKitWeightWatcher800.ttf; sourceTree = "<group>"; };
+ 6510A78111EC643800410867 /* WebKitWeightWatcher900.ttf */ = {isa = PBXFileReference; lastKnownFileType = file; name = WebKitWeightWatcher900.ttf; path = fonts/WebKitWeightWatcher900.ttf; sourceTree = "<group>"; };
+ 65EB859D11EC67CC0034D300 /* ActivateFonts.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActivateFonts.h; sourceTree = "<group>"; };
+ 65EB859F11EC67CC0034D300 /* ActivateFonts.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ActivateFonts.mm; sourceTree = "<group>"; };
+ 8DD76FA10486AA7600D96B5E /* WebKitTestRunner */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = WebKitTestRunner; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC14E4D8120E02D000826C0C /* GCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GCController.h; sourceTree = "<group>"; };
+ BC14E4D9120E02D000826C0C /* GCController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = GCController.cpp; sourceTree = "<group>"; };
+ BC14E4E1120E032000826C0C /* GCController.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = GCController.idl; sourceTree = "<group>"; };
+ BC14E4E8120E03D800826C0C /* JSGCController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSGCController.cpp; path = DerivedSources/WebKitTestRunner/JSGCController.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC14E4E9120E03D800826C0C /* JSGCController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSGCController.h; path = DerivedSources/WebKitTestRunner/JSGCController.h; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC25184611D15767002EBC01 /* InjectedBundleMain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundleMain.cpp; sourceTree = "<group>"; };
+ BC25186211D15D54002EBC01 /* WebKitTestRunnerInjectedBundle.bundle */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = WebKitTestRunnerInjectedBundle.bundle; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC25186311D15D54002EBC01 /* InjectedBundle-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "InjectedBundle-Info.plist"; sourceTree = "<group>"; };
+ BC25197111D15E61002EBC01 /* InjectedBundle.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = InjectedBundle.xcconfig; sourceTree = "<group>"; };
+ BC251A1711D16774002EBC01 /* WebKitTestRunnerPrefix.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitTestRunnerPrefix.h; sourceTree = "<group>"; };
+ BC251A1811D16795002EBC01 /* WebKitTestRunner.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = WebKitTestRunner.xcconfig; sourceTree = "<group>"; };
+ BC7933FF118F7C84005EA8E2 /* main.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = main.mm; sourceTree = "<group>"; };
+ BC793426118F7D3C005EA8E2 /* Base.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Base.xcconfig; sourceTree = "<group>"; };
+ BC793427118F7DAF005EA8E2 /* DebugRelease.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = DebugRelease.xcconfig; sourceTree = "<group>"; };
+ BC79342F118F7F19005EA8E2 /* TestController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestController.h; sourceTree = "<group>"; };
+ BC793430118F7F19005EA8E2 /* TestController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestController.cpp; sourceTree = "<group>"; };
+ BC7934A411906584005EA8E2 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; };
+ BC7934AB1190658C005EA8E2 /* WebKit2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = WebKit2.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC7934DD119066EC005EA8E2 /* PlatformWebView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PlatformWebView.h; sourceTree = "<group>"; };
+ BC7934E711906846005EA8E2 /* PlatformWebViewMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = PlatformWebViewMac.mm; sourceTree = "<group>"; };
+ BC8C795B11D2785D004535A1 /* TestControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = TestControllerMac.mm; sourceTree = "<group>"; };
+ BC8FD8C8120E527F00F3E71A /* EventSendingController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EventSendingController.h; sourceTree = "<group>"; };
+ BC8FD8C9120E527F00F3E71A /* EventSendingController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EventSendingController.cpp; sourceTree = "<group>"; };
+ BC8FD8CB120E52B000F3E71A /* EventSendingController.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = EventSendingController.idl; sourceTree = "<group>"; };
+ BC8FD8D0120E545B00F3E71A /* JSEventSendingController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSEventSendingController.cpp; path = DerivedSources/WebKitTestRunner/JSEventSendingController.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC8FD8D1120E545B00F3E71A /* JSEventSendingController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSEventSendingController.h; path = DerivedSources/WebKitTestRunner/JSEventSendingController.h; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC952C0B11F3B965003398B4 /* JSWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWrapper.h; sourceTree = "<group>"; };
+ BC952C0C11F3B965003398B4 /* JSWrapper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSWrapper.cpp; sourceTree = "<group>"; };
+ BC952C0E11F3B97B003398B4 /* JSWrappable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSWrappable.h; sourceTree = "<group>"; };
+ BC952EC511F3C10F003398B4 /* DerivedSources.make */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = DerivedSources.make; sourceTree = "<group>"; };
+ BC952ED211F3C29F003398B4 /* LayoutTestController.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LayoutTestController.idl; sourceTree = "<group>"; };
+ BC952ED311F3C318003398B4 /* CodeGeneratorTestRunner.pm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.perl; path = CodeGeneratorTestRunner.pm; sourceTree = "<group>"; };
+ BC952F1D11F3C652003398B4 /* JSLayoutTestController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = JSLayoutTestController.cpp; path = DerivedSources/WebKitTestRunner/JSLayoutTestController.cpp; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC952F1E11F3C652003398B4 /* JSLayoutTestController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSLayoutTestController.h; path = DerivedSources/WebKitTestRunner/JSLayoutTestController.h; sourceTree = BUILT_PRODUCTS_DIR; };
+ BC99A4841208901A007E9F08 /* StringFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringFunctions.h; sourceTree = "<group>"; };
+ BCC997A011D3C8F60017BCA2 /* InjectedBundle.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundle.cpp; sourceTree = "<group>"; };
+ BCC997A111D3C8F60017BCA2 /* InjectedBundle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedBundle.h; sourceTree = "<group>"; };
+ BCC997A211D3C8F60017BCA2 /* InjectedBundlePage.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = InjectedBundlePage.cpp; sourceTree = "<group>"; };
+ BCC997A311D3C8F60017BCA2 /* InjectedBundlePage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = InjectedBundlePage.h; sourceTree = "<group>"; };
+ BCC9981611D3F51E0017BCA2 /* LayoutTestController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LayoutTestController.h; sourceTree = "<group>"; };
+ BCC9981711D3F51E0017BCA2 /* LayoutTestController.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LayoutTestController.cpp; sourceTree = "<group>"; };
+ BCD7D2F611921278006DB7EE /* TestInvocation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TestInvocation.h; sourceTree = "<group>"; };
+ BCD7D2F711921278006DB7EE /* TestInvocation.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TestInvocation.cpp; sourceTree = "<group>"; };
+ BCDA2B991191051F00C3BC47 /* JavaScriptCore.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; path = JavaScriptCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ C0CE720A1247C93300BC0EC4 /* LayoutTestControllerMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = LayoutTestControllerMac.mm; path = mac/LayoutTestControllerMac.mm; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8DD76F9B0486AA7600D96B5E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BC7934A511906584005EA8E2 /* Cocoa.framework in Frameworks */,
+ BC7934AC1190658C005EA8E2 /* WebKit2.framework in Frameworks */,
+ BCDA2B9A1191051F00C3BC47 /* JavaScriptCore.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BC25186011D15D54002EBC01 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BC25193E11D15D8B002EBC01 /* Cocoa.framework in Frameworks */,
+ BC25193F11D15D8B002EBC01 /* WebKit2.framework in Frameworks */,
+ BC25194011D15D8B002EBC01 /* JavaScriptCore.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* WebKitTestRunner */ = {
+ isa = PBXGroup;
+ children = (
+ BC952EC511F3C10F003398B4 /* DerivedSources.make */,
+ BC99CBF11207642D00FDEE76 /* Shared */,
+ 08FB7795FE84155DC02AAC07 /* TestRunner */,
+ BC25183511D1571D002EBC01 /* InjectedBundle */,
+ BC793401118F7C8A005EA8E2 /* Configurations */,
+ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */,
+ BC25194411D15DBE002EBC01 /* Resources */,
+ 1AB674ADFE9D54B511CA2CBB /* Products */,
+ );
+ name = WebKitTestRunner;
+ sourceTree = "<group>";
+ };
+ 08FB7795FE84155DC02AAC07 /* TestRunner */ = {
+ isa = PBXGroup;
+ children = (
+ BC7933FE118F7C74005EA8E2 /* mac */,
+ BC251A1711D16774002EBC01 /* WebKitTestRunnerPrefix.h */,
+ BC7934DD119066EC005EA8E2 /* PlatformWebView.h */,
+ BC79342F118F7F19005EA8E2 /* TestController.h */,
+ BC793430118F7F19005EA8E2 /* TestController.cpp */,
+ BCD7D2F611921278006DB7EE /* TestInvocation.h */,
+ BCD7D2F711921278006DB7EE /* TestInvocation.cpp */,
+ );
+ name = TestRunner;
+ sourceTree = "<group>";
+ };
+ 08FB779DFE84155DC02AAC07 /* External Frameworks and Libraries */ = {
+ isa = PBXGroup;
+ children = (
+ BC7934A411906584005EA8E2 /* Cocoa.framework */,
+ BC7934AB1190658C005EA8E2 /* WebKit2.framework */,
+ BCDA2B991191051F00C3BC47 /* JavaScriptCore.framework */,
+ );
+ name = "External Frameworks and Libraries";
+ sourceTree = "<group>";
+ };
+ 1AB674ADFE9D54B511CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8DD76FA10486AA7600D96B5E /* WebKitTestRunner */,
+ BC25186211D15D54002EBC01 /* WebKitTestRunnerInjectedBundle.bundle */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ 65EB859E11EC67CC0034D300 /* mac */ = {
+ isa = PBXGroup;
+ children = (
+ 65EB859F11EC67CC0034D300 /* ActivateFonts.mm */,
+ );
+ path = mac;
+ sourceTree = "<group>";
+ };
+ BC14E4E0120E02F900826C0C /* Controllers */ = {
+ isa = PBXGroup;
+ children = (
+ BC8FD8C9120E527F00F3E71A /* EventSendingController.cpp */,
+ BC8FD8C8120E527F00F3E71A /* EventSendingController.h */,
+ BC14E4D9120E02D000826C0C /* GCController.cpp */,
+ BC14E4D8120E02D000826C0C /* GCController.h */,
+ BCC9981711D3F51E0017BCA2 /* LayoutTestController.cpp */,
+ BCC9981611D3F51E0017BCA2 /* LayoutTestController.h */,
+ C0CE720A1247C93300BC0EC4 /* LayoutTestControllerMac.mm */,
+ );
+ name = Controllers;
+ sourceTree = "<group>";
+ };
+ BC25183511D1571D002EBC01 /* InjectedBundle */ = {
+ isa = PBXGroup;
+ children = (
+ BC952D3A11F3BF1F003398B4 /* Derived Sources */,
+ BC952C0A11F3B939003398B4 /* Bindings */,
+ BC14E4E0120E02F900826C0C /* Controllers */,
+ 65EB859E11EC67CC0034D300 /* mac */,
+ 65EB859D11EC67CC0034D300 /* ActivateFonts.h */,
+ BCC997A011D3C8F60017BCA2 /* InjectedBundle.cpp */,
+ BCC997A111D3C8F60017BCA2 /* InjectedBundle.h */,
+ BC25184611D15767002EBC01 /* InjectedBundleMain.cpp */,
+ BCC997A211D3C8F60017BCA2 /* InjectedBundlePage.cpp */,
+ BCC997A311D3C8F60017BCA2 /* InjectedBundlePage.h */,
+ );
+ path = InjectedBundle;
+ sourceTree = "<group>";
+ };
+ BC25194411D15DBE002EBC01 /* Resources */ = {
+ isa = PBXGroup;
+ children = (
+ BC25186311D15D54002EBC01 /* InjectedBundle-Info.plist */,
+ 6510A77711EC643800410867 /* AHEM____.TTF */,
+ 6510A77811EC643800410867 /* ColorBits.ttf */,
+ 6510A77911EC643800410867 /* WebKitWeightWatcher100.ttf */,
+ 6510A77A11EC643800410867 /* WebKitWeightWatcher200.ttf */,
+ 6510A77B11EC643800410867 /* WebKitWeightWatcher300.ttf */,
+ 6510A77C11EC643800410867 /* WebKitWeightWatcher400.ttf */,
+ 6510A77D11EC643800410867 /* WebKitWeightWatcher500.ttf */,
+ 6510A77E11EC643800410867 /* WebKitWeightWatcher600.ttf */,
+ 6510A77F11EC643800410867 /* WebKitWeightWatcher700.ttf */,
+ 6510A78011EC643800410867 /* WebKitWeightWatcher800.ttf */,
+ 6510A78111EC643800410867 /* WebKitWeightWatcher900.ttf */,
+ );
+ name = Resources;
+ sourceTree = "<group>";
+ };
+ BC7933FE118F7C74005EA8E2 /* mac */ = {
+ isa = PBXGroup;
+ children = (
+ BC7933FF118F7C84005EA8E2 /* main.mm */,
+ BC7934E711906846005EA8E2 /* PlatformWebViewMac.mm */,
+ BC8C795B11D2785D004535A1 /* TestControllerMac.mm */,
+ );
+ path = mac;
+ sourceTree = "<group>";
+ };
+ BC793401118F7C8A005EA8E2 /* Configurations */ = {
+ isa = PBXGroup;
+ children = (
+ BC793426118F7D3C005EA8E2 /* Base.xcconfig */,
+ BC793427118F7DAF005EA8E2 /* DebugRelease.xcconfig */,
+ BC25197111D15E61002EBC01 /* InjectedBundle.xcconfig */,
+ BC251A1811D16795002EBC01 /* WebKitTestRunner.xcconfig */,
+ );
+ path = Configurations;
+ sourceTree = "<group>";
+ };
+ BC952C0A11F3B939003398B4 /* Bindings */ = {
+ isa = PBXGroup;
+ children = (
+ BC952ED311F3C318003398B4 /* CodeGeneratorTestRunner.pm */,
+ BC952C0E11F3B97B003398B4 /* JSWrappable.h */,
+ BC952C0C11F3B965003398B4 /* JSWrapper.cpp */,
+ BC952C0B11F3B965003398B4 /* JSWrapper.h */,
+ BC8FD8CB120E52B000F3E71A /* EventSendingController.idl */,
+ BC14E4E1120E032000826C0C /* GCController.idl */,
+ BC952ED211F3C29F003398B4 /* LayoutTestController.idl */,
+ );
+ path = Bindings;
+ sourceTree = "<group>";
+ };
+ BC952D3A11F3BF1F003398B4 /* Derived Sources */ = {
+ isa = PBXGroup;
+ children = (
+ BC8FD8D0120E545B00F3E71A /* JSEventSendingController.cpp */,
+ BC8FD8D1120E545B00F3E71A /* JSEventSendingController.h */,
+ BC14E4E8120E03D800826C0C /* JSGCController.cpp */,
+ BC14E4E9120E03D800826C0C /* JSGCController.h */,
+ BC952F1D11F3C652003398B4 /* JSLayoutTestController.cpp */,
+ BC952F1E11F3C652003398B4 /* JSLayoutTestController.h */,
+ );
+ name = "Derived Sources";
+ sourceTree = "<group>";
+ };
+ BC99CBF11207642D00FDEE76 /* Shared */ = {
+ isa = PBXGroup;
+ children = (
+ BC99A4841208901A007E9F08 /* StringFunctions.h */,
+ );
+ name = Shared;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 8DD76F960486AA7600D96B5E /* WebKitTestRunner */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "WebKitTestRunner" */;
+ buildPhases = (
+ 8DD76F990486AA7600D96B5E /* Sources */,
+ 8DD76F9B0486AA7600D96B5E /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ BC25194211D15D94002EBC01 /* PBXTargetDependency */,
+ );
+ name = WebKitTestRunner;
+ productInstallPath = "$(HOME)/bin";
+ productName = WebKitTestRunner;
+ productReference = 8DD76FA10486AA7600D96B5E /* WebKitTestRunner */;
+ productType = "com.apple.product-type.tool";
+ };
+ BC25186111D15D54002EBC01 /* WebKitTestRunnerInjectedBundle */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = BC25186611D15D55002EBC01 /* Build configuration list for PBXNativeTarget "WebKitTestRunnerInjectedBundle" */;
+ buildPhases = (
+ BC25185E11D15D54002EBC01 /* Resources */,
+ BC25185F11D15D54002EBC01 /* Sources */,
+ BC25186011D15D54002EBC01 /* Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ BC952ED711F3C38B003398B4 /* PBXTargetDependency */,
+ );
+ name = WebKitTestRunnerInjectedBundle;
+ productName = InjectedBundle;
+ productReference = BC25186211D15D54002EBC01 /* WebKitTestRunnerInjectedBundle.bundle */;
+ productType = "com.apple.product-type.bundle";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "WebKitTestRunner" */;
+ compatibilityVersion = "Xcode 3.1";
+ developmentRegion = English;
+ hasScannedForEncodings = 1;
+ knownRegions = (
+ English,
+ Japanese,
+ French,
+ German,
+ );
+ mainGroup = 08FB7794FE84155DC02AAC07 /* WebKitTestRunner */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8DD76F960486AA7600D96B5E /* WebKitTestRunner */,
+ BC25186111D15D54002EBC01 /* WebKitTestRunnerInjectedBundle */,
+ BC952D7711F3BF5D003398B4 /* Derived Sources */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ BC25185E11D15D54002EBC01 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 6510A78211EC643800410867 /* AHEM____.TTF in Resources */,
+ 6510A78311EC643800410867 /* ColorBits.ttf in Resources */,
+ 6510A78411EC643800410867 /* WebKitWeightWatcher100.ttf in Resources */,
+ 6510A78511EC643800410867 /* WebKitWeightWatcher200.ttf in Resources */,
+ 6510A78611EC643800410867 /* WebKitWeightWatcher300.ttf in Resources */,
+ 6510A78711EC643800410867 /* WebKitWeightWatcher400.ttf in Resources */,
+ 6510A78811EC643800410867 /* WebKitWeightWatcher500.ttf in Resources */,
+ 6510A78911EC643800410867 /* WebKitWeightWatcher600.ttf in Resources */,
+ 6510A78A11EC643800410867 /* WebKitWeightWatcher700.ttf in Resources */,
+ 6510A78B11EC643800410867 /* WebKitWeightWatcher800.ttf in Resources */,
+ 6510A78C11EC643800410867 /* WebKitWeightWatcher900.ttf in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXShellScriptBuildPhase section */
+ BC952D8211F3BF78003398B4 /* Generate Derived Sources */ = {
+ isa = PBXShellScriptBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ inputPaths = (
+ );
+ name = "Generate Derived Sources";
+ outputPaths = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ shellPath = /bin/sh;
+ shellScript = "mkdir -p \"${BUILT_PRODUCTS_DIR}/DerivedSources/WebKitTestRunner\"\ncd \"${BUILT_PRODUCTS_DIR}/DerivedSources/WebKitTestRunner\"\n\nexport WebKitTestRunner=\"${SRCROOT}\"\nexport WebCoreScripts=\"${WEBCORE_PRIVATE_HEADERS_DIR}\"\n\nif [ \"${ACTION}\" = \"build\" -o \"${ACTION}\" = \"install\" -o \"${ACTION}\" = \"installhdrs\" ]; then\n make -f \"${WebKitTestRunner}/DerivedSources.make\" -j `/usr/sbin/sysctl -n hw.availcpu`\nfi\n";
+ };
+/* End PBXShellScriptBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8DD76F990486AA7600D96B5E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BC793400118F7C84005EA8E2 /* main.mm in Sources */,
+ BC793431118F7F19005EA8E2 /* TestController.cpp in Sources */,
+ BC7934E811906846005EA8E2 /* PlatformWebViewMac.mm in Sources */,
+ BCD7D2F811921278006DB7EE /* TestInvocation.cpp in Sources */,
+ BC8C795C11D2785D004535A1 /* TestControllerMac.mm in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ BC25185F11D15D54002EBC01 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ BC251A3E11D16831002EBC01 /* InjectedBundleMain.cpp in Sources */,
+ BCC997A411D3C8F60017BCA2 /* InjectedBundle.cpp in Sources */,
+ BCC997A511D3C8F60017BCA2 /* InjectedBundlePage.cpp in Sources */,
+ BCC9981811D3F51E0017BCA2 /* LayoutTestController.cpp in Sources */,
+ 65EB85A011EC67CC0034D300 /* ActivateFonts.mm in Sources */,
+ BC952C0D11F3B965003398B4 /* JSWrapper.cpp in Sources */,
+ BC952F1F11F3C652003398B4 /* JSLayoutTestController.cpp in Sources */,
+ BC14E4DB120E02D000826C0C /* GCController.cpp in Sources */,
+ BC14E4EA120E03D800826C0C /* JSGCController.cpp in Sources */,
+ BC8FD8CA120E527F00F3E71A /* EventSendingController.cpp in Sources */,
+ BC8FD8D2120E545B00F3E71A /* JSEventSendingController.cpp in Sources */,
+ C0CE720B1247C93300BC0EC4 /* LayoutTestControllerMac.mm in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ BC25194211D15D94002EBC01 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BC25186111D15D54002EBC01 /* WebKitTestRunnerInjectedBundle */;
+ targetProxy = BC25194111D15D94002EBC01 /* PBXContainerItemProxy */;
+ };
+ BC952ED711F3C38B003398B4 /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = BC952D7711F3BF5D003398B4 /* Derived Sources */;
+ targetProxy = BC952ED611F3C38B003398B4 /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB927508733DD40010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC251A1811D16795002EBC01 /* WebKitTestRunner.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ 1DEB927608733DD40010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC251A1811D16795002EBC01 /* WebKitTestRunner.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ 1DEB927908733DD40010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC793427118F7DAF005EA8E2 /* DebugRelease.xcconfig */;
+ buildSettings = {
+ GCC_OPTIMIZATION_LEVEL = 0;
+ };
+ name = Debug;
+ };
+ 1DEB927A08733DD40010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC793427118F7DAF005EA8E2 /* DebugRelease.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ BC25186411D15D55002EBC01 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC25197111D15E61002EBC01 /* InjectedBundle.xcconfig */;
+ buildSettings = {
+ };
+ name = Debug;
+ };
+ BC25186511D15D55002EBC01 /* Release */ = {
+ isa = XCBuildConfiguration;
+ baseConfigurationReference = BC25197111D15E61002EBC01 /* InjectedBundle.xcconfig */;
+ buildSettings = {
+ };
+ name = Release;
+ };
+ BC952D7811F3BF5E003398B4 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ PRODUCT_NAME = "Derived Sources";
+ };
+ name = Debug;
+ };
+ BC952D7911F3BF5E003398B4 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = YES;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_ENABLE_FIX_AND_CONTINUE = NO;
+ PRODUCT_NAME = "Derived Sources";
+ ZERO_LINK = NO;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB927408733DD40010E9CD /* Build configuration list for PBXNativeTarget "WebKitTestRunner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB927508733DD40010E9CD /* Debug */,
+ 1DEB927608733DD40010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1DEB927808733DD40010E9CD /* Build configuration list for PBXProject "WebKitTestRunner" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB927908733DD40010E9CD /* Debug */,
+ 1DEB927A08733DD40010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BC25186611D15D55002EBC01 /* Build configuration list for PBXNativeTarget "WebKitTestRunnerInjectedBundle" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BC25186411D15D55002EBC01 /* Debug */,
+ BC25186511D15D55002EBC01 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ BC952D7D11F3BF6A003398B4 /* Build configuration list for PBXAggregateTarget "Derived Sources" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ BC952D7811F3BF5E003398B4 /* Debug */,
+ BC952D7911F3BF5E003398B4 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
diff --git a/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h b/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h
new file mode 100644
index 0000000..9d508ed
--- /dev/null
+++ b/Tools/WebKitTestRunner/WebKitTestRunnerPrefix.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#ifdef __OBJC__
+#include <Cocoa/Cocoa.h>
+#endif
+
+#if defined(WIN32) || defined(_WIN32)
+// 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
+#endif
+
+#include <WebKit2/WebKit2.h>
diff --git a/Tools/WebKitTestRunner/fonts/AHEM____.TTF b/Tools/WebKitTestRunner/fonts/AHEM____.TTF
new file mode 100644
index 0000000..ac81cb0
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/AHEM____.TTF
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/ColorBits-A.png b/Tools/WebKitTestRunner/fonts/ColorBits-A.png
new file mode 100644
index 0000000..8b9319c
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/ColorBits-A.png
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/ColorBits.ttf b/Tools/WebKitTestRunner/fonts/ColorBits.ttf
new file mode 100644
index 0000000..cd919e8
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/ColorBits.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/WebKit Layout Tests 2.ttf b/Tools/WebKitTestRunner/fonts/WebKit Layout Tests 2.ttf
new file mode 100644
index 0000000..e732fbc
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/WebKit Layout Tests 2.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/WebKit Layout Tests.ttf b/Tools/WebKitTestRunner/fonts/WebKit Layout Tests.ttf
new file mode 100644
index 0000000..f9f997e
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/WebKit Layout Tests.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher100.ttf b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher100.ttf
new file mode 100644
index 0000000..22b00de
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher100.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher200.ttf b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher200.ttf
new file mode 100644
index 0000000..1ccadba
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher200.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher300.ttf b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher300.ttf
new file mode 100644
index 0000000..ab5563d
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher300.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher400.ttf b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher400.ttf
new file mode 100644
index 0000000..56d279e
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher400.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher500.ttf b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher500.ttf
new file mode 100644
index 0000000..d827d7d
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher500.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher600.ttf b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher600.ttf
new file mode 100644
index 0000000..9141596
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher600.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher700.ttf b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher700.ttf
new file mode 100644
index 0000000..a2d0505
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher700.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher800.ttf b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher800.ttf
new file mode 100644
index 0000000..d0f354b
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher800.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher900.ttf b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher900.ttf
new file mode 100644
index 0000000..6b895ca
--- /dev/null
+++ b/Tools/WebKitTestRunner/fonts/WebKitWeightWatcher900.ttf
Binary files differ
diff --git a/Tools/WebKitTestRunner/mac/PlatformWebViewMac.mm b/Tools/WebKitTestRunner/mac/PlatformWebViewMac.mm
new file mode 100644
index 0000000..b68f6a3
--- /dev/null
+++ b/Tools/WebKitTestRunner/mac/PlatformWebViewMac.mm
@@ -0,0 +1,83 @@
+/*
+ * 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 "PlatformWebView.h"
+
+namespace WTR {
+
+PlatformWebView::PlatformWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
+{
+ NSRect rect = NSMakeRect(0, 0, 800, 600);
+ m_view = [[WKView alloc] initWithFrame:rect contextRef:contextRef pageGroupRef:pageGroupRef];
+
+ NSRect windowRect = NSOffsetRect(rect, -10000, [[[NSScreen screens] objectAtIndex:0] frame].size.height - rect.size.height + 10000);
+ m_window = [[NSWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:YES];
+ [m_window setColorSpace:[[NSScreen mainScreen] colorSpace]];
+ [[m_window contentView] addSubview:m_view];
+ [m_window orderBack:nil];
+ [m_window setAutodisplay:NO];
+ [m_window setReleasedWhenClosed:NO];
+}
+
+void PlatformWebView::resizeTo(unsigned width, unsigned height)
+{
+ [m_view setFrame:NSMakeRect(0, 0, width, height)];
+}
+
+PlatformWebView::~PlatformWebView()
+{
+ [m_window close];
+ [m_window release];
+ [m_view release];
+}
+
+WKPageRef PlatformWebView::page()
+{
+ return [m_view pageRef];
+}
+
+void PlatformWebView::focus()
+{
+ // Implement.
+}
+
+WKRect PlatformWebView::windowFrame()
+{
+ NSRect frame = [m_window frame];
+
+ WKRect wkFrame;
+ wkFrame.origin.x = frame.origin.x;
+ wkFrame.origin.y = frame.origin.y;
+ wkFrame.size.width = frame.size.width;
+ wkFrame.size.height = frame.size.height;
+ return wkFrame;
+}
+
+void PlatformWebView::setWindowFrame(WKRect frame)
+{
+ [m_window setFrame:NSMakeRect(frame.origin.x, frame.origin.y, frame.size.width, frame.size.height) display:YES];
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/mac/TestControllerMac.mm b/Tools/WebKitTestRunner/mac/TestControllerMac.mm
new file mode 100644
index 0000000..fee0070
--- /dev/null
+++ b/Tools/WebKitTestRunner/mac/TestControllerMac.mm
@@ -0,0 +1,63 @@
+/*
+ * 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 "TestController.h"
+
+#include <WebKit2/WKStringCF.h>
+#include <mach-o/dyld.h>
+
+namespace WTR {
+
+void TestController::notifyDone()
+{
+}
+
+void TestController::platformInitialize()
+{
+}
+
+void TestController::initializeInjectedBundlePath()
+{
+ NSString *nsBundlePath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:@"WebKitTestRunnerInjectedBundle.bundle"];
+ m_injectedBundlePath.adopt(WKStringCreateWithCFString((CFStringRef)nsBundlePath));
+}
+
+void TestController::initializeTestPluginDirectory()
+{
+ m_testPluginDirectory.adopt(WKStringCreateWithCFString((CFStringRef)[[NSBundle mainBundle] bundlePath]));
+}
+
+void TestController::platformRunUntil(bool& done, double timeout)
+{
+ CFAbsoluteTime end = CFAbsoluteTimeGetCurrent() + timeout;
+ while (!done && CFAbsoluteTimeGetCurrent() < end)
+ [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
+}
+
+void TestController::platformInitializeContext()
+{
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/mac/main.mm b/Tools/WebKitTestRunner/mac/main.mm
new file mode 100644
index 0000000..d2f26ab
--- /dev/null
+++ b/Tools/WebKitTestRunner/mac/main.mm
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+
+#import "TestController.h"
+
+int main(int argc, const char* argv[])
+{
+ NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
+ [NSApplication sharedApplication];
+ {
+ WTR::TestController controller(argc, argv);
+ }
+ [pool drain];
+ return 0;
+}
diff --git a/Tools/WebKitTestRunner/qt/PlatformWebViewQt.cpp b/Tools/WebKitTestRunner/qt/PlatformWebViewQt.cpp
new file mode 100644
index 0000000..18e2523
--- /dev/null
+++ b/Tools/WebKitTestRunner/qt/PlatformWebViewQt.cpp
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 University of Szeged. 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 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 "PlatformWebView.h"
+#include "qgraphicswkview.h"
+#include "qwkcontext.h"
+#include <QtGui>
+
+namespace WTR {
+
+class WebView : public QGraphicsView {
+public:
+ WebView(WKContextRef);
+
+ QGraphicsWKView* wkView() const { return m_item; }
+
+ virtual ~WebView() { delete m_item; }
+
+private:
+ QGraphicsWKView* m_item;
+};
+
+WebView::WebView(WKContextRef contextRef)
+ : QGraphicsView()
+ , m_item(new QGraphicsWKView(new QWKContext(contextRef, this)))
+{
+ setScene(new QGraphicsScene(this));
+ scene()->addItem(m_item);
+}
+
+PlatformWebView::PlatformWebView(WKContextRef contextRef, WKPageGroupRef)
+ : m_view(new WebView(contextRef))
+ , m_window(new QMainWindow())
+{
+ m_view->setParent(m_window);
+ m_window->setCentralWidget(m_view);
+ m_window->setGeometry(0, 0, 800, 600);
+}
+
+PlatformWebView::~PlatformWebView()
+{
+ delete m_window;
+}
+
+void PlatformWebView::resizeTo(unsigned width, unsigned height)
+{
+ m_window->resize(width, height);
+}
+
+WKPageRef PlatformWebView::page()
+{
+ return m_view->wkView()->page()->pageRef();
+}
+
+void PlatformWebView::focus()
+{
+ m_view->setFocus(Qt::OtherFocusReason);
+}
+
+WKRect PlatformWebView::windowFrame()
+{
+ // Implement.
+
+ WKRect wkFrame;
+ wkFrame.origin.x = 0;
+ wkFrame.origin.y = 0;
+ wkFrame.size.width = 0;
+ wkFrame.size.height = 0;
+ return wkFrame;
+}
+
+void PlatformWebView::setWindowFrame(WKRect)
+{
+ // Implement.
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/qt/TestControllerQt.cpp b/Tools/WebKitTestRunner/qt/TestControllerQt.cpp
new file mode 100644
index 0000000..ca0a00c
--- /dev/null
+++ b/Tools/WebKitTestRunner/qt/TestControllerQt.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 University of Szeged. 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 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 "TestController.h"
+
+#include "WKStringQt.h"
+
+#include <cstdlib>
+#include <QCoreApplication>
+#include <QEventLoop>
+#include <QFileInfo>
+#include <QLibrary>
+#include <QObject>
+#include <QtGlobal>
+#include <wtf/Platform.h>
+#include <wtf/text/WTFString.h>
+
+namespace WTR {
+
+class TestControllerRunLoop : public QObject {
+ Q_OBJECT
+public:
+ static TestControllerRunLoop* instance()
+ {
+ static TestControllerRunLoop* result = new TestControllerRunLoop;
+ return result;
+ }
+
+ void start(int msec)
+ {
+ m_timerID = startTimer(msec);
+ ASSERT(m_timerID);
+ m_eventLoop.exec(QEventLoop::ExcludeUserInputEvents);
+ }
+
+ void stop()
+ {
+ killTimer(m_timerID);
+ m_eventLoop.quit();
+ }
+private:
+ TestControllerRunLoop() {}
+
+ void timerEvent(QTimerEvent*)
+ {
+ fprintf(stderr, "FAIL: TestControllerRunLoop timed out.\n");
+ stop();
+ }
+
+ QEventLoop m_eventLoop;
+ int m_timerID;
+};
+
+void TestController::notifyDone()
+{
+ TestControllerRunLoop::instance()->stop();
+}
+
+void TestController::platformInitialize()
+{
+}
+
+void TestController::platformRunUntil(bool&, double timeout)
+{
+ TestControllerRunLoop::instance()->start(static_cast<int>(timeout * 1000));
+}
+
+static bool isExistingLibrary(const QString& path)
+{
+#if OS(WINDOWS) || OS(SYMBIAN)
+ const char* librarySuffixes[] = { ".dll" };
+#elif OS(MAC_OS_X)
+ const char* librarySuffixes[] = { ".bundle", ".dylib", ".so" };
+#elif OS(UNIX)
+ const char* librarySuffixes[] = { ".so" };
+#else
+#error Library path suffix should be specified for this platform
+#endif
+ for (unsigned i = 0; i < sizeof(librarySuffixes) / sizeof(const char*); ++i) {
+ if (QLibrary::isLibrary(path + librarySuffixes[i]))
+ return true;
+ }
+
+ return false;
+}
+
+void TestController::initializeInjectedBundlePath()
+{
+ QString path = QLatin1String(getenv("WTR_INJECTEDBUNDLE_PATH"));
+ if (path.isEmpty())
+ path = QFileInfo(QCoreApplication::applicationDirPath() + "/../lib/libWTRInjectedBundle").absoluteFilePath();
+ if (!isExistingLibrary(path))
+ qFatal("Cannot find the injected bundle at %s\n", qPrintable(path));
+
+ m_injectedBundlePath = WKStringCreateWithQString(path);
+}
+
+void TestController::initializeTestPluginDirectory()
+{
+ // This is called after initializeInjectedBundlePath.
+ m_testPluginDirectory = m_injectedBundlePath;
+}
+
+void TestController::platformInitializeContext()
+{
+}
+
+#include "TestControllerQt.moc"
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro b/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro
new file mode 100644
index 0000000..cf5d5b8
--- /dev/null
+++ b/Tools/WebKitTestRunner/qt/WebKitTestRunner.pro
@@ -0,0 +1,71 @@
+TARGET = WebKitTestRunner
+CONFIG -= app_bundle
+
+BASEDIR = $$PWD/../
+isEmpty(OUTPUT_DIR): OUTPUT_DIR = ../../..
+GENERATED_SOURCES_DIR = ../generated
+
+
+include(../../../WebKit.pri)
+
+!CONFIG(release, debug|release) {
+ OBJECTS_DIR = obj/debug
+} else { # Release
+ OBJECTS_DIR = obj/release
+}
+
+DEFINES += USE_SYSTEM_MALLOC
+
+INCLUDEPATH += \
+ $$BASEDIR \
+ $$BASEDIR/../../JavaScriptCore \
+ $$BASEDIR/../../WebKit2 \
+ $$BASEDIR/../../WebKit2/Shared \
+ $$BASEDIR/../../WebKit2/UIProcess/API/qt \
+ $$BASEDIR/../../WebKit2/UIProcess/API/cpp/qt \
+ $$GENERATED_SOURCES_DIR
+
+INCLUDEPATH += \
+ $$OUTPUT_DIR/include \
+
+
+DESTDIR = $$OUTPUT_DIR/bin
+
+unix:!mac:!symbian {
+ CONFIG += link_pkgconfig
+ PKGCONFIG += fontconfig
+}
+
+QT = core gui network
+
+HEADERS = \
+ $$BASEDIR/PlatformWebView.h \
+ $$BASEDIR/StringFunctions.h \
+ $$BASEDIR/TestController.h \
+ $$BASEDIR/TestInvocation.h
+
+SOURCES = \
+ main.cpp \
+ PlatformWebViewQt.cpp \
+ TestControllerQt.cpp \
+ $$BASEDIR/TestController.cpp \
+ $$BASEDIR/TestInvocation.cpp \
+
+PREFIX_HEADER = $$BASEDIR/WebKitTestRunnerPrefix.h
+QMAKE_CXXFLAGS += "-include $$PREFIX_HEADER"
+
+linux-* {
+ # From Creator's src/rpath.pri:
+ # Do the rpath by hand since it's not possible to use ORIGIN in QMAKE_RPATHDIR
+ # this expands to $ORIGIN (after qmake and make), it does NOT read a qmake var.
+ QMAKE_RPATHDIR = \$\$ORIGIN/../lib $$QMAKE_RPATHDIR
+ MY_RPATH = $$join(QMAKE_RPATHDIR, ":")
+
+ QMAKE_LFLAGS += -Wl,-z,origin \'-Wl,-rpath,$${MY_RPATH}\'
+ QMAKE_RPATHDIR =
+} else {
+ QMAKE_RPATHDIR = $$OUTPUT_DIR/lib $$QMAKE_RPATHDIR
+}
+
+include(../../../JavaScriptCore/JavaScriptCore.pri)
+addJavaScriptCoreLib(../../../JavaScriptCore)
diff --git a/Tools/WebKitTestRunner/qt/main.cpp b/Tools/WebKitTestRunner/qt/main.cpp
new file mode 100644
index 0000000..4312a05
--- /dev/null
+++ b/Tools/WebKitTestRunner/qt/main.cpp
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ * Copyright (C) 2010 University of Szeged.
+ *
+ * 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 "TestController.h"
+
+#include <QApplication>
+#include <QObject>
+#include <QTimer>
+
+class Launcher : public QObject {
+ Q_OBJECT
+
+public:
+ Launcher(int argc, char** argv)
+ : m_argc(argc)
+ , m_argv(argv)
+ {
+ }
+
+ ~Launcher()
+ {
+ delete m_controller;
+ }
+
+public slots:
+ void launch()
+ {
+ m_controller = new WTR::TestController(m_argc, const_cast<const char**>(m_argv));
+ QApplication::exit();
+ }
+
+private:
+ WTR::TestController* m_controller;
+ int m_argc;
+ char** m_argv;
+};
+
+int main(int argc, char** argv)
+{
+ QApplication app(argc, argv);
+ Launcher launcher(argc, argv);
+ QTimer::singleShot(0, &launcher, SLOT(launch()));
+ return app.exec();;
+}
+
+#include "main.moc"
diff --git a/Tools/WebKitTestRunner/win/InjectedBundle.vcproj b/Tools/WebKitTestRunner/win/InjectedBundle.vcproj
new file mode 100644
index 0000000..cdf1af3
--- /dev/null
+++ b/Tools/WebKitTestRunner/win/InjectedBundle.vcproj
@@ -0,0 +1,492 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="InjectedBundle"
+ ProjectGUID="{CBC3391C-F060-4BF5-A66E-81404168816B}"
+ RootNamespace="InjectedBundle"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;..\Configurations\InjectedBundleCoreFoundation.vsprops;..\Configurations\InjectedBundleCommon.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="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;..\Configurations\InjectedBundleCoreFoundation.vsprops;..\Configurations\InjectedBundleCommon.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="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;..\Configurations\InjectedBundleCoreFoundation.vsprops;..\Configurations\InjectedBundleCommon.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="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;..\Configurations\InjectedBundleCFLite.vsprops;..\Configurations\InjectedBundleCommon.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="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;..\Configurations\InjectedBundleCFLite.vsprops;..\Configurations\InjectedBundleCommon.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_LTCG|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;..\Configurations\InjectedBundleCoreFoundation.vsprops;..\Configurations\InjectedBundleCommon.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="Bindings"
+ >
+ <File
+ RelativePath="..\InjectedBundle\Bindings\CodeGeneratorTestRunner.pm"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\Bindings\JSWrappable.h"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\Bindings\JSWrapper.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\Bindings\JSWrapper.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Derived Sources"
+ >
+ <File
+ RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSEventSendingController.cpp"
+ >
+ </File>
+ <File
+ RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSEventSendingController.h"
+ >
+ </File>
+ <File
+ RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSGCController.cpp"
+ >
+ </File>
+ <File
+ RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSGCController.h"
+ >
+ </File>
+ <File
+ RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSLayoutTestController.cpp"
+ >
+ </File>
+ <File
+ RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\JSLayoutTestController.h"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath="..\InjectedBundle\win\ActivateFonts.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\EventSendingController.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\EventSendingController.h"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\GCController.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\GCController.h"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\InjectedBundle.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\InjectedBundle.h"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\InjectedBundleMain.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\InjectedBundlePage.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\InjectedBundlePage.h"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\LayoutTestController.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\LayoutTestController.h"
+ >
+ </File>
+ <File
+ RelativePath="..\InjectedBundle\win\LayoutTestControllerWin.cpp"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/WebKitTestRunner/win/InjectedBundleGenerated.vcproj b/Tools/WebKitTestRunner/win/InjectedBundleGenerated.vcproj
new file mode 100755
index 0000000..83c3868
--- /dev/null
+++ b/Tools/WebKitTestRunner/win/InjectedBundleGenerated.vcproj
@@ -0,0 +1,87 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="InjectedBundleGenerated"
+ ProjectGUID="{4343BC0B-A2E0-4B48-8277-F33CFBFA83CD}"
+ RootNamespace="InjectedBundleGenerated"
+ Keyword="MakeFileProj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="0"
+ InheritedPropertySheets=".\InjectedBundleGeneratedCommon.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="0"
+ InheritedPropertySheets=".\InjectedBundleGeneratedCommon.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_All|Win32"
+ ConfigurationType="0"
+ InheritedPropertySheets=".\InjectedBundleGeneratedCommon.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_LTCG|Win32"
+ ConfigurationType="0"
+ InheritedPropertySheets=".\InjectedBundleGeneratedCommon.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_Cairo_CFLite|Win32"
+ ConfigurationType="0"
+ InheritedPropertySheets=".\InjectedBundleGeneratedCommon.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_Cairo_CFLite|Win32"
+ ConfigurationType="0"
+ InheritedPropertySheets=".\InjectedBundleGeneratedCommon.vsprops"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\build-generated-files.sh"
+ >
+ </File>
+ <File
+ RelativePath="..\DerivedSources.make"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/WebKitTestRunner/win/InjectedBundleGeneratedCommon.vsprops b/Tools/WebKitTestRunner/win/InjectedBundleGeneratedCommon.vsprops
new file mode 100644
index 0000000..5675aed
--- /dev/null
+++ b/Tools/WebKitTestRunner/win/InjectedBundleGeneratedCommon.vsprops
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="InjectedBundleGeneratedCommon"
+ OutputDirectory="$(WebKitOutputDir)\lib"
+ IntermediateDirectory="$(WebKitOutputDir)\obj\$(ProjectName)\$(ConfigurationName)"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="if exist &quot;$(WebKitOutputDir)\buildfailed&quot; grep XX$(ProjectName)XX &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;if errorlevel 1 exit 1&#x0D;&#x0A;echo XX$(ProjectName)XX &gt; &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;set PATH=%SystemDrive%\cygwin\bin;%PATH%&#x0D;&#x0A;bash build-generated-files.sh &quot;$(WebKitOutputDir)&quot; &quot;$(WebKitLibrariesDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit 1&#x0D;&#x0A;&#x0D;&#x0A;if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;"
+ ReBuildCommandLine="echo XX$(ProjectName)XX &gt; &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;&#x0D;&#x0A;del /s /q &quot;$(WebKitOutputDir)\obj\InjectedBundle\DerivedSources&quot;&#x0D;&#x0A;set PATH=%SystemDrive%\cygwin\bin;%PATH%&#x0D;&#x0A;bash build-generated-files.sh &quot;$(WebKitOutputDir)&quot; &quot;$(WebKitLibrariesDir)&quot;&#x0D;&#x0A;if errorlevel 1 exit 1&#x0D;&#x0A;&#x0D;&#x0A;if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;"
+ CleanCommandLine="del /s /q &quot;$(WebKitOutputDir)\obj\InjectedBundle\DerivedSources&quot;&#x0D;&#x0A;if exist &quot;$(WebKitOutputDir)\buildfailed&quot; del &quot;$(WebKitOutputDir)\buildfailed&quot;&#x0D;&#x0A;"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/WebKitTestRunner/win/InjectedBundlePostBuild.cmd b/Tools/WebKitTestRunner/win/InjectedBundlePostBuild.cmd
new file mode 100644
index 0000000..f011495
--- /dev/null
+++ b/Tools/WebKitTestRunner/win/InjectedBundlePostBuild.cmd
@@ -0,0 +1 @@
+if exist "%WEBKITOUTPUTDIR%\buildfailed" del "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/WebKitTestRunner/win/InjectedBundlePreBuild.cmd b/Tools/WebKitTestRunner/win/InjectedBundlePreBuild.cmd
new file mode 100644
index 0000000..3a84c26
--- /dev/null
+++ b/Tools/WebKitTestRunner/win/InjectedBundlePreBuild.cmd
@@ -0,0 +1,6 @@
+%SystemDrive%\cygwin\bin\which.exe bash
+if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
+cmd /c
+if exist "%WEBKITOUTPUTDIR%\buildfailed" grep XX%PROJECTNAME%XX "%WEBKITOUTPUTDIR%\buildfailed"
+if errorlevel 1 exit 1
+echo XX%PROJECTNAME%XX > "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/WebKitTestRunner/win/PlatformWebViewWin.cpp b/Tools/WebKitTestRunner/win/PlatformWebViewWin.cpp
new file mode 100644
index 0000000..c132275
--- /dev/null
+++ b/Tools/WebKitTestRunner/win/PlatformWebViewWin.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 "PlatformWebView.h"
+
+namespace WTR {
+
+static LPCWSTR hostWindowClassName = L"WTRWebViewHostWindow";
+
+static void registerWindowClass()
+{
+ static bool initialized;
+ if (initialized)
+ return;
+ initialized = true;
+
+ WNDCLASSEXW wndClass = {0};
+ wndClass.cbSize = sizeof(wndClass);
+ wndClass.style = CS_HREDRAW | CS_VREDRAW;
+ wndClass.lpfnWndProc = DefWindowProcW;
+ wndClass.hCursor = LoadCursor(0, IDC_ARROW);
+ wndClass.hInstance = GetModuleHandle(0);
+ wndClass.lpszClassName = hostWindowClassName;
+
+ RegisterClassExW(&wndClass);
+}
+
+PlatformWebView::PlatformWebView(WKContextRef contextRef, WKPageGroupRef pageGroupRef)
+{
+ registerWindowClass();
+
+ RECT viewRect = {0, 0, 800, 600};
+ m_window = CreateWindowExW(0, hostWindowClassName, L"WebKitTestRunner", WS_OVERLAPPEDWINDOW, 0 /*XOFFSET*/, 0 /*YOFFSET*/, viewRect.right, viewRect.bottom, 0, 0, GetModuleHandle(0), 0);
+ m_view = WKViewCreate(viewRect, contextRef, pageGroupRef, m_window);
+}
+
+PlatformWebView::~PlatformWebView()
+{
+ if (::IsWindow(m_window))
+ ::DestroyWindow(m_window);
+ WKRelease(m_view);
+}
+
+void PlatformWebView::resizeTo(unsigned width, unsigned height)
+{
+ ::SetWindowPos(WKViewGetWindow(m_view), 0, 0, 0, width, height, SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS);
+}
+
+WKPageRef PlatformWebView::page()
+{
+ return WKViewGetPage(m_view);
+}
+
+void PlatformWebView::focus()
+{
+ ::SetFocus(::WKViewGetWindow(m_view));
+}
+
+WKRect PlatformWebView::windowFrame()
+{
+ // Implement.
+
+ WKRect wkFrame;
+ wkFrame.origin.x = 0;
+ wkFrame.origin.y = 0;
+ wkFrame.size.width = 0;
+ wkFrame.size.height = 0;
+ return wkFrame;
+}
+
+void PlatformWebView::setWindowFrame(WKRect)
+{
+ // Implement.
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/win/TestControllerWin.cpp b/Tools/WebKitTestRunner/win/TestControllerWin.cpp
new file mode 100644
index 0000000..e562ada
--- /dev/null
+++ b/Tools/WebKitTestRunner/win/TestControllerWin.cpp
@@ -0,0 +1,155 @@
+/*
+ * 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 "TestController.h"
+
+#include <fcntl.h>
+#include <io.h>
+#include <shlwapi.h>
+#include <string>
+#include <WebKit2/WKContextPrivateWin.h>
+#include <WebKit2/WKStringCF.h>
+#include <wtf/RetainPtr.h>
+#include <wtf/Vector.h>
+
+using namespace std;
+
+namespace WTR {
+
+#ifdef DEBUG_ALL
+const LPWSTR testPluginDirectoryName = L"TestNetscapePlugin_Debug";
+const char* injectedBundleDLL = "\\InjectedBundle_debug.dll";
+#else
+const LPWSTR testPluginDirectoryName = L"TestNetscapePlugin";
+const char* injectedBundleDLL = "\\InjectedBundle.dll";
+#endif
+
+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 = ::SHGetValueW(HKEY_LOCAL_MACHINE, quickTimeKeyName, quickTimeSysDir, &keyType, (LPVOID)qtPath, &qtPathBufferLen);
+ if (result != ERROR_SUCCESS || !qtPathBufferLen || keyType != REG_SZ) {
+ qtPathBufferLen = sizeof(qtPath);
+ result = ::SHGetValueW(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());
+}
+
+static LONG WINAPI exceptionFilter(EXCEPTION_POINTERS*)
+{
+ fputs("#CRASHED\n", stderr);
+ fflush(stderr);
+ return EXCEPTION_CONTINUE_SEARCH;
+}
+
+void TestController::notifyDone()
+{
+}
+
+void TestController::platformInitialize()
+{
+ ::SetUnhandledExceptionFilter(exceptionFilter);
+
+ _setmode(1, _O_BINARY);
+ _setmode(2, _O_BINARY);
+
+ // 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();
+}
+
+void TestController::initializeInjectedBundlePath()
+{
+ CFStringRef exeContainerPath = CFURLCopyFileSystemPath(CFURLCreateCopyDeletingLastPathComponent(0, CFBundleCopyExecutableURL(CFBundleGetMainBundle())), kCFURLWindowsPathStyle);
+ CFMutableStringRef bundlePath = CFStringCreateMutableCopy(0, 0, exeContainerPath);
+ CFStringAppendCString(bundlePath, injectedBundleDLL, kCFStringEncodingWindowsLatin1);
+ m_injectedBundlePath.adopt(WKStringCreateWithCFString(bundlePath));
+}
+
+void TestController::initializeTestPluginDirectory()
+{
+ RetainPtr<CFURLRef> bundleURL(AdoptCF, CFBundleCopyExecutableURL(CFBundleGetMainBundle()));
+ RetainPtr<CFURLRef> bundleDirectoryURL(AdoptCF, CFURLCreateCopyDeletingLastPathComponent(0, bundleURL.get()));
+ RetainPtr<CFStringRef> testPluginDirectoryNameString(AdoptCF, CFStringCreateWithCharacters(0, reinterpret_cast<const UniChar*>(testPluginDirectoryName), wcslen(testPluginDirectoryName)));
+ RetainPtr<CFURLRef> testPluginDirectoryURL(AdoptCF, CFURLCreateCopyAppendingPathComponent(0, bundleDirectoryURL.get(), testPluginDirectoryNameString.get(), true));
+ RetainPtr<CFStringRef> testPluginDirectoryPath(AdoptCF, CFURLCopyFileSystemPath(testPluginDirectoryURL.get(), kCFURLWindowsPathStyle));
+ m_testPluginDirectory.adopt(WKStringCreateWithCFString(testPluginDirectoryPath.get()));
+}
+
+void TestController::platformRunUntil(bool& done, double timeout)
+{
+ DWORD end = ::GetTickCount() + timeout * 1000;
+ while (!done) {
+ DWORD now = ::GetTickCount();
+ if (now > end)
+ return;
+
+ DWORD result = ::MsgWaitForMultipleObjectsEx(0, 0, end - now, QS_ALLINPUT, 0);
+ if (result == WAIT_TIMEOUT)
+ return;
+
+ ASSERT(result == WAIT_OBJECT_0);
+ // There are messages in the queue. Process them.
+ MSG msg;
+ while (::PeekMessageW(&msg, 0, 0, 0, PM_REMOVE)) {
+ ::TranslateMessage(&msg);
+ ::DispatchMessageW(&msg);
+ }
+ }
+}
+
+void TestController::platformInitializeContext()
+{
+ // FIXME: Make DRT pass with Windows native controls. <http://webkit.org/b/25592>
+ WKContextSetShouldPaintNativeControls(m_context.get(), false);
+}
+
+} // namespace WTR
diff --git a/Tools/WebKitTestRunner/win/WebKitTestRunner.vcproj b/Tools/WebKitTestRunner/win/WebKitTestRunner.vcproj
new file mode 100644
index 0000000..09dea95
--- /dev/null
+++ b/Tools/WebKitTestRunner/win/WebKitTestRunner.vcproj
@@ -0,0 +1,432 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="WebKitTestRunner"
+ ProjectGUID="{3B99669B-1817-443B-BCBE-835580146668}"
+ RootNamespace="WebKitTestRunner"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;..\Configurations\WebKitTestRunnerCommon.vsprops;..\Configurations\WebKitTestRunnerCoreFoundation.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="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;..\Configurations\WebKitTestRunnerCommon.vsprops;..\Configurations\WebKitTestRunnerCoreFoundation.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="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;..\Configurations\WebKitTestRunnerCommon.vsprops;..\Configurations\WebKitTestRunnerCoreFoundation.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="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;..\Configurations\WebKitTestRunnerCommon.vsprops;..\Configurations\WebKitTestRunnerCFLite.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="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;..\Configurations\WebKitTestRunnerCommon.vsprops;..\Configurations\WebKitTestRunnerCFLite.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_LTCG|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;..\Configurations\WebKitTestRunnerCommon.vsprops;..\Configurations\WebKitTestRunnerCoreFoundation.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="win"
+ >
+ <File
+ RelativePath=".\main.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\PlatformWebViewWin.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\TestControllerWin.cpp"
+ >
+ </File>
+ </Filter>
+ <File
+ RelativePath="..\PlatformWebView.h"
+ >
+ </File>
+ <File
+ RelativePath="..\TestController.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\TestController.h"
+ >
+ </File>
+ <File
+ RelativePath="..\TestInvocation.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\TestInvocation.h"
+ >
+ </File>
+ <File
+ RelativePath="..\WebKitTestRunnerPrefix.h"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/WebKitTestRunner/win/WebKitTestRunnerPostBuild.cmd b/Tools/WebKitTestRunner/win/WebKitTestRunnerPostBuild.cmd
new file mode 100644
index 0000000..5d8b6a3
--- /dev/null
+++ b/Tools/WebKitTestRunner/win/WebKitTestRunnerPostBuild.cmd
@@ -0,0 +1,38 @@
+if exist "%WEBKITOUTPUTDIR%\buildfailed" del "%WEBKITOUTPUTDIR%\buildfailed"
+
+if not defined ARCHIVE_BUILD (if defined PRODUCTION exit /b)
+
+mkdir 2>NUL "%WEBKITOUTPUTDIR%\bin"
+
+if not exist "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.dll" exit /b
+
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreFoundation%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFNetwork%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CFNetwork%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CFNetwork.resources" "%WEBKITOUTPUTDIR%\bin\CFNetwork.resources"
+xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CoreFoundation.resources" "%WEBKITOUTPUTDIR%\bin\CoreFoundation.resources"
+xcopy /y /d /e /i "%WEBKITLIBRARIESDIR%\bin\CharacterSets" "%WEBKITOUTPUTDIR%\bin\CharacterSets"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreGraphics%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\CoreGraphics%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\dnssd.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icudt40.dll" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt40.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icudt40%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt40%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin40%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc40%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icudt42.dll" xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt42.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icudt42%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icudt42%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuin42%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.dll"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+if exist "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.pdb"xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\icuuc42%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxml2%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\libxslt%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\pthreadVC2%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\SQLite3%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.dll" "%WEBKITOUTPUTDIR%\bin"
+xcopy /y /d "%WEBKITLIBRARIESDIR%\bin\zlib1%LIBRARYCONFIGSUFFIX%.pdb" "%WEBKITOUTPUTDIR%\bin"
diff --git a/Tools/WebKitTestRunner/win/WebKitTestRunnerPreBuild.cmd b/Tools/WebKitTestRunner/win/WebKitTestRunnerPreBuild.cmd
new file mode 100644
index 0000000..3a84c26
--- /dev/null
+++ b/Tools/WebKitTestRunner/win/WebKitTestRunnerPreBuild.cmd
@@ -0,0 +1,6 @@
+%SystemDrive%\cygwin\bin\which.exe bash
+if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
+cmd /c
+if exist "%WEBKITOUTPUTDIR%\buildfailed" grep XX%PROJECTNAME%XX "%WEBKITOUTPUTDIR%\buildfailed"
+if errorlevel 1 exit 1
+echo XX%PROJECTNAME%XX > "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/WebKitTestRunner/win/build-generated-files.sh b/Tools/WebKitTestRunner/win/build-generated-files.sh
new file mode 100644
index 0000000..8c599c1
--- /dev/null
+++ b/Tools/WebKitTestRunner/win/build-generated-files.sh
@@ -0,0 +1,42 @@
+# 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.
+
+# Calls to `cygpath -ms` below are needed to remove spaces from paths, which
+# confuse GNU make. See <http://webkit.org/b/8173>.
+
+WebKitOutputDir=$(cygpath -u "$(cygpath -ms "${1}")")
+WebKitLibrariesDir=$(cygpath -u "$(cygpath -ms "${2}")")
+DerivedSources="${WebKitOutputDir}/obj/InjectedBundle/DerivedSources"
+
+export WebKitTestRunner=$(cygpath -u "$(cygpath -ms "$(realpath ..)")")
+
+if [ -e "${WebKitOutputDir}/obj/WebCore/scripts" ]; then
+ export WebCoreScripts="${WebKitOutputDir}/obj/WebCore/scripts"
+else
+ export WebCoreScripts="${WebKitLibrariesDir}/tools/scripts"
+fi
+
+mkdir -p "${DerivedSources}"
+cd "${DerivedSources}"
+
+make -f "${WebKitTestRunner}/DerivedSources.make"
diff --git a/Tools/WebKitTestRunner/win/main.cpp b/Tools/WebKitTestRunner/win/main.cpp
new file mode 100644
index 0000000..6ef0f66
--- /dev/null
+++ b/Tools/WebKitTestRunner/win/main.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 "TestController.h"
+
+int main(int argc, const char* argv[])
+{
+ {
+ WTR::TestController controller(argc, argv);
+ }
+
+ return 0;
+}
diff --git a/Tools/WinCELauncher/main.cpp b/Tools/WinCELauncher/main.cpp
new file mode 100644
index 0000000..36c6606
--- /dev/null
+++ b/Tools/WinCELauncher/main.cpp
@@ -0,0 +1,132 @@
+/*
+ * Copyright (C) 2010 Patrick Gansterer <paroga@paroga.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 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 "WebView.h"
+#include <windows.h>
+
+static const LPCWSTR kMainWindowTitle = L"WebKit for WinCE";
+static const LPCWSTR kMainWindowClassName = L"MainWindowClass";
+
+
+static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+
+ return 0;
+}
+
+int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
+{
+ UNREFERENCED_PARAMETER(hPrevInstance);
+
+ CoInitializeEx(0, COINIT_MULTITHREADED);
+ WebView::initialize(hInstance);
+
+ LPCWSTR homeUrl = lpCmdLine;
+ bool enableDoubleBuffer = true;
+ bool fullscreen = false;
+
+ if (homeUrl[0] == '-') {
+ for (; *homeUrl && *homeUrl != ' '; ++homeUrl) {
+ switch (*homeUrl) {
+ case 'd':
+ enableDoubleBuffer = false;
+ break;
+ case 'f':
+ fullscreen = true;
+ break;
+ default:
+ break;
+ }
+ }
+ if (*homeUrl)
+ ++homeUrl;
+ }
+
+ DWORD styles = WS_VISIBLE;
+
+ if (!fullscreen) {
+ styles |= WS_CAPTION
+ | WS_MAXIMIZEBOX
+ | WS_MINIMIZEBOX
+ | WS_OVERLAPPED
+ | WS_SYSMENU
+ | WS_THICKFRAME;
+ }
+
+ WNDCLASSW wc;
+ wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.lpfnWndProc = WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = hInstance;
+ wc.hIcon = 0;
+ wc.hCursor = 0;
+ wc.hbrBackground = static_cast<HBRUSH>(GetStockObject(WHITE_BRUSH));
+ wc.lpszMenuName = 0;
+ wc.lpszClassName = kMainWindowClassName;
+ RegisterClass(&wc);
+
+ HWND hMainWindow = CreateWindowW(kMainWindowClassName, kMainWindowTitle, styles,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, 0, 0, hInstance, 0);
+
+ if (fullscreen) {
+ SetWindowPos(hMainWindow, HWND_TOPMOST, 0, 0, GetSystemMetrics(SM_CXSCREEN),
+ GetSystemMetrics(SM_CYSCREEN), SWP_SHOWWINDOW);
+ }
+
+ ShowWindow(hMainWindow, nCmdShow);
+ UpdateWindow(hMainWindow);
+
+ WTF::OwnPtr<WebView> webView = WTF::adoptPtr(new WebView(hMainWindow, enableDoubleBuffer ? WebView::EnableDoubleBuffering : WebView::NoFeature));
+ webView->load(homeUrl);
+
+ // Main message loop:
+ MSG msg;
+ BOOL bRet;
+ while (bRet = GetMessage(&msg, 0, 0, 0)) {
+ if (bRet == -1) {
+ // FIXME: Handle the error and possibly exit.
+ } else {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+ webView.clear();
+ DestroyWindow(hMainWindow);
+
+ WebView::cleanup();
+ CoUninitialize();
+
+ return msg.wParam;
+}
diff --git a/Tools/WinLauncher/PrintWebUIDelegate.cpp b/Tools/WinLauncher/PrintWebUIDelegate.cpp
new file mode 100644
index 0000000..ccc267b
--- /dev/null
+++ b/Tools/WinLauncher/PrintWebUIDelegate.cpp
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 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 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 "stdafx.h"
+#include "PrintWebUIDelegate.h"
+
+#include <commctrl.h>
+#include <commdlg.h>
+#include <objbase.h>
+#include <shlwapi.h>
+#include <wininet.h>
+
+#include <WebKit/WebKitCOMAPI.h>
+
+static const int MARGIN = 20;
+
+HRESULT PrintWebUIDelegate::QueryInterface(REFIID riid, void** ppvObject)
+{
+ *ppvObject = 0;
+ if (IsEqualIID(riid, IID_IUnknown))
+ *ppvObject = static_cast<IWebUIDelegate*>(this);
+ else if (IsEqualIID(riid, IID_IWebUIDelegate))
+ *ppvObject = static_cast<IWebUIDelegate*>(this);
+ else
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG PrintWebUIDelegate::AddRef(void)
+{
+ return ++m_refCount;
+}
+
+ULONG PrintWebUIDelegate::Release(void)
+{
+ ULONG newRef = --m_refCount;
+ if (!newRef)
+ delete this;
+
+ return newRef;
+}
+
+HRESULT PrintWebUIDelegate::webViewPrintingMarginRect(IWebView* view, RECT* rect)
+{
+ if (!view || !rect)
+ return E_POINTER;
+
+ IWebFrame* mainFrame = 0;
+ if (FAILED(view->mainFrame(&mainFrame)))
+ return E_FAIL;
+
+ IWebFramePrivate* privateFrame = 0;
+ if (FAILED(mainFrame->QueryInterface(&privateFrame))) {
+ mainFrame->Release();
+ return E_FAIL;
+ }
+
+ privateFrame->frameBounds(rect);
+
+ rect->left += MARGIN;
+ rect->top += MARGIN;
+ HDC dc = ::GetDC(0);
+ rect->right = (::GetDeviceCaps(dc, LOGPIXELSX) * 6.5) - MARGIN;
+ rect->bottom = (::GetDeviceCaps(dc, LOGPIXELSY) * 11) - MARGIN;
+ ::ReleaseDC(0, dc);
+
+ privateFrame->Release();
+ mainFrame->Release();
+
+ return S_OK;
+}
+
+HRESULT PrintWebUIDelegate::webViewHeaderHeight(IWebView* webView, float* height)
+{
+ if (!webView || !height)
+ return E_POINTER;
+
+ HDC dc = ::GetDC(0);
+
+ TEXTMETRIC textMetric;
+ ::GetTextMetrics(dc, &textMetric);
+ ::ReleaseDC(0, dc);
+
+ *height = 1.1 * textMetric.tmHeight;
+
+ return S_OK;
+}
+
+HRESULT PrintWebUIDelegate::webViewFooterHeight(IWebView* webView, float* height)
+{
+ if (!webView || !height)
+ return E_POINTER;
+
+ HDC dc = ::GetDC(0);
+
+ TEXTMETRIC textMetric;
+ ::GetTextMetrics(dc, &textMetric);
+ ::ReleaseDC(0, dc);
+
+ *height = 1.1 * textMetric.tmHeight;
+
+ return S_OK;
+}
+
+HRESULT PrintWebUIDelegate::drawHeaderInRect(
+ /* [in] */ IWebView *webView,
+ /* [in] */ RECT *rect,
+ /* [in] */ OLE_HANDLE drawingContext)
+{
+ if (!webView || !rect)
+ return E_POINTER;
+
+ // Turn off header for now.
+ HDC dc = reinterpret_cast<HDC>(drawingContext);
+
+ HFONT hFont = (HFONT)::GetStockObject(ANSI_VAR_FONT);
+ HFONT hOldFont = (HFONT)::SelectObject(dc, hFont);
+
+ LPCTSTR header(_T("[Sample Header]"));
+ int length = _tcslen(header);
+
+ int rc = ::DrawText(dc, header, length, rect, DT_LEFT | DT_NOCLIP | DT_VCENTER | DT_SINGLELINE);
+ ::SelectObject(dc, hOldFont);
+
+ if (!rc)
+ return E_FAIL;
+
+ ::MoveToEx(dc, rect->left, rect->bottom, 0);
+ HPEN hPen = (HPEN)::GetStockObject(BLACK_PEN);
+ HPEN hOldPen = (HPEN)::SelectObject(dc, hPen);
+ ::LineTo(dc, rect->right, rect->bottom);
+ ::SelectObject(dc, hOldPen);
+
+ return S_OK;
+}
+
+HRESULT PrintWebUIDelegate::drawFooterInRect(
+ /* [in] */ IWebView *webView,
+ /* [in] */ RECT *rect,
+ /* [in] */ OLE_HANDLE drawingContext,
+ /* [in] */ UINT pageIndex,
+ /* [in] */ UINT pageCount)
+{
+ if (!webView || !rect)
+ return E_POINTER;
+
+ HDC dc = reinterpret_cast<HDC>(drawingContext);
+
+ HFONT hFont = (HFONT)::GetStockObject(ANSI_VAR_FONT);
+ HFONT hOldFont = (HFONT)::SelectObject(dc, hFont);
+
+ LPCTSTR footer(_T("[Sample Footer]"));
+ int length = _tcslen(footer);
+
+ // Add a line, 1/10th inch above the footer text from left margin to right margin.
+ ::MoveToEx(dc, rect->left, rect->top, 0);
+ HPEN hPen = (HPEN)::GetStockObject(BLACK_PEN);
+ HPEN hOldPen = (HPEN)::SelectObject(dc, hPen);
+ ::LineTo(dc, rect->right, rect->top);
+ ::SelectObject(dc, hOldPen);
+
+ int rc = ::DrawText(dc, footer, length, rect, DT_LEFT | DT_NOCLIP | DT_VCENTER | DT_SINGLELINE);
+ ::SelectObject(dc, hOldFont);
+
+ if (!rc)
+ return E_FAIL;
+
+ return S_OK;
+}
diff --git a/Tools/WinLauncher/PrintWebUIDelegate.h b/Tools/WinLauncher/PrintWebUIDelegate.h
new file mode 100644
index 0000000..9749a98
--- /dev/null
+++ b/Tools/WinLauncher/PrintWebUIDelegate.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 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 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 PrintWebUIDelegate_h
+#define PrintWebUIDelegate_h
+
+#include <WebKit/WebKit.h>
+
+class PrintWebUIDelegate : public IWebUIDelegate {
+public:
+ PrintWebUIDelegate() : m_refCount(1) {}
+
+ // IUnknown
+ virtual HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void** ppvObject);
+ virtual ULONG STDMETHODCALLTYPE AddRef(void);
+ virtual ULONG STDMETHODCALLTYPE Release(void);
+
+ virtual HRESULT STDMETHODCALLTYPE createWebViewWithRequest(IWebView*, IWebURLRequest*, IWebView**) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE webViewShow(IWebView*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE webViewClose(IWebView*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE webViewFocus(IWebView*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE webViewUnfocus(IWebView*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE webViewFirstResponder(IWebView*, OLE_HANDLE*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE makeFirstResponder(IWebView*, OLE_HANDLE) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE setStatusText(IWebView*, BSTR) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE webViewStatusText(IWebView*, BSTR*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE webViewAreToolbarsVisible(IWebView*, BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE setToolbarsVisible(IWebView*, BOOL) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE webViewIsStatusBarVisible(IWebView*, BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE setStatusBarVisible(IWebView*, BOOL) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE webViewIsResizable(IWebView*, BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE setResizable(IWebView*, BOOL) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE setFrame(IWebView*, RECT*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE webViewFrame(IWebView*, RECT*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE setContentRect(IWebView*, RECT*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE webViewContentRect(IWebView*, RECT*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE runJavaScriptAlertPanelWithMessage(IWebView*, BSTR) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE runJavaScriptConfirmPanelWithMessage(IWebView*, BSTR, BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE runJavaScriptTextInputPanelWithPrompt(IWebView*, BSTR, BSTR, BSTR*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE runBeforeUnloadConfirmPanelWithMessage(IWebView*, BSTR, IWebFrame*, BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE runOpenPanelForFileButtonWithResultListener(IWebView*, IWebOpenPanelResultListener*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE mouseDidMoveOverElement(IWebView*, IPropertyBag*, UINT) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE contextMenuItemsForElement(IWebView*, IPropertyBag*, OLE_HANDLE, OLE_HANDLE*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE validateUserInterfaceItem(IWebView*, UINT, BOOL, BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE shouldPerformAction(IWebView*, UINT, UINT) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE dragDestinationActionMaskForDraggingInfo(IWebView*, IDataObject*, WebDragDestinationAction*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE willPerformDragDestinationAction(IWebView*, WebDragDestinationAction, IDataObject*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE dragSourceActionMaskForPoint(IWebView*, LPPOINT, WebDragSourceAction*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE willPerformDragSourceAction(IWebView*, WebDragSourceAction, LPPOINT, IDataObject*, IDataObject**) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE contextMenuItemSelected(IWebView*, void*, IPropertyBag*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE hasCustomMenuImplementation(BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE trackCustomPopupMenu(IWebView*, OLE_HANDLE, LPPOINT) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE measureCustomMenuItem(IWebView*, void*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE drawCustomMenuItem(IWebView*, void*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE addCustomMenuDrawingData(IWebView*, OLE_HANDLE) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE cleanUpCustomMenuDrawingData(IWebView*, OLE_HANDLE) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE canTakeFocus(IWebView*, BOOL, BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE takeFocus(IWebView*, BOOL) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE registerUndoWithTarget(IWebUndoTarget*, BSTR, IUnknown*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE removeAllActionsWithTarget(IWebUndoTarget*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE setActionTitle(BSTR) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE undo() { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE redo() { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE canUndo(BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE canRedo(BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE printFrame(IWebView*, IWebFrame *) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE ftpDirectoryTemplatePath(IWebView*, BSTR*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE webViewHeaderHeight(IWebView*, float*);
+ virtual HRESULT STDMETHODCALLTYPE webViewFooterHeight(IWebView*, float*);
+ virtual HRESULT STDMETHODCALLTYPE drawHeaderInRect(IWebView*, RECT*, OLE_HANDLE);
+ virtual HRESULT STDMETHODCALLTYPE drawFooterInRect(IWebView*, RECT*, OLE_HANDLE, UINT, UINT);
+ virtual HRESULT STDMETHODCALLTYPE webViewPrintingMarginRect(IWebView*, RECT*);
+ virtual HRESULT STDMETHODCALLTYPE canRunModal(IWebView*, BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE createModalDialog(IWebView*, IWebURLRequest*, IWebView**) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE runModal(IWebView*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE isMenuBarVisible(IWebView*, BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE setMenuBarVisible(IWebView*, BOOL) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE runDatabaseSizeLimitPrompt(IWebView*, BSTR, IWebFrame*, BOOL*) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE paintCustomScrollbar(IWebView*, HDC, RECT, WebScrollBarControlSize, WebScrollbarControlState, WebScrollbarControlPart, BOOL, float, float, WebScrollbarControlPartMask) { return E_NOTIMPL; }
+ virtual HRESULT STDMETHODCALLTYPE paintCustomScrollCorner(IWebView*, HDC, RECT) { return E_NOTIMPL; }
+
+private:
+ int m_refCount;
+};
+
+#endif
diff --git a/Tools/WinLauncher/WinLauncher.cpp b/Tools/WinLauncher/WinLauncher.cpp
new file mode 100644
index 0000000..5caf230
--- /dev/null
+++ b/Tools/WinLauncher/WinLauncher.cpp
@@ -0,0 +1,500 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Computer, Inc. All rights reserved.
+ * Copyright (C) 2009 Brent Fulgha. 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 "stdafx.h"
+#include "WinLauncher.h"
+#include <WebKit/WebKitCOMAPI.h>
+
+#include <commctrl.h>
+#include <commdlg.h>
+#include <objbase.h>
+#include <shlwapi.h>
+#include <wininet.h>
+
+#include "PrintWebUIDelegate.h"
+
+#define MAX_LOADSTRING 100
+#define URLBAR_HEIGHT 24
+
+// Global Variables:
+HINSTANCE hInst; // current instance
+HWND hMainWnd;
+HWND hURLBarWnd;
+long DefEditProc;
+IWebView* gWebView = 0;
+HWND gViewWindow = 0;
+WinLauncherWebHost* gWebHost = 0;
+PrintWebUIDelegate* gPrintDelegate = 0;
+TCHAR szTitle[MAX_LOADSTRING]; // The title bar text
+TCHAR szWindowClass[MAX_LOADSTRING]; // the main window class name
+
+// Forward declarations of functions included in this code module:
+ATOM MyRegisterClass(HINSTANCE hInstance);
+BOOL InitInstance(HINSTANCE, int);
+LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
+INT_PTR CALLBACK About(HWND, UINT, WPARAM, LPARAM);
+LRESULT CALLBACK MyEditProc(HWND, UINT, WPARAM, LPARAM);
+
+static void loadURL(BSTR urlBStr);
+
+HRESULT WinLauncherWebHost::updateAddressBar(IWebView* webView)
+{
+ IWebFrame* mainFrame = 0;
+ IWebDataSource* dataSource = 0;
+ IWebMutableURLRequest* request = 0;
+ BSTR frameURL = 0;
+
+ HRESULT hr = S_OK;
+
+ hr = webView->mainFrame(&mainFrame);
+ if (FAILED(hr))
+ goto exit;
+
+ hr = mainFrame->dataSource(&dataSource);
+ if (FAILED(hr) || !dataSource)
+ hr = mainFrame->provisionalDataSource(&dataSource);
+ if (FAILED(hr) || !dataSource)
+ goto exit;
+
+ hr = dataSource->request(&request);
+ if (FAILED(hr) || !request)
+ goto exit;
+
+ hr = request->mainDocumentURL(&frameURL);
+ if (FAILED(hr))
+ goto exit;
+
+ SendMessage(hURLBarWnd, (UINT)WM_SETTEXT, 0, (LPARAM)frameURL);
+
+exit:
+ if (mainFrame)
+ mainFrame->Release();
+ if (dataSource)
+ dataSource->Release();
+ if (request)
+ request->Release();
+ SysFreeString(frameURL);
+ return 0;
+}
+
+HRESULT STDMETHODCALLTYPE WinLauncherWebHost::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
+ return E_NOINTERFACE;
+
+ AddRef();
+ return S_OK;
+}
+
+ULONG STDMETHODCALLTYPE WinLauncherWebHost::AddRef(void)
+{
+ return ++m_refCount;
+}
+
+ULONG STDMETHODCALLTYPE WinLauncherWebHost::Release(void)
+{
+ ULONG newRef = --m_refCount;
+ if (!newRef)
+ delete(this);
+
+ return newRef;
+}
+
+static void resizeSubViews()
+{
+ RECT rcClient;
+ GetClientRect(hMainWnd, &rcClient);
+ MoveWindow(hURLBarWnd, 0, 0, rcClient.right, URLBAR_HEIGHT, TRUE);
+ MoveWindow(gViewWindow, 0, URLBAR_HEIGHT, rcClient.right, rcClient.bottom - URLBAR_HEIGHT, TRUE);
+}
+
+int APIENTRY _tWinMain(HINSTANCE hInstance,
+ HINSTANCE hPrevInstance,
+ LPTSTR lpCmdLine,
+ int nCmdShow)
+{
+#ifdef _CRTDBG_MAP_ALLOC
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+#endif
+
+ UNREFERENCED_PARAMETER(hPrevInstance);
+ UNREFERENCED_PARAMETER(lpCmdLine);
+
+ // TODO: Place code here.
+ MSG msg = {0};
+ HACCEL hAccelTable;
+
+ INITCOMMONCONTROLSEX InitCtrlEx;
+
+ InitCtrlEx.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ InitCtrlEx.dwICC = 0x00004000; //ICC_STANDARD_CLASSES;
+ InitCommonControlsEx(&InitCtrlEx);
+
+ // Initialize global strings
+ LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
+ LoadString(hInstance, IDC_WINLAUNCHER, szWindowClass, MAX_LOADSTRING);
+ MyRegisterClass(hInstance);
+
+ // Perform application initialization:
+ if (!InitInstance (hInstance, nCmdShow))
+ return FALSE;
+
+ // Init COM
+ OleInitialize(NULL);
+
+ hURLBarWnd = CreateWindow(L"EDIT", 0,
+ WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL,
+ 0, 0, 0, 0,
+ hMainWnd,
+ 0,
+ hInstance, 0);
+
+ DefEditProc = GetWindowLong(hURLBarWnd, GWL_WNDPROC);
+ SetWindowLong(hURLBarWnd, GWL_WNDPROC,(long)MyEditProc);
+ SetFocus(hURLBarWnd);
+
+ HRESULT hr = WebKitCreateInstance(CLSID_WebView, 0, IID_IWebView, (void**)&gWebView);
+ if (FAILED(hr))
+ goto exit;
+
+ gWebHost = new WinLauncherWebHost();
+ gWebHost->AddRef();
+ hr = gWebView->setFrameLoadDelegate(gWebHost);
+ if (FAILED(hr))
+ goto exit;
+
+ gPrintDelegate = new PrintWebUIDelegate;
+ gPrintDelegate->AddRef();
+ hr = gWebView->setUIDelegate(gPrintDelegate);
+ if (FAILED (hr))
+ goto exit;
+
+ hr = gWebView->setHostWindow((OLE_HANDLE) hMainWnd);
+ if (FAILED(hr))
+ goto exit;
+
+ RECT clientRect;
+ GetClientRect(hMainWnd, &clientRect);
+ hr = gWebView->initWithFrame(clientRect, 0, 0);
+ if (FAILED(hr))
+ goto exit;
+
+ IWebFrame* frame;
+ hr = gWebView->mainFrame(&frame);
+ if (FAILED(hr))
+ goto exit;
+
+ static BSTR defaultHTML = SysAllocString(TEXT("<p style=\"background-color: #00FF00\">Testing</p><img src=\"http://webkit.org/images/icon-gold.png\" alt=\"Face\"><div style=\"border: solid blue\" contenteditable=\"true\">div with blue border</div><ul><li>foo<li>bar<li>baz</ul>"));
+ frame->loadHTMLString(defaultHTML, 0);
+ frame->Release();
+
+ IWebViewPrivate* viewExt;
+ hr = gWebView->QueryInterface(IID_IWebViewPrivate, (void**)&viewExt);
+ if (FAILED(hr))
+ goto exit;
+
+ hr = viewExt->viewWindow((OLE_HANDLE*) &gViewWindow);
+ viewExt->Release();
+ if (FAILED(hr) || !gViewWindow)
+ goto exit;
+
+ resizeSubViews();
+
+ ShowWindow(gViewWindow, nCmdShow);
+ UpdateWindow(gViewWindow);
+
+ hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WINLAUNCHER));
+
+ // Main message loop:
+ while (GetMessage(&msg, NULL, 0, 0)) {
+ if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+
+exit:
+ gPrintDelegate->Release();
+ gWebView->Release();
+ shutDownWebKit();
+#ifdef _CRTDBG_MAP_ALLOC
+ _CrtDumpMemoryLeaks();
+#endif
+
+ // Shut down COM.
+ OleUninitialize();
+
+ return static_cast<int>(msg.wParam);
+}
+
+ATOM MyRegisterClass(HINSTANCE hInstance)
+{
+ WNDCLASSEX wcex;
+
+ wcex.cbSize = sizeof(WNDCLASSEX);
+
+ wcex.style = CS_HREDRAW | CS_VREDRAW;
+ wcex.lpfnWndProc = WndProc;
+ wcex.cbClsExtra = 0;
+ wcex.cbWndExtra = 0;
+ wcex.hInstance = hInstance;
+ wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WINLAUNCHER));
+ wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wcex.hbrBackground = 0;
+ wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WINLAUNCHER);
+ wcex.lpszClassName = szWindowClass;
+ wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
+
+ return RegisterClassEx(&wcex);
+}
+
+BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
+{
+ hInst = hInstance; // Store instance handle in our global variable
+
+ hMainWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
+ CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
+
+ if (!hMainWnd)
+ return FALSE;
+
+ ShowWindow(hMainWnd, nCmdShow);
+ UpdateWindow(hMainWnd);
+
+ return TRUE;
+}
+
+static BOOL CALLBACK AbortProc(HDC hDC, int Error)
+{
+ MSG msg;
+ while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
+ ::TranslateMessage(&msg);
+ ::DispatchMessage(&msg);
+ }
+
+ return TRUE;
+}
+
+static HDC getPrinterDC()
+{
+ PRINTDLG pdlg;
+ memset(&pdlg, 0, sizeof(PRINTDLG));
+ pdlg.lStructSize = sizeof(PRINTDLG);
+ pdlg.Flags = PD_PRINTSETUP | PD_RETURNDC;
+
+ ::PrintDlg(&pdlg);
+
+ return pdlg.hDC;
+}
+
+static void initDocStruct(DOCINFO* di, TCHAR* docname)
+{
+ memset(di, 0, sizeof(DOCINFO));
+ di->cbSize = sizeof(DOCINFO);
+ di->lpszDocName = docname;
+}
+
+void PrintView(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ HDC printDC = getPrinterDC();
+ if (!printDC) {
+ ::MessageBox(0, _T("Error creating printing DC"), _T("Error"), MB_APPLMODAL | MB_OK);
+ return;
+ }
+
+ if (::SetAbortProc(printDC, AbortProc) == SP_ERROR) {
+ ::MessageBox(0, _T("Error setting up AbortProc"), _T("Error"), MB_APPLMODAL | MB_OK);
+ return;
+ }
+
+ IWebFrame* frame = 0;
+ IWebFramePrivate* framePrivate = 0;
+ if (FAILED(gWebView->mainFrame(&frame)))
+ goto exit;
+
+ if (FAILED(frame->QueryInterface(&framePrivate)))
+ goto exit;
+
+ framePrivate->setInPrintingMode(TRUE, printDC);
+
+ UINT pageCount = 0;
+ framePrivate->getPrintedPageCount(printDC, &pageCount);
+
+ DOCINFO di;
+ initDocStruct(&di, _T("WebKit Doc"));
+ ::StartDoc(printDC, &di);
+
+ // FIXME: Need CoreGraphics implementation
+ void* graphicsContext = 0;
+ for (size_t page = 1; page <= pageCount; ++page) {
+ ::StartPage(printDC);
+ framePrivate->spoolPages(printDC, page, page, graphicsContext);
+ ::EndPage(printDC);
+ }
+
+ framePrivate->setInPrintingMode(FALSE, printDC);
+
+ ::EndDoc(printDC);
+ ::DeleteDC(printDC);
+
+exit:
+ if (frame)
+ frame->Release();
+ if (framePrivate)
+ framePrivate->Release();
+}
+
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ int wmId, wmEvent;
+
+ switch (message) {
+ case WM_COMMAND:
+ wmId = LOWORD(wParam);
+ wmEvent = HIWORD(wParam);
+ // Parse the menu selections:
+ switch (wmId) {
+ case IDM_ABOUT:
+ DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
+ break;
+ case IDM_EXIT:
+ DestroyWindow(hWnd);
+ break;
+ case IDM_PRINT:
+ PrintView(hWnd, message, wParam, lParam);
+ break;
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ break;
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ break;
+ case WM_SIZE:
+ if (!gWebView)
+ break;
+ resizeSubViews();
+ break;
+ default:
+ return DefWindowProc(hWnd, message, wParam, lParam);
+ }
+ return 0;
+}
+
+
+#define MAX_URL_LENGTH 1024
+
+LRESULT CALLBACK MyEditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_CHAR:
+ if (wParam == 13) { // Enter Key
+ wchar_t strPtr[MAX_URL_LENGTH];
+ *((LPWORD)strPtr) = MAX_URL_LENGTH;
+ int strLen = SendMessage(hDlg, EM_GETLINE, 0, (LPARAM)strPtr);
+
+ BSTR bstr = SysAllocStringLen(strPtr, strLen);
+ loadURL(bstr);
+ SysFreeString(bstr);
+
+ return 0;
+ } else
+ return (LRESULT)CallWindowProc((WNDPROC)DefEditProc,hDlg,message,wParam,lParam);
+ break;
+ default:
+ return (LRESULT)CallWindowProc((WNDPROC)DefEditProc,hDlg,message,wParam,lParam);
+ break;
+ }
+}
+
+
+// Message handler for about box.
+INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ UNREFERENCED_PARAMETER(lParam);
+ switch (message) {
+ case WM_INITDIALOG:
+ return (INT_PTR)TRUE;
+
+ case WM_COMMAND:
+ if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
+ EndDialog(hDlg, LOWORD(wParam));
+ return (INT_PTR)TRUE;
+ }
+ break;
+ }
+ return (INT_PTR)FALSE;
+}
+
+static void loadURL(BSTR urlBStr)
+{
+ IWebFrame* frame = 0;
+ IWebMutableURLRequest* request = 0;
+
+ static BSTR methodBStr = SysAllocString(TEXT("GET"));
+
+ if (urlBStr && urlBStr[0] && (PathFileExists(urlBStr) || PathIsUNC(urlBStr))) {
+ TCHAR fileURL[INTERNET_MAX_URL_LENGTH];
+ DWORD fileURLLength = sizeof(fileURL)/sizeof(fileURL[0]);
+
+ if (SUCCEEDED(UrlCreateFromPath(urlBStr, fileURL, &fileURLLength, 0)))
+ SysReAllocString(&urlBStr, fileURL);
+ }
+
+ HRESULT hr = gWebView->mainFrame(&frame);
+ if (FAILED(hr))
+ goto exit;
+
+ hr = WebKitCreateInstance(CLSID_WebMutableURLRequest, 0, IID_IWebMutableURLRequest, (void**)&request);
+ if (FAILED(hr))
+ goto exit;
+
+ hr = request->initWithURL(urlBStr, WebURLRequestUseProtocolCachePolicy, 60);
+ if (FAILED(hr))
+ goto exit;
+
+ hr = request->setHTTPMethod(methodBStr);
+ if (FAILED(hr))
+ goto exit;
+
+ hr = frame->loadRequest(request);
+ if (FAILED(hr))
+ goto exit;
+
+ SetFocus(gViewWindow);
+
+exit:
+ if (frame)
+ frame->Release();
+ if (request)
+ request->Release();
+}
diff --git a/Tools/WinLauncher/WinLauncher.h b/Tools/WinLauncher/WinLauncher.h
new file mode 100644
index 0000000..a82d7b1
--- /dev/null
+++ b/Tools/WinLauncher/WinLauncher.h
@@ -0,0 +1,119 @@
+/*
+ * 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 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.
+ */
+
+#pragma once
+
+#include "resource.h"
+#include <WebKit/WebKit.h>
+
+class WinLauncherWebHost : public IWebFrameLoadDelegate
+{
+public:
+ WinLauncherWebHost() : m_refCount(1) {}
+
+ // 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*/) { return S_OK; }
+
+ virtual HRESULT STDMETHODCALLTYPE didReceiveServerRedirectForProvisionalLoadForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame) { return S_OK; }
+
+ virtual HRESULT STDMETHODCALLTYPE didFailProvisionalLoadWithError(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebError *error,
+ /* [in] */ IWebFrame *frame) { return S_OK; }
+
+ virtual HRESULT STDMETHODCALLTYPE didCommitLoadForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame) { return updateAddressBar(webView); }
+
+ virtual HRESULT STDMETHODCALLTYPE didReceiveTitle(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BSTR title,
+ /* [in] */ IWebFrame *frame) { return S_OK; }
+
+ virtual HRESULT STDMETHODCALLTYPE didChangeIcons(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame) { return S_OK; }
+
+ virtual HRESULT STDMETHODCALLTYPE didReceiveIcon(
+ /* [in] */ IWebView *webView,
+ /* [in] */ OLE_HANDLE hBitmap,
+ /* [in] */ IWebFrame *frame) { return S_OK; }
+
+ virtual HRESULT STDMETHODCALLTYPE didFinishLoadForFrame(
+ /* [in] */ IWebView* webView,
+ /* [in] */ IWebFrame* /*frame*/) { return S_OK; }
+
+ virtual HRESULT STDMETHODCALLTYPE didFailLoadWithError(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebError *error,
+ /* [in] */ IWebFrame *forFrame) { return S_OK; }
+
+ virtual HRESULT STDMETHODCALLTYPE didChangeLocationWithinPageForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame) { return S_OK; }
+
+ virtual HRESULT STDMETHODCALLTYPE willPerformClientRedirectToURL(
+ /* [in] */ IWebView *webView,
+ /* [in] */ BSTR url,
+ /* [in] */ double delaySeconds,
+ /* [in] */ DATE fireDate,
+ /* [in] */ IWebFrame *frame) { return S_OK; }
+
+ virtual HRESULT STDMETHODCALLTYPE didCancelClientRedirectForFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame) { return S_OK; }
+
+ virtual HRESULT STDMETHODCALLTYPE willCloseFrame(
+ /* [in] */ IWebView *webView,
+ /* [in] */ IWebFrame *frame) { return S_OK; }
+
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE windowScriptObjectAvailable(
+ /* [in] */ IWebView *webView,
+ /* [in] */ JSContextRef context,
+ /* [in] */ JSObjectRef windowScriptObject) { return S_OK; }
+
+ virtual /* [local] */ HRESULT STDMETHODCALLTYPE didClearWindowObject(
+ /* [in] */ IWebView *webView,
+ /* [in] */ JSContextRef context,
+ /* [in] */ JSObjectRef windowScriptObject,
+ /* [in] */ IWebFrame *frame) { return S_OK; }
+
+ // WinLauncherWebHost
+
+protected:
+ HRESULT updateAddressBar(IWebView* webView);
+
+protected:
+ ULONG m_refCount;
+};
diff --git a/Tools/WinLauncher/WinLauncher.ico b/Tools/WinLauncher/WinLauncher.ico
new file mode 100644
index 0000000..d551aa3
--- /dev/null
+++ b/Tools/WinLauncher/WinLauncher.ico
Binary files differ
diff --git a/Tools/WinLauncher/WinLauncher.rc b/Tools/WinLauncher/WinLauncher.rc
new file mode 100644
index 0000000..172ed4a
--- /dev/null
+++ b/Tools/WinLauncher/WinLauncher.rc
@@ -0,0 +1,137 @@
+// Microsoft Visual C++ generated resource script.
+//
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+#define APSTUDIO_HIDDEN_SYMBOLS
+#include "windows.h"
+#undef APSTUDIO_HIDDEN_SYMBOLS
+
+/////////////////////////////////////////////////////////////////////////////
+#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
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_WINLAUNCHER ICON "WinLauncher.ico"
+IDI_SMALL ICON "small.ico"
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Menu
+//
+
+IDC_WINLAUNCHER MENU
+BEGIN
+ POPUP "&File"
+ BEGIN
+ MENUITEM "&Print\tCtrl-P", IDM_PRINT
+ MENUITEM "E&xit", IDM_EXIT
+ END
+ POPUP "&Help"
+ BEGIN
+ MENUITEM "&About ...", IDM_ABOUT
+ END
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Accelerator
+//
+
+IDC_WINLAUNCHER ACCELERATORS
+BEGIN
+ "?", IDM_ABOUT, ASCII, ALT
+ "/", IDM_ABOUT, ASCII, ALT
+END
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_ABOUTBOX DIALOGEX 22, 17, 230, 75
+STYLE DS_SETFONT | DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
+CAPTION "About"
+FONT 8, "System", 0, 0, 0x0
+BEGIN
+ ICON IDI_WINLAUNCHER,IDC_MYICON,14,9,20,20
+ LTEXT "WinLauncher Version 1.2",IDC_STATIC,49,10,119,8,SS_NOPREFIX
+ LTEXT "Copyright (C) 2009",IDC_STATIC,49,20,119,8
+ DEFPUSHBUTTON "OK",IDOK,195,6,30,11,WS_GROUP
+END
+
+
+#ifdef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// TEXTINCLUDE
+//
+
+1 TEXTINCLUDE
+BEGIN
+ "resource.h\0"
+END
+
+2 TEXTINCLUDE
+BEGIN
+ "#define APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "#include ""windows.h""\r\n"
+ "#undef APSTUDIO_HIDDEN_SYMBOLS\r\n"
+ "\0"
+END
+
+3 TEXTINCLUDE
+BEGIN
+ "\r\n"
+ "\0"
+END
+
+#endif // APSTUDIO_INVOKED
+
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// String Table
+//
+
+STRINGTABLE
+BEGIN
+ IDS_APP_TITLE "WinLauncher"
+ IDC_WINLAUNCHER "WINLAUNCHER"
+END
+
+#endif // English (U.S.) resources
+/////////////////////////////////////////////////////////////////////////////
+
+
+
+#ifndef APSTUDIO_INVOKED
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 3 resource.
+//
+
+
+/////////////////////////////////////////////////////////////////////////////
+#endif // not APSTUDIO_INVOKED
+
diff --git a/Tools/WinLauncher/WinLauncher.vcproj b/Tools/WinLauncher/WinLauncher.vcproj
new file mode 100644
index 0000000..2f23abe
--- /dev/null
+++ b/Tools/WinLauncher/WinLauncher.vcproj
@@ -0,0 +1,498 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="WinLauncher"
+ ProjectGUID="{114FCA11-216B-4C8C-957E-30A75AE80443}"
+ RootNamespace="WinLauncher"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\WinLauncherCommon.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\WinLauncherCommon.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;.\WinLauncherCommon.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\WinLauncherCommon.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_LTCG|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\WinLauncherCommon.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;.\WinLauncherCommon.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="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\PrintWebUIDelegate.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.cpp"
+ >
+ <FileConfiguration
+ Name="Debug|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_LTCG|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_Cairo_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ UsePrecompiledHeader="1"
+ />
+ </FileConfiguration>
+ </File>
+ <File
+ RelativePath=".\WinLauncher.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ <File
+ RelativePath=".\PrintWebUIDelegate.h"
+ >
+ </File>
+ <File
+ RelativePath=".\Resource.h"
+ >
+ </File>
+ <File
+ RelativePath=".\stdafx.h"
+ >
+ </File>
+ <File
+ RelativePath=".\WinLauncher.h"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ <File
+ RelativePath=".\small.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\WinLauncher.ico"
+ >
+ </File>
+ <File
+ RelativePath=".\WinLauncher.rc"
+ >
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/WinLauncher/WinLauncherCommon.vsprops b/Tools/WinLauncher/WinLauncherCommon.vsprops
new file mode 100644
index 0000000..70c1c6d
--- /dev/null
+++ b/Tools/WinLauncher/WinLauncherCommon.vsprops
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="WinLauncherCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="&quot;$(WebKitOutputDir)\include\WebKit&quot;;&quot;$(WebKitOutputDir)\Include&quot;;&quot;$(WebKitLibrariesDir)\Include&quot;;&quot;$(WebKitOutputDir)\Include\WebCore&quot;;&quot;$(WebKitLibrariesDir)\Include\WebCore&quot;;&quot;$(WebKitOutputDir)\Include\WebCore\ForwardingHeaders&quot;;&quot;$(WebKitLibrariesDir)\Include\WebCore\ForwardingHeaders&quot;;&quot;$(WebKitOutputDir)\Include\JavaScriptCore&quot;;&quot;$(WebKitLibrariesDir)\Include\JavaScriptCore&quot;;&quot;$(ProjectDir)\..&quot;;&quot;$(ProjectDir)&quot;;&quot;$(IntDir)\Include&quot;;&quot;$(WebKitOutputDir)\obj\WebKit\DerivedSources&quot;"
+ UsePrecompiledHeader="2"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="comdlg32.lib gdi32.lib comctl32.lib shlwapi.lib user32.lib ole32.lib oleaut32.lib WebKitGUID$(WebKitConfigSuffix).lib WebKit$(WebKitDLLConfigSuffix).lib"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/WinLauncher/WinLauncherPostBuild.cmd b/Tools/WinLauncher/WinLauncherPostBuild.cmd
new file mode 100644
index 0000000..f011495
--- /dev/null
+++ b/Tools/WinLauncher/WinLauncherPostBuild.cmd
@@ -0,0 +1 @@
+if exist "%WEBKITOUTPUTDIR%\buildfailed" del "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/WinLauncher/WinLauncherPreBuild.cmd b/Tools/WinLauncher/WinLauncherPreBuild.cmd
new file mode 100644
index 0000000..3a84c26
--- /dev/null
+++ b/Tools/WinLauncher/WinLauncherPreBuild.cmd
@@ -0,0 +1,6 @@
+%SystemDrive%\cygwin\bin\which.exe bash
+if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
+cmd /c
+if exist "%WEBKITOUTPUTDIR%\buildfailed" grep XX%PROJECTNAME%XX "%WEBKITOUTPUTDIR%\buildfailed"
+if errorlevel 1 exit 1
+echo XX%PROJECTNAME%XX > "%WEBKITOUTPUTDIR%\buildfailed"
diff --git a/Tools/WinLauncher/resource.h b/Tools/WinLauncher/resource.h
new file mode 100644
index 0000000..c98fac7
--- /dev/null
+++ b/Tools/WinLauncher/resource.h
@@ -0,0 +1,28 @@
+//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by WinLauncher.rc
+//
+#define IDC_MYICON 2
+#define IDD_WINLAUNCHER_DIALOG 102
+#define IDS_APP_TITLE 103
+#define IDD_ABOUTBOX 103
+#define IDM_ABOUT 104
+#define IDM_EXIT 105
+#define IDM_PRINT 106
+#define IDI_WINLAUNCHER 107
+#define IDI_SMALL 108
+#define IDC_WINLAUNCHER 109
+#define IDR_MAINFRAME 128
+#define IDC_STATIC -1
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NO_MFC 1
+#define _APS_NEXT_RESOURCE_VALUE 129
+#define _APS_NEXT_COMMAND_VALUE 32771
+#define _APS_NEXT_CONTROL_VALUE 1000
+#define _APS_NEXT_SYMED_VALUE 110
+#endif
+#endif
diff --git a/Tools/WinLauncher/small.ico b/Tools/WinLauncher/small.ico
new file mode 100644
index 0000000..d551aa3
--- /dev/null
+++ b/Tools/WinLauncher/small.ico
Binary files differ
diff --git a/Tools/WinLauncher/stdafx.cpp b/Tools/WinLauncher/stdafx.cpp
new file mode 100644
index 0000000..541dcb1
--- /dev/null
+++ b/Tools/WinLauncher/stdafx.cpp
@@ -0,0 +1,33 @@
+/*
+ * 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 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.
+ */
+
+// stdafx.cpp : source file that includes just the standard includes
+// Spinneret.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/Tools/WinLauncher/stdafx.h b/Tools/WinLauncher/stdafx.h
new file mode 100644
index 0000000..86f76cc
--- /dev/null
+++ b/Tools/WinLauncher/stdafx.h
@@ -0,0 +1,69 @@
+/*
+ * 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 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.
+ */
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef WINVER // Allow use of features specific to Windows XP or later.
+#define WINVER 0x0501 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
+#ifndef _WIN32_WINNT // Allow use of features specific to Windows XP or later.
+#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
+#ifndef _WIN32_WINDOWS // Allow use of features specific to Windows 98 or later.
+#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
+#endif
+
+#ifndef _WIN32_IE // Allow use of features specific to IE 6.0 or later.
+#define _WIN32_IE 0x0600 // Change this to the appropriate value to target other versions of IE.
+#endif
+
+#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+// Windows Header Files:
+#include <windows.h>
+
+// C RunTime Header Files
+#include <stdlib.h>
+#include <malloc.h>
+#include <memory.h>
+#include <tchar.h>
+
+#if 0
+// Visual Studio Leak Detection
+// <http://msdn2.microsoft.com/en-US/library/e5ewb1h3.aspx>
+#if defined(_MSC_VER) && defined(_DEBUG)
+#define _CRTDBG_MAP_ALLOC
+#include <stdlib.h>
+#include <crtdbg.h>
+#endif
+#endif
diff --git a/Tools/android/flex-2.5.4a/COPYING b/Tools/android/flex-2.5.4a/COPYING
new file mode 100644
index 0000000..c041f02
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/COPYING
@@ -0,0 +1,38 @@
+Flex carries the copyright used for BSD software, slightly modified
+because it originated at the Lawrence Berkeley (not Livermore!) Laboratory,
+which operates under a contract with the Department of Energy:
+
+ Copyright (c) 1990 The Regents of the University of California.
+ All rights reserved.
+
+ This code is derived from software contributed to Berkeley by
+ Vern Paxson.
+
+ The United States Government has rights in this work pursuant
+ to contract no. DE-AC03-76SF00098 between the United States
+ Department of Energy and the University of California.
+
+ Redistribution and use in source and binary forms with or without
+ modification are permitted provided that: (1) source distributions
+ retain this entire copyright notice and comment, and (2)
+ distributions including binaries display the following
+ acknowledgement: ``This product includes software developed by the
+ University of California, Berkeley and its contributors'' in the
+ documentation or other materials provided with the distribution and
+ in all advertising materials mentioning features or use of this
+ software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE.
+
+This basically says "do whatever you please with this software except
+remove this notice or take advantage of the University's (or the flex
+authors') name".
+
+Note that the "flex.skl" scanner skeleton carries no copyright notice.
+You are free to do whatever you please with scanners generated using flex;
+for them, you are not even bound by the above copyright.
diff --git a/Tools/android/flex-2.5.4a/FlexLexer.h b/Tools/android/flex-2.5.4a/FlexLexer.h
new file mode 100644
index 0000000..9605588
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/FlexLexer.h
@@ -0,0 +1,186 @@
+// $Header: /home/daffy/u0/vern/flex/RCS/FlexLexer.h,v 1.19 96/05/25 20:43:02 vern Exp $
+
+// FlexLexer.h -- define interfaces for lexical analyzer classes generated
+// by flex
+
+// Copyright (c) 1993 The Regents of the University of California.
+// All rights reserved.
+//
+// This code is derived from software contributed to Berkeley by
+// Kent Williams and Tom Epperly.
+//
+// Redistribution and use in source and binary forms with or without
+// modification are permitted provided that: (1) source distributions retain
+// this entire copyright notice and comment, and (2) distributions including
+// binaries display the following acknowledgement: ``This product includes
+// software developed by the University of California, Berkeley and its
+// contributors'' in the documentation or other materials provided with the
+// distribution and in all advertising materials mentioning features or use
+// of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+// This file defines FlexLexer, an abstract class which specifies the
+// external interface provided to flex C++ lexer objects, and yyFlexLexer,
+// which defines a particular lexer class.
+//
+// If you want to create multiple lexer classes, you use the -P flag
+// to rename each yyFlexLexer to some other xxFlexLexer. You then
+// include <FlexLexer.h> in your other sources once per lexer class:
+//
+// #undef yyFlexLexer
+// #define yyFlexLexer xxFlexLexer
+// #include <FlexLexer.h>
+//
+// #undef yyFlexLexer
+// #define yyFlexLexer zzFlexLexer
+// #include <FlexLexer.h>
+// ...
+
+#ifndef __FLEX_LEXER_H
+// Never included before - need to define base class.
+#define __FLEX_LEXER_H
+#include <iostream.h>
+
+extern "C++" {
+
+struct yy_buffer_state;
+typedef int yy_state_type;
+
+class FlexLexer {
+public:
+ virtual ~FlexLexer() { }
+
+ const char* YYText() { return yytext; }
+ int YYLeng() { return yyleng; }
+
+ virtual void
+ yy_switch_to_buffer( struct yy_buffer_state* new_buffer ) = 0;
+ virtual struct yy_buffer_state*
+ yy_create_buffer( istream* s, int size ) = 0;
+ virtual void yy_delete_buffer( struct yy_buffer_state* b ) = 0;
+ virtual void yyrestart( istream* s ) = 0;
+
+ virtual int yylex() = 0;
+
+ // Call yylex with new input/output sources.
+ int yylex( istream* new_in, ostream* new_out = 0 )
+ {
+ switch_streams( new_in, new_out );
+ return yylex();
+ }
+
+ // Switch to new input/output streams. A nil stream pointer
+ // indicates "keep the current one".
+ virtual void switch_streams( istream* new_in = 0,
+ ostream* new_out = 0 ) = 0;
+
+ int lineno() const { return yylineno; }
+
+ int debug() const { return yy_flex_debug; }
+ void set_debug( int flag ) { yy_flex_debug = flag; }
+
+protected:
+ char* yytext;
+ int yyleng;
+ int yylineno; // only maintained if you use %option yylineno
+ int yy_flex_debug; // only has effect with -d or "%option debug"
+};
+
+}
+#endif
+
+#if defined(yyFlexLexer) || ! defined(yyFlexLexerOnce)
+// Either this is the first time through (yyFlexLexerOnce not defined),
+// or this is a repeated include to define a different flavor of
+// yyFlexLexer, as discussed in the flex man page.
+#define yyFlexLexerOnce
+
+class yyFlexLexer : public FlexLexer {
+public:
+ // arg_yyin and arg_yyout default to the cin and cout, but we
+ // only make that assignment when initializing in yylex().
+ yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 );
+
+ virtual ~yyFlexLexer();
+
+ void yy_switch_to_buffer( struct yy_buffer_state* new_buffer );
+ struct yy_buffer_state* yy_create_buffer( istream* s, int size );
+ void yy_delete_buffer( struct yy_buffer_state* b );
+ void yyrestart( istream* s );
+
+ virtual int yylex();
+ virtual void switch_streams( istream* new_in, ostream* new_out );
+
+protected:
+ virtual int LexerInput( char* buf, int max_size );
+ virtual void LexerOutput( const char* buf, int size );
+ virtual void LexerError( const char* msg );
+
+ void yyunput( int c, char* buf_ptr );
+ int yyinput();
+
+ void yy_load_buffer_state();
+ void yy_init_buffer( struct yy_buffer_state* b, istream* s );
+ void yy_flush_buffer( struct yy_buffer_state* b );
+
+ int yy_start_stack_ptr;
+ int yy_start_stack_depth;
+ int* yy_start_stack;
+
+ void yy_push_state( int new_state );
+ void yy_pop_state();
+ int yy_top_state();
+
+ yy_state_type yy_get_previous_state();
+ yy_state_type yy_try_NUL_trans( yy_state_type current_state );
+ int yy_get_next_buffer();
+
+ istream* yyin; // input source for default LexerInput
+ ostream* yyout; // output sink for default LexerOutput
+
+ struct yy_buffer_state* yy_current_buffer;
+
+ // yy_hold_char holds the character lost when yytext is formed.
+ char yy_hold_char;
+
+ // Number of characters read into yy_ch_buf.
+ int yy_n_chars;
+
+ // Points to current character in buffer.
+ char* yy_c_buf_p;
+
+ int yy_init; // whether we need to initialize
+ int yy_start; // start state number
+
+ // Flag which is used to allow yywrap()'s to do buffer switches
+ // instead of setting up a fresh yyin. A bit of a hack ...
+ int yy_did_buffer_switch_on_eof;
+
+ // The following are not always needed, but may be depending
+ // on use of certain flex features (like REJECT or yymore()).
+
+ yy_state_type yy_last_accepting_state;
+ char* yy_last_accepting_cpos;
+
+ yy_state_type* yy_state_buf;
+ yy_state_type* yy_state_ptr;
+
+ char* yy_full_match;
+ int* yy_full_state;
+ int yy_full_lp;
+
+ int yy_lp;
+ int yy_looking_for_trail_begin;
+
+ int yy_more_flag;
+ int yy_more_len;
+ int yy_more_offset;
+ int yy_prev_more_offset;
+};
+
+#endif
diff --git a/Tools/android/flex-2.5.4a/INSTALL b/Tools/android/flex-2.5.4a/INSTALL
new file mode 100644
index 0000000..6e7ed85
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/INSTALL
@@ -0,0 +1,117 @@
+This is a generic INSTALL file for utilities distributions.
+If this package does not come with, e.g., installable documentation or
+data files, please ignore the references to them below.
+
+To compile this package:
+
+1. Configure the package for your system. In the directory that this
+file is in, type `./configure'. If you're using `csh' on an old
+version of System V, you might need to type `sh configure' instead to
+prevent `csh' from trying to execute `configure' itself.
+
+The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation, and
+creates the Makefile(s) (one in each subdirectory of the source
+directory). In some packages it creates a C header file containing
+system-dependent definitions. It also creates a file `config.status'
+that you can run in the future to recreate the current configuration.
+
+Running `configure' takes a minute or two. While it is running, it
+prints some messages that tell what it is doing. If you don't want to
+see the messages, run `configure' with its standard output redirected
+to `/dev/null'; for example, `./configure >/dev/null'.
+
+To compile the package in a different directory from the one
+containing the source code, you must use a version of `make' that
+supports the VPATH variable, such as GNU `make'. `cd' to the directory
+where you want the object files and executables to go and run
+`configure'. `configure' automatically checks for the source code in
+the directory that `configure' is in and in `..'. If for some reason
+`configure' is not in the source code directory that you are
+configuring, then it will report that it can't find the source code.
+In that case, run `configure' with the option `--srcdir=DIR', where
+DIR is the directory that contains the source code.
+
+By default, `make install' will install the package's files in
+/usr/local/bin, /usr/local/lib, /usr/local/man, etc. You can specify
+an installation prefix other than /usr/local by giving `configure' the
+option `--prefix=PATH'. Alternately, you can do so by giving a value
+for the `prefix' variable when you run `make', e.g.,
+ make prefix=/usr/gnu
+
+You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files. If
+you give `configure' the option `--exec-prefix=PATH' or set the
+`make' variable `exec_prefix' to PATH, the package will use PATH as
+the prefix for installing programs and libraries. Data files and
+documentation will still use the regular prefix. Normally, all files
+are installed using the regular prefix.
+
+Another `configure' option is useful mainly in `Makefile' rules for
+updating `config.status' and `Makefile'. The `--no-create' option
+figures out the configuration for your system and records it in
+`config.status', without actually configuring the package (creating
+`Makefile's and perhaps a configuration header file). Later, you can
+run `./config.status' to actually configure the package. You can also
+give `config.status' the `--recheck' option, which makes it re-run
+`configure' with the same arguments you used before. This option is
+useful if you change `configure'.
+
+Some packages pay attention to `--with-PACKAGE' options to `configure',
+where PACKAGE is something like `gnu-libc' or `x' (for X windows).
+The README should mention any --with- options that the package recognizes.
+
+`configure' ignores any other arguments that you give it.
+
+If your system requires unusual options for compilation or linking
+that `configure' doesn't know about, you can give `configure' initial
+values for some variables by setting them in the environment. In
+Bourne-compatible shells, you can do that on the command line like
+this:
+ CC='gcc -traditional' DEFS=-D_POSIX_SOURCE ./configure
+
+The `make' variables that you might want to override with environment
+variables when running `configure' are:
+
+(For these variables, any value given in the environment overrides the
+value that `configure' would choose:)
+CC C compiler program.
+ Default is `cc', or `gcc' if `gcc' is in your PATH.
+INSTALL Program to use to install files.
+ Default is `install' if you have it, `cp' otherwise.
+
+(For these variables, any value given in the environment is added to
+the value that `configure' chooses:)
+DEFS Configuration options, in the form `-Dfoo -Dbar ...'
+ Do not use this variable in packages that create a
+ configuration header file.
+LIBS Libraries to link with, in the form `-lfoo -lbar ...'
+
+If you need to do unusual things to compile the package, we encourage
+you to figure out how `configure' could check whether to do them, and
+mail diffs or instructions to the address given in the README so we
+can include them in the next release.
+
+2. Type `make' to compile the package. If you want, you can override
+the `make' variables CFLAGS and LDFLAGS like this:
+
+ make CFLAGS=-O2 LDFLAGS=-s
+
+3. If the package comes with self-tests and you want to run them,
+type `make check'. If you're not sure whether there are any, try it;
+if `make' responds with something like
+ make: *** No way to make target `check'. Stop.
+then the package does not come with self-tests.
+
+4. Type `make install' to install programs, data files, and
+documentation.
+
+5. You can remove the program binaries and object files from the
+source directory by typing `make clean'. To also remove the
+Makefile(s), the header file containing system-dependent definitions
+(if the package uses one), and `config.status' (all the files that
+`configure' created), type `make distclean'.
+
+The file `configure.in' is used as a template to create `configure' by
+a program called `autoconf'. You will only need it if you want to
+regenerate `configure' using a newer version of `autoconf'.
diff --git a/Tools/android/flex-2.5.4a/MISC/Amiga/README.amiga b/Tools/android/flex-2.5.4a/MISC/Amiga/README.amiga
new file mode 100644
index 0000000..0efdb93
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Amiga/README.amiga
@@ -0,0 +1,72 @@
+
+This file, ./MISC/Amiga/README.amiga, describes the necessary steps to get
+the FLEX 2.5.1 program up and running on the Commodore AMIGA with the
+help of SAS/C++ 6.51 and SMake 6.50. Also it describes the contents of the
+subdirectory ./MISC/Amiga, where `.' denotes the root directory of the
+standard installation of FLEX 2.5.1.
+
+
+FILES ADDED FOR INSTALLING FLEX 2.5.1 ON THE AMIGA
+
+The standard distribution of FLEX 2.5.1 is assumed to be installed on
+your AMIGA computer. `Installed' means that all source files from the
+original archive are present in a root directory (denoted by `.' in what
+follows) and, if appropriate, one or more subdirectories, on your machine.
+
+The original source files are totally left untouched, the necessary changes
+are applied in the form of `change files'. For installing FLEX 2.5.1 on
+the AMIGA, several additional files come with this patch.
+
+ -----rw-d 2 738 Apr 3 11:49 config.h
+ -----rw-d 1 169 Apr 3 11:33 libmain.ch
+ -----rw-d 1 159 Apr 3 11:33 libyywrap.ch
+ -----rw-d 1 167 Apr 3 11:33 parse.ych
+ -----rw-d 6 2840 Apr 3 11:34 README.amiga
+ -----rw-d 11 5503 Apr 3 11:45 smakefile
+ Dirs:0 Files:6 Blocks:22 Bytes:9576
+
+
+HOW TO INSTALL FLEX 2.5.1 ON THE AMIGA
+
+Copy all files from ./MISC/Amiga to the root directory of the FLEX 2.5.1
+distribution and edit `SMakefile' as it instructs you. There shouldn't be
+too many changes necessary. Then say "make bootflex". This creates a
+preliminary version of FLEX 2.5.1 without using itself.
+
+WARNING: Don't say "make flex" yet. Any pre-2.5 version of FLEX will fail
+on the file `scan.l' due to some new features only present in FLEX 2.5.
+
+Then say "make flex". At least once the FLEX program created in the first
+step will be used. To make sure that everything is alright, finally say
+"make check". If you change the code, you should also say "make bigcheck"
+for some more thorough testing.
+
+When you are satisfied with the results, say "make install". This will
+copy the `flex' binary, the `libfl.lib' file, and the `FlexLexer.h' header
+to the paths specified in the `SMakefile'.
+
+Finally, you should say "make clean" to remove all intermediate files from
+the root directory. "make veryclean" also removes `flex' and `scan.c'.
+
+
+TROUBLE SHOOTING
+
+FLEX 2.5.1 was ported to the AMIGA and tested with the following setup:
+
+ AMIGA 2000
+ GVP G-Force 030/50/50/8
+ SAS/C++ 6.51
+ SED 2.05
+ BISON 1.22
+ WMERGE from the CWEB distribution
+
+Should you encounter problems with this AMIGA patch for FLEX 2.5.1 or
+should you have ideas for further improvements, like using GnuMake instead
+of SMake, contact the author of this contribution
+
+Andreas Scherer
+Roland-Stra{\ss}e 16
+52070 Aachen
+Germany
+
+<scherer@genesis.informatik.rwth-aachen.de> (Internet)
diff --git a/Tools/android/flex-2.5.4a/MISC/Amiga/SMakefile b/Tools/android/flex-2.5.4a/MISC/Amiga/SMakefile
new file mode 100644
index 0000000..28e0dd4
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Amiga/SMakefile
@@ -0,0 +1,195 @@
+# @(#) $Header: Makefile.in,v 1.2 94/01/04 14:33:19 vern Exp $ (LBL)
+
+# If your version of "make" does not define $(MAKE), comment in the
+# definition of "MAKE" below. (You only need to do this if you intend
+# to do "make bigcheck" or "make dist".)
+MAKE = smake
+
+# Possible values for DEFS:
+#
+# For flex to always generate 8-bit scanners, add "-DDEFAULT_CSIZE=256"
+# to DEFS.
+#
+# For Vax/VMS, add "-DVMS" to DEFS.
+#
+# For MS-DOS, add "-DMS_DOS" to DEFS. See the directory MISC/MSDOS for
+# additional info.
+
+CFLAGS = data=far ignore=85 noicons stackextend optimize
+DEFS = define=YYBISON=1 define=YY_NEVER_INTERACTIVE=1
+LDFLAGS = noicons
+LIBS =
+
+# Installation targeting. Files will be installed under the tree
+# rooted at prefix. flex will be installed in bindir, libfl.lib in
+# libdir, FlexLexer.h will be installed in includedir, and the manual
+# pages will be installed in mandir with extension manext.
+#
+# Raw, unformatted troff source will be installed if INSTALLMAN=man,
+# nroff preformatted versions will be installed if INSTALLMAN=cat.
+
+prefix = Programmer:other # Change this for your AMIGA system.
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+libdir = $(exec_prefix)/lib
+includedir = $(prefix)/include
+manext = 1
+mandir = $(prefix)/man/man$(manext)
+
+# You can define this to be "lex" if you want to replace lex at your site.
+FLEX = flex
+
+INSTALLMAN = man
+
+SHELL =
+srcdir = .
+VPATH =
+
+LN_S =
+YACC = bison -y
+SED = sed
+CC = sc
+WMERGE = wmerge # from the CWEB distribution
+AR = oml
+RANLIB =
+INSTALL = copy clone
+INSTALL_DATA = $(INSTALL)
+INSTALL_PROGRAM = $(INSTALL)
+
+# You normally do not need to modify anything below this point.
+# ------------------------------------------------------------
+
+CPPFLAGS = idir=. idir=$(srcdir) $(DEFS)
+
+.c.o:
+ $(CC) $(CPPFLAGS) $(CFLAGS) $<
+
+HEADERS = flexdef.h version.h
+
+SOURCES = ccl.c dfa.c ecs.c gen.c main.c misc.c nfa.c parse.y \
+ scan.l skel.c sym.c tblcmp.c yylex.c
+OBJECTS = ccl.o dfa.o ecs.o gen.o main.o misc.o nfa.o parse.o \
+ skel.o sym.o tblcmp.o yylex.o \
+ $(libdir)/alloca.o $(libdir)/xmalloc.o
+
+LIBSRCS = libmain.c libyywrap.c
+LIBOBJS = ansilibmain.o ansilibyywrap.o
+
+LINTSRCS = ccl.c dfa.c ecs.c gen.c main.c misc.c nfa.c parse.c \
+ scan.c skel.c sym.c tblcmp.c yylex.c
+
+DISTFILES = README NEWS COPYING INSTALL FlexLexer.h \
+ configure.in conf.in Makefile.in mkskel.sh skel.c flex.skl \
+ $(HEADERS) $(SOURCES) $(LIBSRCS) MISC \
+ flex.1 scan.c install.sh mkinstalldirs configure
+
+DIST_NAME = flex
+
+# which "flex" to use to generate scan.c from scan.l
+FLEX_EXEC = ./$(FLEX)
+FLEX_FLAGS = -t $(PERF_REPORT)
+COMPRESSION =
+PERF_REPORT = -p
+
+FLEXLIB = libfl.lib
+
+all: $(FLEX)
+
+$(FLEX): $(OBJECTS) $(FLEXLIB) scan.o
+ $(CC) $(CFLAGS) link to $(FLEX) $(LDFLAGS) $(OBJECTS) scan.o $(FLEXLIB) $(LIBS)
+
+bootflex: $(OBJECTS) $(FLEXLIB) initscan.o
+ $(CC) $(CFLAGS) link to $(FLEX) $(LDFLAGS) $(OBJECTS) initscan.o $(FLEXLIB) $(LIBS)
+
+parse.c: ansiparse.y
+ $(YACC) -d ansiparse.y
+ $(SED) "/extern char.*malloc/d" <y.tab.c >parse.tmp
+ copy parse.tmp parse.c
+ copy y.tab.h parse.h
+ @delete y.tab.c y.tab.h parse.tmp
+ansiparse.y: $(srcdir)/parse.y parse.ych
+ $(WMERGE) $(srcdir)/parse.y parse.ych ansiparse.y
+
+parse.h: parse.c
+
+scan.c: scan.l
+ $(FLEX_EXEC) $(FLEX_FLAGS) $(COMPRESSION) $(srcdir)/scan.l >scan.tmp
+ $(SED) s,\"$(srcdir)/scan.l\",\"scan.l\", <scan.tmp >scan.c
+ @delete scan.tmp
+
+scan.o: scan.c parse.h flexdef.h config.h
+initscan.o: initscan.c parse.h flexdef.h config.h
+yylex.o: yylex.c parse.h flexdef.h config.h
+
+skel.c: flex.skl mkskel.sh
+ $(SHELL) $(srcdir)/mkskel.sh $(srcdir)/flex.skl >skel.c
+
+main.o: main.c flexdef.h config.h version.h
+ccl.o: ccl.c flexdef.h config.h
+dfa.o: dfa.c flexdef.h config.h
+ecs.o: ecs.c flexdef.h config.h
+gen.o: gen.c flexdef.h config.h
+misc.o: misc.c flexdef.h config.h
+nfa.o: nfa.c flexdef.h config.h
+parse.o: parse.c flexdef.h config.h
+skel.o: skel.c flexdef.h config.h
+sym.o: sym.c flexdef.h config.h
+tblcmp.o: tblcmp.c flexdef.h config.h
+
+alloca.o: alloca.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) define=xmalloc=yy_flex_xmalloc alloca.c
+
+alloca.c: $(srcdir)/MISC/alloca.c
+ @delete alloca.c
+ copy $(srcdir)/MISC/alloca.c .
+
+test: check
+check: flex
+ $(FLEX_EXEC) $(FLEX_FLAGS) $(COMPRESSION) $(srcdir)/scan.l > temp_a
+ $(SED) s,"$(srcdir)/scan.l","scan.l", < temp_a > temp_b
+ -diff scan.c temp_b -l10000 -w
+ @delete temp_?
+ @echo "Check successful, using COMPRESSION='$(COMPRESSION)'"
+
+bigcheck:
+ delete scan.c
+ $(MAKE) COMPRESSION=-C check
+ delete scan.c
+ $(MAKE) COMPRESSION=-Ce check
+ delete scan.c
+ $(MAKE) COMPRESSION=-Cm check
+ delete scan.c
+ $(MAKE) COMPRESSION=-Cfea check
+ delete scan.c
+ $(MAKE) COMPRESSION=-CFer check
+ delete scan.c
+ $(MAKE) COMPRESSION=-l PERF_REPORT= check
+ delete scan.c
+ $(MAKE)
+ @echo "All checks successful"
+
+$(FLEXLIB): $(LIBOBJS)
+ $(AR) $(FLEXLIB) R $(LIBOBJS)
+
+$(FLEX).man: flex.1 # SMAKE can't `cd', sorry. And, I don't have nroff.
+# cd $(srcdir), nroff -man flex.1 >$(FLEX).man
+
+install: $(FLEX) $(FLEXLIB)
+ $(INSTALL_PROGRAM) $(FLEX) $(bindir)/$(FLEX)
+# @delete $(bindir)/$(FLEX)++
+ $(INSTALL_DATA) $(FLEXLIB) $(libdir)/libfl.lib
+ $(INSTALL_DATA) $(srcdir)/FlexLexer.h $(includedir)/FlexLexer.h
+
+ansilibmain.o: ansilibmain.c
+ansilibmain.c: libmain.c libmain.ch
+ $(WMERGE) libmain.c libmain.ch ansilibmain.c
+ansilibyywrap.o: ansilibyywrap.c
+ansilibyywrap.c: libyywrap.c libyywrap.ch
+ $(WMERGE) libyywrap.c libyywrap.ch ansilibyywrap.c
+
+clean:
+ -delete parse.(c|h) ansi\#? \#?.(bak|o|lnk) \
+ alloca.c lex.yy.(c|cc) $(FLEXLIB)
+
+veryclean: clean
+ -delete $(FLEX) scan.c
diff --git a/Tools/android/flex-2.5.4a/MISC/Amiga/config.h b/Tools/android/flex-2.5.4a/MISC/Amiga/config.h
new file mode 100644
index 0000000..1c02a3c
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Amiga/config.h
@@ -0,0 +1,25 @@
+/* $Header: /home/daffy/u0/vern/flex/RCS/conf.in,v 1.2 95/01/09 12:11:51 vern Exp $ */
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#undef HAVE_ALLOCA_H
+
+/* Define if platform-specific command line handling is necessary. */
+#undef NEED_ARGV_FIXUP
diff --git a/Tools/android/flex-2.5.4a/MISC/Amiga/libmain.ch b/Tools/android/flex-2.5.4a/MISC/Amiga/libmain.ch
new file mode 100644
index 0000000..e0f5b40
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Amiga/libmain.ch
@@ -0,0 +1,8 @@
+Changes for LIBMAIN.C 2.4.7 by Andreas Scherer, January 19, 1995.
+Modified for LIBMAIN.C 2.5.1, April 3, 1995.
+
+@x l.5
+extern int yylex();
+@y
+extern int yylex(void);
+@z
diff --git a/Tools/android/flex-2.5.4a/MISC/Amiga/libyywrap.ch b/Tools/android/flex-2.5.4a/MISC/Amiga/libyywrap.ch
new file mode 100644
index 0000000..b2d6a3f
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Amiga/libyywrap.ch
@@ -0,0 +1,8 @@
+Changes for LIBYYWRAP.C 2.4.7 by Andreas Scherer, January 19, 1995.
+Modified for LIBYYWRAP.C 2.5.1, April 3, 1995.
+
+@x l.5
+int yywrap()
+@y
+int yywrap(void)
+@z
diff --git a/Tools/android/flex-2.5.4a/MISC/Amiga/parse.ych b/Tools/android/flex-2.5.4a/MISC/Amiga/parse.ych
new file mode 100644
index 0000000..5671a5b
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Amiga/parse.ych
@@ -0,0 +1,8 @@
+Changes for PARSE.Y 2.4.7 by Andreas Scherer, January 20, 1995.
+Modified for PARSE.Y 2.5.1, April 3, 1995.
+
+@x l.60
+char *alloca ();
+@y
+char *alloca(unsigned int);
+@z
diff --git a/Tools/android/flex-2.5.4a/MISC/Atari/Atari.patches b/Tools/android/flex-2.5.4a/MISC/Atari/Atari.patches
new file mode 100644
index 0000000..dc04263
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Atari/Atari.patches
@@ -0,0 +1,911 @@
+(Message inbox:32)
+Date: Mon, 03 Jul 89 21:15:32 CET
+From: V61%DHDURZ1.BITNET@lbl.gov
+Subject: Flex, bug fix, improvments, patches for Minix & TOS
+To: vern@lbl-csam.arpa
+
+At first I have to thank you for your wonderful program. I had ported the
+old version to OS9,TOS (Atari ST) and Minix and the new version 2.1 Beta
+to Minix and TOS.
+
+While porting and using flex I detected a bug and made some improvements.
+I have included a shared, compressed and uuencoded file contaning all cdiffs
+and additional files (Sorry, but I'm on EBCDIC-Bitnet) and a short discussion
+of the changes. Even some of the TOS specific changes might be of general
+interest !
+
+I posted these cdiffs to the minix discussion group, but I think it's up
+to you to post them to the unix-sources group. If you plan to post even
+the TOS compiler specific patches please contact me because there might be
+further compiler (P.D.) additions. If you have an interest I could also
+port the new version to OS9 -- this is a little bit more difficult, because
+OS9 uses CR as end of line character (the EOL char. is coded into the
+initscan.c tables,...). It is necessary to change all occurences of '\n' to
+macros and variables and it's useful to add a new -n options (see commented
+line in main.c)
+
+
+
+The changes: (1.7.89 RAL)
+
+ - Bug fix: The original flex didn't like trailing spaces in exclusive start
+ condition lists ! If you add an trailing space to line 68 in scan.l
+
+ "%x SECT2 SECT2PROLOG SECT3 CODEBLOCK PICKUPDEF SC CARETISBOL NUM QUOTE "
+
+ you get a misleading error message:
+
+ "Syntax error at line 69: bad start condition list"
+
+ This bug can either be fixed in parse.y or in scan.l . I have chosen the
+ last because there the fix is minimal: Just change the rule (line 128)
+
+ "\n" to "{OPTWS}\n"
+
+ - Enhancements:
+ - new option "-?" that provides some help information about the other
+ flags (main.c)
+ - new option "-aTMPPATH" that allows a redefinition of the standard
+ path for the temporary file (this might be rather large >200k if
+ F,f options are selected). (main.c, flexdef.h (l.376))
+ - hexdump of illegal characters -- this proved to be a useful debugging
+ tool especialy if invisible control characters occur which weren't
+ covered by the rules. (scan.l fprintf statement line 129,...)
+
+ - Patches due to TOS
+ - General: TOS uses CR,LF as end of line char., Flex wants only a single
+ LF as EOL char. Therefore all I/O must be translated using f* calls.
+ This is done everywhere besides the YY_INPUT macro (flex.skel (scan.c),
+ line 31) that uses a low level 'read'. This should be definitly changed
+ to fread, so that all I/O calls occur on the same level.
+ - the short action_file_name has been "flexXXXXXX.tmp", but that's too
+ much for TOS,MSDOS ! I changed it to "flexXXXX.tmp" in main.c (patch
+ covered by the -a option additions)
+ - some compilers don't like external names that are ambiguous within
+ the first 8 characters. I defined macros that change all these long
+ external names to names that are unique within the first 8 characters.
+ Just define SHORT_EXTERNAL_NAMES to use this feature (flexdef.h)
+ - some statement changes that some compiler don't like:
+ typedef *xxx[] -> typedef **xxx (flexdef.h.,l.308)
+ "/*" -> '/','*' within a comment in (scan.l, l.209)
+ - changed short "lexyy.c" to "lex_yy.c" what's more similar to the unix
+ "lex.yy.c" (main.c).
+ - a few further really compiler dependent changes provided with
+ #ifdef ATARI && LATTICE res. TURBO braces.
+
+ - Additional TOS only files
+ - Makefile.tos: Common makefile for all TOS compilers. If you add further
+ ones please email me the new makefile.
+ - flex.lnk: Lattice - GST linker argument extension file
+ - flex.tlk: Turbo linker argument extension file
+
+
+Additional remarks:
+
+I didn't add a new initscan.c (= flex -ist scan.l). The current one is good
+enough for a first compilation. With this first version of flex you can
+rebuild your own scan.c and the final flex version !
+
+Minix ST :
+ - I had to "chmem =70000 cv" (>50000) to get flex linked
+ - 'memset' (PC 1.3, EFTH40,...) is necessary
+ - chmem =90000 flex may be sufficient
+
+Minix PC :
+ It should be possible to port Flex to Minix PC. The current sizes of flex
+ are:
+ Minix ST (ACK) Lattice (TOS) Turbo (TOS)
+
+ size 75300 83305 57957
+ compilation time 22' 15' 3'40"
+ flex -is scan.l 1'49" 43" 30"
+
+ The Minix ST size includes the bad generated code using only a subset of
+ the 68000 commands, long addresses only and a huge relocation table.
+ Therefore the PC size will be <64 k ! More serious is the fact that I had
+ to chmem =90000 flex to get scan.l converted to scan.c . But I never saw
+ a more complex lex source than scan.l -- so it should be possible to
+ reduce some array sizes without limitation for all day usage.
+
+ No one volunteered yet for a Minix PC port -- but if someone will try it
+ I would provide him with a new scan.c and some hints.
+
+TOS:
+ Don't forget to adapt the flexskel path within flexdef.h !
+
+
+Bitnet: V61@DHDURZ1 Ronald Lamprecht
+UUCP: ...!unido!DHDURZ1.bitnet!V61 Theoretische Physik
+ARPAnet: V61%DHDURZ1.BITNET@CUNYVM.CUNY.EDU (Heidelberg, West Germany)
+(Message inbox:36)
+Date: Wed, 05 Jul 89 21:16:07 CET
+From: V61%DHDURZ1.BITNET@csa2.lbl.gov
+Subject: Re: What is TOS
+To: vern@lbl-csam.arpa
+
+TOS is the name of the Atari ST operating system that is very similar
+to MSDOS (Both use CR,LF as end of line character). Therefore I have
+been astonished that no EOL convertion porblems occur within MSDOS.
+
+I have been aware of the double buffering when changing read to fread and I
+accept your argument of a possible slow down. But if you integrate the other
+Atari - TOS changes, please insert a
+ #ifdef ATARI
+ fread ....
+ #else
+ read ....
+ #endif
+in flex.skel .
+
+Bitnet: V61@DHDURZ1 Ronald Lamprecht
+UUCP: ...!unido!DHDURZ1.bitnet!V61 Theoretische Physik
+ARPAnet: V61%DHDURZ1.BITNET@CUNYVM.CUNY.EDU (Heidelberg, West Germany)
+
+
+
+
+echo x - Makefile_cdiff
+sed '/^X/s///' > Makefile_cdiff << '/'
+X*** Src_2.1/Makefile Thu Jun 28 00:06:42 1989
+X--- Makefile Thu Jul 3 02:12:48 1989
+X***************
+X*** 5,10 ****
+X--- 5,11 ----
+X # Porting considerations:
+X #
+X # For System V Unix machines, add -DSYS_V to CFLAGS.
+X+ # For Minix (ST), add -DSYS_V to CFLAGS
+X # For Vax/VMS, add -DSYS_V to CFLAGS.
+X # For MS-DOS, add "-DMS_DOS -DSYS_V" to CFLAGS. Create \tmp if not present.
+X # You will also want to rename flex.skel to something with a three
+X***************
+X*** 21,28 ****
+X SKELETON_DIR = /usr/local/lib
+X SKELETON_FILE = flex.skel
+X SKELFLAGS = -DDEFAULT_SKELETON_FILE=\"$(SKELETON_DIR)/$(SKELETON_FILE)\"
+X! CFLAGS = -O
+X! LDFLAGS = -s
+X
+X FLEX_FLAGS =
+X FLEX = ./flex
+X--- 22,29 ----
+X SKELETON_DIR = /usr/local/lib
+X SKELETON_FILE = flex.skel
+X SKELFLAGS = -DDEFAULT_SKELETON_FILE=\"$(SKELETON_DIR)/$(SKELETON_FILE)\"
+X! CFLAGS = -O -DSYS_V
+X! LDFLAGS =
+X
+X FLEX_FLAGS =
+X FLEX = ./flex
+X***************
+X*** 57,63 ****
+X yylex.c
+X
+X flex : $(FLEXOBJS)
+X! $(CC) $(CFLAGS) -o flex $(LDFLAGS) $(FLEXOBJS)
+X
+X first_flex:
+X cp initscan.c scan.c
+X--- 58,65 ----
+X yylex.c
+X
+X flex : $(FLEXOBJS)
+X! $(CC) $(CFLAGS) -o flex $(FLEXOBJS) $(LDFLAGS)
+X! chmem =150000 flex
+X
+X first_flex:
+X cp initscan.c scan.c
+/
+echo x - flex.skel_cdif
+sed '/^X/s///' > flex.skel_cdif << '/'
+X*** Src_2.1/flex.skel Thu Jun 28 00:19:20 1989
+X--- flex.skel Thu Jul 2 22:18:31 1989
+X***************
+X*** 28,34 ****
+X * is returned in "result".
+X */
+X #define YY_INPUT(buf,result,max_size) \
+X! if ( (result = read( fileno(yyin), buf, max_size )) < 0 ) \
+X YY_FATAL_ERROR( "read() in flex scanner failed" );
+X #define YY_NULL 0
+X #define yyterminate() return ( YY_NULL )
+X--- 28,34 ----
+X * is returned in "result".
+X */
+X #define YY_INPUT(buf,result,max_size) \
+X! if ( (result = fread( buf,1, max_size, yyin )) < 0 ) \
+X YY_FATAL_ERROR( "read() in flex scanner failed" );
+X #define YY_NULL 0
+X #define yyterminate() return ( YY_NULL )
+/
+echo x - flexdef.h_cdif
+sed '/^X/s///' > flexdef.h_cdif << '/'
+X*** Src_2.1/flexdef.h Thu Jun 28 00:43:27 1989
+X--- flexdef.h Thu Jul 3 02:45:50 1989
+X***************
+X*** 26,31 ****
+X--- 26,40 ----
+X
+X /* @(#) $Header: flexdef.h,v 2.0 89/06/20 15:49:50 vern Locked $ (LBL) */
+X
+X+ #ifdef ATARI
+X+ #define SYS_V
+X+ #define abs(x) ((x) < 0 ? -(x) : (x))
+X+ #define SHORT_FILE_NAMES
+X+ #ifdef TURBO
+X+ #define SHORT_EXTERNAL_NAMES
+X+ #endif
+X+ #endif
+X+
+X #ifndef FILE
+X #include <stdio.h>
+X #endif
+X***************
+X*** 41,47 ****
+X #endif
+X
+X #ifndef VMS
+X! char *memset();
+X #else
+X /* memset is needed for old versions of the VMS C runtime library */
+X #define memset(s, c, n) \
+X--- 50,58 ----
+X #endif
+X
+X #ifndef VMS
+X! #ifndef ATARI && TURBO
+X! char *memset();
+X! #endif
+X #else
+X /* memset is needed for old versions of the VMS C runtime library */
+X #define memset(s, c, n) \
+X***************
+X*** 81,91 ****
+X--- 92,129 ----
+X #define true 1
+X #define false 0
+X
+X+ #ifdef ATARI
+X+ #define DEFAULT_SKELETON_FILE "D:\\include\\flexskel"
+X+ #endif
+X+
+X
+X #ifndef DEFAULT_SKELETON_FILE
+X #define DEFAULT_SKELETON_FILE "flex.skel"
+X #endif
+X
+X+ #ifdef SHORT_EXTERNAL_NAMES
+X+ /* avoid long external names that are ambiguous within the first 8 characters */
+X+ #define current_mns c__mns
+X+ #define current_max_rules c__max_rules
+X+ #define current_max_state_type c__max_state_type
+X+ #define current_max_scs c__max_scs
+X+ #define current_max_dfa_size c__max__size
+X+ #define current_max_xpairs c__max_xpairs
+X+ #define current_max_template_xpairs c__max_template_xpairs
+X+ #define current_max_dfas c__max_dfas
+X+ #define current_maxccls c__maxccles
+X+ #define current_max_ccl_tbl_size c__max_ccl_tbl_size
+X+ #define indent_puts ind_puts
+X+ #define indent_put2s ind_put2s
+X+ #define gen_next_compressed_state gen_n_comressed_state
+X+ #define gen_next_match gen_n_match
+X+ #define gen_next_state gen_n_state
+X+ #define variable_trailing_context_rules var_tr_context_rules
+X+ #define variable_trailing_rule var_tr_rule
+X+ #define backtrack_report backtr_report
+X+ #define backtrack_file backtr_file
+X+ #endif
+X+
+X /* special chk[] values marking the slots taking by end-of-buffer and action
+X * numbers
+X */
+X***************
+X*** 305,311 ****
+X int int_val;
+X } ;
+X
+X! typedef struct hash_entry *hash_table[];
+X
+X #define NAME_TABLE_HASH_SIZE 101
+X #define START_COND_HASH_SIZE 101
+X--- 343,349 ----
+X int int_val;
+X } ;
+X
+X! typedef struct hash_entry **hash_table;
+X
+X #define NAME_TABLE_HASH_SIZE 101
+X #define START_COND_HASH_SIZE 101
+X***************
+X*** 372,378 ****
+X extern int datapos, dataline, linenum;
+X extern FILE *skelfile, *yyin, *temp_action_file, *backtrack_file;
+X extern char *infilename;
+X! extern char action_file_name[];
+X
+X
+X /* variables for stack of states having only one out-transition:
+X--- 410,416 ----
+X extern int datapos, dataline, linenum;
+X extern FILE *skelfile, *yyin, *temp_action_file, *backtrack_file;
+X extern char *infilename;
+X! extern char *action_file_name;
+X
+X
+X /* variables for stack of states having only one out-transition:
+/
+echo x - main.c_cdiff
+sed '/^X/s///' > main.c_cdiff << '/'
+X*** Src_2.1/main.c Thu Jun 28 00:30:39 1989
+X--- main.c Thu Jul 3 02:27:47 1989
+X***************
+X*** 81,96 ****
+X FILE *temp_action_file;
+X FILE *backtrack_file;
+X int end_of_buffer_state;
+X! #ifndef SHORT_FILE_NAMES
+X! char action_file_name[] = "/tmp/flexXXXXXX";
+X! #else
+X! char action_file_name[] = "flexXXXXXX.tmp";
+X! #endif
+X!
+X #ifndef SHORT_FILE_NAMES
+X static char outfile[] = "lex.yy.c";
+X #else
+X! static char outfile[] = "lexyy.c";
+X #endif
+X static int outfile_created = 0;
+X
+X--- 81,91 ----
+X FILE *temp_action_file;
+X FILE *backtrack_file;
+X int end_of_buffer_state;
+X! char *action_file_name;
+X #ifndef SHORT_FILE_NAMES
+X static char outfile[] = "lex.yy.c";
+X #else
+X! static char outfile[] = "lex_yy.c";
+X #endif
+X static int outfile_created = 0;
+X
+X***************
+X*** 328,333 ****
+X--- 323,329 ----
+X {
+X int i, sawcmpflag, use_stdout;
+X char *arg, *skelname = NULL, *flex_gettime(), clower(), *mktemp();
+X+ char *tmp_action =(char *)0, *malloc();
+X
+X printstats = syntaxerror = trace = spprdflt = interactive = caseins = false;
+X backtrack_report = performance_report = ddebug = fulltbl = fullspd = false;
+X***************
+X*** 349,354 ****
+X--- 345,355 ----
+X for ( i = 1; arg[i] != '\0'; ++i )
+X switch ( arg[i] )
+X {
+X+ case 'a':
+X+ if ( i != 1 )
+X+ flexerror( "-a flag must be given separately" );
+X+ tmp_action = &arg[i+1];
+X+ goto get_next_arg;
+X case 'b':
+X backtrack_report = true;
+X break;
+X***************
+X*** 445,452 ****
+X printstats = true;
+X break;
+X
+X! default:
+X! lerrif( "unknown flag %c", (int) arg[i] );
+X break;
+X }
+X
+X--- 446,458 ----
+X printstats = true;
+X break;
+X
+X! case '?':
+X! flexinfo(0);
+X! break;
+X!
+X! default:
+X! fprintf(stderr,"flex : unknown flag %c\n", (int) arg[i] );
+X! flexinfo(1);
+X break;
+X }
+X
+X***************
+X*** 454,459 ****
+X--- 460,493 ----
+X ;
+X }
+X
+X+
+X+ /* if you change the default tmp file names don't forget to change the
+X+ initialization for i, too !
+X+
+X+ */
+X+ #ifndef SHORT_FILE_NAMES
+X+ i = 10;
+X+ if (!tmp_action) i += 5;
+X+ #else
+X+ i = 12;
+X+ #endif
+X+ if (tmp_action)
+X+ i += strlen(tmp_action) + 1;
+X+ if((action_file_name = malloc(i+1)) == (char *)0)
+X+ flexerror("No memory for action_file_name");
+X+ *action_file_name = (char) NULL;
+X+ if (tmp_action)
+X+ strcat(action_file_name,tmp_action);
+X+ #ifndef SHORT_FILE_NAMES
+X+ else
+X+ strcat(action_file_name,"/tmp");
+X+ strcat(action_file_name,"/flexXXXXXX");
+X+ #else
+X+ if (tmp_action)
+X+ strcat(action_file_name,"/");
+X+ strcat(action_file_name,"flexXXXX.tmp");
+X+ #endif
+X+
+X if ( (fulltbl || fullspd) && usemecs )
+X flexerror( "full table and -cm don't make sense together" );
+X
+X***************
+X*** 520,526 ****
+X if ( (skelfile = fopen( skelname, "r" )) == NULL )
+X lerrsf( "can't open skeleton file %s", skelname );
+X
+X! (void) mktemp( action_file_name );
+X
+X if ( (temp_action_file = fopen( action_file_name, "w" )) == NULL )
+X lerrsf( "can't open temporary action file %s", action_file_name );
+X--- 554,562 ----
+X if ( (skelfile = fopen( skelname, "r" )) == NULL )
+X lerrsf( "can't open skeleton file %s", skelname );
+X
+X! #ifndef ATARI && LATTICE
+X! (void) mktemp( action_file_name );
+X! #endif
+X
+X if ( (temp_action_file = fopen( action_file_name, "w" )) == NULL )
+X lerrsf( "can't open temporary action file %s", action_file_name );
+X***************
+X*** 566,571 ****
+X--- 602,640 ----
+X }
+X
+X
+X+ flexinfo(status)
+X+ int status;
+X+ {
+X+ fprintf(stderr,"Syntax : FLEX inp_file\n");
+X+ fprintf(stderr,"Function: fast lexical analyzer generator V%s\n",flex_version);
+X+ fprintf(stderr,"Options : a dir_path : directory path for temporary files\n");
+X+ fprintf(stderr," - b : generate backtracking information to lex.backtrack\n");
+X+ fprintf(stderr," - c : compressed table, no equiv., no meta equiv.classes\n");
+X+ fprintf(stderr," e : equivalence classes\n");
+X+ fprintf(stderr," F : fast table\n");
+X+ fprintf(stderr," |f : full table\n");
+X+ fprintf(stderr," |m : meta equivalence classes\n");
+X+ fprintf(stderr," - d : generate debugging scanner\n");
+X+ fprintf(stderr," - F : fast table\n");
+X+ fprintf(stderr," - f : full (not compressed) table\n");
+X+ fprintf(stderr," - I : generate interactive scanner\n");
+X+ fprintf(stderr," - i : generate case-insensitive scanner\n");
+X+ fprintf(stderr," - L : supress #line directives\n");
+X+ /* fprintf(stderr," - n hexnum : generate scanner using <hexnum> as newline char.\n");*/
+X+ fprintf(stderr," - p : generate performance report to stderr\n");
+X+ fprintf(stderr," - S skeleton_path : file path for skeleton file\n");
+X+ fprintf(stderr," - s : suppress echo of unmatched scanner input to stdout\n");
+X+ fprintf(stderr," - T : run flex in trace mode\n");
+X+ #ifdef ATARI
+X+ fprintf(stderr," - t : place result on stdout instead of lex_yy.c\n");
+X+ #else
+X+ fprintf(stderr," - t : place result on stdout instead of lex.yy.c\n");
+X+ #endif
+X+ fprintf(stderr," - v : print statistics of generated scanner\n");
+X+ fprintf(stderr," default = -cem\n");
+X+ exit(status);
+X+ }
+X+
+X /* readin - read in the rules section of the input file(s)
+X *
+X * synopsis
+/
+echo x - scan.l_cdiff
+sed '/^X/s///' > scan.l_cdiff << '/'
+X*** Src_2.1/scan.l Thu Jun 30 19:42:00 1989
+X--- scan.l Thu Jul 2 22:19:26 1989
+X***************
+X*** 125,132 ****
+X
+X {SCNAME} RETURNNAME;
+X ^{OPTWS}\n ++linenum; /* allows blank lines in section 1 */
+X! \n ++linenum; return ( '\n' );
+X! . synerr( "illegal character" ); BEGIN(RECOVER);
+X
+X
+X <C_COMMENT>"*/" ECHO; BEGIN(0);
+X--- 125,136 ----
+X
+X {SCNAME} RETURNNAME;
+X ^{OPTWS}\n ++linenum; /* allows blank lines in section 1 */
+X! {OPTWS}\n ++linenum; return ( '\n' );
+X! . {
+X! synerr( "illegal character" );
+X! fprintf(stderr,"Char : $%x\n",yytext[yyleng-1]);
+X! BEGIN(RECOVER);
+X! }
+X
+X
+X <C_COMMENT>"*/" ECHO; BEGIN(0);
+X***************
+X*** 206,212 ****
+X <SECT2>^{OPTWS}\n ++linenum; /* allow blank lines in section 2 */
+X
+X /* this horrible mess of a rule matches indented lines which
+X! * do not contain "/*". We need to make the distinction because
+X * otherwise this rule will be taken instead of the rule which
+X * matches the beginning of comments like this one
+X */
+X--- 210,216 ----
+X <SECT2>^{OPTWS}\n ++linenum; /* allow blank lines in section 2 */
+X
+X /* this horrible mess of a rule matches indented lines which
+X! * do not contain '/','*'. We need to make the distinction because
+X * otherwise this rule will be taken instead of the rule which
+X * matches the beginning of comments like this one
+X */
+/
+echo x - Makefile.tos
+sed '/^X/s///' > Makefile.tos << '/'
+X# make file for "flex" tool
+X
+X# @(#) $Header: Makefile,v 2.3 89/06/20 17:27:12 vern Exp $ (LBL)
+X
+X# Porting considerations:
+X#
+X# For System V Unix machines, add -DSYS_V to CFLAGS.
+X# For Vax/VMS, add -DSYS_V to CFLAGS.
+X# For MS-DOS, add "-DMS_DOS -DSYS_V" to CFLAGS. Create \tmp if not present.
+X# You will also want to rename flex.skel to something with a three
+X# character extension, change SKELETON_FILE below appropriately,
+X# For Amiga, add "-DAMIGA -DSYS_V" to CFLAGS.
+X#
+X# A long time ago, flex was successfully built using Microsoft C and
+X# the following options: /AL, /stack:10000, -LARGE, -Ml, -Mt128, -DSYS_V
+X
+X
+X# the first time around use "make first_flex"
+X
+X# The following definitions must be set according to your compiler -
+X# examples for a Lattice Compiler with GST assembler and TURBO C with
+X# assembler are provided below and must just be updated (don't forget to
+X# update the linker argument extension files (*.lnk,*.tlk), too) :
+X#
+X#CCPATH = path to compiler directory without trailing \
+X#CHPATH = path to header files without trailing \
+X#CC = filename of the compiler
+X#CFLAGS = compiler option flags
+X#CIEXT = extension of C sources that should be used for input filenames
+X#ASMPATH = path to assembler directory without trailing \
+X#ASM = filename of the assembler
+X#AFLAGS = assembler option flags
+X#AIEXT = extension of assembler sources that should be used for assembler
+X# input filenames
+X#AEXT = general assembler filename extension
+X#LNKPATH = path to linker directory without trailing \
+X#LINK = filename of the linker
+X#LFLAG0 = first option (full pathname of C startupcode)
+X#LFLAG1 = further options + option flag for argument extension filename
+X#LFLAG2 = further options + option flag for output-filename
+X#LNKEXT = extension of linker argument extension file
+X#OIEXT = extension of objects that should be used for linker input files
+X#OEXT = general object file extension
+X
+X# Lattice definitions
+XCCPATH = d:\latt
+XCHPATH = d:\latt\include
+XCC = lc.ttp
+XCFLAGS = -h -n -cw -cc -i$(CHPATH)\ -g$(CCPATH)\ -dLATTICE -dATARI
+XCIEXT =
+XASMPATH = d:\gst
+XASM = assem.ttp
+XAFLAGS = -nolist -errors errors.out
+XAIEXT =
+XAEXT = .asm
+XLNKPATH = d:\gst
+XLINK = ld.ttp
+XLFLAG0 =
+XLFLAG1 = -with
+XLFLAG2 = -nolist -sec -mem 200 -prog
+XLNKEXT = .lnk
+XOIEXT =
+XOEXT = .bin
+X
+X# Turbo definitions
+X#CCPATH = d:\turbo
+X#CHPATH = d:\turbo\include
+X#CC = tcc.prg
+X#CFLAGS = -GJMPRZ -H=$(CHPATH)\ -w- -DTURBO -DATARI
+X#CIEXT = .c
+X#ASMPATH = d:\turbo
+X#ASM = mas.prg
+X#AFLAGS =
+X#AIEXT = .s
+X#AEXT = .s
+X#LNKPATH = d:\turbo
+X#LINK = tlink.ttp
+X#LFLAG0 = $(LNKPATH)\lib\tcstart.o
+X#LFLAG1 = -I=
+X#LFLAG2 = -O=
+X#LNKEXT = .tlk
+X#OIEXT = .o
+X#OEXT = .o
+X
+X# Other definitions
+X# (not used for Atari because of short argument string - defined in flexdef.h
+X
+XSKELETON_DIR = /usr/lib
+XSKELETON_FILE = flex.skel
+XSKELFLAGS = -DDEFAULT_SKELETON_FILE=\"$(SKELETON_DIR)/$(SKELETON_FILE)\"
+X
+X
+XFLEX = d:\etc\flex.ttp
+XFLEX_FLAGS = -is
+XYACC = d:\etc\yacc.ttp
+XRENAME = d:\bin\rename
+XDEL = d:\bin\del
+X
+X# Internal definitions
+XLNK = $(LNKPATH)\$(LINK)
+X
+XFLEXOBJS = \
+X ccl$(OEXT) \
+X dfa$(OEXT) \
+X ecs$(OEXT) \
+X gen$(OEXT) \
+X main$(OEXT) \
+X misc$(OEXT) \
+X nfa$(OEXT) \
+X parse$(OEXT) \
+X scan$(OEXT) \
+X sym$(OEXT) \
+X tblcmp$(OEXT) \
+X yylex$(OEXT)
+X
+XFLEX_C_SOURCES = \
+X ccl.c \
+X dfa.c \
+X ecs.c \
+X gen.c \
+X main.c \
+X misc.c \
+X nfa.c \
+X parse.c \
+X scan.c \
+X sym.c \
+X tblcmp.c \
+X yylex.c
+X
+Xflex : $(FLEXOBJS)
+X $(LNK) $(LFLAG0) $(LFLAG1)flex$(LNKEXT) $(LFLAG2)flex.ttp
+X
+Xfirst_flex:
+X cp initscan.c scan.c
+X make $(MFLAGS) flex
+X
+Xparse.h parse.c : parse.y
+X $(YACC) -d parse.y
+X $(DEL) parse.c
+X $(RENAME) y_tab.c parse.c
+X $(DEL) parse.h
+X $(RENAME) y_tab.h parse.h
+X
+Xscan.c : scan.l
+X $(FLEX) $(FLEX_FLAGS) scan.l
+X $(RENAME) lex_yy.c scan.c
+X
+Xscan$(OEXT) : scan.c parse.h flexdef.h
+X $(CCPATH)\$(CC) $(CFLAGS) scan$(CIEXT)
+X
+Xmain$(OEXT) : main.c flexdef.h
+X $(CCPATH)\$(CC) $(CFLAGS) main$(CIEXT)
+X
+Xccl$(OEXT) : ccl.c flexdef.h
+X $(CCPATH)\$(CC) $(CFLAGS) ccl$(CIEXT)
+X
+Xdfa$(OEXT) : dfa.c flexdef.h
+X $(CCPATH)\$(CC) $(CFLAGS) dfa$(CIEXT)
+X
+Xecs$(OEXT) : ecs.c flexdef.h
+X $(CCPATH)\$(CC) $(CFLAGS) ecs$(CIEXT)
+X
+Xgen$(OEXT) : gen.c flexdef.h
+X $(CCPATH)\$(CC) $(CFLAGS) gen$(CIEXT)
+X
+Xmisc$(OEXT) : misc.c flexdef.h
+X $(CCPATH)\$(CC) $(CFLAGS) misc$(CIEXT)
+X
+Xnfa$(OEXT) : nfa.c flexdef.h
+X $(CCPATH)\$(CC) $(CFLAGS) nfa$(CIEXT)
+X
+Xparse$(OEXT) : parse.c flexdef.h
+X $(CCPATH)\$(CC) $(CFLAGS) parse$(CIEXT)
+X
+Xsym$(OEXT) : sym.c flexdef.h
+X $(CCPATH)\$(CC) $(CFLAGS) sym$(CIEXT)
+X
+Xtblcmp$(OEXT) : tblcmp.c flexdef.h
+X $(CCPATH)\$(CC) $(CFLAGS) tblcmp$(CIEXT)
+X
+Xyylex$(OEXT) : yylex.c flexdef.h
+X $(CCPATH)\$(CC) $(CFLAGS) yylex$(CIEXT)
+X
+Xflex.man : flex.1
+X nroff -man flex.1 >flex.man
+X
+Xlint : $(FLEX_C_SOURCES)
+X lint $(FLEX_C_SOURCES) > flex.lint
+X
+Xdistrib :
+X mv scan.c initscan.c
+X chmod 444 initscan.c
+X $(MAKE) $(MFLAGS) clean
+X
+Xclean :
+X rm -f core errs flex *$(OEXT) parse.c *.lint parse.h flex.man tags
+X
+Xtags :
+X ctags $(FLEX_C_SOURCES)
+X
+Xvms : flex.man
+X $(MAKE) $(MFLAGS) distrib
+X
+Xtest :
+X $(FLEX) $(FLEX_FLAGS) scan.l
+X $(RENAME) lex_yy.c scan.ctest
+X cmp scan.c scan.ctest
+X
+/
+echo x - Readme2
+sed '/^X/s///' > Readme2 << '/'
+XThe changes: (1.7.89 RAL)
+X
+X - Bug fix: The original flex didn't like trailing spaces in exclusive start
+X condition lists ! If you add an trailing space to line 68 in scan.l
+X
+X "%x SECT2 SECT2PROLOG SECT3 CODEBLOCK PICKUPDEF SC CARETISBOL NUM QUOTE "
+X
+X you get a misleading error message:
+X
+X "Syntax error at line 69: bad start condition list"
+X
+X This bug can either be fixed in parse.y or in scan.l . I have chosen the
+X last because there the fix is minimal: Just change the rule (line 128)
+X
+X "\n" to "{OPTWS}\n"
+X
+X - Enhancements:
+X - new option "-?" that provides some help information about the other
+X flags (main.c)
+X - new option "-aTMPPATH" that allows a redefinition of the standard
+X path for the temporary file (this might be rather large >200k if
+X F,f options are selected). (main.c, flexdef.h (l.376))
+X - hexdump of illegal characters -- this proved to be a useful debugging
+X tool especialy if invisible control characters occur which weren't
+X covered by the rules. (scan.l fprintf statement line 129,...)
+X
+X - Patches due to TOS
+X - General: TOS uses CR,LF as end of line char., Flex wants only a single
+X LF as EOL char. Therefore all I/O must be translated using f* calls.
+X This is done everywhere besides the YY_INPUT macro (flex.skel (scan.c),
+X line 31) that uses a low level 'read'. This should be definitly changed
+X to fread, so that all I/O calls occur on the same level.
+X - the short action_file_name has been "flexXXXXXX.tmp", but that's too
+X much for TOS,MSDOS ! I changed it to "flexXXXX.tmp" in main.c (patch
+X covered by the -a option additions)
+X - some compilers don't like external names that are ambiguous within
+X the first 8 characters. I defined macros that change all these long
+X external names to names that are unique within the first 8 characters.
+X Just define SHORT_EXTERNAL_NAMES to use this feature (flexdef.h)
+X - some statement changes that some compiler don't like:
+X typedef *xxx[] -> typedef **xxx (flexdef.h.,l.308)
+X "/*" -> '/','*' within a comment in (scan.l, l.209)
+X - changed short "lexyy.c" to "lex_yy.c" what's more similar to the unix
+X "lex.yy.c" (main.c).
+X - a few further really compiler dependent changes provided with
+X #ifdef ATARI && LATTICE res. TURBO braces.
+X
+X - Additional TOS only files
+X - Makefile.tos: Common makefile for all TOS compilers. If you add further
+X ones please email me the new makefile.
+X - flex.lnk: Lattice - GST linker argument extension file
+X - flex.tlk: Turbo linker argument extension file
+X
+X
+XAdditional remarks:
+X
+XI didn't add a new initscan.c (= flex -ist scan.l). The current one is good
+Xenough for a first compilation. With this first version of flex you can
+Xrebuild your own scan.c and the final flex version !
+X
+XMinix ST :
+X - I had to "chmem =70000 cv" (>50000) to get flex linked
+X - 'memset' (PC 1.3, EFTH40,...) is necessary
+X - chmem =90000 flex may be sufficient
+X
+XMinix PC :
+X It should be possible to port Flex to Minix PC. The current sizes of flex
+X are:
+X Minix ST (ACK) Lattice (TOS) Turbo (TOS)
+X
+X size 75300 83305 57957
+X compilation time 22' 15' 3'40"
+X flex -is scan.l 1'49" 43" 30"
+X
+X The Minix ST size includes the bad generated code using only a subset of
+X the 68000 commands, long addresses only and a huge relocation table.
+X Therefore the PC size will be <64 k ! More serious is the fact that I had
+X to chmem =90000 flex to get scan.l converted to scan.c . But I never saw
+X a more complex lex source than scan.l -- so it should be possible to
+X reduce some array sizes without limitation for all day usage.
+X
+X No one volunteered yet for a Minix PC port -- but if someone will try it
+X I would provide him with a new scan.c and some hints.
+X
+XTOS:
+X Don't forget to adapt the flexskel path within flexdef.h !
+X
+X
+/
+echo x - flex.lnk
+sed '/^X/s///' > flex.lnk << '/'
+X*
+X*
+X* linker control file for flex.ttp
+X*
+X*
+X*
+XINPUT d:\latt\lib\startup.bin
+X*
+XINPUT ccl.bin
+XINPUT dfa.bin
+XINPUT ecs.bin
+XINPUT gen.bin
+XINPUT misc.bin
+XINPUT nfa.bin
+XINPUT parse.bin
+XINPUT sym.bin
+XINPUT tblcmp.bin
+XINPUT main.bin
+XINPUT yylex.bin
+XINPUT scan.bin
+X*
+XLIBRARY d:\latt\lib\clib.bin
+X
+/
+echo x - flex.tlk
+sed '/^X/s///' > flex.tlk << '/'
+Xccl.o
+Xdfa.o
+Xecs.o
+Xgen.o
+Xmisc.o
+Xnfa.o
+Xparse.o
+Xsym.o
+Xtblcmp.o
+Xyylex.o
+Xmain.o
+Xscan.o
+Xd:\turbo\lib\tcstdlib.lib ; standard lib
+Xd:\turbo\lib\tcextlib.lib ; extended lib
+Xd:\turbo\lib\tctoslib.lib ; TOS lib
+Xd:\turbo\lib\tcgemlib.lib ; AES and VDI lib
+X-S=200000
+/
diff --git a/Tools/android/flex-2.5.4a/MISC/Borland.old/Borland-2.4 b/Tools/android/flex-2.5.4a/MISC/Borland.old/Borland-2.4
new file mode 100644
index 0000000..5602a14
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Borland.old/Borland-2.4
@@ -0,0 +1,419 @@
+Received: from 128.140.1.1 by ee.lbl.gov for <vern@ee.lbl.gov> (8.6.9/1.43r)
+ id HAA01193; Thu, 29 Sep 1994 07:26:54 -0700
+Received: from larry-le0.cc.emory.edu by
+ emoryu1.cc.emory.edu (5.65/Emory_cc.4.0.1) via SMTP
+ id AA07292 ; Thu, 29 Sep 94 10:26:41 -0400
+From: tkane01@unix.cc.emory.edu (Terrence O Kane)
+Received: by larry.cc.emory.edu (5.0) id AA11757; Thu, 29 Sep 1994 10:26:43 +0500
+Message-Id: <9409291426.AA11757@larry.cc.emory.edu>
+Subject: patches and makefile for Borland C 4.02, flex 2.4.7
+To: vern@ee.lbl.gov
+Date: Thu, 29 Sep 1994 10:26:42 -0400 (EDT)
+X-Mailer: ELM [version 2.4 PL23]
+Mime-Version: 1.0
+Content-Type: text/plain; charset=US-ASCII
+Content-Transfer-Encoding: 7bit
+Content-Length: 9900
+
+Enclosed are unified diffs and a makefile for Borland 4.02
+
+The changes in the enclosed are 1) make the size parameters for memory
+allocation "size_t", 2) change an include file when the lexer is
+compiled within 'extern "C" {...}' in a C++ file, and 3) include pragmas
+in the header suitable for BCC 4.02 to hush on warnings.
+
+The latter is done because of the limit on command line size. A tradeoff
+exists between putting pragmas in the header, or #defines in the header -
+I put in the pragmas since they're suppoed to be ignored unless
+understood - *and* they're enclosed in BCC specific ifdefs, anyway.
+
+All changes are enclosed in "#ifdef __BORLANDC__".
+
+
+
+
+
+--- misc.c Tue Jan 04 14:33:10 1994
++++ ../misc.c Wed Sep 28 18:44:32 1994
+@@ -55,15 +55,19 @@
+ action_index += len;
+ }
+
+
+ /* allocate_array - allocate memory for an integer array of the given size */
+
+ void *allocate_array( size, element_size )
++#ifndef __BORLANDC__
+ int size, element_size;
++#else /* __BORLANDC__ */
++size_t size, element_size;
++#endif /* __BORLANDC__ */
+ {
+ register void *mem;
+
+ /* On 16-bit int machines (e.g., 80286) we might be trying to
+ * allocate more than a signed int can hold, and that won't
+ * work. Cheap test:
+ */
+@@ -634,15 +638,19 @@
+ }
+
+
+ /* reallocate_array - increase the size of a dynamic array */
+
+ void *reallocate_array( array, size, element_size )
+ void *array;
++#ifndef __BORLANDC__
+ int size, element_size;
++#else /* __BORLANDC__ */
++size_t size, element_size;
++#endif /* __BORLANDC__ */
+ {
+ register void *new_array;
+
+ /* Same worry as in allocate_array(): */
+ if ( size * element_size <= 0 )
+ flexfatal(
+ "attempt to increase array size by less than 1 byte" );
+@@ -739,15 +747,19 @@
+ }
+
+
+ /* The following is only needed when building flex's parser using certain
+ * broken versions of bison.
+ */
+ void *yy_flex_xmalloc( size )
++#ifndef __BORLANDC__
+ int size;
++#else /* __BORLANDC__ */
++size_t size;
++#endif /* __BORLANDC__ */
+ {
+ void *result = flex_alloc( size );
+
+ if ( ! result )
+ flexfatal( "memory allocation failed in yy_flex_xmalloc()" );
+
+ return result;
+
+
+
+
+
+--- skel.c Wed Aug 03 11:38:32 1994
++++ ../skel.c Wed Sep 28 18:50:58 1994
+@@ -26,15 +26,19 @@
+ "",
+ "#ifdef __cplusplus",
+ "",
+ "#include <stdlib.h>",
+ "%+",
+ "class istream;",
+ "%*",
++ "#ifndef __BORLANDC__",
+ "#include <unistd.h>",
++ "#else /* __BORLANDC__ */",
++ "#include <io.h>",
++ "#endif /* __BORLANDC__ */",
+ "",
+ "/* Use prototypes in function declarations. */",
+ "#define YY_USE_PROTOS",
+ "",
+ "/* The \"const\" storage-class-modifier is valid. */",
+ "#define YY_USE_CONST",
+ "",
+@@ -240,16 +244,21 @@
+ "static int yy_start_stack_depth = 0;",
+ "static int *yy_start_stack = 0;",
+ "static void yy_push_state YY_PROTO(( int new_state ));",
+ "static void yy_pop_state YY_PROTO(( void ));",
+ "static int yy_top_state YY_PROTO(( void ));",
+ "%*",
+ "",
++ "#ifndef __BORLANDC__",
+ "static void *yy_flex_alloc YY_PROTO(( unsigned int ));",
+ "static void *yy_flex_realloc YY_PROTO(( void *, unsigned int ));",
++ "#else /* __BORLANDC__ */",
++ "static void *yy_flex_alloc YY_PROTO(( size_t ));",
++ "static void *yy_flex_realloc YY_PROTO(( void *, size_t ));",
++ "#endif /* __BORLANDC__ */",
+ "static void yy_flex_free YY_PROTO(( void * ));",
+ "",
+ "#define yy_new_buffer yy_create_buffer",
+ "",
+ "%% yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here",
+ "",
+ "#ifndef yytext_ptr",
+
+
+
+
+
+--- initscan.c Wed Aug 03 11:42:46 1994
++++ ../initscan.c Wed Sep 28 18:51:34 1994
+@@ -16,15 +16,19 @@
+ #endif
+ #endif
+
+
+ #ifdef __cplusplus
+
+ #include <stdlib.h>
++#ifndef __BORLANDC__
+ #include <unistd.h>
++#else /* __BORLANDC__ */
++#include <io.h>
++#endif /* __BORLANDC__ */
+
+ /* Use prototypes in function declarations. */
+ #define YY_USE_PROTOS
+
+ /* The "const" storage-class-modifier is valid. */
+ #define YY_USE_CONST
+
+@@ -220,16 +224,21 @@
+ static int yy_start_stack_ptr = 0;
+ static int yy_start_stack_depth = 0;
+ static int *yy_start_stack = 0;
+ static void yy_push_state YY_PROTO(( int new_state ));
+ static void yy_pop_state YY_PROTO(( void ));
+ static int yy_top_state YY_PROTO(( void ));
+
++#ifndef __BORLANDC__
+ static void *yy_flex_alloc YY_PROTO(( unsigned int ));
+ static void *yy_flex_realloc YY_PROTO(( void *, unsigned int ));
++#else /* __BORLANDC__ */
++static void *yy_flex_alloc YY_PROTO(( size_t ));
++static void *yy_flex_realloc YY_PROTO(( void *, size_t ));
++#endif /* __BORLANDC__ */
+ static void yy_flex_free YY_PROTO(( void * ));
+
+ #define yy_new_buffer yy_create_buffer
+
+ #define INITIAL 0
+ #define SECT2 1
+ #define SECT2PROLOG 2
+
+
+
+
+
+--- flexdef.h Tue Jan 04 14:33:14 1994
++++ ../flexdef.h Wed Sep 28 18:53:44 1994
+@@ -27,14 +27,25 @@
+ */
+
+ /* @(#) $Header: flexdef.h,v 1.2 94/01/04 14:33:14 vern Exp $ (LBL) */
+
+ #include <stdio.h>
+ #include <ctype.h>
+
++#ifdef __BORLANDC__
++#include <malloc.h>
++
++#pragma warn -pro
++#pragma warn -rch
++#pragma warn -use
++#pragma warn -aus
++#pragma warn -par
++#pragma warn -pia
++
++#endif /* __BORLANDC__ */
+ #if HAVE_STRING_H
+ #include <string.h>
+ #else
+ #include <strings.h>
+ #endif
+
+ #if __STDC__
+@@ -607,19 +618,29 @@
+ */
+
+ extern char nmstr[MAXLINE];
+ extern int sectnum, nummt, hshcol, dfaeql, numeps, eps2, num_reallocs;
+ extern int tmpuses, totnst, peakpairs, numuniq, numdup, hshsave;
+ extern int num_backing_up, bol_needed;
+
++#ifndef __BORLANDC__
+ void *allocate_array PROTO((int, int));
+ void *reallocate_array PROTO((void*, int, int));
++#else /* __BORLANDC__ */
++void *allocate_array PROTO((size_t, size_t));
++void *reallocate_array PROTO((void*, size_t, size_t));
++#endif /* __BORLANDC__ */
+
++#ifndef __BORLANDC__
+ void *flex_alloc PROTO((unsigned int));
+ void *flex_realloc PROTO((void*, unsigned int));
++#else /* __BORLANDC__ */
++void *flex_alloc PROTO((size_t));
++void *flex_realloc PROTO((void*, size_t));
++#endif /* __BORLANDC__ */
+ void flex_free PROTO((void*));
+
+ #define allocate_integer_array(size) \
+ (int *) allocate_array( size, sizeof( int ) )
+
+ #define reallocate_integer_array(array,size) \
+ (int *) reallocate_array( (void *) array, size, sizeof( int ) )
+@@ -772,15 +793,19 @@
+ /* Write out one section of the skeleton file. */
+ extern void skelout PROTO((void));
+
+ /* Output a yy_trans_info structure. */
+ extern void transition_struct_out PROTO((int, int));
+
+ /* Only needed when using certain broken versions of bison to build parse.c. */
++#ifndef __BORLANDC__
+ extern void *yy_flex_xmalloc PROTO(( int ));
++#else /* __BORLANDC__ */
++extern void *yy_flex_xmalloc PROTO(( size_t ));
++#endif /* __BORLANDC__ */
+
+ /* Set a region of memory to 0. */
+ extern void zero_out PROTO((char *, int));
+
+
+ /* from file nfa.c */
+
+
+
+
+
+###############################################################################
+# Makefile for flex 2.4.7 with Borland C/C++ version 4.02
+#
+# This will probably need to be adjusted for your existing lexer/parser
+# generators. See definitions for FLEX and YACC near the bottom of the
+# makefile.
+#
+# Copy initscan.c to scan.c to make your first executable. After that,
+# you may choose to try alternate compression options for your everyday
+# flex executable.
+#
+# This will build flex with the large model. Don't use huge, but if you
+# feel like experimenting with other models, post your success stories to
+# comp.compilers, OK?
+#
+# This makefile does *not* implement the big testing found in "makefile.in".
+#
+# I also assume the availability of sed and the gnu file utilities on the
+# system - they're readily available, so if you don't have them, why not?
+# <grin>
+#
+# The resulting generated lexer (the real goal, right?) will compile
+# (and run nicely, too) as a .c file, as well as being included such as
+# extern "C" { #include "lexyyc" } in a .cplusplus file.
+#
+###############################################################################
+
+DEBUG = 1
+
+.autodepend
+
+all: flex.exe
+
+###############################################################################
+#
+# standard utilitities? ha.
+#
+
+CC = bcc
+CPP = bcc
+
+###############################################################################
+#
+
+MODEL = l
+
+!if $(DEBUG) == 1
+!message Building with debug.
+debugCompile = -v
+debugLink = /v
+!else
+!message Building without debug.
+debugCompile =
+debugLink =
+!endif
+
+LOADER = c0$(MODEL).obj
+LIBS = c$(MODEL).lib
+LINKFLAGS = $(debugLink)
+
+DATASEG = -dc -Ff
+SizeOPT = -Os -G-
+Defines = -DSHORT_FILE_NAMES=1 -DHAVE_STRING_H=1
+
+COMMON = -A -c -m$(MODEL) $(SizeOPT) $(DATASEG) $(Defines) $(debugCompile)
+CFLAGS = -o$@ $(COMMON)
+CCFLAGS = -o$@ $(COMMON) -Pcc
+
+###############################################################################
+
+.SUFFIXES: .cc
+
+.cc.obj:
+ $(CPP) $(CCFLAGS) $<
+
+.c.obj:
+ $(CPP) $(CFLAGS) $<
+
+###############################################################################
+#
+# source & object files
+#
+
+SRC = ccl.c dfa.c ecs.c gen.c main.c misc.c nfa.c parse.c \
+ scan.c sym.c tblcmp.c yylex.c skel.c
+
+OBJS = $(SRC:.c=.obj)
+
+objects: $(OBJS)
+ @echo $(OBJS)
+
+###############################################################################
+#
+# Executable
+#
+
+flex.exe: $(OBJS)
+ tlink $(LINKFLAGS) @&&!
+$(LOADER) $**
+$&.exe
+$&.map
+$(LIBS)
+!
+
+#
+###############################################################################
+#
+# Lex files
+#
+
+FLEX = .\flex
+FLEX_FLAGS = -ist
+
+scan.c: scan.l
+ $(FLEX) $(FLEX_FLAGS) scan.l >scan.tmp
+ sed s,\"$(srcdir)/scan.l\",\"scan.l\", <scan.tmp >scan.c
+ @rm scan.tmp
+
+###############################################################################
+#
+# YACC files
+#
+
+YACC = .\bison
+YFLAGS = -vdyl
+
+parse.c: parse.y
+ $(YACC) -ydl parse.y
+ @sed "/extern char.*malloc/d" <y_tab.c >parse.c
+ @rm -f y_tab.c
+ @mv y_tab.h parse.h
+
+#
+# end Makefile
+#
+###############################################################################
+
diff --git a/Tools/android/flex-2.5.4a/MISC/Borland.old/Turbo-C b/Tools/android/flex-2.5.4a/MISC/Borland.old/Turbo-C
new file mode 100644
index 0000000..bfe8a92
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Borland.old/Turbo-C
@@ -0,0 +1,179 @@
+Received: from 128.84.254.220 by ee.lbl.gov for <vern@ee.lbl.gov> (8.6.8.1/1.43r)
+ id PAA27266; Mon, 18 Apr 1994 15:08:26 -0700
+Received: from CLOYD.CS.CORNELL.EDU by thialfi.cs.cornell.edu (5.67/I-1.99E)
+ id AA28742; Mon, 18 Apr 94 18:08:14 -0400
+Received: from iraun1.ira.uka.de by cloyd.cs.cornell.edu (5.67/I-1.99D)
+ id AA19613; Mon, 18 Apr 94 18:08:19 -0400
+Received: from t500i2.telematik.informatik. (actually t500i2.telematik.informatik.uni-karlsruhe.de)
+ by iraun1.ira.uka.de with SMTP (PP); Tue, 19 Apr 1994 00:07:55 +0200
+Received: by t500i2.telematik.informatik.uni-karlsruhe.de (5.57/Ultrix3.0-C)
+ id AA10269; Tue, 19 Apr 94 00:09:14 +0200
+From: beigl@t500i2.telematik.informatik.uni-karlsruhe.de (Michael Beigl)
+Message-Id: <9404182209.AA10269@t500i2.telematik.informatik.uni-karlsruhe.de>
+Subject: Makefile-TurboC
+To: vern@cs.cornell.edu
+Date: Tue, 19 Apr 1994 00:09:13 +0200 (MET DST)
+X-Mailer: ELM [version 2.4 PL22]
+Mime-Version: 1.0
+Content-Type: text/plain; charset=US-ASCII
+Content-Transfer-Encoding: 7bit
+Content-Length: 2739
+
+Hello
+
+Here are some additional adjustments to my Makefile. I was using "pure" DOS
+and an old Turbo C++ 1.0 version, so I had some problems with systemtools
+like mv etc. and problems with variables in my Makefile.
+
+Now follows my Makefile
+############################################################################
+# make file for "flex" tool
+
+# @(#) $Header: Makefile,v 2.3 89/06/20 17:27:12 vern Exp $ (LBL)
+
+# Porting considerations:
+#
+# For BSD machines:
+# CFLAGS =
+# LDFLAGS = -s
+# LINK = $(CC) $(CFLAGS) -o flex $(LDFLAGS) $(FLEXOBJS)
+# SKELETON_DIR = .
+# SKELETON_FILE = flex.skel
+# SKELFLAGS = -DDEFAULT_SKELETON_FILE=\"$(SKELETON_DIR)/$(SKELETON_FILE)\"
+# O = o
+# YTAB = y.tab
+# FLEX = ./flex
+#
+# For System V Unix or Vax/VMS machines, merely add:
+# CFLAGS = -DSYS_V
+#
+# For MS-DOS, Turbo C:
+CC = tcc
+# -2+ 286 Options
+CFLAGS = -DSYS_V -DMS_DOS -O -G -Z -ml -v -2
+# /3 enable 32 bit processing
+# /ye expanded memory swapping
+# /yx extended memory swapping
+LINK = tlink @flex.lnk/c/x/v/3/ye
+SKELETON_DIR = .
+SKELETON_FILE = flex.skl
+SKELFLAGS = -DDEFAULT_SKELETON_FILE="$(SKELETON_DIR)/$(SKELETON_FILE)"
+O = obj
+EXE = .exe
+YTAB = y_tab
+FLEX = flex
+YACC = /yacc/byacc
+
+#
+# the first time around use "make first_flex"
+#
+
+FLEX_FLAGS =
+
+FLEXOBJS = \
+ ccl.$O \
+ dfa.$O \
+ ecs.$O \
+ gen.$O \
+ main.$O \
+ misc.$O \
+ nfa.$O \
+ parse.$O \
+ scan.$O \
+ sym.$O \
+ tblcmp.$O \
+ yylex.$O
+
+FLEX_C_SOURCES = \
+ ccl.c \
+ dfa.c \
+ ecs.c \
+ gen.c \
+ main.c \
+ misc.c \
+ nfa.c \
+ parse.c \
+ scan.c \
+ sym.c \
+ tblcmp.c \
+ yylex.c
+
+FLEX_C_SOURCES_1 = \
+ ccl.c \
+ dfa.c \
+ ecs.c \
+ gen.c \
+ main.c \
+ misc.c
+
+FLEX_C_SOURCES_2 = \
+ nfa.c \
+ parse.c \
+ scan.c \
+ sym.c \
+ tblcmp.c \
+ yylex.c
+
+flex.exe: $(FLEXOBJS)
+ $(LINK)
+
+
+flex: $(FLEX_C_SOURCES)
+ $(CC) $(CFLAGS) -c $(SKELFLAGS) $(FLEX_C_SOURCES_1)
+ $(CC) $(CFLAGS) -c $(SKELFLAGS) $(FLEX_C_SOURCES_2)
+ $(LINK)
+
+
+first_flex:
+ copy initscan.c scan.c
+ $(MAKE) flex
+
+parse.h parse.c: parse.y
+ $(YACC) -d parse.y
+ @rename $(YTAB).c parse.c
+ @rename $(YTAB).h parse.h
+
+scan.c: scan.l
+ $(FLEX) -ist $(FLEX_FLAGS) scan.l >scan.c
+
+scan.$O: scan.c parse.h
+
+main.$O: main.c
+ $(CC) $(CFLAGS) -c $(SKELFLAGS) main.c
+
+flex.man: flex.1
+ nroff -man flex.1 >flex.man
+
+lint: $(FLEX_C_SOURCES)
+ lint $(FLEX_C_SOURCES) > flex.lint
+
+distrib:
+ rename scan.c initscan.c
+ attrib +R -A -H -S initscan.c
+ $(MAKE) clean
+
+clean:
+ del *.obj
+ del *.lint
+ del core
+ del errs
+ del flex.exe
+ del parse.c
+ del parse.h
+ del flex.man
+ del tags
+
+tags:
+ ctags $(FLEX_C_SOURCES)
+
+vms: flex.man
+ $(MAKE) distrib
+
+test:
+ $(FLEX) -ist $(FLEX_FLAGS) scan.l | diff scan.c -
+
+############################################################################
+
+I think this Makefile will help some other simple DOS user
+
+ M. Beigl
diff --git a/Tools/android/flex-2.5.4a/MISC/Borland/Makefile b/Tools/android/flex-2.5.4a/MISC/Borland/Makefile
new file mode 100644
index 0000000..3b20090
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Borland/Makefile
@@ -0,0 +1,163 @@
+###############################################################################
+# Makefile for flex 2.5.0.6 (beta) with Borland C/C++ version 4.02
+#
+# This will probably need to be adjusted for your existing lexer/parser
+# generators. See definitions for FLEX and YACC near the bottom of the
+# makefile.
+#
+# This makefile builds initflex.exe and flex.exe by default. It
+# removes initflex.exe after making flex.exe. After that, you may
+# choose to try alternate compression options for your everyday flex
+# executable.
+#
+# This will build flex with the large model. Don't use huge, but if you
+# feel like experimenting with other models, post your success stories to
+# comp.compilers, OK?
+#
+# This makefile does *not* implement the big testing found in "makefile.in".
+#
+# I also assume the availability of sed and the gnu file utilities on the
+# system - they're readily available, so if you don't have them, why not?
+# <grin>
+#
+# The resulting generated lexer (the real goal, right?) will compile
+# (and run nicely, too) as a .c file, as well as being included such as
+# extern "C" { #include "lexyyc" } in a .cplusplus file.
+#
+###############################################################################
+
+DEBUG = 1
+
+.autodepend
+
+all: initflex.exe flex.exe
+ rm initflex.exe initflex.map
+
+###############################################################################
+#
+# standard utilitities? ha.
+#
+
+CC = bcc
+CPP = bcc
+
+###############################################################################
+#
+
+MODEL = l
+
+!if $(DEBUG) == 1
+!message Building with debug.
+debugCompile = -v
+debugLink = /v
+!else
+!message Building without debug.
+debugCompile =
+debugLink =
+!endif
+
+LOADER = c0$(MODEL).obj
+LIBS = c$(MODEL).lib
+LINKFLAGS = $(debugLink)
+
+DATASEG = -dc -Ff
+SizeOPT = -Os -G-
+Defines =
+
+COMMON = -A -c -m$(MODEL) $(SizeOPT) $(DATASEG) $(Defines) $(debugCompile)
+CFLAGS = -o$@ $(COMMON)
+CCFLAGS = -o$@ $(COMMON) -Pcc
+
+###############################################################################
+
+.SUFFIXES: .cc
+
+.cc.obj:
+ $(CPP) $(CCFLAGS) $<
+
+.c.obj:
+ $(CPP) $(CFLAGS) $<
+
+###############################################################################
+#
+# source & object files
+#
+
+BASESRC = ccl.c dfa.c ecs.c gen.c main.c misc.c nfa.c parse.c \
+ sym.c tblcmp.c yylex.c skel.c
+
+INITSRC = $(BASESRC) initscan.c
+
+INITOBJS = $(INITSRC:.c=.obj)
+
+SRC = $(BASESRC) scan.c
+
+OBJS = $(SRC:.c=.obj)
+
+objects: $(OBJS)
+ @echo $(OBJS)
+
+###############################################################################
+#
+# Executable
+#
+
+initflex.exe: $(INITOBJS)
+ tlink $(LINKFLAGS) @&&!
+$(LOADER) $**
+$&.exe
+
+$(LIBS)
+!
+
+flex.exe: $(OBJS)
+ tlink $(LINKFLAGS) @&&!
+$(LOADER) $**
+$&.exe
+
+$(LIBS)
+!
+
+#
+###############################################################################
+#
+# Lex files
+#
+
+FLEX = .\initflex
+FLEX_FLAGS = -ist
+
+scan.c: scan.l
+ $(FLEX) $(FLEX_FLAGS) scan.l >scan.tmp
+ sed s,\"$(srcdir)/scan.l\",\"scan.l\", <scan.tmp >scan.c
+ @rm scan.tmp
+
+###############################################################################
+#
+# YACC files
+#
+
+YACC = .\bison
+YFLAGS = -vdyl
+
+parse.c: parse.y
+ $(YACC) -ydl parse.y
+ @sed "/extern char.*malloc/d" <y_tab.c >parse.c
+ @rm -f y_tab.c
+ @mv y_tab.h parse.h
+
+###############################################################################
+#
+# cleanup
+#
+
+clean:
+ -rm *.obj *.map initflex.exe
+
+realclean: clean
+ -rm flex.exe
+
+#
+# end Makefile
+#
+###############################################################################
diff --git a/Tools/android/flex-2.5.4a/MISC/Borland/NOTES b/Tools/android/flex-2.5.4a/MISC/Borland/NOTES
new file mode 100644
index 0000000..caac3cc
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Borland/NOTES
@@ -0,0 +1,66 @@
+Received: from 128.140.1.1 by ee.lbl.gov for <vern@ee.lbl.gov> (8.6.9/1.43r)
+ id PAA03966; Tue, 24 Jan 1995 15:03:57 -0800
+Received: from larry-le0.cc.emory.edu by
+ emoryu1.cc.emory.edu (5.65/Emory_cc.4.0.1) via SMTP
+ id AA24158 ; Tue, 24 Jan 95 17:18:18 -0500
+From: tkane01@unix.cc.emory.edu (Terrence O Kane)
+Received: by larry.cc.emory.edu (5.0) id AA21979; Tue, 24 Jan 1995 17:17:40 -0500
+Message-Id: <9501242217.AA21979@larry.cc.emory.edu>
+Subject: Re: Beta test for DOS
+To: vern@ee.lbl.gov (Vern Paxson)
+Date: Tue, 24 Jan 1995 17:17:38 -0500 (EST)
+In-Reply-To: <199501232138.NAA11430@daffy.ee.lbl.gov> from "Vern Paxson" at Jan 23, 95 01:38:02 pm
+X-Mailer: ELM [version 2.4 PL23]
+Mime-Version: 1.0
+Content-Type: text/plain; charset=US-ASCII
+Content-Transfer-Encoding: 7bit
+Content-Length: 5792
+
+Vern,
+
+I've made flex 2.5.0.6 successfully with no changes to the source
+code at all. I'm including the Borland 4.02 makefile and config.h
+at the end of this message.
+
+When you're ready for release, I'll be happy to take care of getting
+the appropriate archive files up to Simtel if you wish.
+
+I have not used this version for any of my "work-related" scanners
+yet, but have run the fastwc benchmark. The compiles were for large
+memory model and optimization for fastest possible code. The test
+machine was a Pentium-90 (hey! timing output was integer!) with
+enhanced IDE on a PCI bus and no file system caching. I ran the
+test on two different input files.
+
+(Times are in seconds.)
+
+The first input was a typical postscript file concatenated 10 times;
+by typical, I mean that there were relatively few spaces, lots of lines
+with no space, using lots of parentheses.
+
+ lines words characters
+ 91200 356260 5889240
+
+ mywc 8.89
+ wc1s 15.22 default
+ wc1 10.82 -Cf
+ wc2 10.16 -Cf
+ wc3 9.17 -Cf
+ wc4 9.22 -Cf
+ wc5 10.98 -Cf
+
+The second test run was on a file that consisted of 20 concatenations
+of 'misc/flex.man'.
+
+ lines words characters
+ 69960 305140 2399960
+
+ mywc 4.01
+ wc1s 6.87
+ wc1 5.32
+ wc2 4.95
+ wc3 4.12
+ wc4 4.12
+ wc5 5.05
+
+[[Makefile and config.h moved to separate files -VP]]
diff --git a/Tools/android/flex-2.5.4a/MISC/Borland/config.h b/Tools/android/flex-2.5.4a/MISC/Borland/config.h
new file mode 100644
index 0000000..5e210da
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Borland/config.h
@@ -0,0 +1,29 @@
+/* $Header: /home/daffy/u0/vern/flex/RCS/conf.in,v 1.2 95/01/09 12:11:51 vern Exp $ */
+/* ------------------------------------------------ */
+/* version of config.h for Borland C/C++ v4.02 */
+/* flex version 2.5.0.6 (beta) */
+/* ------------------------------------------------ */
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#undef HAVE_ALLOCA_H
+
+/* Define if platform-specific command line handling is necessary. */
+#undef NEED_ARGV_FIXUP
diff --git a/Tools/android/flex-2.5.4a/MISC/EBCDIC b/Tools/android/flex-2.5.4a/MISC/EBCDIC
new file mode 100644
index 0000000..e4ebd71
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/EBCDIC
@@ -0,0 +1,48 @@
+Return-Path: Mark_Ganter@liz.com
+Received: from 192.216.61.11 by horse.ee.lbl.gov for vern (5.65/1.43r)
+ id AA02152; Tue, 11 Jan 94 06:19:36 -0800
+Received: from melonville.radiomail.net (mayberry.radiomail.net) by radiomail.net with SMTP id AA20220
+ (5.65c+/IDA-1.4.4 for <vern@horse.ee.lbl.gov>); Tue, 11 Jan 1994 06:19:35 -0800
+Message-Id: <199401111419.AA20220@radiomail.net>
+Received: from liz.com by melonville.radiomail.net with CCGW-1.7(930217);
+ Tue, 11 Jan 94 06:19:17
+From: Mark_Ganter@liz.com
+Date: 11 Jan 94 09:05
+To: vern@horse.ee.lbl.gov
+Subject: Re[2]: Flex on an AS400
+
+ I have no problem at all with being a contact for advice
+ on porting Flex to EBCDIC. The code was put on an AS400, so
+ filing the message under /MISC/AS400 is more appropriate.
+ The port was an interesting, very educational experience.
+ Thanks again.
+
+
+ Mark
+
+------------------------------------------------------------------------
+Date: Tue, 18 Apr 1995 12:33:48 -0400
+To: "Michael W. Duffy" <mduffy@netcom.com>, Mark_Ganter@liz.com,
+ vern@ee.lbl.gov (Vern Paxson), slayten@cas.org
+From: slayten@cas.org (Steve Layten)
+Subject: RE: Porting LEX scanner on EBCDIC machine
+X-Mailer: <Windows Eudora Version 2.0.2>
+Content-Length: 918
+
+I came in late on this discussion - I don't follow comp.compilers very
+closely these days because my job has shifted somewhat.
+
+I ported (quite some time ago) flex 2.3.6 to an IBM 3090 under MVS, using
+the SAS C compiler. The approach I used was, as Vern suggested, was to
+translate the tables to reflect EBCDIC-based indices. I haven't even
+downloaded flex 2.4 yet, so I don't know what's in the current distribution.
+My patches were in the flex 2.3 distribution for a while in the MISC
+directory. If you want any more info feel free to drop me a line - I still
+have (somewhere) the patches that I created from version 2.3.6.
+
+Steve Layten
+--
+Steven W. Layten, Senior Research Scientist
+Chemical Abstracts Service PO BOX 3012, Columbus, OH 43210 +1 614 447 3600
+INET: slayten@cas.org FAX: +1 614 447 3813
+# # Speaking only for myself, and NOT for Chemical Abstracts Service! # # #
diff --git a/Tools/android/flex-2.5.4a/MISC/MSDOS/MSC70.make b/Tools/android/flex-2.5.4a/MISC/MSDOS/MSC70.make
new file mode 100644
index 0000000..5980f3a
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/MSDOS/MSC70.make
@@ -0,0 +1,115 @@
+#
+# make file for "flex" tool
+# @(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/Makefile,v 2.9 90/05/26 17:28:44
+ vern Exp $ (LBL)
+#
+# the first time around use "make f_flex"
+#
+# This makefile is specific for Microsoft's C/C++ compiler (v7), nmake and
+# lib
+# - Paul Stuart, Jan 93 (pjs@scammell.ecos.tne.oz.au)
+#
+
+
+SKELFLAGS = -DDEFAULT_SKELETON_FILE=\"c:/src/flex/flex.skl\"
+CFLAGS = -nologo -AL -W2 -F 8000 -Ox -Gt16000 -DMS_DOS -DUSG
+LDFLAGS = /nologo /NOI /BATCH /ONERROR:NOEXE /STACK:8000
+FLEX_FLAGS = -ist8 -Sflex.skl
+
+FLEX = .\flex.exe
+CC = cl
+YACC = c:\lib\byacc
+MAKE = nmake /nologo
+
+#
+# break obj-list into two because of 128 character command-line limit of
+# Microsoft's link and lib utilities.
+#
+FLEXOBJS1 = \
+ ccl.obj \
+ dfa.obj \
+ ecs.obj \
+ gen.obj \
+ main.obj \
+ misc.obj \
+ nfa.obj \
+ parse.obj
+
+FLEXOBJS2 = \
+ scan.obj \
+ sym.obj \
+ tblcmp.obj \
+ yylex.obj
+
+FLEX_C_SOURCES = \
+ ccl.c \
+ dfa.c \
+ ecs.c \
+ gen.c \
+ main.c \
+ misc.c \
+ nfa.c \
+ parse.c \
+ scan.c \
+ sym.c \
+ tblcmp.c \
+ yylex.c
+
+FLEX_LIB_OBJS = \
+ libmain.obj
+
+
+all : flex.exe
+
+#
+# lib is used to get around the 128 character command-line limit of 'link'.
+#
+flex.exe : $(FLEXOBJS1) $(FLEXOBJS2)
+ lib /nologo tmplib $(FLEXOBJS1);
+ link $(LDFLAGS) $(FLEXOBJS2),$*.exe,,tmplib;
+ del tmplib.lib
+
+f_flex:
+ copy initscan.c scan.c
+ touch scan.c
+ @echo compiling first flex
+ $(MAKE) flex.exe
+ del scan.c
+ @echo using first flex to generate final version...
+ $(MAKE) flex.exe
+
+#
+# general inference rule
+#
+.c.obj:
+ $(CC) -c $(CFLAGS) $*.c
+
+parse.h parse.c : parse.y
+ $(YACC) -d parse.y
+ @mv y_tab.c parse.c
+ @mv y_tab.h parse.h
+
+scan.c : scan.l
+ $(FLEX) $(FLEX_FLAGS) $(COMPRESSION) scan.l >scan.c
+
+
+scan.obj : scan.c parse.h flexdef.h
+
+main.obj : main.c flexdef.h
+ $(CC) $(CFLAGS) -c $(SKELFLAGS) main.c
+
+ccl.obj : ccl.c flexdef.h
+dfa.obj : dfa.c flexdef.h
+ecs.obj : ecs.c flexdef.h
+gen.obj : gen.c flexdef.h
+misc.obj : misc.c flexdef.h
+nfa.obj : nfa.c flexdef.h
+parse.obj : parse.c flexdef.h
+sym.obj : sym.c flexdef.h
+tblcmp.obj : tblcmp.c flexdef.h
+yylex.obj : yylex.c flexdef.h
+
+
+clean :
+ del *.obj
+ del *.map
diff --git a/Tools/android/flex-2.5.4a/MISC/MSDOS/configur.bat b/Tools/android/flex-2.5.4a/MISC/MSDOS/configur.bat
new file mode 100644
index 0000000..dbea0e4
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/MSDOS/configur.bat
@@ -0,0 +1,6 @@
+@echo off
+
+sed -e "s/y\.tab\./parse_tab\./" -e "/sed/ s/'/\"/g" < Makefile.in > Makefile
+sed -f MISC/MSDOS/djgpp.sed Makefile.in > Makefile
+
+update initscan.c scan.c
diff --git a/Tools/android/flex-2.5.4a/MISC/MSDOS/djgpp.sed b/Tools/android/flex-2.5.4a/MISC/MSDOS/djgpp.sed
new file mode 100644
index 0000000..b436113
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/MSDOS/djgpp.sed
@@ -0,0 +1,12 @@
+s/y\.tab\./parse_tab\./
+s/@DEFS@/-DMS_DOS/
+s/@LIBS@//
+s/@srcdir@/./
+s/@YACC@/bison/
+s/@CC@/gcc/
+s/@RANLIB@/ranlib/
+s/@ALLOCA@//
+/^flex/ s/\.bootstrap//
+/sed.*extern.*malloc/ c\
+ @mv parse_tab.c parse.c
+/rm.*parse_tab.c/ d
diff --git a/Tools/android/flex-2.5.4a/MISC/MVS/MVS.mail b/Tools/android/flex-2.5.4a/MISC/MVS/MVS.mail
new file mode 100644
index 0000000..5a75e5b
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/MVS/MVS.mail
@@ -0,0 +1,56 @@
+(Message inbox:40)
+Date: Tue, 17 Jul 1990 11:56 EDT
+From: swl26%CAS.BITNET@CORNELLC.cit.cornell.edu
+Subject: Re(2): port of flex-2.3 to IBM/MVS
+To: vern@cs.cornell.edu
+
+>Message received. I'm sending this response to
+>swl26%CAS.BITNET@CORNELLC.cit.cornell.edu.
+
+Great -- we can talk.
+
+>How extensive are the diffs? If they're fairly short then yes, please
+>send them. If they're pretty involved then probably not, as I'm not aware
+>of many MVS flex users ...
+
+I've built a context diff file which is ~850 lines.
+
+Summary of major changes necessary:
+
+ o a new initscan.c -- because MVS is ebcdic, the initial scanner had
+ to be changed. I built a scanner from scan.l using -Ce, then
+ hand-manipulated the yy_ec table to fit EBCDIC instead of ASCII
+ chars. (This is not included in the diff file above.)
+
+ o changes in main and flexdef.h to change how files are handled. (No
+ dynamic file names, etc.)
+
+ o Some lines had to be shortened to 80 bytes. This mostly impacted
+ your RCSID lines, which with the full path name were too long.
+
+ o SASC and the linker don't allow externals to be longer than 8 chars.
+ I thus wrote a Q&D program to shorten all externals. (This would be
+ a separate file 'fixit.l', which is not included in the diffs.)
+
+ o There are several places where there are tests for 'isascii' (which I
+ deleted conditionally, using #ifdefs), and tests for 'A' <= x <= 'Z'
+ which I changed to 'isupper'.
+
+Many of the changes I've incorporated without impacting other systems.
+Others are with 'ifdefs'. Still others (the short external names and new
+initscan) are 'isolable' as separate files which would have to be
+included with a distribution.
+
+Obviously, you are not going to want to (even if you can :-) ) worry about
+testing new versions in the MVS environment. Likewise, I don't have the
+time or resources to provide much support. (I'm not sure my management
+would allow any :-( )
+
+With all of the above feel free to say "Thanks, but no thanks." If you
+want to see the diffs anyway, I will certainly mail them.
+
+Thanks for your time and efforts.
+
+Steve Layten
+Chemical Abstracts Service, PO Box 3012, Columbus, OH 43210, +1 614 421-3600
+INET: swl26%cas.BITNET@CUNYVM.CUNY.Edu
diff --git a/Tools/android/flex-2.5.4a/MISC/MVS/MVS.todo b/Tools/android/flex-2.5.4a/MISC/MVS/MVS.todo
new file mode 100644
index 0000000..b6060ec
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/MVS/MVS.todo
@@ -0,0 +1,23 @@
+(Message inbox:47)
+Date: Wed, 18 Jul 1990 14:16 EDT
+From: swl26%CAS.BITNET@CORNELLC.cit.cornell.edu
+Subject: Re(2): Re(2): diffs for mvs port of flex-2.3
+To: vern@cs.cornell.edu
+
+
+
+>Thanks, I've successfully unpacked the archive. I may simply distribute
+>the diffs as a set of files in the MISC/ directory rather than incorporating
+>them into the 2.4 release. Let me know if you don't want me to do so.
+>
+> Vern
+
+
+Thank you! What you propose is okay. I might suggest, however, that you
+look in the diffs for dfa.c, misc.c, and yylex.c, and consider removing
+some of the ASCIIisms which are probably unnecessary. The manner in
+which I made the changes was pure brute force, and there might be a
+better way, but the changes I made there shouldn't hurt anything.
+
+ regards,
+ Steve
diff --git a/Tools/android/flex-2.5.4a/MISC/MVS/MVS.uudecode b/Tools/android/flex-2.5.4a/MISC/MVS/MVS.uudecode
new file mode 100644
index 0000000..2b8e802
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/MVS/MVS.uudecode
@@ -0,0 +1,341 @@
+Received: from CU-ARPA.CS.CORNELL.EDU by loki.cs.cornell.edu (5.61/I-1.91f)
+ id AA25874; Wed, 18 Jul 90 12:02:22 -0400
+Message-Id: <9007181320.AA24810@cu-arpa.cs.cornell.edu>
+Received: from CORNELLC.CIT.CORNELL.EDU by cu-arpa.cs.cornell.edu (5.61+2/1.91d)
+ id AA24810; Wed, 18 Jul 90 09:20:21 -0400
+Received: from CORNELLC by CORNELLC.cit.cornell.edu (IBM VM SMTP R1.2.1MX) with BSMTP id 6769; Wed, 18 Jul 90 09:18:46 EDT
+Received: from CAS.BITNET (MAILER) by CORNELLC (Mailer R2.05X) with BSMTP id
+ 5378; Wed, 18 Jul 90 09:18:38 EDT
+From: swl26%CAS.BITNET@CORNELLC.cit.cornell.edu
+Date: Wed, 18 Jul 1990 09:16 EDT
+Subject: Re(2): diffs for mvs port of flex-2.3
+In-Reply-To: Your message of Tue, 17 Jul 90 17:42:3
+To: vern@cs.cornell.edu
+
+Sorry about the trailing blank problem. It's farily common with data sent
+through bitnet paths, but ever the optimist ...
+
+>I think there should be an 'M' at the beginning of the second line.
+
+This isn't a problem. I believe that the first byte of the line indicates
+it's length (in some manner).
+
+Rather than re-send the data, how about a uudecode that compensates for
+the trailing blank problem? I manually mangled the uuencoded file and ran
+the following decode, and it seemed to work.
+
+#! /bin/sh
+# This is a shell archive. Remove anything before this line, then feed it
+# into a shell via "sh file" or similar. To overwrite existing files,
+# type "sh file -c".
+# The tool that generated this appeared in the comp.sources.unix newsgroup;
+# send mail to comp-sources-unix@uunet.uu.net if you want that tool.
+# If this archive is complete, you will see the following message at the end:
+# "End of shell archive."
+# Contents: uudecode.c
+# Wrapped by swl26@swl26aws on Wed Jul 18 08:59:24 1990
+PATH=/bin:/usr/bin:/usr/ucb ; export PATH
+if test -f 'uudecode.c' -a "${1}" != "-c" ; then
+ echo shar: Will not clobber existing file \"'uudecode.c'\"
+else
+echo shar: Extracting \"'uudecode.c'\" \(6418 characters\)
+sed "s/^X//" >'uudecode.c' <<'END_OF_FILE'
+X/* #ifndef lint
+Xstatic char sccsid[] = "@(#)uudecode.c 5.3-1 (Berkeley) 9/1/87";
+X#endif */
+X
+X/* Written by Mark Horton */
+X/* Modified by ajr (Alan J Rosenthatl,flaps@utcsri.UUCP) to use checksums */
+X/* Modified by fnf (Fred Fish,well!fnf) to use Keith Pyle's suggestion for
+X compatibility */
+X/* Modified by bcn (Bryce Nesbitt,ucbvax!cogsci!bryce) to fix a misleading
+X error message on the Amiga port, to fix a bug that prevented decoding
+X certain files, to work even if trailing spaces have been removed from a
+X file, to check the filesize (if present), to add some error checking, to
+X loop for multiple decodes from a single file, and to handle common
+X BITNET mangling. Also kludged around a missing string function in Aztec
+X C */
+X
+X/*
+X * uudecode [input]
+X *
+X * Decode a file encoded with uuencode. WIll extract multiple encoded
+X * modules from a single file. Can deal with most mangled files, including
+X * BITNET.
+X */
+X
+X#include <stdio.h>
+X#include <ctype.h>
+X
+X#ifdef AMIGA
+X#define AMIGA_LATTICE /* Set for Amiga Lattice C */
+X#define MCH_AMIGA
+X#define MPU68000
+X#endif
+X
+X#ifdef unix
+X#include <pwd.h>
+X#include <sys/types.h>
+X#include <sys/stat.h>
+X#endif
+X
+X#define SUMSIZE 64
+X#define DEC(c) (((c) - ' ') & 077) /* single character decode */
+X
+Xmain(argc, argv)
+Xchar **argv;
+X{
+XFILE *in, *out;
+Xint through_loop=0; /* Dejavu indicator */
+Xint mode; /* file's mode (from header) */
+Xlong filesize; /* theoretical file size (from header) */
+Xchar dest[128];
+Xchar buf[80];
+X
+X#ifdef AMIGA_LATTICE
+Xextern int Enable_Abort;
+X Enable_Abort=1;
+X#endif
+X
+X /* A filename can be specified to be uudecoded, or nothing can
+X be specified, and the input will come from STDIN */
+X
+X switch (argc)
+X {
+X case 1:
+X in=stdin;
+X break;
+X
+X case 2:
+X if ((in = fopen(argv[1], "r")) == NULL)
+X {
+X fprintf(stderr, "ERROR: can't find %s\n", argv[1]);
+X fprintf(stderr, "USAGE: uudecode [infile]\n");
+X exit(10);
+X }
+X break;
+X
+X default:
+X fprintf(stderr, "USAGE: uudecode [infile]\n");
+X exit(11);
+X break;
+X }
+X
+X /* Loop through file, searching for headers. Decode anything with a
+X header, complain if there where no headers. */
+X
+Xfor (;;)
+X{
+X /* search file for header line */
+X for (;;)
+X {
+X if (fgets(buf, sizeof buf, in) == NULL)
+X {
+X if (!through_loop)
+X {
+X fprintf(stderr, "ERROR: no `begin' line!\n");
+X exit(12);
+X }
+X else
+X {
+X exit(0);
+X }
+X }
+X if (strncmp(buf, "begin ", 6) == 0)
+X break;
+X }
+X sscanf(buf, "begin %o %s", &mode, dest);
+X
+X#ifdef unix
+X /* handle ~user/file format */
+X if (dest[0] == '~')
+X {
+X char *sl;
+X struct passwd *getpwnam();
+X char *index();
+X struct passwd *user;
+X char dnbuf[100];
+X
+X sl = index(dest, '/');
+X if (sl == NULL)
+X {
+X fprintf(stderr, "Illegal ~user\n");
+X exit(13);
+X }
+X *sl++ = 0;
+X user = getpwnam(dest+1);
+X if (user == NULL)
+X {
+X fprintf(stderr, "No such user as %s\n", dest);
+X exit(14);
+X }
+X strcpy(dnbuf, user->pw_dir);
+X strcat(dnbuf, "/");
+X strcat(dnbuf, sl);
+X strcpy(dest, dnbuf);
+X }
+X#endif
+X
+X /* create output file */
+X if ((out = fopen(dest, "w")) == NULL)
+X {
+X fprintf(stderr, "ERROR: can't open output file %s\n", dest);
+X exit(15);
+X }
+X#ifdef unix
+X chmod(dest, mode);
+X#endif
+X
+X decode(in, out, dest);
+X
+X if (fgets(buf, sizeof buf, in) == NULL || strncmp(buf,"end",3))
+X { /* don't be overly picky about newline ^ */
+X fprintf(stderr, "ERROR: no `end' line\n");
+X exit(16);
+X }
+X
+X if (!(fgets(buf,sizeof buf,in) == NULL || strncmp(buf,"size ",3)))
+X {
+X sscanf(buf, "size %ld", &filesize);
+X if (ftell(out) != filesize)
+X {
+X fprintf(stderr, "ERROR: file should have been %ld bytes long but was
+X exit(17);
+X }
+X }
+X through_loop = 1;
+X} /* forever */
+X} /* main */
+X
+X/*
+X * Copy from in to out, decoding as you go.
+X * If a return or newline is encountered too early in a line, it is
+X * assumed that means that some editor has truncated trailing spaces.
+X */
+Xdecode(in, out, dest)
+XFILE *in;
+XFILE *out;
+Xchar *dest;
+X{
+Xchar buf[81];
+Xchar *bp;
+Xint nosum=0;
+X#ifndef unix
+Xextern errno;
+X#endif
+Xregister int j;
+Xregister int n;
+Xint checksum, line;
+X
+X for (line = 1; ; line++) /* for each input line */
+X {
+X if (fgets(buf, sizeof buf, in) == NULL)
+X {
+X fprintf(stderr, "ERROR: input ended unexpectedly!\n");
+X exit(18);
+X }
+X
+X /* Pad end of lines in case some editor truncated trailing
+X spaces */
+X
+X for (n=0;n<79;n++) /* search for first \r, \n or \000 */
+X {
+X if (buf[n]=='\176') /* If BITNET made a twiddle, */
+X buf[n]='\136'; /* we make a caret */
+X if (buf[n]=='\r'||buf[n]=='\n'||buf[n]=='\000')
+X break;
+X }
+X for (;n<79;n++) /* when found, fill rest of line with space */
+X {
+X buf[n]=' ';
+X }
+X buf[79]=0; /* terminate new string */
+X
+X checksum = 0;
+X n = DEC(buf[0]);
+X if (n <= 0)
+X break; /* 0 bytes on a line?? Must be the last line */
+X
+X bp = &buf[1];
+X
+X /* FOUR input characters go into each THREE output charcters */
+X
+X while (n >= 4)
+X {
+X j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4; putc(j, out); checksum += j;
+X j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2; putc(j, out); checksum += j;
+X j = DEC(bp[2]) << 6 | DEC(bp[3]); putc(j, out); checksum += j;
+X checksum = checksum % SUMSIZE;
+X bp += 4;
+X n -= 3;
+X }
+X
+X j = DEC(bp[0]) << 2 | DEC(bp[1]) >> 4;
+X checksum += j;
+X if (n >= 1)
+X putc(j, out);
+X j = DEC(bp[1]) << 4 | DEC(bp[2]) >> 2;
+X checksum += j;
+X if (n >= 2)
+X putc(j, out);
+X j = DEC(bp[2]) << 6 | DEC(bp[3]);
+X checksum += j;
+X if (n >= 3)
+X putc(j, out);
+X checksum = checksum % SUMSIZE;
+X bp += 4;
+X n -= 3;
+X
+X#ifndef unix
+X /* Error checking under UNIX??? You must be kidding... */
+X /* Check if an error occured while writing to that last line */
+X if (errno)
+X {
+X fprintf(stderr, "ERROR: error writing to %s\n",dest);
+X exit(19);
+X }
+X#endif
+X
+X /* The line has been decoded; now check that sum */
+X
+X nosum |= !isspace(*bp);
+X if (nosum) /* Is there a checksum at all?? */
+X {
+X if (checksum != DEC(*bp)) /* Does that checksum match? */
+X {
+X fprintf(stderr, "ERROR: checksum mismatch decoding %s, line %d.\
+X }
+X } /* sum */
+X } /* line */
+X} /* function */
+X
+X#ifdef unix
+X/*
+X * Return the ptr in sp at which the character c appears;
+X * 0 if not found
+X */
+Xchar *
+Xindex(sp, c)
+Xregister char *sp, c;
+X{
+X do
+X {
+X if (*sp == c)
+X return(sp);
+X }
+X while (*sp++);
+X
+X return(0);
+X}
+X#endif unix
+X
+
+END_OF_FILE
+echo shar: NEWLINE appended to \"'uudecode.c'\"
+if test 6419 -ne `wc -c <'uudecode.c'`; then
+ echo shar: \"'uudecode.c'\" unpacked with wrong size!
+fi
+# end of 'uudecode.c'
+fi
+echo shar: End of shell archive.
+exit 0
diff --git a/Tools/android/flex-2.5.4a/MISC/MVS/README b/Tools/android/flex-2.5.4a/MISC/MVS/README
new file mode 100644
index 0000000..09741ab
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/MVS/README
@@ -0,0 +1,44 @@
+These patches and supplemental programs should allow porting to MVS or MVS/XA
+in an EBCDIC envrionment, using SAS C V4.00C.
+
+Included are:
+ -rw-r--r-- 1 swl26 1573 Jul 17 14:32 README
+ -rw-rw-r-- 1 swl26 20861 Jul 17 13:41 diffs
+ -rw-rw-r-- 1 swl26 5022 Jul 17 14:00 fixit.l
+ -rw-rw-r-- 1 swl26 97644 Jul 17 13:42 initscan.mvs.c
+ -rw-rw-r-- 1 swl26 4898 Jul 17 14:08 unfixit.l
+
+The file "diffs" contains context diffs for changes to flex 2.3.
+
+The file "fixit.l" contains flex sources for a program to shorten external
+variable and function names to 8 characters or less. This is required for the
+"dumb" compiler linker used.
+
+The file "unfixit.l" reverses the changes in "fixit.l", to restore long names.
+This is useful when trying to build diff files as created here.
+
+The file "initscan.mvs.c" is an already "flexed" version of scan.l, in an
+EBCDIC environment.
+
+To install in an MVS environment, use patch to apply the diffs to flex 2.3,
+then run "fixit" on all .c, .h, .l, .y, and .skel files. Move the files
+to the MVS machine, and compile each of the .c files. (You will need a
+"yacc" functional equivalent under MVS to expand parse.y in that
+environment.) Link together, and the resulting flex should be ready to
+go. To test, run the MVSflex -is8 -Ce on the scan.l, and you should get
+back a file which is identical to initscan.mvs.c.
+
+Enjoy.
+
+Steven W. Layten
+Senior Engineer
+Chemical Abstracts Service
+PO Box 3012
+2540 Olentangy River Road
+Columbus, Ohio 43210
+
++1 614 421 3600 extension 3451
+
+INET: swl26%cas.BITNET@CUNYVM.CUNY.Edu
+UUCP: osu-cis!chemabs!swl26
+BITNET: swl26@cas.bitnet
diff --git a/Tools/android/flex-2.5.4a/MISC/MVS/diffs b/Tools/android/flex-2.5.4a/MISC/MVS/diffs
new file mode 100644
index 0000000..98dfbdf
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/MVS/diffs
@@ -0,0 +1,854 @@
+diff -c ../Makefile ./Makefile
+*** ../Makefile Thu Jun 28 00:44:07 1990
+--- ./Makefile Mon Jul 16 13:57:26 1990
+***************
+*** 39,49 ****
+ # AUXDIR, manual pages will be installed in MANDIR with extension MANEXT.
+ # Raw, unformatted troff source will be installed if INSTALLMAN=man, nroff
+ # preformatted versions will be installed if INSTALLMAN=cat.
+! DESTDIR =
+ BINDIR = /usr/local
+ LIBDIR = /usr/local/lib
+ AUXDIR = /usr/local/lib
+ MANDIR = /usr/man/manl
+ MANEXT = l
+ INSTALLMAN = man
+
+--- 39,50 ----
+ # AUXDIR, manual pages will be installed in MANDIR with extension MANEXT.
+ # Raw, unformatted troff source will be installed if INSTALLMAN=man, nroff
+ # preformatted versions will be installed if INSTALLMAN=cat.
+! DESTDIR = /projects/m751stereo/code/c/swl26
+ BINDIR = /usr/local
+ LIBDIR = /usr/local/lib
+ AUXDIR = /usr/local/lib
+ MANDIR = /usr/man/manl
++ INCLUDEDIR = .
+ MANEXT = l
+ INSTALLMAN = man
+
+***************
+*** 52,58 ****
+
+ SKELETON_FILE = $(DESTDIR)$(AUXDIR)/flex.skel
+ SKELFLAGS = -DDEFAULT_SKELETON_FILE=\"$(SKELETON_FILE)\"
+! CFLAGS = -O
+ LDFLAGS = -s
+
+ COMPRESSION =
+--- 53,59 ----
+
+ SKELETON_FILE = $(DESTDIR)$(AUXDIR)/flex.skel
+ SKELFLAGS = -DDEFAULT_SKELETON_FILE=\"$(SKELETON_FILE)\"
+! CFLAGS = -O -DUSG -I$(INCLUDEDIR)
+ LDFLAGS = -s
+
+ COMPRESSION =
+diff -c ../ccl.c ./ccl.c
+*** ../ccl.c Thu Jun 28 00:44:07 1990
+--- ./ccl.c Mon Jul 16 13:57:27 1990
+***************
+*** 28,37 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/ccl.c,v 2.5 90/06/27 23:48:13 vern Exp $ (LBL)";
+ #endif
+
+! #include "flexdef.h"
+
+ /* ccladd - add a single character to a ccl
+ *
+--- 28,37 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: ccl.c,v 2.5 90/06/27 23:48:13 vern Exp $ (LBL)";
+ #endif
+
+! #include <flexdef.h>
+
+ /* ccladd - add a single character to a ccl
+ *
+diff -c ../dfa.c ./dfa.c
+*** ../dfa.c Thu Jun 28 00:44:08 1990
+--- ./dfa.c Mon Jul 16 13:57:28 1990
+***************
+*** 28,37 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/dfa.c,v 2.7 90/06/27 23:48:15 vern Exp $ (LBL)";
+ #endif
+
+! #include "flexdef.h"
+
+
+ /* declare functions that have forward references */
+--- 28,38 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: dfa.c,v 2.7 90/06/27 23:48:15 vern Exp $ (LBL)";
+ #endif
+
+! #include <flexdef.h>
+! #include <ctype.h>
+
+
+ /* declare functions that have forward references */
+***************
+*** 682,688 ****
+ register int j;
+
+ for ( i = 'A', j = 'a'; i <= 'Z'; ++i, ++j )
+! state[i] = state[j];
+ }
+
+ if ( ds > num_start_states )
+--- 683,692 ----
+ register int j;
+
+ for ( i = 'A', j = 'a'; i <= 'Z'; ++i, ++j )
+! {
+! if (isupper(i) )
+! state[i] = state[j];
+! }
+ }
+
+ if ( ds > num_start_states )
+***************
+*** 958,964 ****
+ }
+ }
+
+! else if ( sym >= 'A' && sym <= 'Z' && caseins )
+ flexfatal( "consistency check failed in symfollowset" );
+
+ else if ( sym == SYM_EPSILON )
+--- 962,968 ----
+ }
+ }
+
+! else if ( isupper ( sym ) && caseins )
+ flexfatal( "consistency check failed in symfollowset" );
+
+ else if ( sym == SYM_EPSILON )
+Only in .: diffs
+Only in .: diffs.new
+diff -c ../ecs.c ./ecs.c
+*** ../ecs.c Thu Jun 28 00:44:08 1990
+--- ./ecs.c Mon Jul 16 13:57:28 1990
+***************
+*** 28,37 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/ecs.c,v 2.5 90/06/27 23:48:17 vern Exp $ (LBL)";
+ #endif
+
+! #include "flexdef.h"
+
+ /* ccl2ecl - convert character classes to set of equivalence classes
+ *
+--- 28,37 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: ecs.c,v 2.5 90/06/27 23:48:17 vern Exp $ (LBL)";
+ #endif
+
+! #include <flexdef.h>
+
+ /* ccl2ecl - convert character classes to set of equivalence classes
+ *
+diff -c ../flex.skel ./flex.skel
+*** ../flex.skel Thu Jun 28 00:44:27 1990
+--- ./flex.skel Mon Jul 16 13:57:29 1990
+***************
+*** 1,7 ****
+ /* A lexical scanner generated by flex */
+
+ /* scanner skeleton version:
+! * $Header: /usr/fsys/odin/a/vern/flex/RCS/flex.skel,v 2.13 90/05/26 17:24:13 vern Exp $
+ */
+
+ #define FLEX_SCANNER
+--- 1,7 ----
+ /* A lexical scanner generated by flex */
+
+ /* scanner skeleton version:
+! * $Header: flex.skel,v 2.13 90/05/26 17:24:13 vern Exp $
+ */
+
+ #define FLEX_SCANNER
+diff -c ../flexdef.h ./flexdef.h
+*** ../flexdef.h Thu Jun 28 00:44:27 1990
+--- ./flexdef.h Mon Jul 16 13:57:30 1990
+***************
+*** 26,32 ****
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+! /* @(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/flexdef.h,v 2.7 90/06/27 23:48:19 vern Exp $ (LBL) */
+
+ #ifndef FILE
+ #include <stdio.h>
+--- 26,32 ----
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+! /* @(#) $Header: flexdef.h,v 2.7 90/06/27 23:48:19 vern Exp $ (LBL) */
+
+ #ifndef FILE
+ #include <stdio.h>
+***************
+*** 45,51 ****
+
+ /* size of input alphabet - should be size of ASCII set */
+ #ifndef DEFAULT_CSIZE
+! #define DEFAULT_CSIZE 128
+ #endif
+
+ #ifndef PROTO
+--- 45,51 ----
+
+ /* size of input alphabet - should be size of ASCII set */
+ #ifndef DEFAULT_CSIZE
+! #define DEFAULT_CSIZE 256
+ #endif
+
+ #ifndef PROTO
+***************
+*** 90,96 ****
+--- 90,98 ----
+ #define SHORT_FILE_NAMES
+ #endif
+
++ #ifndef OSVS
+ char *malloc(), *realloc();
++ #endif
+
+
+ /* maximum line length we'll have to deal with */
+***************
+*** 116,125 ****
+ #define true 1
+ #define false 0
+
+-
+ #ifndef DEFAULT_SKELETON_FILE
+ #define DEFAULT_SKELETON_FILE "flex.skel"
+! #endif
+
+ /* special chk[] values marking the slots taking by end-of-buffer and action
+ * numbers
+--- 118,132 ----
+ #define true 1
+ #define false 0
+
+ #ifndef DEFAULT_SKELETON_FILE
++ #ifdef OSVS
++ #define DEFAULT_SKELETON_FILE "ctri01"
++ #define SYSUT1 "sysut1"
++ #define SYSUT2 "sysut2"
++ #else
+ #define DEFAULT_SKELETON_FILE "flex.skel"
+! #endif /* OSVS */
+! #endif /* DEFAULT_SKELETON_FILE */
+
+ /* special chk[] values marking the slots taking by end-of-buffer and action
+ * numbers
+***************
+*** 226,233 ****
+ #define INITIAL_MAX_SCS 40 /* maximum number of start conditions */
+ #define MAX_SCS_INCREMENT 40 /* amount to bump by if it's not enough */
+
+! #define ONE_STACK_SIZE 500 /* stack of states with only one out-transition */
+! #define SAME_TRANS -1 /* transition is the same as "default" entry for state */
+
+ /* the following percentages are used to tune table compression:
+
+--- 233,240 ----
+ #define INITIAL_MAX_SCS 40 /* maximum number of start conditions */
+ #define MAX_SCS_INCREMENT 40 /* amount to bump by if it's not enough */
+
+! #define ONE_STACK_SIZE 500 /*stack of states with only one out-transition*/
+! #define SAME_TRANS -1 /*transition is the same as "default" entry for state */
+
+ /* the following percentages are used to tune table compression:
+
+diff -c ../gen.c ./gen.c
+*** ../gen.c Thu Jun 28 00:44:28 1990
+--- ./gen.c Mon Jul 16 13:57:32 1990
+***************
+*** 28,37 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/gen.c,v 2.9 90/06/27 23:48:22 vern Exp $ (LBL)";
+ #endif
+
+! #include "flexdef.h"
+
+
+ /* declare functions that have forward references */
+--- 28,37 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: gen.c,v 2.9 90/06/27 23:48:22 vern Exp $ (LBL)";
+ #endif
+
+! #include <flexdef.h>
+
+
+ /* declare functions that have forward references */
+***************
+*** 292,298 ****
+
+ indent_puts( "{" );
+
+! indent_puts( "if ( yy_lp && yy_lp < yy_accept[yy_current_state + 1] )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_act = yy_acclist[yy_lp];" );
+--- 292,298 ----
+
+ indent_puts( "{" );
+
+! indent_puts("if( yy_lp && yy_lp < yy_accept[yy_current_state + 1] )");
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_act = yy_acclist[yy_lp];" );
+diff -c ../initscan.c ./initscan.c
+*** ../initscan.c Thu Jun 28 00:44:51 1990
+--- ./initscan.c Mon Jul 16 13:57:33 1990
+***************
+*** 1,7 ****
+ /* A lexical scanner generated by flex */
+
+ /* scanner skeleton version:
+! * $Header: /usr/fsys/odin/a/vern/flex/RCS/flex.skel,v 2.13 90/05/26 17:24:13 vern Exp $
+ */
+
+ #define FLEX_SCANNER
+--- 1,7 ----
+ /* A lexical scanner generated by flex */
+
+ /* scanner skeleton version:
+! * $Header: flex.skel,v 2.13 90/05/26 17:24:13 vern Exp $
+ */
+
+ #define FLEX_SCANNER
+***************
+*** 193,199 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/scan.l,v 2.9 90/06/27 23:48:34 vern Exp $ (LBL)";
+ #endif
+
+ #undef yywrap
+--- 193,199 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: scan.l,v 2.9 90/06/27 23:48:34 vern Exp $ (LBL)";
+ #endif
+
+ #undef yywrap
+diff -c ../libmain.c ./libmain.c
+*** ../libmain.c Thu Jun 28 00:44:28 1990
+--- ./libmain.c Mon Jul 16 13:57:34 1990
+***************
+*** 1,6 ****
+ /* libmain - flex run-time support library "main" function */
+
+! /* $Header: /usr/fsys/odin/a/vern/flex/RCS/libmain.c,v 1.2 90/05/26 16:50:08 vern Exp $ */
+
+ extern int yylex();
+
+--- 1,6 ----
+ /* libmain - flex run-time support library "main" function */
+
+! /* $Header: libmain.c,v 1.2 90/05/26 16:50:08 vern Exp $ */
+
+ extern int yylex();
+
+diff -c ../main.c ./main.c
+*** ../main.c Thu Jun 28 00:44:29 1990
+--- ./main.c Mon Jul 16 13:57:34 1990
+***************
+*** 34,44 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/main.c,v 2.9 90/06/27 23:48:24 vern Exp $ (LBL)";
+ #endif
+
+
+! #include "flexdef.h"
+
+ static char flex_version[] = "2.3";
+
+--- 34,44 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: main.c,v 2.9 90/06/27 23:48:24 vern Exp $ (LBL)";
+ #endif
+
+
+! #include <flexdef.h>
+
+ static char flex_version[] = "2.3";
+
+***************
+*** 97,106 ****
+ char *program_name;
+
+ #ifndef SHORT_FILE_NAMES
+ static char *outfile = "lex.yy.c";
+! #else
+ static char *outfile = "lexyy.c";
+! #endif
+ static int outfile_created = 0;
+ static int use_stdout;
+ static char *skelname = NULL;
+--- 97,110 ----
+ char *program_name;
+
+ #ifndef SHORT_FILE_NAMES
++ #ifdef OSVS
++ static char *outfile = "ctro01";
++ #else /* not OSVS */
+ static char *outfile = "lex.yy.c";
+! #endif /* not OSVS */
+! #else /* SHORT_FILE_NAMES */
+ static char *outfile = "lexyy.c";
+! #endif /* SHORT_FILE_NAMES */
+ static int outfile_created = 0;
+ static int use_stdout;
+ static char *skelname = NULL;
+***************
+*** 209,216 ****
+--- 213,222 ----
+ else if ( fclose( temp_action_file ) )
+ flexfatal( "error occurred when closing temporary action file" );
+
++ #ifndef OSVS
+ else if ( unlink( action_file_name ) )
+ flexfatal( "error occurred when deleting temporary action file" );
++ #endif
+ }
+
+ if ( status != 0 && outfile_created )
+***************
+*** 221,228 ****
+--- 227,236 ----
+ else if ( fclose( stdout ) )
+ flexfatal( "error occurred when closing output file" );
+
++ #ifndef OSVS
+ else if ( unlink( outfile ) )
+ flexfatal( "error occurred when deleting output file" );
++ #endif
+ }
+
+ if ( backtrack_report && backtrack_file )
+***************
+*** 574,583 ****
+ if ( backtrack_report )
+ {
+ #ifndef SHORT_FILE_NAMES
+ backtrack_file = fopen( "lex.backtrack", "w" );
+! #else
+ backtrack_file = fopen( "lex.bck", "w" );
+! #endif
+
+ if ( backtrack_file == NULL )
+ flexerror( "could not create lex.backtrack" );
+--- 582,595 ----
+ if ( backtrack_report )
+ {
+ #ifndef SHORT_FILE_NAMES
++ #ifdef OSVS
++ backtrack_file = fopen( SYSUT2, "w");
++ #else /* not OSVS */
+ backtrack_file = fopen( "lex.backtrack", "w" );
+! #endif /* OSVS */
+! #else /* SHORT_FILE_NAMES */
+ backtrack_file = fopen( "lex.bck", "w" );
+! #endif /* SHORT_FILE_NAMES */
+
+ if ( backtrack_file == NULL )
+ flexerror( "could not create lex.backtrack" );
+***************
+*** 597,604 ****
+ lerrsf( "can't open skeleton file %s", skelname );
+
+ #ifdef SYS_V
+ action_file_name = tmpnam( NULL );
+! #endif
+
+ if ( action_file_name == NULL )
+ {
+--- 609,620 ----
+ lerrsf( "can't open skeleton file %s", skelname );
+
+ #ifdef SYS_V
++ #ifndef OSVS
+ action_file_name = tmpnam( NULL );
+! #else /* OSVS */
+! action_file_name = SYSUT1;
+! #endif /* OSVS */
+! #endif /* SYS_V */
+
+ if ( action_file_name == NULL )
+ {
+***************
+*** 609,615 ****
+--- 625,636 ----
+ #else
+ (void) strcpy( temp_action_file_name, "flexXXXXXX.tmp" );
+ #endif
++ #ifndef OSVS
+ (void) mktemp( temp_action_file_name );
++ #else /* OSVS */
++ /* should never be executed in OSVS as IF should always be false */
++ (void) strcpy( temp_action_file_name, SYSUT1 ) ;
++ #endif /* OSVS */
+
+ action_file_name = temp_action_file_name;
+ }
+diff -c ../misc.c ./misc.c
+*** ../misc.c Thu Jun 28 00:44:40 1990
+--- ./misc.c Mon Jul 16 13:57:35 1990
+***************
+*** 28,38 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/misc.c,v 2.7 90/06/27 23:48:27 vern Exp $ (LBL)";
+ #endif
+
+ #include <ctype.h>
+! #include "flexdef.h"
+
+
+ /* ANSI C does not guarantee that isascii() is defined */
+--- 28,38 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: misc.c,v 2.7 90/06/27 23:48:27 vern Exp $ (LBL)";
+ #endif
+
+ #include <ctype.h>
+! #include <flexdef.h>
+
+
+ /* ANSI C does not guarantee that isascii() is defined */
+***************
+*** 107,113 ****
+--- 107,117 ----
+ {
+ while ( *str )
+ {
++ #ifdef OSVS
++ if ( ! islower( *str ) )
++ #else
+ if ( ! isascii( *str ) || ! islower( *str ) )
++ #endif
+ return ( 0 );
+ ++str;
+ }
+***************
+*** 130,136 ****
+--- 134,144 ----
+ {
+ while ( *str )
+ {
++ #ifdef OSVS
++ if ( ! isupper( (char) *str ) )
++ #else
+ if ( ! isascii( *str ) || ! isupper( (char) *str ) )
++ #endif
+ return ( 0 );
+ ++str;
+ }
+***************
+*** 182,188 ****
+--- 190,200 ----
+ register int c;
+
+ {
++ #ifdef OSVS
++ return ( isupper( c ) ? (Char) tolower( c ) : (Char) c );
++ #else
+ return ( (isascii( c ) && isupper( c )) ? tolower( c ) : c );
++ #endif
+ }
+
+
+***************
+*** 204,210 ****
+ for ( c = str; *c; ++c )
+ ;
+
+! copy = malloc( (unsigned) ((c - str + 1) * sizeof( char )) );
+
+ if ( copy == NULL )
+ flexfatal( "dynamic memory failure in copy_string()" );
+--- 216,222 ----
+ for ( c = str; *c; ++c )
+ ;
+
+! copy = (char *) malloc( (unsigned) ((c - str + 1) * sizeof( char )) );
+
+ if ( copy == NULL )
+ flexfatal( "dynamic memory failure in copy_string()" );
+***************
+*** 392,403 ****
+--- 404,421 ----
+
+ #ifndef MS_DOS
+ #ifndef VMS
++ #ifndef OSVS
+ #include <sys/types.h>
++ #endif /* OSVS */
+ #else
+ #include <types.h>
+ #endif
+ #endif
+
++ #ifdef OSVS
++ #include <time.h>
++ #endif /* OSVS */
++
+ #ifdef MS_DOS
+ #include <time.h>
+ typedef long time_t;
+***************
+*** 615,621 ****
+--- 633,643 ----
+ if ( array[1] == 'x' )
+ ++sptr;
+
++ #ifdef OSVS
++ while ( isdigit( array[sptr] ) )
++ #else
+ while ( isascii( array[sptr] ) && isdigit( array[sptr] ) )
++ #endif
+ /* don't increment inside loop control because if
+ * isdigit() is a macro it will expand it to two
+ * increments ...
+Only in ..: new
+diff -c ../nfa.c ./nfa.c
+*** ../nfa.c Thu Jun 28 00:44:40 1990
+--- ./nfa.c Mon Jul 16 13:57:36 1990
+***************
+*** 28,37 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/nfa.c,v 2.6 90/06/27 23:48:29 vern Exp $ (LBL)";
+ #endif
+
+! #include "flexdef.h"
+
+
+ /* declare functions that have forward references */
+--- 28,37 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: nfa.c,v 2.6 90/06/27 23:48:29 vern Exp $ (LBL)";
+ #endif
+
+! #include <flexdef.h>
+
+
+ /* declare functions that have forward references */
+***************
+*** 110,116 ****
+ {
+ int sym, tsp1, tsp2, anum, ns;
+
+! fprintf( stderr, "\n\n********** beginning dump of nfa with start state %d\n",
+ state1 );
+
+ /* we probably should loop starting at firstst[state1] and going to
+--- 110,116 ----
+ {
+ int sym, tsp1, tsp2, anum, ns;
+
+! fprintf(stderr,"\n\n********* beginning dump of nfa with start state %d\n",
+ state1 );
+
+ /* we probably should loop starting at firstst[state1] and going to
+diff -c ../parse.y ./parse.y
+*** ../parse.y Thu Jun 28 00:44:40 1990
+--- ./parse.y Mon Jul 16 13:57:36 1990
+***************
+*** 32,45 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/parse.y,v 2.7 90/06/27 23:48:31 vern Exp $ (LBL)";
+ #endif
+
+! #include "flexdef.h"
+
+ int pat, scnum, eps, headcnt, trailcnt, anyccl, lastchar, i, actvp, rulelen;
+ int trlcontxt, xcluflg, cclsorted, varlength, variable_trail_rule;
+ Char clower();
+
+ static int madeany = false; /* whether we've made the '.' character class */
+ int previous_continued_action; /* whether the previous rule's action was '|' */
+--- 32,47 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: parse.y,v 2.7 90/06/27 23:48:31 vern Exp $ (LBL)";
+ #endif
+
+! #include <flexdef.h>
+
+ int pat, scnum, eps, headcnt, trailcnt, anyccl, lastchar, i, actvp, rulelen;
+ int trlcontxt, xcluflg, cclsorted, varlength, variable_trail_rule;
+ Char clower();
++ void build_eof_action();
++ void yyerror();
+
+ static int madeany = false; /* whether we've made the '.' character class */
+ int previous_continued_action; /* whether the previous rule's action was '|' */
+diff -c ../scan.l ./scan.l
+*** ../scan.l Thu Jun 28 00:44:41 1990
+--- ./scan.l Mon Jul 16 13:57:37 1990
+***************
+*** 30,42 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/scan.l,v 2.9 90/06/27 23:48:34 vern Exp $ (LBL)";
+ #endif
+
+ #undef yywrap
+
+! #include "flexdef.h"
+! #include "parse.h"
+
+ #define ACTION_ECHO fprintf( temp_action_file, "%s", yytext )
+ #define MARK_END_OF_PROLOG fprintf( temp_action_file, "%%%% end of prolog\n" );
+--- 30,42 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: scan.l,v 2.9 90/06/27 23:48:34 vern Exp $ (LBL)";
+ #endif
+
+ #undef yywrap
+
+! #include <flexdef.h>
+! #include <parse.h>
+
+ #define ACTION_ECHO fprintf( temp_action_file, "%s", yytext )
+ #define MARK_END_OF_PROLOG fprintf( temp_action_file, "%%%% end of prolog\n" );
+diff -c ../sym.c ./sym.c
+*** ../sym.c Thu Jun 28 00:44:41 1990
+--- ./sym.c Mon Jul 16 13:57:37 1990
+***************
+*** 28,37 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/sym.c,v 2.4 90/06/27 23:48:36 vern Exp $ (LBL)";
+ #endif
+
+! #include "flexdef.h"
+
+
+ /* declare functions that have forward references */
+--- 28,37 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: sym.c,v 2.4 90/06/27 23:48:36 vern Exp $ (LBL)";
+ #endif
+
+! #include <flexdef.h>
+
+
+ /* declare functions that have forward references */
+diff -c ../tblcmp.c ./tblcmp.c
+*** ../tblcmp.c Thu Jun 28 00:44:41 1990
+--- ./tblcmp.c Mon Jul 16 13:57:38 1990
+***************
+*** 28,37 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/tblcmp.c,v 2.5 90/06/27 23:48:38 vern Exp $ (LBL)";
+ #endif
+
+! #include "flexdef.h"
+
+
+ /* declarations for functions that have forward references */
+--- 28,37 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: tblcmp.c,v 2.5 90/06/27 23:48:38 vern Exp $ (LBL)";
+ #endif
+
+! #include <flexdef.h>
+
+
+ /* declarations for functions that have forward references */
+diff -c ../yylex.c ./yylex.c
+*** ../yylex.c Thu Jun 28 00:44:41 1990
+--- ./yylex.c Mon Jul 16 13:57:38 1990
+***************
+*** 28,39 ****
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/yylex.c,v 2.5 90/06/27 23:48:40 vern Exp $ (LBL)";
+ #endif
+
+ #include <ctype.h>
+! #include "flexdef.h"
+! #include "parse.h"
+
+
+ /* ANSI C does not guarantee that isascii() is defined */
+--- 28,39 ----
+
+ #ifndef lint
+ static char rcsid[] =
+! "@(#) $Header: yylex.c,v 2.5 90/06/27 23:48:40 vern Exp $ (LBL)";
+ #endif
+
+ #include <ctype.h>
+! #include <flexdef.h>
+! #include <parse.h>
+
+
+ /* ANSI C does not guarantee that isascii() is defined */
+***************
+*** 180,186 ****
+--- 180,190 ----
+ break;
+
+ default:
++ #ifdef OSVS
++ if ( ! isprint( yylval ) )
++ #else
+ if ( ! isascii( yylval ) || ! isprint( yylval ) )
++ #endif
+ fprintf( stderr, "\\%.3o", yylval );
+ else
+ (void) putc( yylval, stderr );
diff --git a/Tools/android/flex-2.5.4a/MISC/MVS/fixit.l b/Tools/android/flex-2.5.4a/MISC/MVS/fixit.l
new file mode 100644
index 0000000..3e15b6f
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/MVS/fixit.l
@@ -0,0 +1,138 @@
+%{
+/* fixit.l - convert long external names to names of 8-bytes or less */
+/*
+ * This program is included to satisfy "dumb" compilers/linkers which
+ * do not know about externals of names longer than 8 bytes.
+ *
+ * Steven W. Layten
+ * Chemical Abstracts Service
+ * PO BOX 3012
+ * Columbus, OH 43210
+ */
+%}
+%%
+"action_file_name" printf("actfilnm");
+"action_out" printf("actnout");
+"add_accept" printf("addacpt");
+"all_lower" printf("alllower");
+"all_upper" printf("allupper");
+"allocate_array" printf("allocarr");
+"assoc_rule" printf("asscrule");
+"backtrack_file" printf("bktrkfil");
+"backtrack_report" printf("bktrkrep");
+"bol_needed" printf("bol_nded");
+"build_eof_action" printf("bldeofac");
+"cclinstal" printf("cclnstal");
+"ccllookup" printf("ccllookp");
+"cclnegate" printf("cclnegat");
+"cclsorted" printf("cclsrted");
+"check_for_backtracking" printf("ck4bktrk");
+"check_trailing_context" printf("cktrlcnt");
+"continued_action" printf("cntdactn");
+"copy_string" printf("copystrn");
+"copy_unsigned_string" printf("cpunsstr");
+"copyright" printf("cpyrght");
+"copysingl" printf("copysngl");
+"current_max_ccl_tbl_size" printf("c_mx_ccl");
+"current_max_dfa_size" printf("c_mx_dfa");
+"current_max_dfas" printf("c_mxdfas");
+"current_max_rules" printf("curmxrls");
+"current_max_scs" printf("c_mx_scs");
+"current_max_template_xpairs" printf("c_mx_tmp");
+"current_max_xpairs" printf("c_mx_xpr");
+"current_maxccls" printf("c_mxccls");
+"current_mns" printf("curr_mns");
+"current_state_type" printf("cursttyp");
+"dataflush" printf("datflush");
+"dfaacc_union" printf("dfacunin");
+"do_indent" printf("do_indnt");
+"dump_associated_rules" printf("dmpasrl");
+"dump_transitions" printf("dmptrns");
+"dupmachine" printf("dupmach");
+"ecs_from_xlation" printf("ecsfrmxt");
+"end_of_buffer_state" printf("eobstate");
+"epsclosure" printf("epsclos");
+"expand_nxt_chk" printf("expnxtck");
+"find_table_space" printf("fndtblsp");
+"finish_rule" printf("fnshrule");
+"firstfree" printf("firstfre");
+"firstprot" printf("firstprt");
+"flex_gettime" printf("flxgettm");
+"flexerror" printf("flxerror");
+"flexfatal" printf("flxfatal");
+"format_pinpoint_message" printf("fmtptmsg");
+"gen_NUL_trans" printf("gnNULtrn");
+"gen_backtracking" printf("gnbktrkg");
+"gen_bt_action" printf("gnbtactn");
+"gen_find_action" printf("gnfndact");
+"gen_line_dirs" printf("gnlindir");
+"gen_next_compressed_state" printf("gnnxcste");
+"gen_next_match" printf("gnnxmtch");
+"gen_next_state" printf("gnnxtst");
+"gen_start_state" printf("gnstrtst");
+"hash_entry" printf("hshentry");
+"hashfunct" printf("hshfct");
+"increase_max_dfas" printf("incmxdfa");
+"indent_put2s" printf("indput2s");
+"indent_puts" printf("indputs");
+"infilename" printf("infilnam");
+"input_files" printf("inp_fles");
+"interactive" printf("intractv");
+"line_directive_out" printf("lndirout");
+"link_machines" printf("lnkmchns");
+"list_character_set" printf("lst_cset");
+"make_tables" printf("maketbls");
+"mark_beginning_as_normal" printf("mkbgnorm");
+"mktemplate" printf("mktmplat");
+"num_backtracking" printf("nbktrckg");
+"num_input_files" printf("ninfiles");
+"num_reallocs" printf("numraloc");
+"num_rules" printf("numrules");
+"num_xlations" printf("nuxlatns");
+"numsnpairs" printf("numnpair");
+"output_file_name" printf("outfilnm");
+"peakpairs" printf("peakpair");
+"performance_report" printf("perf_rep");
+"pinpoint_message" printf("pptmsg");
+"place_state" printf("plcstate");
+"previous_continued_action" printf("prvctdan");
+"printstats" printf("prtstats");
+"program_name" printf("pgm_name");
+"protcomst" printf("prtcomst");
+"readable_form" printf("rdblefrm");
+"real_reject" printf("realrjct");
+"reallocate_array" printf("rallocar");
+"reject_really_used" printf("rjctused");
+"rule_linenum" printf("rulelnno");
+"rule_type" printf("ruletype");
+"set_input_file" printf("stinpfle");
+"set_up_initial_allocations" printf("setupia");
+"starttime" printf("startime");
+"state_type" printf("ste_type");
+"symfollowset" printf("symfollo");
+"sympartition" printf("sympartn");
+"syntaxerror" printf("syntxerr");
+"temp_action_file" printf("tmpactfl");
+"todo_head" printf("todohead");
+"todo_next" printf("todonext");
+"transchar" printf("trnschar");
+"transition_struct_out" printf("trnstout");
+"trlcontxt" printf("trlcntxt");
+"variable_trail_rule" printf("vtrailrl");
+"variable_trailing_context_rules" printf("vtrlctrl");
+"varlength" printf("varlngth");
+"yy_create_buffer" printf("yycrbffr");
+"yy_delete_buffer" printf("yydlbffr");
+"yy_init_buffer" printf("yyinbffr");
+"yy_load_buffer_state" printf("yyldbfst");
+"yy_switch_to_buffer" printf("yyswtobf");
+"yyerrflag" printf("yyerrflg");
+"yymore_really_used" printf("yymrreus");
+"yymore_used" printf("yymrused");
+"yyrestart" printf("yyrestrt");
+. ECHO;
+%%
+main()
+{
+ yylex();
+}
diff --git a/Tools/android/flex-2.5.4a/MISC/MVS/initscan-mvs.c b/Tools/android/flex-2.5.4a/MISC/MVS/initscan-mvs.c
new file mode 100644
index 0000000..93c8591
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/MVS/initscan-mvs.c
@@ -0,0 +1,2672 @@
+/* A lexical scanner generated by flex */
+
+/* scanner skeleton version:
+ * $Header: flex.skel,v 2.13 90/05/26 17:24:13 ve
+ */
+
+#define FLEX_SCANNER
+
+#include <stdio.h>
+
+#ifdef __STDC__
+
+#ifndef DONT_HAVE_STDLIB_H
+#include <stdlib.h>
+#else
+void *malloc( unsigned );
+void free( void* );
+#endif
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+#endif
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#ifndef __STDC__
+#include <stdlib.h>
+#endif
+
+#include <osfcn.h>
+
+/* use prototypes in function declarations */
+#define YY_USE_PROTOS
+
+/* the "const" storage-class-modifier is valid */
+#define YY_USE_CONST
+
+#endif
+
+
+#ifdef __TURBOC__
+#define YY_USE_CONST
+#endif
+
+
+#ifndef YY_USE_CONST
+#define const
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+/* there's no standard place to get these definitions */
+char *malloc();
+int free();
+int read();
+#endif
+
+
+/* amount of stuff to slurp up with each read */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* returned upon end-of-file */
+#define YY_END_TOK 0
+
+/* copy whatever the last rule matched to the standard output */
+
+/* cast to (char *) is because for 8-bit chars, yytext is (unsigned char *) */
+/* this used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite()
+ */
+#define ECHO (void) fwrite( (char *) yytext, yyleng, 1, yyout )
+
+/* gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#define YY_INPUT(buf,result,max_size) \
+ if ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \
+ YY_FATAL_ERROR( "read() in flex scanner failed" );
+#define YY_NULL 0
+
+/* no semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#define yyterminate() return ( YY_NULL )
+
+/* report a fatal error */
+
+/* The funky do-while is used to turn this macro definition into
+ * a single C statement (which needs a semi-colon terminator).
+ * This avoids problems with code like:
+ *
+ * if ( something_happens )
+ * YY_FATAL_ERROR( "oops, the something happened" );
+ * else
+ * everything_okay();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the YY_FATAL_ERROR() call.
+ */
+
+#define YY_FATAL_ERROR(msg) \
+ do \
+ { \
+ (void) fputs( msg, stderr ); \
+ (void) putc( '\n', stderr ); \
+ exit( 1 ); \
+ } \
+ while ( 0 )
+
+/* default yywrap function - always treat EOF as an EOF */
+#define yywrap() 1
+
+/* enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* action number for EOF rule of a given start state */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* special action meaning "start processing a new file" */
+#define YY_NEW_FILE \
+ do \
+ { \
+ yyinbffr( yy_current_buffer, yyin ); \
+ yyldbfst(); \
+ } \
+ while ( 0 )
+
+/* default declaration of generated scanner - a define so the user can
+ * easily add parameters
+ */
+#define YY_DECL int yylex YY_PROTO(( void ))
+
+/* code executed at the end of each rule */
+#define YY_BREAK break;
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+#ifndef YY_BUF_SIZE
+#define YY_BUF_SIZE (YY_READ_BUF_SIZE * 2) /* size of default input buffer */
+#endif
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+#define YY_CHAR unsigned char
+# line 1 "<stdin>"
+#define INITIAL 0
+/* scan.l - scanner for flex input */
+# line 5 "<stdin>"
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+static char rcsid[] =
+ "@(#) $Header: scan.l,v 2.9 90/06/27 23:48:34 vern Exp $ (LBL)";
+#endif
+
+#undef yywrap
+
+#include <flexdef.h>
+#include <parse.h>
+
+#define ACTION_ECHO fprintf( tmpactfl, "%s", yytext )
+#define MARK_END_OF_PROLOG fprintf( tmpactfl, "%%%% end of prolog\n" );
+
+#undef YY_DECL
+#define YY_DECL \
+ int flexscan()
+
+#define RETURNCHAR \
+ yylval = yytext[0]; \
+ return ( CHAR );
+
+#define RETURNNAME \
+ (void) strcpy( nmstr, (char *) yytext ); \
+ return ( NAME );
+
+#define PUT_BACK_STRING(str, start) \
+ for ( i = strlen( (char *) (str) ) - 1; i >= start; --i ) \
+ unput((str)[i])
+
+#define CHECK_REJECT(str) \
+ if ( allupper( str ) ) \
+ reject = true;
+
+#define CHECK_YYMORE(str) \
+ if ( alllower( str ) ) \
+ yymrused = true;
+#define SECT2 1
+#define SECT2PROLOG 2
+#define SECT3 3
+#define CODEBLOCK 4
+#define PICKUPDEF 5
+#define SC 6
+#define CARETISBOL 7
+#define NUM 8
+#define QUOTE 9
+#define FIRSTCCL 10
+#define CCL 11
+#define ACTION 12
+#define RECOVER 13
+#define BRACEERROR 14
+#define C_COMMENT 15
+#define ACTION_COMMENT 16
+#define ACTION_STRING 17
+#define PERCENT_BRACE_ACTION 18
+#define USED_LIST 19
+#define CODEBLOCK_2 20
+#define XLATION 21
+# line 84 "<stdin>"
+
+/* done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext = yy_bp; \
+ yyleng = yy_cp - yy_bp; \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* return all but the first 'n' matched characters back to the input stream */
+#define yyless(n) \
+ do \
+ { \
+ /* undo effects of setting up yytext */ \
+ *yy_cp = yy_hold_char; \
+ yy_c_buf_p = yy_cp = yy_bp + n; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext )
+
+
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ YY_CHAR *yy_ch_buf; /* input buffer */
+ YY_CHAR *yy_buf_pos; /* current position in input buffer */
+
+ /* size of input buffer in bytes, not including room for EOB characters*/
+ int yy_buf_size;
+
+ /* number of characters read into yy_ch_buf, not including EOB characters */
+ int yy_n_chars;
+
+ int yy_eof_status; /* whether we've seen an EOF on this buffer */
+#define EOF_NOT_SEEN 0
+ /* "pending" happens when the EOF has been seen but there's still
+ * some text process
+ */
+#define EOF_PENDING 1
+#define EOF_DONE 2
+ };
+
+static YY_BUFFER_STATE yy_current_buffer;
+
+/* we provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state"
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed */
+static YY_CHAR yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+#ifndef YY_USER_INIT
+#define YY_USER_INIT
+#endif
+
+extern YY_CHAR *yytext;
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+YY_CHAR *yytext;
+int yyleng;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+#define YY_END_OF_BUFFER 121
+typedef int yy_ste_type;
+static const short int yy_accept[341] =
+ { 0,
+ 0, 0, 0, 0, 0, 0, 119, 119, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 121, 19, 7, 18, 19, 16,
+ 1, 17, 19, 19, 15, 19, 67, 59, 60, 66,
+ 51, 67, 53, 67, 67, 67, 50, 49, 52, 67,
+ 120, 47, 119, 119, 28, 29, 28, 28, 28, 28,
+ 31, 30, 32, 73, 120, 69, 72, 70, 74, 88,
+ 89, 86, 87, 85, 75, 77, 76, 75, 81, 81,
+
+ 80, 81, 83, 83, 84, 83, 99, 104, 105, 100,
+ 105, 103, 100, 100, 97, 98, 120, 33, 91, 90,
+ 22, 24, 23, 107, 109, 108, 111, 113, 114, 115,
+ 95, 95, 96, 95, 95, 95, 95, 38, 35, 34,
+ 38, 38, 44, 42, 45, 44, 44, 41, 41, 41,
+ 41, 40, 7, 18, 0, 16, 1, 17, 3, 14,
+ 8, 0, 12, 4, 0, 0, 5, 0, 15, 0,
+ 2, 59, 60, 0, 0, 0, 56, 0, 0, 55,
+ 55, 54, 117, 117, 117, 50, 49, 63, 50, 0,
+ 47, 46, 119, 119, 28, 28, 28, 28, 28, 31,
+
+ 30, 72, 71, 85, 78, 79, 118, 118, 118, 82,
+ 99, 101, 100, 0, 102, 0, 100, 100, 0, 33,
+ 22, 20, 107, 106, 111, 112, 95, 95, 95, 92,
+ 95, 95, 95, 38, 35, 38, 38, 42, 0, 43,
+ 43, 43, 42, 40, 0, 13, 14, 8, 8, 0,
+ 12, 4, 0, 0, 0, 5, 0, 6, 0, 58,
+ 57, 0, 64, 0, 0, 55, 55, 65, 117, 117,
+ 63, 28, 28, 28, 25, 0, 118, 118, 100, 100,
+ 0, 21, 92, 92, 95, 95, 38, 38, 0, 39,
+ 43, 43, 0, 11, 4, 0, 11, 0, 0, 5,
+
+ 0, 0, 0, 117, 28, 28, 118, 100, 100, 95,
+ 95, 38, 38, 43, 0, 9, 0, 0, 0, 28,
+ 28, 100, 100, 95, 95, 38, 38, 0, 0, 26,
+ 27, 93, 94, 93, 94, 36, 37, 10, 62, 0
+ } ;
+
+static const YY_CHAR yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 2, 1, 1, 1, 1, 1,
+ 1, 3, 1, 1, 1, 1, 1, 1, 1, 1,
+ 4, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 5, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 6, 7, 6, 6, 8, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 9, 10, 6, 1, 11, 12, 13, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 14, 15, 16, 17,
+ 6, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 18, 1, 19, 1, 20, 1, 21, 22,
+ 23, 24, 25, 26, 16, 16, 16, 16, 16, 16,
+ 16, 16, 16, 16, 27, 28, 16, 29, 30, 31,
+ 28, 16, 32, 16, 16, 16, 16, 16, 16, 16,
+ 16, 33, 34, 35, 16, 16, 36, 37, 16, 1,
+ 1, 1, 38, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 39, 1,
+ 1, 40, 21, 22, 23, 24, 25, 26, 16, 16,
+
+ 16, 1, 1, 1, 1, 1, 1, 41, 27, 28,
+ 16, 29, 30, 31, 28, 16, 32, 1, 1, 1,
+ 1, 1, 1, 42, 1, 33, 34, 35, 16, 16,
+ 36, 37, 16, 1, 1, 1, 1, 1, 1, 43,
+ 43, 43, 43, 43, 43, 43, 43, 43, 43, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static const short int yy_base[404] =
+ { 0,
+ 0, 43, 85, 126, 1573, 1572, 1571, 1570, 168, 1558,
+ 97, 104, 211, 0, 1544, 1543, 99, 106, 118, 251,
+ 252, 254, 112, 114, 296, 0, 1549, 1548, 107, 111,
+ 140, 151, 153, 155, 253, 336, 378, 0, 339, 420,
+ 0, 0, 424, 465, 1550, 3243, 257, 3243, 1515, 0,
+ 265, 3243, 1538, 494, 0, 1540, 3243, 272, 3243, 3243,
+ 1495, 277, 3243, 1459, 534, 61, 343, 3243, 3243, 81,
+ 1496, 0, 1495, 3243, 0, 3243, 0, 1473, 1443, 1438,
+ 0, 281, 3243, 3243, 3243, 3243, 0, 1467, 3243, 3243,
+ 3243, 3243, 3243, 1434, 3243, 3243, 3243, 76, 3243, 1463,
+
+ 3243, 242, 3243, 0, 3243, 314, 0, 3243, 1464, 0,
+ 330, 3243, 1448, 745, 3243, 3243, 777, 3243, 3243, 3243,
+ 0, 3243, 767, 0, 3243, 766, 0, 3243, 3243, 0,
+ 0, 350, 3243, 737, 0, 752, 739, 0, 286, 3243,
+ 750, 737, 3243, 357, 3243, 739, 318, 3243, 428, 738,
+ 327, 728, 364, 3243, 432, 0, 438, 3243, 3243, 372,
+ 442, 765, 446, 0, 451, 84, 0, 765, 0, 764,
+ 3243, 457, 3243, 763, 718, 732, 3243, 434, 438, 0,
+ 566, 3243, 3243, 0, 712, 480, 3243, 0, 3243, 750,
+ 0, 3243, 749, 3243, 0, 0, 725, 722, 609, 0,
+
+ 484, 0, 3243, 707, 3243, 3243, 3243, 0, 706, 3243,
+ 0, 3243, 0, 456, 3243, 0, 721, 718, 742, 3243,
+ 0, 741, 0, 3243, 0, 3243, 0, 488, 703, 652,
+ 0, 709, 706, 0, 494, 707, 704, 499, 508, 3243,
+ 0, 689, 694, 688, 581, 3243, 518, 0, 603, 725,
+ 698, 0, 702, 693, 697, 0, 706, 3243, 705, 3243,
+ 3243, 671, 3243, 717, 669, 0, 0, 3243, 0, 655,
+ 0, 631, 573, 0, 3243, 577, 0, 537, 554, 507,
+ 529, 3243, 0, 0, 507, 500, 493, 485, 711, 3243,
+ 0, 471, 502, 3243, 0, 715, 3243, 472, 476, 0,
+
+ 468, 740, 682, 3243, 469, 447, 3243, 455, 432, 440,
+ 426, 427, 414, 3243, 413, 3243, 415, 684, 688, 339,
+ 339, 258, 265, 238, 142, 128, 133, 121, 126, 0,
+ 0, 0, 0, 0, 0, 0, 0, 3243, 3243, 3243,
+ 783, 826, 869, 912, 955, 998, 1041, 1084, 1127, 1170,
+ 1213, 1256, 1299, 1342, 1385, 1428, 1460, 1503, 1535, 1578,
+ 1621, 1664, 1707, 1750, 1793, 1836, 1868, 1911, 1943, 1986,
+ 2029, 2072, 2115, 2147, 2190, 2233, 2276, 2319, 2362, 2405,
+ 2448, 2480, 2523, 2566, 2609, 2637, 2659, 2696, 2739, 2782,
+ 2805, 2848, 2871, 2914, 2937, 2980, 3012, 3044, 3067, 3110,
+
+ 3133, 3176, 3199
+ } ;
+
+static const short int yy_def[404] =
+ { 0,
+ 340, 340, 341, 341, 342, 342, 343, 343, 340, 9,
+ 344, 344, 340, 13, 345, 345, 346, 346, 347, 347,
+ 348, 348, 349, 349, 340, 25, 350, 350, 345, 345,
+ 351, 351, 352, 352, 353, 353, 340, 37, 354, 354,
+ 37, 37, 355, 356, 340, 340, 340, 340, 340, 357,
+ 340, 340, 340, 358, 359, 360, 340, 340, 340, 340,
+ 340, 340, 340, 361, 340, 362, 340, 340, 340, 340,
+ 363, 364, 365, 340, 366, 340, 367, 367, 367, 366,
+ 368, 340, 340, 340, 340, 340, 369, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 362, 340, 370,
+
+ 340, 371, 340, 372, 340, 362, 373, 340, 340, 374,
+ 375, 340, 374, 374, 340, 340, 376, 340, 340, 340,
+ 377, 340, 340, 378, 340, 340, 379, 340, 340, 380,
+ 381, 381, 340, 381, 382, 382, 382, 383, 340, 340,
+ 383, 383, 340, 340, 340, 340, 384, 340, 340, 340,
+ 384, 340, 340, 340, 340, 357, 340, 340, 340, 340,
+ 385, 340, 340, 386, 340, 340, 387, 388, 359, 360,
+ 340, 340, 340, 389, 340, 340, 340, 361, 361, 390,
+ 390, 340, 340, 391, 340, 340, 340, 392, 340, 363,
+ 364, 340, 365, 340, 366, 367, 367, 367, 340, 368,
+
+ 340, 369, 340, 340, 340, 340, 340, 393, 340, 340,
+ 373, 340, 374, 375, 340, 375, 374, 374, 376, 340,
+ 377, 394, 378, 340, 379, 340, 381, 381, 381, 340,
+ 382, 382, 382, 383, 340, 383, 383, 340, 340, 340,
+ 395, 340, 340, 340, 340, 340, 340, 385, 385, 396,
+ 340, 397, 396, 340, 340, 398, 388, 340, 389, 340,
+ 340, 340, 340, 361, 361, 390, 181, 340, 399, 340,
+ 392, 367, 367, 199, 340, 400, 401, 340, 374, 374,
+ 394, 340, 230, 402, 382, 382, 383, 383, 340, 340,
+ 403, 340, 396, 340, 397, 396, 340, 340, 340, 398,
+
+ 340, 264, 361, 340, 367, 367, 340, 374, 374, 382,
+ 382, 383, 383, 340, 340, 340, 340, 361, 361, 367,
+ 367, 374, 374, 382, 382, 383, 383, 340, 340, 367,
+ 367, 374, 374, 382, 382, 383, 383, 340, 340, 0,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+
+ 340, 340, 340
+ } ;
+
+static const short int yy_nxt[3287] =
+ { 0,
+ 46, 47, 47, 48, 47, 46, 46, 46, 46, 46,
+ 46, 46, 46, 46, 49, 50, 46, 46, 46, 46,
+ 50, 50, 50, 50, 50, 50, 50, 50, 50, 50,
+ 50, 50, 50, 50, 50, 50, 50, 46, 46, 46,
+ 46, 46, 46, 46, 51, 51, 52, 51, 46, 46,
+ 46, 46, 46, 46, 46, 53, 46, 54, 55, 46,
+ 56, 46, 46, 55, 55, 55, 55, 55, 55, 55,
+ 55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
+ 46, 46, 46, 46, 46, 46, 58, 58, 59, 58,
+ 60, 61, 60, 62, 60, 188, 184, 60, 82, 82,
+
+ 83, 82, 91, 185, 63, 82, 82, 83, 82, 91,
+ 119, 184, 92, 254, 119, 85, 255, 85, 185, 92,
+ 189, 96, 64, 104, 65, 104, 66, 67, 67, 68,
+ 67, 60, 61, 60, 62, 60, 69, 97, 60, 93,
+ 70, 94, 339, 122, 338, 63, 93, 120, 94, 123,
+ 105, 120, 105, 106, 122, 106, 125, 337, 125, 98,
+ 123, 336, 126, 64, 126, 65, 335, 66, 75, 75,
+ 75, 76, 75, 75, 75, 75, 75, 75, 75, 75,
+ 75, 75, 75, 77, 75, 75, 75, 75, 77, 77,
+ 77, 77, 77, 77, 77, 77, 77, 77, 77, 78,
+
+ 77, 77, 77, 77, 79, 75, 75, 75, 75, 75,
+ 75, 84, 84, 84, 85, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 86, 84, 87, 88, 84, 84,
+ 84, 87, 87, 87, 87, 87, 87, 87, 87, 87,
+ 87, 87, 87, 87, 87, 87, 87, 87, 84, 84,
+ 84, 84, 84, 84, 96, 85, 128, 85, 153, 153,
+ 154, 153, 100, 101, 100, 101, 157, 157, 158, 157,
+ 97, 334, 129, 172, 172, 173, 172, 208, 177, 174,
+ 177, 177, 201, 201, 209, 201, 175, 235, 235, 333,
+ 235, 332, 98, 102, 130, 102, 107, 107, 107, 108,
+
+ 107, 107, 107, 107, 107, 107, 107, 107, 109, 107,
+ 107, 110, 107, 107, 111, 112, 110, 110, 110, 110,
+ 110, 110, 110, 110, 110, 110, 110, 113, 110, 110,
+ 110, 110, 114, 107, 107, 115, 116, 107, 107, 128,
+ 139, 139, 140, 139, 186, 186, 187, 186, 215, 184,
+ 174, 228, 228, 241, 228, 129, 185, 175, 238, 238,
+ 242, 238, 241, 331, 229, 153, 153, 154, 153, 242,
+ 141, 216, 330, 247, 247, 142, 247, 130, 131, 132,
+ 132, 133, 132, 131, 131, 131, 131, 131, 131, 131,
+ 131, 131, 134, 135, 131, 131, 131, 131, 135, 135,
+
+ 135, 135, 135, 135, 135, 135, 135, 135, 135, 136,
+ 135, 135, 135, 135, 137, 131, 131, 131, 131, 131,
+ 131, 139, 139, 140, 139, 144, 144, 145, 144, 243,
+ 243, 329, 243, 245, 245, 246, 245, 328, 146, 157,
+ 157, 158, 157, 249, 249, 327, 249, 251, 251, 326,
+ 251, 141, 245, 245, 246, 253, 142, 325, 172, 172,
+ 173, 172, 324, 323, 174, 147, 149, 149, 145, 149,
+ 244, 175, 263, 264, 215, 179, 178, 322, 321, 150,
+ 265, 186, 186, 187, 186, 201, 201, 174, 201, 228,
+ 228, 320, 228, 317, 175, 235, 235, 216, 235, 316,
+
+ 238, 238, 229, 238, 315, 294, 151, 152, 161, 289,
+ 289, 290, 289, 240, 162, 313, 163, 312, 162, 247,
+ 247, 162, 247, 162, 162, 163, 164, 165, 166, 167,
+ 311, 310, 282, 168, 180, 180, 180, 309, 180, 180,
+ 180, 180, 180, 180, 180, 180, 180, 180, 180, 181,
+ 180, 180, 180, 180, 181, 181, 181, 181, 181, 181,
+ 181, 181, 181, 181, 181, 181, 181, 181, 181, 181,
+ 181, 180, 180, 180, 180, 180, 182, 267, 308, 207,
+ 275, 267, 245, 245, 246, 245, 267, 267, 267, 267,
+ 267, 267, 267, 267, 267, 267, 267, 267, 267, 267,
+
+ 267, 267, 267, 306, 249, 249, 268, 249, 267, 274,
+ 274, 274, 275, 274, 274, 274, 274, 274, 274, 274,
+ 274, 274, 274, 274, 276, 274, 274, 274, 274, 276,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
+ 276, 276, 276, 276, 276, 276, 274, 274, 274, 274,
+ 274, 274, 283, 283, 283, 305, 283, 283, 283, 283,
+ 283, 283, 283, 283, 283, 283, 283, 284, 283, 283,
+ 283, 283, 284, 284, 284, 284, 284, 284, 284, 284,
+ 284, 284, 284, 284, 284, 284, 284, 284, 284, 283,
+ 283, 283, 283, 283, 283, 243, 243, 183, 243, 251,
+
+ 251, 301, 251, 296, 296, 297, 296, 263, 260, 258,
+ 179, 303, 289, 289, 290, 289, 296, 296, 297, 296,
+ 263, 299, 263, 179, 319, 179, 263, 298, 294, 179,
+ 244, 292, 288, 287, 286, 285, 244, 302, 302, 302,
+ 302, 302, 302, 230, 282, 220, 280, 279, 278, 204,
+ 273, 272, 194, 191, 270, 263, 262, 261, 179, 302,
+ 318, 318, 318, 318, 318, 318, 260, 171, 258, 250,
+ 244, 239, 239, 237, 236, 233, 232, 230, 224, 222,
+ 220, 218, 318, 57, 57, 57, 57, 57, 57, 57,
+ 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+
+ 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+ 57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
+ 57, 57, 57, 57, 57, 57, 71, 71, 71, 71,
+ 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+ 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+ 71, 71, 71, 71, 71, 71, 71, 71, 71, 71,
+ 71, 71, 71, 71, 71, 71, 71, 71, 71, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 85, 85, 85, 85, 85,
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85,
+ 85, 85, 85, 85, 85, 85, 85, 85, 90, 90,
+
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 90, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 103, 103, 103, 103, 103, 103, 103, 103, 103, 103,
+ 117, 117, 117, 117, 117, 117, 117, 117, 117, 117,
+ 117, 117, 117, 117, 117, 117, 117, 117, 117, 117,
+ 117, 117, 117, 117, 117, 117, 117, 117, 117, 117,
+
+ 117, 117, 117, 117, 117, 117, 117, 117, 117, 117,
+ 117, 117, 117, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 121, 121, 121, 121, 121, 121, 124, 124, 124, 124,
+ 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+ 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+ 124, 124, 124, 124, 124, 124, 124, 124, 124, 124,
+ 124, 124, 124, 124, 124, 124, 124, 124, 124, 127,
+
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 127, 127, 127, 127, 127, 127, 127, 127,
+ 127, 127, 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 138, 138, 138, 138, 138,
+ 138, 138, 138, 138, 138, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 143, 143,
+ 143, 143, 143, 143, 143, 143, 143, 143, 148, 148,
+ 148, 148, 148, 148, 148, 148, 148, 148, 148, 148,
+ 148, 148, 148, 148, 148, 148, 148, 148, 148, 148,
+ 148, 148, 148, 148, 148, 148, 148, 148, 148, 148,
+ 148, 148, 148, 148, 148, 148, 148, 148, 148, 148,
+ 148, 156, 217, 212, 206, 156, 204, 203, 199, 198,
+ 156, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+ 156, 156, 156, 156, 156, 156, 156, 197, 194, 191,
+
+ 179, 176, 156, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 160, 160, 160, 160, 160, 160, 160,
+ 160, 160, 160, 171, 160, 160, 169, 159, 155, 340,
+ 169, 118, 118, 89, 89, 169, 169, 169, 169, 169,
+ 169, 169, 169, 169, 169, 169, 169, 169, 169, 169,
+ 169, 169, 80, 74, 74, 72, 72, 169, 170, 170,
+ 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
+ 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
+
+ 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
+ 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
+ 170, 178, 178, 178, 340, 178, 178, 178, 178, 178,
+ 178, 178, 178, 178, 178, 178, 178, 178, 178, 178,
+ 178, 178, 178, 178, 178, 178, 178, 178, 178, 178,
+ 178, 178, 178, 178, 178, 178, 178, 178, 178, 340,
+ 178, 178, 178, 178, 183, 183, 183, 340, 183, 183,
+ 183, 183, 183, 183, 183, 183, 183, 183, 183, 183,
+ 183, 183, 183, 183, 183, 183, 183, 183, 183, 183,
+ 183, 183, 183, 183, 183, 183, 183, 183, 183, 183,
+
+ 183, 183, 183, 183, 183, 183, 183, 190, 190, 190,
+ 190, 190, 190, 190, 190, 190, 190, 190, 190, 190,
+ 190, 190, 190, 190, 190, 190, 190, 190, 190, 190,
+ 190, 190, 190, 190, 190, 190, 190, 190, 190, 190,
+ 190, 190, 190, 190, 190, 190, 190, 190, 190, 190,
+ 192, 340, 340, 340, 340, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 192, 192, 192, 192, 192, 192, 192,
+ 192, 192, 192, 193, 193, 193, 193, 193, 193, 193,
+
+ 193, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+ 193, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+ 193, 193, 193, 193, 193, 193, 193, 193, 193, 193,
+ 193, 193, 193, 193, 193, 193, 195, 195, 195, 340,
+ 195, 195, 195, 195, 195, 195, 195, 195, 195, 195,
+ 195, 340, 195, 195, 195, 195, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 195, 195, 195, 195, 195, 195, 196,
+ 340, 340, 340, 196, 340, 340, 340, 340, 196, 196,
+ 196, 196, 196, 196, 196, 196, 196, 196, 196, 196,
+
+ 196, 196, 196, 196, 196, 340, 340, 340, 340, 340,
+ 196, 200, 200, 200, 340, 200, 200, 200, 200, 200,
+ 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
+ 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
+ 200, 200, 200, 200, 200, 200, 200, 200, 200, 200,
+ 200, 200, 200, 200, 202, 340, 340, 340, 202, 340,
+ 340, 340, 340, 202, 202, 202, 202, 202, 202, 202,
+ 202, 202, 202, 202, 202, 202, 202, 202, 202, 202,
+ 340, 340, 340, 340, 340, 202, 205, 205, 205, 340,
+ 205, 205, 205, 205, 205, 205, 205, 205, 205, 205,
+
+ 205, 205, 205, 205, 205, 205, 205, 205, 205, 205,
+ 205, 205, 205, 205, 205, 205, 205, 205, 205, 205,
+ 205, 205, 205, 205, 205, 205, 205, 205, 205, 207,
+ 207, 207, 340, 207, 207, 207, 207, 207, 207, 207,
+ 207, 207, 207, 207, 207, 207, 207, 207, 207, 207,
+ 207, 207, 207, 207, 207, 207, 207, 207, 207, 207,
+ 207, 207, 207, 207, 207, 207, 207, 207, 207, 207,
+ 207, 207, 210, 210, 210, 340, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+
+ 210, 210, 210, 210, 210, 210, 210, 210, 210, 210,
+ 340, 210, 210, 210, 210, 211, 211, 211, 340, 211,
+ 211, 211, 211, 211, 211, 211, 211, 340, 211, 211,
+ 340, 211, 211, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 211, 211, 340, 340, 211, 211, 213, 340,
+ 340, 340, 213, 340, 340, 340, 340, 213, 213, 213,
+ 213, 213, 213, 213, 213, 213, 213, 213, 213, 213,
+ 213, 213, 213, 213, 340, 340, 340, 340, 340, 213,
+ 214, 214, 214, 340, 214, 214, 214, 214, 214, 214,
+
+ 214, 214, 214, 214, 214, 214, 214, 214, 214, 214,
+ 214, 214, 214, 214, 214, 214, 214, 214, 214, 214,
+ 214, 214, 214, 214, 214, 214, 214, 214, 214, 214,
+ 214, 214, 214, 219, 219, 219, 219, 219, 219, 219,
+ 219, 219, 219, 219, 219, 219, 219, 219, 219, 219,
+ 219, 219, 219, 219, 219, 219, 219, 219, 219, 219,
+ 219, 219, 219, 219, 219, 219, 219, 219, 219, 219,
+ 219, 219, 219, 219, 219, 219, 221, 221, 221, 340,
+ 221, 221, 221, 221, 221, 340, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221, 221, 221,
+
+ 221, 221, 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 221, 221, 221, 223,
+ 223, 223, 340, 223, 223, 223, 223, 223, 340, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 223, 223, 223, 223, 223, 223, 223, 223,
+ 223, 223, 225, 225, 225, 340, 225, 225, 225, 225,
+ 225, 225, 225, 225, 225, 225, 225, 225, 225, 225,
+ 225, 340, 225, 225, 225, 225, 225, 225, 225, 225,
+ 225, 225, 225, 225, 225, 225, 225, 225, 225, 225,
+
+ 225, 225, 225, 340, 225, 226, 226, 226, 340, 226,
+ 226, 226, 226, 226, 226, 226, 226, 226, 226, 226,
+ 226, 226, 226, 226, 226, 226, 226, 226, 226, 226,
+ 226, 226, 226, 226, 226, 226, 226, 226, 226, 226,
+ 226, 226, 226, 226, 226, 226, 226, 226, 227, 227,
+ 227, 340, 227, 227, 227, 227, 227, 227, 227, 227,
+ 227, 227, 227, 340, 227, 227, 227, 227, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 227, 227, 227, 227, 227,
+ 227, 231, 340, 340, 340, 231, 340, 340, 340, 340,
+
+ 231, 231, 231, 231, 231, 231, 231, 231, 231, 231,
+ 231, 231, 231, 231, 231, 231, 231, 340, 340, 340,
+ 340, 340, 231, 234, 340, 340, 340, 340, 234, 234,
+ 234, 234, 234, 234, 234, 234, 234, 234, 234, 234,
+ 234, 234, 234, 234, 234, 234, 234, 234, 234, 234,
+ 234, 234, 234, 234, 234, 234, 234, 234, 234, 234,
+ 234, 234, 234, 234, 234, 234, 240, 240, 240, 340,
+ 240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
+ 240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
+ 240, 240, 240, 240, 240, 240, 240, 240, 240, 240,
+
+ 240, 240, 240, 240, 240, 240, 240, 240, 240, 248,
+ 248, 248, 340, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 248, 248, 248, 248, 248, 248, 248, 248,
+ 248, 248, 252, 340, 340, 340, 340, 252, 252, 252,
+ 252, 252, 252, 252, 252, 252, 252, 252, 252, 252,
+ 252, 252, 252, 252, 256, 340, 340, 340, 340, 256,
+ 256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
+ 256, 256, 256, 256, 256, 256, 257, 257, 257, 257,
+
+ 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
+ 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
+ 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
+ 257, 257, 257, 257, 257, 257, 257, 257, 257, 259,
+ 259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+ 259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+ 259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+ 259, 259, 259, 259, 259, 259, 259, 259, 259, 259,
+ 259, 259, 266, 266, 266, 340, 266, 266, 266, 266,
+ 266, 266, 266, 266, 266, 266, 266, 266, 266, 266,
+
+ 266, 266, 266, 266, 266, 266, 266, 266, 266, 266,
+ 266, 266, 266, 266, 266, 266, 266, 266, 266, 266,
+ 266, 266, 340, 266, 266, 269, 269, 269, 269, 269,
+ 269, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 269, 271, 271,
+ 271, 340, 271, 271, 271, 271, 271, 271, 271, 271,
+ 271, 271, 271, 271, 271, 271, 271, 271, 271, 271,
+ 271, 271, 271, 271, 271, 271, 271, 271, 271, 271,
+ 271, 271, 271, 271, 271, 271, 271, 271, 271, 271,
+ 271, 277, 277, 277, 277, 277, 277, 340, 340, 340,
+
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 277, 281, 281, 281, 281, 281, 281,
+ 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
+ 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
+ 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
+ 281, 281, 281, 281, 281, 281, 281, 291, 291, 291,
+ 291, 291, 291, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 291,
+ 293, 293, 293, 293, 293, 293, 293, 293, 293, 293,
+ 293, 293, 293, 293, 293, 293, 293, 293, 293, 293,
+
+ 293, 293, 293, 293, 293, 293, 293, 293, 293, 293,
+ 293, 293, 293, 293, 293, 293, 293, 293, 293, 293,
+ 293, 293, 293, 295, 340, 340, 340, 295, 340, 340,
+ 340, 340, 295, 295, 295, 295, 295, 295, 295, 295,
+ 295, 295, 295, 295, 295, 295, 295, 295, 295, 340,
+ 340, 340, 340, 340, 295, 300, 340, 340, 340, 300,
+ 340, 340, 340, 340, 300, 300, 300, 300, 300, 300,
+ 300, 300, 300, 300, 300, 300, 300, 300, 300, 300,
+ 300, 340, 340, 340, 340, 340, 300, 304, 304, 304,
+ 304, 304, 304, 340, 340, 340, 340, 340, 340, 340,
+
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 304,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
+ 276, 276, 276, 276, 276, 276, 276, 276, 276, 276,
+ 276, 276, 276, 307, 307, 307, 307, 307, 307, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 307, 284, 284, 284, 340,
+ 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
+ 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
+
+ 284, 284, 284, 284, 284, 284, 284, 284, 284, 284,
+ 284, 284, 284, 284, 284, 284, 284, 284, 284, 314,
+ 314, 314, 314, 314, 314, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 314, 45, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340
+ } ;
+
+static const short int yy_chk[3287] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 70, 66, 3, 11, 11,
+
+ 11, 11, 17, 66, 3, 12, 12, 12, 12, 18,
+ 29, 98, 17, 166, 30, 23, 166, 24, 98, 18,
+ 70, 19, 3, 23, 3, 24, 3, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 19, 4, 17,
+ 4, 17, 329, 31, 328, 4, 18, 29, 18, 31,
+ 23, 30, 24, 23, 32, 24, 33, 327, 34, 19,
+ 32, 326, 33, 4, 34, 4, 325, 4, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 20, 21, 35, 22, 47, 47,
+ 47, 47, 21, 21, 22, 22, 51, 51, 51, 51,
+ 20, 324, 35, 58, 58, 58, 58, 102, 62, 58,
+ 62, 62, 82, 82, 102, 82, 58, 139, 139, 323,
+ 139, 322, 20, 21, 35, 22, 25, 25, 25, 25,
+
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 36,
+ 39, 39, 39, 39, 67, 67, 67, 67, 111, 106,
+ 67, 132, 132, 147, 132, 36, 106, 67, 144, 144,
+ 147, 144, 151, 321, 132, 153, 153, 153, 153, 151,
+ 39, 111, 320, 160, 160, 39, 160, 36, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+
+ 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 37, 37, 37, 37, 37, 37, 37, 37, 37,
+ 37, 40, 40, 40, 40, 43, 43, 43, 43, 149,
+ 149, 317, 149, 155, 155, 155, 155, 315, 43, 157,
+ 157, 157, 157, 161, 161, 313, 161, 163, 163, 312,
+ 163, 40, 165, 165, 165, 165, 40, 311, 172, 172,
+ 172, 172, 310, 309, 172, 43, 44, 44, 44, 44,
+ 149, 172, 178, 179, 214, 178, 179, 308, 306, 44,
+ 179, 186, 186, 186, 186, 201, 201, 186, 201, 228,
+ 228, 305, 228, 301, 186, 235, 235, 214, 235, 299,
+
+ 238, 238, 228, 238, 298, 293, 44, 44, 54, 239,
+ 239, 239, 239, 292, 54, 288, 54, 287, 54, 247,
+ 247, 54, 247, 54, 54, 54, 54, 54, 54, 54,
+ 286, 285, 281, 54, 65, 65, 65, 280, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
+ 65, 65, 65, 65, 65, 65, 65, 181, 279, 278,
+ 276, 181, 245, 245, 245, 245, 181, 181, 181, 181,
+ 181, 181, 181, 181, 181, 181, 181, 181, 181, 181,
+
+ 181, 181, 181, 273, 249, 249, 181, 249, 181, 199,
+ 199, 199, 199, 199, 199, 199, 199, 199, 199, 199,
+ 199, 199, 199, 199, 199, 199, 199, 199, 199, 199,
+ 199, 199, 199, 199, 199, 199, 199, 199, 199, 199,
+ 199, 199, 199, 199, 199, 199, 199, 199, 199, 199,
+ 199, 199, 230, 230, 230, 272, 230, 230, 230, 230,
+ 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
+ 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
+ 230, 230, 230, 230, 230, 230, 230, 230, 230, 230,
+ 230, 230, 230, 230, 230, 243, 243, 270, 243, 251,
+
+ 251, 262, 251, 253, 253, 253, 253, 265, 259, 257,
+ 265, 265, 289, 289, 289, 289, 296, 296, 296, 296,
+ 303, 255, 318, 303, 303, 318, 319, 254, 250, 319,
+ 244, 242, 237, 236, 233, 232, 243, 264, 264, 264,
+ 264, 264, 264, 229, 222, 219, 218, 217, 209, 204,
+ 198, 197, 193, 190, 185, 264, 176, 175, 264, 264,
+ 302, 302, 302, 302, 302, 302, 174, 170, 168, 162,
+ 152, 150, 146, 142, 141, 137, 136, 134, 126, 123,
+ 117, 114, 302, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 341, 341, 341,
+
+ 341, 341, 341, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 341, 341, 341, 341, 342, 342, 342, 342,
+ 342, 342, 342, 342, 342, 342, 342, 342, 342, 342,
+ 342, 342, 342, 342, 342, 342, 342, 342, 342, 342,
+ 342, 342, 342, 342, 342, 342, 342, 342, 342, 342,
+ 342, 342, 342, 342, 342, 342, 342, 342, 342, 343,
+ 343, 343, 343, 343, 343, 343, 343, 343, 343, 343,
+ 343, 343, 343, 343, 343, 343, 343, 343, 343, 343,
+ 343, 343, 343, 343, 343, 343, 343, 343, 343, 343,
+
+ 343, 343, 343, 343, 343, 343, 343, 343, 343, 343,
+ 343, 343, 344, 344, 344, 344, 344, 344, 344, 344,
+ 344, 344, 344, 344, 344, 344, 344, 344, 344, 344,
+ 344, 344, 344, 344, 344, 344, 344, 344, 344, 344,
+ 344, 344, 344, 344, 344, 344, 344, 344, 344, 344,
+ 344, 344, 344, 344, 344, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345, 345, 345,
+ 345, 345, 345, 345, 345, 345, 345, 345, 346, 346,
+
+ 346, 346, 346, 346, 346, 346, 346, 346, 346, 346,
+ 346, 346, 346, 346, 346, 346, 346, 346, 346, 346,
+ 346, 346, 346, 346, 346, 346, 346, 346, 346, 346,
+ 346, 346, 346, 346, 346, 346, 346, 346, 346, 346,
+ 346, 347, 347, 347, 347, 347, 347, 347, 347, 347,
+ 347, 347, 347, 347, 347, 347, 347, 347, 347, 347,
+ 347, 347, 347, 347, 347, 347, 347, 347, 347, 347,
+ 347, 347, 347, 347, 347, 347, 347, 347, 347, 347,
+ 347, 347, 347, 347, 348, 348, 348, 348, 348, 348,
+ 348, 348, 348, 348, 348, 348, 348, 348, 348, 348,
+
+ 348, 348, 348, 348, 348, 348, 348, 348, 348, 348,
+ 348, 348, 348, 348, 348, 348, 348, 348, 348, 348,
+ 348, 348, 348, 348, 348, 348, 348, 349, 349, 349,
+ 349, 349, 349, 349, 349, 349, 349, 349, 349, 349,
+ 349, 349, 349, 349, 349, 349, 349, 349, 349, 349,
+ 349, 349, 349, 349, 349, 349, 349, 349, 349, 349,
+ 349, 349, 349, 349, 349, 349, 349, 349, 349, 349,
+ 350, 350, 350, 350, 350, 350, 350, 350, 350, 350,
+ 350, 350, 350, 350, 350, 350, 350, 350, 350, 350,
+ 350, 350, 350, 350, 350, 350, 350, 350, 350, 350,
+
+ 350, 350, 350, 350, 350, 350, 350, 350, 350, 350,
+ 350, 350, 350, 351, 351, 351, 351, 351, 351, 351,
+ 351, 351, 351, 351, 351, 351, 351, 351, 351, 351,
+ 351, 351, 351, 351, 351, 351, 351, 351, 351, 351,
+ 351, 351, 351, 351, 351, 351, 351, 351, 351, 351,
+ 351, 351, 351, 351, 351, 351, 352, 352, 352, 352,
+ 352, 352, 352, 352, 352, 352, 352, 352, 352, 352,
+ 352, 352, 352, 352, 352, 352, 352, 352, 352, 352,
+ 352, 352, 352, 352, 352, 352, 352, 352, 352, 352,
+ 352, 352, 352, 352, 352, 352, 352, 352, 352, 353,
+
+ 353, 353, 353, 353, 353, 353, 353, 353, 353, 353,
+ 353, 353, 353, 353, 353, 353, 353, 353, 353, 353,
+ 353, 353, 353, 353, 353, 353, 353, 353, 353, 353,
+ 353, 353, 353, 353, 353, 353, 353, 353, 353, 353,
+ 353, 353, 354, 354, 354, 354, 354, 354, 354, 354,
+ 354, 354, 354, 354, 354, 354, 354, 354, 354, 354,
+ 354, 354, 354, 354, 354, 354, 354, 354, 354, 354,
+ 354, 354, 354, 354, 354, 354, 354, 354, 354, 354,
+ 354, 354, 354, 354, 354, 355, 355, 355, 355, 355,
+ 355, 355, 355, 355, 355, 355, 355, 355, 355, 355,
+
+ 355, 355, 355, 355, 355, 355, 355, 355, 355, 355,
+ 355, 355, 355, 355, 355, 355, 355, 355, 355, 355,
+ 355, 355, 355, 355, 355, 355, 355, 355, 356, 356,
+ 356, 356, 356, 356, 356, 356, 356, 356, 356, 356,
+ 356, 356, 356, 356, 356, 356, 356, 356, 356, 356,
+ 356, 356, 356, 356, 356, 356, 356, 356, 356, 356,
+ 356, 356, 356, 356, 356, 356, 356, 356, 356, 356,
+ 356, 357, 113, 109, 100, 357, 94, 88, 80, 79,
+ 357, 357, 357, 357, 357, 357, 357, 357, 357, 357,
+ 357, 357, 357, 357, 357, 357, 357, 78, 73, 71,
+
+ 64, 61, 357, 358, 358, 358, 358, 358, 358, 358,
+ 358, 358, 358, 358, 358, 358, 358, 358, 358, 358,
+ 358, 358, 358, 358, 358, 358, 358, 358, 358, 358,
+ 358, 358, 358, 358, 358, 358, 358, 358, 358, 358,
+ 358, 358, 358, 56, 358, 358, 359, 53, 49, 45,
+ 359, 28, 27, 16, 15, 359, 359, 359, 359, 359,
+ 359, 359, 359, 359, 359, 359, 359, 359, 359, 359,
+ 359, 359, 10, 8, 7, 6, 5, 359, 360, 360,
+ 360, 360, 360, 360, 360, 360, 360, 360, 360, 360,
+ 360, 360, 360, 360, 360, 360, 360, 360, 360, 360,
+
+ 360, 360, 360, 360, 360, 360, 360, 360, 360, 360,
+ 360, 360, 360, 360, 360, 360, 360, 360, 360, 360,
+ 360, 361, 361, 361, 0, 361, 361, 361, 361, 361,
+ 361, 361, 361, 361, 361, 361, 361, 361, 361, 361,
+ 361, 361, 361, 361, 361, 361, 361, 361, 361, 361,
+ 361, 361, 361, 361, 361, 361, 361, 361, 361, 0,
+ 361, 361, 361, 361, 362, 362, 362, 0, 362, 362,
+ 362, 362, 362, 362, 362, 362, 362, 362, 362, 362,
+ 362, 362, 362, 362, 362, 362, 362, 362, 362, 362,
+ 362, 362, 362, 362, 362, 362, 362, 362, 362, 362,
+
+ 362, 362, 362, 362, 362, 362, 362, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 363, 363, 363, 363, 363, 363, 363, 363, 363, 363,
+ 364, 0, 0, 0, 0, 364, 364, 364, 364, 364,
+ 364, 364, 364, 364, 364, 364, 364, 364, 364, 364,
+ 364, 364, 364, 364, 364, 364, 364, 364, 364, 364,
+ 364, 364, 364, 364, 364, 364, 364, 364, 364, 364,
+ 364, 364, 364, 365, 365, 365, 365, 365, 365, 365,
+
+ 365, 365, 365, 365, 365, 365, 365, 365, 365, 365,
+ 365, 365, 365, 365, 365, 365, 365, 365, 365, 365,
+ 365, 365, 365, 365, 365, 365, 365, 365, 365, 365,
+ 365, 365, 365, 365, 365, 365, 366, 366, 366, 0,
+ 366, 366, 366, 366, 366, 366, 366, 366, 366, 366,
+ 366, 0, 366, 366, 366, 366, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 366, 366, 366, 366, 366, 366, 367,
+ 0, 0, 0, 367, 0, 0, 0, 0, 367, 367,
+ 367, 367, 367, 367, 367, 367, 367, 367, 367, 367,
+
+ 367, 367, 367, 367, 367, 0, 0, 0, 0, 0,
+ 367, 368, 368, 368, 0, 368, 368, 368, 368, 368,
+ 368, 368, 368, 368, 368, 368, 368, 368, 368, 368,
+ 368, 368, 368, 368, 368, 368, 368, 368, 368, 368,
+ 368, 368, 368, 368, 368, 368, 368, 368, 368, 368,
+ 368, 368, 368, 368, 369, 0, 0, 0, 369, 0,
+ 0, 0, 0, 369, 369, 369, 369, 369, 369, 369,
+ 369, 369, 369, 369, 369, 369, 369, 369, 369, 369,
+ 0, 0, 0, 0, 0, 369, 370, 370, 370, 0,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 370,
+ 370, 370, 370, 370, 370, 370, 370, 370, 370, 371,
+ 371, 371, 0, 371, 371, 371, 371, 371, 371, 371,
+ 371, 371, 371, 371, 371, 371, 371, 371, 371, 371,
+ 371, 371, 371, 371, 371, 371, 371, 371, 371, 371,
+ 371, 371, 371, 371, 371, 371, 371, 371, 371, 371,
+ 371, 371, 372, 372, 372, 0, 372, 372, 372, 372,
+ 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
+ 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
+
+ 372, 372, 372, 372, 372, 372, 372, 372, 372, 372,
+ 0, 372, 372, 372, 372, 373, 373, 373, 0, 373,
+ 373, 373, 373, 373, 373, 373, 373, 0, 373, 373,
+ 0, 373, 373, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 373, 373, 0, 0, 373, 373, 374, 0,
+ 0, 0, 374, 0, 0, 0, 0, 374, 374, 374,
+ 374, 374, 374, 374, 374, 374, 374, 374, 374, 374,
+ 374, 374, 374, 374, 0, 0, 0, 0, 0, 374,
+ 375, 375, 375, 0, 375, 375, 375, 375, 375, 375,
+
+ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
+ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
+ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
+ 375, 375, 375, 376, 376, 376, 376, 376, 376, 376,
+ 376, 376, 376, 376, 376, 376, 376, 376, 376, 376,
+ 376, 376, 376, 376, 376, 376, 376, 376, 376, 376,
+ 376, 376, 376, 376, 376, 376, 376, 376, 376, 376,
+ 376, 376, 376, 376, 376, 376, 377, 377, 377, 0,
+ 377, 377, 377, 377, 377, 0, 377, 377, 377, 377,
+ 377, 377, 377, 377, 377, 377, 377, 377, 377, 377,
+
+ 377, 377, 377, 377, 377, 377, 377, 377, 377, 377,
+ 377, 377, 377, 377, 377, 377, 377, 377, 377, 378,
+ 378, 378, 0, 378, 378, 378, 378, 378, 0, 378,
+ 378, 378, 378, 378, 378, 378, 378, 378, 378, 378,
+ 378, 378, 378, 378, 378, 378, 378, 378, 378, 378,
+ 378, 378, 378, 378, 378, 378, 378, 378, 378, 378,
+ 378, 378, 379, 379, 379, 0, 379, 379, 379, 379,
+ 379, 379, 379, 379, 379, 379, 379, 379, 379, 379,
+ 379, 0, 379, 379, 379, 379, 379, 379, 379, 379,
+ 379, 379, 379, 379, 379, 379, 379, 379, 379, 379,
+
+ 379, 379, 379, 0, 379, 380, 380, 380, 0, 380,
+ 380, 380, 380, 380, 380, 380, 380, 380, 380, 380,
+ 380, 380, 380, 380, 380, 380, 380, 380, 380, 380,
+ 380, 380, 380, 380, 380, 380, 380, 380, 380, 380,
+ 380, 380, 380, 380, 380, 380, 380, 380, 381, 381,
+ 381, 0, 381, 381, 381, 381, 381, 381, 381, 381,
+ 381, 381, 381, 0, 381, 381, 381, 381, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 381, 381, 381, 381, 381,
+ 381, 382, 0, 0, 0, 382, 0, 0, 0, 0,
+
+ 382, 382, 382, 382, 382, 382, 382, 382, 382, 382,
+ 382, 382, 382, 382, 382, 382, 382, 0, 0, 0,
+ 0, 0, 382, 383, 0, 0, 0, 0, 383, 383,
+ 383, 383, 383, 383, 383, 383, 383, 383, 383, 383,
+ 383, 383, 383, 383, 383, 383, 383, 383, 383, 383,
+ 383, 383, 383, 383, 383, 383, 383, 383, 383, 383,
+ 383, 383, 383, 383, 383, 383, 384, 384, 384, 0,
+ 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,
+ 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,
+ 384, 384, 384, 384, 384, 384, 384, 384, 384, 384,
+
+ 384, 384, 384, 384, 384, 384, 384, 384, 384, 385,
+ 385, 385, 0, 385, 385, 385, 385, 385, 385, 385,
+ 385, 385, 385, 385, 385, 385, 385, 385, 385, 385,
+ 385, 385, 385, 385, 385, 385, 385, 385, 385, 385,
+ 385, 385, 385, 385, 385, 385, 385, 385, 385, 385,
+ 385, 385, 386, 0, 0, 0, 0, 386, 386, 386,
+ 386, 386, 386, 386, 386, 386, 386, 386, 386, 386,
+ 386, 386, 386, 386, 387, 0, 0, 0, 0, 387,
+ 387, 387, 387, 387, 387, 387, 387, 387, 387, 387,
+ 387, 387, 387, 387, 387, 387, 388, 388, 388, 388,
+
+ 388, 388, 388, 388, 388, 388, 388, 388, 388, 388,
+ 388, 388, 388, 388, 388, 388, 388, 388, 388, 388,
+ 388, 388, 388, 388, 388, 388, 388, 388, 388, 388,
+ 388, 388, 388, 388, 388, 388, 388, 388, 388, 389,
+ 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
+ 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
+ 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
+ 389, 389, 389, 389, 389, 389, 389, 389, 389, 389,
+ 389, 389, 390, 390, 390, 0, 390, 390, 390, 390,
+ 390, 390, 390, 390, 390, 390, 390, 390, 390, 390,
+
+ 390, 390, 390, 390, 390, 390, 390, 390, 390, 390,
+ 390, 390, 390, 390, 390, 390, 390, 390, 390, 390,
+ 390, 390, 0, 390, 390, 391, 391, 391, 391, 391,
+ 391, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 391, 392, 392,
+ 392, 0, 392, 392, 392, 392, 392, 392, 392, 392,
+ 392, 392, 392, 392, 392, 392, 392, 392, 392, 392,
+ 392, 392, 392, 392, 392, 392, 392, 392, 392, 392,
+ 392, 392, 392, 392, 392, 392, 392, 392, 392, 392,
+ 392, 393, 393, 393, 393, 393, 393, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 393, 394, 394, 394, 394, 394, 394,
+ 394, 394, 394, 394, 394, 394, 394, 394, 394, 394,
+ 394, 394, 394, 394, 394, 394, 394, 394, 394, 394,
+ 394, 394, 394, 394, 394, 394, 394, 394, 394, 394,
+ 394, 394, 394, 394, 394, 394, 394, 395, 395, 395,
+ 395, 395, 395, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 395,
+ 396, 396, 396, 396, 396, 396, 396, 396, 396, 396,
+ 396, 396, 396, 396, 396, 396, 396, 396, 396, 396,
+
+ 396, 396, 396, 396, 396, 396, 396, 396, 396, 396,
+ 396, 396, 396, 396, 396, 396, 396, 396, 396, 396,
+ 396, 396, 396, 397, 0, 0, 0, 397, 0, 0,
+ 0, 0, 397, 397, 397, 397, 397, 397, 397, 397,
+ 397, 397, 397, 397, 397, 397, 397, 397, 397, 0,
+ 0, 0, 0, 0, 397, 398, 0, 0, 0, 398,
+ 0, 0, 0, 0, 398, 398, 398, 398, 398, 398,
+ 398, 398, 398, 398, 398, 398, 398, 398, 398, 398,
+ 398, 0, 0, 0, 0, 0, 398, 399, 399, 399,
+ 399, 399, 399, 0, 0, 0, 0, 0, 0, 0,
+
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 399,
+ 400, 400, 400, 400, 400, 400, 400, 400, 400, 400,
+ 400, 400, 400, 400, 400, 400, 400, 400, 400, 400,
+ 400, 400, 400, 400, 400, 400, 400, 400, 400, 400,
+ 400, 400, 400, 400, 400, 400, 400, 400, 400, 400,
+ 400, 400, 400, 401, 401, 401, 401, 401, 401, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 401, 402, 402, 402, 0,
+ 402, 402, 402, 402, 402, 402, 402, 402, 402, 402,
+ 402, 402, 402, 402, 402, 402, 402, 402, 402, 402,
+
+ 402, 402, 402, 402, 402, 402, 402, 402, 402, 402,
+ 402, 402, 402, 402, 402, 402, 402, 402, 402, 403,
+ 403, 403, 403, 403, 403, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 403, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340, 340, 340, 340, 340,
+ 340, 340, 340, 340, 340, 340
+ } ;
+
+static yy_ste_type yy_last_accepting_state;
+static YY_CHAR *yy_last_accepting_cpos;
+
+/* the intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymrused_but_not_detected
+#define YY_MORE_ADJ 0
+
+/* these variables are all declared out here so that section 3 code can
+ * manipulate them
+ */
+/* points to current character in buffer */
+static YY_CHAR *yy_c_buf_p = (YY_CHAR *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+static yy_ste_type yy_get_previous_state YY_PROTO(( void ));
+static yy_ste_type yy_try_NUL_trans YY_PROTO(( yy_ste_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yyunput YY_PROTO(( YY_CHAR c, YY_CHAR *buf_ptr ));
+void yyrestrt YY_PROTO(( FILE *input_file ));
+void yyswtobf YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yyldbfst YY_PROTO(( void ));
+YY_BUFFER_STATE yycrbffr YY_PROTO(( FILE *file, int size ));
+void yydlbffr YY_PROTO(( YY_BUFFER_STATE b ));
+void yyinbffr YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+
+#define yy_new_buffer yycrbffr
+
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+
+YY_DECL
+ {
+ register yy_ste_type yy_current_state;
+ register YY_CHAR *yy_cp, *yy_bp;
+ register int yy_act;
+
+
+ static int bracelevel, didadef;
+ int i, indented_code, checking_used, new_xlation;
+ int doing_codeblock = false;
+ Char nmdef[MAXLINE], myesc();
+
+
+ if ( yy_init )
+ {
+ YY_USER_INIT;
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( yy_current_buffer )
+ yyinbffr( yy_current_buffer, yyin );
+ else
+ yy_current_buffer = yycrbffr( yyin, YY_BUF_SIZE );
+
+ yyldbfst();
+
+ yy_init = 0;
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yy_c_buf_p;
+
+ /* support of yytext */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of the
+ * current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yy_start;
+ if ( yy_bp[-1] == '\n' )
+ ++yy_current_state;
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[*yy_cp];
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while(yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state)
+ {
+ yy_current_state = yy_def[yy_current_state];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ ++yy_cp;
+ }
+ while ( yy_current_state != 340 );
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+
+ YY_DO_BEFORE_ACTION;
+ YY_USER_ACTION;
+
+do_action: /* this label is used only to access EOF actions */
+
+
+ switch ( yy_act )
+ {
+ case 0: /* must backtrack */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yy_hold_char;
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ goto yy_find_action;
+
+case 1:
+# line 90 "<stdin>"
+indented_code = true; BEGIN(CODEBLOCK);
+ YY_BREAK
+case 2:
+# line 91 "<stdin>"
+++linenum; /* treat as a comment */
+ YY_BREAK
+case 3:
+# line 92 "<stdin>"
+ECHO; BEGIN(C_COMMENT);
+ YY_BREAK
+case 4:
+# line 93 "<stdin>"
+return ( SCDECL );
+ YY_BREAK
+case 5:
+# line 94 "<stdin>"
+return ( XSCDECL );
+ YY_BREAK
+case 6:
+# line 95 "<stdin>"
+{
+ ++linenum;
+ lndirout( stdout );
+ indented_code = false;
+ BEGIN(CODEBLOCK);
+ }
+ YY_BREAK
+case 7:
+# line 102 "<stdin>"
+return ( WHITESPACE );
+ YY_BREAK
+case 8:
+# line 104 "<stdin>"
+{
+ sectnum = 2;
+ lndirout( stdout );
+ BEGIN(SECT2PROLOG);
+ return ( SECTEND );
+ }
+ YY_BREAK
+case 9:
+# line 111 "<stdin>"
+{
+ pptmsg( "warning - %%used/%%unused have been deprecated" );
+ checking_used = REALLY_USED; BEGIN(USED_LIST);
+ }
+ YY_BREAK
+case 10:
+# line 115 "<stdin>"
+{
+ checking_used = REALLY_NOT_USED; BEGIN(USED_LIST);
+ pptmsg( "warning - %%used/%%unused have been deprecated" );
+ checking_used = REALLY_NOT_USED; BEGIN(USED_LIST);
+ }
+ YY_BREAK
+case 11:
+# line 122 "<stdin>"
+{
+#ifdef NOTDEF
+ fprintf( stderr,
+ "old-style lex command at line %d ignored:\n\t%s",
+ linenum, yytext );
+#endif
+ ++linenum;
+ }
+ YY_BREAK
+case 12:
+# line 131 "<stdin>"
+/* ignore old lex directive */
+ YY_BREAK
+case 13:
+# line 133 "<stdin>"
+{
+ ++linenum;
+ xlation =
+ (int *) malloc( sizeof( int ) * (unsigned) csize );
+
+ if ( ! xlation )
+ flxfatal(
+ "dynamic memory failure building %t table" );
+
+ for ( i = 0; i < csize; ++i )
+ xlation[i] = 0;
+
+ nuxlatns = 0;
+
+ BEGIN(XLATION);
+ }
+ YY_BREAK
+case 14:
+# line 150 "<stdin>"
+synerr( "unrecognized '%' directive" );
+ YY_BREAK
+case 15:
+# line 152 "<stdin>"
+{
+ (void) strcpy( nmstr, (char *) yytext );
+ didadef = false;
+ BEGIN(PICKUPDEF);
+ }
+ YY_BREAK
+case 16:
+# line 158 "<stdin>"
+RETURNNAME;
+ YY_BREAK
+case 17:
+# line 159 "<stdin>"
+++linenum; /* allows blank lines in section 1 */
+ YY_BREAK
+case 18:
+# line 160 "<stdin>"
+++linenum; return ( '\n' );
+ YY_BREAK
+case 19:
+# line 161 "<stdin>"
+synerr( "illegal character" ); BEGIN(RECOVER);
+ YY_BREAK
+case 20:
+# line 164 "<stdin>"
+ECHO; BEGIN(INITIAL);
+ YY_BREAK
+case 21:
+# line 165 "<stdin>"
+++linenum; ECHO; BEGIN(INITIAL);
+ YY_BREAK
+case 22:
+# line 166 "<stdin>"
+ECHO;
+ YY_BREAK
+case 23:
+# line 167 "<stdin>"
+ECHO;
+ YY_BREAK
+case 24:
+# line 168 "<stdin>"
+++linenum; ECHO;
+ YY_BREAK
+case 25:
+# line 171 "<stdin>"
+++linenum; BEGIN(INITIAL);
+ YY_BREAK
+case 26:
+# line 172 "<stdin>"
+ECHO; CHECK_REJECT(yytext);
+ YY_BREAK
+case 27:
+# line 173 "<stdin>"
+ECHO; CHECK_YYMORE(yytext);
+ YY_BREAK
+case 28:
+# line 174 "<stdin>"
+ECHO;
+ YY_BREAK
+case 29:
+# line 175 "<stdin>"
+{
+ ++linenum;
+ ECHO;
+ if ( indented_code )
+ BEGIN(INITIAL);
+ }
+ YY_BREAK
+case 30:
+# line 183 "<stdin>"
+/* separates name and definition */
+ YY_BREAK
+case 31:
+# line 185 "<stdin>"
+{
+ (void) strcpy( (char *) nmdef, (char *) yytext );
+
+ for ( i = strlen( (char *) nmdef ) - 1;
+ i >= 0 &&
+ nmdef[i] == ' ' || nmdef[i] == '\t';
+ --i )
+ ;
+
+ nmdef[i + 1] = '\0';
+
+ ndinstal( nmstr, nmdef );
+ didadef = true;
+ }
+ YY_BREAK
+case 32:
+# line 200 "<stdin>"
+{
+ if ( ! didadef )
+ synerr( "incomplete name definition" );
+ BEGIN(INITIAL);
+ ++linenum;
+ }
+ YY_BREAK
+case 33:
+# line 207 "<stdin>"
+++linenum; BEGIN(INITIAL); RETURNNAME;
+ YY_BREAK
+case 34:
+# line 210 "<stdin>"
+++linenum; BEGIN(INITIAL);
+ YY_BREAK
+case 35:
+# line 211 "<stdin>"
+
+ YY_BREAK
+case 36:
+# line 212 "<stdin>"
+{
+ if ( allupper( yytext ) )
+ rjctused = checking_used;
+ else
+ synerr( "unrecognized %used/%unused construct" );
+ }
+ YY_BREAK
+case 37:
+# line 218 "<stdin>"
+{
+ if ( alllower( yytext ) )
+ yymrreus = checking_used;
+ else
+ synerr( "unrecognized %used/%unused construct" );
+ }
+ YY_BREAK
+case 38:
+# line 224 "<stdin>"
+synerr( "unrecognized %used/%unused construct" );
+ YY_BREAK
+case 39:
+# line 227 "<stdin>"
+++linenum; BEGIN(INITIAL);
+ YY_BREAK
+case 40:
+# line 228 "<stdin>"
+++nuxlatns; new_xlation = true;
+ YY_BREAK
+case 41:
+# line 229 "<stdin>"
+synerr( "bad row in translation table" );
+ YY_BREAK
+case 42:
+# line 230 "<stdin>"
+/* ignore whitespace */
+ YY_BREAK
+case 43:
+# line 232 "<stdin>"
+{
+ xlation[myesc( yytext )] =
+ (new_xlation ? nuxlatns : -nuxlatns);
+ new_xlation = false;
+ }
+ YY_BREAK
+case 44:
+# line 237 "<stdin>"
+{
+ xlation[yytext[0]] =
+ (new_xlation ? nuxlatns : -nuxlatns);
+ new_xlation = false;
+ }
+ YY_BREAK
+case 45:
+# line 243 "<stdin>"
+++linenum;
+ YY_BREAK
+case 46:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+# line 246 "<stdin>"
+{
+ ++linenum;
+ ACTION_ECHO;
+ MARK_END_OF_PROLOG;
+ BEGIN(SECT2);
+ }
+ YY_BREAK
+case 47:
+# line 253 "<stdin>"
+++linenum; ACTION_ECHO;
+ YY_BREAK
+case YY_STATE_EOF(SECT2PROLOG):
+# line 255 "<stdin>"
+MARK_END_OF_PROLOG; yyterminate();
+ YY_BREAK
+case 49:
+# line 257 "<stdin>"
+++linenum; /* allow blank lines in section 2 */
+ YY_BREAK
+case 50:
+# line 259 "<stdin>"
+{
+ indented_code = (yytext[0] != '%');
+ doing_codeblock = true;
+ bracelevel = 1;
+
+ if ( indented_code )
+ ACTION_ECHO;
+
+ BEGIN(CODEBLOCK_2);
+ }
+ YY_BREAK
+case 51:
+# line 270 "<stdin>"
+BEGIN(SC); return ( '<' );
+ YY_BREAK
+case 52:
+# line 271 "<stdin>"
+return ( '^' );
+ YY_BREAK
+case 53:
+# line 272 "<stdin>"
+BEGIN(QUOTE); return ( '"' );
+ YY_BREAK
+case 54:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+# line 273 "<stdin>"
+BEGIN(NUM); return ( '{' );
+ YY_BREAK
+case 55:
+# line 274 "<stdin>"
+BEGIN(BRACEERROR);
+ YY_BREAK
+case 56:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+# line 275 "<stdin>"
+return ( '$' );
+ YY_BREAK
+case 57:
+# line 277 "<stdin>"
+{
+ bracelevel = 1;
+ BEGIN(PERCENT_BRACE_ACTION);
+ return ( '\n' );
+ }
+ YY_BREAK
+case 58:
+# line 282 "<stdin>"
+cntdactn = true; ++linenum; return ( '\n' );
+ YY_BREAK
+case 59:
+# line 284 "<stdin>"
+{
+ /* this rule is separate from the one below because
+ * otherwise we get variable trailing context, so
+ * we can't build the scanner using -{f,F}
+ */
+ bracelevel = 0;
+ cntdactn = false;
+ BEGIN(ACTION);
+ return ( '\n' );
+ }
+ YY_BREAK
+case 60:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+# line 295 "<stdin>"
+{
+ bracelevel = 0;
+ cntdactn = false;
+ BEGIN(ACTION);
+ return ( '\n' );
+ }
+ YY_BREAK
+case 61:
+# line 302 "<stdin>"
+++linenum; return ( '\n' );
+ YY_BREAK
+case 62:
+# line 304 "<stdin>"
+return ( EOF_OP );
+ YY_BREAK
+case 63:
+# line 306 "<stdin>"
+{
+ sectnum = 3;
+ BEGIN(SECT3);
+ return ( EOF ); /* to stop the parser */
+ }
+ YY_BREAK
+case 64:
+# line 312 "<stdin>"
+{
+ int cclval;
+
+ (void) strcpy( nmstr, (char *) yytext );
+
+ /* check to see if we've already encountered this ccl */
+ if ( (cclval = ccllookp( (Char *) nmstr )) )
+ {
+ yylval = cclval;
+ ++cclreuse;
+ return ( PREVCCL );
+ }
+ else
+ {
+ /* we fudge a bit. We know that this ccl will
+ * soon be numbered as lastccl + 1 by cclinit
+ */
+ cclnstal( (Char *) nmstr, lastccl + 1 );
+
+ /* push back everything but the leading bracket
+ * so the ccl can be rescanned
+ */
+ PUT_BACK_STRING((Char *) nmstr, 1);
+
+ BEGIN(FIRSTCCL);
+ return ( '[' );
+ }
+ }
+ YY_BREAK
+case 65:
+# line 341 "<stdin>"
+{
+ register Char *nmdefptr;
+ Char *ndlookup();
+
+ (void) strcpy( nmstr, (char *) yytext );
+ nmstr[yyleng - 1] = '\0'; /* chop trailing brace */
+
+ /* lookup from "nmstr + 1" to chop leading brace */
+ if ( ! (nmdefptr = ndlookup( nmstr + 1 )) )
+ synerr( "undefined {name}" );
+
+ else
+ { /* push back name surrounded by ()'s */
+ unput(')');
+ PUT_BACK_STRING(nmdefptr, 0);
+ unput('(');
+ }
+ }
+ YY_BREAK
+case 66:
+# line 360 "<stdin>"
+return ( yytext[0] );
+ YY_BREAK
+case 67:
+# line 361 "<stdin>"
+RETURNCHAR;
+ YY_BREAK
+case 68:
+# line 362 "<stdin>"
+++linenum; return ( '\n' );
+ YY_BREAK
+case 69:
+# line 365 "<stdin>"
+return ( ',' );
+ YY_BREAK
+case 70:
+# line 366 "<stdin>"
+BEGIN(SECT2); return ( '>' );
+ YY_BREAK
+case 71:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+# line 367 "<stdin>"
+BEGIN(CARETISBOL); return ( '>' );
+ YY_BREAK
+case 72:
+# line 368 "<stdin>"
+RETURNNAME;
+ YY_BREAK
+case 73:
+# line 369 "<stdin>"
+synerr( "bad start condition name" );
+ YY_BREAK
+case 74:
+# line 371 "<stdin>"
+BEGIN(SECT2); return ( '^' );
+ YY_BREAK
+case 75:
+# line 374 "<stdin>"
+RETURNCHAR;
+ YY_BREAK
+case 76:
+# line 375 "<stdin>"
+BEGIN(SECT2); return ( '"' );
+ YY_BREAK
+case 77:
+# line 377 "<stdin>"
+{
+ synerr( "missing quote" );
+ BEGIN(SECT2);
+ ++linenum;
+ return ( '"' );
+ }
+ YY_BREAK
+case 78:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+# line 385 "<stdin>"
+BEGIN(CCL); return ( '^' );
+ YY_BREAK
+case 79:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+# line 386 "<stdin>"
+return ( '^' );
+ YY_BREAK
+case 80:
+# line 387 "<stdin>"
+BEGIN(CCL); yylval = '-'; return ( CHAR );
+ YY_BREAK
+case 81:
+# line 388 "<stdin>"
+BEGIN(CCL); RETURNCHAR;
+ YY_BREAK
+case 82:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+# line 390 "<stdin>"
+return ( '-' );
+ YY_BREAK
+case 83:
+# line 391 "<stdin>"
+RETURNCHAR;
+ YY_BREAK
+case 84:
+# line 392 "<stdin>"
+BEGIN(SECT2); return ( ']' );
+ YY_BREAK
+case 85:
+# line 395 "<stdin>"
+{
+ yylval = myctoi( yytext );
+ return ( NUMBER );
+ }
+ YY_BREAK
+case 86:
+# line 400 "<stdin>"
+return ( ',' );
+ YY_BREAK
+case 87:
+# line 401 "<stdin>"
+BEGIN(SECT2); return ( '}' );
+ YY_BREAK
+case 88:
+# line 403 "<stdin>"
+{
+ synerr( "bad character inside {}'s" );
+ BEGIN(SECT2);
+ return ( '}' );
+ }
+ YY_BREAK
+case 89:
+# line 409 "<stdin>"
+{
+ synerr( "missing }" );
+ BEGIN(SECT2);
+ ++linenum;
+ return ( '}' );
+ }
+ YY_BREAK
+case 90:
+# line 417 "<stdin>"
+synerr( "bad name in {}'s" ); BEGIN(SECT2);
+ YY_BREAK
+case 91:
+# line 418 "<stdin>"
+synerr( "missing }" ); ++linenum; BEGIN(SECT2);
+ YY_BREAK
+case 92:
+# line 421 "<stdin>"
+bracelevel = 0;
+ YY_BREAK
+case 93:
+# line 422 "<stdin>"
+{
+ ACTION_ECHO;
+ CHECK_REJECT(yytext);
+ }
+ YY_BREAK
+case 94:
+# line 426 "<stdin>"
+{
+ ACTION_ECHO;
+ CHECK_YYMORE(yytext);
+ }
+ YY_BREAK
+case 95:
+# line 430 "<stdin>"
+ACTION_ECHO;
+ YY_BREAK
+case 96:
+# line 431 "<stdin>"
+{
+ ++linenum;
+ ACTION_ECHO;
+ if ( bracelevel == 0 ||
+ (doing_codeblock && indented_code) )
+ {
+ if ( ! doing_codeblock )
+ fputs( "\tYY_BREAK\n", tmpactfl );
+
+ doing_codeblock = false;
+ BEGIN(SECT2);
+ }
+ }
+ YY_BREAK
+ /* Reject and YYmore() are checked for above, in PERCENT_BRACE_ACTION */
+case 97:
+# line 447 "<stdin>"
+ACTION_ECHO; ++bracelevel;
+ YY_BREAK
+case 98:
+# line 448 "<stdin>"
+ACTION_ECHO; --bracelevel;
+ YY_BREAK
+case 99:
+# line 449 "<stdin>"
+ACTION_ECHO;
+ YY_BREAK
+case 100:
+# line 450 "<stdin>"
+ACTION_ECHO;
+ YY_BREAK
+case 101:
+# line 451 "<stdin>"
+ACTION_ECHO; BEGIN(ACTION_COMMENT);
+ YY_BREAK
+case 102:
+# line 452 "<stdin>"
+ACTION_ECHO; /* character constant */
+ YY_BREAK
+case 103:
+# line 453 "<stdin>"
+ACTION_ECHO; BEGIN(ACTION_STRING);
+ YY_BREAK
+case 104:
+# line 454 "<stdin>"
+{
+ ++linenum;
+ ACTION_ECHO;
+ if ( bracelevel == 0 )
+ {
+ fputs( "\tYY_BREAK\n", tmpactfl );
+ BEGIN(SECT2);
+ }
+ }
+ YY_BREAK
+case 105:
+# line 463 "<stdin>"
+ACTION_ECHO;
+ YY_BREAK
+case 106:
+# line 465 "<stdin>"
+ACTION_ECHO; BEGIN(ACTION);
+ YY_BREAK
+case 107:
+# line 466 "<stdin>"
+ACTION_ECHO;
+ YY_BREAK
+case 108:
+# line 467 "<stdin>"
+ACTION_ECHO;
+ YY_BREAK
+case 109:
+# line 468 "<stdin>"
+++linenum; ACTION_ECHO;
+ YY_BREAK
+case 110:
+# line 469 "<stdin>"
+ACTION_ECHO;
+ YY_BREAK
+case 111:
+# line 471 "<stdin>"
+ACTION_ECHO;
+ YY_BREAK
+case 112:
+# line 472 "<stdin>"
+ACTION_ECHO;
+ YY_BREAK
+case 113:
+# line 473 "<stdin>"
+++linenum; ACTION_ECHO;
+ YY_BREAK
+case 114:
+# line 474 "<stdin>"
+ACTION_ECHO; BEGIN(ACTION);
+ YY_BREAK
+case 115:
+# line 475 "<stdin>"
+ACTION_ECHO;
+ YY_BREAK
+case YY_STATE_EOF(ACTION):
+case YY_STATE_EOF(ACTION_COMMENT):
+case YY_STATE_EOF(ACTION_STRING):
+# line 477 "<stdin>"
+{
+ synerr( "EOF encountered inside an action" );
+ yyterminate();
+ }
+ YY_BREAK
+case 117:
+# line 483 "<stdin>"
+{
+ yylval = myesc( yytext );
+ return ( CHAR );
+ }
+ YY_BREAK
+case 118:
+# line 488 "<stdin>"
+{
+ yylval = myesc( yytext );
+ BEGIN(CCL);
+ return ( CHAR );
+ }
+ YY_BREAK
+case 119:
+# line 495 "<stdin>"
+ECHO;
+ YY_BREAK
+case 120:
+# line 496 "<stdin>"
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(SECT2):
+case YY_STATE_EOF(SECT3):
+case YY_STATE_EOF(CODEBLOCK):
+case YY_STATE_EOF(PICKUPDEF):
+case YY_STATE_EOF(SC):
+case YY_STATE_EOF(CARETISBOL):
+case YY_STATE_EOF(NUM):
+case YY_STATE_EOF(QUOTE):
+case YY_STATE_EOF(FIRSTCCL):
+case YY_STATE_EOF(CCL):
+case YY_STATE_EOF(RECOVER):
+case YY_STATE_EOF(BRACEERROR):
+case YY_STATE_EOF(C_COMMENT):
+case YY_STATE_EOF(PERCENT_BRACE_ACTION):
+case YY_STATE_EOF(USED_LIST):
+case YY_STATE_EOF(CODEBLOCK_2):
+case YY_STATE_EOF(XLATION):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* amount of text matched not including the EOB char */
+ int yy_amount_of_matched_text = yy_cp - yytext - 1;
+
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yy_hold_char;
+
+ /* note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the end-
+ * of-buffer state). Contrast this with the test in yyinput().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* this was really a NUL */
+ {
+ yy_ste_type yy_next_state;
+
+ yy_c_buf_p = yytext + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* okay, we're now positioned to make the
+ * NUL transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we
+ * don't want to build jamming into it because
+ * then it will run more slowly)
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* consume the NUL */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* note: because we've taken care in
+ * yy_get_next_buffer() to have set up yytext,
+ * we can now set up yy_c_buf_p so that if some
+ * total hoser (like flex itself) wants
+ * to call the scanner after we return the
+ * YY_NULL, it'll still work - another YY_NULL
+ * will get returned.
+ */
+ yy_c_buf_p = yytext + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF((yy_start - 1) / 2);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ }
+ break;
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+#ifdef FLEX_DEBUG
+ printf( "action # %d\n", yy_act );
+#endif
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ }
+ }
+ }
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * synopsis
+ * int yy_get_next_buffer();
+ *
+ * returns a code representing an action
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+
+ {
+ register YY_CHAR *dest = yy_current_buffer->yy_ch_buf;
+ register YY_CHAR *source = yytext - 1; /* copy prev. char, too */
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ /* try to read more data */
+
+ /* first move last chars to start of buffer */
+ number_to_move = yy_c_buf_p - yytext;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_eof_status != EOF_NOT_SEEN )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read = yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ else if ( num_to_read <= 0 )
+ YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" );
+
+ /* read in more data */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move == 1 )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yy_current_buffer->yy_eof_status = EOF_DONE;
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_eof_status = EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ /* yytext begins at the second character in yy_ch_buf; the first
+ * character is the one which preceded it before reading in the latest
+ * buffer; it needs to be kept around in case it's a newline, so
+ * yy_get_previous_state() will have with '^' rules active
+ */
+
+ yytext = &yy_current_buffer->yy_ch_buf[1];
+
+ return ( ret_val );
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached
+ *
+ * synopsis
+ * yy_ste_type yy_get_previous_state();
+ */
+
+static yy_ste_type yy_get_previous_state()
+
+ {
+ register yy_ste_type yy_current_state;
+ register YY_CHAR *yy_cp;
+
+ register YY_CHAR *yy_bp = yytext;
+
+ yy_current_state = yy_start;
+ if ( yy_bp[-1] == '\n' )
+ ++yy_current_state;
+
+ for ( yy_cp = yytext + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[*yy_cp] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = yy_def[yy_current_state];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ }
+
+ return ( yy_current_state );
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_ste_type yy_try_NUL_trans( register yy_ste_type yy_current_state )
+#else
+static yy_ste_type yy_try_NUL_trans( yy_current_state )
+register yy_ste_type yy_current_state;
+#endif
+
+ {
+ register int yy_is_jam;
+ register YY_CHAR *yy_cp = yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = yy_def[yy_current_state];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
+ yy_is_jam = (yy_current_state == 340);
+
+ return ( yy_is_jam ? 0 : yy_current_state );
+ }
+
+
+#ifdef YY_USE_PROTOS
+static void yyunput( YY_CHAR c, register YY_CHAR *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+YY_CHAR c;
+register YY_CHAR *yy_bp;
+#endif
+
+ {
+ register YY_CHAR *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ register int number_to_move = yy_n_chars + 2; /* +2 for EOB chars */
+ register YY_CHAR *dest =
+ &yy_current_buffer->yy_ch_buf[yy_current_buffer->yy_buf_size + 2];
+ register YY_CHAR *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += dest - source;
+ yy_bp += dest - source;
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ if ( yy_cp > yy_bp && yy_cp[-1] == '\n' )
+ yy_cp[-2] = '\n';
+
+ *--yy_cp = c;
+
+ /* note: the formal parameter *must* be called "yy_bp" for this
+ * macro to now work correctly
+ */
+ YY_DO_BEFORE_ACTION; /* set up yytext again */
+ }
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+
+ {
+ int c;
+ YY_CHAR *yy_cp = yy_c_buf_p;
+
+ *yy_cp = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* this was really a NUL */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ yytext = yy_c_buf_p;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ {
+ yy_c_buf_p = yytext + YY_MORE_ADJ;
+ return ( EOF );
+ }
+
+ YY_NEW_FILE;
+
+#ifdef __cplusplus
+ return ( yyinput() );
+#else
+ return ( input() );
+#endif
+ }
+ break;
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext + YY_MORE_ADJ;
+ break;
+
+ case EOB_ACT_LAST_MATCH:
+#ifdef __cplusplus
+ YY_FATAL_ERROR( "unexpected last match in yyinput()" );
+#else
+ YY_FATAL_ERROR( "unexpected last match in input()" );
+#endif
+ }
+ }
+ }
+
+ c = *yy_c_buf_p;
+ yy_hold_char = *++yy_c_buf_p;
+
+ return ( c );
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yyrestrt( FILE *input_file )
+#else
+void yyrestrt( input_file )
+FILE *input_file;
+#endif
+
+ {
+ yyinbffr( yy_current_buffer, input_file );
+ yyldbfst();
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yyswtobf( YY_BUFFER_STATE new_buffer )
+#else
+void yyswtobf( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* flush out information for old buffer */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yyldbfst();
+
+ /* we don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yyldbfst( void )
+#else
+void yyldbfst()
+#endif
+
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yycrbffr( FILE *file, int size )
+#else
+YY_BUFFER_STATE yycrbffr( file, size )
+FILE *file;
+int size;
+#endif
+
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) malloc( sizeof( struct yy_buffer_state ) );
+
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yycrbffr()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (YY_CHAR *) malloc( (unsigned) (b->yy_buf_size + 2) );
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yycrbffr()" );
+
+ yyinbffr( b, file );
+
+ return ( b );
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yydlbffr( YY_BUFFER_STATE b )
+#else
+void yydlbffr( b )
+YY_BUFFER_STATE b;
+#endif
+
+ {
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ free( (char *) b->yy_ch_buf );
+ free( (char *) b );
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yyinbffr( YY_BUFFER_STATE b, FILE *file )
+#else
+void yyinbffr( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+ {
+ b->yy_input_file = file;
+
+ /* we put in the '\n' and start reading from [1] so that an
+ * initial match-at-newline will be true.
+ */
+
+ b->yy_ch_buf[0] = '\n';
+ b->yy_n_chars = 1;
+
+ /* we always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[2] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[1];
+
+ b->yy_eof_status = EOF_NOT_SEEN;
+ }
+# line 496 "<stdin>"
+
+
+
+int yywrap()
+
+ {
+ if ( --ninfiles > 0 )
+ {
+ stinpfle( *++inp_fles );
+ return ( 0 );
+ }
+
+ else
+ return ( 1 );
+ }
+
+
+/* stinpfle - open the given file (if NULL, stdin) for scanning */
+
+void stinpfle( file )
+char *file;
+
+ {
+ if ( file )
+ {
+ infilnam = file;
+ yyin = fopen( infilnam, "r" );
+
+ if ( yyin == NULL )
+ lerrsf( "can't open %s", file );
+ }
+
+ else
+ {
+ yyin = stdin;
+ infilnam = "<stdin>";
+ }
+ }
diff --git a/Tools/android/flex-2.5.4a/MISC/MVS/unfixit.l b/Tools/android/flex-2.5.4a/MISC/MVS/unfixit.l
new file mode 100644
index 0000000..3f8dddc
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/MVS/unfixit.l
@@ -0,0 +1,141 @@
+%{
+/* unfixit.l - convert shortened external names to names back to their
+ * original names. (See fixit.l)
+ */
+
+/*
+ * This program is included to satisfy "dumb" compilers/linkers which
+ * do not know about externals of names longer than 8 bytes.
+ *
+ * Steven W. Layten
+ * Chemical Abstracts Service
+ * PO BOX 3012
+ * Columbus, OH 43210
+ */
+%}
+%%
+"actfilnm" printf("action_file_name");
+"actnout" printf("action_out");
+"addacpt" printf("add_accept");
+"alllower" printf("all_lower");
+"allupper" printf("all_upper");
+"allocarr" printf("allocate_array");
+"asscrule" printf("assoc_rule");
+"bktrkfil" printf("backtrack_file");
+"bktrkrep" printf("backtrack_report");
+"bol_nded" printf("bol_needed");
+"bldeofac" printf("build_eof_action");
+"cclnstal" printf("cclinstal");
+"ccllookp" printf("ccllookup");
+"cclnegat" printf("cclnegate");
+"cclsrted" printf("cclsorted");
+"ck4bktrk" printf("check_for_backtracking");
+"cktrlcnt" printf("check_trailing_context");
+"cntdactn" printf("continued_action");
+"copystrn" printf("copy_string");
+"cpunsstr" printf("copy_unsigned_string");
+"cpyrght" printf("copyright");
+"copysngl" printf("copysingl");
+"c_mx_ccl" printf("current_max_ccl_tbl_size");
+"c_mx_dfa" printf("current_max_dfa_size");
+"c_mxdfas" printf("current_max_dfas");
+"curmxrls" printf("current_max_rules");
+"c_mx_scs" printf("current_max_scs");
+"c_mx_tmp" printf("current_max_template_xpairs");
+"c_mx_xpr" printf("current_max_xpairs");
+"c_mxccls" printf("current_maxccls");
+"curr_mns" printf("current_mns");
+"cursttyp" printf("current_state_type");
+"datflush" printf("dataflush");
+"dfacunin" printf("dfaacc_union");
+"do_indnt" printf("do_indent");
+"dmpasrl" printf("dump_associated_rules");
+"dmptrns" printf("dump_transitions");
+"dupmach" printf("dupmachine");
+"ecsfrmxt" printf("ecs_from_xlation");
+"eobstate" printf("end_of_buffer_state");
+"epsclos" printf("epsclosure");
+"expnxtck" printf("expand_nxt_chk");
+"fndtblsp" printf("find_table_space");
+"fnshrule" printf("finish_rule");
+"firstfre" printf("firstfree");
+"firstprt" printf("firstprot");
+"flxgettm" printf("flex_gettime");
+"flxerror" printf("flexerror");
+"flxfatal" printf("flexfatal");
+"fmtptmsg" printf("format_pinpoint_message");
+"gnNULtrn" printf("gen_NUL_trans");
+"gnbktrkg" printf("gen_backtracking");
+"gnbtactn" printf("gen_bt_action");
+"gnfndact" printf("gen_find_action");
+"gnlindir" printf("gen_line_dirs");
+"gnnxcste" printf("gen_next_compressed_state");
+"gnnxmtch" printf("gen_next_match");
+"gnnxtst" printf("gen_next_state");
+"gnstrtst" printf("gen_start_state");
+"hshentry" printf("hash_entry");
+"hshfct" printf("hashfunct");
+"incmxdfa" printf("increase_max_dfas");
+"indput2s" printf("indent_put2s");
+"indputs" printf("indent_puts");
+"infilnam" printf("infilename");
+"inp_fles" printf("input_files");
+"intractv" printf("interactive");
+"lndirout" printf("line_directive_out");
+"lnkmchns" printf("link_machines");
+"lst_cset" printf("list_character_set");
+"maketbls" printf("make_tables");
+"mkbgnorm" printf("mark_beginning_as_normal");
+"mktmplat" printf("mktemplate");
+"nbktrckg" printf("num_backtracking");
+"ninfiles" printf("num_input_files");
+"numraloc" printf("num_reallocs");
+"numrules" printf("num_rules");
+"nuxlatns" printf("num_xlations");
+"numnpair" printf("numsnpairs");
+"outfilnm" printf("output_file_name");
+"peakpair" printf("peakpairs");
+"perf_rep" printf("performance_report");
+"pptmsg" printf("pinpoint_message");
+"plcstate" printf("place_state");
+"prvctdan" printf("previous_continued_action");
+"prtstats" printf("printstats");
+"pgm_name" printf("program_name");
+"prtcomst" printf("protcomst");
+"rdblefrm" printf("readable_form");
+"realrjct" printf("real_reject");
+"rallocar" printf("reallocate_array");
+"rjctused" printf("reject_really_used");
+"rulelnno" printf("rule_linenum");
+"ruletype" printf("rule_type");
+"stinpfle" printf("set_input_file");
+"setupia" printf("set_up_initial_allocations");
+"startime" printf("starttime");
+"ste_type" printf("state_type");
+"symfollo" printf("symfollowset");
+"sympartn" printf("sympartition");
+"syntxerr" printf("syntaxerror");
+"tmpactfl" printf("temp_action_file");
+"todohead" printf("todo_head");
+"todonext" printf("todo_next");
+"trnschar" printf("transchar");
+"trnstout" printf("transition_struct_out");
+"trlcntxt" printf("trlcontxt");
+"vtrailrl" printf("variable_trail_rule");
+"vtrlctrl" printf("variable_trailing_context_rules");
+"varlngth" printf("varlength");
+"yycrbffr" printf("yy_create_buffer");
+"yydlbffr" printf("yy_delete_buffer");
+"yyinbffr" printf("yy_init_buffer");
+"yyldbfst" printf("yy_load_buffer_state");
+"yyswtobf" printf("yy_switch_to_buffer");
+"yyerrflg" printf("yyerrflag");
+"yymrreus" printf("yymore_really_used");
+"yymrused" printf("yymore_used");
+"yyrestrt" printf("yyrestart");
+. ECHO;
+%%
+main()
+{
+ yylex();
+}
diff --git a/Tools/android/flex-2.5.4a/MISC/Macintosh/THINK_C_notes b/Tools/android/flex-2.5.4a/MISC/Macintosh/THINK_C_notes
new file mode 100644
index 0000000..e99c972
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Macintosh/THINK_C_notes
@@ -0,0 +1,100 @@
+Notes on the THINK C version of Flex 2.4.6
+Scott Hofmann 23-JUL-94
+Internet: scotth@visix.com
+
+The only changes needed to compile Flex 2.4.6 under Symantec C++ 6.0 was
+to #include <console.h> in main.c and call ccommand() just before flexinit()
+in main(). The notes below are mostly of historical significance only; most
+of the workarounds below were to get around restrictions/problems in earlier
+versions of THINK C. The only section which still applies is Russell Finn's
+description of how to make Flex generate output of type 'KAHL'. Also, 4-byte
+ints must be used by any project which uses Flex output.
+
+If you want to recreate the project, you'll need to add the files
+alloca.c and xmalloc.c in this directory. Both files are copylefted; see
+the GNU General Public License for details. You will also need to recompile
+both the ANSI and unix libraries to use 4 byte ints, and if you want the
+files that flex creates to have 'KAHL' as the creator you'll need to apply
+Russell Finn's patch.
+
+Notes on the THINK C version of Flex 2.3.7
+Jonas Barklund, 25-JAN-92
+Internet: jonas@csd.uu.se
+
+I have merged the sources for Flex version 2.3.7 with the older version
+which was hacked for THINK C version 4. I have conditionalized the code
+so that I think it should work with both THINK C version 4 and 5 (for
+those of you who don't know: the THINK_C symbol is defined as 1 in version
+4 and as 5 in version 5). I have put in some missing prototypes, so it
+compiles also with "require prototypes" on.
+
+Most of the notes below still apply, in particular that about the MakeRes
+program.
+
+
+Notes on the THINK C version of Flex
+Russell S. Finn, 19-FEB-90
+Internet: rsfinn@athena.mit.edu, rsfinn@neutron.lcs.mit.edu
+CompuServe: 76377,1107
+GEnie: RSFINN
+
+Flex appears to be covered by a copyright notice from the University of
+California, similar to the one covering Berkeley Unix; the Free Software
+Foundation is not part of the picture here. So here is a version
+created with THINK C 4.0, along with the source code; as with the
+Bison distribution, I am including *all* of the source code I received
+with the package.
+
+The current version (modification date January 25, 1990) has only the
+bare-bones interface provided by the THINK C library routine "ccommand",
+which allows the user to type a command line and to redirect the output.
+Perhaps someday I may try to implement a "real" user interface; perhaps
+not.
+
+The only modifications made to the source file are surrounded by "#ifdef
+THINK_C"..."#endif"; in theory, then, these sources could be recompiled
+on another system if necessary. These are the actual files modified:
+alloca.c, dfa.c, flexdef.h, main.c, misc.c, scan.c, sym.c. Most of these
+changes were minor, and many of them would have been unnecessary if the
+original Flex source code had been written for an ANSI-compliant C compiler.
+In addition, the file "macutils.c" is completely new; see the discussion
+of "MakeRes" below.
+
+THINK C users may find it convenient to have the output text files written
+by Flex be THINK C documents. To do this, create a copy of the "ANSI"
+project called "ANSI-KAHL", and a copy of the file "fopen.c" called
+"fopen-KAHL.c". In the copy, find the routine "setfiletype", and replace
+the lines:
+ if (!(oflag & F_BINARY))
+ pb.ioFlFndrInfo.fdType = 'TEXT';
+with the lines:
+ if (!(oflag & F_BINARY)) {
+ pb.ioFlFndrInfo.fdType = 'TEXT';
+ pb.ioFlFndrInfo.fdCreator = 'KAHL';
+ }
+Replace "fopen.c" with the new "fopen-KAHL.c", rebuild the new project
+"ANSI-KAHL", and use this project in the project file "Flex.¹"
+instead of the "ANSI" project.
+
+** The "MakeRes" program
+
+The output files created by Flex contain large amounts of preinitialized
+static data; the file "scan.c" contained in the Flex.¹ project is one
+such file. However, the Macintosh architecture limits normal applications
+to 32K of global data. In many cases (including Flex), this limit can
+be surpassed by the static data generated by Flex.
+
+The solution I have implemented for the THINK C version of Flex is to
+extract the data tables from the Flex output file, and paste them into
+the file "MakeRes.c". Then, by recompiling and running the program in
+the "MakeRes.¹" project (it is not necessary to create an application),
+a resource file called "Flex.¹.rsrc" is created in the current directory.
+The Flex output file "scan.c" has been modified to load the static data
+from the resource fork of the Flex application. This is done by calling
+the "load_table" function, which is defined in the file "macutils.c".
+
+In the application for which I needed Flex, the data tables were small
+enough that I didn't need to do this. However, if your application
+requires you to do this, simply follow the model of "scan.c"; the MakeRes
+project and source code has been included for your use.
+
diff --git a/Tools/android/flex-2.5.4a/MISC/Macintosh/alloca.c b/Tools/android/flex-2.5.4a/MISC/Macintosh/alloca.c
new file mode 100644
index 0000000..9cb6fa0
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Macintosh/alloca.c
@@ -0,0 +1,195 @@
+/*
+ alloca -- (mostly) portable public-domain implementation -- D A Gwyn
+
+ last edit: 86/05/30 rms
+ include config.h, since on VMS it renames some symbols.
+ Use xmalloc instead of malloc.
+
+ This implementation of the PWB library alloca() function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+
+ It should work under any C implementation that uses an
+ actual procedure stack (as opposed to a linked list of
+ frames). There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca()-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection.
+*/
+#ifndef lint
+static char SCCSid[] = "@(#)alloca.c 1.1"; /* for the "what" utility */
+#endif
+
+#ifdef emacs
+#include "config.h"
+#ifdef static
+/* actually, only want this if static is defined as ""
+ -- this is for usg, in which emacs must undefine static
+ in order to make unexec workable
+ */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+#ifndef alloca /* If compiling with GCC, this file's not needed. */
+
+#ifdef __STDC__
+typedef void *pointer; /* generic pointer type */
+#else
+typedef char *pointer; /* generic pointer type */
+#endif
+
+#define NULL 0 /* null pointer constant */
+
+extern void free();
+extern pointer xmalloc();
+
+/*
+ Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown
+*/
+
+#ifndef STACK_DIRECTION
+#define STACK_DIRECTION 0 /* direction unknown */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define STACK_DIR STACK_DIRECTION /* known at compile-time */
+
+#else /* STACK_DIRECTION == 0; need run-time code */
+
+static int stack_dir; /* 1 or -1 once known */
+#define STACK_DIR stack_dir
+
+static void
+find_stack_direction (/* void */)
+{
+ static char *addr = NULL; /* address of first
+ `dummy', once known */
+ auto char dummy; /* to get stack address */
+
+ if (addr == NULL)
+ { /* initial entry */
+ addr = &dummy;
+
+ find_stack_direction (); /* recurse once */
+ }
+ else /* second entry */
+ if (&dummy > addr)
+ stack_dir = 1; /* stack grew upward */
+ else
+ stack_dir = -1; /* stack grew downward */
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/*
+ An "alloca header" is used to:
+ (a) chain together all alloca()ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc()
+ alignment chunk size. The following default should work okay.
+*/
+
+#ifndef ALIGN_SIZE
+#define ALIGN_SIZE sizeof(double)
+#endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* to force sizeof(header) */
+ struct
+ {
+ union hdr *next; /* for chaining headers */
+ char *deep; /* for stack depth measure */
+ } h;
+} header;
+
+/*
+ alloca( size ) returns a pointer to at least `size' bytes of
+ storage which will be automatically reclaimed upon exit from
+ the procedure that called alloca(). Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32.
+*/
+
+static header *last_alloca_header = NULL; /* -> last alloca header */
+
+pointer
+alloca (size) /* returns pointer to storage */
+ unsigned size; /* # bytes to allocate */
+{
+ auto char probe; /* probes stack depth: */
+ register char *depth = &probe;
+
+#if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* unknown growth direction */
+ find_stack_direction ();
+#endif
+
+ /* Reclaim garbage, defined as all alloca()ed storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ register header *hp; /* traverses linked list */
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if ((STACK_DIR > 0 && hp->h.deep > depth)
+ || (STACK_DIR < 0 && hp->h.deep < depth))
+ {
+ register header *np = hp->h.next;
+
+ free ((pointer) hp); /* collect garbage */
+
+ hp = np; /* -> next header */
+ }
+ else
+ break; /* rest are not deeper */
+
+ last_alloca_header = hp; /* -> last valid storage */
+ }
+
+ if (size == 0)
+ return NULL; /* no allocation required */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ register pointer new = xmalloc (sizeof (header) + size);
+
+ /* address of header */
+
+ ((header *)new)->h.next = last_alloca_header;
+ ((header *)new)->h.deep = depth;
+
+ last_alloca_header = (header *)new;
+
+ /* User storage begins just after header. */
+
+ return (pointer)((char *)new + sizeof(header));
+ }
+}
+
+#endif /* no alloca */
diff --git a/Tools/android/flex-2.5.4a/MISC/Macintosh/alloca.h b/Tools/android/flex-2.5.4a/MISC/Macintosh/alloca.h
new file mode 100644
index 0000000..f48eaf2
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Macintosh/alloca.h
@@ -0,0 +1,10 @@
+/****************
+** alloca.h
+**
+** header for alloca()
+*****************/
+
+typedef void *pointer;
+
+pointer alloca(unsigned size);
+
diff --git a/Tools/android/flex-2.5.4a/MISC/Macintosh/xmalloc.c b/Tools/android/flex-2.5.4a/MISC/Macintosh/xmalloc.c
new file mode 100644
index 0000000..5bef831
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/Macintosh/xmalloc.c
@@ -0,0 +1,69 @@
+/* xmalloc.c -- malloc with out of memory checking
+ Copyright (C) 1990, 1991 Free Software Foundation, Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2, or (at your option)
+ any later version.
+
+ This program 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 General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+#if STDC_HEADERS || THINK_C
+#include <stdlib.h>
+#else
+char *malloc ();
+char *realloc ();
+void free ();
+#endif
+
+#ifdef THINK_C
+#define error(x, y, z) perror(z) /* Throw out meaningless arguments */
+#else
+void error ();
+#endif
+
+/* Allocate N bytes of memory dynamically, with error checking. */
+
+char *
+xmalloc (n)
+ unsigned n;
+{
+ char *p;
+
+ p = malloc (n);
+ if (p == 0)
+ /* Must exit with 2 for `cmp'. */
+ error (2, 0, "virtual memory exhausted");
+ return p;
+}
+
+/* Change the size of an allocated block of memory P to N bytes,
+ with error checking.
+ If P is NULL, run xmalloc.
+ If N is 0, run free and return NULL. */
+
+char *
+xrealloc (p, n)
+ char *p;
+ unsigned n;
+{
+ if (p == 0)
+ return xmalloc (n);
+ if (n == 0)
+ {
+ free (p);
+ return 0;
+ }
+ p = realloc (p, n);
+ if (p == 0)
+ /* Must exit with 2 for `cmp'. */
+ error (2, 0, "virtual memory exhausted");
+ return p;
+}
diff --git a/Tools/android/flex-2.5.4a/MISC/NT/Makefile b/Tools/android/flex-2.5.4a/MISC/NT/Makefile
new file mode 100644
index 0000000..581d497
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/NT/Makefile
@@ -0,0 +1,103 @@
+#
+# make file for "flex" tool
+# @(#) $Header: /usr/fsys/odin/a/vern/flex/RCS/Makefile,v 2.9
+# 90/05/26 17:28:44 vern Exp $ (LBL)
+#
+# the first time around use "nmake f_flex"
+#
+# This makefile is specific for Microsoft's Visual C 2.0, & nmake
+#
+# - Stan Adermann <stana@leonardo.lmt.com>
+#
+
+
+SKELFLAGS = -DDEFAULT_SKELETON_FILE=\"c:/src/flex/flex.skl\"
+CFLAGS = -nologo -W2 -F 8000 -Ox -DUSG
+LDFLAGS = /nologo /BATCH /STACK:8000
+FLEX_FLAGS = -ist8 -Sflex.skl
+
+FLEX = .\flex.exe
+CC = cl
+YACC = c:\lib\byacc
+MAKE = nmake /nologo
+
+FLEXOBJS = \
+ ccl.obj \
+ dfa.obj \
+ ecs.obj \
+ gen.obj \
+ main.obj \
+ misc.obj \
+ nfa.obj \
+ parse.obj \
+ scan.obj \
+ skel.obj \
+ sym.obj \
+ tblcmp.obj \
+ yylex.obj
+
+FLEX_C_SOURCES = \
+ ccl.c \
+ dfa.c \
+ ecs.c \
+ gen.c \
+ main.c \
+ misc.c \
+ nfa.c \
+ parse.c \
+ scan.c \
+ skel.c \
+ sym.c \
+ tblcmp.c \
+ yylex.c
+
+all : flex.exe
+
+flex.exe : $(FLEXOBJS)
+ link $(LDFLAGS) $(FLEXOBJS) -out:$*.exe
+
+f_flex:
+ copy initscan.c scan.c
+ touch scan.c
+ @echo compiling first flex
+ $(MAKE) flex.exe
+ del scan.c
+ @echo using first flex to generate final version...
+ $(MAKE) flex.exe
+
+#
+# general inference rule
+#
+.c.obj:
+ $(CC) -c $(CFLAGS) $*.c
+
+parse.h parse.c : parse.y
+ $(YACC) -d parse.y
+ @move y_tab.c parse.c
+ @move y_tab.h parse.h
+
+scan.c : scan.l
+ $(FLEX) $(FLEX_FLAGS) $(COMPRESSION) scan.l >scan.c
+
+
+scan.obj : scan.c parse.h flexdef.h
+
+main.obj : main.c flexdef.h
+ $(CC) $(CFLAGS) -c $(SKELFLAGS) main.c
+
+ccl.obj : ccl.c flexdef.h
+dfa.obj : dfa.c flexdef.h
+ecs.obj : ecs.c flexdef.h
+gen.obj : gen.c flexdef.h
+misc.obj : misc.c flexdef.h
+nfa.obj : nfa.c flexdef.h
+parse.obj : parse.c flexdef.h
+sym.obj : sym.c flexdef.h
+tblcmp.obj : tblcmp.c flexdef.h
+yylex.obj : yylex.c flexdef.h
+skel.obj : skel.c flexdef.h
+
+
+clean :
+ del *.obj
+ del *.map
diff --git a/Tools/android/flex-2.5.4a/MISC/NT/config.h b/Tools/android/flex-2.5.4a/MISC/NT/config.h
new file mode 100644
index 0000000..17e831a
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/NT/config.h
@@ -0,0 +1,32 @@
+/* config.h. Generated automatically by configure. */
+/* $Header: /home/daffy/u0/vern/flex/RCS/conf.in,v 1.2 95/01/09
+12:11:51 vern Exp $ */
+
+/* Define to empty if the keyword does not work. */
+/* #undef const */
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+/* #undef size_t */
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have <alloca.h> and it should be used (not on
+Ultrix). */
+#define HAVE_ALLOCA_H 0
+
+/* Define if platform-specific command line handling is necessary. */
+/* #undef NEED_ARGV_FIXUP */
+
+/* Define if you use FAT file system, leave undefined for NTFS */
+#undef SHORT_FILE_NAMES
+/* #define SHORT_FILE_NAMES 1 */
diff --git a/Tools/android/flex-2.5.4a/MISC/NeXT b/Tools/android/flex-2.5.4a/MISC/NeXT
new file mode 100644
index 0000000..f862a1f
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/NeXT
@@ -0,0 +1,34 @@
+this API is not documented/supported by NeXT and may go away at any time,
+ so test again when you upgrade (works fine for me on NEXTSTEP_Dev_3.2)
+-------------------------------------------------------------------------
+See KBNS.32.2.029 from the successor of:
+ftp://ftp.cs.orst.edu/software/NeXT/documents/KBNS.32.1.rtf
+Otherwise (that successor not yet having been published), ask me for a copy
+of the item on RfSchtkt@maze.ruca.ua.ac.be. Bison's messages are not as
+disciplined as flex' ones, so it should get more discipline first.
+
+Specifically (in addition to what's described in the KBNS item):
+makeUser.o and make_support.o should be added to OBJECTS in Makefile.in
+In parse.y, line_pinpoint() (assumption all messages ultimately go there), add:
+ make_support(
+ // don't worry about declaring: cc's source doesn't either,
+ // it seems
+ syntaxerror?0:1,
+ NULL,
+ infilename,
+ line,
+ str,
+ 0,0,0
+ );
+
+FMyIO: in cc, these files contain the word make_support:
+ ChangeLog-NeXT
+ Makefile.in
+ config/next.h: defines REPORT_EVENT in terms of make_support
+ make_support.c
+
+FMyIO: in cc, these files contain the word REPORT_EVENT:
+ cccp.c
+ config/next.h
+ gcc.c
+ toplev.c
diff --git a/Tools/android/flex-2.5.4a/MISC/OS2/Makefile.os2 b/Tools/android/flex-2.5.4a/MISC/OS2/Makefile.os2
new file mode 100644
index 0000000..e984f6d
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/OS2/Makefile.os2
@@ -0,0 +1,72 @@
+# make file for "flex" tool, emx+gcc
+
+release:
+ $(MAKE) -f Makefile.os2 flex.exe \
+ CC="gcc -Zomf -O" O=".obj" A=".lib" AR="emxomfar" \
+ LDFLAGS="-s -Zcrtdll -Zstack 512"
+debug:
+ $(MAKE) -f Makefile.os2 flex.exe \
+ CC="gcc -g" O=".o" A=".a" AR="ar"
+
+CFLAGS = -DOS2 -DSHORT_FILE_NAMES
+
+YACC = bison
+FLEX = flex
+FLEX_FLAGS = -ist
+
+.SUFFIXES: .c $O
+
+.c$O:
+ $(CC) $(CFLAGS) -c $<
+
+FLEXLIB = fl$A
+FLEXOBJS = ccl$O dfa$O ecs$O gen$O main$O misc$O nfa$O parse$O \
+ scan$O skel$O sym$O tblcmp$O yylex$O
+LIBOBJS = libmain$O libyywrap$O
+
+flex.exe : $(FLEXOBJS) $(FLEXLIB)
+ $(CC) $(LDFLAGS) -o $@ $(FLEXOBJS) $(FLEXLIB)
+
+first_flex:
+ cp initscan.c scan.c
+ $(MAKE) $(MFLAGS) flex
+
+$(FLEXLIB): $(LIBOBJS)
+ $(AR) cru $(FLEXLIB) $(LIBOBJS)
+ $(AR) s $(FLEXLIB)
+
+parse.h parse.c: parse.y
+ $(YACC) -d -o parse.c parse.y
+
+scan.c : scan.l
+ $(FLEX) $(FLEX_FLAGS) $(COMPRESSION) scan.l >scan.c
+
+scan$O : scan.c parse.h flexdef.h
+
+main$O : main.c flexdef.h
+ccl$O : ccl.c flexdef.h
+dfa$O : dfa.c flexdef.h
+ecs$O : ecs.c flexdef.h
+gen$O : gen.c flexdef.h
+misc$O : misc.c flexdef.h
+nfa$O : nfa.c flexdef.h
+parse$O : parse.c flexdef.h
+sym$O : sym.c flexdef.h
+tblcmp$O : tblcmp.c flexdef.h
+yylex$O : yylex.c flexdef.h
+
+skel.c: flex.skl mkskel.sh
+ $(SHELL) mkskel.sh flex.skl >skel.c
+
+test : flex
+ flex $(FLEX_FLAGS) $(COMPRESSION) scan.l | diff scan.c -
+
+bigtest :
+ rm -f scan.c ; $(MAKE) COMPRESSION="-C" test
+ rm -f scan.c ; $(MAKE) COMPRESSION="-Ce" test
+ rm -f scan.c ; $(MAKE) COMPRESSION="-Cm" test
+ rm -f scan.c ; $(MAKE) COMPRESSION="-Cfe" test
+ rm -f scan.c ; $(MAKE) COMPRESSION="-CFe" test
+ rm -f scan.c ; $(MAKE) COMPRESSION="-Cf" test
+ rm -f scan.c ; $(MAKE) COMPRESSION="-CF" test
+ rm -f scan.c ; $(MAKE)
diff --git a/Tools/android/flex-2.5.4a/MISC/OS2/config.h b/Tools/android/flex-2.5.4a/MISC/OS2/config.h
new file mode 100644
index 0000000..acf7b86
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/OS2/config.h
@@ -0,0 +1,28 @@
+/* ------------------------------------------------ */
+/* version of config.h for OS/2 */
+/* ------------------------------------------------ */
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#define HAVE_ALLOCA_H
+
+/* Define if platform-specific command line handling is necessary. */
+#define NEED_ARGV_FIXUP
+#define argv_fixup(ac,av) { _response(ac,av); _wildcard(ac,av);}
diff --git a/Tools/android/flex-2.5.4a/MISC/README b/Tools/android/flex-2.5.4a/MISC/README
new file mode 100644
index 0000000..dc16b02
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/README
@@ -0,0 +1,76 @@
+Miscellaneous flex stuff. The items which have been tested with flex 2.5 are:
+
+ - texinfo/, a subdirectory containing a "texinfo" version of flex(1)
+ and the corresponding "info" files (contributed by Francois Pinard).
+
+ - VMS/, a subdirectory containing makefiles, configuration files,
+ run-time support, and installation notes for building flex 2.5
+ on VMS (contributed by Pat Rankin).
+
+ - Borland/ - makefile and config.h for Borland 4.02 compiler
+ (contributed by Terrence O Kane, who notes that no source
+ code changes were necessary).
+
+ - NT/ - Makefile and config.h for NT, contributed by Stan Adermann.
+
+ - OS2/ - Makefile and config.h for building flex under OS/2,
+ contributed by Kai Uwe Rommel.
+
+ - Amiga/: notes on building flex for the Amiga, contributed
+ by Andreas Scherer.
+
+ - parse.c, parse.h - output of running yacc (byacc, actually)
+ on parse.y. If your system doesn't have a flavor of yacc available,
+ copy these into the main flex source directory instead.
+
+ - flex.man - preformatted version of flex man page
+
+
+The following have been tested using flex 2.4:
+
+ - debflex.awk, an awk script for anotating flex debug output.
+ It presently only works with gawk and mawk, not with "old"
+ or "new" awk.
+
+ - NeXT: ProjectBuilder.app support for use in the NeXT world.
+
+ - Notes on building flex for the Macintosh using Think-C,
+ in the Macintosh/ subdirectory.
+
+ - testxxLexer.l, a sample C++ program that uses flex's scanner
+ class option ("-+").
+
+ - fastwc/, a subdirectory containing examples of how to use flex
+ to write progressively higher-performance versions of the Unix
+ "wc" utility. This certainly should work with 2.5, but hasn't
+ been tested.
+
+ - Borland.old/: notes on building flex 2.4 for Borland C++ 3.1
+ on MS-DOS. These shouldn't be needed for flex 2.5. Included
+ only in case you encounter unanticipated difficulties.
+
+ - EBCDIC: contact information for building flex for EBCDIC.
+
+
+The following are all out-of-date with respect to flex release 2.4 (and
+in general up-to-date for flex 2.3):
+
+ - Atari/Atari.patches, patches for porting flex to the Atari and
+ to Minix.
+
+ - A number of notes and Makefiles for compiling flex under MS-DOS,
+ in the MSDOS/ subdirectory.
+
+ - Notes on building flex for MVS, in the MVS/ subdirectory.
+
+If any of this is out-of-date and can be deleted, please let me know.
+
+And the following is included for compatibility with some broken versions
+of bison:
+
+ - alloca.c, a public-domain, mostly-portable version of the
+ alloca() routine (used by bison's parsers) written by D. A. Gwyn.
+
+
+Many thanks to those who contributed these files. Updated versions will
+be appreciated!
diff --git a/Tools/android/flex-2.5.4a/MISC/VMS/README.VMS b/Tools/android/flex-2.5.4a/MISC/VMS/README.VMS
new file mode 100644
index 0000000..e4a4966
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/VMS/README.VMS
@@ -0,0 +1,83 @@
+Brief instructions for building flex 2.5.x for VMS:
+
+ 0) if you have either MMS (from Digital) or MMK (freeware) for use
+as a `make' utility, follow the directions in steps #1 through #5 below.
+If not, execute
+ @BUILD.COM xxxC
+where "xxxC" is either "VAXC" or "DECC" or "GNUC", and then skip to
+step #5.
+
+ 1) set default to the source directory (not the [.MISC.VMS] subdirectory
+where this file is located).
+
+ 2) COPY [.MISC.VMS]DESCRIP.MMS []*.*
+(Recursive invocations of `make' for the `bigcheck' test assume that the
+makefile will be found as descrip.mms in the current directory.)
+
+To build with VAX C for VAX/VMS:
+ 3) MMS /MACRO=("VAXC=1") FLEX.EXE
+(The /macro qualifier is optional in this case.)
+
+To build with GNU C for VAX/VMS:
+ 2.5) possibly edit descrip.mms to uncomment `SET COMMAND' for GCCINIT,
+ depending on local site configuration
+ 3) MMS /MACRO=("GNUC=1") FLEX.EXE
+
+To build with DEC C for either VAX/VMS or Alpha/VMS:
+ 3) MMS /MACRO=("DECC=1") FLEX.EXE
+(Expect one or two informational messages from the compiler about
+implicitly declared functions.)
+
+Minimal testing of the resulting program:
+ 4) MMS CHECK
+(If `diff' reports no warnings, the test has succeeded.)
+
+More thorough testing:
+ 4.5) MMS /MACRO=("xxxC=1") BIGCHECK ! "xxxC=1" as in step #3 above
+(If using an older version of MMK rather than MMS, this might fail when
+`make' is invoked recursively due to excessive BYTLM usage by MMK.)
+
+Installation (the VMS makefile does not support an `install' target;
+you'll need to do this part manually):
+ 5) copy flex.exe, flex.doc, flex.skl, flexlib.olb, and FlexLexer.h to
+location(s) appropriate for your site. To use flex, define a "foreign"
+command by making a DCL symbol whose value begins with a dollar sign
+immediately followed by the filename for flex.exe, as in
+ $ flex :== $local_tools:flex.exe
+where `local_tools:' is the logical name pointing to flex.exe's location.
+This symbol will ordinarily be a candidate for your login.com. When
+invoking flex, upper- or mixed-case command line options must be enclosed
+in quotes. For example,
+ $ flex "-Pxyz" "-L" -t mylexer.l > mylexer.c
+(use prefix "xyz" instead of "yy", suppress `#line' compiler directives
+in the output, write the output to `stdout', process file mylexer.l,
+and capture `stdout' in file mylexer.c). As illustrated here, this VMS
+version of flex supports emulation of command line I/O redirection used
+by Unix shells.
+
+ flex.exe -- the executable image for the flex program;
+ flex.doc -- documentation, the "man page" describing flex (flex.1
+ processed with `nroff -man' followed by `col -b');
+ flex.skl -- a text file containing flex's default skeleton;
+ with this version of flex, it is for reference only;
+ flex.exe does not need to know where to find it;
+ flexlib.olb -- an object library containing some support routines;
+ you might need to link your generated lexer against
+ it, depending on how your program is designed;
+ flex.exe does not access it; it corresponds to
+ `libfl.a' under Unix;
+ FlexLexer.h -- header file used for C++ class-based lexers; not
+ needed for ordinary C lexers.
+
+Notes:
+ This VMS port of flex supports only the original Unix command line
+interface, not the native DCL interface which was available for flex 2.3.
+
+ build.com -- DCL command procedure as alternative to descrip.mms;
+ descrip.mms -- 2.5.x makefile for use with MMS or MMK (see step #1);
+ mkskel.tpu -- TPU program used to make skel.c from flex.skl for full
+ build from scratch; performs same function as mkskel.sh;
+ vms-conf.h -- pre-configured `conf.in', copied to [-.-]config.h;
+ vms-code.c -- VMS-specific support code, copied to [-.-]vms-code.c;
+ README.VMS -- this file
+
diff --git a/Tools/android/flex-2.5.4a/MISC/VMS/build.com b/Tools/android/flex-2.5.4a/MISC/VMS/build.com
new file mode 100644
index 0000000..dbde55a
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/VMS/build.com
@@ -0,0 +1,155 @@
+$! VMS build procedure for flex 2.5.x;
+$ v = 'f$verify(0)'
+$!
+$! usage:
+$! $ @[.MISC.VMS]BUILD.COM compiler parser [test]
+$! where `compiler' is either "GNUC" or "DECC" or "VAXC" or empty
+$! and `parser' is either "BISON" or "BYACC" or "YACC" or empty
+$! and `[test]' is either "CHECK-ONLY" or "NO-CHECK" or empty
+$! empty compiler defaults to VAX C (even under Alpha/VMS);
+$! special "LINK" compiler value does link without compilation;
+$! empty parser defaults to using supplied parse code in [.MISC];
+$! optional test is performed by default.
+$!
+$
+$! we start from [.MISC.VMS], then move to the main source directory
+$ where = f$parse("_._;",f$environ("PROCEDURE")) - "_._;"
+$ set default 'where'
+$ brkt = f$extract(f$length(where)-1,1,where)
+$ if f$locate(".MISC.VMS"+brkt,where).lt.f$length(where) then -
+ set default 'f$string(f$extract(0,1,f$dir()) + "-.-" + brkt)'
+$
+$ p1 := 'p1'
+$ p2 := 'p2'
+$ p3 := 'p3'
+$ if p1.eqs."LINK" then goto link
+$ if p3.eqs."CHECK-ONLY" then goto check
+$ p2 = p2 - "_PARSER"
+$!
+$ CDEFS = "/Define=(""VMS"")" ! =(""VMS"",""DEFAULT_CSIZE=256"")
+$!
+$ if p1.eqs."GNUC"
+$ then CC = "gcc"
+$ CFLAGS = "/noList/Opt=2/Debug/noVerbose"
+$ LIBS = "gnu_cc:[000000]gcclib.olb/Library, sys$library:vaxcrtl.olb/Library"
+$ else CC = "cc"
+$ if p1.eqs."DECC"
+$ then CFLAGS = "/noList/Prefix=All"
+$ LIBS = ""
+$ if f$trnlnm("DECC$CC_DEFAULT").nes."" then CC = CC + "/DECC"
+$ else CFLAGS = "/noList/Optimize=noInline"
+$ LIBS = "sys$share:vaxcrtl.exe/Shareable"
+$ if f$trnlnm("DECC$CC_DEFAULT").nes."" then CC = CC + "/VAXC"
+$ if p1.nes."" .and. p1.nes."VAXC" then exit %x002C
+$ endif
+$ endif
+$!
+$ no_parser = 0
+$ if p2.eqs."BISON"
+$ then YACC = "bison"
+$ YACCFLAGS = "/Defines/Fixed_Outfiles"
+$ ALLOCA = ",[]alloca.obj"
+$ else
+$ YACCFLAGS = "-d"
+$ ALLOCA = ""
+$ if p2.eqs."BYACC" .or. p2.eqs."YACC"
+$ then YACC = f$edit(p2,"LOWERCASE")
+$ else YACC = "! yacc"
+$ if p2.nes."" .and. p2.nes."NO" .and. p2.nes."NONE" then exit %x002C
+$ no_parser = 1
+$ endif
+$ endif
+$!
+$ ECHO = "write sys$output"
+$ COPY = "copy_"
+$ MOVE = "rename_/New_Vers"
+$ MUNG = "search_/Exact/Match=NOR"
+$ PURGE = "purge_/noConfirm/noLog"
+$ REMOVE = "delete_/noConfirm/noLog"
+$ TPU = "edit_/TPU/noJournal/noDisplay/noSection"
+$!
+$ if v then set verify
+$!
+$ 'COPY' [.misc.vms]vms-conf.h config.h
+$ 'COPY' [.misc.vms]vms-code.c vms-code.c
+$ 'COPY' [.misc]flex.man flex.doc
+$ if ALLOCA.nes."" then 'COPY' [.MISC]alloca.c alloca.c
+$ 'COPY' initscan.c scan.c !make.bootstrap
+$!
+$ if f$search("skel.c").nes."" then -
+ if f$cvtime(f$file_attr("skel.c","RDT")).gts. -
+ f$cvtime(f$file_attr("flex.skl","RDT")) then goto skip_mkskel
+$ 'TPU' /Command=[.misc.vms]mkskel.tpu flex.skl /Output=skel.c
+$skip_mkskel:
+$!
+$ if f$search("parse.c").nes."" .and. f$search("parse.h").nes."" then -
+ if f$cvtime(f$file_attr("parse.c","RDT")).gts. -
+ f$cvtime(f$file_attr("parse.y","RDT")) then goto skip_yacc
+$ if f$search("y_tab.%").nes."" then 'REMOVE' y_tab.%;*
+$ if no_parser
+$ then 'COPY' [.misc]parse.% sys$disk:[]y_tab.*
+$ else 'YACC' 'YACCFLAGS' parse.y
+$ endif
+$ 'MUNG' y_tab.c "#module","#line" /Output=parse.c
+$ 'REMOVE' y_tab.c;*
+$ 'MOVE' y_tab.h parse.h
+$skip_yacc:
+$!
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] ccl.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] dfa.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] ecs.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] gen.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] main.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] misc.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] nfa.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] parse.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] scan.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] skel.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] sym.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] tblcmp.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] yylex.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] vms-code.c
+$ if ALLOCA.nes."" then - !bison
+ 'CC' 'CFLAGS' /Define=("STACK_DIRECTION=-1","xmalloc=yy_flex_xmalloc") alloca.c
+$!
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] libmain.c
+$ 'CC' 'CFLAGS' 'CDEFS' /Include=[] libyywrap.c
+$ library/Obj flexlib.olb/Create libmain.obj,libyywrap.obj/Insert
+$ if f$search("flexlib.olb;-1").nes."" then 'PURGE' flexlib.olb
+$!
+$ open/Write optfile sys$disk:[]crtl.opt
+$ write optfile LIBS
+$ close optfile
+$ if f$search("crtl.opt;-1").nes."" then 'PURGE' crtl.opt
+$!
+$ version = "# flex ""2.5""" !default, overridden by version.h
+$ open/Read/Error=v_h_2 hfile version.h
+$ read/End=v_h_1 hfile version
+$v_h_1: close/noLog hfile
+$v_h_2: version = f$element(1,"""",version)
+$ open/Write optfile sys$disk:[]ident.opt
+$ write optfile "identification=""flex ''version'"""
+$ close optfile
+$ if f$search("ident.opt;-1").nes."" then 'PURGE' ident.opt
+$!
+$link:
+$ link/noMap/Exe=flex.exe ccl.obj,dfa.obj,ecs.obj,gen.obj,main.obj,misc.obj,-
+ nfa.obj,parse.obj,scan.obj,skel.obj,sym.obj,tblcmp.obj,yylex.obj,-
+ vms-code.obj 'ALLOCA' ,flexlib.olb/Lib,-
+ sys$disk:[]crtl.opt/Opt,sys$disk:[]ident.opt/Opt
+$!
+$ if p3.eqs."NO-CHECK" .or. p3.eqs."NOCHECK" then goto done
+$
+$check:
+$ 'ECHO' ""
+$ 'ECHO' " Checking with COMPRESSION="""""
+$ mcr sys$disk:[]flex.exe -t -p scan.l > scan.chk
+$ diff_/Output=_NL:/Maximum_Diff=1 scan.c scan.chk
+$ if $status
+$ then 'ECHO' " Test passed."
+$ 'REMOVE' scan.chk;*
+$ else 'ECHO' "? Test failed!"
+$ endif
+$
+$done:
+$ exit
diff --git a/Tools/android/flex-2.5.4a/MISC/VMS/descrip.mms b/Tools/android/flex-2.5.4a/MISC/VMS/descrip.mms
new file mode 100644
index 0000000..5b2859d
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/VMS/descrip.mms
@@ -0,0 +1,311 @@
+# descrip.mms -- makefile for building `flex' using MMS or MMK on VMS;
+# created manually from Makefile.in
+# flex 2.5.0 Jan'95
+
+MAKEFILE = descrip.mms # from [.MISC.VMS]
+MAKE = $(MMS) /Descr=$(MAKEFILE)
+MAKEFLAGS = $(MMSQUALIFIERS)
+
+# Possible values for DEFS:
+# "VMS" -- used just to make sure parentheses aren't empty;
+# For flex to always generate 8-bit scanners, append
+# ,"DEFAULT_CSIZE=256" inside /Define=() of DEFS.
+
+DEFS = /Define=("VMS")
+LDFLAGS = /noMap
+
+# compiler handling
+.ifdef GNUC
+CC = gcc
+GCCINIT = ! SET COMMAND GNU_CC:[000000]GCC
+CFLAGS = /noList/Opt=2/Debug/noVerbose
+LIBS = gnu_cc:[000000]gcclib.olb/Library, sys$library:vaxcrtl.olb/Library
+C_CHOICE = "GNUC=1"
+.else ! not GNU C
+CC = cc
+GCCINIT =
+.ifdef DECC
+CFLAGS = /noList/Prefix=All
+LIBS =
+C_CHOICE = "DECC=1"
+.else ! not DEC C; assume VAX C
+CFLAGS = /noList/Optimize=noInline
+LIBS = sys$share:vaxcrtl.exe/Shareable
+C_CHOICE = "VAXC=1"
+.endif
+.endif
+
+# parser handling
+# mms/macro=("xxxC=1","zzz_parser=1"), where "zzz_parser" is
+# either "bison_parser" or "byacc_parser" or "yacc_parser",
+# otherwise assumed to be "no_parser"; and where "xxxC=1" is
+# either "VAXC=1", "GNUC=1", or "DECC=1" as above
+.ifdef bison_parser
+YACC = bison
+YACCFLAGS = /Defines/Fixed_Outfiles
+YACCINIT = set command gnu_bison:[000000]bison
+ALLOCA = ,[]alloca.obj # note leading comma
+.else
+YACCFLAGS = -d
+YACCINIT =
+ALLOCA =
+.ifdef byacc_parser
+YACC = byacc
+.else
+.ifdef yacc_parser
+YACC = yacc
+.else
+# none of bison, byacc, or yacc specified
+.ifdef no_parser
+.else
+no_parser=1
+.endif #<none>
+.endif #yacc
+.endif #byacc
+.endif #bison
+
+# VMS-specific hackery
+ECHO = write sys$output # requires single quoted arg
+COPY = copy_ #
+MOVE = rename_/New_Vers # within same device only
+MUNG = search_/Exact/Match=NOR # to strip unwanted `#module' directive
+NOOP = continue # non-empty command that does nothing
+PURGE = purge_/noConfirm/noLog # relatively quiet file removal
+REMOVE = delete_/noConfirm/noLog # ditto
+TOUCH = append_/New _NL: # requires single file arg
+TPU = edit_/TPU/noJournal/noDisplay/noSection
+
+# You can define this to be "lex.exe" if you want to replace lex at your site.
+FLEX =flex.exe
+# note: there should be no whitespace between `=' and the name,
+# or else $(FLEX_EXEC) below will not function properly.
+FLEXLIB = flexlib.olb
+
+# You normally do not need to modify anything below this point.
+# ------------------------------------------------------------
+
+VMSDIR = [.MISC.VMS]
+MISCDIR = [.MISC]
+CURDIR = sys$disk:[]
+
+CPPFLAGS = $(DEFS)/Include=[]
+LIBOPT = $(CURDIR)crtl.opt # run-time library(s)
+ID_OPT = $(CURDIR)ident.opt # version identification
+
+.SUFFIXES : # avoid overhead of umpteen built-in rules
+.SUFFIXES : .obj .c
+
+.c.obj :
+ $(CC)$(CFLAGS)$(CPPFLAGS) $<
+
+VMSHDRS = $(VMSDIR)vms-conf.h # copied to []config.h
+VMSSRCS = $(VMSDIR)vms-code.c # copied to []vms-code.c
+VMSOBJS = ,vms-code.obj # note leading comma
+
+HEADERS = flexdef.h version.h
+
+SOURCES = ccl.c dfa.c ecs.c gen.c main.c misc.c nfa.c parse.y \
+ scan.l skel.c sym.c tblcmp.c yylex.c
+OBJECTS = ccl.obj,dfa.obj,ecs.obj,gen.obj,main.obj,misc.obj,nfa.obj,parse.obj,\
+ scan.obj,skel.obj,sym.obj,tblcmp.obj,yylex.obj $(VMSOBJS) $(ALLOCA)
+
+LIBSRCS = libmain.c libyywrap.c
+LIBOBJS = libmain.obj,libyywrap.obj
+
+LINTSRCS = ccl.c dfa.c ecs.c gen.c main.c misc.c nfa.c parse.c \
+ scan.c skel.c sym.c tblcmp.c yylex.c
+
+DISTFILES = README NEWS COPYING INSTALL FlexLexer.h \
+ configure.in conf.in Makefile.in mkskel.sh flex.skl \
+ $(HEADERS) $(SOURCES) $(LIBSRCS) MISC \
+ flex.1 scan.c install.sh mkinstalldirs configure
+
+DIST_NAME = flex
+
+# flex options to use when generating scan.c from scan.l
+COMPRESSION =
+PERF_REPORT = -p
+# which "flex" to use to generate scan.c from scan.l
+FLEX_EXEC = mcr $(CURDIR)$(FLEX)
+FLEX_FLAGS = -t $(PERF_REPORT) #$(COMPRESSION)
+
+MARKER = make.bootstrap
+
+##### targets start here #####
+
+all : $(FLEX) flex.doc
+ @ $(NOOP)
+
+install : $(FLEX) flex.doc flex.skl $(FLEXLIB) FlexLexer.h
+ @ $(ECHO) "-- Installation must be done manually."
+ @ $(ECHO) " $+"
+
+.ifdef GCCINIT
+.FIRST
+ $(GCCINIT)
+
+.endif #GCCINIT
+
+flex : $(FLEX)
+ @ $(NOOP)
+
+$(FLEX) : $(MARKER) $(OBJECTS) $(FLEXLIB) $(LIBOPT) $(ID_OPT)
+ $(LINK)/Exe=$(FLEX) $(LDFLAGS)\
+ $(OBJECTS),$(FLEXLIB)/Lib,$(LIBOPT)/Opt,$(ID_OPT)/Opt
+
+$(MARKER) : initscan.c
+ @- if f$search("scan.c").nes."" then $(REMOVE) scan.c;*
+ $(COPY) initscan.c scan.c
+ @ $(TOUCH) $(MARKER)
+
+parse.c : parse.y
+ @- if f$search("y_tab.%").nes."" then $(REMOVE) y_tab.%;*
+.ifdef no_parser
+ $(COPY) $(MISCDIR)parse.% $(CURDIR)y_tab.*
+.else
+ $(YACCINIT)
+ $(YACC) $(YACCFLAGS) parse.y
+.endif
+ $(MUNG) y_tab.c "#module","#line" /Output=parse.c
+ @- $(REMOVE) y_tab.c;*
+ $(MOVE) y_tab.h parse.h
+
+parse.h : parse.c
+ @ $(TOUCH) parse.h
+
+scan.c : scan.l
+ $(FLEX_EXEC) $(FLEX_FLAGS) $(COMPRESSION) scan.l > scan.c
+
+scan.obj : scan.c parse.h flexdef.h config.h
+yylex.obj : yylex.c parse.h flexdef.h config.h
+
+skel.c : flex.skl $(VMSDIR)mkskel.tpu
+ $(TPU) /Command=$(VMSDIR)mkskel.tpu flex.skl /Output=skel.c
+
+main.obj : main.c flexdef.h config.h version.h
+ccl.obj : ccl.c flexdef.h config.h
+dfa.obj : dfa.c flexdef.h config.h
+ecs.obj : ecs.c flexdef.h config.h
+gen.obj : gen.c flexdef.h config.h
+misc.obj : misc.c flexdef.h config.h
+nfa.obj : nfa.c flexdef.h config.h
+parse.obj : parse.c flexdef.h config.h
+skel.obj : skel.c flexdef.h config.h
+sym.obj : sym.c flexdef.h config.h
+tblcmp.obj : tblcmp.c flexdef.h config.h
+vms-code.obj : vms-code.c flexdef.h config.h
+
+[]alloca.obj : alloca.c
+ $(CC)$(CFLAGS)/Define=("STACK_DIRECTION=-1","xmalloc=yy_flex_xmalloc") alloca.c
+
+alloca.c : $(MISCDIR)alloca.c
+ $(COPY) $(MISCDIR)alloca.c alloca.c
+
+config.h : $(VMSDIR)vms-conf.h
+ $(COPY) $(VMSDIR)vms-conf.h config.h
+
+vms-code.c : $(VMSDIR)vms-code.c
+ $(COPY) $(VMSDIR)vms-code.c vms-code.c
+
+test : check
+ @ $(NOOP)
+check : $(FLEX)
+ @ $(ECHO) ""
+ @ $(ECHO) " Checking with COMPRESSION="$(COMPRESSION)""
+ $(FLEX_EXEC) $(FLEX_FLAGS) $(COMPRESSION) scan.l > scan.chk
+ diff_/Output=_NL:/Maximum_Diff=1 scan.c scan.chk
+
+bigcheck :
+ @- if f$search("scan.c").nes."" then $(REMOVE) scan.c;*
+ $(MAKE)$(MAKEFLAGS) /Macro=($(C_CHOICE),"COMPRESSION=""-C""") check
+ @- $(REMOVE) scan.c;*
+ $(MAKE)$(MAKEFLAGS) /Macro=($(C_CHOICE),"COMPRESSION=""-Ce""") check
+ @- $(REMOVE) scan.c;*
+ $(MAKE)$(MAKEFLAGS) /Macro=($(C_CHOICE),"COMPRESSION=""-Cm""") check
+ @- $(REMOVE) scan.c;*
+ $(MAKE)$(MAKEFLAGS) /Macro=($(C_CHOICE),"COMPRESSION=""-f""") check
+ @- $(REMOVE) scan.c;*
+ $(MAKE)$(MAKEFLAGS) /Macro=($(C_CHOICE),"COMPRESSION=""-Cfea""") check
+ @- $(REMOVE) scan.c;*
+ $(MAKE)$(MAKEFLAGS) /Macro=($(C_CHOICE),"COMPRESSION=""-CFer""") check
+ @- $(REMOVE) scan.c;*
+ $(MAKE)$(MAKEFLAGS) /Macro=($(C_CHOICE),"COMPRESSION=""-l""","PERF_REPORT=") check
+ @- $(REMOVE) scan.c;*,scan.chk;*
+ $(MAKE)$(MAKEFLAGS) $(FLEX)
+ @- $(PURGE) scan.obj
+ @ $(ECHO) "All checks successful"
+
+$(FLEXLIB) : $(LIBOBJS)
+ library/Obj $(FLEXLIB)/Create $(LIBOBJS)/Insert
+ @ if f$search("$(FLEXLIB);-1").nes."" then $(PURGE) $(FLEXLIB)
+
+# We call it .doc instead of .man, to lessen culture shock. :-}
+# If MISC/flex.man is out of date relative to flex.1, there's
+# not much we can do about it with the tools readily available.
+flex.doc : flex.1
+ @ if f$search("$(MISCDIR)flex.man").eqs."" then \
+ $(COPY) flex.1 $(MISCDIR)flex.man
+ $(COPY) $(MISCDIR)flex.man flex.doc
+
+#
+# This is completely VMS-specific...
+#
+
+# Linker options file specifying run-time library(s) to link against;
+# choice depends on which C compiler is used, and might be empty.
+$(LIBOPT) : $(MAKEFILE)
+ @ open/Write optfile $(LIBOPT)
+ @ write optfile "$(LIBS)"
+ @ close optfile
+
+# Linker options file putting the version number where the ANALYZE/IMAGE
+# command will be able to find and report it; assumes that the first line
+# of version.h has the version number enclosed within the first and second
+# double quotes on it [as in ``#define FLEX_VERSION "2.5.0"''].
+$(ID_OPT) : version.h
+ @ version = "# flex ""2.5""" !default, overridden by version.h
+ @- open/Read hfile version.h
+ @- read hfile version
+ @- close/noLog hfile
+ @ version = f$element(1,"""",version)
+ @ open/Write optfile $(ID_OPT)
+ @ write optfile "identification=""flex ''version'"""
+ @ close optfile
+
+
+#
+# This is the only stuff moderately useful from the remainder
+# of Makefile.in...
+#
+
+mostlyclean :
+ @- if f$search("scan.chk").nes."" then $(REMOVE) scan.chk;*
+ @- if f$search("*.obj;-1").nes."" then $(PURGE) *.obj
+ @- if f$search("*.exe;-1").nes."" then $(PURGE) *.exe
+ @- if f$search("*.opt;-1").nes."" then $(PURGE) *.opt
+
+clean : mostlyclean
+ @- if f$search("*.obj").nes."" then $(REMOVE) *.obj;*
+ @- if f$search("parse.h").nes."" then $(REMOVE) parse.h;*
+ @- if f$search("parse.c").nes."" then $(REMOVE) parse.c;*
+ @- if f$search("alloca.c").nes."" .and.-
+ f$search("$(MISCDIR)alloca.c").nes."" then $(REMOVE) alloca.c;*
+ @- if f$search("$(LIBOPT)").nes."" then $(REMOVE) $(LIBOPT);*
+ @- if f$search("$(ID_OPT)").nes."" then $(REMOVE) $(ID_OPT);*
+
+distclean : clean
+ @- if f$search("$(MARKER)").nes."" then $(REMOVE) $(MARKER);*
+ @- if f$search("$(FLEX)").nes."" then $(REMOVE) $(FLEX);*
+ @- if f$search("$(FLEXLIB)").nes."" then $(REMOVE) $(FLEXLIB);*
+ @- if f$search("flex.doc").nes."" then $(REMOVE) flex.doc;*
+ @- if f$search("scan.c").nes."" then $(REMOVE) scan.c;*
+ @- if f$search("vms-code.c").nes."" .and.-
+ f$search("$(VMSDIR)vms-code.c").nes."" then $(REMOVE) vms-code.c;*
+ @- if f$search("config.h").nes."" .and.-
+ f$search("$(VMSDIR)vms-conf.h").nes."" then $(REMOVE) config.h;*
+# @- if f$search("descrip.mms").nes."" .and.-
+# f$search("$(VMSDIR)descrip.mms").nes."" then $(REMOVE) descrip.mms;*
+
+realclean : distclean
+ @- if f$search("skel.c").nes."" then $(REMOVE) skel.c;*
+
diff --git a/Tools/android/flex-2.5.4a/MISC/VMS/mkskel.tpu b/Tools/android/flex-2.5.4a/MISC/VMS/mkskel.tpu
new file mode 100644
index 0000000..e20a0eb
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/VMS/mkskel.tpu
@@ -0,0 +1,45 @@
+! mkskel.tpu
+! usage:
+! edit/TPU/noDisplay/noSection/Command=mkskel.tpu flex.skl /Output=skel.c
+!
+! Create a C source file from the flex skeleton data. Copy the file,
+! changing backslash (\) to doubled backslash (\\) and quote (")
+! to backslash quote (\"). For each line, insert space+space+quote
+! at the beginning and quote+comma at the end. Bracket the updated
+! text with several lines of prologue and epilogue.
+!
+ skelfile := CREATE_BUFFER("file", GET_INFO(COMMAND_LINE, "file_name"));
+ SET(NO_WRITE, skelfile);
+ target := '"' | '\'; !do this once, outside loops
+ POSITION(BEGINNING_OF(skelfile)); !start here
+ rest_of_line := CREATE_RANGE(MARK(NONE), MARK(NONE)); !also outside loops
+ LOOP
+ EXITIF MARK(NONE) = END_OF(skelfile); !are we done yet?
+ COPY_TEXT(' "'); start_pos := MARK(NONE);
+ POSITION(LINE_END); end_pos := MARK(NONE);
+ MODIFY_RANGE(rest_of_line, start_pos, end_pos);
+ LOOP
+ next_match := SEARCH_QUIETLY(target, FORWARD, EXACT, rest_of_line);
+ EXITIF next_match = 0;
+ POSITION(BEGINNING_OF(next_match));
+ COPY_TEXT('\'); MOVE_HORIZONTAL(1); !past the matched character
+ MODIFY_RANGE(rest_of_line, MARK(NONE), end_pos);
+ ENDLOOP;
+ POSITION(LINE_END); COPY_TEXT('",');
+ MOVE_VERTICAL(1); POSITION(LINE_BEGIN); !go to next line
+ ENDLOOP;
+
+ POSITION(BEGINNING_OF(skelfile)); !insert five line prologue
+ COPY_TEXT('/* File created from flex.skl via mkskel.tpu */'); SPLIT_LINE;
+ SPLIT_LINE;
+ COPY_TEXT('#include "flexdef.h"'); SPLIT_LINE;
+ SPLIT_LINE;
+ COPY_TEXT('const char *skel[] = {'); SPLIT_LINE;
+
+ POSITION(END_OF(skelfile)); !append two line epilogue
+ COPY_TEXT(' 0'); SPLIT_LINE;
+ COPY_TEXT('};'); !! SPLIT_LINE;
+
+ WRITE_FILE(skelfile, GET_INFO(COMMAND_LINE, "output_file"));
+ QUIT
+!--<eof>--
diff --git a/Tools/android/flex-2.5.4a/MISC/VMS/vms-code.c b/Tools/android/flex-2.5.4a/MISC/VMS/vms-code.c
new file mode 100644
index 0000000..825a6b3
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/VMS/vms-code.c
@@ -0,0 +1,152 @@
+/* vms-code.c -- additional VMS-specific support code for flex
+ */
+
+#include "flexdef.h"
+
+static const char *original_arg0;
+static const char default_arg0[] = "flex.exe";
+
+#define IN_FD 0
+#define OUT_FD 1
+#define ERR_FD 2
+
+static char *fix_arg0 PROTO((const char *));
+
+/* Command line arguments fixup -- simplify argv[0], and handle `>'
+ output redirection request; called first thing from main(). */
+
+void argv_fixup( iargc, iargv )
+int *iargc;
+char ***iargv;
+{
+ const char *mode[3], *rfm[3], *name[3];
+ char *p;
+ int i, oargc, punct, which, append, alt_rfm;
+
+ /*
+ * Get original argv[0] supplied by run-time library startup code,
+ * then replace it with a stripped down one.
+ */
+ original_arg0 = (*iargv)[0];
+ (*iargv)[0] = fix_arg0(original_arg0);
+
+ /*
+ * Check command line arguments for redirection request(s).
+ * For simplicity, if multiple attempts are made, the last one wins.
+ */
+ name[0] = name[1] = name[2] = 0;
+ oargc = 1; /* number of args caller will see; count includes argv[0] */
+ for (i = 1; i < *iargc; i++) {
+ p = (*iargv)[i];
+ switch (*p) {
+ case '<':
+ /* might be "<dir>file"; then again, perhaps "<<dir>file" */
+ punct = (strchr(p, '>') != 0);
+ if (p[1] == '<') {
+ if (!punct || p[2] == '<')
+ flexerror("<<'sentinel' input not supported.");
+ punct = 0;
+ }
+ if (punct) /* the '<' seems to be directory punctuation */
+ goto arg; /*GOTO*/
+ mode[IN_FD] = "r";
+ rfm[IN_FD] = 0;
+ name[IN_FD] = ++p;
+ if (!*p && (i + 1) < *iargc)
+ name[IN_FD] = (*iargv)[++i];
+ break;
+ case '>':
+ append = (p[1] == '>');
+ if (append) ++p;
+ alt_rfm = (p[1] == '$');
+ if (alt_rfm) ++p;
+ which = (p[1] == '&' ? ERR_FD : OUT_FD);
+ if (which == ERR_FD) ++p;
+ mode[which] = append ? "a" : "w";
+ rfm[which] = alt_rfm ? "rfm=var" : "rfm=stmlf";
+ name[which] = ++p;
+ if (!*p && (i + 1) < *iargc)
+ name[which] = (*iargv)[++i];
+ break;
+ case '|':
+ flexerror("pipe output not supported.");
+ /*NOTREACHED*/
+ break;
+ default:
+ arg: /* ordinary option or argument */
+ (*iargv)[oargc++] = p;
+ break;
+ }
+ }
+ /* perform any requested redirection; don't bother with SYS$xxx logicals */
+ if (name[IN_FD])
+ if (!freopen(name[IN_FD], mode[IN_FD], stdin))
+ lerrsf("failed to redirect `stdin' from \"%s\"", name[IN_FD]);
+ if (name[OUT_FD])
+ if (!freopen(name[OUT_FD], mode[OUT_FD], stdout,
+ rfm[OUT_FD], "rat=cr", "mbc=32", "shr=nil"))
+ lerrsf("failed to redirect `stdout' to \"%s\"", name[OUT_FD]);
+ if (name[ERR_FD]) /* likely won't see message if this fails; oh well... */
+ if (!freopen(name[ERR_FD], mode[ERR_FD], stderr,
+ rfm[ERR_FD], "rat=cr"))
+ lerrsf("failed to redirect `stderr' to \"%s\"", name[ERR_FD]);
+ /* remove any excess arguments (used up from redirection) */
+ while (*iargc > oargc)
+ (*iargv)[--*iargc] = 0;
+ /* all done */
+ return;
+}
+
+/* Pick out the basename of a full filename, and return a pointer
+ to a modifiable copy of it. */
+
+static char *fix_arg0( arg0 )
+const char *arg0;
+{
+ char *p, *new_arg0;
+
+ if (arg0) {
+ /* strip off the path */
+ if ((p = strrchr(arg0, ':')) != 0) /* device punctuation */
+ arg0 = p + 1;
+ if ((p = strrchr(arg0, ']')) != 0) /* directory punctuation */
+ arg0 = p + 1;
+ if ((p = strrchr(arg0, '>')) != 0) /* alternate dir punct */
+ arg0 = p + 1;
+ }
+ if (!arg0 || !*arg0)
+ arg0 = default_arg0;
+ /* should now have "something.exe;#"; make a modifiable copy */
+ new_arg0 = copy_string(arg0);
+
+ /* strip off ".exe" and/or ";#" (version number),
+ unless it ended up as the whole name */
+ if ((p = strchr(new_arg0, '.')) != 0 && (p > new_arg0)
+ && (p[1] == 'e' || p[1] == 'E')
+ && (p[2] == 'x' || p[2] == 'X')
+ && (p[3] == 'e' || p[3] == 'E')
+ && (p[4] == ';' || p[4] == '.' || p[4] == '\0'))
+ *p = '\0';
+ else if ((p = strchr(new_arg0, ';')) != 0 && (p > new_arg0))
+ *p = '\0';
+
+ return new_arg0;
+}
+
+
+#include <ssdef.h>
+#include <stsdef.h>
+
+#ifdef exit
+#undef exit
+extern void exit PROTO((int)); /* <stdlib.h> ended up prototyping vms_exit */
+#endif
+
+/* Convert zero to VMS success and non-zero to VMS failure. The latter
+ does not bother trying to distinguish between various failure reasons. */
+
+void vms_exit( status )
+int status;
+{
+ exit( status == 0 ? SS$_NORMAL : (SS$_ABORT | STS$M_INHIB_MSG) );
+}
diff --git a/Tools/android/flex-2.5.4a/MISC/VMS/vms-conf.h b/Tools/android/flex-2.5.4a/MISC/VMS/vms-conf.h
new file mode 100644
index 0000000..65aa477
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/VMS/vms-conf.h
@@ -0,0 +1,32 @@
+/* config.h manually constructed for VMS */
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS
+
+/* Define if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H
+
+/* Define if you have the <sys/types.h> header file. */
+#ifndef __GNUC__
+#undef HAVE_SYS_TYPES_H
+#else
+#define HAVE_SYS_TYPES_H
+#endif
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#undef HAVE_ALLOCA_H
+
+/* Extra platform-specific command line handling. */
+#define NEED_ARGV_FIXUP
+
+/* Override default exit behavior. */
+#define exit vms_exit
diff --git a/Tools/android/flex-2.5.4a/MISC/alloca.c b/Tools/android/flex-2.5.4a/MISC/alloca.c
new file mode 100644
index 0000000..bd4932a
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/alloca.c
@@ -0,0 +1,484 @@
+/* alloca.c -- allocate automatically reclaimed memory
+ (Mostly) portable public-domain implementation -- D A Gwyn
+
+ This implementation of the PWB library alloca function,
+ which is used to allocate space off the run-time stack so
+ that it is automatically reclaimed upon procedure exit,
+ was inspired by discussions with J. Q. Johnson of Cornell.
+ J.Otto Tennant <jot@cray.com> contributed the Cray support.
+
+ There are some preprocessor constants that can
+ be defined when compiling for your specific system, for
+ improved efficiency; however, the defaults should be okay.
+
+ The general concept of this implementation is to keep
+ track of all alloca-allocated blocks, and reclaim any
+ that are found to be deeper in the stack than the current
+ invocation. This heuristic does not reclaim storage as
+ soon as it becomes invalid, but it will do so eventually.
+
+ As a special case, alloca(0) reclaims storage without
+ allocating any. It is a good idea to use alloca(0) in
+ your main control loop, etc. to force garbage collection. */
+
+#ifdef HAVE_CONFIG_H
+#if defined (emacs) || defined (CONFIG_BROKETS)
+#include <config.h>
+#else
+#include "config.h"
+#endif
+#endif
+
+/* If compiling with GCC 2, this file's not needed. */
+#if !defined (__GNUC__) || __GNUC__ < 2
+
+/* If someone has defined alloca as a macro,
+ there must be some other way alloca is supposed to work. */
+#ifndef alloca
+
+#ifdef emacs
+#ifdef static
+/* actually, only want this if static is defined as ""
+ -- this is for usg, in which emacs must undefine static
+ in order to make unexec workable
+ */
+#ifndef STACK_DIRECTION
+you
+lose
+-- must know STACK_DIRECTION at compile-time
+#endif /* STACK_DIRECTION undefined */
+#endif /* static */
+#endif /* emacs */
+
+/* If your stack is a linked list of frames, you have to
+ provide an "address metric" ADDRESS_FUNCTION macro. */
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+long i00afunc ();
+#define ADDRESS_FUNCTION(arg) (char *) i00afunc (&(arg))
+#else
+#define ADDRESS_FUNCTION(arg) &(arg)
+#endif
+
+#if __STDC__
+typedef void *pointer;
+#else
+typedef char *pointer;
+#endif
+
+#define NULL 0
+
+/* Different portions of Emacs need to call different versions of
+ malloc. The Emacs executable needs alloca to call xmalloc, because
+ ordinary malloc isn't protected from input signals. On the other
+ hand, the utilities in lib-src need alloca to call malloc; some of
+ them are very simple, and don't have an xmalloc routine.
+
+ Non-Emacs programs expect this to call use xmalloc.
+
+ Callers below should use malloc. */
+
+#ifndef emacs
+#define malloc xmalloc
+#endif
+extern pointer malloc ();
+
+/* Define STACK_DIRECTION if you know the direction of stack
+ growth for your system; otherwise it will be automatically
+ deduced at run-time.
+
+ STACK_DIRECTION > 0 => grows toward higher addresses
+ STACK_DIRECTION < 0 => grows toward lower addresses
+ STACK_DIRECTION = 0 => direction of growth unknown */
+
+#ifndef STACK_DIRECTION
+#define STACK_DIRECTION 0 /* Direction unknown. */
+#endif
+
+#if STACK_DIRECTION != 0
+
+#define STACK_DIR STACK_DIRECTION /* Known at compile-time. */
+
+#else /* STACK_DIRECTION == 0; need run-time code. */
+
+static int stack_dir; /* 1 or -1 once known. */
+#define STACK_DIR stack_dir
+
+static void
+find_stack_direction ()
+{
+ static char *addr = NULL; /* Address of first `dummy', once known. */
+ auto char dummy; /* To get stack address. */
+
+ if (addr == NULL)
+ { /* Initial entry. */
+ addr = ADDRESS_FUNCTION (dummy);
+
+ find_stack_direction (); /* Recurse once. */
+ }
+ else
+ {
+ /* Second entry. */
+ if (ADDRESS_FUNCTION (dummy) > addr)
+ stack_dir = 1; /* Stack grew upward. */
+ else
+ stack_dir = -1; /* Stack grew downward. */
+ }
+}
+
+#endif /* STACK_DIRECTION == 0 */
+
+/* An "alloca header" is used to:
+ (a) chain together all alloca'ed blocks;
+ (b) keep track of stack depth.
+
+ It is very important that sizeof(header) agree with malloc
+ alignment chunk size. The following default should work okay. */
+
+#ifndef ALIGN_SIZE
+#define ALIGN_SIZE sizeof(double)
+#endif
+
+typedef union hdr
+{
+ char align[ALIGN_SIZE]; /* To force sizeof(header). */
+ struct
+ {
+ union hdr *next; /* For chaining headers. */
+ char *deep; /* For stack depth measure. */
+ } h;
+} header;
+
+static header *last_alloca_header = NULL; /* -> last alloca header. */
+
+/* Return a pointer to at least SIZE bytes of storage,
+ which will be automatically reclaimed upon exit from
+ the procedure that called alloca. Originally, this space
+ was supposed to be taken from the current stack frame of the
+ caller, but that method cannot be made to work for some
+ implementations of C, for example under Gould's UTX/32. */
+
+pointer
+alloca (size)
+ unsigned size;
+{
+ auto char probe; /* Probes stack depth: */
+ register char *depth = ADDRESS_FUNCTION (probe);
+
+#if STACK_DIRECTION == 0
+ if (STACK_DIR == 0) /* Unknown growth direction. */
+ find_stack_direction ();
+#endif
+
+ /* Reclaim garbage, defined as all alloca'd storage that
+ was allocated from deeper in the stack than currently. */
+
+ {
+ register header *hp; /* Traverses linked list. */
+
+ for (hp = last_alloca_header; hp != NULL;)
+ if ((STACK_DIR > 0 && hp->h.deep > depth)
+ || (STACK_DIR < 0 && hp->h.deep < depth))
+ {
+ register header *np = hp->h.next;
+
+ free ((pointer) hp); /* Collect garbage. */
+
+ hp = np; /* -> next header. */
+ }
+ else
+ break; /* Rest are not deeper. */
+
+ last_alloca_header = hp; /* -> last valid storage. */
+ }
+
+ if (size == 0)
+ return NULL; /* No allocation required. */
+
+ /* Allocate combined header + user data storage. */
+
+ {
+ register pointer new = malloc (sizeof (header) + size);
+ /* Address of header. */
+
+ ((header *) new)->h.next = last_alloca_header;
+ ((header *) new)->h.deep = depth;
+
+ last_alloca_header = (header *) new;
+
+ /* User storage begins just after header. */
+
+ return (pointer) ((char *) new + sizeof (header));
+ }
+}
+
+#if defined (CRAY) && defined (CRAY_STACKSEG_END)
+
+#ifdef DEBUG_I00AFUNC
+#include <stdio.h>
+#endif
+
+#ifndef CRAY_STACK
+#define CRAY_STACK
+#ifndef CRAY2
+/* Stack structures for CRAY-1, CRAY X-MP, and CRAY Y-MP */
+struct stack_control_header
+ {
+ long shgrow:32; /* Number of times stack has grown. */
+ long shaseg:32; /* Size of increments to stack. */
+ long shhwm:32; /* High water mark of stack. */
+ long shsize:32; /* Current size of stack (all segments). */
+ };
+
+/* The stack segment linkage control information occurs at
+ the high-address end of a stack segment. (The stack
+ grows from low addresses to high addresses.) The initial
+ part of the stack segment linkage control information is
+ 0200 (octal) words. This provides for register storage
+ for the routine which overflows the stack. */
+
+struct stack_segment_linkage
+ {
+ long ss[0200]; /* 0200 overflow words. */
+ long sssize:32; /* Number of words in this segment. */
+ long ssbase:32; /* Offset to stack base. */
+ long:32;
+ long sspseg:32; /* Offset to linkage control of previous
+ segment of stack. */
+ long:32;
+ long sstcpt:32; /* Pointer to task common address block. */
+ long sscsnm; /* Private control structure number for
+ microtasking. */
+ long ssusr1; /* Reserved for user. */
+ long ssusr2; /* Reserved for user. */
+ long sstpid; /* Process ID for pid based multi-tasking. */
+ long ssgvup; /* Pointer to multitasking thread giveup. */
+ long sscray[7]; /* Reserved for Cray Research. */
+ long ssa0;
+ long ssa1;
+ long ssa2;
+ long ssa3;
+ long ssa4;
+ long ssa5;
+ long ssa6;
+ long ssa7;
+ long sss0;
+ long sss1;
+ long sss2;
+ long sss3;
+ long sss4;
+ long sss5;
+ long sss6;
+ long sss7;
+ };
+
+#else /* CRAY2 */
+/* The following structure defines the vector of words
+ returned by the STKSTAT library routine. */
+struct stk_stat
+ {
+ long now; /* Current total stack size. */
+ long maxc; /* Amount of contiguous space which would
+ be required to satisfy the maximum
+ stack demand to date. */
+ long high_water; /* Stack high-water mark. */
+ long overflows; /* Number of stack overflow ($STKOFEN) calls. */
+ long hits; /* Number of internal buffer hits. */
+ long extends; /* Number of block extensions. */
+ long stko_mallocs; /* Block allocations by $STKOFEN. */
+ long underflows; /* Number of stack underflow calls ($STKRETN). */
+ long stko_free; /* Number of deallocations by $STKRETN. */
+ long stkm_free; /* Number of deallocations by $STKMRET. */
+ long segments; /* Current number of stack segments. */
+ long maxs; /* Maximum number of stack segments so far. */
+ long pad_size; /* Stack pad size. */
+ long current_address; /* Current stack segment address. */
+ long current_size; /* Current stack segment size. This
+ number is actually corrupted by STKSTAT to
+ include the fifteen word trailer area. */
+ long initial_address; /* Address of initial segment. */
+ long initial_size; /* Size of initial segment. */
+ };
+
+/* The following structure describes the data structure which trails
+ any stack segment. I think that the description in 'asdef' is
+ out of date. I only describe the parts that I am sure about. */
+
+struct stk_trailer
+ {
+ long this_address; /* Address of this block. */
+ long this_size; /* Size of this block (does not include
+ this trailer). */
+ long unknown2;
+ long unknown3;
+ long link; /* Address of trailer block of previous
+ segment. */
+ long unknown5;
+ long unknown6;
+ long unknown7;
+ long unknown8;
+ long unknown9;
+ long unknown10;
+ long unknown11;
+ long unknown12;
+ long unknown13;
+ long unknown14;
+ };
+
+#endif /* CRAY2 */
+#endif /* not CRAY_STACK */
+
+#ifdef CRAY2
+/* Determine a "stack measure" for an arbitrary ADDRESS.
+ I doubt that "lint" will like this much. */
+
+static long
+i00afunc (long *address)
+{
+ struct stk_stat status;
+ struct stk_trailer *trailer;
+ long *block, size;
+ long result = 0;
+
+ /* We want to iterate through all of the segments. The first
+ step is to get the stack status structure. We could do this
+ more quickly and more directly, perhaps, by referencing the
+ $LM00 common block, but I know that this works. */
+
+ STKSTAT (&status);
+
+ /* Set up the iteration. */
+
+ trailer = (struct stk_trailer *) (status.current_address
+ + status.current_size
+ - 15);
+
+ /* There must be at least one stack segment. Therefore it is
+ a fatal error if "trailer" is null. */
+
+ if (trailer == 0)
+ abort ();
+
+ /* Discard segments that do not contain our argument address. */
+
+ while (trailer != 0)
+ {
+ block = (long *) trailer->this_address;
+ size = trailer->this_size;
+ if (block == 0 || size == 0)
+ abort ();
+ trailer = (struct stk_trailer *) trailer->link;
+ if ((block <= address) && (address < (block + size)))
+ break;
+ }
+
+ /* Set the result to the offset in this segment and add the sizes
+ of all predecessor segments. */
+
+ result = address - block;
+
+ if (trailer == 0)
+ {
+ return result;
+ }
+
+ do
+ {
+ if (trailer->this_size <= 0)
+ abort ();
+ result += trailer->this_size;
+ trailer = (struct stk_trailer *) trailer->link;
+ }
+ while (trailer != 0);
+
+ /* We are done. Note that if you present a bogus address (one
+ not in any segment), you will get a different number back, formed
+ from subtracting the address of the first block. This is probably
+ not what you want. */
+
+ return (result);
+}
+
+#else /* not CRAY2 */
+/* Stack address function for a CRAY-1, CRAY X-MP, or CRAY Y-MP.
+ Determine the number of the cell within the stack,
+ given the address of the cell. The purpose of this
+ routine is to linearize, in some sense, stack addresses
+ for alloca. */
+
+static long
+i00afunc (long address)
+{
+ long stkl = 0;
+
+ long size, pseg, this_segment, stack;
+ long result = 0;
+
+ struct stack_segment_linkage *ssptr;
+
+ /* Register B67 contains the address of the end of the
+ current stack segment. If you (as a subprogram) store
+ your registers on the stack and find that you are past
+ the contents of B67, you have overflowed the segment.
+
+ B67 also points to the stack segment linkage control
+ area, which is what we are really interested in. */
+
+ stkl = CRAY_STACKSEG_END ();
+ ssptr = (struct stack_segment_linkage *) stkl;
+
+ /* If one subtracts 'size' from the end of the segment,
+ one has the address of the first word of the segment.
+
+ If this is not the first segment, 'pseg' will be
+ nonzero. */
+
+ pseg = ssptr->sspseg;
+ size = ssptr->sssize;
+
+ this_segment = stkl - size;
+
+ /* It is possible that calling this routine itself caused
+ a stack overflow. Discard stack segments which do not
+ contain the target address. */
+
+ while (!(this_segment <= address && address <= stkl))
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o %011o\n", this_segment, address, stkl);
+#endif
+ if (pseg == 0)
+ break;
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ this_segment = stkl - size;
+ }
+
+ result = address - this_segment;
+
+ /* If you subtract pseg from the current end of the stack,
+ you get the address of the previous stack segment's end.
+ This seems a little convoluted to me, but I'll bet you save
+ a cycle somewhere. */
+
+ while (pseg != 0)
+ {
+#ifdef DEBUG_I00AFUNC
+ fprintf (stderr, "%011o %011o\n", pseg, size);
+#endif
+ stkl = stkl - pseg;
+ ssptr = (struct stack_segment_linkage *) stkl;
+ size = ssptr->sssize;
+ pseg = ssptr->sspseg;
+ result += size;
+ }
+ return (result);
+}
+
+#endif /* not CRAY2 */
+#endif /* CRAY */
+
+#endif /* no alloca */
+#endif /* not GCC version 2 */
diff --git a/Tools/android/flex-2.5.4a/MISC/debflex.awk b/Tools/android/flex-2.5.4a/MISC/debflex.awk
new file mode 100644
index 0000000..b1eda49
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/debflex.awk
@@ -0,0 +1,119 @@
+# Clarify the flex debug trace by substituting first line of each rule.
+# Francois Pinard <pinard@iro.umontreal.ca>, July 1990.
+#
+# Rewritten to process correctly \n's in scanner input.
+# BEGIN section modified to correct a collection of rules.
+# Michal Jaegermann <michal@phys.ualberta.ca>, December 1993
+#
+# Sample usage:
+# flex -d PROGRAM.l
+# gcc -o PROGRAM PROGRAM.c -lfl
+# PROGRAM 2>&1 | gawk -f debflex.awk PROGRAM.l
+#
+# (VP's note: this script presently does not work with either "old" or
+# "new" awk; fixes so it does will be welcome)
+
+BEGIN {
+ # Insure proper usage.
+
+ if (ARGC != 2) {
+ print "usage: gawk -f debflex.awk FLEX_SOURCE <DEBUG_OUTPUT";
+ exit (1);
+ }
+
+ # Remove and save the name of flex source.
+
+ source = ARGV[1];
+ ARGC--;
+
+ # Swallow the flex source file.
+
+ line = 0;
+ section = 1;
+ while (getline <source) {
+
+ # Count the lines.
+
+ line++;
+
+ # Count the sections. When encountering section 3,
+ # break out of the awk BEGIN block.
+
+ if (match ($0, /^%%/)) {
+ section++;
+ if (section == 3) {
+ break;
+ }
+ }
+ else {
+ # Only the lines in section 2 which do not begin in a
+ # tab or space might be referred to by the flex debug
+ # trace. Save only those lines.
+
+ if (section == 2 && match ($0, /^[^ \t]/)) {
+ rules[line] = $0;
+ }
+ }
+ }
+ dashes = "-----------------------------------------------------------";
+ collect = "";
+ line = 0;
+}
+
+# collect complete rule output from a scanner
+$0 !~ /^--/ {
+ collect = collect "\n" $0;
+ next;
+}
+# otherwise we have a new rule - process what we got so far
+{
+ process();
+}
+# and the same thing if we hit EOF
+END {
+ process();
+}
+
+function process() {
+
+ # splitting this way we loose some double dashes and
+ # left parentheses from echoed input - a small price to pay
+ n = split(collect, field, "\n--|[(]");
+
+ # this loop kicks in only when we already collected something
+ for (i = 1; i <= n; i++) {
+ if (0 != line) {
+ # we do not care for traces of newlines.
+ if (0 == match(field[i], /\"\n+\"[)]/)) {
+ if (rules[line]) {
+ text = field[i];
+ while ( ++i <= n) {
+ text = text field[i];
+ }
+ printf("%s:%d: %-8s -- %s\n",
+ source, line, text, rules[line]);
+ }
+ else {
+ print;
+ printf "%s:%d: *** No such rule.\n", source, line;
+ }
+ }
+ line = 0;
+ break;
+ }
+ if ("" != field[i]) {
+ if ("end of buffer or a NUL)" == field[i]) {
+ print dashes; # Simplify trace of buffer reloads
+ continue;
+ }
+ if (match(field[i], /accepting rule at line /)) {
+ # force interpretation of line as a number
+ line = 0 + substr(field[i], RLENGTH);
+ continue;
+ }
+ # echo everything else
+ printf("--%s\n", field[i]);
+ }
+ }
+ collect = "\n" $0; # ... and start next trace
+}
diff --git a/Tools/android/flex-2.5.4a/MISC/fastwc/README b/Tools/android/flex-2.5.4a/MISC/fastwc/README
new file mode 100644
index 0000000..0dd3afe
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/fastwc/README
@@ -0,0 +1,56 @@
+This directory contains some examples illustrating techniques for extracting
+high-performance from flex scanners. Each program implements a simplified
+version of the Unix "wc" tool: read text from stdin and print the number of
+characters, words, and lines present in the text. All programs were compiled
+using gcc (version unavailable, sorry) with the -O flag, and run on a
+SPARCstation 1+. The input used was a PostScript file, mainly containing
+figures, with the following "wc" counts:
+
+ lines words characters
+ 214217 635954 2592172
+
+
+The basic principles illustrated by these programs are:
+
+ - match as much text with each rule as possible
+ - adding rules does not slow you down!
+ - avoid backing up
+
+and the big caveat that comes with them is:
+
+ - you buy performance with decreased maintainability; make
+ sure you really need it before applying the above techniques.
+
+See the "Performance Considerations" section of flexdoc for more
+details regarding these principles.
+
+
+The different versions of "wc":
+
+ mywc.c
+ a simple but fairly efficient C version
+
+ wc1.l a naive flex "wc" implementation
+
+ wc2.l somewhat faster; adds rules to match multiple tokens at once
+
+ wc3.l faster still; adds more rules to match longer runs of tokens
+
+ wc4.l fastest; still more rules added; hard to do much better
+ using flex (or, I suspect, hand-coding)
+
+ wc5.l identical to wc3.l except one rule has been slightly
+ shortened, introducing backing-up
+
+Timing results (all times in user CPU seconds):
+
+ program time notes
+ ------- ---- -----
+ wc1 16.4 default flex table compression (= -Cem)
+ wc1 6.7 -Cf compression option
+ /bin/wc 5.8 Sun's standard "wc" tool
+ mywc 4.6 simple but better C implementation!
+ wc2 4.6 as good as C implementation; built using -Cf
+ wc3 3.8 -Cf
+ wc4 3.3 -Cf
+ wc5 5.7 -Cf; ouch, backing up is expensive
diff --git a/Tools/android/flex-2.5.4a/MISC/fastwc/mywc.c b/Tools/android/flex-2.5.4a/MISC/fastwc/mywc.c
new file mode 100644
index 0000000..92e5a36
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/fastwc/mywc.c
@@ -0,0 +1,26 @@
+/* A simple but fairly efficient C version of the Unix "wc" tool */
+
+#include <stdio.h>
+#include <ctype.h>
+
+main()
+{
+ register int c, cc = 0, wc = 0, lc = 0;
+ FILE *f = stdin;
+
+ while ((c = getc(f)) != EOF) {
+ ++cc;
+ if (isgraph(c)) {
+ ++wc;
+ do {
+ c = getc(f);
+ if (c == EOF)
+ goto done;
+ ++cc;
+ } while (isgraph(c));
+ }
+ if (c == '\n')
+ ++lc;
+ }
+done: printf( "%8d%8d%8d\n", lc, wc, cc );
+}
diff --git a/Tools/android/flex-2.5.4a/MISC/fastwc/wc1.l b/Tools/android/flex-2.5.4a/MISC/fastwc/wc1.l
new file mode 100644
index 0000000..d6696bc
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/fastwc/wc1.l
@@ -0,0 +1,18 @@
+/* First cut at a flex-based "wc" tool. */
+
+ws [ \t]
+nonws [^ \t\n]
+
+%%
+ int cc = 0, wc = 0, lc = 0;
+
+{nonws}+ cc += yyleng; ++wc;
+
+{ws}+ cc += yyleng;
+
+\n ++lc; ++cc;
+
+<<EOF>> {
+ printf( "%8d %8d %8d\n", lc, wc, cc );
+ yyterminate();
+ }
diff --git a/Tools/android/flex-2.5.4a/MISC/fastwc/wc2.l b/Tools/android/flex-2.5.4a/MISC/fastwc/wc2.l
new file mode 100644
index 0000000..bd63cd4
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/fastwc/wc2.l
@@ -0,0 +1,20 @@
+/* Somewhat faster "wc" tool: match more text with each rule */
+
+ws [ \t]
+nonws [^ \t\n]
+word {ws}*{nonws}+
+
+%%
+ int cc = 0, wc = 0, lc = 0;
+
+{word}{ws}* cc += yyleng; ++wc;
+{word}{ws}*\n cc += yyleng; ++wc; ++lc;
+
+{ws}+ cc += yyleng;
+
+\n+ cc += yyleng; lc += yyleng;
+
+<<EOF>> {
+ printf( "%8d %8d %8d\n", lc, wc, cc );
+ yyterminate();
+ }
diff --git a/Tools/android/flex-2.5.4a/MISC/fastwc/wc3.l b/Tools/android/flex-2.5.4a/MISC/fastwc/wc3.l
new file mode 100644
index 0000000..7c5f2e2
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/fastwc/wc3.l
@@ -0,0 +1,24 @@
+/* Somewhat faster still: potentially match a lot of text with each rule */
+
+ws [ \t]
+nonws [^ \t\n]
+word {ws}*{nonws}+
+words {word}{ws}+
+
+%%
+ int cc = 0, wc = 0, lc = 0;
+
+{word}{ws}* cc += yyleng; ++wc;
+{word}{ws}*\n cc += yyleng; ++wc; ++lc;
+{words}{word}{ws}* cc += yyleng; wc += 2;
+{words}{2}{word}{ws}* cc += yyleng; wc += 3;
+{words}{3}{word}{ws}* cc += yyleng; wc += 4;
+
+{ws}+ cc += yyleng;
+
+\n+ cc += yyleng; lc += yyleng;
+
+<<EOF>> {
+ printf( "%8d %8d %8d\n", lc, wc, cc );
+ yyterminate();
+ }
diff --git a/Tools/android/flex-2.5.4a/MISC/fastwc/wc4.l b/Tools/android/flex-2.5.4a/MISC/fastwc/wc4.l
new file mode 100644
index 0000000..cbe56f6
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/fastwc/wc4.l
@@ -0,0 +1,27 @@
+/* Fastest version of wc: add rules to pick up newlines, too */
+
+ws [ \t]
+nonws [^ \t\n]
+word {ws}*{nonws}+
+words {word}{ws}+
+
+%%
+ int cc = 0, wc = 0, lc = 0;
+
+{word}{ws}* ++wc; cc += yyleng;
+{word}{ws}*\n ++wc; cc += yyleng; ++lc;
+{words}{word}{ws}* wc += 2; cc += yyleng;
+{words}{word}{ws}*\n wc += 2; cc += yyleng; ++lc;
+{words}{2}{word}{ws}* wc += 3; cc += yyleng;
+{words}{2}{word}{ws}*\n wc += 3; cc += yyleng; ++lc;
+{words}{3}{word}{ws}* wc += 4; cc += yyleng;
+{words}{3}{word}{ws}*\n wc += 4; cc += yyleng; ++lc;
+
+{ws}+ cc += yyleng;
+
+\n+ cc += yyleng; lc += yyleng;
+
+<<EOF>> {
+ printf( "%8d %8d %8d\n", lc, wc, cc );
+ yyterminate();
+ }
diff --git a/Tools/android/flex-2.5.4a/MISC/fastwc/wc5.l b/Tools/android/flex-2.5.4a/MISC/fastwc/wc5.l
new file mode 100644
index 0000000..8fe17b6
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/fastwc/wc5.l
@@ -0,0 +1,24 @@
+/* Oops; slight change from wc3.l introduces backtracking */
+
+ws [ \t]
+nonws [^ \t\n]
+word {ws}*{nonws}+
+words {word}{ws}+
+
+%%
+ int cc = 0, wc = 0, lc = 0;
+
+{word}{ws}* cc += yyleng; ++wc;
+{word}{ws}*\n cc += yyleng; ++wc; ++lc;
+{words}{word} cc += yyleng; wc += 2; /* oops */
+{words}{2}{word}{ws}* cc += yyleng; wc += 3;
+{words}{3}{word}{ws}* cc += yyleng; wc += 4;
+
+{ws}+ cc += yyleng;
+
+\n+ cc += yyleng; lc += yyleng;
+
+<<EOF>> {
+ printf( "%8d %8d %8d\n", lc, wc, cc );
+ yyterminate();
+ }
diff --git a/Tools/android/flex-2.5.4a/MISC/flex.man b/Tools/android/flex-2.5.4a/MISC/flex.man
new file mode 100644
index 0000000..d41f5ba
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/flex.man
@@ -0,0 +1,3696 @@
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+NAME
+ flex - fast lexical analyzer generator
+
+SYNOPSIS
+ flex [-bcdfhilnpstvwBFILTV78+? -C[aefFmr] -ooutput -Pprefix
+ -Sskeleton] [--help --version] [filename ...]
+
+OVERVIEW
+ This manual describes flex, a tool for generating programs
+ that perform pattern-matching on text. The manual includes
+ both tutorial and reference sections:
+
+ Description
+ a brief overview of the tool
+
+ Some Simple Examples
+
+ Format Of The Input File
+
+ Patterns
+ the extended regular expressions used by flex
+
+ How The Input Is Matched
+ the rules for determining what has been matched
+
+ Actions
+ how to specify what to do when a pattern is matched
+
+ The Generated Scanner
+ details regarding the scanner that flex produces;
+ how to control the input source
+
+ Start Conditions
+ introducing context into your scanners, and
+ managing "mini-scanners"
+
+ Multiple Input Buffers
+ how to manipulate multiple input sources; how to
+ scan from strings instead of files
+
+ End-of-file Rules
+ special rules for matching the end of the input
+
+ Miscellaneous Macros
+ a summary of macros available to the actions
+
+ Values Available To The User
+ a summary of values available to the actions
+
+ Interfacing With Yacc
+ connecting flex scanners together with yacc parsers
+
+
+
+
+Version 2.5 Last change: April 1995 1
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ Options
+ flex command-line options, and the "%option"
+ directive
+
+ Performance Considerations
+ how to make your scanner go as fast as possible
+
+ Generating C++ Scanners
+ the (experimental) facility for generating C++
+ scanner classes
+
+ Incompatibilities With Lex And POSIX
+ how flex differs from AT&T lex and the POSIX lex
+ standard
+
+ Diagnostics
+ those error messages produced by flex (or scanners
+ it generates) whose meanings might not be apparent
+
+ Files
+ files used by flex
+
+ Deficiencies / Bugs
+ known problems with flex
+
+ See Also
+ other documentation, related tools
+
+ Author
+ includes contact information
+
+
+DESCRIPTION
+ flex is a tool for generating scanners: programs which
+ recognized lexical patterns in text. flex reads the given
+ input files, or its standard input if no file names are
+ given, for a description of a scanner to generate. The
+ description is in the form of pairs of regular expressions
+ and C code, called rules. flex generates as output a C
+ source file, lex.yy.c, which defines a routine yylex(). This
+ file is compiled and linked with the -lfl library to produce
+ an executable. When the executable is run, it analyzes its
+ input for occurrences of the regular expressions. Whenever
+ it finds one, it executes the corresponding C code.
+
+SOME SIMPLE EXAMPLES
+ First some simple examples to get the flavor of how one uses
+ flex. The following flex input specifies a scanner which
+ whenever it encounters the string "username" will replace it
+ with the user's login name:
+
+ %%
+
+
+
+Version 2.5 Last change: April 1995 2
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ username printf( "%s", getlogin() );
+
+ By default, any text not matched by a flex scanner is copied
+ to the output, so the net effect of this scanner is to copy
+ its input file to its output with each occurrence of "user-
+ name" expanded. In this input, there is just one rule.
+ "username" is the pattern and the "printf" is the action.
+ The "%%" marks the beginning of the rules.
+
+ Here's another simple example:
+
+ int num_lines = 0, num_chars = 0;
+
+ %%
+ \n ++num_lines; ++num_chars;
+ . ++num_chars;
+
+ %%
+ main()
+ {
+ yylex();
+ printf( "# of lines = %d, # of chars = %d\n",
+ num_lines, num_chars );
+ }
+
+ This scanner counts the number of characters and the number
+ of lines in its input (it produces no output other than the
+ final report on the counts). The first line declares two
+ globals, "num_lines" and "num_chars", which are accessible
+ both inside yylex() and in the main() routine declared after
+ the second "%%". There are two rules, one which matches a
+ newline ("\n") and increments both the line count and the
+ character count, and one which matches any character other
+ than a newline (indicated by the "." regular expression).
+
+ A somewhat more complicated example:
+
+ /* scanner for a toy Pascal-like language */
+
+ %{
+ /* need this for the call to atof() below */
+ #include <math.h>
+ %}
+
+ DIGIT [0-9]
+ ID [a-z][a-z0-9]*
+
+ %%
+
+ {DIGIT}+ {
+ printf( "An integer: %s (%d)\n", yytext,
+ atoi( yytext ) );
+
+
+
+Version 2.5 Last change: April 1995 3
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ }
+
+ {DIGIT}+"."{DIGIT}* {
+ printf( "A float: %s (%g)\n", yytext,
+ atof( yytext ) );
+ }
+
+ if|then|begin|end|procedure|function {
+ printf( "A keyword: %s\n", yytext );
+ }
+
+ {ID} printf( "An identifier: %s\n", yytext );
+
+ "+"|"-"|"*"|"/" printf( "An operator: %s\n", yytext );
+
+ "{"[^}\n]*"}" /* eat up one-line comments */
+
+ [ \t\n]+ /* eat up whitespace */
+
+ . printf( "Unrecognized character: %s\n", yytext );
+
+ %%
+
+ main( argc, argv )
+ int argc;
+ char **argv;
+ {
+ ++argv, --argc; /* skip over program name */
+ if ( argc > 0 )
+ yyin = fopen( argv[0], "r" );
+ else
+ yyin = stdin;
+
+ yylex();
+ }
+
+ This is the beginnings of a simple scanner for a language
+ like Pascal. It identifies different types of tokens and
+ reports on what it has seen.
+
+ The details of this example will be explained in the follow-
+ ing sections.
+
+FORMAT OF THE INPUT FILE
+ The flex input file consists of three sections, separated by
+ a line with just %% in it:
+
+ definitions
+ %%
+ rules
+ %%
+ user code
+
+
+
+Version 2.5 Last change: April 1995 4
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ The definitions section contains declarations of simple name
+ definitions to simplify the scanner specification, and
+ declarations of start conditions, which are explained in a
+ later section.
+
+ Name definitions have the form:
+
+ name definition
+
+ The "name" is a word beginning with a letter or an under-
+ score ('_') followed by zero or more letters, digits, '_',
+ or '-' (dash). The definition is taken to begin at the
+ first non-white-space character following the name and con-
+ tinuing to the end of the line. The definition can subse-
+ quently be referred to using "{name}", which will expand to
+ "(definition)". For example,
+
+ DIGIT [0-9]
+ ID [a-z][a-z0-9]*
+
+ defines "DIGIT" to be a regular expression which matches a
+ single digit, and "ID" to be a regular expression which
+ matches a letter followed by zero-or-more letters-or-digits.
+ A subsequent reference to
+
+ {DIGIT}+"."{DIGIT}*
+
+ is identical to
+
+ ([0-9])+"."([0-9])*
+
+ and matches one-or-more digits followed by a '.' followed by
+ zero-or-more digits.
+
+ The rules section of the flex input contains a series of
+ rules of the form:
+
+ pattern action
+
+ where the pattern must be unindented and the action must
+ begin on the same line.
+
+ See below for a further description of patterns and actions.
+
+ Finally, the user code section is simply copied to lex.yy.c
+ verbatim. It is used for companion routines which call or
+ are called by the scanner. The presence of this section is
+ optional; if it is missing, the second %% in the input file
+ may be skipped, too.
+
+ In the definitions and rules sections, any indented text or
+ text enclosed in %{ and %} is copied verbatim to the output
+
+
+
+Version 2.5 Last change: April 1995 5
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ (with the %{}'s removed). The %{}'s must appear unindented
+ on lines by themselves.
+
+ In the rules section, any indented or %{} text appearing
+ before the first rule may be used to declare variables which
+ are local to the scanning routine and (after the declara-
+ tions) code which is to be executed whenever the scanning
+ routine is entered. Other indented or %{} text in the rule
+ section is still copied to the output, but its meaning is
+ not well-defined and it may well cause compile-time errors
+ (this feature is present for POSIX compliance; see below for
+ other such features).
+
+ In the definitions section (but not in the rules section),
+ an unindented comment (i.e., a line beginning with "/*") is
+ also copied verbatim to the output up to the next "*/".
+
+PATTERNS
+ The patterns in the input are written using an extended set
+ of regular expressions. These are:
+
+ x match the character 'x'
+ . any character (byte) except newline
+ [xyz] a "character class"; in this case, the pattern
+ matches either an 'x', a 'y', or a 'z'
+ [abj-oZ] a "character class" with a range in it; matches
+ an 'a', a 'b', any letter from 'j' through 'o',
+ or a 'Z'
+ [^A-Z] a "negated character class", i.e., any character
+ but those in the class. In this case, any
+ character EXCEPT an uppercase letter.
+ [^A-Z\n] any character EXCEPT an uppercase letter or
+ a newline
+ r* zero or more r's, where r is any regular expression
+ r+ one or more r's
+ r? zero or one r's (that is, "an optional r")
+ r{2,5} anywhere from two to five r's
+ r{2,} two or more r's
+ r{4} exactly 4 r's
+ {name} the expansion of the "name" definition
+ (see above)
+ "[xyz]\"foo"
+ the literal string: [xyz]"foo
+ \X if X is an 'a', 'b', 'f', 'n', 'r', 't', or 'v',
+ then the ANSI-C interpretation of \x.
+ Otherwise, a literal 'X' (used to escape
+ operators such as '*')
+ \0 a NUL character (ASCII code 0)
+ \123 the character with octal value 123
+ \x2a the character with hexadecimal value 2a
+ (r) match an r; parentheses are used to override
+ precedence (see below)
+
+
+
+Version 2.5 Last change: April 1995 6
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ rs the regular expression r followed by the
+ regular expression s; called "concatenation"
+
+
+ r|s either an r or an s
+
+
+ r/s an r but only if it is followed by an s. The
+ text matched by s is included when determining
+ whether this rule is the "longest match",
+ but is then returned to the input before
+ the action is executed. So the action only
+ sees the text matched by r. This type
+ of pattern is called trailing context".
+ (There are some combinations of r/s that flex
+ cannot match correctly; see notes in the
+ Deficiencies / Bugs section below regarding
+ "dangerous trailing context".)
+ ^r an r, but only at the beginning of a line (i.e.,
+ which just starting to scan, or right after a
+ newline has been scanned).
+ r$ an r, but only at the end of a line (i.e., just
+ before a newline). Equivalent to "r/\n".
+
+ Note that flex's notion of "newline" is exactly
+ whatever the C compiler used to compile flex
+ interprets '\n' as; in particular, on some DOS
+ systems you must either filter out \r's in the
+ input yourself, or explicitly use r/\r\n for "r$".
+
+
+ <s>r an r, but only in start condition s (see
+ below for discussion of start conditions)
+ <s1,s2,s3>r
+ same, but in any of start conditions s1,
+ s2, or s3
+ <*>r an r in any start condition, even an exclusive one.
+
+
+ <<EOF>> an end-of-file
+ <s1,s2><<EOF>>
+ an end-of-file when in start condition s1 or s2
+
+ Note that inside of a character class, all regular expres-
+ sion operators lose their special meaning except escape
+ ('\') and the character class operators, '-', ']', and, at
+ the beginning of the class, '^'.
+
+ The regular expressions listed above are grouped according
+ to precedence, from highest precedence at the top to lowest
+ at the bottom. Those grouped together have equal pre-
+ cedence. For example,
+
+
+
+Version 2.5 Last change: April 1995 7
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ foo|bar*
+
+ is the same as
+
+ (foo)|(ba(r*))
+
+ since the '*' operator has higher precedence than concatena-
+ tion, and concatenation higher than alternation ('|'). This
+ pattern therefore matches either the string "foo" or the
+ string "ba" followed by zero-or-more r's. To match "foo" or
+ zero-or-more "bar"'s, use:
+
+ foo|(bar)*
+
+ and to match zero-or-more "foo"'s-or-"bar"'s:
+
+ (foo|bar)*
+
+
+ In addition to characters and ranges of characters, charac-
+ ter classes can also contain character class expressions.
+ These are expressions enclosed inside [: and :] delimiters
+ (which themselves must appear between the '[' and ']' of the
+ character class; other elements may occur inside the charac-
+ ter class, too). The valid expressions are:
+
+ [:alnum:] [:alpha:] [:blank:]
+ [:cntrl:] [:digit:] [:graph:]
+ [:lower:] [:print:] [:punct:]
+ [:space:] [:upper:] [:xdigit:]
+
+ These expressions all designate a set of characters
+ equivalent to the corresponding standard C isXXX function.
+ For example, [:alnum:] designates those characters for which
+ isalnum() returns true - i.e., any alphabetic or numeric.
+ Some systems don't provide isblank(), so flex defines
+ [:blank:] as a blank or a tab.
+
+ For example, the following character classes are all
+ equivalent:
+
+ [[:alnum:]]
+ [[:alpha:][:digit:]
+ [[:alpha:]0-9]
+ [a-zA-Z0-9]
+
+ If your scanner is case-insensitive (the -i flag), then
+ [:upper:] and [:lower:] are equivalent to [:alpha:].
+
+ Some notes on patterns:
+
+ - A negated character class such as the example "[^A-Z]"
+
+
+
+Version 2.5 Last change: April 1995 8
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ above will match a newline unless "\n" (or an
+ equivalent escape sequence) is one of the characters
+ explicitly present in the negated character class
+ (e.g., "[^A-Z\n]"). This is unlike how many other reg-
+ ular expression tools treat negated character classes,
+ but unfortunately the inconsistency is historically
+ entrenched. Matching newlines means that a pattern
+ like [^"]* can match the entire input unless there's
+ another quote in the input.
+
+ - A rule can have at most one instance of trailing con-
+ text (the '/' operator or the '$' operator). The start
+ condition, '^', and "<<EOF>>" patterns can only occur
+ at the beginning of a pattern, and, as well as with '/'
+ and '$', cannot be grouped inside parentheses. A '^'
+ which does not occur at the beginning of a rule or a
+ '$' which does not occur at the end of a rule loses its
+ special properties and is treated as a normal charac-
+ ter.
+
+ The following are illegal:
+
+ foo/bar$
+ <sc1>foo<sc2>bar
+
+ Note that the first of these, can be written
+ "foo/bar\n".
+
+ The following will result in '$' or '^' being treated
+ as a normal character:
+
+ foo|(bar$)
+ foo|^bar
+
+ If what's wanted is a "foo" or a bar-followed-by-a-
+ newline, the following could be used (the special '|'
+ action is explained below):
+
+ foo |
+ bar$ /* action goes here */
+
+ A similar trick will work for matching a foo or a bar-
+ at-the-beginning-of-a-line.
+
+HOW THE INPUT IS MATCHED
+ When the generated scanner is run, it analyzes its input
+ looking for strings which match any of its patterns. If it
+ finds more than one match, it takes the one matching the
+ most text (for trailing context rules, this includes the
+ length of the trailing part, even though it will then be
+ returned to the input). If it finds two or more matches of
+ the same length, the rule listed first in the flex input
+
+
+
+Version 2.5 Last change: April 1995 9
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ file is chosen.
+
+ Once the match is determined, the text corresponding to the
+ match (called the token) is made available in the global
+ character pointer yytext, and its length in the global
+ integer yyleng. The action corresponding to the matched pat-
+ tern is then executed (a more detailed description of
+ actions follows), and then the remaining input is scanned
+ for another match.
+
+ If no match is found, then the default rule is executed: the
+ next character in the input is considered matched and copied
+ to the standard output. Thus, the simplest legal flex input
+ is:
+
+ %%
+
+ which generates a scanner that simply copies its input (one
+ character at a time) to its output.
+
+ Note that yytext can be defined in two different ways:
+ either as a character pointer or as a character array. You
+ can control which definition flex uses by including one of
+ the special directives %pointer or %array in the first
+ (definitions) section of your flex input. The default is
+ %pointer, unless you use the -l lex compatibility option, in
+ which case yytext will be an array. The advantage of using
+ %pointer is substantially faster scanning and no buffer
+ overflow when matching very large tokens (unless you run out
+ of dynamic memory). The disadvantage is that you are res-
+ tricted in how your actions can modify yytext (see the next
+ section), and calls to the unput() function destroys the
+ present contents of yytext, which can be a considerable
+ porting headache when moving between different lex versions.
+
+ The advantage of %array is that you can then modify yytext
+ to your heart's content, and calls to unput() do not destroy
+ yytext (see below). Furthermore, existing lex programs
+ sometimes access yytext externally using declarations of the
+ form:
+ extern char yytext[];
+ This definition is erroneous when used with %pointer, but
+ correct for %array.
+
+ %array defines yytext to be an array of YYLMAX characters,
+ which defaults to a fairly large value. You can change the
+ size by simply #define'ing YYLMAX to a different value in
+ the first section of your flex input. As mentioned above,
+ with %pointer yytext grows dynamically to accommodate large
+ tokens. While this means your %pointer scanner can accommo-
+ date very large tokens (such as matching entire blocks of
+ comments), bear in mind that each time the scanner must
+
+
+
+Version 2.5 Last change: April 1995 10
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ resize yytext it also must rescan the entire token from the
+ beginning, so matching such tokens can prove slow. yytext
+ presently does not dynamically grow if a call to unput()
+ results in too much text being pushed back; instead, a run-
+ time error results.
+
+ Also note that you cannot use %array with C++ scanner
+ classes (the c++ option; see below).
+
+ACTIONS
+ Each pattern in a rule has a corresponding action, which can
+ be any arbitrary C statement. The pattern ends at the first
+ non-escaped whitespace character; the remainder of the line
+ is its action. If the action is empty, then when the pat-
+ tern is matched the input token is simply discarded. For
+ example, here is the specification for a program which
+ deletes all occurrences of "zap me" from its input:
+
+ %%
+ "zap me"
+
+ (It will copy all other characters in the input to the out-
+ put since they will be matched by the default rule.)
+
+ Here is a program which compresses multiple blanks and tabs
+ down to a single blank, and throws away whitespace found at
+ the end of a line:
+
+ %%
+ [ \t]+ putchar( ' ' );
+ [ \t]+$ /* ignore this token */
+
+
+ If the action contains a '{', then the action spans till the
+ balancing '}' is found, and the action may cross multiple
+ lines. flex knows about C strings and comments and won't be
+ fooled by braces found within them, but also allows actions
+ to begin with %{ and will consider the action to be all the
+ text up to the next %} (regardless of ordinary braces inside
+ the action).
+
+ An action consisting solely of a vertical bar ('|') means
+ "same as the action for the next rule." See below for an
+ illustration.
+
+ Actions can include arbitrary C code, including return
+ statements to return a value to whatever routine called
+ yylex(). Each time yylex() is called it continues processing
+ tokens from where it last left off until it either reaches
+ the end of the file or executes a return.
+
+
+
+
+
+Version 2.5 Last change: April 1995 11
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ Actions are free to modify yytext except for lengthening it
+ (adding characters to its end--these will overwrite later
+ characters in the input stream). This however does not
+ apply when using %array (see above); in that case, yytext
+ may be freely modified in any way.
+
+ Actions are free to modify yyleng except they should not do
+ so if the action also includes use of yymore() (see below).
+
+ There are a number of special directives which can be
+ included within an action:
+
+ - ECHO copies yytext to the scanner's output.
+
+ - BEGIN followed by the name of a start condition places
+ the scanner in the corresponding start condition (see
+ below).
+
+ - REJECT directs the scanner to proceed on to the "second
+ best" rule which matched the input (or a prefix of the
+ input). The rule is chosen as described above in "How
+ the Input is Matched", and yytext and yyleng set up
+ appropriately. It may either be one which matched as
+ much text as the originally chosen rule but came later
+ in the flex input file, or one which matched less text.
+ For example, the following will both count the words in
+ the input and call the routine special() whenever
+ "frob" is seen:
+
+ int word_count = 0;
+ %%
+
+ frob special(); REJECT;
+ [^ \t\n]+ ++word_count;
+
+ Without the REJECT, any "frob"'s in the input would not
+ be counted as words, since the scanner normally exe-
+ cutes only one action per token. Multiple REJECT's are
+ allowed, each one finding the next best choice to the
+ currently active rule. For example, when the following
+ scanner scans the token "abcd", it will write "abcdab-
+ caba" to the output:
+
+ %%
+ a |
+ ab |
+ abc |
+ abcd ECHO; REJECT;
+ .|\n /* eat up any unmatched character */
+
+ (The first three rules share the fourth's action since
+ they use the special '|' action.) REJECT is a
+
+
+
+Version 2.5 Last change: April 1995 12
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ particularly expensive feature in terms of scanner per-
+ formance; if it is used in any of the scanner's actions
+ it will slow down all of the scanner's matching.
+ Furthermore, REJECT cannot be used with the -Cf or -CF
+ options (see below).
+
+ Note also that unlike the other special actions, REJECT
+ is a branch; code immediately following it in the
+ action will not be executed.
+
+ - yymore() tells the scanner that the next time it
+ matches a rule, the corresponding token should be
+ appended onto the current value of yytext rather than
+ replacing it. For example, given the input "mega-
+ kludge" the following will write "mega-mega-kludge" to
+ the output:
+
+ %%
+ mega- ECHO; yymore();
+ kludge ECHO;
+
+ First "mega-" is matched and echoed to the output.
+ Then "kludge" is matched, but the previous "mega-" is
+ still hanging around at the beginning of yytext so the
+ ECHO for the "kludge" rule will actually write "mega-
+ kludge".
+
+ Two notes regarding use of yymore(). First, yymore() depends
+ on the value of yyleng correctly reflecting the size of the
+ current token, so you must not modify yyleng if you are
+ using yymore(). Second, the presence of yymore() in the
+ scanner's action entails a minor performance penalty in the
+ scanner's matching speed.
+
+ - yyless(n) returns all but the first n characters of the
+ current token back to the input stream, where they will
+ be rescanned when the scanner looks for the next match.
+ yytext and yyleng are adjusted appropriately (e.g.,
+ yyleng will now be equal to n ). For example, on the
+ input "foobar" the following will write out "foobar-
+ bar":
+
+ %%
+ foobar ECHO; yyless(3);
+ [a-z]+ ECHO;
+
+ An argument of 0 to yyless will cause the entire
+ current input string to be scanned again. Unless
+ you've changed how the scanner will subsequently pro-
+ cess its input (using BEGIN, for example), this will
+ result in an endless loop.
+
+
+
+
+Version 2.5 Last change: April 1995 13
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ Note that yyless is a macro and can only be used in the flex
+ input file, not from other source files.
+
+ - unput(c) puts the character c back onto the input
+ stream. It will be the next character scanned. The
+ following action will take the current token and cause
+ it to be rescanned enclosed in parentheses.
+
+ {
+ int i;
+ /* Copy yytext because unput() trashes yytext */
+ char *yycopy = strdup( yytext );
+ unput( ')' );
+ for ( i = yyleng - 1; i >= 0; --i )
+ unput( yycopy[i] );
+ unput( '(' );
+ free( yycopy );
+ }
+
+ Note that since each unput() puts the given character
+ back at the beginning of the input stream, pushing back
+ strings must be done back-to-front.
+
+ An important potential problem when using unput() is that if
+ you are using %pointer (the default), a call to unput() des-
+ troys the contents of yytext, starting with its rightmost
+ character and devouring one character to the left with each
+ call. If you need the value of yytext preserved after a
+ call to unput() (as in the above example), you must either
+ first copy it elsewhere, or build your scanner using %array
+ instead (see How The Input Is Matched).
+
+ Finally, note that you cannot put back EOF to attempt to
+ mark the input stream with an end-of-file.
+
+ - input() reads the next character from the input stream.
+ For example, the following is one way to eat up C com-
+ ments:
+
+ %%
+ "/*" {
+ register int c;
+
+ for ( ; ; )
+ {
+ while ( (c = input()) != '*' &&
+ c != EOF )
+ ; /* eat up text of comment */
+
+ if ( c == '*' )
+ {
+ while ( (c = input()) == '*' )
+
+
+
+Version 2.5 Last change: April 1995 14
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ ;
+ if ( c == '/' )
+ break; /* found the end */
+ }
+
+ if ( c == EOF )
+ {
+ error( "EOF in comment" );
+ break;
+ }
+ }
+ }
+
+ (Note that if the scanner is compiled using C++, then
+ input() is instead referred to as yyinput(), in order
+ to avoid a name clash with the C++ stream by the name
+ of input.)
+
+ - YY_FLUSH_BUFFER flushes the scanner's internal buffer
+ so that the next time the scanner attempts to match a
+ token, it will first refill the buffer using YY_INPUT
+ (see The Generated Scanner, below). This action is a
+ special case of the more general yy_flush_buffer()
+ function, described below in the section Multiple Input
+ Buffers.
+
+ - yyterminate() can be used in lieu of a return statement
+ in an action. It terminates the scanner and returns a
+ 0 to the scanner's caller, indicating "all done". By
+ default, yyterminate() is also called when an end-of-
+ file is encountered. It is a macro and may be rede-
+ fined.
+
+THE GENERATED SCANNER
+ The output of flex is the file lex.yy.c, which contains the
+ scanning routine yylex(), a number of tables used by it for
+ matching tokens, and a number of auxiliary routines and mac-
+ ros. By default, yylex() is declared as follows:
+
+ int yylex()
+ {
+ ... various definitions and the actions in here ...
+ }
+
+ (If your environment supports function prototypes, then it
+ will be "int yylex( void )".) This definition may be
+ changed by defining the "YY_DECL" macro. For example, you
+ could use:
+
+ #define YY_DECL float lexscan( a, b ) float a, b;
+
+ to give the scanning routine the name lexscan, returning a
+
+
+
+Version 2.5 Last change: April 1995 15
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ float, and taking two floats as arguments. Note that if you
+ give arguments to the scanning routine using a K&R-
+ style/non-prototyped function declaration, you must ter-
+ minate the definition with a semi-colon (;).
+
+ Whenever yylex() is called, it scans tokens from the global
+ input file yyin (which defaults to stdin). It continues
+ until it either reaches an end-of-file (at which point it
+ returns the value 0) or one of its actions executes a return
+ statement.
+
+ If the scanner reaches an end-of-file, subsequent calls are
+ undefined unless either yyin is pointed at a new input file
+ (in which case scanning continues from that file), or yyres-
+ tart() is called. yyrestart() takes one argument, a FILE *
+ pointer (which can be nil, if you've set up YY_INPUT to scan
+ from a source other than yyin), and initializes yyin for
+ scanning from that file. Essentially there is no difference
+ between just assigning yyin to a new input file or using
+ yyrestart() to do so; the latter is available for compati-
+ bility with previous versions of flex, and because it can be
+ used to switch input files in the middle of scanning. It
+ can also be used to throw away the current input buffer, by
+ calling it with an argument of yyin; but better is to use
+ YY_FLUSH_BUFFER (see above). Note that yyrestart() does not
+ reset the start condition to INITIAL (see Start Conditions,
+ below).
+
+ If yylex() stops scanning due to executing a return state-
+ ment in one of the actions, the scanner may then be called
+ again and it will resume scanning where it left off.
+
+ By default (and for purposes of efficiency), the scanner
+ uses block-reads rather than simple getc() calls to read
+ characters from yyin. The nature of how it gets its input
+ can be controlled by defining the YY_INPUT macro.
+ YY_INPUT's calling sequence is
+ "YY_INPUT(buf,result,max_size)". Its action is to place up
+ to max_size characters in the character array buf and return
+ in the integer variable result either the number of charac-
+ ters read or the constant YY_NULL (0 on Unix systems) to
+ indicate EOF. The default YY_INPUT reads from the global
+ file-pointer "yyin".
+
+ A sample definition of YY_INPUT (in the definitions section
+ of the input file):
+
+ %{
+ #define YY_INPUT(buf,result,max_size) \
+ { \
+ int c = getchar(); \
+ result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
+
+
+
+Version 2.5 Last change: April 1995 16
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ }
+ %}
+
+ This definition will change the input processing to occur
+ one character at a time.
+
+ When the scanner receives an end-of-file indication from
+ YY_INPUT, it then checks the yywrap() function. If yywrap()
+ returns false (zero), then it is assumed that the function
+ has gone ahead and set up yyin to point to another input
+ file, and scanning continues. If it returns true (non-
+ zero), then the scanner terminates, returning 0 to its
+ caller. Note that in either case, the start condition
+ remains unchanged; it does not revert to INITIAL.
+
+ If you do not supply your own version of yywrap(), then you
+ must either use %option noyywrap (in which case the scanner
+ behaves as though yywrap() returned 1), or you must link
+ with -lfl to obtain the default version of the routine,
+ which always returns 1.
+
+ Three routines are available for scanning from in-memory
+ buffers rather than files: yy_scan_string(),
+ yy_scan_bytes(), and yy_scan_buffer(). See the discussion of
+ them below in the section Multiple Input Buffers.
+
+ The scanner writes its ECHO output to the yyout global
+ (default, stdout), which may be redefined by the user simply
+ by assigning it to some other FILE pointer.
+
+START CONDITIONS
+ flex provides a mechanism for conditionally activating
+ rules. Any rule whose pattern is prefixed with "<sc>" will
+ only be active when the scanner is in the start condition
+ named "sc". For example,
+
+ <STRING>[^"]* { /* eat up the string body ... */
+ ...
+ }
+
+ will be active only when the scanner is in the "STRING"
+ start condition, and
+
+ <INITIAL,STRING,QUOTE>\. { /* handle an escape ... */
+ ...
+ }
+
+ will be active only when the current start condition is
+ either "INITIAL", "STRING", or "QUOTE".
+
+ Start conditions are declared in the definitions (first)
+ section of the input using unindented lines beginning with
+
+
+
+Version 2.5 Last change: April 1995 17
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ either %s or %x followed by a list of names. The former
+ declares inclusive start conditions, the latter exclusive
+ start conditions. A start condition is activated using the
+ BEGIN action. Until the next BEGIN action is executed,
+ rules with the given start condition will be active and
+ rules with other start conditions will be inactive. If the
+ start condition is inclusive, then rules with no start con-
+ ditions at all will also be active. If it is exclusive,
+ then only rules qualified with the start condition will be
+ active. A set of rules contingent on the same exclusive
+ start condition describe a scanner which is independent of
+ any of the other rules in the flex input. Because of this,
+ exclusive start conditions make it easy to specify "mini-
+ scanners" which scan portions of the input that are syntac-
+ tically different from the rest (e.g., comments).
+
+ If the distinction between inclusive and exclusive start
+ conditions is still a little vague, here's a simple example
+ illustrating the connection between the two. The set of
+ rules:
+
+ %s example
+ %%
+
+ <example>foo do_something();
+
+ bar something_else();
+
+ is equivalent to
+
+ %x example
+ %%
+
+ <example>foo do_something();
+
+ <INITIAL,example>bar something_else();
+
+ Without the <INITIAL,example> qualifier, the bar pattern in
+ the second example wouldn't be active (i.e., couldn't match)
+ when in start condition example. If we just used <example>
+ to qualify bar, though, then it would only be active in
+ example and not in INITIAL, while in the first example it's
+ active in both, because in the first example the example
+ startion condition is an inclusive (%s) start condition.
+
+ Also note that the special start-condition specifier <*>
+ matches every start condition. Thus, the above example
+ could also have been written;
+
+ %x example
+ %%
+
+
+
+
+Version 2.5 Last change: April 1995 18
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ <example>foo do_something();
+
+ <*>bar something_else();
+
+
+ The default rule (to ECHO any unmatched character) remains
+ active in start conditions. It is equivalent to:
+
+ <*>.|\n ECHO;
+
+
+ BEGIN(0) returns to the original state where only the rules
+ with no start conditions are active. This state can also be
+ referred to as the start-condition "INITIAL", so
+ BEGIN(INITIAL) is equivalent to BEGIN(0). (The parentheses
+ around the start condition name are not required but are
+ considered good style.)
+
+ BEGIN actions can also be given as indented code at the
+ beginning of the rules section. For example, the following
+ will cause the scanner to enter the "SPECIAL" start condi-
+ tion whenever yylex() is called and the global variable
+ enter_special is true:
+
+ int enter_special;
+
+ %x SPECIAL
+ %%
+ if ( enter_special )
+ BEGIN(SPECIAL);
+
+ <SPECIAL>blahblahblah
+ ...more rules follow...
+
+
+ To illustrate the uses of start conditions, here is a
+ scanner which provides two different interpretations of a
+ string like "123.456". By default it will treat it as three
+ tokens, the integer "123", a dot ('.'), and the integer
+ "456". But if the string is preceded earlier in the line by
+ the string "expect-floats" it will treat it as a single
+ token, the floating-point number 123.456:
+
+ %{
+ #include <math.h>
+ %}
+ %s expect
+
+ %%
+ expect-floats BEGIN(expect);
+
+ <expect>[0-9]+"."[0-9]+ {
+
+
+
+Version 2.5 Last change: April 1995 19
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ printf( "found a float, = %f\n",
+ atof( yytext ) );
+ }
+ <expect>\n {
+ /* that's the end of the line, so
+ * we need another "expect-number"
+ * before we'll recognize any more
+ * numbers
+ */
+ BEGIN(INITIAL);
+ }
+
+ [0-9]+ {
+ printf( "found an integer, = %d\n",
+ atoi( yytext ) );
+ }
+
+ "." printf( "found a dot\n" );
+
+ Here is a scanner which recognizes (and discards) C comments
+ while maintaining a count of the current input line.
+
+ %x comment
+ %%
+ int line_num = 1;
+
+ "/*" BEGIN(comment);
+
+ <comment>[^*\n]* /* eat anything that's not a '*' */
+ <comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+ <comment>\n ++line_num;
+ <comment>"*"+"/" BEGIN(INITIAL);
+
+ This scanner goes to a bit of trouble to match as much text
+ as possible with each rule. In general, when attempting to
+ write a high-speed scanner try to match as much possible in
+ each rule, as it's a big win.
+
+ Note that start-conditions names are really integer values
+ and can be stored as such. Thus, the above could be
+ extended in the following fashion:
+
+ %x comment foo
+ %%
+ int line_num = 1;
+ int comment_caller;
+
+ "/*" {
+ comment_caller = INITIAL;
+ BEGIN(comment);
+ }
+
+
+
+
+Version 2.5 Last change: April 1995 20
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ ...
+
+ <foo>"/*" {
+ comment_caller = foo;
+ BEGIN(comment);
+ }
+
+ <comment>[^*\n]* /* eat anything that's not a '*' */
+ <comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+ <comment>\n ++line_num;
+ <comment>"*"+"/" BEGIN(comment_caller);
+
+ Furthermore, you can access the current start condition
+ using the integer-valued YY_START macro. For example, the
+ above assignments to comment_caller could instead be written
+
+ comment_caller = YY_START;
+
+ Flex provides YYSTATE as an alias for YY_START (since that
+ is what's used by AT&T lex).
+
+ Note that start conditions do not have their own name-space;
+ %s's and %x's declare names in the same fashion as
+ #define's.
+
+ Finally, here's an example of how to match C-style quoted
+ strings using exclusive start conditions, including expanded
+ escape sequences (but not including checking for a string
+ that's too long):
+
+ %x str
+
+ %%
+ char string_buf[MAX_STR_CONST];
+ char *string_buf_ptr;
+
+
+ \" string_buf_ptr = string_buf; BEGIN(str);
+
+ <str>\" { /* saw closing quote - all done */
+ BEGIN(INITIAL);
+ *string_buf_ptr = '\0';
+ /* return string constant token type and
+ * value to parser
+ */
+ }
+
+ <str>\n {
+ /* error - unterminated string constant */
+ /* generate error message */
+ }
+
+
+
+
+Version 2.5 Last change: April 1995 21
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ <str>\\[0-7]{1,3} {
+ /* octal escape sequence */
+ int result;
+
+ (void) sscanf( yytext + 1, "%o", &result );
+
+ if ( result > 0xff )
+ /* error, constant is out-of-bounds */
+
+ *string_buf_ptr++ = result;
+ }
+
+ <str>\\[0-9]+ {
+ /* generate error - bad escape sequence; something
+ * like '\48' or '\0777777'
+ */
+ }
+
+ <str>\\n *string_buf_ptr++ = '\n';
+ <str>\\t *string_buf_ptr++ = '\t';
+ <str>\\r *string_buf_ptr++ = '\r';
+ <str>\\b *string_buf_ptr++ = '\b';
+ <str>\\f *string_buf_ptr++ = '\f';
+
+ <str>\\(.|\n) *string_buf_ptr++ = yytext[1];
+
+ <str>[^\\\n\"]+ {
+ char *yptr = yytext;
+
+ while ( *yptr )
+ *string_buf_ptr++ = *yptr++;
+ }
+
+
+ Often, such as in some of the examples above, you wind up
+ writing a whole bunch of rules all preceded by the same
+ start condition(s). Flex makes this a little easier and
+ cleaner by introducing a notion of start condition scope. A
+ start condition scope is begun with:
+
+ <SCs>{
+
+ where SCs is a list of one or more start conditions. Inside
+ the start condition scope, every rule automatically has the
+ prefix <SCs> applied to it, until a '}' which matches the
+ initial '{'. So, for example,
+
+ <ESC>{
+ "\\n" return '\n';
+ "\\r" return '\r';
+ "\\f" return '\f';
+ "\\0" return '\0';
+
+
+
+Version 2.5 Last change: April 1995 22
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ }
+
+ is equivalent to:
+
+ <ESC>"\\n" return '\n';
+ <ESC>"\\r" return '\r';
+ <ESC>"\\f" return '\f';
+ <ESC>"\\0" return '\0';
+
+ Start condition scopes may be nested.
+
+ Three routines are available for manipulating stacks of
+ start conditions:
+
+ void yy_push_state(int new_state)
+ pushes the current start condition onto the top of the
+ start condition stack and switches to new_state as
+ though you had used BEGIN new_state (recall that start
+ condition names are also integers).
+
+ void yy_pop_state()
+ pops the top of the stack and switches to it via BEGIN.
+
+ int yy_top_state()
+ returns the top of the stack without altering the
+ stack's contents.
+
+ The start condition stack grows dynamically and so has no
+ built-in size limitation. If memory is exhausted, program
+ execution aborts.
+
+ To use start condition stacks, your scanner must include a
+ %option stack directive (see Options below).
+
+MULTIPLE INPUT BUFFERS
+ Some scanners (such as those which support "include" files)
+ require reading from several input streams. As flex
+ scanners do a large amount of buffering, one cannot control
+ where the next input will be read from by simply writing a
+ YY_INPUT which is sensitive to the scanning context.
+ YY_INPUT is only called when the scanner reaches the end of
+ its buffer, which may be a long time after scanning a state-
+ ment such as an "include" which requires switching the input
+ source.
+
+ To negotiate these sorts of problems, flex provides a
+ mechanism for creating and switching between multiple input
+ buffers. An input buffer is created by using:
+
+ YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+
+ which takes a FILE pointer and a size and creates a buffer
+
+
+
+Version 2.5 Last change: April 1995 23
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ associated with the given file and large enough to hold size
+ characters (when in doubt, use YY_BUF_SIZE for the size).
+ It returns a YY_BUFFER_STATE handle, which may then be
+ passed to other routines (see below). The YY_BUFFER_STATE
+ type is a pointer to an opaque struct yy_buffer_state struc-
+ ture, so you may safely initialize YY_BUFFER_STATE variables
+ to ((YY_BUFFER_STATE) 0) if you wish, and also refer to the
+ opaque structure in order to correctly declare input buffers
+ in source files other than that of your scanner. Note that
+ the FILE pointer in the call to yy_create_buffer is only
+ used as the value of yyin seen by YY_INPUT; if you redefine
+ YY_INPUT so it no longer uses yyin, then you can safely pass
+ a nil FILE pointer to yy_create_buffer. You select a partic-
+ ular buffer to scan from using:
+
+ void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+
+ switches the scanner's input buffer so subsequent tokens
+ will come from new_buffer. Note that yy_switch_to_buffer()
+ may be used by yywrap() to set things up for continued scan-
+ ning, instead of opening a new file and pointing yyin at it.
+ Note also that switching input sources via either
+ yy_switch_to_buffer() or yywrap() does not change the start
+ condition.
+
+ void yy_delete_buffer( YY_BUFFER_STATE buffer )
+
+ is used to reclaim the storage associated with a buffer. (
+ buffer can be nil, in which case the routine does nothing.)
+ You can also clear the current contents of a buffer using:
+
+ void yy_flush_buffer( YY_BUFFER_STATE buffer )
+
+ This function discards the buffer's contents, so the next
+ time the scanner attempts to match a token from the buffer,
+ it will first fill the buffer anew using YY_INPUT.
+
+ yy_new_buffer() is an alias for yy_create_buffer(), provided
+ for compatibility with the C++ use of new and delete for
+ creating and destroying dynamic objects.
+
+ Finally, the YY_CURRENT_BUFFER macro returns a
+ YY_BUFFER_STATE handle to the current buffer.
+
+ Here is an example of using these features for writing a
+ scanner which expands include files (the <<EOF>> feature is
+ discussed below):
+
+ /* the "incl" state is used for picking up the name
+ * of an include file
+ */
+ %x incl
+
+
+
+Version 2.5 Last change: April 1995 24
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ %{
+ #define MAX_INCLUDE_DEPTH 10
+ YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
+ int include_stack_ptr = 0;
+ %}
+
+ %%
+ include BEGIN(incl);
+
+ [a-z]+ ECHO;
+ [^a-z\n]*\n? ECHO;
+
+ <incl>[ \t]* /* eat the whitespace */
+ <incl>[^ \t\n]+ { /* got the include file name */
+ if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
+ {
+ fprintf( stderr, "Includes nested too deeply" );
+ exit( 1 );
+ }
+
+ include_stack[include_stack_ptr++] =
+ YY_CURRENT_BUFFER;
+
+ yyin = fopen( yytext, "r" );
+
+ if ( ! yyin )
+ error( ... );
+
+ yy_switch_to_buffer(
+ yy_create_buffer( yyin, YY_BUF_SIZE ) );
+
+ BEGIN(INITIAL);
+ }
+
+ <<EOF>> {
+ if ( --include_stack_ptr < 0 )
+ {
+ yyterminate();
+ }
+
+ else
+ {
+ yy_delete_buffer( YY_CURRENT_BUFFER );
+ yy_switch_to_buffer(
+ include_stack[include_stack_ptr] );
+ }
+ }
+
+ Three routines are available for setting up input buffers
+ for scanning in-memory strings instead of files. All of
+ them create a new input buffer for scanning the string, and
+ return a corresponding YY_BUFFER_STATE handle (which you
+
+
+
+Version 2.5 Last change: April 1995 25
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ should delete with yy_delete_buffer() when done with it).
+ They also switch to the new buffer using
+ yy_switch_to_buffer(), so the next call to yylex() will
+ start scanning the string.
+
+ yy_scan_string(const char *str)
+ scans a NUL-terminated string.
+
+ yy_scan_bytes(const char *bytes, int len)
+ scans len bytes (including possibly NUL's) starting at
+ location bytes.
+
+ Note that both of these functions create and scan a copy of
+ the string or bytes. (This may be desirable, since yylex()
+ modifies the contents of the buffer it is scanning.) You
+ can avoid the copy by using:
+
+ yy_scan_buffer(char *base, yy_size_t size)
+ which scans in place the buffer starting at base, con-
+ sisting of size bytes, the last two bytes of which must
+ be YY_END_OF_BUFFER_CHAR (ASCII NUL). These last two
+ bytes are not scanned; thus, scanning consists of
+ base[0] through base[size-2], inclusive.
+
+ If you fail to set up base in this manner (i.e., forget
+ the final two YY_END_OF_BUFFER_CHAR bytes), then
+ yy_scan_buffer() returns a nil pointer instead of
+ creating a new input buffer.
+
+ The type yy_size_t is an integral type to which you can
+ cast an integer expression reflecting the size of the
+ buffer.
+
+END-OF-FILE RULES
+ The special rule "<<EOF>>" indicates actions which are to be
+ taken when an end-of-file is encountered and yywrap()
+ returns non-zero (i.e., indicates no further files to pro-
+ cess). The action must finish by doing one of four things:
+
+ - assigning yyin to a new input file (in previous ver-
+ sions of flex, after doing the assignment you had to
+ call the special action YY_NEW_FILE; this is no longer
+ necessary);
+
+ - executing a return statement;
+
+ - executing the special yyterminate() action;
+
+ - or, switching to a new buffer using
+ yy_switch_to_buffer() as shown in the example above.
+
+
+
+
+
+Version 2.5 Last change: April 1995 26
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ <<EOF>> rules may not be used with other patterns; they may
+ only be qualified with a list of start conditions. If an
+ unqualified <<EOF>> rule is given, it applies to all start
+ conditions which do not already have <<EOF>> actions. To
+ specify an <<EOF>> rule for only the initial start condi-
+ tion, use
+
+ <INITIAL><<EOF>>
+
+
+ These rules are useful for catching things like unclosed
+ comments. An example:
+
+ %x quote
+ %%
+
+ ...other rules for dealing with quotes...
+
+ <quote><<EOF>> {
+ error( "unterminated quote" );
+ yyterminate();
+ }
+ <<EOF>> {
+ if ( *++filelist )
+ yyin = fopen( *filelist, "r" );
+ else
+ yyterminate();
+ }
+
+
+MISCELLANEOUS MACROS
+ The macro YY_USER_ACTION can be defined to provide an action
+ which is always executed prior to the matched rule's action.
+ For example, it could be #define'd to call a routine to con-
+ vert yytext to lower-case. When YY_USER_ACTION is invoked,
+ the variable yy_act gives the number of the matched rule
+ (rules are numbered starting with 1). Suppose you want to
+ profile how often each of your rules is matched. The fol-
+ lowing would do the trick:
+
+ #define YY_USER_ACTION ++ctr[yy_act]
+
+ where ctr is an array to hold the counts for the different
+ rules. Note that the macro YY_NUM_RULES gives the total
+ number of rules (including the default rule, even if you use
+ -s), so a correct declaration for ctr is:
+
+ int ctr[YY_NUM_RULES];
+
+
+ The macro YY_USER_INIT may be defined to provide an action
+ which is always executed before the first scan (and before
+
+
+
+Version 2.5 Last change: April 1995 27
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ the scanner's internal initializations are done). For exam-
+ ple, it could be used to call a routine to read in a data
+ table or open a logging file.
+
+ The macro yy_set_interactive(is_interactive) can be used to
+ control whether the current buffer is considered interac-
+ tive. An interactive buffer is processed more slowly, but
+ must be used when the scanner's input source is indeed
+ interactive to avoid problems due to waiting to fill buffers
+ (see the discussion of the -I flag below). A non-zero value
+ in the macro invocation marks the buffer as interactive, a
+ zero value as non-interactive. Note that use of this macro
+ overrides %option always-interactive or %option never-
+ interactive (see Options below). yy_set_interactive() must
+ be invoked prior to beginning to scan the buffer that is (or
+ is not) to be considered interactive.
+
+ The macro yy_set_bol(at_bol) can be used to control whether
+ the current buffer's scanning context for the next token
+ match is done as though at the beginning of a line. A non-
+ zero macro argument makes rules anchored with
+
+ The macro YY_AT_BOL() returns true if the next token scanned
+ from the current buffer will have '^' rules active, false
+ otherwise.
+
+ In the generated scanner, the actions are all gathered in
+ one large switch statement and separated using YY_BREAK,
+ which may be redefined. By default, it is simply a "break",
+ to separate each rule's action from the following rule's.
+ Redefining YY_BREAK allows, for example, C++ users to
+ #define YY_BREAK to do nothing (while being very careful
+ that every rule ends with a "break" or a "return"!) to avoid
+ suffering from unreachable statement warnings where because
+ a rule's action ends with "return", the YY_BREAK is inacces-
+ sible.
+
+VALUES AVAILABLE TO THE USER
+ This section summarizes the various values available to the
+ user in the rule actions.
+
+ - char *yytext holds the text of the current token. It
+ may be modified but not lengthened (you cannot append
+ characters to the end).
+
+ If the special directive %array appears in the first
+ section of the scanner description, then yytext is
+ instead declared char yytext[YYLMAX], where YYLMAX is a
+ macro definition that you can redefine in the first
+ section if you don't like the default value (generally
+ 8KB). Using %array results in somewhat slower
+ scanners, but the value of yytext becomes immune to
+
+
+
+Version 2.5 Last change: April 1995 28
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ calls to input() and unput(), which potentially destroy
+ its value when yytext is a character pointer. The
+ opposite of %array is %pointer, which is the default.
+
+ You cannot use %array when generating C++ scanner
+ classes (the -+ flag).
+
+ - int yyleng holds the length of the current token.
+
+ - FILE *yyin is the file which by default flex reads
+ from. It may be redefined but doing so only makes
+ sense before scanning begins or after an EOF has been
+ encountered. Changing it in the midst of scanning will
+ have unexpected results since flex buffers its input;
+ use yyrestart() instead. Once scanning terminates
+ because an end-of-file has been seen, you can assign
+ yyin at the new input file and then call the scanner
+ again to continue scanning.
+
+ - void yyrestart( FILE *new_file ) may be called to point
+ yyin at the new input file. The switch-over to the new
+ file is immediate (any previously buffered-up input is
+ lost). Note that calling yyrestart() with yyin as an
+ argument thus throws away the current input buffer and
+ continues scanning the same input file.
+
+ - FILE *yyout is the file to which ECHO actions are done.
+ It can be reassigned by the user.
+
+ - YY_CURRENT_BUFFER returns a YY_BUFFER_STATE handle to
+ the current buffer.
+
+ - YY_START returns an integer value corresponding to the
+ current start condition. You can subsequently use this
+ value with BEGIN to return to that start condition.
+
+INTERFACING WITH YACC
+ One of the main uses of flex is as a companion to the yacc
+ parser-generator. yacc parsers expect to call a routine
+ named yylex() to find the next input token. The routine is
+ supposed to return the type of the next token as well as
+ putting any associated value in the global yylval. To use
+ flex with yacc, one specifies the -d option to yacc to
+ instruct it to generate the file y.tab.h containing defini-
+ tions of all the %tokens appearing in the yacc input. This
+ file is then included in the flex scanner. For example, if
+ one of the tokens is "TOK_NUMBER", part of the scanner might
+ look like:
+
+ %{
+ #include "y.tab.h"
+ %}
+
+
+
+Version 2.5 Last change: April 1995 29
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ %%
+
+ [0-9]+ yylval = atoi( yytext ); return TOK_NUMBER;
+
+
+OPTIONS
+ flex has the following options:
+
+ -b Generate backing-up information to lex.backup. This is
+ a list of scanner states which require backing up and
+ the input characters on which they do so. By adding
+ rules one can remove backing-up states. If all
+ backing-up states are eliminated and -Cf or -CF is
+ used, the generated scanner will run faster (see the -p
+ flag). Only users who wish to squeeze every last cycle
+ out of their scanners need worry about this option.
+ (See the section on Performance Considerations below.)
+
+ -c is a do-nothing, deprecated option included for POSIX
+ compliance.
+
+ -d makes the generated scanner run in debug mode. When-
+ ever a pattern is recognized and the global
+ yy_flex_debug is non-zero (which is the default), the
+ scanner will write to stderr a line of the form:
+
+ --accepting rule at line 53 ("the matched text")
+
+ The line number refers to the location of the rule in
+ the file defining the scanner (i.e., the file that was
+ fed to flex). Messages are also generated when the
+ scanner backs up, accepts the default rule, reaches the
+ end of its input buffer (or encounters a NUL; at this
+ point, the two look the same as far as the scanner's
+ concerned), or reaches an end-of-file.
+
+ -f specifies fast scanner. No table compression is done
+ and stdio is bypassed. The result is large but fast.
+ This option is equivalent to -Cfr (see below).
+
+ -h generates a "help" summary of flex's options to stdout
+ and then exits. -? and --help are synonyms for -h.
+
+ -i instructs flex to generate a case-insensitive scanner.
+ The case of letters given in the flex input patterns
+ will be ignored, and tokens in the input will be
+ matched regardless of case. The matched text given in
+ yytext will have the preserved case (i.e., it will not
+ be folded).
+
+ -l turns on maximum compatibility with the original AT&T
+ lex implementation. Note that this does not mean full
+
+
+
+Version 2.5 Last change: April 1995 30
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ compatibility. Use of this option costs a considerable
+ amount of performance, and it cannot be used with the
+ -+, -f, -F, -Cf, or -CF options. For details on the
+ compatibilities it provides, see the section "Incompa-
+ tibilities With Lex And POSIX" below. This option also
+ results in the name YY_FLEX_LEX_COMPAT being #define'd
+ in the generated scanner.
+
+ -n is another do-nothing, deprecated option included only
+ for POSIX compliance.
+
+ -p generates a performance report to stderr. The report
+ consists of comments regarding features of the flex
+ input file which will cause a serious loss of perfor-
+ mance in the resulting scanner. If you give the flag
+ twice, you will also get comments regarding features
+ that lead to minor performance losses.
+
+ Note that the use of REJECT, %option yylineno, and
+ variable trailing context (see the Deficiencies / Bugs
+ section below) entails a substantial performance
+ penalty; use of yymore(), the ^ operator, and the -I
+ flag entail minor performance penalties.
+
+ -s causes the default rule (that unmatched scanner input
+ is echoed to stdout) to be suppressed. If the scanner
+ encounters input that does not match any of its rules,
+ it aborts with an error. This option is useful for
+ finding holes in a scanner's rule set.
+
+ -t instructs flex to write the scanner it generates to
+ standard output instead of lex.yy.c.
+
+ -v specifies that flex should write to stderr a summary of
+ statistics regarding the scanner it generates. Most of
+ the statistics are meaningless to the casual flex user,
+ but the first line identifies the version of flex (same
+ as reported by -V), and the next line the flags used
+ when generating the scanner, including those that are
+ on by default.
+
+ -w suppresses warning messages.
+
+ -B instructs flex to generate a batch scanner, the oppo-
+ site of interactive scanners generated by -I (see
+ below). In general, you use -B when you are certain
+ that your scanner will never be used interactively, and
+ you want to squeeze a little more performance out of
+ it. If your goal is instead to squeeze out a lot more
+ performance, you should be using the -Cf or -CF
+ options (discussed below), which turn on -B automati-
+ cally anyway.
+
+
+
+Version 2.5 Last change: April 1995 31
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ -F specifies that the fast scanner table representation
+ should be used (and stdio bypassed). This representa-
+ tion is about as fast as the full table representation
+ (-f), and for some sets of patterns will be consider-
+ ably smaller (and for others, larger). In general, if
+ the pattern set contains both "keywords" and a catch-
+ all, "identifier" rule, such as in the set:
+
+ "case" return TOK_CASE;
+ "switch" return TOK_SWITCH;
+ ...
+ "default" return TOK_DEFAULT;
+ [a-z]+ return TOK_ID;
+
+ then you're better off using the full table representa-
+ tion. If only the "identifier" rule is present and you
+ then use a hash table or some such to detect the key-
+ words, you're better off using -F.
+
+ This option is equivalent to -CFr (see below). It can-
+ not be used with -+.
+
+ -I instructs flex to generate an interactive scanner. An
+ interactive scanner is one that only looks ahead to
+ decide what token has been matched if it absolutely
+ must. It turns out that always looking one extra char-
+ acter ahead, even if the scanner has already seen
+ enough text to disambiguate the current token, is a bit
+ faster than only looking ahead when necessary. But
+ scanners that always look ahead give dreadful interac-
+ tive performance; for example, when a user types a new-
+ line, it is not recognized as a newline token until
+ they enter another token, which often means typing in
+ another whole line.
+
+ Flex scanners default to interactive unless you use the
+ -Cf or -CF table-compression options (see below).
+ That's because if you're looking for high-performance
+ you should be using one of these options, so if you
+ didn't, flex assumes you'd rather trade off a bit of
+ run-time performance for intuitive interactive
+ behavior. Note also that you cannot use -I in conjunc-
+ tion with -Cf or -CF. Thus, this option is not really
+ needed; it is on by default for all those cases in
+ which it is allowed.
+
+ You can force a scanner to not be interactive by using
+ -B (see above).
+
+ -L instructs flex not to generate #line directives.
+ Without this option, flex peppers the generated scanner
+ with #line directives so error messages in the actions
+
+
+
+Version 2.5 Last change: April 1995 32
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ will be correctly located with respect to either the
+ original flex input file (if the errors are due to code
+ in the input file), or lex.yy.c (if the errors are
+ flex's fault -- you should report these sorts of errors
+ to the email address given below).
+
+ -T makes flex run in trace mode. It will generate a lot
+ of messages to stderr concerning the form of the input
+ and the resultant non-deterministic and deterministic
+ finite automata. This option is mostly for use in
+ maintaining flex.
+
+ -V prints the version number to stdout and exits. --ver-
+ sion is a synonym for -V.
+
+ -7 instructs flex to generate a 7-bit scanner, i.e., one
+ which can only recognized 7-bit characters in its
+ input. The advantage of using -7 is that the scanner's
+ tables can be up to half the size of those generated
+ using the -8 option (see below). The disadvantage is
+ that such scanners often hang or crash if their input
+ contains an 8-bit character.
+
+ Note, however, that unless you generate your scanner
+ using the -Cf or -CF table compression options, use of
+ -7 will save only a small amount of table space, and
+ make your scanner considerably less portable. Flex's
+ default behavior is to generate an 8-bit scanner unless
+ you use the -Cf or -CF, in which case flex defaults to
+ generating 7-bit scanners unless your site was always
+ configured to generate 8-bit scanners (as will often be
+ the case with non-USA sites). You can tell whether
+ flex generated a 7-bit or an 8-bit scanner by inspect-
+ ing the flag summary in the -v output as described
+ above.
+
+ Note that if you use -Cfe or -CFe (those table compres-
+ sion options, but also using equivalence classes as
+ discussed see below), flex still defaults to generating
+ an 8-bit scanner, since usually with these compression
+ options full 8-bit tables are not much more expensive
+ than 7-bit tables.
+
+ -8 instructs flex to generate an 8-bit scanner, i.e., one
+ which can recognize 8-bit characters. This flag is
+ only needed for scanners generated using -Cf or -CF, as
+ otherwise flex defaults to generating an 8-bit scanner
+ anyway.
+
+ See the discussion of -7 above for flex's default
+ behavior and the tradeoffs between 7-bit and 8-bit
+ scanners.
+
+
+
+Version 2.5 Last change: April 1995 33
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ -+ specifies that you want flex to generate a C++ scanner
+ class. See the section on Generating C++ Scanners
+ below for details.
+
+ -C[aefFmr]
+ controls the degree of table compression and, more gen-
+ erally, trade-offs between small scanners and fast
+ scanners.
+
+ -Ca ("align") instructs flex to trade off larger tables
+ in the generated scanner for faster performance because
+ the elements of the tables are better aligned for
+ memory access and computation. On some RISC architec-
+ tures, fetching and manipulating longwords is more
+ efficient than with smaller-sized units such as short-
+ words. This option can double the size of the tables
+ used by your scanner.
+
+ -Ce directs flex to construct equivalence classes,
+ i.e., sets of characters which have identical lexical
+ properties (for example, if the only appearance of
+ digits in the flex input is in the character class
+ "[0-9]" then the digits '0', '1', ..., '9' will all be
+ put in the same equivalence class). Equivalence
+ classes usually give dramatic reductions in the final
+ table/object file sizes (typically a factor of 2-5) and
+ are pretty cheap performance-wise (one array look-up
+ per character scanned).
+
+ -Cf specifies that the full scanner tables should be
+ generated - flex should not compress the tables by tak-
+ ing advantages of similar transition functions for dif-
+ ferent states.
+
+ -CF specifies that the alternate fast scanner represen-
+ tation (described above under the -F flag) should be
+ used. This option cannot be used with -+.
+
+ -Cm directs flex to construct meta-equivalence classes,
+ which are sets of equivalence classes (or characters,
+ if equivalence classes are not being used) that are
+ commonly used together. Meta-equivalence classes are
+ often a big win when using compressed tables, but they
+ have a moderate performance impact (one or two "if"
+ tests and one array look-up per character scanned).
+
+ -Cr causes the generated scanner to bypass use of the
+ standard I/O library (stdio) for input. Instead of
+ calling fread() or getc(), the scanner will use the
+ read() system call, resulting in a performance gain
+ which varies from system to system, but in general is
+ probably negligible unless you are also using -Cf or
+
+
+
+Version 2.5 Last change: April 1995 34
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ -CF. Using -Cr can cause strange behavior if, for exam-
+ ple, you read from yyin using stdio prior to calling
+ the scanner (because the scanner will miss whatever
+ text your previous reads left in the stdio input
+ buffer).
+
+ -Cr has no effect if you define YY_INPUT (see The Gen-
+ erated Scanner above).
+
+ A lone -C specifies that the scanner tables should be
+ compressed but neither equivalence classes nor meta-
+ equivalence classes should be used.
+
+ The options -Cf or -CF and -Cm do not make sense
+ together - there is no opportunity for meta-equivalence
+ classes if the table is not being compressed. Other-
+ wise the options may be freely mixed, and are cumula-
+ tive.
+
+ The default setting is -Cem, which specifies that flex
+ should generate equivalence classes and meta-
+ equivalence classes. This setting provides the highest
+ degree of table compression. You can trade off
+ faster-executing scanners at the cost of larger tables
+ with the following generally being true:
+
+ slowest & smallest
+ -Cem
+ -Cm
+ -Ce
+ -C
+ -C{f,F}e
+ -C{f,F}
+ -C{f,F}a
+ fastest & largest
+
+ Note that scanners with the smallest tables are usually
+ generated and compiled the quickest, so during develop-
+ ment you will usually want to use the default, maximal
+ compression.
+
+ -Cfe is often a good compromise between speed and size
+ for production scanners.
+
+ -ooutput
+ directs flex to write the scanner to the file output
+ instead of lex.yy.c. If you combine -o with the -t
+ option, then the scanner is written to stdout but its
+ #line directives (see the -L option above) refer to the
+ file output.
+
+ -Pprefix
+
+
+
+Version 2.5 Last change: April 1995 35
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ changes the default yy prefix used by flex for all
+ globally-visible variable and function names to instead
+ be prefix. For example, -Pfoo changes the name of
+ yytext to footext. It also changes the name of the
+ default output file from lex.yy.c to lex.foo.c. Here
+ are all of the names affected:
+
+ yy_create_buffer
+ yy_delete_buffer
+ yy_flex_debug
+ yy_init_buffer
+ yy_flush_buffer
+ yy_load_buffer_state
+ yy_switch_to_buffer
+ yyin
+ yyleng
+ yylex
+ yylineno
+ yyout
+ yyrestart
+ yytext
+ yywrap
+
+ (If you are using a C++ scanner, then only yywrap and
+ yyFlexLexer are affected.) Within your scanner itself,
+ you can still refer to the global variables and func-
+ tions using either version of their name; but exter-
+ nally, they have the modified name.
+
+ This option lets you easily link together multiple flex
+ programs into the same executable. Note, though, that
+ using this option also renames yywrap(), so you now
+ must either provide your own (appropriately-named) ver-
+ sion of the routine for your scanner, or use %option
+ noyywrap, as linking with -lfl no longer provides one
+ for you by default.
+
+ -Sskeleton_file
+ overrides the default skeleton file from which flex
+ constructs its scanners. You'll never need this option
+ unless you are doing flex maintenance or development.
+
+ flex also provides a mechanism for controlling options
+ within the scanner specification itself, rather than from
+ the flex command-line. This is done by including %option
+ directives in the first section of the scanner specifica-
+ tion. You can specify multiple options with a single
+ %option directive, and multiple directives in the first sec-
+ tion of your flex input file.
+
+ Most options are given simply as names, optionally preceded
+ by the word "no" (with no intervening whitespace) to negate
+
+
+
+Version 2.5 Last change: April 1995 36
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ their meaning. A number are equivalent to flex flags or
+ their negation:
+
+ 7bit -7 option
+ 8bit -8 option
+ align -Ca option
+ backup -b option
+ batch -B option
+ c++ -+ option
+
+ caseful or
+ case-sensitive opposite of -i (default)
+
+ case-insensitive or
+ caseless -i option
+
+ debug -d option
+ default opposite of -s option
+ ecs -Ce option
+ fast -F option
+ full -f option
+ interactive -I option
+ lex-compat -l option
+ meta-ecs -Cm option
+ perf-report -p option
+ read -Cr option
+ stdout -t option
+ verbose -v option
+ warn opposite of -w option
+ (use "%option nowarn" for -w)
+
+ array equivalent to "%array"
+ pointer equivalent to "%pointer" (default)
+
+ Some %option's provide features otherwise not available:
+
+ always-interactive
+ instructs flex to generate a scanner which always con-
+ siders its input "interactive". Normally, on each new
+ input file the scanner calls isatty() in an attempt to
+ determine whether the scanner's input source is
+ interactive and thus should be read a character at a
+ time. When this option is used, however, then no such
+ call is made.
+
+ main directs flex to provide a default main() program for
+ the scanner, which simply calls yylex(). This option
+ implies noyywrap (see below).
+
+ never-interactive
+ instructs flex to generate a scanner which never con-
+ siders its input "interactive" (again, no call made to
+
+
+
+Version 2.5 Last change: April 1995 37
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ isatty()). This is the opposite of always-interactive.
+
+ stack
+ enables the use of start condition stacks (see Start
+ Conditions above).
+
+ stdinit
+ if set (i.e., %option stdinit) initializes yyin and
+ yyout to stdin and stdout, instead of the default of
+ nil. Some existing lex programs depend on this
+ behavior, even though it is not compliant with ANSI C,
+ which does not require stdin and stdout to be compile-
+ time constant.
+
+ yylineno
+ directs flex to generate a scanner that maintains the
+ number of the current line read from its input in the
+ global variable yylineno. This option is implied by
+ %option lex-compat.
+
+ yywrap
+ if unset (i.e., %option noyywrap), makes the scanner
+ not call yywrap() upon an end-of-file, but simply
+ assume that there are no more files to scan (until the
+ user points yyin at a new file and calls yylex()
+ again).
+
+ flex scans your rule actions to determine whether you use
+ the REJECT or yymore() features. The reject and yymore
+ options are available to override its decision as to whether
+ you use the options, either by setting them (e.g., %option
+ reject) to indicate the feature is indeed used, or unsetting
+ them to indicate it actually is not used (e.g., %option
+ noyymore).
+
+ Three options take string-delimited values, offset with '=':
+
+ %option outfile="ABC"
+
+ is equivalent to -oABC, and
+
+ %option prefix="XYZ"
+
+ is equivalent to -PXYZ. Finally,
+
+ %option yyclass="foo"
+
+ only applies when generating a C++ scanner ( -+ option). It
+ informs flex that you have derived foo as a subclass of
+ yyFlexLexer, so flex will place your actions in the member
+ function foo::yylex() instead of yyFlexLexer::yylex(). It
+ also generates a yyFlexLexer::yylex() member function that
+
+
+
+Version 2.5 Last change: April 1995 38
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ emits a run-time error (by invoking
+ yyFlexLexer::LexerError()) if called. See Generating C++
+ Scanners, below, for additional information.
+
+ A number of options are available for lint purists who want
+ to suppress the appearance of unneeded routines in the gen-
+ erated scanner. Each of the following, if unset (e.g.,
+ %option nounput ), results in the corresponding routine not
+ appearing in the generated scanner:
+
+ input, unput
+ yy_push_state, yy_pop_state, yy_top_state
+ yy_scan_buffer, yy_scan_bytes, yy_scan_string
+
+ (though yy_push_state() and friends won't appear anyway
+ unless you use %option stack).
+
+PERFORMANCE CONSIDERATIONS
+ The main design goal of flex is that it generate high-
+ performance scanners. It has been optimized for dealing
+ well with large sets of rules. Aside from the effects on
+ scanner speed of the table compression -C options outlined
+ above, there are a number of options/actions which degrade
+ performance. These are, from most expensive to least:
+
+ REJECT
+ %option yylineno
+ arbitrary trailing context
+
+ pattern sets that require backing up
+ %array
+ %option interactive
+ %option always-interactive
+
+ '^' beginning-of-line operator
+ yymore()
+
+ with the first three all being quite expensive and the last
+ two being quite cheap. Note also that unput() is imple-
+ mented as a routine call that potentially does quite a bit
+ of work, while yyless() is a quite-cheap macro; so if just
+ putting back some excess text you scanned, use yyless().
+
+ REJECT should be avoided at all costs when performance is
+ important. It is a particularly expensive option.
+
+ Getting rid of backing up is messy and often may be an enor-
+ mous amount of work for a complicated scanner. In princi-
+ pal, one begins by using the -b flag to generate a
+ lex.backup file. For example, on the input
+
+ %%
+
+
+
+Version 2.5 Last change: April 1995 39
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ foo return TOK_KEYWORD;
+ foobar return TOK_KEYWORD;
+
+ the file looks like:
+
+ State #6 is non-accepting -
+ associated rule line numbers:
+ 2 3
+ out-transitions: [ o ]
+ jam-transitions: EOF [ \001-n p-\177 ]
+
+ State #8 is non-accepting -
+ associated rule line numbers:
+ 3
+ out-transitions: [ a ]
+ jam-transitions: EOF [ \001-` b-\177 ]
+
+ State #9 is non-accepting -
+ associated rule line numbers:
+ 3
+ out-transitions: [ r ]
+ jam-transitions: EOF [ \001-q s-\177 ]
+
+ Compressed tables always back up.
+
+ The first few lines tell us that there's a scanner state in
+ which it can make a transition on an 'o' but not on any
+ other character, and that in that state the currently
+ scanned text does not match any rule. The state occurs when
+ trying to match the rules found at lines 2 and 3 in the
+ input file. If the scanner is in that state and then reads
+ something other than an 'o', it will have to back up to find
+ a rule which is matched. With a bit of headscratching one
+ can see that this must be the state it's in when it has seen
+ "fo". When this has happened, if anything other than
+ another 'o' is seen, the scanner will have to back up to
+ simply match the 'f' (by the default rule).
+
+ The comment regarding State #8 indicates there's a problem
+ when "foob" has been scanned. Indeed, on any character
+ other than an 'a', the scanner will have to back up to
+ accept "foo". Similarly, the comment for State #9 concerns
+ when "fooba" has been scanned and an 'r' does not follow.
+
+ The final comment reminds us that there's no point going to
+ all the trouble of removing backing up from the rules unless
+ we're using -Cf or -CF, since there's no performance gain
+ doing so with compressed scanners.
+
+ The way to remove the backing up is to add "error" rules:
+
+ %%
+
+
+
+Version 2.5 Last change: April 1995 40
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ foo return TOK_KEYWORD;
+ foobar return TOK_KEYWORD;
+
+ fooba |
+ foob |
+ fo {
+ /* false alarm, not really a keyword */
+ return TOK_ID;
+ }
+
+
+ Eliminating backing up among a list of keywords can also be
+ done using a "catch-all" rule:
+
+ %%
+ foo return TOK_KEYWORD;
+ foobar return TOK_KEYWORD;
+
+ [a-z]+ return TOK_ID;
+
+ This is usually the best solution when appropriate.
+
+ Backing up messages tend to cascade. With a complicated set
+ of rules it's not uncommon to get hundreds of messages. If
+ one can decipher them, though, it often only takes a dozen
+ or so rules to eliminate the backing up (though it's easy to
+ make a mistake and have an error rule accidentally match a
+ valid token. A possible future flex feature will be to
+ automatically add rules to eliminate backing up).
+
+ It's important to keep in mind that you gain the benefits of
+ eliminating backing up only if you eliminate every instance
+ of backing up. Leaving just one means you gain nothing.
+
+ Variable trailing context (where both the leading and trail-
+ ing parts do not have a fixed length) entails almost the
+ same performance loss as REJECT (i.e., substantial). So
+ when possible a rule like:
+
+ %%
+ mouse|rat/(cat|dog) run();
+
+ is better written:
+
+ %%
+ mouse/cat|dog run();
+ rat/cat|dog run();
+
+ or as
+
+ %%
+ mouse|rat/cat run();
+
+
+
+Version 2.5 Last change: April 1995 41
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ mouse|rat/dog run();
+
+ Note that here the special '|' action does not provide any
+ savings, and can even make things worse (see Deficiencies /
+ Bugs below).
+
+ Another area where the user can increase a scanner's perfor-
+ mance (and one that's easier to implement) arises from the
+ fact that the longer the tokens matched, the faster the
+ scanner will run. This is because with long tokens the pro-
+ cessing of most input characters takes place in the (short)
+ inner scanning loop, and does not often have to go through
+ the additional work of setting up the scanning environment
+ (e.g., yytext) for the action. Recall the scanner for C
+ comments:
+
+ %x comment
+ %%
+ int line_num = 1;
+
+ "/*" BEGIN(comment);
+
+ <comment>[^*\n]*
+ <comment>"*"+[^*/\n]*
+ <comment>\n ++line_num;
+ <comment>"*"+"/" BEGIN(INITIAL);
+
+ This could be sped up by writing it as:
+
+ %x comment
+ %%
+ int line_num = 1;
+
+ "/*" BEGIN(comment);
+
+ <comment>[^*\n]*
+ <comment>[^*\n]*\n ++line_num;
+ <comment>"*"+[^*/\n]*
+ <comment>"*"+[^*/\n]*\n ++line_num;
+ <comment>"*"+"/" BEGIN(INITIAL);
+
+ Now instead of each newline requiring the processing of
+ another action, recognizing the newlines is "distributed"
+ over the other rules to keep the matched text as long as
+ possible. Note that adding rules does not slow down the
+ scanner! The speed of the scanner is independent of the
+ number of rules or (modulo the considerations given at the
+ beginning of this section) how complicated the rules are
+ with regard to operators such as '*' and '|'.
+
+ A final example in speeding up a scanner: suppose you want
+ to scan through a file containing identifiers and keywords,
+
+
+
+Version 2.5 Last change: April 1995 42
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ one per line and with no other extraneous characters, and
+ recognize all the keywords. A natural first approach is:
+
+ %%
+ asm |
+ auto |
+ break |
+ ... etc ...
+ volatile |
+ while /* it's a keyword */
+
+ .|\n /* it's not a keyword */
+
+ To eliminate the back-tracking, introduce a catch-all rule:
+
+ %%
+ asm |
+ auto |
+ break |
+ ... etc ...
+ volatile |
+ while /* it's a keyword */
+
+ [a-z]+ |
+ .|\n /* it's not a keyword */
+
+ Now, if it's guaranteed that there's exactly one word per
+ line, then we can reduce the total number of matches by a
+ half by merging in the recognition of newlines with that of
+ the other tokens:
+
+ %%
+ asm\n |
+ auto\n |
+ break\n |
+ ... etc ...
+ volatile\n |
+ while\n /* it's a keyword */
+
+ [a-z]+\n |
+ .|\n /* it's not a keyword */
+
+ One has to be careful here, as we have now reintroduced
+ backing up into the scanner. In particular, while we know
+ that there will never be any characters in the input stream
+ other than letters or newlines, flex can't figure this out,
+ and it will plan for possibly needing to back up when it has
+ scanned a token like "auto" and then the next character is
+ something other than a newline or a letter. Previously it
+ would then just match the "auto" rule and be done, but now
+ it has no "auto" rule, only a "auto\n" rule. To eliminate
+ the possibility of backing up, we could either duplicate all
+
+
+
+Version 2.5 Last change: April 1995 43
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ rules but without final newlines, or, since we never expect
+ to encounter such an input and therefore don't how it's
+ classified, we can introduce one more catch-all rule, this
+ one which doesn't include a newline:
+
+ %%
+ asm\n |
+ auto\n |
+ break\n |
+ ... etc ...
+ volatile\n |
+ while\n /* it's a keyword */
+
+ [a-z]+\n |
+ [a-z]+ |
+ .|\n /* it's not a keyword */
+
+ Compiled with -Cf, this is about as fast as one can get a
+ flex scanner to go for this particular problem.
+
+ A final note: flex is slow when matching NUL's, particularly
+ when a token contains multiple NUL's. It's best to write
+ rules which match short amounts of text if it's anticipated
+ that the text will often include NUL's.
+
+ Another final note regarding performance: as mentioned above
+ in the section How the Input is Matched, dynamically resiz-
+ ing yytext to accommodate huge tokens is a slow process
+ because it presently requires that the (huge) token be res-
+ canned from the beginning. Thus if performance is vital,
+ you should attempt to match "large" quantities of text but
+ not "huge" quantities, where the cutoff between the two is
+ at about 8K characters/token.
+
+GENERATING C++ SCANNERS
+ flex provides two different ways to generate scanners for
+ use with C++. The first way is to simply compile a scanner
+ generated by flex using a C++ compiler instead of a C com-
+ piler. You should not encounter any compilations errors
+ (please report any you find to the email address given in
+ the Author section below). You can then use C++ code in
+ your rule actions instead of C code. Note that the default
+ input source for your scanner remains yyin, and default
+ echoing is still done to yyout. Both of these remain FILE *
+ variables and not C++ streams.
+
+ You can also use flex to generate a C++ scanner class, using
+ the -+ option (or, equivalently, %option c++), which is
+ automatically specified if the name of the flex executable
+ ends in a '+', such as flex++. When using this option, flex
+ defaults to generating the scanner to the file lex.yy.cc
+ instead of lex.yy.c. The generated scanner includes the
+
+
+
+Version 2.5 Last change: April 1995 44
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ header file FlexLexer.h, which defines the interface to two
+ C++ classes.
+
+ The first class, FlexLexer, provides an abstract base class
+ defining the general scanner class interface. It provides
+ the following member functions:
+
+ const char* YYText()
+ returns the text of the most recently matched token,
+ the equivalent of yytext.
+
+ int YYLeng()
+ returns the length of the most recently matched token,
+ the equivalent of yyleng.
+
+ int lineno() const
+ returns the current input line number (see %option
+ yylineno), or 1 if %option yylineno was not used.
+
+ void set_debug( int flag )
+ sets the debugging flag for the scanner, equivalent to
+ assigning to yy_flex_debug (see the Options section
+ above). Note that you must build the scanner using
+ %option debug to include debugging information in it.
+
+ int debug() const
+ returns the current setting of the debugging flag.
+
+ Also provided are member functions equivalent to
+ yy_switch_to_buffer(), yy_create_buffer() (though the first
+ argument is an istream* object pointer and not a FILE*),
+ yy_flush_buffer(), yy_delete_buffer(), and yyrestart()
+ (again, the first argument is a istream* object pointer).
+
+ The second class defined in FlexLexer.h is yyFlexLexer,
+ which is derived from FlexLexer. It defines the following
+ additional member functions:
+
+ yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )
+ constructs a yyFlexLexer object using the given streams
+ for input and output. If not specified, the streams
+ default to cin and cout, respectively.
+
+ virtual int yylex()
+ performs the same role is yylex() does for ordinary
+ flex scanners: it scans the input stream, consuming
+ tokens, until a rule's action returns a value. If you
+ derive a subclass S from yyFlexLexer and want to access
+ the member functions and variables of S inside yylex(),
+ then you need to use %option yyclass="S" to inform flex
+ that you will be using that subclass instead of yyFlex-
+ Lexer. In this case, rather than generating
+
+
+
+Version 2.5 Last change: April 1995 45
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ yyFlexLexer::yylex(), flex generates S::yylex() (and
+ also generates a dummy yyFlexLexer::yylex() that calls
+ yyFlexLexer::LexerError() if called).
+
+ virtual void switch_streams(istream* new_in = 0,
+ ostream* new_out = 0) reassigns yyin to new_in (if
+ non-nil) and yyout to new_out (ditto), deleting the
+ previous input buffer if yyin is reassigned.
+
+ int yylex( istream* new_in, ostream* new_out = 0 )
+ first switches the input streams via switch_streams(
+ new_in, new_out ) and then returns the value of
+ yylex().
+
+ In addition, yyFlexLexer defines the following protected
+ virtual functions which you can redefine in derived classes
+ to tailor the scanner:
+
+ virtual int LexerInput( char* buf, int max_size )
+ reads up to max_size characters into buf and returns
+ the number of characters read. To indicate end-of-
+ input, return 0 characters. Note that "interactive"
+ scanners (see the -B and -I flags) define the macro
+ YY_INTERACTIVE. If you redefine LexerInput() and need
+ to take different actions depending on whether or not
+ the scanner might be scanning an interactive input
+ source, you can test for the presence of this name via
+ #ifdef.
+
+ virtual void LexerOutput( const char* buf, int size )
+ writes out size characters from the buffer buf, which,
+ while NUL-terminated, may also contain "internal" NUL's
+ if the scanner's rules can match text with NUL's in
+ them.
+
+ virtual void LexerError( const char* msg )
+ reports a fatal error message. The default version of
+ this function writes the message to the stream cerr and
+ exits.
+
+ Note that a yyFlexLexer object contains its entire scanning
+ state. Thus you can use such objects to create reentrant
+ scanners. You can instantiate multiple instances of the
+ same yyFlexLexer class, and you can also combine multiple
+ C++ scanner classes together in the same program using the
+ -P option discussed above.
+
+ Finally, note that the %array feature is not available to
+ C++ scanner classes; you must use %pointer (the default).
+
+ Here is an example of a simple C++ scanner:
+
+
+
+
+Version 2.5 Last change: April 1995 46
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ // An example of using the flex C++ scanner class.
+
+ %{
+ int mylineno = 0;
+ %}
+
+ string \"[^\n"]+\"
+
+ ws [ \t]+
+
+ alpha [A-Za-z]
+ dig [0-9]
+ name ({alpha}|{dig}|\$)({alpha}|{dig}|[_.\-/$])*
+ num1 [-+]?{dig}+\.?([eE][-+]?{dig}+)?
+ num2 [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)?
+ number {num1}|{num2}
+
+ %%
+
+ {ws} /* skip blanks and tabs */
+
+ "/*" {
+ int c;
+
+ while((c = yyinput()) != 0)
+ {
+ if(c == '\n')
+ ++mylineno;
+
+ else if(c == '*')
+ {
+ if((c = yyinput()) == '/')
+ break;
+ else
+ unput(c);
+ }
+ }
+ }
+
+ {number} cout << "number " << YYText() << '\n';
+
+ \n mylineno++;
+
+ {name} cout << "name " << YYText() << '\n';
+
+ {string} cout << "string " << YYText() << '\n';
+
+ %%
+
+ int main( int /* argc */, char** /* argv */ )
+ {
+ FlexLexer* lexer = new yyFlexLexer;
+
+
+
+Version 2.5 Last change: April 1995 47
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ while(lexer->yylex() != 0)
+ ;
+ return 0;
+ }
+ If you want to create multiple (different) lexer classes,
+ you use the -P flag (or the prefix= option) to rename each
+ yyFlexLexer to some other xxFlexLexer. You then can include
+ <FlexLexer.h> in your other sources once per lexer class,
+ first renaming yyFlexLexer as follows:
+
+ #undef yyFlexLexer
+ #define yyFlexLexer xxFlexLexer
+ #include <FlexLexer.h>
+
+ #undef yyFlexLexer
+ #define yyFlexLexer zzFlexLexer
+ #include <FlexLexer.h>
+
+ if, for example, you used %option prefix="xx" for one of
+ your scanners and %option prefix="zz" for the other.
+
+ IMPORTANT: the present form of the scanning class is experi-
+ mental and may change considerably between major releases.
+
+INCOMPATIBILITIES WITH LEX AND POSIX
+ flex is a rewrite of the AT&T Unix lex tool (the two imple-
+ mentations do not share any code, though), with some exten-
+ sions and incompatibilities, both of which are of concern to
+ those who wish to write scanners acceptable to either imple-
+ mentation. Flex is fully compliant with the POSIX lex
+ specification, except that when using %pointer (the
+ default), a call to unput() destroys the contents of yytext,
+ which is counter to the POSIX specification.
+
+ In this section we discuss all of the known areas of incom-
+ patibility between flex, AT&T lex, and the POSIX specifica-
+ tion.
+
+ flex's -l option turns on maximum compatibility with the
+ original AT&T lex implementation, at the cost of a major
+ loss in the generated scanner's performance. We note below
+ which incompatibilities can be overcome using the -l option.
+
+ flex is fully compatible with lex with the following excep-
+ tions:
+
+ - The undocumented lex scanner internal variable yylineno
+ is not supported unless -l or %option yylineno is used.
+
+ yylineno should be maintained on a per-buffer basis,
+ rather than a per-scanner (single global variable)
+ basis.
+
+
+
+Version 2.5 Last change: April 1995 48
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ yylineno is not part of the POSIX specification.
+
+ - The input() routine is not redefinable, though it may
+ be called to read characters following whatever has
+ been matched by a rule. If input() encounters an end-
+ of-file the normal yywrap() processing is done. A
+ ``real'' end-of-file is returned by input() as EOF.
+
+ Input is instead controlled by defining the YY_INPUT
+ macro.
+
+ The flex restriction that input() cannot be redefined
+ is in accordance with the POSIX specification, which
+ simply does not specify any way of controlling the
+ scanner's input other than by making an initial assign-
+ ment to yyin.
+
+ - The unput() routine is not redefinable. This restric-
+ tion is in accordance with POSIX.
+
+ - flex scanners are not as reentrant as lex scanners. In
+ particular, if you have an interactive scanner and an
+ interrupt handler which long-jumps out of the scanner,
+ and the scanner is subsequently called again, you may
+ get the following message:
+
+ fatal flex scanner internal error--end of buffer missed
+
+ To reenter the scanner, first use
+
+ yyrestart( yyin );
+
+ Note that this call will throw away any buffered input;
+ usually this isn't a problem with an interactive
+ scanner.
+
+ Also note that flex C++ scanner classes are reentrant,
+ so if using C++ is an option for you, you should use
+ them instead. See "Generating C++ Scanners" above for
+ details.
+
+ - output() is not supported. Output from the ECHO macro
+ is done to the file-pointer yyout (default stdout).
+
+ output() is not part of the POSIX specification.
+
+ - lex does not support exclusive start conditions (%x),
+ though they are in the POSIX specification.
+
+ - When definitions are expanded, flex encloses them in
+ parentheses. With lex, the following:
+
+
+
+
+Version 2.5 Last change: April 1995 49
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ NAME [A-Z][A-Z0-9]*
+ %%
+ foo{NAME}? printf( "Found it\n" );
+ %%
+
+ will not match the string "foo" because when the macro
+ is expanded the rule is equivalent to "foo[A-Z][A-Z0-
+ 9]*?" and the precedence is such that the '?' is asso-
+ ciated with "[A-Z0-9]*". With flex, the rule will be
+ expanded to "foo([A-Z][A-Z0-9]*)?" and so the string
+ "foo" will match.
+
+ Note that if the definition begins with ^ or ends with
+ $ then it is not expanded with parentheses, to allow
+ these operators to appear in definitions without losing
+ their special meanings. But the <s>, /, and <<EOF>>
+ operators cannot be used in a flex definition.
+
+ Using -l results in the lex behavior of no parentheses
+ around the definition.
+
+ The POSIX specification is that the definition be
+ enclosed in parentheses.
+
+ - Some implementations of lex allow a rule's action to
+ begin on a separate line, if the rule's pattern has
+ trailing whitespace:
+
+ %%
+ foo|bar<space here>
+ { foobar_action(); }
+
+ flex does not support this feature.
+
+ - The lex %r (generate a Ratfor scanner) option is not
+ supported. It is not part of the POSIX specification.
+
+ - After a call to unput(), yytext is undefined until the
+ next token is matched, unless the scanner was built
+ using %array. This is not the case with lex or the
+ POSIX specification. The -l option does away with this
+ incompatibility.
+
+ - The precedence of the {} (numeric range) operator is
+ different. lex interprets "abc{1,3}" as "match one,
+ two, or three occurrences of 'abc'", whereas flex
+ interprets it as "match 'ab' followed by one, two, or
+ three occurrences of 'c'". The latter is in agreement
+ with the POSIX specification.
+
+ - The precedence of the ^ operator is different. lex
+ interprets "^foo|bar" as "match either 'foo' at the
+
+
+
+Version 2.5 Last change: April 1995 50
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ beginning of a line, or 'bar' anywhere", whereas flex
+ interprets it as "match either 'foo' or 'bar' if they
+ come at the beginning of a line". The latter is in
+ agreement with the POSIX specification.
+
+ - The special table-size declarations such as %a sup-
+ ported by lex are not required by flex scanners; flex
+ ignores them.
+
+ - The name FLEX_SCANNER is #define'd so scanners may be
+ written for use with either flex or lex. Scanners also
+ include YY_FLEX_MAJOR_VERSION and YY_FLEX_MINOR_VERSION
+ indicating which version of flex generated the scanner
+ (for example, for the 2.5 release, these defines would
+ be 2 and 5 respectively).
+
+ The following flex features are not included in lex or the
+ POSIX specification:
+
+ C++ scanners
+ %option
+ start condition scopes
+ start condition stacks
+ interactive/non-interactive scanners
+ yy_scan_string() and friends
+ yyterminate()
+ yy_set_interactive()
+ yy_set_bol()
+ YY_AT_BOL()
+ <<EOF>>
+ <*>
+ YY_DECL
+ YY_START
+ YY_USER_ACTION
+ YY_USER_INIT
+ #line directives
+ %{}'s around actions
+ multiple actions on a line
+
+ plus almost all of the flex flags. The last feature in the
+ list refers to the fact that with flex you can put multiple
+ actions on the same line, separated with semi-colons, while
+ with lex, the following
+
+ foo handle_foo(); ++num_foos_seen;
+
+ is (rather surprisingly) truncated to
+
+ foo handle_foo();
+
+ flex does not truncate the action. Actions that are not
+ enclosed in braces are simply terminated at the end of the
+
+
+
+Version 2.5 Last change: April 1995 51
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ line.
+
+DIAGNOSTICS
+ warning, rule cannot be matched indicates that the given
+ rule cannot be matched because it follows other rules that
+ will always match the same text as it. For example, in the
+ following "foo" cannot be matched because it comes after an
+ identifier "catch-all" rule:
+
+ [a-z]+ got_identifier();
+ foo got_foo();
+
+ Using REJECT in a scanner suppresses this warning.
+
+ warning, -s option given but default rule can be matched
+ means that it is possible (perhaps only in a particular
+ start condition) that the default rule (match any single
+ character) is the only one that will match a particular
+ input. Since -s was given, presumably this is not intended.
+
+ reject_used_but_not_detected undefined or
+ yymore_used_but_not_detected undefined - These errors can
+ occur at compile time. They indicate that the scanner uses
+ REJECT or yymore() but that flex failed to notice the fact,
+ meaning that flex scanned the first two sections looking for
+ occurrences of these actions and failed to find any, but
+ somehow you snuck some in (via a #include file, for exam-
+ ple). Use %option reject or %option yymore to indicate to
+ flex that you really do use these features.
+
+ flex scanner jammed - a scanner compiled with -s has encoun-
+ tered an input string which wasn't matched by any of its
+ rules. This error can also occur due to internal problems.
+
+ token too large, exceeds YYLMAX - your scanner uses %array
+ and one of its rules matched a string longer than the YYLMAX
+ constant (8K bytes by default). You can increase the value
+ by #define'ing YYLMAX in the definitions section of your
+ flex input.
+
+ scanner requires -8 flag to use the character 'x' - Your
+ scanner specification includes recognizing the 8-bit charac-
+ ter 'x' and you did not specify the -8 flag, and your
+ scanner defaulted to 7-bit because you used the -Cf or -CF
+ table compression options. See the discussion of the -7
+ flag for details.
+
+ flex scanner push-back overflow - you used unput() to push
+ back so much text that the scanner's buffer could not hold
+ both the pushed-back text and the current token in yytext.
+ Ideally the scanner should dynamically resize the buffer in
+ this case, but at present it does not.
+
+
+
+Version 2.5 Last change: April 1995 52
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ input buffer overflow, can't enlarge buffer because scanner
+ uses REJECT - the scanner was working on matching an
+ extremely large token and needed to expand the input buffer.
+ This doesn't work with scanners that use REJECT.
+
+ fatal flex scanner internal error--end of buffer missed -
+ This can occur in an scanner which is reentered after a
+ long-jump has jumped out (or over) the scanner's activation
+ frame. Before reentering the scanner, use:
+
+ yyrestart( yyin );
+
+ or, as noted above, switch to using the C++ scanner class.
+
+ too many start conditions in <> you listed more start condi-
+ tions in a <> construct than exist (so you must have listed
+ at least one of them twice).
+
+FILES
+ -lfl library with which scanners must be linked.
+
+ lex.yy.c
+ generated scanner (called lexyy.c on some systems).
+
+ lex.yy.cc
+ generated C++ scanner class, when using -+.
+
+ <FlexLexer.h>
+ header file defining the C++ scanner base class, Flex-
+ Lexer, and its derived class, yyFlexLexer.
+
+ flex.skl
+ skeleton scanner. This file is only used when building
+ flex, not when flex executes.
+
+ lex.backup
+ backing-up information for -b flag (called lex.bck on
+ some systems).
+
+DEFICIENCIES / BUGS
+ Some trailing context patterns cannot be properly matched
+ and generate warning messages ("dangerous trailing con-
+ text"). These are patterns where the ending of the first
+ part of the rule matches the beginning of the second part,
+ such as "zx*/xy*", where the 'x*' matches the 'x' at the
+ beginning of the trailing context. (Note that the POSIX
+ draft states that the text matched by such patterns is unde-
+ fined.)
+
+ For some trailing context rules, parts which are actually
+ fixed-length are not recognized as such, leading to the
+ abovementioned performance loss. In particular, parts using
+
+
+
+Version 2.5 Last change: April 1995 53
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ '|' or {n} (such as "foo{3}") are always considered
+ variable-length.
+
+ Combining trailing context with the special '|' action can
+ result in fixed trailing context being turned into the more
+ expensive variable trailing context. For example, in the
+ following:
+
+ %%
+ abc |
+ xyz/def
+
+
+ Use of unput() invalidates yytext and yyleng, unless the
+ %array directive or the -l option has been used.
+
+ Pattern-matching of NUL's is substantially slower than
+ matching other characters.
+
+ Dynamic resizing of the input buffer is slow, as it entails
+ rescanning all the text matched so far by the current (gen-
+ erally huge) token.
+
+ Due to both buffering of input and read-ahead, you cannot
+ intermix calls to <stdio.h> routines, such as, for example,
+ getchar(), with flex rules and expect it to work. Call
+ input() instead.
+
+ The total table entries listed by the -v flag excludes the
+ number of table entries needed to determine what rule has
+ been matched. The number of entries is equal to the number
+ of DFA states if the scanner does not use REJECT, and some-
+ what greater than the number of states if it does.
+
+ REJECT cannot be used with the -f or -F options.
+
+ The flex internal algorithms need documentation.
+
+SEE ALSO
+ lex(1), yacc(1), sed(1), awk(1).
+
+ John Levine, Tony Mason, and Doug Brown, Lex & Yacc,
+ O'Reilly and Associates. Be sure to get the 2nd edition.
+
+ M. E. Lesk and E. Schmidt, LEX - Lexical Analyzer Generator
+
+ Alfred Aho, Ravi Sethi and Jeffrey Ullman, Compilers: Prin-
+ ciples, Techniques and Tools, Addison-Wesley (1986).
+ Describes the pattern-matching techniques used by flex
+ (deterministic finite automata).
+
+
+
+
+
+Version 2.5 Last change: April 1995 54
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+AUTHOR
+ Vern Paxson, with the help of many ideas and much inspira-
+ tion from Van Jacobson. Original version by Jef Poskanzer.
+ The fast table representation is a partial implementation of
+ a design done by Van Jacobson. The implementation was done
+ by Kevin Gong and Vern Paxson.
+
+ Thanks to the many flex beta-testers, feedbackers, and con-
+ tributors, especially Francois Pinard, Casey Leedom, Robert
+ Abramovitz, Stan Adermann, Terry Allen, David Barker-
+ Plummer, John Basrai, Neal Becker, Nelson H.F. Beebe,
+ benson@odi.com, Karl Berry, Peter A. Bigot, Simon Blanchard,
+ Keith Bostic, Frederic Brehm, Ian Brockbank, Kin Cho, Nick
+ Christopher, Brian Clapper, J.T. Conklin, Jason Coughlin,
+ Bill Cox, Nick Cropper, Dave Curtis, Scott David Daniels,
+ Chris G. Demetriou, Theo Deraadt, Mike Donahue, Chuck
+ Doucette, Tom Epperly, Leo Eskin, Chris Faylor, Chris
+ Flatters, Jon Forrest, Jeffrey Friedl, Joe Gayda, Kaveh R.
+ Ghazi, Wolfgang Glunz, Eric Goldman, Christopher M. Gould,
+ Ulrich Grepel, Peer Griebel, Jan Hajic, Charles Hemphill,
+ NORO Hideo, Jarkko Hietaniemi, Scott Hofmann, Jeff Honig,
+ Dana Hudes, Eric Hughes, John Interrante, Ceriel Jacobs,
+ Michal Jaegermann, Sakari Jalovaara, Jeffrey R. Jones, Henry
+ Juengst, Klaus Kaempf, Jonathan I. Kamens, Terrence O Kane,
+ Amir Katz, ken@ken.hilco.com, Kevin B. Kenny, Steve Kirsch,
+ Winfried Koenig, Marq Kole, Ronald Lamprecht, Greg Lee,
+ Rohan Lenard, Craig Leres, John Levine, Steve Liddle, David
+ Loffredo, Mike Long, Mohamed el Lozy, Brian Madsen, Malte,
+ Joe Marshall, Bengt Martensson, Chris Metcalf, Luke Mewburn,
+ Jim Meyering, R. Alexander Milowski, Erik Naggum, G.T.
+ Nicol, Landon Noll, James Nordby, Marc Nozell, Richard
+ Ohnemus, Karsten Pahnke, Sven Panne, Roland Pesch, Walter
+ Pelissero, Gaumond Pierre, Esmond Pitt, Jef Poskanzer, Joe
+ Rahmeh, Jarmo Raiha, Frederic Raimbault, Pat Rankin, Rick
+ Richardson, Kevin Rodgers, Kai Uwe Rommel, Jim Roskind,
+ Alberto Santini, Andreas Scherer, Darrell Schiebel, Raf
+ Schietekat, Doug Schmidt, Philippe Schnoebelen, Andreas
+ Schwab, Larry Schwimmer, Alex Siegel, Eckehard Stolz, Jan-
+ Erik Strvmquist, Mike Stump, Paul Stuart, Dave Tallman, Ian
+ Lance Taylor, Chris Thewalt, Richard M. Timoney, Jodi Tsai,
+ Paul Tuinenga, Gary Weik, Frank Whaley, Gerhard Wilhelms,
+ Kent Williams, Ken Yap, Ron Zellar, Nathan Zelle, David
+ Zuhn, and those whose names have slipped my marginal mail-
+ archiving skills but whose contributions are appreciated all
+ the same.
+
+ Thanks to Keith Bostic, Jon Forrest, Noah Friedman, John
+ Gilmore, Craig Leres, John Levine, Bob Mulcahy, G.T. Nicol,
+ Francois Pinard, Rich Salz, and Richard Stallman for help
+ with various distribution headaches.
+
+
+
+
+
+Version 2.5 Last change: April 1995 55
+
+
+
+
+
+
+FLEX(1) USER COMMANDS FLEX(1)
+
+
+
+ Thanks to Esmond Pitt and Earle Horton for 8-bit character
+ support; to Benson Margulies and Fred Burke for C++ support;
+ to Kent Williams and Tom Epperly for C++ class support; to
+ Ove Ewerlid for support of NUL's; and to Eric Hughes for
+ support of multiple buffers.
+
+ This work was primarily done when I was with the Real Time
+ Systems Group at the Lawrence Berkeley Laboratory in Berke-
+ ley, CA. Many thanks to all there for the support I
+ received.
+
+ Send comments to vern@ee.lbl.gov.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Version 2.5 Last change: April 1995 56
+
+
+
diff --git a/Tools/android/flex-2.5.4a/MISC/parse.c b/Tools/android/flex-2.5.4a/MISC/parse.c
new file mode 100644
index 0000000..fea9b91
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/parse.c
@@ -0,0 +1,1452 @@
+#ifndef lint
+static char yysccsid[] = "@(#)yaccpar 1.9 (Berkeley) 02/21/93";
+#endif
+#define YYBYACC 1
+#define YYMAJOR 1
+#define YYMINOR 9
+#define yyclearin (yychar=(-1))
+#define yyerrok (yyerrflag=0)
+#define YYRECOVERING (yyerrflag!=0)
+#define YYPREFIX "yy"
+#line 10 "./parse.y"
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/parse.y,v 2.28 95/04/21 11:51:51 vern Exp $ */
+
+
+/* Some versions of bison are broken in that they use alloca() but don't
+ * declare it properly. The following is the patented (just kidding!)
+ * #ifdef chud to fix the problem, courtesy of Francois Pinard.
+ */
+#ifdef YYBISON
+/* AIX requires this to be the first thing in the file. What a piece. */
+# ifdef _AIX
+ #pragma alloca
+# endif
+#endif
+
+#include "flexdef.h"
+
+/* The remainder of the alloca() cruft has to come after including flexdef.h,
+ * so HAVE_ALLOCA_H is (possibly) defined.
+ */
+#ifdef YYBISON
+# ifdef __GNUC__
+# ifndef alloca
+# define alloca __builtin_alloca
+# endif
+# else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef __hpux
+void *alloca ();
+# else
+# ifdef __TURBOC__
+# include <malloc.h>
+# else
+char *alloca ();
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* Bletch, ^^^^ that was ugly! */
+
+
+int pat, scnum, eps, headcnt, trailcnt, anyccl, lastchar, i, rulelen;
+int trlcontxt, xcluflg, currccl, cclsorted, varlength, variable_trail_rule;
+
+int *scon_stk;
+int scon_stk_ptr;
+
+static int madeany = false; /* whether we've made the '.' character class */
+int previous_continued_action; /* whether the previous rule's action was '|' */
+
+/* Expand a POSIX character class expression. */
+#define CCL_EXPR(func) \
+ { \
+ int c; \
+ for ( c = 0; c < csize; ++c ) \
+ if ( isascii(c) && func(c) ) \
+ ccladd( currccl, c ); \
+ }
+
+/* While POSIX defines isblank(), it's not ANSI C. */
+#define IS_BLANK(c) ((c) == ' ' || (c) == '\t')
+
+/* On some over-ambitious machines, such as DEC Alpha's, the default
+ * token type is "long" instead of "int"; this leads to problems with
+ * declaring yylval in flexdef.h. But so far, all the yacc's I've seen
+ * wrap their definitions of YYSTYPE with "#ifndef YYSTYPE"'s, so the
+ * following should ensure that the default token type is "int".
+ */
+#define YYSTYPE int
+
+#line 112 "y.tab.c"
+#define CHAR 257
+#define NUMBER 258
+#define SECTEND 259
+#define SCDECL 260
+#define XSCDECL 261
+#define NAME 262
+#define PREVCCL 263
+#define EOF_OP 264
+#define OPTION_OP 265
+#define OPT_OUTFILE 266
+#define OPT_PREFIX 267
+#define OPT_YYCLASS 268
+#define CCE_ALNUM 269
+#define CCE_ALPHA 270
+#define CCE_BLANK 271
+#define CCE_CNTRL 272
+#define CCE_DIGIT 273
+#define CCE_GRAPH 274
+#define CCE_LOWER 275
+#define CCE_PRINT 276
+#define CCE_PUNCT 277
+#define CCE_SPACE 278
+#define CCE_UPPER 279
+#define CCE_XDIGIT 280
+#define YYERRCODE 256
+short yylhs[] = { -1,
+ 0, 1, 2, 2, 2, 2, 3, 6, 6, 7,
+ 7, 7, 8, 9, 9, 10, 10, 10, 4, 4,
+ 4, 5, 12, 12, 12, 12, 14, 11, 11, 11,
+ 15, 15, 15, 16, 13, 13, 13, 13, 18, 18,
+ 17, 19, 19, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 21, 21, 23, 23, 23,
+ 23, 24, 24, 24, 24, 24, 24, 24, 24, 24,
+ 24, 24, 24, 22, 22,
+};
+short yylen[] = { 2,
+ 5, 0, 3, 2, 0, 1, 1, 1, 1, 2,
+ 1, 1, 2, 2, 0, 3, 3, 3, 5, 5,
+ 0, 0, 2, 1, 1, 1, 0, 4, 3, 0,
+ 3, 1, 1, 1, 2, 3, 2, 1, 3, 1,
+ 2, 2, 1, 2, 2, 2, 6, 5, 4, 1,
+ 1, 1, 3, 3, 1, 3, 4, 4, 2, 2,
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 2, 0,
+};
+short yydefred[] = { 2,
+ 0, 0, 6, 0, 7, 8, 9, 15, 21, 0,
+ 4, 0, 0, 12, 11, 0, 0, 0, 0, 14,
+ 0, 1, 0, 10, 0, 0, 0, 0, 0, 21,
+ 0, 16, 17, 18, 29, 33, 34, 0, 32, 0,
+ 26, 55, 52, 25, 0, 50, 75, 0, 0, 0,
+ 24, 0, 0, 0, 0, 51, 28, 0, 20, 23,
+ 0, 0, 61, 0, 19, 0, 37, 0, 41, 0,
+ 0, 44, 45, 46, 31, 74, 53, 54, 0, 0,
+ 62, 63, 64, 65, 66, 67, 68, 69, 70, 71,
+ 72, 73, 56, 60, 36, 0, 0, 57, 0, 49,
+ 0, 58, 0, 48, 47,
+};
+short yydgoto[] = { 1,
+ 2, 4, 9, 13, 22, 10, 16, 11, 12, 20,
+ 23, 50, 51, 29, 38, 39, 52, 53, 54, 55,
+ 56, 61, 64, 94,
+};
+short yysindex[] = { 0,
+ 0, -235, 0, -191, 0, 0, 0, 0, 0, -207,
+ 0, -215, -18, 0, 0, -202, 4, 26, 32, 0,
+ 41, 0, -35, 0, -168, -166, -165, 38, -180, 0,
+ -30, 0, 0, 0, 0, 0, 0, -16, 0, -40,
+ 0, 0, 0, 0, -2, 0, 0, -2, 8, 93,
+ 0, -2, -25, -2, 15, 0, 0, -153, 0, 0,
+ -27, -26, 0, -88, 0, -23, 0, -2, 0, 15,
+ -150, 0, 0, 0, 0, 0, 0, 0, -3, 65,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, -2, -21, 0, -145, 0,
+ -116, 0, -12, 0, 0,
+};
+short yyrindex[] = { 0,
+ 0, -188, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, -154, 1, 0, 0, -140, 0, 0, 0, 0,
+ -176, 0, -28, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, -32,
+ 0, 0, 0, 0, 0, 0, 0, 0, 22, 0,
+ 0, 0, 106, 7, -10, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 108, 0, 0, 0, -7,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 46,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 9, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0,
+};
+short yygindex[] = { 0,
+ 0, 0, 0, 92, 100, 0, 0, 0, 0, 0,
+ 0, 0, 81, 0, 0, 69, 0, 27, 60, -29,
+ 0, 0, 66, 0,
+};
+#define YYTABLESIZE 326
+short yytable[] = { 43,
+ 22, 30, 42, 47, 93, 22, 77, 30, 104, 48,
+ 67, 22, 95, 30, 78, 46, 40, 22, 39, 21,
+ 3, 69, 101, 43, 70, 43, 42, 58, 42, 43,
+ 43, 47, 42, 42, 30, 43, 43, 48, 42, 42,
+ 30, 21, 40, 46, 39, 57, 30, 40, 14, 39,
+ 17, 18, 19, 40, 15, 39, 72, 73, 30, 24,
+ 49, 30, 22, 45, 25, 22, 70, 5, 6, 7,
+ 5, 5, 5, 8, 62, 36, 5, 74, 66, 27,
+ 43, 37, 28, 42, 59, 27, 26, 30, 49, 98,
+ 30, 30, 27, 32, 30, 33, 34, 68, 68, 35,
+ 68, 63, 65, 100, 13, 13, 13, 97, 37, 99,
+ 13, 102, 105, 43, 61, 38, 42, 35, 3, 3,
+ 3, 40, 31, 30, 3, 60, 75, 96, 79, 0,
+ 40, 0, 39, 0, 0, 0, 0, 71, 59, 0,
+ 0, 103, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 80, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 81, 82, 83, 84, 85, 86, 87, 88, 89, 90,
+ 91, 92, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 30, 30, 41, 42, 22, 22, 76,
+ 30, 30, 43, 44, 22, 22, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 43, 0, 0, 42,
+ 0, 0, 43, 80, 42, 42, 30, 30, 0, 0,
+ 43, 0, 0, 30, 30, 81, 82, 83, 84, 85,
+ 86, 87, 88, 89, 90, 91, 92, 0, 61, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
+ 61, 61, 59, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 59, 59, 59, 59, 59, 59,
+ 59, 59, 59, 59, 59, 59,
+};
+short yycheck[] = { 10,
+ 0, 34, 10, 34, 93, 34, 34, 40, 125, 40,
+ 36, 40, 36, 46, 41, 46, 10, 46, 10, 60,
+ 256, 47, 44, 34, 54, 36, 34, 44, 36, 40,
+ 41, 34, 40, 41, 34, 46, 47, 40, 46, 47,
+ 40, 60, 36, 46, 36, 62, 46, 41, 256, 41,
+ 266, 267, 268, 47, 262, 47, 42, 43, 91, 262,
+ 91, 94, 91, 94, 61, 94, 96, 259, 260, 261,
+ 259, 260, 261, 265, 48, 256, 265, 63, 52, 256,
+ 91, 262, 42, 91, 125, 262, 61, 123, 91, 93,
+ 123, 91, 61, 262, 94, 262, 262, 124, 124, 62,
+ 124, 94, 10, 125, 259, 260, 261, 258, 262, 45,
+ 265, 257, 125, 124, 93, 10, 124, 10, 259, 260,
+ 261, 30, 23, 123, 265, 45, 58, 68, 63, -1,
+ 124, -1, 124, -1, -1, -1, -1, 123, 93, -1,
+ -1, 258, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, 257, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 269, 270, 271, 272, 273, 274, 275, 276, 277, 278,
+ 279, 280, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, 256, 257, 256, 257, 256, 257, 257,
+ 263, 264, 263, 264, 263, 264, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, 257, -1, -1, 257,
+ -1, -1, 263, 257, 257, 263, 256, 257, -1, -1,
+ 263, -1, -1, 263, 264, 269, 270, 271, 272, 273,
+ 274, 275, 276, 277, 278, 279, 280, -1, 257, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 269, 270, 271, 272, 273, 274, 275, 276, 277, 278,
+ 279, 280, 257, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, 269, 270, 271, 272, 273, 274,
+ 275, 276, 277, 278, 279, 280,
+};
+#define YYFINAL 1
+#ifndef YYDEBUG
+#define YYDEBUG 0
+#endif
+#define YYMAXTOKEN 280
+#if YYDEBUG
+char *yyname[] = {
+"end-of-file",0,0,0,0,0,0,0,0,0,"'\\n'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,"'\"'",0,"'$'",0,0,0,"'('","')'","'*'","'+'","','","'-'","'.'","'/'",0,0,
+0,0,0,0,0,0,0,0,0,0,"'<'","'='","'>'","'?'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,"'['",0,"']'","'^'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,"'{'","'|'","'}'",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"CHAR","NUMBER","SECTEND",
+"SCDECL","XSCDECL","NAME","PREVCCL","EOF_OP","OPTION_OP","OPT_OUTFILE",
+"OPT_PREFIX","OPT_YYCLASS","CCE_ALNUM","CCE_ALPHA","CCE_BLANK","CCE_CNTRL",
+"CCE_DIGIT","CCE_GRAPH","CCE_LOWER","CCE_PRINT","CCE_PUNCT","CCE_SPACE",
+"CCE_UPPER","CCE_XDIGIT",
+};
+char *yyrule[] = {
+"$accept : goal",
+"goal : initlex sect1 sect1end sect2 initforrule",
+"initlex :",
+"sect1 : sect1 startconddecl namelist1",
+"sect1 : sect1 options",
+"sect1 :",
+"sect1 : error",
+"sect1end : SECTEND",
+"startconddecl : SCDECL",
+"startconddecl : XSCDECL",
+"namelist1 : namelist1 NAME",
+"namelist1 : NAME",
+"namelist1 : error",
+"options : OPTION_OP optionlist",
+"optionlist : optionlist option",
+"optionlist :",
+"option : OPT_OUTFILE '=' NAME",
+"option : OPT_PREFIX '=' NAME",
+"option : OPT_YYCLASS '=' NAME",
+"sect2 : sect2 scon initforrule flexrule '\\n'",
+"sect2 : sect2 scon '{' sect2 '}'",
+"sect2 :",
+"initforrule :",
+"flexrule : '^' rule",
+"flexrule : rule",
+"flexrule : EOF_OP",
+"flexrule : error",
+"scon_stk_ptr :",
+"scon : '<' scon_stk_ptr namelist2 '>'",
+"scon : '<' '*' '>'",
+"scon :",
+"namelist2 : namelist2 ',' sconname",
+"namelist2 : sconname",
+"namelist2 : error",
+"sconname : NAME",
+"rule : re2 re",
+"rule : re2 re '$'",
+"rule : re '$'",
+"rule : re",
+"re : re '|' series",
+"re : series",
+"re2 : re '/'",
+"series : series singleton",
+"series : singleton",
+"singleton : singleton '*'",
+"singleton : singleton '+'",
+"singleton : singleton '?'",
+"singleton : singleton '{' NUMBER ',' NUMBER '}'",
+"singleton : singleton '{' NUMBER ',' '}'",
+"singleton : singleton '{' NUMBER '}'",
+"singleton : '.'",
+"singleton : fullccl",
+"singleton : PREVCCL",
+"singleton : '\"' string '\"'",
+"singleton : '(' re ')'",
+"singleton : CHAR",
+"fullccl : '[' ccl ']'",
+"fullccl : '[' '^' ccl ']'",
+"ccl : ccl CHAR '-' CHAR",
+"ccl : ccl CHAR",
+"ccl : ccl ccl_expr",
+"ccl :",
+"ccl_expr : CCE_ALNUM",
+"ccl_expr : CCE_ALPHA",
+"ccl_expr : CCE_BLANK",
+"ccl_expr : CCE_CNTRL",
+"ccl_expr : CCE_DIGIT",
+"ccl_expr : CCE_GRAPH",
+"ccl_expr : CCE_LOWER",
+"ccl_expr : CCE_PRINT",
+"ccl_expr : CCE_PUNCT",
+"ccl_expr : CCE_SPACE",
+"ccl_expr : CCE_UPPER",
+"ccl_expr : CCE_XDIGIT",
+"string : string CHAR",
+"string :",
+};
+#endif
+#ifndef YYSTYPE
+typedef int YYSTYPE;
+#endif
+#ifdef YYSTACKSIZE
+#undef YYMAXDEPTH
+#define YYMAXDEPTH YYSTACKSIZE
+#else
+#ifdef YYMAXDEPTH
+#define YYSTACKSIZE YYMAXDEPTH
+#else
+#define YYSTACKSIZE 500
+#define YYMAXDEPTH 500
+#endif
+#endif
+int yydebug;
+int yynerrs;
+int yyerrflag;
+int yychar;
+short *yyssp;
+YYSTYPE *yyvsp;
+YYSTYPE yyval;
+YYSTYPE yylval;
+short yyss[YYSTACKSIZE];
+YYSTYPE yyvs[YYSTACKSIZE];
+#define yystacksize YYSTACKSIZE
+#line 776 "./parse.y"
+
+
+/* build_eof_action - build the "<<EOF>>" action for the active start
+ * conditions
+ */
+
+void build_eof_action()
+ {
+ register int i;
+ char action_text[MAXLINE];
+
+ for ( i = 1; i <= scon_stk_ptr; ++i )
+ {
+ if ( sceof[scon_stk[i]] )
+ format_pinpoint_message(
+ "multiple <<EOF>> rules for start condition %s",
+ scname[scon_stk[i]] );
+
+ else
+ {
+ sceof[scon_stk[i]] = true;
+ sprintf( action_text, "case YY_STATE_EOF(%s):\n",
+ scname[scon_stk[i]] );
+ add_action( action_text );
+ }
+ }
+
+ line_directive_out( (FILE *) 0, 1 );
+
+ /* This isn't a normal rule after all - don't count it as
+ * such, so we don't have any holes in the rule numbering
+ * (which make generating "rule can never match" warnings
+ * more difficult.
+ */
+ --num_rules;
+ ++num_eof_rules;
+ }
+
+
+/* format_synerr - write out formatted syntax error */
+
+void format_synerr( msg, arg )
+char msg[], arg[];
+ {
+ char errmsg[MAXLINE];
+
+ (void) sprintf( errmsg, msg, arg );
+ synerr( errmsg );
+ }
+
+
+/* synerr - report a syntax error */
+
+void synerr( str )
+char str[];
+ {
+ syntaxerror = true;
+ pinpoint_message( str );
+ }
+
+
+/* format_warn - write out formatted warning */
+
+void format_warn( msg, arg )
+char msg[], arg[];
+ {
+ char warn_msg[MAXLINE];
+
+ (void) sprintf( warn_msg, msg, arg );
+ warn( warn_msg );
+ }
+
+
+/* warn - report a warning, unless -w was given */
+
+void warn( str )
+char str[];
+ {
+ line_warning( str, linenum );
+ }
+
+/* format_pinpoint_message - write out a message formatted with one string,
+ * pinpointing its location
+ */
+
+void format_pinpoint_message( msg, arg )
+char msg[], arg[];
+ {
+ char errmsg[MAXLINE];
+
+ (void) sprintf( errmsg, msg, arg );
+ pinpoint_message( errmsg );
+ }
+
+
+/* pinpoint_message - write out a message, pinpointing its location */
+
+void pinpoint_message( str )
+char str[];
+ {
+ line_pinpoint( str, linenum );
+ }
+
+
+/* line_warning - report a warning at a given line, unless -w was given */
+
+void line_warning( str, line )
+char str[];
+int line;
+ {
+ char warning[MAXLINE];
+
+ if ( ! nowarn )
+ {
+ sprintf( warning, "warning, %s", str );
+ line_pinpoint( warning, line );
+ }
+ }
+
+
+/* line_pinpoint - write out a message, pinpointing it at the given line */
+
+void line_pinpoint( str, line )
+char str[];
+int line;
+ {
+ fprintf( stderr, "\"%s\", line %d: %s\n", infilename, line, str );
+ }
+
+
+/* yyerror - eat up an error message from the parser;
+ * currently, messages are ignore
+ */
+
+void yyerror( msg )
+char msg[];
+ {
+ }
+#line 541 "y.tab.c"
+#define YYABORT goto yyabort
+#define YYREJECT goto yyabort
+#define YYACCEPT goto yyaccept
+#define YYERROR goto yyerrlab
+int
+yyparse()
+{
+ register int yym, yyn, yystate;
+#if YYDEBUG
+ register char *yys;
+ extern char *getenv();
+
+ if (yys = getenv("YYDEBUG"))
+ {
+ yyn = *yys;
+ if (yyn >= '0' && yyn <= '9')
+ yydebug = yyn - '0';
+ }
+#endif
+
+ yynerrs = 0;
+ yyerrflag = 0;
+ yychar = (-1);
+
+ yyssp = yyss;
+ yyvsp = yyvs;
+ *yyssp = yystate = 0;
+
+yyloop:
+ if (yyn = yydefred[yystate]) goto yyreduce;
+ if (yychar < 0)
+ {
+ if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+ if (!yys) yys = "illegal-symbol";
+ printf("%sdebug: state %d, reading %d (%s)\n",
+ YYPREFIX, yystate, yychar, yys);
+ }
+#endif
+ }
+ if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, shifting to state %d\n",
+ YYPREFIX, yystate, yytable[yyn]);
+#endif
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ goto yyoverflow;
+ }
+ *++yyssp = yystate = yytable[yyn];
+ *++yyvsp = yylval;
+ yychar = (-1);
+ if (yyerrflag > 0) --yyerrflag;
+ goto yyloop;
+ }
+ if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yychar)
+ {
+ yyn = yytable[yyn];
+ goto yyreduce;
+ }
+ if (yyerrflag) goto yyinrecovery;
+#ifdef lint
+ goto yynewerror;
+#endif
+yynewerror:
+ yyerror("syntax error");
+#ifdef lint
+ goto yyerrlab;
+#endif
+yyerrlab:
+ ++yynerrs;
+yyinrecovery:
+ if (yyerrflag < 3)
+ {
+ yyerrflag = 3;
+ for (;;)
+ {
+ if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, error recovery shifting\
+ to state %d\n", YYPREFIX, *yyssp, yytable[yyn]);
+#endif
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ goto yyoverflow;
+ }
+ *++yyssp = yystate = yytable[yyn];
+ *++yyvsp = yylval;
+ goto yyloop;
+ }
+ else
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: error recovery discarding state %d\n",
+ YYPREFIX, *yyssp);
+#endif
+ if (yyssp <= yyss) goto yyabort;
+ --yyssp;
+ --yyvsp;
+ }
+ }
+ }
+ else
+ {
+ if (yychar == 0) goto yyabort;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+ if (!yys) yys = "illegal-symbol";
+ printf("%sdebug: state %d, error recovery discards token %d (%s)\n",
+ YYPREFIX, yystate, yychar, yys);
+ }
+#endif
+ yychar = (-1);
+ goto yyloop;
+ }
+yyreduce:
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: state %d, reducing by rule %d (%s)\n",
+ YYPREFIX, yystate, yyn, yyrule[yyn]);
+#endif
+ yym = yylen[yyn];
+ yyval = yyvsp[1-yym];
+ switch (yyn)
+ {
+case 1:
+#line 113 "./parse.y"
+{ /* add default rule */
+ int def_rule;
+
+ pat = cclinit();
+ cclnegate( pat );
+
+ def_rule = mkstate( -pat );
+
+ /* Remember the number of the default rule so we
+ * don't generate "can't match" warnings for it.
+ */
+ default_rule = num_rules;
+
+ finish_rule( def_rule, false, 0, 0 );
+
+ for ( i = 1; i <= lastsc; ++i )
+ scset[i] = mkbranch( scset[i], def_rule );
+
+ if ( spprdflt )
+ add_action(
+ "YY_FATAL_ERROR( \"flex scanner jammed\" )" );
+ else
+ add_action( "ECHO" );
+
+ add_action( ";\n\tYY_BREAK\n" );
+ }
+break;
+case 2:
+#line 142 "./parse.y"
+{ /* initialize for processing rules */
+
+ /* Create default DFA start condition. */
+ scinstal( "INITIAL", false );
+ }
+break;
+case 6:
+#line 153 "./parse.y"
+{ synerr( "unknown error processing section 1" ); }
+break;
+case 7:
+#line 157 "./parse.y"
+{
+ check_options();
+ scon_stk = allocate_integer_array( lastsc + 1 );
+ scon_stk_ptr = 0;
+ }
+break;
+case 8:
+#line 165 "./parse.y"
+{ xcluflg = false; }
+break;
+case 9:
+#line 168 "./parse.y"
+{ xcluflg = true; }
+break;
+case 10:
+#line 172 "./parse.y"
+{ scinstal( nmstr, xcluflg ); }
+break;
+case 11:
+#line 175 "./parse.y"
+{ scinstal( nmstr, xcluflg ); }
+break;
+case 12:
+#line 178 "./parse.y"
+{ synerr( "bad start condition list" ); }
+break;
+case 16:
+#line 189 "./parse.y"
+{
+ outfilename = copy_string( nmstr );
+ did_outfilename = 1;
+ }
+break;
+case 17:
+#line 194 "./parse.y"
+{ prefix = copy_string( nmstr ); }
+break;
+case 18:
+#line 196 "./parse.y"
+{ yyclass = copy_string( nmstr ); }
+break;
+case 19:
+#line 200 "./parse.y"
+{ scon_stk_ptr = yyvsp[-3]; }
+break;
+case 20:
+#line 202 "./parse.y"
+{ scon_stk_ptr = yyvsp[-3]; }
+break;
+case 22:
+#line 207 "./parse.y"
+{
+ /* Initialize for a parse of one rule. */
+ trlcontxt = variable_trail_rule = varlength = false;
+ trailcnt = headcnt = rulelen = 0;
+ current_state_type = STATE_NORMAL;
+ previous_continued_action = continued_action;
+ in_rule = true;
+
+ new_rule();
+ }
+break;
+case 23:
+#line 220 "./parse.y"
+{
+ pat = yyvsp[0];
+ finish_rule( pat, variable_trail_rule,
+ headcnt, trailcnt );
+
+ if ( scon_stk_ptr > 0 )
+ {
+ for ( i = 1; i <= scon_stk_ptr; ++i )
+ scbol[scon_stk[i]] =
+ mkbranch( scbol[scon_stk[i]],
+ pat );
+ }
+
+ else
+ {
+ /* Add to all non-exclusive start conditions,
+ * including the default (0) start condition.
+ */
+
+ for ( i = 1; i <= lastsc; ++i )
+ if ( ! scxclu[i] )
+ scbol[i] = mkbranch( scbol[i],
+ pat );
+ }
+
+ if ( ! bol_needed )
+ {
+ bol_needed = true;
+
+ if ( performance_report > 1 )
+ pinpoint_message(
+ "'^' operator results in sub-optimal performance" );
+ }
+ }
+break;
+case 24:
+#line 256 "./parse.y"
+{
+ pat = yyvsp[0];
+ finish_rule( pat, variable_trail_rule,
+ headcnt, trailcnt );
+
+ if ( scon_stk_ptr > 0 )
+ {
+ for ( i = 1; i <= scon_stk_ptr; ++i )
+ scset[scon_stk[i]] =
+ mkbranch( scset[scon_stk[i]],
+ pat );
+ }
+
+ else
+ {
+ for ( i = 1; i <= lastsc; ++i )
+ if ( ! scxclu[i] )
+ scset[i] =
+ mkbranch( scset[i],
+ pat );
+ }
+ }
+break;
+case 25:
+#line 280 "./parse.y"
+{
+ if ( scon_stk_ptr > 0 )
+ build_eof_action();
+
+ else
+ {
+ /* This EOF applies to all start conditions
+ * which don't already have EOF actions.
+ */
+ for ( i = 1; i <= lastsc; ++i )
+ if ( ! sceof[i] )
+ scon_stk[++scon_stk_ptr] = i;
+
+ if ( scon_stk_ptr == 0 )
+ warn(
+ "all start conditions already have <<EOF>> rules" );
+
+ else
+ build_eof_action();
+ }
+ }
+break;
+case 26:
+#line 303 "./parse.y"
+{ synerr( "unrecognized rule" ); }
+break;
+case 27:
+#line 307 "./parse.y"
+{ yyval = scon_stk_ptr; }
+break;
+case 28:
+#line 311 "./parse.y"
+{ yyval = yyvsp[-2]; }
+break;
+case 29:
+#line 314 "./parse.y"
+{
+ yyval = scon_stk_ptr;
+
+ for ( i = 1; i <= lastsc; ++i )
+ {
+ int j;
+
+ for ( j = 1; j <= scon_stk_ptr; ++j )
+ if ( scon_stk[j] == i )
+ break;
+
+ if ( j > scon_stk_ptr )
+ scon_stk[++scon_stk_ptr] = i;
+ }
+ }
+break;
+case 30:
+#line 331 "./parse.y"
+{ yyval = scon_stk_ptr; }
+break;
+case 33:
+#line 339 "./parse.y"
+{ synerr( "bad start condition list" ); }
+break;
+case 34:
+#line 343 "./parse.y"
+{
+ if ( (scnum = sclookup( nmstr )) == 0 )
+ format_pinpoint_message(
+ "undeclared start condition %s",
+ nmstr );
+ else
+ {
+ for ( i = 1; i <= scon_stk_ptr; ++i )
+ if ( scon_stk[i] == scnum )
+ {
+ format_warn(
+ "<%s> specified twice",
+ scname[scnum] );
+ break;
+ }
+
+ if ( i > scon_stk_ptr )
+ scon_stk[++scon_stk_ptr] = scnum;
+ }
+ }
+break;
+case 35:
+#line 366 "./parse.y"
+{
+ if ( transchar[lastst[yyvsp[0]]] != SYM_EPSILON )
+ /* Provide final transition \now/ so it
+ * will be marked as a trailing context
+ * state.
+ */
+ yyvsp[0] = link_machines( yyvsp[0],
+ mkstate( SYM_EPSILON ) );
+
+ mark_beginning_as_normal( yyvsp[0] );
+ current_state_type = STATE_NORMAL;
+
+ if ( previous_continued_action )
+ {
+ /* We need to treat this as variable trailing
+ * context so that the backup does not happen
+ * in the action but before the action switch
+ * statement. If the backup happens in the
+ * action, then the rules "falling into" this
+ * one's action will *also* do the backup,
+ * erroneously.
+ */
+ if ( ! varlength || headcnt != 0 )
+ warn(
+ "trailing context made variable due to preceding '|' action" );
+
+ /* Mark as variable. */
+ varlength = true;
+ headcnt = 0;
+ }
+
+ if ( lex_compat || (varlength && headcnt == 0) )
+ { /* variable trailing context rule */
+ /* Mark the first part of the rule as the
+ * accepting "head" part of a trailing
+ * context rule.
+ *
+ * By the way, we didn't do this at the
+ * beginning of this production because back
+ * then current_state_type was set up for a
+ * trail rule, and add_accept() can create
+ * a new state ...
+ */
+ add_accept( yyvsp[-1],
+ num_rules | YY_TRAILING_HEAD_MASK );
+ variable_trail_rule = true;
+ }
+
+ else
+ trailcnt = rulelen;
+
+ yyval = link_machines( yyvsp[-1], yyvsp[0] );
+ }
+break;
+case 36:
+#line 421 "./parse.y"
+{ synerr( "trailing context used twice" ); }
+break;
+case 37:
+#line 424 "./parse.y"
+{
+ headcnt = 0;
+ trailcnt = 1;
+ rulelen = 1;
+ varlength = false;
+
+ current_state_type = STATE_TRAILING_CONTEXT;
+
+ if ( trlcontxt )
+ {
+ synerr( "trailing context used twice" );
+ yyval = mkstate( SYM_EPSILON );
+ }
+
+ else if ( previous_continued_action )
+ {
+ /* See the comment in the rule for "re2 re"
+ * above.
+ */
+ warn(
+ "trailing context made variable due to preceding '|' action" );
+
+ varlength = true;
+ }
+
+ if ( lex_compat || varlength )
+ {
+ /* Again, see the comment in the rule for
+ * "re2 re" above.
+ */
+ add_accept( yyvsp[-1],
+ num_rules | YY_TRAILING_HEAD_MASK );
+ variable_trail_rule = true;
+ }
+
+ trlcontxt = true;
+
+ eps = mkstate( SYM_EPSILON );
+ yyval = link_machines( yyvsp[-1],
+ link_machines( eps, mkstate( '\n' ) ) );
+ }
+break;
+case 38:
+#line 467 "./parse.y"
+{
+ yyval = yyvsp[0];
+
+ if ( trlcontxt )
+ {
+ if ( lex_compat || (varlength && headcnt == 0) )
+ /* Both head and trail are
+ * variable-length.
+ */
+ variable_trail_rule = true;
+ else
+ trailcnt = rulelen;
+ }
+ }
+break;
+case 39:
+#line 485 "./parse.y"
+{
+ varlength = true;
+ yyval = mkor( yyvsp[-2], yyvsp[0] );
+ }
+break;
+case 40:
+#line 491 "./parse.y"
+{ yyval = yyvsp[0]; }
+break;
+case 41:
+#line 496 "./parse.y"
+{
+ /* This rule is written separately so the
+ * reduction will occur before the trailing
+ * series is parsed.
+ */
+
+ if ( trlcontxt )
+ synerr( "trailing context used twice" );
+ else
+ trlcontxt = true;
+
+ if ( varlength )
+ /* We hope the trailing context is
+ * fixed-length.
+ */
+ varlength = false;
+ else
+ headcnt = rulelen;
+
+ rulelen = 0;
+
+ current_state_type = STATE_TRAILING_CONTEXT;
+ yyval = yyvsp[-1];
+ }
+break;
+case 42:
+#line 523 "./parse.y"
+{
+ /* This is where concatenation of adjacent patterns
+ * gets done.
+ */
+ yyval = link_machines( yyvsp[-1], yyvsp[0] );
+ }
+break;
+case 43:
+#line 531 "./parse.y"
+{ yyval = yyvsp[0]; }
+break;
+case 44:
+#line 535 "./parse.y"
+{
+ varlength = true;
+
+ yyval = mkclos( yyvsp[-1] );
+ }
+break;
+case 45:
+#line 542 "./parse.y"
+{
+ varlength = true;
+ yyval = mkposcl( yyvsp[-1] );
+ }
+break;
+case 46:
+#line 548 "./parse.y"
+{
+ varlength = true;
+ yyval = mkopt( yyvsp[-1] );
+ }
+break;
+case 47:
+#line 554 "./parse.y"
+{
+ varlength = true;
+
+ if ( yyvsp[-3] > yyvsp[-1] || yyvsp[-3] < 0 )
+ {
+ synerr( "bad iteration values" );
+ yyval = yyvsp[-5];
+ }
+ else
+ {
+ if ( yyvsp[-3] == 0 )
+ {
+ if ( yyvsp[-1] <= 0 )
+ {
+ synerr(
+ "bad iteration values" );
+ yyval = yyvsp[-5];
+ }
+ else
+ yyval = mkopt(
+ mkrep( yyvsp[-5], 1, yyvsp[-1] ) );
+ }
+ else
+ yyval = mkrep( yyvsp[-5], yyvsp[-3], yyvsp[-1] );
+ }
+ }
+break;
+case 48:
+#line 582 "./parse.y"
+{
+ varlength = true;
+
+ if ( yyvsp[-2] <= 0 )
+ {
+ synerr( "iteration value must be positive" );
+ yyval = yyvsp[-4];
+ }
+
+ else
+ yyval = mkrep( yyvsp[-4], yyvsp[-2], INFINITY );
+ }
+break;
+case 49:
+#line 596 "./parse.y"
+{
+ /* The singleton could be something like "(foo)",
+ * in which case we have no idea what its length
+ * is, so we punt here.
+ */
+ varlength = true;
+
+ if ( yyvsp[-1] <= 0 )
+ {
+ synerr( "iteration value must be positive" );
+ yyval = yyvsp[-3];
+ }
+
+ else
+ yyval = link_machines( yyvsp[-3],
+ copysingl( yyvsp[-3], yyvsp[-1] - 1 ) );
+ }
+break;
+case 50:
+#line 615 "./parse.y"
+{
+ if ( ! madeany )
+ {
+ /* Create the '.' character class. */
+ anyccl = cclinit();
+ ccladd( anyccl, '\n' );
+ cclnegate( anyccl );
+
+ if ( useecs )
+ mkeccl( ccltbl + cclmap[anyccl],
+ ccllen[anyccl], nextecm,
+ ecgroup, csize, csize );
+
+ madeany = true;
+ }
+
+ ++rulelen;
+
+ yyval = mkstate( -anyccl );
+ }
+break;
+case 51:
+#line 637 "./parse.y"
+{
+ if ( ! cclsorted )
+ /* Sort characters for fast searching. We
+ * use a shell sort since this list could
+ * be large.
+ */
+ cshell( ccltbl + cclmap[yyvsp[0]], ccllen[yyvsp[0]], true );
+
+ if ( useecs )
+ mkeccl( ccltbl + cclmap[yyvsp[0]], ccllen[yyvsp[0]],
+ nextecm, ecgroup, csize, csize );
+
+ ++rulelen;
+
+ yyval = mkstate( -yyvsp[0] );
+ }
+break;
+case 52:
+#line 655 "./parse.y"
+{
+ ++rulelen;
+
+ yyval = mkstate( -yyvsp[0] );
+ }
+break;
+case 53:
+#line 662 "./parse.y"
+{ yyval = yyvsp[-1]; }
+break;
+case 54:
+#line 665 "./parse.y"
+{ yyval = yyvsp[-1]; }
+break;
+case 55:
+#line 668 "./parse.y"
+{
+ ++rulelen;
+
+ if ( caseins && yyvsp[0] >= 'A' && yyvsp[0] <= 'Z' )
+ yyvsp[0] = clower( yyvsp[0] );
+
+ yyval = mkstate( yyvsp[0] );
+ }
+break;
+case 56:
+#line 679 "./parse.y"
+{ yyval = yyvsp[-1]; }
+break;
+case 57:
+#line 682 "./parse.y"
+{
+ cclnegate( yyvsp[-1] );
+ yyval = yyvsp[-1];
+ }
+break;
+case 58:
+#line 689 "./parse.y"
+{
+ if ( caseins )
+ {
+ if ( yyvsp[-2] >= 'A' && yyvsp[-2] <= 'Z' )
+ yyvsp[-2] = clower( yyvsp[-2] );
+ if ( yyvsp[0] >= 'A' && yyvsp[0] <= 'Z' )
+ yyvsp[0] = clower( yyvsp[0] );
+ }
+
+ if ( yyvsp[-2] > yyvsp[0] )
+ synerr( "negative range in character class" );
+
+ else
+ {
+ for ( i = yyvsp[-2]; i <= yyvsp[0]; ++i )
+ ccladd( yyvsp[-3], i );
+
+ /* Keep track if this ccl is staying in
+ * alphabetical order.
+ */
+ cclsorted = cclsorted && (yyvsp[-2] > lastchar);
+ lastchar = yyvsp[0];
+ }
+
+ yyval = yyvsp[-3];
+ }
+break;
+case 59:
+#line 717 "./parse.y"
+{
+ if ( caseins && yyvsp[0] >= 'A' && yyvsp[0] <= 'Z' )
+ yyvsp[0] = clower( yyvsp[0] );
+
+ ccladd( yyvsp[-1], yyvsp[0] );
+ cclsorted = cclsorted && (yyvsp[0] > lastchar);
+ lastchar = yyvsp[0];
+ yyval = yyvsp[-1];
+ }
+break;
+case 60:
+#line 728 "./parse.y"
+{
+ /* Too hard to properly maintain cclsorted. */
+ cclsorted = false;
+ yyval = yyvsp[-1];
+ }
+break;
+case 61:
+#line 735 "./parse.y"
+{
+ cclsorted = true;
+ lastchar = 0;
+ currccl = yyval = cclinit();
+ }
+break;
+case 62:
+#line 742 "./parse.y"
+{ CCL_EXPR(isalnum) }
+break;
+case 63:
+#line 743 "./parse.y"
+{ CCL_EXPR(isalpha) }
+break;
+case 64:
+#line 744 "./parse.y"
+{ CCL_EXPR(IS_BLANK) }
+break;
+case 65:
+#line 745 "./parse.y"
+{ CCL_EXPR(iscntrl) }
+break;
+case 66:
+#line 746 "./parse.y"
+{ CCL_EXPR(isdigit) }
+break;
+case 67:
+#line 747 "./parse.y"
+{ CCL_EXPR(isgraph) }
+break;
+case 68:
+#line 748 "./parse.y"
+{ CCL_EXPR(islower) }
+break;
+case 69:
+#line 749 "./parse.y"
+{ CCL_EXPR(isprint) }
+break;
+case 70:
+#line 750 "./parse.y"
+{ CCL_EXPR(ispunct) }
+break;
+case 71:
+#line 751 "./parse.y"
+{ CCL_EXPR(isspace) }
+break;
+case 72:
+#line 752 "./parse.y"
+{
+ if ( caseins )
+ CCL_EXPR(islower)
+ else
+ CCL_EXPR(isupper)
+ }
+break;
+case 73:
+#line 758 "./parse.y"
+{ CCL_EXPR(isxdigit) }
+break;
+case 74:
+#line 762 "./parse.y"
+{
+ if ( caseins && yyvsp[0] >= 'A' && yyvsp[0] <= 'Z' )
+ yyvsp[0] = clower( yyvsp[0] );
+
+ ++rulelen;
+
+ yyval = link_machines( yyvsp[-1], mkstate( yyvsp[0] ) );
+ }
+break;
+case 75:
+#line 772 "./parse.y"
+{ yyval = mkstate( SYM_EPSILON ); }
+break;
+#line 1397 "y.tab.c"
+ }
+ yyssp -= yym;
+ yystate = *yyssp;
+ yyvsp -= yym;
+ yym = yylhs[yyn];
+ if (yystate == 0 && yym == 0)
+ {
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: after reduction, shifting from state 0 to\
+ state %d\n", YYPREFIX, YYFINAL);
+#endif
+ yystate = YYFINAL;
+ *++yyssp = YYFINAL;
+ *++yyvsp = yyval;
+ if (yychar < 0)
+ {
+ if ((yychar = yylex()) < 0) yychar = 0;
+#if YYDEBUG
+ if (yydebug)
+ {
+ yys = 0;
+ if (yychar <= YYMAXTOKEN) yys = yyname[yychar];
+ if (!yys) yys = "illegal-symbol";
+ printf("%sdebug: state %d, reading %d (%s)\n",
+ YYPREFIX, YYFINAL, yychar, yys);
+ }
+#endif
+ }
+ if (yychar == 0) goto yyaccept;
+ goto yyloop;
+ }
+ if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 &&
+ yyn <= YYTABLESIZE && yycheck[yyn] == yystate)
+ yystate = yytable[yyn];
+ else
+ yystate = yydgoto[yym];
+#if YYDEBUG
+ if (yydebug)
+ printf("%sdebug: after reduction, shifting from state %d \
+to state %d\n", YYPREFIX, *yyssp, yystate);
+#endif
+ if (yyssp >= yyss + yystacksize - 1)
+ {
+ goto yyoverflow;
+ }
+ *++yyssp = yystate;
+ *++yyvsp = yyval;
+ goto yyloop;
+yyoverflow:
+ yyerror("yacc stack overflow");
+yyabort:
+ return (1);
+yyaccept:
+ return (0);
+}
diff --git a/Tools/android/flex-2.5.4a/MISC/parse.h b/Tools/android/flex-2.5.4a/MISC/parse.h
new file mode 100644
index 0000000..10febed
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/parse.h
@@ -0,0 +1,24 @@
+#define CHAR 257
+#define NUMBER 258
+#define SECTEND 259
+#define SCDECL 260
+#define XSCDECL 261
+#define NAME 262
+#define PREVCCL 263
+#define EOF_OP 264
+#define OPTION_OP 265
+#define OPT_OUTFILE 266
+#define OPT_PREFIX 267
+#define OPT_YYCLASS 268
+#define CCE_ALNUM 269
+#define CCE_ALPHA 270
+#define CCE_BLANK 271
+#define CCE_CNTRL 272
+#define CCE_DIGIT 273
+#define CCE_GRAPH 274
+#define CCE_LOWER 275
+#define CCE_PRINT 276
+#define CCE_PUNCT 277
+#define CCE_SPACE 278
+#define CCE_UPPER 279
+#define CCE_XDIGIT 280
diff --git a/Tools/android/flex-2.5.4a/MISC/testxxLexer.l b/Tools/android/flex-2.5.4a/MISC/testxxLexer.l
new file mode 100644
index 0000000..9421541
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/testxxLexer.l
@@ -0,0 +1,58 @@
+ // An example of using the flex C++ scanner class.
+
+%option C++ noyywrap
+
+%{
+int mylineno = 0;
+%}
+
+string \"[^\n"]+\"
+
+ws [ \t]+
+
+alpha [A-Za-z]
+dig [0-9]
+name ({alpha}|{dig}|\$)({alpha}|{dig}|\_|\.|\-|\/|\$)*
+num1 [-+]?{dig}+\.?([eE][-+]?{dig}+)?
+num2 [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)?
+number {num1}|{num2}
+
+%%
+
+{ws} /* skip blanks and tabs */
+
+"/*" {
+ int c;
+
+ while((c = yyinput()) != 0)
+ {
+ if(c == '\n')
+ ++mylineno;
+
+ else if(c == '*')
+ {
+ if((c = yyinput()) == '/')
+ break;
+ else
+ unput(c);
+ }
+ }
+ }
+
+{number} cout << "number " << YYText() << '\n';
+
+\n mylineno++;
+
+{name} cout << "name " << YYText() << '\n';
+
+{string} cout << "string " << YYText() << '\n';
+
+%%
+
+int main( int /* argc */, char** /* argv */ )
+ {
+ FlexLexer* lexer = new yyFlexLexer;
+ while(lexer->yylex() != 0)
+ ;
+ return 0;
+ }
diff --git a/Tools/android/flex-2.5.4a/MISC/texinfo/flex.info b/Tools/android/flex-2.5.4a/MISC/texinfo/flex.info
new file mode 100644
index 0000000..9269418
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/texinfo/flex.info
@@ -0,0 +1,2951 @@
+This is Info file flex.info, produced by Makeinfo-1.55 from the input
+file flex.texi.
+
+START-INFO-DIR-ENTRY
+* Flex: (flex). A fast scanner generator.
+END-INFO-DIR-ENTRY
+
+ This file documents Flex.
+
+ Copyright (c) 1990 The Regents of the University of California. All
+rights reserved.
+
+ This code is derived from software contributed to Berkeley by Vern
+Paxson.
+
+ The United States Government has rights in this work pursuant to
+contract no. DE-AC03-76SF00098 between the United States Department of
+Energy and the University of California.
+
+ Redistribution and use in source and binary forms with or without
+modification are permitted provided that: (1) source distributions
+retain this entire copyright notice and comment, and (2) distributions
+including binaries display the following acknowledgement: "This
+product includes software developed by the University of California,
+Berkeley and its contributors" in the documentation or other materials
+provided with the distribution and in all advertising materials
+mentioning features or use of this software. Neither the name of the
+University 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 "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
+WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+
+
+File: flex.info, Node: Top, Next: Name, Prev: (dir), Up: (dir)
+
+flex
+****
+
+ This manual documents `flex'. It covers release 2.5.
+
+* Menu:
+
+* Name:: Name
+* Synopsis:: Synopsis
+* Overview:: Overview
+* Description:: Description
+* Examples:: Some simple examples
+* Format:: Format of the input file
+* Patterns:: Patterns
+* Matching:: How the input is matched
+* Actions:: Actions
+* Generated scanner:: The generated scanner
+* Start conditions:: Start conditions
+* Multiple buffers:: Multiple input buffers
+* End-of-file rules:: End-of-file rules
+* Miscellaneous:: Miscellaneous macros
+* User variables:: Values available to the user
+* YACC interface:: Interfacing with `yacc'
+* Options:: Options
+* Performance:: Performance considerations
+* C++:: Generating C++ scanners
+* Incompatibilities:: Incompatibilities with `lex' and POSIX
+* Diagnostics:: Diagnostics
+* Files:: Files
+* Deficiencies:: Deficiencies / Bugs
+* See also:: See also
+* Author:: Author
+
+
+File: flex.info, Node: Name, Next: Synopsis, Prev: Top, Up: Top
+
+Name
+====
+
+ flex - fast lexical analyzer generator
+
+
+File: flex.info, Node: Synopsis, Next: Overview, Prev: Name, Up: Top
+
+Synopsis
+========
+
+ flex [-bcdfhilnpstvwBFILTV78+? -C[aefFmr] -ooutput -Pprefix -Sskeleton]
+ [--help --version] [FILENAME ...]
+
+
+File: flex.info, Node: Overview, Next: Description, Prev: Synopsis, Up: Top
+
+Overview
+========
+
+ This manual describes `flex', a tool for generating programs that
+perform pattern-matching on text. The manual includes both tutorial
+and reference sections:
+
+Description
+ a brief overview of the tool
+
+Some Simple Examples
+Format Of The Input File
+Patterns
+ the extended regular expressions used by flex
+
+How The Input Is Matched
+ the rules for determining what has been matched
+
+Actions
+ how to specify what to do when a pattern is matched
+
+The Generated Scanner
+ details regarding the scanner that flex produces; how to control
+ the input source
+
+Start Conditions
+ introducing context into your scanners, and managing
+ "mini-scanners"
+
+Multiple Input Buffers
+ how to manipulate multiple input sources; how to scan from strings
+ instead of files
+
+End-of-file Rules
+ special rules for matching the end of the input
+
+Miscellaneous Macros
+ a summary of macros available to the actions
+
+Values Available To The User
+ a summary of values available to the actions
+
+Interfacing With Yacc
+ connecting flex scanners together with yacc parsers
+
+Options
+ flex command-line options, and the "%option" directive
+
+Performance Considerations
+ how to make your scanner go as fast as possible
+
+Generating C++ Scanners
+ the (experimental) facility for generating C++ scanner classes
+
+Incompatibilities With Lex And POSIX
+ how flex differs from AT&T lex and the POSIX lex standard
+
+Diagnostics
+ those error messages produced by flex (or scanners it generates)
+ whose meanings might not be apparent
+
+Files
+ files used by flex
+
+Deficiencies / Bugs
+ known problems with flex
+
+See Also
+ other documentation, related tools
+
+Author
+ includes contact information
+
+
+File: flex.info, Node: Description, Next: Examples, Prev: Overview, Up: Top
+
+Description
+===========
+
+ `flex' is a tool for generating "scanners": programs which
+recognized lexical patterns in text. `flex' reads the given input
+files, or its standard input if no file names are given, for a
+description of a scanner to generate. The description is in the form
+of pairs of regular expressions and C code, called "rules". `flex'
+generates as output a C source file, `lex.yy.c', which defines a
+routine `yylex()'. This file is compiled and linked with the `-lfl'
+library to produce an executable. When the executable is run, it
+analyzes its input for occurrences of the regular expressions.
+Whenever it finds one, it executes the corresponding C code.
+
+
+File: flex.info, Node: Examples, Next: Format, Prev: Description, Up: Top
+
+Some simple examples
+====================
+
+ First some simple examples to get the flavor of how one uses `flex'.
+The following `flex' input specifies a scanner which whenever it
+encounters the string "username" will replace it with the user's login
+name:
+
+ %%
+ username printf( "%s", getlogin() );
+
+ By default, any text not matched by a `flex' scanner is copied to
+the output, so the net effect of this scanner is to copy its input file
+to its output with each occurrence of "username" expanded. In this
+input, there is just one rule. "username" is the PATTERN and the
+"printf" is the ACTION. The "%%" marks the beginning of the rules.
+
+ Here's another simple example:
+
+ int num_lines = 0, num_chars = 0;
+
+ %%
+ \n ++num_lines; ++num_chars;
+ . ++num_chars;
+
+ %%
+ main()
+ {
+ yylex();
+ printf( "# of lines = %d, # of chars = %d\n",
+ num_lines, num_chars );
+ }
+
+ This scanner counts the number of characters and the number of lines
+in its input (it produces no output other than the final report on the
+counts). The first line declares two globals, "num_lines" and
+"num_chars", which are accessible both inside `yylex()' and in the
+`main()' routine declared after the second "%%". There are two rules,
+one which matches a newline ("\n") and increments both the line count
+and the character count, and one which matches any character other than
+a newline (indicated by the "." regular expression).
+
+ A somewhat more complicated example:
+
+ /* scanner for a toy Pascal-like language */
+
+ %{
+ /* need this for the call to atof() below */
+ #include <math.h>
+ %}
+
+ DIGIT [0-9]
+ ID [a-z][a-z0-9]*
+
+ %%
+
+ {DIGIT}+ {
+ printf( "An integer: %s (%d)\n", yytext,
+ atoi( yytext ) );
+ }
+
+ {DIGIT}+"."{DIGIT}* {
+ printf( "A float: %s (%g)\n", yytext,
+ atof( yytext ) );
+ }
+
+ if|then|begin|end|procedure|function {
+ printf( "A keyword: %s\n", yytext );
+ }
+
+ {ID} printf( "An identifier: %s\n", yytext );
+
+ "+"|"-"|"*"|"/" printf( "An operator: %s\n", yytext );
+
+ "{"[^}\n]*"}" /* eat up one-line comments */
+
+ [ \t\n]+ /* eat up whitespace */
+
+ . printf( "Unrecognized character: %s\n", yytext );
+
+ %%
+
+ main( argc, argv )
+ int argc;
+ char **argv;
+ {
+ ++argv, --argc; /* skip over program name */
+ if ( argc > 0 )
+ yyin = fopen( argv[0], "r" );
+ else
+ yyin = stdin;
+
+ yylex();
+ }
+
+ This is the beginnings of a simple scanner for a language like
+Pascal. It identifies different types of TOKENS and reports on what it
+has seen.
+
+ The details of this example will be explained in the following
+sections.
+
+
+File: flex.info, Node: Format, Next: Patterns, Prev: Examples, Up: Top
+
+Format of the input file
+========================
+
+ The `flex' input file consists of three sections, separated by a
+line with just `%%' in it:
+
+ definitions
+ %%
+ rules
+ %%
+ user code
+
+ The "definitions" section contains declarations of simple "name"
+definitions to simplify the scanner specification, and declarations of
+"start conditions", which are explained in a later section. Name
+definitions have the form:
+
+ name definition
+
+ The "name" is a word beginning with a letter or an underscore ('_')
+followed by zero or more letters, digits, '_', or '-' (dash). The
+definition is taken to begin at the first non-white-space character
+following the name and continuing to the end of the line. The
+definition can subsequently be referred to using "{name}", which will
+expand to "(definition)". For example,
+
+ DIGIT [0-9]
+ ID [a-z][a-z0-9]*
+
+defines "DIGIT" to be a regular expression which matches a single
+digit, and "ID" to be a regular expression which matches a letter
+followed by zero-or-more letters-or-digits. A subsequent reference to
+
+ {DIGIT}+"."{DIGIT}*
+
+is identical to
+
+ ([0-9])+"."([0-9])*
+
+and matches one-or-more digits followed by a '.' followed by
+zero-or-more digits.
+
+ The RULES section of the `flex' input contains a series of rules of
+the form:
+
+ pattern action
+
+where the pattern must be unindented and the action must begin on the
+same line.
+
+ See below for a further description of patterns and actions.
+
+ Finally, the user code section is simply copied to `lex.yy.c'
+verbatim. It is used for companion routines which call or are called
+by the scanner. The presence of this section is optional; if it is
+missing, the second `%%' in the input file may be skipped, too.
+
+ In the definitions and rules sections, any *indented* text or text
+enclosed in `%{' and `%}' is copied verbatim to the output (with the
+`%{}''s removed). The `%{}''s must appear unindented on lines by
+themselves.
+
+ In the rules section, any indented or %{} text appearing before the
+first rule may be used to declare variables which are local to the
+scanning routine and (after the declarations) code which is to be
+executed whenever the scanning routine is entered. Other indented or
+%{} text in the rule section is still copied to the output, but its
+meaning is not well-defined and it may well cause compile-time errors
+(this feature is present for `POSIX' compliance; see below for other
+such features).
+
+ In the definitions section (but not in the rules section), an
+unindented comment (i.e., a line beginning with "/*") is also copied
+verbatim to the output up to the next "*/".
+
+
+File: flex.info, Node: Patterns, Next: Matching, Prev: Format, Up: Top
+
+Patterns
+========
+
+ The patterns in the input are written using an extended set of
+regular expressions. These are:
+
+`x'
+ match the character `x'
+
+`.'
+ any character (byte) except newline
+
+`[xyz]'
+ a "character class"; in this case, the pattern matches either an
+ `x', a `y', or a `z'
+
+`[abj-oZ]'
+ a "character class" with a range in it; matches an `a', a `b', any
+ letter from `j' through `o', or a `Z'
+
+`[^A-Z]'
+ a "negated character class", i.e., any character but those in the
+ class. In this case, any character EXCEPT an uppercase letter.
+
+`[^A-Z\n]'
+ any character EXCEPT an uppercase letter or a newline
+
+`R*'
+ zero or more R's, where R is any regular expression
+
+`R+'
+ one or more R's
+
+`R?'
+ zero or one R's (that is, "an optional R")
+
+`R{2,5}'
+ anywhere from two to five R's
+
+`R{2,}'
+ two or more R's
+
+`R{4}'
+ exactly 4 R's
+
+`{NAME}'
+ the expansion of the "NAME" definition (see above)
+
+`"[xyz]\"foo"'
+ the literal string: `[xyz]"foo'
+
+`\X'
+ if X is an `a', `b', `f', `n', `r', `t', or `v', then the ANSI-C
+ interpretation of \X. Otherwise, a literal `X' (used to escape
+ operators such as `*')
+
+`\0'
+ a NUL character (ASCII code 0)
+
+`\123'
+ the character with octal value 123
+
+`\x2a'
+ the character with hexadecimal value `2a'
+
+`(R)'
+ match an R; parentheses are used to override precedence (see below)
+
+`RS'
+ the regular expression R followed by the regular expression S;
+ called "concatenation"
+
+`R|S'
+ either an R or an S
+
+`R/S'
+ an R but only if it is followed by an S. The text matched by S is
+ included when determining whether this rule is the "longest
+ match", but is then returned to the input before the action is
+ executed. So the action only sees the text matched by R. This
+ type of pattern is called "trailing context". (There are some
+ combinations of `R/S' that `flex' cannot match correctly; see
+ notes in the Deficiencies / Bugs section below regarding
+ "dangerous trailing context".)
+
+`^R'
+ an R, but only at the beginning of a line (i.e., which just
+ starting to scan, or right after a newline has been scanned).
+
+`R$'
+ an R, but only at the end of a line (i.e., just before a newline).
+ Equivalent to "R/\n".
+
+ Note that flex's notion of "newline" is exactly whatever the C
+ compiler used to compile flex interprets '\n' as; in particular,
+ on some DOS systems you must either filter out \r's in the input
+ yourself, or explicitly use R/\r\n for "r$".
+
+`<S>R'
+ an R, but only in start condition S (see below for discussion of
+ start conditions) <S1,S2,S3>R same, but in any of start conditions
+ S1, S2, or S3
+
+`<*>R'
+ an R in any start condition, even an exclusive one.
+
+`<<EOF>>'
+ an end-of-file <S1,S2><<EOF>> an end-of-file when in start
+ condition S1 or S2
+
+ Note that inside of a character class, all regular expression
+operators lose their special meaning except escape ('\') and the
+character class operators, '-', ']', and, at the beginning of the
+class, '^'.
+
+ The regular expressions listed above are grouped according to
+precedence, from highest precedence at the top to lowest at the bottom.
+Those grouped together have equal precedence. For example,
+
+ foo|bar*
+
+is the same as
+
+ (foo)|(ba(r*))
+
+since the '*' operator has higher precedence than concatenation, and
+concatenation higher than alternation ('|'). This pattern therefore
+matches *either* the string "foo" *or* the string "ba" followed by
+zero-or-more r's. To match "foo" or zero-or-more "bar"'s, use:
+
+ foo|(bar)*
+
+and to match zero-or-more "foo"'s-or-"bar"'s:
+
+ (foo|bar)*
+
+ In addition to characters and ranges of characters, character
+classes can also contain character class "expressions". These are
+expressions enclosed inside `[': and `:'] delimiters (which themselves
+must appear between the '[' and ']' of the character class; other
+elements may occur inside the character class, too). The valid
+expressions are:
+
+ [:alnum:] [:alpha:] [:blank:]
+ [:cntrl:] [:digit:] [:graph:]
+ [:lower:] [:print:] [:punct:]
+ [:space:] [:upper:] [:xdigit:]
+
+ These expressions all designate a set of characters equivalent to
+the corresponding standard C `isXXX' function. For example,
+`[:alnum:]' designates those characters for which `isalnum()' returns
+true - i.e., any alphabetic or numeric. Some systems don't provide
+`isblank()', so flex defines `[:blank:]' as a blank or a tab.
+
+ For example, the following character classes are all equivalent:
+
+ [[:alnum:]]
+ [[:alpha:][:digit:]
+ [[:alpha:]0-9]
+ [a-zA-Z0-9]
+
+ If your scanner is case-insensitive (the `-i' flag), then
+`[:upper:]' and `[:lower:]' are equivalent to `[:alpha:]'.
+
+ Some notes on patterns:
+
+ - A negated character class such as the example "[^A-Z]" above *will
+ match a newline* unless "\n" (or an equivalent escape sequence) is
+ one of the characters explicitly present in the negated character
+ class (e.g., "[^A-Z\n]"). This is unlike how many other regular
+ expression tools treat negated character classes, but
+ unfortunately the inconsistency is historically entrenched.
+ Matching newlines means that a pattern like [^"]* can match the
+ entire input unless there's another quote in the input.
+
+ - A rule can have at most one instance of trailing context (the '/'
+ operator or the '$' operator). The start condition, '^', and
+ "<<EOF>>" patterns can only occur at the beginning of a pattern,
+ and, as well as with '/' and '$', cannot be grouped inside
+ parentheses. A '^' which does not occur at the beginning of a
+ rule or a '$' which does not occur at the end of a rule loses its
+ special properties and is treated as a normal character.
+
+ The following are illegal:
+
+ foo/bar$
+ <sc1>foo<sc2>bar
+
+ Note that the first of these, can be written "foo/bar\n".
+
+ The following will result in '$' or '^' being treated as a normal
+ character:
+
+ foo|(bar$)
+ foo|^bar
+
+ If what's wanted is a "foo" or a bar-followed-by-a-newline, the
+ following could be used (the special '|' action is explained
+ below):
+
+ foo |
+ bar$ /* action goes here */
+
+ A similar trick will work for matching a foo or a
+ bar-at-the-beginning-of-a-line.
+
+
+File: flex.info, Node: Matching, Next: Actions, Prev: Patterns, Up: Top
+
+How the input is matched
+========================
+
+ When the generated scanner is run, it analyzes its input looking for
+strings which match any of its patterns. If it finds more than one
+match, it takes the one matching the most text (for trailing context
+rules, this includes the length of the trailing part, even though it
+will then be returned to the input). If it finds two or more matches
+of the same length, the rule listed first in the `flex' input file is
+chosen.
+
+ Once the match is determined, the text corresponding to the match
+(called the TOKEN) is made available in the global character pointer
+`yytext', and its length in the global integer `yyleng'. The ACTION
+corresponding to the matched pattern is then executed (a more detailed
+description of actions follows), and then the remaining input is
+scanned for another match.
+
+ If no match is found, then the "default rule" is executed: the next
+character in the input is considered matched and copied to the standard
+output. Thus, the simplest legal `flex' input is:
+
+ %%
+
+ which generates a scanner that simply copies its input (one
+character at a time) to its output.
+
+ Note that `yytext' can be defined in two different ways: either as a
+character *pointer* or as a character *array*. You can control which
+definition `flex' uses by including one of the special directives
+`%pointer' or `%array' in the first (definitions) section of your flex
+input. The default is `%pointer', unless you use the `-l' lex
+compatibility option, in which case `yytext' will be an array. The
+advantage of using `%pointer' is substantially faster scanning and no
+buffer overflow when matching very large tokens (unless you run out of
+dynamic memory). The disadvantage is that you are restricted in how
+your actions can modify `yytext' (see the next section), and calls to
+the `unput()' function destroys the present contents of `yytext', which
+can be a considerable porting headache when moving between different
+`lex' versions.
+
+ The advantage of `%array' is that you can then modify `yytext' to
+your heart's content, and calls to `unput()' do not destroy `yytext'
+(see below). Furthermore, existing `lex' programs sometimes access
+`yytext' externally using declarations of the form:
+ extern char yytext[];
+ This definition is erroneous when used with `%pointer', but correct
+for `%array'.
+
+ `%array' defines `yytext' to be an array of `YYLMAX' characters,
+which defaults to a fairly large value. You can change the size by
+simply #define'ing `YYLMAX' to a different value in the first section
+of your `flex' input. As mentioned above, with `%pointer' yytext grows
+dynamically to accommodate large tokens. While this means your
+`%pointer' scanner can accommodate very large tokens (such as matching
+entire blocks of comments), bear in mind that each time the scanner
+must resize `yytext' it also must rescan the entire token from the
+beginning, so matching such tokens can prove slow. `yytext' presently
+does *not* dynamically grow if a call to `unput()' results in too much
+text being pushed back; instead, a run-time error results.
+
+ Also note that you cannot use `%array' with C++ scanner classes (the
+`c++' option; see below).
+
+
+File: flex.info, Node: Actions, Next: Generated scanner, Prev: Matching, Up: Top
+
+Actions
+=======
+
+ Each pattern in a rule has a corresponding action, which can be any
+arbitrary C statement. The pattern ends at the first non-escaped
+whitespace character; the remainder of the line is its action. If the
+action is empty, then when the pattern is matched the input token is
+simply discarded. For example, here is the specification for a program
+which deletes all occurrences of "zap me" from its input:
+
+ %%
+ "zap me"
+
+ (It will copy all other characters in the input to the output since
+they will be matched by the default rule.)
+
+ Here is a program which compresses multiple blanks and tabs down to
+a single blank, and throws away whitespace found at the end of a line:
+
+ %%
+ [ \t]+ putchar( ' ' );
+ [ \t]+$ /* ignore this token */
+
+ If the action contains a '{', then the action spans till the
+balancing '}' is found, and the action may cross multiple lines.
+`flex' knows about C strings and comments and won't be fooled by braces
+found within them, but also allows actions to begin with `%{' and will
+consider the action to be all the text up to the next `%}' (regardless
+of ordinary braces inside the action).
+
+ An action consisting solely of a vertical bar ('|') means "same as
+the action for the next rule." See below for an illustration.
+
+ Actions can include arbitrary C code, including `return' statements
+to return a value to whatever routine called `yylex()'. Each time
+`yylex()' is called it continues processing tokens from where it last
+left off until it either reaches the end of the file or executes a
+return.
+
+ Actions are free to modify `yytext' except for lengthening it
+(adding characters to its end-these will overwrite later characters in
+the input stream). This however does not apply when using `%array'
+(see above); in that case, `yytext' may be freely modified in any way.
+
+ Actions are free to modify `yyleng' except they should not do so if
+the action also includes use of `yymore()' (see below).
+
+ There are a number of special directives which can be included
+within an action:
+
+ - `ECHO' copies yytext to the scanner's output.
+
+ - `BEGIN' followed by the name of a start condition places the
+ scanner in the corresponding start condition (see below).
+
+ - `REJECT' directs the scanner to proceed on to the "second best"
+ rule which matched the input (or a prefix of the input). The rule
+ is chosen as described above in "How the Input is Matched", and
+ `yytext' and `yyleng' set up appropriately. It may either be one
+ which matched as much text as the originally chosen rule but came
+ later in the `flex' input file, or one which matched less text.
+ For example, the following will both count the words in the input
+ and call the routine special() whenever "frob" is seen:
+
+ int word_count = 0;
+ %%
+
+ frob special(); REJECT;
+ [^ \t\n]+ ++word_count;
+
+ Without the `REJECT', any "frob"'s in the input would not be
+ counted as words, since the scanner normally executes only one
+ action per token. Multiple `REJECT's' are allowed, each one
+ finding the next best choice to the currently active rule. For
+ example, when the following scanner scans the token "abcd", it
+ will write "abcdabcaba" to the output:
+
+ %%
+ a |
+ ab |
+ abc |
+ abcd ECHO; REJECT;
+ .|\n /* eat up any unmatched character */
+
+ (The first three rules share the fourth's action since they use
+ the special '|' action.) `REJECT' is a particularly expensive
+ feature in terms of scanner performance; if it is used in *any* of
+ the scanner's actions it will slow down *all* of the scanner's
+ matching. Furthermore, `REJECT' cannot be used with the `-Cf' or
+ `-CF' options (see below).
+
+ Note also that unlike the other special actions, `REJECT' is a
+ *branch*; code immediately following it in the action will *not*
+ be executed.
+
+ - `yymore()' tells the scanner that the next time it matches a rule,
+ the corresponding token should be *appended* onto the current
+ value of `yytext' rather than replacing it. For example, given
+ the input "mega-kludge" the following will write
+ "mega-mega-kludge" to the output:
+
+ %%
+ mega- ECHO; yymore();
+ kludge ECHO;
+
+ First "mega-" is matched and echoed to the output. Then "kludge"
+ is matched, but the previous "mega-" is still hanging around at
+ the beginning of `yytext' so the `ECHO' for the "kludge" rule will
+ actually write "mega-kludge".
+
+ Two notes regarding use of `yymore()'. First, `yymore()' depends on
+the value of `yyleng' correctly reflecting the size of the current
+token, so you must not modify `yyleng' if you are using `yymore()'.
+Second, the presence of `yymore()' in the scanner's action entails a
+minor performance penalty in the scanner's matching speed.
+
+ - `yyless(n)' returns all but the first N characters of the current
+ token back to the input stream, where they will be rescanned when
+ the scanner looks for the next match. `yytext' and `yyleng' are
+ adjusted appropriately (e.g., `yyleng' will now be equal to N ).
+ For example, on the input "foobar" the following will write out
+ "foobarbar":
+
+ %%
+ foobar ECHO; yyless(3);
+ [a-z]+ ECHO;
+
+ An argument of 0 to `yyless' will cause the entire current input
+ string to be scanned again. Unless you've changed how the scanner
+ will subsequently process its input (using `BEGIN', for example),
+ this will result in an endless loop.
+
+ Note that `yyless' is a macro and can only be used in the flex
+ input file, not from other source files.
+
+ - `unput(c)' puts the character `c' back onto the input stream. It
+ will be the next character scanned. The following action will
+ take the current token and cause it to be rescanned enclosed in
+ parentheses.
+
+ {
+ int i;
+ /* Copy yytext because unput() trashes yytext */
+ char *yycopy = strdup( yytext );
+ unput( ')' );
+ for ( i = yyleng - 1; i >= 0; --i )
+ unput( yycopy[i] );
+ unput( '(' );
+ free( yycopy );
+ }
+
+ Note that since each `unput()' puts the given character back at
+ the *beginning* of the input stream, pushing back strings must be
+ done back-to-front. An important potential problem when using
+ `unput()' is that if you are using `%pointer' (the default), a
+ call to `unput()' *destroys* the contents of `yytext', starting
+ with its rightmost character and devouring one character to the
+ left with each call. If you need the value of yytext preserved
+ after a call to `unput()' (as in the above example), you must
+ either first copy it elsewhere, or build your scanner using
+ `%array' instead (see How The Input Is Matched).
+
+ Finally, note that you cannot put back `EOF' to attempt to mark
+ the input stream with an end-of-file.
+
+ - `input()' reads the next character from the input stream. For
+ example, the following is one way to eat up C comments:
+
+ %%
+ "/*" {
+ register int c;
+
+ for ( ; ; )
+ {
+ while ( (c = input()) != '*' &&
+ c != EOF )
+ ; /* eat up text of comment */
+
+ if ( c == '*' )
+ {
+ while ( (c = input()) == '*' )
+ ;
+ if ( c == '/' )
+ break; /* found the end */
+ }
+
+ if ( c == EOF )
+ {
+ error( "EOF in comment" );
+ break;
+ }
+ }
+ }
+
+ (Note that if the scanner is compiled using `C++', then `input()'
+ is instead referred to as `yyinput()', in order to avoid a name
+ clash with the `C++' stream by the name of `input'.)
+
+ - YY_FLUSH_BUFFER flushes the scanner's internal buffer so that the
+ next time the scanner attempts to match a token, it will first
+ refill the buffer using `YY_INPUT' (see The Generated Scanner,
+ below). This action is a special case of the more general
+ `yy_flush_buffer()' function, described below in the section
+ Multiple Input Buffers.
+
+ - `yyterminate()' can be used in lieu of a return statement in an
+ action. It terminates the scanner and returns a 0 to the
+ scanner's caller, indicating "all done". By default,
+ `yyterminate()' is also called when an end-of-file is encountered.
+ It is a macro and may be redefined.
+
+
+File: flex.info, Node: Generated scanner, Next: Start conditions, Prev: Actions, Up: Top
+
+The generated scanner
+=====================
+
+ The output of `flex' is the file `lex.yy.c', which contains the
+scanning routine `yylex()', a number of tables used by it for matching
+tokens, and a number of auxiliary routines and macros. By default,
+`yylex()' is declared as follows:
+
+ int yylex()
+ {
+ ... various definitions and the actions in here ...
+ }
+
+ (If your environment supports function prototypes, then it will be
+"int yylex( void )".) This definition may be changed by defining
+the "YY_DECL" macro. For example, you could use:
+
+ #define YY_DECL float lexscan( a, b ) float a, b;
+
+ to give the scanning routine the name `lexscan', returning a float,
+and taking two floats as arguments. Note that if you give arguments to
+the scanning routine using a K&R-style/non-prototyped function
+declaration, you must terminate the definition with a semi-colon (`;').
+
+ Whenever `yylex()' is called, it scans tokens from the global input
+file `yyin' (which defaults to stdin). It continues until it either
+reaches an end-of-file (at which point it returns the value 0) or one
+of its actions executes a `return' statement.
+
+ If the scanner reaches an end-of-file, subsequent calls are undefined
+unless either `yyin' is pointed at a new input file (in which case
+scanning continues from that file), or `yyrestart()' is called.
+`yyrestart()' takes one argument, a `FILE *' pointer (which can be nil,
+if you've set up `YY_INPUT' to scan from a source other than `yyin'),
+and initializes `yyin' for scanning from that file. Essentially there
+is no difference between just assigning `yyin' to a new input file or
+using `yyrestart()' to do so; the latter is available for compatibility
+with previous versions of `flex', and because it can be used to switch
+input files in the middle of scanning. It can also be used to throw
+away the current input buffer, by calling it with an argument of
+`yyin'; but better is to use `YY_FLUSH_BUFFER' (see above). Note that
+`yyrestart()' does *not* reset the start condition to `INITIAL' (see
+Start Conditions, below).
+
+ If `yylex()' stops scanning due to executing a `return' statement in
+one of the actions, the scanner may then be called again and it will
+resume scanning where it left off.
+
+ By default (and for purposes of efficiency), the scanner uses
+block-reads rather than simple `getc()' calls to read characters from
+`yyin'. The nature of how it gets its input can be controlled by
+defining the `YY_INPUT' macro. YY_INPUT's calling sequence is
+"YY_INPUT(buf,result,max_size)". Its action is to place up to MAX_SIZE
+characters in the character array BUF and return in the integer
+variable RESULT either the number of characters read or the constant
+YY_NULL (0 on Unix systems) to indicate EOF. The default YY_INPUT
+reads from the global file-pointer "yyin".
+
+ A sample definition of YY_INPUT (in the definitions section of the
+input file):
+
+ %{
+ #define YY_INPUT(buf,result,max_size) \
+ { \
+ int c = getchar(); \
+ result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
+ }
+ %}
+
+ This definition will change the input processing to occur one
+character at a time.
+
+ When the scanner receives an end-of-file indication from YY_INPUT,
+it then checks the `yywrap()' function. If `yywrap()' returns false
+(zero), then it is assumed that the function has gone ahead and set up
+`yyin' to point to another input file, and scanning continues. If it
+returns true (non-zero), then the scanner terminates, returning 0 to
+its caller. Note that in either case, the start condition remains
+unchanged; it does *not* revert to `INITIAL'.
+
+ If you do not supply your own version of `yywrap()', then you must
+either use `%option noyywrap' (in which case the scanner behaves as
+though `yywrap()' returned 1), or you must link with `-lfl' to obtain
+the default version of the routine, which always returns 1.
+
+ Three routines are available for scanning from in-memory buffers
+rather than files: `yy_scan_string()', `yy_scan_bytes()', and
+`yy_scan_buffer()'. See the discussion of them below in the section
+Multiple Input Buffers.
+
+ The scanner writes its `ECHO' output to the `yyout' global (default,
+stdout), which may be redefined by the user simply by assigning it to
+some other `FILE' pointer.
+
+
+File: flex.info, Node: Start conditions, Next: Multiple buffers, Prev: Generated scanner, Up: Top
+
+Start conditions
+================
+
+ `flex' provides a mechanism for conditionally activating rules. Any
+rule whose pattern is prefixed with "<sc>" will only be active when the
+scanner is in the start condition named "sc". For example,
+
+ <STRING>[^"]* { /* eat up the string body ... */
+ ...
+ }
+
+will be active only when the scanner is in the "STRING" start
+condition, and
+
+ <INITIAL,STRING,QUOTE>\. { /* handle an escape ... */
+ ...
+ }
+
+will be active only when the current start condition is either
+"INITIAL", "STRING", or "QUOTE".
+
+ Start conditions are declared in the definitions (first) section of
+the input using unindented lines beginning with either `%s' or `%x'
+followed by a list of names. The former declares *inclusive* start
+conditions, the latter *exclusive* start conditions. A start condition
+is activated using the `BEGIN' action. Until the next `BEGIN' action is
+executed, rules with the given start condition will be active and rules
+with other start conditions will be inactive. If the start condition
+is *inclusive*, then rules with no start conditions at all will also be
+active. If it is *exclusive*, then *only* rules qualified with the
+start condition will be active. A set of rules contingent on the same
+exclusive start condition describe a scanner which is independent of
+any of the other rules in the `flex' input. Because of this, exclusive
+start conditions make it easy to specify "mini-scanners" which scan
+portions of the input that are syntactically different from the rest
+(e.g., comments).
+
+ If the distinction between inclusive and exclusive start conditions
+is still a little vague, here's a simple example illustrating the
+connection between the two. The set of rules:
+
+ %s example
+ %%
+
+ <example>foo do_something();
+
+ bar something_else();
+
+is equivalent to
+
+ %x example
+ %%
+
+ <example>foo do_something();
+
+ <INITIAL,example>bar something_else();
+
+ Without the `<INITIAL,example>' qualifier, the `bar' pattern in the
+second example wouldn't be active (i.e., couldn't match) when in start
+condition `example'. If we just used `<example>' to qualify `bar',
+though, then it would only be active in `example' and not in `INITIAL',
+while in the first example it's active in both, because in the first
+example the `example' starting condition is an *inclusive* (`%s') start
+condition.
+
+ Also note that the special start-condition specifier `<*>' matches
+every start condition. Thus, the above example could also have been
+written;
+
+ %x example
+ %%
+
+ <example>foo do_something();
+
+ <*>bar something_else();
+
+ The default rule (to `ECHO' any unmatched character) remains active
+in start conditions. It is equivalent to:
+
+ <*>.|\\n ECHO;
+
+ `BEGIN(0)' returns to the original state where only the rules with
+no start conditions are active. This state can also be referred to as
+the start-condition "INITIAL", so `BEGIN(INITIAL)' is equivalent to
+`BEGIN(0)'. (The parentheses around the start condition name are not
+required but are considered good style.)
+
+ `BEGIN' actions can also be given as indented code at the beginning
+of the rules section. For example, the following will cause the
+scanner to enter the "SPECIAL" start condition whenever `yylex()' is
+called and the global variable `enter_special' is true:
+
+ int enter_special;
+
+ %x SPECIAL
+ %%
+ if ( enter_special )
+ BEGIN(SPECIAL);
+
+ <SPECIAL>blahblahblah
+ ...more rules follow...
+
+ To illustrate the uses of start conditions, here is a scanner which
+provides two different interpretations of a string like "123.456". By
+default it will treat it as as three tokens, the integer "123", a dot
+('.'), and the integer "456". But if the string is preceded earlier in
+the line by the string "expect-floats" it will treat it as a single
+token, the floating-point number 123.456:
+
+ %{
+ #include <math.h>
+ %}
+ %s expect
+
+ %%
+ expect-floats BEGIN(expect);
+
+ <expect>[0-9]+"."[0-9]+ {
+ printf( "found a float, = %f\n",
+ atof( yytext ) );
+ }
+ <expect>\n {
+ /* that's the end of the line, so
+ * we need another "expect-number"
+ * before we'll recognize any more
+ * numbers
+ */
+ BEGIN(INITIAL);
+ }
+
+ [0-9]+ {
+
+ Version 2.5 December 1994 18
+
+ printf( "found an integer, = %d\n",
+ atoi( yytext ) );
+ }
+
+ "." printf( "found a dot\n" );
+
+ Here is a scanner which recognizes (and discards) C comments while
+maintaining a count of the current input line.
+
+ %x comment
+ %%
+ int line_num = 1;
+
+ "/*" BEGIN(comment);
+
+ <comment>[^*\n]* /* eat anything that's not a '*' */
+ <comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+ <comment>\n ++line_num;
+ <comment>"*"+"/" BEGIN(INITIAL);
+
+ This scanner goes to a bit of trouble to match as much text as
+possible with each rule. In general, when attempting to write a
+high-speed scanner try to match as much possible in each rule, as it's
+a big win.
+
+ Note that start-conditions names are really integer values and can
+be stored as such. Thus, the above could be extended in the following
+fashion:
+
+ %x comment foo
+ %%
+ int line_num = 1;
+ int comment_caller;
+
+ "/*" {
+ comment_caller = INITIAL;
+ BEGIN(comment);
+ }
+
+ ...
+
+ <foo>"/*" {
+ comment_caller = foo;
+ BEGIN(comment);
+ }
+
+ <comment>[^*\n]* /* eat anything that's not a '*' */
+ <comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+ <comment>\n ++line_num;
+ <comment>"*"+"/" BEGIN(comment_caller);
+
+ Furthermore, you can access the current start condition using the
+integer-valued `YY_START' macro. For example, the above assignments to
+`comment_caller' could instead be written
+
+ comment_caller = YY_START;
+
+ Flex provides `YYSTATE' as an alias for `YY_START' (since that is
+what's used by AT&T `lex').
+
+ Note that start conditions do not have their own name-space; %s's
+and %x's declare names in the same fashion as #define's.
+
+ Finally, here's an example of how to match C-style quoted strings
+using exclusive start conditions, including expanded escape sequences
+(but not including checking for a string that's too long):
+
+ %x str
+
+ %%
+ char string_buf[MAX_STR_CONST];
+ char *string_buf_ptr;
+
+ \" string_buf_ptr = string_buf; BEGIN(str);
+
+ <str>\" { /* saw closing quote - all done */
+ BEGIN(INITIAL);
+ *string_buf_ptr = '\0';
+ /* return string constant token type and
+ * value to parser
+ */
+ }
+
+ <str>\n {
+ /* error - unterminated string constant */
+ /* generate error message */
+ }
+
+ <str>\\[0-7]{1,3} {
+ /* octal escape sequence */
+ int result;
+
+ (void) sscanf( yytext + 1, "%o", &result );
+
+ if ( result > 0xff )
+ /* error, constant is out-of-bounds */
+
+ *string_buf_ptr++ = result;
+ }
+
+ <str>\\[0-9]+ {
+ /* generate error - bad escape sequence; something
+ * like '\48' or '\0777777'
+ */
+ }
+
+ <str>\\n *string_buf_ptr++ = '\n';
+ <str>\\t *string_buf_ptr++ = '\t';
+ <str>\\r *string_buf_ptr++ = '\r';
+ <str>\\b *string_buf_ptr++ = '\b';
+ <str>\\f *string_buf_ptr++ = '\f';
+
+ <str>\\(.|\n) *string_buf_ptr++ = yytext[1];
+
+ <str>[^\\\n\"]+ {
+ char *yptr = yytext;
+
+ while ( *yptr )
+ *string_buf_ptr++ = *yptr++;
+ }
+
+ Often, such as in some of the examples above, you wind up writing a
+whole bunch of rules all preceded by the same start condition(s). Flex
+makes this a little easier and cleaner by introducing a notion of start
+condition "scope". A start condition scope is begun with:
+
+ <SCs>{
+
+where SCs is a list of one or more start conditions. Inside the start
+condition scope, every rule automatically has the prefix `<SCs>'
+applied to it, until a `}' which matches the initial `{'. So, for
+example,
+
+ <ESC>{
+ "\\n" return '\n';
+ "\\r" return '\r';
+ "\\f" return '\f';
+ "\\0" return '\0';
+ }
+
+is equivalent to:
+
+ <ESC>"\\n" return '\n';
+ <ESC>"\\r" return '\r';
+ <ESC>"\\f" return '\f';
+ <ESC>"\\0" return '\0';
+
+ Start condition scopes may be nested.
+
+ Three routines are available for manipulating stacks of start
+conditions:
+
+`void yy_push_state(int new_state)'
+ pushes the current start condition onto the top of the start
+ condition stack and switches to NEW_STATE as though you had used
+ `BEGIN new_state' (recall that start condition names are also
+ integers).
+
+`void yy_pop_state()'
+ pops the top of the stack and switches to it via `BEGIN'.
+
+`int yy_top_state()'
+ returns the top of the stack without altering the stack's contents.
+
+ The start condition stack grows dynamically and so has no built-in
+size limitation. If memory is exhausted, program execution aborts.
+
+ To use start condition stacks, your scanner must include a `%option
+stack' directive (see Options below).
+
+
+File: flex.info, Node: Multiple buffers, Next: End-of-file rules, Prev: Start conditions, Up: Top
+
+Multiple input buffers
+======================
+
+ Some scanners (such as those which support "include" files) require
+reading from several input streams. As `flex' scanners do a large
+amount of buffering, one cannot control where the next input will be
+read from by simply writing a `YY_INPUT' which is sensitive to the
+scanning context. `YY_INPUT' is only called when the scanner reaches
+the end of its buffer, which may be a long time after scanning a
+statement such as an "include" which requires switching the input
+source.
+
+ To negotiate these sorts of problems, `flex' provides a mechanism
+for creating and switching between multiple input buffers. An input
+buffer is created by using:
+
+ YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+
+which takes a `FILE' pointer and a size and creates a buffer associated
+with the given file and large enough to hold SIZE characters (when in
+doubt, use `YY_BUF_SIZE' for the size). It returns a `YY_BUFFER_STATE'
+handle, which may then be passed to other routines (see below). The
+`YY_BUFFER_STATE' type is a pointer to an opaque `struct'
+`yy_buffer_state' structure, so you may safely initialize
+YY_BUFFER_STATE variables to `((YY_BUFFER_STATE) 0)' if you wish, and
+also refer to the opaque structure in order to correctly declare input
+buffers in source files other than that of your scanner. Note that the
+`FILE' pointer in the call to `yy_create_buffer' is only used as the
+value of `yyin' seen by `YY_INPUT'; if you redefine `YY_INPUT' so it no
+longer uses `yyin', then you can safely pass a nil `FILE' pointer to
+`yy_create_buffer'. You select a particular buffer to scan from using:
+
+ void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+
+ switches the scanner's input buffer so subsequent tokens will come
+from NEW_BUFFER. Note that `yy_switch_to_buffer()' may be used by
+`yywrap()' to set things up for continued scanning, instead of opening
+a new file and pointing `yyin' at it. Note also that switching input
+sources via either `yy_switch_to_buffer()' or `yywrap()' does *not*
+change the start condition.
+
+ void yy_delete_buffer( YY_BUFFER_STATE buffer )
+
+is used to reclaim the storage associated with a buffer. You can also
+clear the current contents of a buffer using:
+
+ void yy_flush_buffer( YY_BUFFER_STATE buffer )
+
+ This function discards the buffer's contents, so the next time the
+scanner attempts to match a token from the buffer, it will first fill
+the buffer anew using `YY_INPUT'.
+
+ `yy_new_buffer()' is an alias for `yy_create_buffer()', provided for
+compatibility with the C++ use of `new' and `delete' for creating and
+destroying dynamic objects.
+
+ Finally, the `YY_CURRENT_BUFFER' macro returns a `YY_BUFFER_STATE'
+handle to the current buffer.
+
+ Here is an example of using these features for writing a scanner
+which expands include files (the `<<EOF>>' feature is discussed below):
+
+ /* the "incl" state is used for picking up the name
+ * of an include file
+ */
+ %x incl
+
+ %{
+ #define MAX_INCLUDE_DEPTH 10
+ YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
+ int include_stack_ptr = 0;
+ %}
+
+ %%
+ include BEGIN(incl);
+
+ [a-z]+ ECHO;
+ [^a-z\n]*\n? ECHO;
+
+ <incl>[ \t]* /* eat the whitespace */
+ <incl>[^ \t\n]+ { /* got the include file name */
+ if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
+ {
+ fprintf( stderr, "Includes nested too deeply" );
+ exit( 1 );
+ }
+
+ include_stack[include_stack_ptr++] =
+ YY_CURRENT_BUFFER;
+
+ yyin = fopen( yytext, "r" );
+
+ if ( ! yyin )
+ error( ... );
+
+ yy_switch_to_buffer(
+ yy_create_buffer( yyin, YY_BUF_SIZE ) );
+
+ BEGIN(INITIAL);
+ }
+
+ <<EOF>> {
+ if ( --include_stack_ptr < 0 )
+ {
+ yyterminate();
+ }
+
+ else
+ {
+ yy_delete_buffer( YY_CURRENT_BUFFER );
+ yy_switch_to_buffer(
+ include_stack[include_stack_ptr] );
+ }
+ }
+
+ Three routines are available for setting up input buffers for
+scanning in-memory strings instead of files. All of them create a new
+input buffer for scanning the string, and return a corresponding
+`YY_BUFFER_STATE' handle (which you should delete with
+`yy_delete_buffer()' when done with it). They also switch to the new
+buffer using `yy_switch_to_buffer()', so the next call to `yylex()' will
+start scanning the string.
+
+`yy_scan_string(const char *str)'
+ scans a NUL-terminated string.
+
+`yy_scan_bytes(const char *bytes, int len)'
+ scans `len' bytes (including possibly NUL's) starting at location
+ BYTES.
+
+ Note that both of these functions create and scan a *copy* of the
+string or bytes. (This may be desirable, since `yylex()' modifies the
+contents of the buffer it is scanning.) You can avoid the copy by using:
+
+`yy_scan_buffer(char *base, yy_size_t size)'
+ which scans in place the buffer starting at BASE, consisting of
+ SIZE bytes, the last two bytes of which *must* be
+ `YY_END_OF_BUFFER_CHAR' (ASCII NUL). These last two bytes are not
+ scanned; thus, scanning consists of `base[0]' through
+ `base[size-2]', inclusive.
+
+ If you fail to set up BASE in this manner (i.e., forget the final
+ two `YY_END_OF_BUFFER_CHAR' bytes), then `yy_scan_buffer()'
+ returns a nil pointer instead of creating a new input buffer.
+
+ The type `yy_size_t' is an integral type to which you can cast an
+ integer expression reflecting the size of the buffer.
+
+
+File: flex.info, Node: End-of-file rules, Next: Miscellaneous, Prev: Multiple buffers, Up: Top
+
+End-of-file rules
+=================
+
+ The special rule "<<EOF>>" indicates actions which are to be taken
+when an end-of-file is encountered and yywrap() returns non-zero (i.e.,
+indicates no further files to process). The action must finish by
+doing one of four things:
+
+ - assigning `yyin' to a new input file (in previous versions of
+ flex, after doing the assignment you had to call the special
+ action `YY_NEW_FILE'; this is no longer necessary);
+
+ - executing a `return' statement;
+
+ - executing the special `yyterminate()' action;
+
+ - or, switching to a new buffer using `yy_switch_to_buffer()' as
+ shown in the example above.
+
+ <<EOF>> rules may not be used with other patterns; they may only be
+qualified with a list of start conditions. If an unqualified <<EOF>>
+rule is given, it applies to *all* start conditions which do not
+already have <<EOF>> actions. To specify an <<EOF>> rule for only the
+initial start condition, use
+
+ <INITIAL><<EOF>>
+
+ These rules are useful for catching things like unclosed comments.
+An example:
+
+ %x quote
+ %%
+
+ ...other rules for dealing with quotes...
+
+ <quote><<EOF>> {
+ error( "unterminated quote" );
+ yyterminate();
+ }
+ <<EOF>> {
+ if ( *++filelist )
+ yyin = fopen( *filelist, "r" );
+ else
+ yyterminate();
+ }
+
+
+File: flex.info, Node: Miscellaneous, Next: User variables, Prev: End-of-file rules, Up: Top
+
+Miscellaneous macros
+====================
+
+ The macro `YY_USER_ACTION' can be defined to provide an action which
+is always executed prior to the matched rule's action. For example, it
+could be #define'd to call a routine to convert yytext to lower-case.
+When `YY_USER_ACTION' is invoked, the variable `yy_act' gives the
+number of the matched rule (rules are numbered starting with 1).
+Suppose you want to profile how often each of your rules is matched.
+The following would do the trick:
+
+ #define YY_USER_ACTION ++ctr[yy_act]
+
+ where `ctr' is an array to hold the counts for the different rules.
+Note that the macro `YY_NUM_RULES' gives the total number of rules
+(including the default rule, even if you use `-s', so a correct
+declaration for `ctr' is:
+
+ int ctr[YY_NUM_RULES];
+
+ The macro `YY_USER_INIT' may be defined to provide an action which
+is always executed before the first scan (and before the scanner's
+internal initializations are done). For example, it could be used to
+call a routine to read in a data table or open a logging file.
+
+ The macro `yy_set_interactive(is_interactive)' can be used to
+control whether the current buffer is considered *interactive*. An
+interactive buffer is processed more slowly, but must be used when the
+scanner's input source is indeed interactive to avoid problems due to
+waiting to fill buffers (see the discussion of the `-I' flag below). A
+non-zero value in the macro invocation marks the buffer as interactive,
+a zero value as non-interactive. Note that use of this macro overrides
+`%option always-interactive' or `%option never-interactive' (see
+Options below). `yy_set_interactive()' must be invoked prior to
+beginning to scan the buffer that is (or is not) to be considered
+interactive.
+
+ The macro `yy_set_bol(at_bol)' can be used to control whether the
+current buffer's scanning context for the next token match is done as
+though at the beginning of a line. A non-zero macro argument makes
+rules anchored with
+
+ The macro `YY_AT_BOL()' returns true if the next token scanned from
+the current buffer will have '^' rules active, false otherwise.
+
+ In the generated scanner, the actions are all gathered in one large
+switch statement and separated using `YY_BREAK', which may be
+redefined. By default, it is simply a "break", to separate each rule's
+action from the following rule's. Redefining `YY_BREAK' allows, for
+example, C++ users to #define YY_BREAK to do nothing (while being very
+careful that every rule ends with a "break" or a "return"!) to avoid
+suffering from unreachable statement warnings where because a rule's
+action ends with "return", the `YY_BREAK' is inaccessible.
+
+
+File: flex.info, Node: User variables, Next: YACC interface, Prev: Miscellaneous, Up: Top
+
+Values available to the user
+============================
+
+ This section summarizes the various values available to the user in
+the rule actions.
+
+ - `char *yytext' holds the text of the current token. It may be
+ modified but not lengthened (you cannot append characters to the
+ end).
+
+ If the special directive `%array' appears in the first section of
+ the scanner description, then `yytext' is instead declared `char
+ yytext[YYLMAX]', where `YYLMAX' is a macro definition that you can
+ redefine in the first section if you don't like the default value
+ (generally 8KB). Using `%array' results in somewhat slower
+ scanners, but the value of `yytext' becomes immune to calls to
+ `input()' and `unput()', which potentially destroy its value when
+ `yytext' is a character pointer. The opposite of `%array' is
+ `%pointer', which is the default.
+
+ You cannot use `%array' when generating C++ scanner classes (the
+ `-+' flag).
+
+ - `int yyleng' holds the length of the current token.
+
+ - `FILE *yyin' is the file which by default `flex' reads from. It
+ may be redefined but doing so only makes sense before scanning
+ begins or after an EOF has been encountered. Changing it in the
+ midst of scanning will have unexpected results since `flex'
+ buffers its input; use `yyrestart()' instead. Once scanning
+ terminates because an end-of-file has been seen, you can assign
+ `yyin' at the new input file and then call the scanner again to
+ continue scanning.
+
+ - `void yyrestart( FILE *new_file )' may be called to point `yyin'
+ at the new input file. The switch-over to the new file is
+ immediate (any previously buffered-up input is lost). Note that
+ calling `yyrestart()' with `yyin' as an argument thus throws away
+ the current input buffer and continues scanning the same input
+ file.
+
+ - `FILE *yyout' is the file to which `ECHO' actions are done. It
+ can be reassigned by the user.
+
+ - `YY_CURRENT_BUFFER' returns a `YY_BUFFER_STATE' handle to the
+ current buffer.
+
+ - `YY_START' returns an integer value corresponding to the current
+ start condition. You can subsequently use this value with `BEGIN'
+ to return to that start condition.
+
+
+File: flex.info, Node: YACC interface, Next: Options, Prev: User variables, Up: Top
+
+Interfacing with `yacc'
+=======================
+
+ One of the main uses of `flex' is as a companion to the `yacc'
+parser-generator. `yacc' parsers expect to call a routine named
+`yylex()' to find the next input token. The routine is supposed to
+return the type of the next token as well as putting any associated
+value in the global `yylval'. To use `flex' with `yacc', one specifies
+the `-d' option to `yacc' to instruct it to generate the file `y.tab.h'
+containing definitions of all the `%tokens' appearing in the `yacc'
+input. This file is then included in the `flex' scanner. For example,
+if one of the tokens is "TOK_NUMBER", part of the scanner might look
+like:
+
+ %{
+ #include "y.tab.h"
+ %}
+
+ %%
+
+ [0-9]+ yylval = atoi( yytext ); return TOK_NUMBER;
+
+
+File: flex.info, Node: Options, Next: Performance, Prev: YACC interface, Up: Top
+
+Options
+=======
+
+ `flex' has the following options:
+
+`-b'
+ Generate backing-up information to `lex.backup'. This is a list
+ of scanner states which require backing up and the input
+ characters on which they do so. By adding rules one can remove
+ backing-up states. If *all* backing-up states are eliminated and
+ `-Cf' or `-CF' is used, the generated scanner will run faster (see
+ the `-p' flag). Only users who wish to squeeze every last cycle
+ out of their scanners need worry about this option. (See the
+ section on Performance Considerations below.)
+
+`-c'
+ is a do-nothing, deprecated option included for POSIX compliance.
+
+`-d'
+ makes the generated scanner run in "debug" mode. Whenever a
+ pattern is recognized and the global `yy_flex_debug' is non-zero
+ (which is the default), the scanner will write to `stderr' a line
+ of the form:
+
+ --accepting rule at line 53 ("the matched text")
+
+ The line number refers to the location of the rule in the file
+ defining the scanner (i.e., the file that was fed to flex).
+ Messages are also generated when the scanner backs up, accepts the
+ default rule, reaches the end of its input buffer (or encounters a
+ NUL; at this point, the two look the same as far as the scanner's
+ concerned), or reaches an end-of-file.
+
+`-f'
+ specifies "fast scanner". No table compression is done and stdio
+ is bypassed. The result is large but fast. This option is
+ equivalent to `-Cfr' (see below).
+
+`-h'
+ generates a "help" summary of `flex's' options to `stdout' and
+ then exits. `-?' and `--help' are synonyms for `-h'.
+
+`-i'
+ instructs `flex' to generate a *case-insensitive* scanner. The
+ case of letters given in the `flex' input patterns will be
+ ignored, and tokens in the input will be matched regardless of
+ case. The matched text given in `yytext' will have the preserved
+ case (i.e., it will not be folded).
+
+`-l'
+ turns on maximum compatibility with the original AT&T `lex'
+ implementation. Note that this does not mean *full*
+ compatibility. Use of this option costs a considerable amount of
+ performance, and it cannot be used with the `-+, -f, -F, -Cf', or
+ `-CF' options. For details on the compatibilities it provides, see
+ the section "Incompatibilities With Lex And POSIX" below. This
+ option also results in the name `YY_FLEX_LEX_COMPAT' being
+ #define'd in the generated scanner.
+
+`-n'
+ is another do-nothing, deprecated option included only for POSIX
+ compliance.
+
+`-p'
+ generates a performance report to stderr. The report consists of
+ comments regarding features of the `flex' input file which will
+ cause a serious loss of performance in the resulting scanner. If
+ you give the flag twice, you will also get comments regarding
+ features that lead to minor performance losses.
+
+ Note that the use of `REJECT', `%option yylineno' and variable
+ trailing context (see the Deficiencies / Bugs section below)
+ entails a substantial performance penalty; use of `yymore()', the
+ `^' operator, and the `-I' flag entail minor performance penalties.
+
+`-s'
+ causes the "default rule" (that unmatched scanner input is echoed
+ to `stdout') to be suppressed. If the scanner encounters input
+ that does not match any of its rules, it aborts with an error.
+ This option is useful for finding holes in a scanner's rule set.
+
+`-t'
+ instructs `flex' to write the scanner it generates to standard
+ output instead of `lex.yy.c'.
+
+`-v'
+ specifies that `flex' should write to `stderr' a summary of
+ statistics regarding the scanner it generates. Most of the
+ statistics are meaningless to the casual `flex' user, but the
+ first line identifies the version of `flex' (same as reported by
+ `-V'), and the next line the flags used when generating the
+ scanner, including those that are on by default.
+
+`-w'
+ suppresses warning messages.
+
+`-B'
+ instructs `flex' to generate a *batch* scanner, the opposite of
+ *interactive* scanners generated by `-I' (see below). In general,
+ you use `-B' when you are *certain* that your scanner will never
+ be used interactively, and you want to squeeze a *little* more
+ performance out of it. If your goal is instead to squeeze out a
+ *lot* more performance, you should be using the `-Cf' or `-CF'
+ options (discussed below), which turn on `-B' automatically anyway.
+
+`-F'
+ specifies that the "fast" scanner table representation should be
+ used (and stdio bypassed). This representation is about as fast
+ as the full table representation `(-f)', and for some sets of
+ patterns will be considerably smaller (and for others, larger).
+ In general, if the pattern set contains both "keywords" and a
+ catch-all, "identifier" rule, such as in the set:
+
+ "case" return TOK_CASE;
+ "switch" return TOK_SWITCH;
+ ...
+ "default" return TOK_DEFAULT;
+ [a-z]+ return TOK_ID;
+
+ then you're better off using the full table representation. If
+ only the "identifier" rule is present and you then use a hash
+ table or some such to detect the keywords, you're better off using
+ `-F'.
+
+ This option is equivalent to `-CFr' (see below). It cannot be
+ used with `-+'.
+
+`-I'
+ instructs `flex' to generate an *interactive* scanner. An
+ interactive scanner is one that only looks ahead to decide what
+ token has been matched if it absolutely must. It turns out that
+ always looking one extra character ahead, even if the scanner has
+ already seen enough text to disambiguate the current token, is a
+ bit faster than only looking ahead when necessary. But scanners
+ that always look ahead give dreadful interactive performance; for
+ example, when a user types a newline, it is not recognized as a
+ newline token until they enter *another* token, which often means
+ typing in another whole line.
+
+ `Flex' scanners default to *interactive* unless you use the `-Cf'
+ or `-CF' table-compression options (see below). That's because if
+ you're looking for high-performance you should be using one of
+ these options, so if you didn't, `flex' assumes you'd rather trade
+ off a bit of run-time performance for intuitive interactive
+ behavior. Note also that you *cannot* use `-I' in conjunction
+ with `-Cf' or `-CF'. Thus, this option is not really needed; it
+ is on by default for all those cases in which it is allowed.
+
+ You can force a scanner to *not* be interactive by using `-B' (see
+ above).
+
+`-L'
+ instructs `flex' not to generate `#line' directives. Without this
+ option, `flex' peppers the generated scanner with #line directives
+ so error messages in the actions will be correctly located with
+ respect to either the original `flex' input file (if the errors
+ are due to code in the input file), or `lex.yy.c' (if the errors
+ are `flex's' fault - you should report these sorts of errors to
+ the email address given below).
+
+`-T'
+ makes `flex' run in `trace' mode. It will generate a lot of
+ messages to `stderr' concerning the form of the input and the
+ resultant non-deterministic and deterministic finite automata.
+ This option is mostly for use in maintaining `flex'.
+
+`-V'
+ prints the version number to `stdout' and exits. `--version' is a
+ synonym for `-V'.
+
+`-7'
+ instructs `flex' to generate a 7-bit scanner, i.e., one which can
+ only recognized 7-bit characters in its input. The advantage of
+ using `-7' is that the scanner's tables can be up to half the size
+ of those generated using the `-8' option (see below). The
+ disadvantage is that such scanners often hang or crash if their
+ input contains an 8-bit character.
+
+ Note, however, that unless you generate your scanner using the
+ `-Cf' or `-CF' table compression options, use of `-7' will save
+ only a small amount of table space, and make your scanner
+ considerably less portable. `Flex's' default behavior is to
+ generate an 8-bit scanner unless you use the `-Cf' or `-CF', in
+ which case `flex' defaults to generating 7-bit scanners unless
+ your site was always configured to generate 8-bit scanners (as
+ will often be the case with non-USA sites). You can tell whether
+ flex generated a 7-bit or an 8-bit scanner by inspecting the flag
+ summary in the `-v' output as described above.
+
+ Note that if you use `-Cfe' or `-CFe' (those table compression
+ options, but also using equivalence classes as discussed see
+ below), flex still defaults to generating an 8-bit scanner, since
+ usually with these compression options full 8-bit tables are not
+ much more expensive than 7-bit tables.
+
+`-8'
+ instructs `flex' to generate an 8-bit scanner, i.e., one which can
+ recognize 8-bit characters. This flag is only needed for scanners
+ generated using `-Cf' or `-CF', as otherwise flex defaults to
+ generating an 8-bit scanner anyway.
+
+ See the discussion of `-7' above for flex's default behavior and
+ the tradeoffs between 7-bit and 8-bit scanners.
+
+`-+'
+ specifies that you want flex to generate a C++ scanner class. See
+ the section on Generating C++ Scanners below for details.
+
+`-C[aefFmr]'
+ controls the degree of table compression and, more generally,
+ trade-offs between small scanners and fast scanners.
+
+ `-Ca' ("align") instructs flex to trade off larger tables in the
+ generated scanner for faster performance because the elements of
+ the tables are better aligned for memory access and computation.
+ On some RISC architectures, fetching and manipulating long-words
+ is more efficient than with smaller-sized units such as
+ shortwords. This option can double the size of the tables used by
+ your scanner.
+
+ `-Ce' directs `flex' to construct "equivalence classes", i.e.,
+ sets of characters which have identical lexical properties (for
+ example, if the only appearance of digits in the `flex' input is
+ in the character class "[0-9]" then the digits '0', '1', ..., '9'
+ will all be put in the same equivalence class). Equivalence
+ classes usually give dramatic reductions in the final table/object
+ file sizes (typically a factor of 2-5) and are pretty cheap
+ performance-wise (one array look-up per character scanned).
+
+ `-Cf' specifies that the *full* scanner tables should be generated
+ - `flex' should not compress the tables by taking advantages of
+ similar transition functions for different states.
+
+ `-CF' specifies that the alternate fast scanner representation
+ (described above under the `-F' flag) should be used. This option
+ cannot be used with `-+'.
+
+ `-Cm' directs `flex' to construct "meta-equivalence classes",
+ which are sets of equivalence classes (or characters, if
+ equivalence classes are not being used) that are commonly used
+ together. Meta-equivalence classes are often a big win when using
+ compressed tables, but they have a moderate performance impact
+ (one or two "if" tests and one array look-up per character
+ scanned).
+
+ `-Cr' causes the generated scanner to *bypass* use of the standard
+ I/O library (stdio) for input. Instead of calling `fread()' or
+ `getc()', the scanner will use the `read()' system call, resulting
+ in a performance gain which varies from system to system, but in
+ general is probably negligible unless you are also using `-Cf' or
+ `-CF'. Using `-Cr' can cause strange behavior if, for example,
+ you read from `yyin' using stdio prior to calling the scanner
+ (because the scanner will miss whatever text your previous reads
+ left in the stdio input buffer).
+
+ `-Cr' has no effect if you define `YY_INPUT' (see The Generated
+ Scanner above).
+
+ A lone `-C' specifies that the scanner tables should be compressed
+ but neither equivalence classes nor meta-equivalence classes
+ should be used.
+
+ The options `-Cf' or `-CF' and `-Cm' do not make sense together -
+ there is no opportunity for meta-equivalence classes if the table
+ is not being compressed. Otherwise the options may be freely
+ mixed, and are cumulative.
+
+ The default setting is `-Cem', which specifies that `flex' should
+ generate equivalence classes and meta-equivalence classes. This
+ setting provides the highest degree of table compression. You can
+ trade off faster-executing scanners at the cost of larger tables
+ with the following generally being true:
+
+ slowest & smallest
+ -Cem
+ -Cm
+ -Ce
+ -C
+ -C{f,F}e
+ -C{f,F}
+ -C{f,F}a
+ fastest & largest
+
+ Note that scanners with the smallest tables are usually generated
+ and compiled the quickest, so during development you will usually
+ want to use the default, maximal compression.
+
+ `-Cfe' is often a good compromise between speed and size for
+ production scanners.
+
+`-ooutput'
+ directs flex to write the scanner to the file `out-' `put' instead
+ of `lex.yy.c'. If you combine `-o' with the `-t' option, then the
+ scanner is written to `stdout' but its `#line' directives (see the
+ `-L' option above) refer to the file `output'.
+
+`-Pprefix'
+ changes the default `yy' prefix used by `flex' for all
+ globally-visible variable and function names to instead be PREFIX.
+ For example, `-Pfoo' changes the name of `yytext' to `footext'.
+ It also changes the name of the default output file from
+ `lex.yy.c' to `lex.foo.c'. Here are all of the names affected:
+
+ yy_create_buffer
+ yy_delete_buffer
+ yy_flex_debug
+ yy_init_buffer
+ yy_flush_buffer
+ yy_load_buffer_state
+ yy_switch_to_buffer
+ yyin
+ yyleng
+ yylex
+ yylineno
+ yyout
+ yyrestart
+ yytext
+ yywrap
+
+ (If you are using a C++ scanner, then only `yywrap' and
+ `yyFlexLexer' are affected.) Within your scanner itself, you can
+ still refer to the global variables and functions using either
+ version of their name; but externally, they have the modified name.
+
+ This option lets you easily link together multiple `flex' programs
+ into the same executable. Note, though, that using this option
+ also renames `yywrap()', so you now *must* either provide your own
+ (appropriately-named) version of the routine for your scanner, or
+ use `%option noyywrap', as linking with `-lfl' no longer provides
+ one for you by default.
+
+`-Sskeleton_file'
+ overrides the default skeleton file from which `flex' constructs
+ its scanners. You'll never need this option unless you are doing
+ `flex' maintenance or development.
+
+ `flex' also provides a mechanism for controlling options within the
+scanner specification itself, rather than from the flex command-line.
+This is done by including `%option' directives in the first section of
+the scanner specification. You can specify multiple options with a
+single `%option' directive, and multiple directives in the first
+section of your flex input file. Most options are given simply as
+names, optionally preceded by the word "no" (with no intervening
+whitespace) to negate their meaning. A number are equivalent to flex
+flags or their negation:
+
+ 7bit -7 option
+ 8bit -8 option
+ align -Ca option
+ backup -b option
+ batch -B option
+ c++ -+ option
+
+ caseful or
+ case-sensitive opposite of -i (default)
+
+ case-insensitive or
+ caseless -i option
+
+ debug -d option
+ default opposite of -s option
+ ecs -Ce option
+ fast -F option
+ full -f option
+ interactive -I option
+ lex-compat -l option
+ meta-ecs -Cm option
+ perf-report -p option
+ read -Cr option
+ stdout -t option
+ verbose -v option
+ warn opposite of -w option
+ (use "%option nowarn" for -w)
+
+ array equivalent to "%array"
+ pointer equivalent to "%pointer" (default)
+
+ Some `%option's' provide features otherwise not available:
+
+`always-interactive'
+ instructs flex to generate a scanner which always considers its
+ input "interactive". Normally, on each new input file the scanner
+ calls `isatty()' in an attempt to determine whether the scanner's
+ input source is interactive and thus should be read a character at
+ a time. When this option is used, however, then no such call is
+ made.
+
+`main'
+ directs flex to provide a default `main()' program for the
+ scanner, which simply calls `yylex()'. This option implies
+ `noyywrap' (see below).
+
+`never-interactive'
+ instructs flex to generate a scanner which never considers its
+ input "interactive" (again, no call made to `isatty())'. This is
+ the opposite of `always-' *interactive*.
+
+`stack'
+ enables the use of start condition stacks (see Start Conditions
+ above).
+
+`stdinit'
+ if unset (i.e., `%option nostdinit') initializes `yyin' and
+ `yyout' to nil `FILE' pointers, instead of `stdin' and `stdout'.
+
+`yylineno'
+ directs `flex' to generate a scanner that maintains the number of
+ the current line read from its input in the global variable
+ `yylineno'. This option is implied by `%option lex-compat'.
+
+`yywrap'
+ if unset (i.e., `%option noyywrap'), makes the scanner not call
+ `yywrap()' upon an end-of-file, but simply assume that there are
+ no more files to scan (until the user points `yyin' at a new file
+ and calls `yylex()' again).
+
+ `flex' scans your rule actions to determine whether you use the
+`REJECT' or `yymore()' features. The `reject' and `yymore' options are
+available to override its decision as to whether you use the options,
+either by setting them (e.g., `%option reject') to indicate the feature
+is indeed used, or unsetting them to indicate it actually is not used
+(e.g., `%option noyymore').
+
+ Three options take string-delimited values, offset with '=':
+
+ %option outfile="ABC"
+
+is equivalent to `-oABC', and
+
+ %option prefix="XYZ"
+
+is equivalent to `-PXYZ'.
+
+ Finally,
+
+ %option yyclass="foo"
+
+only applies when generating a C++ scanner (`-+' option). It informs
+`flex' that you have derived `foo' as a subclass of `yyFlexLexer' so
+`flex' will place your actions in the member function `foo::yylex()'
+instead of `yyFlexLexer::yylex()'. It also generates a
+`yyFlexLexer::yylex()' member function that emits a run-time error (by
+invoking `yyFlexLexer::LexerError()') if called. See Generating C++
+Scanners, below, for additional information.
+
+ A number of options are available for lint purists who want to
+suppress the appearance of unneeded routines in the generated scanner.
+Each of the following, if unset, results in the corresponding routine
+not appearing in the generated scanner:
+
+ input, unput
+ yy_push_state, yy_pop_state, yy_top_state
+ yy_scan_buffer, yy_scan_bytes, yy_scan_string
+
+(though `yy_push_state()' and friends won't appear anyway unless you
+use `%option stack').
+
+
+File: flex.info, Node: Performance, Next: C++, Prev: Options, Up: Top
+
+Performance considerations
+==========================
+
+ The main design goal of `flex' is that it generate high-performance
+scanners. It has been optimized for dealing well with large sets of
+rules. Aside from the effects on scanner speed of the table
+compression `-C' options outlined above, there are a number of
+options/actions which degrade performance. These are, from most
+expensive to least:
+
+ REJECT
+ %option yylineno
+ arbitrary trailing context
+
+ pattern sets that require backing up
+ %array
+ %option interactive
+ %option always-interactive
+
+ '^' beginning-of-line operator
+ yymore()
+
+ with the first three all being quite expensive and the last two
+being quite cheap. Note also that `unput()' is implemented as a
+routine call that potentially does quite a bit of work, while
+`yyless()' is a quite-cheap macro; so if just putting back some excess
+text you scanned, use `yyless()'.
+
+ `REJECT' should be avoided at all costs when performance is
+important. It is a particularly expensive option.
+
+ Getting rid of backing up is messy and often may be an enormous
+amount of work for a complicated scanner. In principal, one begins by
+using the `-b' flag to generate a `lex.backup' file. For example, on
+the input
+
+ %%
+ foo return TOK_KEYWORD;
+ foobar return TOK_KEYWORD;
+
+the file looks like:
+
+ State #6 is non-accepting -
+ associated rule line numbers:
+ 2 3
+ out-transitions: [ o ]
+ jam-transitions: EOF [ \001-n p-\177 ]
+
+ State #8 is non-accepting -
+ associated rule line numbers:
+ 3
+ out-transitions: [ a ]
+ jam-transitions: EOF [ \001-` b-\177 ]
+
+ State #9 is non-accepting -
+ associated rule line numbers:
+ 3
+ out-transitions: [ r ]
+ jam-transitions: EOF [ \001-q s-\177 ]
+
+ Compressed tables always back up.
+
+ The first few lines tell us that there's a scanner state in which it
+can make a transition on an 'o' but not on any other character, and
+that in that state the currently scanned text does not match any rule.
+The state occurs when trying to match the rules found at lines 2 and 3
+in the input file. If the scanner is in that state and then reads
+something other than an 'o', it will have to back up to find a rule
+which is matched. With a bit of head-scratching one can see that this
+must be the state it's in when it has seen "fo". When this has
+happened, if anything other than another 'o' is seen, the scanner will
+have to back up to simply match the 'f' (by the default rule).
+
+ The comment regarding State #8 indicates there's a problem when
+"foob" has been scanned. Indeed, on any character other than an 'a',
+the scanner will have to back up to accept "foo". Similarly, the
+comment for State #9 concerns when "fooba" has been scanned and an 'r'
+does not follow.
+
+ The final comment reminds us that there's no point going to all the
+trouble of removing backing up from the rules unless we're using `-Cf'
+or `-CF', since there's no performance gain doing so with compressed
+scanners.
+
+ The way to remove the backing up is to add "error" rules:
+
+ %%
+ foo return TOK_KEYWORD;
+ foobar return TOK_KEYWORD;
+
+ fooba |
+ foob |
+ fo {
+ /* false alarm, not really a keyword */
+ return TOK_ID;
+ }
+
+ Eliminating backing up among a list of keywords can also be done
+using a "catch-all" rule:
+
+ %%
+ foo return TOK_KEYWORD;
+ foobar return TOK_KEYWORD;
+
+ [a-z]+ return TOK_ID;
+
+ This is usually the best solution when appropriate.
+
+ Backing up messages tend to cascade. With a complicated set of
+rules it's not uncommon to get hundreds of messages. If one can
+decipher them, though, it often only takes a dozen or so rules to
+eliminate the backing up (though it's easy to make a mistake and have
+an error rule accidentally match a valid token. A possible future
+`flex' feature will be to automatically add rules to eliminate backing
+up).
+
+ It's important to keep in mind that you gain the benefits of
+eliminating backing up only if you eliminate *every* instance of
+backing up. Leaving just one means you gain nothing.
+
+ VARIABLE trailing context (where both the leading and trailing parts
+do not have a fixed length) entails almost the same performance loss as
+`REJECT' (i.e., substantial). So when possible a rule like:
+
+ %%
+ mouse|rat/(cat|dog) run();
+
+is better written:
+
+ %%
+ mouse/cat|dog run();
+ rat/cat|dog run();
+
+or as
+
+ %%
+ mouse|rat/cat run();
+ mouse|rat/dog run();
+
+ Note that here the special '|' action does *not* provide any
+savings, and can even make things worse (see Deficiencies / Bugs below).
+
+ Another area where the user can increase a scanner's performance
+(and one that's easier to implement) arises from the fact that the
+longer the tokens matched, the faster the scanner will run. This is
+because with long tokens the processing of most input characters takes
+place in the (short) inner scanning loop, and does not often have to go
+through the additional work of setting up the scanning environment
+(e.g., `yytext') for the action. Recall the scanner for C comments:
+
+ %x comment
+ %%
+ int line_num = 1;
+
+ "/*" BEGIN(comment);
+
+ <comment>[^*\n]*
+ <comment>"*"+[^*/\n]*
+ <comment>\n ++line_num;
+ <comment>"*"+"/" BEGIN(INITIAL);
+
+ This could be sped up by writing it as:
+
+ %x comment
+ %%
+ int line_num = 1;
+
+ "/*" BEGIN(comment);
+
+ <comment>[^*\n]*
+ <comment>[^*\n]*\n ++line_num;
+ <comment>"*"+[^*/\n]*
+ <comment>"*"+[^*/\n]*\n ++line_num;
+ <comment>"*"+"/" BEGIN(INITIAL);
+
+ Now instead of each newline requiring the processing of another
+action, recognizing the newlines is "distributed" over the other rules
+to keep the matched text as long as possible. Note that *adding* rules
+does *not* slow down the scanner! The speed of the scanner is
+independent of the number of rules or (modulo the considerations given
+at the beginning of this section) how complicated the rules are with
+regard to operators such as '*' and '|'.
+
+ A final example in speeding up a scanner: suppose you want to scan
+through a file containing identifiers and keywords, one per line and
+with no other extraneous characters, and recognize all the keywords. A
+natural first approach is:
+
+ %%
+ asm |
+ auto |
+ break |
+ ... etc ...
+ volatile |
+ while /* it's a keyword */
+
+ .|\n /* it's not a keyword */
+
+ To eliminate the back-tracking, introduce a catch-all rule:
+
+ %%
+ asm |
+ auto |
+ break |
+ ... etc ...
+ volatile |
+ while /* it's a keyword */
+
+ [a-z]+ |
+ .|\n /* it's not a keyword */
+
+ Now, if it's guaranteed that there's exactly one word per line, then
+we can reduce the total number of matches by a half by merging in the
+recognition of newlines with that of the other tokens:
+
+ %%
+ asm\n |
+ auto\n |
+ break\n |
+ ... etc ...
+ volatile\n |
+ while\n /* it's a keyword */
+
+ [a-z]+\n |
+ .|\n /* it's not a keyword */
+
+ One has to be careful here, as we have now reintroduced backing up
+into the scanner. In particular, while *we* know that there will never
+be any characters in the input stream other than letters or newlines,
+`flex' can't figure this out, and it will plan for possibly needing to
+back up when it has scanned a token like "auto" and then the next
+character is something other than a newline or a letter. Previously it
+would then just match the "auto" rule and be done, but now it has no
+"auto" rule, only a "auto\n" rule. To eliminate the possibility of
+backing up, we could either duplicate all rules but without final
+newlines, or, since we never expect to encounter such an input and
+therefore don't how it's classified, we can introduce one more
+catch-all rule, this one which doesn't include a newline:
+
+ %%
+ asm\n |
+ auto\n |
+ break\n |
+ ... etc ...
+ volatile\n |
+ while\n /* it's a keyword */
+
+ [a-z]+\n |
+ [a-z]+ |
+ .|\n /* it's not a keyword */
+
+ Compiled with `-Cf', this is about as fast as one can get a `flex'
+scanner to go for this particular problem.
+
+ A final note: `flex' is slow when matching NUL's, particularly when
+a token contains multiple NUL's. It's best to write rules which match
+*short* amounts of text if it's anticipated that the text will often
+include NUL's.
+
+ Another final note regarding performance: as mentioned above in the
+section How the Input is Matched, dynamically resizing `yytext' to
+accommodate huge tokens is a slow process because it presently requires
+that the (huge) token be rescanned from the beginning. Thus if
+performance is vital, you should attempt to match "large" quantities of
+text but not "huge" quantities, where the cutoff between the two is at
+about 8K characters/token.
+
+
+File: flex.info, Node: C++, Next: Incompatibilities, Prev: Performance, Up: Top
+
+Generating C++ scanners
+=======================
+
+ `flex' provides two different ways to generate scanners for use with
+C++. The first way is to simply compile a scanner generated by `flex'
+using a C++ compiler instead of a C compiler. You should not encounter
+any compilations errors (please report any you find to the email address
+given in the Author section below). You can then use C++ code in your
+rule actions instead of C code. Note that the default input source for
+your scanner remains `yyin', and default echoing is still done to
+`yyout'. Both of these remain `FILE *' variables and not C++ `streams'.
+
+ You can also use `flex' to generate a C++ scanner class, using the
+`-+' option, (or, equivalently, `%option c++'), which is automatically
+specified if the name of the flex executable ends in a `+', such as
+`flex++'. When using this option, flex defaults to generating the
+scanner to the file `lex.yy.cc' instead of `lex.yy.c'. The generated
+scanner includes the header file `FlexLexer.h', which defines the
+interface to two C++ classes.
+
+ The first class, `FlexLexer', provides an abstract base class
+defining the general scanner class interface. It provides the
+following member functions:
+
+`const char* YYText()'
+ returns the text of the most recently matched token, the
+ equivalent of `yytext'.
+
+`int YYLeng()'
+ returns the length of the most recently matched token, the
+ equivalent of `yyleng'.
+
+`int lineno() const'
+ returns the current input line number (see `%option yylineno'), or
+ 1 if `%option yylineno' was not used.
+
+`void set_debug( int flag )'
+ sets the debugging flag for the scanner, equivalent to assigning to
+ `yy_flex_debug' (see the Options section above). Note that you
+ must build the scanner using `%option debug' to include debugging
+ information in it.
+
+`int debug() const'
+ returns the current setting of the debugging flag.
+
+ Also provided are member functions equivalent to
+`yy_switch_to_buffer(), yy_create_buffer()' (though the first argument
+is an `istream*' object pointer and not a `FILE*', `yy_flush_buffer()',
+`yy_delete_buffer()', and `yyrestart()' (again, the first argument is a
+`istream*' object pointer).
+
+ The second class defined in `FlexLexer.h' is `yyFlexLexer', which is
+derived from `FlexLexer'. It defines the following additional member
+functions:
+
+`yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )'
+ constructs a `yyFlexLexer' object using the given streams for
+ input and output. If not specified, the streams default to `cin'
+ and `cout', respectively.
+
+`virtual int yylex()'
+ performs the same role is `yylex()' does for ordinary flex
+ scanners: it scans the input stream, consuming tokens, until a
+ rule's action returns a value. If you derive a subclass S from
+ `yyFlexLexer' and want to access the member functions and
+ variables of S inside `yylex()', then you need to use `%option
+ yyclass="S"' to inform `flex' that you will be using that subclass
+ instead of `yyFlexLexer'. In this case, rather than generating
+ `yyFlexLexer::yylex()', `flex' generates `S::yylex()' (and also
+ generates a dummy `yyFlexLexer::yylex()' that calls
+ `yyFlexLexer::LexerError()' if called).
+
+`virtual void switch_streams(istream* new_in = 0, ostream* new_out = 0)'
+ reassigns `yyin' to `new_in' (if non-nil) and `yyout' to `new_out'
+ (ditto), deleting the previous input buffer if `yyin' is
+ reassigned.
+
+`int yylex( istream* new_in = 0, ostream* new_out = 0 )'
+ first switches the input streams via `switch_streams( new_in,
+ new_out )' and then returns the value of `yylex()'.
+
+ In addition, `yyFlexLexer' defines the following protected virtual
+functions which you can redefine in derived classes to tailor the
+scanner:
+
+`virtual int LexerInput( char* buf, int max_size )'
+ reads up to `max_size' characters into BUF and returns the number
+ of characters read. To indicate end-of-input, return 0
+ characters. Note that "interactive" scanners (see the `-B' and
+ `-I' flags) define the macro `YY_INTERACTIVE'. If you redefine
+ `LexerInput()' and need to take different actions depending on
+ whether or not the scanner might be scanning an interactive input
+ source, you can test for the presence of this name via `#ifdef'.
+
+`virtual void LexerOutput( const char* buf, int size )'
+ writes out SIZE characters from the buffer BUF, which, while
+ NUL-terminated, may also contain "internal" NUL's if the scanner's
+ rules can match text with NUL's in them.
+
+`virtual void LexerError( const char* msg )'
+ reports a fatal error message. The default version of this
+ function writes the message to the stream `cerr' and exits.
+
+ Note that a `yyFlexLexer' object contains its *entire* scanning
+state. Thus you can use such objects to create reentrant scanners.
+You can instantiate multiple instances of the same `yyFlexLexer' class,
+and you can also combine multiple C++ scanner classes together in the
+same program using the `-P' option discussed above. Finally, note that
+the `%array' feature is not available to C++ scanner classes; you must
+use `%pointer' (the default).
+
+ Here is an example of a simple C++ scanner:
+
+ // An example of using the flex C++ scanner class.
+
+ %{
+ int mylineno = 0;
+ %}
+
+ string \"[^\n"]+\"
+
+ ws [ \t]+
+
+ alpha [A-Za-z]
+ dig [0-9]
+ name ({alpha}|{dig}|\$)({alpha}|{dig}|[_.\-/$])*
+ num1 [-+]?{dig}+\.?([eE][-+]?{dig}+)?
+ num2 [-+]?{dig}*\.{dig}+([eE][-+]?{dig}+)?
+ number {num1}|{num2}
+
+ %%
+
+ {ws} /* skip blanks and tabs */
+
+ "/*" {
+ int c;
+
+ while((c = yyinput()) != 0)
+ {
+ if(c == '\n')
+ ++mylineno;
+
+ else if(c == '*')
+ {
+ if((c = yyinput()) == '/')
+ break;
+ else
+ unput(c);
+ }
+ }
+ }
+
+ {number} cout << "number " << YYText() << '\n';
+
+ \n mylineno++;
+
+ {name} cout << "name " << YYText() << '\n';
+
+ {string} cout << "string " << YYText() << '\n';
+
+ %%
+
+ Version 2.5 December 1994 44
+
+ int main( int /* argc */, char** /* argv */ )
+ {
+ FlexLexer* lexer = new yyFlexLexer;
+ while(lexer->yylex() != 0)
+ ;
+ return 0;
+ }
+
+ If you want to create multiple (different) lexer classes, you use
+the `-P' flag (or the `prefix=' option) to rename each `yyFlexLexer' to
+some other `xxFlexLexer'. You then can include `<FlexLexer.h>' in your
+other sources once per lexer class, first renaming `yyFlexLexer' as
+follows:
+
+ #undef yyFlexLexer
+ #define yyFlexLexer xxFlexLexer
+ #include <FlexLexer.h>
+
+ #undef yyFlexLexer
+ #define yyFlexLexer zzFlexLexer
+ #include <FlexLexer.h>
+
+ if, for example, you used `%option prefix="xx"' for one of your
+scanners and `%option prefix="zz"' for the other.
+
+ IMPORTANT: the present form of the scanning class is *experimental*
+and may change considerably between major releases.
+
+
+File: flex.info, Node: Incompatibilities, Next: Diagnostics, Prev: C++, Up: Top
+
+Incompatibilities with `lex' and POSIX
+======================================
+
+ `flex' is a rewrite of the AT&T Unix `lex' tool (the two
+implementations do not share any code, though), with some extensions
+and incompatibilities, both of which are of concern to those who wish
+to write scanners acceptable to either implementation. Flex is fully
+compliant with the POSIX `lex' specification, except that when using
+`%pointer' (the default), a call to `unput()' destroys the contents of
+`yytext', which is counter to the POSIX specification.
+
+ In this section we discuss all of the known areas of incompatibility
+between flex, AT&T lex, and the POSIX specification.
+
+ `flex's' `-l' option turns on maximum compatibility with the
+original AT&T `lex' implementation, at the cost of a major loss in the
+generated scanner's performance. We note below which incompatibilities
+can be overcome using the `-l' option.
+
+ `flex' is fully compatible with `lex' with the following exceptions:
+
+ - The undocumented `lex' scanner internal variable `yylineno' is not
+ supported unless `-l' or `%option yylineno' is used. `yylineno'
+ should be maintained on a per-buffer basis, rather than a
+ per-scanner (single global variable) basis. `yylineno' is not
+ part of the POSIX specification.
+
+ - The `input()' routine is not redefinable, though it may be called
+ to read characters following whatever has been matched by a rule.
+ If `input()' encounters an end-of-file the normal `yywrap()'
+ processing is done. A "real" end-of-file is returned by `input()'
+ as `EOF'.
+
+ Input is instead controlled by defining the `YY_INPUT' macro.
+
+ The `flex' restriction that `input()' cannot be redefined is in
+ accordance with the POSIX specification, which simply does not
+ specify any way of controlling the scanner's input other than by
+ making an initial assignment to `yyin'.
+
+ - The `unput()' routine is not redefinable. This restriction is in
+ accordance with POSIX.
+
+ - `flex' scanners are not as reentrant as `lex' scanners. In
+ particular, if you have an interactive scanner and an interrupt
+ handler which long-jumps out of the scanner, and the scanner is
+ subsequently called again, you may get the following message:
+
+ fatal flex scanner internal error--end of buffer missed
+
+ To reenter the scanner, first use
+
+ yyrestart( yyin );
+
+ Note that this call will throw away any buffered input; usually
+ this isn't a problem with an interactive scanner.
+
+ Also note that flex C++ scanner classes *are* reentrant, so if
+ using C++ is an option for you, you should use them instead. See
+ "Generating C++ Scanners" above for details.
+
+ - `output()' is not supported. Output from the `ECHO' macro is done
+ to the file-pointer `yyout' (default `stdout').
+
+ `output()' is not part of the POSIX specification.
+
+ - `lex' does not support exclusive start conditions (%x), though
+ they are in the POSIX specification.
+
+ - When definitions are expanded, `flex' encloses them in
+ parentheses. With lex, the following:
+
+ NAME [A-Z][A-Z0-9]*
+ %%
+ foo{NAME}? printf( "Found it\n" );
+ %%
+
+ will not match the string "foo" because when the macro is expanded
+ the rule is equivalent to "foo[A-Z][A-Z0-9]*?" and the precedence
+ is such that the '?' is associated with "[A-Z0-9]*". With `flex',
+ the rule will be expanded to "foo([A-Z][A-Z0-9]*)?" and so the
+ string "foo" will match.
+
+ Note that if the definition begins with `^' or ends with `$' then
+ it is *not* expanded with parentheses, to allow these operators to
+ appear in definitions without losing their special meanings. But
+ the `<s>, /', and `<<EOF>>' operators cannot be used in a `flex'
+ definition.
+
+ Using `-l' results in the `lex' behavior of no parentheses around
+ the definition.
+
+ The POSIX specification is that the definition be enclosed in
+ parentheses.
+
+ - Some implementations of `lex' allow a rule's action to begin on a
+ separate line, if the rule's pattern has trailing whitespace:
+
+ %%
+ foo|bar<space here>
+ { foobar_action(); }
+
+ `flex' does not support this feature.
+
+ - The `lex' `%r' (generate a Ratfor scanner) option is not
+ supported. It is not part of the POSIX specification.
+
+ - After a call to `unput()', `yytext' is undefined until the next
+ token is matched, unless the scanner was built using `%array'.
+ This is not the case with `lex' or the POSIX specification. The
+ `-l' option does away with this incompatibility.
+
+ - The precedence of the `{}' (numeric range) operator is different.
+ `lex' interprets "abc{1,3}" as "match one, two, or three
+ occurrences of 'abc'", whereas `flex' interprets it as "match 'ab'
+ followed by one, two, or three occurrences of 'c'". The latter is
+ in agreement with the POSIX specification.
+
+ - The precedence of the `^' operator is different. `lex' interprets
+ "^foo|bar" as "match either 'foo' at the beginning of a line, or
+ 'bar' anywhere", whereas `flex' interprets it as "match either
+ 'foo' or 'bar' if they come at the beginning of a line". The
+ latter is in agreement with the POSIX specification.
+
+ - The special table-size declarations such as `%a' supported by
+ `lex' are not required by `flex' scanners; `flex' ignores them.
+
+ - The name FLEX_SCANNER is #define'd so scanners may be written for
+ use with either `flex' or `lex'. Scanners also include
+ `YY_FLEX_MAJOR_VERSION' and `YY_FLEX_MINOR_VERSION' indicating
+ which version of `flex' generated the scanner (for example, for the
+ 2.5 release, these defines would be 2 and 5 respectively).
+
+ The following `flex' features are not included in `lex' or the POSIX
+specification:
+
+ C++ scanners
+ %option
+ start condition scopes
+ start condition stacks
+ interactive/non-interactive scanners
+ yy_scan_string() and friends
+ yyterminate()
+ yy_set_interactive()
+ yy_set_bol()
+ YY_AT_BOL()
+ <<EOF>>
+ <*>
+ YY_DECL
+ YY_START
+ YY_USER_ACTION
+ YY_USER_INIT
+ #line directives
+ %{}'s around actions
+ multiple actions on a line
+
+plus almost all of the flex flags. The last feature in the list refers
+to the fact that with `flex' you can put multiple actions on the same
+line, separated with semicolons, while with `lex', the following
+
+ foo handle_foo(); ++num_foos_seen;
+
+is (rather surprisingly) truncated to
+
+ foo handle_foo();
+
+ `flex' does not truncate the action. Actions that are not enclosed
+in braces are simply terminated at the end of the line.
+
+
+File: flex.info, Node: Diagnostics, Next: Files, Prev: Incompatibilities, Up: Top
+
+Diagnostics
+===========
+
+`warning, rule cannot be matched'
+ indicates that the given rule cannot be matched because it follows
+ other rules that will always match the same text as it. For
+ example, in the following "foo" cannot be matched because it comes
+ after an identifier "catch-all" rule:
+
+ [a-z]+ got_identifier();
+ foo got_foo();
+
+ Using `REJECT' in a scanner suppresses this warning.
+
+`warning, -s option given but default rule can be matched'
+ means that it is possible (perhaps only in a particular start
+ condition) that the default rule (match any single character) is
+ the only one that will match a particular input. Since `-s' was
+ given, presumably this is not intended.
+
+`reject_used_but_not_detected undefined'
+`yymore_used_but_not_detected undefined'
+ These errors can occur at compile time. They indicate that the
+ scanner uses `REJECT' or `yymore()' but that `flex' failed to
+ notice the fact, meaning that `flex' scanned the first two sections
+ looking for occurrences of these actions and failed to find any,
+ but somehow you snuck some in (via a #include file, for example).
+ Use `%option reject' or `%option yymore' to indicate to flex that
+ you really do use these features.
+
+`flex scanner jammed'
+ a scanner compiled with `-s' has encountered an input string which
+ wasn't matched by any of its rules. This error can also occur due
+ to internal problems.
+
+`token too large, exceeds YYLMAX'
+ your scanner uses `%array' and one of its rules matched a string
+ longer than the `YYL-' `MAX' constant (8K bytes by default). You
+ can increase the value by #define'ing `YYLMAX' in the definitions
+ section of your `flex' input.
+
+`scanner requires -8 flag to use the character 'X''
+ Your scanner specification includes recognizing the 8-bit
+ character X and you did not specify the -8 flag, and your scanner
+ defaulted to 7-bit because you used the `-Cf' or `-CF' table
+ compression options. See the discussion of the `-7' flag for
+ details.
+
+`flex scanner push-back overflow'
+ you used `unput()' to push back so much text that the scanner's
+ buffer could not hold both the pushed-back text and the current
+ token in `yytext'. Ideally the scanner should dynamically resize
+ the buffer in this case, but at present it does not.
+
+`input buffer overflow, can't enlarge buffer because scanner uses REJECT'
+ the scanner was working on matching an extremely large token and
+ needed to expand the input buffer. This doesn't work with
+ scanners that use `REJECT'.
+
+`fatal flex scanner internal error--end of buffer missed'
+ This can occur in an scanner which is reentered after a long-jump
+ has jumped out (or over) the scanner's activation frame. Before
+ reentering the scanner, use:
+
+ yyrestart( yyin );
+
+ or, as noted above, switch to using the C++ scanner class.
+
+`too many start conditions in <> construct!'
+ you listed more start conditions in a <> construct than exist (so
+ you must have listed at least one of them twice).
+
+
+File: flex.info, Node: Files, Next: Deficiencies, Prev: Diagnostics, Up: Top
+
+Files
+=====
+
+`-lfl'
+ library with which scanners must be linked.
+
+`lex.yy.c'
+ generated scanner (called `lexyy.c' on some systems).
+
+`lex.yy.cc'
+ generated C++ scanner class, when using `-+'.
+
+`<FlexLexer.h>'
+ header file defining the C++ scanner base class, `FlexLexer', and
+ its derived class, `yyFlexLexer'.
+
+`flex.skl'
+ skeleton scanner. This file is only used when building flex, not
+ when flex executes.
+
+`lex.backup'
+ backing-up information for `-b' flag (called `lex.bck' on some
+ systems).
+
+
+File: flex.info, Node: Deficiencies, Next: See also, Prev: Files, Up: Top
+
+Deficiencies / Bugs
+===================
+
+ Some trailing context patterns cannot be properly matched and
+generate warning messages ("dangerous trailing context"). These are
+patterns where the ending of the first part of the rule matches the
+beginning of the second part, such as "zx*/xy*", where the 'x*' matches
+the 'x' at the beginning of the trailing context. (Note that the POSIX
+draft states that the text matched by such patterns is undefined.)
+
+ For some trailing context rules, parts which are actually
+fixed-length are not recognized as such, leading to the abovementioned
+performance loss. In particular, parts using '|' or {n} (such as
+"foo{3}") are always considered variable-length.
+
+ Combining trailing context with the special '|' action can result in
+*fixed* trailing context being turned into the more expensive VARIABLE
+trailing context. For example, in the following:
+
+ %%
+ abc |
+ xyz/def
+
+ Use of `unput()' invalidates yytext and yyleng, unless the `%array'
+directive or the `-l' option has been used.
+
+ Pattern-matching of NUL's is substantially slower than matching
+other characters.
+
+ Dynamic resizing of the input buffer is slow, as it entails
+rescanning all the text matched so far by the current (generally huge)
+token.
+
+ Due to both buffering of input and read-ahead, you cannot intermix
+calls to <stdio.h> routines, such as, for example, `getchar()', with
+`flex' rules and expect it to work. Call `input()' instead.
+
+ The total table entries listed by the `-v' flag excludes the number
+of table entries needed to determine what rule has been matched. The
+number of entries is equal to the number of DFA states if the scanner
+does not use `REJECT', and somewhat greater than the number of states
+if it does.
+
+ `REJECT' cannot be used with the `-f' or `-F' options.
+
+ The `flex' internal algorithms need documentation.
+
+
+File: flex.info, Node: See also, Next: Author, Prev: Deficiencies, Up: Top
+
+See also
+========
+
+ `lex'(1), `yacc'(1), `sed'(1), `awk'(1).
+
+ John Levine, Tony Mason, and Doug Brown: Lex & Yacc; O'Reilly and
+Associates. Be sure to get the 2nd edition.
+
+ M. E. Lesk and E. Schmidt, LEX - Lexical Analyzer Generator.
+
+ Alfred Aho, Ravi Sethi and Jeffrey Ullman: Compilers: Principles,
+Techniques and Tools; Addison-Wesley (1986). Describes the
+pattern-matching techniques used by `flex' (deterministic finite
+automata).
+
+
+File: flex.info, Node: Author, Prev: See also, Up: Top
+
+Author
+======
+
+ Vern Paxson, with the help of many ideas and much inspiration from
+Van Jacobson. Original version by Jef Poskanzer. The fast table
+representation is a partial implementation of a design done by Van
+Jacobson. The implementation was done by Kevin Gong and Vern Paxson.
+
+ Thanks to the many `flex' beta-testers, feedbackers, and
+contributors, especially Francois Pinard, Casey Leedom, Stan Adermann,
+Terry Allen, David Barker-Plummer, John Basrai, Nelson H.F. Beebe,
+`benson@odi.com', Karl Berry, Peter A. Bigot, Simon Blanchard, Keith
+Bostic, Frederic Brehm, Ian Brockbank, Kin Cho, Nick Christopher, Brian
+Clapper, J.T. Conklin, Jason Coughlin, Bill Cox, Nick Cropper, Dave
+Curtis, Scott David Daniels, Chris G. Demetriou, Theo Deraadt, Mike
+Donahue, Chuck Doucette, Tom Epperly, Leo Eskin, Chris Faylor, Chris
+Flatters, Jon Forrest, Joe Gayda, Kaveh R. Ghazi, Eric Goldman,
+Christopher M. Gould, Ulrich Grepel, Peer Griebel, Jan Hajic, Charles
+Hemphill, NORO Hideo, Jarkko Hietaniemi, Scott Hofmann, Jeff Honig,
+Dana Hudes, Eric Hughes, John Interrante, Ceriel Jacobs, Michal
+Jaegermann, Sakari Jalovaara, Jeffrey R. Jones, Henry Juengst, Klaus
+Kaempf, Jonathan I. Kamens, Terrence O Kane, Amir Katz,
+`ken@ken.hilco.com', Kevin B. Kenny, Steve Kirsch, Winfried Koenig,
+Marq Kole, Ronald Lamprecht, Greg Lee, Rohan Lenard, Craig Leres, John
+Levine, Steve Liddle, Mike Long, Mohamed el Lozy, Brian Madsen, Malte,
+Joe Marshall, Bengt Martensson, Chris Metcalf, Luke Mewburn, Jim
+Meyering, R. Alexander Milowski, Erik Naggum, G.T. Nicol, Landon Noll,
+James Nordby, Marc Nozell, Richard Ohnemus, Karsten Pahnke, Sven Panne,
+Roland Pesch, Walter Pelissero, Gaumond Pierre, Esmond Pitt, Jef
+Poskanzer, Joe Rahmeh, Jarmo Raiha, Frederic Raimbault, Pat Rankin,
+Rick Richardson, Kevin Rodgers, Kai Uwe Rommel, Jim Roskind, Alberto
+Santini, Andreas Scherer, Darrell Schiebel, Raf Schietekat, Doug
+Schmidt, Philippe Schnoebelen, Andreas Schwab, Alex Siegel, Eckehard
+Stolz, Jan-Erik Strvmquist, Mike Stump, Paul Stuart, Dave Tallman, Ian
+Lance Taylor, Chris Thewalt, Richard M. Timoney, Jodi Tsai, Paul
+Tuinenga, Gary Weik, Frank Whaley, Gerhard Wilhelms, Kent Williams, Ken
+Yap, Ron Zellar, Nathan Zelle, David Zuhn, and those whose names have
+slipped my marginal mail-archiving skills but whose contributions are
+appreciated all the same.
+
+ Thanks to Keith Bostic, Jon Forrest, Noah Friedman, John Gilmore,
+Craig Leres, John Levine, Bob Mulcahy, G.T. Nicol, Francois Pinard,
+Rich Salz, and Richard Stallman for help with various distribution
+headaches.
+
+ Thanks to Esmond Pitt and Earle Horton for 8-bit character support;
+to Benson Margulies and Fred Burke for C++ support; to Kent Williams
+and Tom Epperly for C++ class support; to Ove Ewerlid for support of
+NUL's; and to Eric Hughes for support of multiple buffers.
+
+ This work was primarily done when I was with the Real Time Systems
+Group at the Lawrence Berkeley Laboratory in Berkeley, CA. Many thanks
+to all there for the support I received.
+
+ Send comments to `vern@ee.lbl.gov'.
+
+
+
+Tag Table:
+Node: Top1430
+Node: Name2808
+Node: Synopsis2933
+Node: Overview3145
+Node: Description4986
+Node: Examples5748
+Node: Format8896
+Node: Patterns11637
+Node: Matching18138
+Node: Actions21438
+Node: Generated scanner30560
+Node: Start conditions34988
+Node: Multiple buffers45069
+Node: End-of-file rules50975
+Node: Miscellaneous52508
+Node: User variables55279
+Node: YACC interface57651
+Node: Options58542
+Node: Performance78234
+Node: C++87532
+Node: Incompatibilities94993
+Node: Diagnostics101853
+Node: Files105094
+Node: Deficiencies105715
+Node: See also107684
+Node: Author108216
+
+End Tag Table
diff --git a/Tools/android/flex-2.5.4a/MISC/texinfo/flex.texi b/Tools/android/flex-2.5.4a/MISC/texinfo/flex.texi
new file mode 100644
index 0000000..23280b1
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/MISC/texinfo/flex.texi
@@ -0,0 +1,3448 @@
+\input texinfo
+@c %**start of header
+@setfilename flex.info
+@settitle Flex - a scanner generator
+@c @finalout
+@c @setchapternewpage odd
+@c %**end of header
+
+@set EDITION 2.5
+@set UPDATED March 1995
+@set VERSION 2.5
+
+@c FIXME - Reread a printed copy with a red pen and patience.
+@c FIXME - Modify all "See ..." references and replace with @xref's.
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* Flex: (flex). A fast scanner generator.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@c Define new indices for commands, filenames, and options.
+@c @defcodeindex cm
+@c @defcodeindex fl
+@c @defcodeindex op
+
+@c Put everything in one index (arbitrarily chosen to be the concept index).
+@c @syncodeindex cm cp
+@c @syncodeindex fl cp
+@syncodeindex fn cp
+@syncodeindex ky cp
+@c @syncodeindex op cp
+@syncodeindex pg cp
+@syncodeindex vr cp
+
+@ifinfo
+This file documents Flex.
+
+Copyright (c) 1990 The Regents of the University of California.
+All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Vern Paxson.
+
+The United States Government has rights in this work pursuant
+to contract no. DE-AC03-76SF00098 between the United States
+Department of Energy and the University of California.
+
+Redistribution and use in source and binary forms with or without
+modification are permitted provided that: (1) source distributions
+retain this entire copyright notice and comment, and (2)
+distributions including binaries display the following
+acknowledgement: ``This product includes software developed by the
+University of California, Berkeley and its contributors'' in the
+documentation or other materials provided with the distribution and
+in all advertising materials mentioning features or use of this
+software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries copying permission
+notice identical to this one except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+
+@end ignore
+@end ifinfo
+
+@titlepage
+@title Flex, version @value{VERSION}
+@subtitle A fast scanner generator
+@subtitle Edition @value{EDITION}, @value{UPDATED}
+@author Vern Paxson
+
+@page
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1990 The Regents of the University of California.
+All rights reserved.
+
+This code is derived from software contributed to Berkeley by
+Vern Paxson.
+
+The United States Government has rights in this work pursuant
+to contract no. DE-AC03-76SF00098 between the United States
+Department of Energy and the University of California.
+
+Redistribution and use in source and binary forms with or without
+modification are permitted provided that: (1) source distributions
+retain this entire copyright notice and comment, and (2)
+distributions including binaries display the following
+acknowledgement: ``This product includes software developed by the
+University of California, Berkeley and its contributors'' in the
+documentation or other materials provided with the distribution and
+in all advertising materials mentioning features or use of this
+software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.
+@end titlepage
+
+@ifinfo
+
+@node Top, Name, (dir), (dir)
+@top flex
+
+@cindex scanner generator
+
+This manual documents @code{flex}. It covers release @value{VERSION}.
+
+@menu
+* Name:: Name
+* Synopsis:: Synopsis
+* Overview:: Overview
+* Description:: Description
+* Examples:: Some simple examples
+* Format:: Format of the input file
+* Patterns:: Patterns
+* Matching:: How the input is matched
+* Actions:: Actions
+* Generated scanner:: The generated scanner
+* Start conditions:: Start conditions
+* Multiple buffers:: Multiple input buffers
+* End-of-file rules:: End-of-file rules
+* Miscellaneous:: Miscellaneous macros
+* User variables:: Values available to the user
+* YACC interface:: Interfacing with @code{yacc}
+* Options:: Options
+* Performance:: Performance considerations
+* C++:: Generating C++ scanners
+* Incompatibilities:: Incompatibilities with @code{lex} and POSIX
+* Diagnostics:: Diagnostics
+* Files:: Files
+* Deficiencies:: Deficiencies / Bugs
+* See also:: See also
+* Author:: Author
+@c * Index:: Index
+@end menu
+
+@end ifinfo
+
+@node Name, Synopsis, Top, Top
+@section Name
+
+flex - fast lexical analyzer generator
+
+@node Synopsis, Overview, Name, Top
+@section Synopsis
+
+@example
+flex [-bcdfhilnpstvwBFILTV78+? -C[aefFmr] -ooutput -Pprefix -Sskeleton]
+[--help --version] [@var{filename} @dots{}]
+@end example
+
+@node Overview, Description, Synopsis, Top
+@section Overview
+
+This manual describes @code{flex}, a tool for generating programs
+that perform pattern-matching on text. The manual
+includes both tutorial and reference sections:
+
+@table @asis
+@item Description
+a brief overview of the tool
+
+@item Some Simple Examples
+
+@item Format Of The Input File
+
+@item Patterns
+the extended regular expressions used by flex
+
+@item How The Input Is Matched
+the rules for determining what has been matched
+
+@item Actions
+how to specify what to do when a pattern is matched
+
+@item The Generated Scanner
+details regarding the scanner that flex produces;
+how to control the input source
+
+@item Start Conditions
+introducing context into your scanners, and
+managing "mini-scanners"
+
+@item Multiple Input Buffers
+how to manipulate multiple input sources; how to
+scan from strings instead of files
+
+@item End-of-file Rules
+special rules for matching the end of the input
+
+@item Miscellaneous Macros
+a summary of macros available to the actions
+
+@item Values Available To The User
+a summary of values available to the actions
+
+@item Interfacing With Yacc
+connecting flex scanners together with yacc parsers
+
+@item Options
+flex command-line options, and the "%option"
+directive
+
+@item Performance Considerations
+how to make your scanner go as fast as possible
+
+@item Generating C++ Scanners
+the (experimental) facility for generating C++
+scanner classes
+
+@item Incompatibilities With Lex And POSIX
+how flex differs from AT&T lex and the POSIX lex
+standard
+
+@item Diagnostics
+those error messages produced by flex (or scanners
+it generates) whose meanings might not be apparent
+
+@item Files
+files used by flex
+
+@item Deficiencies / Bugs
+known problems with flex
+
+@item See Also
+other documentation, related tools
+
+@item Author
+includes contact information
+@end table
+
+@node Description, Examples, Overview, Top
+@section Description
+
+@code{flex} is a tool for generating @dfn{scanners}: programs which
+recognized lexical patterns in text. @code{flex} reads the given
+input files, or its standard input if no file names are
+given, for a description of a scanner to generate. The
+description is in the form of pairs of regular expressions
+and C code, called @dfn{rules}. @code{flex} generates as output a C
+source file, @file{lex.yy.c}, which defines a routine @samp{yylex()}.
+This file is compiled and linked with the @samp{-lfl} library to
+produce an executable. When the executable is run, it
+analyzes its input for occurrences of the regular
+expressions. Whenever it finds one, it executes the
+corresponding C code.
+
+@node Examples, Format, Description, Top
+@section Some simple examples
+
+First some simple examples to get the flavor of how one
+uses @code{flex}. The following @code{flex} input specifies a scanner
+which whenever it encounters the string "username" will
+replace it with the user's login name:
+
+@example
+%%
+username printf( "%s", getlogin() );
+@end example
+
+By default, any text not matched by a @code{flex} scanner is
+copied to the output, so the net effect of this scanner is
+to copy its input file to its output with each occurrence
+of "username" expanded. In this input, there is just one
+rule. "username" is the @var{pattern} and the "printf" is the
+@var{action}. The "%%" marks the beginning of the rules.
+
+Here's another simple example:
+
+@example
+ int num_lines = 0, num_chars = 0;
+
+%%
+\n ++num_lines; ++num_chars;
+. ++num_chars;
+
+%%
+main()
+ @{
+ yylex();
+ printf( "# of lines = %d, # of chars = %d\n",
+ num_lines, num_chars );
+ @}
+@end example
+
+This scanner counts the number of characters and the
+number of lines in its input (it produces no output other
+than the final report on the counts). The first line
+declares two globals, "num_lines" and "num_chars", which
+are accessible both inside @samp{yylex()} and in the @samp{main()}
+routine declared after the second "%%". There are two rules,
+one which matches a newline ("\n") and increments both the
+line count and the character count, and one which matches
+any character other than a newline (indicated by the "."
+regular expression).
+
+A somewhat more complicated example:
+
+@example
+/* scanner for a toy Pascal-like language */
+
+%@{
+/* need this for the call to atof() below */
+#include <math.h>
+%@}
+
+DIGIT [0-9]
+ID [a-z][a-z0-9]*
+
+%%
+
+@{DIGIT@}+ @{
+ printf( "An integer: %s (%d)\n", yytext,
+ atoi( yytext ) );
+ @}
+
+@{DIGIT@}+"."@{DIGIT@}* @{
+ printf( "A float: %s (%g)\n", yytext,
+ atof( yytext ) );
+ @}
+
+if|then|begin|end|procedure|function @{
+ printf( "A keyword: %s\n", yytext );
+ @}
+
+@{ID@} printf( "An identifier: %s\n", yytext );
+
+"+"|"-"|"*"|"/" printf( "An operator: %s\n", yytext );
+
+"@{"[^@}\n]*"@}" /* eat up one-line comments */
+
+[ \t\n]+ /* eat up whitespace */
+
+. printf( "Unrecognized character: %s\n", yytext );
+
+%%
+
+main( argc, argv )
+int argc;
+char **argv;
+ @{
+ ++argv, --argc; /* skip over program name */
+ if ( argc > 0 )
+ yyin = fopen( argv[0], "r" );
+ else
+ yyin = stdin;
+
+ yylex();
+ @}
+@end example
+
+This is the beginnings of a simple scanner for a language
+like Pascal. It identifies different types of @var{tokens} and
+reports on what it has seen.
+
+The details of this example will be explained in the
+following sections.
+
+@node Format, Patterns, Examples, Top
+@section Format of the input file
+
+The @code{flex} input file consists of three sections, separated
+by a line with just @samp{%%} in it:
+
+@example
+definitions
+%%
+rules
+%%
+user code
+@end example
+
+The @dfn{definitions} section contains declarations of simple
+@dfn{name} definitions to simplify the scanner specification,
+and declarations of @dfn{start conditions}, which are explained
+in a later section.
+Name definitions have the form:
+
+@example
+name definition
+@end example
+
+The "name" is a word beginning with a letter or an
+underscore ('_') followed by zero or more letters, digits, '_',
+or '-' (dash). The definition is taken to begin at the
+first non-white-space character following the name and
+continuing to the end of the line. The definition can
+subsequently be referred to using "@{name@}", which will
+expand to "(definition)". For example,
+
+@example
+DIGIT [0-9]
+ID [a-z][a-z0-9]*
+@end example
+
+@noindent
+defines "DIGIT" to be a regular expression which matches a
+single digit, and "ID" to be a regular expression which
+matches a letter followed by zero-or-more
+letters-or-digits. A subsequent reference to
+
+@example
+@{DIGIT@}+"."@{DIGIT@}*
+@end example
+
+@noindent
+is identical to
+
+@example
+([0-9])+"."([0-9])*
+@end example
+
+@noindent
+and matches one-or-more digits followed by a '.' followed
+by zero-or-more digits.
+
+The @var{rules} section of the @code{flex} input contains a series of
+rules of the form:
+
+@example
+pattern action
+@end example
+
+@noindent
+where the pattern must be unindented and the action must
+begin on the same line.
+
+See below for a further description of patterns and
+actions.
+
+Finally, the user code section is simply copied to
+@file{lex.yy.c} verbatim. It is used for companion routines
+which call or are called by the scanner. The presence of
+this section is optional; if it is missing, the second @samp{%%}
+in the input file may be skipped, too.
+
+In the definitions and rules sections, any @emph{indented} text or
+text enclosed in @samp{%@{} and @samp{%@}} is copied verbatim to the
+output (with the @samp{%@{@}}'s removed). The @samp{%@{@}}'s must
+appear unindented on lines by themselves.
+
+In the rules section, any indented or %@{@} text appearing
+before the first rule may be used to declare variables
+which are local to the scanning routine and (after the
+declarations) code which is to be executed whenever the
+scanning routine is entered. Other indented or %@{@} text
+in the rule section is still copied to the output, but its
+meaning is not well-defined and it may well cause
+compile-time errors (this feature is present for @code{POSIX} compliance;
+see below for other such features).
+
+In the definitions section (but not in the rules section),
+an unindented comment (i.e., a line beginning with "/*")
+is also copied verbatim to the output up to the next "*/".
+
+@node Patterns, Matching, Format, Top
+@section Patterns
+
+The patterns in the input are written using an extended
+set of regular expressions. These are:
+
+@table @samp
+@item x
+match the character @samp{x}
+@item .
+any character (byte) except newline
+@item [xyz]
+a "character class"; in this case, the pattern
+matches either an @samp{x}, a @samp{y}, or a @samp{z}
+@item [abj-oZ]
+a "character class" with a range in it; matches
+an @samp{a}, a @samp{b}, any letter from @samp{j} through @samp{o},
+or a @samp{Z}
+@item [^A-Z]
+a "negated character class", i.e., any character
+but those in the class. In this case, any
+character EXCEPT an uppercase letter.
+@item [^A-Z\n]
+any character EXCEPT an uppercase letter or
+a newline
+@item @var{r}*
+zero or more @var{r}'s, where @var{r} is any regular expression
+@item @var{r}+
+one or more @var{r}'s
+@item @var{r}?
+zero or one @var{r}'s (that is, "an optional @var{r}")
+@item @var{r}@{2,5@}
+anywhere from two to five @var{r}'s
+@item @var{r}@{2,@}
+two or more @var{r}'s
+@item @var{r}@{4@}
+exactly 4 @var{r}'s
+@item @{@var{name}@}
+the expansion of the "@var{name}" definition
+(see above)
+@item "[xyz]\"foo"
+the literal string: @samp{[xyz]"foo}
+@item \@var{x}
+if @var{x} is an @samp{a}, @samp{b}, @samp{f}, @samp{n}, @samp{r}, @samp{t}, or @samp{v},
+then the ANSI-C interpretation of \@var{x}.
+Otherwise, a literal @samp{@var{x}} (used to escape
+operators such as @samp{*})
+@item \0
+a NUL character (ASCII code 0)
+@item \123
+the character with octal value 123
+@item \x2a
+the character with hexadecimal value @code{2a}
+@item (@var{r})
+match an @var{r}; parentheses are used to override
+precedence (see below)
+@item @var{r}@var{s}
+the regular expression @var{r} followed by the
+regular expression @var{s}; called "concatenation"
+@item @var{r}|@var{s}
+either an @var{r} or an @var{s}
+@item @var{r}/@var{s}
+an @var{r} but only if it is followed by an @var{s}. The text
+matched by @var{s} is included when determining whether this rule is
+the @dfn{longest match}, but is then returned to the input before
+the action is executed. So the action only sees the text matched
+by @var{r}. This type of pattern is called @dfn{trailing context}.
+(There are some combinations of @samp{@var{r}/@var{s}} that @code{flex}
+cannot match correctly; see notes in the Deficiencies / Bugs section
+below regarding "dangerous trailing context".)
+@item ^@var{r}
+an @var{r}, but only at the beginning of a line (i.e.,
+which just starting to scan, or right after a
+newline has been scanned).
+@item @var{r}$
+an @var{r}, but only at the end of a line (i.e., just
+before a newline). Equivalent to "@var{r}/\n".
+
+Note that flex's notion of "newline" is exactly
+whatever the C compiler used to compile flex
+interprets '\n' as; in particular, on some DOS
+systems you must either filter out \r's in the
+input yourself, or explicitly use @var{r}/\r\n for "r$".
+@item <@var{s}>@var{r}
+an @var{r}, but only in start condition @var{s} (see
+below for discussion of start conditions)
+<@var{s1},@var{s2},@var{s3}>@var{r}
+same, but in any of start conditions @var{s1},
+@var{s2}, or @var{s3}
+@item <*>@var{r}
+an @var{r} in any start condition, even an exclusive one.
+@item <<EOF>>
+an end-of-file
+<@var{s1},@var{s2}><<EOF>>
+an end-of-file when in start condition @var{s1} or @var{s2}
+@end table
+
+Note that inside of a character class, all regular
+expression operators lose their special meaning except escape
+('\') and the character class operators, '-', ']', and, at
+the beginning of the class, '^'.
+
+The regular expressions listed above are grouped according
+to precedence, from highest precedence at the top to
+lowest at the bottom. Those grouped together have equal
+precedence. For example,
+
+@example
+foo|bar*
+@end example
+
+@noindent
+is the same as
+
+@example
+(foo)|(ba(r*))
+@end example
+
+@noindent
+since the '*' operator has higher precedence than
+concatenation, and concatenation higher than alternation ('|').
+This pattern therefore matches @emph{either} the string "foo" @emph{or}
+the string "ba" followed by zero-or-more r's. To match
+"foo" or zero-or-more "bar"'s, use:
+
+@example
+foo|(bar)*
+@end example
+
+@noindent
+and to match zero-or-more "foo"'s-or-"bar"'s:
+
+@example
+(foo|bar)*
+@end example
+
+In addition to characters and ranges of characters,
+character classes can also contain character class
+@dfn{expressions}. These are expressions enclosed inside @samp{[}: and @samp{:}]
+delimiters (which themselves must appear between the '['
+and ']' of the character class; other elements may occur
+inside the character class, too). The valid expressions
+are:
+
+@example
+[:alnum:] [:alpha:] [:blank:]
+[:cntrl:] [:digit:] [:graph:]
+[:lower:] [:print:] [:punct:]
+[:space:] [:upper:] [:xdigit:]
+@end example
+
+These expressions all designate a set of characters
+equivalent to the corresponding standard C @samp{isXXX} function. For
+example, @samp{[:alnum:]} designates those characters for which
+@samp{isalnum()} returns true - i.e., any alphabetic or numeric.
+Some systems don't provide @samp{isblank()}, so flex defines
+@samp{[:blank:]} as a blank or a tab.
+
+For example, the following character classes are all
+equivalent:
+
+@example
+[[:alnum:]]
+[[:alpha:][:digit:]
+[[:alpha:]0-9]
+[a-zA-Z0-9]
+@end example
+
+If your scanner is case-insensitive (the @samp{-i} flag), then
+@samp{[:upper:]} and @samp{[:lower:]} are equivalent to @samp{[:alpha:]}.
+
+Some notes on patterns:
+
+@itemize -
+@item
+A negated character class such as the example
+"[^A-Z]" above @emph{will match a newline} unless "\n" (or an
+equivalent escape sequence) is one of the
+characters explicitly present in the negated character
+class (e.g., "[^A-Z\n]"). This is unlike how many
+other regular expression tools treat negated
+character classes, but unfortunately the inconsistency
+is historically entrenched. Matching newlines
+means that a pattern like [^"]* can match the
+entire input unless there's another quote in the
+input.
+
+@item
+A rule can have at most one instance of trailing
+context (the '/' operator or the '$' operator).
+The start condition, '^', and "<<EOF>>" patterns
+can only occur at the beginning of a pattern, and,
+as well as with '/' and '$', cannot be grouped
+inside parentheses. A '^' which does not occur at
+the beginning of a rule or a '$' which does not
+occur at the end of a rule loses its special
+properties and is treated as a normal character.
+
+The following are illegal:
+
+@example
+foo/bar$
+<sc1>foo<sc2>bar
+@end example
+
+Note that the first of these, can be written
+"foo/bar\n".
+
+The following will result in '$' or '^' being
+treated as a normal character:
+
+@example
+foo|(bar$)
+foo|^bar
+@end example
+
+If what's wanted is a "foo" or a
+bar-followed-by-a-newline, the following could be used (the special
+'|' action is explained below):
+
+@example
+foo |
+bar$ /* action goes here */
+@end example
+
+A similar trick will work for matching a foo or a
+bar-at-the-beginning-of-a-line.
+@end itemize
+
+@node Matching, Actions, Patterns, Top
+@section How the input is matched
+
+When the generated scanner is run, it analyzes its input
+looking for strings which match any of its patterns. If
+it finds more than one match, it takes the one matching
+the most text (for trailing context rules, this includes
+the length of the trailing part, even though it will then
+be returned to the input). If it finds two or more
+matches of the same length, the rule listed first in the
+@code{flex} input file is chosen.
+
+Once the match is determined, the text corresponding to
+the match (called the @var{token}) is made available in the
+global character pointer @code{yytext}, and its length in the
+global integer @code{yyleng}. The @var{action} corresponding to the
+matched pattern is then executed (a more detailed
+description of actions follows), and then the remaining input is
+scanned for another match.
+
+If no match is found, then the @dfn{default rule} is executed:
+the next character in the input is considered matched and
+copied to the standard output. Thus, the simplest legal
+@code{flex} input is:
+
+@example
+%%
+@end example
+
+which generates a scanner that simply copies its input
+(one character at a time) to its output.
+
+Note that @code{yytext} can be defined in two different ways:
+either as a character @emph{pointer} or as a character @emph{array}.
+You can control which definition @code{flex} uses by including
+one of the special directives @samp{%pointer} or @samp{%array} in the
+first (definitions) section of your flex input. The
+default is @samp{%pointer}, unless you use the @samp{-l} lex
+compatibility option, in which case @code{yytext} will be an array. The
+advantage of using @samp{%pointer} is substantially faster
+scanning and no buffer overflow when matching very large
+tokens (unless you run out of dynamic memory). The
+disadvantage is that you are restricted in how your actions can
+modify @code{yytext} (see the next section), and calls to the
+@samp{unput()} function destroys the present contents of @code{yytext},
+which can be a considerable porting headache when moving
+between different @code{lex} versions.
+
+The advantage of @samp{%array} is that you can then modify @code{yytext}
+to your heart's content, and calls to @samp{unput()} do not
+destroy @code{yytext} (see below). Furthermore, existing @code{lex}
+programs sometimes access @code{yytext} externally using
+declarations of the form:
+@example
+extern char yytext[];
+@end example
+This definition is erroneous when used with @samp{%pointer}, but
+correct for @samp{%array}.
+
+@samp{%array} defines @code{yytext} to be an array of @code{YYLMAX} characters,
+which defaults to a fairly large value. You can change
+the size by simply #define'ing @code{YYLMAX} to a different value
+in the first section of your @code{flex} input. As mentioned
+above, with @samp{%pointer} yytext grows dynamically to
+accommodate large tokens. While this means your @samp{%pointer} scanner
+can accommodate very large tokens (such as matching entire
+blocks of comments), bear in mind that each time the
+scanner must resize @code{yytext} it also must rescan the entire
+token from the beginning, so matching such tokens can
+prove slow. @code{yytext} presently does @emph{not} dynamically grow if
+a call to @samp{unput()} results in too much text being pushed
+back; instead, a run-time error results.
+
+Also note that you cannot use @samp{%array} with C++ scanner
+classes (the @code{c++} option; see below).
+
+@node Actions, Generated scanner, Matching, Top
+@section Actions
+
+Each pattern in a rule has a corresponding action, which
+can be any arbitrary C statement. The pattern ends at the
+first non-escaped whitespace character; the remainder of
+the line is its action. If the action is empty, then when
+the pattern is matched the input token is simply
+discarded. For example, here is the specification for a
+program which deletes all occurrences of "zap me" from its
+input:
+
+@example
+%%
+"zap me"
+@end example
+
+(It will copy all other characters in the input to the
+output since they will be matched by the default rule.)
+
+Here is a program which compresses multiple blanks and
+tabs down to a single blank, and throws away whitespace
+found at the end of a line:
+
+@example
+%%
+[ \t]+ putchar( ' ' );
+[ \t]+$ /* ignore this token */
+@end example
+
+If the action contains a '@{', then the action spans till
+the balancing '@}' is found, and the action may cross
+multiple lines. @code{flex} knows about C strings and comments and
+won't be fooled by braces found within them, but also
+allows actions to begin with @samp{%@{} and will consider the
+action to be all the text up to the next @samp{%@}} (regardless of
+ordinary braces inside the action).
+
+An action consisting solely of a vertical bar ('|') means
+"same as the action for the next rule." See below for an
+illustration.
+
+Actions can include arbitrary C code, including @code{return}
+statements to return a value to whatever routine called
+@samp{yylex()}. Each time @samp{yylex()} is called it continues
+processing tokens from where it last left off until it either
+reaches the end of the file or executes a return.
+
+Actions are free to modify @code{yytext} except for lengthening
+it (adding characters to its end--these will overwrite
+later characters in the input stream). This however does
+not apply when using @samp{%array} (see above); in that case,
+@code{yytext} may be freely modified in any way.
+
+Actions are free to modify @code{yyleng} except they should not
+do so if the action also includes use of @samp{yymore()} (see
+below).
+
+There are a number of special directives which can be
+included within an action:
+
+@itemize -
+@item
+@samp{ECHO} copies yytext to the scanner's output.
+
+@item
+@code{BEGIN} followed by the name of a start condition
+places the scanner in the corresponding start
+condition (see below).
+
+@item
+@code{REJECT} directs the scanner to proceed on to the
+"second best" rule which matched the input (or a
+prefix of the input). The rule is chosen as
+described above in "How the Input is Matched", and
+@code{yytext} and @code{yyleng} set up appropriately. It may
+either be one which matched as much text as the
+originally chosen rule but came later in the @code{flex}
+input file, or one which matched less text. For
+example, the following will both count the words in
+the input and call the routine special() whenever
+"frob" is seen:
+
+@example
+ int word_count = 0;
+%%
+
+frob special(); REJECT;
+[^ \t\n]+ ++word_count;
+@end example
+
+Without the @code{REJECT}, any "frob"'s in the input would
+not be counted as words, since the scanner normally
+executes only one action per token. Multiple
+@code{REJECT's} are allowed, each one finding the next
+best choice to the currently active rule. For
+example, when the following scanner scans the token
+"abcd", it will write "abcdabcaba" to the output:
+
+@example
+%%
+a |
+ab |
+abc |
+abcd ECHO; REJECT;
+.|\n /* eat up any unmatched character */
+@end example
+
+(The first three rules share the fourth's action
+since they use the special '|' action.) @code{REJECT} is
+a particularly expensive feature in terms of
+scanner performance; if it is used in @emph{any} of the
+scanner's actions it will slow down @emph{all} of the
+scanner's matching. Furthermore, @code{REJECT} cannot be used
+with the @samp{-Cf} or @samp{-CF} options (see below).
+
+Note also that unlike the other special actions,
+@code{REJECT} is a @emph{branch}; code immediately following it
+in the action will @emph{not} be executed.
+
+@item
+@samp{yymore()} tells the scanner that the next time it
+matches a rule, the corresponding token should be
+@emph{appended} onto the current value of @code{yytext} rather
+than replacing it. For example, given the input
+"mega-kludge" the following will write
+"mega-mega-kludge" to the output:
+
+@example
+%%
+mega- ECHO; yymore();
+kludge ECHO;
+@end example
+
+First "mega-" is matched and echoed to the output.
+Then "kludge" is matched, but the previous "mega-"
+is still hanging around at the beginning of @code{yytext}
+so the @samp{ECHO} for the "kludge" rule will actually
+write "mega-kludge".
+@end itemize
+
+Two notes regarding use of @samp{yymore()}. First, @samp{yymore()}
+depends on the value of @code{yyleng} correctly reflecting the
+size of the current token, so you must not modify @code{yyleng}
+if you are using @samp{yymore()}. Second, the presence of
+@samp{yymore()} in the scanner's action entails a minor
+performance penalty in the scanner's matching speed.
+
+@itemize -
+@item
+@samp{yyless(n)} returns all but the first @var{n} characters of
+the current token back to the input stream, where
+they will be rescanned when the scanner looks for
+the next match. @code{yytext} and @code{yyleng} are adjusted
+appropriately (e.g., @code{yyleng} will now be equal to @var{n}
+). For example, on the input "foobar" the
+following will write out "foobarbar":
+
+@example
+%%
+foobar ECHO; yyless(3);
+[a-z]+ ECHO;
+@end example
+
+An argument of 0 to @code{yyless} will cause the entire
+current input string to be scanned again. Unless
+you've changed how the scanner will subsequently
+process its input (using @code{BEGIN}, for example), this
+will result in an endless loop.
+
+Note that @code{yyless} is a macro and can only be used in the
+flex input file, not from other source files.
+
+@item
+@samp{unput(c)} puts the character @code{c} back onto the input
+stream. It will be the next character scanned.
+The following action will take the current token
+and cause it to be rescanned enclosed in
+parentheses.
+
+@example
+@{
+int i;
+/* Copy yytext because unput() trashes yytext */
+char *yycopy = strdup( yytext );
+unput( ')' );
+for ( i = yyleng - 1; i >= 0; --i )
+ unput( yycopy[i] );
+unput( '(' );
+free( yycopy );
+@}
+@end example
+
+Note that since each @samp{unput()} puts the given
+character back at the @emph{beginning} of the input stream,
+pushing back strings must be done back-to-front.
+An important potential problem when using @samp{unput()} is that
+if you are using @samp{%pointer} (the default), a call to @samp{unput()}
+@emph{destroys} the contents of @code{yytext}, starting with its
+rightmost character and devouring one character to the left
+with each call. If you need the value of yytext preserved
+after a call to @samp{unput()} (as in the above example), you
+must either first copy it elsewhere, or build your scanner
+using @samp{%array} instead (see How The Input Is Matched).
+
+Finally, note that you cannot put back @code{EOF} to attempt to
+mark the input stream with an end-of-file.
+
+@item
+@samp{input()} reads the next character from the input
+stream. For example, the following is one way to
+eat up C comments:
+
+@example
+%%
+"/*" @{
+ register int c;
+
+ for ( ; ; )
+ @{
+ while ( (c = input()) != '*' &&
+ c != EOF )
+ ; /* eat up text of comment */
+
+ if ( c == '*' )
+ @{
+ while ( (c = input()) == '*' )
+ ;
+ if ( c == '/' )
+ break; /* found the end */
+ @}
+
+ if ( c == EOF )
+ @{
+ error( "EOF in comment" );
+ break;
+ @}
+ @}
+ @}
+@end example
+
+(Note that if the scanner is compiled using @samp{C++},
+then @samp{input()} is instead referred to as @samp{yyinput()},
+in order to avoid a name clash with the @samp{C++} stream
+by the name of @code{input}.)
+
+@item YY_FLUSH_BUFFER
+flushes the scanner's internal buffer so that the next time the scanner
+attempts to match a token, it will first refill the buffer using
+@code{YY_INPUT} (see The Generated Scanner, below). This action is
+a special case of the more general @samp{yy_flush_buffer()} function,
+described below in the section Multiple Input Buffers.
+
+@item
+@samp{yyterminate()} can be used in lieu of a return
+statement in an action. It terminates the scanner
+and returns a 0 to the scanner's caller, indicating
+"all done". By default, @samp{yyterminate()} is also
+called when an end-of-file is encountered. It is a
+macro and may be redefined.
+@end itemize
+
+@node Generated scanner, Start conditions, Actions, Top
+@section The generated scanner
+
+The output of @code{flex} is the file @file{lex.yy.c}, which contains
+the scanning routine @samp{yylex()}, a number of tables used by
+it for matching tokens, and a number of auxiliary routines
+and macros. By default, @samp{yylex()} is declared as follows:
+
+@example
+int yylex()
+ @{
+ @dots{} various definitions and the actions in here @dots{}
+ @}
+@end example
+
+(If your environment supports function prototypes, then it
+will be "int yylex( void )".) This definition may be
+changed by defining the "YY_DECL" macro. For example, you
+could use:
+
+@example
+#define YY_DECL float lexscan( a, b ) float a, b;
+@end example
+
+to give the scanning routine the name @code{lexscan}, returning a
+float, and taking two floats as arguments. Note that if
+you give arguments to the scanning routine using a
+K&R-style/non-prototyped function declaration, you must
+terminate the definition with a semi-colon (@samp{;}).
+
+Whenever @samp{yylex()} is called, it scans tokens from the
+global input file @code{yyin} (which defaults to stdin). It
+continues until it either reaches an end-of-file (at which
+point it returns the value 0) or one of its actions
+executes a @code{return} statement.
+
+If the scanner reaches an end-of-file, subsequent calls are undefined
+unless either @code{yyin} is pointed at a new input file (in which case
+scanning continues from that file), or @samp{yyrestart()} is called.
+@samp{yyrestart()} takes one argument, a @samp{FILE *} pointer (which
+can be nil, if you've set up @code{YY_INPUT} to scan from a source
+other than @code{yyin}), and initializes @code{yyin} for scanning from
+that file. Essentially there is no difference between just assigning
+@code{yyin} to a new input file or using @samp{yyrestart()} to do so;
+the latter is available for compatibility with previous versions of
+@code{flex}, and because it can be used to switch input files in the
+middle of scanning. It can also be used to throw away the current
+input buffer, by calling it with an argument of @code{yyin}; but
+better is to use @code{YY_FLUSH_BUFFER} (see above). Note that
+@samp{yyrestart()} does @emph{not} reset the start condition to
+@code{INITIAL} (see Start Conditions, below).
+
+
+If @samp{yylex()} stops scanning due to executing a @code{return}
+statement in one of the actions, the scanner may then be called
+again and it will resume scanning where it left off.
+
+By default (and for purposes of efficiency), the scanner
+uses block-reads rather than simple @samp{getc()} calls to read
+characters from @code{yyin}. The nature of how it gets its input
+can be controlled by defining the @code{YY_INPUT} macro.
+YY_INPUT's calling sequence is
+"YY_INPUT(buf,result,max_size)". Its action is to place
+up to @var{max_size} characters in the character array @var{buf} and
+return in the integer variable @var{result} either the number of
+characters read or the constant YY_NULL (0 on Unix
+systems) to indicate EOF. The default YY_INPUT reads from
+the global file-pointer "yyin".
+
+A sample definition of YY_INPUT (in the definitions
+section of the input file):
+
+@example
+%@{
+#define YY_INPUT(buf,result,max_size) \
+ @{ \
+ int c = getchar(); \
+ result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \
+ @}
+%@}
+@end example
+
+This definition will change the input processing to occur
+one character at a time.
+
+When the scanner receives an end-of-file indication from
+YY_INPUT, it then checks the @samp{yywrap()} function. If
+@samp{yywrap()} returns false (zero), then it is assumed that the
+function has gone ahead and set up @code{yyin} to point to
+another input file, and scanning continues. If it returns
+true (non-zero), then the scanner terminates, returning 0
+to its caller. Note that in either case, the start
+condition remains unchanged; it does @emph{not} revert to @code{INITIAL}.
+
+If you do not supply your own version of @samp{yywrap()}, then you
+must either use @samp{%option noyywrap} (in which case the scanner
+behaves as though @samp{yywrap()} returned 1), or you must link with
+@samp{-lfl} to obtain the default version of the routine, which always
+returns 1.
+
+Three routines are available for scanning from in-memory
+buffers rather than files: @samp{yy_scan_string()},
+@samp{yy_scan_bytes()}, and @samp{yy_scan_buffer()}. See the discussion
+of them below in the section Multiple Input Buffers.
+
+The scanner writes its @samp{ECHO} output to the @code{yyout} global
+(default, stdout), which may be redefined by the user
+simply by assigning it to some other @code{FILE} pointer.
+
+@node Start conditions, Multiple buffers, Generated scanner, Top
+@section Start conditions
+
+@code{flex} provides a mechanism for conditionally activating
+rules. Any rule whose pattern is prefixed with "<sc>"
+will only be active when the scanner is in the start
+condition named "sc". For example,
+
+@example
+<STRING>[^"]* @{ /* eat up the string body ... */
+ @dots{}
+ @}
+@end example
+
+@noindent
+will be active only when the scanner is in the "STRING"
+start condition, and
+
+@example
+<INITIAL,STRING,QUOTE>\. @{ /* handle an escape ... */
+ @dots{}
+ @}
+@end example
+
+@noindent
+will be active only when the current start condition is
+either "INITIAL", "STRING", or "QUOTE".
+
+Start conditions are declared in the definitions (first)
+section of the input using unindented lines beginning with
+either @samp{%s} or @samp{%x} followed by a list of names. The former
+declares @emph{inclusive} start conditions, the latter @emph{exclusive}
+start conditions. A start condition is activated using
+the @code{BEGIN} action. Until the next @code{BEGIN} action is
+executed, rules with the given start condition will be active
+and rules with other start conditions will be inactive.
+If the start condition is @emph{inclusive}, then rules with no
+start conditions at all will also be active. If it is
+@emph{exclusive}, then @emph{only} rules qualified with the start
+condition will be active. A set of rules contingent on the
+same exclusive start condition describe a scanner which is
+independent of any of the other rules in the @code{flex} input.
+Because of this, exclusive start conditions make it easy
+to specify "mini-scanners" which scan portions of the
+input that are syntactically different from the rest
+(e.g., comments).
+
+If the distinction between inclusive and exclusive start
+conditions is still a little vague, here's a simple
+example illustrating the connection between the two. The set
+of rules:
+
+@example
+%s example
+%%
+
+<example>foo do_something();
+
+bar something_else();
+@end example
+
+@noindent
+is equivalent to
+
+@example
+%x example
+%%
+
+<example>foo do_something();
+
+<INITIAL,example>bar something_else();
+@end example
+
+Without the @samp{<INITIAL,example>} qualifier, the @samp{bar} pattern
+in the second example wouldn't be active (i.e., couldn't match) when
+in start condition @samp{example}. If we just used @samp{<example>}
+to qualify @samp{bar}, though, then it would only be active in
+@samp{example} and not in @code{INITIAL}, while in the first example
+it's active in both, because in the first example the @samp{example}
+starting condition is an @emph{inclusive} (@samp{%s}) start condition.
+
+Also note that the special start-condition specifier @samp{<*>}
+matches every start condition. Thus, the above example
+could also have been written;
+
+@example
+%x example
+%%
+
+<example>foo do_something();
+
+<*>bar something_else();
+@end example
+
+The default rule (to @samp{ECHO} any unmatched character) remains
+active in start conditions. It is equivalent to:
+
+@example
+<*>.|\\n ECHO;
+@end example
+
+@samp{BEGIN(0)} returns to the original state where only the
+rules with no start conditions are active. This state can
+also be referred to as the start-condition "INITIAL", so
+@samp{BEGIN(INITIAL)} is equivalent to @samp{BEGIN(0)}. (The
+parentheses around the start condition name are not required but
+are considered good style.)
+
+@code{BEGIN} actions can also be given as indented code at the
+beginning of the rules section. For example, the
+following will cause the scanner to enter the "SPECIAL" start
+condition whenever @samp{yylex()} is called and the global
+variable @code{enter_special} is true:
+
+@example
+ int enter_special;
+
+%x SPECIAL
+%%
+ if ( enter_special )
+ BEGIN(SPECIAL);
+
+<SPECIAL>blahblahblah
+@dots{}more rules follow@dots{}
+@end example
+
+To illustrate the uses of start conditions, here is a
+scanner which provides two different interpretations of a
+string like "123.456". By default it will treat it as as
+three tokens, the integer "123", a dot ('.'), and the
+integer "456". But if the string is preceded earlier in
+the line by the string "expect-floats" it will treat it as
+a single token, the floating-point number 123.456:
+
+@example
+%@{
+#include <math.h>
+%@}
+%s expect
+
+%%
+expect-floats BEGIN(expect);
+
+<expect>[0-9]+"."[0-9]+ @{
+ printf( "found a float, = %f\n",
+ atof( yytext ) );
+ @}
+<expect>\n @{
+ /* that's the end of the line, so
+ * we need another "expect-number"
+ * before we'll recognize any more
+ * numbers
+ */
+ BEGIN(INITIAL);
+ @}
+
+[0-9]+ @{
+
+Version 2.5 December 1994 18
+
+ printf( "found an integer, = %d\n",
+ atoi( yytext ) );
+ @}
+
+"." printf( "found a dot\n" );
+@end example
+
+Here is a scanner which recognizes (and discards) C
+comments while maintaining a count of the current input line.
+
+@example
+%x comment
+%%
+ int line_num = 1;
+
+"/*" BEGIN(comment);
+
+<comment>[^*\n]* /* eat anything that's not a '*' */
+<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+<comment>\n ++line_num;
+<comment>"*"+"/" BEGIN(INITIAL);
+@end example
+
+This scanner goes to a bit of trouble to match as much
+text as possible with each rule. In general, when
+attempting to write a high-speed scanner try to match as
+much possible in each rule, as it's a big win.
+
+Note that start-conditions names are really integer values
+and can be stored as such. Thus, the above could be
+extended in the following fashion:
+
+@example
+%x comment foo
+%%
+ int line_num = 1;
+ int comment_caller;
+
+"/*" @{
+ comment_caller = INITIAL;
+ BEGIN(comment);
+ @}
+
+@dots{}
+
+<foo>"/*" @{
+ comment_caller = foo;
+ BEGIN(comment);
+ @}
+
+<comment>[^*\n]* /* eat anything that's not a '*' */
+<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+<comment>\n ++line_num;
+<comment>"*"+"/" BEGIN(comment_caller);
+@end example
+
+Furthermore, you can access the current start condition
+using the integer-valued @code{YY_START} macro. For example, the
+above assignments to @code{comment_caller} could instead be
+written
+
+@example
+comment_caller = YY_START;
+@end example
+
+Flex provides @code{YYSTATE} as an alias for @code{YY_START} (since that
+is what's used by AT&T @code{lex}).
+
+Note that start conditions do not have their own
+name-space; %s's and %x's declare names in the same fashion as
+#define's.
+
+Finally, here's an example of how to match C-style quoted
+strings using exclusive start conditions, including
+expanded escape sequences (but not including checking for
+a string that's too long):
+
+@example
+%x str
+
+%%
+ char string_buf[MAX_STR_CONST];
+ char *string_buf_ptr;
+
+\" string_buf_ptr = string_buf; BEGIN(str);
+
+<str>\" @{ /* saw closing quote - all done */
+ BEGIN(INITIAL);
+ *string_buf_ptr = '\0';
+ /* return string constant token type and
+ * value to parser
+ */
+ @}
+
+<str>\n @{
+ /* error - unterminated string constant */
+ /* generate error message */
+ @}
+
+<str>\\[0-7]@{1,3@} @{
+ /* octal escape sequence */
+ int result;
+
+ (void) sscanf( yytext + 1, "%o", &result );
+
+ if ( result > 0xff )
+ /* error, constant is out-of-bounds */
+
+ *string_buf_ptr++ = result;
+ @}
+
+<str>\\[0-9]+ @{
+ /* generate error - bad escape sequence; something
+ * like '\48' or '\0777777'
+ */
+ @}
+
+<str>\\n *string_buf_ptr++ = '\n';
+<str>\\t *string_buf_ptr++ = '\t';
+<str>\\r *string_buf_ptr++ = '\r';
+<str>\\b *string_buf_ptr++ = '\b';
+<str>\\f *string_buf_ptr++ = '\f';
+
+<str>\\(.|\n) *string_buf_ptr++ = yytext[1];
+
+<str>[^\\\n\"]+ @{
+ char *yptr = yytext;
+
+ while ( *yptr )
+ *string_buf_ptr++ = *yptr++;
+ @}
+@end example
+
+Often, such as in some of the examples above, you wind up
+writing a whole bunch of rules all preceded by the same
+start condition(s). Flex makes this a little easier and
+cleaner by introducing a notion of start condition @dfn{scope}.
+A start condition scope is begun with:
+
+@example
+<SCs>@{
+@end example
+
+@noindent
+where SCs is a list of one or more start conditions.
+Inside the start condition scope, every rule automatically
+has the prefix @samp{<SCs>} applied to it, until a @samp{@}} which
+matches the initial @samp{@{}. So, for example,
+
+@example
+<ESC>@{
+ "\\n" return '\n';
+ "\\r" return '\r';
+ "\\f" return '\f';
+ "\\0" return '\0';
+@}
+@end example
+
+@noindent
+is equivalent to:
+
+@example
+<ESC>"\\n" return '\n';
+<ESC>"\\r" return '\r';
+<ESC>"\\f" return '\f';
+<ESC>"\\0" return '\0';
+@end example
+
+Start condition scopes may be nested.
+
+Three routines are available for manipulating stacks of
+start conditions:
+
+@table @samp
+@item void yy_push_state(int new_state)
+pushes the current start condition onto the top of
+the start condition stack and switches to @var{new_state}
+as though you had used @samp{BEGIN new_state} (recall that
+start condition names are also integers).
+
+@item void yy_pop_state()
+pops the top of the stack and switches to it via
+@code{BEGIN}.
+
+@item int yy_top_state()
+returns the top of the stack without altering the
+stack's contents.
+@end table
+
+The start condition stack grows dynamically and so has no
+built-in size limitation. If memory is exhausted, program
+execution aborts.
+
+To use start condition stacks, your scanner must include a
+@samp{%option stack} directive (see Options below).
+
+@node Multiple buffers, End-of-file rules, Start conditions, Top
+@section Multiple input buffers
+
+Some scanners (such as those which support "include"
+files) require reading from several input streams. As
+@code{flex} scanners do a large amount of buffering, one cannot
+control where the next input will be read from by simply
+writing a @code{YY_INPUT} which is sensitive to the scanning
+context. @code{YY_INPUT} is only called when the scanner reaches
+the end of its buffer, which may be a long time after
+scanning a statement such as an "include" which requires
+switching the input source.
+
+To negotiate these sorts of problems, @code{flex} provides a
+mechanism for creating and switching between multiple
+input buffers. An input buffer is created by using:
+
+@example
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+@end example
+
+@noindent
+which takes a @code{FILE} pointer and a size and creates a buffer
+associated with the given file and large enough to hold
+@var{size} characters (when in doubt, use @code{YY_BUF_SIZE} for the
+size). It returns a @code{YY_BUFFER_STATE} handle, which may
+then be passed to other routines (see below). The
+@code{YY_BUFFER_STATE} type is a pointer to an opaque @code{struct}
+@code{yy_buffer_state} structure, so you may safely initialize
+YY_BUFFER_STATE variables to @samp{((YY_BUFFER_STATE) 0)} if you
+wish, and also refer to the opaque structure in order to
+correctly declare input buffers in source files other than
+that of your scanner. Note that the @code{FILE} pointer in the
+call to @code{yy_create_buffer} is only used as the value of @code{yyin}
+seen by @code{YY_INPUT}; if you redefine @code{YY_INPUT} so it no longer
+uses @code{yyin}, then you can safely pass a nil @code{FILE} pointer to
+@code{yy_create_buffer}. You select a particular buffer to scan
+from using:
+
+@example
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+@end example
+
+switches the scanner's input buffer so subsequent tokens
+will come from @var{new_buffer}. Note that
+@samp{yy_switch_to_buffer()} may be used by @samp{yywrap()} to set
+things up for continued scanning, instead of opening a new
+file and pointing @code{yyin} at it. Note also that switching
+input sources via either @samp{yy_switch_to_buffer()} or @samp{yywrap()}
+does @emph{not} change the start condition.
+
+@example
+void yy_delete_buffer( YY_BUFFER_STATE buffer )
+@end example
+
+@noindent
+is used to reclaim the storage associated with a buffer.
+You can also clear the current contents of a buffer using:
+
+@example
+void yy_flush_buffer( YY_BUFFER_STATE buffer )
+@end example
+
+This function discards the buffer's contents, so the next time the
+scanner attempts to match a token from the buffer, it will first fill
+the buffer anew using @code{YY_INPUT}.
+
+@samp{yy_new_buffer()} is an alias for @samp{yy_create_buffer()},
+provided for compatibility with the C++ use of @code{new} and @code{delete}
+for creating and destroying dynamic objects.
+
+Finally, the @code{YY_CURRENT_BUFFER} macro returns a
+@code{YY_BUFFER_STATE} handle to the current buffer.
+
+Here is an example of using these features for writing a
+scanner which expands include files (the @samp{<<EOF>>} feature
+is discussed below):
+
+@example
+/* the "incl" state is used for picking up the name
+ * of an include file
+ */
+%x incl
+
+%@{
+#define MAX_INCLUDE_DEPTH 10
+YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
+int include_stack_ptr = 0;
+%@}
+
+%%
+include BEGIN(incl);
+
+[a-z]+ ECHO;
+[^a-z\n]*\n? ECHO;
+
+<incl>[ \t]* /* eat the whitespace */
+<incl>[^ \t\n]+ @{ /* got the include file name */
+ if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
+ @{
+ fprintf( stderr, "Includes nested too deeply" );
+ exit( 1 );
+ @}
+
+ include_stack[include_stack_ptr++] =
+ YY_CURRENT_BUFFER;
+
+ yyin = fopen( yytext, "r" );
+
+ if ( ! yyin )
+ error( @dots{} );
+
+ yy_switch_to_buffer(
+ yy_create_buffer( yyin, YY_BUF_SIZE ) );
+
+ BEGIN(INITIAL);
+ @}
+
+<<EOF>> @{
+ if ( --include_stack_ptr < 0 )
+ @{
+ yyterminate();
+ @}
+
+ else
+ @{
+ yy_delete_buffer( YY_CURRENT_BUFFER );
+ yy_switch_to_buffer(
+ include_stack[include_stack_ptr] );
+ @}
+ @}
+@end example
+
+Three routines are available for setting up input buffers
+for scanning in-memory strings instead of files. All of
+them create a new input buffer for scanning the string,
+and return a corresponding @code{YY_BUFFER_STATE} handle (which
+you should delete with @samp{yy_delete_buffer()} when done with
+it). They also switch to the new buffer using
+@samp{yy_switch_to_buffer()}, so the next call to @samp{yylex()} will
+start scanning the string.
+
+@table @samp
+@item yy_scan_string(const char *str)
+scans a NUL-terminated string.
+
+@item yy_scan_bytes(const char *bytes, int len)
+scans @code{len} bytes (including possibly NUL's) starting
+at location @var{bytes}.
+@end table
+
+Note that both of these functions create and scan a @emph{copy}
+of the string or bytes. (This may be desirable, since
+@samp{yylex()} modifies the contents of the buffer it is
+scanning.) You can avoid the copy by using:
+
+@table @samp
+@item yy_scan_buffer(char *base, yy_size_t size)
+which scans in place the buffer starting at @var{base},
+consisting of @var{size} bytes, the last two bytes of
+which @emph{must} be @code{YY_END_OF_BUFFER_CHAR} (ASCII NUL).
+These last two bytes are not scanned; thus,
+scanning consists of @samp{base[0]} through @samp{base[size-2]},
+inclusive.
+
+If you fail to set up @var{base} in this manner (i.e.,
+forget the final two @code{YY_END_OF_BUFFER_CHAR} bytes),
+then @samp{yy_scan_buffer()} returns a nil pointer instead
+of creating a new input buffer.
+
+The type @code{yy_size_t} is an integral type to which you
+can cast an integer expression reflecting the size
+of the buffer.
+@end table
+
+@node End-of-file rules, Miscellaneous, Multiple buffers, Top
+@section End-of-file rules
+
+The special rule "<<EOF>>" indicates actions which are to
+be taken when an end-of-file is encountered and yywrap()
+returns non-zero (i.e., indicates no further files to
+process). The action must finish by doing one of four
+things:
+
+@itemize -
+@item
+assigning @code{yyin} to a new input file (in previous
+versions of flex, after doing the assignment you
+had to call the special action @code{YY_NEW_FILE}; this is
+no longer necessary);
+
+@item
+executing a @code{return} statement;
+
+@item
+executing the special @samp{yyterminate()} action;
+
+@item
+or, switching to a new buffer using
+@samp{yy_switch_to_buffer()} as shown in the example
+above.
+@end itemize
+
+<<EOF>> rules may not be used with other patterns; they
+may only be qualified with a list of start conditions. If
+an unqualified <<EOF>> rule is given, it applies to @emph{all}
+start conditions which do not already have <<EOF>>
+actions. To specify an <<EOF>> rule for only the initial
+start condition, use
+
+@example
+<INITIAL><<EOF>>
+@end example
+
+These rules are useful for catching things like unclosed
+comments. An example:
+
+@example
+%x quote
+%%
+
+@dots{}other rules for dealing with quotes@dots{}
+
+<quote><<EOF>> @{
+ error( "unterminated quote" );
+ yyterminate();
+ @}
+<<EOF>> @{
+ if ( *++filelist )
+ yyin = fopen( *filelist, "r" );
+ else
+ yyterminate();
+ @}
+@end example
+
+@node Miscellaneous, User variables, End-of-file rules, Top
+@section Miscellaneous macros
+
+The macro @code{YY_USER_ACTION} can be defined to provide an
+action which is always executed prior to the matched
+rule's action. For example, it could be #define'd to call
+a routine to convert yytext to lower-case. When
+@code{YY_USER_ACTION} is invoked, the variable @code{yy_act} gives the
+number of the matched rule (rules are numbered starting
+with 1). Suppose you want to profile how often each of
+your rules is matched. The following would do the trick:
+
+@example
+#define YY_USER_ACTION ++ctr[yy_act]
+@end example
+
+where @code{ctr} is an array to hold the counts for the different
+rules. Note that the macro @code{YY_NUM_RULES} gives the total number
+of rules (including the default rule, even if you use @samp{-s}, so
+a correct declaration for @code{ctr} is:
+
+@example
+int ctr[YY_NUM_RULES];
+@end example
+
+The macro @code{YY_USER_INIT} may be defined to provide an action
+which is always executed before the first scan (and before
+the scanner's internal initializations are done). For
+example, it could be used to call a routine to read in a
+data table or open a logging file.
+
+The macro @samp{yy_set_interactive(is_interactive)} can be used
+to control whether the current buffer is considered
+@emph{interactive}. An interactive buffer is processed more slowly,
+but must be used when the scanner's input source is indeed
+interactive to avoid problems due to waiting to fill
+buffers (see the discussion of the @samp{-I} flag below). A
+non-zero value in the macro invocation marks the buffer as
+interactive, a zero value as non-interactive. Note that
+use of this macro overrides @samp{%option always-interactive} or
+@samp{%option never-interactive} (see Options below).
+@samp{yy_set_interactive()} must be invoked prior to beginning to
+scan the buffer that is (or is not) to be considered
+interactive.
+
+The macro @samp{yy_set_bol(at_bol)} can be used to control
+whether the current buffer's scanning context for the next
+token match is done as though at the beginning of a line.
+A non-zero macro argument makes rules anchored with
+
+The macro @samp{YY_AT_BOL()} returns true if the next token
+scanned from the current buffer will have '^' rules
+active, false otherwise.
+
+In the generated scanner, the actions are all gathered in
+one large switch statement and separated using @code{YY_BREAK},
+which may be redefined. By default, it is simply a
+"break", to separate each rule's action from the following
+rule's. Redefining @code{YY_BREAK} allows, for example, C++
+users to #define YY_BREAK to do nothing (while being very
+careful that every rule ends with a "break" or a
+"return"!) to avoid suffering from unreachable statement
+warnings where because a rule's action ends with "return",
+the @code{YY_BREAK} is inaccessible.
+
+@node User variables, YACC interface, Miscellaneous, Top
+@section Values available to the user
+
+This section summarizes the various values available to
+the user in the rule actions.
+
+@itemize -
+@item
+@samp{char *yytext} holds the text of the current token.
+It may be modified but not lengthened (you cannot
+append characters to the end).
+
+If the special directive @samp{%array} appears in the
+first section of the scanner description, then
+@code{yytext} is instead declared @samp{char yytext[YYLMAX]},
+where @code{YYLMAX} is a macro definition that you can
+redefine in the first section if you don't like the
+default value (generally 8KB). Using @samp{%array}
+results in somewhat slower scanners, but the value
+of @code{yytext} becomes immune to calls to @samp{input()} and
+@samp{unput()}, which potentially destroy its value when
+@code{yytext} is a character pointer. The opposite of
+@samp{%array} is @samp{%pointer}, which is the default.
+
+You cannot use @samp{%array} when generating C++ scanner
+classes (the @samp{-+} flag).
+
+@item
+@samp{int yyleng} holds the length of the current token.
+
+@item
+@samp{FILE *yyin} is the file which by default @code{flex} reads
+from. It may be redefined but doing so only makes
+sense before scanning begins or after an EOF has
+been encountered. Changing it in the midst of
+scanning will have unexpected results since @code{flex}
+buffers its input; use @samp{yyrestart()} instead. Once
+scanning terminates because an end-of-file has been
+seen, you can assign @code{yyin} at the new input file and
+then call the scanner again to continue scanning.
+
+@item
+@samp{void yyrestart( FILE *new_file )} may be called to
+point @code{yyin} at the new input file. The switch-over
+to the new file is immediate (any previously
+buffered-up input is lost). Note that calling
+@samp{yyrestart()} with @code{yyin} as an argument thus throws
+away the current input buffer and continues
+scanning the same input file.
+
+@item
+@samp{FILE *yyout} is the file to which @samp{ECHO} actions are
+done. It can be reassigned by the user.
+
+@item
+@code{YY_CURRENT_BUFFER} returns a @code{YY_BUFFER_STATE} handle
+to the current buffer.
+
+@item
+@code{YY_START} returns an integer value corresponding to
+the current start condition. You can subsequently
+use this value with @code{BEGIN} to return to that start
+condition.
+@end itemize
+
+@node YACC interface, Options, User variables, Top
+@section Interfacing with @code{yacc}
+
+One of the main uses of @code{flex} is as a companion to the @code{yacc}
+parser-generator. @code{yacc} parsers expect to call a routine
+named @samp{yylex()} to find the next input token. The routine
+is supposed to return the type of the next token as well
+as putting any associated value in the global @code{yylval}. To
+use @code{flex} with @code{yacc}, one specifies the @samp{-d} option to @code{yacc} to
+instruct it to generate the file @file{y.tab.h} containing
+definitions of all the @samp{%tokens} appearing in the @code{yacc} input.
+This file is then included in the @code{flex} scanner. For
+example, if one of the tokens is "TOK_NUMBER", part of the
+scanner might look like:
+
+@example
+%@{
+#include "y.tab.h"
+%@}
+
+%%
+
+[0-9]+ yylval = atoi( yytext ); return TOK_NUMBER;
+@end example
+
+@node Options, Performance, YACC interface, Top
+@section Options
+@code{flex} has the following options:
+
+@table @samp
+@item -b
+Generate backing-up information to @file{lex.backup}.
+This is a list of scanner states which require
+backing up and the input characters on which they
+do so. By adding rules one can remove backing-up
+states. If @emph{all} backing-up states are eliminated
+and @samp{-Cf} or @samp{-CF} is used, the generated scanner will
+run faster (see the @samp{-p} flag). Only users who wish
+to squeeze every last cycle out of their scanners
+need worry about this option. (See the section on
+Performance Considerations below.)
+
+@item -c
+is a do-nothing, deprecated option included for
+POSIX compliance.
+
+@item -d
+makes the generated scanner run in @dfn{debug} mode.
+Whenever a pattern is recognized and the global
+@code{yy_flex_debug} is non-zero (which is the default),
+the scanner will write to @code{stderr} a line of the
+form:
+
+@example
+--accepting rule at line 53 ("the matched text")
+@end example
+
+The line number refers to the location of the rule
+in the file defining the scanner (i.e., the file
+that was fed to flex). Messages are also generated
+when the scanner backs up, accepts the default
+rule, reaches the end of its input buffer (or
+encounters a NUL; at this point, the two look the
+same as far as the scanner's concerned), or reaches
+an end-of-file.
+
+@item -f
+specifies @dfn{fast scanner}. No table compression is
+done and stdio is bypassed. The result is large
+but fast. This option is equivalent to @samp{-Cfr} (see
+below).
+
+@item -h
+generates a "help" summary of @code{flex's} options to
+@code{stdout} and then exits. @samp{-?} and @samp{--help} are synonyms
+for @samp{-h}.
+
+@item -i
+instructs @code{flex} to generate a @emph{case-insensitive}
+scanner. The case of letters given in the @code{flex} input
+patterns will be ignored, and tokens in the input
+will be matched regardless of case. The matched
+text given in @code{yytext} will have the preserved case
+(i.e., it will not be folded).
+
+@item -l
+turns on maximum compatibility with the original
+AT&T @code{lex} implementation. Note that this does not
+mean @emph{full} compatibility. Use of this option costs
+a considerable amount of performance, and it cannot
+be used with the @samp{-+, -f, -F, -Cf}, or @samp{-CF} options.
+For details on the compatibilities it provides, see
+the section "Incompatibilities With Lex And POSIX"
+below. This option also results in the name
+@code{YY_FLEX_LEX_COMPAT} being #define'd in the generated
+scanner.
+
+@item -n
+is another do-nothing, deprecated option included
+only for POSIX compliance.
+
+@item -p
+generates a performance report to stderr. The
+report consists of comments regarding features of
+the @code{flex} input file which will cause a serious loss
+of performance in the resulting scanner. If you
+give the flag twice, you will also get comments
+regarding features that lead to minor performance
+losses.
+
+Note that the use of @code{REJECT}, @samp{%option yylineno} and
+variable trailing context (see the Deficiencies / Bugs section below)
+entails a substantial performance penalty; use of @samp{yymore()},
+the @samp{^} operator, and the @samp{-I} flag entail minor performance
+penalties.
+
+@item -s
+causes the @dfn{default rule} (that unmatched scanner
+input is echoed to @code{stdout}) to be suppressed. If
+the scanner encounters input that does not match
+any of its rules, it aborts with an error. This
+option is useful for finding holes in a scanner's
+rule set.
+
+@item -t
+instructs @code{flex} to write the scanner it generates to
+standard output instead of @file{lex.yy.c}.
+
+@item -v
+specifies that @code{flex} should write to @code{stderr} a
+summary of statistics regarding the scanner it
+generates. Most of the statistics are meaningless to
+the casual @code{flex} user, but the first line identifies
+the version of @code{flex} (same as reported by @samp{-V}), and
+the next line the flags used when generating the
+scanner, including those that are on by default.
+
+@item -w
+suppresses warning messages.
+
+@item -B
+instructs @code{flex} to generate a @emph{batch} scanner, the
+opposite of @emph{interactive} scanners generated by @samp{-I}
+(see below). In general, you use @samp{-B} when you are
+@emph{certain} that your scanner will never be used
+interactively, and you want to squeeze a @emph{little} more
+performance out of it. If your goal is instead to
+squeeze out a @emph{lot} more performance, you should be
+using the @samp{-Cf} or @samp{-CF} options (discussed below),
+which turn on @samp{-B} automatically anyway.
+
+@item -F
+specifies that the @dfn{fast} scanner table
+representation should be used (and stdio bypassed). This
+representation is about as fast as the full table
+representation @samp{(-f)}, and for some sets of patterns
+will be considerably smaller (and for others,
+larger). In general, if the pattern set contains
+both "keywords" and a catch-all, "identifier" rule,
+such as in the set:
+
+@example
+"case" return TOK_CASE;
+"switch" return TOK_SWITCH;
+...
+"default" return TOK_DEFAULT;
+[a-z]+ return TOK_ID;
+@end example
+
+@noindent
+then you're better off using the full table
+representation. If only the "identifier" rule is
+present and you then use a hash table or some such to
+detect the keywords, you're better off using @samp{-F}.
+
+This option is equivalent to @samp{-CFr} (see below). It
+cannot be used with @samp{-+}.
+
+@item -I
+instructs @code{flex} to generate an @emph{interactive} scanner.
+An interactive scanner is one that only looks ahead
+to decide what token has been matched if it
+absolutely must. It turns out that always looking one
+extra character ahead, even if the scanner has
+already seen enough text to disambiguate the
+current token, is a bit faster than only looking ahead
+when necessary. But scanners that always look
+ahead give dreadful interactive performance; for
+example, when a user types a newline, it is not
+recognized as a newline token until they enter
+@emph{another} token, which often means typing in another
+whole line.
+
+@code{Flex} scanners default to @emph{interactive} unless you use
+the @samp{-Cf} or @samp{-CF} table-compression options (see
+below). That's because if you're looking for
+high-performance you should be using one of these
+options, so if you didn't, @code{flex} assumes you'd
+rather trade off a bit of run-time performance for
+intuitive interactive behavior. Note also that you
+@emph{cannot} use @samp{-I} in conjunction with @samp{-Cf} or @samp{-CF}.
+Thus, this option is not really needed; it is on by
+default for all those cases in which it is allowed.
+
+You can force a scanner to @emph{not} be interactive by
+using @samp{-B} (see above).
+
+@item -L
+instructs @code{flex} not to generate @samp{#line} directives.
+Without this option, @code{flex} peppers the generated
+scanner with #line directives so error messages in
+the actions will be correctly located with respect
+to either the original @code{flex} input file (if the
+errors are due to code in the input file), or
+@file{lex.yy.c} (if the errors are @code{flex's} fault -- you
+should report these sorts of errors to the email
+address given below).
+
+@item -T
+makes @code{flex} run in @code{trace} mode. It will generate a
+lot of messages to @code{stderr} concerning the form of
+the input and the resultant non-deterministic and
+deterministic finite automata. This option is
+mostly for use in maintaining @code{flex}.
+
+@item -V
+prints the version number to @code{stdout} and exits.
+@samp{--version} is a synonym for @samp{-V}.
+
+@item -7
+instructs @code{flex} to generate a 7-bit scanner, i.e.,
+one which can only recognized 7-bit characters in
+its input. The advantage of using @samp{-7} is that the
+scanner's tables can be up to half the size of
+those generated using the @samp{-8} option (see below).
+The disadvantage is that such scanners often hang
+or crash if their input contains an 8-bit
+character.
+
+Note, however, that unless you generate your
+scanner using the @samp{-Cf} or @samp{-CF} table compression options,
+use of @samp{-7} will save only a small amount of table
+space, and make your scanner considerably less
+portable. @code{Flex's} default behavior is to generate
+an 8-bit scanner unless you use the @samp{-Cf} or @samp{-CF}, in
+which case @code{flex} defaults to generating 7-bit
+scanners unless your site was always configured to
+generate 8-bit scanners (as will often be the case
+with non-USA sites). You can tell whether flex
+generated a 7-bit or an 8-bit scanner by inspecting
+the flag summary in the @samp{-v} output as described
+above.
+
+Note that if you use @samp{-Cfe} or @samp{-CFe} (those table
+compression options, but also using equivalence
+classes as discussed see below), flex still
+defaults to generating an 8-bit scanner, since
+usually with these compression options full 8-bit
+tables are not much more expensive than 7-bit
+tables.
+
+@item -8
+instructs @code{flex} to generate an 8-bit scanner, i.e.,
+one which can recognize 8-bit characters. This
+flag is only needed for scanners generated using
+@samp{-Cf} or @samp{-CF}, as otherwise flex defaults to
+generating an 8-bit scanner anyway.
+
+See the discussion of @samp{-7} above for flex's default
+behavior and the tradeoffs between 7-bit and 8-bit
+scanners.
+
+@item -+
+specifies that you want flex to generate a C++
+scanner class. See the section on Generating C++
+Scanners below for details.
+
+@item -C[aefFmr]
+controls the degree of table compression and, more
+generally, trade-offs between small scanners and
+fast scanners.
+
+@samp{-Ca} ("align") instructs flex to trade off larger
+tables in the generated scanner for faster
+performance because the elements of the tables are better
+aligned for memory access and computation. On some
+RISC architectures, fetching and manipulating
+long-words is more efficient than with smaller-sized
+units such as shortwords. This option can double
+the size of the tables used by your scanner.
+
+@samp{-Ce} directs @code{flex} to construct @dfn{equivalence classes},
+i.e., sets of characters which have identical
+lexical properties (for example, if the only appearance
+of digits in the @code{flex} input is in the character
+class "[0-9]" then the digits '0', '1', @dots{}, '9'
+will all be put in the same equivalence class).
+Equivalence classes usually give dramatic
+reductions in the final table/object file sizes
+(typically a factor of 2-5) and are pretty cheap
+performance-wise (one array look-up per character
+scanned).
+
+@samp{-Cf} specifies that the @emph{full} scanner tables should
+be generated - @code{flex} should not compress the tables
+by taking advantages of similar transition
+functions for different states.
+
+@samp{-CF} specifies that the alternate fast scanner
+representation (described above under the @samp{-F} flag)
+should be used. This option cannot be used with
+@samp{-+}.
+
+@samp{-Cm} directs @code{flex} to construct @dfn{meta-equivalence
+classes}, which are sets of equivalence classes (or
+characters, if equivalence classes are not being
+used) that are commonly used together.
+Meta-equivalence classes are often a big win when using
+compressed tables, but they have a moderate
+performance impact (one or two "if" tests and one array
+look-up per character scanned).
+
+@samp{-Cr} causes the generated scanner to @emph{bypass} use of
+the standard I/O library (stdio) for input.
+Instead of calling @samp{fread()} or @samp{getc()}, the scanner
+will use the @samp{read()} system call, resulting in a
+performance gain which varies from system to
+system, but in general is probably negligible unless
+you are also using @samp{-Cf} or @samp{-CF}. Using @samp{-Cr} can cause
+strange behavior if, for example, you read from
+@code{yyin} using stdio prior to calling the scanner
+(because the scanner will miss whatever text your
+previous reads left in the stdio input buffer).
+
+@samp{-Cr} has no effect if you define @code{YY_INPUT} (see The
+Generated Scanner above).
+
+A lone @samp{-C} specifies that the scanner tables should
+be compressed but neither equivalence classes nor
+meta-equivalence classes should be used.
+
+The options @samp{-Cf} or @samp{-CF} and @samp{-Cm} do not make sense
+together - there is no opportunity for
+meta-equivalence classes if the table is not being
+compressed. Otherwise the options may be freely
+mixed, and are cumulative.
+
+The default setting is @samp{-Cem}, which specifies that
+@code{flex} should generate equivalence classes and
+meta-equivalence classes. This setting provides the
+highest degree of table compression. You can trade
+off faster-executing scanners at the cost of larger
+tables with the following generally being true:
+
+@example
+slowest & smallest
+ -Cem
+ -Cm
+ -Ce
+ -C
+ -C@{f,F@}e
+ -C@{f,F@}
+ -C@{f,F@}a
+fastest & largest
+@end example
+
+Note that scanners with the smallest tables are
+usually generated and compiled the quickest, so
+during development you will usually want to use the
+default, maximal compression.
+
+@samp{-Cfe} is often a good compromise between speed and
+size for production scanners.
+
+@item -ooutput
+directs flex to write the scanner to the file @samp{out-}
+@code{put} instead of @file{lex.yy.c}. If you combine @samp{-o} with
+the @samp{-t} option, then the scanner is written to
+@code{stdout} but its @samp{#line} directives (see the @samp{-L} option
+above) refer to the file @code{output}.
+
+@item -Pprefix
+changes the default @samp{yy} prefix used by @code{flex} for all
+globally-visible variable and function names to
+instead be @var{prefix}. For example, @samp{-Pfoo} changes the
+name of @code{yytext} to @file{footext}. It also changes the
+name of the default output file from @file{lex.yy.c} to
+@file{lex.foo.c}. Here are all of the names affected:
+
+@example
+yy_create_buffer
+yy_delete_buffer
+yy_flex_debug
+yy_init_buffer
+yy_flush_buffer
+yy_load_buffer_state
+yy_switch_to_buffer
+yyin
+yyleng
+yylex
+yylineno
+yyout
+yyrestart
+yytext
+yywrap
+@end example
+
+(If you are using a C++ scanner, then only @code{yywrap}
+and @code{yyFlexLexer} are affected.) Within your scanner
+itself, you can still refer to the global variables
+and functions using either version of their name;
+but externally, they have the modified name.
+
+This option lets you easily link together multiple
+@code{flex} programs into the same executable. Note,
+though, that using this option also renames
+@samp{yywrap()}, so you now @emph{must} either provide your own
+(appropriately-named) version of the routine for
+your scanner, or use @samp{%option noyywrap}, as linking
+with @samp{-lfl} no longer provides one for you by
+default.
+
+@item -Sskeleton_file
+overrides the default skeleton file from which @code{flex}
+constructs its scanners. You'll never need this
+option unless you are doing @code{flex} maintenance or
+development.
+@end table
+
+@code{flex} also provides a mechanism for controlling options
+within the scanner specification itself, rather than from
+the flex command-line. This is done by including @samp{%option}
+directives in the first section of the scanner
+specification. You can specify multiple options with a single
+@samp{%option} directive, and multiple directives in the first
+section of your flex input file. Most options are given
+simply as names, optionally preceded by the word "no"
+(with no intervening whitespace) to negate their meaning.
+A number are equivalent to flex flags or their negation:
+
+@example
+7bit -7 option
+8bit -8 option
+align -Ca option
+backup -b option
+batch -B option
+c++ -+ option
+
+caseful or
+case-sensitive opposite of -i (default)
+
+case-insensitive or
+caseless -i option
+
+debug -d option
+default opposite of -s option
+ecs -Ce option
+fast -F option
+full -f option
+interactive -I option
+lex-compat -l option
+meta-ecs -Cm option
+perf-report -p option
+read -Cr option
+stdout -t option
+verbose -v option
+warn opposite of -w option
+ (use "%option nowarn" for -w)
+
+array equivalent to "%array"
+pointer equivalent to "%pointer" (default)
+@end example
+
+Some @samp{%option's} provide features otherwise not available:
+
+@table @samp
+@item always-interactive
+instructs flex to generate a scanner which always
+considers its input "interactive". Normally, on
+each new input file the scanner calls @samp{isatty()} in
+an attempt to determine whether the scanner's input
+source is interactive and thus should be read a
+character at a time. When this option is used,
+however, then no such call is made.
+
+@item main
+directs flex to provide a default @samp{main()} program
+for the scanner, which simply calls @samp{yylex()}. This
+option implies @code{noyywrap} (see below).
+
+@item never-interactive
+instructs flex to generate a scanner which never
+considers its input "interactive" (again, no call
+made to @samp{isatty())}. This is the opposite of @samp{always-}
+@emph{interactive}.
+
+@item stack
+enables the use of start condition stacks (see
+Start Conditions above).
+
+@item stdinit
+if unset (i.e., @samp{%option nostdinit}) initializes @code{yyin}
+and @code{yyout} to nil @code{FILE} pointers, instead of @code{stdin}
+and @code{stdout}.
+
+@item yylineno
+directs @code{flex} to generate a scanner that maintains the number
+of the current line read from its input in the global variable
+@code{yylineno}. This option is implied by @samp{%option lex-compat}.
+
+@item yywrap
+if unset (i.e., @samp{%option noyywrap}), makes the
+scanner not call @samp{yywrap()} upon an end-of-file, but
+simply assume that there are no more files to scan
+(until the user points @code{yyin} at a new file and calls
+@samp{yylex()} again).
+@end table
+
+@code{flex} scans your rule actions to determine whether you use
+the @code{REJECT} or @samp{yymore()} features. The @code{reject} and @code{yymore}
+options are available to override its decision as to
+whether you use the options, either by setting them (e.g.,
+@samp{%option reject}) to indicate the feature is indeed used, or
+unsetting them to indicate it actually is not used (e.g.,
+@samp{%option noyymore}).
+
+Three options take string-delimited values, offset with '=':
+
+@example
+%option outfile="ABC"
+@end example
+
+@noindent
+is equivalent to @samp{-oABC}, and
+
+@example
+%option prefix="XYZ"
+@end example
+
+@noindent
+is equivalent to @samp{-PXYZ}.
+
+Finally,
+
+@example
+%option yyclass="foo"
+@end example
+
+@noindent
+only applies when generating a C++ scanner (@samp{-+} option). It
+informs @code{flex} that you have derived @samp{foo} as a subclass of
+@code{yyFlexLexer} so @code{flex} will place your actions in the member
+function @samp{foo::yylex()} instead of @samp{yyFlexLexer::yylex()}.
+It also generates a @samp{yyFlexLexer::yylex()} member function that
+emits a run-time error (by invoking @samp{yyFlexLexer::LexerError()})
+if called. See Generating C++ Scanners, below, for additional
+information.
+
+A number of options are available for lint purists who
+want to suppress the appearance of unneeded routines in
+the generated scanner. Each of the following, if unset,
+results in the corresponding routine not appearing in the
+generated scanner:
+
+@example
+input, unput
+yy_push_state, yy_pop_state, yy_top_state
+yy_scan_buffer, yy_scan_bytes, yy_scan_string
+@end example
+
+@noindent
+(though @samp{yy_push_state()} and friends won't appear anyway
+unless you use @samp{%option stack}).
+
+@node Performance, C++, Options, Top
+@section Performance considerations
+
+The main design goal of @code{flex} is that it generate
+high-performance scanners. It has been optimized for dealing
+well with large sets of rules. Aside from the effects on
+scanner speed of the table compression @samp{-C} options outlined
+above, there are a number of options/actions which degrade
+performance. These are, from most expensive to least:
+
+@example
+REJECT
+%option yylineno
+arbitrary trailing context
+
+pattern sets that require backing up
+%array
+%option interactive
+%option always-interactive
+
+'^' beginning-of-line operator
+yymore()
+@end example
+
+with the first three all being quite expensive and the
+last two being quite cheap. Note also that @samp{unput()} is
+implemented as a routine call that potentially does quite
+a bit of work, while @samp{yyless()} is a quite-cheap macro; so
+if just putting back some excess text you scanned, use
+@samp{yyless()}.
+
+@code{REJECT} should be avoided at all costs when performance is
+important. It is a particularly expensive option.
+
+Getting rid of backing up is messy and often may be an
+enormous amount of work for a complicated scanner. In
+principal, one begins by using the @samp{-b} flag to generate a
+@file{lex.backup} file. For example, on the input
+
+@example
+%%
+foo return TOK_KEYWORD;
+foobar return TOK_KEYWORD;
+@end example
+
+@noindent
+the file looks like:
+
+@example
+State #6 is non-accepting -
+ associated rule line numbers:
+ 2 3
+ out-transitions: [ o ]
+ jam-transitions: EOF [ \001-n p-\177 ]
+
+State #8 is non-accepting -
+ associated rule line numbers:
+ 3
+ out-transitions: [ a ]
+ jam-transitions: EOF [ \001-` b-\177 ]
+
+State #9 is non-accepting -
+ associated rule line numbers:
+ 3
+ out-transitions: [ r ]
+ jam-transitions: EOF [ \001-q s-\177 ]
+
+Compressed tables always back up.
+@end example
+
+The first few lines tell us that there's a scanner state
+in which it can make a transition on an 'o' but not on any
+other character, and that in that state the currently
+scanned text does not match any rule. The state occurs
+when trying to match the rules found at lines 2 and 3 in
+the input file. If the scanner is in that state and then
+reads something other than an 'o', it will have to back up
+to find a rule which is matched. With a bit of
+head-scratching one can see that this must be the state it's in
+when it has seen "fo". When this has happened, if
+anything other than another 'o' is seen, the scanner will
+have to back up to simply match the 'f' (by the default
+rule).
+
+The comment regarding State #8 indicates there's a problem
+when "foob" has been scanned. Indeed, on any character
+other than an 'a', the scanner will have to back up to
+accept "foo". Similarly, the comment for State #9
+concerns when "fooba" has been scanned and an 'r' does not
+follow.
+
+The final comment reminds us that there's no point going
+to all the trouble of removing backing up from the rules
+unless we're using @samp{-Cf} or @samp{-CF}, since there's no
+performance gain doing so with compressed scanners.
+
+The way to remove the backing up is to add "error" rules:
+
+@example
+%%
+foo return TOK_KEYWORD;
+foobar return TOK_KEYWORD;
+
+fooba |
+foob |
+fo @{
+ /* false alarm, not really a keyword */
+ return TOK_ID;
+ @}
+@end example
+
+Eliminating backing up among a list of keywords can also
+be done using a "catch-all" rule:
+
+@example
+%%
+foo return TOK_KEYWORD;
+foobar return TOK_KEYWORD;
+
+[a-z]+ return TOK_ID;
+@end example
+
+This is usually the best solution when appropriate.
+
+Backing up messages tend to cascade. With a complicated
+set of rules it's not uncommon to get hundreds of
+messages. If one can decipher them, though, it often only
+takes a dozen or so rules to eliminate the backing up
+(though it's easy to make a mistake and have an error rule
+accidentally match a valid token. A possible future @code{flex}
+feature will be to automatically add rules to eliminate
+backing up).
+
+It's important to keep in mind that you gain the benefits
+of eliminating backing up only if you eliminate @emph{every}
+instance of backing up. Leaving just one means you gain
+nothing.
+
+@var{Variable} trailing context (where both the leading and
+trailing parts do not have a fixed length) entails almost
+the same performance loss as @code{REJECT} (i.e., substantial).
+So when possible a rule like:
+
+@example
+%%
+mouse|rat/(cat|dog) run();
+@end example
+
+@noindent
+is better written:
+
+@example
+%%
+mouse/cat|dog run();
+rat/cat|dog run();
+@end example
+
+@noindent
+or as
+
+@example
+%%
+mouse|rat/cat run();
+mouse|rat/dog run();
+@end example
+
+Note that here the special '|' action does @emph{not} provide any
+savings, and can even make things worse (see Deficiencies
+/ Bugs below).
+
+Another area where the user can increase a scanner's
+performance (and one that's easier to implement) arises from
+the fact that the longer the tokens matched, the faster
+the scanner will run. This is because with long tokens
+the processing of most input characters takes place in the
+(short) inner scanning loop, and does not often have to go
+through the additional work of setting up the scanning
+environment (e.g., @code{yytext}) for the action. Recall the
+scanner for C comments:
+
+@example
+%x comment
+%%
+ int line_num = 1;
+
+"/*" BEGIN(comment);
+
+<comment>[^*\n]*
+<comment>"*"+[^*/\n]*
+<comment>\n ++line_num;
+<comment>"*"+"/" BEGIN(INITIAL);
+@end example
+
+This could be sped up by writing it as:
+
+@example
+%x comment
+%%
+ int line_num = 1;
+
+"/*" BEGIN(comment);
+
+<comment>[^*\n]*
+<comment>[^*\n]*\n ++line_num;
+<comment>"*"+[^*/\n]*
+<comment>"*"+[^*/\n]*\n ++line_num;
+<comment>"*"+"/" BEGIN(INITIAL);
+@end example
+
+Now instead of each newline requiring the processing of
+another action, recognizing the newlines is "distributed"
+over the other rules to keep the matched text as long as
+possible. Note that @emph{adding} rules does @emph{not} slow down the
+scanner! The speed of the scanner is independent of the
+number of rules or (modulo the considerations given at the
+beginning of this section) how complicated the rules are
+with regard to operators such as '*' and '|'.
+
+A final example in speeding up a scanner: suppose you want
+to scan through a file containing identifiers and
+keywords, one per line and with no other extraneous
+characters, and recognize all the keywords. A natural first
+approach is:
+
+@example
+%%
+asm |
+auto |
+break |
+@dots{} etc @dots{}
+volatile |
+while /* it's a keyword */
+
+.|\n /* it's not a keyword */
+@end example
+
+To eliminate the back-tracking, introduce a catch-all
+rule:
+
+@example
+%%
+asm |
+auto |
+break |
+... etc ...
+volatile |
+while /* it's a keyword */
+
+[a-z]+ |
+.|\n /* it's not a keyword */
+@end example
+
+Now, if it's guaranteed that there's exactly one word per
+line, then we can reduce the total number of matches by a
+half by merging in the recognition of newlines with that
+of the other tokens:
+
+@example
+%%
+asm\n |
+auto\n |
+break\n |
+@dots{} etc @dots{}
+volatile\n |
+while\n /* it's a keyword */
+
+[a-z]+\n |
+.|\n /* it's not a keyword */
+@end example
+
+One has to be careful here, as we have now reintroduced
+backing up into the scanner. In particular, while @emph{we} know
+that there will never be any characters in the input
+stream other than letters or newlines, @code{flex} can't figure
+this out, and it will plan for possibly needing to back up
+when it has scanned a token like "auto" and then the next
+character is something other than a newline or a letter.
+Previously it would then just match the "auto" rule and be
+done, but now it has no "auto" rule, only a "auto\n" rule.
+To eliminate the possibility of backing up, we could
+either duplicate all rules but without final newlines, or,
+since we never expect to encounter such an input and
+therefore don't how it's classified, we can introduce one
+more catch-all rule, this one which doesn't include a
+newline:
+
+@example
+%%
+asm\n |
+auto\n |
+break\n |
+@dots{} etc @dots{}
+volatile\n |
+while\n /* it's a keyword */
+
+[a-z]+\n |
+[a-z]+ |
+.|\n /* it's not a keyword */
+@end example
+
+Compiled with @samp{-Cf}, this is about as fast as one can get a
+@code{flex} scanner to go for this particular problem.
+
+A final note: @code{flex} is slow when matching NUL's,
+particularly when a token contains multiple NUL's. It's best to
+write rules which match @emph{short} amounts of text if it's
+anticipated that the text will often include NUL's.
+
+Another final note regarding performance: as mentioned
+above in the section How the Input is Matched, dynamically
+resizing @code{yytext} to accommodate huge tokens is a slow
+process because it presently requires that the (huge) token
+be rescanned from the beginning. Thus if performance is
+vital, you should attempt to match "large" quantities of
+text but not "huge" quantities, where the cutoff between
+the two is at about 8K characters/token.
+
+@node C++, Incompatibilities, Performance, Top
+@section Generating C++ scanners
+
+@code{flex} provides two different ways to generate scanners for
+use with C++. The first way is to simply compile a
+scanner generated by @code{flex} using a C++ compiler instead of a C
+compiler. You should not encounter any compilations
+errors (please report any you find to the email address
+given in the Author section below). You can then use C++
+code in your rule actions instead of C code. Note that
+the default input source for your scanner remains @code{yyin},
+and default echoing is still done to @code{yyout}. Both of these
+remain @samp{FILE *} variables and not C++ @code{streams}.
+
+You can also use @code{flex} to generate a C++ scanner class, using
+the @samp{-+} option, (or, equivalently, @samp{%option c++}), which
+is automatically specified if the name of the flex executable ends
+in a @samp{+}, such as @code{flex++}. When using this option, flex
+defaults to generating the scanner to the file @file{lex.yy.cc} instead
+of @file{lex.yy.c}. The generated scanner includes the header file
+@file{FlexLexer.h}, which defines the interface to two C++ classes.
+
+The first class, @code{FlexLexer}, provides an abstract base
+class defining the general scanner class interface. It
+provides the following member functions:
+
+@table @samp
+@item const char* YYText()
+returns the text of the most recently matched
+token, the equivalent of @code{yytext}.
+
+@item int YYLeng()
+returns the length of the most recently matched
+token, the equivalent of @code{yyleng}.
+
+@item int lineno() const
+returns the current input line number (see @samp{%option yylineno}),
+or 1 if @samp{%option yylineno} was not used.
+
+@item void set_debug( int flag )
+sets the debugging flag for the scanner, equivalent to assigning to
+@code{yy_flex_debug} (see the Options section above). Note that you
+must build the scanner using @samp{%option debug} to include debugging
+information in it.
+
+@item int debug() const
+returns the current setting of the debugging flag.
+@end table
+
+Also provided are member functions equivalent to
+@samp{yy_switch_to_buffer(), yy_create_buffer()} (though the
+first argument is an @samp{istream*} object pointer and not a
+@samp{FILE*}, @samp{yy_flush_buffer()}, @samp{yy_delete_buffer()},
+and @samp{yyrestart()} (again, the first argument is a @samp{istream*}
+object pointer).
+
+The second class defined in @file{FlexLexer.h} is @code{yyFlexLexer},
+which is derived from @code{FlexLexer}. It defines the following
+additional member functions:
+
+@table @samp
+@item yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )
+constructs a @code{yyFlexLexer} object using the given
+streams for input and output. If not specified,
+the streams default to @code{cin} and @code{cout}, respectively.
+
+@item virtual int yylex()
+performs the same role is @samp{yylex()} does for ordinary
+flex scanners: it scans the input stream, consuming
+tokens, until a rule's action returns a value. If you derive a subclass
+@var{S}
+from @code{yyFlexLexer}
+and want to access the member functions and variables of
+@var{S}
+inside @samp{yylex()},
+then you need to use @samp{%option yyclass="@var{S}"}
+to inform @code{flex}
+that you will be using that subclass instead of @code{yyFlexLexer}.
+In this case, rather than generating @samp{yyFlexLexer::yylex()},
+@code{flex} generates @samp{@var{S}::yylex()}
+(and also generates a dummy @samp{yyFlexLexer::yylex()}
+that calls @samp{yyFlexLexer::LexerError()}
+if called).
+
+@item virtual void switch_streams(istream* new_in = 0, ostream* new_out = 0)
+reassigns @code{yyin} to @code{new_in}
+(if non-nil)
+and @code{yyout} to @code{new_out}
+(ditto), deleting the previous input buffer if @code{yyin}
+is reassigned.
+
+@item int yylex( istream* new_in = 0, ostream* new_out = 0 )
+first switches the input streams via @samp{switch_streams( new_in, new_out )}
+and then returns the value of @samp{yylex()}.
+@end table
+
+In addition, @code{yyFlexLexer} defines the following protected
+virtual functions which you can redefine in derived
+classes to tailor the scanner:
+
+@table @samp
+@item virtual int LexerInput( char* buf, int max_size )
+reads up to @samp{max_size} characters into @var{buf} and
+returns the number of characters read. To indicate
+end-of-input, return 0 characters. Note that
+"interactive" scanners (see the @samp{-B} and @samp{-I} flags)
+define the macro @code{YY_INTERACTIVE}. If you redefine
+@code{LexerInput()} and need to take different actions
+depending on whether or not the scanner might be
+scanning an interactive input source, you can test
+for the presence of this name via @samp{#ifdef}.
+
+@item virtual void LexerOutput( const char* buf, int size )
+writes out @var{size} characters from the buffer @var{buf},
+which, while NUL-terminated, may also contain
+"internal" NUL's if the scanner's rules can match
+text with NUL's in them.
+
+@item virtual void LexerError( const char* msg )
+reports a fatal error message. The default version
+of this function writes the message to the stream
+@code{cerr} and exits.
+@end table
+
+Note that a @code{yyFlexLexer} object contains its @emph{entire}
+scanning state. Thus you can use such objects to create
+reentrant scanners. You can instantiate multiple instances of
+the same @code{yyFlexLexer} class, and you can also combine
+multiple C++ scanner classes together in the same program
+using the @samp{-P} option discussed above.
+Finally, note that the @samp{%array} feature is not available to
+C++ scanner classes; you must use @samp{%pointer} (the default).
+
+Here is an example of a simple C++ scanner:
+
+@example
+ // An example of using the flex C++ scanner class.
+
+%@{
+int mylineno = 0;
+%@}
+
+string \"[^\n"]+\"
+
+ws [ \t]+
+
+alpha [A-Za-z]
+dig [0-9]
+name (@{alpha@}|@{dig@}|\$)(@{alpha@}|@{dig@}|[_.\-/$])*
+num1 [-+]?@{dig@}+\.?([eE][-+]?@{dig@}+)?
+num2 [-+]?@{dig@}*\.@{dig@}+([eE][-+]?@{dig@}+)?
+number @{num1@}|@{num2@}
+
+%%
+
+@{ws@} /* skip blanks and tabs */
+
+"/*" @{
+ int c;
+
+ while((c = yyinput()) != 0)
+ @{
+ if(c == '\n')
+ ++mylineno;
+
+ else if(c == '*')
+ @{
+ if((c = yyinput()) == '/')
+ break;
+ else
+ unput(c);
+ @}
+ @}
+ @}
+
+@{number@} cout << "number " << YYText() << '\n';
+
+\n mylineno++;
+
+@{name@} cout << "name " << YYText() << '\n';
+
+@{string@} cout << "string " << YYText() << '\n';
+
+%%
+
+Version 2.5 December 1994 44
+
+int main( int /* argc */, char** /* argv */ )
+ @{
+ FlexLexer* lexer = new yyFlexLexer;
+ while(lexer->yylex() != 0)
+ ;
+ return 0;
+ @}
+@end example
+
+If you want to create multiple (different) lexer classes,
+you use the @samp{-P} flag (or the @samp{prefix=} option) to rename each
+@code{yyFlexLexer} to some other @code{xxFlexLexer}. You then can
+include @samp{<FlexLexer.h>} in your other sources once per lexer
+class, first renaming @code{yyFlexLexer} as follows:
+
+@example
+#undef yyFlexLexer
+#define yyFlexLexer xxFlexLexer
+#include <FlexLexer.h>
+
+#undef yyFlexLexer
+#define yyFlexLexer zzFlexLexer
+#include <FlexLexer.h>
+@end example
+
+if, for example, you used @samp{%option prefix="xx"} for one of
+your scanners and @samp{%option prefix="zz"} for the other.
+
+IMPORTANT: the present form of the scanning class is
+@emph{experimental} and may change considerably between major
+releases.
+
+@node Incompatibilities, Diagnostics, C++, Top
+@section Incompatibilities with @code{lex} and POSIX
+
+@code{flex} is a rewrite of the AT&T Unix @code{lex} tool (the two
+implementations do not share any code, though), with some
+extensions and incompatibilities, both of which are of
+concern to those who wish to write scanners acceptable to
+either implementation. Flex is fully compliant with the
+POSIX @code{lex} specification, except that when using @samp{%pointer}
+(the default), a call to @samp{unput()} destroys the contents of
+@code{yytext}, which is counter to the POSIX specification.
+
+In this section we discuss all of the known areas of
+incompatibility between flex, AT&T lex, and the POSIX
+specification.
+
+@code{flex's} @samp{-l} option turns on maximum compatibility with the
+original AT&T @code{lex} implementation, at the cost of a major
+loss in the generated scanner's performance. We note
+below which incompatibilities can be overcome using the @samp{-l}
+option.
+
+@code{flex} is fully compatible with @code{lex} with the following
+exceptions:
+
+@itemize -
+@item
+The undocumented @code{lex} scanner internal variable @code{yylineno}
+is not supported unless @samp{-l} or @samp{%option yylineno} is used.
+@code{yylineno} should be maintained on a per-buffer basis, rather
+than a per-scanner (single global variable) basis. @code{yylineno} is
+not part of the POSIX specification.
+
+@item
+The @samp{input()} routine is not redefinable, though it
+may be called to read characters following whatever
+has been matched by a rule. If @samp{input()} encounters
+an end-of-file the normal @samp{yywrap()} processing is
+done. A ``real'' end-of-file is returned by
+@samp{input()} as @code{EOF}.
+
+Input is instead controlled by defining the
+@code{YY_INPUT} macro.
+
+The @code{flex} restriction that @samp{input()} cannot be
+redefined is in accordance with the POSIX
+specification, which simply does not specify any way of
+controlling the scanner's input other than by making
+an initial assignment to @code{yyin}.
+
+@item
+The @samp{unput()} routine is not redefinable. This
+restriction is in accordance with POSIX.
+
+@item
+@code{flex} scanners are not as reentrant as @code{lex} scanners.
+In particular, if you have an interactive scanner
+and an interrupt handler which long-jumps out of
+the scanner, and the scanner is subsequently called
+again, you may get the following message:
+
+@example
+fatal flex scanner internal error--end of buffer missed
+@end example
+
+To reenter the scanner, first use
+
+@example
+yyrestart( yyin );
+@end example
+
+Note that this call will throw away any buffered
+input; usually this isn't a problem with an
+interactive scanner.
+
+Also note that flex C++ scanner classes @emph{are}
+reentrant, so if using C++ is an option for you, you
+should use them instead. See "Generating C++
+Scanners" above for details.
+
+@item
+@samp{output()} is not supported. Output from the @samp{ECHO}
+macro is done to the file-pointer @code{yyout} (default
+@code{stdout}).
+
+@samp{output()} is not part of the POSIX specification.
+
+@item
+@code{lex} does not support exclusive start conditions
+(%x), though they are in the POSIX specification.
+
+@item
+When definitions are expanded, @code{flex} encloses them
+in parentheses. With lex, the following:
+
+@example
+NAME [A-Z][A-Z0-9]*
+%%
+foo@{NAME@}? printf( "Found it\n" );
+%%
+@end example
+
+will not match the string "foo" because when the
+macro is expanded the rule is equivalent to
+"foo[A-Z][A-Z0-9]*?" and the precedence is such that the
+'?' is associated with "[A-Z0-9]*". With @code{flex}, the
+rule will be expanded to "foo([A-Z][A-Z0-9]*)?" and
+so the string "foo" will match.
+
+Note that if the definition begins with @samp{^} or ends
+with @samp{$} then it is @emph{not} expanded with parentheses, to
+allow these operators to appear in definitions
+without losing their special meanings. But the
+@samp{<s>, /}, and @samp{<<EOF>>} operators cannot be used in a
+@code{flex} definition.
+
+Using @samp{-l} results in the @code{lex} behavior of no
+parentheses around the definition.
+
+The POSIX specification is that the definition be enclosed in
+parentheses.
+
+@item
+Some implementations of @code{lex} allow a rule's action to begin on
+a separate line, if the rule's pattern has trailing whitespace:
+
+@example
+%%
+foo|bar<space here>
+ @{ foobar_action(); @}
+@end example
+
+@code{flex} does not support this feature.
+
+@item
+The @code{lex} @samp{%r} (generate a Ratfor scanner) option is
+not supported. It is not part of the POSIX
+specification.
+
+@item
+After a call to @samp{unput()}, @code{yytext} is undefined until
+the next token is matched, unless the scanner was
+built using @samp{%array}. This is not the case with @code{lex}
+or the POSIX specification. The @samp{-l} option does
+away with this incompatibility.
+
+@item
+The precedence of the @samp{@{@}} (numeric range) operator
+is different. @code{lex} interprets "abc@{1,3@}" as "match
+one, two, or three occurrences of 'abc'", whereas
+@code{flex} interprets it as "match 'ab' followed by one,
+two, or three occurrences of 'c'". The latter is
+in agreement with the POSIX specification.
+
+@item
+The precedence of the @samp{^} operator is different. @code{lex}
+interprets "^foo|bar" as "match either 'foo' at the
+beginning of a line, or 'bar' anywhere", whereas
+@code{flex} interprets it as "match either 'foo' or 'bar'
+if they come at the beginning of a line". The
+latter is in agreement with the POSIX specification.
+
+@item
+The special table-size declarations such as @samp{%a}
+supported by @code{lex} are not required by @code{flex} scanners;
+@code{flex} ignores them.
+
+@item
+The name FLEX_SCANNER is #define'd so scanners may
+be written for use with either @code{flex} or @code{lex}.
+Scanners also include @code{YY_FLEX_MAJOR_VERSION} and
+@code{YY_FLEX_MINOR_VERSION} indicating which version of
+@code{flex} generated the scanner (for example, for the
+2.5 release, these defines would be 2 and 5
+respectively).
+@end itemize
+
+The following @code{flex} features are not included in @code{lex} or the
+POSIX specification:
+
+@example
+C++ scanners
+%option
+start condition scopes
+start condition stacks
+interactive/non-interactive scanners
+yy_scan_string() and friends
+yyterminate()
+yy_set_interactive()
+yy_set_bol()
+YY_AT_BOL()
+<<EOF>>
+<*>
+YY_DECL
+YY_START
+YY_USER_ACTION
+YY_USER_INIT
+#line directives
+%@{@}'s around actions
+multiple actions on a line
+@end example
+
+@noindent
+plus almost all of the flex flags. The last feature in
+the list refers to the fact that with @code{flex} you can put
+multiple actions on the same line, separated with
+semicolons, while with @code{lex}, the following
+
+@example
+foo handle_foo(); ++num_foos_seen;
+@end example
+
+@noindent
+is (rather surprisingly) truncated to
+
+@example
+foo handle_foo();
+@end example
+
+@code{flex} does not truncate the action. Actions that are not
+enclosed in braces are simply terminated at the end of the
+line.
+
+@node Diagnostics, Files, Incompatibilities, Top
+@section Diagnostics
+
+@table @samp
+@item warning, rule cannot be matched
+indicates that the given
+rule cannot be matched because it follows other rules that
+will always match the same text as it. For example, in
+the following "foo" cannot be matched because it comes
+after an identifier "catch-all" rule:
+
+@example
+[a-z]+ got_identifier();
+foo got_foo();
+@end example
+
+Using @code{REJECT} in a scanner suppresses this warning.
+
+@item warning, -s option given but default rule can be matched
+means that it is possible (perhaps only in a particular
+start condition) that the default rule (match any single
+character) is the only one that will match a particular
+input. Since @samp{-s} was given, presumably this is not
+intended.
+
+@item reject_used_but_not_detected undefined
+@itemx yymore_used_but_not_detected undefined
+These errors can
+occur at compile time. They indicate that the scanner
+uses @code{REJECT} or @samp{yymore()} but that @code{flex} failed to notice the
+fact, meaning that @code{flex} scanned the first two sections
+looking for occurrences of these actions and failed to
+find any, but somehow you snuck some in (via a #include
+file, for example). Use @samp{%option reject} or @samp{%option yymore}
+to indicate to flex that you really do use these features.
+
+@item flex scanner jammed
+a scanner compiled with @samp{-s} has
+encountered an input string which wasn't matched by any of
+its rules. This error can also occur due to internal
+problems.
+
+@item token too large, exceeds YYLMAX
+your scanner uses @samp{%array}
+and one of its rules matched a string longer than the @samp{YYL-}
+@code{MAX} constant (8K bytes by default). You can increase the
+value by #define'ing @code{YYLMAX} in the definitions section of
+your @code{flex} input.
+
+@item scanner requires -8 flag to use the character '@var{x}'
+Your
+scanner specification includes recognizing the 8-bit
+character @var{x} and you did not specify the -8 flag, and your
+scanner defaulted to 7-bit because you used the @samp{-Cf} or @samp{-CF}
+table compression options. See the discussion of the @samp{-7}
+flag for details.
+
+@item flex scanner push-back overflow
+you used @samp{unput()} to push
+back so much text that the scanner's buffer could not hold
+both the pushed-back text and the current token in @code{yytext}.
+Ideally the scanner should dynamically resize the buffer
+in this case, but at present it does not.
+
+@item input buffer overflow, can't enlarge buffer because scanner uses REJECT
+the scanner was working on matching an
+extremely large token and needed to expand the input
+buffer. This doesn't work with scanners that use @code{REJECT}.
+
+@item fatal flex scanner internal error--end of buffer missed
+This can occur in an scanner which is reentered after a
+long-jump has jumped out (or over) the scanner's
+activation frame. Before reentering the scanner, use:
+
+@example
+yyrestart( yyin );
+@end example
+
+@noindent
+or, as noted above, switch to using the C++ scanner class.
+
+@item too many start conditions in <> construct!
+you listed
+more start conditions in a <> construct than exist (so you
+must have listed at least one of them twice).
+@end table
+
+@node Files, Deficiencies, Diagnostics, Top
+@section Files
+
+@table @file
+@item -lfl
+library with which scanners must be linked.
+
+@item lex.yy.c
+generated scanner (called @file{lexyy.c} on some systems).
+
+@item lex.yy.cc
+generated C++ scanner class, when using @samp{-+}.
+
+@item <FlexLexer.h>
+header file defining the C++ scanner base class,
+@code{FlexLexer}, and its derived class, @code{yyFlexLexer}.
+
+@item flex.skl
+skeleton scanner. This file is only used when
+building flex, not when flex executes.
+
+@item lex.backup
+backing-up information for @samp{-b} flag (called @file{lex.bck}
+on some systems).
+@end table
+
+@node Deficiencies, See also, Files, Top
+@section Deficiencies / Bugs
+
+Some trailing context patterns cannot be properly matched
+and generate warning messages ("dangerous trailing
+context"). These are patterns where the ending of the first
+part of the rule matches the beginning of the second part,
+such as "zx*/xy*", where the 'x*' matches the 'x' at the
+beginning of the trailing context. (Note that the POSIX
+draft states that the text matched by such patterns is
+undefined.)
+
+For some trailing context rules, parts which are actually
+fixed-length are not recognized as such, leading to the
+abovementioned performance loss. In particular, parts
+using '|' or @{n@} (such as "foo@{3@}") are always considered
+variable-length.
+
+Combining trailing context with the special '|' action can
+result in @emph{fixed} trailing context being turned into the
+more expensive @var{variable} trailing context. For example, in
+the following:
+
+@example
+%%
+abc |
+xyz/def
+@end example
+
+Use of @samp{unput()} invalidates yytext and yyleng, unless the
+@samp{%array} directive or the @samp{-l} option has been used.
+
+Pattern-matching of NUL's is substantially slower than
+matching other characters.
+
+Dynamic resizing of the input buffer is slow, as it
+entails rescanning all the text matched so far by the
+current (generally huge) token.
+
+Due to both buffering of input and read-ahead, you cannot
+intermix calls to <stdio.h> routines, such as, for
+example, @samp{getchar()}, with @code{flex} rules and expect it to work.
+Call @samp{input()} instead.
+
+The total table entries listed by the @samp{-v} flag excludes the
+number of table entries needed to determine what rule has
+been matched. The number of entries is equal to the
+number of DFA states if the scanner does not use @code{REJECT}, and
+somewhat greater than the number of states if it does.
+
+@code{REJECT} cannot be used with the @samp{-f} or @samp{-F} options.
+
+The @code{flex} internal algorithms need documentation.
+
+@node See also, Author, Deficiencies, Top
+@section See also
+
+@code{lex}(1), @code{yacc}(1), @code{sed}(1), @code{awk}(1).
+
+John Levine, Tony Mason, and Doug Brown: Lex & Yacc;
+O'Reilly and Associates. Be sure to get the 2nd edition.
+
+M. E. Lesk and E. Schmidt, LEX - Lexical Analyzer Generator.
+
+Alfred Aho, Ravi Sethi and Jeffrey Ullman: Compilers:
+Principles, Techniques and Tools; Addison-Wesley (1986).
+Describes the pattern-matching techniques used by @code{flex}
+(deterministic finite automata).
+
+@node Author, , See also, Top
+@section Author
+
+Vern Paxson, with the help of many ideas and much inspiration from
+Van Jacobson. Original version by Jef Poskanzer. The fast table
+representation is a partial implementation of a design done by Van
+Jacobson. The implementation was done by Kevin Gong and Vern Paxson.
+
+Thanks to the many @code{flex} beta-testers, feedbackers, and
+contributors, especially Francois Pinard, Casey Leedom, Stan
+Adermann, Terry Allen, David Barker-Plummer, John Basrai, Nelson
+H.F. Beebe, @samp{benson@@odi.com}, Karl Berry, Peter A. Bigot,
+Simon Blanchard, Keith Bostic, Frederic Brehm, Ian Brockbank, Kin
+Cho, Nick Christopher, Brian Clapper, J.T. Conklin, Jason Coughlin,
+Bill Cox, Nick Cropper, Dave Curtis, Scott David Daniels, Chris
+G. Demetriou, Theo Deraadt, Mike Donahue, Chuck Doucette, Tom Epperly,
+Leo Eskin, Chris Faylor, Chris Flatters, Jon Forrest, Joe Gayda, Kaveh
+R. Ghazi, Eric Goldman, Christopher M. Gould, Ulrich Grepel, Peer
+Griebel, Jan Hajic, Charles Hemphill, NORO Hideo, Jarkko Hietaniemi,
+Scott Hofmann, Jeff Honig, Dana Hudes, Eric Hughes, John Interrante,
+Ceriel Jacobs, Michal Jaegermann, Sakari Jalovaara, Jeffrey R. Jones,
+Henry Juengst, Klaus Kaempf, Jonathan I. Kamens, Terrence O Kane,
+Amir Katz, @samp{ken@@ken.hilco.com}, Kevin B. Kenny, Steve Kirsch,
+Winfried Koenig, Marq Kole, Ronald Lamprecht, Greg Lee, Rohan Lenard,
+Craig Leres, John Levine, Steve Liddle, Mike Long, Mohamed el Lozy,
+Brian Madsen, Malte, Joe Marshall, Bengt Martensson, Chris Metcalf,
+Luke Mewburn, Jim Meyering, R. Alexander Milowski, Erik Naggum,
+G.T. Nicol, Landon Noll, James Nordby, Marc Nozell, Richard Ohnemus,
+Karsten Pahnke, Sven Panne, Roland Pesch, Walter Pelissero, Gaumond
+Pierre, Esmond Pitt, Jef Poskanzer, Joe Rahmeh, Jarmo Raiha, Frederic
+Raimbault, Pat Rankin, Rick Richardson, Kevin Rodgers, Kai Uwe Rommel,
+Jim Roskind, Alberto Santini, Andreas Scherer, Darrell Schiebel, Raf
+Schietekat, Doug Schmidt, Philippe Schnoebelen, Andreas Schwab, Alex
+Siegel, Eckehard Stolz, Jan-Erik Strvmquist, Mike Stump, Paul Stuart,
+Dave Tallman, Ian Lance Taylor, Chris Thewalt, Richard M. Timoney,
+Jodi Tsai, Paul Tuinenga, Gary Weik, Frank Whaley, Gerhard Wilhelms,
+Kent Williams, Ken Yap, Ron Zellar, Nathan Zelle, David Zuhn, and
+those whose names have slipped my marginal mail-archiving skills but
+whose contributions are appreciated all the same.
+
+Thanks to Keith Bostic, Jon Forrest, Noah Friedman, John Gilmore,
+Craig Leres, John Levine, Bob Mulcahy, G.T. Nicol, Francois Pinard,
+Rich Salz, and Richard Stallman for help with various distribution
+headaches.
+
+Thanks to Esmond Pitt and Earle Horton for 8-bit character support;
+to Benson Margulies and Fred Burke for C++ support; to Kent Williams
+and Tom Epperly for C++ class support; to Ove Ewerlid for support of
+NUL's; and to Eric Hughes for support of multiple buffers.
+
+This work was primarily done when I was with the Real Time Systems
+Group at the Lawrence Berkeley Laboratory in Berkeley, CA. Many thanks
+to all there for the support I received.
+
+Send comments to @samp{vern@@ee.lbl.gov}.
+
+@c @node Index, , Top, Top
+@c @unnumbered Index
+@c
+@c @printindex cp
+
+@contents
+@bye
+
+@c Local variables:
+@c texinfo-column-for-description: 32
+@c End:
diff --git a/Tools/android/flex-2.5.4a/Makefile.in b/Tools/android/flex-2.5.4a/Makefile.in
new file mode 100644
index 0000000..c414220
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/Makefile.in
@@ -0,0 +1,262 @@
+# @(#) $Header: /home/daffy/u0/vern/flex/RCS/Makefile.in,v 1.45 96/09/10 16:59:04 vern Exp $ (LBL)
+
+@SET_MAKE@
+
+# Possible values for DEFS:
+#
+# By default, flex generates 8-bit scanners when using table compression,
+# and 7-bit scanners when using uncompressed tables (-f or -F options).
+# For flex to always generate 8-bit scanners, add "-DDEFAULT_CSIZE=256"
+# to DEFS.
+#
+# For Vax/VMS, add "-DVMS" to DEFS.
+#
+# For MS-DOS, add "-DMS_DOS" to DEFS. See the directory MISC/MSDOS for
+# additional info.
+
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+DEFS = @DEFS@
+LDFLAGS =
+LIBS = @LIBS@
+
+# Installation targeting. Files will be installed under the tree
+# rooted at prefix. flex will be installed in bindir, libfl.a in
+# libdir, FlexLexer.h will be installed in includedir, and the manual
+# pages will be installed in mandir with extension manext.
+#
+# Raw, unformatted troff source will be installed if INSTALLMAN=man,
+# nroff preformatted versions will be installed if INSTALLMAN=cat.
+
+prefix = @prefix@
+exec_prefix = @exec_prefix@
+bindir = $(exec_prefix)/bin
+libdir = $(exec_prefix)/lib
+includedir = $(prefix)/include
+manext = 1
+mandir = $(prefix)/man/man$(manext)
+
+# You can define these to be "lex" and "libl.a" if you want to replace
+# lex at your site.
+FLEX = flex
+FLEXLIB = libfl.a
+
+INSTALLMAN = man
+
+SHELL = /bin/sh
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+LN_S = @LN_S@
+YACC = @YACC@
+CC = @CC@
+AR = ar
+RANLIB = @RANLIB@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+
+# You normally do not need to modify anything below this point.
+# ------------------------------------------------------------
+
+CPPFLAGS = -I. -I$(srcdir)
+
+.c.o:
+ $(CC) -c $(CPPFLAGS) $(CFLAGS) $<
+
+HEADERS = flexdef.h version.h
+
+SOURCES = ccl.c dfa.c ecs.c gen.c main.c misc.c nfa.c parse.y \
+ scan.l skel.c sym.c tblcmp.c yylex.c
+OBJECTS = ccl.o dfa.o ecs.o gen.o main.o misc.o nfa.o parse.o \
+ scan.o skel.o sym.o tblcmp.o yylex.o @ALLOCA@
+
+LIBSRCS = libmain.c libyywrap.c
+LIBOBJS = libmain.o libyywrap.o
+
+LINTSRCS = ccl.c dfa.c ecs.c gen.c main.c misc.c nfa.c parse.c \
+ scan.c skel.c sym.c tblcmp.c yylex.c
+
+DISTFILES = README NEWS COPYING INSTALL FlexLexer.h \
+ configure.in conf.in Makefile.in mkskel.sh flex.skl \
+ $(HEADERS) $(SOURCES) $(LIBSRCS) MISC \
+ flex.1 scan.c install.sh mkinstalldirs configure
+
+DIST_NAME = flex
+
+# which "flex" to use to generate scan.c from scan.l
+FLEX_EXEC = ./$(FLEX)
+FLEX_FLAGS = -t $(PERF_REPORT)
+COMPRESSION =
+PERF_REPORT = -p
+
+
+all: $(FLEX)
+
+$(FLEX): .bootstrap $(OBJECTS) $(FLEXLIB)
+ $(CC) $(CFLAGS) -o $(FLEX) $(LDFLAGS) $(OBJECTS) $(FLEXLIB) $(LIBS)
+
+.bootstrap: initscan.c
+ @rm -f scan.c
+ cp $(srcdir)/initscan.c scan.c
+ touch .bootstrap
+
+parse.c: parse.y
+ $(YACC) -d $(srcdir)/parse.y
+ @sed '/extern char.*malloc/d' <y.tab.c >parse.tmp
+ @mv parse.tmp parse.c
+ @mv y.tab.h parse.h
+ @rm -f y.tab.c
+
+parse.h: parse.c
+
+scan.c: scan.l
+ $(FLEX_EXEC) $(FLEX_FLAGS) $(COMPRESSION) $(srcdir)/scan.l >scan.c
+ @sed s,\"$(srcdir)/scan.l\",\"scan.l\", <scan.c >scan.tmp
+ @mv scan.tmp scan.c
+
+scan.o: scan.c parse.h flexdef.h config.h
+yylex.o: yylex.c parse.h flexdef.h config.h
+
+skel.c: flex.skl mkskel.sh
+ $(SHELL) $(srcdir)/mkskel.sh $(srcdir)/flex.skl >skel.c
+
+main.o: main.c flexdef.h config.h version.h
+ccl.o: ccl.c flexdef.h config.h
+dfa.o: dfa.c flexdef.h config.h
+ecs.o: ecs.c flexdef.h config.h
+gen.o: gen.c flexdef.h config.h
+misc.o: misc.c flexdef.h config.h
+nfa.o: nfa.c flexdef.h config.h
+parse.o: parse.c flexdef.h config.h
+skel.o: skel.c flexdef.h config.h
+sym.o: sym.c flexdef.h config.h
+tblcmp.o: tblcmp.c flexdef.h config.h
+
+alloca.o: alloca.c
+ $(CC) $(CPPFLAGS) $(CFLAGS) -c -Dxmalloc=yy_flex_xmalloc alloca.c
+
+alloca.c: $(srcdir)/MISC/alloca.c
+ @rm -f alloca.c
+ cp $(srcdir)/MISC/alloca.c .
+
+test: check
+check: $(FLEX)
+ $(FLEX_EXEC) $(FLEX_FLAGS) $(COMPRESSION) $(srcdir)/scan.l \
+ | sed s,\"$(srcdir)/scan.l\",\"scan.l\", \
+ | diff scan.c -
+ @echo "Check successful, using COMPRESSION=\"$(COMPRESSION)\""
+
+bigcheck:
+ rm -f scan.c ; $(MAKE) COMPRESSION="-C" check
+ rm -f scan.c ; $(MAKE) COMPRESSION="-Ce" check
+ rm -f scan.c ; $(MAKE) COMPRESSION="-Cm" check
+ rm -f scan.c ; $(MAKE) COMPRESSION="-f" check
+ rm -f scan.c ; $(MAKE) COMPRESSION="-Cfea" check
+ rm -f scan.c ; $(MAKE) COMPRESSION="-CFer" check
+ rm -f scan.c ; $(MAKE) COMPRESSION="-l" PERF_REPORT="" check
+ rm -f scan.c ; $(MAKE)
+ @echo "All checks successful"
+
+$(FLEXLIB): $(LIBOBJS)
+ $(AR) cru $(FLEXLIB) $(LIBOBJS)
+ -$(RANLIB) $(FLEXLIB)
+
+$(FLEX).man: flex.1
+ cd $(srcdir) && nroff -man flex.1 >$(FLEX).man
+
+install: $(FLEX) $(FLEXLIB) installdirs install.$(INSTALLMAN)
+ $(INSTALL_PROGRAM) $(FLEX) $(bindir)/$(FLEX)
+ @rm -f $(bindir)/$(FLEX)++
+ cd $(bindir) && $(LN_S) $(FLEX) $(FLEX)++
+ $(INSTALL_DATA) $(FLEXLIB) $(libdir)/$(FLEXLIB)
+ -cd $(libdir) && $(RANLIB) $(FLEXLIB)
+ $(INSTALL_DATA) $(srcdir)/FlexLexer.h $(includedir)/FlexLexer.h
+
+# Note, the following rules delete any vestigial flexdoc installed
+# for a prior flex release.
+install.man: flex.1
+ rm -f $(mandir)/$(FLEX)doc.$(manext)
+ $(INSTALL_DATA) $(srcdir)/flex.1 $(mandir)/$(FLEX).$(manext)
+
+install.cat: $(FLEX).man
+ rm -f $(mandir)/$(FLEX)doc.$(manext)
+ $(INSTALL_DATA) $(srcdir)/$(FLEX).man $(mandir)/$(FLEX).$(manext)
+
+installdirs:
+ $(SHELL) $(srcdir)/mkinstalldirs \
+ $(bindir) $(libdir) $(includedir) $(mandir)
+
+uninstall:
+ rm -f $(bindir)/$(FLEX) $(bindir)/$(FLEX)++
+ rm -f $(libdir)/$(FLEXLIB)
+ rm -f $(includedir)/FlexLexer.h
+ rm -f $(mandir)/$(FLEX).$(manext) $(mandir)/$(FLEX)doc.$(manext)
+
+tags: $(SOURCES)
+ ctags $(SOURCES)
+
+TAGS: $(SOURCES)
+ etags $(SOURCES)
+
+lint: $(LINTSRCS)
+ lint -Dconst= $(LINTSRCS) > flex.lint
+
+gcc-lint: $(LINTSRCS)
+ gcc -Dlint -Wall $(LINTSRCS) >flex.gcc-lint 2>&1
+
+mostlyclean:
+ rm -f a.out *.bak core errs scan.tmp
+
+clean: mostlyclean
+ rm -f flex parse.c parse.h *.o alloca.c *.lint lex.yy.c lex.yy.cc \
+ $(FLEXLIB) config.log config.cache
+
+distclean: clean
+ rm -f .bootstrap $(FLEX) scan.c tags TAGS Makefile config.status \
+ config.h stamp-h config.log config.cache
+
+maintainer-clean: distclean
+ @echo "This command is intended for maintainers to use;"
+ @echo "it deletes files that may require special tools to rebuild."
+ rm -f $(FLEX).man skel.c flex*.tar.gz flex*.tar.Z
+
+dist: $(FLEX) $(DISTFILES) parse.c parse.h $(srcdir)/$(FLEX).man
+ $(MAKE) DIST_NAME=flex-`sed <version.h 's/[^"]*"//' | sed 's/"//'` dist2
+
+dist2:
+ @rm -rf $(DIST_NAME)
+ @rm -f $(DIST_NAME).tar $(DIST_NAME).tar.Z $(DIST_NAME).tar.gz
+ @mkdir $(DIST_NAME)
+ tar cf - $(DISTFILES) | (cd $(DIST_NAME) && tar xfB -)
+ @mv $(DIST_NAME)/scan.c $(DIST_NAME)/initscan.c
+ @chmod 444 $(DIST_NAME)/initscan.c
+ @chmod +w $(DIST_NAME)/Makefile.in
+ @cp parse.c parse.h $(DIST_NAME)/MISC
+ @col -b <$(srcdir)/$(FLEX).man >$(DIST_NAME)/MISC/flex.man
+ tar chf $(DIST_NAME).tar $(DIST_NAME)
+ compress <$(DIST_NAME).tar >$(DIST_NAME).tar.Z
+ gzip <$(DIST_NAME).tar >$(DIST_NAME).tar.gz
+ @rm $(DIST_NAME).tar
+
+# For an explanation of the following Makefile rules, see node
+# `Automatic Remaking' in GNU Autoconf documentation.
+Makefile: $(srcdir)/Makefile.in config.status
+ CONFIG_FILES=$@ CONFIG_HEADERS= ./config.status
+config.status: configure
+ ./config.status --recheck
+configure: configure.in
+ cd $(srcdir) && autoconf
+config.h: stamp-h
+stamp-h: conf.in config.status
+ CONFIG_FILES= CONFIG_HEADERS=config.h:conf.in ./config.status
+ echo timestamp >stamp-h
+# conf.in: stamp-h.in
+# stamp-h.in: configure.in acconfig.h
+# cd $(srcdir) && autoheader
+# config.h.in conf.in
+# cho timestamp > $(srcdir)/stamp-h.in
+
+# Tell versions [3.59,3.63) of GNU make not to export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/Tools/android/flex-2.5.4a/NEWS b/Tools/android/flex-2.5.4a/NEWS
new file mode 100644
index 0000000..3e23e7d
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/NEWS
@@ -0,0 +1,1233 @@
+Changes between release 2.5.4 (11Sep96) and release 2.5.3:
+
+ - Fixed a bug introduced in 2.5.3 that blew it when a call
+ to input() occurred at the end of an input file.
+
+ - Fixed scanner skeleton so the example in the man page of
+ scanning strings using exclusive start conditions works.
+
+ - Minor Makefile tweaks.
+
+
+Changes between release 2.5.3 (29May96) and release 2.5.2:
+
+ - Some serious bugs in yymore() have been fixed. In particular,
+ when using AT&T-lex-compatibility or %array, you can intermix
+ calls to input(), unput(), and yymore(). (This still doesn't
+ work for %pointer, and isn't likely to in the future.)
+
+ - A bug in handling NUL's in the input stream of scanners using
+ REJECT has been fixed.
+
+ - The default main() in libfl.a now repeatedly calls yylex() until
+ it returns 0, rather than just calling it once.
+
+ - Minor tweak for Windows NT Makefile, MISC/NT/Makefile.
+
+
+Changes between release 2.5.2 (25Apr95) and release 2.5.1:
+
+ - The --prefix configuration option now works.
+
+ - A bug that completely broke the "-Cf" table compression
+ option has been fixed.
+
+ - A major headache involving "const" declarators and Solaris
+ systems has been fixed.
+
+ - An octal escape sequence in a flex regular expression must
+ now contain only the digits 0-7.
+
+ - You can now use "--" on the flex command line to mark the
+ end of flex options.
+
+ - You can now specify the filename '-' as a synonym for stdin.
+
+ - By default, the scanners generated by flex no longer
+ statically initialize yyin and yyout to stdin and stdout.
+ This change is necessary because in some ANSI environments,
+ stdin and stdout are not compile-time constant. You can
+ force the initialization using "%option stdinit" in the first
+ section of your flex input.
+
+ - "%option nounput" now correctly omits the unput() routine
+ from the output.
+
+ - "make clean" now removes config.log, config.cache, and the
+ flex binary. The fact that it removes the flex binary means
+ you should take care if making changes to scan.l, to make
+ sure you don't wind up in a bootstrap problem.
+
+ - In general, the Makefile has been reworked somewhat (thanks
+ to Francois Pinard) for added flexibility - more changes will
+ follow in subsequent releases.
+
+ - The .texi and .info files in MISC/texinfo/ have been updated,
+ thanks also to Francois Pinard.
+
+ - The FlexLexer::yylex(istream* new_in, ostream* new_out) method
+ now does not have a default for the first argument, to disambiguate
+ it from FlexLexer::yylex().
+
+ - A bug in destructing a FlexLexer object before doing any scanning
+ with it has been fixed.
+
+ - A problem with including FlexLexer.h multiple times has been fixed.
+
+ - The alloca() chud necessary to accommodate bison has grown
+ even uglier, but hopefully more correct.
+
+ - A portability tweak has been added to accommodate compilers that
+ use char* generic pointers.
+
+ - EBCDIC contact information in the file MISC/EBCDIC has been updated.
+
+ - An OS/2 Makefile and config.h for flex 2.5 is now available in
+ MISC/OS2/, contributed by Kai Uwe Rommel.
+
+ - The descrip.mms file for building flex under VMS has been updated,
+ thanks to Pat Rankin.
+
+ - The notes on building flex for the Amiga have been updated for
+ flex 2.5, contributed by Andreas Scherer.
+
+
+Changes between release 2.5.1 (28Mar95) and release 2.4.7:
+
+ - A new concept of "start condition" scope has been introduced.
+ A start condition scope is begun with:
+
+ <SCs>{
+
+ where SCs is a list of one or more start conditions. Inside
+ the start condition scope, every rule automatically has the
+ prefix <SCs> applied to it, until a '}' which matches the
+ initial '{'. So, for example:
+
+ <ESC>{
+ "\\n" return '\n';
+ "\\r" return '\r';
+ "\\f" return '\f';
+ "\\0" return '\0';
+ }
+
+ is equivalent to:
+
+ <ESC>"\\n" return '\n';
+ <ESC>"\\r" return '\r';
+ <ESC>"\\f" return '\f';
+ <ESC>"\\0" return '\0';
+
+ As indicated in this example, rules inside start condition scopes
+ (and any rule, actually, other than the first) can be indented,
+ to better show the extent of the scope.
+
+ Start condition scopes may be nested.
+
+ - The new %option directive can be used in the first section of
+ a flex scanner to control scanner-generation options. Most
+ options are given simply as names, optionally preceded by the
+ word "no" (with no intervening whitespace) to negate their
+ meaning. Some are equivalent to flex flags, so putting them
+ in your scanner source is equivalent to always specifying
+ the flag (%option's take precedence over flags):
+
+ 7bit -7 option
+ 8bit -8 option
+ align -Ca option
+ backup -b option
+ batch -B option
+ c++ -+ option
+ caseful opposite of -i option (caseful is the default);
+ case-sensitive same as above
+ caseless -i option;
+ case-insensitive same as above
+ debug -d option
+ default opposite of -s option
+ ecs -Ce option
+ fast -F option
+ full -f option
+ interactive -I option
+ lex-compat -l option
+ meta-ecs -Cm option
+ perf-report -p option
+ read -Cr option
+ stdout -t option
+ verbose -v option
+ warn opposite of -w option (so use "%option nowarn" for -w)
+
+ array equivalent to "%array"
+ pointer equivalent to "%pointer" (default)
+
+ Some provide new features:
+
+ always-interactive generate a scanner which always
+ considers its input "interactive" (no call to isatty()
+ will be made when the scanner runs)
+ main supply a main program for the scanner, which
+ simply calls yylex(). Implies %option noyywrap.
+ never-interactive generate a scanner which never
+ considers its input "interactive" (no call to isatty()
+ will be made when the scanner runs)
+ stack if set, enable start condition stacks (see below)
+ stdinit if unset ("%option nostdinit"), initialize yyin
+ and yyout statically to nil FILE* pointers, instead
+ of stdin and stdout
+ yylineno if set, keep track of the current line
+ number in global yylineno (this option is expensive
+ in terms of performance). The line number is available
+ to C++ scanning objects via the new member function
+ lineno().
+ yywrap if unset ("%option noyywrap"), scanner does not
+ call yywrap() upon EOF but simply assumes there
+ are no more files to scan
+
+ Flex scans your rule actions to determine whether you use the
+ REJECT or yymore features (this is not new). Two %options can be
+ used to override its decision, either by setting them to indicate
+ the feature is indeed used, or unsetting them to indicate it
+ actually is not used:
+
+ reject
+ yymore
+
+ Three %option's take string-delimited values, offset with '=':
+
+ outfile="<name>" equivalent to -o<name>
+ prefix="<name>" equivalent to -P<name>
+ yyclass="<name>" set the name of the C++ scanning class
+ (see below)
+
+ A number of %option's are available for lint purists who
+ want to suppress the appearance of unneeded routines in
+ the generated scanner. Each of the following, if unset,
+ results in the corresponding routine not appearing in the
+ generated scanner:
+
+ input, unput
+ yy_push_state, yy_pop_state, yy_top_state
+ yy_scan_buffer, yy_scan_bytes, yy_scan_string
+
+ You can specify multiple options with a single %option directive,
+ and multiple directives in the first section of your flex input file.
+
+ - The new function:
+
+ YY_BUFFER_STATE yy_scan_string( const char *str )
+
+ returns a YY_BUFFER_STATE (which also becomes the current input
+ buffer) for scanning the given string, which occurs starting
+ with the next call to yylex(). The string must be NUL-terminated.
+ A related function:
+
+ YY_BUFFER_STATE yy_scan_bytes( const char *bytes, int len )
+
+ creates a buffer for scanning "len" bytes (including possibly NUL's)
+ starting at location "bytes".
+
+ Note that both of these functions create and scan a *copy* of
+ the string/bytes. (This may be desirable, since yylex() modifies
+ the contents of the buffer it is scanning.) You can avoid the
+ copy by using:
+
+ YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+
+ which scans in place the buffer starting at "base", consisting
+ of "size" bytes, the last two bytes of which *must* be
+ YY_END_OF_BUFFER_CHAR (these bytes are not scanned; thus, scanning
+ consists of base[0] through base[size-2], inclusive). If you
+ fail to set up "base" in this manner, yy_scan_buffer returns a
+ nil pointer instead of creating a new input buffer.
+
+ The type yy_size_t is an integral type to which you can cast
+ an integer expression reflecting the size of the buffer.
+
+ - Three new routines are available for manipulating stacks of
+ start conditions:
+
+ void yy_push_state( int new_state )
+
+ pushes the current start condition onto the top of the stack
+ and BEGIN's "new_state" (recall that start condition names are
+ also integers).
+
+ void yy_pop_state()
+
+ pops the top of the stack and BEGIN's to it, and
+
+ int yy_top_state()
+
+ returns the top of the stack without altering the stack's
+ contents.
+
+ The start condition stack grows dynamically and so has no built-in
+ size limitation. If memory is exhausted, program execution
+ is aborted.
+
+ To use start condition stacks, your scanner must include
+ a "%option stack" directive.
+
+ - flex now supports POSIX character class expressions. These
+ are expressions enclosed inside "[:" and ":]" delimiters (which
+ themselves must appear between the '[' and ']' of a character
+ class; other elements may occur inside the character class, too).
+ The expressions flex recognizes are:
+
+ [:alnum:] [:alpha:] [:blank:] [:cntrl:] [:digit:] [:graph:]
+ [:lower:] [:print:] [:punct:] [:space:] [:upper:] [:xdigit:]
+
+ These expressions all designate a set of characters equivalent to
+ the corresponding isXXX function (for example, [:alnum:] designates
+ those characters for which isalnum() returns true - i.e., any
+ alphabetic or numeric). Some systems don't provide isblank(),
+ so flex defines [:blank:] as a blank or a tab.
+
+ For example, the following character classes are all equivalent:
+
+ [[:alnum:]]
+ [[:alpha:][:digit:]
+ [[:alpha:]0-9]
+ [a-zA-Z0-9]
+
+ If your scanner is case-insensitive (-i flag), then [:upper:]
+ and [:lower:] are equivalent to [:alpha:].
+
+ - The promised rewrite of the C++ FlexLexer class has not yet
+ been done. Support for FlexLexer is limited at the moment to
+ fixing show-stopper bugs, so, for example, the new functions
+ yy_scan_string() & friends are not available to FlexLexer
+ objects.
+
+ - The new macro
+
+ yy_set_interactive(is_interactive)
+
+ can be used to control whether the current buffer is considered
+ "interactive". An interactive buffer is processed more slowly,
+ but must be used when the scanner's input source is indeed
+ interactive to avoid problems due to waiting to fill buffers
+ (see the discussion of the -I flag in flex.1). A non-zero value
+ in the macro invocation marks the buffer as interactive, a zero
+ value as non-interactive. Note that use of this macro overrides
+ "%option always-interactive" or "%option never-interactive".
+
+ yy_set_interactive() must be invoked prior to beginning to
+ scan the buffer.
+
+ - The new macro
+
+ yy_set_bol(at_bol)
+
+ can be used to control whether the current buffer's scanning
+ context for the next token match is done as though at the
+ beginning of a line (non-zero macro argument; makes '^' anchored
+ rules active) or not at the beginning of a line (zero argument,
+ '^' rules inactive).
+
+ - Related to this change, the mechanism for determining when a scan is
+ starting at the beginning of a line has changed. It used to be
+ that '^' was active iff the character prior to that at which the
+ scan started was a newline. The mechanism now is that '^' is
+ active iff the last token ended in a newline (or the last call to
+ input() returned a newline). For most users, the difference in
+ mechanisms is negligible. Where it will make a difference,
+ however, is if unput() or yyless() is used to alter the input
+ stream. When in doubt, use yy_set_bol().
+
+ - The new beginning-of-line mechanism involved changing some fairly
+ twisted code, so it may have introduced bugs - beware ...
+
+ - The macro YY_AT_BOL() returns true if the next token scanned from
+ the current buffer will have '^' rules active, false otherwise.
+
+ - The new function
+
+ void yy_flush_buffer( struct yy_buffer_state* b )
+
+ flushes the contents of the current buffer (i.e., next time
+ the scanner attempts to match a token using b as the current
+ buffer, it will begin by invoking YY_INPUT to fill the buffer).
+ This routine is also available to C++ scanners (unlike some
+ of the other new routines).
+
+ The related macro
+
+ YY_FLUSH_BUFFER
+
+ flushes the contents of the current buffer.
+
+ - A new "-ooutput" option writes the generated scanner to "output".
+ If used with -t, the scanner is still written to stdout, but
+ its internal #line directives (see previous item) use "output".
+
+ - Flex now generates #line directives relating the code it
+ produces to the output file; this means that error messages
+ in the flex-generated code should be correctly pinpointed.
+
+ - When generating #line directives, filenames with embedded '\'s
+ have those characters escaped (i.e., turned into '\\'). This
+ feature helps with reporting filenames for some MS-DOS and OS/2
+ systems.
+
+ - The FlexLexer class includes two new public member functions:
+
+ virtual void switch_streams( istream* new_in = 0,
+ ostream* new_out = 0 )
+
+ reassigns yyin to new_in (if non-nil) and yyout to new_out
+ (ditto), deleting the previous input buffer if yyin is
+ reassigned. It is used by:
+
+ int yylex( istream* new_in = 0, ostream* new_out = 0 )
+
+ which first calls switch_streams() and then returns the value
+ of calling yylex().
+
+ - C++ scanners now have yy_flex_debug as a member variable of
+ FlexLexer rather than a global, and member functions for testing
+ and setting it.
+
+ - When generating a C++ scanning class, you can now use
+
+ %option yyclass="foo"
+
+ to inform flex that you have derived "foo" as a subclass of
+ yyFlexLexer, so flex will place your actions in the member
+ function foo::yylex() instead of yyFlexLexer::yylex(). It also
+ generates a yyFlexLexer::yylex() member function that generates a
+ run-time error if called (by invoking yyFlexLexer::LexerError()).
+ This feature is necessary if your subclass "foo" introduces some
+ additional member functions or variables that you need to access
+ from yylex().
+
+ - Current texinfo files in MISC/texinfo, contributed by Francois
+ Pinard.
+
+ - You can now change the name "flex" to something else (e.g., "lex")
+ by redefining $(FLEX) in the Makefile.
+
+ - Two bugs (one serious) that could cause "bigcheck" to fail have
+ been fixed.
+
+ - A number of portability/configuration changes have been made
+ for easier portability.
+
+ - You can use "YYSTATE" in your scanner as an alias for YY_START
+ (for AT&T lex compatibility).
+
+ - input() now maintains yylineno.
+
+ - input() no longer trashes yytext.
+
+ - interactive scanners now read characters in YY_INPUT up to a
+ newline, a large performance gain.
+
+ - C++ scanner objects now work with the -P option. You include
+ <FlexLexer.h> once per scanner - see comments in <FlexLexer.h>
+ (or flex.1) for details.
+
+ - C++ FlexLexer objects now use the "cerr" stream to report -d output
+ instead of stdio.
+
+ - The -c flag now has its full glorious POSIX interpretation (do
+ nothing), rather than being interpreted as an old-style -C flag.
+
+ - Scanners generated by flex now include two #define's giving
+ the major and minor version numbers (YY_FLEX_MAJOR_VERSION,
+ YY_FLEX_MINOR_VERSION). These can then be tested to see
+ whether certain flex features are available.
+
+ - Scanners generated using -l lex compatibility now have the symbol
+ YY_FLEX_LEX_COMPAT #define'd.
+
+ - When initializing (i.e., yy_init is non-zero on entry to yylex()),
+ generated scanners now set yy_init to zero before executing
+ YY_USER_INIT. This means that you can set yy_init back to a
+ non-zero value in YY_USER_INIT if you need the scanner to be
+ reinitialized on the next call.
+
+ - You can now use "#line" directives in the first section of your
+ scanner specification.
+
+ - When generating full-table scanners (-Cf), flex now puts braces
+ around each row of the 2-d array initialization, to silence warnings
+ on over-zealous compilers.
+
+ - Improved support for MS-DOS. The flex sources have been successfully
+ built, unmodified, for Borland 4.02 (all that's required is a
+ Borland Makefile and config.h file, which are supplied in
+ MISC/Borland - contributed by Terrence O Kane).
+
+ - Improved support for Macintosh using Think C - the sources should
+ build for this platform "out of the box". Contributed by Scott
+ Hofmann.
+
+ - Improved support for VMS, in MISC/VMS/, contributed by Pat Rankin.
+
+ - Support for the Amiga, in MISC/Amiga/, contributed by Andreas
+ Scherer. Note that the contributed files were developed for
+ flex 2.4 and have not been tested with flex 2.5.
+
+ - Some notes on support for the NeXT, in MISC/NeXT, contributed
+ by Raf Schietekat.
+
+ - The MISC/ directory now includes a preformatted version of flex.1
+ in flex.man, and pre-yacc'd versions of parse.y in parse.{c,h}.
+
+ - The flex.1 and flexdoc.1 manual pages have been merged. There
+ is now just one document, flex.1, which includes an overview
+ at the beginning to help you find the section you need.
+
+ - Documentation now clarifies that start conditions persist across
+ switches to new input files or different input buffers. If you
+ want to e.g., return to INITIAL, you must explicitly do so.
+
+ - The "Performance Considerations" section of the manual has been
+ updated.
+
+ - Documented the "yy_act" variable, which when YY_USER_ACTION is
+ invoked holds the number of the matched rule, and added an
+ example of using yy_act to profile how often each rule is matched.
+
+ - Added YY_NUM_RULES, a definition that gives the total number
+ of rules in the file, including the default rule (even if you
+ use -s).
+
+ - Documentation now clarifies that you can pass a nil FILE* pointer
+ to yy_create_buffer() or yyrestart() if you've arrange YY_INPUT
+ to not need yyin.
+
+ - Documentation now clarifies that YY_BUFFER_STATE is a pointer to
+ an opaque "struct yy_buffer_state".
+
+ - Documentation now stresses that you gain the benefits of removing
+ backing-up states only if you remove *all* of them.
+
+ - Documentation now points out that traditional lex allows you
+ to put the action on a separate line from the rule pattern if
+ the pattern has trailing whitespace (ugh!), but flex doesn't
+ support this.
+
+ - A broken example in documentation of the difference between
+ inclusive and exclusive start conditions is now fixed.
+
+ - Usage (-h) report now goes to stdout.
+
+ - Version (-V) info now goes to stdout.
+
+ - More #ifdef chud has been added to the parser in attempt to
+ deal with bison's use of alloca().
+
+ - "make clean" no longer deletes emacs backup files (*~).
+
+ - Some memory leaks have been fixed.
+
+ - A bug was fixed in which dynamically-expanded buffers were
+ reallocated a couple of bytes too small.
+
+ - A bug was fixed which could cause flex to read and write beyond
+ the end of the input buffer.
+
+ - -S will not be going away.
+
+
+Changes between release 2.4.7 (03Aug94) and release 2.4.6:
+
+ - Fixed serious bug in reading multiple files.
+
+ - Fixed bug in scanning NUL's.
+
+ - Fixed bug in input() returning 8-bit characters.
+
+ - Fixed bug in matching text with embedded NUL's when
+ using %array or lex compatibility.
+
+ - Fixed multiple invocations of YY_USER_ACTION when using '|'
+ continuation action.
+
+ - Minor prototyping fixes.
+
+Changes between release 2.4.6 (04Jan94) and release 2.4.5:
+
+ - Linking with -lfl no longer required if your program includes
+ its own yywrap() and main() functions. (This change will cause
+ problems if you have a non-ANSI compiler on a system for which
+ sizeof(int) != sizeof(void*) or sizeof(int) != sizeof(size_t).)
+
+ - The use of 'extern "C++"' in FlexLexer.h has been modified to
+ get around an incompatibility with g++'s header files.
+
+Changes between release 2.4.5 (11Dec93) and release 2.4.4:
+
+ - Fixed bug breaking C++ scanners that use REJECT or variable
+ trailing context.
+
+ - Fixed serious input problem for interactive scanners on
+ systems for which char is unsigned.
+
+ - Fixed bug in incorrectly treating '$' operator as variable
+ trailing context.
+
+ - Fixed bug in -CF table representation that could lead to
+ corrupt tables.
+
+ - Fixed fairly benign memory leak.
+
+ - Added `extern "C++"' wrapper to FlexLexer.h header. This
+ should overcome the g++ 2.5.X problems mentioned in the
+ NEWS for release 2.4.3.
+
+ - Changed #include of FlexLexer.h to use <> instead of "".
+
+ - Added feature to control whether the scanner attempts to
+ refill the input buffer once it's exhausted. This feature
+ will be documented in the 2.5 release.
+
+
+Changes between release 2.4.4 (07Dec93) and release 2.4.3:
+
+ - Fixed two serious bugs in scanning 8-bit characters.
+
+ - Fixed bug in YY_USER_ACTION that caused it to be executed
+ inappropriately (on the scanner's own internal actions, and
+ with incorrect yytext/yyleng values).
+
+ - Fixed bug in pointing yyin at a new file and resuming scanning.
+
+ - Portability fix regarding min/max/abs macros conflicting with
+ function definitions in standard header files.
+
+ - Added a virtual LexerError() method to the C++ yyFlexLexer class
+ for reporting error messages instead of always using cerr.
+
+ - Added warning in flexdoc that the C++ scanning class is presently
+ experimental and subject to considerable change between major
+ releases.
+
+
+Changes between release 2.4.3 (03Dec93) and release 2.4.2:
+
+ - Fixed bug causing fatal scanner messages to fail to print.
+
+ - Fixed things so FlexLexer.h can be included in other C++
+ sources. One side-effect of this change is that -+ and -CF
+ are now incompatible.
+
+ - libfl.a now supplies private versions of the the <string.h>/
+ <strings.h> string routines needed by flex and the scanners
+ it generates, to enhance portability to some BSD systems.
+
+ - More robust solution to 2.4.2's flexfatal() bug fix.
+
+ - Added ranlib of installed libfl.a.
+
+ - Some lint tweaks.
+
+ - NOTE: problems have been encountered attempting to build flex
+ C++ scanners using g++ version 2.5.X. The problem is due to an
+ unfortunate heuristic in g++ 2.5.X that attempts to discern between
+ C and C++ headers. Because FlexLexer.h is installed (by default)
+ in /usr/local/include and not /usr/local/lib/g++-include, g++ 2.5.X
+ decides that it's a C header :-(. So if you have problems, install
+ the header in /usr/local/lib/g++-include instead.
+
+
+Changes between release 2.4.2 (01Dec93) and release 2.4.1:
+
+ - Fixed bug in libfl.a referring to non-existent "flexfatal" function.
+
+ - Modified to produce both compress'd and gzip'd tar files for
+ distributions (you probably don't care about this change!).
+
+
+Changes between release 2.4.1 (30Nov93) and release 2.3.8:
+
+ - The new '-+' flag instructs flex to generate a C++ scanner class
+ (thanks to Kent Williams). flex writes an implementation of the
+ class defined in FlexLexer.h to lex.yy.cc. You may include
+ multiple scanner classes in your program using the -P flag. Note
+ that the scanner class also provides a mechanism for creating
+ reentrant scanners. The scanner class uses C++ streams for I/O
+ instead of FILE*'s (thanks to Tom Epperly). If the flex executable's
+ name ends in '+' then the '-+' flag is automatically on, so creating
+ a symlink or copy of "flex" to "flex++" results in a version of
+ flex that can be used exclusively for C++ scanners.
+
+ Note that without the '-+' flag, flex-generated scanners can still
+ be compiled using C++ compilers, though they use FILE*'s for I/O
+ instead of streams.
+
+ See the "GENERATING C++ SCANNERS" section of flexdoc for details.
+
+ - The new '-l' flag turns on maximum AT&T lex compatibility. In
+ particular, -l includes support for "yylineno" and makes yytext
+ be an array instead of a pointer. It does not, however, do away
+ with all incompatibilities. See the "INCOMPATIBILITIES WITH LEX
+ AND POSIX" section of flexdoc for details.
+
+ - The new '-P' option specifies a prefix to use other than "yy"
+ for the scanner's globally-visible variables, and for the
+ "lex.yy.c" filename. Using -P you can link together multiple
+ flex scanners in the same executable.
+
+ - The distribution includes a "texinfo" version of flexdoc.1,
+ contributed by Roland Pesch (thanks also to Marq Kole, who
+ contributed another version). It has not been brought up to
+ date, but reflects version 2.3. See MISC/flex.texinfo.
+
+ The flex distribution will soon include G.T. Nicol's flex
+ manual; he is presently bringing it up-to-date for version 2.4.
+
+ - yywrap() is now a function, and you now *must* link flex scanners
+ with libfl.a.
+
+ - Site-configuration is now done via an autoconf-generated
+ "configure" script contributed by Francois Pinard.
+
+ - Scanners now use fread() (or getc(), if interactive) and not
+ read() for input. A new "table compression" option, -Cr,
+ overrides this change and causes the scanner to use read()
+ (because read() is a bit faster than fread()). -f and -F
+ are now equivalent to -Cfr and -CFr; i.e., they imply the
+ -Cr option.
+
+ - In the blessed name of POSIX compliance, flex supports "%array"
+ and "%pointer" directives in the definitions (first) section of
+ the scanner specification. The former specifies that yytext
+ should be an array (of size YYLMAX), the latter, that it should
+ be a pointer. The array version of yytext is universally slower
+ than the pointer version, but has the advantage that its contents
+ remain unmodified across calls to input() and unput() (the pointer
+ version of yytext is, still, trashed by such calls).
+
+ "%array" cannot be used with the '-+' C++ scanner class option.
+
+ - The new '-Ca' option directs flex to trade off memory for
+ natural alignment when generating a scanner's tables. In
+ particular, table entries that would otherwise be "short"
+ become "long".
+
+ - The new '-h' option produces a summary of the flex flags.
+
+ - The new '-V' option reports the flex version number and exits.
+
+ - The new scanner macro YY_START returns an integer value
+ corresponding to the current start condition. You can return
+ to that start condition by passing the value to a subsequent
+ "BEGIN" action. You also can implement "start condition stacks"
+ by storing the values in an integer stack.
+
+ - You can now redefine macros such as YY_INPUT by just #define'ing
+ them to some other value in the first section of the flex input;
+ no need to first #undef them.
+
+ - flex now generates warnings for rules that can't be matched.
+ These warnings can be turned off using the new '-w' flag. If
+ your scanner uses REJECT then you will not get these warnings.
+
+ - If you specify the '-s' flag but the default rule can be matched,
+ flex now generates a warning.
+
+ - "yyleng" is now a global, and may be modified by the user (though
+ doing so and then using yymore() will yield weird results).
+
+ - Name definitions in the first section of a scanner specification
+ can now include a leading '^' or trailing '$' operator. In this
+ case, the definition is *not* pushed back inside of parentheses.
+
+ - Scanners with compressed tables are now "interactive" (-I option)
+ by default. You can suppress this attribute (which makes them
+ run slightly slower) using the new '-B' flag.
+
+ - Flex now generates 8-bit scanners by default, unless you use the
+ -Cf or -CF compression options (-Cfe and -CFe result in 8-bit
+ scanners). You can force it to generate a 7-bit scanner using
+ the new '-7' flag. You can build flex to generate 8-bit scanners
+ for -Cf and -CF, too, by adding -DDEFAULT_CSIZE=256 to CFLAGS
+ in the Makefile.
+
+ - You no longer need to call the scanner routine yyrestart() to
+ inform the scanner that you have switched to a new file after
+ having seen an EOF on the current input file. Instead, just
+ point yyin at the new file and continue scanning.
+
+ - You no longer need to invoke YY_NEW_FILE in an <<EOF>> action
+ to indicate you wish to continue scanning. Simply point yyin
+ at a new file.
+
+ - A leading '#' no longer introduces a comment in a flex input.
+
+ - flex no longer considers formfeed ('\f') a whitespace character.
+
+ - %t, I'm happy to report, has been nuked.
+
+ - The '-p' option may be given twice ('-pp') to instruct flex to
+ report minor performance problems as well as major ones.
+
+ - The '-v' verbose output no longer includes start/finish time
+ information.
+
+ - Newlines in flex inputs can optionally include leading or
+ trailing carriage-returns ('\r'), in support of several PC/Mac
+ run-time libraries that automatically include these.
+
+ - A start condition of the form "<*>" makes the following rule
+ active in every start condition, whether exclusive or inclusive.
+
+ - The following items have been corrected in the flex documentation:
+
+ - '-C' table compression options *are* cumulative.
+
+ - You may modify yytext but not lengthen it by appending
+ characters to the end. Modifying its final character
+ will affect '^' anchoring for the next rule matched
+ if the character is changed to or from a newline.
+
+ - The term "backtracking" has been renamed "backing up",
+ since it is a one-time repositioning and not a repeated
+ search. What used to be the "lex.backtrack" file is now
+ "lex.backup".
+
+ - Unindented "/* ... */" comments are allowed in the first
+ flex input section, but not in the second.
+
+ - yyless() can only be used in the flex input source, not
+ externally.
+
+ - You can use "yyrestart(yyin)" to throw away the
+ current contents of the input buffer.
+
+ - To write high-speed scanners, attempt to match as much
+ text as possible with each rule. See MISC/fastwc/README
+ for more information.
+
+ - Using the beginning-of-line operator ('^') is fairly
+ cheap. Using unput() is expensive. Using yyless() is
+ cheap.
+
+ - An example of scanning strings with embedded escape
+ sequences has been added.
+
+ - The example of backing-up in flexdoc was erroneous; it
+ has been corrected.
+
+ - A flex scanner's internal buffer now dynamically grows if needed
+ to match large tokens. Note that growing the buffer presently
+ requires rescanning the (large) token, so consuming a lot of
+ text this way is a slow process. Also note that presently the
+ buffer does *not* grow if you unput() more text than can fit
+ into the buffer.
+
+ - The MISC/ directory has been reorganized; see MISC/README for
+ details.
+
+ - yyless() can now be used in the third (user action) section
+ of a scanner specification, thanks to Ceriel Jacobs. yyless()
+ remains a macro and cannot be used outside of the scanner source.
+
+ - The skeleton file is no longer opened at run-time, but instead
+ compiled into a large string array (thanks to John Gilmore and
+ friends at Cygnus). You can still use the -S flag to point flex
+ at a different skeleton file.
+
+ - flex no longer uses a temporary file to store the scanner's
+ actions.
+
+ - A number of changes have been made to decrease porting headaches.
+ In particular, flex no longer uses memset() or ctime(), and
+ provides a single simple mechanism for dealing with C compilers
+ that still define malloc() as returning char* instead of void*.
+
+ - Flex now detects if the scanner specification requires the -8 flag
+ but the flag was not given or on by default.
+
+ - A number of table-expansion fencepost bugs have been fixed,
+ making flex more robust for generating large scanners.
+
+ - flex more consistently identifies the location of errors in
+ its input.
+
+ - YY_USER_ACTION is now invoked only for "real" actions, not for
+ internal actions used by the scanner for things like filling
+ the buffer or handling EOF.
+
+ - The rule "[^]]" now matches any character other than a ']';
+ formerly it matched any character at all followed by a ']'.
+ This change was made for compatibility with AT&T lex.
+
+ - A large number of miscellaneous bugs have been found and fixed
+ thanks to Gerhard Wilhelms.
+
+ - The source code has been heavily reformatted, making patches
+ relative to previous flex releases no longer accurate.
+
+
+Changes between 2.3 Patch #8 (21Feb93) and 2.3 Patch #7:
+
+ - Fixed bugs in dynamic memory allocation leading to grievous
+ fencepost problems when generating large scanners.
+ - Fixed bug causing infinite loops on character classes with 8-bit
+ characters in them.
+ - Fixed bug in matching repetitions with a lower bound of 0.
+ - Fixed bug in scanning NUL characters using an "interactive" scanner.
+ - Fixed bug in using yymore() at the end of a file.
+ - Fixed bug in misrecognizing rules with variable trailing context.
+ - Fixed bug compiling flex on Suns using gcc 2.
+ - Fixed bug in not recognizing that input files with the character
+ ASCII 128 in them require the -8 flag.
+ - Fixed bug that could cause an infinite loop writing out
+ error messages.
+ - Fixed bug in not recognizing old-style lex % declarations if
+ followed by a tab instead of a space.
+ - Fixed potential crash when flex terminated early (usually due
+ to a bad flag) and the -v flag had been given.
+ - Added some missing declarations of void functions.
+ - Changed to only use '\a' for __STDC__ compilers.
+ - Updated mailing addresses.
+
+
+Changes between 2.3 Patch #7 (28Mar91) and 2.3 Patch #6:
+
+ - Fixed out-of-bounds array access that caused bad tables
+ to be produced on machines where the bad reference happened
+ to yield a 1. This caused problems installing or running
+ flex on some Suns, in particular.
+
+
+Changes between 2.3 Patch #6 (29Aug90) and 2.3 Patch #5:
+
+ - Fixed a serious bug in yymore() which basically made it
+ completely broken. Thanks goes to Jean Christophe of
+ the Nethack development team for finding the problem
+ and passing along the fix.
+
+
+Changes between 2.3 Patch #5 (16Aug90) and 2.3 Patch #4:
+
+ - An up-to-date version of initscan.c so "make test" will
+ work after applying the previous patches
+
+
+Changes between 2.3 Patch #4 (14Aug90) and 2.3 Patch #3:
+
+ - Fixed bug in hexadecimal escapes which allowed only digits,
+ not letters, in escapes
+ - Fixed bug in previous "Changes" file!
+
+
+Changes between 2.3 Patch #3 (03Aug90) and 2.3 Patch #2:
+
+ - Correction to patch #2 for gcc compilation; thanks goes to
+ Paul Eggert for catching this.
+
+
+Changes between 2.3 Patch #2 (02Aug90) and original 2.3 release:
+
+ - Fixed (hopefully) headaches involving declaring malloc()
+ and free() for gcc, which defines __STDC__ but (often) doesn't
+ come with the standard include files such as <stdlib.h>.
+ Reordered #ifdef maze in the scanner skeleton in the hope of
+ getting the declarations right for cfront and g++, too.
+
+ - Note that this patch supercedes patch #1 for release 2.3,
+ which was never announced but was available briefly for
+ anonymous ftp.
+
+
+Changes between 2.3 (full) release of 28Jun90 and 2.2 (alpha) release:
+
+ User-visible:
+
+ - A lone <<EOF>> rule (that is, one which is not qualified with
+ a list of start conditions) now specifies the EOF action for
+ *all* start conditions which haven't already had <<EOF>> actions
+ given. To specify an end-of-file action for just the initial
+ state, use <INITIAL><<EOF>>.
+
+ - -d debug output is now contigent on the global yy_flex_debug
+ being set to a non-zero value, which it is by default.
+
+ - A new macro, YY_USER_INIT, is provided for the user to specify
+ initialization action to be taken on the first call to the
+ scanner. This action is done before the scanner does its
+ own initialization.
+
+ - yy_new_buffer() has been added as an alias for yy_create_buffer()
+
+ - Comments beginning with '#' and extending to the end of the line
+ now work, but have been deprecated (in anticipation of making
+ flex recognize #line directives).
+
+ - The funky restrictions on when semi-colons could follow the
+ YY_NEW_FILE and yyless macros have been removed. They now
+ behave identically to functions.
+
+ - A bug in the sample redefinition of YY_INPUT in the documentation
+ has been corrected.
+
+ - A bug in the sample simple tokener in the documentation has
+ been corrected.
+
+ - The documentation on the incompatibilities between flex and
+ lex has been reordered so that the discussion of yylineno
+ and input() come first, as it's anticipated that these will
+ be the most common source of headaches.
+
+
+ Things which didn't used to be documented but now are:
+
+ - flex interprets "^foo|bar" differently from lex. flex interprets
+ it as "match either a 'foo' or a 'bar', providing it comes at the
+ beginning of a line", whereas lex interprets it as "match either
+ a 'foo' at the beginning of a line, or a 'bar' anywhere".
+
+ - flex initializes the global "yyin" on the first call to the
+ scanner, while lex initializes it at compile-time.
+
+ - yy_switch_to_buffer() can be used in the yywrap() macro/routine.
+
+ - flex scanners do not use stdio for their input, and hence when
+ writing an interactive scanner one must explictly call fflush()
+ after writing out a prompt.
+
+ - flex scanner can be made reentrant (after a fashion) by using
+ "yyrestart( yyin );". This is useful for interactive scanners
+ which have interrupt handlers that long-jump out of the scanner.
+
+ - a defense of why yylineno is not supported is included, along
+ with a suggestion on how to convert scanners which rely on it.
+
+
+ Other changes:
+
+ - Prototypes and proper declarations of void routines have
+ been added to the flex source code, courtesy of Kevin B. Kenny.
+
+ - Routines dealing with memory allocation now use void* pointers
+ instead of char* - see Makefile for porting implications.
+
+ - Error-checking is now done when flex closes a file.
+
+ - Various lint tweaks were added to reduce the number of gripes.
+
+ - Makefile has been further parameterized to aid in porting.
+
+ - Support for SCO Unix added.
+
+ - Flex now sports the latest & greatest UC copyright notice
+ (which is only slightly different from the previous one).
+
+ - A note has been added to flexdoc.1 mentioning work in progress
+ on modifying flex to generate straight C code rather than a
+ table-driven automaton, with an email address of whom to contact
+ if you are working along similar lines.
+
+
+Changes between 2.2 Patch #3 (30Mar90) and 2.2 Patch #2:
+
+ - fixed bug which caused -I scanners to bomb
+
+
+Changes between 2.2 Patch #2 (27Mar90) and 2.2 Patch #1:
+
+ - fixed bug writing past end of input buffer in yyunput()
+ - fixed bug detecting NUL's at the end of a buffer
+
+
+Changes between 2.2 Patch #1 (23Mar90) and 2.2 (alpha) release:
+
+ - Makefile fixes: definition of MAKE variable for systems
+ which don't have it; installation of flexdoc.1 along with
+ flex.1; fixed two bugs which could cause "bigtest" to fail.
+
+ - flex.skel fix for compiling with g++.
+
+ - README and flexdoc.1 no longer list an out-of-date BITNET address
+ for contacting me.
+
+ - minor typos and formatting changes to flex.1 and flexdoc.1.
+
+
+Changes between 2.2 (alpha) release of March '90 and previous release:
+
+ User-visible:
+
+ - Full user documentation now available.
+
+ - Support for 8-bit scanners.
+
+ - Scanners now accept NUL's.
+
+ - A facility has been added for dealing with multiple
+ input buffers.
+
+ - Two manual entries now. One which fully describes flex
+ (rather than just its differences from lex), and the
+ other for quick(er) reference.
+
+ - A number of changes to bring flex closer into compliance
+ with the latest POSIX lex draft:
+
+ %t support
+ flex now accepts multiple input files and concatenates
+ them together to form its input
+ previous -c (compress) flag renamed -C
+ do-nothing -c and -n flags added
+ Any indented code or code within %{}'s in section 2 is
+ now copied to the output
+
+ - yyleng is now a bona fide global integer.
+
+ - -d debug information now gives the line number of the
+ matched rule instead of which number rule it was from
+ the beginning of the file.
+
+ - -v output now includes a summary of the flags used to generate
+ the scanner.
+
+ - unput() and yyrestart() are now globally callable.
+
+ - yyrestart() no longer closes the previous value of yyin.
+
+ - C++ support; generated scanners can be compiled with C++ compiler.
+
+ - Primitive -lfl library added, containing default main()
+ which calls yylex(). A number of routines currently living
+ in the scanner skeleton will probably migrate to here
+ in the future (in particular, yywrap() will probably cease
+ to be a macro and instead be a function in the -lfl library).
+
+ - Hexadecimal (\x) escape sequences added.
+
+ - Support for MS-DOS, VMS, and Turbo-C integrated.
+
+ - The %used/%unused operators have been deprecated. They
+ may go away soon.
+
+
+ Other changes:
+
+ - Makefile enhanced for easier testing and installation.
+ - The parser has been tweaked to detect some erroneous
+ constructions which previously were missed.
+ - Scanner input buffer overflow is now detected.
+ - Bugs with missing "const" declarations fixed.
+ - Out-of-date Minix/Atari patches provided.
+ - Scanners no longer require printf() unless FLEX_DEBUG is being used.
+ - A subtle input() bug has been fixed.
+ - Line numbers for "continued action" rules (those following
+ the special '|' action) are now correct.
+ - unput() bug fixed; had been causing problems porting flex to VMS.
+ - yymore() handling rewritten to fix bug with interaction
+ between yymore() and trailing context.
+ - EOF in actions now generates an error message.
+ - Bug involving -CFe and generating equivalence classes fixed.
+ - Bug which made -CF be treated as -Cf fixed.
+ - Support for SysV tmpnam() added.
+ - Unused #define's for scanner no longer generated.
+ - Error messages which are associated with a particular input
+ line are now all identified with their input line in standard
+ format.
+ - % directives which are valid to lex but not to flex are
+ now ignored instead of generating warnings.
+ - -DSYS_V flag can now also be specified -DUSG for System V
+ compilation.
+
+
+Changes between 2.1 beta-test release of June '89 and previous release:
+
+ User-visible:
+
+ - -p flag generates a performance report to stderr. The report
+ consists of comments regarding features of the scanner rules
+ which result in slower scanners.
+
+ - -b flag generates backtracking information to lex.backtrack.
+ This is a list of scanner states which require backtracking
+ and the characters on which they do so. By adding rules
+ one can remove backtracking states. If all backtracking states
+ are eliminated, the generated scanner will run faster.
+ Backtracking is not yet documented in the manual entry.
+
+ - Variable trailing context now works, i.e., one can have
+ rules like "(foo)*/[ \t]*bletch". Some trailing context
+ patterns still cannot be properly matched and generate
+ error messages. These are patterns where the ending of the
+ first part of the rule matches the beginning of the second
+ part, such as "zx*/xy*", where the 'x*' matches the 'x' at
+ the beginning of the trailing context. Lex won't get these
+ patterns right either.
+
+ - Faster scanners.
+
+ - End-of-file rules. The special rule "<<EOF>>" indicates
+ actions which are to be taken when an end-of-file is
+ encountered and yywrap() returns non-zero (i.e., indicates
+ no further files to process). See manual entry for example.
+
+ - The -r (reject used) flag is gone. flex now scans the input
+ for occurrences of the string "REJECT" to determine if the
+ action is needed. It tries to be intelligent about this but
+ can be fooled. One can force the presence or absence of
+ REJECT by adding a line in the first section of the form
+ "%used REJECT" or "%unused REJECT".
+
+ - yymore() has been implemented. Similarly to REJECT, flex
+ detects the use of yymore(), which can be overridden using
+ "%used" or "%unused".
+
+ - Patterns like "x{0,3}" now work (i.e., with lower-limit == 0).
+
+ - Removed '\^x' for ctrl-x misfeature.
+
+ - Added '\a' and '\v' escape sequences.
+
+ - \<digits> now works for octal escape sequences; previously
+ \0<digits> was required.
+
+ - Better error reporting; line numbers are associated with rules.
+
+ - yyleng is a macro; it cannot be accessed outside of the
+ scanner source file.
+
+ - yytext and yyleng should not be modified within a flex action.
+
+ - Generated scanners #define the name FLEX_SCANNER.
+
+ - Rules are internally separated by YY_BREAK in lex.yy.c rather
+ than break, to allow redefinition.
+
+ - The macro YY_USER_ACTION can be redefined to provide an action
+ which is always executed prior to the matched rule's action.
+
+ - yyrestart() is a new action which can be used to restart
+ the scanner after it has seen an end-of-file (a "real" one,
+ that is, one for which yywrap() returned non-zero). It takes
+ a FILE* argument indicating a new file to scan and sets
+ things up so that a subsequent call to yylex() will start
+ scanning that file.
+
+ - Internal scanner names all preceded by "yy_"
+
+ - lex.yy.c is deleted if errors are encountered during processing.
+
+ - Comments may be put in the first section of the input by preceding
+ them with '#'.
+
+
+
+ Other changes:
+
+ - Some portability-related bugs fixed, in particular for machines
+ with unsigned characters or sizeof( int* ) != sizeof( int ).
+ Also, tweaks for VMS and Microsoft C (MS-DOS), and identifiers all
+ trimmed to be 31 or fewer characters. Shortened file names
+ for dinosaur OS's. Checks for allocating > 64K memory
+ on 16 bit'ers. Amiga tweaks. Compiles using gcc on a Sun-3.
+ - Compressed and fast scanner skeletons merged.
+ - Skeleton header files done away with.
+ - Generated scanner uses prototypes and "const" for __STDC__.
+ - -DSV flag is now -DSYS_V for System V compilation.
+ - Removed all references to FTL language.
+ - Software now covered by BSD Copyright.
+ - flex will replace lex in subsequent BSD releases.
diff --git a/Tools/android/flex-2.5.4a/README b/Tools/android/flex-2.5.4a/README
new file mode 100644
index 0000000..7a4224d
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/README
@@ -0,0 +1,60 @@
+This is release 2.5 of flex. See "version.h" for the exact patch-level.
+
+See the file "NEWS" to find out what is new in this Flex release.
+
+Read the file "INSTALL" for general installation directives. Peek near
+the beginning of the file "Makefile.in" for special DEFS values. On most
+systems, you can just run the "configure" script and type "make" to build
+flex; then "make check" to test whether it built correctly; and if it did,
+then "make install" to install it.
+
+If you're feeling adventurous, you can also issue "make bigcheck" (be
+prepared to wait a while).
+
+Note that flex is distributed under a copyright very similar to that of
+BSD Unix, and not under the GNU General Public License (GPL), except for
+the "configure" script, which is covered by the GPL.
+
+Many thanks to the 2.5 beta-testers for finding bugs and helping test and
+increase portability: Stan Adermann, Scott David Daniels, Charles Elliott,
+Joe Gayda, Chris Meier, James Nordby, Terrence O'Kane, Karsten Pahnke,
+Francois Pinard, Pat Rankin, Andreas Scherer, Marc Wiese, Nathan Zelle.
+
+Please send bug reports and feedback to: Vern Paxson (vern@ee.lbl.gov).
+
+
+The flex distribution consists of the following files:
+
+ README This message
+
+ NEWS Differences between the various releases
+
+ INSTALL General installation information
+
+ COPYING flex's copyright
+
+ conf.in, configure.in, configure, Makefile.in, install.sh,
+ mkinstalldirs
+ elements of the "autoconf" auto-configuration process
+
+ flexdef.h, parse.y, scan.l, ccl.c, dfa.c, ecs.c, gen.c, main.c,
+ misc.c, nfa.c, sym.c, tblcmp.c, yylex.c
+ source files
+
+ version.h version of this flex release
+
+ flex.skl flex scanner skeleton
+ mkskel.sh script for converting flex.skl to C source file skel.c
+ skel.c pre-converted C version of flex.skl
+
+ libmain.c flex library (-lfl) sources
+ libyywrap.c
+
+ initscan.c pre-flex'd version of scan.l
+
+ FlexLexer.h header file for C++ lexer class
+
+ flex.1 user documentation
+
+ MISC/ a directory containing miscellaneous contributions.
+ See MISC/README for details.
diff --git a/Tools/android/flex-2.5.4a/ccl.c b/Tools/android/flex-2.5.4a/ccl.c
new file mode 100644
index 0000000..8697305
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/ccl.c
@@ -0,0 +1,149 @@
+/* ccl - routines for character classes */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/ccl.c,v 2.9 93/09/16 20:32:14 vern Exp $ */
+
+#include "flexdef.h"
+
+/* ccladd - add a single character to a ccl */
+
+void ccladd( cclp, ch )
+int cclp;
+int ch;
+ {
+ int ind, len, newpos, i;
+
+ check_char( ch );
+
+ len = ccllen[cclp];
+ ind = cclmap[cclp];
+
+ /* check to see if the character is already in the ccl */
+
+ for ( i = 0; i < len; ++i )
+ if ( ccltbl[ind + i] == ch )
+ return;
+
+ newpos = ind + len;
+
+ if ( newpos >= current_max_ccl_tbl_size )
+ {
+ current_max_ccl_tbl_size += MAX_CCL_TBL_SIZE_INCREMENT;
+
+ ++num_reallocs;
+
+ ccltbl = reallocate_Character_array( ccltbl,
+ current_max_ccl_tbl_size );
+ }
+
+ ccllen[cclp] = len + 1;
+ ccltbl[newpos] = ch;
+ }
+
+
+/* cclinit - return an empty ccl */
+
+int cclinit()
+ {
+ if ( ++lastccl >= current_maxccls )
+ {
+ current_maxccls += MAX_CCLS_INCREMENT;
+
+ ++num_reallocs;
+
+ cclmap = reallocate_integer_array( cclmap, current_maxccls );
+ ccllen = reallocate_integer_array( ccllen, current_maxccls );
+ cclng = reallocate_integer_array( cclng, current_maxccls );
+ }
+
+ if ( lastccl == 1 )
+ /* we're making the first ccl */
+ cclmap[lastccl] = 0;
+
+ else
+ /* The new pointer is just past the end of the last ccl.
+ * Since the cclmap points to the \first/ character of a
+ * ccl, adding the length of the ccl to the cclmap pointer
+ * will produce a cursor to the first free space.
+ */
+ cclmap[lastccl] = cclmap[lastccl - 1] + ccllen[lastccl - 1];
+
+ ccllen[lastccl] = 0;
+ cclng[lastccl] = 0; /* ccl's start out life un-negated */
+
+ return lastccl;
+ }
+
+
+/* cclnegate - negate the given ccl */
+
+void cclnegate( cclp )
+int cclp;
+ {
+ cclng[cclp] = 1;
+ }
+
+
+/* list_character_set - list the members of a set of characters in CCL form
+ *
+ * Writes to the given file a character-class representation of those
+ * characters present in the given CCL. A character is present if it
+ * has a non-zero value in the cset array.
+ */
+
+void list_character_set( file, cset )
+FILE *file;
+int cset[];
+ {
+ register int i;
+
+ putc( '[', file );
+
+ for ( i = 0; i < csize; ++i )
+ {
+ if ( cset[i] )
+ {
+ register int start_char = i;
+
+ putc( ' ', file );
+
+ fputs( readable_form( i ), file );
+
+ while ( ++i < csize && cset[i] )
+ ;
+
+ if ( i - 1 > start_char )
+ /* this was a run */
+ fprintf( file, "-%s", readable_form( i - 1 ) );
+
+ putc( ' ', file );
+ }
+ }
+
+ putc( ']', file );
+ }
diff --git a/Tools/android/flex-2.5.4a/conf.in b/Tools/android/flex-2.5.4a/conf.in
new file mode 100644
index 0000000..3f06ba4
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/conf.in
@@ -0,0 +1,25 @@
+/* $Header: /home/daffy/u0/vern/flex/RCS/conf.in,v 1.2 95/01/09 12:11:51 vern Exp $ */
+
+/* Define to empty if the keyword does not work. */
+#undef const
+
+/* Define to `unsigned' if <sys/types.h> doesn't define. */
+#undef size_t
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you have the <malloc.h> header file. */
+#undef HAVE_MALLOC_H
+
+/* Define if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Define if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* Define if you have <alloca.h> and it should be used (not on Ultrix). */
+#undef HAVE_ALLOCA_H
+
+/* Define if platform-specific command line handling is necessary. */
+#undef NEED_ARGV_FIXUP
diff --git a/Tools/android/flex-2.5.4a/configure b/Tools/android/flex-2.5.4a/configure
new file mode 100755
index 0000000..be7f861
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/configure
@@ -0,0 +1,1632 @@
+#!/bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.1
+# Copyright (C) 1992, 1993, 1994 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Initialize some other variables.
+subdirs=
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -build | --build | --buil | --bui | --bu | --b)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=* | --b=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=PREFIX install architecture-dependent files in PREFIX
+ [same as prefix]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+--enable and --with options recognized:$ac_help
+EOF
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.1"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 unused; standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 unused; some systems may open it to /dev/tty
+# 4 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 4>/dev/null
+else
+ exec 4>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set LANG and LC_ALL to C if already set.
+# These must not be set unconditionally because not all systems understand
+# e.g. LANG=C (notably SCO).
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=initscan.c
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} $CFLAGS $CPPFLAGS conftest.$ac_ext -c 1>&5 2>&5'
+ac_link='${CC-cc} $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext -o conftest $LIBS 1>&5 2>&5'
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_prog_LN_S'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+ rm -f conftestdata
+ ac_cv_prog_LN_S="ln -s"
+else
+ ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+ echo "$ac_t""yes" 1>&4
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+for ac_prog in 'bison -y' byacc
+do
+# Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_prog_YACC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ if test -n "$YACC"; then
+ ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_YACC="$ac_prog"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+YACC="$ac_cv_prog_YACC"
+if test -n "$YACC"; then
+ echo "$ac_t""$YACC" 1>&4
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_CC" && ac_cv_prog_CC="cc"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&4
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if ${CC-cc} -E conftest.c 2>&5 | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+echo "$ac_t""$ac_cv_prog_gcc" 1>&4
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+ if test "${CFLAGS+set}" != set; then
+ echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_prog_gcc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_gcc_g=yes
+else
+ ac_cv_prog_gcc_g=no
+fi
+rm -f conftest*
+
+fi
+ echo "$ac_t""$ac_cv_prog_gcc_g" 1>&4
+ if test $ac_cv_prog_gcc_g = yes; then
+ CFLAGS="-g -O"
+ else
+ CFLAGS="-O"
+ fi
+ fi
+else
+ GCC=
+ test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+
+# Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&4
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&4
+if test -z "$INSTALL"; then
+if eval "test \"`echo '${'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ case "$ac_dir" in
+ ''|.|/etc|/usr/sbin|/usr/etc|/sbin|/usr/afsws/bin|/usr/ucb) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ for ac_prog in ginstall installbsd scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_ifs"
+ # As a last resort, use the slow shell script.
+ test -z "$ac_cv_path_install" && ac_cv_path_install="$ac_install_sh"
+fi
+ INSTALL="$ac_cv_path_install"
+fi
+echo "$ac_t""$INSTALL" 1>&4
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+echo $ac_n "checking whether ${MAKE-make} sets \$MAKE""... $ac_c" 1>&4
+set dummy ${MAKE-make}; ac_make=$2
+if eval "test \"`echo '${'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&4
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+echo $ac_n "checking for working const""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_c_const'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 658 "configure"
+#include "confdefs.h"
+
+int main() { return 0; }
+int t() {
+
+/* Ultrix mips cc rejects this. */
+typedef int charset[2]; const charset x;
+/* SunOS 4.1.1 cc rejects this. */
+char const *const *ccp;
+char **p;
+/* NEC SVR4.0.2 mips cc rejects this. */
+struct point {int x, y;};
+static struct point const zero;
+/* AIX XL C 1.02.0.0 rejects this.
+ It does not let you subtract one const X* pointer from another in an arm
+ of an if-expression whose if-part is not a constant expression */
+const char *g = "string";
+ccp = &g + (g ? g-g : 0);
+/* HPUX 7.0 cc rejects these. */
+++ccp;
+p = (char**) ccp;
+ccp = (char const *const *) p;
+{ /* SCO 3.2v4 cc rejects this. */
+ char *t;
+ char const *s = 0 ? (char *) 0 : (char const *) 0;
+
+ *t++ = 0;
+}
+{ /* Someone thinks the Sun supposedly-ANSI compiler will reject this. */
+ int x[] = {25, 17};
+ const int *foo = &x[0];
+ ++foo;
+}
+{ /* Sun SC1.0 ANSI compiler rejects this -- but not the above. */
+ typedef const int *iptr;
+ iptr p = 0;
+ ++p;
+}
+{ /* AIX XL C 1.02.0.0 rejects this saying
+ "k.c", line 2.27: 1506-025 (S) Operand must be a modifiable lvalue. */
+ struct s { int j; const int *ap[3]; };
+ struct s *b; b->j = 5;
+}
+{ /* ULTRIX-32 V3.1 (Rev 9) vcc rejects this */
+ const int foo = 10;
+}
+
+; return 0; }
+EOF
+if eval $ac_compile; then
+ rm -rf conftest*
+ ac_cv_c_const=yes
+else
+ rm -rf conftest*
+ ac_cv_c_const=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_c_const" 1>&4
+if test $ac_cv_c_const = no; then
+ cat >> confdefs.h <<\EOF
+#define const
+EOF
+
+fi
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&4
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '${'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 741 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 755 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+fi
+CPP="$ac_cv_prog_CPP"
+echo "$ac_t""$CPP" 1>&4
+
+# If we cannot run a trivial program, we must be cross compiling.
+echo $ac_n "checking whether cross-compiling""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_c_cross'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_cross=yes
+else
+cat > conftest.$ac_ext <<EOF
+#line 787 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ ac_cv_c_cross=no
+else
+ ac_cv_c_cross=yes
+fi
+fi
+rm -fr conftest*
+fi
+cross_compiling=$ac_cv_c_cross
+echo "$ac_t""$ac_cv_c_cross" 1>&4
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 808 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 830 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 848 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ ac_cv_header_stdc=no
+else
+cat > conftest.$ac_ext <<EOF
+#line 869 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+fi
+rm -fr conftest*
+fi
+fi
+echo "$ac_t""$ac_cv_header_stdc" 1>&4
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for size_t""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_type_size_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 903 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "size_t" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_size_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_size_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_size_t" 1>&4
+if test $ac_cv_type_size_t = no; then
+ cat >> confdefs.h <<\EOF
+#define size_t unsigned
+EOF
+
+fi
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 934 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 956 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 974 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ ac_cv_header_stdc=no
+else
+cat > conftest.$ac_ext <<EOF
+#line 995 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ :
+else
+ ac_cv_header_stdc=no
+fi
+fi
+rm -fr conftest*
+fi
+fi
+echo "$ac_t""$ac_cv_header_stdc" 1>&4
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+for ac_hdr in string.h malloc.h sys/types.h
+do
+ac_safe=`echo "$ac_hdr" | tr './\055' '___'`
+echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1032 "configure"
+#include "confdefs.h"
+#include <$ac_hdr>
+EOF
+eval "$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ ac_tr_hdr=HAVE_`echo $ac_hdr | tr '[a-z]./\055' '[A-Z]___'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_hdr 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+fi
+done
+
+
+case "$YACC" in
+*bison*)
+ # The Ultrix 4.2 mips builtin alloca declared by alloca.h only works
+# for constant arguments. Useless!
+echo $ac_n "checking for working alloca.h""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_header_alloca_h'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1070 "configure"
+#include "confdefs.h"
+#include <alloca.h>
+int main() { return 0; }
+int t() {
+char *p = alloca(2 * sizeof(int));
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ ac_cv_header_alloca_h=yes
+else
+ rm -rf conftest*
+ ac_cv_header_alloca_h=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_header_alloca_h" 1>&4
+if test $ac_cv_header_alloca_h = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA_H 1
+EOF
+
+fi
+
+echo $ac_n "checking for alloca""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func_alloca'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1101 "configure"
+#include "confdefs.h"
+
+#ifdef __GNUC__
+# define alloca __builtin_alloca
+#else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef _AIX
+ #pragma alloca
+# else
+# ifndef alloca /* predefined by HP cc +Olibcalls */
+char *alloca ();
+# endif
+# endif
+# endif
+#endif
+
+int main() { return 0; }
+int t() {
+char *p = (char *) alloca(1);
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ ac_cv_func_alloca=yes
+else
+ rm -rf conftest*
+ ac_cv_func_alloca=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_func_alloca" 1>&4
+if test $ac_cv_func_alloca = yes; then
+ cat >> confdefs.h <<\EOF
+#define HAVE_ALLOCA 1
+EOF
+
+fi
+
+if test $ac_cv_func_alloca = no; then
+ # The SVR3 libPW and SVR4 libucb both contain incompatible functions
+ # that cause trouble. Some versions do not even contain alloca or
+ # contain a buggy version. If you still want to use their alloca,
+ # use ar to extract alloca.o from them instead of compiling alloca.c.
+ ALLOCA=alloca.o
+ cat >> confdefs.h <<\EOF
+#define C_ALLOCA 1
+EOF
+
+
+echo $ac_n "checking whether alloca needs Cray hooks""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_os_cray'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1159 "configure"
+#include "confdefs.h"
+#if defined(CRAY) && ! defined(CRAY2)
+webecray
+#else
+wenotbecray
+#endif
+
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "webecray" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_os_cray=yes
+else
+ rm -rf conftest*
+ ac_cv_os_cray=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_os_cray" 1>&4
+if test $ac_cv_os_cray = yes; then
+echo $ac_n "checking for _getb67""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func__getb67'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1186 "configure"
+#include "confdefs.h"
+#include <ctype.h> /* Arbitrary system header to define __stub macros. */
+/* Override any gcc2 internal prototype to avoid an error. */
+char _getb67();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub__getb67) || defined (__stub____getb67)
+choke me
+#else
+_getb67();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_func__getb67=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func__getb67=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'_getb67`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ cat >> confdefs.h <<\EOF
+#define CRAY_STACKSEG_END _getb67
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+echo $ac_n "checking for GETB67""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func_GETB67'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1229 "configure"
+#include "confdefs.h"
+#include <ctype.h> /* Arbitrary system header to define __stub macros. */
+/* Override any gcc2 internal prototype to avoid an error. */
+char GETB67();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_GETB67) || defined (__stub___GETB67)
+choke me
+#else
+GETB67();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_func_GETB67=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func_GETB67=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'GETB67`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ cat >> confdefs.h <<\EOF
+#define CRAY_STACKSEG_END GETB67
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+echo $ac_n "checking for getb67""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_func_getb67'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1272 "configure"
+#include "confdefs.h"
+#include <ctype.h> /* Arbitrary system header to define __stub macros. */
+/* Override any gcc2 internal prototype to avoid an error. */
+char getb67();
+
+int main() { return 0; }
+int t() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_getb67) || defined (__stub___getb67)
+choke me
+#else
+getb67();
+#endif
+
+; return 0; }
+EOF
+if eval $ac_link; then
+ rm -rf conftest*
+ eval "ac_cv_func_getb67=yes"
+else
+ rm -rf conftest*
+ eval "ac_cv_func_getb67=no"
+fi
+rm -f conftest*
+
+fi
+if eval "test \"`echo '$ac_cv_func_'getb67`\" = yes"; then
+ echo "$ac_t""yes" 1>&4
+ cat >> confdefs.h <<\EOF
+#define CRAY_STACKSEG_END getb67
+EOF
+
+else
+ echo "$ac_t""no" 1>&4
+fi
+
+fi
+
+fi
+
+fi
+
+echo $ac_n "checking stack direction for C alloca""... $ac_c" 1>&4
+if eval "test \"`echo '${'ac_cv_c_stack_direction'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&4
+else
+ if test "$cross_compiling" = yes; then
+ ac_cv_c_stack_direction=0
+else
+cat > conftest.$ac_ext <<EOF
+#line 1326 "configure"
+#include "confdefs.h"
+find_stack_direction ()
+{
+ static char *addr = 0;
+ auto char dummy;
+ if (addr == 0)
+ {
+ addr = &dummy;
+ return find_stack_direction ();
+ }
+ else
+ return (&dummy > addr) ? 1 : -1;
+}
+main ()
+{
+ exit (find_stack_direction() < 0);
+}
+EOF
+eval $ac_link
+if test -s conftest && (./conftest; exit) 2>/dev/null; then
+ ac_cv_c_stack_direction=1
+else
+ ac_cv_c_stack_direction=-1
+fi
+fi
+rm -fr conftest*
+fi
+echo "$ac_t""$ac_cv_c_stack_direction" 1>&4
+cat >> confdefs.h <<EOF
+#define STACK_DIRECTION $ac_cv_c_stack_direction
+EOF
+
+fi
+
+ ;;
+esac
+
+trap '' 1 2 15
+if test -w $cache_file; then
+echo "updating cache $cache_file"
+cat > $cache_file <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# Ultrix sh set writes to stderr and can't be redirected directly.
+(set) 2>&1 |
+ sed -n "s/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/: \${\1='\2'}/p" \
+ >> $cache_file
+else
+echo "not updating unwritable cache $cache_file"
+fi
+
+trap 'rm -fr conftest* confdefs* core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#!/bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.1"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr Makefile config.h:conf.in conftest*; exit 1' 1 2 15
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g$/@g/; /@g$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g$/%g/' > conftest.subs <<\CEOF
+$ac_vpsub
+$extrasub
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@LN_S@%$LN_S%g
+s%@YACC@%$YACC%g
+s%@CC@%$CC%g
+s%@RANLIB@%$RANLIB%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@CPP@%$CPP%g
+s%@ALLOCA@%$ALLOCA%g
+
+CEOF
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"Makefile"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust relative srcdir, etc. for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/$ac_dir"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" -f conftest.subs $ac_given_srcdir/$ac_file_in > $ac_file
+fi; done
+rm -f conftest.subs
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+CONFIG_HEADERS=${CONFIG_HEADERS-"config.h:conf.in"}
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%.*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ cp $ac_given_srcdir/$ac_file_in conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) \(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+# Maximum number of lines to put in a single here document.
+ac_max_here_lines=12
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+
+test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS
+
diff --git a/Tools/android/flex-2.5.4a/configure.in b/Tools/android/flex-2.5.4a/configure.in
new file mode 100644
index 0000000..366e65e
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/configure.in
@@ -0,0 +1,24 @@
+dnl Process this file with autoconf to produce a configure script.
+dnl
+AC_INIT(initscan.c)
+AC_CONFIG_HEADER(config.h:conf.in)
+
+AC_LN_S
+AC_PROG_YACC
+AC_PROG_CC
+AC_PROG_RANLIB
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+AC_CONST
+AC_TYPE_SIZE_T
+AC_HEADER_STDC
+AC_HAVE_HEADERS(string.h malloc.h sys/types.h)
+
+case "$YACC" in
+*bison*)
+ AC_ALLOCA
+ ;;
+esac
+
+AC_OUTPUT(Makefile,
+[test -z "$CONFIG_HEADERS" || echo timestamp > stamp-h])
diff --git a/Tools/android/flex-2.5.4a/dfa.c b/Tools/android/flex-2.5.4a/dfa.c
new file mode 100644
index 0000000..446114f
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/dfa.c
@@ -0,0 +1,1095 @@
+/* dfa - DFA construction routines */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/dfa.c,v 2.26 95/04/20 13:53:14 vern Exp $ */
+
+#include "flexdef.h"
+
+
+/* declare functions that have forward references */
+
+void dump_associated_rules PROTO((FILE*, int));
+void dump_transitions PROTO((FILE*, int[]));
+void sympartition PROTO((int[], int, int[], int[]));
+int symfollowset PROTO((int[], int, int, int[]));
+
+
+/* check_for_backing_up - check a DFA state for backing up
+ *
+ * synopsis
+ * void check_for_backing_up( int ds, int state[numecs] );
+ *
+ * ds is the number of the state to check and state[] is its out-transitions,
+ * indexed by equivalence class.
+ */
+
+void check_for_backing_up( ds, state )
+int ds;
+int state[];
+ {
+ if ( (reject && ! dfaacc[ds].dfaacc_set) ||
+ (! reject && ! dfaacc[ds].dfaacc_state) )
+ { /* state is non-accepting */
+ ++num_backing_up;
+
+ if ( backing_up_report )
+ {
+ fprintf( backing_up_file,
+ _( "State #%d is non-accepting -\n" ), ds );
+
+ /* identify the state */
+ dump_associated_rules( backing_up_file, ds );
+
+ /* Now identify it further using the out- and
+ * jam-transitions.
+ */
+ dump_transitions( backing_up_file, state );
+
+ putc( '\n', backing_up_file );
+ }
+ }
+ }
+
+
+/* check_trailing_context - check to see if NFA state set constitutes
+ * "dangerous" trailing context
+ *
+ * synopsis
+ * void check_trailing_context( int nfa_states[num_states+1], int num_states,
+ * int accset[nacc+1], int nacc );
+ *
+ * NOTES
+ * Trailing context is "dangerous" if both the head and the trailing
+ * part are of variable size \and/ there's a DFA state which contains
+ * both an accepting state for the head part of the rule and NFA states
+ * which occur after the beginning of the trailing context.
+ *
+ * When such a rule is matched, it's impossible to tell if having been
+ * in the DFA state indicates the beginning of the trailing context or
+ * further-along scanning of the pattern. In these cases, a warning
+ * message is issued.
+ *
+ * nfa_states[1 .. num_states] is the list of NFA states in the DFA.
+ * accset[1 .. nacc] is the list of accepting numbers for the DFA state.
+ */
+
+void check_trailing_context( nfa_states, num_states, accset, nacc )
+int *nfa_states, num_states;
+int *accset;
+int nacc;
+ {
+ register int i, j;
+
+ for ( i = 1; i <= num_states; ++i )
+ {
+ int ns = nfa_states[i];
+ register int type = state_type[ns];
+ register int ar = assoc_rule[ns];
+
+ if ( type == STATE_NORMAL || rule_type[ar] != RULE_VARIABLE )
+ { /* do nothing */
+ }
+
+ else if ( type == STATE_TRAILING_CONTEXT )
+ {
+ /* Potential trouble. Scan set of accepting numbers
+ * for the one marking the end of the "head". We
+ * assume that this looping will be fairly cheap
+ * since it's rare that an accepting number set
+ * is large.
+ */
+ for ( j = 1; j <= nacc; ++j )
+ if ( accset[j] & YY_TRAILING_HEAD_MASK )
+ {
+ line_warning(
+ _( "dangerous trailing context" ),
+ rule_linenum[ar] );
+ return;
+ }
+ }
+ }
+ }
+
+
+/* dump_associated_rules - list the rules associated with a DFA state
+ *
+ * Goes through the set of NFA states associated with the DFA and
+ * extracts the first MAX_ASSOC_RULES unique rules, sorts them,
+ * and writes a report to the given file.
+ */
+
+void dump_associated_rules( file, ds )
+FILE *file;
+int ds;
+ {
+ register int i, j;
+ register int num_associated_rules = 0;
+ int rule_set[MAX_ASSOC_RULES + 1];
+ int *dset = dss[ds];
+ int size = dfasiz[ds];
+
+ for ( i = 1; i <= size; ++i )
+ {
+ register int rule_num = rule_linenum[assoc_rule[dset[i]]];
+
+ for ( j = 1; j <= num_associated_rules; ++j )
+ if ( rule_num == rule_set[j] )
+ break;
+
+ if ( j > num_associated_rules )
+ { /* new rule */
+ if ( num_associated_rules < MAX_ASSOC_RULES )
+ rule_set[++num_associated_rules] = rule_num;
+ }
+ }
+
+ bubble( rule_set, num_associated_rules );
+
+ fprintf( file, _( " associated rule line numbers:" ) );
+
+ for ( i = 1; i <= num_associated_rules; ++i )
+ {
+ if ( i % 8 == 1 )
+ putc( '\n', file );
+
+ fprintf( file, "\t%d", rule_set[i] );
+ }
+
+ putc( '\n', file );
+ }
+
+
+/* dump_transitions - list the transitions associated with a DFA state
+ *
+ * synopsis
+ * dump_transitions( FILE *file, int state[numecs] );
+ *
+ * Goes through the set of out-transitions and lists them in human-readable
+ * form (i.e., not as equivalence classes); also lists jam transitions
+ * (i.e., all those which are not out-transitions, plus EOF). The dump
+ * is done to the given file.
+ */
+
+void dump_transitions( file, state )
+FILE *file;
+int state[];
+ {
+ register int i, ec;
+ int out_char_set[CSIZE];
+
+ for ( i = 0; i < csize; ++i )
+ {
+ ec = ABS( ecgroup[i] );
+ out_char_set[i] = state[ec];
+ }
+
+ fprintf( file, _( " out-transitions: " ) );
+
+ list_character_set( file, out_char_set );
+
+ /* now invert the members of the set to get the jam transitions */
+ for ( i = 0; i < csize; ++i )
+ out_char_set[i] = ! out_char_set[i];
+
+ fprintf( file, _( "\n jam-transitions: EOF " ) );
+
+ list_character_set( file, out_char_set );
+
+ putc( '\n', file );
+ }
+
+
+/* epsclosure - construct the epsilon closure of a set of ndfa states
+ *
+ * synopsis
+ * int *epsclosure( int t[num_states], int *numstates_addr,
+ * int accset[num_rules+1], int *nacc_addr,
+ * int *hashval_addr );
+ *
+ * NOTES
+ * The epsilon closure is the set of all states reachable by an arbitrary
+ * number of epsilon transitions, which themselves do not have epsilon
+ * transitions going out, unioned with the set of states which have non-null
+ * accepting numbers. t is an array of size numstates of nfa state numbers.
+ * Upon return, t holds the epsilon closure and *numstates_addr is updated.
+ * accset holds a list of the accepting numbers, and the size of accset is
+ * given by *nacc_addr. t may be subjected to reallocation if it is not
+ * large enough to hold the epsilon closure.
+ *
+ * hashval is the hash value for the dfa corresponding to the state set.
+ */
+
+int *epsclosure( t, ns_addr, accset, nacc_addr, hv_addr )
+int *t, *ns_addr, accset[], *nacc_addr, *hv_addr;
+ {
+ register int stkpos, ns, tsp;
+ int numstates = *ns_addr, nacc, hashval, transsym, nfaccnum;
+ int stkend, nstate;
+ static int did_stk_init = false, *stk;
+
+#define MARK_STATE(state) \
+trans1[state] = trans1[state] - MARKER_DIFFERENCE;
+
+#define IS_MARKED(state) (trans1[state] < 0)
+
+#define UNMARK_STATE(state) \
+trans1[state] = trans1[state] + MARKER_DIFFERENCE;
+
+#define CHECK_ACCEPT(state) \
+{ \
+nfaccnum = accptnum[state]; \
+if ( nfaccnum != NIL ) \
+accset[++nacc] = nfaccnum; \
+}
+
+#define DO_REALLOCATION \
+{ \
+current_max_dfa_size += MAX_DFA_SIZE_INCREMENT; \
+++num_reallocs; \
+t = reallocate_integer_array( t, current_max_dfa_size ); \
+stk = reallocate_integer_array( stk, current_max_dfa_size ); \
+} \
+
+#define PUT_ON_STACK(state) \
+{ \
+if ( ++stkend >= current_max_dfa_size ) \
+DO_REALLOCATION \
+stk[stkend] = state; \
+MARK_STATE(state) \
+}
+
+#define ADD_STATE(state) \
+{ \
+if ( ++numstates >= current_max_dfa_size ) \
+DO_REALLOCATION \
+t[numstates] = state; \
+hashval += state; \
+}
+
+#define STACK_STATE(state) \
+{ \
+PUT_ON_STACK(state) \
+CHECK_ACCEPT(state) \
+if ( nfaccnum != NIL || transchar[state] != SYM_EPSILON ) \
+ADD_STATE(state) \
+}
+
+
+ if ( ! did_stk_init )
+ {
+ stk = allocate_integer_array( current_max_dfa_size );
+ did_stk_init = true;
+ }
+
+ nacc = stkend = hashval = 0;
+
+ for ( nstate = 1; nstate <= numstates; ++nstate )
+ {
+ ns = t[nstate];
+
+ /* The state could be marked if we've already pushed it onto
+ * the stack.
+ */
+ if ( ! IS_MARKED(ns) )
+ {
+ PUT_ON_STACK(ns)
+ CHECK_ACCEPT(ns)
+ hashval += ns;
+ }
+ }
+
+ for ( stkpos = 1; stkpos <= stkend; ++stkpos )
+ {
+ ns = stk[stkpos];
+ transsym = transchar[ns];
+
+ if ( transsym == SYM_EPSILON )
+ {
+ tsp = trans1[ns] + MARKER_DIFFERENCE;
+
+ if ( tsp != NO_TRANSITION )
+ {
+ if ( ! IS_MARKED(tsp) )
+ STACK_STATE(tsp)
+
+ tsp = trans2[ns];
+
+ if ( tsp != NO_TRANSITION && ! IS_MARKED(tsp) )
+ STACK_STATE(tsp)
+ }
+ }
+ }
+
+ /* Clear out "visit" markers. */
+
+ for ( stkpos = 1; stkpos <= stkend; ++stkpos )
+ {
+ if ( IS_MARKED(stk[stkpos]) )
+ UNMARK_STATE(stk[stkpos])
+ else
+ flexfatal(
+ _( "consistency check failed in epsclosure()" ) );
+ }
+
+ *ns_addr = numstates;
+ *hv_addr = hashval;
+ *nacc_addr = nacc;
+
+ return t;
+ }
+
+
+/* increase_max_dfas - increase the maximum number of DFAs */
+
+void increase_max_dfas()
+ {
+ current_max_dfas += MAX_DFAS_INCREMENT;
+
+ ++num_reallocs;
+
+ base = reallocate_integer_array( base, current_max_dfas );
+ def = reallocate_integer_array( def, current_max_dfas );
+ dfasiz = reallocate_integer_array( dfasiz, current_max_dfas );
+ accsiz = reallocate_integer_array( accsiz, current_max_dfas );
+ dhash = reallocate_integer_array( dhash, current_max_dfas );
+ dss = reallocate_int_ptr_array( dss, current_max_dfas );
+ dfaacc = reallocate_dfaacc_union( dfaacc, current_max_dfas );
+
+ if ( nultrans )
+ nultrans =
+ reallocate_integer_array( nultrans, current_max_dfas );
+ }
+
+
+/* ntod - convert an ndfa to a dfa
+ *
+ * Creates the dfa corresponding to the ndfa we've constructed. The
+ * dfa starts out in state #1.
+ */
+
+void ntod()
+ {
+ int *accset, ds, nacc, newds;
+ int sym, hashval, numstates, dsize;
+ int num_full_table_rows; /* used only for -f */
+ int *nset, *dset;
+ int targptr, totaltrans, i, comstate, comfreq, targ;
+ int symlist[CSIZE + 1];
+ int num_start_states;
+ int todo_head, todo_next;
+
+ /* Note that the following are indexed by *equivalence classes*
+ * and not by characters. Since equivalence classes are indexed
+ * beginning with 1, even if the scanner accepts NUL's, this
+ * means that (since every character is potentially in its own
+ * equivalence class) these arrays must have room for indices
+ * from 1 to CSIZE, so their size must be CSIZE + 1.
+ */
+ int duplist[CSIZE + 1], state[CSIZE + 1];
+ int targfreq[CSIZE + 1], targstate[CSIZE + 1];
+
+ accset = allocate_integer_array( num_rules + 1 );
+ nset = allocate_integer_array( current_max_dfa_size );
+
+ /* The "todo" queue is represented by the head, which is the DFA
+ * state currently being processed, and the "next", which is the
+ * next DFA state number available (not in use). We depend on the
+ * fact that snstods() returns DFA's \in increasing order/, and thus
+ * need only know the bounds of the dfas to be processed.
+ */
+ todo_head = todo_next = 0;
+
+ for ( i = 0; i <= csize; ++i )
+ {
+ duplist[i] = NIL;
+ symlist[i] = false;
+ }
+
+ for ( i = 0; i <= num_rules; ++i )
+ accset[i] = NIL;
+
+ if ( trace )
+ {
+ dumpnfa( scset[1] );
+ fputs( _( "\n\nDFA Dump:\n\n" ), stderr );
+ }
+
+ inittbl();
+
+ /* Check to see whether we should build a separate table for
+ * transitions on NUL characters. We don't do this for full-speed
+ * (-F) scanners, since for them we don't have a simple state
+ * number lying around with which to index the table. We also
+ * don't bother doing it for scanners unless (1) NUL is in its own
+ * equivalence class (indicated by a positive value of
+ * ecgroup[NUL]), (2) NUL's equivalence class is the last
+ * equivalence class, and (3) the number of equivalence classes is
+ * the same as the number of characters. This latter case comes
+ * about when useecs is false or when it's true but every character
+ * still manages to land in its own class (unlikely, but it's
+ * cheap to check for). If all these things are true then the
+ * character code needed to represent NUL's equivalence class for
+ * indexing the tables is going to take one more bit than the
+ * number of characters, and therefore we won't be assured of
+ * being able to fit it into a YY_CHAR variable. This rules out
+ * storing the transitions in a compressed table, since the code
+ * for interpreting them uses a YY_CHAR variable (perhaps it
+ * should just use an integer, though; this is worth pondering ...
+ * ###).
+ *
+ * Finally, for full tables, we want the number of entries in the
+ * table to be a power of two so the array references go fast (it
+ * will just take a shift to compute the major index). If
+ * encoding NUL's transitions in the table will spoil this, we
+ * give it its own table (note that this will be the case if we're
+ * not using equivalence classes).
+ */
+
+ /* Note that the test for ecgroup[0] == numecs below accomplishes
+ * both (1) and (2) above
+ */
+ if ( ! fullspd && ecgroup[0] == numecs )
+ {
+ /* NUL is alone in its equivalence class, which is the
+ * last one.
+ */
+ int use_NUL_table = (numecs == csize);
+
+ if ( fulltbl && ! use_NUL_table )
+ {
+ /* We still may want to use the table if numecs
+ * is a power of 2.
+ */
+ int power_of_two;
+
+ for ( power_of_two = 1; power_of_two <= csize;
+ power_of_two *= 2 )
+ if ( numecs == power_of_two )
+ {
+ use_NUL_table = true;
+ break;
+ }
+ }
+
+ if ( use_NUL_table )
+ nultrans = allocate_integer_array( current_max_dfas );
+
+ /* From now on, nultrans != nil indicates that we're
+ * saving null transitions for later, separate encoding.
+ */
+ }
+
+
+ if ( fullspd )
+ {
+ for ( i = 0; i <= numecs; ++i )
+ state[i] = 0;
+
+ place_state( state, 0, 0 );
+ dfaacc[0].dfaacc_state = 0;
+ }
+
+ else if ( fulltbl )
+ {
+ if ( nultrans )
+ /* We won't be including NUL's transitions in the
+ * table, so build it for entries from 0 .. numecs - 1.
+ */
+ num_full_table_rows = numecs;
+
+ else
+ /* Take into account the fact that we'll be including
+ * the NUL entries in the transition table. Build it
+ * from 0 .. numecs.
+ */
+ num_full_table_rows = numecs + 1;
+
+ /* Unless -Ca, declare it "short" because it's a real
+ * long-shot that that won't be large enough.
+ */
+ out_str_dec( "static yyconst %s yy_nxt[][%d] =\n {\n",
+ /* '}' so vi doesn't get too confused */
+ long_align ? "long" : "short", num_full_table_rows );
+
+ outn( " {" );
+
+ /* Generate 0 entries for state #0. */
+ for ( i = 0; i < num_full_table_rows; ++i )
+ mk2data( 0 );
+
+ dataflush();
+ outn( " },\n" );
+ }
+
+ /* Create the first states. */
+
+ num_start_states = lastsc * 2;
+
+ for ( i = 1; i <= num_start_states; ++i )
+ {
+ numstates = 1;
+
+ /* For each start condition, make one state for the case when
+ * we're at the beginning of the line (the '^' operator) and
+ * one for the case when we're not.
+ */
+ if ( i % 2 == 1 )
+ nset[numstates] = scset[(i / 2) + 1];
+ else
+ nset[numstates] =
+ mkbranch( scbol[i / 2], scset[i / 2] );
+
+ nset = epsclosure( nset, &numstates, accset, &nacc, &hashval );
+
+ if ( snstods( nset, numstates, accset, nacc, hashval, &ds ) )
+ {
+ numas += nacc;
+ totnst += numstates;
+ ++todo_next;
+
+ if ( variable_trailing_context_rules && nacc > 0 )
+ check_trailing_context( nset, numstates,
+ accset, nacc );
+ }
+ }
+
+ if ( ! fullspd )
+ {
+ if ( ! snstods( nset, 0, accset, 0, 0, &end_of_buffer_state ) )
+ flexfatal(
+ _( "could not create unique end-of-buffer state" ) );
+
+ ++numas;
+ ++num_start_states;
+ ++todo_next;
+ }
+
+ while ( todo_head < todo_next )
+ {
+ targptr = 0;
+ totaltrans = 0;
+
+ for ( i = 1; i <= numecs; ++i )
+ state[i] = 0;
+
+ ds = ++todo_head;
+
+ dset = dss[ds];
+ dsize = dfasiz[ds];
+
+ if ( trace )
+ fprintf( stderr, _( "state # %d:\n" ), ds );
+
+ sympartition( dset, dsize, symlist, duplist );
+
+ for ( sym = 1; sym <= numecs; ++sym )
+ {
+ if ( symlist[sym] )
+ {
+ symlist[sym] = 0;
+
+ if ( duplist[sym] == NIL )
+ {
+ /* Symbol has unique out-transitions. */
+ numstates = symfollowset( dset, dsize,
+ sym, nset );
+ nset = epsclosure( nset, &numstates,
+ accset, &nacc, &hashval );
+
+ if ( snstods( nset, numstates, accset,
+ nacc, hashval, &newds ) )
+ {
+ totnst = totnst + numstates;
+ ++todo_next;
+ numas += nacc;
+
+ if (
+ variable_trailing_context_rules &&
+ nacc > 0 )
+ check_trailing_context(
+ nset, numstates,
+ accset, nacc );
+ }
+
+ state[sym] = newds;
+
+ if ( trace )
+ fprintf( stderr, "\t%d\t%d\n",
+ sym, newds );
+
+ targfreq[++targptr] = 1;
+ targstate[targptr] = newds;
+ ++numuniq;
+ }
+
+ else
+ {
+ /* sym's equivalence class has the same
+ * transitions as duplist(sym)'s
+ * equivalence class.
+ */
+ targ = state[duplist[sym]];
+ state[sym] = targ;
+
+ if ( trace )
+ fprintf( stderr, "\t%d\t%d\n",
+ sym, targ );
+
+ /* Update frequency count for
+ * destination state.
+ */
+
+ i = 0;
+ while ( targstate[++i] != targ )
+ ;
+
+ ++targfreq[i];
+ ++numdup;
+ }
+
+ ++totaltrans;
+ duplist[sym] = NIL;
+ }
+ }
+
+ if ( caseins && ! useecs )
+ {
+ register int j;
+
+ for ( i = 'A', j = 'a'; i <= 'Z'; ++i, ++j )
+ {
+ if ( state[i] == 0 && state[j] != 0 )
+ /* We're adding a transition. */
+ ++totaltrans;
+
+ else if ( state[i] != 0 && state[j] == 0 )
+ /* We're taking away a transition. */
+ --totaltrans;
+
+ state[i] = state[j];
+ }
+ }
+
+ numsnpairs += totaltrans;
+
+ if ( ds > num_start_states )
+ check_for_backing_up( ds, state );
+
+ if ( nultrans )
+ {
+ nultrans[ds] = state[NUL_ec];
+ state[NUL_ec] = 0; /* remove transition */
+ }
+
+ if ( fulltbl )
+ {
+ outn( " {" );
+
+ /* Supply array's 0-element. */
+ if ( ds == end_of_buffer_state )
+ mk2data( -end_of_buffer_state );
+ else
+ mk2data( end_of_buffer_state );
+
+ for ( i = 1; i < num_full_table_rows; ++i )
+ /* Jams are marked by negative of state
+ * number.
+ */
+ mk2data( state[i] ? state[i] : -ds );
+
+ dataflush();
+ outn( " },\n" );
+ }
+
+ else if ( fullspd )
+ place_state( state, ds, totaltrans );
+
+ else if ( ds == end_of_buffer_state )
+ /* Special case this state to make sure it does what
+ * it's supposed to, i.e., jam on end-of-buffer.
+ */
+ stack1( ds, 0, 0, JAMSTATE );
+
+ else /* normal, compressed state */
+ {
+ /* Determine which destination state is the most
+ * common, and how many transitions to it there are.
+ */
+
+ comfreq = 0;
+ comstate = 0;
+
+ for ( i = 1; i <= targptr; ++i )
+ if ( targfreq[i] > comfreq )
+ {
+ comfreq = targfreq[i];
+ comstate = targstate[i];
+ }
+
+ bldtbl( state, ds, totaltrans, comstate, comfreq );
+ }
+ }
+
+ if ( fulltbl )
+ dataend();
+
+ else if ( ! fullspd )
+ {
+ cmptmps(); /* create compressed template entries */
+
+ /* Create tables for all the states with only one
+ * out-transition.
+ */
+ while ( onesp > 0 )
+ {
+ mk1tbl( onestate[onesp], onesym[onesp], onenext[onesp],
+ onedef[onesp] );
+ --onesp;
+ }
+
+ mkdeftbl();
+ }
+
+ flex_free( (void *) accset );
+ flex_free( (void *) nset );
+ }
+
+
+/* snstods - converts a set of ndfa states into a dfa state
+ *
+ * synopsis
+ * is_new_state = snstods( int sns[numstates], int numstates,
+ * int accset[num_rules+1], int nacc,
+ * int hashval, int *newds_addr );
+ *
+ * On return, the dfa state number is in newds.
+ */
+
+int snstods( sns, numstates, accset, nacc, hashval, newds_addr )
+int sns[], numstates, accset[], nacc, hashval, *newds_addr;
+ {
+ int didsort = 0;
+ register int i, j;
+ int newds, *oldsns;
+
+ for ( i = 1; i <= lastdfa; ++i )
+ if ( hashval == dhash[i] )
+ {
+ if ( numstates == dfasiz[i] )
+ {
+ oldsns = dss[i];
+
+ if ( ! didsort )
+ {
+ /* We sort the states in sns so we
+ * can compare it to oldsns quickly.
+ * We use bubble because there probably
+ * aren't very many states.
+ */
+ bubble( sns, numstates );
+ didsort = 1;
+ }
+
+ for ( j = 1; j <= numstates; ++j )
+ if ( sns[j] != oldsns[j] )
+ break;
+
+ if ( j > numstates )
+ {
+ ++dfaeql;
+ *newds_addr = i;
+ return 0;
+ }
+
+ ++hshcol;
+ }
+
+ else
+ ++hshsave;
+ }
+
+ /* Make a new dfa. */
+
+ if ( ++lastdfa >= current_max_dfas )
+ increase_max_dfas();
+
+ newds = lastdfa;
+
+ dss[newds] = allocate_integer_array( numstates + 1 );
+
+ /* If we haven't already sorted the states in sns, we do so now,
+ * so that future comparisons with it can be made quickly.
+ */
+
+ if ( ! didsort )
+ bubble( sns, numstates );
+
+ for ( i = 1; i <= numstates; ++i )
+ dss[newds][i] = sns[i];
+
+ dfasiz[newds] = numstates;
+ dhash[newds] = hashval;
+
+ if ( nacc == 0 )
+ {
+ if ( reject )
+ dfaacc[newds].dfaacc_set = (int *) 0;
+ else
+ dfaacc[newds].dfaacc_state = 0;
+
+ accsiz[newds] = 0;
+ }
+
+ else if ( reject )
+ {
+ /* We sort the accepting set in increasing order so the
+ * disambiguating rule that the first rule listed is considered
+ * match in the event of ties will work. We use a bubble
+ * sort since the list is probably quite small.
+ */
+
+ bubble( accset, nacc );
+
+ dfaacc[newds].dfaacc_set = allocate_integer_array( nacc + 1 );
+
+ /* Save the accepting set for later */
+ for ( i = 1; i <= nacc; ++i )
+ {
+ dfaacc[newds].dfaacc_set[i] = accset[i];
+
+ if ( accset[i] <= num_rules )
+ /* Who knows, perhaps a REJECT can yield
+ * this rule.
+ */
+ rule_useful[accset[i]] = true;
+ }
+
+ accsiz[newds] = nacc;
+ }
+
+ else
+ {
+ /* Find lowest numbered rule so the disambiguating rule
+ * will work.
+ */
+ j = num_rules + 1;
+
+ for ( i = 1; i <= nacc; ++i )
+ if ( accset[i] < j )
+ j = accset[i];
+
+ dfaacc[newds].dfaacc_state = j;
+
+ if ( j <= num_rules )
+ rule_useful[j] = true;
+ }
+
+ *newds_addr = newds;
+
+ return 1;
+ }
+
+
+/* symfollowset - follow the symbol transitions one step
+ *
+ * synopsis
+ * numstates = symfollowset( int ds[current_max_dfa_size], int dsize,
+ * int transsym, int nset[current_max_dfa_size] );
+ */
+
+int symfollowset( ds, dsize, transsym, nset )
+int ds[], dsize, transsym, nset[];
+ {
+ int ns, tsp, sym, i, j, lenccl, ch, numstates, ccllist;
+
+ numstates = 0;
+
+ for ( i = 1; i <= dsize; ++i )
+ { /* for each nfa state ns in the state set of ds */
+ ns = ds[i];
+ sym = transchar[ns];
+ tsp = trans1[ns];
+
+ if ( sym < 0 )
+ { /* it's a character class */
+ sym = -sym;
+ ccllist = cclmap[sym];
+ lenccl = ccllen[sym];
+
+ if ( cclng[sym] )
+ {
+ for ( j = 0; j < lenccl; ++j )
+ {
+ /* Loop through negated character
+ * class.
+ */
+ ch = ccltbl[ccllist + j];
+
+ if ( ch == 0 )
+ ch = NUL_ec;
+
+ if ( ch > transsym )
+ /* Transsym isn't in negated
+ * ccl.
+ */
+ break;
+
+ else if ( ch == transsym )
+ /* next 2 */ goto bottom;
+ }
+
+ /* Didn't find transsym in ccl. */
+ nset[++numstates] = tsp;
+ }
+
+ else
+ for ( j = 0; j < lenccl; ++j )
+ {
+ ch = ccltbl[ccllist + j];
+
+ if ( ch == 0 )
+ ch = NUL_ec;
+
+ if ( ch > transsym )
+ break;
+ else if ( ch == transsym )
+ {
+ nset[++numstates] = tsp;
+ break;
+ }
+ }
+ }
+
+ else if ( sym >= 'A' && sym <= 'Z' && caseins )
+ flexfatal(
+ _( "consistency check failed in symfollowset" ) );
+
+ else if ( sym == SYM_EPSILON )
+ { /* do nothing */
+ }
+
+ else if ( ABS( ecgroup[sym] ) == transsym )
+ nset[++numstates] = tsp;
+
+ bottom: ;
+ }
+
+ return numstates;
+ }
+
+
+/* sympartition - partition characters with same out-transitions
+ *
+ * synopsis
+ * sympartition( int ds[current_max_dfa_size], int numstates,
+ * int symlist[numecs], int duplist[numecs] );
+ */
+
+void sympartition( ds, numstates, symlist, duplist )
+int ds[], numstates;
+int symlist[], duplist[];
+ {
+ int tch, i, j, k, ns, dupfwd[CSIZE + 1], lenccl, cclp, ich;
+
+ /* Partitioning is done by creating equivalence classes for those
+ * characters which have out-transitions from the given state. Thus
+ * we are really creating equivalence classes of equivalence classes.
+ */
+
+ for ( i = 1; i <= numecs; ++i )
+ { /* initialize equivalence class list */
+ duplist[i] = i - 1;
+ dupfwd[i] = i + 1;
+ }
+
+ duplist[1] = NIL;
+ dupfwd[numecs] = NIL;
+
+ for ( i = 1; i <= numstates; ++i )
+ {
+ ns = ds[i];
+ tch = transchar[ns];
+
+ if ( tch != SYM_EPSILON )
+ {
+ if ( tch < -lastccl || tch >= csize )
+ {
+ flexfatal(
+ _( "bad transition character detected in sympartition()" ) );
+ }
+
+ if ( tch >= 0 )
+ { /* character transition */
+ int ec = ecgroup[tch];
+
+ mkechar( ec, dupfwd, duplist );
+ symlist[ec] = 1;
+ }
+
+ else
+ { /* character class */
+ tch = -tch;
+
+ lenccl = ccllen[tch];
+ cclp = cclmap[tch];
+ mkeccl( ccltbl + cclp, lenccl, dupfwd,
+ duplist, numecs, NUL_ec );
+
+ if ( cclng[tch] )
+ {
+ j = 0;
+
+ for ( k = 0; k < lenccl; ++k )
+ {
+ ich = ccltbl[cclp + k];
+
+ if ( ich == 0 )
+ ich = NUL_ec;
+
+ for ( ++j; j < ich; ++j )
+ symlist[j] = 1;
+ }
+
+ for ( ++j; j <= numecs; ++j )
+ symlist[j] = 1;
+ }
+
+ else
+ for ( k = 0; k < lenccl; ++k )
+ {
+ ich = ccltbl[cclp + k];
+
+ if ( ich == 0 )
+ ich = NUL_ec;
+
+ symlist[ich] = 1;
+ }
+ }
+ }
+ }
+ }
diff --git a/Tools/android/flex-2.5.4a/ecs.c b/Tools/android/flex-2.5.4a/ecs.c
new file mode 100644
index 0000000..b873c28
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/ecs.c
@@ -0,0 +1,225 @@
+/* ecs - equivalence class routines */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/ecs.c,v 2.9 93/12/07 10:18:20 vern Exp $ */
+
+#include "flexdef.h"
+
+/* ccl2ecl - convert character classes to set of equivalence classes */
+
+void ccl2ecl()
+ {
+ int i, ich, newlen, cclp, ccls, cclmec;
+
+ for ( i = 1; i <= lastccl; ++i )
+ {
+ /* We loop through each character class, and for each character
+ * in the class, add the character's equivalence class to the
+ * new "character" class we are creating. Thus when we are all
+ * done, character classes will really consist of collections
+ * of equivalence classes
+ */
+
+ newlen = 0;
+ cclp = cclmap[i];
+
+ for ( ccls = 0; ccls < ccllen[i]; ++ccls )
+ {
+ ich = ccltbl[cclp + ccls];
+ cclmec = ecgroup[ich];
+
+ if ( cclmec > 0 )
+ {
+ ccltbl[cclp + newlen] = cclmec;
+ ++newlen;
+ }
+ }
+
+ ccllen[i] = newlen;
+ }
+ }
+
+
+/* cre8ecs - associate equivalence class numbers with class members
+ *
+ * fwd is the forward linked-list of equivalence class members. bck
+ * is the backward linked-list, and num is the number of class members.
+ *
+ * Returned is the number of classes.
+ */
+
+int cre8ecs( fwd, bck, num )
+int fwd[], bck[], num;
+ {
+ int i, j, numcl;
+
+ numcl = 0;
+
+ /* Create equivalence class numbers. From now on, ABS( bck(x) )
+ * is the equivalence class number for object x. If bck(x)
+ * is positive, then x is the representative of its equivalence
+ * class.
+ */
+ for ( i = 1; i <= num; ++i )
+ if ( bck[i] == NIL )
+ {
+ bck[i] = ++numcl;
+ for ( j = fwd[i]; j != NIL; j = fwd[j] )
+ bck[j] = -numcl;
+ }
+
+ return numcl;
+ }
+
+
+/* mkeccl - update equivalence classes based on character class xtions
+ *
+ * synopsis
+ * Char ccls[];
+ * int lenccl, fwd[llsiz], bck[llsiz], llsiz, NUL_mapping;
+ * void mkeccl( Char ccls[], int lenccl, int fwd[llsiz], int bck[llsiz],
+ * int llsiz, int NUL_mapping );
+ *
+ * ccls contains the elements of the character class, lenccl is the
+ * number of elements in the ccl, fwd is the forward link-list of equivalent
+ * characters, bck is the backward link-list, and llsiz size of the link-list.
+ *
+ * NUL_mapping is the value which NUL (0) should be mapped to.
+ */
+
+void mkeccl( ccls, lenccl, fwd, bck, llsiz, NUL_mapping )
+Char ccls[];
+int lenccl, fwd[], bck[], llsiz, NUL_mapping;
+ {
+ int cclp, oldec, newec;
+ int cclm, i, j;
+ static unsigned char cclflags[CSIZE]; /* initialized to all '\0' */
+
+ /* Note that it doesn't matter whether or not the character class is
+ * negated. The same results will be obtained in either case.
+ */
+
+ cclp = 0;
+
+ while ( cclp < lenccl )
+ {
+ cclm = ccls[cclp];
+
+ if ( NUL_mapping && cclm == 0 )
+ cclm = NUL_mapping;
+
+ oldec = bck[cclm];
+ newec = cclm;
+
+ j = cclp + 1;
+
+ for ( i = fwd[cclm]; i != NIL && i <= llsiz; i = fwd[i] )
+ { /* look for the symbol in the character class */
+ for ( ; j < lenccl; ++j )
+ {
+ register int ccl_char;
+
+ if ( NUL_mapping && ccls[j] == 0 )
+ ccl_char = NUL_mapping;
+ else
+ ccl_char = ccls[j];
+
+ if ( ccl_char > i )
+ break;
+
+ if ( ccl_char == i && ! cclflags[j] )
+ {
+ /* We found an old companion of cclm
+ * in the ccl. Link it into the new
+ * equivalence class and flag it as
+ * having been processed.
+ */
+
+ bck[i] = newec;
+ fwd[newec] = i;
+ newec = i;
+ /* Set flag so we don't reprocess. */
+ cclflags[j] = 1;
+
+ /* Get next equivalence class member. */
+ /* continue 2 */
+ goto next_pt;
+ }
+ }
+
+ /* Symbol isn't in character class. Put it in the old
+ * equivalence class.
+ */
+
+ bck[i] = oldec;
+
+ if ( oldec != NIL )
+ fwd[oldec] = i;
+
+ oldec = i;
+
+ next_pt: ;
+ }
+
+ if ( bck[cclm] != NIL || oldec != bck[cclm] )
+ {
+ bck[cclm] = NIL;
+ fwd[oldec] = NIL;
+ }
+
+ fwd[newec] = NIL;
+
+ /* Find next ccl member to process. */
+
+ for ( ++cclp; cclflags[cclp] && cclp < lenccl; ++cclp )
+ {
+ /* Reset "doesn't need processing" flag. */
+ cclflags[cclp] = 0;
+ }
+ }
+ }
+
+
+/* mkechar - create equivalence class for single character */
+
+void mkechar( tch, fwd, bck )
+int tch, fwd[], bck[];
+ {
+ /* If until now the character has been a proper subset of
+ * an equivalence class, break it away to create a new ec
+ */
+
+ if ( fwd[tch] != NIL )
+ bck[fwd[tch]] = bck[tch];
+
+ if ( bck[tch] != NIL )
+ fwd[bck[tch]] = fwd[tch];
+
+ fwd[tch] = NIL;
+ bck[tch] = NIL;
+ }
diff --git a/Tools/android/flex-2.5.4a/flex.1 b/Tools/android/flex-2.5.4a/flex.1
new file mode 100644
index 0000000..f79a3ef
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/flex.1
@@ -0,0 +1,4060 @@
+.TH FLEX 1 "April 1995" "Version 2.5"
+.SH NAME
+flex \- fast lexical analyzer generator
+.SH SYNOPSIS
+.B flex
+.B [\-bcdfhilnpstvwBFILTV78+? \-C[aefFmr] \-ooutput \-Pprefix \-Sskeleton]
+.B [\-\-help \-\-version]
+.I [filename ...]
+.SH OVERVIEW
+This manual describes
+.I flex,
+a tool for generating programs that perform pattern-matching on text. The
+manual includes both tutorial and reference sections:
+.nf
+
+ Description
+ a brief overview of the tool
+
+ Some Simple Examples
+
+ Format Of The Input File
+
+ Patterns
+ the extended regular expressions used by flex
+
+ How The Input Is Matched
+ the rules for determining what has been matched
+
+ Actions
+ how to specify what to do when a pattern is matched
+
+ The Generated Scanner
+ details regarding the scanner that flex produces;
+ how to control the input source
+
+ Start Conditions
+ introducing context into your scanners, and
+ managing "mini-scanners"
+
+ Multiple Input Buffers
+ how to manipulate multiple input sources; how to
+ scan from strings instead of files
+
+ End-of-file Rules
+ special rules for matching the end of the input
+
+ Miscellaneous Macros
+ a summary of macros available to the actions
+
+ Values Available To The User
+ a summary of values available to the actions
+
+ Interfacing With Yacc
+ connecting flex scanners together with yacc parsers
+
+ Options
+ flex command-line options, and the "%option"
+ directive
+
+ Performance Considerations
+ how to make your scanner go as fast as possible
+
+ Generating C++ Scanners
+ the (experimental) facility for generating C++
+ scanner classes
+
+ Incompatibilities With Lex And POSIX
+ how flex differs from AT&T lex and the POSIX lex
+ standard
+
+ Diagnostics
+ those error messages produced by flex (or scanners
+ it generates) whose meanings might not be apparent
+
+ Files
+ files used by flex
+
+ Deficiencies / Bugs
+ known problems with flex
+
+ See Also
+ other documentation, related tools
+
+ Author
+ includes contact information
+
+.fi
+.SH DESCRIPTION
+.I flex
+is a tool for generating
+.I scanners:
+programs which recognized lexical patterns in text.
+.I flex
+reads
+the given input files, or its standard input if no file names are given,
+for a description of a scanner to generate. The description is in
+the form of pairs
+of regular expressions and C code, called
+.I rules. flex
+generates as output a C source file,
+.B lex.yy.c,
+which defines a routine
+.B yylex().
+This file is compiled and linked with the
+.B \-lfl
+library to produce an executable. When the executable is run,
+it analyzes its input for occurrences
+of the regular expressions. Whenever it finds one, it executes
+the corresponding C code.
+.SH SOME SIMPLE EXAMPLES
+.PP
+First some simple examples to get the flavor of how one uses
+.I flex.
+The following
+.I flex
+input specifies a scanner which whenever it encounters the string
+"username" will replace it with the user's login name:
+.nf
+
+ %%
+ username printf( "%s", getlogin() );
+
+.fi
+By default, any text not matched by a
+.I flex
+scanner
+is copied to the output, so the net effect of this scanner is
+to copy its input file to its output with each occurrence
+of "username" expanded.
+In this input, there is just one rule. "username" is the
+.I pattern
+and the "printf" is the
+.I action.
+The "%%" marks the beginning of the rules.
+.PP
+Here's another simple example:
+.nf
+
+ int num_lines = 0, num_chars = 0;
+
+ %%
+ \\n ++num_lines; ++num_chars;
+ . ++num_chars;
+
+ %%
+ main()
+ {
+ yylex();
+ printf( "# of lines = %d, # of chars = %d\\n",
+ num_lines, num_chars );
+ }
+
+.fi
+This scanner counts the number of characters and the number
+of lines in its input (it produces no output other than the
+final report on the counts). The first line
+declares two globals, "num_lines" and "num_chars", which are accessible
+both inside
+.B yylex()
+and in the
+.B main()
+routine declared after the second "%%". There are two rules, one
+which matches a newline ("\\n") and increments both the line count and
+the character count, and one which matches any character other than
+a newline (indicated by the "." regular expression).
+.PP
+A somewhat more complicated example:
+.nf
+
+ /* scanner for a toy Pascal-like language */
+
+ %{
+ /* need this for the call to atof() below */
+ #include <math.h>
+ %}
+
+ DIGIT [0-9]
+ ID [a-z][a-z0-9]*
+
+ %%
+
+ {DIGIT}+ {
+ printf( "An integer: %s (%d)\\n", yytext,
+ atoi( yytext ) );
+ }
+
+ {DIGIT}+"."{DIGIT}* {
+ printf( "A float: %s (%g)\\n", yytext,
+ atof( yytext ) );
+ }
+
+ if|then|begin|end|procedure|function {
+ printf( "A keyword: %s\\n", yytext );
+ }
+
+ {ID} printf( "An identifier: %s\\n", yytext );
+
+ "+"|"-"|"*"|"/" printf( "An operator: %s\\n", yytext );
+
+ "{"[^}\\n]*"}" /* eat up one-line comments */
+
+ [ \\t\\n]+ /* eat up whitespace */
+
+ . printf( "Unrecognized character: %s\\n", yytext );
+
+ %%
+
+ main( argc, argv )
+ int argc;
+ char **argv;
+ {
+ ++argv, --argc; /* skip over program name */
+ if ( argc > 0 )
+ yyin = fopen( argv[0], "r" );
+ else
+ yyin = stdin;
+
+ yylex();
+ }
+
+.fi
+This is the beginnings of a simple scanner for a language like
+Pascal. It identifies different types of
+.I tokens
+and reports on what it has seen.
+.PP
+The details of this example will be explained in the following
+sections.
+.SH FORMAT OF THE INPUT FILE
+The
+.I flex
+input file consists of three sections, separated by a line with just
+.B %%
+in it:
+.nf
+
+ definitions
+ %%
+ rules
+ %%
+ user code
+
+.fi
+The
+.I definitions
+section contains declarations of simple
+.I name
+definitions to simplify the scanner specification, and declarations of
+.I start conditions,
+which are explained in a later section.
+.PP
+Name definitions have the form:
+.nf
+
+ name definition
+
+.fi
+The "name" is a word beginning with a letter or an underscore ('_')
+followed by zero or more letters, digits, '_', or '-' (dash).
+The definition is taken to begin at the first non-white-space character
+following the name and continuing to the end of the line.
+The definition can subsequently be referred to using "{name}", which
+will expand to "(definition)". For example,
+.nf
+
+ DIGIT [0-9]
+ ID [a-z][a-z0-9]*
+
+.fi
+defines "DIGIT" to be a regular expression which matches a
+single digit, and
+"ID" to be a regular expression which matches a letter
+followed by zero-or-more letters-or-digits.
+A subsequent reference to
+.nf
+
+ {DIGIT}+"."{DIGIT}*
+
+.fi
+is identical to
+.nf
+
+ ([0-9])+"."([0-9])*
+
+.fi
+and matches one-or-more digits followed by a '.' followed
+by zero-or-more digits.
+.PP
+The
+.I rules
+section of the
+.I flex
+input contains a series of rules of the form:
+.nf
+
+ pattern action
+
+.fi
+where the pattern must be unindented and the action must begin
+on the same line.
+.PP
+See below for a further description of patterns and actions.
+.PP
+Finally, the user code section is simply copied to
+.B lex.yy.c
+verbatim.
+It is used for companion routines which call or are called
+by the scanner. The presence of this section is optional;
+if it is missing, the second
+.B %%
+in the input file may be skipped, too.
+.PP
+In the definitions and rules sections, any
+.I indented
+text or text enclosed in
+.B %{
+and
+.B %}
+is copied verbatim to the output (with the %{}'s removed).
+The %{}'s must appear unindented on lines by themselves.
+.PP
+In the rules section,
+any indented or %{} text appearing before the
+first rule may be used to declare variables
+which are local to the scanning routine and (after the declarations)
+code which is to be executed whenever the scanning routine is entered.
+Other indented or %{} text in the rule section is still copied to the output,
+but its meaning is not well-defined and it may well cause compile-time
+errors (this feature is present for
+.I POSIX
+compliance; see below for other such features).
+.PP
+In the definitions section (but not in the rules section),
+an unindented comment (i.e., a line
+beginning with "/*") is also copied verbatim to the output up
+to the next "*/".
+.SH PATTERNS
+The patterns in the input are written using an extended set of regular
+expressions. These are:
+.nf
+
+ x match the character 'x'
+ . any character (byte) except newline
+ [xyz] a "character class"; in this case, the pattern
+ matches either an 'x', a 'y', or a 'z'
+ [abj-oZ] a "character class" with a range in it; matches
+ an 'a', a 'b', any letter from 'j' through 'o',
+ or a 'Z'
+ [^A-Z] a "negated character class", i.e., any character
+ but those in the class. In this case, any
+ character EXCEPT an uppercase letter.
+ [^A-Z\\n] any character EXCEPT an uppercase letter or
+ a newline
+ r* zero or more r's, where r is any regular expression
+ r+ one or more r's
+ r? zero or one r's (that is, "an optional r")
+ r{2,5} anywhere from two to five r's
+ r{2,} two or more r's
+ r{4} exactly 4 r's
+ {name} the expansion of the "name" definition
+ (see above)
+ "[xyz]\\"foo"
+ the literal string: [xyz]"foo
+ \\X if X is an 'a', 'b', 'f', 'n', 'r', 't', or 'v',
+ then the ANSI-C interpretation of \\x.
+ Otherwise, a literal 'X' (used to escape
+ operators such as '*')
+ \\0 a NUL character (ASCII code 0)
+ \\123 the character with octal value 123
+ \\x2a the character with hexadecimal value 2a
+ (r) match an r; parentheses are used to override
+ precedence (see below)
+
+
+ rs the regular expression r followed by the
+ regular expression s; called "concatenation"
+
+
+ r|s either an r or an s
+
+
+ r/s an r but only if it is followed by an s. The
+ text matched by s is included when determining
+ whether this rule is the "longest match",
+ but is then returned to the input before
+ the action is executed. So the action only
+ sees the text matched by r. This type
+ of pattern is called trailing context".
+ (There are some combinations of r/s that flex
+ cannot match correctly; see notes in the
+ Deficiencies / Bugs section below regarding
+ "dangerous trailing context".)
+ ^r an r, but only at the beginning of a line (i.e.,
+ which just starting to scan, or right after a
+ newline has been scanned).
+ r$ an r, but only at the end of a line (i.e., just
+ before a newline). Equivalent to "r/\\n".
+
+ Note that flex's notion of "newline" is exactly
+ whatever the C compiler used to compile flex
+ interprets '\\n' as; in particular, on some DOS
+ systems you must either filter out \\r's in the
+ input yourself, or explicitly use r/\\r\\n for "r$".
+
+
+ <s>r an r, but only in start condition s (see
+ below for discussion of start conditions)
+ <s1,s2,s3>r
+ same, but in any of start conditions s1,
+ s2, or s3
+ <*>r an r in any start condition, even an exclusive one.
+
+
+ <<EOF>> an end-of-file
+ <s1,s2><<EOF>>
+ an end-of-file when in start condition s1 or s2
+
+.fi
+Note that inside of a character class, all regular expression operators
+lose their special meaning except escape ('\\') and the character class
+operators, '-', ']', and, at the beginning of the class, '^'.
+.PP
+The regular expressions listed above are grouped according to
+precedence, from highest precedence at the top to lowest at the bottom.
+Those grouped together have equal precedence. For example,
+.nf
+
+ foo|bar*
+
+.fi
+is the same as
+.nf
+
+ (foo)|(ba(r*))
+
+.fi
+since the '*' operator has higher precedence than concatenation,
+and concatenation higher than alternation ('|'). This pattern
+therefore matches
+.I either
+the string "foo"
+.I or
+the string "ba" followed by zero-or-more r's.
+To match "foo" or zero-or-more "bar"'s, use:
+.nf
+
+ foo|(bar)*
+
+.fi
+and to match zero-or-more "foo"'s-or-"bar"'s:
+.nf
+
+ (foo|bar)*
+
+.fi
+.PP
+In addition to characters and ranges of characters, character classes
+can also contain character class
+.I expressions.
+These are expressions enclosed inside
+.B [:
+and
+.B :]
+delimiters (which themselves must appear between the '[' and ']' of the
+character class; other elements may occur inside the character class, too).
+The valid expressions are:
+.nf
+
+ [:alnum:] [:alpha:] [:blank:]
+ [:cntrl:] [:digit:] [:graph:]
+ [:lower:] [:print:] [:punct:]
+ [:space:] [:upper:] [:xdigit:]
+
+.fi
+These expressions all designate a set of characters equivalent to
+the corresponding standard C
+.B isXXX
+function. For example,
+.B [:alnum:]
+designates those characters for which
+.B isalnum()
+returns true - i.e., any alphabetic or numeric.
+Some systems don't provide
+.B isblank(),
+so flex defines
+.B [:blank:]
+as a blank or a tab.
+.PP
+For example, the following character classes are all equivalent:
+.nf
+
+ [[:alnum:]]
+ [[:alpha:][:digit:]
+ [[:alpha:]0-9]
+ [a-zA-Z0-9]
+
+.fi
+If your scanner is case-insensitive (the
+.B \-i
+flag), then
+.B [:upper:]
+and
+.B [:lower:]
+are equivalent to
+.B [:alpha:].
+.PP
+Some notes on patterns:
+.IP -
+A negated character class such as the example "[^A-Z]"
+above
+.I will match a newline
+unless "\\n" (or an equivalent escape sequence) is one of the
+characters explicitly present in the negated character class
+(e.g., "[^A-Z\\n]"). This is unlike how many other regular
+expression tools treat negated character classes, but unfortunately
+the inconsistency is historically entrenched.
+Matching newlines means that a pattern like [^"]* can match the entire
+input unless there's another quote in the input.
+.IP -
+A rule can have at most one instance of trailing context (the '/' operator
+or the '$' operator). The start condition, '^', and "<<EOF>>" patterns
+can only occur at the beginning of a pattern, and, as well as with '/' and '$',
+cannot be grouped inside parentheses. A '^' which does not occur at
+the beginning of a rule or a '$' which does not occur at the end of
+a rule loses its special properties and is treated as a normal character.
+.IP
+The following are illegal:
+.nf
+
+ foo/bar$
+ <sc1>foo<sc2>bar
+
+.fi
+Note that the first of these, can be written "foo/bar\\n".
+.IP
+The following will result in '$' or '^' being treated as a normal character:
+.nf
+
+ foo|(bar$)
+ foo|^bar
+
+.fi
+If what's wanted is a "foo" or a bar-followed-by-a-newline, the following
+could be used (the special '|' action is explained below):
+.nf
+
+ foo |
+ bar$ /* action goes here */
+
+.fi
+A similar trick will work for matching a foo or a
+bar-at-the-beginning-of-a-line.
+.SH HOW THE INPUT IS MATCHED
+When the generated scanner is run, it analyzes its input looking
+for strings which match any of its patterns. If it finds more than
+one match, it takes the one matching the most text (for trailing
+context rules, this includes the length of the trailing part, even
+though it will then be returned to the input). If it finds two
+or more matches of the same length, the
+rule listed first in the
+.I flex
+input file is chosen.
+.PP
+Once the match is determined, the text corresponding to the match
+(called the
+.I token)
+is made available in the global character pointer
+.B yytext,
+and its length in the global integer
+.B yyleng.
+The
+.I action
+corresponding to the matched pattern is then executed (a more
+detailed description of actions follows), and then the remaining
+input is scanned for another match.
+.PP
+If no match is found, then the
+.I default rule
+is executed: the next character in the input is considered matched and
+copied to the standard output. Thus, the simplest legal
+.I flex
+input is:
+.nf
+
+ %%
+
+.fi
+which generates a scanner that simply copies its input (one character
+at a time) to its output.
+.PP
+Note that
+.B yytext
+can be defined in two different ways: either as a character
+.I pointer
+or as a character
+.I array.
+You can control which definition
+.I flex
+uses by including one of the special directives
+.B %pointer
+or
+.B %array
+in the first (definitions) section of your flex input. The default is
+.B %pointer,
+unless you use the
+.B -l
+lex compatibility option, in which case
+.B yytext
+will be an array.
+The advantage of using
+.B %pointer
+is substantially faster scanning and no buffer overflow when matching
+very large tokens (unless you run out of dynamic memory). The disadvantage
+is that you are restricted in how your actions can modify
+.B yytext
+(see the next section), and calls to the
+.B unput()
+function destroys the present contents of
+.B yytext,
+which can be a considerable porting headache when moving between different
+.I lex
+versions.
+.PP
+The advantage of
+.B %array
+is that you can then modify
+.B yytext
+to your heart's content, and calls to
+.B unput()
+do not destroy
+.B yytext
+(see below). Furthermore, existing
+.I lex
+programs sometimes access
+.B yytext
+externally using declarations of the form:
+.nf
+ extern char yytext[];
+.fi
+This definition is erroneous when used with
+.B %pointer,
+but correct for
+.B %array.
+.PP
+.B %array
+defines
+.B yytext
+to be an array of
+.B YYLMAX
+characters, which defaults to a fairly large value. You can change
+the size by simply #define'ing
+.B YYLMAX
+to a different value in the first section of your
+.I flex
+input. As mentioned above, with
+.B %pointer
+yytext grows dynamically to accommodate large tokens. While this means your
+.B %pointer
+scanner can accommodate very large tokens (such as matching entire blocks
+of comments), bear in mind that each time the scanner must resize
+.B yytext
+it also must rescan the entire token from the beginning, so matching such
+tokens can prove slow.
+.B yytext
+presently does
+.I not
+dynamically grow if a call to
+.B unput()
+results in too much text being pushed back; instead, a run-time error results.
+.PP
+Also note that you cannot use
+.B %array
+with C++ scanner classes
+(the
+.B c++
+option; see below).
+.SH ACTIONS
+Each pattern in a rule has a corresponding action, which can be any
+arbitrary C statement. The pattern ends at the first non-escaped
+whitespace character; the remainder of the line is its action. If the
+action is empty, then when the pattern is matched the input token
+is simply discarded. For example, here is the specification for a program
+which deletes all occurrences of "zap me" from its input:
+.nf
+
+ %%
+ "zap me"
+
+.fi
+(It will copy all other characters in the input to the output since
+they will be matched by the default rule.)
+.PP
+Here is a program which compresses multiple blanks and tabs down to
+a single blank, and throws away whitespace found at the end of a line:
+.nf
+
+ %%
+ [ \\t]+ putchar( ' ' );
+ [ \\t]+$ /* ignore this token */
+
+.fi
+.PP
+If the action contains a '{', then the action spans till the balancing '}'
+is found, and the action may cross multiple lines.
+.I flex
+knows about C strings and comments and won't be fooled by braces found
+within them, but also allows actions to begin with
+.B %{
+and will consider the action to be all the text up to the next
+.B %}
+(regardless of ordinary braces inside the action).
+.PP
+An action consisting solely of a vertical bar ('|') means "same as
+the action for the next rule." See below for an illustration.
+.PP
+Actions can include arbitrary C code, including
+.B return
+statements to return a value to whatever routine called
+.B yylex().
+Each time
+.B yylex()
+is called it continues processing tokens from where it last left
+off until it either reaches
+the end of the file or executes a return.
+.PP
+Actions are free to modify
+.B yytext
+except for lengthening it (adding
+characters to its end--these will overwrite later characters in the
+input stream). This however does not apply when using
+.B %array
+(see above); in that case,
+.B yytext
+may be freely modified in any way.
+.PP
+Actions are free to modify
+.B yyleng
+except they should not do so if the action also includes use of
+.B yymore()
+(see below).
+.PP
+There are a number of special directives which can be included within
+an action:
+.IP -
+.B ECHO
+copies yytext to the scanner's output.
+.IP -
+.B BEGIN
+followed by the name of a start condition places the scanner in the
+corresponding start condition (see below).
+.IP -
+.B REJECT
+directs the scanner to proceed on to the "second best" rule which matched the
+input (or a prefix of the input). The rule is chosen as described
+above in "How the Input is Matched", and
+.B yytext
+and
+.B yyleng
+set up appropriately.
+It may either be one which matched as much text
+as the originally chosen rule but came later in the
+.I flex
+input file, or one which matched less text.
+For example, the following will both count the
+words in the input and call the routine special() whenever "frob" is seen:
+.nf
+
+ int word_count = 0;
+ %%
+
+ frob special(); REJECT;
+ [^ \\t\\n]+ ++word_count;
+
+.fi
+Without the
+.B REJECT,
+any "frob"'s in the input would not be counted as words, since the
+scanner normally executes only one action per token.
+Multiple
+.B REJECT's
+are allowed, each one finding the next best choice to the currently
+active rule. For example, when the following scanner scans the token
+"abcd", it will write "abcdabcaba" to the output:
+.nf
+
+ %%
+ a |
+ ab |
+ abc |
+ abcd ECHO; REJECT;
+ .|\\n /* eat up any unmatched character */
+
+.fi
+(The first three rules share the fourth's action since they use
+the special '|' action.)
+.B REJECT
+is a particularly expensive feature in terms of scanner performance;
+if it is used in
+.I any
+of the scanner's actions it will slow down
+.I all
+of the scanner's matching. Furthermore,
+.B REJECT
+cannot be used with the
+.I -Cf
+or
+.I -CF
+options (see below).
+.IP
+Note also that unlike the other special actions,
+.B REJECT
+is a
+.I branch;
+code immediately following it in the action will
+.I not
+be executed.
+.IP -
+.B yymore()
+tells the scanner that the next time it matches a rule, the corresponding
+token should be
+.I appended
+onto the current value of
+.B yytext
+rather than replacing it. For example, given the input "mega-kludge"
+the following will write "mega-mega-kludge" to the output:
+.nf
+
+ %%
+ mega- ECHO; yymore();
+ kludge ECHO;
+
+.fi
+First "mega-" is matched and echoed to the output. Then "kludge"
+is matched, but the previous "mega-" is still hanging around at the
+beginning of
+.B yytext
+so the
+.B ECHO
+for the "kludge" rule will actually write "mega-kludge".
+.PP
+Two notes regarding use of
+.B yymore().
+First,
+.B yymore()
+depends on the value of
+.I yyleng
+correctly reflecting the size of the current token, so you must not
+modify
+.I yyleng
+if you are using
+.B yymore().
+Second, the presence of
+.B yymore()
+in the scanner's action entails a minor performance penalty in the
+scanner's matching speed.
+.IP -
+.B yyless(n)
+returns all but the first
+.I n
+characters of the current token back to the input stream, where they
+will be rescanned when the scanner looks for the next match.
+.B yytext
+and
+.B yyleng
+are adjusted appropriately (e.g.,
+.B yyleng
+will now be equal to
+.I n
+). For example, on the input "foobar" the following will write out
+"foobarbar":
+.nf
+
+ %%
+ foobar ECHO; yyless(3);
+ [a-z]+ ECHO;
+
+.fi
+An argument of 0 to
+.B yyless
+will cause the entire current input string to be scanned again. Unless you've
+changed how the scanner will subsequently process its input (using
+.B BEGIN,
+for example), this will result in an endless loop.
+.PP
+Note that
+.B yyless
+is a macro and can only be used in the flex input file, not from
+other source files.
+.IP -
+.B unput(c)
+puts the character
+.I c
+back onto the input stream. It will be the next character scanned.
+The following action will take the current token and cause it
+to be rescanned enclosed in parentheses.
+.nf
+
+ {
+ int i;
+ /* Copy yytext because unput() trashes yytext */
+ char *yycopy = strdup( yytext );
+ unput( ')' );
+ for ( i = yyleng - 1; i >= 0; --i )
+ unput( yycopy[i] );
+ unput( '(' );
+ free( yycopy );
+ }
+
+.fi
+Note that since each
+.B unput()
+puts the given character back at the
+.I beginning
+of the input stream, pushing back strings must be done back-to-front.
+.PP
+An important potential problem when using
+.B unput()
+is that if you are using
+.B %pointer
+(the default), a call to
+.B unput()
+.I destroys
+the contents of
+.I yytext,
+starting with its rightmost character and devouring one character to
+the left with each call. If you need the value of yytext preserved
+after a call to
+.B unput()
+(as in the above example),
+you must either first copy it elsewhere, or build your scanner using
+.B %array
+instead (see How The Input Is Matched).
+.PP
+Finally, note that you cannot put back
+.B EOF
+to attempt to mark the input stream with an end-of-file.
+.IP -
+.B input()
+reads the next character from the input stream. For example,
+the following is one way to eat up C comments:
+.nf
+
+ %%
+ "/*" {
+ register int c;
+
+ for ( ; ; )
+ {
+ while ( (c = input()) != '*' &&
+ c != EOF )
+ ; /* eat up text of comment */
+
+ if ( c == '*' )
+ {
+ while ( (c = input()) == '*' )
+ ;
+ if ( c == '/' )
+ break; /* found the end */
+ }
+
+ if ( c == EOF )
+ {
+ error( "EOF in comment" );
+ break;
+ }
+ }
+ }
+
+.fi
+(Note that if the scanner is compiled using
+.B C++,
+then
+.B input()
+is instead referred to as
+.B yyinput(),
+in order to avoid a name clash with the
+.B C++
+stream by the name of
+.I input.)
+.IP -
+.B YY_FLUSH_BUFFER
+flushes the scanner's internal buffer
+so that the next time the scanner attempts to match a token, it will
+first refill the buffer using
+.B YY_INPUT
+(see The Generated Scanner, below). This action is a special case
+of the more general
+.B yy_flush_buffer()
+function, described below in the section Multiple Input Buffers.
+.IP -
+.B yyterminate()
+can be used in lieu of a return statement in an action. It terminates
+the scanner and returns a 0 to the scanner's caller, indicating "all done".
+By default,
+.B yyterminate()
+is also called when an end-of-file is encountered. It is a macro and
+may be redefined.
+.SH THE GENERATED SCANNER
+The output of
+.I flex
+is the file
+.B lex.yy.c,
+which contains the scanning routine
+.B yylex(),
+a number of tables used by it for matching tokens, and a number
+of auxiliary routines and macros. By default,
+.B yylex()
+is declared as follows:
+.nf
+
+ int yylex()
+ {
+ ... various definitions and the actions in here ...
+ }
+
+.fi
+(If your environment supports function prototypes, then it will
+be "int yylex( void )".) This definition may be changed by defining
+the "YY_DECL" macro. For example, you could use:
+.nf
+
+ #define YY_DECL float lexscan( a, b ) float a, b;
+
+.fi
+to give the scanning routine the name
+.I lexscan,
+returning a float, and taking two floats as arguments. Note that
+if you give arguments to the scanning routine using a
+K&R-style/non-prototyped function declaration, you must terminate
+the definition with a semi-colon (;).
+.PP
+Whenever
+.B yylex()
+is called, it scans tokens from the global input file
+.I yyin
+(which defaults to stdin). It continues until it either reaches
+an end-of-file (at which point it returns the value 0) or
+one of its actions executes a
+.I return
+statement.
+.PP
+If the scanner reaches an end-of-file, subsequent calls are undefined
+unless either
+.I yyin
+is pointed at a new input file (in which case scanning continues from
+that file), or
+.B yyrestart()
+is called.
+.B yyrestart()
+takes one argument, a
+.B FILE *
+pointer (which can be nil, if you've set up
+.B YY_INPUT
+to scan from a source other than
+.I yyin),
+and initializes
+.I yyin
+for scanning from that file. Essentially there is no difference between
+just assigning
+.I yyin
+to a new input file or using
+.B yyrestart()
+to do so; the latter is available for compatibility with previous versions
+of
+.I flex,
+and because it can be used to switch input files in the middle of scanning.
+It can also be used to throw away the current input buffer, by calling
+it with an argument of
+.I yyin;
+but better is to use
+.B YY_FLUSH_BUFFER
+(see above).
+Note that
+.B yyrestart()
+does
+.I not
+reset the start condition to
+.B INITIAL
+(see Start Conditions, below).
+.PP
+If
+.B yylex()
+stops scanning due to executing a
+.I return
+statement in one of the actions, the scanner may then be called again and it
+will resume scanning where it left off.
+.PP
+By default (and for purposes of efficiency), the scanner uses
+block-reads rather than simple
+.I getc()
+calls to read characters from
+.I yyin.
+The nature of how it gets its input can be controlled by defining the
+.B YY_INPUT
+macro.
+YY_INPUT's calling sequence is "YY_INPUT(buf,result,max_size)". Its
+action is to place up to
+.I max_size
+characters in the character array
+.I buf
+and return in the integer variable
+.I result
+either the
+number of characters read or the constant YY_NULL (0 on Unix systems)
+to indicate EOF. The default YY_INPUT reads from the
+global file-pointer "yyin".
+.PP
+A sample definition of YY_INPUT (in the definitions
+section of the input file):
+.nf
+
+ %{
+ #define YY_INPUT(buf,result,max_size) \\
+ { \\
+ int c = getchar(); \\
+ result = (c == EOF) ? YY_NULL : (buf[0] = c, 1); \\
+ }
+ %}
+
+.fi
+This definition will change the input processing to occur
+one character at a time.
+.PP
+When the scanner receives an end-of-file indication from YY_INPUT,
+it then checks the
+.B yywrap()
+function. If
+.B yywrap()
+returns false (zero), then it is assumed that the
+function has gone ahead and set up
+.I yyin
+to point to another input file, and scanning continues. If it returns
+true (non-zero), then the scanner terminates, returning 0 to its
+caller. Note that in either case, the start condition remains unchanged;
+it does
+.I not
+revert to
+.B INITIAL.
+.PP
+If you do not supply your own version of
+.B yywrap(),
+then you must either use
+.B %option noyywrap
+(in which case the scanner behaves as though
+.B yywrap()
+returned 1), or you must link with
+.B \-lfl
+to obtain the default version of the routine, which always returns 1.
+.PP
+Three routines are available for scanning from in-memory buffers rather
+than files:
+.B yy_scan_string(), yy_scan_bytes(),
+and
+.B yy_scan_buffer().
+See the discussion of them below in the section Multiple Input Buffers.
+.PP
+The scanner writes its
+.B ECHO
+output to the
+.I yyout
+global (default, stdout), which may be redefined by the user simply
+by assigning it to some other
+.B FILE
+pointer.
+.SH START CONDITIONS
+.I flex
+provides a mechanism for conditionally activating rules. Any rule
+whose pattern is prefixed with "<sc>" will only be active when
+the scanner is in the start condition named "sc". For example,
+.nf
+
+ <STRING>[^"]* { /* eat up the string body ... */
+ ...
+ }
+
+.fi
+will be active only when the scanner is in the "STRING" start
+condition, and
+.nf
+
+ <INITIAL,STRING,QUOTE>\\. { /* handle an escape ... */
+ ...
+ }
+
+.fi
+will be active only when the current start condition is
+either "INITIAL", "STRING", or "QUOTE".
+.PP
+Start conditions
+are declared in the definitions (first) section of the input
+using unindented lines beginning with either
+.B %s
+or
+.B %x
+followed by a list of names.
+The former declares
+.I inclusive
+start conditions, the latter
+.I exclusive
+start conditions. A start condition is activated using the
+.B BEGIN
+action. Until the next
+.B BEGIN
+action is executed, rules with the given start
+condition will be active and
+rules with other start conditions will be inactive.
+If the start condition is
+.I inclusive,
+then rules with no start conditions at all will also be active.
+If it is
+.I exclusive,
+then
+.I only
+rules qualified with the start condition will be active.
+A set of rules contingent on the same exclusive start condition
+describe a scanner which is independent of any of the other rules in the
+.I flex
+input. Because of this,
+exclusive start conditions make it easy to specify "mini-scanners"
+which scan portions of the input that are syntactically different
+from the rest (e.g., comments).
+.PP
+If the distinction between inclusive and exclusive start conditions
+is still a little vague, here's a simple example illustrating the
+connection between the two. The set of rules:
+.nf
+
+ %s example
+ %%
+
+ <example>foo do_something();
+
+ bar something_else();
+
+.fi
+is equivalent to
+.nf
+
+ %x example
+ %%
+
+ <example>foo do_something();
+
+ <INITIAL,example>bar something_else();
+
+.fi
+Without the
+.B <INITIAL,example>
+qualifier, the
+.I bar
+pattern in the second example wouldn't be active (i.e., couldn't match)
+when in start condition
+.B example.
+If we just used
+.B <example>
+to qualify
+.I bar,
+though, then it would only be active in
+.B example
+and not in
+.B INITIAL,
+while in the first example it's active in both, because in the first
+example the
+.B example
+startion condition is an
+.I inclusive
+.B (%s)
+start condition.
+.PP
+Also note that the special start-condition specifier
+.B <*>
+matches every start condition. Thus, the above example could also
+have been written;
+.nf
+
+ %x example
+ %%
+
+ <example>foo do_something();
+
+ <*>bar something_else();
+
+.fi
+.PP
+The default rule (to
+.B ECHO
+any unmatched character) remains active in start conditions. It
+is equivalent to:
+.nf
+
+ <*>.|\\n ECHO;
+
+.fi
+.PP
+.B BEGIN(0)
+returns to the original state where only the rules with
+no start conditions are active. This state can also be
+referred to as the start-condition "INITIAL", so
+.B BEGIN(INITIAL)
+is equivalent to
+.B BEGIN(0).
+(The parentheses around the start condition name are not required but
+are considered good style.)
+.PP
+.B BEGIN
+actions can also be given as indented code at the beginning
+of the rules section. For example, the following will cause
+the scanner to enter the "SPECIAL" start condition whenever
+.B yylex()
+is called and the global variable
+.I enter_special
+is true:
+.nf
+
+ int enter_special;
+
+ %x SPECIAL
+ %%
+ if ( enter_special )
+ BEGIN(SPECIAL);
+
+ <SPECIAL>blahblahblah
+ ...more rules follow...
+
+.fi
+.PP
+To illustrate the uses of start conditions,
+here is a scanner which provides two different interpretations
+of a string like "123.456". By default it will treat it as
+three tokens, the integer "123", a dot ('.'), and the integer "456".
+But if the string is preceded earlier in the line by the string
+"expect-floats"
+it will treat it as a single token, the floating-point number
+123.456:
+.nf
+
+ %{
+ #include <math.h>
+ %}
+ %s expect
+
+ %%
+ expect-floats BEGIN(expect);
+
+ <expect>[0-9]+"."[0-9]+ {
+ printf( "found a float, = %f\\n",
+ atof( yytext ) );
+ }
+ <expect>\\n {
+ /* that's the end of the line, so
+ * we need another "expect-number"
+ * before we'll recognize any more
+ * numbers
+ */
+ BEGIN(INITIAL);
+ }
+
+ [0-9]+ {
+ printf( "found an integer, = %d\\n",
+ atoi( yytext ) );
+ }
+
+ "." printf( "found a dot\\n" );
+
+.fi
+Here is a scanner which recognizes (and discards) C comments while
+maintaining a count of the current input line.
+.nf
+
+ %x comment
+ %%
+ int line_num = 1;
+
+ "/*" BEGIN(comment);
+
+ <comment>[^*\\n]* /* eat anything that's not a '*' */
+ <comment>"*"+[^*/\\n]* /* eat up '*'s not followed by '/'s */
+ <comment>\\n ++line_num;
+ <comment>"*"+"/" BEGIN(INITIAL);
+
+.fi
+This scanner goes to a bit of trouble to match as much
+text as possible with each rule. In general, when attempting to write
+a high-speed scanner try to match as much possible in each rule, as
+it's a big win.
+.PP
+Note that start-conditions names are really integer values and
+can be stored as such. Thus, the above could be extended in the
+following fashion:
+.nf
+
+ %x comment foo
+ %%
+ int line_num = 1;
+ int comment_caller;
+
+ "/*" {
+ comment_caller = INITIAL;
+ BEGIN(comment);
+ }
+
+ ...
+
+ <foo>"/*" {
+ comment_caller = foo;
+ BEGIN(comment);
+ }
+
+ <comment>[^*\\n]* /* eat anything that's not a '*' */
+ <comment>"*"+[^*/\\n]* /* eat up '*'s not followed by '/'s */
+ <comment>\\n ++line_num;
+ <comment>"*"+"/" BEGIN(comment_caller);
+
+.fi
+Furthermore, you can access the current start condition using
+the integer-valued
+.B YY_START
+macro. For example, the above assignments to
+.I comment_caller
+could instead be written
+.nf
+
+ comment_caller = YY_START;
+
+.fi
+Flex provides
+.B YYSTATE
+as an alias for
+.B YY_START
+(since that is what's used by AT&T
+.I lex).
+.PP
+Note that start conditions do not have their own name-space; %s's and %x's
+declare names in the same fashion as #define's.
+.PP
+Finally, here's an example of how to match C-style quoted strings using
+exclusive start conditions, including expanded escape sequences (but
+not including checking for a string that's too long):
+.nf
+
+ %x str
+
+ %%
+ char string_buf[MAX_STR_CONST];
+ char *string_buf_ptr;
+
+
+ \\" string_buf_ptr = string_buf; BEGIN(str);
+
+ <str>\\" { /* saw closing quote - all done */
+ BEGIN(INITIAL);
+ *string_buf_ptr = '\\0';
+ /* return string constant token type and
+ * value to parser
+ */
+ }
+
+ <str>\\n {
+ /* error - unterminated string constant */
+ /* generate error message */
+ }
+
+ <str>\\\\[0-7]{1,3} {
+ /* octal escape sequence */
+ int result;
+
+ (void) sscanf( yytext + 1, "%o", &result );
+
+ if ( result > 0xff )
+ /* error, constant is out-of-bounds */
+
+ *string_buf_ptr++ = result;
+ }
+
+ <str>\\\\[0-9]+ {
+ /* generate error - bad escape sequence; something
+ * like '\\48' or '\\0777777'
+ */
+ }
+
+ <str>\\\\n *string_buf_ptr++ = '\\n';
+ <str>\\\\t *string_buf_ptr++ = '\\t';
+ <str>\\\\r *string_buf_ptr++ = '\\r';
+ <str>\\\\b *string_buf_ptr++ = '\\b';
+ <str>\\\\f *string_buf_ptr++ = '\\f';
+
+ <str>\\\\(.|\\n) *string_buf_ptr++ = yytext[1];
+
+ <str>[^\\\\\\n\\"]+ {
+ char *yptr = yytext;
+
+ while ( *yptr )
+ *string_buf_ptr++ = *yptr++;
+ }
+
+.fi
+.PP
+Often, such as in some of the examples above, you wind up writing a
+whole bunch of rules all preceded by the same start condition(s). Flex
+makes this a little easier and cleaner by introducing a notion of
+start condition
+.I scope.
+A start condition scope is begun with:
+.nf
+
+ <SCs>{
+
+.fi
+where
+.I SCs
+is a list of one or more start conditions. Inside the start condition
+scope, every rule automatically has the prefix
+.I <SCs>
+applied to it, until a
+.I '}'
+which matches the initial
+.I '{'.
+So, for example,
+.nf
+
+ <ESC>{
+ "\\\\n" return '\\n';
+ "\\\\r" return '\\r';
+ "\\\\f" return '\\f';
+ "\\\\0" return '\\0';
+ }
+
+.fi
+is equivalent to:
+.nf
+
+ <ESC>"\\\\n" return '\\n';
+ <ESC>"\\\\r" return '\\r';
+ <ESC>"\\\\f" return '\\f';
+ <ESC>"\\\\0" return '\\0';
+
+.fi
+Start condition scopes may be nested.
+.PP
+Three routines are available for manipulating stacks of start conditions:
+.TP
+.B void yy_push_state(int new_state)
+pushes the current start condition onto the top of the start condition
+stack and switches to
+.I new_state
+as though you had used
+.B BEGIN new_state
+(recall that start condition names are also integers).
+.TP
+.B void yy_pop_state()
+pops the top of the stack and switches to it via
+.B BEGIN.
+.TP
+.B int yy_top_state()
+returns the top of the stack without altering the stack's contents.
+.PP
+The start condition stack grows dynamically and so has no built-in
+size limitation. If memory is exhausted, program execution aborts.
+.PP
+To use start condition stacks, your scanner must include a
+.B %option stack
+directive (see Options below).
+.SH MULTIPLE INPUT BUFFERS
+Some scanners (such as those which support "include" files)
+require reading from several input streams. As
+.I flex
+scanners do a large amount of buffering, one cannot control
+where the next input will be read from by simply writing a
+.B YY_INPUT
+which is sensitive to the scanning context.
+.B YY_INPUT
+is only called when the scanner reaches the end of its buffer, which
+may be a long time after scanning a statement such as an "include"
+which requires switching the input source.
+.PP
+To negotiate these sorts of problems,
+.I flex
+provides a mechanism for creating and switching between multiple
+input buffers. An input buffer is created by using:
+.nf
+
+ YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+
+.fi
+which takes a
+.I FILE
+pointer and a size and creates a buffer associated with the given
+file and large enough to hold
+.I size
+characters (when in doubt, use
+.B YY_BUF_SIZE
+for the size). It returns a
+.B YY_BUFFER_STATE
+handle, which may then be passed to other routines (see below). The
+.B YY_BUFFER_STATE
+type is a pointer to an opaque
+.B struct yy_buffer_state
+structure, so you may safely initialize YY_BUFFER_STATE variables to
+.B ((YY_BUFFER_STATE) 0)
+if you wish, and also refer to the opaque structure in order to
+correctly declare input buffers in source files other than that
+of your scanner. Note that the
+.I FILE
+pointer in the call to
+.B yy_create_buffer
+is only used as the value of
+.I yyin
+seen by
+.B YY_INPUT;
+if you redefine
+.B YY_INPUT
+so it no longer uses
+.I yyin,
+then you can safely pass a nil
+.I FILE
+pointer to
+.B yy_create_buffer.
+You select a particular buffer to scan from using:
+.nf
+
+ void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+
+.fi
+switches the scanner's input buffer so subsequent tokens will
+come from
+.I new_buffer.
+Note that
+.B yy_switch_to_buffer()
+may be used by yywrap() to set things up for continued scanning, instead
+of opening a new file and pointing
+.I yyin
+at it. Note also that switching input sources via either
+.B yy_switch_to_buffer()
+or
+.B yywrap()
+does
+.I not
+change the start condition.
+.nf
+
+ void yy_delete_buffer( YY_BUFFER_STATE buffer )
+
+.fi
+is used to reclaim the storage associated with a buffer. (
+.B buffer
+can be nil, in which case the routine does nothing.)
+You can also clear the current contents of a buffer using:
+.nf
+
+ void yy_flush_buffer( YY_BUFFER_STATE buffer )
+
+.fi
+This function discards the buffer's contents,
+so the next time the scanner attempts to match a token from the
+buffer, it will first fill the buffer anew using
+.B YY_INPUT.
+.PP
+.B yy_new_buffer()
+is an alias for
+.B yy_create_buffer(),
+provided for compatibility with the C++ use of
+.I new
+and
+.I delete
+for creating and destroying dynamic objects.
+.PP
+Finally, the
+.B YY_CURRENT_BUFFER
+macro returns a
+.B YY_BUFFER_STATE
+handle to the current buffer.
+.PP
+Here is an example of using these features for writing a scanner
+which expands include files (the
+.B <<EOF>>
+feature is discussed below):
+.nf
+
+ /* the "incl" state is used for picking up the name
+ * of an include file
+ */
+ %x incl
+
+ %{
+ #define MAX_INCLUDE_DEPTH 10
+ YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
+ int include_stack_ptr = 0;
+ %}
+
+ %%
+ include BEGIN(incl);
+
+ [a-z]+ ECHO;
+ [^a-z\\n]*\\n? ECHO;
+
+ <incl>[ \\t]* /* eat the whitespace */
+ <incl>[^ \\t\\n]+ { /* got the include file name */
+ if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
+ {
+ fprintf( stderr, "Includes nested too deeply" );
+ exit( 1 );
+ }
+
+ include_stack[include_stack_ptr++] =
+ YY_CURRENT_BUFFER;
+
+ yyin = fopen( yytext, "r" );
+
+ if ( ! yyin )
+ error( ... );
+
+ yy_switch_to_buffer(
+ yy_create_buffer( yyin, YY_BUF_SIZE ) );
+
+ BEGIN(INITIAL);
+ }
+
+ <<EOF>> {
+ if ( --include_stack_ptr < 0 )
+ {
+ yyterminate();
+ }
+
+ else
+ {
+ yy_delete_buffer( YY_CURRENT_BUFFER );
+ yy_switch_to_buffer(
+ include_stack[include_stack_ptr] );
+ }
+ }
+
+.fi
+Three routines are available for setting up input buffers for
+scanning in-memory strings instead of files. All of them create
+a new input buffer for scanning the string, and return a corresponding
+.B YY_BUFFER_STATE
+handle (which you should delete with
+.B yy_delete_buffer()
+when done with it). They also switch to the new buffer using
+.B yy_switch_to_buffer(),
+so the next call to
+.B yylex()
+will start scanning the string.
+.TP
+.B yy_scan_string(const char *str)
+scans a NUL-terminated string.
+.TP
+.B yy_scan_bytes(const char *bytes, int len)
+scans
+.I len
+bytes (including possibly NUL's)
+starting at location
+.I bytes.
+.PP
+Note that both of these functions create and scan a
+.I copy
+of the string or bytes. (This may be desirable, since
+.B yylex()
+modifies the contents of the buffer it is scanning.) You can avoid the
+copy by using:
+.TP
+.B yy_scan_buffer(char *base, yy_size_t size)
+which scans in place the buffer starting at
+.I base,
+consisting of
+.I size
+bytes, the last two bytes of which
+.I must
+be
+.B YY_END_OF_BUFFER_CHAR
+(ASCII NUL).
+These last two bytes are not scanned; thus, scanning
+consists of
+.B base[0]
+through
+.B base[size-2],
+inclusive.
+.IP
+If you fail to set up
+.I base
+in this manner (i.e., forget the final two
+.B YY_END_OF_BUFFER_CHAR
+bytes), then
+.B yy_scan_buffer()
+returns a nil pointer instead of creating a new input buffer.
+.IP
+The type
+.B yy_size_t
+is an integral type to which you can cast an integer expression
+reflecting the size of the buffer.
+.SH END-OF-FILE RULES
+The special rule "<<EOF>>" indicates
+actions which are to be taken when an end-of-file is
+encountered and yywrap() returns non-zero (i.e., indicates
+no further files to process). The action must finish
+by doing one of four things:
+.IP -
+assigning
+.I yyin
+to a new input file (in previous versions of flex, after doing the
+assignment you had to call the special action
+.B YY_NEW_FILE;
+this is no longer necessary);
+.IP -
+executing a
+.I return
+statement;
+.IP -
+executing the special
+.B yyterminate()
+action;
+.IP -
+or, switching to a new buffer using
+.B yy_switch_to_buffer()
+as shown in the example above.
+.PP
+<<EOF>> rules may not be used with other
+patterns; they may only be qualified with a list of start
+conditions. If an unqualified <<EOF>> rule is given, it
+applies to
+.I all
+start conditions which do not already have <<EOF>> actions. To
+specify an <<EOF>> rule for only the initial start condition, use
+.nf
+
+ <INITIAL><<EOF>>
+
+.fi
+.PP
+These rules are useful for catching things like unclosed comments.
+An example:
+.nf
+
+ %x quote
+ %%
+
+ ...other rules for dealing with quotes...
+
+ <quote><<EOF>> {
+ error( "unterminated quote" );
+ yyterminate();
+ }
+ <<EOF>> {
+ if ( *++filelist )
+ yyin = fopen( *filelist, "r" );
+ else
+ yyterminate();
+ }
+
+.fi
+.SH MISCELLANEOUS MACROS
+The macro
+.B YY_USER_ACTION
+can be defined to provide an action
+which is always executed prior to the matched rule's action. For example,
+it could be #define'd to call a routine to convert yytext to lower-case.
+When
+.B YY_USER_ACTION
+is invoked, the variable
+.I yy_act
+gives the number of the matched rule (rules are numbered starting with 1).
+Suppose you want to profile how often each of your rules is matched. The
+following would do the trick:
+.nf
+
+ #define YY_USER_ACTION ++ctr[yy_act]
+
+.fi
+where
+.I ctr
+is an array to hold the counts for the different rules. Note that
+the macro
+.B YY_NUM_RULES
+gives the total number of rules (including the default rule, even if
+you use
+.B \-s),
+so a correct declaration for
+.I ctr
+is:
+.nf
+
+ int ctr[YY_NUM_RULES];
+
+.fi
+.PP
+The macro
+.B YY_USER_INIT
+may be defined to provide an action which is always executed before
+the first scan (and before the scanner's internal initializations are done).
+For example, it could be used to call a routine to read
+in a data table or open a logging file.
+.PP
+The macro
+.B yy_set_interactive(is_interactive)
+can be used to control whether the current buffer is considered
+.I interactive.
+An interactive buffer is processed more slowly,
+but must be used when the scanner's input source is indeed
+interactive to avoid problems due to waiting to fill buffers
+(see the discussion of the
+.B \-I
+flag below). A non-zero value
+in the macro invocation marks the buffer as interactive, a zero
+value as non-interactive. Note that use of this macro overrides
+.B %option always-interactive
+or
+.B %option never-interactive
+(see Options below).
+.B yy_set_interactive()
+must be invoked prior to beginning to scan the buffer that is
+(or is not) to be considered interactive.
+.PP
+The macro
+.B yy_set_bol(at_bol)
+can be used to control whether the current buffer's scanning
+context for the next token match is done as though at the
+beginning of a line. A non-zero macro argument makes rules anchored with
+'^' active, while a zero argument makes '^' rules inactive.
+.PP
+The macro
+.B YY_AT_BOL()
+returns true if the next token scanned from the current buffer
+will have '^' rules active, false otherwise.
+.PP
+In the generated scanner, the actions are all gathered in one large
+switch statement and separated using
+.B YY_BREAK,
+which may be redefined. By default, it is simply a "break", to separate
+each rule's action from the following rule's.
+Redefining
+.B YY_BREAK
+allows, for example, C++ users to
+#define YY_BREAK to do nothing (while being very careful that every
+rule ends with a "break" or a "return"!) to avoid suffering from
+unreachable statement warnings where because a rule's action ends with
+"return", the
+.B YY_BREAK
+is inaccessible.
+.SH VALUES AVAILABLE TO THE USER
+This section summarizes the various values available to the user
+in the rule actions.
+.IP -
+.B char *yytext
+holds the text of the current token. It may be modified but not lengthened
+(you cannot append characters to the end).
+.IP
+If the special directive
+.B %array
+appears in the first section of the scanner description, then
+.B yytext
+is instead declared
+.B char yytext[YYLMAX],
+where
+.B YYLMAX
+is a macro definition that you can redefine in the first section
+if you don't like the default value (generally 8KB). Using
+.B %array
+results in somewhat slower scanners, but the value of
+.B yytext
+becomes immune to calls to
+.I input()
+and
+.I unput(),
+which potentially destroy its value when
+.B yytext
+is a character pointer. The opposite of
+.B %array
+is
+.B %pointer,
+which is the default.
+.IP
+You cannot use
+.B %array
+when generating C++ scanner classes
+(the
+.B \-+
+flag).
+.IP -
+.B int yyleng
+holds the length of the current token.
+.IP -
+.B FILE *yyin
+is the file which by default
+.I flex
+reads from. It may be redefined but doing so only makes sense before
+scanning begins or after an EOF has been encountered. Changing it in
+the midst of scanning will have unexpected results since
+.I flex
+buffers its input; use
+.B yyrestart()
+instead.
+Once scanning terminates because an end-of-file
+has been seen, you can assign
+.I yyin
+at the new input file and then call the scanner again to continue scanning.
+.IP -
+.B void yyrestart( FILE *new_file )
+may be called to point
+.I yyin
+at the new input file. The switch-over to the new file is immediate
+(any previously buffered-up input is lost). Note that calling
+.B yyrestart()
+with
+.I yyin
+as an argument thus throws away the current input buffer and continues
+scanning the same input file.
+.IP -
+.B FILE *yyout
+is the file to which
+.B ECHO
+actions are done. It can be reassigned by the user.
+.IP -
+.B YY_CURRENT_BUFFER
+returns a
+.B YY_BUFFER_STATE
+handle to the current buffer.
+.IP -
+.B YY_START
+returns an integer value corresponding to the current start
+condition. You can subsequently use this value with
+.B BEGIN
+to return to that start condition.
+.SH INTERFACING WITH YACC
+One of the main uses of
+.I flex
+is as a companion to the
+.I yacc
+parser-generator.
+.I yacc
+parsers expect to call a routine named
+.B yylex()
+to find the next input token. The routine is supposed to
+return the type of the next token as well as putting any associated
+value in the global
+.B yylval.
+To use
+.I flex
+with
+.I yacc,
+one specifies the
+.B \-d
+option to
+.I yacc
+to instruct it to generate the file
+.B y.tab.h
+containing definitions of all the
+.B %tokens
+appearing in the
+.I yacc
+input. This file is then included in the
+.I flex
+scanner. For example, if one of the tokens is "TOK_NUMBER",
+part of the scanner might look like:
+.nf
+
+ %{
+ #include "y.tab.h"
+ %}
+
+ %%
+
+ [0-9]+ yylval = atoi( yytext ); return TOK_NUMBER;
+
+.fi
+.SH OPTIONS
+.I flex
+has the following options:
+.TP
+.B \-b
+Generate backing-up information to
+.I lex.backup.
+This is a list of scanner states which require backing up
+and the input characters on which they do so. By adding rules one
+can remove backing-up states. If
+.I all
+backing-up states are eliminated and
+.B \-Cf
+or
+.B \-CF
+is used, the generated scanner will run faster (see the
+.B \-p
+flag). Only users who wish to squeeze every last cycle out of their
+scanners need worry about this option. (See the section on Performance
+Considerations below.)
+.TP
+.B \-c
+is a do-nothing, deprecated option included for POSIX compliance.
+.TP
+.B \-d
+makes the generated scanner run in
+.I debug
+mode. Whenever a pattern is recognized and the global
+.B yy_flex_debug
+is non-zero (which is the default),
+the scanner will write to
+.I stderr
+a line of the form:
+.nf
+
+ --accepting rule at line 53 ("the matched text")
+
+.fi
+The line number refers to the location of the rule in the file
+defining the scanner (i.e., the file that was fed to flex). Messages
+are also generated when the scanner backs up, accepts the
+default rule, reaches the end of its input buffer (or encounters
+a NUL; at this point, the two look the same as far as the scanner's concerned),
+or reaches an end-of-file.
+.TP
+.B \-f
+specifies
+.I fast scanner.
+No table compression is done and stdio is bypassed.
+The result is large but fast. This option is equivalent to
+.B \-Cfr
+(see below).
+.TP
+.B \-h
+generates a "help" summary of
+.I flex's
+options to
+.I stdout
+and then exits.
+.B \-?
+and
+.B \-\-help
+are synonyms for
+.B \-h.
+.TP
+.B \-i
+instructs
+.I flex
+to generate a
+.I case-insensitive
+scanner. The case of letters given in the
+.I flex
+input patterns will
+be ignored, and tokens in the input will be matched regardless of case. The
+matched text given in
+.I yytext
+will have the preserved case (i.e., it will not be folded).
+.TP
+.B \-l
+turns on maximum compatibility with the original AT&T
+.I lex
+implementation. Note that this does not mean
+.I full
+compatibility. Use of this option costs a considerable amount of
+performance, and it cannot be used with the
+.B \-+, -f, -F, -Cf,
+or
+.B -CF
+options. For details on the compatibilities it provides, see the section
+"Incompatibilities With Lex And POSIX" below. This option also results
+in the name
+.B YY_FLEX_LEX_COMPAT
+being #define'd in the generated scanner.
+.TP
+.B \-n
+is another do-nothing, deprecated option included only for
+POSIX compliance.
+.TP
+.B \-p
+generates a performance report to stderr. The report
+consists of comments regarding features of the
+.I flex
+input file which will cause a serious loss of performance in the resulting
+scanner. If you give the flag twice, you will also get comments regarding
+features that lead to minor performance losses.
+.IP
+Note that the use of
+.B REJECT,
+.B %option yylineno,
+and variable trailing context (see the Deficiencies / Bugs section below)
+entails a substantial performance penalty; use of
+.I yymore(),
+the
+.B ^
+operator,
+and the
+.B \-I
+flag entail minor performance penalties.
+.TP
+.B \-s
+causes the
+.I default rule
+(that unmatched scanner input is echoed to
+.I stdout)
+to be suppressed. If the scanner encounters input that does not
+match any of its rules, it aborts with an error. This option is
+useful for finding holes in a scanner's rule set.
+.TP
+.B \-t
+instructs
+.I flex
+to write the scanner it generates to standard output instead
+of
+.B lex.yy.c.
+.TP
+.B \-v
+specifies that
+.I flex
+should write to
+.I stderr
+a summary of statistics regarding the scanner it generates.
+Most of the statistics are meaningless to the casual
+.I flex
+user, but the first line identifies the version of
+.I flex
+(same as reported by
+.B \-V),
+and the next line the flags used when generating the scanner, including
+those that are on by default.
+.TP
+.B \-w
+suppresses warning messages.
+.TP
+.B \-B
+instructs
+.I flex
+to generate a
+.I batch
+scanner, the opposite of
+.I interactive
+scanners generated by
+.B \-I
+(see below). In general, you use
+.B \-B
+when you are
+.I certain
+that your scanner will never be used interactively, and you want to
+squeeze a
+.I little
+more performance out of it. If your goal is instead to squeeze out a
+.I lot
+more performance, you should be using the
+.B \-Cf
+or
+.B \-CF
+options (discussed below), which turn on
+.B \-B
+automatically anyway.
+.TP
+.B \-F
+specifies that the
+.ul
+fast
+scanner table representation should be used (and stdio
+bypassed). This representation is
+about as fast as the full table representation
+.B (-f),
+and for some sets of patterns will be considerably smaller (and for
+others, larger). In general, if the pattern set contains both "keywords"
+and a catch-all, "identifier" rule, such as in the set:
+.nf
+
+ "case" return TOK_CASE;
+ "switch" return TOK_SWITCH;
+ ...
+ "default" return TOK_DEFAULT;
+ [a-z]+ return TOK_ID;
+
+.fi
+then you're better off using the full table representation. If only
+the "identifier" rule is present and you then use a hash table or some such
+to detect the keywords, you're better off using
+.B -F.
+.IP
+This option is equivalent to
+.B \-CFr
+(see below). It cannot be used with
+.B \-+.
+.TP
+.B \-I
+instructs
+.I flex
+to generate an
+.I interactive
+scanner. An interactive scanner is one that only looks ahead to decide
+what token has been matched if it absolutely must. It turns out that
+always looking one extra character ahead, even if the scanner has already
+seen enough text to disambiguate the current token, is a bit faster than
+only looking ahead when necessary. But scanners that always look ahead
+give dreadful interactive performance; for example, when a user types
+a newline, it is not recognized as a newline token until they enter
+.I another
+token, which often means typing in another whole line.
+.IP
+.I Flex
+scanners default to
+.I interactive
+unless you use the
+.B \-Cf
+or
+.B \-CF
+table-compression options (see below). That's because if you're looking
+for high-performance you should be using one of these options, so if you
+didn't,
+.I flex
+assumes you'd rather trade off a bit of run-time performance for intuitive
+interactive behavior. Note also that you
+.I cannot
+use
+.B \-I
+in conjunction with
+.B \-Cf
+or
+.B \-CF.
+Thus, this option is not really needed; it is on by default for all those
+cases in which it is allowed.
+.IP
+You can force a scanner to
+.I not
+be interactive by using
+.B \-B
+(see above).
+.TP
+.B \-L
+instructs
+.I flex
+not to generate
+.B #line
+directives. Without this option,
+.I flex
+peppers the generated scanner
+with #line directives so error messages in the actions will be correctly
+located with respect to either the original
+.I flex
+input file (if the errors are due to code in the input file), or
+.B lex.yy.c
+(if the errors are
+.I flex's
+fault -- you should report these sorts of errors to the email address
+given below).
+.TP
+.B \-T
+makes
+.I flex
+run in
+.I trace
+mode. It will generate a lot of messages to
+.I stderr
+concerning
+the form of the input and the resultant non-deterministic and deterministic
+finite automata. This option is mostly for use in maintaining
+.I flex.
+.TP
+.B \-V
+prints the version number to
+.I stdout
+and exits.
+.B \-\-version
+is a synonym for
+.B \-V.
+.TP
+.B \-7
+instructs
+.I flex
+to generate a 7-bit scanner, i.e., one which can only recognized 7-bit
+characters in its input. The advantage of using
+.B \-7
+is that the scanner's tables can be up to half the size of those generated
+using the
+.B \-8
+option (see below). The disadvantage is that such scanners often hang
+or crash if their input contains an 8-bit character.
+.IP
+Note, however, that unless you generate your scanner using the
+.B \-Cf
+or
+.B \-CF
+table compression options, use of
+.B \-7
+will save only a small amount of table space, and make your scanner
+considerably less portable.
+.I Flex's
+default behavior is to generate an 8-bit scanner unless you use the
+.B \-Cf
+or
+.B \-CF,
+in which case
+.I flex
+defaults to generating 7-bit scanners unless your site was always
+configured to generate 8-bit scanners (as will often be the case
+with non-USA sites). You can tell whether flex generated a 7-bit
+or an 8-bit scanner by inspecting the flag summary in the
+.B \-v
+output as described above.
+.IP
+Note that if you use
+.B \-Cfe
+or
+.B \-CFe
+(those table compression options, but also using equivalence classes as
+discussed see below), flex still defaults to generating an 8-bit
+scanner, since usually with these compression options full 8-bit tables
+are not much more expensive than 7-bit tables.
+.TP
+.B \-8
+instructs
+.I flex
+to generate an 8-bit scanner, i.e., one which can recognize 8-bit
+characters. This flag is only needed for scanners generated using
+.B \-Cf
+or
+.B \-CF,
+as otherwise flex defaults to generating an 8-bit scanner anyway.
+.IP
+See the discussion of
+.B \-7
+above for flex's default behavior and the tradeoffs between 7-bit
+and 8-bit scanners.
+.TP
+.B \-+
+specifies that you want flex to generate a C++
+scanner class. See the section on Generating C++ Scanners below for
+details.
+.TP
+.B \-C[aefFmr]
+controls the degree of table compression and, more generally, trade-offs
+between small scanners and fast scanners.
+.IP
+.B \-Ca
+("align") instructs flex to trade off larger tables in the
+generated scanner for faster performance because the elements of
+the tables are better aligned for memory access and computation. On some
+RISC architectures, fetching and manipulating longwords is more efficient
+than with smaller-sized units such as shortwords. This option can
+double the size of the tables used by your scanner.
+.IP
+.B \-Ce
+directs
+.I flex
+to construct
+.I equivalence classes,
+i.e., sets of characters
+which have identical lexical properties (for example, if the only
+appearance of digits in the
+.I flex
+input is in the character class
+"[0-9]" then the digits '0', '1', ..., '9' will all be put
+in the same equivalence class). Equivalence classes usually give
+dramatic reductions in the final table/object file sizes (typically
+a factor of 2-5) and are pretty cheap performance-wise (one array
+look-up per character scanned).
+.IP
+.B \-Cf
+specifies that the
+.I full
+scanner tables should be generated -
+.I flex
+should not compress the
+tables by taking advantages of similar transition functions for
+different states.
+.IP
+.B \-CF
+specifies that the alternate fast scanner representation (described
+above under the
+.B \-F
+flag)
+should be used. This option cannot be used with
+.B \-+.
+.IP
+.B \-Cm
+directs
+.I flex
+to construct
+.I meta-equivalence classes,
+which are sets of equivalence classes (or characters, if equivalence
+classes are not being used) that are commonly used together. Meta-equivalence
+classes are often a big win when using compressed tables, but they
+have a moderate performance impact (one or two "if" tests and one
+array look-up per character scanned).
+.IP
+.B \-Cr
+causes the generated scanner to
+.I bypass
+use of the standard I/O library (stdio) for input. Instead of calling
+.B fread()
+or
+.B getc(),
+the scanner will use the
+.B read()
+system call, resulting in a performance gain which varies from system
+to system, but in general is probably negligible unless you are also using
+.B \-Cf
+or
+.B \-CF.
+Using
+.B \-Cr
+can cause strange behavior if, for example, you read from
+.I yyin
+using stdio prior to calling the scanner (because the scanner will miss
+whatever text your previous reads left in the stdio input buffer).
+.IP
+.B \-Cr
+has no effect if you define
+.B YY_INPUT
+(see The Generated Scanner above).
+.IP
+A lone
+.B \-C
+specifies that the scanner tables should be compressed but neither
+equivalence classes nor meta-equivalence classes should be used.
+.IP
+The options
+.B \-Cf
+or
+.B \-CF
+and
+.B \-Cm
+do not make sense together - there is no opportunity for meta-equivalence
+classes if the table is not being compressed. Otherwise the options
+may be freely mixed, and are cumulative.
+.IP
+The default setting is
+.B \-Cem,
+which specifies that
+.I flex
+should generate equivalence classes
+and meta-equivalence classes. This setting provides the highest
+degree of table compression. You can trade off
+faster-executing scanners at the cost of larger tables with
+the following generally being true:
+.nf
+
+ slowest & smallest
+ -Cem
+ -Cm
+ -Ce
+ -C
+ -C{f,F}e
+ -C{f,F}
+ -C{f,F}a
+ fastest & largest
+
+.fi
+Note that scanners with the smallest tables are usually generated and
+compiled the quickest, so
+during development you will usually want to use the default, maximal
+compression.
+.IP
+.B \-Cfe
+is often a good compromise between speed and size for production
+scanners.
+.TP
+.B \-ooutput
+directs flex to write the scanner to the file
+.B output
+instead of
+.B lex.yy.c.
+If you combine
+.B \-o
+with the
+.B \-t
+option, then the scanner is written to
+.I stdout
+but its
+.B #line
+directives (see the
+.B \\-L
+option above) refer to the file
+.B output.
+.TP
+.B \-Pprefix
+changes the default
+.I "yy"
+prefix used by
+.I flex
+for all globally-visible variable and function names to instead be
+.I prefix.
+For example,
+.B \-Pfoo
+changes the name of
+.B yytext
+to
+.B footext.
+It also changes the name of the default output file from
+.B lex.yy.c
+to
+.B lex.foo.c.
+Here are all of the names affected:
+.nf
+
+ yy_create_buffer
+ yy_delete_buffer
+ yy_flex_debug
+ yy_init_buffer
+ yy_flush_buffer
+ yy_load_buffer_state
+ yy_switch_to_buffer
+ yyin
+ yyleng
+ yylex
+ yylineno
+ yyout
+ yyrestart
+ yytext
+ yywrap
+
+.fi
+(If you are using a C++ scanner, then only
+.B yywrap
+and
+.B yyFlexLexer
+are affected.)
+Within your scanner itself, you can still refer to the global variables
+and functions using either version of their name; but externally, they
+have the modified name.
+.IP
+This option lets you easily link together multiple
+.I flex
+programs into the same executable. Note, though, that using this
+option also renames
+.B yywrap(),
+so you now
+.I must
+either
+provide your own (appropriately-named) version of the routine for your
+scanner, or use
+.B %option noyywrap,
+as linking with
+.B \-lfl
+no longer provides one for you by default.
+.TP
+.B \-Sskeleton_file
+overrides the default skeleton file from which
+.I flex
+constructs its scanners. You'll never need this option unless you are doing
+.I flex
+maintenance or development.
+.PP
+.I flex
+also provides a mechanism for controlling options within the
+scanner specification itself, rather than from the flex command-line.
+This is done by including
+.B %option
+directives in the first section of the scanner specification.
+You can specify multiple options with a single
+.B %option
+directive, and multiple directives in the first section of your flex input
+file.
+.PP
+Most options are given simply as names, optionally preceded by the
+word "no" (with no intervening whitespace) to negate their meaning.
+A number are equivalent to flex flags or their negation:
+.nf
+
+ 7bit -7 option
+ 8bit -8 option
+ align -Ca option
+ backup -b option
+ batch -B option
+ c++ -+ option
+
+ caseful or
+ case-sensitive opposite of -i (default)
+
+ case-insensitive or
+ caseless -i option
+
+ debug -d option
+ default opposite of -s option
+ ecs -Ce option
+ fast -F option
+ full -f option
+ interactive -I option
+ lex-compat -l option
+ meta-ecs -Cm option
+ perf-report -p option
+ read -Cr option
+ stdout -t option
+ verbose -v option
+ warn opposite of -w option
+ (use "%option nowarn" for -w)
+
+ array equivalent to "%array"
+ pointer equivalent to "%pointer" (default)
+
+.fi
+Some
+.B %option's
+provide features otherwise not available:
+.TP
+.B always-interactive
+instructs flex to generate a scanner which always considers its input
+"interactive". Normally, on each new input file the scanner calls
+.B isatty()
+in an attempt to determine whether
+the scanner's input source is interactive and thus should be read a
+character at a time. When this option is used, however, then no
+such call is made.
+.TP
+.B main
+directs flex to provide a default
+.B main()
+program for the scanner, which simply calls
+.B yylex().
+This option implies
+.B noyywrap
+(see below).
+.TP
+.B never-interactive
+instructs flex to generate a scanner which never considers its input
+"interactive" (again, no call made to
+.B isatty()).
+This is the opposite of
+.B always-interactive.
+.TP
+.B stack
+enables the use of start condition stacks (see Start Conditions above).
+.TP
+.B stdinit
+if set (i.e.,
+.B %option stdinit)
+initializes
+.I yyin
+and
+.I yyout
+to
+.I stdin
+and
+.I stdout,
+instead of the default of
+.I nil.
+Some existing
+.I lex
+programs depend on this behavior, even though it is not compliant with
+ANSI C, which does not require
+.I stdin
+and
+.I stdout
+to be compile-time constant.
+.TP
+.B yylineno
+directs
+.I flex
+to generate a scanner that maintains the number of the current line
+read from its input in the global variable
+.B yylineno.
+This option is implied by
+.B %option lex-compat.
+.TP
+.B yywrap
+if unset (i.e.,
+.B %option noyywrap),
+makes the scanner not call
+.B yywrap()
+upon an end-of-file, but simply assume that there are no more
+files to scan (until the user points
+.I yyin
+at a new file and calls
+.B yylex()
+again).
+.PP
+.I flex
+scans your rule actions to determine whether you use the
+.B REJECT
+or
+.B yymore()
+features. The
+.B reject
+and
+.B yymore
+options are available to override its decision as to whether you use the
+options, either by setting them (e.g.,
+.B %option reject)
+to indicate the feature is indeed used, or
+unsetting them to indicate it actually is not used
+(e.g.,
+.B %option noyymore).
+.PP
+Three options take string-delimited values, offset with '=':
+.nf
+
+ %option outfile="ABC"
+
+.fi
+is equivalent to
+.B -oABC,
+and
+.nf
+
+ %option prefix="XYZ"
+
+.fi
+is equivalent to
+.B -PXYZ.
+Finally,
+.nf
+
+ %option yyclass="foo"
+
+.fi
+only applies when generating a C++ scanner (
+.B \-+
+option). It informs
+.I flex
+that you have derived
+.B foo
+as a subclass of
+.B yyFlexLexer,
+so
+.I flex
+will place your actions in the member function
+.B foo::yylex()
+instead of
+.B yyFlexLexer::yylex().
+It also generates a
+.B yyFlexLexer::yylex()
+member function that emits a run-time error (by invoking
+.B yyFlexLexer::LexerError())
+if called.
+See Generating C++ Scanners, below, for additional information.
+.PP
+A number of options are available for lint purists who want to suppress
+the appearance of unneeded routines in the generated scanner. Each of the
+following, if unset
+(e.g.,
+.B %option nounput
+), results in the corresponding routine not appearing in
+the generated scanner:
+.nf
+
+ input, unput
+ yy_push_state, yy_pop_state, yy_top_state
+ yy_scan_buffer, yy_scan_bytes, yy_scan_string
+
+.fi
+(though
+.B yy_push_state()
+and friends won't appear anyway unless you use
+.B %option stack).
+.SH PERFORMANCE CONSIDERATIONS
+The main design goal of
+.I flex
+is that it generate high-performance scanners. It has been optimized
+for dealing well with large sets of rules. Aside from the effects on
+scanner speed of the table compression
+.B \-C
+options outlined above,
+there are a number of options/actions which degrade performance. These
+are, from most expensive to least:
+.nf
+
+ REJECT
+ %option yylineno
+ arbitrary trailing context
+
+ pattern sets that require backing up
+ %array
+ %option interactive
+ %option always-interactive
+
+ '^' beginning-of-line operator
+ yymore()
+
+.fi
+with the first three all being quite expensive and the last two
+being quite cheap. Note also that
+.B unput()
+is implemented as a routine call that potentially does quite a bit of
+work, while
+.B yyless()
+is a quite-cheap macro; so if just putting back some excess text you
+scanned, use
+.B yyless().
+.PP
+.B REJECT
+should be avoided at all costs when performance is important.
+It is a particularly expensive option.
+.PP
+Getting rid of backing up is messy and often may be an enormous
+amount of work for a complicated scanner. In principal, one begins
+by using the
+.B \-b
+flag to generate a
+.I lex.backup
+file. For example, on the input
+.nf
+
+ %%
+ foo return TOK_KEYWORD;
+ foobar return TOK_KEYWORD;
+
+.fi
+the file looks like:
+.nf
+
+ State #6 is non-accepting -
+ associated rule line numbers:
+ 2 3
+ out-transitions: [ o ]
+ jam-transitions: EOF [ \\001-n p-\\177 ]
+
+ State #8 is non-accepting -
+ associated rule line numbers:
+ 3
+ out-transitions: [ a ]
+ jam-transitions: EOF [ \\001-` b-\\177 ]
+
+ State #9 is non-accepting -
+ associated rule line numbers:
+ 3
+ out-transitions: [ r ]
+ jam-transitions: EOF [ \\001-q s-\\177 ]
+
+ Compressed tables always back up.
+
+.fi
+The first few lines tell us that there's a scanner state in
+which it can make a transition on an 'o' but not on any other
+character, and that in that state the currently scanned text does not match
+any rule. The state occurs when trying to match the rules found
+at lines 2 and 3 in the input file.
+If the scanner is in that state and then reads
+something other than an 'o', it will have to back up to find
+a rule which is matched. With
+a bit of headscratching one can see that this must be the
+state it's in when it has seen "fo". When this has happened,
+if anything other than another 'o' is seen, the scanner will
+have to back up to simply match the 'f' (by the default rule).
+.PP
+The comment regarding State #8 indicates there's a problem
+when "foob" has been scanned. Indeed, on any character other
+than an 'a', the scanner will have to back up to accept "foo".
+Similarly, the comment for State #9 concerns when "fooba" has
+been scanned and an 'r' does not follow.
+.PP
+The final comment reminds us that there's no point going to
+all the trouble of removing backing up from the rules unless
+we're using
+.B \-Cf
+or
+.B \-CF,
+since there's no performance gain doing so with compressed scanners.
+.PP
+The way to remove the backing up is to add "error" rules:
+.nf
+
+ %%
+ foo return TOK_KEYWORD;
+ foobar return TOK_KEYWORD;
+
+ fooba |
+ foob |
+ fo {
+ /* false alarm, not really a keyword */
+ return TOK_ID;
+ }
+
+.fi
+.PP
+Eliminating backing up among a list of keywords can also be
+done using a "catch-all" rule:
+.nf
+
+ %%
+ foo return TOK_KEYWORD;
+ foobar return TOK_KEYWORD;
+
+ [a-z]+ return TOK_ID;
+
+.fi
+This is usually the best solution when appropriate.
+.PP
+Backing up messages tend to cascade.
+With a complicated set of rules it's not uncommon to get hundreds
+of messages. If one can decipher them, though, it often
+only takes a dozen or so rules to eliminate the backing up (though
+it's easy to make a mistake and have an error rule accidentally match
+a valid token. A possible future
+.I flex
+feature will be to automatically add rules to eliminate backing up).
+.PP
+It's important to keep in mind that you gain the benefits of eliminating
+backing up only if you eliminate
+.I every
+instance of backing up. Leaving just one means you gain nothing.
+.PP
+.I Variable
+trailing context (where both the leading and trailing parts do not have
+a fixed length) entails almost the same performance loss as
+.B REJECT
+(i.e., substantial). So when possible a rule like:
+.nf
+
+ %%
+ mouse|rat/(cat|dog) run();
+
+.fi
+is better written:
+.nf
+
+ %%
+ mouse/cat|dog run();
+ rat/cat|dog run();
+
+.fi
+or as
+.nf
+
+ %%
+ mouse|rat/cat run();
+ mouse|rat/dog run();
+
+.fi
+Note that here the special '|' action does
+.I not
+provide any savings, and can even make things worse (see
+Deficiencies / Bugs below).
+.LP
+Another area where the user can increase a scanner's performance
+(and one that's easier to implement) arises from the fact that
+the longer the tokens matched, the faster the scanner will run.
+This is because with long tokens the processing of most input
+characters takes place in the (short) inner scanning loop, and
+does not often have to go through the additional work of setting up
+the scanning environment (e.g.,
+.B yytext)
+for the action. Recall the scanner for C comments:
+.nf
+
+ %x comment
+ %%
+ int line_num = 1;
+
+ "/*" BEGIN(comment);
+
+ <comment>[^*\\n]*
+ <comment>"*"+[^*/\\n]*
+ <comment>\\n ++line_num;
+ <comment>"*"+"/" BEGIN(INITIAL);
+
+.fi
+This could be sped up by writing it as:
+.nf
+
+ %x comment
+ %%
+ int line_num = 1;
+
+ "/*" BEGIN(comment);
+
+ <comment>[^*\\n]*
+ <comment>[^*\\n]*\\n ++line_num;
+ <comment>"*"+[^*/\\n]*
+ <comment>"*"+[^*/\\n]*\\n ++line_num;
+ <comment>"*"+"/" BEGIN(INITIAL);
+
+.fi
+Now instead of each newline requiring the processing of another
+action, recognizing the newlines is "distributed" over the other rules
+to keep the matched text as long as possible. Note that
+.I adding
+rules does
+.I not
+slow down the scanner! The speed of the scanner is independent
+of the number of rules or (modulo the considerations given at the
+beginning of this section) how complicated the rules are with
+regard to operators such as '*' and '|'.
+.PP
+A final example in speeding up a scanner: suppose you want to scan
+through a file containing identifiers and keywords, one per line
+and with no other extraneous characters, and recognize all the
+keywords. A natural first approach is:
+.nf
+
+ %%
+ asm |
+ auto |
+ break |
+ ... etc ...
+ volatile |
+ while /* it's a keyword */
+
+ .|\\n /* it's not a keyword */
+
+.fi
+To eliminate the back-tracking, introduce a catch-all rule:
+.nf
+
+ %%
+ asm |
+ auto |
+ break |
+ ... etc ...
+ volatile |
+ while /* it's a keyword */
+
+ [a-z]+ |
+ .|\\n /* it's not a keyword */
+
+.fi
+Now, if it's guaranteed that there's exactly one word per line,
+then we can reduce the total number of matches by a half by
+merging in the recognition of newlines with that of the other
+tokens:
+.nf
+
+ %%
+ asm\\n |
+ auto\\n |
+ break\\n |
+ ... etc ...
+ volatile\\n |
+ while\\n /* it's a keyword */
+
+ [a-z]+\\n |
+ .|\\n /* it's not a keyword */
+
+.fi
+One has to be careful here, as we have now reintroduced backing up
+into the scanner. In particular, while
+.I we
+know that there will never be any characters in the input stream
+other than letters or newlines,
+.I flex
+can't figure this out, and it will plan for possibly needing to back up
+when it has scanned a token like "auto" and then the next character
+is something other than a newline or a letter. Previously it would
+then just match the "auto" rule and be done, but now it has no "auto"
+rule, only a "auto\\n" rule. To eliminate the possibility of backing up,
+we could either duplicate all rules but without final newlines, or,
+since we never expect to encounter such an input and therefore don't
+how it's classified, we can introduce one more catch-all rule, this
+one which doesn't include a newline:
+.nf
+
+ %%
+ asm\\n |
+ auto\\n |
+ break\\n |
+ ... etc ...
+ volatile\\n |
+ while\\n /* it's a keyword */
+
+ [a-z]+\\n |
+ [a-z]+ |
+ .|\\n /* it's not a keyword */
+
+.fi
+Compiled with
+.B \-Cf,
+this is about as fast as one can get a
+.I flex
+scanner to go for this particular problem.
+.PP
+A final note:
+.I flex
+is slow when matching NUL's, particularly when a token contains
+multiple NUL's.
+It's best to write rules which match
+.I short
+amounts of text if it's anticipated that the text will often include NUL's.
+.PP
+Another final note regarding performance: as mentioned above in the section
+How the Input is Matched, dynamically resizing
+.B yytext
+to accommodate huge tokens is a slow process because it presently requires that
+the (huge) token be rescanned from the beginning. Thus if performance is
+vital, you should attempt to match "large" quantities of text but not
+"huge" quantities, where the cutoff between the two is at about 8K
+characters/token.
+.SH GENERATING C++ SCANNERS
+.I flex
+provides two different ways to generate scanners for use with C++. The
+first way is to simply compile a scanner generated by
+.I flex
+using a C++ compiler instead of a C compiler. You should not encounter
+any compilations errors (please report any you find to the email address
+given in the Author section below). You can then use C++ code in your
+rule actions instead of C code. Note that the default input source for
+your scanner remains
+.I yyin,
+and default echoing is still done to
+.I yyout.
+Both of these remain
+.I FILE *
+variables and not C++
+.I streams.
+.PP
+You can also use
+.I flex
+to generate a C++ scanner class, using the
+.B \-+
+option (or, equivalently,
+.B %option c++),
+which is automatically specified if the name of the flex
+executable ends in a '+', such as
+.I flex++.
+When using this option, flex defaults to generating the scanner to the file
+.B lex.yy.cc
+instead of
+.B lex.yy.c.
+The generated scanner includes the header file
+.I FlexLexer.h,
+which defines the interface to two C++ classes.
+.PP
+The first class,
+.B FlexLexer,
+provides an abstract base class defining the general scanner class
+interface. It provides the following member functions:
+.TP
+.B const char* YYText()
+returns the text of the most recently matched token, the equivalent of
+.B yytext.
+.TP
+.B int YYLeng()
+returns the length of the most recently matched token, the equivalent of
+.B yyleng.
+.TP
+.B int lineno() const
+returns the current input line number
+(see
+.B %option yylineno),
+or
+.B 1
+if
+.B %option yylineno
+was not used.
+.TP
+.B void set_debug( int flag )
+sets the debugging flag for the scanner, equivalent to assigning to
+.B yy_flex_debug
+(see the Options section above). Note that you must build the scanner
+using
+.B %option debug
+to include debugging information in it.
+.TP
+.B int debug() const
+returns the current setting of the debugging flag.
+.PP
+Also provided are member functions equivalent to
+.B yy_switch_to_buffer(),
+.B yy_create_buffer()
+(though the first argument is an
+.B istream*
+object pointer and not a
+.B FILE*),
+.B yy_flush_buffer(),
+.B yy_delete_buffer(),
+and
+.B yyrestart()
+(again, the first argument is a
+.B istream*
+object pointer).
+.PP
+The second class defined in
+.I FlexLexer.h
+is
+.B yyFlexLexer,
+which is derived from
+.B FlexLexer.
+It defines the following additional member functions:
+.TP
+.B
+yyFlexLexer( istream* arg_yyin = 0, ostream* arg_yyout = 0 )
+constructs a
+.B yyFlexLexer
+object using the given streams for input and output. If not specified,
+the streams default to
+.B cin
+and
+.B cout,
+respectively.
+.TP
+.B virtual int yylex()
+performs the same role is
+.B yylex()
+does for ordinary flex scanners: it scans the input stream, consuming
+tokens, until a rule's action returns a value. If you derive a subclass
+.B S
+from
+.B yyFlexLexer
+and want to access the member functions and variables of
+.B S
+inside
+.B yylex(),
+then you need to use
+.B %option yyclass="S"
+to inform
+.I flex
+that you will be using that subclass instead of
+.B yyFlexLexer.
+In this case, rather than generating
+.B yyFlexLexer::yylex(),
+.I flex
+generates
+.B S::yylex()
+(and also generates a dummy
+.B yyFlexLexer::yylex()
+that calls
+.B yyFlexLexer::LexerError()
+if called).
+.TP
+.B
+virtual void switch_streams(istream* new_in = 0,
+.B
+ostream* new_out = 0)
+reassigns
+.B yyin
+to
+.B new_in
+(if non-nil)
+and
+.B yyout
+to
+.B new_out
+(ditto), deleting the previous input buffer if
+.B yyin
+is reassigned.
+.TP
+.B
+int yylex( istream* new_in, ostream* new_out = 0 )
+first switches the input streams via
+.B switch_streams( new_in, new_out )
+and then returns the value of
+.B yylex().
+.PP
+In addition,
+.B yyFlexLexer
+defines the following protected virtual functions which you can redefine
+in derived classes to tailor the scanner:
+.TP
+.B
+virtual int LexerInput( char* buf, int max_size )
+reads up to
+.B max_size
+characters into
+.B buf
+and returns the number of characters read. To indicate end-of-input,
+return 0 characters. Note that "interactive" scanners (see the
+.B \-B
+and
+.B \-I
+flags) define the macro
+.B YY_INTERACTIVE.
+If you redefine
+.B LexerInput()
+and need to take different actions depending on whether or not
+the scanner might be scanning an interactive input source, you can
+test for the presence of this name via
+.B #ifdef.
+.TP
+.B
+virtual void LexerOutput( const char* buf, int size )
+writes out
+.B size
+characters from the buffer
+.B buf,
+which, while NUL-terminated, may also contain "internal" NUL's if
+the scanner's rules can match text with NUL's in them.
+.TP
+.B
+virtual void LexerError( const char* msg )
+reports a fatal error message. The default version of this function
+writes the message to the stream
+.B cerr
+and exits.
+.PP
+Note that a
+.B yyFlexLexer
+object contains its
+.I entire
+scanning state. Thus you can use such objects to create reentrant
+scanners. You can instantiate multiple instances of the same
+.B yyFlexLexer
+class, and you can also combine multiple C++ scanner classes together
+in the same program using the
+.B \-P
+option discussed above.
+.PP
+Finally, note that the
+.B %array
+feature is not available to C++ scanner classes; you must use
+.B %pointer
+(the default).
+.PP
+Here is an example of a simple C++ scanner:
+.nf
+
+ // An example of using the flex C++ scanner class.
+
+ %{
+ int mylineno = 0;
+ %}
+
+ string \\"[^\\n"]+\\"
+
+ ws [ \\t]+
+
+ alpha [A-Za-z]
+ dig [0-9]
+ name ({alpha}|{dig}|\\$)({alpha}|{dig}|[_.\\-/$])*
+ num1 [-+]?{dig}+\\.?([eE][-+]?{dig}+)?
+ num2 [-+]?{dig}*\\.{dig}+([eE][-+]?{dig}+)?
+ number {num1}|{num2}
+
+ %%
+
+ {ws} /* skip blanks and tabs */
+
+ "/*" {
+ int c;
+
+ while((c = yyinput()) != 0)
+ {
+ if(c == '\\n')
+ ++mylineno;
+
+ else if(c == '*')
+ {
+ if((c = yyinput()) == '/')
+ break;
+ else
+ unput(c);
+ }
+ }
+ }
+
+ {number} cout << "number " << YYText() << '\\n';
+
+ \\n mylineno++;
+
+ {name} cout << "name " << YYText() << '\\n';
+
+ {string} cout << "string " << YYText() << '\\n';
+
+ %%
+
+ int main( int /* argc */, char** /* argv */ )
+ {
+ FlexLexer* lexer = new yyFlexLexer;
+ while(lexer->yylex() != 0)
+ ;
+ return 0;
+ }
+.fi
+If you want to create multiple (different) lexer classes, you use the
+.B \-P
+flag (or the
+.B prefix=
+option) to rename each
+.B yyFlexLexer
+to some other
+.B xxFlexLexer.
+You then can include
+.B <FlexLexer.h>
+in your other sources once per lexer class, first renaming
+.B yyFlexLexer
+as follows:
+.nf
+
+ #undef yyFlexLexer
+ #define yyFlexLexer xxFlexLexer
+ #include <FlexLexer.h>
+
+ #undef yyFlexLexer
+ #define yyFlexLexer zzFlexLexer
+ #include <FlexLexer.h>
+
+.fi
+if, for example, you used
+.B %option prefix="xx"
+for one of your scanners and
+.B %option prefix="zz"
+for the other.
+.PP
+IMPORTANT: the present form of the scanning class is
+.I experimental
+and may change considerably between major releases.
+.SH INCOMPATIBILITIES WITH LEX AND POSIX
+.I flex
+is a rewrite of the AT&T Unix
+.I lex
+tool (the two implementations do not share any code, though),
+with some extensions and incompatibilities, both of which
+are of concern to those who wish to write scanners acceptable
+to either implementation. Flex is fully compliant with the POSIX
+.I lex
+specification, except that when using
+.B %pointer
+(the default), a call to
+.B unput()
+destroys the contents of
+.B yytext,
+which is counter to the POSIX specification.
+.PP
+In this section we discuss all of the known areas of incompatibility
+between flex, AT&T lex, and the POSIX specification.
+.PP
+.I flex's
+.B \-l
+option turns on maximum compatibility with the original AT&T
+.I lex
+implementation, at the cost of a major loss in the generated scanner's
+performance. We note below which incompatibilities can be overcome
+using the
+.B \-l
+option.
+.PP
+.I flex
+is fully compatible with
+.I lex
+with the following exceptions:
+.IP -
+The undocumented
+.I lex
+scanner internal variable
+.B yylineno
+is not supported unless
+.B \-l
+or
+.B %option yylineno
+is used.
+.IP
+.B yylineno
+should be maintained on a per-buffer basis, rather than a per-scanner
+(single global variable) basis.
+.IP
+.B yylineno
+is not part of the POSIX specification.
+.IP -
+The
+.B input()
+routine is not redefinable, though it may be called to read characters
+following whatever has been matched by a rule. If
+.B input()
+encounters an end-of-file the normal
+.B yywrap()
+processing is done. A ``real'' end-of-file is returned by
+.B input()
+as
+.I EOF.
+.IP
+Input is instead controlled by defining the
+.B YY_INPUT
+macro.
+.IP
+The
+.I flex
+restriction that
+.B input()
+cannot be redefined is in accordance with the POSIX specification,
+which simply does not specify any way of controlling the
+scanner's input other than by making an initial assignment to
+.I yyin.
+.IP -
+The
+.B unput()
+routine is not redefinable. This restriction is in accordance with POSIX.
+.IP -
+.I flex
+scanners are not as reentrant as
+.I lex
+scanners. In particular, if you have an interactive scanner and
+an interrupt handler which long-jumps out of the scanner, and
+the scanner is subsequently called again, you may get the following
+message:
+.nf
+
+ fatal flex scanner internal error--end of buffer missed
+
+.fi
+To reenter the scanner, first use
+.nf
+
+ yyrestart( yyin );
+
+.fi
+Note that this call will throw away any buffered input; usually this
+isn't a problem with an interactive scanner.
+.IP
+Also note that flex C++ scanner classes
+.I are
+reentrant, so if using C++ is an option for you, you should use
+them instead. See "Generating C++ Scanners" above for details.
+.IP -
+.B output()
+is not supported.
+Output from the
+.B ECHO
+macro is done to the file-pointer
+.I yyout
+(default
+.I stdout).
+.IP
+.B output()
+is not part of the POSIX specification.
+.IP -
+.I lex
+does not support exclusive start conditions (%x), though they
+are in the POSIX specification.
+.IP -
+When definitions are expanded,
+.I flex
+encloses them in parentheses.
+With lex, the following:
+.nf
+
+ NAME [A-Z][A-Z0-9]*
+ %%
+ foo{NAME}? printf( "Found it\\n" );
+ %%
+
+.fi
+will not match the string "foo" because when the macro
+is expanded the rule is equivalent to "foo[A-Z][A-Z0-9]*?"
+and the precedence is such that the '?' is associated with
+"[A-Z0-9]*". With
+.I flex,
+the rule will be expanded to
+"foo([A-Z][A-Z0-9]*)?" and so the string "foo" will match.
+.IP
+Note that if the definition begins with
+.B ^
+or ends with
+.B $
+then it is
+.I not
+expanded with parentheses, to allow these operators to appear in
+definitions without losing their special meanings. But the
+.B <s>, /,
+and
+.B <<EOF>>
+operators cannot be used in a
+.I flex
+definition.
+.IP
+Using
+.B \-l
+results in the
+.I lex
+behavior of no parentheses around the definition.
+.IP
+The POSIX specification is that the definition be enclosed in parentheses.
+.IP -
+Some implementations of
+.I lex
+allow a rule's action to begin on a separate line, if the rule's pattern
+has trailing whitespace:
+.nf
+
+ %%
+ foo|bar<space here>
+ { foobar_action(); }
+
+.fi
+.I flex
+does not support this feature.
+.IP -
+The
+.I lex
+.B %r
+(generate a Ratfor scanner) option is not supported. It is not part
+of the POSIX specification.
+.IP -
+After a call to
+.B unput(),
+.I yytext
+is undefined until the next token is matched, unless the scanner
+was built using
+.B %array.
+This is not the case with
+.I lex
+or the POSIX specification. The
+.B \-l
+option does away with this incompatibility.
+.IP -
+The precedence of the
+.B {}
+(numeric range) operator is different.
+.I lex
+interprets "abc{1,3}" as "match one, two, or
+three occurrences of 'abc'", whereas
+.I flex
+interprets it as "match 'ab'
+followed by one, two, or three occurrences of 'c'". The latter is
+in agreement with the POSIX specification.
+.IP -
+The precedence of the
+.B ^
+operator is different.
+.I lex
+interprets "^foo|bar" as "match either 'foo' at the beginning of a line,
+or 'bar' anywhere", whereas
+.I flex
+interprets it as "match either 'foo' or 'bar' if they come at the beginning
+of a line". The latter is in agreement with the POSIX specification.
+.IP -
+The special table-size declarations such as
+.B %a
+supported by
+.I lex
+are not required by
+.I flex
+scanners;
+.I flex
+ignores them.
+.IP -
+The name
+.bd
+FLEX_SCANNER
+is #define'd so scanners may be written for use with either
+.I flex
+or
+.I lex.
+Scanners also include
+.B YY_FLEX_MAJOR_VERSION
+and
+.B YY_FLEX_MINOR_VERSION
+indicating which version of
+.I flex
+generated the scanner
+(for example, for the 2.5 release, these defines would be 2 and 5
+respectively).
+.PP
+The following
+.I flex
+features are not included in
+.I lex
+or the POSIX specification:
+.nf
+
+ C++ scanners
+ %option
+ start condition scopes
+ start condition stacks
+ interactive/non-interactive scanners
+ yy_scan_string() and friends
+ yyterminate()
+ yy_set_interactive()
+ yy_set_bol()
+ YY_AT_BOL()
+ <<EOF>>
+ <*>
+ YY_DECL
+ YY_START
+ YY_USER_ACTION
+ YY_USER_INIT
+ #line directives
+ %{}'s around actions
+ multiple actions on a line
+
+.fi
+plus almost all of the flex flags.
+The last feature in the list refers to the fact that with
+.I flex
+you can put multiple actions on the same line, separated with
+semi-colons, while with
+.I lex,
+the following
+.nf
+
+ foo handle_foo(); ++num_foos_seen;
+
+.fi
+is (rather surprisingly) truncated to
+.nf
+
+ foo handle_foo();
+
+.fi
+.I flex
+does not truncate the action. Actions that are not enclosed in
+braces are simply terminated at the end of the line.
+.SH DIAGNOSTICS
+.PP
+.I warning, rule cannot be matched
+indicates that the given rule
+cannot be matched because it follows other rules that will
+always match the same text as it. For
+example, in the following "foo" cannot be matched because it comes after
+an identifier "catch-all" rule:
+.nf
+
+ [a-z]+ got_identifier();
+ foo got_foo();
+
+.fi
+Using
+.B REJECT
+in a scanner suppresses this warning.
+.PP
+.I warning,
+.B \-s
+.I
+option given but default rule can be matched
+means that it is possible (perhaps only in a particular start condition)
+that the default rule (match any single character) is the only one
+that will match a particular input. Since
+.B \-s
+was given, presumably this is not intended.
+.PP
+.I reject_used_but_not_detected undefined
+or
+.I yymore_used_but_not_detected undefined -
+These errors can occur at compile time. They indicate that the
+scanner uses
+.B REJECT
+or
+.B yymore()
+but that
+.I flex
+failed to notice the fact, meaning that
+.I flex
+scanned the first two sections looking for occurrences of these actions
+and failed to find any, but somehow you snuck some in (via a #include
+file, for example). Use
+.B %option reject
+or
+.B %option yymore
+to indicate to flex that you really do use these features.
+.PP
+.I flex scanner jammed -
+a scanner compiled with
+.B \-s
+has encountered an input string which wasn't matched by
+any of its rules. This error can also occur due to internal problems.
+.PP
+.I token too large, exceeds YYLMAX -
+your scanner uses
+.B %array
+and one of its rules matched a string longer than the
+.B YYLMAX
+constant (8K bytes by default). You can increase the value by
+#define'ing
+.B YYLMAX
+in the definitions section of your
+.I flex
+input.
+.PP
+.I scanner requires \-8 flag to
+.I use the character 'x' -
+Your scanner specification includes recognizing the 8-bit character
+.I 'x'
+and you did not specify the \-8 flag, and your scanner defaulted to 7-bit
+because you used the
+.B \-Cf
+or
+.B \-CF
+table compression options. See the discussion of the
+.B \-7
+flag for details.
+.PP
+.I flex scanner push-back overflow -
+you used
+.B unput()
+to push back so much text that the scanner's buffer could not hold
+both the pushed-back text and the current token in
+.B yytext.
+Ideally the scanner should dynamically resize the buffer in this case, but at
+present it does not.
+.PP
+.I
+input buffer overflow, can't enlarge buffer because scanner uses REJECT -
+the scanner was working on matching an extremely large token and needed
+to expand the input buffer. This doesn't work with scanners that use
+.B
+REJECT.
+.PP
+.I
+fatal flex scanner internal error--end of buffer missed -
+This can occur in an scanner which is reentered after a long-jump
+has jumped out (or over) the scanner's activation frame. Before
+reentering the scanner, use:
+.nf
+
+ yyrestart( yyin );
+
+.fi
+or, as noted above, switch to using the C++ scanner class.
+.PP
+.I too many start conditions in <> construct! -
+you listed more start conditions in a <> construct than exist (so
+you must have listed at least one of them twice).
+.SH FILES
+.TP
+.B \-lfl
+library with which scanners must be linked.
+.TP
+.I lex.yy.c
+generated scanner (called
+.I lexyy.c
+on some systems).
+.TP
+.I lex.yy.cc
+generated C++ scanner class, when using
+.B -+.
+.TP
+.I <FlexLexer.h>
+header file defining the C++ scanner base class,
+.B FlexLexer,
+and its derived class,
+.B yyFlexLexer.
+.TP
+.I flex.skl
+skeleton scanner. This file is only used when building flex, not when
+flex executes.
+.TP
+.I lex.backup
+backing-up information for
+.B \-b
+flag (called
+.I lex.bck
+on some systems).
+.SH DEFICIENCIES / BUGS
+.PP
+Some trailing context
+patterns cannot be properly matched and generate
+warning messages ("dangerous trailing context"). These are
+patterns where the ending of the
+first part of the rule matches the beginning of the second
+part, such as "zx*/xy*", where the 'x*' matches the 'x' at
+the beginning of the trailing context. (Note that the POSIX draft
+states that the text matched by such patterns is undefined.)
+.PP
+For some trailing context rules, parts which are actually fixed-length are
+not recognized as such, leading to the abovementioned performance loss.
+In particular, parts using '|' or {n} (such as "foo{3}") are always
+considered variable-length.
+.PP
+Combining trailing context with the special '|' action can result in
+.I fixed
+trailing context being turned into the more expensive
+.I variable
+trailing context. For example, in the following:
+.nf
+
+ %%
+ abc |
+ xyz/def
+
+.fi
+.PP
+Use of
+.B unput()
+invalidates yytext and yyleng, unless the
+.B %array
+directive
+or the
+.B \-l
+option has been used.
+.PP
+Pattern-matching of NUL's is substantially slower than matching other
+characters.
+.PP
+Dynamic resizing of the input buffer is slow, as it entails rescanning
+all the text matched so far by the current (generally huge) token.
+.PP
+Due to both buffering of input and read-ahead, you cannot intermix
+calls to <stdio.h> routines, such as, for example,
+.B getchar(),
+with
+.I flex
+rules and expect it to work. Call
+.B input()
+instead.
+.PP
+The total table entries listed by the
+.B \-v
+flag excludes the number of table entries needed to determine
+what rule has been matched. The number of entries is equal
+to the number of DFA states if the scanner does not use
+.B REJECT,
+and somewhat greater than the number of states if it does.
+.PP
+.B REJECT
+cannot be used with the
+.B \-f
+or
+.B \-F
+options.
+.PP
+The
+.I flex
+internal algorithms need documentation.
+.SH SEE ALSO
+.PP
+lex(1), yacc(1), sed(1), awk(1).
+.PP
+John Levine, Tony Mason, and Doug Brown,
+.I Lex & Yacc,
+O'Reilly and Associates. Be sure to get the 2nd edition.
+.PP
+M. E. Lesk and E. Schmidt,
+.I LEX \- Lexical Analyzer Generator
+.PP
+Alfred Aho, Ravi Sethi and Jeffrey Ullman,
+.I Compilers: Principles, Techniques and Tools,
+Addison-Wesley (1986). Describes the pattern-matching techniques used by
+.I flex
+(deterministic finite automata).
+.SH AUTHOR
+Vern Paxson, with the help of many ideas and much inspiration from
+Van Jacobson. Original version by Jef Poskanzer. The fast table
+representation is a partial implementation of a design done by Van
+Jacobson. The implementation was done by Kevin Gong and Vern Paxson.
+.PP
+Thanks to the many
+.I flex
+beta-testers, feedbackers, and contributors, especially Francois Pinard,
+Casey Leedom,
+Robert Abramovitz,
+Stan Adermann, Terry Allen, David Barker-Plummer, John Basrai,
+Neal Becker, Nelson H.F. Beebe, benson@odi.com,
+Karl Berry, Peter A. Bigot, Simon Blanchard,
+Keith Bostic, Frederic Brehm, Ian Brockbank, Kin Cho, Nick Christopher,
+Brian Clapper, J.T. Conklin,
+Jason Coughlin, Bill Cox, Nick Cropper, Dave Curtis, Scott David
+Daniels, Chris G. Demetriou, Theo Deraadt,
+Mike Donahue, Chuck Doucette, Tom Epperly, Leo Eskin,
+Chris Faylor, Chris Flatters, Jon Forrest, Jeffrey Friedl,
+Joe Gayda, Kaveh R. Ghazi, Wolfgang Glunz,
+Eric Goldman, Christopher M. Gould, Ulrich Grepel, Peer Griebel,
+Jan Hajic, Charles Hemphill, NORO Hideo,
+Jarkko Hietaniemi, Scott Hofmann,
+Jeff Honig, Dana Hudes, Eric Hughes, John Interrante,
+Ceriel Jacobs, Michal Jaegermann, Sakari Jalovaara, Jeffrey R. Jones,
+Henry Juengst, Klaus Kaempf, Jonathan I. Kamens, Terrence O Kane,
+Amir Katz, ken@ken.hilco.com, Kevin B. Kenny,
+Steve Kirsch, Winfried Koenig, Marq Kole, Ronald Lamprecht,
+Greg Lee, Rohan Lenard, Craig Leres, John Levine, Steve Liddle,
+David Loffredo, Mike Long,
+Mohamed el Lozy, Brian Madsen, Malte, Joe Marshall,
+Bengt Martensson, Chris Metcalf,
+Luke Mewburn, Jim Meyering, R. Alexander Milowski, Erik Naggum,
+G.T. Nicol, Landon Noll, James Nordby, Marc Nozell,
+Richard Ohnemus, Karsten Pahnke,
+Sven Panne, Roland Pesch, Walter Pelissero, Gaumond
+Pierre, Esmond Pitt, Jef Poskanzer, Joe Rahmeh, Jarmo Raiha,
+Frederic Raimbault, Pat Rankin, Rick Richardson,
+Kevin Rodgers, Kai Uwe Rommel, Jim Roskind, Alberto Santini,
+Andreas Scherer, Darrell Schiebel, Raf Schietekat,
+Doug Schmidt, Philippe Schnoebelen, Andreas Schwab,
+Larry Schwimmer, Alex Siegel, Eckehard Stolz, Jan-Erik Strvmquist,
+Mike Stump, Paul Stuart, Dave Tallman, Ian Lance Taylor,
+Chris Thewalt, Richard M. Timoney, Jodi Tsai,
+Paul Tuinenga, Gary Weik, Frank Whaley, Gerhard Wilhelms, Kent Williams, Ken
+Yap, Ron Zellar, Nathan Zelle, David Zuhn,
+and those whose names have slipped my marginal
+mail-archiving skills but whose contributions are appreciated all the
+same.
+.PP
+Thanks to Keith Bostic, Jon Forrest, Noah Friedman,
+John Gilmore, Craig Leres, John Levine, Bob Mulcahy, G.T.
+Nicol, Francois Pinard, Rich Salz, and Richard Stallman for help with various
+distribution headaches.
+.PP
+Thanks to Esmond Pitt and Earle Horton for 8-bit character support; to
+Benson Margulies and Fred Burke for C++ support; to Kent Williams and Tom
+Epperly for C++ class support; to Ove Ewerlid for support of NUL's; and to
+Eric Hughes for support of multiple buffers.
+.PP
+This work was primarily done when I was with the Real Time Systems Group
+at the Lawrence Berkeley Laboratory in Berkeley, CA. Many thanks to all there
+for the support I received.
+.PP
+Send comments to vern@ee.lbl.gov.
diff --git a/Tools/android/flex-2.5.4a/flex.skl b/Tools/android/flex-2.5.4a/flex.skl
new file mode 100644
index 0000000..71a9cb6
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/flex.skl
@@ -0,0 +1,1541 @@
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+%-
+#include <stdio.h>
+%*
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+%+
+class istream;
+%*
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+%-
+extern FILE *yyin, *yyout;
+%*
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+ {
+%-
+ FILE *yy_input_file;
+%+
+ istream* yy_input_file;
+%*
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+ };
+
+%- Standard (non-C++) definition
+static YY_BUFFER_STATE yy_current_buffer = 0;
+%*
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+%- Standard (non-C++) definition
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+%*
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+%% yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here
+
+%- Standard (non-C++) definition
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+%*
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+%% code to fiddle yytext and yyleng for yymore() goes here
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+%% code to copy yytext_ptr to yytext[] goes here, if %array
+ yy_c_buf_p = yy_cp;
+
+%% data tables for the DFA and the user's section 1 definitions go here
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+%-
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+%*
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+%- Standard (non-C++) definition
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+%*
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+%- Standard (non-C++) definition
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+%+ C++ definition
+#define ECHO LexerOutput( yytext, yyleng )
+%*
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+%% fread()/read() definition of YY_INPUT goes here unless we're doing C++
+%+ C++ definition
+ if ( (result = LexerInput( (char *) buf, max_size )) < 0 ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+%*
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+%-
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+%+
+#define YY_FATAL_ERROR(msg) LexerError( msg )
+%*
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+%- Standard (non-C++) definition
+#define YY_DECL int yylex YY_PROTO(( void ))
+%+ C++ definition
+#define YY_DECL int yyFlexLexer::yylex()
+%*
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+%% YY_RULE_SETUP definition goes here
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+%% user's declarations go here
+
+ if ( yy_init )
+ {
+ yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+%-
+ yyin = stdin;
+%+
+ yyin = &cin;
+%*
+
+ if ( ! yyout )
+%-
+ yyout = stdout;
+%+
+ yyout = &cout;
+%*
+
+ if ( ! yy_current_buffer )
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+%% yymore()-related code goes here
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+%% code to set up and find next match goes here
+
+yy_find_action:
+%% code to find the action number goes here
+
+ YY_DO_BEFORE_ACTION;
+
+%% code for yylineno update goes here
+
+do_action: /* This label is used only to access EOF actions. */
+
+%% debug code goes here
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+%% actions go here
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+%% code to do back-up for compressed tables and set up yy_cp goes here
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of yylex */
+
+%+
+yyFlexLexer::yyFlexLexer( istream* arg_yyin, ostream* arg_yyout )
+ {
+ yyin = arg_yyin;
+ yyout = arg_yyout;
+ yy_c_buf_p = 0;
+ yy_init = 1;
+ yy_start = 0;
+ yy_flex_debug = 0;
+ yylineno = 1; // this will only get updated if %option yylineno
+
+ yy_did_buffer_switch_on_eof = 0;
+
+ yy_looking_for_trail_begin = 0;
+ yy_more_flag = 0;
+ yy_more_len = 0;
+ yy_more_offset = yy_prev_more_offset = 0;
+
+ yy_start_stack_ptr = yy_start_stack_depth = 0;
+ yy_start_stack = 0;
+
+ yy_current_buffer = 0;
+
+#ifdef YY_USES_REJECT
+ yy_state_buf = new yy_state_type[YY_BUF_SIZE + 2];
+#else
+ yy_state_buf = 0;
+#endif
+ }
+
+yyFlexLexer::~yyFlexLexer()
+ {
+ delete yy_state_buf;
+ yy_delete_buffer( yy_current_buffer );
+ }
+
+void yyFlexLexer::switch_streams( istream* new_in, ostream* new_out )
+ {
+ if ( new_in )
+ {
+ yy_delete_buffer( yy_current_buffer );
+ yy_switch_to_buffer( yy_create_buffer( new_in, YY_BUF_SIZE ) );
+ }
+
+ if ( new_out )
+ yyout = new_out;
+ }
+
+#ifdef YY_INTERACTIVE
+int yyFlexLexer::LexerInput( char* buf, int /* max_size */ )
+#else
+int yyFlexLexer::LexerInput( char* buf, int max_size )
+#endif
+ {
+ if ( yyin->eof() || yyin->fail() )
+ return 0;
+
+#ifdef YY_INTERACTIVE
+ yyin->get( buf[0] );
+
+ if ( yyin->eof() )
+ return 0;
+
+ if ( yyin->bad() )
+ return -1;
+
+ return 1;
+
+#else
+ (void) yyin->read( buf, max_size );
+
+ if ( yyin->bad() )
+ return -1;
+ else
+ return yyin->gcount();
+#endif
+ }
+
+void yyFlexLexer::LexerOutput( const char* buf, int size )
+ {
+ (void) yyout->write( buf, size );
+ }
+%*
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+%-
+static int yy_get_next_buffer()
+%+
+int yyFlexLexer::yy_get_next_buffer()
+%*
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset =
+ (int) (yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+%-
+static yy_state_type yy_get_previous_state()
+%+
+yy_state_type yyFlexLexer::yy_get_previous_state()
+%*
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+%% code to get the start state into yy_current_state goes here
+
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+%% code to find the next state goes here
+ }
+
+ return yy_current_state;
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+%-
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+%+
+yy_state_type yyFlexLexer::yy_try_NUL_trans( yy_state_type yy_current_state )
+%*
+ {
+ register int yy_is_jam;
+%% code to find the next state, and perhaps do backing up, goes here
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+
+%-
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+%+
+void yyFlexLexer::yyunput( int c, register char* yy_bp )
+%*
+ {
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ yy_current_buffer->yy_n_chars =
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+%% update yylineno here
+
+ yytext_ptr = yy_bp;
+ yy_hold_char = *yy_cp;
+ yy_c_buf_p = yy_cp;
+ }
+%-
+#endif /* ifndef YY_NO_UNPUT */
+%*
+
+
+%-
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+%+
+int yyFlexLexer::yyinput()
+%*
+ {
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yy_c_buf_p - yytext_ptr;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ return EOF;
+
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+%% update BOL and yylineno
+
+ return c;
+ }
+
+
+%-
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+%+
+void yyFlexLexer::yyrestart( istream* input_file )
+%*
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
+ }
+
+
+%-
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+%+
+void yyFlexLexer::yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+%*
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+%-
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+%+
+void yyFlexLexer::yy_load_buffer_state()
+%*
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+%-
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+%+
+YY_BUFFER_STATE yyFlexLexer::yy_create_buffer( istream* file, int size )
+%*
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+%-
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+%+
+void yyFlexLexer::yy_delete_buffer( YY_BUFFER_STATE b )
+%*
+ {
+ if ( ! b )
+ return;
+
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yy_flex_free( (void *) b->yy_ch_buf );
+
+ yy_flex_free( (void *) b );
+ }
+
+
+%-
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+%+
+extern "C" int isatty YY_PROTO(( int ));
+void yyFlexLexer::yy_init_buffer( YY_BUFFER_STATE b, istream* file )
+%*
+
+ {
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+%-
+#if YY_ALWAYS_INTERACTIVE
+ b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+ b->yy_is_interactive = 0;
+#else
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+%+
+ b->yy_is_interactive = 0;
+%*
+ }
+
+
+%-
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+%+
+void yyFlexLexer::yy_flush_buffer( YY_BUFFER_STATE b )
+%*
+ {
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == yy_current_buffer )
+ yy_load_buffer_state();
+ }
+%*
+
+
+#ifndef YY_NO_SCAN_BUFFER
+%-
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b );
+
+ return b;
+ }
+%*
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+%-
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+ {
+ int len;
+ for ( len = 0; yy_str[len]; ++len )
+ ;
+
+ return yy_scan_bytes( yy_str, len );
+ }
+%*
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+%-
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) yy_flex_alloc( n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+ }
+%*
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+%-
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+%+
+void yyFlexLexer::yy_push_state( int new_state )
+%*
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
+
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
+
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+%-
+static void yy_pop_state()
+%+
+void yyFlexLexer::yy_pop_state()
+%*
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+%-
+static int yy_top_state()
+%+
+int yyFlexLexer::yy_top_state()
+%*
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+%-
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+ }
+
+%+
+
+void yyFlexLexer::LexerError( yyconst char msg[] )
+ {
+ cerr << msg << '\n';
+ exit( YY_EXIT_FAILURE );
+ }
+%*
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+#if YY_MAIN
+int main()
+ {
+ yylex();
+ return 0;
+ }
+#endif
diff --git a/Tools/android/flex-2.5.4a/flexdef.h b/Tools/android/flex-2.5.4a/flexdef.h
new file mode 100644
index 0000000..f50a4b3
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/flexdef.h
@@ -0,0 +1,1048 @@
+/* flexdef - definitions file for flex */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* @(#) $Header: /home/daffy/u0/vern/flex/RCS/flexdef.h,v 2.53 95/04/20 11:17:36 vern Exp $ (LBL) */
+
+#include <stdio.h>
+#include <ctype.h>
+
+#include "config.h"
+
+#ifdef __TURBOC__
+#define HAVE_STRING_H 1
+#define MS_DOS 1
+#ifndef __STDC__
+#define __STDC__ 1
+#endif
+ #pragma warn -pro
+ #pragma warn -rch
+ #pragma warn -use
+ #pragma warn -aus
+ #pragma warn -par
+ #pragma warn -pia
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#else
+#include <strings.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef HAVE_MALLOC_H
+#include <malloc.h>
+#endif
+
+#ifdef STDC_HEADERS
+#include <stdlib.h>
+#endif
+
+/* As an aid for the internationalization patch to flex, which
+ * is maintained outside this distribution for copyright reasons.
+ */
+#define _(String) (String)
+
+/* Always be prepared to generate an 8-bit scanner. */
+#define CSIZE 256
+#define Char unsigned char
+
+/* Size of input alphabet - should be size of ASCII set. */
+#ifndef DEFAULT_CSIZE
+#define DEFAULT_CSIZE 128
+#endif
+
+#ifndef PROTO
+#if __STDC__
+#define PROTO(proto) proto
+#else
+#define PROTO(proto) ()
+#endif
+#endif
+
+#ifdef VMS
+#ifndef __VMS_POSIX
+#define unlink remove
+#define SHORT_FILE_NAMES
+#endif
+#endif
+
+#ifdef MS_DOS
+#define SHORT_FILE_NAMES
+#endif
+
+
+/* Maximum line length we'll have to deal with. */
+#define MAXLINE 2048
+
+#ifndef MIN
+#define MIN(x,y) ((x) < (y) ? (x) : (y))
+#endif
+#ifndef MAX
+#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#endif
+#ifndef ABS
+#define ABS(x) ((x) < 0 ? -(x) : (x))
+#endif
+
+
+/* ANSI C does not guarantee that isascii() is defined */
+#ifndef isascii
+#define isascii(c) ((c) <= 0177)
+#endif
+
+
+#define true 1
+#define false 0
+#define unspecified -1
+
+
+/* Special chk[] values marking the slots taking by end-of-buffer and action
+ * numbers.
+ */
+#define EOB_POSITION -1
+#define ACTION_POSITION -2
+
+/* Number of data items per line for -f output. */
+#define NUMDATAITEMS 10
+
+/* Number of lines of data in -f output before inserting a blank line for
+ * readability.
+ */
+#define NUMDATALINES 10
+
+/* transition_struct_out() definitions. */
+#define TRANS_STRUCT_PRINT_LENGTH 14
+
+/* Returns true if an nfa state has an epsilon out-transition slot
+ * that can be used. This definition is currently not used.
+ */
+#define FREE_EPSILON(state) \
+ (transchar[state] == SYM_EPSILON && \
+ trans2[state] == NO_TRANSITION && \
+ finalst[state] != state)
+
+/* Returns true if an nfa state has an epsilon out-transition character
+ * and both slots are free
+ */
+#define SUPER_FREE_EPSILON(state) \
+ (transchar[state] == SYM_EPSILON && \
+ trans1[state] == NO_TRANSITION) \
+
+/* Maximum number of NFA states that can comprise a DFA state. It's real
+ * big because if there's a lot of rules, the initial state will have a
+ * huge epsilon closure.
+ */
+#define INITIAL_MAX_DFA_SIZE 750
+#define MAX_DFA_SIZE_INCREMENT 750
+
+
+/* A note on the following masks. They are used to mark accepting numbers
+ * as being special. As such, they implicitly limit the number of accepting
+ * numbers (i.e., rules) because if there are too many rules the rule numbers
+ * will overload the mask bits. Fortunately, this limit is \large/ (0x2000 ==
+ * 8192) so unlikely to actually cause any problems. A check is made in
+ * new_rule() to ensure that this limit is not reached.
+ */
+
+/* Mask to mark a trailing context accepting number. */
+#define YY_TRAILING_MASK 0x2000
+
+/* Mask to mark the accepting number of the "head" of a trailing context
+ * rule.
+ */
+#define YY_TRAILING_HEAD_MASK 0x4000
+
+/* Maximum number of rules, as outlined in the above note. */
+#define MAX_RULE (YY_TRAILING_MASK - 1)
+
+
+/* NIL must be 0. If not, its special meaning when making equivalence classes
+ * (it marks the representative of a given e.c.) will be unidentifiable.
+ */
+#define NIL 0
+
+#define JAM -1 /* to mark a missing DFA transition */
+#define NO_TRANSITION NIL
+#define UNIQUE -1 /* marks a symbol as an e.c. representative */
+#define INFINITY -1 /* for x{5,} constructions */
+
+#define INITIAL_MAX_CCLS 100 /* max number of unique character classes */
+#define MAX_CCLS_INCREMENT 100
+
+/* Size of table holding members of character classes. */
+#define INITIAL_MAX_CCL_TBL_SIZE 500
+#define MAX_CCL_TBL_SIZE_INCREMENT 250
+
+#define INITIAL_MAX_RULES 100 /* default maximum number of rules */
+#define MAX_RULES_INCREMENT 100
+
+#define INITIAL_MNS 2000 /* default maximum number of nfa states */
+#define MNS_INCREMENT 1000 /* amount to bump above by if it's not enough */
+
+#define INITIAL_MAX_DFAS 1000 /* default maximum number of dfa states */
+#define MAX_DFAS_INCREMENT 1000
+
+#define JAMSTATE -32766 /* marks a reference to the state that always jams */
+
+/* Maximum number of NFA states. */
+#define MAXIMUM_MNS 31999
+
+/* Enough so that if it's subtracted from an NFA state number, the result
+ * is guaranteed to be negative.
+ */
+#define MARKER_DIFFERENCE (MAXIMUM_MNS+2)
+
+/* Maximum number of nxt/chk pairs for non-templates. */
+#define INITIAL_MAX_XPAIRS 2000
+#define MAX_XPAIRS_INCREMENT 2000
+
+/* Maximum number of nxt/chk pairs needed for templates. */
+#define INITIAL_MAX_TEMPLATE_XPAIRS 2500
+#define MAX_TEMPLATE_XPAIRS_INCREMENT 2500
+
+#define SYM_EPSILON (CSIZE + 1) /* to mark transitions on the symbol epsilon */
+
+#define INITIAL_MAX_SCS 40 /* maximum number of start conditions */
+#define MAX_SCS_INCREMENT 40 /* amount to bump by if it's not enough */
+
+#define ONE_STACK_SIZE 500 /* stack of states with only one out-transition */
+#define SAME_TRANS -1 /* transition is the same as "default" entry for state */
+
+/* The following percentages are used to tune table compression:
+
+ * The percentage the number of out-transitions a state must be of the
+ * number of equivalence classes in order to be considered for table
+ * compaction by using protos.
+ */
+#define PROTO_SIZE_PERCENTAGE 15
+
+/* The percentage the number of homogeneous out-transitions of a state
+ * must be of the number of total out-transitions of the state in order
+ * that the state's transition table is first compared with a potential
+ * template of the most common out-transition instead of with the first
+ * proto in the proto queue.
+ */
+#define CHECK_COM_PERCENTAGE 50
+
+/* The percentage the number of differences between a state's transition
+ * table and the proto it was first compared with must be of the total
+ * number of out-transitions of the state in order to keep the first
+ * proto as a good match and not search any further.
+ */
+#define FIRST_MATCH_DIFF_PERCENTAGE 10
+
+/* The percentage the number of differences between a state's transition
+ * table and the most similar proto must be of the state's total number
+ * of out-transitions to use the proto as an acceptable close match.
+ */
+#define ACCEPTABLE_DIFF_PERCENTAGE 50
+
+/* The percentage the number of homogeneous out-transitions of a state
+ * must be of the number of total out-transitions of the state in order
+ * to consider making a template from the state.
+ */
+#define TEMPLATE_SAME_PERCENTAGE 60
+
+/* The percentage the number of differences between a state's transition
+ * table and the most similar proto must be of the state's total number
+ * of out-transitions to create a new proto from the state.
+ */
+#define NEW_PROTO_DIFF_PERCENTAGE 20
+
+/* The percentage the total number of out-transitions of a state must be
+ * of the number of equivalence classes in order to consider trying to
+ * fit the transition table into "holes" inside the nxt/chk table.
+ */
+#define INTERIOR_FIT_PERCENTAGE 15
+
+/* Size of region set aside to cache the complete transition table of
+ * protos on the proto queue to enable quick comparisons.
+ */
+#define PROT_SAVE_SIZE 2000
+
+#define MSP 50 /* maximum number of saved protos (protos on the proto queue) */
+
+/* Maximum number of out-transitions a state can have that we'll rummage
+ * around through the interior of the internal fast table looking for a
+ * spot for it.
+ */
+#define MAX_XTIONS_FULL_INTERIOR_FIT 4
+
+/* Maximum number of rules which will be reported as being associated
+ * with a DFA state.
+ */
+#define MAX_ASSOC_RULES 100
+
+/* Number that, if used to subscript an array, has a good chance of producing
+ * an error; should be small enough to fit into a short.
+ */
+#define BAD_SUBSCRIPT -32767
+
+/* Absolute value of largest number that can be stored in a short, with a
+ * bit of slop thrown in for general paranoia.
+ */
+#define MAX_SHORT 32700
+
+
+/* Declarations for global variables. */
+
+/* Variables for symbol tables:
+ * sctbl - start-condition symbol table
+ * ndtbl - name-definition symbol table
+ * ccltab - character class text symbol table
+ */
+
+struct hash_entry
+ {
+ struct hash_entry *prev, *next;
+ char *name;
+ char *str_val;
+ int int_val;
+ } ;
+
+typedef struct hash_entry **hash_table;
+
+#define NAME_TABLE_HASH_SIZE 101
+#define START_COND_HASH_SIZE 101
+#define CCL_HASH_SIZE 101
+
+extern struct hash_entry *ndtbl[NAME_TABLE_HASH_SIZE];
+extern struct hash_entry *sctbl[START_COND_HASH_SIZE];
+extern struct hash_entry *ccltab[CCL_HASH_SIZE];
+
+
+/* Variables for flags:
+ * printstats - if true (-v), dump statistics
+ * syntaxerror - true if a syntax error has been found
+ * eofseen - true if we've seen an eof in the input file
+ * ddebug - if true (-d), make a "debug" scanner
+ * trace - if true (-T), trace processing
+ * nowarn - if true (-w), do not generate warnings
+ * spprdflt - if true (-s), suppress the default rule
+ * interactive - if true (-I), generate an interactive scanner
+ * caseins - if true (-i), generate a case-insensitive scanner
+ * lex_compat - if true (-l), maximize compatibility with AT&T lex
+ * do_yylineno - if true, generate code to maintain yylineno
+ * useecs - if true (-Ce flag), use equivalence classes
+ * fulltbl - if true (-Cf flag), don't compress the DFA state table
+ * usemecs - if true (-Cm flag), use meta-equivalence classes
+ * fullspd - if true (-F flag), use Jacobson method of table representation
+ * gen_line_dirs - if true (i.e., no -L flag), generate #line directives
+ * performance_report - if > 0 (i.e., -p flag), generate a report relating
+ * to scanner performance; if > 1 (-p -p), report on minor performance
+ * problems, too
+ * backing_up_report - if true (i.e., -b flag), generate "lex.backup" file
+ * listing backing-up states
+ * C_plus_plus - if true (i.e., -+ flag), generate a C++ scanner class;
+ * otherwise, a standard C scanner
+ * long_align - if true (-Ca flag), favor long-word alignment.
+ * use_read - if true (-f, -F, or -Cr) then use read() for scanner input;
+ * otherwise, use fread().
+ * yytext_is_array - if true (i.e., %array directive), then declare
+ * yytext as a array instead of a character pointer. Nice and inefficient.
+ * do_yywrap - do yywrap() processing on EOF. If false, EOF treated as
+ * "no more files".
+ * csize - size of character set for the scanner we're generating;
+ * 128 for 7-bit chars and 256 for 8-bit
+ * yymore_used - if true, yymore() is used in input rules
+ * reject - if true, generate back-up tables for REJECT macro
+ * real_reject - if true, scanner really uses REJECT (as opposed to just
+ * having "reject" set for variable trailing context)
+ * continued_action - true if this rule's action is to "fall through" to
+ * the next rule's action (i.e., the '|' action)
+ * in_rule - true if we're inside an individual rule, false if not.
+ * yymore_really_used - whether to treat yymore() as really used, regardless
+ * of what we think based on references to it in the user's actions.
+ * reject_really_used - same for REJECT
+ */
+
+extern int printstats, syntaxerror, eofseen, ddebug, trace, nowarn, spprdflt;
+extern int interactive, caseins, lex_compat, do_yylineno;
+extern int useecs, fulltbl, usemecs, fullspd;
+extern int gen_line_dirs, performance_report, backing_up_report;
+extern int C_plus_plus, long_align, use_read, yytext_is_array, do_yywrap;
+extern int csize;
+extern int yymore_used, reject, real_reject, continued_action, in_rule;
+
+extern int yymore_really_used, reject_really_used;
+
+
+/* Variables used in the flex input routines:
+ * datapos - characters on current output line
+ * dataline - number of contiguous lines of data in current data
+ * statement. Used to generate readable -f output
+ * linenum - current input line number
+ * out_linenum - current output line number
+ * skelfile - the skeleton file
+ * skel - compiled-in skeleton array
+ * skel_ind - index into "skel" array, if skelfile is nil
+ * yyin - input file
+ * backing_up_file - file to summarize backing-up states to
+ * infilename - name of input file
+ * outfilename - name of output file
+ * did_outfilename - whether outfilename was explicitly set
+ * prefix - the prefix used for externally visible names ("yy" by default)
+ * yyclass - yyFlexLexer subclass to use for YY_DECL
+ * do_stdinit - whether to initialize yyin/yyout to stdin/stdout
+ * use_stdout - the -t flag
+ * input_files - array holding names of input files
+ * num_input_files - size of input_files array
+ * program_name - name with which program was invoked
+ *
+ * action_array - array to hold the rule actions
+ * action_size - size of action_array
+ * defs1_offset - index where the user's section 1 definitions start
+ * in action_array
+ * prolog_offset - index where the prolog starts in action_array
+ * action_offset - index where the non-prolog starts in action_array
+ * action_index - index where the next action should go, with respect
+ * to "action_array"
+ */
+
+extern int datapos, dataline, linenum, out_linenum;
+extern FILE *skelfile, *yyin, *backing_up_file;
+extern const char *skel[];
+extern int skel_ind;
+extern char *infilename, *outfilename;
+extern int did_outfilename;
+extern char *prefix, *yyclass;
+extern int do_stdinit, use_stdout;
+extern char **input_files;
+extern int num_input_files;
+extern char *program_name;
+
+extern char *action_array;
+extern int action_size;
+extern int defs1_offset, prolog_offset, action_offset, action_index;
+
+
+/* Variables for stack of states having only one out-transition:
+ * onestate - state number
+ * onesym - transition symbol
+ * onenext - target state
+ * onedef - default base entry
+ * onesp - stack pointer
+ */
+
+extern int onestate[ONE_STACK_SIZE], onesym[ONE_STACK_SIZE];
+extern int onenext[ONE_STACK_SIZE], onedef[ONE_STACK_SIZE], onesp;
+
+
+/* Variables for nfa machine data:
+ * current_mns - current maximum on number of NFA states
+ * num_rules - number of the last accepting state; also is number of
+ * rules created so far
+ * num_eof_rules - number of <<EOF>> rules
+ * default_rule - number of the default rule
+ * current_max_rules - current maximum number of rules
+ * lastnfa - last nfa state number created
+ * firstst - physically the first state of a fragment
+ * lastst - last physical state of fragment
+ * finalst - last logical state of fragment
+ * transchar - transition character
+ * trans1 - transition state
+ * trans2 - 2nd transition state for epsilons
+ * accptnum - accepting number
+ * assoc_rule - rule associated with this NFA state (or 0 if none)
+ * state_type - a STATE_xxx type identifying whether the state is part
+ * of a normal rule, the leading state in a trailing context
+ * rule (i.e., the state which marks the transition from
+ * recognizing the text-to-be-matched to the beginning of
+ * the trailing context), or a subsequent state in a trailing
+ * context rule
+ * rule_type - a RULE_xxx type identifying whether this a ho-hum
+ * normal rule or one which has variable head & trailing
+ * context
+ * rule_linenum - line number associated with rule
+ * rule_useful - true if we've determined that the rule can be matched
+ */
+
+extern int current_mns, current_max_rules;
+extern int num_rules, num_eof_rules, default_rule, lastnfa;
+extern int *firstst, *lastst, *finalst, *transchar, *trans1, *trans2;
+extern int *accptnum, *assoc_rule, *state_type;
+extern int *rule_type, *rule_linenum, *rule_useful;
+
+/* Different types of states; values are useful as masks, as well, for
+ * routines like check_trailing_context().
+ */
+#define STATE_NORMAL 0x1
+#define STATE_TRAILING_CONTEXT 0x2
+
+/* Global holding current type of state we're making. */
+
+extern int current_state_type;
+
+/* Different types of rules. */
+#define RULE_NORMAL 0
+#define RULE_VARIABLE 1
+
+/* True if the input rules include a rule with both variable-length head
+ * and trailing context, false otherwise.
+ */
+extern int variable_trailing_context_rules;
+
+
+/* Variables for protos:
+ * numtemps - number of templates created
+ * numprots - number of protos created
+ * protprev - backlink to a more-recently used proto
+ * protnext - forward link to a less-recently used proto
+ * prottbl - base/def table entry for proto
+ * protcomst - common state of proto
+ * firstprot - number of the most recently used proto
+ * lastprot - number of the least recently used proto
+ * protsave contains the entire state array for protos
+ */
+
+extern int numtemps, numprots, protprev[MSP], protnext[MSP], prottbl[MSP];
+extern int protcomst[MSP], firstprot, lastprot, protsave[PROT_SAVE_SIZE];
+
+
+/* Variables for managing equivalence classes:
+ * numecs - number of equivalence classes
+ * nextecm - forward link of Equivalence Class members
+ * ecgroup - class number or backward link of EC members
+ * nummecs - number of meta-equivalence classes (used to compress
+ * templates)
+ * tecfwd - forward link of meta-equivalence classes members
+ * tecbck - backward link of MEC's
+ */
+
+/* Reserve enough room in the equivalence class arrays so that we
+ * can use the CSIZE'th element to hold equivalence class information
+ * for the NUL character. Later we'll move this information into
+ * the 0th element.
+ */
+extern int numecs, nextecm[CSIZE + 1], ecgroup[CSIZE + 1], nummecs;
+
+/* Meta-equivalence classes are indexed starting at 1, so it's possible
+ * that they will require positions from 1 .. CSIZE, i.e., CSIZE + 1
+ * slots total (since the arrays are 0-based). nextecm[] and ecgroup[]
+ * don't require the extra position since they're indexed from 1 .. CSIZE - 1.
+ */
+extern int tecfwd[CSIZE + 1], tecbck[CSIZE + 1];
+
+
+/* Variables for start conditions:
+ * lastsc - last start condition created
+ * current_max_scs - current limit on number of start conditions
+ * scset - set of rules active in start condition
+ * scbol - set of rules active only at the beginning of line in a s.c.
+ * scxclu - true if start condition is exclusive
+ * sceof - true if start condition has EOF rule
+ * scname - start condition name
+ */
+
+extern int lastsc, *scset, *scbol, *scxclu, *sceof;
+extern int current_max_scs;
+extern char **scname;
+
+
+/* Variables for dfa machine data:
+ * current_max_dfa_size - current maximum number of NFA states in DFA
+ * current_max_xpairs - current maximum number of non-template xtion pairs
+ * current_max_template_xpairs - current maximum number of template pairs
+ * current_max_dfas - current maximum number DFA states
+ * lastdfa - last dfa state number created
+ * nxt - state to enter upon reading character
+ * chk - check value to see if "nxt" applies
+ * tnxt - internal nxt table for templates
+ * base - offset into "nxt" for given state
+ * def - where to go if "chk" disallows "nxt" entry
+ * nultrans - NUL transition for each state
+ * NUL_ec - equivalence class of the NUL character
+ * tblend - last "nxt/chk" table entry being used
+ * firstfree - first empty entry in "nxt/chk" table
+ * dss - nfa state set for each dfa
+ * dfasiz - size of nfa state set for each dfa
+ * dfaacc - accepting set for each dfa state (if using REJECT), or accepting
+ * number, if not
+ * accsiz - size of accepting set for each dfa state
+ * dhash - dfa state hash value
+ * numas - number of DFA accepting states created; note that this
+ * is not necessarily the same value as num_rules, which is the analogous
+ * value for the NFA
+ * numsnpairs - number of state/nextstate transition pairs
+ * jambase - position in base/def where the default jam table starts
+ * jamstate - state number corresponding to "jam" state
+ * end_of_buffer_state - end-of-buffer dfa state number
+ */
+
+extern int current_max_dfa_size, current_max_xpairs;
+extern int current_max_template_xpairs, current_max_dfas;
+extern int lastdfa, *nxt, *chk, *tnxt;
+extern int *base, *def, *nultrans, NUL_ec, tblend, firstfree, **dss, *dfasiz;
+extern union dfaacc_union
+ {
+ int *dfaacc_set;
+ int dfaacc_state;
+ } *dfaacc;
+extern int *accsiz, *dhash, numas;
+extern int numsnpairs, jambase, jamstate;
+extern int end_of_buffer_state;
+
+/* Variables for ccl information:
+ * lastccl - ccl index of the last created ccl
+ * current_maxccls - current limit on the maximum number of unique ccl's
+ * cclmap - maps a ccl index to its set pointer
+ * ccllen - gives the length of a ccl
+ * cclng - true for a given ccl if the ccl is negated
+ * cclreuse - counts how many times a ccl is re-used
+ * current_max_ccl_tbl_size - current limit on number of characters needed
+ * to represent the unique ccl's
+ * ccltbl - holds the characters in each ccl - indexed by cclmap
+ */
+
+extern int lastccl, *cclmap, *ccllen, *cclng, cclreuse;
+extern int current_maxccls, current_max_ccl_tbl_size;
+extern Char *ccltbl;
+
+
+/* Variables for miscellaneous information:
+ * nmstr - last NAME scanned by the scanner
+ * sectnum - section number currently being parsed
+ * nummt - number of empty nxt/chk table entries
+ * hshcol - number of hash collisions detected by snstods
+ * dfaeql - number of times a newly created dfa was equal to an old one
+ * numeps - number of epsilon NFA states created
+ * eps2 - number of epsilon states which have 2 out-transitions
+ * num_reallocs - number of times it was necessary to realloc() a group
+ * of arrays
+ * tmpuses - number of DFA states that chain to templates
+ * totnst - total number of NFA states used to make DFA states
+ * peakpairs - peak number of transition pairs we had to store internally
+ * numuniq - number of unique transitions
+ * numdup - number of duplicate transitions
+ * hshsave - number of hash collisions saved by checking number of states
+ * num_backing_up - number of DFA states requiring backing up
+ * bol_needed - whether scanner needs beginning-of-line recognition
+ */
+
+extern char nmstr[MAXLINE];
+extern int sectnum, nummt, hshcol, dfaeql, numeps, eps2, num_reallocs;
+extern int tmpuses, totnst, peakpairs, numuniq, numdup, hshsave;
+extern int num_backing_up, bol_needed;
+
+void *allocate_array PROTO((int, size_t));
+void *reallocate_array PROTO((void*, int, size_t));
+
+void *flex_alloc PROTO((size_t));
+void *flex_realloc PROTO((void*, size_t));
+void flex_free PROTO((void*));
+
+#define allocate_integer_array(size) \
+ (int *) allocate_array( size, sizeof( int ) )
+
+#define reallocate_integer_array(array,size) \
+ (int *) reallocate_array( (void *) array, size, sizeof( int ) )
+
+#define allocate_int_ptr_array(size) \
+ (int **) allocate_array( size, sizeof( int * ) )
+
+#define allocate_char_ptr_array(size) \
+ (char **) allocate_array( size, sizeof( char * ) )
+
+#define allocate_dfaacc_union(size) \
+ (union dfaacc_union *) \
+ allocate_array( size, sizeof( union dfaacc_union ) )
+
+#define reallocate_int_ptr_array(array,size) \
+ (int **) reallocate_array( (void *) array, size, sizeof( int * ) )
+
+#define reallocate_char_ptr_array(array,size) \
+ (char **) reallocate_array( (void *) array, size, sizeof( char * ) )
+
+#define reallocate_dfaacc_union(array, size) \
+ (union dfaacc_union *) \
+ reallocate_array( (void *) array, size, sizeof( union dfaacc_union ) )
+
+#define allocate_character_array(size) \
+ (char *) allocate_array( size, sizeof( char ) )
+
+#define reallocate_character_array(array,size) \
+ (char *) reallocate_array( (void *) array, size, sizeof( char ) )
+
+#define allocate_Character_array(size) \
+ (Char *) allocate_array( size, sizeof( Char ) )
+
+#define reallocate_Character_array(array,size) \
+ (Char *) reallocate_array( (void *) array, size, sizeof( Char ) )
+
+
+/* Used to communicate between scanner and parser. The type should really
+ * be YYSTYPE, but we can't easily get our hands on it.
+ */
+extern int yylval;
+
+
+/* External functions that are cross-referenced among the flex source files. */
+
+
+/* from file ccl.c */
+
+extern void ccladd PROTO((int, int)); /* add a single character to a ccl */
+extern int cclinit PROTO((void)); /* make an empty ccl */
+extern void cclnegate PROTO((int)); /* negate a ccl */
+
+/* List the members of a set of characters in CCL form. */
+extern void list_character_set PROTO((FILE*, int[]));
+
+
+/* from file dfa.c */
+
+/* Check a DFA state for backing up. */
+extern void check_for_backing_up PROTO((int, int[]));
+
+/* Check to see if NFA state set constitutes "dangerous" trailing context. */
+extern void check_trailing_context PROTO((int*, int, int*, int));
+
+/* Construct the epsilon closure of a set of ndfa states. */
+extern int *epsclosure PROTO((int*, int*, int[], int*, int*));
+
+/* Increase the maximum number of dfas. */
+extern void increase_max_dfas PROTO((void));
+
+extern void ntod PROTO((void)); /* convert a ndfa to a dfa */
+
+/* Converts a set of ndfa states into a dfa state. */
+extern int snstods PROTO((int[], int, int[], int, int, int*));
+
+
+/* from file ecs.c */
+
+/* Convert character classes to set of equivalence classes. */
+extern void ccl2ecl PROTO((void));
+
+/* Associate equivalence class numbers with class members. */
+extern int cre8ecs PROTO((int[], int[], int));
+
+/* Update equivalence classes based on character class transitions. */
+extern void mkeccl PROTO((Char[], int, int[], int[], int, int));
+
+/* Create equivalence class for single character. */
+extern void mkechar PROTO((int, int[], int[]));
+
+
+/* from file gen.c */
+
+extern void do_indent PROTO((void)); /* indent to the current level */
+
+/* Generate the code to keep backing-up information. */
+extern void gen_backing_up PROTO((void));
+
+/* Generate the code to perform the backing up. */
+extern void gen_bu_action PROTO((void));
+
+/* Generate full speed compressed transition table. */
+extern void genctbl PROTO((void));
+
+/* Generate the code to find the action number. */
+extern void gen_find_action PROTO((void));
+
+extern void genftbl PROTO((void)); /* generate full transition table */
+
+/* Generate the code to find the next compressed-table state. */
+extern void gen_next_compressed_state PROTO((char*));
+
+/* Generate the code to find the next match. */
+extern void gen_next_match PROTO((void));
+
+/* Generate the code to find the next state. */
+extern void gen_next_state PROTO((int));
+
+/* Generate the code to make a NUL transition. */
+extern void gen_NUL_trans PROTO((void));
+
+/* Generate the code to find the start state. */
+extern void gen_start_state PROTO((void));
+
+/* Generate data statements for the transition tables. */
+extern void gentabs PROTO((void));
+
+/* Write out a formatted string at the current indentation level. */
+extern void indent_put2s PROTO((char[], char[]));
+
+/* Write out a string + newline at the current indentation level. */
+extern void indent_puts PROTO((char[]));
+
+extern void make_tables PROTO((void)); /* generate transition tables */
+
+
+/* from file main.c */
+
+extern void check_options PROTO((void));
+extern void flexend PROTO((int));
+extern void usage PROTO((void));
+
+
+/* from file misc.c */
+
+/* Add a #define to the action file. */
+extern void action_define PROTO(( char *defname, int value ));
+
+/* Add the given text to the stored actions. */
+extern void add_action PROTO(( char *new_text ));
+
+/* True if a string is all lower case. */
+extern int all_lower PROTO((register char *));
+
+/* True if a string is all upper case. */
+extern int all_upper PROTO((register char *));
+
+/* Bubble sort an integer array. */
+extern void bubble PROTO((int [], int));
+
+/* Check a character to make sure it's in the expected range. */
+extern void check_char PROTO((int c));
+
+/* Replace upper-case letter to lower-case. */
+extern Char clower PROTO((int));
+
+/* Returns a dynamically allocated copy of a string. */
+extern char *copy_string PROTO((register const char *));
+
+/* Returns a dynamically allocated copy of a (potentially) unsigned string. */
+extern Char *copy_unsigned_string PROTO((register Char *));
+
+/* Shell sort a character array. */
+extern void cshell PROTO((Char [], int, int));
+
+/* Finish up a block of data declarations. */
+extern void dataend PROTO((void));
+
+/* Flush generated data statements. */
+extern void dataflush PROTO((void));
+
+/* Report an error message and terminate. */
+extern void flexerror PROTO((const char[]));
+
+/* Report a fatal error message and terminate. */
+extern void flexfatal PROTO((const char[]));
+
+/* Convert a hexadecimal digit string to an integer value. */
+extern int htoi PROTO((Char[]));
+
+/* Report an error message formatted with one integer argument. */
+extern void lerrif PROTO((const char[], int));
+
+/* Report an error message formatted with one string argument. */
+extern void lerrsf PROTO((const char[], const char[]));
+
+/* Spit out a "#line" statement. */
+extern void line_directive_out PROTO((FILE*, int));
+
+/* Mark the current position in the action array as the end of the section 1
+ * user defs.
+ */
+extern void mark_defs1 PROTO((void));
+
+/* Mark the current position in the action array as the end of the prolog. */
+extern void mark_prolog PROTO((void));
+
+/* Generate a data statment for a two-dimensional array. */
+extern void mk2data PROTO((int));
+
+extern void mkdata PROTO((int)); /* generate a data statement */
+
+/* Return the integer represented by a string of digits. */
+extern int myctoi PROTO((char []));
+
+/* Return character corresponding to escape sequence. */
+extern Char myesc PROTO((Char[]));
+
+/* Convert an octal digit string to an integer value. */
+extern int otoi PROTO((Char [] ));
+
+/* Output a (possibly-formatted) string to the generated scanner. */
+extern void out PROTO((const char []));
+extern void out_dec PROTO((const char [], int));
+extern void out_dec2 PROTO((const char [], int, int));
+extern void out_hex PROTO((const char [], unsigned int));
+extern void out_line_count PROTO((const char []));
+extern void out_str PROTO((const char [], const char []));
+extern void out_str3
+ PROTO((const char [], const char [], const char [], const char []));
+extern void out_str_dec PROTO((const char [], const char [], int));
+extern void outc PROTO((int));
+extern void outn PROTO((const char []));
+
+/* Return a printable version of the given character, which might be
+ * 8-bit.
+ */
+extern char *readable_form PROTO((int));
+
+/* Write out one section of the skeleton file. */
+extern void skelout PROTO((void));
+
+/* Output a yy_trans_info structure. */
+extern void transition_struct_out PROTO((int, int));
+
+/* Only needed when using certain broken versions of bison to build parse.c. */
+extern void *yy_flex_xmalloc PROTO(( int ));
+
+/* Set a region of memory to 0. */
+extern void zero_out PROTO((char *, size_t));
+
+
+/* from file nfa.c */
+
+/* Add an accepting state to a machine. */
+extern void add_accept PROTO((int, int));
+
+/* Make a given number of copies of a singleton machine. */
+extern int copysingl PROTO((int, int));
+
+/* Debugging routine to write out an nfa. */
+extern void dumpnfa PROTO((int));
+
+/* Finish up the processing for a rule. */
+extern void finish_rule PROTO((int, int, int, int));
+
+/* Connect two machines together. */
+extern int link_machines PROTO((int, int));
+
+/* Mark each "beginning" state in a machine as being a "normal" (i.e.,
+ * not trailing context associated) state.
+ */
+extern void mark_beginning_as_normal PROTO((register int));
+
+/* Make a machine that branches to two machines. */
+extern int mkbranch PROTO((int, int));
+
+extern int mkclos PROTO((int)); /* convert a machine into a closure */
+extern int mkopt PROTO((int)); /* make a machine optional */
+
+/* Make a machine that matches either one of two machines. */
+extern int mkor PROTO((int, int));
+
+/* Convert a machine into a positive closure. */
+extern int mkposcl PROTO((int));
+
+extern int mkrep PROTO((int, int, int)); /* make a replicated machine */
+
+/* Create a state with a transition on a given symbol. */
+extern int mkstate PROTO((int));
+
+extern void new_rule PROTO((void)); /* initialize for a new rule */
+
+
+/* from file parse.y */
+
+/* Build the "<<EOF>>" action for the active start conditions. */
+extern void build_eof_action PROTO((void));
+
+/* Write out a message formatted with one string, pinpointing its location. */
+extern void format_pinpoint_message PROTO((char[], char[]));
+
+/* Write out a message, pinpointing its location. */
+extern void pinpoint_message PROTO((char[]));
+
+/* Write out a warning, pinpointing it at the given line. */
+extern void line_warning PROTO(( char[], int ));
+
+/* Write out a message, pinpointing it at the given line. */
+extern void line_pinpoint PROTO(( char[], int ));
+
+/* Report a formatted syntax error. */
+extern void format_synerr PROTO((char [], char[]));
+extern void synerr PROTO((char [])); /* report a syntax error */
+extern void format_warn PROTO((char [], char[]));
+extern void warn PROTO((char [])); /* report a warning */
+extern void yyerror PROTO((char [])); /* report a parse error */
+extern int yyparse PROTO((void)); /* the YACC parser */
+
+
+/* from file scan.l */
+
+/* The Flex-generated scanner for flex. */
+extern int flexscan PROTO((void));
+
+/* Open the given file (if NULL, stdin) for scanning. */
+extern void set_input_file PROTO((char*));
+
+/* Wrapup a file in the lexical analyzer. */
+extern int yywrap PROTO((void));
+
+
+/* from file sym.c */
+
+/* Add symbol and definitions to symbol table. */
+extern int addsym PROTO((register char[], char*, int, hash_table, int));
+
+/* Save the text of a character class. */
+extern void cclinstal PROTO ((Char [], int));
+
+/* Lookup the number associated with character class. */
+extern int ccllookup PROTO((Char []));
+
+/* Find symbol in symbol table. */
+extern struct hash_entry *findsym PROTO((register char[], hash_table, int ));
+
+extern void ndinstal PROTO((char[], Char[])); /* install a name definition */
+extern Char *ndlookup PROTO((char[])); /* lookup a name definition */
+
+/* Increase maximum number of SC's. */
+extern void scextend PROTO((void));
+extern void scinstal PROTO((char[], int)); /* make a start condition */
+
+/* Lookup the number associated with a start condition. */
+extern int sclookup PROTO((char[]));
+
+
+/* from file tblcmp.c */
+
+/* Build table entries for dfa state. */
+extern void bldtbl PROTO((int[], int, int, int, int));
+
+extern void cmptmps PROTO((void)); /* compress template table entries */
+extern void expand_nxt_chk PROTO((void)); /* increase nxt/chk arrays */
+/* Finds a space in the table for a state to be placed. */
+extern int find_table_space PROTO((int*, int));
+extern void inittbl PROTO((void)); /* initialize transition tables */
+/* Make the default, "jam" table entries. */
+extern void mkdeftbl PROTO((void));
+
+/* Create table entries for a state (or state fragment) which has
+ * only one out-transition.
+ */
+extern void mk1tbl PROTO((int, int, int, int));
+
+/* Place a state into full speed transition table. */
+extern void place_state PROTO((int*, int, int));
+
+/* Save states with only one out-transition to be processed later. */
+extern void stack1 PROTO((int, int, int, int));
+
+
+/* from file yylex.c */
+
+extern int yylex PROTO((void));
diff --git a/Tools/android/flex-2.5.4a/gen.c b/Tools/android/flex-2.5.4a/gen.c
new file mode 100644
index 0000000..a6159f0
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/gen.c
@@ -0,0 +1,1625 @@
+/* gen - actual generation (writing) of flex scanners */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/gen.c,v 2.56 96/05/25 20:43:38 vern Exp $ */
+
+#include "flexdef.h"
+
+
+/* declare functions that have forward references */
+
+void gen_next_state PROTO((int));
+void genecs PROTO((void));
+void indent_put2s PROTO((char [], char []));
+void indent_puts PROTO((char []));
+
+
+static int indent_level = 0; /* each level is 8 spaces */
+
+#define indent_up() (++indent_level)
+#define indent_down() (--indent_level)
+#define set_indent(indent_val) indent_level = indent_val
+
+/* Almost everything is done in terms of arrays starting at 1, so provide
+ * a null entry for the zero element of all C arrays. (The exception
+ * to this is that the fast table representation generally uses the
+ * 0 elements of its arrays, too.)
+ */
+static char C_int_decl[] = "static yyconst int %s[%d] =\n { 0,\n";
+static char C_short_decl[] = "static yyconst short int %s[%d] =\n { 0,\n";
+static char C_long_decl[] = "static yyconst long int %s[%d] =\n { 0,\n";
+static char C_state_decl[] =
+ "static yyconst yy_state_type %s[%d] =\n { 0,\n";
+
+
+/* Indent to the current level. */
+
+void do_indent()
+ {
+ register int i = indent_level * 8;
+
+ while ( i >= 8 )
+ {
+ outc( '\t' );
+ i -= 8;
+ }
+
+ while ( i > 0 )
+ {
+ outc( ' ' );
+ --i;
+ }
+ }
+
+
+/* Generate the code to keep backing-up information. */
+
+void gen_backing_up()
+ {
+ if ( reject || num_backing_up == 0 )
+ return;
+
+ if ( fullspd )
+ indent_puts( "if ( yy_current_state[-1].yy_nxt )" );
+ else
+ indent_puts( "if ( yy_accept[yy_current_state] )" );
+
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_last_accepting_state = yy_current_state;" );
+ indent_puts( "yy_last_accepting_cpos = yy_cp;" );
+ indent_puts( "}" );
+ indent_down();
+ }
+
+
+/* Generate the code to perform the backing up. */
+
+void gen_bu_action()
+ {
+ if ( reject || num_backing_up == 0 )
+ return;
+
+ set_indent( 3 );
+
+ indent_puts( "case 0: /* must back up */" );
+ indent_puts( "/* undo the effects of YY_DO_BEFORE_ACTION */" );
+ indent_puts( "*yy_cp = yy_hold_char;" );
+
+ if ( fullspd || fulltbl )
+ indent_puts( "yy_cp = yy_last_accepting_cpos + 1;" );
+ else
+ /* Backing-up info for compressed tables is taken \after/
+ * yy_cp has been incremented for the next state.
+ */
+ indent_puts( "yy_cp = yy_last_accepting_cpos;" );
+
+ indent_puts( "yy_current_state = yy_last_accepting_state;" );
+ indent_puts( "goto yy_find_action;" );
+ outc( '\n' );
+
+ set_indent( 0 );
+ }
+
+
+/* genctbl - generates full speed compressed transition table */
+
+void genctbl()
+ {
+ register int i;
+ int end_of_buffer_action = num_rules + 1;
+
+ /* Table of verify for transition and offset to next state. */
+ out_dec( "static yyconst struct yy_trans_info yy_transition[%d] =\n",
+ tblend + numecs + 1 );
+ outn( " {" );
+
+ /* We want the transition to be represented as the offset to the
+ * next state, not the actual state number, which is what it currently
+ * is. The offset is base[nxt[i]] - (base of current state)]. That's
+ * just the difference between the starting points of the two involved
+ * states (to - from).
+ *
+ * First, though, we need to find some way to put in our end-of-buffer
+ * flags and states. We do this by making a state with absolutely no
+ * transitions. We put it at the end of the table.
+ */
+
+ /* We need to have room in nxt/chk for two more slots: One for the
+ * action and one for the end-of-buffer transition. We now *assume*
+ * that we're guaranteed the only character we'll try to index this
+ * nxt/chk pair with is EOB, i.e., 0, so we don't have to make sure
+ * there's room for jam entries for other characters.
+ */
+
+ while ( tblend + 2 >= current_max_xpairs )
+ expand_nxt_chk();
+
+ while ( lastdfa + 1 >= current_max_dfas )
+ increase_max_dfas();
+
+ base[lastdfa + 1] = tblend + 2;
+ nxt[tblend + 1] = end_of_buffer_action;
+ chk[tblend + 1] = numecs + 1;
+ chk[tblend + 2] = 1; /* anything but EOB */
+
+ /* So that "make test" won't show arb. differences. */
+ nxt[tblend + 2] = 0;
+
+ /* Make sure every state has an end-of-buffer transition and an
+ * action #.
+ */
+ for ( i = 0; i <= lastdfa; ++i )
+ {
+ int anum = dfaacc[i].dfaacc_state;
+ int offset = base[i];
+
+ chk[offset] = EOB_POSITION;
+ chk[offset - 1] = ACTION_POSITION;
+ nxt[offset - 1] = anum; /* action number */
+ }
+
+ for ( i = 0; i <= tblend; ++i )
+ {
+ if ( chk[i] == EOB_POSITION )
+ transition_struct_out( 0, base[lastdfa + 1] - i );
+
+ else if ( chk[i] == ACTION_POSITION )
+ transition_struct_out( 0, nxt[i] );
+
+ else if ( chk[i] > numecs || chk[i] == 0 )
+ transition_struct_out( 0, 0 ); /* unused slot */
+
+ else /* verify, transition */
+ transition_struct_out( chk[i],
+ base[nxt[i]] - (i - chk[i]) );
+ }
+
+
+ /* Here's the final, end-of-buffer state. */
+ transition_struct_out( chk[tblend + 1], nxt[tblend + 1] );
+ transition_struct_out( chk[tblend + 2], nxt[tblend + 2] );
+
+ outn( " };\n" );
+
+ /* Table of pointers to start states. */
+ out_dec(
+ "static yyconst struct yy_trans_info *yy_start_state_list[%d] =\n",
+ lastsc * 2 + 1 );
+ outn( " {" ); /* } so vi doesn't get confused */
+
+ for ( i = 0; i <= lastsc * 2; ++i )
+ out_dec( " &yy_transition[%d],\n", base[i] );
+
+ dataend();
+
+ if ( useecs )
+ genecs();
+ }
+
+
+/* Generate equivalence-class tables. */
+
+void genecs()
+ {
+ register int i, j;
+ int numrows;
+
+ out_str_dec( C_int_decl, "yy_ec", csize );
+
+ for ( i = 1; i < csize; ++i )
+ {
+ if ( caseins && (i >= 'A') && (i <= 'Z') )
+ ecgroup[i] = ecgroup[clower( i )];
+
+ ecgroup[i] = ABS( ecgroup[i] );
+ mkdata( ecgroup[i] );
+ }
+
+ dataend();
+
+ if ( trace )
+ {
+ fputs( _( "\n\nEquivalence Classes:\n\n" ), stderr );
+
+ numrows = csize / 8;
+
+ for ( j = 0; j < numrows; ++j )
+ {
+ for ( i = j; i < csize; i = i + numrows )
+ {
+ fprintf( stderr, "%4s = %-2d",
+ readable_form( i ), ecgroup[i] );
+
+ putc( ' ', stderr );
+ }
+
+ putc( '\n', stderr );
+ }
+ }
+ }
+
+
+/* Generate the code to find the action number. */
+
+void gen_find_action()
+ {
+ if ( fullspd )
+ indent_puts( "yy_act = yy_current_state[-1].yy_nxt;" );
+
+ else if ( fulltbl )
+ indent_puts( "yy_act = yy_accept[yy_current_state];" );
+
+ else if ( reject )
+ {
+ indent_puts( "yy_current_state = *--yy_state_ptr;" );
+ indent_puts( "yy_lp = yy_accept[yy_current_state];" );
+
+ outn(
+ "find_rule: /* we branch to this label when backing up */" );
+
+ indent_puts(
+ "for ( ; ; ) /* until we find what rule we matched */" );
+
+ indent_up();
+
+ indent_puts( "{" );
+
+ indent_puts(
+ "if ( yy_lp && yy_lp < yy_accept[yy_current_state + 1] )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_act = yy_acclist[yy_lp];" );
+
+ if ( variable_trailing_context_rules )
+ {
+ indent_puts( "if ( yy_act & YY_TRAILING_HEAD_MASK ||" );
+ indent_puts( " yy_looking_for_trail_begin )" );
+ indent_up();
+ indent_puts( "{" );
+
+ indent_puts(
+ "if ( yy_act == yy_looking_for_trail_begin )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_looking_for_trail_begin = 0;" );
+ indent_puts( "yy_act &= ~YY_TRAILING_HEAD_MASK;" );
+ indent_puts( "break;" );
+ indent_puts( "}" );
+ indent_down();
+
+ indent_puts( "}" );
+ indent_down();
+
+ indent_puts( "else if ( yy_act & YY_TRAILING_MASK )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts(
+ "yy_looking_for_trail_begin = yy_act & ~YY_TRAILING_MASK;" );
+ indent_puts(
+ "yy_looking_for_trail_begin |= YY_TRAILING_HEAD_MASK;" );
+
+ if ( real_reject )
+ {
+ /* Remember matched text in case we back up
+ * due to REJECT.
+ */
+ indent_puts( "yy_full_match = yy_cp;" );
+ indent_puts( "yy_full_state = yy_state_ptr;" );
+ indent_puts( "yy_full_lp = yy_lp;" );
+ }
+
+ indent_puts( "}" );
+ indent_down();
+
+ indent_puts( "else" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_full_match = yy_cp;" );
+ indent_puts( "yy_full_state = yy_state_ptr;" );
+ indent_puts( "yy_full_lp = yy_lp;" );
+ indent_puts( "break;" );
+ indent_puts( "}" );
+ indent_down();
+
+ indent_puts( "++yy_lp;" );
+ indent_puts( "goto find_rule;" );
+ }
+
+ else
+ {
+ /* Remember matched text in case we back up due to
+ * trailing context plus REJECT.
+ */
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_full_match = yy_cp;" );
+ indent_puts( "break;" );
+ indent_puts( "}" );
+ indent_down();
+ }
+
+ indent_puts( "}" );
+ indent_down();
+
+ indent_puts( "--yy_cp;" );
+
+ /* We could consolidate the following two lines with those at
+ * the beginning, but at the cost of complaints that we're
+ * branching inside a loop.
+ */
+ indent_puts( "yy_current_state = *--yy_state_ptr;" );
+ indent_puts( "yy_lp = yy_accept[yy_current_state];" );
+
+ indent_puts( "}" );
+
+ indent_down();
+ }
+
+ else
+ { /* compressed */
+ indent_puts( "yy_act = yy_accept[yy_current_state];" );
+
+ if ( interactive && ! reject )
+ {
+ /* Do the guaranteed-needed backing up to figure out
+ * the match.
+ */
+ indent_puts( "if ( yy_act == 0 )" );
+ indent_up();
+ indent_puts( "{ /* have to back up */" );
+ indent_puts( "yy_cp = yy_last_accepting_cpos;" );
+ indent_puts(
+ "yy_current_state = yy_last_accepting_state;" );
+ indent_puts( "yy_act = yy_accept[yy_current_state];" );
+ indent_puts( "}" );
+ indent_down();
+ }
+ }
+ }
+
+
+/* genftbl - generate full transition table */
+
+void genftbl()
+ {
+ register int i;
+ int end_of_buffer_action = num_rules + 1;
+
+ out_str_dec( long_align ? C_long_decl : C_short_decl,
+ "yy_accept", lastdfa + 1 );
+
+ dfaacc[end_of_buffer_state].dfaacc_state = end_of_buffer_action;
+
+ for ( i = 1; i <= lastdfa; ++i )
+ {
+ register int anum = dfaacc[i].dfaacc_state;
+
+ mkdata( anum );
+
+ if ( trace && anum )
+ fprintf( stderr, _( "state # %d accepts: [%d]\n" ),
+ i, anum );
+ }
+
+ dataend();
+
+ if ( useecs )
+ genecs();
+
+ /* Don't have to dump the actual full table entries - they were
+ * created on-the-fly.
+ */
+ }
+
+
+/* Generate the code to find the next compressed-table state. */
+
+void gen_next_compressed_state( char_map )
+char *char_map;
+ {
+ indent_put2s( "register YY_CHAR yy_c = %s;", char_map );
+
+ /* Save the backing-up info \before/ computing the next state
+ * because we always compute one more state than needed - we
+ * always proceed until we reach a jam state
+ */
+ gen_backing_up();
+
+ indent_puts(
+"while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_current_state = (int) yy_def[yy_current_state];" );
+
+ if ( usemecs )
+ {
+ /* We've arrange it so that templates are never chained
+ * to one another. This means we can afford to make a
+ * very simple test to see if we need to convert to
+ * yy_c's meta-equivalence class without worrying
+ * about erroneously looking up the meta-equivalence
+ * class twice
+ */
+ do_indent();
+
+ /* lastdfa + 2 is the beginning of the templates */
+ out_dec( "if ( yy_current_state >= %d )\n", lastdfa + 2 );
+
+ indent_up();
+ indent_puts( "yy_c = yy_meta[(unsigned int) yy_c];" );
+ indent_down();
+ }
+
+ indent_puts( "}" );
+ indent_down();
+
+ indent_puts(
+"yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];" );
+ }
+
+
+/* Generate the code to find the next match. */
+
+void gen_next_match()
+ {
+ /* NOTE - changes in here should be reflected in gen_next_state() and
+ * gen_NUL_trans().
+ */
+ char *char_map = useecs ?
+ "yy_ec[YY_SC_TO_UI(*yy_cp)]" :
+ "YY_SC_TO_UI(*yy_cp)";
+
+ char *char_map_2 = useecs ?
+ "yy_ec[YY_SC_TO_UI(*++yy_cp)]" :
+ "YY_SC_TO_UI(*++yy_cp)";
+
+ if ( fulltbl )
+ {
+ indent_put2s(
+ "while ( (yy_current_state = yy_nxt[yy_current_state][%s]) > 0 )",
+ char_map );
+
+ indent_up();
+
+ if ( num_backing_up > 0 )
+ {
+ indent_puts( "{" ); /* } for vi */
+ gen_backing_up();
+ outc( '\n' );
+ }
+
+ indent_puts( "++yy_cp;" );
+
+ if ( num_backing_up > 0 )
+ /* { for vi */
+ indent_puts( "}" );
+
+ indent_down();
+
+ outc( '\n' );
+ indent_puts( "yy_current_state = -yy_current_state;" );
+ }
+
+ else if ( fullspd )
+ {
+ indent_puts( "{" ); /* } for vi */
+ indent_puts(
+ "register yyconst struct yy_trans_info *yy_trans_info;\n" );
+ indent_puts( "register YY_CHAR yy_c;\n" );
+ indent_put2s( "for ( yy_c = %s;", char_map );
+ indent_puts(
+ " (yy_trans_info = &yy_current_state[(unsigned int) yy_c])->" );
+ indent_puts( "yy_verify == yy_c;" );
+ indent_put2s( " yy_c = %s )", char_map_2 );
+
+ indent_up();
+
+ if ( num_backing_up > 0 )
+ indent_puts( "{" ); /* } for vi */
+
+ indent_puts( "yy_current_state += yy_trans_info->yy_nxt;" );
+
+ if ( num_backing_up > 0 )
+ {
+ outc( '\n' );
+ gen_backing_up(); /* { for vi */
+ indent_puts( "}" );
+ }
+
+ indent_down(); /* { for vi */
+ indent_puts( "}" );
+ }
+
+ else
+ { /* compressed */
+ indent_puts( "do" );
+
+ indent_up();
+ indent_puts( "{" ); /* } for vi */
+
+ gen_next_state( false );
+
+ indent_puts( "++yy_cp;" );
+
+ /* { for vi */
+ indent_puts( "}" );
+ indent_down();
+
+ do_indent();
+
+ if ( interactive )
+ out_dec( "while ( yy_base[yy_current_state] != %d );\n",
+ jambase );
+ else
+ out_dec( "while ( yy_current_state != %d );\n",
+ jamstate );
+
+ if ( ! reject && ! interactive )
+ {
+ /* Do the guaranteed-needed backing up to figure out
+ * the match.
+ */
+ indent_puts( "yy_cp = yy_last_accepting_cpos;" );
+ indent_puts(
+ "yy_current_state = yy_last_accepting_state;" );
+ }
+ }
+ }
+
+
+/* Generate the code to find the next state. */
+
+void gen_next_state( worry_about_NULs )
+int worry_about_NULs;
+ { /* NOTE - changes in here should be reflected in gen_next_match() */
+ char char_map[256];
+
+ if ( worry_about_NULs && ! nultrans )
+ {
+ if ( useecs )
+ (void) sprintf( char_map,
+ "(*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : %d)",
+ NUL_ec );
+ else
+ (void) sprintf( char_map,
+ "(*yy_cp ? YY_SC_TO_UI(*yy_cp) : %d)", NUL_ec );
+ }
+
+ else
+ strcpy( char_map, useecs ?
+ "yy_ec[YY_SC_TO_UI(*yy_cp)]" : "YY_SC_TO_UI(*yy_cp)" );
+
+ if ( worry_about_NULs && nultrans )
+ {
+ if ( ! fulltbl && ! fullspd )
+ /* Compressed tables back up *before* they match. */
+ gen_backing_up();
+
+ indent_puts( "if ( *yy_cp )" );
+ indent_up();
+ indent_puts( "{" ); /* } for vi */
+ }
+
+ if ( fulltbl )
+ indent_put2s(
+ "yy_current_state = yy_nxt[yy_current_state][%s];",
+ char_map );
+
+ else if ( fullspd )
+ indent_put2s(
+ "yy_current_state += yy_current_state[%s].yy_nxt;",
+ char_map );
+
+ else
+ gen_next_compressed_state( char_map );
+
+ if ( worry_about_NULs && nultrans )
+ {
+ /* { for vi */
+ indent_puts( "}" );
+ indent_down();
+ indent_puts( "else" );
+ indent_up();
+ indent_puts(
+ "yy_current_state = yy_NUL_trans[yy_current_state];" );
+ indent_down();
+ }
+
+ if ( fullspd || fulltbl )
+ gen_backing_up();
+
+ if ( reject )
+ indent_puts( "*yy_state_ptr++ = yy_current_state;" );
+ }
+
+
+/* Generate the code to make a NUL transition. */
+
+void gen_NUL_trans()
+ { /* NOTE - changes in here should be reflected in gen_next_match() */
+ /* Only generate a definition for "yy_cp" if we'll generate code
+ * that uses it. Otherwise lint and the like complain.
+ */
+ int need_backing_up = (num_backing_up > 0 && ! reject);
+
+ if ( need_backing_up && (! nultrans || fullspd || fulltbl) )
+ /* We're going to need yy_cp lying around for the call
+ * below to gen_backing_up().
+ */
+ indent_puts( "register char *yy_cp = yy_c_buf_p;" );
+
+ outc( '\n' );
+
+ if ( nultrans )
+ {
+ indent_puts(
+ "yy_current_state = yy_NUL_trans[yy_current_state];" );
+ indent_puts( "yy_is_jam = (yy_current_state == 0);" );
+ }
+
+ else if ( fulltbl )
+ {
+ do_indent();
+ out_dec( "yy_current_state = yy_nxt[yy_current_state][%d];\n",
+ NUL_ec );
+ indent_puts( "yy_is_jam = (yy_current_state <= 0);" );
+ }
+
+ else if ( fullspd )
+ {
+ do_indent();
+ out_dec( "register int yy_c = %d;\n", NUL_ec );
+
+ indent_puts(
+ "register yyconst struct yy_trans_info *yy_trans_info;\n" );
+ indent_puts(
+ "yy_trans_info = &yy_current_state[(unsigned int) yy_c];" );
+ indent_puts( "yy_current_state += yy_trans_info->yy_nxt;" );
+
+ indent_puts(
+ "yy_is_jam = (yy_trans_info->yy_verify != yy_c);" );
+ }
+
+ else
+ {
+ char NUL_ec_str[20];
+
+ (void) sprintf( NUL_ec_str, "%d", NUL_ec );
+ gen_next_compressed_state( NUL_ec_str );
+
+ do_indent();
+ out_dec( "yy_is_jam = (yy_current_state == %d);\n", jamstate );
+
+ if ( reject )
+ {
+ /* Only stack this state if it's a transition we
+ * actually make. If we stack it on a jam, then
+ * the state stack and yy_c_buf_p get out of sync.
+ */
+ indent_puts( "if ( ! yy_is_jam )" );
+ indent_up();
+ indent_puts( "*yy_state_ptr++ = yy_current_state;" );
+ indent_down();
+ }
+ }
+
+ /* If we've entered an accepting state, back up; note that
+ * compressed tables have *already* done such backing up, so
+ * we needn't bother with it again.
+ */
+ if ( need_backing_up && (fullspd || fulltbl) )
+ {
+ outc( '\n' );
+ indent_puts( "if ( ! yy_is_jam )" );
+ indent_up();
+ indent_puts( "{" );
+ gen_backing_up();
+ indent_puts( "}" );
+ indent_down();
+ }
+ }
+
+
+/* Generate the code to find the start state. */
+
+void gen_start_state()
+ {
+ if ( fullspd )
+ {
+ if ( bol_needed )
+ {
+ indent_puts(
+ "yy_current_state = yy_start_state_list[yy_start + YY_AT_BOL()];" );
+ }
+ else
+ indent_puts(
+ "yy_current_state = yy_start_state_list[yy_start];" );
+ }
+
+ else
+ {
+ indent_puts( "yy_current_state = yy_start;" );
+
+ if ( bol_needed )
+ indent_puts( "yy_current_state += YY_AT_BOL();" );
+
+ if ( reject )
+ {
+ /* Set up for storing up states. */
+ indent_puts( "yy_state_ptr = yy_state_buf;" );
+ indent_puts( "*yy_state_ptr++ = yy_current_state;" );
+ }
+ }
+ }
+
+
+/* gentabs - generate data statements for the transition tables */
+
+void gentabs()
+ {
+ int i, j, k, *accset, nacc, *acc_array, total_states;
+ int end_of_buffer_action = num_rules + 1;
+
+ acc_array = allocate_integer_array( current_max_dfas );
+ nummt = 0;
+
+ /* The compressed table format jams by entering the "jam state",
+ * losing information about the previous state in the process.
+ * In order to recover the previous state, we effectively need
+ * to keep backing-up information.
+ */
+ ++num_backing_up;
+
+ if ( reject )
+ {
+ /* Write out accepting list and pointer list.
+ *
+ * First we generate the "yy_acclist" array. In the process,
+ * we compute the indices that will go into the "yy_accept"
+ * array, and save the indices in the dfaacc array.
+ */
+ int EOB_accepting_list[2];
+
+ /* Set up accepting structures for the End Of Buffer state. */
+ EOB_accepting_list[0] = 0;
+ EOB_accepting_list[1] = end_of_buffer_action;
+ accsiz[end_of_buffer_state] = 1;
+ dfaacc[end_of_buffer_state].dfaacc_set = EOB_accepting_list;
+
+ out_str_dec( long_align ? C_long_decl : C_short_decl,
+ "yy_acclist", MAX( numas, 1 ) + 1 );
+
+ j = 1; /* index into "yy_acclist" array */
+
+ for ( i = 1; i <= lastdfa; ++i )
+ {
+ acc_array[i] = j;
+
+ if ( accsiz[i] != 0 )
+ {
+ accset = dfaacc[i].dfaacc_set;
+ nacc = accsiz[i];
+
+ if ( trace )
+ fprintf( stderr,
+ _( "state # %d accepts: " ),
+ i );
+
+ for ( k = 1; k <= nacc; ++k )
+ {
+ int accnum = accset[k];
+
+ ++j;
+
+ if ( variable_trailing_context_rules &&
+ ! (accnum & YY_TRAILING_HEAD_MASK) &&
+ accnum > 0 && accnum <= num_rules &&
+ rule_type[accnum] == RULE_VARIABLE )
+ {
+ /* Special hack to flag
+ * accepting number as part
+ * of trailing context rule.
+ */
+ accnum |= YY_TRAILING_MASK;
+ }
+
+ mkdata( accnum );
+
+ if ( trace )
+ {
+ fprintf( stderr, "[%d]",
+ accset[k] );
+
+ if ( k < nacc )
+ fputs( ", ", stderr );
+ else
+ putc( '\n', stderr );
+ }
+ }
+ }
+ }
+
+ /* add accepting number for the "jam" state */
+ acc_array[i] = j;
+
+ dataend();
+ }
+
+ else
+ {
+ dfaacc[end_of_buffer_state].dfaacc_state = end_of_buffer_action;
+
+ for ( i = 1; i <= lastdfa; ++i )
+ acc_array[i] = dfaacc[i].dfaacc_state;
+
+ /* add accepting number for jam state */
+ acc_array[i] = 0;
+ }
+
+ /* Spit out "yy_accept" array. If we're doing "reject", it'll be
+ * pointers into the "yy_acclist" array. Otherwise it's actual
+ * accepting numbers. In either case, we just dump the numbers.
+ */
+
+ /* "lastdfa + 2" is the size of "yy_accept"; includes room for C arrays
+ * beginning at 0 and for "jam" state.
+ */
+ k = lastdfa + 2;
+
+ if ( reject )
+ /* We put a "cap" on the table associating lists of accepting
+ * numbers with state numbers. This is needed because we tell
+ * where the end of an accepting list is by looking at where
+ * the list for the next state starts.
+ */
+ ++k;
+
+ out_str_dec( long_align ? C_long_decl : C_short_decl, "yy_accept", k );
+
+ for ( i = 1; i <= lastdfa; ++i )
+ {
+ mkdata( acc_array[i] );
+
+ if ( ! reject && trace && acc_array[i] )
+ fprintf( stderr, _( "state # %d accepts: [%d]\n" ),
+ i, acc_array[i] );
+ }
+
+ /* Add entry for "jam" state. */
+ mkdata( acc_array[i] );
+
+ if ( reject )
+ /* Add "cap" for the list. */
+ mkdata( acc_array[i] );
+
+ dataend();
+
+ if ( useecs )
+ genecs();
+
+ if ( usemecs )
+ {
+ /* Write out meta-equivalence classes (used to index
+ * templates with).
+ */
+
+ if ( trace )
+ fputs( _( "\n\nMeta-Equivalence Classes:\n" ),
+ stderr );
+
+ out_str_dec( C_int_decl, "yy_meta", numecs + 1 );
+
+ for ( i = 1; i <= numecs; ++i )
+ {
+ if ( trace )
+ fprintf( stderr, "%d = %d\n",
+ i, ABS( tecbck[i] ) );
+
+ mkdata( ABS( tecbck[i] ) );
+ }
+
+ dataend();
+ }
+
+ total_states = lastdfa + numtemps;
+
+ out_str_dec( (tblend >= MAX_SHORT || long_align) ?
+ C_long_decl : C_short_decl,
+ "yy_base", total_states + 1 );
+
+ for ( i = 1; i <= lastdfa; ++i )
+ {
+ register int d = def[i];
+
+ if ( base[i] == JAMSTATE )
+ base[i] = jambase;
+
+ if ( d == JAMSTATE )
+ def[i] = jamstate;
+
+ else if ( d < 0 )
+ {
+ /* Template reference. */
+ ++tmpuses;
+ def[i] = lastdfa - d + 1;
+ }
+
+ mkdata( base[i] );
+ }
+
+ /* Generate jam state's base index. */
+ mkdata( base[i] );
+
+ for ( ++i /* skip jam state */; i <= total_states; ++i )
+ {
+ mkdata( base[i] );
+ def[i] = jamstate;
+ }
+
+ dataend();
+
+ out_str_dec( (total_states >= MAX_SHORT || long_align) ?
+ C_long_decl : C_short_decl,
+ "yy_def", total_states + 1 );
+
+ for ( i = 1; i <= total_states; ++i )
+ mkdata( def[i] );
+
+ dataend();
+
+ out_str_dec( (total_states >= MAX_SHORT || long_align) ?
+ C_long_decl : C_short_decl,
+ "yy_nxt", tblend + 1 );
+
+ for ( i = 1; i <= tblend; ++i )
+ {
+ /* Note, the order of the following test is important.
+ * If chk[i] is 0, then nxt[i] is undefined.
+ */
+ if ( chk[i] == 0 || nxt[i] == 0 )
+ nxt[i] = jamstate; /* new state is the JAM state */
+
+ mkdata( nxt[i] );
+ }
+
+ dataend();
+
+ out_str_dec( (total_states >= MAX_SHORT || long_align) ?
+ C_long_decl : C_short_decl,
+ "yy_chk", tblend + 1 );
+
+ for ( i = 1; i <= tblend; ++i )
+ {
+ if ( chk[i] == 0 )
+ ++nummt;
+
+ mkdata( chk[i] );
+ }
+
+ dataend();
+ }
+
+
+/* Write out a formatted string (with a secondary string argument) at the
+ * current indentation level, adding a final newline.
+ */
+
+void indent_put2s( fmt, arg )
+char fmt[], arg[];
+ {
+ do_indent();
+ out_str( fmt, arg );
+ outn( "" );
+ }
+
+
+/* Write out a string at the current indentation level, adding a final
+ * newline.
+ */
+
+void indent_puts( str )
+char str[];
+ {
+ do_indent();
+ outn( str );
+ }
+
+
+/* make_tables - generate transition tables and finishes generating output file
+ */
+
+void make_tables()
+ {
+ register int i;
+ int did_eof_rule = false;
+
+ skelout();
+
+ /* First, take care of YY_DO_BEFORE_ACTION depending on yymore
+ * being used.
+ */
+ set_indent( 1 );
+
+ if ( yymore_used && ! yytext_is_array )
+ {
+ indent_puts( "yytext_ptr -= yy_more_len; \\" );
+ indent_puts( "yyleng = (int) (yy_cp - yytext_ptr); \\" );
+ }
+
+ else
+ indent_puts( "yyleng = (int) (yy_cp - yy_bp); \\" );
+
+ /* Now also deal with copying yytext_ptr to yytext if needed. */
+ skelout();
+ if ( yytext_is_array )
+ {
+ if ( yymore_used )
+ indent_puts(
+ "if ( yyleng + yy_more_offset >= YYLMAX ) \\" );
+ else
+ indent_puts( "if ( yyleng >= YYLMAX ) \\" );
+
+ indent_up();
+ indent_puts(
+ "YY_FATAL_ERROR( \"token too large, exceeds YYLMAX\" ); \\" );
+ indent_down();
+
+ if ( yymore_used )
+ {
+ indent_puts(
+"yy_flex_strncpy( &yytext[yy_more_offset], yytext_ptr, yyleng + 1 ); \\" );
+ indent_puts( "yyleng += yy_more_offset; \\" );
+ indent_puts(
+ "yy_prev_more_offset = yy_more_offset; \\" );
+ indent_puts( "yy_more_offset = 0; \\" );
+ }
+ else
+ {
+ indent_puts(
+ "yy_flex_strncpy( yytext, yytext_ptr, yyleng + 1 ); \\" );
+ }
+ }
+
+ set_indent( 0 );
+
+ skelout();
+
+
+ out_dec( "#define YY_NUM_RULES %d\n", num_rules );
+ out_dec( "#define YY_END_OF_BUFFER %d\n", num_rules + 1 );
+
+ if ( fullspd )
+ {
+ /* Need to define the transet type as a size large
+ * enough to hold the biggest offset.
+ */
+ int total_table_size = tblend + numecs + 1;
+ char *trans_offset_type =
+ (total_table_size >= MAX_SHORT || long_align) ?
+ "long" : "short";
+
+ set_indent( 0 );
+ indent_puts( "struct yy_trans_info" );
+ indent_up();
+ indent_puts( "{" ); /* } for vi */
+
+ if ( long_align )
+ indent_puts( "long yy_verify;" );
+ else
+ indent_puts( "short yy_verify;" );
+
+ /* In cases where its sister yy_verify *is* a "yes, there is
+ * a transition", yy_nxt is the offset (in records) to the
+ * next state. In most cases where there is no transition,
+ * the value of yy_nxt is irrelevant. If yy_nxt is the -1th
+ * record of a state, though, then yy_nxt is the action number
+ * for that state.
+ */
+
+ indent_put2s( "%s yy_nxt;", trans_offset_type );
+ indent_puts( "};" );
+ indent_down();
+ }
+
+ if ( fullspd )
+ genctbl();
+ else if ( fulltbl )
+ genftbl();
+ else
+ gentabs();
+
+ /* Definitions for backing up. We don't need them if REJECT
+ * is being used because then we use an alternative backin-up
+ * technique instead.
+ */
+ if ( num_backing_up > 0 && ! reject )
+ {
+ if ( ! C_plus_plus )
+ {
+ indent_puts(
+ "static yy_state_type yy_last_accepting_state;" );
+ indent_puts(
+ "static char *yy_last_accepting_cpos;\n" );
+ }
+ }
+
+ if ( nultrans )
+ {
+ out_str_dec( C_state_decl, "yy_NUL_trans", lastdfa + 1 );
+
+ for ( i = 1; i <= lastdfa; ++i )
+ {
+ if ( fullspd )
+ out_dec( " &yy_transition[%d],\n", base[i] );
+ else
+ mkdata( nultrans[i] );
+ }
+
+ dataend();
+ }
+
+ if ( ddebug )
+ { /* Spit out table mapping rules to line numbers. */
+ if ( ! C_plus_plus )
+ {
+ indent_puts( "extern int yy_flex_debug;" );
+ indent_puts( "int yy_flex_debug = 1;\n" );
+ }
+
+ out_str_dec( long_align ? C_long_decl : C_short_decl,
+ "yy_rule_linenum", num_rules );
+ for ( i = 1; i < num_rules; ++i )
+ mkdata( rule_linenum[i] );
+ dataend();
+ }
+
+ if ( reject )
+ {
+ /* Declare state buffer variables. */
+ if ( ! C_plus_plus )
+ {
+ outn(
+ "static yy_state_type yy_state_buf[YY_BUF_SIZE + 2], *yy_state_ptr;" );
+ outn( "static char *yy_full_match;" );
+ outn( "static int yy_lp;" );
+ }
+
+ if ( variable_trailing_context_rules )
+ {
+ if ( ! C_plus_plus )
+ {
+ outn(
+ "static int yy_looking_for_trail_begin = 0;" );
+ outn( "static int yy_full_lp;" );
+ outn( "static int *yy_full_state;" );
+ }
+
+ out_hex( "#define YY_TRAILING_MASK 0x%x\n",
+ (unsigned int) YY_TRAILING_MASK );
+ out_hex( "#define YY_TRAILING_HEAD_MASK 0x%x\n",
+ (unsigned int) YY_TRAILING_HEAD_MASK );
+ }
+
+ outn( "#define REJECT \\" );
+ outn( "{ \\" ); /* } for vi */
+ outn(
+ "*yy_cp = yy_hold_char; /* undo effects of setting up yytext */ \\" );
+ outn(
+ "yy_cp = yy_full_match; /* restore poss. backed-over text */ \\" );
+
+ if ( variable_trailing_context_rules )
+ {
+ outn(
+ "yy_lp = yy_full_lp; /* restore orig. accepting pos. */ \\" );
+ outn(
+ "yy_state_ptr = yy_full_state; /* restore orig. state */ \\" );
+ outn(
+ "yy_current_state = *yy_state_ptr; /* restore curr. state */ \\" );
+ }
+
+ outn( "++yy_lp; \\" );
+ outn( "goto find_rule; \\" );
+ /* { for vi */
+ outn( "}" );
+ }
+
+ else
+ {
+ outn(
+ "/* The intent behind this definition is that it'll catch" );
+ outn( " * any uses of REJECT which flex missed." );
+ outn( " */" );
+ outn( "#define REJECT reject_used_but_not_detected" );
+ }
+
+ if ( yymore_used )
+ {
+ if ( ! C_plus_plus )
+ {
+ if ( yytext_is_array )
+ {
+ indent_puts( "static int yy_more_offset = 0;" );
+ indent_puts(
+ "static int yy_prev_more_offset = 0;" );
+ }
+ else
+ {
+ indent_puts( "static int yy_more_flag = 0;" );
+ indent_puts( "static int yy_more_len = 0;" );
+ }
+ }
+
+ if ( yytext_is_array )
+ {
+ indent_puts(
+ "#define yymore() (yy_more_offset = yy_flex_strlen( yytext ))" );
+ indent_puts( "#define YY_NEED_STRLEN" );
+ indent_puts( "#define YY_MORE_ADJ 0" );
+ indent_puts( "#define YY_RESTORE_YY_MORE_OFFSET \\" );
+ indent_up();
+ indent_puts( "{ \\" );
+ indent_puts( "yy_more_offset = yy_prev_more_offset; \\" );
+ indent_puts( "yyleng -= yy_more_offset; \\" );
+ indent_puts( "}" );
+ indent_down();
+ }
+ else
+ {
+ indent_puts( "#define yymore() (yy_more_flag = 1)" );
+ indent_puts( "#define YY_MORE_ADJ yy_more_len" );
+ indent_puts( "#define YY_RESTORE_YY_MORE_OFFSET" );
+ }
+ }
+
+ else
+ {
+ indent_puts( "#define yymore() yymore_used_but_not_detected" );
+ indent_puts( "#define YY_MORE_ADJ 0" );
+ indent_puts( "#define YY_RESTORE_YY_MORE_OFFSET" );
+ }
+
+ if ( ! C_plus_plus )
+ {
+ if ( yytext_is_array )
+ {
+ outn( "#ifndef YYLMAX" );
+ outn( "#define YYLMAX 8192" );
+ outn( "#endif\n" );
+ outn( "char yytext[YYLMAX];" );
+ outn( "char *yytext_ptr;" );
+ }
+
+ else
+ outn( "char *yytext;" );
+ }
+
+ out( &action_array[defs1_offset] );
+
+ line_directive_out( stdout, 0 );
+
+ skelout();
+
+ if ( ! C_plus_plus )
+ {
+ if ( use_read )
+ {
+ outn(
+"\tif ( (result = read( fileno(yyin), (char *) buf, max_size )) < 0 ) \\" );
+ outn(
+ "\t\tYY_FATAL_ERROR( \"input in flex scanner failed\" );" );
+ }
+
+ else
+ {
+ outn(
+ "\tif ( yy_current_buffer->yy_is_interactive ) \\" );
+ outn( "\t\t{ \\" );
+ outn( "\t\tint c = '*', n; \\" );
+ outn( "\t\tfor ( n = 0; n < max_size && \\" );
+ outn( "\t\t\t (c = getc( yyin )) != EOF && c != '\\n'; ++n ) \\" );
+ outn( "\t\t\tbuf[n] = (char) c; \\" );
+ outn( "\t\tif ( c == '\\n' ) \\" );
+ outn( "\t\t\tbuf[n++] = (char) c; \\" );
+ outn( "\t\tif ( c == EOF && ferror( yyin ) ) \\" );
+ outn(
+ "\t\t\tYY_FATAL_ERROR( \"input in flex scanner failed\" ); \\" );
+ outn( "\t\tresult = n; \\" );
+ outn( "\t\t} \\" );
+ outn(
+ "\telse if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \\" );
+ outn( "\t\t && ferror( yyin ) ) \\" );
+ outn(
+ "\t\tYY_FATAL_ERROR( \"input in flex scanner failed\" );" );
+ }
+ }
+
+ skelout();
+
+ indent_puts( "#define YY_RULE_SETUP \\" );
+ indent_up();
+ if ( bol_needed )
+ {
+ indent_puts( "if ( yyleng > 0 ) \\" );
+ indent_up();
+ indent_puts( "yy_current_buffer->yy_at_bol = \\" );
+ indent_puts( "\t\t(yytext[yyleng - 1] == '\\n'); \\" );
+ indent_down();
+ }
+ indent_puts( "YY_USER_ACTION" );
+ indent_down();
+
+ skelout();
+
+ /* Copy prolog to output file. */
+ out( &action_array[prolog_offset] );
+
+ line_directive_out( stdout, 0 );
+
+ skelout();
+
+ set_indent( 2 );
+
+ if ( yymore_used && ! yytext_is_array )
+ {
+ indent_puts( "yy_more_len = 0;" );
+ indent_puts( "if ( yy_more_flag )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "yy_more_len = yy_c_buf_p - yytext_ptr;" );
+ indent_puts( "yy_more_flag = 0;" );
+ indent_puts( "}" );
+ indent_down();
+ }
+
+ skelout();
+
+ gen_start_state();
+
+ /* Note, don't use any indentation. */
+ outn( "yy_match:" );
+ gen_next_match();
+
+ skelout();
+ set_indent( 2 );
+ gen_find_action();
+
+ skelout();
+ if ( do_yylineno )
+ {
+ indent_puts( "if ( yy_act != YY_END_OF_BUFFER )" );
+ indent_up();
+ indent_puts( "{" );
+ indent_puts( "int yyl;" );
+ indent_puts( "for ( yyl = 0; yyl < yyleng; ++yyl )" );
+ indent_up();
+ indent_puts( "if ( yytext[yyl] == '\\n' )" );
+ indent_up();
+ indent_puts( "++yylineno;" );
+ indent_down();
+ indent_down();
+ indent_puts( "}" );
+ indent_down();
+ }
+
+ skelout();
+ if ( ddebug )
+ {
+ indent_puts( "if ( yy_flex_debug )" );
+ indent_up();
+
+ indent_puts( "{" );
+ indent_puts( "if ( yy_act == 0 )" );
+ indent_up();
+ indent_puts( C_plus_plus ?
+ "cerr << \"--scanner backing up\\n\";" :
+ "fprintf( stderr, \"--scanner backing up\\n\" );" );
+ indent_down();
+
+ do_indent();
+ out_dec( "else if ( yy_act < %d )\n", num_rules );
+ indent_up();
+
+ if ( C_plus_plus )
+ {
+ indent_puts(
+ "cerr << \"--accepting rule at line \" << yy_rule_linenum[yy_act] <<" );
+ indent_puts(
+ " \"(\\\"\" << yytext << \"\\\")\\n\";" );
+ }
+ else
+ {
+ indent_puts(
+ "fprintf( stderr, \"--accepting rule at line %d (\\\"%s\\\")\\n\"," );
+
+ indent_puts(
+ " yy_rule_linenum[yy_act], yytext );" );
+ }
+
+ indent_down();
+
+ do_indent();
+ out_dec( "else if ( yy_act == %d )\n", num_rules );
+ indent_up();
+
+ if ( C_plus_plus )
+ {
+ indent_puts(
+"cerr << \"--accepting default rule (\\\"\" << yytext << \"\\\")\\n\";" );
+ }
+ else
+ {
+ indent_puts(
+ "fprintf( stderr, \"--accepting default rule (\\\"%s\\\")\\n\"," );
+ indent_puts( " yytext );" );
+ }
+
+ indent_down();
+
+ do_indent();
+ out_dec( "else if ( yy_act == %d )\n", num_rules + 1 );
+ indent_up();
+
+ indent_puts( C_plus_plus ?
+ "cerr << \"--(end of buffer or a NUL)\\n\";" :
+ "fprintf( stderr, \"--(end of buffer or a NUL)\\n\" );" );
+
+ indent_down();
+
+ do_indent();
+ outn( "else" );
+ indent_up();
+
+ if ( C_plus_plus )
+ {
+ indent_puts(
+ "cerr << \"--EOF (start condition \" << YY_START << \")\\n\";" );
+ }
+ else
+ {
+ indent_puts(
+ "fprintf( stderr, \"--EOF (start condition %d)\\n\", YY_START );" );
+ }
+
+ indent_down();
+
+ indent_puts( "}" );
+ indent_down();
+ }
+
+ /* Copy actions to output file. */
+ skelout();
+ indent_up();
+ gen_bu_action();
+ out( &action_array[action_offset] );
+
+ line_directive_out( stdout, 0 );
+
+ /* generate cases for any missing EOF rules */
+ for ( i = 1; i <= lastsc; ++i )
+ if ( ! sceof[i] )
+ {
+ do_indent();
+ out_str( "case YY_STATE_EOF(%s):\n", scname[i] );
+ did_eof_rule = true;
+ }
+
+ if ( did_eof_rule )
+ {
+ indent_up();
+ indent_puts( "yyterminate();" );
+ indent_down();
+ }
+
+
+ /* Generate code for handling NUL's, if needed. */
+
+ /* First, deal with backing up and setting up yy_cp if the scanner
+ * finds that it should JAM on the NUL.
+ */
+ skelout();
+ set_indent( 4 );
+
+ if ( fullspd || fulltbl )
+ indent_puts( "yy_cp = yy_c_buf_p;" );
+
+ else
+ { /* compressed table */
+ if ( ! reject && ! interactive )
+ {
+ /* Do the guaranteed-needed backing up to figure
+ * out the match.
+ */
+ indent_puts( "yy_cp = yy_last_accepting_cpos;" );
+ indent_puts(
+ "yy_current_state = yy_last_accepting_state;" );
+ }
+
+ else
+ /* Still need to initialize yy_cp, though
+ * yy_current_state was set up by
+ * yy_get_previous_state().
+ */
+ indent_puts( "yy_cp = yy_c_buf_p;" );
+ }
+
+
+ /* Generate code for yy_get_previous_state(). */
+ set_indent( 1 );
+ skelout();
+
+ gen_start_state();
+
+ set_indent( 2 );
+ skelout();
+ gen_next_state( true );
+
+ set_indent( 1 );
+ skelout();
+ gen_NUL_trans();
+
+ skelout();
+ if ( do_yylineno )
+ { /* update yylineno inside of unput() */
+ indent_puts( "if ( c == '\\n' )" );
+ indent_up();
+ indent_puts( "--yylineno;" );
+ indent_down();
+ }
+
+ skelout();
+ /* Update BOL and yylineno inside of input(). */
+ if ( bol_needed )
+ {
+ indent_puts( "yy_current_buffer->yy_at_bol = (c == '\\n');" );
+ if ( do_yylineno )
+ {
+ indent_puts( "if ( yy_current_buffer->yy_at_bol )" );
+ indent_up();
+ indent_puts( "++yylineno;" );
+ indent_down();
+ }
+ }
+
+ else if ( do_yylineno )
+ {
+ indent_puts( "if ( c == '\\n' )" );
+ indent_up();
+ indent_puts( "++yylineno;" );
+ indent_down();
+ }
+
+ skelout();
+
+ /* Copy remainder of input to output. */
+
+ line_directive_out( stdout, 1 );
+
+ if ( sectnum == 3 )
+ (void) flexscan(); /* copy remainder of input to output */
+ }
diff --git a/Tools/android/flex-2.5.4a/initscan.c b/Tools/android/flex-2.5.4a/initscan.c
new file mode 100644
index 0000000..5951804
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/initscan.c
@@ -0,0 +1,3697 @@
+#line 2 "scan.c"
+/* A lexical scanner generated by flex */
+
+/* Scanner skeleton version:
+ * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $
+ */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+
+#include <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* Use prototypes in function declarations. */
+#define YY_USE_PROTOS
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+#if __STDC__
+
+#define YY_USE_PROTOS
+#define YY_USE_CONST
+
+#endif /* __STDC__ */
+#endif /* ! __cplusplus */
+
+#ifdef __TURBOC__
+ #pragma warn -rch
+ #pragma warn -use
+#include <io.h>
+#include <stdlib.h>
+#define YY_USE_CONST
+#define YY_USE_PROTOS
+#endif
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+
+#ifdef YY_USE_PROTOS
+#define YY_PROTO(proto) proto
+#else
+#define YY_PROTO(proto) ()
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN yy_start = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START ((yy_start - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart( yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#define YY_BUF_SIZE 16384
+
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+
+extern int yyleng;
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+/* The funky do-while in the following #define is used to turn the definition
+ * int a single C statement (which needs a semi-colon terminator). This
+ * avoids problems with code like:
+ *
+ * if ( condition_holds )
+ * yyless( 5 );
+ * else
+ * do_something_else();
+ *
+ * Prior to using the do-while the compiler would get upset at the
+ * "else" because it interpreted the "if" statement as being all
+ * done when it reached the ';' after the yyless() call.
+ */
+
+/* Return all but the first 'n' matched characters back to the input stream. */
+
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ *yy_cp = yy_hold_char; \
+ YY_RESTORE_YY_MORE_OFFSET \
+ yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, yytext_ptr )
+
+/* The following is because we cannot portably get our hands on size_t
+ * (without autoconf's help, which isn't available because we want
+ * flex-generated scanners to compile on their own).
+ */
+typedef unsigned int yy_size_t;
+
+
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ int yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+ };
+
+static YY_BUFFER_STATE yy_current_buffer = 0;
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ */
+#define YY_CURRENT_BUFFER yy_current_buffer
+
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+
+static int yy_n_chars; /* number of characters read into yy_ch_buf */
+
+
+int yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 1; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart YY_PROTO(( FILE *input_file ));
+
+void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));
+void yy_load_buffer_state YY_PROTO(( void ));
+YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));
+void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));
+void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));
+#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )
+
+YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));
+YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));
+YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));
+
+static void *yy_flex_alloc YY_PROTO(( yy_size_t ));
+static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));
+static void yy_flex_free YY_PROTO(( void * ));
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! yy_current_buffer ) \
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \
+ yy_current_buffer->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)
+
+typedef unsigned char YY_CHAR;
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+typedef int yy_state_type;
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state YY_PROTO(( void ));
+static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));
+static int yy_get_next_buffer YY_PROTO(( void ));
+static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ yytext_ptr = yy_bp; \
+ yyleng = (int) (yy_cp - yy_bp); \
+ yy_hold_char = *yy_cp; \
+ *yy_cp = '\0'; \
+ yy_c_buf_p = yy_cp;
+
+#define YY_NUM_RULES 165
+#define YY_END_OF_BUFFER 166
+static yyconst short int yy_accept[769] =
+ { 0,
+ 0, 0, 0, 0, 87, 87, 163, 163, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 166, 164,
+ 7, 18, 164, 16, 1, 17, 164, 164, 164, 164,
+ 15, 108, 100, 101, 108, 93, 108, 107, 108, 108,
+ 108, 107, 99, 89, 108, 108, 91, 92, 87, 88,
+ 87, 86, 85, 86, 86, 163, 163, 28, 29, 28,
+ 28, 28, 28, 28, 28, 31, 30, 32, 31, 113,
+ 109, 110, 112, 114, 141, 142, 141, 139, 138, 140,
+
+ 115, 117, 115, 116, 115, 120, 120, 120, 120, 122,
+ 124, 122, 122, 122, 122, 123, 151, 155, 151, 154,
+ 156, 156, 152, 152, 152, 149, 150, 164, 82, 164,
+ 21, 22, 21, 20, 157, 159, 157, 160, 161, 147,
+ 147, 148, 147, 147, 147, 147, 147, 147, 147, 81,
+ 34, 33, 81, 81, 81, 81, 35, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 26, 23, 26, 24,
+ 7, 18, 0, 16, 1, 17, 0, 0, 0, 14,
+ 8, 0, 0, 0, 0, 4, 5, 0, 2, 15,
+
+ 100, 101, 0, 0, 0, 95, 0, 0, 105, 105,
+ 0, 162, 162, 162, 94, 0, 99, 89, 0, 0,
+ 0, 91, 92, 104, 90, 0, 87, 88, 86, 85,
+ 85, 83, 84, 163, 163, 28, 29, 28, 28, 28,
+ 28, 31, 30, 32, 111, 112, 142, 138, 117, 0,
+ 118, 119, 124, 121, 151, 155, 0, 153, 0, 144,
+ 152, 152, 152, 0, 82, 0, 21, 22, 21, 19,
+ 157, 159, 158, 147, 147, 147, 148, 143, 147, 147,
+ 147, 34, 33, 0, 80, 0, 0, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+
+ 81, 81, 81, 36, 81, 81, 81, 81, 81, 81,
+ 81, 81, 81, 81, 0, 25, 24, 0, 14, 8,
+ 0, 12, 0, 0, 0, 0, 0, 4, 5, 0,
+ 6, 0, 96, 0, 97, 0, 0, 105, 105, 0,
+ 105, 105, 105, 162, 162, 0, 106, 90, 98, 0,
+ 104, 0, 83, 84, 28, 28, 28, 27, 28, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 152, 152, 143, 143, 147, 147, 0, 0, 81,
+ 81, 81, 81, 81, 44, 81, 81, 81, 49, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+
+ 81, 81, 81, 81, 81, 81, 81, 81, 0, 81,
+ 81, 81, 81, 0, 0, 0, 12, 0, 0, 0,
+ 0, 0, 0, 4, 5, 0, 105, 105, 105, 105,
+ 105, 105, 162, 0, 0, 28, 28, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 152, 152, 147, 147, 37, 38, 81, 81, 81, 81,
+ 81, 81, 81, 81, 50, 51, 81, 81, 81, 55,
+ 81, 81, 81, 81, 81, 81, 60, 81, 81, 81,
+ 81, 81, 81, 67, 0, 0, 0, 81, 81, 81,
+ 81, 0, 13, 0, 0, 0, 0, 0, 0, 105,
+
+ 105, 105, 105, 105, 105, 0, 0, 28, 28, 137,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 152, 152, 147, 147, 39, 81, 41, 81,
+ 43, 81, 81, 81, 47, 81, 52, 81, 81, 81,
+ 81, 81, 81, 81, 81, 81, 62, 81, 81, 65,
+ 81, 0, 0, 0, 0, 81, 81, 81, 81, 3,
+ 0, 0, 0, 0, 105, 105, 105, 0, 0, 28,
+ 28, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 145, 146, 145, 146, 81, 42, 81,
+ 81, 81, 81, 81, 81, 81, 81, 81, 81, 81,
+
+ 81, 78, 61, 81, 64, 81, 0, 0, 0, 0,
+ 81, 81, 69, 70, 0, 10, 0, 11, 0, 103,
+ 0, 102, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 81, 81, 81, 45, 81, 48,
+ 81, 81, 81, 81, 77, 81, 59, 63, 66, 0,
+ 0, 0, 0, 79, 81, 0, 102, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 81,
+ 81, 81, 46, 81, 81, 56, 81, 81, 0, 0,
+ 0, 0, 68, 0, 9, 0, 125, 126, 127, 128,
+ 129, 130, 131, 132, 133, 134, 135, 0, 81, 81,
+
+ 81, 81, 81, 81, 81, 0, 0, 0, 0, 0,
+ 136, 81, 81, 81, 81, 54, 81, 81, 0, 0,
+ 0, 0, 0, 0, 81, 81, 81, 53, 81, 58,
+ 0, 0, 0, 0, 0, 0, 81, 81, 81, 81,
+ 72, 0, 0, 0, 0, 73, 81, 81, 81, 81,
+ 71, 0, 75, 0, 81, 81, 81, 74, 76, 81,
+ 81, 81, 81, 81, 81, 57, 40, 0
+ } ;
+
+static yyconst int yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 4, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 5, 6, 7, 8, 1, 9, 10,
+ 10, 11, 12, 13, 14, 10, 15, 16, 16, 16,
+ 16, 16, 16, 16, 17, 18, 19, 20, 1, 21,
+ 22, 23, 10, 1, 31, 32, 33, 34, 35, 36,
+ 37, 38, 39, 40, 41, 42, 43, 44, 45, 46,
+ 47, 48, 49, 50, 51, 52, 53, 54, 55, 47,
+ 26, 27, 28, 29, 30, 1, 31, 32, 33, 34,
+
+ 35, 36, 37, 38, 39, 40, 41, 42, 43, 44,
+ 45, 46, 47, 48, 49, 50, 51, 52, 53, 54,
+ 55, 47, 56, 57, 58, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst int yy_meta[59] =
+ { 0,
+ 1, 1, 2, 1, 3, 1, 1, 1, 4, 1,
+ 5, 6, 1, 7, 4, 8, 8, 8, 8, 1,
+ 1, 1, 1, 9, 10, 1, 11, 12, 1, 13,
+ 14, 14, 14, 14, 14, 14, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 4, 1, 16
+ } ;
+
+static yyconst short int yy_base[858] =
+ { 0,
+ 0, 58, 115, 172, 120, 129, 2712, 2711, 230, 2705,
+ 136, 141, 288, 0, 2683, 2682, 144, 151, 185, 191,
+ 178, 188, 344, 347, 375, 0, 125, 131, 147, 216,
+ 431, 434, 461, 0, 519, 0, 205, 349, 2710, 2716,
+ 353, 2716, 2706, 0, 360, 2716, 2705, 144, 570, 2696,
+ 0, 2716, 577, 2716, 2703, 2716, 438, 2716, 2684, 126,
+ 149, 427, 591, 2716, 2701, 141, 2682, 2716, 0, 2716,
+ 2699, 0, 2699, 2697, 155, 2696, 2716, 0, 2716, 2695,
+ 2716, 0, 2662, 2641, 2637, 0, 2692, 2716, 2690, 2716,
+ 2716, 2663, 0, 2716, 2716, 2716, 2688, 2716, 431, 2716,
+
+ 2716, 2716, 2687, 2716, 567, 2716, 2669, 571, 164, 2716,
+ 2716, 2685, 0, 2667, 573, 2716, 0, 2716, 2683, 2716,
+ 573, 2674, 0, 2649, 2628, 2716, 2716, 222, 2716, 356,
+ 448, 2716, 450, 2667, 0, 2716, 2678, 2716, 0, 0,
+ 198, 2716, 2677, 2621, 2716, 2667, 0, 2642, 2621, 2716,
+ 2673, 2716, 2671, 2668, 2640, 2639, 2716, 544, 2639, 579,
+ 2634, 2635, 318, 0, 2623, 2631, 424, 562, 2614, 587,
+ 2629, 2613, 2618, 2626, 2629, 2604, 2716, 2716, 2653, 612,
+ 634, 2716, 2654, 0, 637, 2716, 2653, 600, 2616, 0,
+ 0, 641, 647, 651, 669, 0, 0, 453, 2716, 0,
+
+ 672, 2716, 2651, 2597, 605, 2716, 2649, 2616, 620, 657,
+ 645, 2716, 662, 0, 2716, 2592, 688, 2716, 2646, 2592,
+ 2636, 2625, 2716, 0, 2716, 2610, 0, 2716, 0, 0,
+ 2642, 0, 0, 2640, 2716, 0, 2716, 0, 2602, 2598,
+ 745, 0, 2638, 2716, 2716, 0, 2716, 688, 2716, 773,
+ 2716, 2716, 2716, 2716, 0, 2716, 673, 2716, 0, 2716,
+ 0, 2599, 2595, 690, 2716, 698, 707, 2716, 709, 2716,
+ 0, 2716, 2716, 0, 596, 2579, 2716, 827, 0, 2596,
+ 2592, 2632, 2716, 2628, 2716, 2593, 2592, 0, 642, 2582,
+ 563, 2617, 2579, 620, 2578, 2577, 2583, 669, 2570, 2584,
+
+ 2572, 0, 2569, 2716, 2570, 2571, 2579, 2582, 685, 125,
+ 2570, 2567, 2566, 688, 2608, 2716, 716, 2568, 0, 0,
+ 720, 2716, 2608, 884, 2562, 2559, 2569, 0, 0, 723,
+ 2716, 739, 2716, 805, 2716, 808, 2562, 787, 869, 876,
+ 930, 881, 973, 800, 0, 2548, 2716, 2716, 2716, 2570,
+ 0, 2559, 0, 0, 2568, 2557, 0, 2716, 0, 1009,
+ 2581, 678, 870, 871, 874, 879, 913, 992, 974, 1013,
+ 885, 2565, 2554, 0, 1067, 2563, 2552, 2546, 2545, 2557,
+ 2562, 2561, 2550, 2557, 0, 2554, 2537, 2556, 0, 2536,
+ 2543, 2533, 2548, 2568, 2537, 2549, 2544, 2542, 2541, 2532,
+
+ 2539, 2540, 2538, 2539, 578, 2520, 2538, 2525, 860, 2526,
+ 2528, 2521, 2517, 2529, 817, 1044, 2716, 822, 1095, 914,
+ 2532, 2523, 2517, 0, 0, 2524, 1102, 1025, 1142, 2539,
+ 1028, 1163, 2716, 2513, 2521, 2523, 2507, 0, 2526, 1058,
+ 891, 1014, 1019, 894, 1038, 1080, 1072, 1086, 1083, 1081,
+ 2520, 2504, 2518, 2502, 2716, 2716, 2505, 2493, 2492, 2495,
+ 2507, 1148, 2507, 2492, 0, 0, 2492, 2493, 2507, 0,
+ 2525, 2490, 2498, 2522, 2485, 2495, 0, 2500, 2491, 2487,
+ 2479, 2479, 2483, 0, 875, 2494, 2481, 2494, 2480, 2475,
+ 2491, 2519, 2716, 920, 999, 2465, 2474, 2468, 2494, 2496,
+
+ 1105, 1184, 1081, 902, 969, 2479, 2491, 2463, 2477, 2716,
+ 165, 1090, 1144, 1143, 1147, 1163, 1095, 1145, 1037, 1085,
+ 1150, 1173, 2461, 2475, 2459, 2473, 0, 2458, 0, 2460,
+ 0, 1165, 2454, 2469, 0, 2461, 0, 2471, 2410, 2414,
+ 2434, 2400, 2393, 2405, 2385, 2382, 0, 2383, 2335, 0,
+ 2335, 2330, 2326, 2309, 2278, 2259, 2269, 2268, 2256, 2297,
+ 1046, 2238, 2242, 2253, 1179, 1142, 1145, 2247, 2246, 0,
+ 0, 1191, 1192, 1172, 1201, 1202, 1204, 1205, 1206, 1207,
+ 1209, 1210, 1208, 0, 0, 0, 0, 2254, 0, 2221,
+ 2229, 2218, 2208, 2200, 2209, 2198, 2195, 2165, 2168, 2149,
+
+ 2132, 0, 0, 2129, 0, 2139, 2143, 2134, 2124, 2137,
+ 2117, 2116, 0, 0, 1228, 2716, 1232, 2716, 2111, 2716,
+ 2117, 2716, 2115, 2114, 2108, 2107, 2106, 2103, 2102, 2098,
+ 2095, 2063, 2047, 1213, 2012, 1986, 1975, 0, 1954, 0,
+ 1947, 1950, 1941, 1945, 0, 1942, 0, 0, 0, 1938,
+ 1940, 1934, 1905, 0, 1872, 1234, 2716, 1888, 1882, 1881,
+ 1864, 1848, 1832, 1828, 1827, 1826, 1823, 1806, 1809, 1784,
+ 1787, 1772, 0, 1781, 1786, 0, 1766, 1767, 1759, 1744,
+ 1213, 1736, 0, 1236, 2716, 1245, 2716, 2716, 2716, 2716,
+ 2716, 2716, 2716, 2716, 2716, 2716, 2716, 1750, 1727, 1720,
+
+ 1701, 1687, 1670, 1681, 1667, 1679, 1659, 689, 1658, 1671,
+ 2716, 1657, 1627, 1621, 1635, 0, 1603, 1596, 1595, 1608,
+ 1602, 1587, 1586, 1583, 1581, 1587, 1555, 0, 1547, 0,
+ 1527, 1507, 1520, 1503, 1483, 1482, 1485, 1443, 1440, 1228,
+ 2716, 1225, 1224, 1206, 1210, 2716, 1213, 1202, 1018, 948,
+ 2716, 945, 2716, 884, 780, 771, 779, 2716, 2716, 689,
+ 673, 581, 408, 318, 86, 0, 0, 2716, 1263, 1279,
+ 1295, 1311, 1327, 1343, 1359, 1375, 1391, 1407, 1423, 1439,
+ 1455, 1471, 1481, 1496, 1505, 1520, 1536, 1545, 1560, 1576,
+ 1592, 1608, 1624, 1634, 1649, 1659, 1674, 1690, 1706, 1718,
+
+ 1728, 1743, 1759, 1775, 1791, 1807, 1817, 1832, 1843, 1236,
+ 1858, 1874, 1890, 1898, 1905, 1920, 1936, 1952, 1968, 1977,
+ 1985, 2001, 2017, 2033, 2049, 2065, 2081, 2097, 2113, 2123,
+ 2138, 2148, 2155, 2170, 2182, 2192, 2207, 2223, 2239, 2255,
+ 2265, 2280, 2291, 2306, 2322, 2338, 2354, 2364, 2373, 2388,
+ 2404, 2420, 2429, 2437, 2453, 2469, 2485
+ } ;
+
+static yyconst short int yy_def[858] =
+ { 0,
+ 768, 768, 769, 769, 770, 771, 772, 772, 768, 9,
+ 773, 773, 768, 13, 774, 774, 775, 775, 776, 776,
+ 777, 777, 778, 778, 768, 25, 779, 779, 780, 780,
+ 781, 781, 768, 33, 768, 35, 782, 782, 768, 768,
+ 768, 768, 768, 783, 768, 768, 768, 768, 784, 768,
+ 785, 768, 768, 768, 768, 768, 768, 768, 768, 786,
+ 787, 788, 768, 768, 768, 768, 768, 768, 789, 768,
+ 789, 790, 791, 790, 790, 792, 768, 793, 768, 793,
+ 768, 794, 794, 794, 793, 795, 768, 768, 795, 768,
+ 768, 768, 796, 768, 768, 768, 768, 768, 768, 768,
+
+ 768, 768, 768, 768, 787, 768, 768, 787, 797, 768,
+ 768, 768, 798, 768, 787, 768, 799, 768, 799, 768,
+ 800, 768, 801, 801, 801, 768, 768, 802, 768, 802,
+ 803, 768, 803, 768, 804, 768, 804, 768, 805, 806,
+ 806, 768, 806, 806, 768, 806, 807, 807, 807, 768,
+ 768, 768, 768, 808, 768, 768, 768, 809, 809, 809,
+ 809, 809, 809, 809, 809, 809, 809, 810, 809, 809,
+ 809, 809, 809, 809, 809, 809, 768, 768, 811, 768,
+ 768, 768, 768, 783, 768, 768, 768, 768, 768, 812,
+ 813, 768, 768, 768, 768, 814, 815, 816, 768, 785,
+
+ 768, 768, 768, 768, 817, 768, 768, 768, 818, 818,
+ 819, 768, 768, 820, 768, 821, 768, 768, 768, 768,
+ 768, 768, 768, 822, 768, 768, 823, 768, 824, 825,
+ 825, 826, 827, 828, 768, 829, 768, 830, 830, 830,
+ 768, 831, 768, 768, 768, 832, 768, 768, 768, 833,
+ 768, 768, 768, 768, 834, 768, 835, 768, 835, 768,
+ 836, 836, 836, 837, 768, 837, 838, 768, 838, 768,
+ 839, 768, 768, 840, 840, 840, 768, 768, 841, 841,
+ 841, 768, 768, 842, 768, 768, 768, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+
+ 843, 843, 843, 768, 843, 843, 843, 843, 843, 843,
+ 843, 843, 843, 843, 844, 768, 768, 768, 845, 846,
+ 847, 768, 768, 768, 768, 768, 768, 848, 849, 850,
+ 768, 850, 768, 851, 768, 851, 768, 852, 852, 852,
+ 768, 852, 852, 768, 853, 854, 768, 768, 768, 768,
+ 855, 768, 826, 827, 830, 830, 241, 768, 241, 241,
+ 833, 833, 833, 833, 833, 833, 833, 833, 833, 833,
+ 833, 836, 836, 278, 278, 841, 841, 768, 768, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+
+ 843, 843, 843, 843, 843, 843, 843, 843, 768, 843,
+ 843, 843, 843, 768, 847, 847, 768, 847, 847, 768,
+ 768, 768, 768, 848, 849, 768, 341, 852, 343, 341,
+ 852, 343, 768, 768, 768, 830, 830, 360, 768, 833,
+ 833, 833, 833, 833, 833, 833, 833, 833, 833, 833,
+ 836, 836, 841, 841, 768, 768, 843, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+ 843, 843, 843, 843, 768, 768, 768, 843, 843, 843,
+ 843, 768, 768, 847, 847, 768, 768, 768, 768, 427,
+
+ 852, 343, 852, 852, 852, 768, 768, 830, 830, 768,
+ 833, 833, 833, 833, 833, 833, 833, 833, 833, 833,
+ 833, 833, 836, 836, 841, 841, 843, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+ 843, 768, 768, 768, 768, 843, 843, 843, 843, 768,
+ 856, 768, 768, 768, 852, 852, 852, 768, 768, 830,
+ 830, 833, 833, 833, 833, 833, 833, 833, 833, 833,
+ 833, 833, 833, 836, 836, 841, 841, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 843,
+
+ 843, 843, 843, 843, 843, 843, 768, 768, 768, 768,
+ 843, 843, 843, 843, 856, 768, 856, 768, 768, 768,
+ 768, 768, 833, 833, 833, 833, 833, 833, 833, 833,
+ 833, 833, 833, 833, 843, 843, 843, 843, 843, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 843, 768,
+ 768, 768, 768, 843, 843, 857, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 833, 843,
+ 843, 843, 843, 843, 843, 843, 843, 843, 768, 768,
+ 768, 768, 843, 857, 768, 857, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 843, 843,
+
+ 843, 843, 843, 843, 843, 768, 768, 768, 768, 768,
+ 768, 843, 843, 843, 843, 843, 843, 843, 768, 768,
+ 768, 768, 768, 768, 843, 843, 843, 843, 843, 843,
+ 768, 768, 768, 768, 768, 768, 843, 843, 843, 843,
+ 768, 768, 768, 768, 768, 768, 843, 843, 843, 843,
+ 768, 768, 768, 768, 843, 843, 843, 768, 768, 843,
+ 843, 843, 843, 843, 843, 843, 843, 0, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768
+ } ;
+
+static yyconst short int yy_nxt[2775] =
+ { 0,
+ 40, 41, 42, 43, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 44, 44, 40, 40, 40, 40, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 44, 44, 44, 40, 40, 40, 40, 45,
+ 46, 47, 40, 48, 40, 49, 40, 40, 40, 40,
+ 40, 40, 50, 40, 40, 40, 40, 40, 40, 40,
+ 40, 51, 51, 40, 40, 40, 40, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 40, 40, 40, 53, 54, 55, 56,
+ 767, 57, 70, 71, 58, 58, 58, 129, 130, 58,
+ 73, 70, 74, 129, 130, 59, 75, 87, 88, 89,
+ 60, 61, 87, 88, 89, 188, 96, 97, 224, 132,
+ 133, 210, 211, 96, 97, 404, 98, 134, 405, 99,
+ 99, 99, 99, 98, 213, 213, 99, 99, 99, 99,
+ 62, 58, 58, 63, 64, 65, 56, 252, 57, 66,
+ 40, 58, 58, 58, 439, 189, 58, 102, 103, 104,
+ 40, 252, 67, 102, 103, 104, 225, 60, 61, 275,
+
+ 68, 100, 214, 107, 108, 276, 109, 178, 100, 179,
+ 232, 105, 233, 107, 108, 572, 109, 105, 132, 133,
+ 180, 180, 180, 180, 265, 266, 134, 62, 58, 58,
+ 78, 78, 79, 80, 78, 78, 78, 78, 78, 78,
+ 81, 78, 78, 78, 78, 78, 78, 78, 78, 78,
+ 78, 78, 78, 82, 82, 78, 78, 78, 78, 82,
+ 82, 82, 82, 82, 82, 82, 82, 82, 82, 82,
+ 82, 82, 82, 82, 82, 82, 82, 83, 82, 82,
+ 82, 82, 82, 82, 84, 78, 78, 78, 90, 90,
+ 40, 90, 90, 90, 90, 90, 90, 90, 91, 90,
+
+ 91, 90, 90, 90, 90, 90, 90, 90, 90, 90,
+ 92, 93, 93, 90, 90, 90, 90, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 93, 93, 93, 93, 93, 93, 93,
+ 93, 93, 93, 90, 90, 90, 111, 112, 296, 111,
+ 112, 178, 766, 179, 181, 182, 183, 113, 265, 266,
+ 113, 185, 186, 187, 180, 180, 180, 180, 297, 114,
+ 115, 116, 114, 115, 116, 117, 117, 118, 119, 120,
+ 117, 117, 117, 121, 117, 117, 117, 117, 117, 122,
+ 117, 117, 117, 117, 117, 117, 117, 117, 123, 123,
+
+ 117, 117, 117, 117, 123, 123, 123, 123, 123, 123,
+ 123, 123, 123, 123, 123, 123, 123, 123, 123, 123,
+ 123, 123, 124, 123, 123, 123, 123, 123, 123, 125,
+ 126, 117, 127, 136, 137, 138, 136, 137, 138, 206,
+ 206, 207, 215, 215, 215, 215, 248, 248, 248, 248,
+ 268, 269, 268, 269, 300, 331, 332, 139, 301, 765,
+ 139, 140, 141, 142, 143, 140, 140, 140, 144, 140,
+ 140, 145, 140, 140, 140, 146, 140, 140, 140, 140,
+ 140, 140, 140, 140, 147, 147, 140, 140, 140, 140,
+ 147, 147, 147, 147, 147, 147, 147, 147, 147, 147,
+
+ 147, 147, 147, 147, 147, 147, 147, 147, 148, 147,
+ 147, 147, 147, 147, 147, 149, 140, 140, 140, 150,
+ 151, 152, 153, 154, 150, 150, 150, 150, 150, 150,
+ 150, 150, 150, 150, 150, 155, 156, 150, 150, 150,
+ 157, 150, 150, 150, 150, 150, 150, 150, 150, 158,
+ 159, 160, 161, 162, 163, 164, 164, 165, 164, 164,
+ 166, 167, 168, 169, 170, 164, 171, 172, 164, 173,
+ 174, 175, 164, 176, 150, 150, 150, 191, 201, 202,
+ 203, 258, 213, 213, 204, 289, 213, 213, 213, 213,
+ 292, 290, 217, 218, 219, 383, 303, 275, 220, 259,
+
+ 192, 188, 193, 276, 193, 221, 304, 335, 336, 293,
+ 193, 222, 384, 193, 194, 195, 480, 193, 196, 223,
+ 214, 306, 481, 197, 214, 198, 214, 317, 317, 317,
+ 317, 307, 764, 205, 308, 181, 182, 183, 185, 186,
+ 187, 189, 321, 322, 323, 339, 340, 205, 321, 322,
+ 323, 387, 321, 322, 323, 388, 324, 324, 324, 324,
+ 342, 342, 324, 324, 324, 324, 324, 324, 324, 324,
+ 321, 322, 323, 201, 202, 203, 341, 344, 344, 204,
+ 380, 258, 339, 340, 324, 324, 324, 324, 325, 217,
+ 218, 219, 265, 266, 381, 220, 326, 439, 343, 259,
+
+ 265, 266, 221, 248, 248, 248, 248, 673, 222, 268,
+ 269, 268, 269, 327, 392, 402, 223, 409, 393, 440,
+ 410, 416, 417, 418, 403, 331, 332, 763, 205, 411,
+ 412, 317, 317, 317, 317, 419, 419, 419, 419, 721,
+ 413, 331, 332, 722, 205, 357, 357, 358, 359, 357,
+ 357, 357, 357, 357, 357, 360, 357, 357, 357, 357,
+ 357, 357, 357, 357, 357, 357, 357, 357, 360, 360,
+ 357, 357, 357, 357, 360, 360, 360, 360, 360, 360,
+ 360, 360, 360, 360, 360, 360, 360, 360, 360, 360,
+ 360, 360, 360, 360, 360, 360, 360, 360, 360, 360,
+
+ 357, 357, 357, 362, 363, 364, 365, 335, 336, 366,
+ 335, 336, 339, 340, 367, 212, 212, 762, 368, 493,
+ 494, 369, 761, 370, 417, 494, 371, 374, 374, 760,
+ 374, 374, 374, 374, 374, 374, 374, 375, 374, 374,
+ 374, 374, 374, 374, 374, 374, 374, 374, 374, 374,
+ 375, 375, 374, 374, 374, 374, 375, 375, 375, 375,
+ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
+ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
+ 375, 375, 374, 374, 374, 420, 322, 323, 427, 439,
+ 439, 428, 428, 439, 339, 340, 431, 431, 439, 324,
+
+ 324, 324, 324, 338, 439, 485, 339, 340, 486, 487,
+ 439, 441, 443, 439, 442, 420, 322, 323, 450, 552,
+ 759, 513, 493, 494, 516, 553, 444, 339, 340, 429,
+ 338, 338, 439, 338, 338, 338, 338, 338, 338, 338,
+ 338, 338, 338, 338, 338, 338, 338, 338, 338, 338,
+ 338, 338, 338, 430, 430, 339, 340, 445, 338, 338,
+ 430, 430, 430, 430, 430, 430, 430, 430, 430, 430,
+ 430, 430, 430, 430, 430, 430, 430, 430, 430, 430,
+ 430, 430, 430, 430, 430, 338, 338, 338, 432, 432,
+ 432, 432, 758, 439, 339, 340, 432, 757, 339, 340,
+
+ 495, 417, 418, 432, 432, 432, 432, 432, 432, 360,
+ 360, 439, 438, 360, 360, 360, 360, 360, 360, 448,
+ 360, 360, 360, 360, 360, 360, 360, 360, 360, 360,
+ 360, 360, 439, 439, 360, 360, 360, 360, 439, 446,
+ 501, 501, 447, 504, 504, 416, 417, 418, 616, 617,
+ 339, 340, 638, 339, 340, 515, 439, 439, 449, 419,
+ 419, 419, 419, 514, 360, 360, 360, 375, 375, 580,
+ 375, 375, 375, 375, 375, 375, 375, 439, 375, 375,
+ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
+ 517, 439, 375, 375, 375, 375, 495, 417, 418, 439,
+
+ 439, 511, 439, 512, 439, 439, 339, 340, 209, 439,
+ 419, 419, 419, 419, 439, 519, 520, 581, 518, 522,
+ 566, 566, 375, 375, 375, 500, 500, 573, 521, 578,
+ 339, 340, 500, 500, 500, 500, 500, 500, 500, 500,
+ 500, 500, 500, 500, 500, 500, 500, 500, 500, 500,
+ 500, 500, 500, 500, 500, 500, 500, 502, 502, 502,
+ 502, 532, 439, 439, 439, 502, 439, 339, 340, 439,
+ 339, 340, 502, 502, 502, 502, 502, 502, 505, 505,
+ 505, 505, 439, 533, 582, 576, 505, 574, 579, 534,
+ 575, 439, 439, 505, 505, 505, 505, 505, 505, 567,
+
+ 567, 567, 567, 590, 339, 340, 338, 567, 577, 583,
+ 439, 439, 625, 591, 567, 567, 567, 567, 567, 567,
+ 439, 439, 624, 439, 439, 439, 439, 439, 439, 439,
+ 616, 617, 439, 623, 616, 617, 685, 686, 685, 686,
+ 756, 628, 626, 632, 708, 755, 634, 685, 686, 302,
+ 302, 627, 629, 754, 753, 630, 631, 633, 752, 751,
+ 750, 709, 669, 52, 52, 52, 52, 52, 52, 52,
+ 52, 52, 52, 52, 52, 52, 52, 52, 52, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 72, 72, 72, 72, 72,
+
+ 72, 72, 72, 72, 72, 72, 72, 72, 72, 72,
+ 72, 76, 76, 76, 76, 76, 76, 76, 76, 76,
+ 76, 76, 76, 76, 76, 76, 76, 86, 86, 86,
+ 86, 86, 86, 86, 86, 86, 86, 86, 86, 86,
+ 86, 86, 86, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 95,
+ 95, 95, 95, 95, 95, 95, 95, 95, 95, 95,
+ 95, 95, 95, 95, 95, 101, 101, 101, 101, 101,
+ 101, 101, 101, 101, 101, 101, 101, 101, 101, 101,
+ 101, 106, 106, 106, 106, 106, 106, 106, 106, 106,
+
+ 106, 106, 106, 106, 106, 106, 106, 110, 110, 110,
+ 110, 110, 110, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 128, 128, 128, 128, 128, 128, 128,
+ 128, 128, 128, 128, 128, 128, 128, 128, 128, 131,
+ 131, 131, 131, 131, 131, 131, 131, 131, 131, 131,
+ 131, 131, 131, 131, 131, 135, 135, 135, 135, 135,
+ 135, 135, 135, 135, 135, 135, 135, 135, 135, 135,
+ 135, 177, 177, 177, 177, 177, 177, 177, 177, 177,
+ 177, 177, 177, 177, 177, 177, 177, 184, 184, 184,
+ 184, 749, 748, 184, 184, 184, 190, 190, 190, 190,
+
+ 190, 190, 190, 190, 190, 190, 190, 190, 190, 190,
+ 190, 200, 200, 200, 200, 747, 746, 200, 200, 200,
+ 209, 745, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 212, 744, 212, 212,
+ 212, 212, 212, 212, 212, 212, 212, 212, 212, 212,
+ 212, 212, 216, 216, 216, 743, 742, 216, 216, 216,
+ 227, 741, 227, 227, 227, 227, 227, 227, 227, 227,
+ 227, 227, 227, 227, 227, 227, 229, 740, 229, 229,
+ 229, 229, 229, 229, 229, 229, 229, 229, 229, 229,
+ 229, 229, 230, 739, 230, 230, 230, 230, 230, 230,
+
+ 230, 230, 230, 230, 230, 230, 230, 230, 234, 234,
+ 234, 234, 234, 234, 234, 234, 234, 234, 234, 234,
+ 234, 234, 234, 234, 236, 738, 236, 236, 737, 236,
+ 236, 236, 736, 735, 236, 236, 734, 733, 732, 236,
+ 238, 238, 238, 238, 731, 730, 238, 238, 238, 242,
+ 729, 242, 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 246, 246, 246, 246, 728,
+ 727, 246, 246, 246, 251, 726, 251, 251, 251, 251,
+ 251, 251, 251, 251, 251, 251, 251, 251, 251, 251,
+ 254, 725, 254, 254, 254, 254, 254, 254, 254, 254,
+
+ 254, 724, 254, 254, 254, 254, 255, 723, 720, 719,
+ 255, 255, 255, 255, 718, 717, 255, 255, 257, 716,
+ 257, 257, 257, 257, 257, 257, 257, 257, 257, 257,
+ 257, 257, 257, 257, 261, 261, 261, 261, 715, 714,
+ 261, 261, 261, 264, 264, 264, 264, 264, 264, 264,
+ 264, 264, 264, 264, 264, 264, 264, 264, 264, 267,
+ 267, 267, 267, 713, 267, 267, 267, 267, 267, 267,
+ 267, 267, 267, 267, 267, 271, 712, 711, 271, 271,
+ 271, 271, 271, 271, 271, 710, 271, 271, 271, 271,
+ 271, 273, 707, 273, 273, 273, 273, 273, 273, 273,
+
+ 273, 273, 273, 273, 273, 273, 273, 274, 706, 274,
+ 274, 705, 274, 274, 274, 704, 703, 274, 274, 702,
+ 701, 700, 274, 279, 279, 279, 279, 699, 698, 279,
+ 279, 279, 284, 697, 284, 284, 284, 284, 284, 284,
+ 284, 284, 284, 284, 284, 284, 284, 284, 288, 288,
+ 696, 288, 288, 695, 694, 693, 288, 288, 315, 692,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 315, 315, 319, 691, 319, 319, 319, 319,
+ 319, 319, 319, 319, 319, 319, 319, 319, 319, 319,
+ 320, 690, 320, 320, 320, 320, 320, 320, 320, 320,
+
+ 320, 320, 320, 320, 320, 320, 328, 328, 689, 688,
+ 328, 328, 328, 329, 329, 687, 683, 329, 329, 329,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+ 330, 330, 330, 330, 330, 330, 334, 334, 334, 334,
+ 334, 334, 334, 334, 334, 334, 334, 334, 334, 334,
+ 334, 334, 338, 682, 338, 338, 338, 338, 338, 338,
+ 338, 338, 338, 681, 338, 338, 338, 338, 209, 680,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 345, 345, 679, 678, 677, 676,
+ 345, 346, 346, 346, 346, 675, 674, 346, 346, 346,
+
+ 346, 351, 673, 351, 351, 351, 351, 351, 351, 351,
+ 351, 351, 351, 351, 351, 351, 351, 227, 672, 227,
+ 227, 227, 227, 227, 227, 227, 227, 227, 227, 227,
+ 227, 227, 227, 229, 671, 229, 229, 229, 229, 229,
+ 229, 229, 229, 229, 229, 229, 229, 229, 229, 230,
+ 670, 230, 230, 230, 230, 230, 230, 230, 230, 230,
+ 230, 230, 230, 230, 230, 353, 668, 353, 353, 353,
+ 353, 353, 353, 353, 353, 353, 353, 353, 353, 353,
+ 353, 354, 667, 354, 354, 354, 354, 354, 354, 354,
+ 354, 354, 354, 354, 354, 354, 354, 234, 234, 234,
+
+ 234, 234, 234, 234, 234, 234, 234, 234, 234, 234,
+ 234, 234, 234, 236, 666, 236, 236, 665, 236, 236,
+ 236, 664, 663, 236, 236, 662, 661, 660, 236, 238,
+ 238, 238, 238, 659, 658, 238, 238, 238, 242, 657,
+ 242, 242, 242, 242, 242, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 246, 246, 246, 246, 656, 655,
+ 246, 246, 246, 361, 361, 654, 653, 652, 361, 361,
+ 255, 651, 650, 649, 255, 255, 255, 255, 648, 647,
+ 255, 255, 257, 646, 257, 257, 257, 257, 257, 257,
+ 257, 257, 257, 257, 257, 257, 257, 257, 261, 261,
+
+ 261, 261, 645, 644, 261, 261, 261, 264, 264, 264,
+ 264, 264, 264, 264, 264, 264, 264, 264, 264, 264,
+ 264, 264, 264, 267, 267, 267, 267, 643, 267, 267,
+ 267, 267, 267, 267, 267, 267, 267, 267, 267, 271,
+ 642, 641, 271, 271, 271, 271, 271, 271, 271, 640,
+ 271, 271, 271, 271, 271, 274, 639, 274, 274, 638,
+ 274, 274, 274, 637, 636, 274, 274, 635, 622, 621,
+ 274, 279, 279, 279, 279, 620, 619, 279, 279, 279,
+ 284, 618, 284, 284, 284, 284, 284, 284, 284, 284,
+ 284, 284, 284, 284, 284, 284, 288, 288, 560, 288,
+
+ 288, 614, 613, 612, 288, 288, 315, 611, 315, 315,
+ 315, 315, 315, 315, 315, 315, 315, 315, 315, 315,
+ 315, 315, 319, 610, 319, 319, 319, 319, 319, 319,
+ 319, 319, 319, 319, 319, 319, 319, 319, 320, 609,
+ 320, 320, 320, 320, 320, 320, 320, 320, 320, 320,
+ 320, 320, 320, 320, 415, 415, 415, 415, 415, 415,
+ 415, 415, 415, 415, 415, 415, 415, 415, 415, 415,
+ 424, 424, 424, 424, 608, 607, 424, 424, 424, 425,
+ 425, 425, 425, 606, 605, 425, 425, 425, 330, 330,
+ 330, 330, 330, 330, 330, 330, 330, 330, 330, 330,
+
+ 330, 330, 330, 330, 334, 334, 334, 334, 334, 334,
+ 334, 334, 334, 334, 334, 334, 334, 334, 334, 334,
+ 338, 604, 338, 338, 338, 338, 338, 338, 338, 338,
+ 338, 603, 338, 338, 338, 338, 433, 433, 602, 601,
+ 600, 599, 433, 346, 346, 346, 346, 598, 597, 346,
+ 346, 346, 346, 351, 596, 351, 351, 351, 351, 351,
+ 351, 351, 351, 351, 351, 351, 351, 351, 351, 615,
+ 615, 615, 615, 615, 615, 615, 615, 615, 615, 615,
+ 615, 615, 615, 615, 615, 684, 684, 684, 684, 684,
+ 684, 684, 684, 684, 684, 684, 684, 684, 684, 684,
+
+ 684, 595, 594, 593, 592, 589, 588, 587, 586, 585,
+ 584, 571, 570, 569, 568, 565, 564, 563, 562, 561,
+ 560, 559, 558, 557, 556, 555, 554, 551, 550, 549,
+ 548, 547, 546, 545, 544, 543, 542, 541, 540, 539,
+ 538, 537, 536, 535, 531, 530, 529, 528, 527, 526,
+ 525, 524, 523, 510, 509, 508, 507, 506, 503, 499,
+ 498, 497, 496, 492, 491, 490, 489, 488, 484, 483,
+ 482, 479, 478, 477, 476, 475, 474, 473, 472, 471,
+ 470, 469, 468, 467, 466, 465, 464, 463, 462, 461,
+ 460, 459, 458, 457, 456, 455, 454, 453, 452, 451,
+
+ 439, 437, 436, 435, 434, 347, 426, 423, 422, 421,
+ 322, 414, 316, 408, 407, 406, 401, 400, 399, 398,
+ 397, 396, 395, 394, 391, 390, 389, 386, 385, 382,
+ 379, 378, 285, 282, 377, 376, 278, 373, 372, 243,
+ 356, 355, 235, 231, 352, 350, 349, 348, 218, 347,
+ 337, 206, 333, 202, 318, 186, 182, 316, 314, 313,
+ 312, 311, 310, 309, 305, 299, 298, 295, 294, 291,
+ 287, 286, 285, 283, 282, 281, 280, 260, 278, 277,
+ 272, 270, 263, 262, 260, 256, 250, 253, 250, 249,
+ 247, 245, 244, 243, 241, 240, 239, 237, 235, 228,
+
+ 231, 228, 226, 218, 208, 202, 199, 186, 182, 768,
+ 94, 94, 85, 77, 77, 39, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768
+ } ;
+
+static yyconst short int yy_chk[2775] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
+ 765, 3, 5, 5, 3, 3, 3, 27, 27, 3,
+ 6, 6, 6, 28, 28, 3, 6, 11, 11, 11,
+ 3, 3, 12, 12, 12, 48, 17, 17, 66, 29,
+ 29, 60, 60, 18, 18, 310, 17, 29, 310, 17,
+ 17, 17, 17, 18, 61, 61, 18, 18, 18, 18,
+ 3, 3, 3, 4, 4, 4, 4, 109, 4, 4,
+ 21, 4, 4, 4, 511, 48, 4, 19, 19, 19,
+ 22, 109, 4, 20, 20, 20, 66, 4, 4, 141,
+
+ 4, 17, 61, 21, 21, 141, 21, 37, 18, 37,
+ 75, 19, 75, 22, 22, 511, 22, 20, 30, 30,
+ 37, 37, 37, 37, 128, 128, 30, 4, 4, 4,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 23, 23, 163, 24,
+ 24, 38, 764, 38, 41, 41, 41, 23, 130, 130,
+ 24, 45, 45, 45, 38, 38, 38, 38, 163, 23,
+ 23, 23, 24, 24, 24, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 25, 25, 31, 31, 31, 32, 32, 32, 57,
+ 57, 57, 62, 62, 62, 62, 99, 99, 99, 99,
+ 131, 131, 133, 133, 167, 198, 198, 31, 167, 763,
+ 32, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 33, 33, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 49, 53, 53,
+ 53, 121, 105, 105, 53, 158, 108, 108, 115, 115,
+ 160, 158, 63, 63, 63, 291, 168, 275, 63, 121,
+
+ 49, 188, 49, 275, 49, 63, 168, 205, 205, 160,
+ 49, 63, 291, 49, 49, 49, 405, 49, 49, 63,
+ 105, 170, 405, 49, 108, 49, 115, 180, 180, 180,
+ 180, 170, 762, 53, 170, 181, 181, 181, 185, 185,
+ 185, 188, 192, 192, 192, 209, 209, 63, 193, 193,
+ 193, 294, 194, 194, 194, 294, 192, 192, 192, 192,
+ 211, 211, 193, 193, 193, 193, 194, 194, 194, 194,
+ 195, 195, 195, 201, 201, 201, 210, 213, 213, 201,
+ 289, 257, 210, 210, 195, 195, 195, 195, 192, 217,
+ 217, 217, 264, 264, 289, 217, 194, 362, 211, 257,
+
+ 266, 266, 217, 248, 248, 248, 248, 761, 217, 267,
+ 267, 269, 269, 195, 298, 309, 217, 314, 298, 362,
+ 314, 321, 321, 321, 309, 330, 330, 760, 201, 314,
+ 314, 317, 317, 317, 317, 321, 321, 321, 321, 708,
+ 314, 332, 332, 708, 217, 241, 241, 241, 241, 241,
+ 241, 241, 241, 241, 241, 241, 241, 241, 241, 241,
+ 241, 241, 241, 241, 241, 241, 241, 241, 241, 241,
+ 241, 241, 241, 241, 241, 241, 241, 241, 241, 241,
+ 241, 241, 241, 241, 241, 241, 241, 241, 241, 241,
+ 241, 241, 241, 241, 241, 241, 241, 241, 241, 241,
+
+ 241, 241, 241, 250, 250, 250, 250, 334, 334, 250,
+ 336, 336, 338, 338, 250, 344, 344, 757, 250, 415,
+ 415, 250, 756, 250, 418, 418, 250, 278, 278, 755,
+ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+ 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+ 278, 278, 278, 278, 278, 324, 324, 324, 339, 363,
+ 364, 340, 340, 365, 339, 339, 342, 342, 366, 324,
+
+ 324, 324, 324, 340, 371, 409, 342, 342, 409, 409,
+ 441, 363, 365, 444, 364, 420, 420, 420, 371, 485,
+ 754, 441, 494, 494, 444, 485, 366, 504, 504, 340,
+ 341, 341, 367, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 367, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 341, 341, 341,
+ 341, 341, 341, 341, 341, 341, 341, 341, 343, 343,
+ 343, 343, 752, 369, 505, 505, 343, 750, 343, 343,
+
+ 495, 495, 495, 343, 343, 343, 343, 343, 343, 360,
+ 360, 368, 360, 360, 360, 360, 360, 360, 360, 369,
+ 360, 360, 360, 360, 360, 360, 360, 360, 360, 360,
+ 360, 360, 370, 442, 360, 360, 360, 360, 443, 368,
+ 428, 428, 368, 431, 431, 416, 416, 416, 561, 561,
+ 428, 428, 749, 431, 431, 443, 519, 445, 370, 416,
+ 416, 416, 416, 442, 360, 360, 360, 375, 375, 519,
+ 375, 375, 375, 375, 375, 375, 375, 440, 375, 375,
+ 375, 375, 375, 375, 375, 375, 375, 375, 375, 375,
+ 445, 447, 375, 375, 375, 375, 419, 419, 419, 446,
+
+ 450, 440, 449, 440, 520, 448, 503, 503, 503, 512,
+ 419, 419, 419, 419, 517, 447, 448, 520, 446, 450,
+ 501, 501, 375, 375, 375, 427, 427, 512, 449, 517,
+ 501, 501, 427, 427, 427, 427, 427, 427, 427, 427,
+ 427, 427, 427, 427, 427, 427, 427, 427, 427, 427,
+ 427, 427, 427, 427, 427, 427, 427, 429, 429, 429,
+ 429, 462, 514, 513, 518, 429, 515, 566, 566, 521,
+ 567, 567, 429, 429, 429, 429, 429, 429, 432, 432,
+ 432, 432, 516, 462, 521, 515, 432, 513, 518, 462,
+ 514, 574, 522, 432, 432, 432, 432, 432, 432, 502,
+
+ 502, 502, 502, 532, 565, 565, 565, 502, 516, 522,
+ 572, 573, 574, 532, 502, 502, 502, 502, 502, 502,
+ 575, 576, 573, 577, 578, 579, 580, 583, 581, 582,
+ 615, 615, 634, 572, 617, 617, 656, 656, 684, 684,
+ 748, 577, 575, 581, 681, 747, 583, 686, 686, 810,
+ 810, 576, 578, 745, 744, 579, 580, 582, 743, 742,
+ 740, 681, 634, 769, 769, 769, 769, 769, 769, 769,
+ 769, 769, 769, 769, 769, 769, 769, 769, 769, 770,
+ 770, 770, 770, 770, 770, 770, 770, 770, 770, 770,
+ 770, 770, 770, 770, 770, 771, 771, 771, 771, 771,
+
+ 771, 771, 771, 771, 771, 771, 771, 771, 771, 771,
+ 771, 772, 772, 772, 772, 772, 772, 772, 772, 772,
+ 772, 772, 772, 772, 772, 772, 772, 773, 773, 773,
+ 773, 773, 773, 773, 773, 773, 773, 773, 773, 773,
+ 773, 773, 773, 774, 774, 774, 774, 774, 774, 774,
+ 774, 774, 774, 774, 774, 774, 774, 774, 774, 775,
+ 775, 775, 775, 775, 775, 775, 775, 775, 775, 775,
+ 775, 775, 775, 775, 775, 776, 776, 776, 776, 776,
+ 776, 776, 776, 776, 776, 776, 776, 776, 776, 776,
+ 776, 777, 777, 777, 777, 777, 777, 777, 777, 777,
+
+ 777, 777, 777, 777, 777, 777, 777, 778, 778, 778,
+ 778, 778, 778, 778, 778, 778, 778, 778, 778, 778,
+ 778, 778, 778, 779, 779, 779, 779, 779, 779, 779,
+ 779, 779, 779, 779, 779, 779, 779, 779, 779, 780,
+ 780, 780, 780, 780, 780, 780, 780, 780, 780, 780,
+ 780, 780, 780, 780, 780, 781, 781, 781, 781, 781,
+ 781, 781, 781, 781, 781, 781, 781, 781, 781, 781,
+ 781, 782, 782, 782, 782, 782, 782, 782, 782, 782,
+ 782, 782, 782, 782, 782, 782, 782, 783, 783, 783,
+ 783, 739, 738, 783, 783, 783, 784, 784, 784, 784,
+
+ 784, 784, 784, 784, 784, 784, 784, 784, 784, 784,
+ 784, 785, 785, 785, 785, 737, 736, 785, 785, 785,
+ 786, 735, 786, 786, 786, 786, 786, 786, 786, 786,
+ 786, 786, 786, 786, 786, 786, 787, 734, 787, 787,
+ 787, 787, 787, 787, 787, 787, 787, 787, 787, 787,
+ 787, 787, 788, 788, 788, 733, 732, 788, 788, 788,
+ 789, 731, 789, 789, 789, 789, 789, 789, 789, 789,
+ 789, 789, 789, 789, 789, 789, 790, 729, 790, 790,
+ 790, 790, 790, 790, 790, 790, 790, 790, 790, 790,
+ 790, 790, 791, 727, 791, 791, 791, 791, 791, 791,
+
+ 791, 791, 791, 791, 791, 791, 791, 791, 792, 792,
+ 792, 792, 792, 792, 792, 792, 792, 792, 792, 792,
+ 792, 792, 792, 792, 793, 726, 793, 793, 725, 793,
+ 793, 793, 724, 723, 793, 793, 722, 721, 720, 793,
+ 794, 794, 794, 794, 719, 718, 794, 794, 794, 795,
+ 717, 795, 795, 795, 795, 795, 795, 795, 795, 795,
+ 795, 795, 795, 795, 795, 796, 796, 796, 796, 715,
+ 714, 796, 796, 796, 797, 713, 797, 797, 797, 797,
+ 797, 797, 797, 797, 797, 797, 797, 797, 797, 797,
+ 798, 712, 798, 798, 798, 798, 798, 798, 798, 798,
+
+ 798, 710, 798, 798, 798, 798, 799, 709, 707, 706,
+ 799, 799, 799, 799, 705, 704, 799, 799, 800, 703,
+ 800, 800, 800, 800, 800, 800, 800, 800, 800, 800,
+ 800, 800, 800, 800, 801, 801, 801, 801, 702, 701,
+ 801, 801, 801, 802, 802, 802, 802, 802, 802, 802,
+ 802, 802, 802, 802, 802, 802, 802, 802, 802, 803,
+ 803, 803, 803, 700, 803, 803, 803, 803, 803, 803,
+ 803, 803, 803, 803, 803, 804, 699, 698, 804, 804,
+ 804, 804, 804, 804, 804, 682, 804, 804, 804, 804,
+ 804, 805, 680, 805, 805, 805, 805, 805, 805, 805,
+
+ 805, 805, 805, 805, 805, 805, 805, 806, 679, 806,
+ 806, 678, 806, 806, 806, 677, 675, 806, 806, 674,
+ 672, 671, 806, 807, 807, 807, 807, 670, 669, 807,
+ 807, 807, 808, 668, 808, 808, 808, 808, 808, 808,
+ 808, 808, 808, 808, 808, 808, 808, 808, 809, 809,
+ 667, 809, 809, 666, 665, 664, 809, 809, 811, 663,
+ 811, 811, 811, 811, 811, 811, 811, 811, 811, 811,
+ 811, 811, 811, 811, 812, 662, 812, 812, 812, 812,
+ 812, 812, 812, 812, 812, 812, 812, 812, 812, 812,
+ 813, 661, 813, 813, 813, 813, 813, 813, 813, 813,
+
+ 813, 813, 813, 813, 813, 813, 814, 814, 660, 659,
+ 814, 814, 814, 815, 815, 658, 655, 815, 815, 815,
+ 816, 816, 816, 816, 816, 816, 816, 816, 816, 816,
+ 816, 816, 816, 816, 816, 816, 817, 817, 817, 817,
+ 817, 817, 817, 817, 817, 817, 817, 817, 817, 817,
+ 817, 817, 818, 653, 818, 818, 818, 818, 818, 818,
+ 818, 818, 818, 652, 818, 818, 818, 818, 819, 651,
+ 819, 819, 819, 819, 819, 819, 819, 819, 819, 819,
+ 819, 819, 819, 819, 820, 820, 650, 646, 644, 643,
+ 820, 821, 821, 821, 821, 642, 641, 821, 821, 821,
+
+ 821, 822, 639, 822, 822, 822, 822, 822, 822, 822,
+ 822, 822, 822, 822, 822, 822, 822, 823, 637, 823,
+ 823, 823, 823, 823, 823, 823, 823, 823, 823, 823,
+ 823, 823, 823, 824, 636, 824, 824, 824, 824, 824,
+ 824, 824, 824, 824, 824, 824, 824, 824, 824, 825,
+ 635, 825, 825, 825, 825, 825, 825, 825, 825, 825,
+ 825, 825, 825, 825, 825, 826, 633, 826, 826, 826,
+ 826, 826, 826, 826, 826, 826, 826, 826, 826, 826,
+ 826, 827, 632, 827, 827, 827, 827, 827, 827, 827,
+ 827, 827, 827, 827, 827, 827, 827, 828, 828, 828,
+
+ 828, 828, 828, 828, 828, 828, 828, 828, 828, 828,
+ 828, 828, 828, 829, 631, 829, 829, 630, 829, 829,
+ 829, 629, 628, 829, 829, 627, 626, 625, 829, 830,
+ 830, 830, 830, 624, 623, 830, 830, 830, 831, 621,
+ 831, 831, 831, 831, 831, 831, 831, 831, 831, 831,
+ 831, 831, 831, 831, 832, 832, 832, 832, 619, 612,
+ 832, 832, 832, 833, 833, 611, 610, 609, 833, 833,
+ 834, 608, 607, 606, 834, 834, 834, 834, 604, 601,
+ 834, 834, 835, 600, 835, 835, 835, 835, 835, 835,
+ 835, 835, 835, 835, 835, 835, 835, 835, 836, 836,
+
+ 836, 836, 599, 598, 836, 836, 836, 837, 837, 837,
+ 837, 837, 837, 837, 837, 837, 837, 837, 837, 837,
+ 837, 837, 837, 838, 838, 838, 838, 597, 838, 838,
+ 838, 838, 838, 838, 838, 838, 838, 838, 838, 839,
+ 596, 595, 839, 839, 839, 839, 839, 839, 839, 594,
+ 839, 839, 839, 839, 839, 840, 593, 840, 840, 592,
+ 840, 840, 840, 591, 590, 840, 840, 588, 569, 568,
+ 840, 841, 841, 841, 841, 564, 563, 841, 841, 841,
+ 842, 562, 842, 842, 842, 842, 842, 842, 842, 842,
+ 842, 842, 842, 842, 842, 842, 843, 843, 560, 843,
+
+ 843, 559, 558, 557, 843, 843, 844, 556, 844, 844,
+ 844, 844, 844, 844, 844, 844, 844, 844, 844, 844,
+ 844, 844, 845, 555, 845, 845, 845, 845, 845, 845,
+ 845, 845, 845, 845, 845, 845, 845, 845, 846, 554,
+ 846, 846, 846, 846, 846, 846, 846, 846, 846, 846,
+ 846, 846, 846, 846, 847, 847, 847, 847, 847, 847,
+ 847, 847, 847, 847, 847, 847, 847, 847, 847, 847,
+ 848, 848, 848, 848, 553, 552, 848, 848, 848, 849,
+ 849, 849, 849, 551, 549, 849, 849, 849, 850, 850,
+ 850, 850, 850, 850, 850, 850, 850, 850, 850, 850,
+
+ 850, 850, 850, 850, 851, 851, 851, 851, 851, 851,
+ 851, 851, 851, 851, 851, 851, 851, 851, 851, 851,
+ 852, 548, 852, 852, 852, 852, 852, 852, 852, 852,
+ 852, 546, 852, 852, 852, 852, 853, 853, 545, 544,
+ 543, 542, 853, 854, 854, 854, 854, 541, 540, 854,
+ 854, 854, 854, 855, 539, 855, 855, 855, 855, 855,
+ 855, 855, 855, 855, 855, 855, 855, 855, 855, 856,
+ 856, 856, 856, 856, 856, 856, 856, 856, 856, 856,
+ 856, 856, 856, 856, 856, 857, 857, 857, 857, 857,
+ 857, 857, 857, 857, 857, 857, 857, 857, 857, 857,
+
+ 857, 538, 536, 534, 533, 530, 528, 526, 525, 524,
+ 523, 509, 508, 507, 506, 500, 499, 498, 497, 496,
+ 492, 491, 490, 489, 488, 487, 486, 483, 482, 481,
+ 480, 479, 478, 476, 475, 474, 473, 472, 471, 469,
+ 468, 467, 464, 463, 461, 460, 459, 458, 457, 454,
+ 453, 452, 451, 439, 437, 436, 435, 434, 430, 426,
+ 423, 422, 421, 414, 413, 412, 411, 410, 408, 407,
+ 406, 404, 403, 402, 401, 400, 399, 398, 397, 396,
+ 395, 394, 393, 392, 391, 390, 388, 387, 386, 384,
+ 383, 382, 381, 380, 379, 378, 377, 376, 373, 372,
+
+ 361, 356, 355, 352, 350, 346, 337, 327, 326, 325,
+ 323, 318, 315, 313, 312, 311, 308, 307, 306, 305,
+ 303, 301, 300, 299, 297, 296, 295, 293, 292, 290,
+ 287, 286, 284, 282, 281, 280, 276, 263, 262, 243,
+ 240, 239, 234, 231, 226, 222, 221, 220, 219, 216,
+ 208, 207, 204, 203, 189, 187, 183, 179, 176, 175,
+ 174, 173, 172, 171, 169, 166, 165, 162, 161, 159,
+ 156, 155, 154, 153, 151, 149, 148, 146, 144, 143,
+ 137, 134, 125, 124, 122, 119, 114, 112, 107, 103,
+ 97, 92, 89, 87, 85, 84, 83, 80, 76, 74,
+
+ 73, 71, 67, 65, 59, 55, 50, 47, 43, 39,
+ 16, 15, 10, 8, 7, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768, 768, 768, 768, 768, 768, 768,
+ 768, 768, 768, 768
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "scan.l"
+#define INITIAL 0
+/* scan.l - scanner for flex input */
+#line 4 "scan.l"
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/scan.l,v 2.56 95/04/24 12:17:19 vern Exp $ */
+
+#include "flexdef.h"
+#include "parse.h"
+
+#define ACTION_ECHO add_action( yytext )
+#define ACTION_IFDEF(def, should_define) \
+ { \
+ if ( should_define ) \
+ action_define( def, 1 ); \
+ }
+
+#define MARK_END_OF_PROLOG mark_prolog();
+
+#define YY_DECL \
+ int flexscan()
+
+#define RETURNCHAR \
+ yylval = (unsigned char) yytext[0]; \
+ return CHAR;
+
+#define RETURNNAME \
+ strcpy( nmstr, yytext ); \
+ return NAME;
+
+#define PUT_BACK_STRING(str, start) \
+ for ( i = strlen( str ) - 1; i >= start; --i ) \
+ unput((str)[i])
+
+#define CHECK_REJECT(str) \
+ if ( all_upper( str ) ) \
+ reject = true;
+
+#define CHECK_YYMORE(str) \
+ if ( all_lower( str ) ) \
+ yymore_used = true;
+#define YY_STACK_USED 1
+#define YY_NO_TOP_STATE 1
+#define SECT2 1
+#define SECT2PROLOG 2
+#define SECT3 3
+#define CODEBLOCK 4
+#define PICKUPDEF 5
+#define SC 6
+#define CARETISBOL 7
+#define NUM 8
+#define QUOTE 9
+
+#define FIRSTCCL 10
+#define CCL 11
+#define ACTION 12
+#define RECOVER 13
+#define COMMENT 14
+#define ACTION_STRING 15
+#define PERCENT_BRACE_ACTION 16
+
+#define OPTION 17
+#define LINEDIR 18
+
+#line 1333 "scan.c"
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap YY_PROTO(( void ));
+#else
+extern int yywrap YY_PROTO(( void ));
+#endif
+#endif
+
+#ifndef YY_NO_UNPUT
+static void yyunput YY_PROTO(( int c, char *buf_ptr ));
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen YY_PROTO(( yyconst char * ));
+#endif
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+static int yyinput YY_PROTO(( void ));
+#else
+static int input YY_PROTO(( void ));
+#endif
+#endif
+
+#if YY_STACK_USED
+static int yy_start_stack_ptr = 0;
+static int yy_start_stack_depth = 0;
+static int *yy_start_stack = 0;
+#ifndef YY_NO_PUSH_STATE
+static void yy_push_state YY_PROTO(( int new_state ));
+#endif
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state YY_PROTO(( void ));
+#endif
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state YY_PROTO(( void ));
+#endif
+
+#else
+#define YY_NO_PUSH_STATE 1
+#define YY_NO_POP_STATE 1
+#define YY_NO_TOP_STATE 1
+#endif
+
+#ifdef YY_MALLOC_DECL
+YY_MALLOC_DECL
+#else
+#if __STDC__
+#ifndef __cplusplus
+#include <stdlib.h>
+#endif
+#else
+/* Just try to get by without declaring the routines. This will fail
+ * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)
+ * or sizeof(void*) != sizeof(int).
+ */
+#endif
+#endif
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#define YY_READ_BUF_SIZE 8192
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( yy_current_buffer->yy_is_interactive ) \
+ { \
+ int c = '*', n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \
+ && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" );
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL int yylex YY_PROTO(( void ))
+#endif
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ if ( yyleng > 0 ) \
+ yy_current_buffer->yy_at_bol = \
+ (yytext[yyleng - 1] == '\n'); \
+ YY_USER_ACTION
+
+YY_DECL
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+#line 94 "scan.l"
+
+ static int bracelevel, didadef, indented_code;
+ static int doing_rule_action = false;
+ static int option_sense;
+
+ int doing_codeblock = false;
+ int i;
+ Char nmdef[MAXLINE], myesc();
+
+
+#line 1498 "scan.c"
+
+ if ( yy_init )
+ {
+ yy_init = 0;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! yy_start )
+ yy_start = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! yy_current_buffer )
+ yy_current_buffer =
+ yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_load_buffer_state();
+ }
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = yy_c_buf_p;
+
+ /* Support of yytext. */
+ *yy_cp = yy_hold_char;
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = yy_start;
+ yy_current_state += YY_AT_BOL();
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 769 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 2716 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+
+do_action: /* This label is used only to access EOF actions. */
+
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = yy_hold_char;
+ yy_cp = yy_last_accepting_cpos;
+ yy_current_state = yy_last_accepting_state;
+ goto yy_find_action;
+
+
+case 1:
+YY_RULE_SETUP
+#line 105 "scan.l"
+indented_code = true; BEGIN(CODEBLOCK);
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 106 "scan.l"
+ACTION_ECHO; yy_push_state( COMMENT );
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 107 "scan.l"
+yy_push_state( LINEDIR );
+ YY_BREAK
+case 4:
+YY_RULE_SETUP
+#line 108 "scan.l"
+return SCDECL;
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 109 "scan.l"
+return XSCDECL;
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 110 "scan.l"
+{
+ ++linenum;
+ line_directive_out( (FILE *) 0, 1 );
+ indented_code = false;
+ BEGIN(CODEBLOCK);
+ }
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 117 "scan.l"
+/* discard */
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 119 "scan.l"
+{
+ sectnum = 2;
+ bracelevel = 0;
+ mark_defs1();
+ line_directive_out( (FILE *) 0, 1 );
+ BEGIN(SECT2PROLOG);
+ return SECTEND;
+ }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 128 "scan.l"
+yytext_is_array = false; ++linenum;
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 129 "scan.l"
+yytext_is_array = true; ++linenum;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 131 "scan.l"
+BEGIN(OPTION); return OPTION_OP;
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 133 "scan.l"
+++linenum; /* ignore */
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 134 "scan.l"
+++linenum; /* ignore */
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 136 "scan.l"
+synerr( _( "unrecognized '%' directive" ) );
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 138 "scan.l"
+{
+ strcpy( nmstr, yytext );
+ didadef = false;
+ BEGIN(PICKUPDEF);
+ }
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 144 "scan.l"
+RETURNNAME;
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 145 "scan.l"
+++linenum; /* allows blank lines in section 1 */
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 146 "scan.l"
+ACTION_ECHO; ++linenum; /* maybe end of comment line */
+ YY_BREAK
+
+
+case 19:
+YY_RULE_SETUP
+#line 151 "scan.l"
+ACTION_ECHO; yy_pop_state();
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 152 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 153 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 154 "scan.l"
+++linenum; ACTION_ECHO;
+ YY_BREAK
+
+
+case 23:
+YY_RULE_SETUP
+#line 158 "scan.l"
+yy_pop_state();
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 159 "scan.l"
+linenum = myctoi( yytext );
+ YY_BREAK
+case 25:
+YY_RULE_SETUP
+#line 161 "scan.l"
+{
+ flex_free( (void *) infilename );
+ infilename = copy_string( yytext + 1 );
+ infilename[strlen( infilename ) - 1] = '\0';
+ }
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 166 "scan.l"
+/* ignore spurious characters */
+ YY_BREAK
+
+
+case 27:
+YY_RULE_SETUP
+#line 170 "scan.l"
+++linenum; BEGIN(INITIAL);
+ YY_BREAK
+case 28:
+YY_RULE_SETUP
+#line 172 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 174 "scan.l"
+{
+ ++linenum;
+ ACTION_ECHO;
+ if ( indented_code )
+ BEGIN(INITIAL);
+ }
+ YY_BREAK
+
+
+case 30:
+YY_RULE_SETUP
+#line 184 "scan.l"
+/* separates name and definition */
+ YY_BREAK
+case 31:
+YY_RULE_SETUP
+#line 186 "scan.l"
+{
+ strcpy( (char *) nmdef, yytext );
+
+ /* Skip trailing whitespace. */
+ for ( i = strlen( (char *) nmdef ) - 1;
+ i >= 0 && (nmdef[i] == ' ' || nmdef[i] == '\t');
+ --i )
+ ;
+
+ nmdef[i + 1] = '\0';
+
+ ndinstal( nmstr, nmdef );
+ didadef = true;
+ }
+ YY_BREAK
+case 32:
+YY_RULE_SETUP
+#line 201 "scan.l"
+{
+ if ( ! didadef )
+ synerr( _( "incomplete name definition" ) );
+ BEGIN(INITIAL);
+ ++linenum;
+ }
+ YY_BREAK
+
+
+case 33:
+YY_RULE_SETUP
+#line 211 "scan.l"
+++linenum; BEGIN(INITIAL);
+ YY_BREAK
+case 34:
+YY_RULE_SETUP
+#line 212 "scan.l"
+option_sense = true;
+ YY_BREAK
+case 35:
+YY_RULE_SETUP
+#line 214 "scan.l"
+return '=';
+ YY_BREAK
+case 36:
+YY_RULE_SETUP
+#line 216 "scan.l"
+option_sense = ! option_sense;
+ YY_BREAK
+case 37:
+YY_RULE_SETUP
+#line 218 "scan.l"
+csize = option_sense ? 128 : 256;
+ YY_BREAK
+case 38:
+YY_RULE_SETUP
+#line 219 "scan.l"
+csize = option_sense ? 256 : 128;
+ YY_BREAK
+case 39:
+YY_RULE_SETUP
+#line 221 "scan.l"
+long_align = option_sense;
+ YY_BREAK
+case 40:
+YY_RULE_SETUP
+#line 222 "scan.l"
+{
+ action_define( "YY_ALWAYS_INTERACTIVE", option_sense );
+ }
+ YY_BREAK
+case 41:
+YY_RULE_SETUP
+#line 225 "scan.l"
+yytext_is_array = option_sense;
+ YY_BREAK
+case 42:
+YY_RULE_SETUP
+#line 226 "scan.l"
+backing_up_report = option_sense;
+ YY_BREAK
+case 43:
+YY_RULE_SETUP
+#line 227 "scan.l"
+interactive = ! option_sense;
+ YY_BREAK
+case 44:
+YY_RULE_SETUP
+#line 228 "scan.l"
+C_plus_plus = option_sense;
+ YY_BREAK
+case 45:
+YY_RULE_SETUP
+#line 229 "scan.l"
+caseins = ! option_sense;
+ YY_BREAK
+case 46:
+YY_RULE_SETUP
+#line 230 "scan.l"
+caseins = option_sense;
+ YY_BREAK
+case 47:
+YY_RULE_SETUP
+#line 231 "scan.l"
+ddebug = option_sense;
+ YY_BREAK
+case 48:
+YY_RULE_SETUP
+#line 232 "scan.l"
+spprdflt = ! option_sense;
+ YY_BREAK
+case 49:
+YY_RULE_SETUP
+#line 233 "scan.l"
+useecs = option_sense;
+ YY_BREAK
+case 50:
+YY_RULE_SETUP
+#line 234 "scan.l"
+{
+ useecs = usemecs = false;
+ use_read = fullspd = true;
+ }
+ YY_BREAK
+case 51:
+YY_RULE_SETUP
+#line 238 "scan.l"
+{
+ useecs = usemecs = false;
+ use_read = fulltbl = true;
+ }
+ YY_BREAK
+case 52:
+YY_RULE_SETUP
+#line 242 "scan.l"
+ACTION_IFDEF("YY_NO_INPUT", ! option_sense);
+ YY_BREAK
+case 53:
+YY_RULE_SETUP
+#line 243 "scan.l"
+interactive = option_sense;
+ YY_BREAK
+case 54:
+YY_RULE_SETUP
+#line 244 "scan.l"
+lex_compat = option_sense;
+ YY_BREAK
+case 55:
+YY_RULE_SETUP
+#line 245 "scan.l"
+{
+ action_define( "YY_MAIN", option_sense );
+ do_yywrap = ! option_sense;
+ }
+ YY_BREAK
+case 56:
+YY_RULE_SETUP
+#line 249 "scan.l"
+usemecs = option_sense;
+ YY_BREAK
+case 57:
+YY_RULE_SETUP
+#line 250 "scan.l"
+{
+ action_define( "YY_NEVER_INTERACTIVE", option_sense );
+ }
+ YY_BREAK
+case 58:
+YY_RULE_SETUP
+#line 253 "scan.l"
+performance_report += option_sense ? 1 : -1;
+ YY_BREAK
+case 59:
+YY_RULE_SETUP
+#line 254 "scan.l"
+yytext_is_array = ! option_sense;
+ YY_BREAK
+case 60:
+YY_RULE_SETUP
+#line 255 "scan.l"
+use_read = option_sense;
+ YY_BREAK
+case 61:
+YY_RULE_SETUP
+#line 256 "scan.l"
+reject_really_used = option_sense;
+ YY_BREAK
+case 62:
+YY_RULE_SETUP
+#line 257 "scan.l"
+action_define( "YY_STACK_USED", option_sense );
+ YY_BREAK
+case 63:
+YY_RULE_SETUP
+#line 258 "scan.l"
+do_stdinit = option_sense;
+ YY_BREAK
+case 64:
+YY_RULE_SETUP
+#line 259 "scan.l"
+use_stdout = option_sense;
+ YY_BREAK
+case 65:
+YY_RULE_SETUP
+#line 260 "scan.l"
+ACTION_IFDEF("YY_NO_UNPUT", ! option_sense);
+ YY_BREAK
+case 66:
+YY_RULE_SETUP
+#line 261 "scan.l"
+printstats = option_sense;
+ YY_BREAK
+case 67:
+YY_RULE_SETUP
+#line 262 "scan.l"
+nowarn = ! option_sense;
+ YY_BREAK
+case 68:
+YY_RULE_SETUP
+#line 263 "scan.l"
+do_yylineno = option_sense;
+ YY_BREAK
+case 69:
+YY_RULE_SETUP
+#line 264 "scan.l"
+yymore_really_used = option_sense;
+ YY_BREAK
+case 70:
+YY_RULE_SETUP
+#line 265 "scan.l"
+do_yywrap = option_sense;
+ YY_BREAK
+case 71:
+YY_RULE_SETUP
+#line 267 "scan.l"
+ACTION_IFDEF("YY_NO_PUSH_STATE", ! option_sense);
+ YY_BREAK
+case 72:
+YY_RULE_SETUP
+#line 268 "scan.l"
+ACTION_IFDEF("YY_NO_POP_STATE", ! option_sense);
+ YY_BREAK
+case 73:
+YY_RULE_SETUP
+#line 269 "scan.l"
+ACTION_IFDEF("YY_NO_TOP_STATE", ! option_sense);
+ YY_BREAK
+case 74:
+YY_RULE_SETUP
+#line 271 "scan.l"
+ACTION_IFDEF("YY_NO_SCAN_BUFFER", ! option_sense);
+ YY_BREAK
+case 75:
+YY_RULE_SETUP
+#line 272 "scan.l"
+ACTION_IFDEF("YY_NO_SCAN_BYTES", ! option_sense);
+ YY_BREAK
+case 76:
+YY_RULE_SETUP
+#line 273 "scan.l"
+ACTION_IFDEF("YY_NO_SCAN_STRING", ! option_sense);
+ YY_BREAK
+case 77:
+YY_RULE_SETUP
+#line 275 "scan.l"
+return OPT_OUTFILE;
+ YY_BREAK
+case 78:
+YY_RULE_SETUP
+#line 276 "scan.l"
+return OPT_PREFIX;
+ YY_BREAK
+case 79:
+YY_RULE_SETUP
+#line 277 "scan.l"
+return OPT_YYCLASS;
+ YY_BREAK
+case 80:
+YY_RULE_SETUP
+#line 279 "scan.l"
+{
+ strcpy( nmstr, yytext + 1 );
+ nmstr[strlen( nmstr ) - 1] = '\0';
+ return NAME;
+ }
+ YY_BREAK
+case 81:
+YY_RULE_SETUP
+#line 285 "scan.l"
+{
+ format_synerr( _( "unrecognized %%option: %s" ),
+ yytext );
+ BEGIN(RECOVER);
+ }
+ YY_BREAK
+
+case 82:
+YY_RULE_SETUP
+#line 292 "scan.l"
+++linenum; BEGIN(INITIAL);
+ YY_BREAK
+
+case 83:
+YY_RULE_SETUP
+#line 296 "scan.l"
+++bracelevel; yyless( 2 ); /* eat only %{ */
+ YY_BREAK
+case 84:
+YY_RULE_SETUP
+#line 297 "scan.l"
+--bracelevel; yyless( 2 ); /* eat only %} */
+ YY_BREAK
+case 85:
+YY_RULE_SETUP
+#line 299 "scan.l"
+ACTION_ECHO; /* indented code in prolog */
+ YY_BREAK
+case 86:
+YY_RULE_SETUP
+#line 301 "scan.l"
+{ /* non-indented code */
+ if ( bracelevel <= 0 )
+ { /* not in %{ ... %} */
+ yyless( 0 ); /* put it all back */
+ yy_set_bol( 1 );
+ mark_prolog();
+ BEGIN(SECT2);
+ }
+ else
+ ACTION_ECHO;
+ }
+ YY_BREAK
+case 87:
+YY_RULE_SETUP
+#line 313 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 88:
+YY_RULE_SETUP
+#line 314 "scan.l"
+++linenum; ACTION_ECHO;
+ YY_BREAK
+case YY_STATE_EOF(SECT2PROLOG):
+#line 316 "scan.l"
+{
+ mark_prolog();
+ sectnum = 0;
+ yyterminate(); /* to stop the parser */
+ }
+ YY_BREAK
+
+
+case 89:
+YY_RULE_SETUP
+#line 324 "scan.l"
+++linenum; /* allow blank lines in section 2 */
+ YY_BREAK
+case 90:
+YY_RULE_SETUP
+#line 326 "scan.l"
+{
+ indented_code = false;
+ doing_codeblock = true;
+ bracelevel = 1;
+ BEGIN(PERCENT_BRACE_ACTION);
+ }
+ YY_BREAK
+case 91:
+YY_RULE_SETUP
+#line 333 "scan.l"
+BEGIN(SC); return '<';
+ YY_BREAK
+case 92:
+YY_RULE_SETUP
+#line 334 "scan.l"
+return '^';
+ YY_BREAK
+case 93:
+YY_RULE_SETUP
+#line 335 "scan.l"
+BEGIN(QUOTE); return '"';
+ YY_BREAK
+case 94:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 336 "scan.l"
+BEGIN(NUM); return '{';
+ YY_BREAK
+case 95:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 337 "scan.l"
+return '$';
+ YY_BREAK
+case 96:
+YY_RULE_SETUP
+#line 339 "scan.l"
+{
+ bracelevel = 1;
+ BEGIN(PERCENT_BRACE_ACTION);
+
+ if ( in_rule )
+ {
+ doing_rule_action = true;
+ in_rule = false;
+ return '\n';
+ }
+ }
+ YY_BREAK
+case 97:
+YY_RULE_SETUP
+#line 350 "scan.l"
+continued_action = true; ++linenum; return '\n';
+ YY_BREAK
+case 98:
+YY_RULE_SETUP
+#line 352 "scan.l"
+{
+ yyless( yyleng - 2 ); /* put back '/', '*' */
+ bracelevel = 0;
+ continued_action = false;
+ BEGIN(ACTION);
+ }
+ YY_BREAK
+case 99:
+YY_RULE_SETUP
+#line 359 "scan.l"
+/* allow indented rules */
+ YY_BREAK
+case 100:
+YY_RULE_SETUP
+#line 361 "scan.l"
+{
+ /* This rule is separate from the one below because
+ * otherwise we get variable trailing context, so
+ * we can't build the scanner using -{f,F}.
+ */
+ bracelevel = 0;
+ continued_action = false;
+ BEGIN(ACTION);
+
+ if ( in_rule )
+ {
+ doing_rule_action = true;
+ in_rule = false;
+ return '\n';
+ }
+ }
+ YY_BREAK
+case 101:
+YY_RULE_SETUP
+#line 378 "scan.l"
+{
+ bracelevel = 0;
+ continued_action = false;
+ BEGIN(ACTION);
+ unput( '\n' ); /* so <ACTION> sees it */
+
+ if ( in_rule )
+ {
+ doing_rule_action = true;
+ in_rule = false;
+ return '\n';
+ }
+ }
+ YY_BREAK
+case 102:
+#line 393 "scan.l"
+case 103:
+YY_RULE_SETUP
+#line 393 "scan.l"
+return EOF_OP;
+ YY_BREAK
+case 104:
+YY_RULE_SETUP
+#line 395 "scan.l"
+{
+ sectnum = 3;
+ BEGIN(SECT3);
+ yyterminate(); /* to stop the parser */
+ }
+ YY_BREAK
+case 105:
+YY_RULE_SETUP
+#line 401 "scan.l"
+{
+ int cclval;
+
+ strcpy( nmstr, yytext );
+
+ /* Check to see if we've already encountered this
+ * ccl.
+ */
+ if ( (cclval = ccllookup( (Char *) nmstr )) != 0 )
+ {
+ if ( input() != ']' )
+ synerr( _( "bad character class" ) );
+
+ yylval = cclval;
+ ++cclreuse;
+ return PREVCCL;
+ }
+ else
+ {
+ /* We fudge a bit. We know that this ccl will
+ * soon be numbered as lastccl + 1 by cclinit.
+ */
+ cclinstal( (Char *) nmstr, lastccl + 1 );
+
+ /* Push back everything but the leading bracket
+ * so the ccl can be rescanned.
+ */
+ yyless( 1 );
+
+ BEGIN(FIRSTCCL);
+ return '[';
+ }
+ }
+ YY_BREAK
+case 106:
+YY_RULE_SETUP
+#line 435 "scan.l"
+{
+ register Char *nmdefptr;
+ Char *ndlookup();
+
+ strcpy( nmstr, yytext + 1 );
+ nmstr[yyleng - 2] = '\0'; /* chop trailing brace */
+
+ if ( (nmdefptr = ndlookup( nmstr )) == 0 )
+ format_synerr(
+ _( "undefined definition {%s}" ),
+ nmstr );
+
+ else
+ { /* push back name surrounded by ()'s */
+ int len = strlen( (char *) nmdefptr );
+
+ if ( lex_compat || nmdefptr[0] == '^' ||
+ (len > 0 && nmdefptr[len - 1] == '$') )
+ { /* don't use ()'s after all */
+ PUT_BACK_STRING((char *) nmdefptr, 0);
+
+ if ( nmdefptr[0] == '^' )
+ BEGIN(CARETISBOL);
+ }
+
+ else
+ {
+ unput(')');
+ PUT_BACK_STRING((char *) nmdefptr, 0);
+ unput('(');
+ }
+ }
+ }
+ YY_BREAK
+case 107:
+YY_RULE_SETUP
+#line 469 "scan.l"
+return (unsigned char) yytext[0];
+ YY_BREAK
+case 108:
+YY_RULE_SETUP
+#line 470 "scan.l"
+RETURNCHAR;
+ YY_BREAK
+
+
+case 109:
+YY_RULE_SETUP
+#line 475 "scan.l"
+return (unsigned char) yytext[0];
+ YY_BREAK
+case 110:
+YY_RULE_SETUP
+#line 476 "scan.l"
+BEGIN(SECT2); return '>';
+ YY_BREAK
+case 111:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 477 "scan.l"
+BEGIN(CARETISBOL); return '>';
+ YY_BREAK
+case 112:
+YY_RULE_SETUP
+#line 478 "scan.l"
+RETURNNAME;
+ YY_BREAK
+case 113:
+YY_RULE_SETUP
+#line 479 "scan.l"
+{
+ format_synerr( _( "bad <start condition>: %s" ),
+ yytext );
+ }
+ YY_BREAK
+
+case 114:
+YY_RULE_SETUP
+#line 485 "scan.l"
+BEGIN(SECT2); return '^';
+ YY_BREAK
+
+case 115:
+YY_RULE_SETUP
+#line 489 "scan.l"
+RETURNCHAR;
+ YY_BREAK
+case 116:
+YY_RULE_SETUP
+#line 490 "scan.l"
+BEGIN(SECT2); return '"';
+ YY_BREAK
+case 117:
+YY_RULE_SETUP
+#line 492 "scan.l"
+{
+ synerr( _( "missing quote" ) );
+ BEGIN(SECT2);
+ ++linenum;
+ return '"';
+ }
+ YY_BREAK
+
+
+case 118:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 502 "scan.l"
+BEGIN(CCL); return '^';
+ YY_BREAK
+case 119:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 503 "scan.l"
+return '^';
+ YY_BREAK
+case 120:
+YY_RULE_SETUP
+#line 504 "scan.l"
+BEGIN(CCL); RETURNCHAR;
+ YY_BREAK
+
+
+case 121:
+*yy_cp = yy_hold_char; /* undo effects of setting up yytext */
+yy_c_buf_p = yy_cp = yy_bp + 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 508 "scan.l"
+return '-';
+ YY_BREAK
+case 122:
+YY_RULE_SETUP
+#line 509 "scan.l"
+RETURNCHAR;
+ YY_BREAK
+case 123:
+YY_RULE_SETUP
+#line 510 "scan.l"
+BEGIN(SECT2); return ']';
+ YY_BREAK
+case 124:
+YY_RULE_SETUP
+#line 511 "scan.l"
+{
+ synerr( _( "bad character class" ) );
+ BEGIN(SECT2);
+ return ']';
+ }
+ YY_BREAK
+
+
+case 125:
+YY_RULE_SETUP
+#line 519 "scan.l"
+BEGIN(CCL); return CCE_ALNUM;
+ YY_BREAK
+case 126:
+YY_RULE_SETUP
+#line 520 "scan.l"
+BEGIN(CCL); return CCE_ALPHA;
+ YY_BREAK
+case 127:
+YY_RULE_SETUP
+#line 521 "scan.l"
+BEGIN(CCL); return CCE_BLANK;
+ YY_BREAK
+case 128:
+YY_RULE_SETUP
+#line 522 "scan.l"
+BEGIN(CCL); return CCE_CNTRL;
+ YY_BREAK
+case 129:
+YY_RULE_SETUP
+#line 523 "scan.l"
+BEGIN(CCL); return CCE_DIGIT;
+ YY_BREAK
+case 130:
+YY_RULE_SETUP
+#line 524 "scan.l"
+BEGIN(CCL); return CCE_GRAPH;
+ YY_BREAK
+case 131:
+YY_RULE_SETUP
+#line 525 "scan.l"
+BEGIN(CCL); return CCE_LOWER;
+ YY_BREAK
+case 132:
+YY_RULE_SETUP
+#line 526 "scan.l"
+BEGIN(CCL); return CCE_PRINT;
+ YY_BREAK
+case 133:
+YY_RULE_SETUP
+#line 527 "scan.l"
+BEGIN(CCL); return CCE_PUNCT;
+ YY_BREAK
+case 134:
+YY_RULE_SETUP
+#line 528 "scan.l"
+BEGIN(CCL); return CCE_SPACE;
+ YY_BREAK
+case 135:
+YY_RULE_SETUP
+#line 529 "scan.l"
+BEGIN(CCL); return CCE_UPPER;
+ YY_BREAK
+case 136:
+YY_RULE_SETUP
+#line 530 "scan.l"
+BEGIN(CCL); return CCE_XDIGIT;
+ YY_BREAK
+case 137:
+YY_RULE_SETUP
+#line 531 "scan.l"
+{
+ format_synerr(
+ _( "bad character class expression: %s" ),
+ yytext );
+ BEGIN(CCL); return CCE_ALNUM;
+ }
+ YY_BREAK
+
+
+case 138:
+YY_RULE_SETUP
+#line 540 "scan.l"
+{
+ yylval = myctoi( yytext );
+ return NUMBER;
+ }
+ YY_BREAK
+case 139:
+YY_RULE_SETUP
+#line 545 "scan.l"
+return ',';
+ YY_BREAK
+case 140:
+YY_RULE_SETUP
+#line 546 "scan.l"
+BEGIN(SECT2); return '}';
+ YY_BREAK
+case 141:
+YY_RULE_SETUP
+#line 548 "scan.l"
+{
+ synerr( _( "bad character inside {}'s" ) );
+ BEGIN(SECT2);
+ return '}';
+ }
+ YY_BREAK
+case 142:
+YY_RULE_SETUP
+#line 554 "scan.l"
+{
+ synerr( _( "missing }" ) );
+ BEGIN(SECT2);
+ ++linenum;
+ return '}';
+ }
+ YY_BREAK
+
+
+case 143:
+YY_RULE_SETUP
+#line 564 "scan.l"
+bracelevel = 0;
+ YY_BREAK
+case 144:
+YY_RULE_SETUP
+#line 566 "scan.l"
+ACTION_ECHO; yy_push_state( COMMENT );
+ YY_BREAK
+
+case 145:
+YY_RULE_SETUP
+#line 569 "scan.l"
+{
+ ACTION_ECHO;
+ CHECK_REJECT(yytext);
+ }
+ YY_BREAK
+case 146:
+YY_RULE_SETUP
+#line 573 "scan.l"
+{
+ ACTION_ECHO;
+ CHECK_YYMORE(yytext);
+ }
+ YY_BREAK
+
+case 147:
+YY_RULE_SETUP
+#line 579 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 148:
+YY_RULE_SETUP
+#line 580 "scan.l"
+{
+ ++linenum;
+ ACTION_ECHO;
+ if ( bracelevel == 0 ||
+ (doing_codeblock && indented_code) )
+ {
+ if ( doing_rule_action )
+ add_action( "\tYY_BREAK\n" );
+
+ doing_rule_action = doing_codeblock = false;
+ BEGIN(SECT2);
+ }
+ }
+ YY_BREAK
+
+/* Reject and YYmore() are checked for above, in PERCENT_BRACE_ACTION */
+
+case 149:
+YY_RULE_SETUP
+#line 598 "scan.l"
+ACTION_ECHO; ++bracelevel;
+ YY_BREAK
+case 150:
+YY_RULE_SETUP
+#line 599 "scan.l"
+ACTION_ECHO; --bracelevel;
+ YY_BREAK
+case 151:
+YY_RULE_SETUP
+#line 600 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 152:
+YY_RULE_SETUP
+#line 601 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 153:
+YY_RULE_SETUP
+#line 602 "scan.l"
+ACTION_ECHO; /* character constant */
+ YY_BREAK
+case 154:
+YY_RULE_SETUP
+#line 603 "scan.l"
+ACTION_ECHO; BEGIN(ACTION_STRING);
+ YY_BREAK
+case 155:
+YY_RULE_SETUP
+#line 604 "scan.l"
+{
+ ++linenum;
+ ACTION_ECHO;
+ if ( bracelevel == 0 )
+ {
+ if ( doing_rule_action )
+ add_action( "\tYY_BREAK\n" );
+
+ doing_rule_action = false;
+ BEGIN(SECT2);
+ }
+ }
+ YY_BREAK
+case 156:
+YY_RULE_SETUP
+#line 616 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+
+
+case 157:
+YY_RULE_SETUP
+#line 620 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 158:
+YY_RULE_SETUP
+#line 621 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+case 159:
+YY_RULE_SETUP
+#line 622 "scan.l"
+++linenum; ACTION_ECHO;
+ YY_BREAK
+case 160:
+YY_RULE_SETUP
+#line 623 "scan.l"
+ACTION_ECHO; BEGIN(ACTION);
+ YY_BREAK
+case 161:
+YY_RULE_SETUP
+#line 624 "scan.l"
+ACTION_ECHO;
+ YY_BREAK
+
+case YY_STATE_EOF(COMMENT):
+case YY_STATE_EOF(ACTION):
+case YY_STATE_EOF(ACTION_STRING):
+#line 627 "scan.l"
+{
+ synerr( _( "EOF encountered inside an action" ) );
+ yyterminate();
+ }
+ YY_BREAK
+case 162:
+YY_RULE_SETUP
+#line 633 "scan.l"
+{
+ yylval = myesc( (Char *) yytext );
+
+ if ( YY_START == FIRSTCCL )
+ BEGIN(CCL);
+
+ return CHAR;
+ }
+ YY_BREAK
+
+case 163:
+YY_RULE_SETUP
+#line 644 "scan.l"
+ECHO;
+ YY_BREAK
+case YY_STATE_EOF(SECT3):
+#line 645 "scan.l"
+sectnum = 0; yyterminate();
+ YY_BREAK
+
+case 164:
+YY_RULE_SETUP
+#line 648 "scan.l"
+format_synerr( _( "bad character: %s" ), yytext );
+ YY_BREAK
+case 165:
+YY_RULE_SETUP
+#line 650 "scan.l"
+YY_FATAL_ERROR( "flex scanner jammed" );
+ YY_BREAK
+#line 2736 "scan.c"
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(SECT2):
+case YY_STATE_EOF(CODEBLOCK):
+case YY_STATE_EOF(PICKUPDEF):
+case YY_STATE_EOF(SC):
+case YY_STATE_EOF(CARETISBOL):
+case YY_STATE_EOF(NUM):
+case YY_STATE_EOF(QUOTE):
+case YY_STATE_EOF(FIRSTCCL):
+case YY_STATE_EOF(CCL):
+case YY_STATE_EOF(RECOVER):
+case YY_STATE_EOF(PERCENT_BRACE_ACTION):
+case YY_STATE_EOF(OPTION):
+case YY_STATE_EOF(LINEDIR):
+ yyterminate();
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = yy_hold_char;
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between yy_current_buffer and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yy_current_buffer->yy_input_file = yyin;
+ yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++yy_c_buf_p;
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = yy_c_buf_p;
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ yy_did_buffer_switch_on_eof = 0;
+
+ if ( yywrap() )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p =
+ yytext_ptr + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ yy_c_buf_p =
+ &yy_current_buffer->yy_ch_buf[yy_n_chars];
+
+ yy_current_state = yy_get_previous_state();
+
+ yy_cp = yy_c_buf_p;
+ yy_bp = yytext_ptr + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of yylex */
+
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+
+static int yy_get_next_buffer()
+ {
+ register char *dest = yy_current_buffer->yy_ch_buf;
+ register char *source = yytext_ptr;
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( yy_current_buffer->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ yy_current_buffer->yy_n_chars = yy_n_chars = 0;
+
+ else
+ {
+ int num_to_read =
+ yy_current_buffer->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+#ifdef YY_USES_REJECT
+ YY_FATAL_ERROR(
+"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
+#else
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = yy_current_buffer;
+
+ int yy_c_buf_p_offset =
+ (int) (yy_c_buf_p - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ int new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yy_flex_realloc( (void *) b->yy_ch_buf,
+ b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = yy_current_buffer->yy_buf_size -
+ number_to_move - 1;
+#endif
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),
+ yy_n_chars, num_to_read );
+
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ if ( yy_n_chars == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart( yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ yy_current_buffer->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ yy_n_chars += number_to_move;
+ yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;
+ yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;
+
+ yytext_ptr = &yy_current_buffer->yy_ch_buf[0];
+
+ return ret_val;
+ }
+
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+static yy_state_type yy_get_previous_state()
+ {
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = yy_start;
+ yy_current_state += YY_AT_BOL();
+
+ for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 769 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+ }
+
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+
+#ifdef YY_USE_PROTOS
+static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )
+#else
+static yy_state_type yy_try_NUL_trans( yy_current_state )
+yy_state_type yy_current_state;
+#endif
+ {
+ register int yy_is_jam;
+ register char *yy_cp = yy_c_buf_p;
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ yy_last_accepting_state = yy_current_state;
+ yy_last_accepting_cpos = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 769 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 768);
+
+ return yy_is_jam ? 0 : yy_current_state;
+ }
+
+
+#ifndef YY_NO_UNPUT
+#ifdef YY_USE_PROTOS
+static void yyunput( int c, register char *yy_bp )
+#else
+static void yyunput( c, yy_bp )
+int c;
+register char *yy_bp;
+#endif
+ {
+ register char *yy_cp = yy_c_buf_p;
+
+ /* undo effects of setting up yytext */
+ *yy_cp = yy_hold_char;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ { /* need to shift things up to make room */
+ /* +2 for EOB chars. */
+ register int number_to_move = yy_n_chars + 2;
+ register char *dest = &yy_current_buffer->yy_ch_buf[
+ yy_current_buffer->yy_buf_size + 2];
+ register char *source =
+ &yy_current_buffer->yy_ch_buf[number_to_move];
+
+ while ( source > yy_current_buffer->yy_ch_buf )
+ *--dest = *--source;
+
+ yy_cp += (int) (dest - source);
+ yy_bp += (int) (dest - source);
+ yy_current_buffer->yy_n_chars =
+ yy_n_chars = yy_current_buffer->yy_buf_size;
+
+ if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )
+ YY_FATAL_ERROR( "flex scanner push-back overflow" );
+ }
+
+ *--yy_cp = (char) c;
+
+
+ yytext_ptr = yy_bp;
+ yy_hold_char = *yy_cp;
+ yy_c_buf_p = yy_cp;
+ }
+#endif /* ifndef YY_NO_UNPUT */
+
+
+#ifdef __cplusplus
+static int yyinput()
+#else
+static int input()
+#endif
+ {
+ int c;
+
+ *yy_c_buf_p = yy_hold_char;
+
+ if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )
+ /* This was really a NUL. */
+ *yy_c_buf_p = '\0';
+
+ else
+ { /* need more input */
+ int offset = yy_c_buf_p - yytext_ptr;
+ ++yy_c_buf_p;
+
+ switch ( yy_get_next_buffer() )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart( yyin );
+
+ /* fall through */
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap() )
+ return EOF;
+
+ if ( ! yy_did_buffer_switch_on_eof )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ yy_c_buf_p = yytext_ptr + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */
+ *yy_c_buf_p = '\0'; /* preserve yytext */
+ yy_hold_char = *++yy_c_buf_p;
+
+ yy_current_buffer->yy_at_bol = (c == '\n');
+
+ return c;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yyrestart( FILE *input_file )
+#else
+void yyrestart( input_file )
+FILE *input_file;
+#endif
+ {
+ if ( ! yy_current_buffer )
+ yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );
+
+ yy_init_buffer( yy_current_buffer, input_file );
+ yy_load_buffer_state();
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )
+#else
+void yy_switch_to_buffer( new_buffer )
+YY_BUFFER_STATE new_buffer;
+#endif
+ {
+ if ( yy_current_buffer == new_buffer )
+ return;
+
+ if ( yy_current_buffer )
+ {
+ /* Flush out information for old buffer. */
+ *yy_c_buf_p = yy_hold_char;
+ yy_current_buffer->yy_buf_pos = yy_c_buf_p;
+ yy_current_buffer->yy_n_chars = yy_n_chars;
+ }
+
+ yy_current_buffer = new_buffer;
+ yy_load_buffer_state();
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ yy_did_buffer_switch_on_eof = 1;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_load_buffer_state( void )
+#else
+void yy_load_buffer_state()
+#endif
+ {
+ yy_n_chars = yy_current_buffer->yy_n_chars;
+ yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;
+ yyin = yy_current_buffer->yy_input_file;
+ yy_hold_char = *yy_c_buf_p;
+ }
+
+
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )
+#else
+YY_BUFFER_STATE yy_create_buffer( file, size )
+FILE *file;
+int size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer( b, file );
+
+ return b;
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_delete_buffer( YY_BUFFER_STATE b )
+#else
+void yy_delete_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+ {
+ if ( ! b )
+ return;
+
+ if ( b == yy_current_buffer )
+ yy_current_buffer = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yy_flex_free( (void *) b->yy_ch_buf );
+
+ yy_flex_free( (void *) b );
+ }
+
+
+#ifndef YY_ALWAYS_INTERACTIVE
+#ifndef YY_NEVER_INTERACTIVE
+extern int isatty YY_PROTO(( int ));
+#endif
+#endif
+
+#ifdef YY_USE_PROTOS
+void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )
+#else
+void yy_init_buffer( b, file )
+YY_BUFFER_STATE b;
+FILE *file;
+#endif
+
+
+ {
+ yy_flush_buffer( b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+#if YY_ALWAYS_INTERACTIVE
+ b->yy_is_interactive = 1;
+#else
+#if YY_NEVER_INTERACTIVE
+ b->yy_is_interactive = 0;
+#else
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+#endif
+#endif
+ }
+
+
+#ifdef YY_USE_PROTOS
+void yy_flush_buffer( YY_BUFFER_STATE b )
+#else
+void yy_flush_buffer( b )
+YY_BUFFER_STATE b;
+#endif
+
+ {
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == yy_current_buffer )
+ yy_load_buffer_state();
+ }
+
+
+#ifndef YY_NO_SCAN_BUFFER
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )
+#else
+YY_BUFFER_STATE yy_scan_buffer( base, size )
+char *base;
+yy_size_t size;
+#endif
+ {
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer( b );
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_STRING
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )
+#else
+YY_BUFFER_STATE yy_scan_string( yy_str )
+yyconst char *yy_str;
+#endif
+ {
+ int len;
+ for ( len = 0; yy_str[len]; ++len )
+ ;
+
+ return yy_scan_bytes( yy_str, len );
+ }
+#endif
+
+
+#ifndef YY_NO_SCAN_BYTES
+#ifdef YY_USE_PROTOS
+YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )
+#else
+YY_BUFFER_STATE yy_scan_bytes( bytes, len )
+yyconst char *bytes;
+int len;
+#endif
+ {
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ int i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = len + 2;
+ buf = (char *) yy_flex_alloc( n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < len; ++i )
+ buf[i] = bytes[i];
+
+ buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer( buf, n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+ }
+#endif
+
+
+#ifndef YY_NO_PUSH_STATE
+#ifdef YY_USE_PROTOS
+static void yy_push_state( int new_state )
+#else
+static void yy_push_state( new_state )
+int new_state;
+#endif
+ {
+ if ( yy_start_stack_ptr >= yy_start_stack_depth )
+ {
+ yy_size_t new_size;
+
+ yy_start_stack_depth += YY_START_STACK_INCR;
+ new_size = yy_start_stack_depth * sizeof( int );
+
+ if ( ! yy_start_stack )
+ yy_start_stack = (int *) yy_flex_alloc( new_size );
+
+ else
+ yy_start_stack = (int *) yy_flex_realloc(
+ (void *) yy_start_stack, new_size );
+
+ if ( ! yy_start_stack )
+ YY_FATAL_ERROR(
+ "out of memory expanding start-condition stack" );
+ }
+
+ yy_start_stack[yy_start_stack_ptr++] = YY_START;
+
+ BEGIN(new_state);
+ }
+#endif
+
+
+#ifndef YY_NO_POP_STATE
+static void yy_pop_state()
+ {
+ if ( --yy_start_stack_ptr < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN(yy_start_stack[yy_start_stack_ptr]);
+ }
+#endif
+
+
+#ifndef YY_NO_TOP_STATE
+static int yy_top_state()
+ {
+ return yy_start_stack[yy_start_stack_ptr - 1];
+ }
+#endif
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+#ifdef YY_USE_PROTOS
+static void yy_fatal_error( yyconst char msg[] )
+#else
+static void yy_fatal_error( msg )
+char msg[];
+#endif
+ {
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+ }
+
+
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ yytext[yyleng] = yy_hold_char; \
+ yy_c_buf_p = yytext + n; \
+ yy_hold_char = *yy_c_buf_p; \
+ *yy_c_buf_p = '\0'; \
+ yyleng = n; \
+ } \
+ while ( 0 )
+
+
+/* Internal utility routines. */
+
+#ifndef yytext_ptr
+#ifdef YY_USE_PROTOS
+static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )
+#else
+static void yy_flex_strncpy( s1, s2, n )
+char *s1;
+yyconst char *s2;
+int n;
+#endif
+ {
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+ }
+#endif
+
+#ifdef YY_NEED_STRLEN
+#ifdef YY_USE_PROTOS
+static int yy_flex_strlen( yyconst char *s )
+#else
+static int yy_flex_strlen( s )
+yyconst char *s;
+#endif
+ {
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+ }
+#endif
+
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_alloc( yy_size_t size )
+#else
+static void *yy_flex_alloc( size )
+yy_size_t size;
+#endif
+ {
+ return (void *) malloc( size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void *yy_flex_realloc( void *ptr, yy_size_t size )
+#else
+static void *yy_flex_realloc( ptr, size )
+void *ptr;
+yy_size_t size;
+#endif
+ {
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+ }
+
+#ifdef YY_USE_PROTOS
+static void yy_flex_free( void *ptr )
+#else
+static void yy_flex_free( ptr )
+void *ptr;
+#endif
+ {
+ free( ptr );
+ }
+
+#if YY_MAIN
+int main()
+ {
+ yylex();
+ return 0;
+ }
+#endif
+#line 650 "scan.l"
+
+
+
+int yywrap()
+ {
+ if ( --num_input_files > 0 )
+ {
+ set_input_file( *++input_files );
+ return 0;
+ }
+
+ else
+ return 1;
+ }
+
+
+/* set_input_file - open the given file (if NULL, stdin) for scanning */
+
+void set_input_file( file )
+char *file;
+ {
+ if ( file && strcmp( file, "-" ) )
+ {
+ infilename = copy_string( file );
+ yyin = fopen( infilename, "r" );
+
+ if ( yyin == NULL )
+ lerrsf( _( "can't open %s" ), file );
+ }
+
+ else
+ {
+ yyin = stdin;
+ infilename = copy_string( "<stdin>" );
+ }
+
+ linenum = 1;
+ }
+
+
+/* Wrapper routines for accessing the scanner's malloc routines. */
+
+void *flex_alloc( size )
+size_t size;
+ {
+ return (void *) malloc( size );
+ }
+
+void *flex_realloc( ptr, size )
+void *ptr;
+size_t size;
+ {
+ return (void *) realloc( ptr, size );
+ }
+
+void flex_free( ptr )
+void *ptr;
+ {
+ if ( ptr )
+ free( ptr );
+ }
diff --git a/Tools/android/flex-2.5.4a/install.sh b/Tools/android/flex-2.5.4a/install.sh
new file mode 100755
index 0000000..0ff4b6a
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/install.sh
@@ -0,0 +1,119 @@
+#!/bin/sh
+
+#
+# install - install a program, script, or datafile
+# This comes from X11R5; it is not part of GNU.
+#
+# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+
+instcmd="$mvprog"
+chmodcmd=""
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+fi
+
+if [ x"$dst" = x ]
+then
+ echo "install: no destination specified"
+ exit 1
+fi
+
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+if [ -d $dst ]
+then
+ dst="$dst"/`basename $src`
+fi
+
+# Make a temp file name in the proper directory.
+
+dstdir=`dirname $dst`
+dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+$doit $instcmd $src $dsttmp
+
+# and set any options; do chmod last to preserve setuid bits
+
+if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi
+if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi
+if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi
+if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi
+
+# Now rename the file to the real destination.
+
+$doit $rmcmd $dst
+$doit $mvcmd $dsttmp $dst
+
+
+exit 0
diff --git a/Tools/android/flex-2.5.4a/libmain.c b/Tools/android/flex-2.5.4a/libmain.c
new file mode 100644
index 0000000..6c43b08
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/libmain.c
@@ -0,0 +1,15 @@
+/* libmain - flex run-time support library "main" function */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/libmain.c,v 1.4 95/09/27 12:47:55 vern Exp $ */
+
+extern int yylex();
+
+int main( argc, argv )
+int argc;
+char *argv[];
+ {
+ while ( yylex() != 0 )
+ ;
+
+ return 0;
+ }
diff --git a/Tools/android/flex-2.5.4a/libyywrap.c b/Tools/android/flex-2.5.4a/libyywrap.c
new file mode 100644
index 0000000..b18f54e
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/libyywrap.c
@@ -0,0 +1,8 @@
+/* libyywrap - flex run-time support library "yywrap" function */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/libyywrap.c,v 1.1 93/10/02 15:23:09 vern Exp $ */
+
+int yywrap()
+ {
+ return 1;
+ }
diff --git a/Tools/android/flex-2.5.4a/main.c b/Tools/android/flex-2.5.4a/main.c
new file mode 100644
index 0000000..7873eec
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/main.c
@@ -0,0 +1,1177 @@
+/* flex - tool to generate fast lexical analyzers */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+#ifndef lint
+char copyright[] =
+"@(#) Copyright (c) 1990 The Regents of the University of California.\n\
+ All rights reserved.\n";
+#endif /* not lint */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/main.c,v 2.64 96/05/25 20:42:42 vern Exp $ */
+
+
+#include "flexdef.h"
+#include "version.h"
+
+static char flex_version[] = FLEX_VERSION;
+
+
+/* declare functions that have forward references */
+
+void flexinit PROTO((int, char**));
+void readin PROTO((void));
+void set_up_initial_allocations PROTO((void));
+
+#ifdef NEED_ARGV_FIXUP
+extern void argv_fixup PROTO((int *, char ***));
+#endif
+
+
+/* these globals are all defined and commented in flexdef.h */
+int printstats, syntaxerror, eofseen, ddebug, trace, nowarn, spprdflt;
+int interactive, caseins, lex_compat, do_yylineno, useecs, fulltbl, usemecs;
+int fullspd, gen_line_dirs, performance_report, backing_up_report;
+int C_plus_plus, long_align, use_read, yytext_is_array, do_yywrap, csize;
+int yymore_used, reject, real_reject, continued_action, in_rule;
+int yymore_really_used, reject_really_used;
+int datapos, dataline, linenum, out_linenum;
+FILE *skelfile = NULL;
+int skel_ind = 0;
+char *action_array;
+int action_size, defs1_offset, prolog_offset, action_offset, action_index;
+char *infilename = NULL, *outfilename = NULL;
+int did_outfilename;
+char *prefix, *yyclass;
+int do_stdinit, use_stdout;
+int onestate[ONE_STACK_SIZE], onesym[ONE_STACK_SIZE];
+int onenext[ONE_STACK_SIZE], onedef[ONE_STACK_SIZE], onesp;
+int current_mns, current_max_rules;
+int num_rules, num_eof_rules, default_rule, lastnfa;
+int *firstst, *lastst, *finalst, *transchar, *trans1, *trans2;
+int *accptnum, *assoc_rule, *state_type;
+int *rule_type, *rule_linenum, *rule_useful;
+int current_state_type;
+int variable_trailing_context_rules;
+int numtemps, numprots, protprev[MSP], protnext[MSP], prottbl[MSP];
+int protcomst[MSP], firstprot, lastprot, protsave[PROT_SAVE_SIZE];
+int numecs, nextecm[CSIZE + 1], ecgroup[CSIZE + 1], nummecs, tecfwd[CSIZE + 1];
+int tecbck[CSIZE + 1];
+int lastsc, *scset, *scbol, *scxclu, *sceof;
+int current_max_scs;
+char **scname;
+int current_max_dfa_size, current_max_xpairs;
+int current_max_template_xpairs, current_max_dfas;
+int lastdfa, *nxt, *chk, *tnxt;
+int *base, *def, *nultrans, NUL_ec, tblend, firstfree, **dss, *dfasiz;
+union dfaacc_union *dfaacc;
+int *accsiz, *dhash, numas;
+int numsnpairs, jambase, jamstate;
+int lastccl, *cclmap, *ccllen, *cclng, cclreuse;
+int current_maxccls, current_max_ccl_tbl_size;
+Char *ccltbl;
+char nmstr[MAXLINE];
+int sectnum, nummt, hshcol, dfaeql, numeps, eps2, num_reallocs;
+int tmpuses, totnst, peakpairs, numuniq, numdup, hshsave;
+int num_backing_up, bol_needed;
+FILE *backing_up_file;
+int end_of_buffer_state;
+char **input_files;
+int num_input_files;
+
+/* Make sure program_name is initialized so we don't crash if writing
+ * out an error message before getting the program name from argv[0].
+ */
+char *program_name = "flex";
+
+#ifndef SHORT_FILE_NAMES
+static char *outfile_template = "lex.%s.%s";
+static char *backing_name = "lex.backup";
+#else
+static char *outfile_template = "lex%s.%s";
+static char *backing_name = "lex.bck";
+#endif
+
+#ifdef THINK_C
+#include <console.h>
+#endif
+
+#ifdef MS_DOS
+extern unsigned _stklen = 16384;
+#endif
+
+static char outfile_path[MAXLINE];
+static int outfile_created = 0;
+static char *skelname = NULL;
+
+
+int main( argc, argv )
+int argc;
+char **argv;
+ {
+ int i;
+
+#ifdef THINK_C
+ argc = ccommand( &argv );
+#endif
+#ifdef NEED_ARGV_FIXUP
+ argv_fixup( &argc, &argv );
+#endif
+
+ flexinit( argc, argv );
+
+ readin();
+
+ ntod();
+
+ for ( i = 1; i <= num_rules; ++i )
+ if ( ! rule_useful[i] && i != default_rule )
+ line_warning( _( "rule cannot be matched" ),
+ rule_linenum[i] );
+
+ if ( spprdflt && ! reject && rule_useful[default_rule] )
+ line_warning(
+ _( "-s option given but default rule can be matched" ),
+ rule_linenum[default_rule] );
+
+ /* Generate the C state transition tables from the DFA. */
+ make_tables();
+
+ /* Note, flexend does not return. It exits with its argument
+ * as status.
+ */
+ flexend( 0 );
+
+ return 0; /* keep compilers/lint happy */
+ }
+
+
+/* check_options - check user-specified options */
+
+void check_options()
+ {
+ int i;
+
+ if ( lex_compat )
+ {
+ if ( C_plus_plus )
+ flexerror( _( "Can't use -+ with -l option" ) );
+
+ if ( fulltbl || fullspd )
+ flexerror( _( "Can't use -f or -F with -l option" ) );
+
+ /* Don't rely on detecting use of yymore() and REJECT,
+ * just assume they'll be used.
+ */
+ yymore_really_used = reject_really_used = true;
+
+ yytext_is_array = true;
+ do_yylineno = true;
+ use_read = false;
+ }
+
+ if ( do_yylineno )
+ /* This should really be "maintain_backup_tables = true" */
+ reject_really_used = true;
+
+ if ( csize == unspecified )
+ {
+ if ( (fulltbl || fullspd) && ! useecs )
+ csize = DEFAULT_CSIZE;
+ else
+ csize = CSIZE;
+ }
+
+ if ( interactive == unspecified )
+ {
+ if ( fulltbl || fullspd )
+ interactive = false;
+ else
+ interactive = true;
+ }
+
+ if ( fulltbl || fullspd )
+ {
+ if ( usemecs )
+ flexerror(
+ _( "-Cf/-CF and -Cm don't make sense together" ) );
+
+ if ( interactive )
+ flexerror( _( "-Cf/-CF and -I are incompatible" ) );
+
+ if ( lex_compat )
+ flexerror(
+ _( "-Cf/-CF are incompatible with lex-compatibility mode" ) );
+
+ if ( do_yylineno )
+ flexerror(
+ _( "-Cf/-CF and %option yylineno are incompatible" ) );
+
+ if ( fulltbl && fullspd )
+ flexerror( _( "-Cf and -CF are mutually exclusive" ) );
+ }
+
+ if ( C_plus_plus && fullspd )
+ flexerror( _( "Can't use -+ with -CF option" ) );
+
+ if ( C_plus_plus && yytext_is_array )
+ {
+ warn( _( "%array incompatible with -+ option" ) );
+ yytext_is_array = false;
+ }
+
+ if ( useecs )
+ { /* Set up doubly-linked equivalence classes. */
+
+ /* We loop all the way up to csize, since ecgroup[csize] is
+ * the position used for NUL characters.
+ */
+ ecgroup[1] = NIL;
+
+ for ( i = 2; i <= csize; ++i )
+ {
+ ecgroup[i] = i - 1;
+ nextecm[i - 1] = i;
+ }
+
+ nextecm[csize] = NIL;
+ }
+
+ else
+ {
+ /* Put everything in its own equivalence class. */
+ for ( i = 1; i <= csize; ++i )
+ {
+ ecgroup[i] = i;
+ nextecm[i] = BAD_SUBSCRIPT; /* to catch errors */
+ }
+ }
+
+ if ( ! use_stdout )
+ {
+ FILE *prev_stdout;
+
+ if ( ! did_outfilename )
+ {
+ char *suffix;
+
+ if ( C_plus_plus )
+ suffix = "cc";
+ else
+ suffix = "c";
+
+ sprintf( outfile_path, outfile_template,
+ prefix, suffix );
+
+ outfilename = outfile_path;
+ }
+
+ prev_stdout = freopen( outfilename, "w", stdout );
+
+ if ( prev_stdout == NULL )
+ lerrsf( _( "could not create %s" ), outfilename );
+
+ outfile_created = 1;
+ }
+
+ if ( skelname && (skelfile = fopen( skelname, "r" )) == NULL )
+ lerrsf( _( "can't open skeleton file %s" ), skelname );
+
+ if ( strcmp( prefix, "yy" ) )
+ {
+#define GEN_PREFIX(name) out_str3( "#define yy%s %s%s\n", name, prefix, name )
+ if ( C_plus_plus )
+ GEN_PREFIX( "FlexLexer" );
+ else
+ {
+ GEN_PREFIX( "_create_buffer" );
+ GEN_PREFIX( "_delete_buffer" );
+ GEN_PREFIX( "_scan_buffer" );
+ GEN_PREFIX( "_scan_string" );
+ GEN_PREFIX( "_scan_bytes" );
+ GEN_PREFIX( "_flex_debug" );
+ GEN_PREFIX( "_init_buffer" );
+ GEN_PREFIX( "_flush_buffer" );
+ GEN_PREFIX( "_load_buffer_state" );
+ GEN_PREFIX( "_switch_to_buffer" );
+ GEN_PREFIX( "in" );
+ GEN_PREFIX( "leng" );
+ GEN_PREFIX( "lex" );
+ GEN_PREFIX( "out" );
+ GEN_PREFIX( "restart" );
+ GEN_PREFIX( "text" );
+
+ if ( do_yylineno )
+ GEN_PREFIX( "lineno" );
+ }
+
+ if ( do_yywrap )
+ GEN_PREFIX( "wrap" );
+
+ outn( "" );
+ }
+
+ if ( did_outfilename )
+ line_directive_out( stdout, 0 );
+
+ skelout();
+ }
+
+
+/* flexend - terminate flex
+ *
+ * note
+ * This routine does not return.
+ */
+
+void flexend( exit_status )
+int exit_status;
+
+ {
+ int tblsiz;
+ int unlink();
+
+ if ( skelfile != NULL )
+ {
+ if ( ferror( skelfile ) )
+ lerrsf( _( "input error reading skeleton file %s" ),
+ skelname );
+
+ else if ( fclose( skelfile ) )
+ lerrsf( _( "error closing skeleton file %s" ),
+ skelname );
+ }
+
+ if ( exit_status != 0 && outfile_created )
+ {
+ if ( ferror( stdout ) )
+ lerrsf( _( "error writing output file %s" ),
+ outfilename );
+
+ else if ( fclose( stdout ) )
+ lerrsf( _( "error closing output file %s" ),
+ outfilename );
+
+ else if ( unlink( outfilename ) )
+ lerrsf( _( "error deleting output file %s" ),
+ outfilename );
+ }
+
+ if ( backing_up_report && backing_up_file )
+ {
+ if ( num_backing_up == 0 )
+ fprintf( backing_up_file, _( "No backing up.\n" ) );
+ else if ( fullspd || fulltbl )
+ fprintf( backing_up_file,
+ _( "%d backing up (non-accepting) states.\n" ),
+ num_backing_up );
+ else
+ fprintf( backing_up_file,
+ _( "Compressed tables always back up.\n" ) );
+
+ if ( ferror( backing_up_file ) )
+ lerrsf( _( "error writing backup file %s" ),
+ backing_name );
+
+ else if ( fclose( backing_up_file ) )
+ lerrsf( _( "error closing backup file %s" ),
+ backing_name );
+ }
+
+ if ( printstats )
+ {
+ fprintf( stderr, _( "%s version %s usage statistics:\n" ),
+ program_name, flex_version );
+
+ fprintf( stderr, _( " scanner options: -" ) );
+
+ if ( C_plus_plus )
+ putc( '+', stderr );
+ if ( backing_up_report )
+ putc( 'b', stderr );
+ if ( ddebug )
+ putc( 'd', stderr );
+ if ( caseins )
+ putc( 'i', stderr );
+ if ( lex_compat )
+ putc( 'l', stderr );
+ if ( performance_report > 0 )
+ putc( 'p', stderr );
+ if ( performance_report > 1 )
+ putc( 'p', stderr );
+ if ( spprdflt )
+ putc( 's', stderr );
+ if ( use_stdout )
+ putc( 't', stderr );
+ if ( printstats )
+ putc( 'v', stderr ); /* always true! */
+ if ( nowarn )
+ putc( 'w', stderr );
+ if ( interactive == false )
+ putc( 'B', stderr );
+ if ( interactive == true )
+ putc( 'I', stderr );
+ if ( ! gen_line_dirs )
+ putc( 'L', stderr );
+ if ( trace )
+ putc( 'T', stderr );
+
+ if ( csize == unspecified )
+ /* We encountered an error fairly early on, so csize
+ * never got specified. Define it now, to prevent
+ * bogus table sizes being written out below.
+ */
+ csize = 256;
+
+ if ( csize == 128 )
+ putc( '7', stderr );
+ else
+ putc( '8', stderr );
+
+ fprintf( stderr, " -C" );
+
+ if ( long_align )
+ putc( 'a', stderr );
+ if ( fulltbl )
+ putc( 'f', stderr );
+ if ( fullspd )
+ putc( 'F', stderr );
+ if ( useecs )
+ putc( 'e', stderr );
+ if ( usemecs )
+ putc( 'm', stderr );
+ if ( use_read )
+ putc( 'r', stderr );
+
+ if ( did_outfilename )
+ fprintf( stderr, " -o%s", outfilename );
+
+ if ( skelname )
+ fprintf( stderr, " -S%s", skelname );
+
+ if ( strcmp( prefix, "yy" ) )
+ fprintf( stderr, " -P%s", prefix );
+
+ putc( '\n', stderr );
+
+ fprintf( stderr, _( " %d/%d NFA states\n" ),
+ lastnfa, current_mns );
+ fprintf( stderr, _( " %d/%d DFA states (%d words)\n" ),
+ lastdfa, current_max_dfas, totnst );
+ fprintf( stderr, _( " %d rules\n" ),
+ num_rules + num_eof_rules - 1 /* - 1 for def. rule */ );
+
+ if ( num_backing_up == 0 )
+ fprintf( stderr, _( " No backing up\n" ) );
+ else if ( fullspd || fulltbl )
+ fprintf( stderr,
+ _( " %d backing-up (non-accepting) states\n" ),
+ num_backing_up );
+ else
+ fprintf( stderr,
+ _( " Compressed tables always back-up\n" ) );
+
+ if ( bol_needed )
+ fprintf( stderr,
+ _( " Beginning-of-line patterns used\n" ) );
+
+ fprintf( stderr, _( " %d/%d start conditions\n" ), lastsc,
+ current_max_scs );
+ fprintf( stderr,
+ _( " %d epsilon states, %d double epsilon states\n" ),
+ numeps, eps2 );
+
+ if ( lastccl == 0 )
+ fprintf( stderr, _( " no character classes\n" ) );
+ else
+ fprintf( stderr,
+_( " %d/%d character classes needed %d/%d words of storage, %d reused\n" ),
+ lastccl, current_maxccls,
+ cclmap[lastccl] + ccllen[lastccl],
+ current_max_ccl_tbl_size, cclreuse );
+
+ fprintf( stderr, _( " %d state/nextstate pairs created\n" ),
+ numsnpairs );
+ fprintf( stderr, _( " %d/%d unique/duplicate transitions\n" ),
+ numuniq, numdup );
+
+ if ( fulltbl )
+ {
+ tblsiz = lastdfa * numecs;
+ fprintf( stderr, _( " %d table entries\n" ), tblsiz );
+ }
+
+ else
+ {
+ tblsiz = 2 * (lastdfa + numtemps) + 2 * tblend;
+
+ fprintf( stderr,
+ _( " %d/%d base-def entries created\n" ),
+ lastdfa + numtemps, current_max_dfas );
+ fprintf( stderr,
+ _( " %d/%d (peak %d) nxt-chk entries created\n" ),
+ tblend, current_max_xpairs, peakpairs );
+ fprintf( stderr,
+ _( " %d/%d (peak %d) template nxt-chk entries created\n" ),
+ numtemps * nummecs,
+ current_max_template_xpairs,
+ numtemps * numecs );
+ fprintf( stderr, _( " %d empty table entries\n" ),
+ nummt );
+ fprintf( stderr, _( " %d protos created\n" ),
+ numprots );
+ fprintf( stderr,
+ _( " %d templates created, %d uses\n" ),
+ numtemps, tmpuses );
+ }
+
+ if ( useecs )
+ {
+ tblsiz = tblsiz + csize;
+ fprintf( stderr,
+ _( " %d/%d equivalence classes created\n" ),
+ numecs, csize );
+ }
+
+ if ( usemecs )
+ {
+ tblsiz = tblsiz + numecs;
+ fprintf( stderr,
+ _( " %d/%d meta-equivalence classes created\n" ),
+ nummecs, csize );
+ }
+
+ fprintf( stderr,
+ _( " %d (%d saved) hash collisions, %d DFAs equal\n" ),
+ hshcol, hshsave, dfaeql );
+ fprintf( stderr, _( " %d sets of reallocations needed\n" ),
+ num_reallocs );
+ fprintf( stderr, _( " %d total table entries needed\n" ),
+ tblsiz );
+ }
+
+ exit( exit_status );
+ }
+
+
+/* flexinit - initialize flex */
+
+void flexinit( argc, argv )
+int argc;
+char **argv;
+ {
+ int i, sawcmpflag;
+ char *arg;
+
+ printstats = syntaxerror = trace = spprdflt = caseins = false;
+ lex_compat = C_plus_plus = backing_up_report = ddebug = fulltbl = false;
+ fullspd = long_align = nowarn = yymore_used = continued_action = false;
+ do_yylineno = yytext_is_array = in_rule = reject = do_stdinit = false;
+ yymore_really_used = reject_really_used = unspecified;
+ interactive = csize = unspecified;
+ do_yywrap = gen_line_dirs = usemecs = useecs = true;
+ performance_report = 0;
+ did_outfilename = 0;
+ prefix = "yy";
+ yyclass = 0;
+ use_read = use_stdout = false;
+
+ sawcmpflag = false;
+
+ /* Initialize dynamic array for holding the rule actions. */
+ action_size = 2048; /* default size of action array in bytes */
+ action_array = allocate_character_array( action_size );
+ defs1_offset = prolog_offset = action_offset = action_index = 0;
+ action_array[0] = '\0';
+
+ program_name = argv[0];
+
+ if ( program_name[0] != '\0' &&
+ program_name[strlen( program_name ) - 1] == '+' )
+ C_plus_plus = true;
+
+ /* read flags */
+ for ( --argc, ++argv; argc ; --argc, ++argv )
+ {
+ arg = argv[0];
+
+ if ( arg[0] != '-' || arg[1] == '\0' )
+ break;
+
+ if ( arg[1] == '-' )
+ { /* --option */
+ if ( ! strcmp( arg, "--help" ) )
+ arg = "-h";
+
+ else if ( ! strcmp( arg, "--version" ) )
+ arg = "-V";
+
+ else if ( ! strcmp( arg, "--" ) )
+ { /* end of options */
+ --argc;
+ ++argv;
+ break;
+ }
+ }
+
+ for ( i = 1; arg[i] != '\0'; ++i )
+ switch ( arg[i] )
+ {
+ case '+':
+ C_plus_plus = true;
+ break;
+
+ case 'B':
+ interactive = false;
+ break;
+
+ case 'b':
+ backing_up_report = true;
+ break;
+
+ case 'c':
+ break;
+
+ case 'C':
+ if ( i != 1 )
+ flexerror(
+ _( "-C flag must be given separately" ) );
+
+ if ( ! sawcmpflag )
+ {
+ useecs = false;
+ usemecs = false;
+ fulltbl = false;
+ sawcmpflag = true;
+ }
+
+ for ( ++i; arg[i] != '\0'; ++i )
+ switch ( arg[i] )
+ {
+ case 'a':
+ long_align =
+ true;
+ break;
+
+ case 'e':
+ useecs = true;
+ break;
+
+ case 'F':
+ fullspd = true;
+ break;
+
+ case 'f':
+ fulltbl = true;
+ break;
+
+ case 'm':
+ usemecs = true;
+ break;
+
+ case 'r':
+ use_read = true;
+ break;
+
+ default:
+ lerrif(
+ _( "unknown -C option '%c'" ),
+ (int) arg[i] );
+ break;
+ }
+
+ goto get_next_arg;
+
+ case 'd':
+ ddebug = true;
+ break;
+
+ case 'f':
+ useecs = usemecs = false;
+ use_read = fulltbl = true;
+ break;
+
+ case 'F':
+ useecs = usemecs = false;
+ use_read = fullspd = true;
+ break;
+
+ case '?':
+ case 'h':
+ usage();
+ exit( 0 );
+
+ case 'I':
+ interactive = true;
+ break;
+
+ case 'i':
+ caseins = true;
+ break;
+
+ case 'l':
+ lex_compat = true;
+ break;
+
+ case 'L':
+ gen_line_dirs = false;
+ break;
+
+ case 'n':
+ /* Stupid do-nothing deprecated
+ * option.
+ */
+ break;
+
+ case 'o':
+ if ( i != 1 )
+ flexerror(
+ _( "-o flag must be given separately" ) );
+
+ outfilename = arg + i + 1;
+ did_outfilename = 1;
+ goto get_next_arg;
+
+ case 'P':
+ if ( i != 1 )
+ flexerror(
+ _( "-P flag must be given separately" ) );
+
+ prefix = arg + i + 1;
+ goto get_next_arg;
+
+ case 'p':
+ ++performance_report;
+ break;
+
+ case 'S':
+ if ( i != 1 )
+ flexerror(
+ _( "-S flag must be given separately" ) );
+
+ skelname = arg + i + 1;
+ goto get_next_arg;
+
+ case 's':
+ spprdflt = true;
+ break;
+
+ case 't':
+ use_stdout = true;
+ break;
+
+ case 'T':
+ trace = true;
+ break;
+
+ case 'v':
+ printstats = true;
+ break;
+
+ case 'V':
+ printf( _( "%s version %s\n" ),
+ program_name, flex_version );
+ exit( 0 );
+
+ case 'w':
+ nowarn = true;
+ break;
+
+ case '7':
+ csize = 128;
+ break;
+
+ case '8':
+ csize = CSIZE;
+ break;
+
+ default:
+ fprintf( stderr,
+ _( "%s: unknown flag '%c'. For usage, try\n\t%s --help\n" ),
+ program_name, (int) arg[i],
+ program_name );
+ exit( 1 );
+ }
+
+ /* Used by -C, -S, -o, and -P flags in lieu of a "continue 2"
+ * control.
+ */
+ get_next_arg: ;
+ }
+
+ num_input_files = argc;
+ input_files = argv;
+ set_input_file( num_input_files > 0 ? input_files[0] : NULL );
+
+ lastccl = lastsc = lastdfa = lastnfa = 0;
+ num_rules = num_eof_rules = default_rule = 0;
+ numas = numsnpairs = tmpuses = 0;
+ numecs = numeps = eps2 = num_reallocs = hshcol = dfaeql = totnst = 0;
+ numuniq = numdup = hshsave = eofseen = datapos = dataline = 0;
+ num_backing_up = onesp = numprots = 0;
+ variable_trailing_context_rules = bol_needed = false;
+
+ out_linenum = linenum = sectnum = 1;
+ firstprot = NIL;
+
+ /* Used in mkprot() so that the first proto goes in slot 1
+ * of the proto queue.
+ */
+ lastprot = 1;
+
+ set_up_initial_allocations();
+ }
+
+
+/* readin - read in the rules section of the input file(s) */
+
+void readin()
+ {
+ static char yy_stdinit[] = "FILE *yyin = stdin, *yyout = stdout;";
+ static char yy_nostdinit[] =
+ "FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;";
+
+ line_directive_out( (FILE *) 0, 1 );
+
+ if ( yyparse() )
+ {
+ pinpoint_message( _( "fatal parse error" ) );
+ flexend( 1 );
+ }
+
+ if ( syntaxerror )
+ flexend( 1 );
+
+ if ( backing_up_report )
+ {
+ backing_up_file = fopen( backing_name, "w" );
+ if ( backing_up_file == NULL )
+ lerrsf(
+ _( "could not create backing-up info file %s" ),
+ backing_name );
+ }
+
+ else
+ backing_up_file = NULL;
+
+ if ( yymore_really_used == true )
+ yymore_used = true;
+ else if ( yymore_really_used == false )
+ yymore_used = false;
+
+ if ( reject_really_used == true )
+ reject = true;
+ else if ( reject_really_used == false )
+ reject = false;
+
+ if ( performance_report > 0 )
+ {
+ if ( lex_compat )
+ {
+ fprintf( stderr,
+_( "-l AT&T lex compatibility option entails a large performance penalty\n" ) );
+ fprintf( stderr,
+_( " and may be the actual source of other reported performance penalties\n" ) );
+ }
+
+ else if ( do_yylineno )
+ {
+ fprintf( stderr,
+ _( "%%option yylineno entails a large performance penalty\n" ) );
+ }
+
+ if ( performance_report > 1 )
+ {
+ if ( interactive )
+ fprintf( stderr,
+ _( "-I (interactive) entails a minor performance penalty\n" ) );
+
+ if ( yymore_used )
+ fprintf( stderr,
+ _( "yymore() entails a minor performance penalty\n" ) );
+ }
+
+ if ( reject )
+ fprintf( stderr,
+ _( "REJECT entails a large performance penalty\n" ) );
+
+ if ( variable_trailing_context_rules )
+ fprintf( stderr,
+_( "Variable trailing context rules entail a large performance penalty\n" ) );
+ }
+
+ if ( reject )
+ real_reject = true;
+
+ if ( variable_trailing_context_rules )
+ reject = true;
+
+ if ( (fulltbl || fullspd) && reject )
+ {
+ if ( real_reject )
+ flexerror(
+ _( "REJECT cannot be used with -f or -F" ) );
+ else if ( do_yylineno )
+ flexerror(
+ _( "%option yylineno cannot be used with -f or -F" ) );
+ else
+ flexerror(
+ _( "variable trailing context rules cannot be used with -f or -F" ) );
+ }
+
+ if ( reject )
+ outn( "\n#define YY_USES_REJECT" );
+
+ if ( ! do_yywrap )
+ {
+ outn( "\n#define yywrap() 1" );
+ outn( "#define YY_SKIP_YYWRAP" );
+ }
+
+ if ( ddebug )
+ outn( "\n#define FLEX_DEBUG" );
+
+ if ( csize == 256 )
+ outn( "typedef unsigned char YY_CHAR;" );
+ else
+ outn( "typedef char YY_CHAR;" );
+
+ if ( C_plus_plus )
+ {
+ outn( "#define yytext_ptr yytext" );
+
+ if ( interactive )
+ outn( "#define YY_INTERACTIVE" );
+ }
+
+ else
+ {
+ if ( do_stdinit )
+ {
+ outn( "#ifdef VMS" );
+ outn( "#ifndef __VMS_POSIX" );
+ outn( yy_nostdinit );
+ outn( "#else" );
+ outn( yy_stdinit );
+ outn( "#endif" );
+ outn( "#else" );
+ outn( yy_stdinit );
+ outn( "#endif" );
+ }
+
+ else
+ outn( yy_nostdinit );
+ }
+
+ if ( fullspd )
+ outn( "typedef yyconst struct yy_trans_info *yy_state_type;" );
+ else if ( ! C_plus_plus )
+ outn( "typedef int yy_state_type;" );
+
+ if ( ddebug )
+ outn( "\n#define FLEX_DEBUG" );
+
+ if ( lex_compat )
+ outn( "#define YY_FLEX_LEX_COMPAT" );
+
+ if ( do_yylineno && ! C_plus_plus )
+ {
+ outn( "extern int yylineno;" );
+ outn( "int yylineno = 1;" );
+ }
+
+ if ( C_plus_plus )
+ {
+ outn( "\n#include <FlexLexer.h>" );
+
+ if ( yyclass )
+ {
+ outn( "int yyFlexLexer::yylex()" );
+ outn( "\t{" );
+ outn(
+"\tLexerError( \"yyFlexLexer::yylex invoked but %option yyclass used\" );" );
+ outn( "\treturn 0;" );
+ outn( "\t}" );
+
+ out_str( "\n#define YY_DECL int %s::yylex()\n",
+ yyclass );
+ }
+ }
+
+ else
+ {
+ if ( yytext_is_array )
+ outn( "extern char yytext[];\n" );
+
+ else
+ {
+ outn( "extern char *yytext;" );
+ outn( "#define yytext_ptr yytext" );
+ }
+
+ if ( yyclass )
+ flexerror(
+ _( "%option yyclass only meaningful for C++ scanners" ) );
+ }
+
+ if ( useecs )
+ numecs = cre8ecs( nextecm, ecgroup, csize );
+ else
+ numecs = csize;
+
+ /* Now map the equivalence class for NUL to its expected place. */
+ ecgroup[0] = ecgroup[csize];
+ NUL_ec = ABS( ecgroup[0] );
+
+ if ( useecs )
+ ccl2ecl();
+ }
+
+
+/* set_up_initial_allocations - allocate memory for internal tables */
+
+void set_up_initial_allocations()
+ {
+ current_mns = INITIAL_MNS;
+ firstst = allocate_integer_array( current_mns );
+ lastst = allocate_integer_array( current_mns );
+ finalst = allocate_integer_array( current_mns );
+ transchar = allocate_integer_array( current_mns );
+ trans1 = allocate_integer_array( current_mns );
+ trans2 = allocate_integer_array( current_mns );
+ accptnum = allocate_integer_array( current_mns );
+ assoc_rule = allocate_integer_array( current_mns );
+ state_type = allocate_integer_array( current_mns );
+
+ current_max_rules = INITIAL_MAX_RULES;
+ rule_type = allocate_integer_array( current_max_rules );
+ rule_linenum = allocate_integer_array( current_max_rules );
+ rule_useful = allocate_integer_array( current_max_rules );
+
+ current_max_scs = INITIAL_MAX_SCS;
+ scset = allocate_integer_array( current_max_scs );
+ scbol = allocate_integer_array( current_max_scs );
+ scxclu = allocate_integer_array( current_max_scs );
+ sceof = allocate_integer_array( current_max_scs );
+ scname = allocate_char_ptr_array( current_max_scs );
+
+ current_maxccls = INITIAL_MAX_CCLS;
+ cclmap = allocate_integer_array( current_maxccls );
+ ccllen = allocate_integer_array( current_maxccls );
+ cclng = allocate_integer_array( current_maxccls );
+
+ current_max_ccl_tbl_size = INITIAL_MAX_CCL_TBL_SIZE;
+ ccltbl = allocate_Character_array( current_max_ccl_tbl_size );
+
+ current_max_dfa_size = INITIAL_MAX_DFA_SIZE;
+
+ current_max_xpairs = INITIAL_MAX_XPAIRS;
+ nxt = allocate_integer_array( current_max_xpairs );
+ chk = allocate_integer_array( current_max_xpairs );
+
+ current_max_template_xpairs = INITIAL_MAX_TEMPLATE_XPAIRS;
+ tnxt = allocate_integer_array( current_max_template_xpairs );
+
+ current_max_dfas = INITIAL_MAX_DFAS;
+ base = allocate_integer_array( current_max_dfas );
+ def = allocate_integer_array( current_max_dfas );
+ dfasiz = allocate_integer_array( current_max_dfas );
+ accsiz = allocate_integer_array( current_max_dfas );
+ dhash = allocate_integer_array( current_max_dfas );
+ dss = allocate_int_ptr_array( current_max_dfas );
+ dfaacc = allocate_dfaacc_union( current_max_dfas );
+
+ nultrans = (int *) 0;
+ }
+
+
+void usage()
+ {
+ FILE *f = stdout;
+
+ fprintf( f,
+_( "%s [-bcdfhilnpstvwBFILTV78+? -C[aefFmr] -ooutput -Pprefix -Sskeleton]\n" ),
+ program_name );
+ fprintf( f, _( "\t[--help --version] [file ...]\n" ) );
+
+ fprintf( f, _( "\t-b generate backing-up information to %s\n" ),
+ backing_name );
+ fprintf( f, _( "\t-c do-nothing POSIX option\n" ) );
+ fprintf( f, _( "\t-d turn on debug mode in generated scanner\n" ) );
+ fprintf( f, _( "\t-f generate fast, large scanner\n" ) );
+ fprintf( f, _( "\t-h produce this help message\n" ) );
+ fprintf( f, _( "\t-i generate case-insensitive scanner\n" ) );
+ fprintf( f, _( "\t-l maximal compatibility with original lex\n" ) );
+ fprintf( f, _( "\t-n do-nothing POSIX option\n" ) );
+ fprintf( f, _( "\t-p generate performance report to stderr\n" ) );
+ fprintf( f,
+ _( "\t-s suppress default rule to ECHO unmatched text\n" ) );
+
+ if ( ! did_outfilename )
+ {
+ sprintf( outfile_path, outfile_template,
+ prefix, C_plus_plus ? "cc" : "c" );
+ outfilename = outfile_path;
+ }
+
+ fprintf( f,
+ _( "\t-t write generated scanner on stdout instead of %s\n" ),
+ outfilename );
+
+ fprintf( f,
+ _( "\t-v write summary of scanner statistics to f\n" ) );
+ fprintf( f, _( "\t-w do not generate warnings\n" ) );
+ fprintf( f, _( "\t-B generate batch scanner (opposite of -I)\n" ) );
+ fprintf( f,
+ _( "\t-F use alternative fast scanner representation\n" ) );
+ fprintf( f,
+ _( "\t-I generate interactive scanner (opposite of -B)\n" ) );
+ fprintf( f, _( "\t-L suppress #line directives in scanner\n" ) );
+ fprintf( f, _( "\t-T %s should run in trace mode\n" ), program_name );
+ fprintf( f, _( "\t-V report %s version\n" ), program_name );
+ fprintf( f, _( "\t-7 generate 7-bit scanner\n" ) );
+ fprintf( f, _( "\t-8 generate 8-bit scanner\n" ) );
+ fprintf( f, _( "\t-+ generate C++ scanner class\n" ) );
+ fprintf( f, _( "\t-? produce this help message\n" ) );
+ fprintf( f,
+_( "\t-C specify degree of table compression (default is -Cem):\n" ) );
+ fprintf( f,
+_( "\t\t-Ca trade off larger tables for better memory alignment\n" ) );
+ fprintf( f, _( "\t\t-Ce construct equivalence classes\n" ) );
+ fprintf( f,
+_( "\t\t-Cf do not compress scanner tables; use -f representation\n" ) );
+ fprintf( f,
+_( "\t\t-CF do not compress scanner tables; use -F representation\n" ) );
+ fprintf( f, _( "\t\t-Cm construct meta-equivalence classes\n" ) );
+ fprintf( f,
+ _( "\t\t-Cr use read() instead of stdio for scanner input\n" ) );
+ fprintf( f, _( "\t-o specify output filename\n" ) );
+ fprintf( f, _( "\t-P specify scanner prefix other than \"yy\"\n" ) );
+ fprintf( f, _( "\t-S specify skeleton file\n" ) );
+ fprintf( f, _( "\t--help produce this help message\n" ) );
+ fprintf( f, _( "\t--version report %s version\n" ), program_name );
+ }
diff --git a/Tools/android/flex-2.5.4a/misc.c b/Tools/android/flex-2.5.4a/misc.c
new file mode 100644
index 0000000..b4dea76
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/misc.c
@@ -0,0 +1,886 @@
+/* misc - miscellaneous flex routines */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/misc.c,v 2.47 95/04/28 11:39:39 vern Exp $ */
+
+#include "flexdef.h"
+
+
+void action_define( defname, value )
+char *defname;
+int value;
+ {
+ char buf[MAXLINE];
+
+ if ( (int) strlen( defname ) > MAXLINE / 2 )
+ {
+ format_pinpoint_message( _( "name \"%s\" ridiculously long" ),
+ defname );
+ return;
+ }
+
+ sprintf( buf, "#define %s %d\n", defname, value );
+ add_action( buf );
+ }
+
+
+void add_action( new_text )
+char *new_text;
+ {
+ int len = strlen( new_text );
+
+ while ( len + action_index >= action_size - 10 /* slop */ )
+ {
+ int new_size = action_size * 2;
+
+ if ( new_size <= 0 )
+ /* Increase just a little, to try to avoid overflow
+ * on 16-bit machines.
+ */
+ action_size += action_size / 8;
+ else
+ action_size = new_size;
+
+ action_array =
+ reallocate_character_array( action_array, action_size );
+ }
+
+ strcpy( &action_array[action_index], new_text );
+
+ action_index += len;
+ }
+
+
+/* allocate_array - allocate memory for an integer array of the given size */
+
+void *allocate_array( size, element_size )
+int size;
+size_t element_size;
+ {
+ register void *mem;
+ size_t num_bytes = element_size * size;
+
+ mem = flex_alloc( num_bytes );
+ if ( ! mem )
+ flexfatal(
+ _( "memory allocation failed in allocate_array()" ) );
+
+ return mem;
+ }
+
+
+/* all_lower - true if a string is all lower-case */
+
+int all_lower( str )
+register char *str;
+ {
+ while ( *str )
+ {
+ if ( ! isascii( (Char) *str ) || ! islower( *str ) )
+ return 0;
+ ++str;
+ }
+
+ return 1;
+ }
+
+
+/* all_upper - true if a string is all upper-case */
+
+int all_upper( str )
+register char *str;
+ {
+ while ( *str )
+ {
+ if ( ! isascii( (Char) *str ) || ! isupper( *str ) )
+ return 0;
+ ++str;
+ }
+
+ return 1;
+ }
+
+
+/* bubble - bubble sort an integer array in increasing order
+ *
+ * synopsis
+ * int v[n], n;
+ * void bubble( v, n );
+ *
+ * description
+ * sorts the first n elements of array v and replaces them in
+ * increasing order.
+ *
+ * passed
+ * v - the array to be sorted
+ * n - the number of elements of 'v' to be sorted
+ */
+
+void bubble( v, n )
+int v[], n;
+ {
+ register int i, j, k;
+
+ for ( i = n; i > 1; --i )
+ for ( j = 1; j < i; ++j )
+ if ( v[j] > v[j + 1] ) /* compare */
+ {
+ k = v[j]; /* exchange */
+ v[j] = v[j + 1];
+ v[j + 1] = k;
+ }
+ }
+
+
+/* check_char - checks a character to make sure it's within the range
+ * we're expecting. If not, generates fatal error message
+ * and exits.
+ */
+
+void check_char( c )
+int c;
+ {
+ if ( c >= CSIZE )
+ lerrsf( _( "bad character '%s' detected in check_char()" ),
+ readable_form( c ) );
+
+ if ( c >= csize )
+ lerrsf(
+ _( "scanner requires -8 flag to use the character %s" ),
+ readable_form( c ) );
+ }
+
+
+
+/* clower - replace upper-case letter to lower-case */
+
+Char clower( c )
+register int c;
+ {
+ return (Char) ((isascii( c ) && isupper( c )) ? tolower( c ) : c);
+ }
+
+
+/* copy_string - returns a dynamically allocated copy of a string */
+
+char *copy_string( str )
+register const char *str;
+ {
+ register const char *c1;
+ register char *c2;
+ char *copy;
+ unsigned int size;
+
+ /* find length */
+ for ( c1 = str; *c1; ++c1 )
+ ;
+
+ size = (c1 - str + 1) * sizeof( char );
+ copy = (char *) flex_alloc( size );
+
+ if ( copy == NULL )
+ flexfatal( _( "dynamic memory failure in copy_string()" ) );
+
+ for ( c2 = copy; (*c2++ = *str++) != 0; )
+ ;
+
+ return copy;
+ }
+
+
+/* copy_unsigned_string -
+ * returns a dynamically allocated copy of a (potentially) unsigned string
+ */
+
+Char *copy_unsigned_string( str )
+register Char *str;
+ {
+ register Char *c;
+ Char *copy;
+
+ /* find length */
+ for ( c = str; *c; ++c )
+ ;
+
+ copy = allocate_Character_array( c - str + 1 );
+
+ for ( c = copy; (*c++ = *str++) != 0; )
+ ;
+
+ return copy;
+ }
+
+
+/* cshell - shell sort a character array in increasing order
+ *
+ * synopsis
+ *
+ * Char v[n];
+ * int n, special_case_0;
+ * cshell( v, n, special_case_0 );
+ *
+ * description
+ * Does a shell sort of the first n elements of array v.
+ * If special_case_0 is true, then any element equal to 0
+ * is instead assumed to have infinite weight.
+ *
+ * passed
+ * v - array to be sorted
+ * n - number of elements of v to be sorted
+ */
+
+void cshell( v, n, special_case_0 )
+Char v[];
+int n, special_case_0;
+ {
+ int gap, i, j, jg;
+ Char k;
+
+ for ( gap = n / 2; gap > 0; gap = gap / 2 )
+ for ( i = gap; i < n; ++i )
+ for ( j = i - gap; j >= 0; j = j - gap )
+ {
+ jg = j + gap;
+
+ if ( special_case_0 )
+ {
+ if ( v[jg] == 0 )
+ break;
+
+ else if ( v[j] != 0 && v[j] <= v[jg] )
+ break;
+ }
+
+ else if ( v[j] <= v[jg] )
+ break;
+
+ k = v[j];
+ v[j] = v[jg];
+ v[jg] = k;
+ }
+ }
+
+
+/* dataend - finish up a block of data declarations */
+
+void dataend()
+ {
+ if ( datapos > 0 )
+ dataflush();
+
+ /* add terminator for initialization; { for vi */
+ outn( " } ;\n" );
+
+ dataline = 0;
+ datapos = 0;
+ }
+
+
+/* dataflush - flush generated data statements */
+
+void dataflush()
+ {
+ outc( '\n' );
+
+ if ( ++dataline >= NUMDATALINES )
+ {
+ /* Put out a blank line so that the table is grouped into
+ * large blocks that enable the user to find elements easily.
+ */
+ outc( '\n' );
+ dataline = 0;
+ }
+
+ /* Reset the number of characters written on the current line. */
+ datapos = 0;
+ }
+
+
+/* flexerror - report an error message and terminate */
+
+void flexerror( msg )
+const char msg[];
+ {
+ fprintf( stderr, "%s: %s\n", program_name, msg );
+ flexend( 1 );
+ }
+
+
+/* flexfatal - report a fatal error message and terminate */
+
+void flexfatal( msg )
+const char msg[];
+ {
+ fprintf( stderr, _( "%s: fatal internal error, %s\n" ),
+ program_name, msg );
+ exit( 1 );
+ }
+
+
+/* htoi - convert a hexadecimal digit string to an integer value */
+
+int htoi( str )
+Char str[];
+ {
+ unsigned int result;
+
+ (void) sscanf( (char *) str, "%x", &result );
+
+ return result;
+ }
+
+
+/* lerrif - report an error message formatted with one integer argument */
+
+void lerrif( msg, arg )
+const char msg[];
+int arg;
+ {
+ char errmsg[MAXLINE];
+ (void) sprintf( errmsg, msg, arg );
+ flexerror( errmsg );
+ }
+
+
+/* lerrsf - report an error message formatted with one string argument */
+
+void lerrsf( msg, arg )
+const char msg[], arg[];
+ {
+ char errmsg[MAXLINE];
+
+ (void) sprintf( errmsg, msg, arg );
+ flexerror( errmsg );
+ }
+
+
+/* line_directive_out - spit out a "#line" statement */
+
+void line_directive_out( output_file, do_infile )
+FILE *output_file;
+int do_infile;
+ {
+ char directive[MAXLINE], filename[MAXLINE];
+ char *s1, *s2, *s3;
+ static char line_fmt[] = "#line %d \"%s\"\n";
+
+ if ( ! gen_line_dirs )
+ return;
+
+ if ( (do_infile && ! infilename) || (! do_infile && ! outfilename) )
+ /* don't know the filename to use, skip */
+ return;
+
+ s1 = do_infile ? infilename : outfilename;
+ s2 = filename;
+ s3 = &filename[sizeof( filename ) - 2];
+
+ while ( s2 < s3 && *s1 )
+ {
+ if ( *s1 == '\\' )
+ /* Escape the '\' */
+ *s2++ = '\\';
+
+ *s2++ = *s1++;
+ }
+
+ *s2 = '\0';
+
+ if ( do_infile )
+ sprintf( directive, line_fmt, linenum, filename );
+ else
+ {
+ if ( output_file == stdout )
+ /* Account for the line directive itself. */
+ ++out_linenum;
+
+ sprintf( directive, line_fmt, out_linenum, filename );
+ }
+
+ /* If output_file is nil then we should put the directive in
+ * the accumulated actions.
+ */
+ if ( output_file )
+ {
+ fputs( directive, output_file );
+ }
+ else
+ add_action( directive );
+ }
+
+
+/* mark_defs1 - mark the current position in the action array as
+ * representing where the user's section 1 definitions end
+ * and the prolog begins
+ */
+void mark_defs1()
+ {
+ defs1_offset = 0;
+ action_array[action_index++] = '\0';
+ action_offset = prolog_offset = action_index;
+ action_array[action_index] = '\0';
+ }
+
+
+/* mark_prolog - mark the current position in the action array as
+ * representing the end of the action prolog
+ */
+void mark_prolog()
+ {
+ action_array[action_index++] = '\0';
+ action_offset = action_index;
+ action_array[action_index] = '\0';
+ }
+
+
+/* mk2data - generate a data statement for a two-dimensional array
+ *
+ * Generates a data statement initializing the current 2-D array to "value".
+ */
+void mk2data( value )
+int value;
+ {
+ if ( datapos >= NUMDATAITEMS )
+ {
+ outc( ',' );
+ dataflush();
+ }
+
+ if ( datapos == 0 )
+ /* Indent. */
+ out( " " );
+
+ else
+ outc( ',' );
+
+ ++datapos;
+
+ out_dec( "%5d", value );
+ }
+
+
+/* mkdata - generate a data statement
+ *
+ * Generates a data statement initializing the current array element to
+ * "value".
+ */
+void mkdata( value )
+int value;
+ {
+ if ( datapos >= NUMDATAITEMS )
+ {
+ outc( ',' );
+ dataflush();
+ }
+
+ if ( datapos == 0 )
+ /* Indent. */
+ out( " " );
+ else
+ outc( ',' );
+
+ ++datapos;
+
+ out_dec( "%5d", value );
+ }
+
+
+/* myctoi - return the integer represented by a string of digits */
+
+int myctoi( array )
+char array[];
+ {
+ int val = 0;
+
+ (void) sscanf( array, "%d", &val );
+
+ return val;
+ }
+
+
+/* myesc - return character corresponding to escape sequence */
+
+Char myesc( array )
+Char array[];
+ {
+ Char c, esc_char;
+
+ switch ( array[1] )
+ {
+ case 'b': return '\b';
+ case 'f': return '\f';
+ case 'n': return '\n';
+ case 'r': return '\r';
+ case 't': return '\t';
+
+#if __STDC__
+ case 'a': return '\a';
+ case 'v': return '\v';
+#else
+ case 'a': return '\007';
+ case 'v': return '\013';
+#endif
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ { /* \<octal> */
+ int sptr = 1;
+
+ while ( isascii( array[sptr] ) &&
+ isdigit( array[sptr] ) )
+ /* Don't increment inside loop control
+ * because if isdigit() is a macro it might
+ * expand into multiple increments ...
+ */
+ ++sptr;
+
+ c = array[sptr];
+ array[sptr] = '\0';
+
+ esc_char = otoi( array + 1 );
+
+ array[sptr] = c;
+
+ return esc_char;
+ }
+
+ case 'x':
+ { /* \x<hex> */
+ int sptr = 2;
+
+ while ( isascii( array[sptr] ) &&
+ isxdigit( (char) array[sptr] ) )
+ /* Don't increment inside loop control
+ * because if isdigit() is a macro it might
+ * expand into multiple increments ...
+ */
+ ++sptr;
+
+ c = array[sptr];
+ array[sptr] = '\0';
+
+ esc_char = htoi( array + 2 );
+
+ array[sptr] = c;
+
+ return esc_char;
+ }
+
+ default:
+ return array[1];
+ }
+ }
+
+
+/* otoi - convert an octal digit string to an integer value */
+
+int otoi( str )
+Char str[];
+ {
+ unsigned int result;
+
+ (void) sscanf( (char *) str, "%o", &result );
+ return result;
+ }
+
+
+/* out - various flavors of outputing a (possibly formatted) string for the
+ * generated scanner, keeping track of the line count.
+ */
+
+void out( str )
+const char str[];
+ {
+ fputs( str, stdout );
+ out_line_count( str );
+ }
+
+void out_dec( fmt, n )
+const char fmt[];
+int n;
+ {
+ printf( fmt, n );
+ out_line_count( fmt );
+ }
+
+void out_dec2( fmt, n1, n2 )
+const char fmt[];
+int n1, n2;
+ {
+ printf( fmt, n1, n2 );
+ out_line_count( fmt );
+ }
+
+void out_hex( fmt, x )
+const char fmt[];
+unsigned int x;
+ {
+ printf( fmt, x );
+ out_line_count( fmt );
+ }
+
+void out_line_count( str )
+const char str[];
+ {
+ register int i;
+
+ for ( i = 0; str[i]; ++i )
+ if ( str[i] == '\n' )
+ ++out_linenum;
+ }
+
+void out_str( fmt, str )
+const char fmt[], str[];
+ {
+ printf( fmt, str );
+ out_line_count( fmt );
+ out_line_count( str );
+ }
+
+void out_str3( fmt, s1, s2, s3 )
+const char fmt[], s1[], s2[], s3[];
+ {
+ printf( fmt, s1, s2, s3 );
+ out_line_count( fmt );
+ out_line_count( s1 );
+ out_line_count( s2 );
+ out_line_count( s3 );
+ }
+
+void out_str_dec( fmt, str, n )
+const char fmt[], str[];
+int n;
+ {
+ printf( fmt, str, n );
+ out_line_count( fmt );
+ out_line_count( str );
+ }
+
+void outc( c )
+int c;
+ {
+ putc( c, stdout );
+
+ if ( c == '\n' )
+ ++out_linenum;
+ }
+
+void outn( str )
+const char str[];
+ {
+ puts( str );
+ out_line_count( str );
+ ++out_linenum;
+ }
+
+
+/* readable_form - return the the human-readable form of a character
+ *
+ * The returned string is in static storage.
+ */
+
+char *readable_form( c )
+register int c;
+ {
+ static char rform[10];
+
+ if ( (c >= 0 && c < 32) || c >= 127 )
+ {
+ switch ( c )
+ {
+ case '\b': return "\\b";
+ case '\f': return "\\f";
+ case '\n': return "\\n";
+ case '\r': return "\\r";
+ case '\t': return "\\t";
+
+#if __STDC__
+ case '\a': return "\\a";
+ case '\v': return "\\v";
+#endif
+
+ default:
+ (void) sprintf( rform, "\\%.3o",
+ (unsigned int) c );
+ return rform;
+ }
+ }
+
+ else if ( c == ' ' )
+ return "' '";
+
+ else
+ {
+ rform[0] = c;
+ rform[1] = '\0';
+
+ return rform;
+ }
+ }
+
+
+/* reallocate_array - increase the size of a dynamic array */
+
+void *reallocate_array( array, size, element_size )
+void *array;
+int size;
+size_t element_size;
+ {
+ register void *new_array;
+ size_t num_bytes = element_size * size;
+
+ new_array = flex_realloc( array, num_bytes );
+ if ( ! new_array )
+ flexfatal( _( "attempt to increase array size failed" ) );
+
+ return new_array;
+ }
+
+
+/* skelout - write out one section of the skeleton file
+ *
+ * Description
+ * Copies skelfile or skel array to stdout until a line beginning with
+ * "%%" or EOF is found.
+ */
+void skelout()
+ {
+ char buf_storage[MAXLINE];
+ char *buf = buf_storage;
+ int do_copy = 1;
+
+ /* Loop pulling lines either from the skelfile, if we're using
+ * one, or from the skel[] array.
+ */
+ while ( skelfile ?
+ (fgets( buf, MAXLINE, skelfile ) != NULL) :
+ ((buf = (char *) skel[skel_ind++]) != 0) )
+ { /* copy from skel array */
+ if ( buf[0] == '%' )
+ { /* control line */
+ switch ( buf[1] )
+ {
+ case '%':
+ return;
+
+ case '+':
+ do_copy = C_plus_plus;
+ break;
+
+ case '-':
+ do_copy = ! C_plus_plus;
+ break;
+
+ case '*':
+ do_copy = 1;
+ break;
+
+ default:
+ flexfatal(
+ _( "bad line in skeleton file" ) );
+ }
+ }
+
+ else if ( do_copy )
+ {
+ if ( skelfile )
+ /* Skeleton file reads include final
+ * newline, skel[] array does not.
+ */
+ out( buf );
+ else
+ outn( buf );
+ }
+ }
+ }
+
+
+/* transition_struct_out - output a yy_trans_info structure
+ *
+ * outputs the yy_trans_info structure with the two elements, element_v and
+ * element_n. Formats the output with spaces and carriage returns.
+ */
+
+void transition_struct_out( element_v, element_n )
+int element_v, element_n;
+ {
+ out_dec2( " {%4d,%4d },", element_v, element_n );
+
+ datapos += TRANS_STRUCT_PRINT_LENGTH;
+
+ if ( datapos >= 79 - TRANS_STRUCT_PRINT_LENGTH )
+ {
+ outc( '\n' );
+
+ if ( ++dataline % 10 == 0 )
+ outc( '\n' );
+
+ datapos = 0;
+ }
+ }
+
+
+/* The following is only needed when building flex's parser using certain
+ * broken versions of bison.
+ */
+void *yy_flex_xmalloc( size )
+int size;
+ {
+ void *result = flex_alloc( (size_t) size );
+
+ if ( ! result )
+ flexfatal(
+ _( "memory allocation failed in yy_flex_xmalloc()" ) );
+
+ return result;
+ }
+
+
+/* zero_out - set a region of memory to 0
+ *
+ * Sets region_ptr[0] through region_ptr[size_in_bytes - 1] to zero.
+ */
+
+void zero_out( region_ptr, size_in_bytes )
+char *region_ptr;
+size_t size_in_bytes;
+ {
+ register char *rp, *rp_end;
+
+ rp = region_ptr;
+ rp_end = region_ptr + size_in_bytes;
+
+ while ( rp < rp_end )
+ *rp++ = 0;
+ }
diff --git a/Tools/android/flex-2.5.4a/mkinstalldirs b/Tools/android/flex-2.5.4a/mkinstalldirs
new file mode 100755
index 0000000..0e29377
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/mkinstalldirs
@@ -0,0 +1,35 @@
+#!/bin/sh
+# Make directory hierarchy.
+# Written by Noah Friedman <friedman@prep.ai.mit.edu>
+# Public domain.
+
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+errstatus=0
+
+for file in ${1+"$@"} ; do
+ oIFS="${IFS}"
+ # Some sh's can't handle IFS=/ for some reason.
+ IFS='%'
+ set - `echo ${file} | sed -e 's@/@%@g' -e 's@^%@/@'`
+ IFS="${oIFS}"
+
+ pathcomp=''
+
+ for d in ${1+"$@"} ; do
+ pathcomp="${pathcomp}${d}"
+
+ if test ! -d "${pathcomp}"; then
+ echo "mkdir $pathcomp" 1>&2
+ mkdir "${pathcomp}" || errstatus=$?
+ fi
+
+ pathcomp="${pathcomp}/"
+ done
+done
+
+exit $errstatus
+
+# eof
diff --git a/Tools/android/flex-2.5.4a/mkskel.sh b/Tools/android/flex-2.5.4a/mkskel.sh
new file mode 100755
index 0000000..a03a11a
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/mkskel.sh
@@ -0,0 +1,16 @@
+#! /bin/sh
+
+cat <<!
+/* File created from flex.skl via mkskel.sh */
+
+#include "flexdef.h"
+
+const char *skel[] = {
+!
+
+sed 's/\\/&&/g' $* | sed 's/"/\\"/g' | sed 's/.*/ "&",/'
+
+cat <<!
+ 0
+};
+!
diff --git a/Tools/android/flex-2.5.4a/nfa.c b/Tools/android/flex-2.5.4a/nfa.c
new file mode 100644
index 0000000..bfa2c29
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/nfa.c
@@ -0,0 +1,709 @@
+/* nfa - NFA construction routines */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/nfa.c,v 2.17 95/03/04 16:11:42 vern Exp $ */
+
+#include "flexdef.h"
+
+
+/* declare functions that have forward references */
+
+int dupmachine PROTO((int));
+void mkxtion PROTO((int, int));
+
+
+/* add_accept - add an accepting state to a machine
+ *
+ * accepting_number becomes mach's accepting number.
+ */
+
+void add_accept( mach, accepting_number )
+int mach, accepting_number;
+ {
+ /* Hang the accepting number off an epsilon state. if it is associated
+ * with a state that has a non-epsilon out-transition, then the state
+ * will accept BEFORE it makes that transition, i.e., one character
+ * too soon.
+ */
+
+ if ( transchar[finalst[mach]] == SYM_EPSILON )
+ accptnum[finalst[mach]] = accepting_number;
+
+ else
+ {
+ int astate = mkstate( SYM_EPSILON );
+ accptnum[astate] = accepting_number;
+ (void) link_machines( mach, astate );
+ }
+ }
+
+
+/* copysingl - make a given number of copies of a singleton machine
+ *
+ * synopsis
+ *
+ * newsng = copysingl( singl, num );
+ *
+ * newsng - a new singleton composed of num copies of singl
+ * singl - a singleton machine
+ * num - the number of copies of singl to be present in newsng
+ */
+
+int copysingl( singl, num )
+int singl, num;
+ {
+ int copy, i;
+
+ copy = mkstate( SYM_EPSILON );
+
+ for ( i = 1; i <= num; ++i )
+ copy = link_machines( copy, dupmachine( singl ) );
+
+ return copy;
+ }
+
+
+/* dumpnfa - debugging routine to write out an nfa */
+
+void dumpnfa( state1 )
+int state1;
+
+ {
+ int sym, tsp1, tsp2, anum, ns;
+
+ fprintf( stderr,
+ _( "\n\n********** beginning dump of nfa with start state %d\n" ),
+ state1 );
+
+ /* We probably should loop starting at firstst[state1] and going to
+ * lastst[state1], but they're not maintained properly when we "or"
+ * all of the rules together. So we use our knowledge that the machine
+ * starts at state 1 and ends at lastnfa.
+ */
+
+ /* for ( ns = firstst[state1]; ns <= lastst[state1]; ++ns ) */
+ for ( ns = 1; ns <= lastnfa; ++ns )
+ {
+ fprintf( stderr, _( "state # %4d\t" ), ns );
+
+ sym = transchar[ns];
+ tsp1 = trans1[ns];
+ tsp2 = trans2[ns];
+ anum = accptnum[ns];
+
+ fprintf( stderr, "%3d: %4d, %4d", sym, tsp1, tsp2 );
+
+ if ( anum != NIL )
+ fprintf( stderr, " [%d]", anum );
+
+ fprintf( stderr, "\n" );
+ }
+
+ fprintf( stderr, _( "********** end of dump\n" ) );
+ }
+
+
+/* dupmachine - make a duplicate of a given machine
+ *
+ * synopsis
+ *
+ * copy = dupmachine( mach );
+ *
+ * copy - holds duplicate of mach
+ * mach - machine to be duplicated
+ *
+ * note that the copy of mach is NOT an exact duplicate; rather, all the
+ * transition states values are adjusted so that the copy is self-contained,
+ * as the original should have been.
+ *
+ * also note that the original MUST be contiguous, with its low and high
+ * states accessible by the arrays firstst and lastst
+ */
+
+int dupmachine( mach )
+int mach;
+ {
+ int i, init, state_offset;
+ int state = 0;
+ int last = lastst[mach];
+
+ for ( i = firstst[mach]; i <= last; ++i )
+ {
+ state = mkstate( transchar[i] );
+
+ if ( trans1[i] != NO_TRANSITION )
+ {
+ mkxtion( finalst[state], trans1[i] + state - i );
+
+ if ( transchar[i] == SYM_EPSILON &&
+ trans2[i] != NO_TRANSITION )
+ mkxtion( finalst[state],
+ trans2[i] + state - i );
+ }
+
+ accptnum[state] = accptnum[i];
+ }
+
+ if ( state == 0 )
+ flexfatal( _( "empty machine in dupmachine()" ) );
+
+ state_offset = state - i + 1;
+
+ init = mach + state_offset;
+ firstst[init] = firstst[mach] + state_offset;
+ finalst[init] = finalst[mach] + state_offset;
+ lastst[init] = lastst[mach] + state_offset;
+
+ return init;
+ }
+
+
+/* finish_rule - finish up the processing for a rule
+ *
+ * An accepting number is added to the given machine. If variable_trail_rule
+ * is true then the rule has trailing context and both the head and trail
+ * are variable size. Otherwise if headcnt or trailcnt is non-zero then
+ * the machine recognizes a pattern with trailing context and headcnt is
+ * the number of characters in the matched part of the pattern, or zero
+ * if the matched part has variable length. trailcnt is the number of
+ * trailing context characters in the pattern, or zero if the trailing
+ * context has variable length.
+ */
+
+void finish_rule( mach, variable_trail_rule, headcnt, trailcnt )
+int mach, variable_trail_rule, headcnt, trailcnt;
+ {
+ char action_text[MAXLINE];
+
+ add_accept( mach, num_rules );
+
+ /* We did this in new_rule(), but it often gets the wrong
+ * number because we do it before we start parsing the current rule.
+ */
+ rule_linenum[num_rules] = linenum;
+
+ /* If this is a continued action, then the line-number has already
+ * been updated, giving us the wrong number.
+ */
+ if ( continued_action )
+ --rule_linenum[num_rules];
+
+ sprintf( action_text, "case %d:\n", num_rules );
+ add_action( action_text );
+
+ if ( variable_trail_rule )
+ {
+ rule_type[num_rules] = RULE_VARIABLE;
+
+ if ( performance_report > 0 )
+ fprintf( stderr,
+ _( "Variable trailing context rule at line %d\n" ),
+ rule_linenum[num_rules] );
+
+ variable_trailing_context_rules = true;
+ }
+
+ else
+ {
+ rule_type[num_rules] = RULE_NORMAL;
+
+ if ( headcnt > 0 || trailcnt > 0 )
+ {
+ /* Do trailing context magic to not match the trailing
+ * characters.
+ */
+ char *scanner_cp = "yy_c_buf_p = yy_cp";
+ char *scanner_bp = "yy_bp";
+
+ add_action(
+ "*yy_cp = yy_hold_char; /* undo effects of setting up yytext */\n" );
+
+ if ( headcnt > 0 )
+ {
+ sprintf( action_text, "%s = %s + %d;\n",
+ scanner_cp, scanner_bp, headcnt );
+ add_action( action_text );
+ }
+
+ else
+ {
+ sprintf( action_text, "%s -= %d;\n",
+ scanner_cp, trailcnt );
+ add_action( action_text );
+ }
+
+ add_action(
+ "YY_DO_BEFORE_ACTION; /* set up yytext again */\n" );
+ }
+ }
+
+ /* Okay, in the action code at this point yytext and yyleng have
+ * their proper final values for this rule, so here's the point
+ * to do any user action. But don't do it for continued actions,
+ * as that'll result in multiple YY_RULE_SETUP's.
+ */
+ if ( ! continued_action )
+ add_action( "YY_RULE_SETUP\n" );
+
+ line_directive_out( (FILE *) 0, 1 );
+ }
+
+
+/* link_machines - connect two machines together
+ *
+ * synopsis
+ *
+ * new = link_machines( first, last );
+ *
+ * new - a machine constructed by connecting first to last
+ * first - the machine whose successor is to be last
+ * last - the machine whose predecessor is to be first
+ *
+ * note: this routine concatenates the machine first with the machine
+ * last to produce a machine new which will pattern-match first first
+ * and then last, and will fail if either of the sub-patterns fails.
+ * FIRST is set to new by the operation. last is unmolested.
+ */
+
+int link_machines( first, last )
+int first, last;
+ {
+ if ( first == NIL )
+ return last;
+
+ else if ( last == NIL )
+ return first;
+
+ else
+ {
+ mkxtion( finalst[first], last );
+ finalst[first] = finalst[last];
+ lastst[first] = MAX( lastst[first], lastst[last] );
+ firstst[first] = MIN( firstst[first], firstst[last] );
+
+ return first;
+ }
+ }
+
+
+/* mark_beginning_as_normal - mark each "beginning" state in a machine
+ * as being a "normal" (i.e., not trailing context-
+ * associated) states
+ *
+ * The "beginning" states are the epsilon closure of the first state
+ */
+
+void mark_beginning_as_normal( mach )
+register int mach;
+ {
+ switch ( state_type[mach] )
+ {
+ case STATE_NORMAL:
+ /* Oh, we've already visited here. */
+ return;
+
+ case STATE_TRAILING_CONTEXT:
+ state_type[mach] = STATE_NORMAL;
+
+ if ( transchar[mach] == SYM_EPSILON )
+ {
+ if ( trans1[mach] != NO_TRANSITION )
+ mark_beginning_as_normal(
+ trans1[mach] );
+
+ if ( trans2[mach] != NO_TRANSITION )
+ mark_beginning_as_normal(
+ trans2[mach] );
+ }
+ break;
+
+ default:
+ flexerror(
+ _( "bad state type in mark_beginning_as_normal()" ) );
+ break;
+ }
+ }
+
+
+/* mkbranch - make a machine that branches to two machines
+ *
+ * synopsis
+ *
+ * branch = mkbranch( first, second );
+ *
+ * branch - a machine which matches either first's pattern or second's
+ * first, second - machines whose patterns are to be or'ed (the | operator)
+ *
+ * Note that first and second are NEITHER destroyed by the operation. Also,
+ * the resulting machine CANNOT be used with any other "mk" operation except
+ * more mkbranch's. Compare with mkor()
+ */
+
+int mkbranch( first, second )
+int first, second;
+ {
+ int eps;
+
+ if ( first == NO_TRANSITION )
+ return second;
+
+ else if ( second == NO_TRANSITION )
+ return first;
+
+ eps = mkstate( SYM_EPSILON );
+
+ mkxtion( eps, first );
+ mkxtion( eps, second );
+
+ return eps;
+ }
+
+
+/* mkclos - convert a machine into a closure
+ *
+ * synopsis
+ * new = mkclos( state );
+ *
+ * new - a new state which matches the closure of "state"
+ */
+
+int mkclos( state )
+int state;
+ {
+ return mkopt( mkposcl( state ) );
+ }
+
+
+/* mkopt - make a machine optional
+ *
+ * synopsis
+ *
+ * new = mkopt( mach );
+ *
+ * new - a machine which optionally matches whatever mach matched
+ * mach - the machine to make optional
+ *
+ * notes:
+ * 1. mach must be the last machine created
+ * 2. mach is destroyed by the call
+ */
+
+int mkopt( mach )
+int mach;
+ {
+ int eps;
+
+ if ( ! SUPER_FREE_EPSILON(finalst[mach]) )
+ {
+ eps = mkstate( SYM_EPSILON );
+ mach = link_machines( mach, eps );
+ }
+
+ /* Can't skimp on the following if FREE_EPSILON(mach) is true because
+ * some state interior to "mach" might point back to the beginning
+ * for a closure.
+ */
+ eps = mkstate( SYM_EPSILON );
+ mach = link_machines( eps, mach );
+
+ mkxtion( mach, finalst[mach] );
+
+ return mach;
+ }
+
+
+/* mkor - make a machine that matches either one of two machines
+ *
+ * synopsis
+ *
+ * new = mkor( first, second );
+ *
+ * new - a machine which matches either first's pattern or second's
+ * first, second - machines whose patterns are to be or'ed (the | operator)
+ *
+ * note that first and second are both destroyed by the operation
+ * the code is rather convoluted because an attempt is made to minimize
+ * the number of epsilon states needed
+ */
+
+int mkor( first, second )
+int first, second;
+ {
+ int eps, orend;
+
+ if ( first == NIL )
+ return second;
+
+ else if ( second == NIL )
+ return first;
+
+ else
+ {
+ /* See comment in mkopt() about why we can't use the first
+ * state of "first" or "second" if they satisfy "FREE_EPSILON".
+ */
+ eps = mkstate( SYM_EPSILON );
+
+ first = link_machines( eps, first );
+
+ mkxtion( first, second );
+
+ if ( SUPER_FREE_EPSILON(finalst[first]) &&
+ accptnum[finalst[first]] == NIL )
+ {
+ orend = finalst[first];
+ mkxtion( finalst[second], orend );
+ }
+
+ else if ( SUPER_FREE_EPSILON(finalst[second]) &&
+ accptnum[finalst[second]] == NIL )
+ {
+ orend = finalst[second];
+ mkxtion( finalst[first], orend );
+ }
+
+ else
+ {
+ eps = mkstate( SYM_EPSILON );
+
+ first = link_machines( first, eps );
+ orend = finalst[first];
+
+ mkxtion( finalst[second], orend );
+ }
+ }
+
+ finalst[first] = orend;
+ return first;
+ }
+
+
+/* mkposcl - convert a machine into a positive closure
+ *
+ * synopsis
+ * new = mkposcl( state );
+ *
+ * new - a machine matching the positive closure of "state"
+ */
+
+int mkposcl( state )
+int state;
+ {
+ int eps;
+
+ if ( SUPER_FREE_EPSILON(finalst[state]) )
+ {
+ mkxtion( finalst[state], state );
+ return state;
+ }
+
+ else
+ {
+ eps = mkstate( SYM_EPSILON );
+ mkxtion( eps, state );
+ return link_machines( state, eps );
+ }
+ }
+
+
+/* mkrep - make a replicated machine
+ *
+ * synopsis
+ * new = mkrep( mach, lb, ub );
+ *
+ * new - a machine that matches whatever "mach" matched from "lb"
+ * number of times to "ub" number of times
+ *
+ * note
+ * if "ub" is INFINITY then "new" matches "lb" or more occurrences of "mach"
+ */
+
+int mkrep( mach, lb, ub )
+int mach, lb, ub;
+ {
+ int base_mach, tail, copy, i;
+
+ base_mach = copysingl( mach, lb - 1 );
+
+ if ( ub == INFINITY )
+ {
+ copy = dupmachine( mach );
+ mach = link_machines( mach,
+ link_machines( base_mach, mkclos( copy ) ) );
+ }
+
+ else
+ {
+ tail = mkstate( SYM_EPSILON );
+
+ for ( i = lb; i < ub; ++i )
+ {
+ copy = dupmachine( mach );
+ tail = mkopt( link_machines( copy, tail ) );
+ }
+
+ mach = link_machines( mach, link_machines( base_mach, tail ) );
+ }
+
+ return mach;
+ }
+
+
+/* mkstate - create a state with a transition on a given symbol
+ *
+ * synopsis
+ *
+ * state = mkstate( sym );
+ *
+ * state - a new state matching sym
+ * sym - the symbol the new state is to have an out-transition on
+ *
+ * note that this routine makes new states in ascending order through the
+ * state array (and increments LASTNFA accordingly). The routine DUPMACHINE
+ * relies on machines being made in ascending order and that they are
+ * CONTIGUOUS. Change it and you will have to rewrite DUPMACHINE (kludge
+ * that it admittedly is)
+ */
+
+int mkstate( sym )
+int sym;
+ {
+ if ( ++lastnfa >= current_mns )
+ {
+ if ( (current_mns += MNS_INCREMENT) >= MAXIMUM_MNS )
+ lerrif(
+ _( "input rules are too complicated (>= %d NFA states)" ),
+ current_mns );
+
+ ++num_reallocs;
+
+ firstst = reallocate_integer_array( firstst, current_mns );
+ lastst = reallocate_integer_array( lastst, current_mns );
+ finalst = reallocate_integer_array( finalst, current_mns );
+ transchar = reallocate_integer_array( transchar, current_mns );
+ trans1 = reallocate_integer_array( trans1, current_mns );
+ trans2 = reallocate_integer_array( trans2, current_mns );
+ accptnum = reallocate_integer_array( accptnum, current_mns );
+ assoc_rule =
+ reallocate_integer_array( assoc_rule, current_mns );
+ state_type =
+ reallocate_integer_array( state_type, current_mns );
+ }
+
+ firstst[lastnfa] = lastnfa;
+ finalst[lastnfa] = lastnfa;
+ lastst[lastnfa] = lastnfa;
+ transchar[lastnfa] = sym;
+ trans1[lastnfa] = NO_TRANSITION;
+ trans2[lastnfa] = NO_TRANSITION;
+ accptnum[lastnfa] = NIL;
+ assoc_rule[lastnfa] = num_rules;
+ state_type[lastnfa] = current_state_type;
+
+ /* Fix up equivalence classes base on this transition. Note that any
+ * character which has its own transition gets its own equivalence
+ * class. Thus only characters which are only in character classes
+ * have a chance at being in the same equivalence class. E.g. "a|b"
+ * puts 'a' and 'b' into two different equivalence classes. "[ab]"
+ * puts them in the same equivalence class (barring other differences
+ * elsewhere in the input).
+ */
+
+ if ( sym < 0 )
+ {
+ /* We don't have to update the equivalence classes since
+ * that was already done when the ccl was created for the
+ * first time.
+ */
+ }
+
+ else if ( sym == SYM_EPSILON )
+ ++numeps;
+
+ else
+ {
+ check_char( sym );
+
+ if ( useecs )
+ /* Map NUL's to csize. */
+ mkechar( sym ? sym : csize, nextecm, ecgroup );
+ }
+
+ return lastnfa;
+ }
+
+
+/* mkxtion - make a transition from one state to another
+ *
+ * synopsis
+ *
+ * mkxtion( statefrom, stateto );
+ *
+ * statefrom - the state from which the transition is to be made
+ * stateto - the state to which the transition is to be made
+ */
+
+void mkxtion( statefrom, stateto )
+int statefrom, stateto;
+ {
+ if ( trans1[statefrom] == NO_TRANSITION )
+ trans1[statefrom] = stateto;
+
+ else if ( (transchar[statefrom] != SYM_EPSILON) ||
+ (trans2[statefrom] != NO_TRANSITION) )
+ flexfatal( _( "found too many transitions in mkxtion()" ) );
+
+ else
+ { /* second out-transition for an epsilon state */
+ ++eps2;
+ trans2[statefrom] = stateto;
+ }
+ }
+
+/* new_rule - initialize for a new rule */
+
+void new_rule()
+ {
+ if ( ++num_rules >= current_max_rules )
+ {
+ ++num_reallocs;
+ current_max_rules += MAX_RULES_INCREMENT;
+ rule_type = reallocate_integer_array( rule_type,
+ current_max_rules );
+ rule_linenum = reallocate_integer_array( rule_linenum,
+ current_max_rules );
+ rule_useful = reallocate_integer_array( rule_useful,
+ current_max_rules );
+ }
+
+ if ( num_rules > MAX_RULE )
+ lerrif( _( "too many rules (> %d)!" ), MAX_RULE );
+
+ rule_linenum[num_rules] = linenum;
+ rule_useful[num_rules] = false;
+ }
diff --git a/Tools/android/flex-2.5.4a/parse.y b/Tools/android/flex-2.5.4a/parse.y
new file mode 100644
index 0000000..c6d7eea
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/parse.y
@@ -0,0 +1,913 @@
+/* parse.y - parser for flex input */
+
+%token CHAR NUMBER SECTEND SCDECL XSCDECL NAME PREVCCL EOF_OP
+%token OPTION_OP OPT_OUTFILE OPT_PREFIX OPT_YYCLASS
+
+%token CCE_ALNUM CCE_ALPHA CCE_BLANK CCE_CNTRL CCE_DIGIT CCE_GRAPH
+%token CCE_LOWER CCE_PRINT CCE_PUNCT CCE_SPACE CCE_UPPER CCE_XDIGIT
+
+%{
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/parse.y,v 2.28 95/04/21 11:51:51 vern Exp $ */
+
+
+/* Some versions of bison are broken in that they use alloca() but don't
+ * declare it properly. The following is the patented (just kidding!)
+ * #ifdef chud to fix the problem, courtesy of Francois Pinard.
+ */
+#ifdef YYBISON
+/* AIX requires this to be the first thing in the file. What a piece. */
+# ifdef _AIX
+ #pragma alloca
+# endif
+#endif
+
+#include "flexdef.h"
+
+/* The remainder of the alloca() cruft has to come after including flexdef.h,
+ * so HAVE_ALLOCA_H is (possibly) defined.
+ */
+#ifdef YYBISON
+# ifdef __GNUC__
+# ifndef alloca
+# define alloca __builtin_alloca
+# endif
+# else
+# if HAVE_ALLOCA_H
+# include <alloca.h>
+# else
+# ifdef __hpux
+void *alloca ();
+# else
+# ifdef __TURBOC__
+# include <malloc.h>
+# else
+char *alloca ();
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* Bletch, ^^^^ that was ugly! */
+
+
+int pat, scnum, eps, headcnt, trailcnt, anyccl, lastchar, i, rulelen;
+int trlcontxt, xcluflg, currccl, cclsorted, varlength, variable_trail_rule;
+
+int *scon_stk;
+int scon_stk_ptr;
+
+static int madeany = false; /* whether we've made the '.' character class */
+int previous_continued_action; /* whether the previous rule's action was '|' */
+
+/* Expand a POSIX character class expression. */
+#define CCL_EXPR(func) \
+ { \
+ int c; \
+ for ( c = 0; c < csize; ++c ) \
+ if ( isascii(c) && func(c) ) \
+ ccladd( currccl, c ); \
+ }
+
+/* While POSIX defines isblank(), it's not ANSI C. */
+#define IS_BLANK(c) ((c) == ' ' || (c) == '\t')
+
+/* On some over-ambitious machines, such as DEC Alpha's, the default
+ * token type is "long" instead of "int"; this leads to problems with
+ * declaring yylval in flexdef.h. But so far, all the yacc's I've seen
+ * wrap their definitions of YYSTYPE with "#ifndef YYSTYPE"'s, so the
+ * following should ensure that the default token type is "int".
+ */
+#define YYSTYPE int
+
+%}
+
+%%
+goal : initlex sect1 sect1end sect2 initforrule
+ { /* add default rule */
+ int def_rule;
+
+ pat = cclinit();
+ cclnegate( pat );
+
+ def_rule = mkstate( -pat );
+
+ /* Remember the number of the default rule so we
+ * don't generate "can't match" warnings for it.
+ */
+ default_rule = num_rules;
+
+ finish_rule( def_rule, false, 0, 0 );
+
+ for ( i = 1; i <= lastsc; ++i )
+ scset[i] = mkbranch( scset[i], def_rule );
+
+ if ( spprdflt )
+ add_action(
+ "YY_FATAL_ERROR( \"flex scanner jammed\" )" );
+ else
+ add_action( "ECHO" );
+
+ add_action( ";\n\tYY_BREAK\n" );
+ }
+ ;
+
+initlex :
+ { /* initialize for processing rules */
+
+ /* Create default DFA start condition. */
+ scinstal( "INITIAL", false );
+ }
+ ;
+
+sect1 : sect1 startconddecl namelist1
+ | sect1 options
+ |
+ | error
+ { synerr( "unknown error processing section 1" ); }
+ ;
+
+sect1end : SECTEND
+ {
+ check_options();
+ scon_stk = allocate_integer_array( lastsc + 1 );
+ scon_stk_ptr = 0;
+ }
+ ;
+
+startconddecl : SCDECL
+ { xcluflg = false; }
+
+ | XSCDECL
+ { xcluflg = true; }
+ ;
+
+namelist1 : namelist1 NAME
+ { scinstal( nmstr, xcluflg ); }
+
+ | NAME
+ { scinstal( nmstr, xcluflg ); }
+
+ | error
+ { synerr( "bad start condition list" ); }
+ ;
+
+options : OPTION_OP optionlist
+ ;
+
+optionlist : optionlist option
+ |
+ ;
+
+option : OPT_OUTFILE '=' NAME
+ {
+ outfilename = copy_string( nmstr );
+ did_outfilename = 1;
+ }
+ | OPT_PREFIX '=' NAME
+ { prefix = copy_string( nmstr ); }
+ | OPT_YYCLASS '=' NAME
+ { yyclass = copy_string( nmstr ); }
+ ;
+
+sect2 : sect2 scon initforrule flexrule '\n'
+ { scon_stk_ptr = $2; }
+ | sect2 scon '{' sect2 '}'
+ { scon_stk_ptr = $2; }
+ |
+ ;
+
+initforrule :
+ {
+ /* Initialize for a parse of one rule. */
+ trlcontxt = variable_trail_rule = varlength = false;
+ trailcnt = headcnt = rulelen = 0;
+ current_state_type = STATE_NORMAL;
+ previous_continued_action = continued_action;
+ in_rule = true;
+
+ new_rule();
+ }
+ ;
+
+flexrule : '^' rule
+ {
+ pat = $2;
+ finish_rule( pat, variable_trail_rule,
+ headcnt, trailcnt );
+
+ if ( scon_stk_ptr > 0 )
+ {
+ for ( i = 1; i <= scon_stk_ptr; ++i )
+ scbol[scon_stk[i]] =
+ mkbranch( scbol[scon_stk[i]],
+ pat );
+ }
+
+ else
+ {
+ /* Add to all non-exclusive start conditions,
+ * including the default (0) start condition.
+ */
+
+ for ( i = 1; i <= lastsc; ++i )
+ if ( ! scxclu[i] )
+ scbol[i] = mkbranch( scbol[i],
+ pat );
+ }
+
+ if ( ! bol_needed )
+ {
+ bol_needed = true;
+
+ if ( performance_report > 1 )
+ pinpoint_message(
+ "'^' operator results in sub-optimal performance" );
+ }
+ }
+
+ | rule
+ {
+ pat = $1;
+ finish_rule( pat, variable_trail_rule,
+ headcnt, trailcnt );
+
+ if ( scon_stk_ptr > 0 )
+ {
+ for ( i = 1; i <= scon_stk_ptr; ++i )
+ scset[scon_stk[i]] =
+ mkbranch( scset[scon_stk[i]],
+ pat );
+ }
+
+ else
+ {
+ for ( i = 1; i <= lastsc; ++i )
+ if ( ! scxclu[i] )
+ scset[i] =
+ mkbranch( scset[i],
+ pat );
+ }
+ }
+
+ | EOF_OP
+ {
+ if ( scon_stk_ptr > 0 )
+ build_eof_action();
+
+ else
+ {
+ /* This EOF applies to all start conditions
+ * which don't already have EOF actions.
+ */
+ for ( i = 1; i <= lastsc; ++i )
+ if ( ! sceof[i] )
+ scon_stk[++scon_stk_ptr] = i;
+
+ if ( scon_stk_ptr == 0 )
+ warn(
+ "all start conditions already have <<EOF>> rules" );
+
+ else
+ build_eof_action();
+ }
+ }
+
+ | error
+ { synerr( "unrecognized rule" ); }
+ ;
+
+scon_stk_ptr :
+ { $$ = scon_stk_ptr; }
+ ;
+
+scon : '<' scon_stk_ptr namelist2 '>'
+ { $$ = $2; }
+
+ | '<' '*' '>'
+ {
+ $$ = scon_stk_ptr;
+
+ for ( i = 1; i <= lastsc; ++i )
+ {
+ int j;
+
+ for ( j = 1; j <= scon_stk_ptr; ++j )
+ if ( scon_stk[j] == i )
+ break;
+
+ if ( j > scon_stk_ptr )
+ scon_stk[++scon_stk_ptr] = i;
+ }
+ }
+
+ |
+ { $$ = scon_stk_ptr; }
+ ;
+
+namelist2 : namelist2 ',' sconname
+
+ | sconname
+
+ | error
+ { synerr( "bad start condition list" ); }
+ ;
+
+sconname : NAME
+ {
+ if ( (scnum = sclookup( nmstr )) == 0 )
+ format_pinpoint_message(
+ "undeclared start condition %s",
+ nmstr );
+ else
+ {
+ for ( i = 1; i <= scon_stk_ptr; ++i )
+ if ( scon_stk[i] == scnum )
+ {
+ format_warn(
+ "<%s> specified twice",
+ scname[scnum] );
+ break;
+ }
+
+ if ( i > scon_stk_ptr )
+ scon_stk[++scon_stk_ptr] = scnum;
+ }
+ }
+ ;
+
+rule : re2 re
+ {
+ if ( transchar[lastst[$2]] != SYM_EPSILON )
+ /* Provide final transition \now/ so it
+ * will be marked as a trailing context
+ * state.
+ */
+ $2 = link_machines( $2,
+ mkstate( SYM_EPSILON ) );
+
+ mark_beginning_as_normal( $2 );
+ current_state_type = STATE_NORMAL;
+
+ if ( previous_continued_action )
+ {
+ /* We need to treat this as variable trailing
+ * context so that the backup does not happen
+ * in the action but before the action switch
+ * statement. If the backup happens in the
+ * action, then the rules "falling into" this
+ * one's action will *also* do the backup,
+ * erroneously.
+ */
+ if ( ! varlength || headcnt != 0 )
+ warn(
+ "trailing context made variable due to preceding '|' action" );
+
+ /* Mark as variable. */
+ varlength = true;
+ headcnt = 0;
+ }
+
+ if ( lex_compat || (varlength && headcnt == 0) )
+ { /* variable trailing context rule */
+ /* Mark the first part of the rule as the
+ * accepting "head" part of a trailing
+ * context rule.
+ *
+ * By the way, we didn't do this at the
+ * beginning of this production because back
+ * then current_state_type was set up for a
+ * trail rule, and add_accept() can create
+ * a new state ...
+ */
+ add_accept( $1,
+ num_rules | YY_TRAILING_HEAD_MASK );
+ variable_trail_rule = true;
+ }
+
+ else
+ trailcnt = rulelen;
+
+ $$ = link_machines( $1, $2 );
+ }
+
+ | re2 re '$'
+ { synerr( "trailing context used twice" ); }
+
+ | re '$'
+ {
+ headcnt = 0;
+ trailcnt = 1;
+ rulelen = 1;
+ varlength = false;
+
+ current_state_type = STATE_TRAILING_CONTEXT;
+
+ if ( trlcontxt )
+ {
+ synerr( "trailing context used twice" );
+ $$ = mkstate( SYM_EPSILON );
+ }
+
+ else if ( previous_continued_action )
+ {
+ /* See the comment in the rule for "re2 re"
+ * above.
+ */
+ warn(
+ "trailing context made variable due to preceding '|' action" );
+
+ varlength = true;
+ }
+
+ if ( lex_compat || varlength )
+ {
+ /* Again, see the comment in the rule for
+ * "re2 re" above.
+ */
+ add_accept( $1,
+ num_rules | YY_TRAILING_HEAD_MASK );
+ variable_trail_rule = true;
+ }
+
+ trlcontxt = true;
+
+ eps = mkstate( SYM_EPSILON );
+ $$ = link_machines( $1,
+ link_machines( eps, mkstate( '\n' ) ) );
+ }
+
+ | re
+ {
+ $$ = $1;
+
+ if ( trlcontxt )
+ {
+ if ( lex_compat || (varlength && headcnt == 0) )
+ /* Both head and trail are
+ * variable-length.
+ */
+ variable_trail_rule = true;
+ else
+ trailcnt = rulelen;
+ }
+ }
+ ;
+
+
+re : re '|' series
+ {
+ varlength = true;
+ $$ = mkor( $1, $3 );
+ }
+
+ | series
+ { $$ = $1; }
+ ;
+
+
+re2 : re '/'
+ {
+ /* This rule is written separately so the
+ * reduction will occur before the trailing
+ * series is parsed.
+ */
+
+ if ( trlcontxt )
+ synerr( "trailing context used twice" );
+ else
+ trlcontxt = true;
+
+ if ( varlength )
+ /* We hope the trailing context is
+ * fixed-length.
+ */
+ varlength = false;
+ else
+ headcnt = rulelen;
+
+ rulelen = 0;
+
+ current_state_type = STATE_TRAILING_CONTEXT;
+ $$ = $1;
+ }
+ ;
+
+series : series singleton
+ {
+ /* This is where concatenation of adjacent patterns
+ * gets done.
+ */
+ $$ = link_machines( $1, $2 );
+ }
+
+ | singleton
+ { $$ = $1; }
+ ;
+
+singleton : singleton '*'
+ {
+ varlength = true;
+
+ $$ = mkclos( $1 );
+ }
+
+ | singleton '+'
+ {
+ varlength = true;
+ $$ = mkposcl( $1 );
+ }
+
+ | singleton '?'
+ {
+ varlength = true;
+ $$ = mkopt( $1 );
+ }
+
+ | singleton '{' NUMBER ',' NUMBER '}'
+ {
+ varlength = true;
+
+ if ( $3 > $5 || $3 < 0 )
+ {
+ synerr( "bad iteration values" );
+ $$ = $1;
+ }
+ else
+ {
+ if ( $3 == 0 )
+ {
+ if ( $5 <= 0 )
+ {
+ synerr(
+ "bad iteration values" );
+ $$ = $1;
+ }
+ else
+ $$ = mkopt(
+ mkrep( $1, 1, $5 ) );
+ }
+ else
+ $$ = mkrep( $1, $3, $5 );
+ }
+ }
+
+ | singleton '{' NUMBER ',' '}'
+ {
+ varlength = true;
+
+ if ( $3 <= 0 )
+ {
+ synerr( "iteration value must be positive" );
+ $$ = $1;
+ }
+
+ else
+ $$ = mkrep( $1, $3, INFINITY );
+ }
+
+ | singleton '{' NUMBER '}'
+ {
+ /* The singleton could be something like "(foo)",
+ * in which case we have no idea what its length
+ * is, so we punt here.
+ */
+ varlength = true;
+
+ if ( $3 <= 0 )
+ {
+ synerr( "iteration value must be positive" );
+ $$ = $1;
+ }
+
+ else
+ $$ = link_machines( $1,
+ copysingl( $1, $3 - 1 ) );
+ }
+
+ | '.'
+ {
+ if ( ! madeany )
+ {
+ /* Create the '.' character class. */
+ anyccl = cclinit();
+ ccladd( anyccl, '\n' );
+ cclnegate( anyccl );
+
+ if ( useecs )
+ mkeccl( ccltbl + cclmap[anyccl],
+ ccllen[anyccl], nextecm,
+ ecgroup, csize, csize );
+
+ madeany = true;
+ }
+
+ ++rulelen;
+
+ $$ = mkstate( -anyccl );
+ }
+
+ | fullccl
+ {
+ if ( ! cclsorted )
+ /* Sort characters for fast searching. We
+ * use a shell sort since this list could
+ * be large.
+ */
+ cshell( ccltbl + cclmap[$1], ccllen[$1], true );
+
+ if ( useecs )
+ mkeccl( ccltbl + cclmap[$1], ccllen[$1],
+ nextecm, ecgroup, csize, csize );
+
+ ++rulelen;
+
+ $$ = mkstate( -$1 );
+ }
+
+ | PREVCCL
+ {
+ ++rulelen;
+
+ $$ = mkstate( -$1 );
+ }
+
+ | '"' string '"'
+ { $$ = $2; }
+
+ | '(' re ')'
+ { $$ = $2; }
+
+ | CHAR
+ {
+ ++rulelen;
+
+ if ( caseins && $1 >= 'A' && $1 <= 'Z' )
+ $1 = clower( $1 );
+
+ $$ = mkstate( $1 );
+ }
+ ;
+
+fullccl : '[' ccl ']'
+ { $$ = $2; }
+
+ | '[' '^' ccl ']'
+ {
+ cclnegate( $3 );
+ $$ = $3;
+ }
+ ;
+
+ccl : ccl CHAR '-' CHAR
+ {
+ if ( caseins )
+ {
+ if ( $2 >= 'A' && $2 <= 'Z' )
+ $2 = clower( $2 );
+ if ( $4 >= 'A' && $4 <= 'Z' )
+ $4 = clower( $4 );
+ }
+
+ if ( $2 > $4 )
+ synerr( "negative range in character class" );
+
+ else
+ {
+ for ( i = $2; i <= $4; ++i )
+ ccladd( $1, i );
+
+ /* Keep track if this ccl is staying in
+ * alphabetical order.
+ */
+ cclsorted = cclsorted && ($2 > lastchar);
+ lastchar = $4;
+ }
+
+ $$ = $1;
+ }
+
+ | ccl CHAR
+ {
+ if ( caseins && $2 >= 'A' && $2 <= 'Z' )
+ $2 = clower( $2 );
+
+ ccladd( $1, $2 );
+ cclsorted = cclsorted && ($2 > lastchar);
+ lastchar = $2;
+ $$ = $1;
+ }
+
+ | ccl ccl_expr
+ {
+ /* Too hard to properly maintain cclsorted. */
+ cclsorted = false;
+ $$ = $1;
+ }
+
+ |
+ {
+ cclsorted = true;
+ lastchar = 0;
+ currccl = $$ = cclinit();
+ }
+ ;
+
+ccl_expr: CCE_ALNUM { CCL_EXPR(isalnum) }
+ | CCE_ALPHA { CCL_EXPR(isalpha) }
+ | CCE_BLANK { CCL_EXPR(IS_BLANK) }
+ | CCE_CNTRL { CCL_EXPR(iscntrl) }
+ | CCE_DIGIT { CCL_EXPR(isdigit) }
+ | CCE_GRAPH { CCL_EXPR(isgraph) }
+ | CCE_LOWER { CCL_EXPR(islower) }
+ | CCE_PRINT { CCL_EXPR(isprint) }
+ | CCE_PUNCT { CCL_EXPR(ispunct) }
+ | CCE_SPACE { CCL_EXPR(isspace) }
+ | CCE_UPPER {
+ if ( caseins )
+ CCL_EXPR(islower)
+ else
+ CCL_EXPR(isupper)
+ }
+ | CCE_XDIGIT { CCL_EXPR(isxdigit) }
+ ;
+
+string : string CHAR
+ {
+ if ( caseins && $2 >= 'A' && $2 <= 'Z' )
+ $2 = clower( $2 );
+
+ ++rulelen;
+
+ $$ = link_machines( $1, mkstate( $2 ) );
+ }
+
+ |
+ { $$ = mkstate( SYM_EPSILON ); }
+ ;
+
+%%
+
+
+/* build_eof_action - build the "<<EOF>>" action for the active start
+ * conditions
+ */
+
+void build_eof_action()
+ {
+ register int i;
+ char action_text[MAXLINE];
+
+ for ( i = 1; i <= scon_stk_ptr; ++i )
+ {
+ if ( sceof[scon_stk[i]] )
+ format_pinpoint_message(
+ "multiple <<EOF>> rules for start condition %s",
+ scname[scon_stk[i]] );
+
+ else
+ {
+ sceof[scon_stk[i]] = true;
+ sprintf( action_text, "case YY_STATE_EOF(%s):\n",
+ scname[scon_stk[i]] );
+ add_action( action_text );
+ }
+ }
+
+ line_directive_out( (FILE *) 0, 1 );
+
+ /* This isn't a normal rule after all - don't count it as
+ * such, so we don't have any holes in the rule numbering
+ * (which make generating "rule can never match" warnings
+ * more difficult.
+ */
+ --num_rules;
+ ++num_eof_rules;
+ }
+
+
+/* format_synerr - write out formatted syntax error */
+
+void format_synerr( msg, arg )
+char msg[], arg[];
+ {
+ char errmsg[MAXLINE];
+
+ (void) sprintf( errmsg, msg, arg );
+ synerr( errmsg );
+ }
+
+
+/* synerr - report a syntax error */
+
+void synerr( str )
+char str[];
+ {
+ syntaxerror = true;
+ pinpoint_message( str );
+ }
+
+
+/* format_warn - write out formatted warning */
+
+void format_warn( msg, arg )
+char msg[], arg[];
+ {
+ char warn_msg[MAXLINE];
+
+ (void) sprintf( warn_msg, msg, arg );
+ warn( warn_msg );
+ }
+
+
+/* warn - report a warning, unless -w was given */
+
+void warn( str )
+char str[];
+ {
+ line_warning( str, linenum );
+ }
+
+/* format_pinpoint_message - write out a message formatted with one string,
+ * pinpointing its location
+ */
+
+void format_pinpoint_message( msg, arg )
+char msg[], arg[];
+ {
+ char errmsg[MAXLINE];
+
+ (void) sprintf( errmsg, msg, arg );
+ pinpoint_message( errmsg );
+ }
+
+
+/* pinpoint_message - write out a message, pinpointing its location */
+
+void pinpoint_message( str )
+char str[];
+ {
+ line_pinpoint( str, linenum );
+ }
+
+
+/* line_warning - report a warning at a given line, unless -w was given */
+
+void line_warning( str, line )
+char str[];
+int line;
+ {
+ char warning[MAXLINE];
+
+ if ( ! nowarn )
+ {
+ sprintf( warning, "warning, %s", str );
+ line_pinpoint( warning, line );
+ }
+ }
+
+
+/* line_pinpoint - write out a message, pinpointing it at the given line */
+
+void line_pinpoint( str, line )
+char str[];
+int line;
+ {
+ fprintf( stderr, "\"%s\", line %d: %s\n", infilename, line, str );
+ }
+
+
+/* yyerror - eat up an error message from the parser;
+ * currently, messages are ignore
+ */
+
+void yyerror( msg )
+char msg[];
+ {
+ }
diff --git a/Tools/android/flex-2.5.4a/scan.l b/Tools/android/flex-2.5.4a/scan.l
new file mode 100644
index 0000000..a02df8c
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/scan.l
@@ -0,0 +1,710 @@
+/* scan.l - scanner for flex input */
+
+%{
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/scan.l,v 2.56 95/04/24 12:17:19 vern Exp $ */
+
+#include "flexdef.h"
+#include "parse.h"
+
+#define ACTION_ECHO add_action( yytext )
+#define ACTION_IFDEF(def, should_define) \
+ { \
+ if ( should_define ) \
+ action_define( def, 1 ); \
+ }
+
+#define MARK_END_OF_PROLOG mark_prolog();
+
+#define YY_DECL \
+ int flexscan()
+
+#define RETURNCHAR \
+ yylval = (unsigned char) yytext[0]; \
+ return CHAR;
+
+#define RETURNNAME \
+ strcpy( nmstr, yytext ); \
+ return NAME;
+
+#define PUT_BACK_STRING(str, start) \
+ for ( i = strlen( str ) - 1; i >= start; --i ) \
+ unput((str)[i])
+
+#define CHECK_REJECT(str) \
+ if ( all_upper( str ) ) \
+ reject = true;
+
+#define CHECK_YYMORE(str) \
+ if ( all_lower( str ) ) \
+ yymore_used = true;
+%}
+
+%option caseless nodefault outfile="scan.c" stack noyy_top_state
+%option nostdinit
+
+%x SECT2 SECT2PROLOG SECT3 CODEBLOCK PICKUPDEF SC CARETISBOL NUM QUOTE
+%x FIRSTCCL CCL ACTION RECOVER COMMENT ACTION_STRING PERCENT_BRACE_ACTION
+%x OPTION LINEDIR
+
+WS [[:blank:]]+
+OPTWS [[:blank:]]*
+NOT_WS [^[:blank:]\n]
+
+NL \r?\n
+
+NAME ([[:alpha:]_][[:alnum:]_-]*)
+NOT_NAME [^[:alpha:]_*\n]+
+
+SCNAME {NAME}
+
+ESCSEQ (\\([^\n]|[0-7]{1,3}|x[[:xdigit:]]{1,2}))
+
+FIRST_CCL_CHAR ([^\\\n]|{ESCSEQ})
+CCL_CHAR ([^\\\n\]]|{ESCSEQ})
+CCL_EXPR ("[:"[[:alpha:]]+":]")
+
+LEXOPT [aceknopr]
+
+%%
+ static int bracelevel, didadef, indented_code;
+ static int doing_rule_action = false;
+ static int option_sense;
+
+ int doing_codeblock = false;
+ int i;
+ Char nmdef[MAXLINE], myesc();
+
+
+<INITIAL>{
+ ^{WS} indented_code = true; BEGIN(CODEBLOCK);
+ ^"/*" ACTION_ECHO; yy_push_state( COMMENT );
+ ^#{OPTWS}line{WS} yy_push_state( LINEDIR );
+ ^"%s"{NAME}? return SCDECL;
+ ^"%x"{NAME}? return XSCDECL;
+ ^"%{".*{NL} {
+ ++linenum;
+ line_directive_out( (FILE *) 0, 1 );
+ indented_code = false;
+ BEGIN(CODEBLOCK);
+ }
+
+ {WS} /* discard */
+
+ ^"%%".* {
+ sectnum = 2;
+ bracelevel = 0;
+ mark_defs1();
+ line_directive_out( (FILE *) 0, 1 );
+ BEGIN(SECT2PROLOG);
+ return SECTEND;
+ }
+
+ ^"%pointer".*{NL} yytext_is_array = false; ++linenum;
+ ^"%array".*{NL} yytext_is_array = true; ++linenum;
+
+ ^"%option" BEGIN(OPTION); return OPTION_OP;
+
+ ^"%"{LEXOPT}{OPTWS}[[:digit:]]*{OPTWS}{NL} ++linenum; /* ignore */
+ ^"%"{LEXOPT}{WS}.*{NL} ++linenum; /* ignore */
+
+ ^"%"[^sxaceknopr{}].* synerr( _( "unrecognized '%' directive" ) );
+
+ ^{NAME} {
+ strcpy( nmstr, yytext );
+ didadef = false;
+ BEGIN(PICKUPDEF);
+ }
+
+ {SCNAME} RETURNNAME;
+ ^{OPTWS}{NL} ++linenum; /* allows blank lines in section 1 */
+ {OPTWS}{NL} ACTION_ECHO; ++linenum; /* maybe end of comment line */
+}
+
+
+<COMMENT>{
+ "*/" ACTION_ECHO; yy_pop_state();
+ "*" ACTION_ECHO;
+ [^*\n]+ ACTION_ECHO;
+ [^*\n]*{NL} ++linenum; ACTION_ECHO;
+}
+
+<LINEDIR>{
+ \n yy_pop_state();
+ [[:digit:]]+ linenum = myctoi( yytext );
+
+ \"[^"\n]*\" {
+ flex_free( (void *) infilename );
+ infilename = copy_string( yytext + 1 );
+ infilename[strlen( infilename ) - 1] = '\0';
+ }
+ . /* ignore spurious characters */
+}
+
+<CODEBLOCK>{
+ ^"%}".*{NL} ++linenum; BEGIN(INITIAL);
+
+ {NAME}|{NOT_NAME}|. ACTION_ECHO;
+
+ {NL} {
+ ++linenum;
+ ACTION_ECHO;
+ if ( indented_code )
+ BEGIN(INITIAL);
+ }
+}
+
+
+<PICKUPDEF>{
+ {WS} /* separates name and definition */
+
+ {NOT_WS}.* {
+ strcpy( (char *) nmdef, yytext );
+
+ /* Skip trailing whitespace. */
+ for ( i = strlen( (char *) nmdef ) - 1;
+ i >= 0 && (nmdef[i] == ' ' || nmdef[i] == '\t');
+ --i )
+ ;
+
+ nmdef[i + 1] = '\0';
+
+ ndinstal( nmstr, nmdef );
+ didadef = true;
+ }
+
+ {NL} {
+ if ( ! didadef )
+ synerr( _( "incomplete name definition" ) );
+ BEGIN(INITIAL);
+ ++linenum;
+ }
+}
+
+
+<OPTION>{
+ {NL} ++linenum; BEGIN(INITIAL);
+ {WS} option_sense = true;
+
+ "=" return '=';
+
+ no option_sense = ! option_sense;
+
+ 7bit csize = option_sense ? 128 : 256;
+ 8bit csize = option_sense ? 256 : 128;
+
+ align long_align = option_sense;
+ always-interactive {
+ action_define( "YY_ALWAYS_INTERACTIVE", option_sense );
+ }
+ array yytext_is_array = option_sense;
+ backup backing_up_report = option_sense;
+ batch interactive = ! option_sense;
+ "c++" C_plus_plus = option_sense;
+ caseful|case-sensitive caseins = ! option_sense;
+ caseless|case-insensitive caseins = option_sense;
+ debug ddebug = option_sense;
+ default spprdflt = ! option_sense;
+ ecs useecs = option_sense;
+ fast {
+ useecs = usemecs = false;
+ use_read = fullspd = true;
+ }
+ full {
+ useecs = usemecs = false;
+ use_read = fulltbl = true;
+ }
+ input ACTION_IFDEF("YY_NO_INPUT", ! option_sense);
+ interactive interactive = option_sense;
+ lex-compat lex_compat = option_sense;
+ main {
+ action_define( "YY_MAIN", option_sense );
+ do_yywrap = ! option_sense;
+ }
+ meta-ecs usemecs = option_sense;
+ never-interactive {
+ action_define( "YY_NEVER_INTERACTIVE", option_sense );
+ }
+ perf-report performance_report += option_sense ? 1 : -1;
+ pointer yytext_is_array = ! option_sense;
+ read use_read = option_sense;
+ reject reject_really_used = option_sense;
+ stack action_define( "YY_STACK_USED", option_sense );
+ stdinit do_stdinit = option_sense;
+ stdout use_stdout = option_sense;
+ unput ACTION_IFDEF("YY_NO_UNPUT", ! option_sense);
+ verbose printstats = option_sense;
+ warn nowarn = ! option_sense;
+ yylineno do_yylineno = option_sense;
+ yymore yymore_really_used = option_sense;
+ yywrap do_yywrap = option_sense;
+
+ yy_push_state ACTION_IFDEF("YY_NO_PUSH_STATE", ! option_sense);
+ yy_pop_state ACTION_IFDEF("YY_NO_POP_STATE", ! option_sense);
+ yy_top_state ACTION_IFDEF("YY_NO_TOP_STATE", ! option_sense);
+
+ yy_scan_buffer ACTION_IFDEF("YY_NO_SCAN_BUFFER", ! option_sense);
+ yy_scan_bytes ACTION_IFDEF("YY_NO_SCAN_BYTES", ! option_sense);
+ yy_scan_string ACTION_IFDEF("YY_NO_SCAN_STRING", ! option_sense);
+
+ outfile return OPT_OUTFILE;
+ prefix return OPT_PREFIX;
+ yyclass return OPT_YYCLASS;
+
+ \"[^"\n]*\" {
+ strcpy( nmstr, yytext + 1 );
+ nmstr[strlen( nmstr ) - 1] = '\0';
+ return NAME;
+ }
+
+ (([a-mo-z]|n[a-np-z])[[:alpha:]\-+]*)|. {
+ format_synerr( _( "unrecognized %%option: %s" ),
+ yytext );
+ BEGIN(RECOVER);
+ }
+}
+
+<RECOVER>.*{NL} ++linenum; BEGIN(INITIAL);
+
+
+<SECT2PROLOG>{
+ ^"%{".* ++bracelevel; yyless( 2 ); /* eat only %{ */
+ ^"%}".* --bracelevel; yyless( 2 ); /* eat only %} */
+
+ ^{WS}.* ACTION_ECHO; /* indented code in prolog */
+
+ ^{NOT_WS}.* { /* non-indented code */
+ if ( bracelevel <= 0 )
+ { /* not in %{ ... %} */
+ yyless( 0 ); /* put it all back */
+ yy_set_bol( 1 );
+ mark_prolog();
+ BEGIN(SECT2);
+ }
+ else
+ ACTION_ECHO;
+ }
+
+ .* ACTION_ECHO;
+ {NL} ++linenum; ACTION_ECHO;
+
+ <<EOF>> {
+ mark_prolog();
+ sectnum = 0;
+ yyterminate(); /* to stop the parser */
+ }
+}
+
+<SECT2>{
+ ^{OPTWS}{NL} ++linenum; /* allow blank lines in section 2 */
+
+ ^{OPTWS}"%{" {
+ indented_code = false;
+ doing_codeblock = true;
+ bracelevel = 1;
+ BEGIN(PERCENT_BRACE_ACTION);
+ }
+
+ ^{OPTWS}"<" BEGIN(SC); return '<';
+ ^{OPTWS}"^" return '^';
+ \" BEGIN(QUOTE); return '"';
+ "{"/[[:digit:]] BEGIN(NUM); return '{';
+ "$"/([[:blank:]]|{NL}) return '$';
+
+ {WS}"%{" {
+ bracelevel = 1;
+ BEGIN(PERCENT_BRACE_ACTION);
+
+ if ( in_rule )
+ {
+ doing_rule_action = true;
+ in_rule = false;
+ return '\n';
+ }
+ }
+ {WS}"|".*{NL} continued_action = true; ++linenum; return '\n';
+
+ ^{WS}"/*" {
+ yyless( yyleng - 2 ); /* put back '/', '*' */
+ bracelevel = 0;
+ continued_action = false;
+ BEGIN(ACTION);
+ }
+
+ ^{WS} /* allow indented rules */
+
+ {WS} {
+ /* This rule is separate from the one below because
+ * otherwise we get variable trailing context, so
+ * we can't build the scanner using -{f,F}.
+ */
+ bracelevel = 0;
+ continued_action = false;
+ BEGIN(ACTION);
+
+ if ( in_rule )
+ {
+ doing_rule_action = true;
+ in_rule = false;
+ return '\n';
+ }
+ }
+
+ {OPTWS}{NL} {
+ bracelevel = 0;
+ continued_action = false;
+ BEGIN(ACTION);
+ unput( '\n' ); /* so <ACTION> sees it */
+
+ if ( in_rule )
+ {
+ doing_rule_action = true;
+ in_rule = false;
+ return '\n';
+ }
+ }
+
+ ^{OPTWS}"<<EOF>>" |
+ "<<EOF>>" return EOF_OP;
+
+ ^"%%".* {
+ sectnum = 3;
+ BEGIN(SECT3);
+ yyterminate(); /* to stop the parser */
+ }
+
+ "["({FIRST_CCL_CHAR}|{CCL_EXPR})({CCL_CHAR}|{CCL_EXPR})* {
+ int cclval;
+
+ strcpy( nmstr, yytext );
+
+ /* Check to see if we've already encountered this
+ * ccl.
+ */
+ if ( (cclval = ccllookup( (Char *) nmstr )) != 0 )
+ {
+ if ( input() != ']' )
+ synerr( _( "bad character class" ) );
+
+ yylval = cclval;
+ ++cclreuse;
+ return PREVCCL;
+ }
+ else
+ {
+ /* We fudge a bit. We know that this ccl will
+ * soon be numbered as lastccl + 1 by cclinit.
+ */
+ cclinstal( (Char *) nmstr, lastccl + 1 );
+
+ /* Push back everything but the leading bracket
+ * so the ccl can be rescanned.
+ */
+ yyless( 1 );
+
+ BEGIN(FIRSTCCL);
+ return '[';
+ }
+ }
+
+ "{"{NAME}"}" {
+ register Char *nmdefptr;
+ Char *ndlookup();
+
+ strcpy( nmstr, yytext + 1 );
+ nmstr[yyleng - 2] = '\0'; /* chop trailing brace */
+
+ if ( (nmdefptr = ndlookup( nmstr )) == 0 )
+ format_synerr(
+ _( "undefined definition {%s}" ),
+ nmstr );
+
+ else
+ { /* push back name surrounded by ()'s */
+ int len = strlen( (char *) nmdefptr );
+
+ if ( lex_compat || nmdefptr[0] == '^' ||
+ (len > 0 && nmdefptr[len - 1] == '$') )
+ { /* don't use ()'s after all */
+ PUT_BACK_STRING((char *) nmdefptr, 0);
+
+ if ( nmdefptr[0] == '^' )
+ BEGIN(CARETISBOL);
+ }
+
+ else
+ {
+ unput(')');
+ PUT_BACK_STRING((char *) nmdefptr, 0);
+ unput('(');
+ }
+ }
+ }
+
+ [/|*+?.(){}] return (unsigned char) yytext[0];
+ . RETURNCHAR;
+}
+
+
+<SC>{
+ [,*] return (unsigned char) yytext[0];
+ ">" BEGIN(SECT2); return '>';
+ ">"/^ BEGIN(CARETISBOL); return '>';
+ {SCNAME} RETURNNAME;
+ . {
+ format_synerr( _( "bad <start condition>: %s" ),
+ yytext );
+ }
+}
+
+<CARETISBOL>"^" BEGIN(SECT2); return '^';
+
+
+<QUOTE>{
+ [^"\n] RETURNCHAR;
+ \" BEGIN(SECT2); return '"';
+
+ {NL} {
+ synerr( _( "missing quote" ) );
+ BEGIN(SECT2);
+ ++linenum;
+ return '"';
+ }
+}
+
+
+<FIRSTCCL>{
+ "^"/[^-\]\n] BEGIN(CCL); return '^';
+ "^"/("-"|"]") return '^';
+ . BEGIN(CCL); RETURNCHAR;
+}
+
+<CCL>{
+ -/[^\]\n] return '-';
+ [^\]\n] RETURNCHAR;
+ "]" BEGIN(SECT2); return ']';
+ .|{NL} {
+ synerr( _( "bad character class" ) );
+ BEGIN(SECT2);
+ return ']';
+ }
+}
+
+<FIRSTCCL,CCL>{
+ "[:alnum:]" BEGIN(CCL); return CCE_ALNUM;
+ "[:alpha:]" BEGIN(CCL); return CCE_ALPHA;
+ "[:blank:]" BEGIN(CCL); return CCE_BLANK;
+ "[:cntrl:]" BEGIN(CCL); return CCE_CNTRL;
+ "[:digit:]" BEGIN(CCL); return CCE_DIGIT;
+ "[:graph:]" BEGIN(CCL); return CCE_GRAPH;
+ "[:lower:]" BEGIN(CCL); return CCE_LOWER;
+ "[:print:]" BEGIN(CCL); return CCE_PRINT;
+ "[:punct:]" BEGIN(CCL); return CCE_PUNCT;
+ "[:space:]" BEGIN(CCL); return CCE_SPACE;
+ "[:upper:]" BEGIN(CCL); return CCE_UPPER;
+ "[:xdigit:]" BEGIN(CCL); return CCE_XDIGIT;
+ {CCL_EXPR} {
+ format_synerr(
+ _( "bad character class expression: %s" ),
+ yytext );
+ BEGIN(CCL); return CCE_ALNUM;
+ }
+}
+
+<NUM>{
+ [[:digit:]]+ {
+ yylval = myctoi( yytext );
+ return NUMBER;
+ }
+
+ "," return ',';
+ "}" BEGIN(SECT2); return '}';
+
+ . {
+ synerr( _( "bad character inside {}'s" ) );
+ BEGIN(SECT2);
+ return '}';
+ }
+
+ {NL} {
+ synerr( _( "missing }" ) );
+ BEGIN(SECT2);
+ ++linenum;
+ return '}';
+ }
+}
+
+
+<PERCENT_BRACE_ACTION>{
+ {OPTWS}"%}".* bracelevel = 0;
+
+ <ACTION>"/*" ACTION_ECHO; yy_push_state( COMMENT );
+
+ <CODEBLOCK,ACTION>{
+ "reject" {
+ ACTION_ECHO;
+ CHECK_REJECT(yytext);
+ }
+ "yymore" {
+ ACTION_ECHO;
+ CHECK_YYMORE(yytext);
+ }
+ }
+
+ {NAME}|{NOT_NAME}|. ACTION_ECHO;
+ {NL} {
+ ++linenum;
+ ACTION_ECHO;
+ if ( bracelevel == 0 ||
+ (doing_codeblock && indented_code) )
+ {
+ if ( doing_rule_action )
+ add_action( "\tYY_BREAK\n" );
+
+ doing_rule_action = doing_codeblock = false;
+ BEGIN(SECT2);
+ }
+ }
+}
+
+
+ /* Reject and YYmore() are checked for above, in PERCENT_BRACE_ACTION */
+<ACTION>{
+ "{" ACTION_ECHO; ++bracelevel;
+ "}" ACTION_ECHO; --bracelevel;
+ [^[:alpha:]_{}"'/\n]+ ACTION_ECHO;
+ {NAME} ACTION_ECHO;
+ "'"([^'\\\n]|\\.)*"'" ACTION_ECHO; /* character constant */
+ \" ACTION_ECHO; BEGIN(ACTION_STRING);
+ {NL} {
+ ++linenum;
+ ACTION_ECHO;
+ if ( bracelevel == 0 )
+ {
+ if ( doing_rule_action )
+ add_action( "\tYY_BREAK\n" );
+
+ doing_rule_action = false;
+ BEGIN(SECT2);
+ }
+ }
+ . ACTION_ECHO;
+}
+
+<ACTION_STRING>{
+ [^"\\\n]+ ACTION_ECHO;
+ \\. ACTION_ECHO;
+ {NL} ++linenum; ACTION_ECHO;
+ \" ACTION_ECHO; BEGIN(ACTION);
+ . ACTION_ECHO;
+}
+
+<COMMENT,ACTION,ACTION_STRING><<EOF>> {
+ synerr( _( "EOF encountered inside an action" ) );
+ yyterminate();
+ }
+
+
+<SECT2,QUOTE,FIRSTCCL,CCL>{ESCSEQ} {
+ yylval = myesc( (Char *) yytext );
+
+ if ( YY_START == FIRSTCCL )
+ BEGIN(CCL);
+
+ return CHAR;
+ }
+
+
+<SECT3>{
+ .*(\n?) ECHO;
+ <<EOF>> sectnum = 0; yyterminate();
+}
+
+<*>.|\n format_synerr( _( "bad character: %s" ), yytext );
+
+%%
+
+
+int yywrap()
+ {
+ if ( --num_input_files > 0 )
+ {
+ set_input_file( *++input_files );
+ return 0;
+ }
+
+ else
+ return 1;
+ }
+
+
+/* set_input_file - open the given file (if NULL, stdin) for scanning */
+
+void set_input_file( file )
+char *file;
+ {
+ if ( file && strcmp( file, "-" ) )
+ {
+ infilename = copy_string( file );
+ yyin = fopen( infilename, "r" );
+
+ if ( yyin == NULL )
+ lerrsf( _( "can't open %s" ), file );
+ }
+
+ else
+ {
+ yyin = stdin;
+ infilename = copy_string( "<stdin>" );
+ }
+
+ linenum = 1;
+ }
+
+
+/* Wrapper routines for accessing the scanner's malloc routines. */
+
+void *flex_alloc( size )
+size_t size;
+ {
+ return (void *) malloc( size );
+ }
+
+void *flex_realloc( ptr, size )
+void *ptr;
+size_t size;
+ {
+ return (void *) realloc( ptr, size );
+ }
+
+void flex_free( ptr )
+void *ptr;
+ {
+ if ( ptr )
+ free( ptr );
+ }
diff --git a/Tools/android/flex-2.5.4a/skel.c b/Tools/android/flex-2.5.4a/skel.c
new file mode 100644
index 0000000..3354600
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/skel.c
@@ -0,0 +1,1548 @@
+/* File created from flex.skl via mkskel.sh */
+
+#include "flexdef.h"
+
+const char *skel[] = {
+ "/* A lexical scanner generated by flex */",
+ "",
+ "/* Scanner skeleton version:",
+ " * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $",
+ " */",
+ "",
+ "#define FLEX_SCANNER",
+ "#define YY_FLEX_MAJOR_VERSION 2",
+ "#define YY_FLEX_MINOR_VERSION 5",
+ "",
+ "%-",
+ "#include <stdio.h>",
+ "%*",
+ "",
+ "",
+ "/* cfront 1.2 defines \"c_plusplus\" instead of \"__cplusplus\" */",
+ "#ifdef c_plusplus",
+ "#ifndef __cplusplus",
+ "#define __cplusplus",
+ "#endif",
+ "#endif",
+ "",
+ "",
+ "#ifdef __cplusplus",
+ "",
+ "#include <stdlib.h>",
+ "%+",
+ "class istream;",
+ "%*",
+ "#include <unistd.h>",
+ "",
+ "/* Use prototypes in function declarations. */",
+ "#define YY_USE_PROTOS",
+ "",
+ "/* The \"const\" storage-class-modifier is valid. */",
+ "#define YY_USE_CONST",
+ "",
+ "#else /* ! __cplusplus */",
+ "",
+ "#if __STDC__",
+ "",
+ "#define YY_USE_PROTOS",
+ "#define YY_USE_CONST",
+ "",
+ "#endif /* __STDC__ */",
+ "#endif /* ! __cplusplus */",
+ "",
+ "#ifdef __TURBOC__",
+ " #pragma warn -rch",
+ " #pragma warn -use",
+ "#include <io.h>",
+ "#include <stdlib.h>",
+ "#define YY_USE_CONST",
+ "#define YY_USE_PROTOS",
+ "#endif",
+ "",
+ "#ifdef YY_USE_CONST",
+ "#define yyconst const",
+ "#else",
+ "#define yyconst",
+ "#endif",
+ "",
+ "",
+ "#ifdef YY_USE_PROTOS",
+ "#define YY_PROTO(proto) proto",
+ "#else",
+ "#define YY_PROTO(proto) ()",
+ "#endif",
+ "",
+ "/* Returned upon end-of-file. */",
+ "#define YY_NULL 0",
+ "",
+ "/* Promotes a possibly negative, possibly signed char to an unsigned",
+ " * integer for use as an array index. If the signed char is negative,",
+ " * we want to instead treat it as an 8-bit unsigned char, hence the",
+ " * double cast.",
+ " */",
+ "#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)",
+ "",
+ "/* Enter a start condition. This macro really ought to take a parameter,",
+ " * but we do it the disgusting crufty way forced on us by the ()-less",
+ " * definition of BEGIN.",
+ " */",
+ "#define BEGIN yy_start = 1 + 2 *",
+ "",
+ "/* Translate the current start state into a value that can be later handed",
+ " * to BEGIN to return to the state. The YYSTATE alias is for lex",
+ " * compatibility.",
+ " */",
+ "#define YY_START ((yy_start - 1) / 2)",
+ "#define YYSTATE YY_START",
+ "",
+ "/* Action number for EOF rule of a given start state. */",
+ "#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)",
+ "",
+ "/* Special action meaning \"start processing a new file\". */",
+ "#define YY_NEW_FILE yyrestart( yyin )",
+ "",
+ "#define YY_END_OF_BUFFER_CHAR 0",
+ "",
+ "/* Size of default input buffer. */",
+ "#define YY_BUF_SIZE 16384",
+ "",
+ "typedef struct yy_buffer_state *YY_BUFFER_STATE;",
+ "",
+ "extern int yyleng;",
+ "%-",
+ "extern FILE *yyin, *yyout;",
+ "%*",
+ "",
+ "#define EOB_ACT_CONTINUE_SCAN 0",
+ "#define EOB_ACT_END_OF_FILE 1",
+ "#define EOB_ACT_LAST_MATCH 2",
+ "",
+ "/* The funky do-while in the following #define is used to turn the definition",
+ " * int a single C statement (which needs a semi-colon terminator). This",
+ " * avoids problems with code like:",
+ " *",
+ " * if ( condition_holds )",
+ " * yyless( 5 );",
+ " * else",
+ " * do_something_else();",
+ " *",
+ " * Prior to using the do-while the compiler would get upset at the",
+ " * \"else\" because it interpreted the \"if\" statement as being all",
+ " * done when it reached the ';' after the yyless() call.",
+ " */",
+ "",
+ "/* Return all but the first 'n' matched characters back to the input stream. */",
+ "",
+ "#define yyless(n) \\",
+ " do \\",
+ " { \\",
+ " /* Undo effects of setting up yytext. */ \\",
+ " *yy_cp = yy_hold_char; \\",
+ " YY_RESTORE_YY_MORE_OFFSET \\",
+ " yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \\",
+ " YY_DO_BEFORE_ACTION; /* set up yytext again */ \\",
+ " } \\",
+ " while ( 0 )",
+ "",
+ "#define unput(c) yyunput( c, yytext_ptr )",
+ "",
+ "/* The following is because we cannot portably get our hands on size_t",
+ " * (without autoconf's help, which isn't available because we want",
+ " * flex-generated scanners to compile on their own).",
+ " */",
+ "typedef unsigned int yy_size_t;",
+ "",
+ "",
+ "struct yy_buffer_state",
+ " {",
+ "%-",
+ " FILE *yy_input_file;",
+ "%+",
+ " istream* yy_input_file;",
+ "%*",
+ "",
+ " char *yy_ch_buf; /* input buffer */",
+ " char *yy_buf_pos; /* current position in input buffer */",
+ "",
+ " /* Size of input buffer in bytes, not including room for EOB",
+ " * characters.",
+ " */",
+ " yy_size_t yy_buf_size;",
+ "",
+ " /* Number of characters read into yy_ch_buf, not including EOB",
+ " * characters.",
+ " */",
+ " int yy_n_chars;",
+ "",
+ " /* Whether we \"own\" the buffer - i.e., we know we created it,",
+ " * and can realloc() it to grow it, and should free() it to",
+ " * delete it.",
+ " */",
+ " int yy_is_our_buffer;",
+ "",
+ " /* Whether this is an \"interactive\" input source; if so, and",
+ " * if we're using stdio for input, then we want to use getc()",
+ " * instead of fread(), to make sure we stop fetching input after",
+ " * each newline.",
+ " */",
+ " int yy_is_interactive;",
+ "",
+ " /* Whether we're considered to be at the beginning of a line.",
+ " * If so, '^' rules will be active on the next match, otherwise",
+ " * not.",
+ " */",
+ " int yy_at_bol;",
+ "",
+ " /* Whether to try to fill the input buffer when we reach the",
+ " * end of it.",
+ " */",
+ " int yy_fill_buffer;",
+ "",
+ " int yy_buffer_status;",
+ "#define YY_BUFFER_NEW 0",
+ "#define YY_BUFFER_NORMAL 1",
+ " /* When an EOF's been seen but there's still some text to process",
+ " * then we mark the buffer as YY_EOF_PENDING, to indicate that we",
+ " * shouldn't try reading from the input source any more. We might",
+ " * still have a bunch of tokens to match, though, because of",
+ " * possible backing-up.",
+ " *",
+ " * When we actually see the EOF, we change the status to \"new\"",
+ " * (via yyrestart()), so that the user can continue scanning by",
+ " * just pointing yyin at a new input file.",
+ " */",
+ "#define YY_BUFFER_EOF_PENDING 2",
+ " };",
+ "",
+ "%- Standard (non-C++) definition",
+ "static YY_BUFFER_STATE yy_current_buffer = 0;",
+ "%*",
+ "",
+ "/* We provide macros for accessing buffer states in case in the",
+ " * future we want to put the buffer states in a more general",
+ " * \"scanner state\".",
+ " */",
+ "#define YY_CURRENT_BUFFER yy_current_buffer",
+ "",
+ "",
+ "%- Standard (non-C++) definition",
+ "/* yy_hold_char holds the character lost when yytext is formed. */",
+ "static char yy_hold_char;",
+ "",
+ "static int yy_n_chars; /* number of characters read into yy_ch_buf */",
+ "",
+ "",
+ "int yyleng;",
+ "",
+ "/* Points to current character in buffer. */",
+ "static char *yy_c_buf_p = (char *) 0;",
+ "static int yy_init = 1; /* whether we need to initialize */",
+ "static int yy_start = 0; /* start state number */",
+ "",
+ "/* Flag which is used to allow yywrap()'s to do buffer switches",
+ " * instead of setting up a fresh yyin. A bit of a hack ...",
+ " */",
+ "static int yy_did_buffer_switch_on_eof;",
+ "",
+ "void yyrestart YY_PROTO(( FILE *input_file ));",
+ "",
+ "void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));",
+ "void yy_load_buffer_state YY_PROTO(( void ));",
+ "YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));",
+ "void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));",
+ "void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));",
+ "void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));",
+ "#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )",
+ "",
+ "YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));",
+ "YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));",
+ "YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));",
+ "%*",
+ "",
+ "static void *yy_flex_alloc YY_PROTO(( yy_size_t ));",
+ "static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));",
+ "static void yy_flex_free YY_PROTO(( void * ));",
+ "",
+ "#define yy_new_buffer yy_create_buffer",
+ "",
+ "#define yy_set_interactive(is_interactive) \\",
+ " { \\",
+ " if ( ! yy_current_buffer ) \\",
+ " yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \\",
+ " yy_current_buffer->yy_is_interactive = is_interactive; \\",
+ " }",
+ "",
+ "#define yy_set_bol(at_bol) \\",
+ " { \\",
+ " if ( ! yy_current_buffer ) \\",
+ " yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \\",
+ " yy_current_buffer->yy_at_bol = at_bol; \\",
+ " }",
+ "",
+ "#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)",
+ "",
+ "%% yytext/yyin/yyout/yy_state_type/yylineno etc. def's & init go here",
+ "",
+ "%- Standard (non-C++) definition",
+ "static yy_state_type yy_get_previous_state YY_PROTO(( void ));",
+ "static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));",
+ "static int yy_get_next_buffer YY_PROTO(( void ));",
+ "static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));",
+ "%*",
+ "",
+ "/* Done after the current pattern has been matched and before the",
+ " * corresponding action - sets up yytext.",
+ " */",
+ "#define YY_DO_BEFORE_ACTION \\",
+ " yytext_ptr = yy_bp; \\",
+ "%% code to fiddle yytext and yyleng for yymore() goes here",
+ " yy_hold_char = *yy_cp; \\",
+ " *yy_cp = '\\0'; \\",
+ "%% code to copy yytext_ptr to yytext[] goes here, if %array",
+ " yy_c_buf_p = yy_cp;",
+ "",
+ "%% data tables for the DFA and the user's section 1 definitions go here",
+ "",
+ "/* Macros after this point can all be overridden by user definitions in",
+ " * section 1.",
+ " */",
+ "",
+ "#ifndef YY_SKIP_YYWRAP",
+ "#ifdef __cplusplus",
+ "extern \"C\" int yywrap YY_PROTO(( void ));",
+ "#else",
+ "extern int yywrap YY_PROTO(( void ));",
+ "#endif",
+ "#endif",
+ "",
+ "%-",
+ "#ifndef YY_NO_UNPUT",
+ "static void yyunput YY_PROTO(( int c, char *buf_ptr ));",
+ "#endif",
+ "%*",
+ "",
+ "#ifndef yytext_ptr",
+ "static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));",
+ "#endif",
+ "",
+ "#ifdef YY_NEED_STRLEN",
+ "static int yy_flex_strlen YY_PROTO(( yyconst char * ));",
+ "#endif",
+ "",
+ "#ifndef YY_NO_INPUT",
+ "%- Standard (non-C++) definition",
+ "#ifdef __cplusplus",
+ "static int yyinput YY_PROTO(( void ));",
+ "#else",
+ "static int input YY_PROTO(( void ));",
+ "#endif",
+ "%*",
+ "#endif",
+ "",
+ "#if YY_STACK_USED",
+ "static int yy_start_stack_ptr = 0;",
+ "static int yy_start_stack_depth = 0;",
+ "static int *yy_start_stack = 0;",
+ "#ifndef YY_NO_PUSH_STATE",
+ "static void yy_push_state YY_PROTO(( int new_state ));",
+ "#endif",
+ "#ifndef YY_NO_POP_STATE",
+ "static void yy_pop_state YY_PROTO(( void ));",
+ "#endif",
+ "#ifndef YY_NO_TOP_STATE",
+ "static int yy_top_state YY_PROTO(( void ));",
+ "#endif",
+ "",
+ "#else",
+ "#define YY_NO_PUSH_STATE 1",
+ "#define YY_NO_POP_STATE 1",
+ "#define YY_NO_TOP_STATE 1",
+ "#endif",
+ "",
+ "#ifdef YY_MALLOC_DECL",
+ "YY_MALLOC_DECL",
+ "#else",
+ "#if __STDC__",
+ "#ifndef __cplusplus",
+ "#include <stdlib.h>",
+ "#endif",
+ "#else",
+ "/* Just try to get by without declaring the routines. This will fail",
+ " * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)",
+ " * or sizeof(void*) != sizeof(int).",
+ " */",
+ "#endif",
+ "#endif",
+ "",
+ "/* Amount of stuff to slurp up with each read. */",
+ "#ifndef YY_READ_BUF_SIZE",
+ "#define YY_READ_BUF_SIZE 8192",
+ "#endif",
+ "",
+ "/* Copy whatever the last rule matched to the standard output. */",
+ "",
+ "#ifndef ECHO",
+ "%- Standard (non-C++) definition",
+ "/* This used to be an fputs(), but since the string might contain NUL's,",
+ " * we now use fwrite().",
+ " */",
+ "#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )",
+ "%+ C++ definition",
+ "#define ECHO LexerOutput( yytext, yyleng )",
+ "%*",
+ "#endif",
+ "",
+ "/* Gets input and stuffs it into \"buf\". number of characters read, or YY_NULL,",
+ " * is returned in \"result\".",
+ " */",
+ "#ifndef YY_INPUT",
+ "#define YY_INPUT(buf,result,max_size) \\",
+ "%% fread()/read() definition of YY_INPUT goes here unless we're doing C++",
+ "%+ C++ definition",
+ " if ( (result = LexerInput( (char *) buf, max_size )) < 0 ) \\",
+ " YY_FATAL_ERROR( \"input in flex scanner failed\" );",
+ "%*",
+ "#endif",
+ "",
+ "/* No semi-colon after return; correct usage is to write \"yyterminate();\" -",
+ " * we don't want an extra ';' after the \"return\" because that will cause",
+ " * some compilers to complain about unreachable statements.",
+ " */",
+ "#ifndef yyterminate",
+ "#define yyterminate() return YY_NULL",
+ "#endif",
+ "",
+ "/* Number of entries by which start-condition stack grows. */",
+ "#ifndef YY_START_STACK_INCR",
+ "#define YY_START_STACK_INCR 25",
+ "#endif",
+ "",
+ "/* Report a fatal error. */",
+ "#ifndef YY_FATAL_ERROR",
+ "%-",
+ "#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )",
+ "%+",
+ "#define YY_FATAL_ERROR(msg) LexerError( msg )",
+ "%*",
+ "#endif",
+ "",
+ "/* Default declaration of generated scanner - a define so the user can",
+ " * easily add parameters.",
+ " */",
+ "#ifndef YY_DECL",
+ "%- Standard (non-C++) definition",
+ "#define YY_DECL int yylex YY_PROTO(( void ))",
+ "%+ C++ definition",
+ "#define YY_DECL int yyFlexLexer::yylex()",
+ "%*",
+ "#endif",
+ "",
+ "/* Code executed at the beginning of each rule, after yytext and yyleng",
+ " * have been set up.",
+ " */",
+ "#ifndef YY_USER_ACTION",
+ "#define YY_USER_ACTION",
+ "#endif",
+ "",
+ "/* Code executed at the end of each rule. */",
+ "#ifndef YY_BREAK",
+ "#define YY_BREAK break;",
+ "#endif",
+ "",
+ "%% YY_RULE_SETUP definition goes here",
+ "",
+ "YY_DECL",
+ " {",
+ " register yy_state_type yy_current_state;",
+ " register char *yy_cp, *yy_bp;",
+ " register int yy_act;",
+ "",
+ "%% user's declarations go here",
+ "",
+ " if ( yy_init )",
+ " {",
+ " yy_init = 0;",
+ "",
+ "#ifdef YY_USER_INIT",
+ " YY_USER_INIT;",
+ "#endif",
+ "",
+ " if ( ! yy_start )",
+ " yy_start = 1; /* first start state */",
+ "",
+ " if ( ! yyin )",
+ "%-",
+ " yyin = stdin;",
+ "%+",
+ " yyin = &cin;",
+ "%*",
+ "",
+ " if ( ! yyout )",
+ "%-",
+ " yyout = stdout;",
+ "%+",
+ " yyout = &cout;",
+ "%*",
+ "",
+ " if ( ! yy_current_buffer )",
+ " yy_current_buffer =",
+ " yy_create_buffer( yyin, YY_BUF_SIZE );",
+ "",
+ " yy_load_buffer_state();",
+ " }",
+ "",
+ " while ( 1 ) /* loops until end-of-file is reached */",
+ " {",
+ "%% yymore()-related code goes here",
+ " yy_cp = yy_c_buf_p;",
+ "",
+ " /* Support of yytext. */",
+ " *yy_cp = yy_hold_char;",
+ "",
+ " /* yy_bp points to the position in yy_ch_buf of the start of",
+ " * the current run.",
+ " */",
+ " yy_bp = yy_cp;",
+ "",
+ "%% code to set up and find next match goes here",
+ "",
+ "yy_find_action:",
+ "%% code to find the action number goes here",
+ "",
+ " YY_DO_BEFORE_ACTION;",
+ "",
+ "%% code for yylineno update goes here",
+ "",
+ "do_action: /* This label is used only to access EOF actions. */",
+ "",
+ "%% debug code goes here",
+ "",
+ " switch ( yy_act )",
+ " { /* beginning of action switch */",
+ "%% actions go here",
+ "",
+ " case YY_END_OF_BUFFER:",
+ " {",
+ " /* Amount of text matched not including the EOB char. */",
+ " int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;",
+ "",
+ " /* Undo the effects of YY_DO_BEFORE_ACTION. */",
+ " *yy_cp = yy_hold_char;",
+ " YY_RESTORE_YY_MORE_OFFSET",
+ "",
+ " if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )",
+ " {",
+ " /* We're scanning a new file or input source. It's",
+ " * possible that this happened because the user",
+ " * just pointed yyin at a new source and called",
+ " * yylex(). If so, then we have to assure",
+ " * consistency between yy_current_buffer and our",
+ " * globals. Here is the right place to do so, because",
+ " * this is the first action (other than possibly a",
+ " * back-up) that will match for the new input source.",
+ " */",
+ " yy_n_chars = yy_current_buffer->yy_n_chars;",
+ " yy_current_buffer->yy_input_file = yyin;",
+ " yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;",
+ " }",
+ "",
+ " /* Note that here we test for yy_c_buf_p \"<=\" to the position",
+ " * of the first EOB in the buffer, since yy_c_buf_p will",
+ " * already have been incremented past the NUL character",
+ " * (since all states make transitions on EOB to the",
+ " * end-of-buffer state). Contrast this with the test",
+ " * in input().",
+ " */",
+ " if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )",
+ " { /* This was really a NUL. */",
+ " yy_state_type yy_next_state;",
+ "",
+ " yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;",
+ "",
+ " yy_current_state = yy_get_previous_state();",
+ "",
+ " /* Okay, we're now positioned to make the NUL",
+ " * transition. We couldn't have",
+ " * yy_get_previous_state() go ahead and do it",
+ " * for us because it doesn't know how to deal",
+ " * with the possibility of jamming (and we don't",
+ " * want to build jamming into it because then it",
+ " * will run more slowly).",
+ " */",
+ "",
+ " yy_next_state = yy_try_NUL_trans( yy_current_state );",
+ "",
+ " yy_bp = yytext_ptr + YY_MORE_ADJ;",
+ "",
+ " if ( yy_next_state )",
+ " {",
+ " /* Consume the NUL. */",
+ " yy_cp = ++yy_c_buf_p;",
+ " yy_current_state = yy_next_state;",
+ " goto yy_match;",
+ " }",
+ "",
+ " else",
+ " {",
+ "%% code to do back-up for compressed tables and set up yy_cp goes here",
+ " goto yy_find_action;",
+ " }",
+ " }",
+ "",
+ " else switch ( yy_get_next_buffer() )",
+ " {",
+ " case EOB_ACT_END_OF_FILE:",
+ " {",
+ " yy_did_buffer_switch_on_eof = 0;",
+ "",
+ " if ( yywrap() )",
+ " {",
+ " /* Note: because we've taken care in",
+ " * yy_get_next_buffer() to have set up",
+ " * yytext, we can now set up",
+ " * yy_c_buf_p so that if some total",
+ " * hoser (like flex itself) wants to",
+ " * call the scanner after we return the",
+ " * YY_NULL, it'll still work - another",
+ " * YY_NULL will get returned.",
+ " */",
+ " yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;",
+ "",
+ " yy_act = YY_STATE_EOF(YY_START);",
+ " goto do_action;",
+ " }",
+ "",
+ " else",
+ " {",
+ " if ( ! yy_did_buffer_switch_on_eof )",
+ " YY_NEW_FILE;",
+ " }",
+ " break;",
+ " }",
+ "",
+ " case EOB_ACT_CONTINUE_SCAN:",
+ " yy_c_buf_p =",
+ " yytext_ptr + yy_amount_of_matched_text;",
+ "",
+ " yy_current_state = yy_get_previous_state();",
+ "",
+ " yy_cp = yy_c_buf_p;",
+ " yy_bp = yytext_ptr + YY_MORE_ADJ;",
+ " goto yy_match;",
+ "",
+ " case EOB_ACT_LAST_MATCH:",
+ " yy_c_buf_p =",
+ " &yy_current_buffer->yy_ch_buf[yy_n_chars];",
+ "",
+ " yy_current_state = yy_get_previous_state();",
+ "",
+ " yy_cp = yy_c_buf_p;",
+ " yy_bp = yytext_ptr + YY_MORE_ADJ;",
+ " goto yy_find_action;",
+ " }",
+ " break;",
+ " }",
+ "",
+ " default:",
+ " YY_FATAL_ERROR(",
+ " \"fatal flex scanner internal error--no action found\" );",
+ " } /* end of action switch */",
+ " } /* end of scanning one token */",
+ " } /* end of yylex */",
+ "",
+ "%+",
+ "yyFlexLexer::yyFlexLexer( istream* arg_yyin, ostream* arg_yyout )",
+ " {",
+ " yyin = arg_yyin;",
+ " yyout = arg_yyout;",
+ " yy_c_buf_p = 0;",
+ " yy_init = 1;",
+ " yy_start = 0;",
+ " yy_flex_debug = 0;",
+ " yylineno = 1; // this will only get updated if %option yylineno",
+ "",
+ " yy_did_buffer_switch_on_eof = 0;",
+ "",
+ " yy_looking_for_trail_begin = 0;",
+ " yy_more_flag = 0;",
+ " yy_more_len = 0;",
+ " yy_more_offset = yy_prev_more_offset = 0;",
+ "",
+ " yy_start_stack_ptr = yy_start_stack_depth = 0;",
+ " yy_start_stack = 0;",
+ "",
+ " yy_current_buffer = 0;",
+ "",
+ "#ifdef YY_USES_REJECT",
+ " yy_state_buf = new yy_state_type[YY_BUF_SIZE + 2];",
+ "#else",
+ " yy_state_buf = 0;",
+ "#endif",
+ " }",
+ "",
+ "yyFlexLexer::~yyFlexLexer()",
+ " {",
+ " delete yy_state_buf;",
+ " yy_delete_buffer( yy_current_buffer );",
+ " }",
+ "",
+ "void yyFlexLexer::switch_streams( istream* new_in, ostream* new_out )",
+ " {",
+ " if ( new_in )",
+ " {",
+ " yy_delete_buffer( yy_current_buffer );",
+ " yy_switch_to_buffer( yy_create_buffer( new_in, YY_BUF_SIZE ) );",
+ " }",
+ "",
+ " if ( new_out )",
+ " yyout = new_out;",
+ " }",
+ "",
+ "#ifdef YY_INTERACTIVE",
+ "int yyFlexLexer::LexerInput( char* buf, int /* max_size */ )",
+ "#else",
+ "int yyFlexLexer::LexerInput( char* buf, int max_size )",
+ "#endif",
+ " {",
+ " if ( yyin->eof() || yyin->fail() )",
+ " return 0;",
+ "",
+ "#ifdef YY_INTERACTIVE",
+ " yyin->get( buf[0] );",
+ "",
+ " if ( yyin->eof() )",
+ " return 0;",
+ "",
+ " if ( yyin->bad() )",
+ " return -1;",
+ "",
+ " return 1;",
+ "",
+ "#else",
+ " (void) yyin->read( buf, max_size );",
+ "",
+ " if ( yyin->bad() )",
+ " return -1;",
+ " else",
+ " return yyin->gcount();",
+ "#endif",
+ " }",
+ "",
+ "void yyFlexLexer::LexerOutput( const char* buf, int size )",
+ " {",
+ " (void) yyout->write( buf, size );",
+ " }",
+ "%*",
+ "",
+ "/* yy_get_next_buffer - try to read in a new buffer",
+ " *",
+ " * Returns a code representing an action:",
+ " * EOB_ACT_LAST_MATCH -",
+ " * EOB_ACT_CONTINUE_SCAN - continue scanning from current position",
+ " * EOB_ACT_END_OF_FILE - end of file",
+ " */",
+ "",
+ "%-",
+ "static int yy_get_next_buffer()",
+ "%+",
+ "int yyFlexLexer::yy_get_next_buffer()",
+ "%*",
+ " {",
+ " register char *dest = yy_current_buffer->yy_ch_buf;",
+ " register char *source = yytext_ptr;",
+ " register int number_to_move, i;",
+ " int ret_val;",
+ "",
+ " if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )",
+ " YY_FATAL_ERROR(",
+ " \"fatal flex scanner internal error--end of buffer missed\" );",
+ "",
+ " if ( yy_current_buffer->yy_fill_buffer == 0 )",
+ " { /* Don't try to fill the buffer, so this is an EOF. */",
+ " if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )",
+ " {",
+ " /* We matched a single character, the EOB, so",
+ " * treat this as a final EOF.",
+ " */",
+ " return EOB_ACT_END_OF_FILE;",
+ " }",
+ "",
+ " else",
+ " {",
+ " /* We matched some text prior to the EOB, first",
+ " * process it.",
+ " */",
+ " return EOB_ACT_LAST_MATCH;",
+ " }",
+ " }",
+ "",
+ " /* Try to read more data. */",
+ "",
+ " /* First move last chars to start of buffer. */",
+ " number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;",
+ "",
+ " for ( i = 0; i < number_to_move; ++i )",
+ " *(dest++) = *(source++);",
+ "",
+ " if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )",
+ " /* don't do the read, it's not guaranteed to return an EOF,",
+ " * just force an EOF",
+ " */",
+ " yy_current_buffer->yy_n_chars = yy_n_chars = 0;",
+ "",
+ " else",
+ " {",
+ " int num_to_read =",
+ " yy_current_buffer->yy_buf_size - number_to_move - 1;",
+ "",
+ " while ( num_to_read <= 0 )",
+ " { /* Not enough room in the buffer - grow it. */",
+ "#ifdef YY_USES_REJECT",
+ " YY_FATAL_ERROR(",
+ "\"input buffer overflow, can't enlarge buffer because scanner uses REJECT\" );",
+ "#else",
+ "",
+ " /* just a shorter name for the current buffer */",
+ " YY_BUFFER_STATE b = yy_current_buffer;",
+ "",
+ " int yy_c_buf_p_offset =",
+ " (int) (yy_c_buf_p - b->yy_ch_buf);",
+ "",
+ " if ( b->yy_is_our_buffer )",
+ " {",
+ " int new_size = b->yy_buf_size * 2;",
+ "",
+ " if ( new_size <= 0 )",
+ " b->yy_buf_size += b->yy_buf_size / 8;",
+ " else",
+ " b->yy_buf_size *= 2;",
+ "",
+ " b->yy_ch_buf = (char *)",
+ " /* Include room in for 2 EOB chars. */",
+ " yy_flex_realloc( (void *) b->yy_ch_buf,",
+ " b->yy_buf_size + 2 );",
+ " }",
+ " else",
+ " /* Can't grow it, we don't own it. */",
+ " b->yy_ch_buf = 0;",
+ "",
+ " if ( ! b->yy_ch_buf )",
+ " YY_FATAL_ERROR(",
+ " \"fatal error - scanner input buffer overflow\" );",
+ "",
+ " yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];",
+ "",
+ " num_to_read = yy_current_buffer->yy_buf_size -",
+ " number_to_move - 1;",
+ "#endif",
+ " }",
+ "",
+ " if ( num_to_read > YY_READ_BUF_SIZE )",
+ " num_to_read = YY_READ_BUF_SIZE;",
+ "",
+ " /* Read in more data. */",
+ " YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),",
+ " yy_n_chars, num_to_read );",
+ "",
+ " yy_current_buffer->yy_n_chars = yy_n_chars;",
+ " }",
+ "",
+ " if ( yy_n_chars == 0 )",
+ " {",
+ " if ( number_to_move == YY_MORE_ADJ )",
+ " {",
+ " ret_val = EOB_ACT_END_OF_FILE;",
+ " yyrestart( yyin );",
+ " }",
+ "",
+ " else",
+ " {",
+ " ret_val = EOB_ACT_LAST_MATCH;",
+ " yy_current_buffer->yy_buffer_status =",
+ " YY_BUFFER_EOF_PENDING;",
+ " }",
+ " }",
+ "",
+ " else",
+ " ret_val = EOB_ACT_CONTINUE_SCAN;",
+ "",
+ " yy_n_chars += number_to_move;",
+ " yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;",
+ " yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;",
+ "",
+ " yytext_ptr = &yy_current_buffer->yy_ch_buf[0];",
+ "",
+ " return ret_val;",
+ " }",
+ "",
+ "",
+ "/* yy_get_previous_state - get the state just before the EOB char was reached */",
+ "",
+ "%-",
+ "static yy_state_type yy_get_previous_state()",
+ "%+",
+ "yy_state_type yyFlexLexer::yy_get_previous_state()",
+ "%*",
+ " {",
+ " register yy_state_type yy_current_state;",
+ " register char *yy_cp;",
+ "",
+ "%% code to get the start state into yy_current_state goes here",
+ "",
+ " for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )",
+ " {",
+ "%% code to find the next state goes here",
+ " }",
+ "",
+ " return yy_current_state;",
+ " }",
+ "",
+ "",
+ "/* yy_try_NUL_trans - try to make a transition on the NUL character",
+ " *",
+ " * synopsis",
+ " * next_state = yy_try_NUL_trans( current_state );",
+ " */",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )",
+ "#else",
+ "static yy_state_type yy_try_NUL_trans( yy_current_state )",
+ "yy_state_type yy_current_state;",
+ "#endif",
+ "%+",
+ "yy_state_type yyFlexLexer::yy_try_NUL_trans( yy_state_type yy_current_state )",
+ "%*",
+ " {",
+ " register int yy_is_jam;",
+ "%% code to find the next state, and perhaps do backing up, goes here",
+ "",
+ " return yy_is_jam ? 0 : yy_current_state;",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifndef YY_NO_UNPUT",
+ "#ifdef YY_USE_PROTOS",
+ "static void yyunput( int c, register char *yy_bp )",
+ "#else",
+ "static void yyunput( c, yy_bp )",
+ "int c;",
+ "register char *yy_bp;",
+ "#endif",
+ "%+",
+ "void yyFlexLexer::yyunput( int c, register char* yy_bp )",
+ "%*",
+ " {",
+ " register char *yy_cp = yy_c_buf_p;",
+ "",
+ " /* undo effects of setting up yytext */",
+ " *yy_cp = yy_hold_char;",
+ "",
+ " if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )",
+ " { /* need to shift things up to make room */",
+ " /* +2 for EOB chars. */",
+ " register int number_to_move = yy_n_chars + 2;",
+ " register char *dest = &yy_current_buffer->yy_ch_buf[",
+ " yy_current_buffer->yy_buf_size + 2];",
+ " register char *source =",
+ " &yy_current_buffer->yy_ch_buf[number_to_move];",
+ "",
+ " while ( source > yy_current_buffer->yy_ch_buf )",
+ " *--dest = *--source;",
+ "",
+ " yy_cp += (int) (dest - source);",
+ " yy_bp += (int) (dest - source);",
+ " yy_current_buffer->yy_n_chars =",
+ " yy_n_chars = yy_current_buffer->yy_buf_size;",
+ "",
+ " if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )",
+ " YY_FATAL_ERROR( \"flex scanner push-back overflow\" );",
+ " }",
+ "",
+ " *--yy_cp = (char) c;",
+ "",
+ "%% update yylineno here",
+ "",
+ " yytext_ptr = yy_bp;",
+ " yy_hold_char = *yy_cp;",
+ " yy_c_buf_p = yy_cp;",
+ " }",
+ "%-",
+ "#endif /* ifndef YY_NO_UNPUT */",
+ "%*",
+ "",
+ "",
+ "%-",
+ "#ifdef __cplusplus",
+ "static int yyinput()",
+ "#else",
+ "static int input()",
+ "#endif",
+ "%+",
+ "int yyFlexLexer::yyinput()",
+ "%*",
+ " {",
+ " int c;",
+ "",
+ " *yy_c_buf_p = yy_hold_char;",
+ "",
+ " if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )",
+ " {",
+ " /* yy_c_buf_p now points to the character we want to return.",
+ " * If this occurs *before* the EOB characters, then it's a",
+ " * valid NUL; if not, then we've hit the end of the buffer.",
+ " */",
+ " if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )",
+ " /* This was really a NUL. */",
+ " *yy_c_buf_p = '\\0';",
+ "",
+ " else",
+ " { /* need more input */",
+ " int offset = yy_c_buf_p - yytext_ptr;",
+ " ++yy_c_buf_p;",
+ "",
+ " switch ( yy_get_next_buffer() )",
+ " {",
+ " case EOB_ACT_LAST_MATCH:",
+ " /* This happens because yy_g_n_b()",
+ " * sees that we've accumulated a",
+ " * token and flags that we need to",
+ " * try matching the token before",
+ " * proceeding. But for input(),",
+ " * there's no matching to consider.",
+ " * So convert the EOB_ACT_LAST_MATCH",
+ " * to EOB_ACT_END_OF_FILE.",
+ " */",
+ "",
+ " /* Reset buffer status. */",
+ " yyrestart( yyin );",
+ "",
+ " /* fall through */",
+ "",
+ " case EOB_ACT_END_OF_FILE:",
+ " {",
+ " if ( yywrap() )",
+ " return EOF;",
+ "",
+ " if ( ! yy_did_buffer_switch_on_eof )",
+ " YY_NEW_FILE;",
+ "#ifdef __cplusplus",
+ " return yyinput();",
+ "#else",
+ " return input();",
+ "#endif",
+ " }",
+ "",
+ " case EOB_ACT_CONTINUE_SCAN:",
+ " yy_c_buf_p = yytext_ptr + offset;",
+ " break;",
+ " }",
+ " }",
+ " }",
+ "",
+ " c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */",
+ " *yy_c_buf_p = '\\0'; /* preserve yytext */",
+ " yy_hold_char = *++yy_c_buf_p;",
+ "",
+ "%% update BOL and yylineno",
+ "",
+ " return c;",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "void yyrestart( FILE *input_file )",
+ "#else",
+ "void yyrestart( input_file )",
+ "FILE *input_file;",
+ "#endif",
+ "%+",
+ "void yyFlexLexer::yyrestart( istream* input_file )",
+ "%*",
+ " {",
+ " if ( ! yy_current_buffer )",
+ " yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );",
+ "",
+ " yy_init_buffer( yy_current_buffer, input_file );",
+ " yy_load_buffer_state();",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )",
+ "#else",
+ "void yy_switch_to_buffer( new_buffer )",
+ "YY_BUFFER_STATE new_buffer;",
+ "#endif",
+ "%+",
+ "void yyFlexLexer::yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )",
+ "%*",
+ " {",
+ " if ( yy_current_buffer == new_buffer )",
+ " return;",
+ "",
+ " if ( yy_current_buffer )",
+ " {",
+ " /* Flush out information for old buffer. */",
+ " *yy_c_buf_p = yy_hold_char;",
+ " yy_current_buffer->yy_buf_pos = yy_c_buf_p;",
+ " yy_current_buffer->yy_n_chars = yy_n_chars;",
+ " }",
+ "",
+ " yy_current_buffer = new_buffer;",
+ " yy_load_buffer_state();",
+ "",
+ " /* We don't actually know whether we did this switch during",
+ " * EOF (yywrap()) processing, but the only time this flag",
+ " * is looked at is after yywrap() is called, so it's safe",
+ " * to go ahead and always set it.",
+ " */",
+ " yy_did_buffer_switch_on_eof = 1;",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "void yy_load_buffer_state( void )",
+ "#else",
+ "void yy_load_buffer_state()",
+ "#endif",
+ "%+",
+ "void yyFlexLexer::yy_load_buffer_state()",
+ "%*",
+ " {",
+ " yy_n_chars = yy_current_buffer->yy_n_chars;",
+ " yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;",
+ " yyin = yy_current_buffer->yy_input_file;",
+ " yy_hold_char = *yy_c_buf_p;",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )",
+ "#else",
+ "YY_BUFFER_STATE yy_create_buffer( file, size )",
+ "FILE *file;",
+ "int size;",
+ "#endif",
+ "%+",
+ "YY_BUFFER_STATE yyFlexLexer::yy_create_buffer( istream* file, int size )",
+ "%*",
+ " {",
+ " YY_BUFFER_STATE b;",
+ "",
+ " b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );",
+ " if ( ! b )",
+ " YY_FATAL_ERROR( \"out of dynamic memory in yy_create_buffer()\" );",
+ "",
+ " b->yy_buf_size = size;",
+ "",
+ " /* yy_ch_buf has to be 2 characters longer than the size given because",
+ " * we need to put in 2 end-of-buffer characters.",
+ " */",
+ " b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );",
+ " if ( ! b->yy_ch_buf )",
+ " YY_FATAL_ERROR( \"out of dynamic memory in yy_create_buffer()\" );",
+ "",
+ " b->yy_is_our_buffer = 1;",
+ "",
+ " yy_init_buffer( b, file );",
+ "",
+ " return b;",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "void yy_delete_buffer( YY_BUFFER_STATE b )",
+ "#else",
+ "void yy_delete_buffer( b )",
+ "YY_BUFFER_STATE b;",
+ "#endif",
+ "%+",
+ "void yyFlexLexer::yy_delete_buffer( YY_BUFFER_STATE b )",
+ "%*",
+ " {",
+ " if ( ! b )",
+ " return;",
+ "",
+ " if ( b == yy_current_buffer )",
+ " yy_current_buffer = (YY_BUFFER_STATE) 0;",
+ "",
+ " if ( b->yy_is_our_buffer )",
+ " yy_flex_free( (void *) b->yy_ch_buf );",
+ "",
+ " yy_flex_free( (void *) b );",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifndef YY_ALWAYS_INTERACTIVE",
+ "#ifndef YY_NEVER_INTERACTIVE",
+ "extern int isatty YY_PROTO(( int ));",
+ "#endif",
+ "#endif",
+ "",
+ "#ifdef YY_USE_PROTOS",
+ "void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )",
+ "#else",
+ "void yy_init_buffer( b, file )",
+ "YY_BUFFER_STATE b;",
+ "FILE *file;",
+ "#endif",
+ "",
+ "%+",
+ "extern \"C\" int isatty YY_PROTO(( int ));",
+ "void yyFlexLexer::yy_init_buffer( YY_BUFFER_STATE b, istream* file )",
+ "%*",
+ "",
+ " {",
+ " yy_flush_buffer( b );",
+ "",
+ " b->yy_input_file = file;",
+ " b->yy_fill_buffer = 1;",
+ "",
+ "%-",
+ "#if YY_ALWAYS_INTERACTIVE",
+ " b->yy_is_interactive = 1;",
+ "#else",
+ "#if YY_NEVER_INTERACTIVE",
+ " b->yy_is_interactive = 0;",
+ "#else",
+ " b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;",
+ "#endif",
+ "#endif",
+ "%+",
+ " b->yy_is_interactive = 0;",
+ "%*",
+ " }",
+ "",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "void yy_flush_buffer( YY_BUFFER_STATE b )",
+ "#else",
+ "void yy_flush_buffer( b )",
+ "YY_BUFFER_STATE b;",
+ "#endif",
+ "",
+ "%+",
+ "void yyFlexLexer::yy_flush_buffer( YY_BUFFER_STATE b )",
+ "%*",
+ " {",
+ " if ( ! b )",
+ " return;",
+ "",
+ " b->yy_n_chars = 0;",
+ "",
+ " /* We always need two end-of-buffer characters. The first causes",
+ " * a transition to the end-of-buffer state. The second causes",
+ " * a jam in that state.",
+ " */",
+ " b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;",
+ " b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;",
+ "",
+ " b->yy_buf_pos = &b->yy_ch_buf[0];",
+ "",
+ " b->yy_at_bol = 1;",
+ " b->yy_buffer_status = YY_BUFFER_NEW;",
+ "",
+ " if ( b == yy_current_buffer )",
+ " yy_load_buffer_state();",
+ " }",
+ "%*",
+ "",
+ "",
+ "#ifndef YY_NO_SCAN_BUFFER",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )",
+ "#else",
+ "YY_BUFFER_STATE yy_scan_buffer( base, size )",
+ "char *base;",
+ "yy_size_t size;",
+ "#endif",
+ " {",
+ " YY_BUFFER_STATE b;",
+ "",
+ " if ( size < 2 ||",
+ " base[size-2] != YY_END_OF_BUFFER_CHAR ||",
+ " base[size-1] != YY_END_OF_BUFFER_CHAR )",
+ " /* They forgot to leave room for the EOB's. */",
+ " return 0;",
+ "",
+ " b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );",
+ " if ( ! b )",
+ " YY_FATAL_ERROR( \"out of dynamic memory in yy_scan_buffer()\" );",
+ "",
+ " b->yy_buf_size = size - 2; /* \"- 2\" to take care of EOB's */",
+ " b->yy_buf_pos = b->yy_ch_buf = base;",
+ " b->yy_is_our_buffer = 0;",
+ " b->yy_input_file = 0;",
+ " b->yy_n_chars = b->yy_buf_size;",
+ " b->yy_is_interactive = 0;",
+ " b->yy_at_bol = 1;",
+ " b->yy_fill_buffer = 0;",
+ " b->yy_buffer_status = YY_BUFFER_NEW;",
+ "",
+ " yy_switch_to_buffer( b );",
+ "",
+ " return b;",
+ " }",
+ "%*",
+ "#endif",
+ "",
+ "",
+ "#ifndef YY_NO_SCAN_STRING",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )",
+ "#else",
+ "YY_BUFFER_STATE yy_scan_string( yy_str )",
+ "yyconst char *yy_str;",
+ "#endif",
+ " {",
+ " int len;",
+ " for ( len = 0; yy_str[len]; ++len )",
+ " ;",
+ "",
+ " return yy_scan_bytes( yy_str, len );",
+ " }",
+ "%*",
+ "#endif",
+ "",
+ "",
+ "#ifndef YY_NO_SCAN_BYTES",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )",
+ "#else",
+ "YY_BUFFER_STATE yy_scan_bytes( bytes, len )",
+ "yyconst char *bytes;",
+ "int len;",
+ "#endif",
+ " {",
+ " YY_BUFFER_STATE b;",
+ " char *buf;",
+ " yy_size_t n;",
+ " int i;",
+ "",
+ " /* Get memory for full buffer, including space for trailing EOB's. */",
+ " n = len + 2;",
+ " buf = (char *) yy_flex_alloc( n );",
+ " if ( ! buf )",
+ " YY_FATAL_ERROR( \"out of dynamic memory in yy_scan_bytes()\" );",
+ "",
+ " for ( i = 0; i < len; ++i )",
+ " buf[i] = bytes[i];",
+ "",
+ " buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;",
+ "",
+ " b = yy_scan_buffer( buf, n );",
+ " if ( ! b )",
+ " YY_FATAL_ERROR( \"bad buffer in yy_scan_bytes()\" );",
+ "",
+ " /* It's okay to grow etc. this buffer, and we should throw it",
+ " * away when we're done.",
+ " */",
+ " b->yy_is_our_buffer = 1;",
+ "",
+ " return b;",
+ " }",
+ "%*",
+ "#endif",
+ "",
+ "",
+ "#ifndef YY_NO_PUSH_STATE",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "static void yy_push_state( int new_state )",
+ "#else",
+ "static void yy_push_state( new_state )",
+ "int new_state;",
+ "#endif",
+ "%+",
+ "void yyFlexLexer::yy_push_state( int new_state )",
+ "%*",
+ " {",
+ " if ( yy_start_stack_ptr >= yy_start_stack_depth )",
+ " {",
+ " yy_size_t new_size;",
+ "",
+ " yy_start_stack_depth += YY_START_STACK_INCR;",
+ " new_size = yy_start_stack_depth * sizeof( int );",
+ "",
+ " if ( ! yy_start_stack )",
+ " yy_start_stack = (int *) yy_flex_alloc( new_size );",
+ "",
+ " else",
+ " yy_start_stack = (int *) yy_flex_realloc(",
+ " (void *) yy_start_stack, new_size );",
+ "",
+ " if ( ! yy_start_stack )",
+ " YY_FATAL_ERROR(",
+ " \"out of memory expanding start-condition stack\" );",
+ " }",
+ "",
+ " yy_start_stack[yy_start_stack_ptr++] = YY_START;",
+ "",
+ " BEGIN(new_state);",
+ " }",
+ "#endif",
+ "",
+ "",
+ "#ifndef YY_NO_POP_STATE",
+ "%-",
+ "static void yy_pop_state()",
+ "%+",
+ "void yyFlexLexer::yy_pop_state()",
+ "%*",
+ " {",
+ " if ( --yy_start_stack_ptr < 0 )",
+ " YY_FATAL_ERROR( \"start-condition stack underflow\" );",
+ "",
+ " BEGIN(yy_start_stack[yy_start_stack_ptr]);",
+ " }",
+ "#endif",
+ "",
+ "",
+ "#ifndef YY_NO_TOP_STATE",
+ "%-",
+ "static int yy_top_state()",
+ "%+",
+ "int yyFlexLexer::yy_top_state()",
+ "%*",
+ " {",
+ " return yy_start_stack[yy_start_stack_ptr - 1];",
+ " }",
+ "#endif",
+ "",
+ "#ifndef YY_EXIT_FAILURE",
+ "#define YY_EXIT_FAILURE 2",
+ "#endif",
+ "",
+ "%-",
+ "#ifdef YY_USE_PROTOS",
+ "static void yy_fatal_error( yyconst char msg[] )",
+ "#else",
+ "static void yy_fatal_error( msg )",
+ "char msg[];",
+ "#endif",
+ " {",
+ " (void) fprintf( stderr, \"%s\\n\", msg );",
+ " exit( YY_EXIT_FAILURE );",
+ " }",
+ "",
+ "%+",
+ "",
+ "void yyFlexLexer::LexerError( yyconst char msg[] )",
+ " {",
+ " cerr << msg << '\\n';",
+ " exit( YY_EXIT_FAILURE );",
+ " }",
+ "%*",
+ "",
+ "",
+ "/* Redefine yyless() so it works in section 3 code. */",
+ "",
+ "#undef yyless",
+ "#define yyless(n) \\",
+ " do \\",
+ " { \\",
+ " /* Undo effects of setting up yytext. */ \\",
+ " yytext[yyleng] = yy_hold_char; \\",
+ " yy_c_buf_p = yytext + n; \\",
+ " yy_hold_char = *yy_c_buf_p; \\",
+ " *yy_c_buf_p = '\\0'; \\",
+ " yyleng = n; \\",
+ " } \\",
+ " while ( 0 )",
+ "",
+ "",
+ "/* Internal utility routines. */",
+ "",
+ "#ifndef yytext_ptr",
+ "#ifdef YY_USE_PROTOS",
+ "static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )",
+ "#else",
+ "static void yy_flex_strncpy( s1, s2, n )",
+ "char *s1;",
+ "yyconst char *s2;",
+ "int n;",
+ "#endif",
+ " {",
+ " register int i;",
+ " for ( i = 0; i < n; ++i )",
+ " s1[i] = s2[i];",
+ " }",
+ "#endif",
+ "",
+ "#ifdef YY_NEED_STRLEN",
+ "#ifdef YY_USE_PROTOS",
+ "static int yy_flex_strlen( yyconst char *s )",
+ "#else",
+ "static int yy_flex_strlen( s )",
+ "yyconst char *s;",
+ "#endif",
+ " {",
+ " register int n;",
+ " for ( n = 0; s[n]; ++n )",
+ " ;",
+ "",
+ " return n;",
+ " }",
+ "#endif",
+ "",
+ "",
+ "#ifdef YY_USE_PROTOS",
+ "static void *yy_flex_alloc( yy_size_t size )",
+ "#else",
+ "static void *yy_flex_alloc( size )",
+ "yy_size_t size;",
+ "#endif",
+ " {",
+ " return (void *) malloc( size );",
+ " }",
+ "",
+ "#ifdef YY_USE_PROTOS",
+ "static void *yy_flex_realloc( void *ptr, yy_size_t size )",
+ "#else",
+ "static void *yy_flex_realloc( ptr, size )",
+ "void *ptr;",
+ "yy_size_t size;",
+ "#endif",
+ " {",
+ " /* The cast to (char *) in the following accommodates both",
+ " * implementations that use char* generic pointers, and those",
+ " * that use void* generic pointers. It works with the latter",
+ " * because both ANSI C and C++ allow castless assignment from",
+ " * any pointer type to void*, and deal with argument conversions",
+ " * as though doing an assignment.",
+ " */",
+ " return (void *) realloc( (char *) ptr, size );",
+ " }",
+ "",
+ "#ifdef YY_USE_PROTOS",
+ "static void yy_flex_free( void *ptr )",
+ "#else",
+ "static void yy_flex_free( ptr )",
+ "void *ptr;",
+ "#endif",
+ " {",
+ " free( ptr );",
+ " }",
+ "",
+ "#if YY_MAIN",
+ "int main()",
+ " {",
+ " yylex();",
+ " return 0;",
+ " }",
+ "#endif",
+ 0
+};
diff --git a/Tools/android/flex-2.5.4a/sym.c b/Tools/android/flex-2.5.4a/sym.c
new file mode 100644
index 0000000..ef08739
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/sym.c
@@ -0,0 +1,262 @@
+/* sym - symbol table routines */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/sym.c,v 2.19 95/03/04 16:11:04 vern Exp $ */
+
+#include "flexdef.h"
+
+
+/* declare functions that have forward references */
+
+int hashfunct PROTO((register char[], int));
+
+
+struct hash_entry *ndtbl[NAME_TABLE_HASH_SIZE];
+struct hash_entry *sctbl[START_COND_HASH_SIZE];
+struct hash_entry *ccltab[CCL_HASH_SIZE];
+
+struct hash_entry *findsym();
+
+
+/* addsym - add symbol and definitions to symbol table
+ *
+ * -1 is returned if the symbol already exists, and the change not made.
+ */
+
+int addsym( sym, str_def, int_def, table, table_size )
+register char sym[];
+char *str_def;
+int int_def;
+hash_table table;
+int table_size;
+ {
+ int hash_val = hashfunct( sym, table_size );
+ register struct hash_entry *sym_entry = table[hash_val];
+ register struct hash_entry *new_entry;
+ register struct hash_entry *successor;
+
+ while ( sym_entry )
+ {
+ if ( ! strcmp( sym, sym_entry->name ) )
+ { /* entry already exists */
+ return -1;
+ }
+
+ sym_entry = sym_entry->next;
+ }
+
+ /* create new entry */
+ new_entry = (struct hash_entry *)
+ flex_alloc( sizeof( struct hash_entry ) );
+
+ if ( new_entry == NULL )
+ flexfatal( _( "symbol table memory allocation failed" ) );
+
+ if ( (successor = table[hash_val]) != 0 )
+ {
+ new_entry->next = successor;
+ successor->prev = new_entry;
+ }
+ else
+ new_entry->next = NULL;
+
+ new_entry->prev = NULL;
+ new_entry->name = sym;
+ new_entry->str_val = str_def;
+ new_entry->int_val = int_def;
+
+ table[hash_val] = new_entry;
+
+ return 0;
+ }
+
+
+/* cclinstal - save the text of a character class */
+
+void cclinstal( ccltxt, cclnum )
+Char ccltxt[];
+int cclnum;
+ {
+ /* We don't bother checking the return status because we are not
+ * called unless the symbol is new.
+ */
+ Char *copy_unsigned_string();
+
+ (void) addsym( (char *) copy_unsigned_string( ccltxt ),
+ (char *) 0, cclnum,
+ ccltab, CCL_HASH_SIZE );
+ }
+
+
+/* ccllookup - lookup the number associated with character class text
+ *
+ * Returns 0 if there's no CCL associated with the text.
+ */
+
+int ccllookup( ccltxt )
+Char ccltxt[];
+ {
+ return findsym( (char *) ccltxt, ccltab, CCL_HASH_SIZE )->int_val;
+ }
+
+
+/* findsym - find symbol in symbol table */
+
+struct hash_entry *findsym( sym, table, table_size )
+register char sym[];
+hash_table table;
+int table_size;
+ {
+ static struct hash_entry empty_entry =
+ {
+ (struct hash_entry *) 0, (struct hash_entry *) 0,
+ (char *) 0, (char *) 0, 0,
+ } ;
+ register struct hash_entry *sym_entry =
+ table[hashfunct( sym, table_size )];
+
+ while ( sym_entry )
+ {
+ if ( ! strcmp( sym, sym_entry->name ) )
+ return sym_entry;
+ sym_entry = sym_entry->next;
+ }
+
+ return &empty_entry;
+ }
+
+
+/* hashfunct - compute the hash value for "str" and hash size "hash_size" */
+
+int hashfunct( str, hash_size )
+register char str[];
+int hash_size;
+ {
+ register int hashval;
+ register int locstr;
+
+ hashval = 0;
+ locstr = 0;
+
+ while ( str[locstr] )
+ {
+ hashval = (hashval << 1) + (unsigned char) str[locstr++];
+ hashval %= hash_size;
+ }
+
+ return hashval;
+ }
+
+
+/* ndinstal - install a name definition */
+
+void ndinstal( name, definition )
+char name[];
+Char definition[];
+ {
+ char *copy_string();
+ Char *copy_unsigned_string();
+
+ if ( addsym( copy_string( name ),
+ (char *) copy_unsigned_string( definition ), 0,
+ ndtbl, NAME_TABLE_HASH_SIZE ) )
+ synerr( _( "name defined twice" ) );
+ }
+
+
+/* ndlookup - lookup a name definition
+ *
+ * Returns a nil pointer if the name definition does not exist.
+ */
+
+Char *ndlookup( nd )
+char nd[];
+ {
+ return (Char *) findsym( nd, ndtbl, NAME_TABLE_HASH_SIZE )->str_val;
+ }
+
+
+/* scextend - increase the maximum number of start conditions */
+
+void scextend()
+ {
+ current_max_scs += MAX_SCS_INCREMENT;
+
+ ++num_reallocs;
+
+ scset = reallocate_integer_array( scset, current_max_scs );
+ scbol = reallocate_integer_array( scbol, current_max_scs );
+ scxclu = reallocate_integer_array( scxclu, current_max_scs );
+ sceof = reallocate_integer_array( sceof, current_max_scs );
+ scname = reallocate_char_ptr_array( scname, current_max_scs );
+ }
+
+
+/* scinstal - make a start condition
+ *
+ * NOTE
+ * The start condition is "exclusive" if xcluflg is true.
+ */
+
+void scinstal( str, xcluflg )
+char str[];
+int xcluflg;
+ {
+ char *copy_string();
+
+ /* Generate start condition definition, for use in BEGIN et al. */
+ action_define( str, lastsc );
+
+ if ( ++lastsc >= current_max_scs )
+ scextend();
+
+ scname[lastsc] = copy_string( str );
+
+ if ( addsym( scname[lastsc], (char *) 0, lastsc,
+ sctbl, START_COND_HASH_SIZE ) )
+ format_pinpoint_message(
+ _( "start condition %s declared twice" ),
+ str );
+
+ scset[lastsc] = mkstate( SYM_EPSILON );
+ scbol[lastsc] = mkstate( SYM_EPSILON );
+ scxclu[lastsc] = xcluflg;
+ sceof[lastsc] = false;
+ }
+
+
+/* sclookup - lookup the number associated with a start condition
+ *
+ * Returns 0 if no such start condition.
+ */
+
+int sclookup( str )
+char str[];
+ {
+ return findsym( str, sctbl, START_COND_HASH_SIZE )->int_val;
+ }
diff --git a/Tools/android/flex-2.5.4a/tblcmp.c b/Tools/android/flex-2.5.4a/tblcmp.c
new file mode 100644
index 0000000..b2e816b
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/tblcmp.c
@@ -0,0 +1,887 @@
+/* tblcmp - table compression routines */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/tblcmp.c,v 2.11 94/11/05 17:08:28 vern Exp $ */
+
+#include "flexdef.h"
+
+
+/* declarations for functions that have forward references */
+
+void mkentry PROTO((register int*, int, int, int, int));
+void mkprot PROTO((int[], int, int));
+void mktemplate PROTO((int[], int, int));
+void mv2front PROTO((int));
+int tbldiff PROTO((int[], int, int[]));
+
+
+/* bldtbl - build table entries for dfa state
+ *
+ * synopsis
+ * int state[numecs], statenum, totaltrans, comstate, comfreq;
+ * bldtbl( state, statenum, totaltrans, comstate, comfreq );
+ *
+ * State is the statenum'th dfa state. It is indexed by equivalence class and
+ * gives the number of the state to enter for a given equivalence class.
+ * totaltrans is the total number of transitions out of the state. Comstate
+ * is that state which is the destination of the most transitions out of State.
+ * Comfreq is how many transitions there are out of State to Comstate.
+ *
+ * A note on terminology:
+ * "protos" are transition tables which have a high probability of
+ * either being redundant (a state processed later will have an identical
+ * transition table) or nearly redundant (a state processed later will have
+ * many of the same out-transitions). A "most recently used" queue of
+ * protos is kept around with the hope that most states will find a proto
+ * which is similar enough to be usable, and therefore compacting the
+ * output tables.
+ * "templates" are a special type of proto. If a transition table is
+ * homogeneous or nearly homogeneous (all transitions go to the same
+ * destination) then the odds are good that future states will also go
+ * to the same destination state on basically the same character set.
+ * These homogeneous states are so common when dealing with large rule
+ * sets that they merit special attention. If the transition table were
+ * simply made into a proto, then (typically) each subsequent, similar
+ * state will differ from the proto for two out-transitions. One of these
+ * out-transitions will be that character on which the proto does not go
+ * to the common destination, and one will be that character on which the
+ * state does not go to the common destination. Templates, on the other
+ * hand, go to the common state on EVERY transition character, and therefore
+ * cost only one difference.
+ */
+
+void bldtbl( state, statenum, totaltrans, comstate, comfreq )
+int state[], statenum, totaltrans, comstate, comfreq;
+ {
+ int extptr, extrct[2][CSIZE + 1];
+ int mindiff, minprot, i, d;
+
+ /* If extptr is 0 then the first array of extrct holds the result
+ * of the "best difference" to date, which is those transitions
+ * which occur in "state" but not in the proto which, to date,
+ * has the fewest differences between itself and "state". If
+ * extptr is 1 then the second array of extrct hold the best
+ * difference. The two arrays are toggled between so that the
+ * best difference to date can be kept around and also a difference
+ * just created by checking against a candidate "best" proto.
+ */
+
+ extptr = 0;
+
+ /* If the state has too few out-transitions, don't bother trying to
+ * compact its tables.
+ */
+
+ if ( (totaltrans * 100) < (numecs * PROTO_SIZE_PERCENTAGE) )
+ mkentry( state, numecs, statenum, JAMSTATE, totaltrans );
+
+ else
+ {
+ /* "checkcom" is true if we should only check "state" against
+ * protos which have the same "comstate" value.
+ */
+ int checkcom =
+ comfreq * 100 > totaltrans * CHECK_COM_PERCENTAGE;
+
+ minprot = firstprot;
+ mindiff = totaltrans;
+
+ if ( checkcom )
+ {
+ /* Find first proto which has the same "comstate". */
+ for ( i = firstprot; i != NIL; i = protnext[i] )
+ if ( protcomst[i] == comstate )
+ {
+ minprot = i;
+ mindiff = tbldiff( state, minprot,
+ extrct[extptr] );
+ break;
+ }
+ }
+
+ else
+ {
+ /* Since we've decided that the most common destination
+ * out of "state" does not occur with a high enough
+ * frequency, we set the "comstate" to zero, assuring
+ * that if this state is entered into the proto list,
+ * it will not be considered a template.
+ */
+ comstate = 0;
+
+ if ( firstprot != NIL )
+ {
+ minprot = firstprot;
+ mindiff = tbldiff( state, minprot,
+ extrct[extptr] );
+ }
+ }
+
+ /* We now have the first interesting proto in "minprot". If
+ * it matches within the tolerances set for the first proto,
+ * we don't want to bother scanning the rest of the proto list
+ * to see if we have any other reasonable matches.
+ */
+
+ if ( mindiff * 100 > totaltrans * FIRST_MATCH_DIFF_PERCENTAGE )
+ {
+ /* Not a good enough match. Scan the rest of the
+ * protos.
+ */
+ for ( i = minprot; i != NIL; i = protnext[i] )
+ {
+ d = tbldiff( state, i, extrct[1 - extptr] );
+ if ( d < mindiff )
+ {
+ extptr = 1 - extptr;
+ mindiff = d;
+ minprot = i;
+ }
+ }
+ }
+
+ /* Check if the proto we've decided on as our best bet is close
+ * enough to the state we want to match to be usable.
+ */
+
+ if ( mindiff * 100 > totaltrans * ACCEPTABLE_DIFF_PERCENTAGE )
+ {
+ /* No good. If the state is homogeneous enough,
+ * we make a template out of it. Otherwise, we
+ * make a proto.
+ */
+
+ if ( comfreq * 100 >=
+ totaltrans * TEMPLATE_SAME_PERCENTAGE )
+ mktemplate( state, statenum, comstate );
+
+ else
+ {
+ mkprot( state, statenum, comstate );
+ mkentry( state, numecs, statenum,
+ JAMSTATE, totaltrans );
+ }
+ }
+
+ else
+ { /* use the proto */
+ mkentry( extrct[extptr], numecs, statenum,
+ prottbl[minprot], mindiff );
+
+ /* If this state was sufficiently different from the
+ * proto we built it from, make it, too, a proto.
+ */
+
+ if ( mindiff * 100 >=
+ totaltrans * NEW_PROTO_DIFF_PERCENTAGE )
+ mkprot( state, statenum, comstate );
+
+ /* Since mkprot added a new proto to the proto queue,
+ * it's possible that "minprot" is no longer on the
+ * proto queue (if it happened to have been the last
+ * entry, it would have been bumped off). If it's
+ * not there, then the new proto took its physical
+ * place (though logically the new proto is at the
+ * beginning of the queue), so in that case the
+ * following call will do nothing.
+ */
+
+ mv2front( minprot );
+ }
+ }
+ }
+
+
+/* cmptmps - compress template table entries
+ *
+ * Template tables are compressed by using the 'template equivalence
+ * classes', which are collections of transition character equivalence
+ * classes which always appear together in templates - really meta-equivalence
+ * classes.
+ */
+
+void cmptmps()
+ {
+ int tmpstorage[CSIZE + 1];
+ register int *tmp = tmpstorage, i, j;
+ int totaltrans, trans;
+
+ peakpairs = numtemps * numecs + tblend;
+
+ if ( usemecs )
+ {
+ /* Create equivalence classes based on data gathered on
+ * template transitions.
+ */
+ nummecs = cre8ecs( tecfwd, tecbck, numecs );
+ }
+
+ else
+ nummecs = numecs;
+
+ while ( lastdfa + numtemps + 1 >= current_max_dfas )
+ increase_max_dfas();
+
+ /* Loop through each template. */
+
+ for ( i = 1; i <= numtemps; ++i )
+ {
+ /* Number of non-jam transitions out of this template. */
+ totaltrans = 0;
+
+ for ( j = 1; j <= numecs; ++j )
+ {
+ trans = tnxt[numecs * i + j];
+
+ if ( usemecs )
+ {
+ /* The absolute value of tecbck is the
+ * meta-equivalence class of a given
+ * equivalence class, as set up by cre8ecs().
+ */
+ if ( tecbck[j] > 0 )
+ {
+ tmp[tecbck[j]] = trans;
+
+ if ( trans > 0 )
+ ++totaltrans;
+ }
+ }
+
+ else
+ {
+ tmp[j] = trans;
+
+ if ( trans > 0 )
+ ++totaltrans;
+ }
+ }
+
+ /* It is assumed (in a rather subtle way) in the skeleton
+ * that if we're using meta-equivalence classes, the def[]
+ * entry for all templates is the jam template, i.e.,
+ * templates never default to other non-jam table entries
+ * (e.g., another template)
+ */
+
+ /* Leave room for the jam-state after the last real state. */
+ mkentry( tmp, nummecs, lastdfa + i + 1, JAMSTATE, totaltrans );
+ }
+ }
+
+
+
+/* expand_nxt_chk - expand the next check arrays */
+
+void expand_nxt_chk()
+ {
+ register int old_max = current_max_xpairs;
+
+ current_max_xpairs += MAX_XPAIRS_INCREMENT;
+
+ ++num_reallocs;
+
+ nxt = reallocate_integer_array( nxt, current_max_xpairs );
+ chk = reallocate_integer_array( chk, current_max_xpairs );
+
+ zero_out( (char *) (chk + old_max),
+ (size_t) (MAX_XPAIRS_INCREMENT * sizeof( int )) );
+ }
+
+
+/* find_table_space - finds a space in the table for a state to be placed
+ *
+ * synopsis
+ * int *state, numtrans, block_start;
+ * int find_table_space();
+ *
+ * block_start = find_table_space( state, numtrans );
+ *
+ * State is the state to be added to the full speed transition table.
+ * Numtrans is the number of out-transitions for the state.
+ *
+ * find_table_space() returns the position of the start of the first block (in
+ * chk) able to accommodate the state
+ *
+ * In determining if a state will or will not fit, find_table_space() must take
+ * into account the fact that an end-of-buffer state will be added at [0],
+ * and an action number will be added in [-1].
+ */
+
+int find_table_space( state, numtrans )
+int *state, numtrans;
+ {
+ /* Firstfree is the position of the first possible occurrence of two
+ * consecutive unused records in the chk and nxt arrays.
+ */
+ register int i;
+ register int *state_ptr, *chk_ptr;
+ register int *ptr_to_last_entry_in_state;
+
+ /* If there are too many out-transitions, put the state at the end of
+ * nxt and chk.
+ */
+ if ( numtrans > MAX_XTIONS_FULL_INTERIOR_FIT )
+ {
+ /* If table is empty, return the first available spot in
+ * chk/nxt, which should be 1.
+ */
+ if ( tblend < 2 )
+ return 1;
+
+ /* Start searching for table space near the end of
+ * chk/nxt arrays.
+ */
+ i = tblend - numecs;
+ }
+
+ else
+ /* Start searching for table space from the beginning
+ * (skipping only the elements which will definitely not
+ * hold the new state).
+ */
+ i = firstfree;
+
+ while ( 1 ) /* loops until a space is found */
+ {
+ while ( i + numecs >= current_max_xpairs )
+ expand_nxt_chk();
+
+ /* Loops until space for end-of-buffer and action number
+ * are found.
+ */
+ while ( 1 )
+ {
+ /* Check for action number space. */
+ if ( chk[i - 1] == 0 )
+ {
+ /* Check for end-of-buffer space. */
+ if ( chk[i] == 0 )
+ break;
+
+ else
+ /* Since i != 0, there is no use
+ * checking to see if (++i) - 1 == 0,
+ * because that's the same as i == 0,
+ * so we skip a space.
+ */
+ i += 2;
+ }
+
+ else
+ ++i;
+
+ while ( i + numecs >= current_max_xpairs )
+ expand_nxt_chk();
+ }
+
+ /* If we started search from the beginning, store the new
+ * firstfree for the next call of find_table_space().
+ */
+ if ( numtrans <= MAX_XTIONS_FULL_INTERIOR_FIT )
+ firstfree = i + 1;
+
+ /* Check to see if all elements in chk (and therefore nxt)
+ * that are needed for the new state have not yet been taken.
+ */
+
+ state_ptr = &state[1];
+ ptr_to_last_entry_in_state = &chk[i + numecs + 1];
+
+ for ( chk_ptr = &chk[i + 1];
+ chk_ptr != ptr_to_last_entry_in_state; ++chk_ptr )
+ if ( *(state_ptr++) != 0 && *chk_ptr != 0 )
+ break;
+
+ if ( chk_ptr == ptr_to_last_entry_in_state )
+ return i;
+
+ else
+ ++i;
+ }
+ }
+
+
+/* inittbl - initialize transition tables
+ *
+ * Initializes "firstfree" to be one beyond the end of the table. Initializes
+ * all "chk" entries to be zero.
+ */
+void inittbl()
+ {
+ register int i;
+
+ zero_out( (char *) chk, (size_t) (current_max_xpairs * sizeof( int )) );
+
+ tblend = 0;
+ firstfree = tblend + 1;
+ numtemps = 0;
+
+ if ( usemecs )
+ {
+ /* Set up doubly-linked meta-equivalence classes; these
+ * are sets of equivalence classes which all have identical
+ * transitions out of TEMPLATES.
+ */
+
+ tecbck[1] = NIL;
+
+ for ( i = 2; i <= numecs; ++i )
+ {
+ tecbck[i] = i - 1;
+ tecfwd[i - 1] = i;
+ }
+
+ tecfwd[numecs] = NIL;
+ }
+ }
+
+
+/* mkdeftbl - make the default, "jam" table entries */
+
+void mkdeftbl()
+ {
+ int i;
+
+ jamstate = lastdfa + 1;
+
+ ++tblend; /* room for transition on end-of-buffer character */
+
+ while ( tblend + numecs >= current_max_xpairs )
+ expand_nxt_chk();
+
+ /* Add in default end-of-buffer transition. */
+ nxt[tblend] = end_of_buffer_state;
+ chk[tblend] = jamstate;
+
+ for ( i = 1; i <= numecs; ++i )
+ {
+ nxt[tblend + i] = 0;
+ chk[tblend + i] = jamstate;
+ }
+
+ jambase = tblend;
+
+ base[jamstate] = jambase;
+ def[jamstate] = 0;
+
+ tblend += numecs;
+ ++numtemps;
+ }
+
+
+/* mkentry - create base/def and nxt/chk entries for transition array
+ *
+ * synopsis
+ * int state[numchars + 1], numchars, statenum, deflink, totaltrans;
+ * mkentry( state, numchars, statenum, deflink, totaltrans );
+ *
+ * "state" is a transition array "numchars" characters in size, "statenum"
+ * is the offset to be used into the base/def tables, and "deflink" is the
+ * entry to put in the "def" table entry. If "deflink" is equal to
+ * "JAMSTATE", then no attempt will be made to fit zero entries of "state"
+ * (i.e., jam entries) into the table. It is assumed that by linking to
+ * "JAMSTATE" they will be taken care of. In any case, entries in "state"
+ * marking transitions to "SAME_TRANS" are treated as though they will be
+ * taken care of by whereever "deflink" points. "totaltrans" is the total
+ * number of transitions out of the state. If it is below a certain threshold,
+ * the tables are searched for an interior spot that will accommodate the
+ * state array.
+ */
+
+void mkentry( state, numchars, statenum, deflink, totaltrans )
+register int *state;
+int numchars, statenum, deflink, totaltrans;
+ {
+ register int minec, maxec, i, baseaddr;
+ int tblbase, tbllast;
+
+ if ( totaltrans == 0 )
+ { /* there are no out-transitions */
+ if ( deflink == JAMSTATE )
+ base[statenum] = JAMSTATE;
+ else
+ base[statenum] = 0;
+
+ def[statenum] = deflink;
+ return;
+ }
+
+ for ( minec = 1; minec <= numchars; ++minec )
+ {
+ if ( state[minec] != SAME_TRANS )
+ if ( state[minec] != 0 || deflink != JAMSTATE )
+ break;
+ }
+
+ if ( totaltrans == 1 )
+ {
+ /* There's only one out-transition. Save it for later to fill
+ * in holes in the tables.
+ */
+ stack1( statenum, minec, state[minec], deflink );
+ return;
+ }
+
+ for ( maxec = numchars; maxec > 0; --maxec )
+ {
+ if ( state[maxec] != SAME_TRANS )
+ if ( state[maxec] != 0 || deflink != JAMSTATE )
+ break;
+ }
+
+ /* Whether we try to fit the state table in the middle of the table
+ * entries we have already generated, or if we just take the state
+ * table at the end of the nxt/chk tables, we must make sure that we
+ * have a valid base address (i.e., non-negative). Note that
+ * negative base addresses dangerous at run-time (because indexing
+ * the nxt array with one and a low-valued character will access
+ * memory before the start of the array.
+ */
+
+ /* Find the first transition of state that we need to worry about. */
+ if ( totaltrans * 100 <= numchars * INTERIOR_FIT_PERCENTAGE )
+ {
+ /* Attempt to squeeze it into the middle of the tables. */
+ baseaddr = firstfree;
+
+ while ( baseaddr < minec )
+ {
+ /* Using baseaddr would result in a negative base
+ * address below; find the next free slot.
+ */
+ for ( ++baseaddr; chk[baseaddr] != 0; ++baseaddr )
+ ;
+ }
+
+ while ( baseaddr + maxec - minec + 1 >= current_max_xpairs )
+ expand_nxt_chk();
+
+ for ( i = minec; i <= maxec; ++i )
+ if ( state[i] != SAME_TRANS &&
+ (state[i] != 0 || deflink != JAMSTATE) &&
+ chk[baseaddr + i - minec] != 0 )
+ { /* baseaddr unsuitable - find another */
+ for ( ++baseaddr;
+ baseaddr < current_max_xpairs &&
+ chk[baseaddr] != 0; ++baseaddr )
+ ;
+
+ while ( baseaddr + maxec - minec + 1 >=
+ current_max_xpairs )
+ expand_nxt_chk();
+
+ /* Reset the loop counter so we'll start all
+ * over again next time it's incremented.
+ */
+
+ i = minec - 1;
+ }
+ }
+
+ else
+ {
+ /* Ensure that the base address we eventually generate is
+ * non-negative.
+ */
+ baseaddr = MAX( tblend + 1, minec );
+ }
+
+ tblbase = baseaddr - minec;
+ tbllast = tblbase + maxec;
+
+ while ( tbllast + 1 >= current_max_xpairs )
+ expand_nxt_chk();
+
+ base[statenum] = tblbase;
+ def[statenum] = deflink;
+
+ for ( i = minec; i <= maxec; ++i )
+ if ( state[i] != SAME_TRANS )
+ if ( state[i] != 0 || deflink != JAMSTATE )
+ {
+ nxt[tblbase + i] = state[i];
+ chk[tblbase + i] = statenum;
+ }
+
+ if ( baseaddr == firstfree )
+ /* Find next free slot in tables. */
+ for ( ++firstfree; chk[firstfree] != 0; ++firstfree )
+ ;
+
+ tblend = MAX( tblend, tbllast );
+ }
+
+
+/* mk1tbl - create table entries for a state (or state fragment) which
+ * has only one out-transition
+ */
+
+void mk1tbl( state, sym, onenxt, onedef )
+int state, sym, onenxt, onedef;
+ {
+ if ( firstfree < sym )
+ firstfree = sym;
+
+ while ( chk[firstfree] != 0 )
+ if ( ++firstfree >= current_max_xpairs )
+ expand_nxt_chk();
+
+ base[state] = firstfree - sym;
+ def[state] = onedef;
+ chk[firstfree] = state;
+ nxt[firstfree] = onenxt;
+
+ if ( firstfree > tblend )
+ {
+ tblend = firstfree++;
+
+ if ( firstfree >= current_max_xpairs )
+ expand_nxt_chk();
+ }
+ }
+
+
+/* mkprot - create new proto entry */
+
+void mkprot( state, statenum, comstate )
+int state[], statenum, comstate;
+ {
+ int i, slot, tblbase;
+
+ if ( ++numprots >= MSP || numecs * numprots >= PROT_SAVE_SIZE )
+ {
+ /* Gotta make room for the new proto by dropping last entry in
+ * the queue.
+ */
+ slot = lastprot;
+ lastprot = protprev[lastprot];
+ protnext[lastprot] = NIL;
+ }
+
+ else
+ slot = numprots;
+
+ protnext[slot] = firstprot;
+
+ if ( firstprot != NIL )
+ protprev[firstprot] = slot;
+
+ firstprot = slot;
+ prottbl[slot] = statenum;
+ protcomst[slot] = comstate;
+
+ /* Copy state into save area so it can be compared with rapidly. */
+ tblbase = numecs * (slot - 1);
+
+ for ( i = 1; i <= numecs; ++i )
+ protsave[tblbase + i] = state[i];
+ }
+
+
+/* mktemplate - create a template entry based on a state, and connect the state
+ * to it
+ */
+
+void mktemplate( state, statenum, comstate )
+int state[], statenum, comstate;
+ {
+ int i, numdiff, tmpbase, tmp[CSIZE + 1];
+ Char transset[CSIZE + 1];
+ int tsptr;
+
+ ++numtemps;
+
+ tsptr = 0;
+
+ /* Calculate where we will temporarily store the transition table
+ * of the template in the tnxt[] array. The final transition table
+ * gets created by cmptmps().
+ */
+
+ tmpbase = numtemps * numecs;
+
+ if ( tmpbase + numecs >= current_max_template_xpairs )
+ {
+ current_max_template_xpairs += MAX_TEMPLATE_XPAIRS_INCREMENT;
+
+ ++num_reallocs;
+
+ tnxt = reallocate_integer_array( tnxt,
+ current_max_template_xpairs );
+ }
+
+ for ( i = 1; i <= numecs; ++i )
+ if ( state[i] == 0 )
+ tnxt[tmpbase + i] = 0;
+ else
+ {
+ transset[tsptr++] = i;
+ tnxt[tmpbase + i] = comstate;
+ }
+
+ if ( usemecs )
+ mkeccl( transset, tsptr, tecfwd, tecbck, numecs, 0 );
+
+ mkprot( tnxt + tmpbase, -numtemps, comstate );
+
+ /* We rely on the fact that mkprot adds things to the beginning
+ * of the proto queue.
+ */
+
+ numdiff = tbldiff( state, firstprot, tmp );
+ mkentry( tmp, numecs, statenum, -numtemps, numdiff );
+ }
+
+
+/* mv2front - move proto queue element to front of queue */
+
+void mv2front( qelm )
+int qelm;
+ {
+ if ( firstprot != qelm )
+ {
+ if ( qelm == lastprot )
+ lastprot = protprev[lastprot];
+
+ protnext[protprev[qelm]] = protnext[qelm];
+
+ if ( protnext[qelm] != NIL )
+ protprev[protnext[qelm]] = protprev[qelm];
+
+ protprev[qelm] = NIL;
+ protnext[qelm] = firstprot;
+ protprev[firstprot] = qelm;
+ firstprot = qelm;
+ }
+ }
+
+
+/* place_state - place a state into full speed transition table
+ *
+ * State is the statenum'th state. It is indexed by equivalence class and
+ * gives the number of the state to enter for a given equivalence class.
+ * Transnum is the number of out-transitions for the state.
+ */
+
+void place_state( state, statenum, transnum )
+int *state, statenum, transnum;
+ {
+ register int i;
+ register int *state_ptr;
+ int position = find_table_space( state, transnum );
+
+ /* "base" is the table of start positions. */
+ base[statenum] = position;
+
+ /* Put in action number marker; this non-zero number makes sure that
+ * find_table_space() knows that this position in chk/nxt is taken
+ * and should not be used for another accepting number in another
+ * state.
+ */
+ chk[position - 1] = 1;
+
+ /* Put in end-of-buffer marker; this is for the same purposes as
+ * above.
+ */
+ chk[position] = 1;
+
+ /* Place the state into chk and nxt. */
+ state_ptr = &state[1];
+
+ for ( i = 1; i <= numecs; ++i, ++state_ptr )
+ if ( *state_ptr != 0 )
+ {
+ chk[position + i] = i;
+ nxt[position + i] = *state_ptr;
+ }
+
+ if ( position + numecs > tblend )
+ tblend = position + numecs;
+ }
+
+
+/* stack1 - save states with only one out-transition to be processed later
+ *
+ * If there's room for another state on the "one-transition" stack, the
+ * state is pushed onto it, to be processed later by mk1tbl. If there's
+ * no room, we process the sucker right now.
+ */
+
+void stack1( statenum, sym, nextstate, deflink )
+int statenum, sym, nextstate, deflink;
+ {
+ if ( onesp >= ONE_STACK_SIZE - 1 )
+ mk1tbl( statenum, sym, nextstate, deflink );
+
+ else
+ {
+ ++onesp;
+ onestate[onesp] = statenum;
+ onesym[onesp] = sym;
+ onenext[onesp] = nextstate;
+ onedef[onesp] = deflink;
+ }
+ }
+
+
+/* tbldiff - compute differences between two state tables
+ *
+ * "state" is the state array which is to be extracted from the pr'th
+ * proto. "pr" is both the number of the proto we are extracting from
+ * and an index into the save area where we can find the proto's complete
+ * state table. Each entry in "state" which differs from the corresponding
+ * entry of "pr" will appear in "ext".
+ *
+ * Entries which are the same in both "state" and "pr" will be marked
+ * as transitions to "SAME_TRANS" in "ext". The total number of differences
+ * between "state" and "pr" is returned as function value. Note that this
+ * number is "numecs" minus the number of "SAME_TRANS" entries in "ext".
+ */
+
+int tbldiff( state, pr, ext )
+int state[], pr, ext[];
+ {
+ register int i, *sp = state, *ep = ext, *protp;
+ register int numdiff = 0;
+
+ protp = &protsave[numecs * (pr - 1)];
+
+ for ( i = numecs; i > 0; --i )
+ {
+ if ( *++protp == *++sp )
+ *++ep = SAME_TRANS;
+ else
+ {
+ *++ep = *sp;
+ ++numdiff;
+ }
+ }
+
+ return numdiff;
+ }
diff --git a/Tools/android/flex-2.5.4a/version.h b/Tools/android/flex-2.5.4a/version.h
new file mode 100644
index 0000000..623ca12
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/version.h
@@ -0,0 +1 @@
+#define FLEX_VERSION "2.5.4"
diff --git a/Tools/android/flex-2.5.4a/yylex.c b/Tools/android/flex-2.5.4a/yylex.c
new file mode 100644
index 0000000..e98835f
--- /dev/null
+++ b/Tools/android/flex-2.5.4a/yylex.c
@@ -0,0 +1,216 @@
+/* yylex - scanner front-end for flex */
+
+/*-
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Vern Paxson.
+ *
+ * The United States Government has rights in this work pursuant
+ * to contract no. DE-AC03-76SF00098 between the United States
+ * Department of Energy and the University of California.
+ *
+ * Redistribution and use in source and binary forms with or without
+ * modification are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement: ``This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software. Neither the name of the University 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 ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ */
+
+/* $Header: /home/daffy/u0/vern/flex/RCS/yylex.c,v 2.13 95/03/04 16:10:41 vern Exp $ */
+
+#include <ctype.h>
+#include "flexdef.h"
+#include "parse.h"
+
+
+/* yylex - scan for a regular expression token */
+
+int yylex()
+ {
+ int toktype;
+ static int beglin = false;
+ extern char *yytext;
+
+ if ( eofseen )
+ toktype = EOF;
+ else
+ toktype = flexscan();
+
+ if ( toktype == EOF || toktype == 0 )
+ {
+ eofseen = 1;
+
+ if ( sectnum == 1 )
+ {
+ synerr( _( "premature EOF" ) );
+ sectnum = 2;
+ toktype = SECTEND;
+ }
+
+ else
+ toktype = 0;
+ }
+
+ if ( trace )
+ {
+ if ( beglin )
+ {
+ fprintf( stderr, "%d\t", num_rules + 1 );
+ beglin = 0;
+ }
+
+ switch ( toktype )
+ {
+ case '<':
+ case '>':
+ case '^':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '|':
+ case '(':
+ case ')':
+ case '-':
+ case '/':
+ case '\\':
+ case '?':
+ case '.':
+ case '*':
+ case '+':
+ case ',':
+ (void) putc( toktype, stderr );
+ break;
+
+ case '\n':
+ (void) putc( '\n', stderr );
+
+ if ( sectnum == 2 )
+ beglin = 1;
+
+ break;
+
+ case SCDECL:
+ fputs( "%s", stderr );
+ break;
+
+ case XSCDECL:
+ fputs( "%x", stderr );
+ break;
+
+ case SECTEND:
+ fputs( "%%\n", stderr );
+
+ /* We set beglin to be true so we'll start
+ * writing out numbers as we echo rules.
+ * flexscan() has already assigned sectnum.
+ */
+ if ( sectnum == 2 )
+ beglin = 1;
+
+ break;
+
+ case NAME:
+ fprintf( stderr, "'%s'", nmstr );
+ break;
+
+ case CHAR:
+ switch ( yylval )
+ {
+ case '<':
+ case '>':
+ case '^':
+ case '$':
+ case '"':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '|':
+ case '(':
+ case ')':
+ case '-':
+ case '/':
+ case '\\':
+ case '?':
+ case '.':
+ case '*':
+ case '+':
+ case ',':
+ fprintf( stderr, "\\%c",
+ yylval );
+ break;
+
+ default:
+ if ( ! isascii( yylval ) ||
+ ! isprint( yylval ) )
+ fprintf( stderr,
+ "\\%.3o",
+ (unsigned int) yylval );
+ else
+ (void) putc( yylval,
+ stderr );
+ break;
+ }
+
+ break;
+
+ case NUMBER:
+ fprintf( stderr, "%d", yylval );
+ break;
+
+ case PREVCCL:
+ fprintf( stderr, "[%d]", yylval );
+ break;
+
+ case EOF_OP:
+ fprintf( stderr, "<<EOF>>" );
+ break;
+
+ case OPTION_OP:
+ fprintf( stderr, "%s ", yytext );
+ break;
+
+ case OPT_OUTFILE:
+ case OPT_PREFIX:
+ case CCE_ALNUM:
+ case CCE_ALPHA:
+ case CCE_BLANK:
+ case CCE_CNTRL:
+ case CCE_DIGIT:
+ case CCE_GRAPH:
+ case CCE_LOWER:
+ case CCE_PRINT:
+ case CCE_PUNCT:
+ case CCE_SPACE:
+ case CCE_UPPER:
+ case CCE_XDIGIT:
+ fprintf( stderr, "%s", yytext );
+ break;
+
+ case 0:
+ fprintf( stderr, _( "End Marker\n" ) );
+ break;
+
+ default:
+ fprintf( stderr,
+ _( "*Something Weird* - tok: %d val: %d\n" ),
+ toktype, yylval );
+ break;
+ }
+ }
+
+ return toktype;
+ }
diff --git a/Tools/android/webkitmerge/Android.mk b/Tools/android/webkitmerge/Android.mk
new file mode 100644
index 0000000..2ff1538
--- /dev/null
+++ b/Tools/android/webkitmerge/Android.mk
@@ -0,0 +1,24 @@
+# Copyright (C) 2009 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := webkitmerge.cpp
+
+LOCAL_MODULE := webkitmerge
+
+LOCAL_MODULE_TAGS := eng
+
+include $(BUILD_HOST_EXECUTABLE)
diff --git a/Tools/android/webkitmerge/webkitmerge.cpp b/Tools/android/webkitmerge/webkitmerge.cpp
new file mode 100644
index 0000000..22eeb54
--- /dev/null
+++ b/Tools/android/webkitmerge/webkitmerge.cpp
@@ -0,0 +1,1834 @@
+/*
+ * Copyright 2009, The Android Open Source Project
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
+ * EXPRESS OR 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 <map>
+#include <string>
+#include <vector>
+#include <cstdio>
+#include <stdlib.h>
+#include <string.h>
+
+using namespace std;
+
+string WEBKITLIB = "external/webkit";
+
+string oldBaseStr;
+string oldCmdStr;
+string newBaseStr;
+string newCmdStr;
+string sandboxBaseStr;
+string sandboxCmdStr;
+string outputDir;
+string scratchDir;
+
+const char* oldBase;
+const char* oldCmd;
+const char* newBase;
+const char* newCmd;
+const char* sandboxBase;
+const char* sandboxCmd;
+
+bool assert_debug;
+
+#define myassert(a) do { \
+ if (!(a)) { \
+ fprintf(stderr, "%s %d %s\n", __FUNCTION__, __LINE__, #a); \
+ fflush(stderr); \
+ if (assert_debug) for(;;); else exit(0); \
+ } \
+} while(false)
+
+class Options {
+public:
+ Options() : emitGitCommands(false), emitPerforceCommands(false),
+ mergeMake(true), copyOther(true), mergeCore(true),
+ removeEmptyDirs(true), removeSVNDirs(true), debug(false),
+ execute(false), verbose(false), cleared(false)
+ {
+ }
+
+ bool finish();
+ void clearOnce()
+ {
+ if (cleared)
+ return;
+ mergeMake = copyOther = mergeCore = removeEmptyDirs = removeSVNDirs = false;
+ cleared = true;
+ }
+ string androidWebKit;
+ string baseWebKit;
+ string newWebKit;
+ bool emitGitCommands;
+ bool emitPerforceCommands;
+ bool mergeMake;
+ bool copyOther;
+ bool mergeCore;
+ bool removeEmptyDirs;
+ bool removeSVNDirs;
+ bool debug;
+ bool execute;
+ bool verbose;
+private:
+ bool cleared;
+};
+
+Options options;
+
+char* GetFile(string fileNameStr, size_t* sizePtr = NULL, int* lines = NULL)
+{
+ const char* fileName = fileNameStr.c_str();
+ FILE* file = fopen(fileName, "r");
+ if (file == NULL)
+ {
+ fprintf(stderr, "can't read %s\n", fileName);
+ myassert(0);
+ return 0;
+ }
+ fseek(file, 0, SEEK_END);
+ size_t size = ftell(file);
+ if (sizePtr)
+ *sizePtr = size;
+ fseek(file, 0, SEEK_SET);
+ char* buffer = new char[size + 2];
+ fread(buffer, size, 1, file);
+ buffer[size] = buffer[size + 1] = '\0';
+ int lineCount = 0;
+ for (size_t index = 0; index < size; index++) {
+ if (buffer[index] == '\n') {
+ buffer[index] = '\0';
+ lineCount++;
+ }
+ }
+ if (lines)
+ *lines = lineCount;
+ fclose(file);
+ return buffer;
+}
+
+bool Options::finish()
+{
+ ::assert_debug = options.debug;
+ if (androidWebKit.size() == 0) {
+ fprintf(stderr, "missing --android parameter");
+ return false;
+ }
+ if (baseWebKit.size() == 0) {
+ fprintf(stderr, "missing --basewebkit parameter");
+ return false;
+ }
+ if (newWebKit.size() == 0) {
+ fprintf(stderr, "missing --newwebkit parameter");
+ return false;
+ }
+ sandboxBaseStr = androidWebKit + "/" + WEBKITLIB;
+ sandboxCmdStr = sandboxBaseStr;
+ int err = system("pwd > pwd.txt");
+ myassert(err != -1);
+ outputDir = string(GetFile("pwd.txt"));
+ system("rm pwd.txt");
+ myassert(outputDir.size() > 0);
+ scratchDir = outputDir;
+ outputDir += "/scripts/";
+ string outputMkdir = "test -d " + outputDir + " || mkdir " + outputDir;
+ system(outputMkdir.c_str());
+ scratchDir += "/scratch/";
+ string scratchMkdir = "test -d " + scratchDir + " || mkdir " + scratchDir;
+ system(scratchMkdir.c_str());
+ oldBaseStr = baseWebKit;
+ oldCmdStr = oldBaseStr;
+ newBaseStr = newWebKit;
+ newCmdStr = newBaseStr;
+ oldBase = oldBaseStr.c_str();
+ oldCmd = oldCmdStr.c_str();
+ newBase = newBaseStr.c_str();
+ newCmd = newCmdStr.c_str();
+ sandboxBase = sandboxBaseStr.c_str();
+ sandboxCmd = sandboxCmdStr.c_str();
+ return true;
+}
+
+// scratch files
+string ScratchFile(const char* name)
+{
+ return scratchDir + name + ".txt";
+}
+
+FILE* commandFile;
+FILE* copyDirFile;
+FILE* oopsFile;
+
+string SedEscape(const char* str)
+{
+ string result;
+ char ch;
+ while ((ch = *str++) != '\0') {
+ if (ch == '/' || ch == '\\' || ch == '$')
+ result += '\\';
+ result += ch;
+ }
+ return result;
+}
+
+char* List(const char* base, char* name, const char* workingDir)
+{
+ string listStr = "ls -F \"";
+ listStr += string(base) + "/" + workingDir + "\" > " + ScratchFile(name);
+ int err = system(listStr.c_str());
+ myassert(err == 0);
+ return GetFile(ScratchFile(name));
+}
+
+bool Merge(const char* oldDir, const char* oldFile, const char* newDir, const char* newFile,
+ const char* outFile)
+{
+ char scratch[2048];
+
+ sprintf(scratch, "merge -p -q \"%s/%s/%s\" \"%s/%s/%s\" \"%s/%s/%s\" > %s",
+ sandboxBase, oldDir, oldFile, oldBase, oldDir, oldFile, newBase, newDir, newFile, outFile);
+ int err = system(scratch);
+ myassert(err == 0 || err ==1 || err == 256);
+ return err == 0;
+}
+
+bool Merge(const char* dir, const char* file)
+{
+ return Merge(dir, file, dir, file, "/dev/null");
+}
+
+/*
+static const char* skipNonSpace(char** linePtr) {
+ char* line = *linePtr;
+ while (line[0] && isspace(line[0]) == false)
+ line++;
+ *linePtr = line;
+ return line;
+}
+*/
+
+static bool endsWith(const char* str, const char* end) {
+ size_t endLen = strlen(end);
+ const char* endStr = str + strlen(str) - endLen;
+ return endStr >= str && strcmp(endStr, end) == 0;
+}
+
+static void skipSpace(char** linePtr) {
+ char* line = *linePtr;
+ while (isspace(line[0]))
+ line++;
+ *linePtr = line;
+}
+
+/*
+static void setTrimmed(string& str, char* loc, int len) {
+ char* start = loc;
+ skipSpace(&loc);
+ len -= loc - start;
+ while (len > 0 && isspace(loc[len - 1]))
+ len--;
+ str = string(loc, len);
+}
+*/
+
+static bool skipText(char** linePtr, const char* text) {
+ skipSpace(linePtr);
+ size_t length = strlen(text);
+ bool result = strncmp(*linePtr, text, length) == 0;
+ if (result)
+ *linePtr += length;
+ skipSpace(linePtr);
+ return result;
+}
+
+static bool isTokenChar(char ch) {
+ return isalnum(ch) || ch == '_';
+}
+
+struct Pair {
+ char* name;
+ int brace;
+};
+
+class Parse {
+public:
+ char* m_text;
+ bool m_inComment;
+ bool m_inFunction;
+ bool m_inFindFunctionType;
+ vector<Pair> m_classes;
+ vector<Pair> m_namespaces;
+ vector<Pair> m_preprocessorConditions;
+ string m_functionName;
+ string m_functionDeclaration;
+ string m_classDeclaration;
+ int m_braceLevel;
+ int m_functionBrace;
+
+ Parse(char* text) : m_text(text), m_inComment(false), m_inFunction(false), m_inFindFunctionType(false),
+ m_braceLevel(0), m_functionBrace(0) {}
+
+ int CheckForBrace()
+ {
+ int indent = 0;
+ // don't count braces in strings, chars, comments
+ do {
+ char* openBrace = strchr(m_text, '{');
+ char* closeBrace = strchr(m_text, '}');
+ if (openBrace == NULL && closeBrace == NULL)
+ break;
+ char* brace = openBrace == NULL ? closeBrace : closeBrace == NULL ? openBrace :
+ openBrace < closeBrace ? openBrace : closeBrace;
+ char* doubleQ = strchr(m_text, '"');
+ char* singleQ = strchr(m_text, '\'');
+ char* quote = doubleQ == NULL ? singleQ : singleQ == NULL ? doubleQ :
+ doubleQ < singleQ ? doubleQ : singleQ;
+ char quoteMark = quote == doubleQ ? '"' : '\'';
+ if (quote && quote < brace) {
+ myassert(quote[-1] != '\\');
+ do {
+ quote = strchr(quote + 1, quoteMark);
+ myassert(doubleQ);
+ } while (quote[-1] == '\\');
+ m_text = quote + 1;
+ continue;
+ }
+ indent += openBrace != NULL ? 1 : -1;
+ m_text = openBrace + 1;
+ } while (m_text[0] != '\0');
+ return indent;
+ }
+
+int ParseLine()
+{
+ size_t textLen = strlen(m_text);
+ char* lineStart = m_text;
+ char* commentStart;
+ if (m_text[0] == '\0')
+ goto nextLine;
+ if (m_inComment == false && m_text[0] == '/') {
+ m_inComment = m_text[1] == '*';
+ if (m_text[1] == '/' || m_text[1] == '*')
+ goto nextLine;
+ }
+ commentStart = m_text; // before anything else, turn embedded comments into their own lines
+ if (m_inComment == false && skipText(&commentStart, "//")) {
+ if (commentStart < lineStart + textLen)
+ commentStart[0] = '/';
+ else
+ commentStart[-1] = ' ';
+ commentStart -= 2;
+ commentStart[0] = '\0';
+ textLen = commentStart - lineStart;
+ goto nextLine;
+ }
+ if (m_inComment || skipText(&commentStart, "/*")) {
+ char* commentEnd = commentStart;
+ if (skipText(&commentEnd, "*/")) {
+ if (commentEnd < lineStart + textLen) {
+ commentEnd[-1] = '\0';
+ textLen = commentEnd - lineStart - 2;
+ }
+ if (m_inComment) {
+ m_inComment = false;
+ goto nextLine;
+ }
+ }
+ if (m_inComment)
+ goto nextLine;
+ memcpy(commentStart - 2, "\0/*", 3);
+ textLen = commentStart - lineStart - 2;
+ }
+ if (skipText(&m_text, "#include"))
+ goto nextLine;
+ if (skipText(&m_text, "#if") || skipText(&m_text, "#else")) {
+ Pair condition = { lineStart, m_braceLevel };
+ m_preprocessorConditions.push_back(condition);
+ goto nextLine;
+ }
+ {
+ bool is_endif = false;
+ if (skipText(&m_text, "#elif") || (is_endif = skipText(&m_text, "#endif")) != false) { // pop prior elif, if
+ char* lastText;
+ do {
+ int last = m_preprocessorConditions.size() - 1;
+ myassert(last >= 0);
+ lastText = m_preprocessorConditions[last].name;
+ m_preprocessorConditions.pop_back();
+ } while (is_endif && skipText(&lastText, "#else") == true);
+ goto nextLine;
+ }
+ }
+ if (skipText(&m_text, "namespace")) {
+ Pair space = { lineStart, m_braceLevel };
+ m_namespaces.push_back(space);
+ goto checkForBrace;
+ }
+ if (m_inFunction)
+ goto checkForBrace;
+ // detect functions by looking for token preceding open-paren.
+ if (m_inFindFunctionType == false) {
+ char* openParen = strchr(m_text, '(');
+ if (openParen) {
+ char* last = openParen;
+ while (last > m_text && isspace(last[-1]))
+ --last;
+ while (last > m_text && ((isTokenChar(last[-1]) || last[-1] == ':') && last[-2] == ':'))
+ --last;
+ myassert(isdigit(last[0]) == false);
+ if (isTokenChar(last[0])) {
+ m_inFindFunctionType = true;
+ m_functionName = string(last);
+ }
+ }
+ }
+ {
+ char* openBrace = strchr(m_text, '{');
+ char* semiColon = strchr(m_text, ';');
+ if (semiColon != NULL && semiColon < openBrace)
+ openBrace = NULL;
+ // functions are of the form: type (class::)*function(parameter-list) {
+ // all of which may be on separate lines
+ // so keep track of returntype, class, function, paramlist, openbrace separately
+ if (m_inFindFunctionType == true) { // look ahead to see which comes first, a semicolon or an open brace
+ if (openBrace) {
+ m_functionBrace = ++m_braceLevel;
+ m_inFunction = true;
+ m_inFindFunctionType = false;
+ m_text = openBrace + 1;
+ goto checkForBrace;
+ }
+ if (semiColon != NULL) { // a function declaration
+ m_inFindFunctionType = false;
+ m_functionDeclaration = m_functionName;
+ m_functionName.erase(0, m_functionName.length());
+ } else
+ goto nextLine;
+ }
+ // FIXME what if class line has neither brace nor semi?
+ if (skipText(&m_text, "class")) {
+ if (openBrace > m_text) {
+ Pair _class = { lineStart, m_braceLevel };
+ m_classes.push_back(_class);
+ } else if (semiColon != NULL) {
+ m_classDeclaration = lineStart; // !!! FIXME should have function form as above
+ }
+ }
+ }
+checkForBrace:
+ m_braceLevel += CheckForBrace();
+ if (m_functionBrace > 0 && m_braceLevel <= m_functionBrace) {
+ m_functionName.erase(0, m_functionName.length());
+ m_functionBrace = 0;
+ }
+nextLine:
+ return textLen;
+}
+
+};
+
+char* const GetAndroidDiffs(const char* dir, const char* filename)
+{
+ char scratch[2048];
+ string diffsFile = ScratchFile(__FUNCTION__);
+ sprintf(scratch, "diff \"%s/%s/%s\" \"%s/%s/%s\" > %s", sandboxBase, dir,
+ filename, oldBase, dir, filename, diffsFile.c_str());
+ int err = system(scratch);
+ myassert(err == 0 || err == 256);
+ char* const diffs = GetFile(diffsFile);
+ return diffs;
+}
+
+void CheckForExec(const char* base1, const char* dir1, const char* file1,
+ const char* base2, const char* dir2, const char* file2, bool* ex1, bool* ex2)
+{
+ size_t file1Len = strlen(file1);
+ size_t file2Len = strlen(file2);
+ bool file1Ex = file1[file1Len - 1] == '*';
+ bool file2Ex = file2[file2Len - 1] == '*';
+ if (file1Ex != file2Ex) {
+ fprintf(stderr, "warning: %s/%s/%s has %sexec bit set while"
+ " %s/%s/%s has %sexec bit set\n",
+ base1, dir1, file1, file1Ex ? "" : "no ",
+ base2, dir2, file2, file2Ex ? "" : "no ");
+ }
+ if (ex1) *ex1 = file1Ex;
+ if (ex2) *ex2 = file2Ex;
+}
+
+bool CompareFiles(const char* base1, const char* dir1, const char* file1,
+ const char* base2, const char* dir2, const char* file2)
+{
+ char scratch[2048];
+ bool file1Ex, file2Ex;
+ string compareFileStr = ScratchFile(__FUNCTION__);
+ CheckForExec(base1, dir1, file1, base2, dir2, file2, &file1Ex, &file2Ex);
+ sprintf(scratch, "diff --brief \"%s/%s/%.*s\" \"%s/%s/%.*s\" > %s",
+ base1, dir1, (int) strlen(file1) - (int) file1Ex, file1,
+ base2, dir2, (int) strlen(file2) - (int) file2Ex, file2,
+ compareFileStr.c_str());
+ int err = system(scratch);
+ myassert(err == 0 || err == 256);
+ char* scratchText = GetFile(compareFileStr);
+ size_t len = strlen(scratchText);
+ delete[] scratchText;
+ return len > 0;
+}
+
+bool CompareFiles(const char* base1, const char* base2, const char* dir, const char* file)
+{
+ return CompareFiles(base1, dir, file, base2, dir, file);
+}
+
+int Compare(char* one, size_t len1, char* two, size_t len2)
+{
+ char* o_end = one + len1;
+ char* t_end = two + len2;
+ do {
+ if (one == o_end)
+ return two == t_end ? 0 : 1;
+ if (two == t_end)
+ return -1;
+ char o = *one++;
+ char t = *two++;
+ if (o == t)
+ continue;
+ if (o == '/')
+ return -1;
+ if (t == '/')
+ return 1;
+ return o < t ? -1 : 1;
+ } while (true);
+ myassert(0);
+ return 0;
+}
+
+string Find(const char* oldList)
+{
+ string result;
+ char scratch[2048];
+ // look in WebCore and JavaScriptCore
+ string findWebCore = ScratchFile("FindWebCore");
+ sprintf(scratch, "cd %s%s ; find . -name \"%s\" > %s",
+ newBase, "/WebCore", oldList, findWebCore.c_str());
+ int err = system(scratch);
+ myassert(err == 0 || err == 256);
+ int webCount;
+ char* foundInWebCore = GetFile(findWebCore, NULL, &webCount);
+ char* originalFoundInWebCore = foundInWebCore;
+ string findJavaScriptCore = ScratchFile("FindJavaScriptCore");
+ sprintf(scratch, "cd %s%s ; find . -name \"%s\" > %s",
+ newBase, "/JavaScriptCore", oldList, findJavaScriptCore.c_str());
+ err = system(scratch);
+ myassert(err == 0 || err == 256);
+ int javaScriptCount;
+ char* foundInJavaScriptCore = GetFile(findJavaScriptCore, NULL, &javaScriptCount);
+ char* originalFoundInJavaScriptCore = foundInJavaScriptCore;
+ if (webCount == 1 && javaScriptCount == 0) {
+ result = "WebCore/" + string(&foundInWebCore[2]);
+ } else if (webCount == 0 && javaScriptCount == 1) {
+ result = "JavaScriptCore/" + string(&foundInJavaScriptCore[2]);
+ } else if (webCount == 1 && javaScriptCount == 1 &&
+ strncmp(&foundInWebCore[2], "ForwardingHeaders/", 18) == 0) {
+ result = "JavaScriptCore/" + string(&foundInJavaScriptCore[2]);
+ } else if (webCount == 1 && javaScriptCount == 1 &&
+ strncmp(&foundInJavaScriptCore[2], "API/tests/", 10) == 0) {
+ result = "JavaScriptCore/" + string(&foundInJavaScriptCore[2]);
+ } else if (webCount + javaScriptCount > 0) {
+ fprintf(stderr, "deleted file \"%s\" has more than one possible rename:\n", oldList);
+ int index;
+ for (index = 0; index < webCount; index++) {
+ fprintf(stderr, "WebCore/%s\n", &foundInWebCore[2]);
+ foundInWebCore += strlen(foundInWebCore) + 1;
+ }
+ for (index = 0; index < javaScriptCount; index++) {
+ fprintf(stderr, "JavaScriptCore/%s\n", &foundInJavaScriptCore[2]);
+ foundInJavaScriptCore += strlen(foundInJavaScriptCore) + 1;
+ }
+ }
+ delete[] originalFoundInWebCore;
+ delete[] originalFoundInJavaScriptCore;
+ return result;
+}
+
+char* GetMakeAndExceptions(const char* dir, const char* filename, size_t* makeSize,
+ string* excludedFilesPtr, string* excludedGeneratedPtr,
+ string* excludedDirsPtr, string* androidFilesPtr,
+ char** startPtr, char** localStartPtr)
+{
+ char scratch[1024];
+ sprintf(scratch, "%s/%s/%s", sandboxBase, dir, filename);
+ char* makeFile = GetFile(scratch, makeSize);
+ char* start = makeFile;
+ do { // find first filename in makefile
+ if (strncmp(start, "# LOCAL_SRC_FILES_EXCLUDED := \\", 30) == 0)
+ break;
+ start += strlen(start) + 1;
+ } while (start < makeFile + *makeSize);
+ myassert(start[0] != '\0');
+ start += strlen(start) + 1;
+ // construct one very large regular expression that looks like:
+ // echo '%s' | grep -v -E 'DerivedSources.cpp|WebCorePrefix.cpp...'
+ // to filter out matches that aren't allowed
+ // wildcards '*' in the original need to be expanded to '.*'
+ string excludedFiles = "grep -v -E '";
+ while (strncmp(start, "#\t", 2) == 0) {
+ start += 2;
+ char ch;
+ while ((ch = *start++) != ' ') {
+ if (ch == '*')
+ excludedFiles += '.';
+ else if (ch == '.')
+ excludedFiles += '\\';
+ excludedFiles += ch;
+ }
+ excludedFiles += "|";
+ myassert(*start == '\\');
+ start += 2;
+ }
+ excludedFiles[excludedFiles.size() - 1] = '\'';
+ *excludedFilesPtr = excludedFiles;
+ do {
+ if (strncmp(start, "# LOCAL_GENERATED_FILES_EXCLUDED := \\", 37) == 0 ||
+ strncmp(start, "# LOCAL_DIR_WILDCARD_EXCLUDED := \\", 34) == 0)
+ break;
+ start += strlen(start) + 1;
+ } while (start < makeFile + *makeSize);
+ if (strncmp(start, "# LOCAL_GENERATED_FILES_EXCLUDED := \\", 37) == 0) {
+ string excludedGenerated = "grep -v -E '";
+ start += strlen(start) + 1;
+ while (strncmp(start, "#\t", 2) == 0) {
+ start += 2;
+ char ch;
+ while ((ch = *start++) != ' ') {
+ if (ch == '*')
+ excludedGenerated += '.';
+ else if (ch == '.')
+ excludedGenerated += '\\';
+ excludedGenerated += ch;
+ }
+ excludedGenerated += "|";
+ myassert(*start == '\\');
+ start += 2;
+ }
+ myassert(excludedGeneratedPtr);
+ excludedGenerated[excludedGenerated.size() - 1] = '\'';
+ *excludedGeneratedPtr = excludedGenerated;
+ }
+ do { // find first filename in makefile
+ if (strncmp(start, "# LOCAL_DIR_WILDCARD_EXCLUDED := \\", 34) == 0)
+ break;
+ start += strlen(start) + 1;
+ } while (start < makeFile + *makeSize);
+ if (start[0] != '\0') {
+ string excludedDirs = "-e '/\\.vcproj\\// d' -e '/\\.svn\\// d' ";
+ do {
+ start += strlen(start) + 1;
+ char* exceptionDirStart = start;
+ if (strncmp(exceptionDirStart, "#\t", 2) != 0) {
+ myassert(exceptionDirStart[0] == '\0');
+ break;
+ }
+ exceptionDirStart += 2;
+ char* exceptionDirEnd = exceptionDirStart;
+ do {
+ exceptionDirEnd = strchr(exceptionDirEnd, '\\');
+ } while (exceptionDirEnd && *++exceptionDirEnd == '/');
+ myassert(exceptionDirEnd);
+ --exceptionDirEnd;
+ myassert(exceptionDirEnd[-1] == ' ');
+ myassert(exceptionDirEnd[-2] == '*');
+ myassert(exceptionDirEnd[-3] == '/');
+ exceptionDirEnd[-3] = '\0';
+ excludedDirs += "-e '/";
+ if (exceptionDirStart[0] == '/')
+ excludedDirs += "\\";
+ excludedDirs += exceptionDirStart;
+ excludedDirs += "\\// d' ";
+ start = exceptionDirEnd;
+ } while (true);
+ *excludedDirsPtr = excludedDirs;
+ }
+ *startPtr = start;
+ // optionally look for android-specific files
+ char* makeEnd = makeFile + *makeSize;
+ do { // find first filename in makefile
+ if (strcmp(start, "# LOCAL_ANDROID_SRC_FILES_INCLUDED := \\") == 0)
+ break;
+ } while ((start += strlen(start) + 1), start < makeEnd);
+ if (start >= makeEnd)
+ return makeFile;
+ start += strlen(start) + 1;
+ string androidFiles = "grep -v -E '";
+ do {
+ myassert(strncmp(start, "#\t", 2) == 0);
+ start += 2;
+ char ch;
+ bool isIdl = strstr(start, "idl \\") != 0;
+ char* lastSlash = strrchr(start, '/') + 1;
+ while ((ch = *start++) != ' ') {
+ if (ch == '*')
+ androidFiles += '.';
+ else if (ch == '.')
+ androidFiles += '\\';
+ androidFiles += ch;
+ if (!isIdl)
+ continue;
+ if (ch == '/' && start == lastSlash)
+ androidFiles += "JS";
+ if (ch == '.') {
+ myassert(strcmp(start, "idl \\") == 0);
+ start += 4;
+ androidFiles += 'h';
+ break;
+ }
+ }
+ androidFiles += "|";
+ myassert(*start == '\\');
+ start += 2;
+ } while (start[0] == '#');
+ androidFiles[androidFiles.size() - 1] = '\'';
+ *androidFilesPtr = androidFiles;
+ return makeFile;
+}
+
+vector<char*> GetDerivedSourcesMake(const char* dir)
+{
+ vector<char*> result;
+ char scratch[1024];
+ sprintf(scratch, "%s/%s/%s", newBase, dir, "DerivedSources.make");
+ size_t fileSize;
+ char* file = GetFile(scratch, &fileSize);
+ char* fileEnd = file + fileSize;
+ myassert(file);
+ size_t len;
+ do { // find first filename in makefile
+ len = strlen(file);
+ if (strcmp(file, "all : \\") == 0)
+ break;
+ file += len + 1;
+ } while (file < fileEnd);
+ myassert(strcmp(file, "all : \\") == 0);
+ file += len + 1;
+ while (file[0] != '#') {
+ len = strlen(file);
+ char* st = file;
+ skipSpace(&st);
+ if (st[0] != '\\' && st[0] != '$')
+ result.push_back(st);
+ file += len + 1;
+ }
+ return result;
+}
+
+bool MarkDerivedFound(vector<char*>& derived, char* check, size_t len)
+{
+ bool found = false;
+ for (unsigned index = 0; index < derived.size(); index++) {
+ char* der = derived[index];
+ if (strncmp(der, check, len) == 0) {
+ der[0] = '\0';
+ found = true;
+ }
+ }
+ return found;
+}
+
+void UpdateDerivedMake()
+{
+ const char* dir = "WebCore";
+ int err;
+ vector<char*> derived = GetDerivedSourcesMake(dir);
+ size_t makeSize;
+ char* start, * localStart;
+ string excludedDirs, excludedFiles, excludedGenerated, androidFiles;
+ char* makeFile = GetMakeAndExceptions(dir, "Android.derived.mk", &makeSize,
+ &excludedFiles, &excludedGenerated, &excludedDirs, &androidFiles,
+ &start, &localStart);
+ if (options.emitPerforceCommands)
+ fprintf(commandFile, "p4 edit %s/%s/%s\n", sandboxCmd, dir, "Android.derived.mk");
+ fprintf(commandFile, "cat %s/%s/%s | sed \\\n", sandboxCmd, dir, "Android.derived.mk");
+ string updateDerivedMake = ScratchFile(__FUNCTION__);
+ string filelist = string("cd ") + newBase + "/" + dir +
+ " ; find . -name '*.idl' | " + excludedFiles +
+ " | sed -e 's/.\\///' " + excludedDirs +
+ " | sed 's@\\(.*\\)/\\(.*\\)\\.idl@ $(intermediates)/\\1/JS\\2.h@' "
+ " | sort -o " + updateDerivedMake;
+ err = system(filelist.c_str());
+ myassert(err == 0 || err == 256);
+ char* bindings = GetFile(updateDerivedMake);
+ bool inGen = false;
+ char* fileEnd = makeFile + makeSize;
+ char* nextStart;
+ do {
+ size_t startLen = strlen(start);
+ nextStart = start + startLen + 1;
+ bool onGen = false;
+ char* st = start;
+ if (inGen == false) {
+ if (strncmp(st, "GEN", 3) != 0)
+ continue;
+ st += 3;
+ skipSpace(&st);
+ if (strncmp(st, ":=", 2) != 0)
+ continue;
+ st += 2;
+ onGen = true;
+ }
+ skipSpace(&st);
+ inGen = start[startLen - 1] == '\\';
+ if (inGen) {
+ if (st[0] == '\\' && st[1] == '\0')
+ continue;
+ if (strcmp(st, "$(addprefix $(intermediates)/, \\") == 0)
+ continue;
+ } else if (st[0] == ')' && st[1] == '\0')
+ continue;
+ static const char bindHead[] = "bindings/js/";
+ const size_t bindLen = sizeof(bindHead) - 1;
+ string escaped;
+ if (strncmp(st, bindHead, bindLen) == 0) {
+ st += bindLen;
+ if (MarkDerivedFound(derived, st, strlen(st)) == false) {
+ fprintf(stderr, "*** webkit removed js binding: %s"
+ " (must be removed manually)\n", st);
+ escaped = SedEscape(st);
+ fprintf(commandFile, "-e '/%s/ d' ", escaped.c_str());
+ }
+ continue;
+ }
+ myassert(strncmp(st, "$(intermediates)", 16) == 0);
+ if (onGen && inGen == false) { // no continuation
+ char* lastSlash;
+ myassert(strrchr(st, '/') != NULL);
+ while ((lastSlash = strrchr(st, '/')) != NULL) {
+ char* lastEnd = strchr(lastSlash, ' ');
+ if (lastEnd == NULL)
+ lastEnd = lastSlash + strlen(lastSlash);
+ myassert(lastSlash != 0);
+ lastSlash++;
+ size_t lastLen = lastEnd - lastSlash;
+ if (MarkDerivedFound(derived, lastSlash, lastLen) == false) {
+ fprintf(stderr, "*** webkit removed generated file:"
+ " %.*s (must be removed manually)\n", (int) lastLen,
+ lastSlash);
+ // escaped = SedEscape(st);
+ // fprintf(commandFile, "-e '/%s/ d' \\\n", escaped.c_str());
+ }
+ char* priorDollar = strrchr(st, '$');
+ myassert(priorDollar != NULL);
+ char* nextDollar = strchr(st, '$');
+ if (nextDollar == priorDollar)
+ break;
+ priorDollar[0] = '\0';
+ }
+ continue;
+ }
+ char* nextSt = nextStart;
+ skipSpace(&nextSt);
+ myassert(strncmp(nextSt, "$(intermediates)", 16) != 0 || strcmp(st, nextSt) < 0);
+ // do {
+ char* bind = bindings;
+ myassert(bind);
+ skipSpace(&bind);
+ int compare = strncmp(bind, st, strlen(bind) - 2);
+ if (compare < 0) { // add a file
+ escaped = SedEscape(st);
+ char* filename = strrchr(bindings, '/');
+ myassert(filename);
+ filename += 3;
+ // FIX ME: exclude items in DerivedSources.make all : $(filter-out ...
+ char* bi = bindings;
+ skipSpace(&bi);
+ char* bindName = strrchr(bi, '/');
+ myassert(bindName != NULL);
+ bindName++;
+ string biStr = SedEscape(bi);
+ fprintf(commandFile, "-e '/%s/ i\\\n_TAB_%s \\\\\n' ",
+ escaped.c_str(), biStr.c_str());
+ MarkDerivedFound(derived, bindName, strlen(bindName));
+ nextStart = start;
+ bindings += strlen(bindings) + 1;
+ inGen = true;
+ } else if (compare > 0) {
+ // if file to be deleted is locally added by android, leave it alone
+ myassert(strncmp(st, "$(intermediates)/", 17) == 0);
+ string subst = string(st).substr(17, strlen(st) - 17 - (inGen ? 2 : 0));
+ string localDerivedStr = ScratchFile("LocalDerived");
+ string filter = string("echo '") + subst + "' | " + androidFiles +
+ " > " + localDerivedStr;
+ if (options.debug)
+ fprintf(stderr, "LocalDerived.txt : %s\n", filter.c_str());
+ err = system(filter.c_str());
+ myassert(err == 0 || err == 256);
+ char* localDerived = GetFile(localDerivedStr);
+ if (localDerived[0] != '\0') {
+ escaped = SedEscape(st);
+ fprintf(commandFile, "-e '/%s/ d' ", escaped.c_str());
+ }
+ } else {
+ char* stName = strrchr(st, '/');
+ myassert(stName);
+ stName++;
+ MarkDerivedFound(derived, stName, strlen(stName));
+ bindings += strlen(bindings) + 1;
+ }
+ // } while (strstr(start, "$(intermediates)") != NULL);
+ // if changing directories, add any new files to the end of this directory first
+ if (bindings[0] != '\0' && strstr(nextStart, "$(intermediates)") == NULL) {
+ st = start;
+ skipSpace(&st);
+ escaped = SedEscape(st);
+ st = strchr(st, '/');
+ char* stDirEnd = strchr(st + 1, '/');
+ do {
+ bind = strchr(bindings, '/');
+ if (!bind)
+ break;
+ char* bindEnd = strchr(bind + 1, '/');
+ if (!bindEnd)
+ break;
+ if (bindEnd - bind != stDirEnd - st)
+ break;
+ if (strncmp(st, bind, stDirEnd - st) != 0)
+ break;
+ if (inGen == false)
+ fprintf(commandFile, "-e '/%s/ s/$/ \\\\/' ", escaped.c_str());
+ char* bi = bindings;
+ skipSpace(&bi);
+ string biStr = SedEscape(bi);
+ fprintf(commandFile, "-e '/%s/ a\\\n_TAB_%s\n' ",
+ escaped.c_str(), biStr.c_str());
+ MarkDerivedFound(derived, bindEnd + 1, strlen(bindEnd + 1));
+ escaped = biStr;
+ inGen = false;
+ bindings += strlen(bindings) + 1;
+ } while (true);
+ }
+ } while (start = nextStart, start < fileEnd);
+ for (unsigned index = 0; index < derived.size(); index++) {
+ char* der = derived[index];
+ if (der[0] == '\0')
+ continue;
+ string excludedGeneratedStr = ScratchFile("ExcludedGenerated");
+ string filter = string("echo '") + der + "' | " + excludedGenerated +
+ " > " + excludedGeneratedStr;
+ err = system(filter.c_str());
+ myassert(err == 0 || err == 256);
+ char* excluded = GetFile(excludedGeneratedStr);
+ if (excluded[0] != '\0')
+ fprintf(stderr, "*** missing rule to generate %s\n", der);
+ }
+ fprintf(commandFile, " | sed 's/^_TAB_/\t/' > %s/%s/%s\n", sandboxCmd, dir, "xAndroid.derived.mk");
+ fprintf(commandFile, "mv %s/%s/%s %s/%s/%s\n",
+ sandboxCmd, dir, "xAndroid.derived.mk", sandboxCmd, dir, "Android.derived.mk");
+ if (options.emitGitCommands)
+ fprintf(commandFile, "git add %s/%s\n", dir, "Android.derived.mk");
+}
+
+int MatchLen(const char* one, const char* two, size_t len)
+{
+ bool svgIn1 = strstr(one, "svg") || strstr(one, "SVG");
+ bool svgIn2 = strstr(two, "svg") || strstr(two, "SVG");
+ if (svgIn1 != svgIn2)
+ return 0;
+ int signedLen = (int) len;
+ int original = signedLen;
+ while (*one++ == *two++ && --signedLen >= 0)
+ ;
+ return original - signedLen;
+}
+
+// create the list of sed commands to update the WebCore Make file
+void UpdateMake(const char* dir)
+{
+ // read in the makefile
+ size_t makeSize;
+ char* start, * localStart = NULL;
+ string excludedDirs, excludedFiles, androidFiles;
+ char* makeFile = GetMakeAndExceptions(dir, "Android.mk", &makeSize,
+ &excludedFiles, NULL, &excludedDirs, &androidFiles, &start, &localStart);
+ char* lastFileName = NULL;
+ size_t lastFileNameLen = 0;
+ int lastLineNumber = -1;
+ // get the actual list of files
+ string updateMakeStr = ScratchFile(__FUNCTION__);
+ string filelist = string("cd ") + newBase + "/" + dir + " ;"
+ " find . -name '*.cpp' -or -name '*.c' -or -name '*.y' | " +
+ excludedFiles + " | sed -e 's/.\\///' " + excludedDirs +
+ " | sort -o " + updateMakeStr;
+ if (options.debug)
+ fprintf(stderr, "make %s/%s filter: %s\n", dir, "Android.mk", filelist.c_str());
+ int err = system(filelist.c_str());
+ myassert(err == 0 || err == 256);
+ char* newList = GetFile(updateMakeStr);
+ do { // find first filename in makefile
+ if (strncmp(start, "LOCAL_SRC_FILES := \\", 20) == 0)
+ break;
+ start += strlen(start) + 1;
+ } while (start < makeFile + makeSize);
+ myassert(start[0] != '\0');
+ if (options.emitPerforceCommands)
+ fprintf(commandFile, "p4 edit %s/%s/%s\n", sandboxCmd, dir, "Android.mk");
+ fprintf(commandFile, "cat %s/%s/%s | sed ", sandboxCmd, dir, "Android.mk");
+ int lineNumber = 0;
+ do {
+ start += strlen(start) + 1;
+ lineNumber++;
+ if (start - makeFile >= makeSize || start[0] == '$')
+ break;
+ if (start[0] == '\0' || !isspace(start[0]))
+ continue;
+ skipSpace(&start);
+ if (start[0] == '\0' || start[0] == '\\')
+ continue;
+ size_t startLen = strlen(start);
+ if (start[startLen - 1] == '\\')
+ --startLen;
+ while (isspace(start[startLen - 1]))
+ --startLen;
+ size_t newListLen = strlen(newList);
+ if (lastFileName != NULL) {
+ myassert(strncmp(start, lastFileName, startLen) > 0 ||
+ startLen > lastFileNameLen);
+ }
+ if (strstr(start, "android") != NULL || strstr(start, "Android") != NULL) {
+ if (startLen == newListLen && strncmp(newList, start, startLen) == 0)
+ newList += newListLen + 1;
+ lastFileName = start;
+ lastFileNameLen = startLen;
+ lastLineNumber = lineNumber;
+ continue;
+ }
+ int compare;
+ bool backslash = lastFileName &&
+ lastFileName[strlen(lastFileName) - 1] == '\\';
+ do {
+ compare = strncmp(newList, start, startLen);
+ if (compare == 0 && startLen != newListLen)
+ compare = newListLen < startLen ? -1 : 1;
+ if (newList[0] == '\0' || compare >= 0)
+ break;
+ // add a file
+ if (lastFileName && lineNumber - lastLineNumber > 1 &&
+ MatchLen(lastFileName, newList, lastFileNameLen) >
+ MatchLen(start, newList, startLen)) {
+ string escaped = SedEscape(lastFileName);
+ if (!backslash)
+ fprintf(commandFile, "-e '/%s/ s/$/ \\\\/' ", escaped.c_str());
+ fprintf(commandFile, "-e '/%s/ a\\\n_TAB_%s%s\n' ",
+ SedEscape(lastFileName).c_str(), newList,
+ backslash ? " \\\\" : "");
+ lastFileName = newList;
+ lastFileNameLen = newListLen;
+ } else {
+ fprintf(commandFile, "-e '/%s/ i\\\n_TAB_%s \\\\\n' ",
+ SedEscape(start).c_str(), newList);
+ }
+ newList += newListLen + 1;
+ newListLen = strlen(newList);
+ } while (true);
+ if (newList[0] == '\0' || compare > 0) {
+ // don't delete files added by Android
+ string localMakeStr = ScratchFile("LocalMake");
+ string filter = "echo '" + string(start).substr(0, startLen) +
+ "' | " + androidFiles + " > " + localMakeStr;
+ int err = system(filter.c_str());
+ myassert(err == 0 || err == 256);
+ char* localMake = GetFile(localMakeStr);
+ if (localMake[0] != '\0') {
+ string escaped = SedEscape(start);
+ fprintf(commandFile, "-e '/%s/ d' ", escaped.c_str());
+ }
+ } else
+ newList += newListLen + 1;
+ lastFileName = start;
+ lastFileNameLen = startLen;
+ lastLineNumber = lineNumber;
+ } while (true);
+ fprintf(commandFile, " | sed 's/^_TAB_/\t/' > %s/%s/%s\n", sandboxCmd, dir, "xAndroid.mk");
+ fprintf(commandFile, "mv %s/%s/%s %s/%s/%s\n",
+ sandboxCmd, dir, "xAndroid.mk", sandboxCmd, dir, "Android.mk");
+ if (options.emitGitCommands)
+ fprintf(commandFile, "git add %s/%s\n", dir, "Android.mk");
+}
+
+static bool emptyDirectory(const char* base, const char* work, const char* dir) {
+ string findEmptyStr = "find \"";
+ string emptyDirStr = ScratchFile("emptyDirectory");
+ if (base[0] != '\0')
+ findEmptyStr += string(base) + "/" + work + "/" + dir + "\"";
+ else
+ findEmptyStr += string(work) + "/" + dir + "\"";
+ findEmptyStr += " -type f -print > " + emptyDirStr;
+ int err = system(findEmptyStr.c_str());
+ if (err != 0)
+ return true;
+ FILE* file = fopen(emptyDirStr.c_str(), "r");
+ if (file == NULL)
+ {
+ fprintf(stderr, "can't read %s\n", emptyDirStr.c_str());
+ myassert(0);
+ return true;
+ }
+ fseek(file, 0, SEEK_END);
+ size_t size = ftell(file);
+ fclose(file);
+ return size == 0;
+}
+
+static bool emptyDirectory(const char* work, const char* dir) {
+ return emptyDirectory("", work, dir);
+}
+
+void CompareDirs(const char* workingDir, bool renamePass)
+{
+ map<string, string> renameMap;
+ char* oldList = List(oldBase, "old", workingDir);
+ char* newList = List(newBase, "new", workingDir);
+ char* sandList = List(sandboxBase, "sandbox", workingDir);
+ char* oldMem = oldList;
+ char* newMem = newList;
+ char* sandboxMem = sandList;
+ // identify files to be added, removed by comparing old, new lists
+ do {
+ size_t oldLen = strlen(oldList);
+ size_t newLen = strlen(newList);
+ size_t sandLen = strlen(sandList);
+ if (oldLen == 0 && newLen == 0 && sandLen == 0)
+ break;
+ bool oldDir = false;
+ bool oldExecutable = false;
+ if (oldLen > 0) {
+ char last = oldList[oldLen - 1];
+ oldDir = last == '/';
+ oldExecutable = last == '*';
+ if (oldDir || oldExecutable)
+ --oldLen;
+ }
+ bool newDir = false;
+ bool newExecutable = false;
+ if (newLen > 0) {
+ char last = newList[newLen - 1];
+ newDir = last == '/';
+ newExecutable = last == '*';
+ if (newDir || newExecutable)
+ --newLen;
+ }
+ bool sandDir = false;
+ bool sandExecutable = false;
+ if (sandLen > 0) {
+ char last = sandList[sandLen - 1];
+ sandDir = last == '/';
+ sandExecutable = last == '*';
+ if (sandDir || sandExecutable)
+ --sandLen;
+ }
+ string oldFileStr = string(oldList).substr(0, oldLen);
+ const char* oldFile = oldFileStr.c_str();
+ string newFileStr = string(newList).substr(0, newLen);
+ const char* newFile = newFileStr.c_str();
+ string sandFileStr = string(sandList).substr(0, sandLen);
+ const char* sandFile = sandFileStr.c_str();
+ int order = Compare(oldList, oldLen, newList, newLen);
+ int sandOrder = 0;
+ if ((oldLen > 0 || sandLen > 0) && order <= 0) {
+ sandOrder = Compare(sandList, sandLen, oldList, oldLen);
+ if (sandOrder > 0 && renamePass == false)
+ fprintf(stderr, "error: file in old webkit missing from sandbox: %s/%s\n",
+ workingDir, oldFile);
+ if (sandOrder < 0 && renamePass == false) {
+ // file added by android -- should always have name 'android?'
+ const char* android = strstr(sandFile, "ndroid");
+ if (android == NULL)
+ fprintf(stderr, "warning: expect added %s to contain 'android': %s/%s\n",
+ sandDir ? "directory" : "file" , workingDir, sandFile);
+ }
+ if (sandOrder == 0) {
+ myassert(oldDir == sandDir);
+ if (oldExecutable != sandExecutable)
+ CheckForExec(oldBase, workingDir, oldList,
+ sandboxBase, workingDir, sandList, 0, 0);
+ }
+ if (sandOrder <= 0)
+ sandList += strlen(sandList) + 1;
+ if (sandOrder < 0)
+ continue;
+ }
+ if (order < 0) { // file in old list is not in new
+ // check to see if file is read only ; if so, call p4 delete -- otherwise, just call delete
+ if (oldDir == false) {
+ bool modifiedFile = false;
+ // check to see if android modified deleted file
+ if (sandOrder == 0) {
+ string rename(workingDir);
+ rename.append("/");
+ rename.append(oldFile);
+ if (renamePass) {
+ string newName = Find(oldFile);
+ if (newName.length() > 0) {
+ map<string, string>::iterator iter = renameMap.find(rename);
+ myassert(iter == renameMap.end()); // if I see the same file twice, must be a bug
+ renameMap[rename] = newName;
+ myassert(rename != newName);
+ if (options.debug)
+ fprintf(stderr, "map %s to %s\n", rename.c_str(), newName.c_str());
+ }
+ }
+ if (renamePass == false) {
+ bool oldSandboxDiff = CompareFiles(oldBase, sandboxBase, workingDir, oldList);
+ const char* renamedDir = workingDir;
+ map<string, string>::iterator iter = renameMap.find(rename);
+ if (iter != renameMap.end()) {
+ string newName = renameMap[rename];
+ renamedDir = newName.c_str();
+ char* renamed = (char*) strrchr(renamedDir, '/');
+ *renamed++ = '\0'; // splits rename into two strings
+ if (options.emitPerforceCommands) {
+ fprintf(commandFile, "p4 integrate \"%s/%s/%s\" \"%s/%s/%s\"\n", sandboxCmd, workingDir, oldFile,
+ sandboxCmd, renamedDir, renamed);
+ fprintf(commandFile, "p4 resolve \"%s/%s/%s\"\n", sandboxCmd, renamedDir, renamed);
+ } else if (options.emitGitCommands) {
+ fprintf(commandFile, "git mv \"%s/%s\" \"%s/%s\"\n", workingDir, oldFile,
+ renamedDir, renamed);
+ }
+ if (oldSandboxDiff) {
+ if (options.emitPerforceCommands)
+ fprintf(commandFile, "p4 open \"%s/%s/%s\"\n", sandboxCmd, renamedDir, renamed);
+ fprintf(commandFile, "merge -q \"%s/%s/%s\" \"%s/%s/%s\" \"%s/%s/%s\"\n",
+ sandboxCmd, renamedDir, renamed, oldCmd, workingDir, oldFile, newCmd, renamedDir, renamed);
+ bool success = Merge(workingDir, oldFile, renamedDir, renamed, "/dev/null");
+ if (success == false) {
+ fprintf(stderr, "*** Manual merge required: %s/%s\n", renamedDir, renamed);
+ fprintf(commandFile, "cat \"%s/%s/%s\" | sed -e 's/^<<<<<<<.*$/#ifdef MANUAL_MERGE_REQUIRED/' "
+ "-e 's/^=======$/#else \\/\\/ MANUAL_MERGE_REQUIRED/' "
+ "-e 's/^>>>>>>>.*$/#endif \\/\\/ MANUAL_MERGE_REQUIRED/' > \"%s/%s/x%s\"\n",
+ sandboxCmd, renamedDir, renamed, sandboxCmd, renamedDir, renamed);
+ fprintf(commandFile, "mv \"%s/%s/x%s\" \"%s/%s/%s\"\n",
+ sandboxCmd, renamedDir, renamed, sandboxCmd, renamedDir, renamed);
+ }
+ if (options.emitGitCommands)
+ fprintf(commandFile, "git add \"%s/%s\"\n", renamedDir, renamed);
+ } else {
+ bool oldNewDiff = CompareFiles(oldBase, workingDir, oldList, newBase, renamedDir, renamed);
+ if (oldNewDiff) {
+ if (options.emitPerforceCommands)
+ fprintf(oopsFile, "p4 open \"%s/%s/%s\"\n", sandboxCmd, renamedDir, renamed);
+ fprintf(oopsFile, "cp \"%s/%s/%s\" \"%s/%s/%s\"\n",
+ newCmd, renamedDir, renamed, sandboxCmd, renamedDir, renamed);
+ if (options.emitGitCommands)
+ fprintf(oopsFile, "git add \"%s/%s\"\n", renamedDir, renamed);
+ }
+ }
+ } else if (oldSandboxDiff) {
+ modifiedFile = true;
+ fprintf(stderr, "*** Modified file deleted: %s/%s\n", workingDir, oldFile);
+// FindDeletedAndroidChanges(workingDir, oldFile);
+ }
+ } // if renamePass == false
+ } // if sandOrder == 0
+ if (modifiedFile) {
+ fprintf(commandFile, "cat \"%s/%s/%s\" | sed -e '1 i\\\n#ifdef MANUAL_MERGE_REQUIRED\n' "
+ "-e '$ a\\\n#endif \\/\\/ MANUAL_MERGE_REQUIRED\n' > \"%s/%s/x%s\"\n",
+ sandboxCmd, workingDir, oldFile, sandboxCmd, workingDir, oldFile);
+ fprintf(commandFile, "mv \"%s/%s/x%s\" \"%s/%s/%s\"\n",
+ sandboxCmd, workingDir, oldFile, sandboxCmd, workingDir, oldFile);
+ } else if (options.emitPerforceCommands)
+ fprintf(commandFile, "p4 delete \"%s/%s/%s\"\n", sandboxCmd, workingDir, oldFile);
+ else if (options.emitGitCommands)
+ fprintf(commandFile, "git rm \"%s/%s\"\n", workingDir, oldFile);
+ else
+ fprintf(commandFile, "rm \"%s/%s/%s\"\n", sandboxCmd, workingDir, oldFile);
+ } else { // if oldDir != false
+ // !!! FIXME start here;
+ // check to see if old directory is empty ... (e.g., WebCore/doc)
+ // ... and/or isn't in sandbox anyway (e.g., WebCore/LayoutTests)
+ // if old directory is in sandbox (e.g. WebCore/kcanvas) that should work
+ if (options.emitPerforceCommands)
+ fprintf(commandFile, "p4 delete \"%s/%s/%s/...\"\n", sandboxCmd, workingDir, oldFile);
+ else if (options.emitGitCommands)
+ fprintf(commandFile, "git rm \"%s/%s/...\"\n", workingDir, oldFile);
+ else
+ fprintf(commandFile, "rm \"%s/%s/%s/...\"\n", sandboxCmd, workingDir, oldFile);
+ if (renamePass == false)
+ fprintf(stderr, "*** Directory deleted: %s/%s\n", workingDir, oldFile);
+ }
+ oldList += strlen(oldList) + 1;
+ continue;
+ }
+ if (order > 0) {
+ if (renamePass == false) {
+ string rename(workingDir);
+ rename.append("/");
+ rename.append(newFile);
+ bool skip = false;
+ for (map<string, string>::iterator iter = renameMap.begin(); iter != renameMap.end(); iter++) {
+ if (iter->second == rename) {
+ skip = true;
+ break;
+ }
+ }
+ if (skip == false) {
+ if (newDir) {
+ if (strcmp(sandFile, newFile) != 0 &&
+ emptyDirectory(newBase, workingDir, newFile) == false) {
+ fprintf(copyDirFile, "find \"%s/%s/%s\" -type d -print | "
+ "sed 's@%s/\\(.*\\)@mkdir %s/\\1@' | bash -s\n",
+ newCmd, workingDir, newFile, newCmd, sandboxCmd);
+ fprintf(copyDirFile, "find \"%s/%s/%s\" -type f -print | "
+ "sed 's@%s/\\(.*\\)@cp %s/\\1 %s/\\1@' | bash -s\n",
+ newCmd, workingDir, newFile, newCmd, newCmd, sandboxCmd);
+ if (options.emitPerforceCommands)
+ fprintf(copyDirFile, "find \"%s/%s/%s\" -type f -print | "
+ "p4 -x - add\n",
+ sandboxCmd, workingDir, newFile);
+ else if (options.emitGitCommands)
+ fprintf(copyDirFile, "git add \"%s/%s\"\n",
+ workingDir, newFile);
+ }
+ } else {
+// if (emptyDirectory(sandboxBase, workingDir)) {
+// fprintf(commandFile, "mkdir \"%s/%s\"\n", sandboxCmd, workingDir);
+// }
+ bool edit = false;
+ size_t newLen1 = strlen(newFile);
+ for (map<string, string>::iterator iter = renameMap.begin(); iter != renameMap.end(); iter++) {
+ if (strcmp(iter->second.c_str(), workingDir) == 0) {
+ const char* first = iter->first.c_str();
+ size_t firstLen = strlen(first);
+ if (firstLen > newLen1 && strcmp(newFile,
+ &first[firstLen - newLen1]) == 0) {
+ edit = true;
+ break;
+ }
+ }
+ }
+ if (edit == false) {
+ fprintf(commandFile, "cp \"%s/%s/%s\" \"%s/%s/%s\"\n",
+ newCmd, workingDir, newFile, sandboxCmd, workingDir, newFile);
+ if (options.emitPerforceCommands)
+ fprintf(commandFile, "p4 add \"%s/%s/%s\"\n", sandboxCmd, workingDir, newFile);
+ else if (options.emitGitCommands)
+ fprintf(commandFile, "git add \"%s/%s\"\n", workingDir, newFile);
+ }
+ }
+ }
+ }
+ newList += strlen(newList) + 1;
+ continue;
+ }
+ if (oldDir) {
+ myassert(newDir);
+ size_t newLen1 = strlen(workingDir) + strlen(oldList);
+ char* newFile = new char[newLen1 + 1];
+ sprintf(newFile, "%s/%.*s", workingDir, (int) strlen(oldList) - 1,
+ oldList);
+ if (sandOrder > 0) { // file is on old and new but not sandbox
+ if (emptyDirectory(newBase, newFile) == false) {
+ fprintf(copyDirFile, "find \"%s/%s\" -type d -print | "
+ "sed 's@%s/\\(.*\\)@mkdir %s/\\1@' | bash -s\n",
+ newCmd, newFile, newCmd, sandboxCmd);
+ fprintf(copyDirFile, "find \"%s/%s\" -type f -print | "
+ "sed 's@%s/\\(.*\\)@cp %s/\\1 %s/\\1@' | bash -s\n",
+ newCmd, newFile, newCmd, newCmd, sandboxCmd);
+ if (options.emitPerforceCommands)
+ fprintf(copyDirFile, "find \"%s/%s\" -type f -print | "
+ "p4 -x - add\n",
+ sandboxCmd, newFile);
+ else if (options.emitGitCommands)
+ fprintf(copyDirFile, "git add \"%s\"", newFile);
+ }
+ } else
+ CompareDirs(newFile, renamePass);
+ delete[] newFile;
+ } else {
+ // at this point, the file is in both old and new webkits; see if it changed
+ // ignore executables, different or not (or always copy, or do text compare? or find binary compare? )
+ if (oldExecutable != newExecutable)
+ fprintf(stderr, "*** %s/%s differs in the execute bit (may cause problems for perforce)\n", workingDir, oldFile);
+ // myassert(sandOrder != 0 || sandFile[sandLen - 1] == '*');
+ // Diff(oldBase, sandboxBase, workingDir, oldFile);
+ bool oldNewDiff = CompareFiles(oldBase, newBase, workingDir, oldList);
+ if (oldNewDiff && sandOrder == 0 && renamePass == false) { // if it changed, see if android also changed it
+ if (options.emitPerforceCommands)
+ fprintf(commandFile, "p4 edit \"%s/%s/%s\"\n", sandboxCmd, workingDir, oldFile);
+ bool oldSandboxDiff = CompareFiles(oldBase, sandboxBase, workingDir, oldFile);
+ if (oldSandboxDiff) {
+ fprintf(commandFile, "merge -q \"%s/%s/%s\" \"%s/%s/%s\" \"%s/%s/%s\"\n",
+ sandboxCmd, workingDir, oldFile, oldCmd, workingDir, oldFile, newCmd, workingDir, oldFile);
+ bool success = Merge(workingDir, oldFile);
+ if (success == false) {
+ fprintf(stderr, "*** Manual merge required: %s/%s\n", workingDir, oldFile);
+ fprintf(commandFile, "cat \"%s/%s/%s\" | sed -e 's/^<<<<<<<.*$/#ifdef MANUAL_MERGE_REQUIRED/' "
+ "-e 's/^=======$/#else \\/\\/ MANUAL_MERGE_REQUIRED/' -e 's/^>>>>>>>.*$/#endif \\/\\/ MANUAL_MERGE_REQUIRED/' > \"%s/%s/x%s\"\n",
+ sandboxCmd, workingDir, oldFile, sandboxCmd, workingDir, oldFile);
+ fprintf(commandFile, "mv \"%s/%s/x%s\" \"%s/%s/%s\"\n",
+ sandboxCmd, workingDir, oldFile, sandboxCmd, workingDir, oldFile);
+ }
+ } else fprintf(commandFile, "cp \"%s/%s/%s\" \"%s/%s/%s\"\n", newCmd, workingDir, oldFile ,
+ sandboxCmd, workingDir, oldFile);
+ if (options.emitGitCommands)
+ fprintf(commandFile, "git add \"%s/%s\"\n", workingDir, oldFile);
+ }
+ }
+ myassert(oldLen == newLen);
+ newList += strlen(newList) + 1;
+ oldList += strlen(oldList) + 1;
+ } while (true);
+ delete[] oldMem;
+ delete[] newMem;
+ delete[] sandboxMem;
+}
+
+bool Ignore(char* fileName, size_t len)
+{
+ if (len == 0)
+ return true;
+ if (fileName[len - 1] =='/')
+ return true;
+ if (strcmp(fileName, ".DS_Store") == 0)
+ return true;
+ if (strcmp(fileName, ".ignoreSVN") == 0)
+ return true;
+ return false;
+}
+
+void FixStar(char* fileName, size_t len)
+{
+ if (fileName[len - 1] =='*')
+ fileName[len - 1] = '\0';
+}
+
+void FixColon(char** fileNamePtr, size_t* lenPtr)
+{
+ char* fileName = *fileNamePtr;
+ size_t len = *lenPtr;
+ if (fileName[len - 1] !=':')
+ return;
+ fileName[len - 1] = '\0';
+ if (strncmp(fileName ,"./", 2) != 0)
+ return;
+ fileName += 2;
+ *fileNamePtr = fileName;
+ len -= 2;
+ *lenPtr = len;
+}
+
+bool IgnoreDirectory(const char* dir, const char** dirList)
+{
+ if (dirList == NULL)
+ return false;
+ const char* test;
+ while ((test = *dirList++) != NULL) {
+ if (strncmp(dir, test, strlen(test)) == 0)
+ return true;
+ }
+ return false;
+}
+
+static void doSystem(char* scratch)
+{
+ if (false) printf("%s\n", scratch);
+ int err = system(scratch);
+ myassert(err == 0);
+}
+
+static void copyToCommand(char* scratch, string file)
+{
+ doSystem(scratch);
+ char* diff = GetFile(file.c_str());
+ while (*diff) {
+ fprintf(commandFile, "%s\n", diff);
+ diff += strlen(diff) + 1;
+ }
+}
+
+#define WEBKIT_EXCLUDED_DIRECTORIES \
+ "-not -path \"*Tests\" " /* includes LayoutTests, PageLoadTests */ \
+ "-not -path \"*Tests/*\" " /* includes LayoutTests, PageLoadTests */ \
+ "-not -path \"*Site\" " /* includes BugsSite, WebKitSite */ \
+ "-not -path \"*Site/*\" " /* includes BugsSite, WebKitSite */ \
+ "-not -path \"./PlanetWebKit/*\" " \
+ "-not -path \"./PlanetWebKit\" "
+
+#define ANDROID_EXCLUDED_FILES \
+ "-e '/^Files .* differ/ d' " \
+ "-e '/^Only in .*/ d' " \
+ "-e '/Android.mk/ d' " \
+ "-e '/android$/ d' "
+
+#define ANDROID_EXCLUDED_DIRS \
+ "-e '/\\/JavaScriptCore\\// d' " \
+ "-e '/\\/WebCore\\// d' "
+
+#define ANDROID_EXCLUDED_DIRS_GIT \
+ "-e '/ JavaScriptCore\\// d' " \
+ "-e '/ WebCore\\// d' "
+
+void CopyOther()
+{
+ string excludedFiles = ANDROID_EXCLUDED_FILES;
+ if (options.emitGitCommands)
+ excludedFiles += ANDROID_EXCLUDED_DIRS_GIT;
+ else
+ excludedFiles += ANDROID_EXCLUDED_DIRS;
+ char scratch[1024];
+ // directories to ignore in webkit
+ string copyOtherWebKit = ScratchFile("CopyOtherWebKit");
+ sprintf(scratch, "cd %s ; find . -type d -not -empty "
+ WEBKIT_EXCLUDED_DIRECTORIES
+ " > %s", newBase, copyOtherWebKit.c_str());
+ doSystem(scratch);
+ // directories to ignore in android
+ string copyOtherAndroid = ScratchFile("CopyOtherAndroid");
+ sprintf(scratch, "cd %s ; find . -type d -not -empty "
+ "-not -path \"*.git*\" "
+ "-not -path \"*android*\" "
+ " > %s", sandboxBase, copyOtherAndroid.c_str());
+ doSystem(scratch);
+ if (0) {
+ string copyOtherMkDir = ScratchFile("CopyOtherMkDir");
+ sprintf(scratch, "diff %s %s | sed -e 's@< \\./\\(.*\\)$"
+ "@mkdir %s/\\1@' "
+ "-e '/^[0-9].*/ d' "
+ "-e '/>.*/ d' "
+ "-e '/---/ d' "
+ "-e '/\\/JavaScriptCore\\// d' "
+ "-e '/\\/WebCore\\// d' "
+ "> %s", copyOtherWebKit.c_str(), copyOtherAndroid.c_str(), sandboxCmd,
+ copyOtherMkDir.c_str());
+ if (options.debug)
+ fprintf(stderr, "%s\n", scratch);
+ copyToCommand(scratch, copyOtherMkDir);
+ }
+ string copyOtherDiff = ScratchFile("CopyOtherDiff");
+ int scratchLen = sprintf(scratch, "diff %s %s | sed -e 's@< \\./\\(.*\\)$"
+ "@mkdir -p -v %s/\\1 ; find %s/\\1 -type f -depth 1 -exec cp {} %s/\\1 \";\"",
+ copyOtherWebKit.c_str(), copyOtherAndroid.c_str(), sandboxCmd, newCmd,
+ sandboxCmd);
+ if (options.emitGitCommands)
+ scratchLen += sprintf(&scratch[scratchLen], " ; cd %s ; find ", sandboxCmd);
+ else
+ scratchLen += sprintf(&scratch[scratchLen], " ; find %s/", sandboxCmd);
+ scratchLen += sprintf(&scratch[scratchLen], "\\1 -type f -depth 1 | ");
+ if (options.emitPerforceCommands)
+ scratchLen += sprintf(&scratch[scratchLen], "p4 -x - add ");
+ else if (options.emitGitCommands)
+ scratchLen += sprintf(&scratch[scratchLen], "xargs git add ");
+ scratchLen += sprintf(&scratch[scratchLen],
+ "@' -e '/^[0-9].*/ d' "
+ "-e '/>.*/ d' "
+ "-e '/---/ d' "
+ "-e '/\\/JavaScriptCore\\// d' "
+ "-e '/\\/WebCore\\// d' "
+ "> %s", copyOtherDiff.c_str());
+ if (options.debug)
+ fprintf(stderr, "%s\n", scratch);
+ copyToCommand(scratch, copyOtherDiff);
+ string deleteOtherDiff = ScratchFile("DeleteOtherDiff");
+ scratchLen = sprintf(scratch, "diff -r -q %s %s | sed -e "
+ "'s@Only in %s/\\(.*\\)\\: \\(.*\\)@",
+ newBase, sandboxBase, sandboxBase);
+ if (options.emitPerforceCommands)
+ scratchLen += sprintf(&scratch[scratchLen], "p4 delete %s/", sandboxCmd);
+ else if (options.emitGitCommands)
+ scratchLen += sprintf(&scratch[scratchLen], "git rm ");
+ else
+ scratchLen += sprintf(&scratch[scratchLen], "rm %s/", sandboxCmd);
+ scratchLen += sprintf(&scratch[scratchLen], "\\1/\\2@' %s > %s",
+ excludedFiles.c_str(), deleteOtherDiff.c_str());
+ if (options.debug)
+ fprintf(stderr, "%s\n", scratch);
+ copyToCommand(scratch, deleteOtherDiff);
+ string addOtherDiff = ScratchFile("AddOtherDiff");
+ scratchLen = sprintf(scratch, "diff -r -q %s %s | sed -e "
+ "'s@Only in %s/\\(.*\\)\\: \\(.*\\)"
+ "@mkdir -p -v %s/\\1 ; cp %s/\\1/\\2 %s/\\1/\\2 ; ",
+ newBase, sandboxBase, newBase, sandboxCmd, newCmd, sandboxCmd);
+ if (options.emitPerforceCommands)
+ scratchLen += sprintf(&scratch[scratchLen],
+ "p4 add %s/\\1/\\2", sandboxCmd);
+ else if (options.emitGitCommands)
+ scratchLen += sprintf(&scratch[scratchLen],
+ "git add \\1/\\2");
+ scratchLen += sprintf(&scratch[scratchLen], "@' %s > %s",
+ excludedFiles.c_str(), addOtherDiff.c_str());
+ if (options.debug)
+ fprintf(stderr, "%s\n", scratch);
+ copyToCommand(scratch, addOtherDiff);
+ string editOtherDiff = ScratchFile("EditOtherDiff");
+ scratchLen = sprintf(scratch, "diff -r -q %s %s | sed -e "
+ "'s@Files %s/\\(.*\\) and %s/\\(.*\\) differ@",
+ newBase, sandboxBase, newBase, sandboxBase);
+ if (options.emitPerforceCommands)
+ scratchLen += sprintf(&scratch[scratchLen],
+ "p4 edit %s/\\2 ; ", sandboxCmd);
+ scratchLen += sprintf(&scratch[scratchLen], "cp %s/\\1 %s/\\2 ",
+ newCmd, sandboxCmd);
+ if (options.emitGitCommands)
+ scratchLen += sprintf(&scratch[scratchLen],
+ " ; git add \\2");
+ scratchLen += sprintf(&scratch[scratchLen], "@' %s > %s",
+ excludedFiles.c_str(), editOtherDiff.c_str());
+ if (options.debug)
+ fprintf(stderr, "%s\n", scratch);
+ copyToCommand(scratch, editOtherDiff);
+}
+
+void MakeExecutable(const string& filename)
+{
+ string makeExScript = "chmod +x ";
+ makeExScript += filename;
+ int err = system(makeExScript.c_str());
+ myassert(err == 0);
+}
+
+bool ReadArgs(char* const args[], int argCount)
+{
+ int index = 0;
+ const char* toolpath = args[index++];
+ // first arg is path to this executable
+ // use this to build default paths
+
+ for (; index < argCount; index++) {
+ const char* arg = args[index];
+ if (strncmp(arg, "-a", 2) == 0 || strcmp(arg, "--android") == 0) {
+ index++;
+ options.androidWebKit = args[index];
+ continue;
+ }
+ if (strncmp(arg, "-b", 2) == 0 || strcmp(arg, "--basewebkit") == 0) {
+ index++;
+ options.baseWebKit = args[index];
+ continue;
+ }
+ if (strncmp(arg, "-c", 2) == 0 || strcmp(arg, "--mergecore") == 0) {
+ options.clearOnce();
+ options.mergeCore = true;
+ continue;
+ }
+ if (strncmp(arg, "-d", 2) == 0 || strcmp(arg, "--debug") == 0) {
+ options.debug = true;
+ continue;
+ }
+ if (strncmp(arg, "-e", 2) == 0 || strcmp(arg, "--emptydirs") == 0) {
+ options.clearOnce();
+ options.removeEmptyDirs = true;
+ continue;
+ }
+ if (strncmp(arg, "-g", 2) == 0 || strcmp(arg, "--git") == 0) {
+ options.emitGitCommands = true;
+ if (options.emitPerforceCommands == false)
+ continue;
+ }
+ if (strncmp(arg, "-m", 2) == 0 || strcmp(arg, "--mergemake") == 0) {
+ options.clearOnce();
+ options.mergeMake = true;
+ continue;
+ }
+ if (strncmp(arg, "-n", 2) == 0 || strcmp(arg, "--newwebkit") == 0) {
+ index++;
+ options.newWebKit = args[index];
+ continue;
+ }
+ if (strncmp(arg, "-o", 2) == 0 || strcmp(arg, "--copyother") == 0) {
+ options.clearOnce();
+ options.copyOther = true;
+ continue;
+ }
+ if (strncmp(arg, "-p", 2) == 0 || strcmp(arg, "--perforce") == 0) {
+ options.emitPerforceCommands = true;
+ if (options.emitGitCommands == false)
+ continue;
+ }
+ if (strncmp(arg, "-s", 2) == 0 || strcmp(arg, "--removesvn") == 0) {
+ options.clearOnce();
+ options.removeSVNDirs = true;
+ continue;
+ }
+ if (strncmp(arg, "-v", 2) == 0 || strcmp(arg, "--verbose") == 0) {
+ options.verbose = true;
+ fprintf(stderr, "path: %s\n", toolpath);
+ int err = system("pwd > pwd.txt");
+ myassert(err != -1);
+ fprintf(stderr, "pwd: %s\n", GetFile("pwd.txt"));
+ system("rm pwd.txt");
+ continue;
+ }
+ if (strncmp(arg, "-x", 2) == 0 || strcmp(arg, "--execute") == 0) {
+ options.execute = true;
+ continue;
+ }
+ if (options.emitGitCommands && options.emitPerforceCommands)
+ printf("choose one of --git and --perforce\n");
+ else if (strncmp(arg, "-h", 2) != 0 && strcmp(arg, "--help") != 0 && strcmp(arg, "-?") != 0)
+ printf("%s not understood\n", args[index]);
+ printf(
+"WebKit Merge for Android version 1.1\n"
+"Usage: webkitmerge -a path -b path -n path [-g or -p] [-c -d -e -m -o -s -v -x]\n"
+"Options -c -e -m -o -s are set unless one or more are passed.\n"
+"Leave -g and -p unset to copy, merge, and delete files outside of source control.\n"
+"-a --android path Set the Android webkit path to merge to.\n"
+"-b --basewebkit path Set the common base for Android and the newer webkit.\n"
+"-c --mergecore Create merge scripts for WebCore, JavaScriptCore .h .cpp.\n"
+"-d --debug Show debugging printfs; loop forever on internal assert.\n"
+"-e --emptydirs Remove empty directories from webkit trees.\n"
+"-g --git Emit git commands.\n"
+"-h --help Show this help.\n"
+"-m --mergemake Create merge scripts for WebCore/Android.mk,\n"
+" WebCore/Android.derived.mk, and JavaScriptCore/Android.mk.\n"
+"-n --newwebkit path Set the webkit to merge from.\n"
+"-o --copyother Create script to copy other webkit directories.\n"
+"-p --perforce Emit perforce commands.\n"
+"-s --removesvn Remove svn directories from webkit trees.\n"
+"-v --verbose Show status printfs.\n"
+"-x --execute Execute the merge scripts.\n"
+ );
+ return false;
+ }
+ return options.finish();
+}
+
+int main (int argCount, char* const args[])
+{
+ if (ReadArgs(args, argCount) == false)
+ return 0;
+ int err;
+ // First remove all .svn directories
+ if (options.removeSVNDirs) {
+ if (options.verbose)
+ fprintf(stderr, "removing svn directories from %s\n", newBase);
+ string removeSVNStr = string("find ") + newBase +
+ " -type d -name \".svn\" -print0 | xargs -0 rm -rf";
+ err = system(removeSVNStr.c_str());
+ myassert(err == 0);
+ }
+ // Remove all empty directories
+ if (options.removeEmptyDirs) {
+ if (options.verbose)
+ fprintf(stderr, "removing empty directories from %s, %s\n",
+ oldBase, newBase);
+ string removeEmpty = string("find ") + oldBase + " " + newBase +
+ " -type d -empty -delete";
+ err = system(removeEmpty.c_str());
+ myassert(err == 0);
+ }
+ if (options.mergeCore /* || options.mergeMake */) {
+ if (options.verbose)
+ fprintf(stderr, "building rename map\n");
+ commandFile = fopen("/dev/null", "w");
+ copyDirFile = fopen("/dev/null", "w");
+ CompareDirs("WebCore", true); // build rename map
+ CompareDirs("JavaScriptCore", true);
+ fclose(copyDirFile);
+ fclose(commandFile);
+ }
+ if (options.mergeMake) {
+ if (options.verbose)
+ fprintf(stderr, "building make.sh\n");
+ string makeShell = outputDir + "make.sh";
+ commandFile = fopen(makeShell.c_str(), "w");
+ if (options.emitGitCommands || options.emitPerforceCommands)
+ fprintf(commandFile, "cd %s\n", sandboxCmd);
+ UpdateMake("WebCore");
+ UpdateMake("JavaScriptCore");
+ UpdateDerivedMake();
+ fclose(commandFile);
+ MakeExecutable(makeShell);
+ }
+ if (options.copyOther) {
+ if (options.verbose)
+ fprintf(stderr, "building copyOther.sh\n");
+ string copyOtherShell = outputDir + "copyOther.sh";
+ commandFile = fopen(copyOtherShell.c_str(), "w");
+ if (options.emitGitCommands || options.emitPerforceCommands)
+ fprintf(commandFile, "cd %s\n", sandboxCmd);
+ CopyOther();
+ fclose(commandFile);
+ MakeExecutable(copyOtherShell);
+ }
+ if (options.mergeCore) {
+ if (options.verbose)
+ fprintf(stderr, "building command.sh copyDir.sh oops.sh\n");
+ string commandShell = outputDir + "command.sh";
+ commandFile = fopen(commandShell.c_str(), "w");
+ if (options.emitGitCommands || options.emitPerforceCommands)
+ fprintf(commandFile, "cd %s\n", sandboxCmd);
+ string copyDirShell = outputDir + "copyDir.sh";
+ copyDirFile = fopen(copyDirShell.c_str(), "w");
+ if (options.emitGitCommands || options.emitPerforceCommands)
+ fprintf(copyDirFile, "cd %s\n", sandboxCmd);
+ string oopsShell = outputDir + "oops.sh";
+ oopsFile = fopen(oopsShell.c_str(), "w");
+ if (options.emitGitCommands || options.emitPerforceCommands)
+ fprintf(oopsFile, "cd %s\n", sandboxCmd);
+ CompareDirs("WebCore", false); // generate command script
+ CompareDirs("JavaScriptCore", false);
+ fclose(oopsFile);
+ fclose(copyDirFile);
+ fclose(commandFile);
+ MakeExecutable(oopsShell);
+ MakeExecutable(copyDirShell);
+ MakeExecutable(commandShell);
+ }
+ if (options.execute) {
+ if (options.mergeCore) {
+ if (options.verbose)
+ fprintf(stderr, "executing command.sh\n");
+ string execCommand = "cd " + options.androidWebKit + "; . " + outputDir + "command.sh";
+ err = system(execCommand.c_str());
+ myassert(err == 0);
+ if (options.verbose)
+ fprintf(stderr, "executing copyDir.sh\n");
+ string execCopy = "cd " + options.androidWebKit + "; . " + outputDir + "copyDir.sh";
+ err = system(execCopy.c_str());
+ myassert(err == 0);
+ }
+ if (options.mergeMake) {
+ if (options.verbose)
+ fprintf(stderr, "executing make.sh\n");
+ string execMake = "cd " + options.androidWebKit + "; . " + outputDir + "make.sh";
+ err = system(execMake.c_str());
+ myassert(err == 0);
+ }
+ if (options.copyOther) {
+ if (options.verbose)
+ fprintf(stderr, "executing copyOther.sh\n");
+ string execCopyOther = "cd " + options.androidWebKit + "; . " + outputDir + "copyOther.sh";
+ err = system(execCopyOther.c_str());
+ myassert(err == 0);
+ }
+ }
+ if (options.verbose)
+ fprintf(stderr, "done!\n");
+ else {
+ string rmAllCmd = "rm " + scratchDir + "* ; rmdir " + scratchDir;
+ err = system(rmAllCmd.c_str());
+ myassert(err == 0);
+ }
+ return 0;
+}
+
+/* things to do:
+ when inserting MANUAL_MERGE_REQUIRED, if contents is #preprocessor, balance first?
+*/
diff --git a/Tools/android/webkitmerge/webkitmerge.xcodeproj/project.pbxproj b/Tools/android/webkitmerge/webkitmerge.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..6bc4b59
--- /dev/null
+++ b/Tools/android/webkitmerge/webkitmerge.xcodeproj/project.pbxproj
@@ -0,0 +1,206 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 44;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ FEA948A00F84F8E8005FB0EC /* webkitmerge.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FEA9489F0F84F8E8005FB0EC /* webkitmerge.cpp */; };
+/* End PBXBuildFile section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 8DD76F690486A84900D96B5E /* CopyFiles */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 8;
+ dstPath = /usr/share/man/man1/;
+ dstSubfolderSpec = 0;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 1;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 8DD76F6C0486A84900D96B5E /* webkitmerge */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = webkitmerge; sourceTree = BUILT_PRODUCTS_DIR; };
+ FEA9489F0F84F8E8005FB0EC /* webkitmerge.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = webkitmerge.cpp; sourceTree = "<group>"; };
+ FEE07B910F866E7500F4A22F /* vector_.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vector_.h; sourceTree = "<group>"; };
+ FEE07B940F8670E200F4A22F /* map_.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = map_.h; sourceTree = "<group>"; };
+ FEE07B970F86734A00F4A22F /* string_.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = string_.h; sourceTree = "<group>"; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8DD76F660486A84900D96B5E /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 08FB7794FE84155DC02AAC07 /* webkitmerge */ = {
+ isa = PBXGroup;
+ children = (
+ 08FB7795FE84155DC02AAC07 /* Source */,
+ C6859E8C029090F304C91782 /* Documentation */,
+ 1AB674ADFE9D54B511CA2CBB /* Products */,
+ );
+ name = webkitmerge;
+ sourceTree = "<group>";
+ };
+ 08FB7795FE84155DC02AAC07 /* Source */ = {
+ isa = PBXGroup;
+ children = (
+ FEE07B970F86734A00F4A22F /* string_.h */,
+ FEE07B940F8670E200F4A22F /* map_.h */,
+ FEE07B910F866E7500F4A22F /* vector_.h */,
+ FEA9489F0F84F8E8005FB0EC /* webkitmerge.cpp */,
+ );
+ name = Source;
+ sourceTree = "<group>";
+ };
+ 1AB674ADFE9D54B511CA2CBB /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8DD76F6C0486A84900D96B5E /* webkitmerge */,
+ );
+ name = Products;
+ sourceTree = "<group>";
+ };
+ C6859E8C029090F304C91782 /* Documentation */ = {
+ isa = PBXGroup;
+ children = (
+ );
+ name = Documentation;
+ sourceTree = "<group>";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXNativeTarget section */
+ 8DD76F620486A84900D96B5E /* webkitmerge */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "webkitmerge" */;
+ buildPhases = (
+ 8DD76F640486A84900D96B5E /* Sources */,
+ 8DD76F660486A84900D96B5E /* Frameworks */,
+ 8DD76F690486A84900D96B5E /* CopyFiles */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = webkitmerge;
+ productInstallPath = "$(HOME)/bin";
+ productName = webkitmerge;
+ productReference = 8DD76F6C0486A84900D96B5E /* webkitmerge */;
+ productType = "com.apple.product-type.tool";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 08FB7793FE84155DC02AAC07 /* Project object */ = {
+ isa = PBXProject;
+ buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "webkitmerge" */;
+ compatibilityVersion = "Xcode 3.0";
+ hasScannedForEncodings = 1;
+ mainGroup = 08FB7794FE84155DC02AAC07 /* webkitmerge */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8DD76F620486A84900D96B5E /* webkitmerge */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8DD76F640486A84900D96B5E /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ FEA948A00F84F8E8005FB0EC /* webkitmerge.cpp in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin XCBuildConfiguration section */
+ 1DEB923208733DC60010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ COPY_PHASE_STRIP = NO;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_ENABLE_FIX_AND_CONTINUE = YES;
+ GCC_MODEL_TUNING = G5;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "_GLIBCXX_DEBUG=1",
+ "_GLIBCXX_DEBUG_PEDANTIC=1",
+ );
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = webkitmerge;
+ ZERO_LINK = YES;
+ };
+ name = Debug;
+ };
+ 1DEB923308733DC60010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ GCC_MODEL_TUNING = G5;
+ INSTALL_PATH = /usr/local/bin;
+ PRODUCT_NAME = webkitmerge;
+ };
+ name = Release;
+ };
+ 1DEB923608733DC60010E9CD /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
+ };
+ name = Debug;
+ };
+ 1DEB923708733DC60010E9CD /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ARCHS = (
+ ppc,
+ i386,
+ );
+ GCC_WARN_ABOUT_RETURN_TYPE = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ PREBINDING = NO;
+ SDKROOT = "$(DEVELOPER_SDK_DIR)/MacOSX10.5.sdk";
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 1DEB923108733DC60010E9CD /* Build configuration list for PBXNativeTarget "webkitmerge" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB923208733DC60010E9CD /* Debug */,
+ 1DEB923308733DC60010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "webkitmerge" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 1DEB923608733DC60010E9CD /* Debug */,
+ 1DEB923708733DC60010E9CD /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 08FB7793FE84155DC02AAC07 /* Project object */;
+}
diff --git a/Tools/gdb/webcore.py b/Tools/gdb/webcore.py
new file mode 100644
index 0000000..8dc4d8e
--- /dev/null
+++ b/Tools/gdb/webcore.py
@@ -0,0 +1,32 @@
+# 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.
+
+# For backward compatibility.
+import webkit
+print ("webcore.py is deprecated. Please use 'import webkit' instead of "
+ "'import webcore' in your ~/.gdbinit.")
diff --git a/Tools/gdb/webkit.py b/Tools/gdb/webkit.py
new file mode 100644
index 0000000..95c3d9c
--- /dev/null
+++ b/Tools/gdb/webkit.py
@@ -0,0 +1,304 @@
+# 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.
+
+"""GDB support for WebKit types.
+
+Add this to your gdb by amending your ~/.gdbinit as follows:
+ python
+ import sys
+ sys.path.insert(0, "/path/to/tools/gdb/")
+ import webkit
+"""
+
+import gdb
+import re
+import struct
+
+
+def ustring_to_string(ptr, length=None):
+ """Convert a pointer to UTF-16 data into a Python Unicode string.
+
+ ptr and length are both gdb.Value objects.
+ If length is unspecified, will guess at the length."""
+ extra = ''
+ if length is None:
+ # Try to guess at the length.
+ for i in xrange(0, 2048):
+ if int((ptr + i).dereference()) == 0:
+ length = i
+ break
+ if length is None:
+ length = 256
+ extra = u' (no trailing NUL found)'
+ else:
+ length = int(length)
+
+ char_vals = [int((ptr + i).dereference()) for i in xrange(length)]
+ string = struct.pack('H' * length, *char_vals).decode('utf-16', 'replace')
+
+ return string + extra
+
+
+class StringPrinter(object):
+ "Shared code between different string-printing classes"
+ def __init__(self, val):
+ self.val = val
+
+ def display_hint(self):
+ return 'string'
+
+
+class UCharStringPrinter(StringPrinter):
+ "Print a UChar*; we must guess at the length"
+ def to_string(self):
+ return ustring_to_string(self.val)
+
+
+class WTFAtomicStringPrinter(StringPrinter):
+ "Print a WTF::AtomicString"
+ def to_string(self):
+ return self.val['m_string']
+
+
+class WTFStringPrinter(StringPrinter):
+ "Print a WTF::String"
+ def get_length(self):
+ if not self.val['m_impl']['m_ptr']:
+ return 0
+ return self.val['m_impl']['m_ptr']['m_length']
+
+ def to_string(self):
+ if self.get_length() == 0:
+ return '(null)'
+
+ return ustring_to_string(self.val['m_impl']['m_ptr']['m_data'],
+ self.get_length())
+
+
+class JSCUStringPrinter(StringPrinter):
+ "Print a JSC::UString"
+ def get_length(self):
+ if not self.val['m_impl']['m_ptr']:
+ return 0
+ return self.val['m_impl']['m_ptr']['m_length']
+
+ def to_string(self):
+ if self.get_length() == 0:
+ return ''
+
+ return ustring_to_string(self.val['m_impl']['m_ptr']['m_data'],
+ self.get_length())
+
+
+class JSCIdentifierPrinter(StringPrinter):
+ "Print a JSC::Identifier"
+ def to_string(self):
+ return JSCUStringPrinter(self.val['m_string']).to_string()
+
+
+class JSCJSStringPrinter(StringPrinter):
+ "Print a JSC::JSString"
+ def to_string(self):
+ if self.val['m_length'] == 0:
+ return ''
+
+ return JSCUStringPrinter(self.val['m_value']).to_string()
+
+
+class WebCoreQualifiedNamePrinter(StringPrinter):
+ "Print a WebCore::QualifiedName"
+
+ def __init__(self, val):
+ super(WebCoreQualifiedNamePrinter, self).__init__(val)
+ self.prefix_length = 0
+ self.length = 0
+ if self.val['m_impl']:
+ self.prefix_printer = WTFStringPrinter(
+ self.val['m_impl']['m_prefix']['m_string'])
+ self.local_name_printer = WTFStringPrinter(
+ self.val['m_impl']['m_localName']['m_string'])
+ self.prefix_length = self.prefix_printer.get_length()
+ if self.prefix_length > 0:
+ self.length = (self.prefix_length + 1 +
+ self.local_name_printer.get_length())
+ else:
+ self.length = self.local_name_printer.get_length()
+
+ def get_length(self):
+ return self.length
+
+ def to_string(self):
+ if self.get_length() == 0:
+ return "(null)"
+ else:
+ if self.prefix_length > 0:
+ return (self.prefix_printer.to_string() + ":" +
+ self.local_name_printer.to_string())
+ else:
+ return self.local_name_printer.to_string()
+
+
+class WTFVectorPrinter:
+ """Pretty Printer for a WTF::Vector.
+
+ The output of this pretty printer is similar to the output of std::vector's
+ pretty printer, which is bundled in gcc.
+
+ Example gdb session should look like:
+ (gdb) p v
+ $3 = WTF::Vector of length 7, capacity 16 = {7, 17, 27, 37, 47, 57, 67}
+ (gdb) set print elements 3
+ (gdb) p v
+ $6 = WTF::Vector of length 7, capacity 16 = {7, 17, 27...}
+ (gdb) set print array
+ (gdb) p v
+ $7 = WTF::Vector of length 7, capacity 16 = {
+ 7,
+ 17,
+ 27
+ ...
+ }
+ (gdb) set print elements 200
+ (gdb) p v
+ $8 = WTF::Vector of length 7, capacity 16 = {
+ 7,
+ 17,
+ 27,
+ 37,
+ 47,
+ 57,
+ 67
+ }
+ """
+
+ class Iterator:
+ def __init__(self, start, finish):
+ self.item = start
+ self.finish = finish
+ self.count = 0
+
+ def __iter__(self):
+ return self
+
+ def next(self):
+ if self.item == self.finish:
+ raise StopIteration
+ count = self.count
+ self.count += 1
+ element = self.item.dereference()
+ self.item += 1
+ return ('[%d]' % count, element)
+
+ def __init__(self, val):
+ self.val = val
+
+ def children(self):
+ start = self.val['m_buffer']['m_buffer']
+ return self.Iterator(start, start + self.val['m_size'])
+
+ def to_string(self):
+ return ('%s of length %d, capacity %d'
+ % ('WTF::Vector', self.val['m_size'], self.val['m_buffer']['m_capacity']))
+
+ def display_hint(self):
+ return 'array'
+
+def add_pretty_printers():
+ pretty_printers_dict = {
+ re.compile("^WTF::Vector<.*>$"): WTFVectorPrinter,
+ re.compile("^WTF::AtomicString$"): WTFAtomicStringPrinter,
+ re.compile("^WTF::String$"): WTFStringPrinter,
+ re.compile("^WebCore::QualifiedName$"): WebCoreQualifiedNamePrinter,
+ re.compile("^JSC::UString$"): JSCUStringPrinter,
+ re.compile("^JSC::Identifier$"): JSCIdentifierPrinter,
+ re.compile("^JSC::JSString$"): JSCJSStringPrinter,
+ }
+
+ def lookup_function(val):
+ """Function used to load pretty printers; will be passed to GDB."""
+ type = val.type
+ if type.code == gdb.TYPE_CODE_REF:
+ type = type.target()
+ type = type.unqualified().strip_typedefs()
+ typename = type.tag
+ if not typename:
+ return None
+ for function, pretty_printer in pretty_printers_dict.items():
+ if function.search(typename):
+ return pretty_printer(val)
+
+ if type.code == gdb.TYPE_CODE_PTR:
+ name = str(type.target().unqualified())
+ if name == 'UChar':
+ return UCharStringPrinter(val)
+ return None
+
+ gdb.pretty_printers.append(lookup_function)
+
+
+add_pretty_printers()
+
+
+class PrintPathToRootCommand(gdb.Command):
+ """Command for printing WebKit Node trees.
+
+ Usage: printpathtoroot variable_name"""
+
+ def __init__(self):
+ super(PrintPathToRootCommand, self).__init__("printpathtoroot",
+ gdb.COMMAND_SUPPORT,
+ gdb.COMPLETE_NONE)
+
+ def invoke(self, arg, from_tty):
+ element_type = gdb.lookup_type('WebCore::Element')
+ node_type = gdb.lookup_type('WebCore::Node')
+ frame = gdb.selected_frame()
+ try:
+ val = gdb.Frame.read_var(frame, arg)
+ except:
+ print "No such variable, or invalid type"
+ return
+
+ target_type = str(val.type.target().strip_typedefs())
+ if target_type == str(node_type):
+ stack = []
+ while val:
+ stack.append([val,
+ val.cast(element_type.pointer()).dereference()['m_tagName']])
+ val = val.dereference()['m_parent']
+
+ padding = ''
+ while len(stack) > 0:
+ pair = stack.pop()
+ print padding, pair[1], pair[0]
+ padding = padding + ' '
+ else:
+ print 'Sorry: I don\'t know how to deal with %s yet.' % target_type
+
+
+PrintPathToRootCommand()
diff --git a/Tools/iExploder/htdocs/config.rb b/Tools/iExploder/htdocs/config.rb
new file mode 100644
index 0000000..d9e7e1b
--- /dev/null
+++ b/Tools/iExploder/htdocs/config.rb
@@ -0,0 +1,6 @@
+# Configuration for iExploder.. not generally tuned.
+
+$HTML_MAX_TAGS = 96;
+$HTML_MAX_ATTRS = 4;
+$CSS_MAX_PROPS = 5;
+
diff --git a/Tools/iExploder/htdocs/cssproperties.in b/Tools/iExploder/htdocs/cssproperties.in
new file mode 100644
index 0000000..d49eb8e
--- /dev/null
+++ b/Tools/iExploder/htdocs/cssproperties.in
@@ -0,0 +1,426 @@
+# From WebKit svn r66165 (WebCore/css/CSSPropertyNames.in)
+-webkit-animation
+-webkit-animation-delay
+-webkit-animation-direction
+-webkit-animation-duration
+-webkit-animation-fill-mode
+-webkit-animation-iteration-count
+-webkit-animation-name
+-webkit-animation-play-state
+-webkit-animation-timing-function
+-webkit-appearance
+-webkit-backface-visibility
+-webkit-background-clip
+-webkit-background-composite
+-webkit-background-origin
+-webkit-background-size
+-webkit-border-end
+-webkit-border-end-color
+-webkit-border-end-style
+-webkit-border-end-width
+-webkit-border-fit
+-webkit-border-horizontal-spacing
+-webkit-border-image
+-webkit-border-radius
+-webkit-border-start
+-webkit-border-start-color
+-webkit-border-start-style
+-webkit-border-start-width
+-webkit-border-vertical-spacing
+-webkit-box-align
+-webkit-box-direction
+-webkit-box-flex
+-webkit-box-flex-group
+-webkit-box-lines
+-webkit-box-ordinal-group
+-webkit-box-orient
+-webkit-box-pack
+-webkit-box-reflect
+-webkit-box-shadow
+-webkit-color-correction
+-webkit-column-break-after
+-webkit-column-break-before
+-webkit-column-break-inside
+-webkit-column-count
+-webkit-column-gap
+-webkit-column-rule
+-webkit-column-rule-color
+-webkit-column-rule-style
+-webkit-column-rule-width
+-webkit-column-span
+-webkit-column-width
+-webkit-columns
+-webkit-font-size-delta
+-webkit-font-smoothing
+-webkit-highlight
+-webkit-hyphenate-character
+-webkit-hyphenate-locale
+-webkit-hyphens
+-webkit-line-break
+-webkit-line-clamp
+-webkit-margin-bottom-collapse
+-webkit-margin-collapse
+-webkit-margin-end
+-webkit-margin-start
+-webkit-margin-top-collapse
+-webkit-marquee
+-webkit-marquee-direction
+-webkit-marquee-increment
+-webkit-marquee-repetition
+-webkit-marquee-speed
+-webkit-marquee-style
+-webkit-mask
+-webkit-mask-attachment
+-webkit-mask-box-image
+-webkit-mask-clip
+-webkit-mask-composite
+-webkit-mask-image
+-webkit-mask-origin
+-webkit-mask-position
+-webkit-mask-position-x
+-webkit-mask-position-y
+-webkit-mask-repeat
+-webkit-mask-repeat-x
+-webkit-mask-repeat-y
+-webkit-mask-size
+-webkit-match-nearest-mail-blockquote-color
+-webkit-nbsp-mode
+-webkit-padding-end
+-webkit-padding-start
+-webkit-perspective
+-webkit-perspective-origin
+-webkit-perspective-origin-x
+-webkit-perspective-origin-y
+-webkit-rtl-ordering
+-webkit-text-decorations-in-effect
+-webkit-text-fill-color
+-webkit-text-security
+-webkit-text-size-adjust
+-webkit-text-stroke
+-webkit-text-stroke-color
+-webkit-text-stroke-width
+-webkit-transform
+-webkit-transform-origin
+-webkit-transform-origin-x
+-webkit-transform-origin-y
+-webkit-transform-origin-z
+-webkit-transform-style
+-webkit-transition
+-webkit-transition-delay
+-webkit-transition-duration
+-webkit-transition-property
+-webkit-transition-timing-function
+-webkit-user-drag
+-webkit-user-modify
+-webkit-user-select
+-webkit-variable-declaration-block
+background
+background-attachment
+background-clip
+background-color
+background-image
+background-origin
+background-position
+background-position-x
+background-position-y
+background-repeat
+background-repeat-x
+background-repeat-y
+background-size
+border
+border-bottom
+border-bottom-color
+border-bottom-left-radius
+border-bottom-right-radius
+border-bottom-style
+border-bottom-width
+border-collapse
+border-color
+border-left
+border-left-color
+border-left-style
+border-left-width
+border-radius
+border-right
+border-right-color
+border-right-style
+border-right-width
+border-spacing
+border-style
+border-top
+border-top-color
+border-top-left-radius
+border-top-right-radius
+border-top-style
+border-top-width
+border-width
+bottom
+box-sizing
+caption-side
+clear
+clip
+color
+content
+counter-increment
+counter-reset
+cursor
+direction
+display
+empty-cells
+float
+font
+font-family
+font-size
+font-stretch
+font-style
+font-variant
+font-weight
+height
+left
+letter-spacing
+line-height
+list-style
+list-style-image
+list-style-position
+list-style-type
+margin
+margin-bottom
+margin-left
+margin-right
+margin-top
+max-height
+max-width
+min-height
+min-width
+opacity
+orphans
+outline
+outline-color
+outline-offset
+outline-style
+outline-width
+overflow
+overflow-x
+overflow-y
+padding
+padding-bottom
+padding-left
+padding-right
+padding-top
+page
+page-break-after
+page-break-before
+page-break-inside
+pointer-events
+position
+quotes
+resize
+right
+size
+src
+table-layout
+text-align
+text-decoration
+text-indent
+text-line-through
+text-line-through-color
+text-line-through-mode
+text-line-through-style
+text-line-through-width
+text-overflow
+text-overline
+text-overline-color
+text-overline-mode
+text-overline-style
+text-overline-width
+text-rendering
+text-shadow
+text-transform
+text-underline
+text-underline-color
+text-underline-mode
+text-underline-style
+text-underline-width
+top
+unicode-bidi
+unicode-range
+vertical-align
+visibility
+white-space
+widows
+width
+word-break
+word-spacing
+word-wrap
+z-index
+zoom
+
+# CSS3 properties - http://www.css3.info/preview/
+background-clip
+background-origin
+border-image
+border-radius
+box-shadow
+box-sizing
+column-count
+column-gap
+column-min-width
+column-rule
+column-rule-color
+column-rule-style
+column-rule-width
+column-space-distribution
+column-span
+column-width
+column-width-policy
+
+# Removed from WebKit between r53119 and r66165
+-webkit-binding
+
+# Removed from WebKit between r44660 and r53119
+-webkit-border-bottom-left-radius
+-webkit-border-bottom-right-radius
+-webkit-border-top-left-radius
+-webkit-border-top-right-radius
+
+# Removed from WebKit between r24523 and r44660
+-webkit-dashboard-region
+scrollbar-3dlight-color
+scrollbar-arrow-color
+scrollbar-darkshadow-color
+scrollbar-face-color
+scrollbar-highlight-color
+scrollbar-shadow-color
+scrollbar-track-color
+
+# All of the following are from khtml's cssproperties.in as of 19oct2004, but are no longer in WebKit
+-khtml-border-horizontal-spacing
+-khtml-border-vertical-spacing
+-khtml-flow-mode
+-khtml-marquee
+-khtml-marquee-direction
+-khtml-marquee-increment
+-khtml-marquee-repetition
+-khtml-marquee-speed
+-khtml-marquee-style
+-khtml-text-decoration-color
+-khtml-user-input
+scrollbar-base-color
+
+# Internet Explorer 6.0 - http://msdn.microsoft.com/workshop/author/css/reference/attributes.asp
+filter:progid:
+filter:
+ime-mode
+layout-flow
+layout-grid
+layout-grid-char
+layout-grid-line
+layout-grid-mode
+layout-grid-type
+line-break
+overflow-x
+overflow-y
+pagebreakafter
+pagebreakbefore
+ruby-align
+ruby-overhang
+ruby-position
+text-autospace
+text-justify
+text-kashida-space
+text-underline-position
+word-break
+writing-mode
+zoom
+
+# from http://msdn.microsoft.com/library/default.asp?url=/workshop/author/filter/reference/reference.asp
+filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(
+filter:progid:DXImageTransform.Microsoft.Blur(
+filter:progid:DXImageTransform.Microsoft.MotionBlur(
+filter:progid:DXImageTransform.Microsoft.Gradient(
+filter:progid:DXImageTransform.Microsoft.Pixelate(
+
+# From Mozilla Firefox CVS on 2006-04-15 (layout/style/nsCSSPropList.h)
+# grep "^CSS_PROP" nsCSSPropList.h | grep -v "_SVG" |cut -d, -f1 | cut -d\( -f2 | sort
+++ /tmp/moz Tue Apr 18 13:45:30 2006
+-moz-appearance
+-moz-background-clip
+-moz-background-inline-policy
+-moz-background-origin
+-moz-binding
+-moz-border-bottom-colors
+-moz-border-left-colors
+-moz-border-radius
+-moz-border-radius-bottomleft
+-moz-border-radius-bottomright
+-moz-border-radius-topleft
+-moz-border-radius-topright
+-moz-border-right-colors
+-moz-border-top-colors
+-moz-box-align
+-moz-box-direction
+-moz-box-flex
+-moz-box-ordinal-group
+-moz-box-orient
+-moz-box-pack
+-moz-box-sizing
+-moz-column-count
+-moz-column-gap
+-moz-column-width
+-moz-float-edge
+-moz-force-broken-image-icon
+-moz-image-region
+-moz-margin-end
+-moz-margin-start
+-moz-outline-radius
+-moz-outline-radius-bottomleft
+-moz-outline-radius-bottomright
+-moz-outline-radius-topleft
+-moz-outline-radius-topright
+-moz-padding-end
+-moz-padding-start
+-moz-user-focus
+-moz-user-input
+-moz-user-modify
+-moz-user-select
+-x-background-x-position
+-x-background-y-position
+azimuth
+cue
+cue-after
+cue-before
+elevation
+font-size-adjust
+margin-end-value
+margin-left-ltr-source
+margin-left-rtl-source
+margin-left-value
+margin-right-ltr-source
+margin-right-rtl-source
+margin-right-value
+margin-start-value
+marker
+marker-offset
+marks
+padding-end-value
+padding-left-ltr-source
+padding-left-rtl-source
+padding-left-value
+padding-right-ltr-source
+padding-right-rtl-source
+padding-right-value
+padding-start-value
+pause
+pause-after
+pause-before
+pitch
+pitch-range
+richness
+speak
+speak-header
+speak-numeral
+speak-punctuation
+speech-rate
+stress
+voice-family
+volume
diff --git a/Tools/iExploder/htdocs/cssvalues.in b/Tools/iExploder/htdocs/cssvalues.in
new file mode 100644
index 0000000..c19f78f
--- /dev/null
+++ b/Tools/iExploder/htdocs/cssvalues.in
@@ -0,0 +1,339 @@
+"Trebuchet MS",Verdana, Arial, Helvetica, sans-serif
+#339933 !important !important !important
+#9999999999999999999999999999999999999999999
+-5, -5, -5
+-9999%
+-999999999999999999999999999%
+-999999999999999999999999999em
+-999999999999999999999999999px
+-9999em
+-9999px
+-webkit-activelink
+-webkit-auto
+-webkit-baseline-middle
+-webkit-body
+-webkit-box
+-webkit-center
+-webkit-focus-ring-color
+-webkit-inline-box
+-webkit-left
+-webkit-link
+-webkit-marquee
+-webkit-nowrap
+-webkit-overlay
+-webkit-right
+-webkit-text
+-webkit-xxx-large
+0
+0 auto
+0 fixed
+2%
+90000000000000000000000000000000000000000000%
+9999999999999999999999
+99999999999999999999999999999999999999 auto
+99999999999999999999999999999999999999999999px
+999999px solid #fff
+above
+absolute
+activeborder
+activecaption
+after-white-space
+ahead
+alternate
+always
+appworkspace
+aqua
+armenian
+attr("ATTRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
+auto
+avoid
+background
+backwards
+baseline
+below
+bidi-override
+black
+blink
+block
+block clear
+block width
+block-axis
+blue
+bold
+bolder
+border
+border-box
+both
+bottom
+break-word
+button
+button-bevel
+buttonface
+buttonhighlight
+buttonshadow
+buttontext
+capitalize
+caption
+captiontext
+caret
+center
+checkbox
+circle
+cjk-ideographic
+clip
+clip:rect(-0px -2000000px -200000px -0px)
+clip:rect(0px 2000000px 200000px 0px)
+close-quote
+collapse
+compact
+condensed
+content
+content-box
+continuous
+crop
+cross
+crosshair
+cursive
+dashed
+decimal
+decimal-leading-zero
+default
+disc
+discard
+dot-dash
+dot-dot-dash
+dotted
+double
+down
+e-resize
+element
+ellipsis
+embed
+end
+expanded
+extra-condensed
+extra-expanded
+fantasy
+fast
+fixed
+forwards
+fuchsia
+georgian
+gray
+graytext
+green
+grey
+groove
+hand
+hebrew
+help
+helvetica, arial, Courier New, Courier, Mono, Blah, Blah, Blah
+hidden
+hide
+higher
+highlight
+highlighttext
+hiragana
+hiragana-iroha
+horizontal
+icon
+ignore
+inactiveborder
+inactivecaption
+inactivecaptiontext
+infinite
+infobackground
+infotext
+inherit
+initial
+inline
+inline-axis
+inline-block
+inline-table
+inset
+inside
+intrinsic
+invert
+italic
+justify
+katakana
+katakana-iroha
+landscape
+large
+larger
+left
+level
+lighter
+lime
+line-through
+list-item
+listbox
+listitem
+logical
+loud
+lower
+lower-alpha
+lower-greek
+lower-latin
+lower-roman
+lowercase
+ltr
+marker
+maroon
+match
+medium
+menu
+menulist
+menulist-button
+menulist-text
+menulist-textfield
+menutext
+message-box
+middle
+min-intrinsic
+mix
+monospace
+move
+multiple
+n-resize
+narrower
+navy
+ne-resize
+no-close
+no-close-quote
+no-open-quote
+no-repeat
+none
+normal
+normal !important
+nowrap
+nw-resize
+oblique
+olive
+once
+open-quote
+orange
+outset
+outside
+overline
+padding
+pointer
+portrait
+pre
+pre-line
+pre-wrap
+purple
+push-button
+radio
+read-only
+read-write
+read-write-plaintext-only
+red
+relative
+repeat
+repeat-x
+repeat-y
+reverse
+rgb(9999999999, 999999999, 9999999999999)
+ridge
+right
+round
+rtl
+run-in
+s-resize
+sans-serif
+scroll
+scrollbar
+scrollbarbutton-down
+scrollbarbutton-left
+scrollbarbutton-right
+scrollbarbutton-up
+scrollbargripper-horizontal
+scrollbargripper-vertical
+scrollbarthumb-horizontal
+scrollbarthumb-vertical
+scrollbartrack-horizontal
+scrollbartrack-vertical
+se-resize
+searchfield
+searchfield-close
+searchfield-results
+semi-condensed
+semi-expanded
+separate
+serif
+show
+silver
+single
+skip-white-space
+slide
+slider-horizontal
+slider-vertical
+sliderthumb-horizontal
+sliderthumb-vertical
+slow
+small
+small-caps
+small-caption
+smaller
+solid
+space
+square
+square-button
+start
+static
+status-bar
+stretch
+sub
+super
+sw-resize
+table
+table-caption
+table-cell
+table-column
+table-column-group
+table-footer-group
+table-header-group
+table-row
+table-row-group
+teal
+text
+text-bottom
+text-top
+textfield
+thick
+thick dashed yellow
+thick dotted blue
+thin
+threeddarkshadow
+threedface
+threedhighlight
+threedlightshadow
+threedshadow
+top
+transparent
+ultra-condensed
+ultra-expanded
+underline
+unfurl
+up
+upper-alpha
+upper-latin
+upper-roman
+uppercase
+vertical
+visible
+visual
+w-resize
+wait
+wave
+white
+wider
+window
+windowframe
+windowtext
+x-large
+x-small
+xx-large
+xx-small
+yellow
diff --git a/Tools/iExploder/htdocs/htmlattrs.in b/Tools/iExploder/htdocs/htmlattrs.in
new file mode 100644
index 0000000..0dc8116
--- /dev/null
+++ b/Tools/iExploder/htdocs/htmlattrs.in
@@ -0,0 +1,373 @@
+# From WebKit svn r66165 (WebCore/html/HTMLAttributeNames.in)
+abbr
+accept
+accept_charset
+accesskey
+action
+align
+alink
+alt
+archive
+aria-activedescendant
+aria-atomic
+aria-busy
+aria-checked
+aria-controls
+aria-describedby
+aria-disabled
+aria-dropeffect
+aria-expanded
+aria-flowto
+aria-grabbed
+aria-haspopup
+aria-help
+aria-hidden
+aria-label
+aria-labeledby
+aria-labelledby
+aria-level
+aria-live
+aria-multiselectable
+aria-orientation
+aria-owns
+aria-pressed
+aria-readonly
+aria-relevant
+aria-required
+aria-selected
+aria-valuemax
+aria-valuemin
+aria-valuenow
+aria-valuetext
+async
+autocomplete
+autofocus
+autoplay
+autosave
+axis
+background
+behavior
+bgcolor
+bgproperties
+border
+bordercolor
+cellborder
+cellpadding
+cellspacing
+challenge
+char
+charoff
+charset
+checked
+cite
+class
+classid
+clear
+code
+codebase
+codetype
+color
+cols
+colspan
+compact
+composite
+content
+contenteditable
+controls
+coords
+data
+datetime
+declare
+defer
+dir
+direction
+disabled
+draggable
+enctype
+end
+event
+expanded
+face
+focused
+for
+formnovalidate
+frame
+frameborder
+headers
+height
+hidden
+high
+href
+hreflang
+hspace
+http_equiv
+id
+incremental
+indeterminate
+ismap
+keytype
+label
+lang
+language
+leftmargin
+link
+list
+longdesc
+loop
+loopend
+loopstart
+low
+lowsrc
+manifest
+marginheight
+marginwidth
+max
+maxlength
+mayscript
+media
+method
+min
+multiple
+name
+nohref
+noresize
+noshade
+novalidate
+nowrap
+object
+onabort
+onbeforecopy
+onbeforecut
+onbeforeload
+onbeforepaste
+onbeforeprocess
+onbeforeunload
+onblur
+oncanplay
+oncanplaythrough
+onchange
+onclick
+oncontextmenu
+oncopy
+oncut
+ondblclick
+ondrag
+ondragend
+ondragenter
+ondragleave
+ondragover
+ondragstart
+ondrop
+ondurationchange
+onemptied
+onended
+onerror
+onfocus
+onfocusin
+onfocusout
+onhashchange
+oninput
+oninvalid
+onkeydown
+onkeypress
+onkeyup
+onload
+onloadeddata
+onloadedmetadata
+onloadstart
+onmousedown
+onmousemove
+onmouseout
+onmouseover
+onmouseup
+onmousewheel
+onoffline
+ononline
+onorientationchange
+onpagehide
+onpageshow
+onpaste
+onpause
+onplay
+onplaying
+onpopstate
+onprogress
+onratechange
+onreset
+onresize
+onscroll
+onsearch
+onseeked
+onseeking
+onselect
+onselectstart
+onstalled
+onstorage
+onsubmit
+onsuspend
+ontimeupdate
+ontouchcancel
+ontouchend
+ontouchmove
+ontouchstart
+onunload
+onvolumechange
+onwaiting
+onwebkitanimationend
+onwebkitanimationiteration
+onwebkitanimationstart
+onwebkitbeginfullscreen
+onwebkitendfullscreen
+onwebkittransitionend
+optimum
+pattern
+placeholder
+playcount
+pluginurl
+poster
+precision
+preload
+primary
+profile
+progress
+prompt
+readonly
+rel
+required
+results
+rev
+role
+rows
+rowspan
+rules
+sandbox
+scheme
+scope
+scrollamount
+scrolldelay
+scrolling
+selected
+shape
+size
+sortable
+sortdirection
+span
+speech
+spellcheck
+src
+standby
+start
+step
+style
+summary
+tabindex
+tableborder
+target
+text
+title
+top
+topmargin
+truespeed
+type
+usemap
+valign
+value
+valuetype
+version
+viewsource
+vlink
+vspace
+webkitdirectory
+width
+wrap
+
+# Removed from WebKit between r53119 and r56558
+autobuffer
+
+# Removed from WebKit between r14011 and r53119
+left
+pagex
+pagey
+plain
+pluginpage
+pluginspage
+
+# was in khtml in 2004, but is no longer in WebCore
+accept-charset
+html
+http-equiv
+nosave
+oversrc
+unknown
+visibility
+z-index
+
+# From Mozilla CVS 2006-04-15 (mozilla/layout/style/xbl-marquee)
+bounce
+finish
+onbounce
+onfinish
+onstart
+
+
+# IE specific, from msdn.microsoft.com/workshop/author/dhtml/reference/properties
+acceptcharset
+allowtransparency
+balance
+choff
+datafld
+dataformatas
+datapagesize
+datasrc
+dynsrc
+framespacing
+galleryimg
+hidefocus
+methods
+scroll
+units
+urn
+volume
+
+# From Mozilla CVS 2006-04-15 (mozilla/content/base/src/nsGkAtomList.h)
+# To get these, I used:
+# ggrep -r "Get.*Attr" * | perl -ne 'if (/nsHTMLAtoms::(\w+)/) { \
+# system("grep \\($1, content/base/src/nsGkAtomList.h"); }' \
+# | cut -d\" -f2 | sort -u
+autocheck
+base
+bottommargin
+event
+font-weight
+handler
+layout
+observer
+ping
+point-size
+rightmargin
+variable
+
+# events from Mozilla CVS 2006-04-15 (mozilla/content/base/src/nsGkAtomList.h)
+# cat nsGkAtomList.h | grep GK_ATOM | cut -d\" -f2 | egrep "^on[a-z]+"
+onzoom
+onunderflow
+ontext
+onset
+onpopupshown
+onpopupshowing
+onpopuphiding
+onpopuphidden
+onpaint
+onpageshow
+onpagehide
+onoverflowchanged
+onoverflow
+onget
+ondraggesture
+ondragexit
+ondragdrop
+oncompositionstart
+oncompositionend
+oncommandupdate
+oncommand
+onclose
diff --git a/Tools/iExploder/htdocs/htmltags.in b/Tools/iExploder/htdocs/htmltags.in
new file mode 100644
index 0000000..319d528
--- /dev/null
+++ b/Tools/iExploder/htdocs/htmltags.in
@@ -0,0 +1,155 @@
+# From WebKit svn r66165 (WebCore/html/HTMLTagNames.in)
+a
+abbr
+acronym
+address
+applet
+area
+article
+aside
+audio
+b
+base
+basefont
+bdo
+bgsound
+big
+blockquote
+body
+br
+button
+canvas
+caption
+center
+cite
+code
+col
+colgroup
+command
+datagrid
+datalist
+dcell
+dcol
+dd
+del
+details
+dfn
+dir
+div
+dl
+drow
+dt
+em
+embed
+fieldset
+figcaption
+figure
+font
+footer
+form
+frame
+frameset
+h1
+h2
+h3
+h4
+h5
+h6
+head
+header
+hgroup
+hr
+html
+i
+iframe
+image
+img
+input
+ins
+isindex
+kbd
+keygen
+label
+layer
+legend
+li
+link
+listing
+map
+mark
+marquee
+menu
+meta
+meter
+nav
+nobr
+noembed
+noframes
+nolayer
+noscript
+noscript
+object
+ol
+optgroup
+option
+p
+param
+plaintext
+pre
+progress
+q
+rp
+rt
+ruby
+s
+samp
+script
+section
+select
+small
+source
+span
+strike
+strong
+style
+sub
+summary
+sup
+table
+tbody
+td
+textarea
+tfoot
+th
+thead
+title
+tr
+track
+tt
+u
+ul
+var
+video
+wbr
+xmp
+
+# This was in khtml in 10-2004
+ilayer
+
+# Additions from Mozilla CVS, 2006-04-18.
+# mozilla/parser/htmlparser/public/nsHTMLTagList.h
+bgsound
+blink
+multicol
+spacer
+
+# The following tags used to be in Mozilla in 10-2004, now removed
+counter
+endnote
+parsererror
+server
+sound
+sourcetext
+
+# From Internet Explorer - http://msdn.microsoft.com/workshop/author/html/reference/elements.asp
+xml
diff --git a/Tools/iExploder/htdocs/htmlvalues.in b/Tools/iExploder/htdocs/htmlvalues.in
new file mode 100644
index 0000000..d54984f
--- /dev/null
+++ b/Tools/iExploder/htdocs/htmlvalues.in
@@ -0,0 +1,35 @@
+# Many of the following are from mangleme.cgi.c's make_up_value() function
+#
+*
+_blank
+_parent
+_self
+_top
+about:
+about:plugins
+file:
+http:
+jar:
+javascript:
+left
+top
+%n%n%n%n%n
+ftp:
+right
+wysiwyg:
+bottom
+none
+ldap:
+%i %i
+999999999,9999999,999999999,9999999,999999999,9999999,999999999,9999999,9
+999999999,9999999,9
+999999999,9999999
+true
+false
+_SEARCH
+javascript
+off
+on
+vbscript
+password
+image
diff --git a/Tools/iExploder/htdocs/iexploder.cgi b/Tools/iExploder/htdocs/iexploder.cgi
new file mode 100755
index 0000000..89e099c
--- /dev/null
+++ b/Tools/iExploder/htdocs/iexploder.cgi
@@ -0,0 +1,45 @@
+#!/usr/bin/ruby
+# iExploder - Generates bad HTML files to perform QA for web browsers.
+# Developed for the Mozilla Foundation.
+#####################
+#
+# Copyright (c) 2006 Thomas Stromberg <thomas%stromberg.org>
+#
+# This software is provided 'as-is', without any express or implied warranty.
+# In no event will the authors be held liable for any damages arising from the
+# use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software in a
+# product, an acknowledgment in the product documentation would be appreciated
+# but is not required.
+#
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+#
+# 3. This notice may not be removed or altered from any source distribution.
+
+require 'cgi';
+require 'iexploder';
+require 'config';
+
+### THE INTERACTION ##################################
+ie = IExploder.new($HTML_MAX_TAGS, $HTML_MAX_ATTRS, $CSS_MAX_PROPS)
+ie.readTagFiles()
+
+cgi = CGI.new("html4");
+ie.url=ENV['SCRIPT_NAME'] || '?'
+ie.test_num = cgi.params['test'][0].to_i
+ie.subtest_num = cgi.params['subtest'][0].to_i || 0
+ie.random_mode = cgi.params['random'][0]
+ie.lookup_mode = cgi.params['lookup'][0]
+ie.stop_num = cgi.params['stop'][0].to_i || 0
+ie.setRandomSeed
+
+cgi.out('type' => 'text/html') do
+ ie.buildPage()
+end
diff --git a/Tools/iExploder/htdocs/iexploder.rb b/Tools/iExploder/htdocs/iexploder.rb
new file mode 100644
index 0000000..eee3e38
--- /dev/null
+++ b/Tools/iExploder/htdocs/iexploder.rb
@@ -0,0 +1,337 @@
+# iExploder - Generates bad HTML files to perform QA for web browsers.
+# Developed for the Mozilla Foundation.
+#####################
+#
+# Copyright (c) 2006 Thomas Stromberg <thomas%stromberg.org>
+#
+# This software is provided 'as-is', without any express or implied warranty.
+# In no event will the authors be held liable for any damages arising from the
+# use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software in a
+# product, an acknowledgment in the product documentation would be appreciated
+# but is not required.
+#
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+#
+# 3. This notice may not be removed or altered from any source distribution.
+
+$VERSION="1.3.2"
+
+class IExploder
+ attr_accessor :test_num, :subtest_num, :lookup_mode, :random_mode, :url
+ attr_accessor :offset, :lines, :stop_num
+
+ def initialize(max_tags, max_attrs, max_props)
+ @htmlMaxTags = max_tags
+ @htmlMaxAttrs = max_attrs
+ @cssMaxProps = max_props
+ @mangledTagTotal = 0
+ @stop_num = 0
+ end
+
+ def setRandomSeed
+ if @test_num > 0
+ srand(@test_num)
+ else
+ srand
+ end
+ end
+
+
+ def readTagFiles
+ # These if statements are so that mod_ruby doesn't have to reload the files
+ # each time
+
+ if (! @cssTags)
+ @cssTags = readTagFile('cssproperties.in');
+ end
+
+ if (! @htmlTags)
+ @htmlTags = readTagFile('htmltags.in');
+ end
+ if (! @htmlAttr)
+ @htmlAttr = readTagFile('htmlattrs.in');
+ end
+
+ if (! @htmlValues)
+ @htmlValues = readTagFile('htmlvalues.in');
+ end
+
+ if (! @cssValues)
+ @cssValues = readTagFile('cssvalues.in');
+ end
+
+ end
+
+
+ def readTagFile(filename)
+ list = Array.new
+ File.new(filename).readlines.each { |line|
+ line.chop!
+
+ # Don't include comments.
+ if (line !~ /^# /) && (line.length > 0)
+ list << line
+ end
+ }
+ return list
+ end
+
+ # based on make_up_value, essentially.
+ def inventValue
+ value = rand(19);
+ case value
+ when 1..3 then return (@htmlValues[rand(@htmlValues.length)])
+ when 4..5 then return (@htmlValues[rand(@htmlValues.length)] + inventValue())
+ when 6 then return (@htmlValues[rand(@htmlValues.length)] + "//" + inventValue())
+ when 7 then return ''
+ # this may return negative argument?
+ when 8..10 then return rand(255).chr * (rand(256)+8)
+ when 11 then return rand(255).chr * (rand(2048)+8)
+ when 12 then return "#" + rand(999999).to_s
+ when 13 then return rand(999999).to_s + "%"
+ when 14..15 then return "&" + rand(999999).to_s + ";"
+ # filters
+ when 16 then
+ return inventValue() + "=" + inventValue()
+
+ # this my return undefined method + for nil:NilClass
+ when 17 then return inventValue() + "," + inventValue()
+ else
+ if rand(5) > 3
+ return "-" + rand(999999).to_s
+ else
+ return rand(999999).to_s
+ end
+ end
+ end
+
+ # based on make_up_value, essentially.
+ def inventCssValue(tag)
+ value = rand(23);
+ case value
+ when 1..10 then return @cssValues[rand(@cssValues.length)]
+ when 11 then return ''
+ when 12 then return rand(255).chr * (rand(8192)+8)
+ when 13
+ length = rand(1024) + 8
+ return (rand(255).chr * length) + " " + (rand(255).chr * length) + " " + (rand(255).chr * length)
+ when 14 then return (rand(255).chr * (rand(1024)+3)) + "px"
+ when 15 then return (rand(255).chr * (rand(1024)+3)) + "em"
+ when 16 then return "url(" + inventValue() + ")"
+ when 17..18 then return "#" + rand(999999999).to_s
+ when 19 then return "-" + rand(99999999).to_s
+ else return rand(99999999).to_s;
+ end
+ end
+
+
+ def mangleTag(tag)
+ @mangledTagTotal += 1
+ out = ''
+
+ # 20% chance of closing a tag instead of opening it. This
+ # still counts against @mangledTagTotal, however.
+ if rand(10) > 8
+ out = "</" + tag + ">"
+ return out
+ end
+
+ # we're opening it.
+ out = "<" + tag
+
+ # forgot the space between the tag and the attributes
+ if rand(15) > 1
+ out << ' '
+ end
+
+ attrNum = rand(@htmlMaxAttrs) + 1
+
+ 1.upto(attrNum) {
+ attr = @htmlAttr[rand(@htmlAttr.length)]
+
+ out << attr
+
+ # 7.5% of the time we skip the = sign. Don't prefix it
+ # if the attribute ends with a ( however.
+
+
+ if rand(15) > 1
+ out << '='
+ end
+
+ # sometimes quote it, sometimes not. I doubt the importance
+ # of this test, but mangleme-1.2 added it, and adding more
+ # random-ness never hurt anything but time. I'll do it less often.
+ quote = rand(2)
+ if (quote > 1)
+ out << "\""
+ end
+
+ out << inventValue()
+
+ # end the quote when you are done
+ if (quote > 1)
+ out << "\" "
+ end
+
+ # 5% chance we skip the space at the end of the name
+ if rand(20) > 1
+ out << ' '
+ end
+
+ }
+
+ # CSS styles!
+ if rand(4) > 1
+ out << " style=\""
+ 1.upto(rand(@cssMaxProps)+1) {
+ out << @cssTags[rand(@cssTags.length)]
+
+ # very small chance we let the tag run on.
+ if rand(50) > 1
+ out << ": "
+ end
+
+ out << inventCssValue(tag)
+ # we almost always put the ; there.
+ if rand(50) > 1
+ out << '; '
+ end
+ }
+ out << "\""
+ end
+
+ out << ">\n"
+
+ # support our local troops!
+ if (@subtest_num > 0) && filterSubTest()
+ if tag =~ /html|body|head/
+ return '<' + tag + '>'
+ else
+ return "<x-#@mangledTagTotal>\n"
+ end
+ else
+ return out
+ end
+ end
+ #end
+
+ def filterSubTest()
+ result = 1
+ if (@mangledTagTotal >= @offset) && (@mangledTagTotal < (@offset + @lines))
+ result = nil
+ end
+ return result
+ end
+
+ def nextTestNum()
+ if random_mode
+ n = rand(99999999)
+ else
+ if @test_num
+ n = @test_num + 1
+ else
+ n = 1
+ end
+ end
+ return n
+ end
+
+ # If we are at line 30 with 8 extra lines, there is no point to try line 31
+ # with 8 lines as well.. skip back to 1 and bump up the line count.
+ def nextSubTestNum()
+ if (@offset + @lines) > @htmlMaxTags
+ nextNum = ((@lines * 2 -1)) * @htmlMaxTags
+ else
+ nextNum = @subtest_num + 1
+ end
+ return nextNum
+ end
+
+
+ def buildPage
+ if (! @test_num) || (@test_num < 1)
+ @test_num = 1
+ end
+ next_num=nextTestNum()
+ @lines = @subtest_num.div(@htmlMaxTags) + 1
+ @offset = @subtest_num.modulo(@htmlMaxTags)
+
+ # building the HTML
+ bodyText = mangleTag('html')
+ bodyText << "\n<head>\n"
+
+ # Only do redirects if lookup=1 has not been specified.
+ if (! @lookup_mode) && (@lines <= @htmlMaxTags) && (@stop_num != @test_num)
+ newpage = @url + "?"
+ if @subtest_num > 0
+ newpage << "test=" << @test_num.to_s << "&subtest=" << nextSubTestNum().to_s
+ else
+ newpage << "test=" << next_num.to_s
+ end
+
+ if @random_mode
+ newpage << "&random=1"
+ end
+
+ if @stop_num > 0
+ newpage << "&stop=" << @stop_num.to_s
+ end
+
+ bodyText << "\t<META HTTP-EQUIV=\"Refresh\" content=\"0;URL=#{newpage}\">\n"
+ # use both techniques, because you never know how you might be corrupting yourself.
+ bodyText << "\t<script language=\"javascript\">setTimeout('window.location=\"#{newpage}\"', 1000);</script>\n"
+ end
+
+ bodyText << "\t" << mangleTag('meta')
+ bodyText << "\t" << mangleTag('meta')
+ bodyText << "\t" << mangleTag('link')
+
+ bodyText << "\t<title>[#@test_num] iExploder #{$VERSION} - #{inventValue()}</title>\n"
+ bodyText << "</head>\n\n"
+
+ # What tags will we be messing with ######################
+ tagList = [ 'body']
+
+ # we already have 5 tags?
+ 1.upto(@htmlMaxTags - 5 ) { tagList << @htmlTags[rand(@htmlTags.length)] }
+
+ tagList.each { |tag|
+ bodyText << mangleTag(tag)
+ bodyText << inventValue() + "\n"
+ }
+ bodyText << "</body>\n</html>"
+ end
+end
+
+
+
+if $0 == __FILE__
+ max=ARGV[0].to_i
+ puts "testing #{max} tags"
+ test = IExploder.new(max, 5, 5)
+ test.readTagFiles()
+ test.test_num=1
+ test.subtest_num=1
+ counter=0
+ test.lines=0
+
+ while test.lines < max
+ test.lines = test.subtest_num.div(max) + 1
+ test.offset = test.subtest_num.modulo(max)
+ test.subtest_num=test.nextSubTestNum
+ counter = counter + 1
+ puts "[#{counter}] subtest #{test.subtest_num} is #{test.lines} lines with #{test.offset} offset"
+ end
+
+ puts "for #{max} tests, you will have #{counter} iterations until #{test.subtest_num}"
+end
+
diff --git a/Tools/iExploder/htdocs/index.html b/Tools/iExploder/htdocs/index.html
new file mode 100644
index 0000000..849bc6b
--- /dev/null
+++ b/Tools/iExploder/htdocs/index.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>iExploder 1.3.2</title>
+</head>
+<body>
+<h2>iExploder: Web Browser Quality Assurance Tester</h2>
+<small>Written by <a href="http://toadstool.se/">Thomas Str&ouml;mberg</a> for the
+<a href="http://www.mozilla.org/firefox/">Mozilla FireFox</a> project</small>
+
+
+<ul>
+ <li><a href="iexploder.cgi">Start test sequence from the beginning!</a></li>
+ <li><a href="iexploder.cgi?random=1">Start test sequence in random</a></li>
+ <li>Start testing from a test number:
+ <form method="get" action="iexploder.cgi" name="test">
+ Test: <input size="9" name="test" value="1"> Subtest: <input size="2" name="subtest" value="">
+ <input value="Start" type="submit">
+ </form>
+ </li>
+
+ <li>Lookup a single test number:
+ <form method="get" action="iexploder.cgi" name="test">
+ <input type="hidden" name="lookup" value="1">
+ Test: <input size="9" name="test" value="1"> Subtest: <input size="2" name="subtest" value="">
+ <input value="Lookup" type="submit"></form>
+ </li>
+</ul>
+
+If your browser crashes, please contact thomas%stromberg.org!
+
+</body>
+</html>
+
diff --git a/Tools/iExploder/htdocs/webserver.rb b/Tools/iExploder/htdocs/webserver.rb
new file mode 100755
index 0000000..5176172
--- /dev/null
+++ b/Tools/iExploder/htdocs/webserver.rb
@@ -0,0 +1,75 @@
+#!/usr/bin/ruby
+# iExploder - Generates bad HTML files to perform QA for web browsers.
+# Developed for the Mozilla Foundation.
+#####################
+#
+# Copyright (c) 2006 Thomas Stromberg <thomas%stromberg.org>
+#
+# This software is provided 'as-is', without any express or implied warranty.
+# In no event will the authors be held liable for any damages arising from the
+# use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software in a
+# product, an acknowledgment in the product documentation would be appreciated
+# but is not required.
+#
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+#
+# 3. This notice may not be removed or altered from any source distribution.
+
+require 'webrick'
+require 'iexploder';
+require 'config';
+
+include WEBrick
+### THE INTERACTION ##################################
+$ie_preload = IExploder.new($HTML_MAX_TAGS, $HTML_MAX_ATTRS, $CSS_MAX_PROPS)
+$ie_preload.readTagFiles()
+$ie_preload.url='/iexploder.cgi'
+
+if ARGV[0]
+ port = ARGV[0].to_i
+else
+ port = 2000
+end
+
+puts "* iExploder #{$VERSION} will be available at http://localhost:#{port}"
+puts "* Max Tags: #$HTML_MAX_TAGS Max Attrs: #$HTML_MAX_ATTRS Max Props: #$CSS_MAX_PROPS"
+puts
+
+s = HTTPServer.new( :Port => port )
+class IEServlet < HTTPServlet::AbstractServlet
+ def do_GET(req, res)
+ ie = $ie_preload.dup
+ ie.test_num = req.query['test'].to_i
+ ie.subtest_num = req.query['subtest'].to_i || 0
+ ie.random_mode = req.query['random']
+ ie.lookup_mode = req.query['lookup']
+ ie.stop_num = req.query['stop'].to_i
+ ie.setRandomSeed
+
+ res['Content-Type'] = 'text/html'
+ res.body = ie.buildPage()
+ end
+end
+
+class IEForm < HTTPServlet::AbstractServlet
+ def do_GET(req, res)
+ res['Content-Type'] = 'text/html'
+ res.body = File.open("index.html").readlines.join("\n")
+ end
+end
+
+
+
+s.mount("/iexploder.cgi", IEServlet)
+s.mount("/", IEForm)
+trap("INT") { s.shutdown }
+
+s.start
diff --git a/Tools/iExploder/iexploder-1.3.2/CHANGELOG.txt b/Tools/iExploder/iexploder-1.3.2/CHANGELOG.txt
new file mode 100644
index 0000000..a9d5060
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/CHANGELOG.txt
@@ -0,0 +1,328 @@
+------------------------------------------------------------------------
+r618 | thomas | 2006-04-21 09:55:51 -0400 (Fri, 21 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/README.txt
+ M /iexploder/htdocs/iexploder.cgi
+ M /iexploder/htdocs/iexploder.rb
+ M /iexploder/htdocs/webserver.rb
+
+1.3.2.. minor adjustment to title and where gets set
+------------------------------------------------------------------------
+r617 | thomas | 2006-04-19 17:14:26 -0400 (Wed, 19 Apr 2006) | 1 line
+Changed paths:
+ A /iexploder/testcases/safari/2500_163-Safari-2.0.3_Mac_OS_X-Crash.html
+
+Add h4+pre+cite+nolayer+code crash for Safari 2.0.3
+------------------------------------------------------------------------
+r616 | thomas | 2006-04-19 17:01:48 -0400 (Wed, 19 Apr 2006) | 1 line
+Changed paths:
+ A /iexploder/tools/showtest.rb
+
+showtest.rb: easily download a testcase
+------------------------------------------------------------------------
+r615 | thomas | 2006-04-19 16:07:13 -0400 (Wed, 19 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/htdocs/iexploder.rb
+
+Remove stopping debug message
+------------------------------------------------------------------------
+r614 | thomas | 2006-04-19 16:02:48 -0400 (Wed, 19 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/README.txt
+ M /iexploder/htdocs/iexploder.rb
+
+New subtest algorithm: double the tag count each iteration
+------------------------------------------------------------------------
+r613 | thomas | 2006-04-19 15:05:30 -0400 (Wed, 19 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/htdocs/cssproperties.in
+
+remove IE dupes: text-overflow and word-wrap
+------------------------------------------------------------------------
+r612 | thomas | 2006-04-19 12:48:07 -0400 (Wed, 19 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/README.txt
+ M /iexploder/htdocs/config.rb
+ M /iexploder/htdocs/iexploder.rb
+
+Add some benchmark/performance info.. set MAX_TAGS default to 96
+------------------------------------------------------------------------
+r611 | thomas | 2006-04-19 10:22:33 -0400 (Wed, 19 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/htdocs/iexploder.cgi
+ M /iexploder/htdocs/iexploder.rb
+ M /iexploder/htdocs/webserver.rb
+
+Add stop parameter, fix port assignment issue, fix indentation
+------------------------------------------------------------------------
+r610 | thomas | 2006-04-19 10:22:06 -0400 (Wed, 19 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/README.txt
+
+1.3.0
+------------------------------------------------------------------------
+r609 | thomas | 2006-04-18 22:46:35 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ A /iexploder/testcases/safari/16170_44-Safari-Nightly-420+-2006-r13911-2006-04-18.html
+
+applet+param Hashmap crash in Safari
+------------------------------------------------------------------------
+r608 | thomas | 2006-04-18 22:07:45 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/htdocs/iexploder.cgi
+ M /iexploder/htdocs/webserver.rb
+
+1.3.0
+------------------------------------------------------------------------
+r607 | thomas | 2006-04-18 22:05:47 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/README.txt
+ M /iexploder/htdocs/webserver.rb
+ M /iexploder/tools/osx_last_crash.rb
+
+commit osx_last_crash minutes->days change, document that you can pass a new port number to the webserver.rb program
+------------------------------------------------------------------------
+r606 | thomas | 2006-04-18 22:02:16 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ A /iexploder/testcases/safari/2969_421-Safari-2.0.3_Mac_OS_X-Crash.html
+ A /iexploder/testcases/safari/5763_181-Safari-Nightly-420+-2006-r13911-2006-04-18.html
+
+Add more Safari crashes to the testcases list
+------------------------------------------------------------------------
+r605 | thomas | 2006-04-18 19:05:46 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/README.txt
+ M /iexploder/htdocs/config.rb
+ M /iexploder/htdocs/iexploder.cgi
+ M /iexploder/htdocs/iexploder.rb
+ M /iexploder/htdocs/webserver.rb
+
+Greatly improve subtests. Not only do we iterate around each tag, but we steadily increase the amount of tags we input as well
+------------------------------------------------------------------------
+r604 | thomas | 2006-04-18 17:04:17 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/README.txt
+ M /iexploder/htdocs/config.rb
+
+1.3b1.. also, raise max tags to 48 now that we have fixed subtest bugs
+------------------------------------------------------------------------
+r603 | thomas | 2006-04-18 16:59:20 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/htdocs/iexploder.cgi
+ M /iexploder/htdocs/iexploder.rb
+ A /iexploder/htdocs/webserver.rb
+
+New Webrick based option for standalone hosting
+------------------------------------------------------------------------
+r602 | thomas | 2006-04-18 16:18:35 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ A /iexploder/htdocs/config.rb
+ M /iexploder/htdocs/cssproperties.in
+ M /iexploder/htdocs/iexploder.cgi
+ A /iexploder/htdocs/iexploder.rb
+
+Split iexploder.cgi into iexploder.rb and config.rb
+------------------------------------------------------------------------
+r601 | thomas | 2006-04-18 13:36:25 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/htdocs/cssvalues.in
+
+Add items from WebKit/WebCore/css/CSSValueKeywords.in
+------------------------------------------------------------------------
+r600 | thomas | 2006-04-18 13:32:45 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ A /iexploder/testcases/opera/4750_Opera_8.5.4_Mac_OS_X-Crash.html
+
+Add odd new crash from Opera 8.5.4 for Mac
+------------------------------------------------------------------------
+r599 | thomas | 2006-04-18 13:10:15 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ A /iexploder/testcases/safari/7483_Safari-Nightly-420+-2006-r13911-2006-04-18.html
+
+Add new Safari test case
+------------------------------------------------------------------------
+r598 | thomas | 2006-04-18 12:25:39 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ M /iexploder/LICENSE.txt
+ M /iexploder/README.txt
+ M /iexploder/htdocs/htmlattrs.in
+ M /iexploder/htdocs/htmltags.in
+ M /iexploder/htdocs/iexploder.cgi
+
+iExploder 1.3: sync with modern rendering kits
+------------------------------------------------------------------------
+r597 | thomas | 2006-04-18 12:25:18 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ A /iexploder/testcases/firefox/354_1-Firefox-1.5.0.1_Solaris-Crash.html
+ A /iexploder/testcases/firefox/44_9-Firefox-1.5.0.1_Solaris-Crash.html
+ A /iexploder/testcases/internet_explorer/8386_11-Internet-Explorer-6.0_WinXP-DoS.html (from /iexploder/testcases/safari/8386_11-Internet-Explorer-6.0_WinXP-DoS.html:596)
+ A /iexploder/testcases/safari/218-Safari-2.0.3_Mac_OS_X-Crash.html
+ D /iexploder/testcases/safari/8386_11-Internet-Explorer-6.0_WinXP-DoS.html
+
+New testcases
+------------------------------------------------------------------------
+r596 | thomas | 2006-04-18 12:23:48 -0400 (Tue, 18 Apr 2006) | 1 line
+Changed paths:
+ D /iexploder/testcases/119_4-Safari-Nightly-420+-2005-10-21-Crash.html
+ D /iexploder/testcases/165367_15-FireFox-1.4.1-Crash.html
+ D /iexploder/testcases/2009-iCab-3.0.1-Mac_OS_X-Crash.html
+ D /iexploder/testcases/2289-iCab-3.0.1-Crash.html
+ D /iexploder/testcases/25057-OmniWeb-5.1.1-Crash.html
+ D /iexploder/testcases/2624-Opera-8.5-Mac_OS_X-Crash.html
+ D /iexploder/testcases/502701_7-FireFox-1.4.1-Crash.html
+ D /iexploder/testcases/60253-OmniWeb-5.1.1-Crash.html
+ D /iexploder/testcases/6134_19-Safari-2.0.1-412.5-Crash.html
+ D /iexploder/testcases/8386_11-Internet-Explorer-6.0_WinXP-DoS.html
+ A /iexploder/testcases/firefox
+ A /iexploder/testcases/firefox/165367_15-Firefox-1.4.1-Crash.html (from /iexploder/testcases/165367_15-FireFox-1.4.1-Crash.html:595)
+ A /iexploder/testcases/firefox/502701_7-Firefox-1.4.1-Crash.html (from /iexploder/testcases/502701_7-FireFox-1.4.1-Crash.html:595)
+ A /iexploder/testcases/icab
+ A /iexploder/testcases/icab/2009-iCab-3.0.1-Mac_OS_X-Crash.html (from /iexploder/testcases/2009-iCab-3.0.1-Mac_OS_X-Crash.html:595)
+ A /iexploder/testcases/icab/2289-iCab-3.0.1-Crash.html (from /iexploder/testcases/2289-iCab-3.0.1-Crash.html:595)
+ A /iexploder/testcases/internet_explorer
+ A /iexploder/testcases/omniweb
+ A /iexploder/testcases/omniweb/25057-OmniWeb-5.1.1-Crash.html (from /iexploder/testcases/25057-OmniWeb-5.1.1-Crash.html:595)
+ A /iexploder/testcases/omniweb/60253-OmniWeb-5.1.1-Crash.html (from /iexploder/testcases/60253-OmniWeb-5.1.1-Crash.html:595)
+ A /iexploder/testcases/opera
+ A /iexploder/testcases/opera/2624-Opera-8.5-Mac_OS_X-Crash.html (from /iexploder/testcases/2624-Opera-8.5-Mac_OS_X-Crash.html:595)
+ A /iexploder/testcases/safari
+ A /iexploder/testcases/safari/119_4-Safari-Nightly-420+-2005-10-21-Crash.html (from /iexploder/testcases/119_4-Safari-Nightly-420+-2005-10-21-Crash.html:595)
+ A /iexploder/testcases/safari/6134_19-Safari-2.0.1-412.5-Crash.html (from /iexploder/testcases/6134_19-Safari-2.0.1-412.5-Crash.html:595)
+ A /iexploder/testcases/safari/8386_11-Internet-Explorer-6.0_WinXP-DoS.html (from /iexploder/testcases/8386_11-Internet-Explorer-6.0_WinXP-DoS.html:595)
+
+Reshuffle testcases
+------------------------------------------------------------------------
+r521 | thomas | 2005-11-03 22:01:43 -0500 (Thu, 03 Nov 2005) | 1 line
+Changed paths:
+ A /iexploder/testcases/2289-iCab-3.0.1-Crash.html
+ A /iexploder/testcases/60253-OmniWeb-5.1.1-Crash.html
+
+add some test cases
+------------------------------------------------------------------------
+r520 | thomas | 2005-11-03 22:01:19 -0500 (Thu, 03 Nov 2005) | 1 line
+Changed paths:
+ M /iexploder/htdocs/iexploder.cgi
+
+Add some cute tabs
+------------------------------------------------------------------------
+r508 | thomas | 2005-10-21 15:34:38 -0400 (Fri, 21 Oct 2005) | 1 line
+Changed paths:
+ A /iexploder/testcases/165367_15-FireFox-1.4.1-Crash.html (from /iexploder/testcases/165367_15-FireFox-1.4.1-Mac_OS_X-Crash.html:505)
+ D /iexploder/testcases/165367_15-FireFox-1.4.1-Mac_OS_X-Crash.html
+
+Crash is not OSX specific
+------------------------------------------------------------------------
+r507 | thomas | 2005-10-21 14:59:41 -0400 (Fri, 21 Oct 2005) | 1 line
+Changed paths:
+ M /iexploder/README.txt
+
+Mention the fact that testcases may not be portable across installations
+------------------------------------------------------------------------
+r506 | thomas | 2005-10-21 14:45:48 -0400 (Fri, 21 Oct 2005) | 1 line
+Changed paths:
+ M /iexploder/htdocs/index.html
+
+Fix lookup html code
+------------------------------------------------------------------------
+r505 | thomas | 2005-10-21 14:22:10 -0400 (Fri, 21 Oct 2005) | 1 line
+Changed paths:
+ A /iexploder/testcases/165367_15-FireFox-1.4.1-Mac_OS_X-Crash.html
+
+QuickDraw crash for Mac OS X
+------------------------------------------------------------------------
+r504 | thomas | 2005-10-21 14:14:34 -0400 (Fri, 21 Oct 2005) | 1 line
+Changed paths:
+ A /iexploder/testcases/25057-OmniWeb-5.1.1-Crash.html
+
+New crash
+------------------------------------------------------------------------
+r503 | thomas | 2005-10-21 14:06:45 -0400 (Fri, 21 Oct 2005) | 1 line
+Changed paths:
+ A /iexploder/testcases/8386_11-Internet-Explorer-6.0_WinXP-DoS.html
+
+IE DoS
+------------------------------------------------------------------------
+r502 | thomas | 2005-10-21 13:24:02 -0400 (Fri, 21 Oct 2005) | 1 line
+Changed paths:
+ M /iexploder/README.txt
+ M /iexploder/htdocs/cssvalues.in
+ M /iexploder/htdocs/iexploder.cgi
+ M /iexploder/htdocs/index.html
+ D /iexploder/testcases/100482.html
+ D /iexploder/testcases/103399-nscssvaluelist.html
+ A /iexploder/testcases/119_4-Safari-Nightly-420+-2005-10-21-Crash.html
+ A /iexploder/testcases/2009-iCab-3.0.1-Mac_OS_X-Crash.html
+ A /iexploder/testcases/2624-Opera-8.5-Mac_OS_X-Crash.html
+ A /iexploder/testcases/502701_7-FireFox-1.4.1-Crash.html
+ A /iexploder/testcases/6134_19-Safari-2.0.1-412.5-Crash.html
+ D /iexploder/testcases/firefox-caption-iframe-table-47179.html
+ D /iexploder/testcases/firefox-caption-marquee-27473.html
+ D /iexploder/testcases/firefox-caption-marquee-66937.html
+ D /iexploder/testcases/firefox-isindex-18149.html
+ D /iexploder/testcases/firefox-visibility-caption-111895.html
+
+1.2 Update, mostly documentation and test cases
+------------------------------------------------------------------------
+r501 | thomas | 2005-10-21 11:41:39 -0400 (Fri, 21 Oct 2005) | 1 line
+Changed paths:
+ M /iexploder/tools/osx_last_crash.rb
+
+back to days, filter out synergy
+------------------------------------------------------------------------
+r500 | thomas | 2005-10-21 11:25:28 -0400 (Fri, 21 Oct 2005) | 1 line
+Changed paths:
+ M /iexploder/htdocs/cssvalues.in
+ M /iexploder/htdocs/iexploder.cgi
+ M /iexploder/tools/lasthit.rb
+
+1.2: We now use javascript reloads after 1 second in case the meta breaks (IE)
+------------------------------------------------------------------------
+r499 | thomas | 2005-10-21 08:51:07 -0400 (Fri, 21 Oct 2005) | 1 line
+Changed paths:
+ M /iexploder/htdocs/iexploder.cgi
+
+1.1: Fix up our subtest model
+------------------------------------------------------------------------
+r498 | thomas | 2005-10-20 21:55:59 -0400 (Thu, 20 Oct 2005) | 1 line
+Changed paths:
+ M /iexploder/htdocs/iexploder.cgi
+
+Support for subtests, and compatibility with mod_ruby
+------------------------------------------------------------------------
+r497 | thomas | 2005-10-20 20:48:59 -0400 (Thu, 20 Oct 2005) | 1 line
+Changed paths:
+ M /iexploder/htdocs/cssproperties.in
+ M /iexploder/htdocs/cssvalues.in
+ M /iexploder/htdocs/htmlattrs.in
+ M /iexploder/htdocs/htmlvalues.in
+ M /iexploder/htdocs/iexploder.cgi
+
+update to v1.0
+------------------------------------------------------------------------
+r455 | tstrombe | 2005-02-28 08:13:25 -0500 (Mon, 28 Feb 2005) | 1 line
+Changed paths:
+ A /iexploder
+ A /iexploder/LICENSE.txt
+ A /iexploder/README.txt
+ A /iexploder/htdocs
+ A /iexploder/htdocs/cssproperties.in
+ A /iexploder/htdocs/cssvalues.in
+ A /iexploder/htdocs/htmlattrs.in
+ A /iexploder/htdocs/htmltags.in
+ A /iexploder/htdocs/htmlvalues.in
+ A /iexploder/htdocs/iexploder.cgi
+ A /iexploder/htdocs/index.html
+ A /iexploder/testcases
+ A /iexploder/testcases/100482.html
+ A /iexploder/testcases/103399-nscssvaluelist.html
+ A /iexploder/testcases/firefox-caption-iframe-table-47179.html
+ A /iexploder/testcases/firefox-caption-marquee-27473.html
+ A /iexploder/testcases/firefox-caption-marquee-66937.html
+ A /iexploder/testcases/firefox-isindex-18149.html
+ A /iexploder/testcases/firefox-visibility-caption-111895.html
+ A /iexploder/tools
+ A /iexploder/tools/lasthit.rb
+ A /iexploder/tools/osx_last_crash.rb
+
+iexploder software
+------------------------------------------------------------------------
diff --git a/Tools/iExploder/iexploder-1.3.2/LICENSE.txt b/Tools/iExploder/iexploder-1.3.2/LICENSE.txt
new file mode 100644
index 0000000..5199718
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/LICENSE.txt
@@ -0,0 +1,20 @@
+#
+# Copyright (c) 2005 Thomas Stromberg <thomas%stromberg.org>
+#
+# This software is provided 'as-is', without any express or implied warranty.
+# In no event will the authors be held liable for any damages arising from the
+# use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software in a
+# product, an acknowledgment in the product documentation would be appreciated
+# but is not required.
+#
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+#
+# 3. This notice may not be removed or altered from any source distribution.
diff --git a/Tools/iExploder/iexploder-1.3.2/README.txt b/Tools/iExploder/iexploder-1.3.2/README.txt
new file mode 100644
index 0000000..a941697
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/README.txt
@@ -0,0 +1,149 @@
+iExploder 1.3.2
+===============
+
+Welcome to iExploder. a highly inefficient, but fairly effective web
+browser tester. The code still has a lot of work to be done, but it's
+definitely usable. Here are some notable features:
+
+* Tests all common HTML and CSS tags and attributes, as parsed from
+the KHTML, WebKit and Mozilla source trees, as well as tags for
+Internet Explorer from MSDN. This also includes a few Javascript hooks.
+* Numeric, and String overflow and formatting tests
+* Sequential and Randomized Test Case Generation
+* Test Case Lookups
+* Subtest generation
+
+
+Installation (Standalone)
+-------------------------
+Make sure you have Ruby installed (comes with Mac OS X, most Linux
+distributions). See http://www.ruby-lang.org/ if you do not.
+
+If you do not already have a webserver setup, you can use the server
+built into iexploder. Simply go into the htdocs directory and type:
+
+% ruby webserver.rb
+
+A webserver will then start on port 2000 with the iexploder form. If
+port 2000 is not preferable, you can pass it another port on the command
+line:
+
+% ruby webserver.rb 2001
+
+Please note that lasthit.rb does not currently work with the logs output
+from this method. I recommend using a seperate instance/port number
+for each browser you test simultaneous using this method.
+
+
+Installation (External Webserver)
+---------------------------------
+If you wish to use an external webserver (required for lasthit.rb use),
+you may do so. IExploder has been tested with apache.
+
+Copy the contents of the htdocs/ folder to any directory served
+by your webserver. Make sure that directory can execute CGI scripts. If
+performance seems to be low, please try using mod_ruby.
+
+
+FAQ:
+----
+1) Are the tests always the same?
+
+ The test cases should always be the same on a single installation, but not
+necessarily on different installations of iExploder. Random generator seeds
+may differ between operating systems and platforms. If you alter the tag and
+property counts in config.rb, it will change the test cases as well.
+
+
+2) How do I look up the last successful test for a client?
+
+Use tools/lasthit.rb. When I get a crash, I usually do something like:
+
+ % tail -15000 /var/log/apache2/access_log | ./lasthit.rb
+
+Letting you know how many tests and what the last test id was for each
+client tested. You can then try to repeat the test, or go through the
+subtests to see if you can repeat the crash.
+
+
+3) How do subtests work?
+
+If you see a crash on a particular test, and would like to determine the exact
+line that is crashing it, you can use subtests. To do so, go back to the test
+submission form, and start the test from the number that a crash was indicated
+on. Instead of leaving the "subtest" field blank, set it to 1. This will rotate
+through each subtest for a particular test.
+
+Each subtest will rotate through a tag offset and a number of tags to
+garble, which should help you isolate the instance. The number of tags
+used doubles each cycle. Here is an idea of how many subtests to expect
+based on your $HTML_MAX_TAGS settings:
+
+tags subtests
+----------------
+32 138
+48 236
+64 332
+96 558
+128 782
+
+Most of the time you will be able to replicate a crash within the first
+$HTML_MAX_TAGS subtests, but sometimes crashes are due to a combination
+of corrupted tags.
+
+
+4) How come I can't seem to repeat the crash?
+
+ Many browser crashes are race conditions that are not easy to repeat. Some
+crashes only happen when going from test 4 -> test 5 -> test 6. If you can't
+repeat the crash through subtests or a lookup of the failing test, try going
+back a few tests.
+
+That said, some crashes are due to race conditions that are very difficult
+to replicate.
+
+
+5) Why did you write this?
+
+ I wanted to make sure that FireFox had as many bugs fixed in it as possible
+before the 1.0 release. After 1.0 came out, I kept improving it.
+
+
+6) Why does Internet Explorer run the tests so slowly?
+
+ <META> refresh tags are very fragile in Internet Explorer, and can be easily
+be rendered useless by other tags on the page. If this happens, a javascript
+refresh will execute after a 1 second delay.
+
+
+
+7) How do I change the number of tags iExploder tests per page?
+
+See config.rb. I personally recommend 32-128 HTML tags per page. While this
+seems to be a lot to go through when designing a test case, that's why the
+subtest engine was made. Different web browsers will have different
+performance characteristics when it comes to the number of tags per page.
+
+Here are the results with Firefox 2.0b1 (Bon Echo) and the iExploder
+built-in webserver running tests 1-250.
+
+tags seconds pages/second tags/second
+-----------------------------------------
+32 60 4.0 131
+48 85 2.9 141
+64 95 2.6 168
+96 120 2.1 200 *DEFAULT*
+128 140 1.8 228
+196 228 1.1 210
+256 308 0.8 207
+
+If you find pages/second to be more important than tags/second, I would
+change $HTML_MAX_TAGS to 32. Do keep in mind that large tag counts mean
+longer subtest generation periods.
+
+
+8) What other performance enhancements can I make?
+
+* Before using iExploder, reset your browser history
+* Minimize your browser while iExploder is running
+* If using Apache, make use of mod_ruby
diff --git a/Tools/iExploder/iexploder-1.3.2/htdocs/config.rb b/Tools/iExploder/iexploder-1.3.2/htdocs/config.rb
new file mode 100644
index 0000000..d9e7e1b
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/htdocs/config.rb
@@ -0,0 +1,6 @@
+# Configuration for iExploder.. not generally tuned.
+
+$HTML_MAX_TAGS = 96;
+$HTML_MAX_ATTRS = 4;
+$CSS_MAX_PROPS = 5;
+
diff --git a/Tools/iExploder/iexploder-1.3.2/htdocs/cssproperties.in b/Tools/iExploder/iexploder-1.3.2/htdocs/cssproperties.in
new file mode 100644
index 0000000..d49eb8e
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/htdocs/cssproperties.in
@@ -0,0 +1,426 @@
+# From WebKit svn r66165 (WebCore/css/CSSPropertyNames.in)
+-webkit-animation
+-webkit-animation-delay
+-webkit-animation-direction
+-webkit-animation-duration
+-webkit-animation-fill-mode
+-webkit-animation-iteration-count
+-webkit-animation-name
+-webkit-animation-play-state
+-webkit-animation-timing-function
+-webkit-appearance
+-webkit-backface-visibility
+-webkit-background-clip
+-webkit-background-composite
+-webkit-background-origin
+-webkit-background-size
+-webkit-border-end
+-webkit-border-end-color
+-webkit-border-end-style
+-webkit-border-end-width
+-webkit-border-fit
+-webkit-border-horizontal-spacing
+-webkit-border-image
+-webkit-border-radius
+-webkit-border-start
+-webkit-border-start-color
+-webkit-border-start-style
+-webkit-border-start-width
+-webkit-border-vertical-spacing
+-webkit-box-align
+-webkit-box-direction
+-webkit-box-flex
+-webkit-box-flex-group
+-webkit-box-lines
+-webkit-box-ordinal-group
+-webkit-box-orient
+-webkit-box-pack
+-webkit-box-reflect
+-webkit-box-shadow
+-webkit-color-correction
+-webkit-column-break-after
+-webkit-column-break-before
+-webkit-column-break-inside
+-webkit-column-count
+-webkit-column-gap
+-webkit-column-rule
+-webkit-column-rule-color
+-webkit-column-rule-style
+-webkit-column-rule-width
+-webkit-column-span
+-webkit-column-width
+-webkit-columns
+-webkit-font-size-delta
+-webkit-font-smoothing
+-webkit-highlight
+-webkit-hyphenate-character
+-webkit-hyphenate-locale
+-webkit-hyphens
+-webkit-line-break
+-webkit-line-clamp
+-webkit-margin-bottom-collapse
+-webkit-margin-collapse
+-webkit-margin-end
+-webkit-margin-start
+-webkit-margin-top-collapse
+-webkit-marquee
+-webkit-marquee-direction
+-webkit-marquee-increment
+-webkit-marquee-repetition
+-webkit-marquee-speed
+-webkit-marquee-style
+-webkit-mask
+-webkit-mask-attachment
+-webkit-mask-box-image
+-webkit-mask-clip
+-webkit-mask-composite
+-webkit-mask-image
+-webkit-mask-origin
+-webkit-mask-position
+-webkit-mask-position-x
+-webkit-mask-position-y
+-webkit-mask-repeat
+-webkit-mask-repeat-x
+-webkit-mask-repeat-y
+-webkit-mask-size
+-webkit-match-nearest-mail-blockquote-color
+-webkit-nbsp-mode
+-webkit-padding-end
+-webkit-padding-start
+-webkit-perspective
+-webkit-perspective-origin
+-webkit-perspective-origin-x
+-webkit-perspective-origin-y
+-webkit-rtl-ordering
+-webkit-text-decorations-in-effect
+-webkit-text-fill-color
+-webkit-text-security
+-webkit-text-size-adjust
+-webkit-text-stroke
+-webkit-text-stroke-color
+-webkit-text-stroke-width
+-webkit-transform
+-webkit-transform-origin
+-webkit-transform-origin-x
+-webkit-transform-origin-y
+-webkit-transform-origin-z
+-webkit-transform-style
+-webkit-transition
+-webkit-transition-delay
+-webkit-transition-duration
+-webkit-transition-property
+-webkit-transition-timing-function
+-webkit-user-drag
+-webkit-user-modify
+-webkit-user-select
+-webkit-variable-declaration-block
+background
+background-attachment
+background-clip
+background-color
+background-image
+background-origin
+background-position
+background-position-x
+background-position-y
+background-repeat
+background-repeat-x
+background-repeat-y
+background-size
+border
+border-bottom
+border-bottom-color
+border-bottom-left-radius
+border-bottom-right-radius
+border-bottom-style
+border-bottom-width
+border-collapse
+border-color
+border-left
+border-left-color
+border-left-style
+border-left-width
+border-radius
+border-right
+border-right-color
+border-right-style
+border-right-width
+border-spacing
+border-style
+border-top
+border-top-color
+border-top-left-radius
+border-top-right-radius
+border-top-style
+border-top-width
+border-width
+bottom
+box-sizing
+caption-side
+clear
+clip
+color
+content
+counter-increment
+counter-reset
+cursor
+direction
+display
+empty-cells
+float
+font
+font-family
+font-size
+font-stretch
+font-style
+font-variant
+font-weight
+height
+left
+letter-spacing
+line-height
+list-style
+list-style-image
+list-style-position
+list-style-type
+margin
+margin-bottom
+margin-left
+margin-right
+margin-top
+max-height
+max-width
+min-height
+min-width
+opacity
+orphans
+outline
+outline-color
+outline-offset
+outline-style
+outline-width
+overflow
+overflow-x
+overflow-y
+padding
+padding-bottom
+padding-left
+padding-right
+padding-top
+page
+page-break-after
+page-break-before
+page-break-inside
+pointer-events
+position
+quotes
+resize
+right
+size
+src
+table-layout
+text-align
+text-decoration
+text-indent
+text-line-through
+text-line-through-color
+text-line-through-mode
+text-line-through-style
+text-line-through-width
+text-overflow
+text-overline
+text-overline-color
+text-overline-mode
+text-overline-style
+text-overline-width
+text-rendering
+text-shadow
+text-transform
+text-underline
+text-underline-color
+text-underline-mode
+text-underline-style
+text-underline-width
+top
+unicode-bidi
+unicode-range
+vertical-align
+visibility
+white-space
+widows
+width
+word-break
+word-spacing
+word-wrap
+z-index
+zoom
+
+# CSS3 properties - http://www.css3.info/preview/
+background-clip
+background-origin
+border-image
+border-radius
+box-shadow
+box-sizing
+column-count
+column-gap
+column-min-width
+column-rule
+column-rule-color
+column-rule-style
+column-rule-width
+column-space-distribution
+column-span
+column-width
+column-width-policy
+
+# Removed from WebKit between r53119 and r66165
+-webkit-binding
+
+# Removed from WebKit between r44660 and r53119
+-webkit-border-bottom-left-radius
+-webkit-border-bottom-right-radius
+-webkit-border-top-left-radius
+-webkit-border-top-right-radius
+
+# Removed from WebKit between r24523 and r44660
+-webkit-dashboard-region
+scrollbar-3dlight-color
+scrollbar-arrow-color
+scrollbar-darkshadow-color
+scrollbar-face-color
+scrollbar-highlight-color
+scrollbar-shadow-color
+scrollbar-track-color
+
+# All of the following are from khtml's cssproperties.in as of 19oct2004, but are no longer in WebKit
+-khtml-border-horizontal-spacing
+-khtml-border-vertical-spacing
+-khtml-flow-mode
+-khtml-marquee
+-khtml-marquee-direction
+-khtml-marquee-increment
+-khtml-marquee-repetition
+-khtml-marquee-speed
+-khtml-marquee-style
+-khtml-text-decoration-color
+-khtml-user-input
+scrollbar-base-color
+
+# Internet Explorer 6.0 - http://msdn.microsoft.com/workshop/author/css/reference/attributes.asp
+filter:progid:
+filter:
+ime-mode
+layout-flow
+layout-grid
+layout-grid-char
+layout-grid-line
+layout-grid-mode
+layout-grid-type
+line-break
+overflow-x
+overflow-y
+pagebreakafter
+pagebreakbefore
+ruby-align
+ruby-overhang
+ruby-position
+text-autospace
+text-justify
+text-kashida-space
+text-underline-position
+word-break
+writing-mode
+zoom
+
+# from http://msdn.microsoft.com/library/default.asp?url=/workshop/author/filter/reference/reference.asp
+filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(
+filter:progid:DXImageTransform.Microsoft.Blur(
+filter:progid:DXImageTransform.Microsoft.MotionBlur(
+filter:progid:DXImageTransform.Microsoft.Gradient(
+filter:progid:DXImageTransform.Microsoft.Pixelate(
+
+# From Mozilla Firefox CVS on 2006-04-15 (layout/style/nsCSSPropList.h)
+# grep "^CSS_PROP" nsCSSPropList.h | grep -v "_SVG" |cut -d, -f1 | cut -d\( -f2 | sort
+++ /tmp/moz Tue Apr 18 13:45:30 2006
+-moz-appearance
+-moz-background-clip
+-moz-background-inline-policy
+-moz-background-origin
+-moz-binding
+-moz-border-bottom-colors
+-moz-border-left-colors
+-moz-border-radius
+-moz-border-radius-bottomleft
+-moz-border-radius-bottomright
+-moz-border-radius-topleft
+-moz-border-radius-topright
+-moz-border-right-colors
+-moz-border-top-colors
+-moz-box-align
+-moz-box-direction
+-moz-box-flex
+-moz-box-ordinal-group
+-moz-box-orient
+-moz-box-pack
+-moz-box-sizing
+-moz-column-count
+-moz-column-gap
+-moz-column-width
+-moz-float-edge
+-moz-force-broken-image-icon
+-moz-image-region
+-moz-margin-end
+-moz-margin-start
+-moz-outline-radius
+-moz-outline-radius-bottomleft
+-moz-outline-radius-bottomright
+-moz-outline-radius-topleft
+-moz-outline-radius-topright
+-moz-padding-end
+-moz-padding-start
+-moz-user-focus
+-moz-user-input
+-moz-user-modify
+-moz-user-select
+-x-background-x-position
+-x-background-y-position
+azimuth
+cue
+cue-after
+cue-before
+elevation
+font-size-adjust
+margin-end-value
+margin-left-ltr-source
+margin-left-rtl-source
+margin-left-value
+margin-right-ltr-source
+margin-right-rtl-source
+margin-right-value
+margin-start-value
+marker
+marker-offset
+marks
+padding-end-value
+padding-left-ltr-source
+padding-left-rtl-source
+padding-left-value
+padding-right-ltr-source
+padding-right-rtl-source
+padding-right-value
+padding-start-value
+pause
+pause-after
+pause-before
+pitch
+pitch-range
+richness
+speak
+speak-header
+speak-numeral
+speak-punctuation
+speech-rate
+stress
+voice-family
+volume
diff --git a/Tools/iExploder/iexploder-1.3.2/htdocs/cssvalues.in b/Tools/iExploder/iexploder-1.3.2/htdocs/cssvalues.in
new file mode 100644
index 0000000..c19f78f
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/htdocs/cssvalues.in
@@ -0,0 +1,339 @@
+"Trebuchet MS",Verdana, Arial, Helvetica, sans-serif
+#339933 !important !important !important
+#9999999999999999999999999999999999999999999
+-5, -5, -5
+-9999%
+-999999999999999999999999999%
+-999999999999999999999999999em
+-999999999999999999999999999px
+-9999em
+-9999px
+-webkit-activelink
+-webkit-auto
+-webkit-baseline-middle
+-webkit-body
+-webkit-box
+-webkit-center
+-webkit-focus-ring-color
+-webkit-inline-box
+-webkit-left
+-webkit-link
+-webkit-marquee
+-webkit-nowrap
+-webkit-overlay
+-webkit-right
+-webkit-text
+-webkit-xxx-large
+0
+0 auto
+0 fixed
+2%
+90000000000000000000000000000000000000000000%
+9999999999999999999999
+99999999999999999999999999999999999999 auto
+99999999999999999999999999999999999999999999px
+999999px solid #fff
+above
+absolute
+activeborder
+activecaption
+after-white-space
+ahead
+alternate
+always
+appworkspace
+aqua
+armenian
+attr("ATTRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
+auto
+avoid
+background
+backwards
+baseline
+below
+bidi-override
+black
+blink
+block
+block clear
+block width
+block-axis
+blue
+bold
+bolder
+border
+border-box
+both
+bottom
+break-word
+button
+button-bevel
+buttonface
+buttonhighlight
+buttonshadow
+buttontext
+capitalize
+caption
+captiontext
+caret
+center
+checkbox
+circle
+cjk-ideographic
+clip
+clip:rect(-0px -2000000px -200000px -0px)
+clip:rect(0px 2000000px 200000px 0px)
+close-quote
+collapse
+compact
+condensed
+content
+content-box
+continuous
+crop
+cross
+crosshair
+cursive
+dashed
+decimal
+decimal-leading-zero
+default
+disc
+discard
+dot-dash
+dot-dot-dash
+dotted
+double
+down
+e-resize
+element
+ellipsis
+embed
+end
+expanded
+extra-condensed
+extra-expanded
+fantasy
+fast
+fixed
+forwards
+fuchsia
+georgian
+gray
+graytext
+green
+grey
+groove
+hand
+hebrew
+help
+helvetica, arial, Courier New, Courier, Mono, Blah, Blah, Blah
+hidden
+hide
+higher
+highlight
+highlighttext
+hiragana
+hiragana-iroha
+horizontal
+icon
+ignore
+inactiveborder
+inactivecaption
+inactivecaptiontext
+infinite
+infobackground
+infotext
+inherit
+initial
+inline
+inline-axis
+inline-block
+inline-table
+inset
+inside
+intrinsic
+invert
+italic
+justify
+katakana
+katakana-iroha
+landscape
+large
+larger
+left
+level
+lighter
+lime
+line-through
+list-item
+listbox
+listitem
+logical
+loud
+lower
+lower-alpha
+lower-greek
+lower-latin
+lower-roman
+lowercase
+ltr
+marker
+maroon
+match
+medium
+menu
+menulist
+menulist-button
+menulist-text
+menulist-textfield
+menutext
+message-box
+middle
+min-intrinsic
+mix
+monospace
+move
+multiple
+n-resize
+narrower
+navy
+ne-resize
+no-close
+no-close-quote
+no-open-quote
+no-repeat
+none
+normal
+normal !important
+nowrap
+nw-resize
+oblique
+olive
+once
+open-quote
+orange
+outset
+outside
+overline
+padding
+pointer
+portrait
+pre
+pre-line
+pre-wrap
+purple
+push-button
+radio
+read-only
+read-write
+read-write-plaintext-only
+red
+relative
+repeat
+repeat-x
+repeat-y
+reverse
+rgb(9999999999, 999999999, 9999999999999)
+ridge
+right
+round
+rtl
+run-in
+s-resize
+sans-serif
+scroll
+scrollbar
+scrollbarbutton-down
+scrollbarbutton-left
+scrollbarbutton-right
+scrollbarbutton-up
+scrollbargripper-horizontal
+scrollbargripper-vertical
+scrollbarthumb-horizontal
+scrollbarthumb-vertical
+scrollbartrack-horizontal
+scrollbartrack-vertical
+se-resize
+searchfield
+searchfield-close
+searchfield-results
+semi-condensed
+semi-expanded
+separate
+serif
+show
+silver
+single
+skip-white-space
+slide
+slider-horizontal
+slider-vertical
+sliderthumb-horizontal
+sliderthumb-vertical
+slow
+small
+small-caps
+small-caption
+smaller
+solid
+space
+square
+square-button
+start
+static
+status-bar
+stretch
+sub
+super
+sw-resize
+table
+table-caption
+table-cell
+table-column
+table-column-group
+table-footer-group
+table-header-group
+table-row
+table-row-group
+teal
+text
+text-bottom
+text-top
+textfield
+thick
+thick dashed yellow
+thick dotted blue
+thin
+threeddarkshadow
+threedface
+threedhighlight
+threedlightshadow
+threedshadow
+top
+transparent
+ultra-condensed
+ultra-expanded
+underline
+unfurl
+up
+upper-alpha
+upper-latin
+upper-roman
+uppercase
+vertical
+visible
+visual
+w-resize
+wait
+wave
+white
+wider
+window
+windowframe
+windowtext
+x-large
+x-small
+xx-large
+xx-small
+yellow
diff --git a/Tools/iExploder/iexploder-1.3.2/htdocs/htmlattrs.in b/Tools/iExploder/iexploder-1.3.2/htdocs/htmlattrs.in
new file mode 100644
index 0000000..0dc8116
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/htdocs/htmlattrs.in
@@ -0,0 +1,373 @@
+# From WebKit svn r66165 (WebCore/html/HTMLAttributeNames.in)
+abbr
+accept
+accept_charset
+accesskey
+action
+align
+alink
+alt
+archive
+aria-activedescendant
+aria-atomic
+aria-busy
+aria-checked
+aria-controls
+aria-describedby
+aria-disabled
+aria-dropeffect
+aria-expanded
+aria-flowto
+aria-grabbed
+aria-haspopup
+aria-help
+aria-hidden
+aria-label
+aria-labeledby
+aria-labelledby
+aria-level
+aria-live
+aria-multiselectable
+aria-orientation
+aria-owns
+aria-pressed
+aria-readonly
+aria-relevant
+aria-required
+aria-selected
+aria-valuemax
+aria-valuemin
+aria-valuenow
+aria-valuetext
+async
+autocomplete
+autofocus
+autoplay
+autosave
+axis
+background
+behavior
+bgcolor
+bgproperties
+border
+bordercolor
+cellborder
+cellpadding
+cellspacing
+challenge
+char
+charoff
+charset
+checked
+cite
+class
+classid
+clear
+code
+codebase
+codetype
+color
+cols
+colspan
+compact
+composite
+content
+contenteditable
+controls
+coords
+data
+datetime
+declare
+defer
+dir
+direction
+disabled
+draggable
+enctype
+end
+event
+expanded
+face
+focused
+for
+formnovalidate
+frame
+frameborder
+headers
+height
+hidden
+high
+href
+hreflang
+hspace
+http_equiv
+id
+incremental
+indeterminate
+ismap
+keytype
+label
+lang
+language
+leftmargin
+link
+list
+longdesc
+loop
+loopend
+loopstart
+low
+lowsrc
+manifest
+marginheight
+marginwidth
+max
+maxlength
+mayscript
+media
+method
+min
+multiple
+name
+nohref
+noresize
+noshade
+novalidate
+nowrap
+object
+onabort
+onbeforecopy
+onbeforecut
+onbeforeload
+onbeforepaste
+onbeforeprocess
+onbeforeunload
+onblur
+oncanplay
+oncanplaythrough
+onchange
+onclick
+oncontextmenu
+oncopy
+oncut
+ondblclick
+ondrag
+ondragend
+ondragenter
+ondragleave
+ondragover
+ondragstart
+ondrop
+ondurationchange
+onemptied
+onended
+onerror
+onfocus
+onfocusin
+onfocusout
+onhashchange
+oninput
+oninvalid
+onkeydown
+onkeypress
+onkeyup
+onload
+onloadeddata
+onloadedmetadata
+onloadstart
+onmousedown
+onmousemove
+onmouseout
+onmouseover
+onmouseup
+onmousewheel
+onoffline
+ononline
+onorientationchange
+onpagehide
+onpageshow
+onpaste
+onpause
+onplay
+onplaying
+onpopstate
+onprogress
+onratechange
+onreset
+onresize
+onscroll
+onsearch
+onseeked
+onseeking
+onselect
+onselectstart
+onstalled
+onstorage
+onsubmit
+onsuspend
+ontimeupdate
+ontouchcancel
+ontouchend
+ontouchmove
+ontouchstart
+onunload
+onvolumechange
+onwaiting
+onwebkitanimationend
+onwebkitanimationiteration
+onwebkitanimationstart
+onwebkitbeginfullscreen
+onwebkitendfullscreen
+onwebkittransitionend
+optimum
+pattern
+placeholder
+playcount
+pluginurl
+poster
+precision
+preload
+primary
+profile
+progress
+prompt
+readonly
+rel
+required
+results
+rev
+role
+rows
+rowspan
+rules
+sandbox
+scheme
+scope
+scrollamount
+scrolldelay
+scrolling
+selected
+shape
+size
+sortable
+sortdirection
+span
+speech
+spellcheck
+src
+standby
+start
+step
+style
+summary
+tabindex
+tableborder
+target
+text
+title
+top
+topmargin
+truespeed
+type
+usemap
+valign
+value
+valuetype
+version
+viewsource
+vlink
+vspace
+webkitdirectory
+width
+wrap
+
+# Removed from WebKit between r53119 and r56558
+autobuffer
+
+# Removed from WebKit between r14011 and r53119
+left
+pagex
+pagey
+plain
+pluginpage
+pluginspage
+
+# was in khtml in 2004, but is no longer in WebCore
+accept-charset
+html
+http-equiv
+nosave
+oversrc
+unknown
+visibility
+z-index
+
+# From Mozilla CVS 2006-04-15 (mozilla/layout/style/xbl-marquee)
+bounce
+finish
+onbounce
+onfinish
+onstart
+
+
+# IE specific, from msdn.microsoft.com/workshop/author/dhtml/reference/properties
+acceptcharset
+allowtransparency
+balance
+choff
+datafld
+dataformatas
+datapagesize
+datasrc
+dynsrc
+framespacing
+galleryimg
+hidefocus
+methods
+scroll
+units
+urn
+volume
+
+# From Mozilla CVS 2006-04-15 (mozilla/content/base/src/nsGkAtomList.h)
+# To get these, I used:
+# ggrep -r "Get.*Attr" * | perl -ne 'if (/nsHTMLAtoms::(\w+)/) { \
+# system("grep \\($1, content/base/src/nsGkAtomList.h"); }' \
+# | cut -d\" -f2 | sort -u
+autocheck
+base
+bottommargin
+event
+font-weight
+handler
+layout
+observer
+ping
+point-size
+rightmargin
+variable
+
+# events from Mozilla CVS 2006-04-15 (mozilla/content/base/src/nsGkAtomList.h)
+# cat nsGkAtomList.h | grep GK_ATOM | cut -d\" -f2 | egrep "^on[a-z]+"
+onzoom
+onunderflow
+ontext
+onset
+onpopupshown
+onpopupshowing
+onpopuphiding
+onpopuphidden
+onpaint
+onpageshow
+onpagehide
+onoverflowchanged
+onoverflow
+onget
+ondraggesture
+ondragexit
+ondragdrop
+oncompositionstart
+oncompositionend
+oncommandupdate
+oncommand
+onclose
diff --git a/Tools/iExploder/iexploder-1.3.2/htdocs/htmltags.in b/Tools/iExploder/iexploder-1.3.2/htdocs/htmltags.in
new file mode 100644
index 0000000..319d528
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/htdocs/htmltags.in
@@ -0,0 +1,155 @@
+# From WebKit svn r66165 (WebCore/html/HTMLTagNames.in)
+a
+abbr
+acronym
+address
+applet
+area
+article
+aside
+audio
+b
+base
+basefont
+bdo
+bgsound
+big
+blockquote
+body
+br
+button
+canvas
+caption
+center
+cite
+code
+col
+colgroup
+command
+datagrid
+datalist
+dcell
+dcol
+dd
+del
+details
+dfn
+dir
+div
+dl
+drow
+dt
+em
+embed
+fieldset
+figcaption
+figure
+font
+footer
+form
+frame
+frameset
+h1
+h2
+h3
+h4
+h5
+h6
+head
+header
+hgroup
+hr
+html
+i
+iframe
+image
+img
+input
+ins
+isindex
+kbd
+keygen
+label
+layer
+legend
+li
+link
+listing
+map
+mark
+marquee
+menu
+meta
+meter
+nav
+nobr
+noembed
+noframes
+nolayer
+noscript
+noscript
+object
+ol
+optgroup
+option
+p
+param
+plaintext
+pre
+progress
+q
+rp
+rt
+ruby
+s
+samp
+script
+section
+select
+small
+source
+span
+strike
+strong
+style
+sub
+summary
+sup
+table
+tbody
+td
+textarea
+tfoot
+th
+thead
+title
+tr
+track
+tt
+u
+ul
+var
+video
+wbr
+xmp
+
+# This was in khtml in 10-2004
+ilayer
+
+# Additions from Mozilla CVS, 2006-04-18.
+# mozilla/parser/htmlparser/public/nsHTMLTagList.h
+bgsound
+blink
+multicol
+spacer
+
+# The following tags used to be in Mozilla in 10-2004, now removed
+counter
+endnote
+parsererror
+server
+sound
+sourcetext
+
+# From Internet Explorer - http://msdn.microsoft.com/workshop/author/html/reference/elements.asp
+xml
diff --git a/Tools/iExploder/iexploder-1.3.2/htdocs/htmlvalues.in b/Tools/iExploder/iexploder-1.3.2/htdocs/htmlvalues.in
new file mode 100644
index 0000000..d54984f
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/htdocs/htmlvalues.in
@@ -0,0 +1,35 @@
+# Many of the following are from mangleme.cgi.c's make_up_value() function
+#
+*
+_blank
+_parent
+_self
+_top
+about:
+about:plugins
+file:
+http:
+jar:
+javascript:
+left
+top
+%n%n%n%n%n
+ftp:
+right
+wysiwyg:
+bottom
+none
+ldap:
+%i %i
+999999999,9999999,999999999,9999999,999999999,9999999,999999999,9999999,9
+999999999,9999999,9
+999999999,9999999
+true
+false
+_SEARCH
+javascript
+off
+on
+vbscript
+password
+image
diff --git a/Tools/iExploder/iexploder-1.3.2/htdocs/iexploder.cgi b/Tools/iExploder/iexploder-1.3.2/htdocs/iexploder.cgi
new file mode 100755
index 0000000..89e099c
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/htdocs/iexploder.cgi
@@ -0,0 +1,45 @@
+#!/usr/bin/ruby
+# iExploder - Generates bad HTML files to perform QA for web browsers.
+# Developed for the Mozilla Foundation.
+#####################
+#
+# Copyright (c) 2006 Thomas Stromberg <thomas%stromberg.org>
+#
+# This software is provided 'as-is', without any express or implied warranty.
+# In no event will the authors be held liable for any damages arising from the
+# use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software in a
+# product, an acknowledgment in the product documentation would be appreciated
+# but is not required.
+#
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+#
+# 3. This notice may not be removed or altered from any source distribution.
+
+require 'cgi';
+require 'iexploder';
+require 'config';
+
+### THE INTERACTION ##################################
+ie = IExploder.new($HTML_MAX_TAGS, $HTML_MAX_ATTRS, $CSS_MAX_PROPS)
+ie.readTagFiles()
+
+cgi = CGI.new("html4");
+ie.url=ENV['SCRIPT_NAME'] || '?'
+ie.test_num = cgi.params['test'][0].to_i
+ie.subtest_num = cgi.params['subtest'][0].to_i || 0
+ie.random_mode = cgi.params['random'][0]
+ie.lookup_mode = cgi.params['lookup'][0]
+ie.stop_num = cgi.params['stop'][0].to_i || 0
+ie.setRandomSeed
+
+cgi.out('type' => 'text/html') do
+ ie.buildPage()
+end
diff --git a/Tools/iExploder/iexploder-1.3.2/htdocs/iexploder.rb b/Tools/iExploder/iexploder-1.3.2/htdocs/iexploder.rb
new file mode 100644
index 0000000..eee3e38
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/htdocs/iexploder.rb
@@ -0,0 +1,337 @@
+# iExploder - Generates bad HTML files to perform QA for web browsers.
+# Developed for the Mozilla Foundation.
+#####################
+#
+# Copyright (c) 2006 Thomas Stromberg <thomas%stromberg.org>
+#
+# This software is provided 'as-is', without any express or implied warranty.
+# In no event will the authors be held liable for any damages arising from the
+# use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software in a
+# product, an acknowledgment in the product documentation would be appreciated
+# but is not required.
+#
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+#
+# 3. This notice may not be removed or altered from any source distribution.
+
+$VERSION="1.3.2"
+
+class IExploder
+ attr_accessor :test_num, :subtest_num, :lookup_mode, :random_mode, :url
+ attr_accessor :offset, :lines, :stop_num
+
+ def initialize(max_tags, max_attrs, max_props)
+ @htmlMaxTags = max_tags
+ @htmlMaxAttrs = max_attrs
+ @cssMaxProps = max_props
+ @mangledTagTotal = 0
+ @stop_num = 0
+ end
+
+ def setRandomSeed
+ if @test_num > 0
+ srand(@test_num)
+ else
+ srand
+ end
+ end
+
+
+ def readTagFiles
+ # These if statements are so that mod_ruby doesn't have to reload the files
+ # each time
+
+ if (! @cssTags)
+ @cssTags = readTagFile('cssproperties.in');
+ end
+
+ if (! @htmlTags)
+ @htmlTags = readTagFile('htmltags.in');
+ end
+ if (! @htmlAttr)
+ @htmlAttr = readTagFile('htmlattrs.in');
+ end
+
+ if (! @htmlValues)
+ @htmlValues = readTagFile('htmlvalues.in');
+ end
+
+ if (! @cssValues)
+ @cssValues = readTagFile('cssvalues.in');
+ end
+
+ end
+
+
+ def readTagFile(filename)
+ list = Array.new
+ File.new(filename).readlines.each { |line|
+ line.chop!
+
+ # Don't include comments.
+ if (line !~ /^# /) && (line.length > 0)
+ list << line
+ end
+ }
+ return list
+ end
+
+ # based on make_up_value, essentially.
+ def inventValue
+ value = rand(19);
+ case value
+ when 1..3 then return (@htmlValues[rand(@htmlValues.length)])
+ when 4..5 then return (@htmlValues[rand(@htmlValues.length)] + inventValue())
+ when 6 then return (@htmlValues[rand(@htmlValues.length)] + "//" + inventValue())
+ when 7 then return ''
+ # this may return negative argument?
+ when 8..10 then return rand(255).chr * (rand(256)+8)
+ when 11 then return rand(255).chr * (rand(2048)+8)
+ when 12 then return "#" + rand(999999).to_s
+ when 13 then return rand(999999).to_s + "%"
+ when 14..15 then return "&" + rand(999999).to_s + ";"
+ # filters
+ when 16 then
+ return inventValue() + "=" + inventValue()
+
+ # this my return undefined method + for nil:NilClass
+ when 17 then return inventValue() + "," + inventValue()
+ else
+ if rand(5) > 3
+ return "-" + rand(999999).to_s
+ else
+ return rand(999999).to_s
+ end
+ end
+ end
+
+ # based on make_up_value, essentially.
+ def inventCssValue(tag)
+ value = rand(23);
+ case value
+ when 1..10 then return @cssValues[rand(@cssValues.length)]
+ when 11 then return ''
+ when 12 then return rand(255).chr * (rand(8192)+8)
+ when 13
+ length = rand(1024) + 8
+ return (rand(255).chr * length) + " " + (rand(255).chr * length) + " " + (rand(255).chr * length)
+ when 14 then return (rand(255).chr * (rand(1024)+3)) + "px"
+ when 15 then return (rand(255).chr * (rand(1024)+3)) + "em"
+ when 16 then return "url(" + inventValue() + ")"
+ when 17..18 then return "#" + rand(999999999).to_s
+ when 19 then return "-" + rand(99999999).to_s
+ else return rand(99999999).to_s;
+ end
+ end
+
+
+ def mangleTag(tag)
+ @mangledTagTotal += 1
+ out = ''
+
+ # 20% chance of closing a tag instead of opening it. This
+ # still counts against @mangledTagTotal, however.
+ if rand(10) > 8
+ out = "</" + tag + ">"
+ return out
+ end
+
+ # we're opening it.
+ out = "<" + tag
+
+ # forgot the space between the tag and the attributes
+ if rand(15) > 1
+ out << ' '
+ end
+
+ attrNum = rand(@htmlMaxAttrs) + 1
+
+ 1.upto(attrNum) {
+ attr = @htmlAttr[rand(@htmlAttr.length)]
+
+ out << attr
+
+ # 7.5% of the time we skip the = sign. Don't prefix it
+ # if the attribute ends with a ( however.
+
+
+ if rand(15) > 1
+ out << '='
+ end
+
+ # sometimes quote it, sometimes not. I doubt the importance
+ # of this test, but mangleme-1.2 added it, and adding more
+ # random-ness never hurt anything but time. I'll do it less often.
+ quote = rand(2)
+ if (quote > 1)
+ out << "\""
+ end
+
+ out << inventValue()
+
+ # end the quote when you are done
+ if (quote > 1)
+ out << "\" "
+ end
+
+ # 5% chance we skip the space at the end of the name
+ if rand(20) > 1
+ out << ' '
+ end
+
+ }
+
+ # CSS styles!
+ if rand(4) > 1
+ out << " style=\""
+ 1.upto(rand(@cssMaxProps)+1) {
+ out << @cssTags[rand(@cssTags.length)]
+
+ # very small chance we let the tag run on.
+ if rand(50) > 1
+ out << ": "
+ end
+
+ out << inventCssValue(tag)
+ # we almost always put the ; there.
+ if rand(50) > 1
+ out << '; '
+ end
+ }
+ out << "\""
+ end
+
+ out << ">\n"
+
+ # support our local troops!
+ if (@subtest_num > 0) && filterSubTest()
+ if tag =~ /html|body|head/
+ return '<' + tag + '>'
+ else
+ return "<x-#@mangledTagTotal>\n"
+ end
+ else
+ return out
+ end
+ end
+ #end
+
+ def filterSubTest()
+ result = 1
+ if (@mangledTagTotal >= @offset) && (@mangledTagTotal < (@offset + @lines))
+ result = nil
+ end
+ return result
+ end
+
+ def nextTestNum()
+ if random_mode
+ n = rand(99999999)
+ else
+ if @test_num
+ n = @test_num + 1
+ else
+ n = 1
+ end
+ end
+ return n
+ end
+
+ # If we are at line 30 with 8 extra lines, there is no point to try line 31
+ # with 8 lines as well.. skip back to 1 and bump up the line count.
+ def nextSubTestNum()
+ if (@offset + @lines) > @htmlMaxTags
+ nextNum = ((@lines * 2 -1)) * @htmlMaxTags
+ else
+ nextNum = @subtest_num + 1
+ end
+ return nextNum
+ end
+
+
+ def buildPage
+ if (! @test_num) || (@test_num < 1)
+ @test_num = 1
+ end
+ next_num=nextTestNum()
+ @lines = @subtest_num.div(@htmlMaxTags) + 1
+ @offset = @subtest_num.modulo(@htmlMaxTags)
+
+ # building the HTML
+ bodyText = mangleTag('html')
+ bodyText << "\n<head>\n"
+
+ # Only do redirects if lookup=1 has not been specified.
+ if (! @lookup_mode) && (@lines <= @htmlMaxTags) && (@stop_num != @test_num)
+ newpage = @url + "?"
+ if @subtest_num > 0
+ newpage << "test=" << @test_num.to_s << "&subtest=" << nextSubTestNum().to_s
+ else
+ newpage << "test=" << next_num.to_s
+ end
+
+ if @random_mode
+ newpage << "&random=1"
+ end
+
+ if @stop_num > 0
+ newpage << "&stop=" << @stop_num.to_s
+ end
+
+ bodyText << "\t<META HTTP-EQUIV=\"Refresh\" content=\"0;URL=#{newpage}\">\n"
+ # use both techniques, because you never know how you might be corrupting yourself.
+ bodyText << "\t<script language=\"javascript\">setTimeout('window.location=\"#{newpage}\"', 1000);</script>\n"
+ end
+
+ bodyText << "\t" << mangleTag('meta')
+ bodyText << "\t" << mangleTag('meta')
+ bodyText << "\t" << mangleTag('link')
+
+ bodyText << "\t<title>[#@test_num] iExploder #{$VERSION} - #{inventValue()}</title>\n"
+ bodyText << "</head>\n\n"
+
+ # What tags will we be messing with ######################
+ tagList = [ 'body']
+
+ # we already have 5 tags?
+ 1.upto(@htmlMaxTags - 5 ) { tagList << @htmlTags[rand(@htmlTags.length)] }
+
+ tagList.each { |tag|
+ bodyText << mangleTag(tag)
+ bodyText << inventValue() + "\n"
+ }
+ bodyText << "</body>\n</html>"
+ end
+end
+
+
+
+if $0 == __FILE__
+ max=ARGV[0].to_i
+ puts "testing #{max} tags"
+ test = IExploder.new(max, 5, 5)
+ test.readTagFiles()
+ test.test_num=1
+ test.subtest_num=1
+ counter=0
+ test.lines=0
+
+ while test.lines < max
+ test.lines = test.subtest_num.div(max) + 1
+ test.offset = test.subtest_num.modulo(max)
+ test.subtest_num=test.nextSubTestNum
+ counter = counter + 1
+ puts "[#{counter}] subtest #{test.subtest_num} is #{test.lines} lines with #{test.offset} offset"
+ end
+
+ puts "for #{max} tests, you will have #{counter} iterations until #{test.subtest_num}"
+end
+
diff --git a/Tools/iExploder/iexploder-1.3.2/htdocs/index.html b/Tools/iExploder/iexploder-1.3.2/htdocs/index.html
new file mode 100644
index 0000000..849bc6b
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/htdocs/index.html
@@ -0,0 +1,34 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>iExploder 1.3.2</title>
+</head>
+<body>
+<h2>iExploder: Web Browser Quality Assurance Tester</h2>
+<small>Written by <a href="http://toadstool.se/">Thomas Str&ouml;mberg</a> for the
+<a href="http://www.mozilla.org/firefox/">Mozilla FireFox</a> project</small>
+
+
+<ul>
+ <li><a href="iexploder.cgi">Start test sequence from the beginning!</a></li>
+ <li><a href="iexploder.cgi?random=1">Start test sequence in random</a></li>
+ <li>Start testing from a test number:
+ <form method="get" action="iexploder.cgi" name="test">
+ Test: <input size="9" name="test" value="1"> Subtest: <input size="2" name="subtest" value="">
+ <input value="Start" type="submit">
+ </form>
+ </li>
+
+ <li>Lookup a single test number:
+ <form method="get" action="iexploder.cgi" name="test">
+ <input type="hidden" name="lookup" value="1">
+ Test: <input size="9" name="test" value="1"> Subtest: <input size="2" name="subtest" value="">
+ <input value="Lookup" type="submit"></form>
+ </li>
+</ul>
+
+If your browser crashes, please contact thomas%stromberg.org!
+
+</body>
+</html>
+
diff --git a/Tools/iExploder/iexploder-1.3.2/htdocs/webserver.rb b/Tools/iExploder/iexploder-1.3.2/htdocs/webserver.rb
new file mode 100755
index 0000000..5176172
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/htdocs/webserver.rb
@@ -0,0 +1,75 @@
+#!/usr/bin/ruby
+# iExploder - Generates bad HTML files to perform QA for web browsers.
+# Developed for the Mozilla Foundation.
+#####################
+#
+# Copyright (c) 2006 Thomas Stromberg <thomas%stromberg.org>
+#
+# This software is provided 'as-is', without any express or implied warranty.
+# In no event will the authors be held liable for any damages arising from the
+# use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software in a
+# product, an acknowledgment in the product documentation would be appreciated
+# but is not required.
+#
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+#
+# 3. This notice may not be removed or altered from any source distribution.
+
+require 'webrick'
+require 'iexploder';
+require 'config';
+
+include WEBrick
+### THE INTERACTION ##################################
+$ie_preload = IExploder.new($HTML_MAX_TAGS, $HTML_MAX_ATTRS, $CSS_MAX_PROPS)
+$ie_preload.readTagFiles()
+$ie_preload.url='/iexploder.cgi'
+
+if ARGV[0]
+ port = ARGV[0].to_i
+else
+ port = 2000
+end
+
+puts "* iExploder #{$VERSION} will be available at http://localhost:#{port}"
+puts "* Max Tags: #$HTML_MAX_TAGS Max Attrs: #$HTML_MAX_ATTRS Max Props: #$CSS_MAX_PROPS"
+puts
+
+s = HTTPServer.new( :Port => port )
+class IEServlet < HTTPServlet::AbstractServlet
+ def do_GET(req, res)
+ ie = $ie_preload.dup
+ ie.test_num = req.query['test'].to_i
+ ie.subtest_num = req.query['subtest'].to_i || 0
+ ie.random_mode = req.query['random']
+ ie.lookup_mode = req.query['lookup']
+ ie.stop_num = req.query['stop'].to_i
+ ie.setRandomSeed
+
+ res['Content-Type'] = 'text/html'
+ res.body = ie.buildPage()
+ end
+end
+
+class IEForm < HTTPServlet::AbstractServlet
+ def do_GET(req, res)
+ res['Content-Type'] = 'text/html'
+ res.body = File.open("index.html").readlines.join("\n")
+ end
+end
+
+
+
+s.mount("/iexploder.cgi", IEServlet)
+s.mount("/", IEForm)
+trap("INT") { s.shutdown }
+
+s.start
diff --git a/Tools/iExploder/iexploder-1.3.2/tools/lasthit.rb b/Tools/iExploder/iexploder-1.3.2/tools/lasthit.rb
new file mode 100755
index 0000000..b569deb
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/tools/lasthit.rb
@@ -0,0 +1,53 @@
+#!/usr/bin/ruby
+# lasthit, part of iExploder
+#
+# Shows statistics about recent agents that have tested with iExploder.
+# It takes all or part of an apache logfile via stdin, and outputs a list
+# of all the agents who tested within that section, what their last test
+# was, and how many tests they have done.
+
+# The usefulness is finding out where a browser crashed.
+
+
+hostHash = Hash.new
+
+if (ARGV[0])
+ file = File.open(ARGV[0])
+else
+ file = $stdin
+end
+
+file.readlines.each { |line|
+ if (line =~ /^(.*?) .*iexploder.*?test=(\d+).* HTTP.* \"(.*?)\"$/)
+ host = $1
+ testnum = $2
+ agent = $3
+ if (! hostHash[host])
+ hostHash[host] = Hash.new
+ end
+ if (! hostHash[host][agent])
+ hostHash[host][agent] = Hash.new
+ hostHash[host][agent]['total'] = 0
+ end
+
+ hostHash[host][agent]['last'] = testnum
+ if line =~ /subtest=(\d+)/
+ hostHash[host][agent]['subtest'] = $1
+ else
+ hostHash[host][agent]['subtest'] = ''
+ end
+ hostHash[host][agent]['total'] = hostHash[host][agent]['total'] + 1
+ end
+}
+
+printf("%14.14s | %8.8s | %3.3s | %8.8s | %s\n",
+ "IP", "Test", "SubTest", "Total", "Agent")
+puts "---------------------------------------------------------------------------"
+hostHash.each_key { |host|
+
+ hostHash[host].each_key { |agent|
+ printf("%14.14s | %8.8s | %3.3s | %8.8s | %s\n",
+ host, hostHash[host][agent]['last'], hostHash[host][agent]['subtest'], hostHash[host][agent]['total'], agent);
+ }
+}
+
diff --git a/Tools/iExploder/iexploder-1.3.2/tools/osx_last_crash.rb b/Tools/iExploder/iexploder-1.3.2/tools/osx_last_crash.rb
new file mode 100755
index 0000000..5b62c6d
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/tools/osx_last_crash.rb
@@ -0,0 +1,48 @@
+#!/usr/bin/ruby
+# Gives you information about the most recent crash for each application
+# that has crashed within the last 2 days
+
+$LogDir=ENV['HOME'] + '/Library/Logs/CrashReporter'
+$Days=1
+$StackCount=5
+
+files=`find #$LogDir -mtime -#$Days -type f | grep -v synergy`
+files.each { |filename|
+ filename.chop!
+ record = 0
+ date=''
+ stackTrace = []
+
+ File.open(filename).readlines.each { |line|
+ #puts line
+
+ if line =~ /^Date.*(200.*)/
+ date = $1
+ end
+
+ if line =~ /^Thread \d+ Crashed/
+ record = 1
+ # reset the stack trace
+ stackTrace = []
+ end
+
+ if record
+ stackTrace << line
+ record = record + 1
+
+ # stop recording after $StackCount lines
+ if record > ($StackCount + 2)
+ record = nil
+ end
+ end
+ }
+
+ puts File.basename(filename) + " - " + date
+ puts "==================================================="
+ stackTrace.each { |line|
+ puts line
+ }
+ puts ""
+}
+
+
diff --git a/Tools/iExploder/iexploder-1.3.2/tools/showtest.rb b/Tools/iExploder/iexploder-1.3.2/tools/showtest.rb
new file mode 100755
index 0000000..af6b101
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.3.2/tools/showtest.rb
@@ -0,0 +1,43 @@
+#!/usr/bin/ruby
+# showtest.rb - simple CLI interface to grab a testcase
+#####################
+#
+# Copyright (c) 2006 Thomas Stromberg <thomas%stromberg.org>
+#
+# This software is provided 'as-is', without any express or implied warranty.
+# In no event will the authors be held liable for any damages arising from the
+# use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software in a
+# product, an acknowledgment in the product documentation would be appreciated
+# but is not required.
+#
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+#
+# 3. This notice may not be removed or altered from any source distribution.
+
+Dir.chdir('../htdocs')
+require 'iexploder';
+require 'config';
+
+### THE INTERACTION ##################################
+ie = IExploder.new($HTML_MAX_TAGS, $HTML_MAX_ATTRS, $CSS_MAX_PROPS)
+ie.readTagFiles()
+
+if ! ARGV[0]
+ puts "syntax: showtest.rb [test#] [subtest#]"
+ exit
+end
+
+ie.test_num = ARGV[0].to_i
+ie.subtest_num = ARGV[1].to_i || 0
+ie.lookup_mode = 1
+ie.setRandomSeed
+
+puts ie.buildPage()
diff --git a/Tools/iExploder/iexploder-1.7.2/ChangeLog.txt b/Tools/iExploder/iexploder-1.7.2/ChangeLog.txt
new file mode 100644
index 0000000..ef8c31e
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/ChangeLog.txt
@@ -0,0 +1,890 @@
+------------------------------------------------------------------------
+r227 | helixblue | 2010-09-20 09:20:36 +0200 (Mon, 20 Sep 2010) | 1 line
+
+update readme
+------------------------------------------------------------------------
+r226 | helixblue | 2010-09-20 09:17:00 +0200 (Mon, 20 Sep 2010) | 1 line
+
+1.7.2
+------------------------------------------------------------------------
+r225 | helixblue | 2010-09-20 08:50:32 +0200 (Mon, 20 Sep 2010) | 1 line
+
+Change style tag generation blacklist lookup to use same format as other tags
+------------------------------------------------------------------------
+r224 | helixblue | 2010-09-19 23:51:56 +0200 (Sun, 19 Sep 2010) | 1 line
+
+Fix whitespace and ruby 1.9 glitches
+------------------------------------------------------------------------
+r223 | helixblue | 2010-09-19 22:45:21 +0200 (Sun, 19 Sep 2010) | 1 line
+
+clean up filters
+------------------------------------------------------------------------
+r222 | helixblue | 2010-09-19 22:08:13 +0200 (Sun, 19 Sep 2010) | 1 line
+
+version bump to 1.7.1
+------------------------------------------------------------------------
+r221 | helixblue | 2010-09-19 22:07:53 +0200 (Sun, 19 Sep 2010) | 1 line
+
+Add progress font 9999 crash
+------------------------------------------------------------------------
+r220 | helixblue | 2010-09-19 21:34:24 +0200 (Sun, 19 Sep 2010) | 1 line
+
+Add Chrome crash for url//%n%n redirect
+------------------------------------------------------------------------
+r219 | helixblue | 2010-09-19 21:34:12 +0200 (Sun, 19 Sep 2010) | 1 line
+
+User the digested user agent
+------------------------------------------------------------------------
+r218 | helixblue | 2010-09-19 21:12:11 +0200 (Sun, 19 Sep 2010) | 1 line
+
+Make it so that the first testing redirect has the same content as the page being tested
+------------------------------------------------------------------------
+r217 | helixblue | 2010-09-19 21:07:44 +0200 (Sun, 19 Sep 2010) | 1 line
+
+Add a second redirection test for better testcase generation
+------------------------------------------------------------------------
+r216 | helixblue | 2010-09-19 21:07:20 +0200 (Sun, 19 Sep 2010) | 1 line
+
+Display lookup_mode in stdout, get user agent from last_page_requested
+------------------------------------------------------------------------
+r215 | helixblue | 2010-09-19 18:50:11 +0200 (Sun, 19 Sep 2010) | 1 line
+
+Fix nextTestNum() so that it works properly with @random_mode
+------------------------------------------------------------------------
+r213 | helixblue | 2010-09-06 12:38:12 +0200 (Mon, 06 Sep 2010) | 1 line
+
+Update docs to point to ../output instead of /tmp
+------------------------------------------------------------------------
+r212 | helixblue | 2010-09-06 11:34:48 +0200 (Mon, 06 Sep 2010) | 3 lines
+
+Add an empty output directory
+
+
+------------------------------------------------------------------------
+r211 | helixblue | 2010-09-06 11:34:30 +0200 (Mon, 06 Sep 2010) | 1 line
+
+change test_dir and log_dir default to ../output
+------------------------------------------------------------------------
+r210 | helixblue | 2010-09-06 11:29:45 +0200 (Mon, 06 Sep 2010) | 1 line
+
+Add some more testcases
+------------------------------------------------------------------------
+r209 | helixblue | 2010-09-06 10:07:45 +0200 (Mon, 06 Sep 2010) | 1 line
+
+Set default watchdog timer to 60s.
+------------------------------------------------------------------------
+r208 | helixblue | 2010-09-06 09:56:48 +0200 (Mon, 06 Sep 2010) | 1 line
+
+Give subtest form more room
+------------------------------------------------------------------------
+r207 | helixblue | 2010-09-06 09:56:40 +0200 (Mon, 06 Sep 2010) | 1 line
+
+Decrease the chance of arbitrary tag closure from 20% to 14%
+------------------------------------------------------------------------
+r206 | helixblue | 2010-09-06 09:49:29 +0200 (Mon, 06 Sep 2010) | 1 line
+
+Fix browser comment
+------------------------------------------------------------------------
+r205 | helixblue | 2010-09-06 09:44:29 +0200 (Mon, 06 Sep 2010) | 1 line
+
+Change Refresh from 0 to 1 when saving testcase
+------------------------------------------------------------------------
+r204 | helixblue | 2010-09-05 11:13:50 +0200 (Sun, 05 Sep 2010) | 1 line
+
+Revisit using THE_END marker, in conjunction w/ test_redirect.
+------------------------------------------------------------------------
+r203 | helixblue | 2010-09-05 11:10:12 +0200 (Sun, 05 Sep 2010) | 1 line
+
+Instead of using THE END, use test_redirect.
+------------------------------------------------------------------------
+r202 | helixblue | 2010-09-05 11:05:03 +0200 (Sun, 05 Sep 2010) | 1 line
+
+Make THE END work the same as surviving a redirect
+------------------------------------------------------------------------
+r201 | helixblue | 2010-09-05 10:51:23 +0200 (Sun, 05 Sep 2010) | 1 line
+
+Mention testcase viewing
+------------------------------------------------------------------------
+r200 | helixblue | 2010-09-05 09:22:26 +0200 (Sun, 05 Sep 2010) | 1 line
+
+Fix comments.
+------------------------------------------------------------------------
+r199 | helixblue | 2010-09-05 09:22:15 +0200 (Sun, 05 Sep 2010) | 1 line
+
+Adjust browser_harness so that references to iexploder.cgi are altered to localhost:3100 instances
+------------------------------------------------------------------------
+r198 | helixblue | 2010-09-03 21:45:27 +0200 (Fri, 03 Sep 2010) | 1 line
+
+If we are at the end, and stalled, save a testcase.
+------------------------------------------------------------------------
+r197 | helixblue | 2010-09-03 18:42:42 +0200 (Fri, 03 Sep 2010) | 1 line
+
+ruby assignments hate me. dup it.
+------------------------------------------------------------------------
+r196 | helixblue | 2010-09-03 18:25:24 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Put comments in for START/END tag, use less attributes per page
+------------------------------------------------------------------------
+r195 | helixblue | 2010-09-03 18:06:53 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Be better about generating sane <style> tags
+------------------------------------------------------------------------
+r194 | helixblue | 2010-09-03 18:06:25 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Make pages a bit smaller
+------------------------------------------------------------------------
+r193 | helixblue | 2010-09-03 17:50:45 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Mark as 1.7-DEV
+------------------------------------------------------------------------
+r192 | helixblue | 2010-09-03 17:49:27 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Add some extra asterisks for fun
+------------------------------------------------------------------------
+r191 | helixblue | 2010-09-03 17:29:30 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Add CSS selector fuzzing
+------------------------------------------------------------------------
+r190 | helixblue | 2010-09-03 16:56:14 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Add css at-rules
+------------------------------------------------------------------------
+r189 | helixblue | 2010-09-03 16:16:35 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Add css selector data, fix html5 mozilla attributes
+------------------------------------------------------------------------
+r188 | helixblue | 2010-09-03 15:07:30 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Bump version to 1.6
+------------------------------------------------------------------------
+r187 | helixblue | 2010-09-03 14:48:52 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Update release tool to use version.rb
+------------------------------------------------------------------------
+r186 | helixblue | 2010-09-03 14:18:06 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Remove pid disappeared warning, fix False usage
+------------------------------------------------------------------------
+r185 | helixblue | 2010-09-03 14:16:14 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Fix log access mode (append)
+------------------------------------------------------------------------
+r184 | helixblue | 2010-09-03 13:27:50 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Update docs for -r
+------------------------------------------------------------------------
+r183 | helixblue | 2010-09-03 13:20:49 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Update options. If we can't figure out the -port option, output an error.
+------------------------------------------------------------------------
+r182 | helixblue | 2010-09-03 13:13:16 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Keep the original browser name in the output doc, do some testcase munging. Don't initialize test_num to 1
+------------------------------------------------------------------------
+r181 | helixblue | 2010-09-03 13:11:49 +0200 (Fri, 03 Sep 2010) | 1 line
+
+New testcases for Chrome and Opera
+------------------------------------------------------------------------
+r180 | helixblue | 2010-09-03 11:10:08 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Reset testcases directory
+------------------------------------------------------------------------
+r179 | helixblue | 2010-09-03 11:05:08 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Ruby 1.9.x fix: trailing colon
+------------------------------------------------------------------------
+r178 | helixblue | 2010-09-03 11:03:05 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Change -r to random_mode, and --rescan to -s/--scan. Remove some extra debug messages
+------------------------------------------------------------------------
+r177 | helixblue | 2010-09-03 10:52:58 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Change find_crash_logs() to use Dir.glob fully
+------------------------------------------------------------------------
+r176 | helixblue | 2010-09-03 08:53:07 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Fix max_age in find_crash_logs
+------------------------------------------------------------------------
+r175 | helixblue | 2010-09-03 08:50:04 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Fix dangling parens
+------------------------------------------------------------------------
+r174 | helixblue | 2010-09-03 08:46:05 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Add client logging, make crash files return list of files
+------------------------------------------------------------------------
+r173 | helixblue | 2010-09-03 08:03:57 +0200 (Fri, 03 Sep 2010) | 1 line
+
+Reach back a little further to get iexploder lines
+------------------------------------------------------------------------
+r172 | helixblue | 2010-09-02 22:06:00 +0200 (Thu, 02 Sep 2010) | 1 line
+
+Extend watchdog from 30s to 45s
+------------------------------------------------------------------------
+r171 | helixblue | 2010-09-02 22:04:47 +0200 (Thu, 02 Sep 2010) | 1 line
+
+divide the sleeping up
+------------------------------------------------------------------------
+r170 | helixblue | 2010-09-02 21:42:28 +0200 (Thu, 02 Sep 2010) | 1 line
+
+More sleepy
+------------------------------------------------------------------------
+r169 | helixblue | 2010-09-02 19:36:00 +0200 (Thu, 02 Sep 2010) | 1 line
+
+Use File.stat for mtime to avoid too many open files
+------------------------------------------------------------------------
+r168 | helixblue | 2010-09-02 18:47:50 +0200 (Thu, 02 Sep 2010) | 1 line
+
+Add better testcase naming
+------------------------------------------------------------------------
+r167 | helixblue | 2010-09-02 18:22:51 +0200 (Thu, 02 Sep 2010) | 1 line
+
+Fix save_testcase
+------------------------------------------------------------------------
+r166 | helixblue | 2010-09-02 18:22:39 +0200 (Thu, 02 Sep 2010) | 1 line
+
+Add more browser_harness docs
+------------------------------------------------------------------------
+r165 | helixblue | 2010-09-02 18:10:20 +0200 (Thu, 02 Sep 2010) | 1 line
+
+Fix posix loading
+------------------------------------------------------------------------
+r164 | helixblue | 2010-09-02 18:06:19 +0200 (Thu, 02 Sep 2010) | 1 line
+
+Add Mac support for the browser_harness
+------------------------------------------------------------------------
+r163 | helixblue | 2010-09-02 12:59:02 +0200 (Thu, 02 Sep 2010) | 1 line
+
+Add version
+------------------------------------------------------------------------
+r162 | helixblue | 2010-09-02 12:14:11 +0200 (Thu, 02 Sep 2010) | 1 line
+
+A fully working browser harness for UNIX. awesome.
+------------------------------------------------------------------------
+r161 | helixblue | 2010-09-01 21:40:02 +0200 (Wed, 01 Sep 2010) | 1 line
+
+Clean up option parsing
+------------------------------------------------------------------------
+r160 | helixblue | 2010-09-01 21:33:22 +0200 (Wed, 01 Sep 2010) | 1 line
+
+Ruby 1.9.x + style fixes
+------------------------------------------------------------------------
+r159 | helixblue | 2010-09-01 21:18:16 +0200 (Wed, 01 Sep 2010) | 1 line
+
+Add hex junk generator, add newlines where spaces used to be, and add some document.write js tests
+------------------------------------------------------------------------
+r158 | helixblue | 2010-09-01 21:16:32 +0200 (Wed, 01 Sep 2010) | 1 line
+
+Add :% value
+------------------------------------------------------------------------
+r157 | helixblue | 2010-09-01 21:15:59 +0200 (Wed, 01 Sep 2010) | 1 line
+
+Add -l option to set a log path
+------------------------------------------------------------------------
+r156 | helixblue | 2010-09-01 16:31:55 +0200 (Wed, 01 Sep 2010) | 1 line
+
+Commit a sample browser harness
+------------------------------------------------------------------------
+r155 | helixblue | 2010-09-01 11:24:30 +0200 (Wed, 01 Sep 2010) | 1 line
+
+Sync to Webkit trunk
+------------------------------------------------------------------------
+r154 | helixblue | 2010-09-01 11:22:16 +0200 (Wed, 01 Sep 2010) | 1 line
+
+Add mozilla tags
+------------------------------------------------------------------------
+r153 | helixblue | 2010-09-01 11:21:56 +0200 (Wed, 01 Sep 2010) | 1 line
+
+Minor fixes, update for mozilla trunk parsing
+------------------------------------------------------------------------
+r150 | helixblue | 2010-03-14 16:10:15 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Update the README
+------------------------------------------------------------------------
+r149 | helixblue | 2010-03-14 15:45:20 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Fix straggler testcase
+------------------------------------------------------------------------
+r148 | helixblue | 2010-03-14 15:30:46 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Add gtkhtml protocols
+------------------------------------------------------------------------
+r147 | helixblue | 2010-03-14 15:30:01 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Add note about asterisk
+------------------------------------------------------------------------
+r146 | helixblue | 2010-03-14 15:29:31 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Comment out chrome video crashes from config.yaml
+------------------------------------------------------------------------
+r145 | helixblue | 2010-03-14 15:28:55 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Output the headers being manipulated
+------------------------------------------------------------------------
+r144 | helixblue | 2010-03-14 15:28:43 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Add Chrome video crashes to config.yaml
+------------------------------------------------------------------------
+r143 | helixblue | 2010-03-14 15:06:33 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Add Chrome hang on textarea letter-spacing
+------------------------------------------------------------------------
+r142 | helixblue | 2010-03-14 14:58:19 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Add LinesAgo column to lasthit
+------------------------------------------------------------------------
+r141 | helixblue | 2010-03-14 14:11:00 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Update lasthit for new subtest data structure
+------------------------------------------------------------------------
+r140 | helixblue | 2010-03-14 14:10:32 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Remove some debug statements
+------------------------------------------------------------------------
+r139 | helixblue | 2010-03-14 14:10:12 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Increase property counts
+------------------------------------------------------------------------
+r138 | helixblue | 2010-03-14 14:09:54 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Add some more chrome crashers
+------------------------------------------------------------------------
+r137 | helixblue | 2010-03-14 13:44:10 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Fix check against subtest_combinations_max, add subtest comment to html output
+------------------------------------------------------------------------
+r136 | helixblue | 2010-03-14 13:43:43 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Remove some debug statements, use the golden ratio to calculate the new width
+------------------------------------------------------------------------
+r135 | helixblue | 2010-03-14 13:43:12 +0100 (Sun, 14 Mar 2010) | 1 line
+
+lower html_tags_per_page to 135 for faster subtest generation
+------------------------------------------------------------------------
+r134 | helixblue | 2010-03-14 12:24:31 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Add an extra width line when we hit 3 offsets
+------------------------------------------------------------------------
+r133 | helixblue | 2010-03-14 12:24:08 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Support an initial_subtest_width
+------------------------------------------------------------------------
+r132 | helixblue | 2010-03-14 10:21:34 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Only add tag_data in subtests if there is data to append
+------------------------------------------------------------------------
+r131 | helixblue | 2010-03-14 10:21:20 +0100 (Sun, 14 Mar 2010) | 1 line
+
+Rename lines_at_time to width, enforce min width of 1
+------------------------------------------------------------------------
+r130 | helixblue | 2010-03-14 10:13:34 +0100 (Sun, 14 Mar 2010) | 5 lines
+
+* Add copyright to scanner, remove comments
+* Make exclusions work better: add check method, make sure that methods that check the property name get the unblacklisted version.
+* Add some initial blacklists
+
+
+------------------------------------------------------------------------
+r129 | helixblue | 2010-03-13 19:21:32 +0100 (Sat, 13 Mar 2010) | 1 line
+
+Oh jesus.. we now have a decent subtest implementation. RIP Bo Skough.
+------------------------------------------------------------------------
+r128 | helixblue | 2010-03-10 08:11:56 +0100 (Wed, 10 Mar 2010) | 2 lines
+
+add interesting firefox 3.6 crasher, still need to isolate testcase
+
+------------------------------------------------------------------------
+r127 | helixblue | 2010-03-10 07:06:16 +0100 (Wed, 10 Mar 2010) | 1 line
+
+Make some doc updates in preparation for 1.5 release
+------------------------------------------------------------------------
+r126 | helixblue | 2010-03-10 07:02:21 +0100 (Wed, 10 Mar 2010) | 1 line
+
+Make lasthit work with webserver.rb
+------------------------------------------------------------------------
+r125 | helixblue | 2010-03-09 19:39:55 +0100 (Tue, 09 Mar 2010) | 1 line
+
+add interesting double-page crash for Chrome
+------------------------------------------------------------------------
+r124 | helixblue | 2010-03-09 16:58:10 +0100 (Tue, 09 Mar 2010) | 1 line
+
+Lower headers_per_page_max, put back missing response.body change in webserver.rb
+------------------------------------------------------------------------
+r123 | helixblue | 2010-03-09 16:47:11 +0100 (Tue, 09 Mar 2010) | 1 line
+
+Make sure things work if @config['exclude'] is defined but empty
+------------------------------------------------------------------------
+r122 | helixblue | 2010-03-09 16:46:50 +0100 (Tue, 09 Mar 2010) | 1 line
+
+Fix buildHeaders bug
+------------------------------------------------------------------------
+r121 | helixblue | 2010-03-09 16:30:59 +0100 (Tue, 09 Mar 2010) | 1 line
+
+Allow iexploder to work if no exclude properties have been set, and fix special case for src tag
+------------------------------------------------------------------------
+r120 | helixblue | 2010-03-09 16:20:48 +0100 (Tue, 09 Mar 2010) | 1 line
+
+Add the ability to exclude certain combinations of tags/properties
+------------------------------------------------------------------------
+r119 | helixblue | 2010-03-09 15:20:37 +0100 (Tue, 09 Mar 2010) | 1 line
+
+Fix bug where we fill subtests with escaped tags
+------------------------------------------------------------------------
+r118 | helixblue | 2010-03-09 15:05:29 +0100 (Tue, 09 Mar 2010) | 1 line
+
+Add firefox hang
+------------------------------------------------------------------------
+r117 | helixblue | 2010-03-09 11:33:06 +0100 (Tue, 09 Mar 2010) | 1 line
+
+More tuning
+------------------------------------------------------------------------
+r116 | helixblue | 2010-03-09 11:29:54 +0100 (Tue, 09 Mar 2010) | 1 line
+
+Move max_garbage_text_size to be tuned by config.yaml
+------------------------------------------------------------------------
+r115 | helixblue | 2010-03-09 11:25:15 +0100 (Tue, 09 Mar 2010) | 1 line
+
+Minor adjustments to the skew mix
+------------------------------------------------------------------------
+r114 | helixblue | 2010-03-09 11:22:23 +0100 (Tue, 09 Mar 2010) | 1 line
+
+Add a list of tags we favor for testing
+------------------------------------------------------------------------
+r113 | helixblue | 2010-03-09 11:11:46 +0100 (Tue, 09 Mar 2010) | 1 line
+
+Make img/src inclusion random, not mandatory. Add raw values to js, fix subtest end lookup
+------------------------------------------------------------------------
+r112 | helixblue | 2010-03-09 10:52:42 +0100 (Tue, 09 Mar 2010) | 1 line
+
+We have a Firefox 3.6 hanger now
+------------------------------------------------------------------------
+r111 | helixblue | 2010-03-09 10:02:35 +0100 (Tue, 09 Mar 2010) | 1 line
+
+Sync the interface changes to the CGI version
+------------------------------------------------------------------------
+r110 | helixblue | 2010-03-08 08:35:12 +0100 (Mon, 08 Mar 2010) | 1 line
+
+Re-arrange testcase directories
+------------------------------------------------------------------------
+r109 | helixblue | 2010-03-08 07:55:27 +0100 (Mon, 08 Mar 2010) | 1 line
+
+Another chrome crasher
+------------------------------------------------------------------------
+r108 | helixblue | 2010-03-08 00:00:41 +0100 (Mon, 08 Mar 2010) | 1 line
+
+More floating point crashes
+------------------------------------------------------------------------
+r107 | helixblue | 2010-03-07 23:46:33 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Mave generateOverflow less static
+------------------------------------------------------------------------
+r106 | helixblue | 2010-03-07 23:45:42 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Tune down some of the excessiveness with overflow triggering. We don't exploit too many of them
+------------------------------------------------------------------------
+r105 | helixblue | 2010-03-07 20:58:35 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Add back the default content-type, remove debug line
+------------------------------------------------------------------------
+r104 | helixblue | 2010-03-07 20:54:12 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Add a dummy favicon.ico link, extend copyright, rename req/res to request/response, fix bug where we reset the http headers before returning
+------------------------------------------------------------------------
+r103 | helixblue | 2010-03-07 18:27:04 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Add video height crasher for Chrome
+------------------------------------------------------------------------
+r102 | helixblue | 2010-03-07 18:26:10 +0100 (Sun, 07 Mar 2010) | 1 line
+
+End garbage text with a newline
+------------------------------------------------------------------------
+r101 | helixblue | 2010-03-07 18:24:18 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Fix subtest generation by making sure all calls to random are accounted for, even when subtesting
+------------------------------------------------------------------------
+r100 | helixblue | 2010-03-07 16:30:09 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Add video width crasher for chrome
+------------------------------------------------------------------------
+r99 | helixblue | 2010-03-07 14:08:06 +0100 (Sun, 07 Mar 2010) | 1 line
+
+1.5-BETA2 - add a Chrome crasher
+------------------------------------------------------------------------
+r97 | helixblue | 2010-03-07 12:54:03 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Add bug.png mapping, fix HTML compliance
+------------------------------------------------------------------------
+r96 | helixblue | 2010-03-07 12:48:11 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Give the form a facelift
+------------------------------------------------------------------------
+r95 | helixblue | 2010-03-07 11:39:55 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Update the docs
+------------------------------------------------------------------------
+r94 | helixblue | 2010-03-07 11:36:52 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Add tool to make source code releases
+------------------------------------------------------------------------
+r93 | helixblue | 2010-03-07 11:33:13 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Do more munging
+------------------------------------------------------------------------
+r92 | helixblue | 2010-03-07 11:26:23 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Change default port to 3100 to avoid conflicts, fix one more upto, and fix mime type parsing
+------------------------------------------------------------------------
+r91 | helixblue | 2010-03-07 11:20:10 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Fix upto syntax
+------------------------------------------------------------------------
+r90 | helixblue | 2010-03-07 11:13:24 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Fix ie.random_mode nil comparison
+------------------------------------------------------------------------
+r89 | helixblue | 2010-03-07 11:08:27 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Rename htdocs to src
+------------------------------------------------------------------------
+r88 | helixblue | 2010-03-07 11:07:36 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Change the way we log to console using webserver.rb
+------------------------------------------------------------------------
+r87 | helixblue | 2010-03-07 09:51:11 +0100 (Sun, 07 Mar 2010) | 1 line
+
+generateGarbageText should also love generateGarbageValue
+------------------------------------------------------------------------
+r86 | helixblue | 2010-03-07 09:40:00 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Activate media fuzzing - oh yeah\!
+------------------------------------------------------------------------
+r85 | helixblue | 2010-03-07 07:34:48 +0100 (Sun, 07 Mar 2010) | 1 line
+
+Add mime-types content
+------------------------------------------------------------------------
+r84 | helixblue | 2010-03-06 22:23:28 +0100 (Sat, 06 Mar 2010) | 1 line
+
+Add some html files for Chrome
+------------------------------------------------------------------------
+r83 | helixblue | 2010-03-06 22:12:29 +0100 (Sat, 06 Mar 2010) | 1 line
+
+Add some url related opera bugs
+------------------------------------------------------------------------
+r82 | helixblue | 2010-03-06 12:34:45 +0100 (Sat, 06 Mar 2010) | 1 line
+
+Add an opera crasher
+------------------------------------------------------------------------
+r81 | helixblue | 2010-03-06 11:58:31 +0100 (Sat, 06 Mar 2010) | 1 line
+
+Better testing values, including a custom handler for html on attributes
+------------------------------------------------------------------------
+r80 | helixblue | 2010-03-06 11:17:48 +0100 (Sat, 06 Mar 2010) | 1 line
+
+iexploder.rb can now load tests.. add javascript testing to each page
+------------------------------------------------------------------------
+r79 | helixblue | 2010-03-06 08:04:14 +0100 (Sat, 06 Mar 2010) | 1 line
+
+Add new protocol/header data
+------------------------------------------------------------------------
+r78 | helixblue | 2010-03-06 08:03:58 +0100 (Sat, 06 Mar 2010) | 1 line
+
+Return accidentally deleted properties
+------------------------------------------------------------------------
+r77 | helixblue | 2010-03-06 08:02:50 +0100 (Sat, 06 Mar 2010) | 1 line
+
+Split out protocol and header properties
+------------------------------------------------------------------------
+r76 | helixblue | 2010-03-06 05:34:31 +0100 (Sat, 06 Mar 2010) | 1 line
+
+We have a Chrome 5.0 crasher
+------------------------------------------------------------------------
+r75 | helixblue | 2010-03-05 14:46:21 +0100 (Fri, 05 Mar 2010) | 1 line
+
+More tweaking: increase attributes_per_html_tag and properties_per_style
+------------------------------------------------------------------------
+r74 | helixblue | 2010-03-05 09:57:06 +0100 (Fri, 05 Mar 2010) | 1 line
+
+Move around our loading text
+------------------------------------------------------------------------
+r73 | helixblue | 2010-03-05 09:54:22 +0100 (Fri, 05 Mar 2010) | 1 line
+
+Fix --port passing
+------------------------------------------------------------------------
+r71 | helixblue | 2010-03-05 09:49:04 +0100 (Fri, 05 Mar 2010) | 1 line
+
+1.4-BETA1
+------------------------------------------------------------------------
+r70 | helixblue | 2010-03-05 09:47:46 +0100 (Fri, 05 Mar 2010) | 1 line
+
+Update README
+------------------------------------------------------------------------
+r69 | helixblue | 2010-03-05 09:44:29 +0100 (Fri, 05 Mar 2010) | 1 line
+
+Fix path interpolation
+------------------------------------------------------------------------
+r68 | helixblue | 2010-03-05 09:30:28 +0100 (Fri, 05 Mar 2010) | 1 line
+
+Add config.yaml file
+------------------------------------------------------------------------
+r67 | helixblue | 2010-03-05 09:30:15 +0100 (Fri, 05 Mar 2010) | 1 line
+
+Do some refactoring, moving configuration into a YAML file
+------------------------------------------------------------------------
+r66 | helixblue | 2010-03-05 07:55:26 +0100 (Fri, 05 Mar 2010) | 1 line
+
+Narrow down some chrome testcases
+------------------------------------------------------------------------
+r65 | helixblue | 2010-03-04 22:42:20 +0100 (Thu, 04 Mar 2010) | 1 line
+
+Narrow down chrome crasher
+------------------------------------------------------------------------
+r64 | helixblue | 2010-03-04 20:25:59 +0100 (Thu, 04 Mar 2010) | 1 line
+
+Fix subtesting
+------------------------------------------------------------------------
+r63 | helixblue | 2010-03-04 20:25:43 +0100 (Thu, 04 Mar 2010) | 1 line
+
+firefox sample
+------------------------------------------------------------------------
+r62 | helixblue | 2010-03-04 18:45:40 +0100 (Thu, 04 Mar 2010) | 1 line
+
+Make it a better URL
+------------------------------------------------------------------------
+r61 | helixblue | 2010-03-04 18:44:59 +0100 (Thu, 04 Mar 2010) | 1 line
+
+Change 127.0.0.1 to a full qualified URL
+------------------------------------------------------------------------
+r60 | helixblue | 2010-03-04 18:15:19 +0100 (Thu, 04 Mar 2010) | 1 line
+
+Make it less likely that there is a missing = after an HTML attribute name
+------------------------------------------------------------------------
+r59 | helixblue | 2010-03-04 17:59:13 +0100 (Thu, 04 Mar 2010) | 1 line
+
+Do some retuning and re-organization for todays generation of bugs. This may cause less crashes, so we need to keep an eye out on the results
+------------------------------------------------------------------------
+r58 | helixblue | 2010-03-04 17:58:32 +0100 (Thu, 04 Mar 2010) | 1 line
+
+update testcases
+------------------------------------------------------------------------
+r57 | helixblue | 2010-03-04 13:46:21 +0100 (Thu, 04 Mar 2010) | 1 line
+
+include the user-agent in the URL as a b variable
+------------------------------------------------------------------------
+r56 | helixblue | 2010-03-04 12:25:26 +0100 (Thu, 04 Mar 2010) | 1 line
+
+HTML_MAX_TAGS 150
+------------------------------------------------------------------------
+r55 | helixblue | 2010-03-04 10:15:48 +0100 (Thu, 04 Mar 2010) | 1 line
+
+Add some chrome test cases
+------------------------------------------------------------------------
+r54 | helixblue | 2010-03-04 09:48:57 +0100 (Thu, 04 Mar 2010) | 1 line
+
+Remove extraneous output
+------------------------------------------------------------------------
+r53 | helixblue | 2010-03-04 09:47:13 +0100 (Thu, 04 Mar 2010) | 1 line
+
+MAX_TAGS = 100
+------------------------------------------------------------------------
+r52 | helixblue | 2010-03-04 09:46:54 +0100 (Thu, 04 Mar 2010) | 1 line
+
+Add html-values
+------------------------------------------------------------------------
+r51 | helixblue | 2010-03-04 09:45:56 +0100 (Thu, 04 Mar 2010) | 1 line
+
+Complete splitting of properties, values, and tags
+------------------------------------------------------------------------
+r50 | helixblue | 2010-03-04 09:25:36 +0100 (Thu, 04 Mar 2010) | 1 line
+
+Start auto-generating html-values as well
+------------------------------------------------------------------------
+r49 | helixblue | 2010-03-04 09:24:46 +0100 (Thu, 04 Mar 2010) | 1 line
+
+Increase MAX_TAGS to 125
+------------------------------------------------------------------------
+r48 | helixblue | 2010-03-03 23:37:11 +0100 (Wed, 03 Mar 2010) | 1 line
+
+make webserver.rb executable
+------------------------------------------------------------------------
+r47 | helixblue | 2010-03-03 23:35:55 +0100 (Wed, 03 Mar 2010) | 1 line
+
+Add support for multiple css attributes in one style tag
+------------------------------------------------------------------------
+r46 | helixblue | 2010-03-03 23:27:10 +0100 (Wed, 03 Mar 2010) | 1 line
+
+Move to tag directories, add tool to extract tags from common open-source browsers
+------------------------------------------------------------------------
+r45 | helixblue | 2010-03-03 20:44:19 +0100 (Wed, 03 Mar 2010) | 3 lines
+
+Move code from /svn/iexploder to /svn/trunk
+
+
+------------------------------------------------------------------------
+r44 | helixblue | 2010-03-03 10:05:40 +0100 (Wed, 03 Mar 2010) | 1 line
+
+Re-license as Apache 2.0
+------------------------------------------------------------------------
+r42 | thomas | 2006-05-31 02:43:02 +0200 (Wed, 31 May 2006) | 1 line
+
+config->ieconfig
+------------------------------------------------------------------------
+r41 | thomas | 2006-05-22 23:21:15 +0200 (Mon, 22 May 2006) | 1 line
+
+Remove version
+------------------------------------------------------------------------
+r40 | thomas | 2006-04-25 21:43:38 +0200 (Tue, 25 Apr 2006) | 1 line
+
+Rename config.rb to ieconfig.rb to avoid conflict with ruby-config
+------------------------------------------------------------------------
+r39 | thomas | 2006-04-21 15:55:51 +0200 (Fri, 21 Apr 2006) | 1 line
+
+1.3.2.. minor adjustment to title and where gets set
+------------------------------------------------------------------------
+r38 | thomas | 2006-04-19 23:14:26 +0200 (Wed, 19 Apr 2006) | 1 line
+
+Add h4+pre+cite+nolayer+code crash for Safari 2.0.3
+------------------------------------------------------------------------
+r37 | thomas | 2006-04-19 23:01:48 +0200 (Wed, 19 Apr 2006) | 1 line
+
+showtest.rb: easily download a testcase
+------------------------------------------------------------------------
+r36 | thomas | 2006-04-19 22:07:13 +0200 (Wed, 19 Apr 2006) | 1 line
+
+Remove stopping debug message
+------------------------------------------------------------------------
+r35 | thomas | 2006-04-19 22:02:48 +0200 (Wed, 19 Apr 2006) | 1 line
+
+New subtest algorithm: double the tag count each iteration
+------------------------------------------------------------------------
+r34 | thomas | 2006-04-19 21:05:30 +0200 (Wed, 19 Apr 2006) | 1 line
+
+remove IE dupes: text-overflow and word-wrap
+------------------------------------------------------------------------
+r33 | thomas | 2006-04-19 18:48:07 +0200 (Wed, 19 Apr 2006) | 1 line
+
+Add some benchmark/performance info.. set MAX_TAGS default to 96
+------------------------------------------------------------------------
+r32 | thomas | 2006-04-19 16:22:33 +0200 (Wed, 19 Apr 2006) | 1 line
+
+Add stop parameter, fix port assignment issue, fix indentation
+------------------------------------------------------------------------
+r31 | thomas | 2006-04-19 16:22:06 +0200 (Wed, 19 Apr 2006) | 1 line
+
+1.3.0
+------------------------------------------------------------------------
+r30 | thomas | 2006-04-19 04:46:35 +0200 (Wed, 19 Apr 2006) | 1 line
+
+applet+param Hashmap crash in Safari
+------------------------------------------------------------------------
+r29 | thomas | 2006-04-19 04:07:45 +0200 (Wed, 19 Apr 2006) | 1 line
+
+1.3.0
+------------------------------------------------------------------------
+r28 | thomas | 2006-04-19 04:05:47 +0200 (Wed, 19 Apr 2006) | 1 line
+
+commit osx_last_crash minutes->days change, document that you can pass a new port number to the webserver.rb program
+------------------------------------------------------------------------
+r27 | thomas | 2006-04-19 04:02:16 +0200 (Wed, 19 Apr 2006) | 1 line
+
+Add more Safari crashes to the testcases list
+------------------------------------------------------------------------
+r26 | thomas | 2006-04-19 01:05:46 +0200 (Wed, 19 Apr 2006) | 1 line
+
+Greatly improve subtests. Not only do we iterate around each tag, but we steadily increase the amount of tags we input as well
+------------------------------------------------------------------------
+r25 | thomas | 2006-04-18 23:04:17 +0200 (Tue, 18 Apr 2006) | 1 line
+
+1.3b1.. also, raise max tags to 48 now that we have fixed subtest bugs
+------------------------------------------------------------------------
+r24 | thomas | 2006-04-18 22:59:20 +0200 (Tue, 18 Apr 2006) | 1 line
+
+New Webrick based option for standalone hosting
+------------------------------------------------------------------------
+r23 | thomas | 2006-04-18 22:18:35 +0200 (Tue, 18 Apr 2006) | 1 line
+
+Split iexploder.cgi into iexploder.rb and config.rb
+------------------------------------------------------------------------
+r22 | thomas | 2006-04-18 19:36:25 +0200 (Tue, 18 Apr 2006) | 1 line
+
+Add items from WebKit/WebCore/css/CSSValueKeywords.in
+------------------------------------------------------------------------
+r21 | thomas | 2006-04-18 19:32:45 +0200 (Tue, 18 Apr 2006) | 1 line
+
+Add odd new crash from Opera 8.5.4 for Mac
+------------------------------------------------------------------------
+r20 | thomas | 2006-04-18 19:10:15 +0200 (Tue, 18 Apr 2006) | 1 line
+
+Add new Safari test case
+------------------------------------------------------------------------
+r19 | thomas | 2006-04-18 18:25:39 +0200 (Tue, 18 Apr 2006) | 1 line
+
+iExploder 1.3: sync with modern rendering kits
+------------------------------------------------------------------------
+r18 | thomas | 2006-04-18 18:25:18 +0200 (Tue, 18 Apr 2006) | 1 line
+
+New testcases
+------------------------------------------------------------------------
+r17 | thomas | 2006-04-18 18:23:48 +0200 (Tue, 18 Apr 2006) | 1 line
+
+Reshuffle testcases
+------------------------------------------------------------------------
+r16 | thomas | 2005-11-04 04:01:43 +0100 (Fri, 04 Nov 2005) | 1 line
+
+add some test cases
+------------------------------------------------------------------------
+r15 | thomas | 2005-11-04 04:01:19 +0100 (Fri, 04 Nov 2005) | 1 line
+
+Add some cute tabs
+------------------------------------------------------------------------
+r14 | thomas | 2005-10-21 21:34:38 +0200 (Fri, 21 Oct 2005) | 1 line
+
+Crash is not OSX specific
+------------------------------------------------------------------------
+r13 | thomas | 2005-10-21 20:59:41 +0200 (Fri, 21 Oct 2005) | 1 line
+
+Mention the fact that testcases may not be portable across installations
+------------------------------------------------------------------------
+r12 | thomas | 2005-10-21 20:45:48 +0200 (Fri, 21 Oct 2005) | 1 line
+
+Fix lookup html code
+------------------------------------------------------------------------
+r11 | thomas | 2005-10-21 20:22:10 +0200 (Fri, 21 Oct 2005) | 1 line
+
+QuickDraw crash for Mac OS X
+------------------------------------------------------------------------
+r10 | thomas | 2005-10-21 20:14:34 +0200 (Fri, 21 Oct 2005) | 1 line
+
+New crash
+------------------------------------------------------------------------
+r9 | thomas | 2005-10-21 20:06:45 +0200 (Fri, 21 Oct 2005) | 1 line
+
+IE DoS
+------------------------------------------------------------------------
+r8 | thomas | 2005-10-21 19:24:02 +0200 (Fri, 21 Oct 2005) | 1 line
+
+1.2 Update, mostly documentation and test cases
+------------------------------------------------------------------------
+r7 | thomas | 2005-10-21 17:41:39 +0200 (Fri, 21 Oct 2005) | 1 line
+
+back to days, filter out synergy
+------------------------------------------------------------------------
+r6 | thomas | 2005-10-21 17:25:28 +0200 (Fri, 21 Oct 2005) | 1 line
+
+1.2: We now use javascript reloads after 1 second in case the meta breaks (IE)
+------------------------------------------------------------------------
+r5 | thomas | 2005-10-21 14:51:07 +0200 (Fri, 21 Oct 2005) | 1 line
+
+1.1: Fix up our subtest model
+------------------------------------------------------------------------
+r4 | thomas | 2005-10-21 03:55:59 +0200 (Fri, 21 Oct 2005) | 1 line
+
+Support for subtests, and compatibility with mod_ruby
+------------------------------------------------------------------------
+r3 | thomas | 2005-10-21 02:48:59 +0200 (Fri, 21 Oct 2005) | 1 line
+
+update to v1.0
+------------------------------------------------------------------------
+r1 | tstrombe | 2005-02-28 14:13:25 +0100 (Mon, 28 Feb 2005) | 1 line
+
+iexploder software
+------------------------------------------------------------------------
diff --git a/Tools/iExploder/iexploder-1.7.2/LICENSE.txt b/Tools/iExploder/iexploder-1.7.2/LICENSE.txt
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/LICENSE.txt
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/Tools/iExploder/iexploder-1.7.2/README.txt b/Tools/iExploder/iexploder-1.7.2/README.txt
new file mode 100644
index 0000000..1f5b77a
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/README.txt
@@ -0,0 +1,174 @@
+Welcome to iExploder. a highly inefficient, but fairly effective web
+browser tester. The code still has a lot of work to be done, but it's
+definitely usable. Here are some notable features:
+
+* Tests all HTML tags and CSS attributes, as parsed from various
+ open-source browsers.
+* HTTP Header testing
+* Basic Media format fuzzing (jpeg, png, snd, wav, etc.)
+* Numeric, and String overflow and formatting tests
+* Sequential and Randomized Test Case Generation
+* Test Case Lookups
+* Subtest generation
+* Test harness mode that controls your browser process and testcase
+ generation.
+
+Requirements:
+-------------
+Make sure you have Ruby installed (comes with Mac OS X, most Linux
+distributions). See http://www.ruby-lang.org/ if you do not.
+
+
+Harness mode (Mac OS X, Linux, other UNIX based operating systems)
+-------------------------------------------------------------------
+In this mode, iExploder controls the stopping and starting of your
+web browser, reproducing crashes, and writing test cases. This is
+the recommended mode of operation for most cases.
+
+
+Usage: browser_harness.rb [options] -- <browser path> <browser options>
+ -t, --test NUM Test to start at
+ -p, --port NUM Listen on TCP port NUM (random)
+ -c, --config PATH Use PATH for configuration file
+ -d, --testdir PATH Use PATH to save testcases (/tmp)
+ -l, --logdir PATH Use PATH to save logs (/tmp)
+ -w, --watchdog NUM How many seconds to wait for pages to load (45s)
+ -r, --random Generate test numbers pseudo-randomly
+ -s, --scan NUM How often to check for new log data (5s)
+ -h, --help Display this screen
+
+Here is an example use with Chrome starting at test number 1000:
+
+% ./browser_harness.rb -t 1000 -- /usr/local/chrome-linux/chrome --incognito
+
+For proper use, the harness mode must *ALWAYS* be used with the browser
+configured to not restore sessions after a restart. Here are some example
+command lines to use:
+
+ chrome --incognito
+ opera --nosession -newprivatetab
+ firefox -private
+
+On Mac OS X you may call the binary directly, or use the .app directory. The latter
+is required for Safari.app, but does not allow arguments to be passed. Here is an
+example:
+
+% ./browser_harness.rb /Applications/Safari.app
+
+By default, all testcases and logs will be written to ../output
+
+
+
+Viewing testcases:
+------------------
+Many test-cases make use of references to external objects (ogg, jpg, etc.)
+where we are fuzzing the HTTP header data. When the browser harness saves a
+testcase in HTML form, it rewrites all references to these external objects
+to refer to http://127.0.0.1:3100/
+
+To properly view these saved .html testcases, please run the built-in
+webserver in the background.
+
+% ruby webserver.rb
+
+
+Standalone Webserver mode:
+--------------------------
+If you do not already have a webserver setup, you can use the server
+built into iexploder. Simply go into the src/ directory and type:
+
+% ruby webserver.rb
+
+A webserver will then start on port 3100 with the iexploder form. You can
+also pass a -p or --port option to select a different location:
+
+% ruby webserver.rb -p 2001
+
+All requests will be logged to the path specified in 'access_log_path'
+parameter in config.yaml.
+
+
+
+Third-party webserver mode:
+---------------------------
+Copy the contents of the src/ folder to any directory served
+by your webserver. Make sure that directory can execute CGI scripts.
+Performance is likely to be very slow unless you use something that
+keeps the interpreter alive like mod_ruby.
+
+
+FAQ:
+----
+1) Are the tests always the same?
+
+ The test cases should always be the same on a single installation, but not
+necessarily on different installations of iExploder. Random generator seeds
+may differ between operating systems and platforms. If you alter config.yaml,
+it is likely to change the test cases as well.
+
+
+2) I found a crash - how do I stop testing for it?
+
+See the 'exclude' section of config.yaml. It allows you to blacklist certain
+tag combinations that are known to result in a crash condition.
+
+
+3) How do I look up the last successful test for a client?
+
+Look at your access log. There is a handy tool to parse access logs and show
+the most recent test for each host and user-agent combo. Try:
+
+tools/lasthit.rb /path/to/access_log
+
+
+4) How do subtests work?
+
+Subtests are how iexploder attempts to isolate the crashing line of code for
+a particular HTML document. It's a multi-pass algorithm, which delivers
+nasty tags to your browser in the following order:
+
+* 1 combination, single line
+* 2 combinations, 3 lines per combination
+* 3 combinations, 5 lines per combination
+* 4 combinations...
+* 5 combinations...
+* Your original document (in case we haven't crashed by now)
+
+
+5) How come I can't seem to repeat the crash?
+
+ Many browser crashes are race conditions that are not easy to repeat. Some
+crashes only happen when going from test 4 -> test 5 -> test 6. If you can't
+repeat the crash through subtests or a lookup of the failing test, try going
+back a few tests.
+
+That said, some crashes are due to race conditions that are very difficult
+to replicate.
+
+
+6) Why did you write this?
+
+ I wanted to make sure that FireFox had as many bugs fixed in it as possible
+before the 1.0 release. After 1.0 came out, I kept improving it.
+
+
+7) Why does Internet Explorer run the tests so slowly?
+
+ <META> refresh tags are very fragile in Internet Explorer, and can be easily
+be rendered useless by other tags on the page. If this happens, a javascript
+refresh will execute after a 1 second delay.
+
+
+8) How do I change the number of tags iExploder tests per page?
+
+See config.yaml.
+
+
+9) What other performance enhancements can I make?
+
+* Use Private Browsing or Incognito mode in your browser
+* Before using iExploder, clear your browser history
+* Minimize your browser while iExploder is running
+* If you are using browser_harness, try adjusting the -w and -s options.
+
+
diff --git a/Tools/iExploder/iexploder-1.7.2/src/browser_harness.rb b/Tools/iExploder/iexploder-1.7.2/src/browser_harness.rb
new file mode 100755
index 0000000..c5bec80
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/browser_harness.rb
@@ -0,0 +1,389 @@
+#!/usr/bin/ruby
+# iExploder browser Harness (test a single web browser)
+#
+# Copyright 2010 Thomas Stromberg - All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#----------------------------------------------------------------------------
+# PLEASE NOTE:
+#
+# You must disable automatic session restoring for this to be useful.
+#
+# chrome --incognito
+# opera --nosession -newprivatetab
+# firefox -private
+require 'cgi'
+require 'open-uri'
+require 'optparse'
+require './iexploder.rb'
+require './scanner.rb'
+
+MAC_CRASH_PATH = "#{ENV['HOME']}/Library/Logs/CrashReporter"
+TESTCASE_URL = "http://127.0.0.1:3100/iexploder.cgi"
+
+class BrowserHarness
+ def initialize(port, config_path, log_dir, test_dir, watchdog_timer, scan_timer)
+ @app_base_url = "http://127.0.0.1:#{port}/"
+ @app_url = "#{@app_base_url}iexploder.cgi"
+ @port = port
+ @log_dir = log_dir
+ @server_log_path = "#{log_dir}/iexploder_webserver-#{port}.log"
+ @client_log_path = "#{log_dir}/iexploder_harness-#{port}.log"
+ @test_dir = test_dir
+ @watchdog_timer = watchdog_timer
+ @scan_timer = scan_timer
+ @config_path = config_path
+
+ @ie = IExploder.new(@config_path)
+ @ie.cgi_url = @app_url
+
+ @browser_id = nil
+ @browser_name = nil
+ msg("Client log: #{@client_log_path}")
+ msg("Server log: #{@server_log_path}")
+ @server_pid = launch_server()
+ end
+
+ def msg(text)
+ now = Time.now()
+ msg = ">>> #{@browser_name}:#{@port} | #{now}: #{text}"
+ puts msg
+ STDOUT.flush
+
+ f = File.open(@client_log_path, 'a')
+ f.puts msg
+ f.close
+ end
+
+ def launch_server()
+ args = ['./webserver.rb', "-p#{@port}", "-c#{@config_path}", "-l#{@server_log_path}"]
+ pids = fork { exec(*args) }
+ msg("Server args: #{args.inspect}")
+ msg("Server pid: #{pids.inspect}")
+ return pids
+ end
+
+ def launch_browser(args, url)
+ if ! File.exist?(args[0])
+ msg("First argument does not appear to be an executable file: #{args[0]}")
+ kill_server()
+ exit
+ end
+
+ browser = File.basename(args[0])
+ @browser_name = File.basename(browser)
+ if browser =~ /\.app$/
+ pids = launch_mac_browser(args, url)
+ else
+ pids = launch_posix_browser(args, url)
+ end
+ sleep(@scan_timer * 3)
+ if ! File.size?(@server_log_path)
+ puts "#{@server_log_path} was never written to. Unable to launch browser?"
+ kill_server()
+ exit
+ end
+ return pids
+ end
+
+ def launch_posix_browser(args, url)
+ browser = File.basename(args[0])
+ msg("Killing browser processes: #{browser}")
+ system("pkill #{browser} && pkill -9 #{browser}")
+ args = args + [url]
+ msg("Launching browser: #{args.inspect}")
+ browser_pid = fork {
+ exec(*args)
+ }
+ return [browser_pid]
+ end
+
+ def find_pids(text)
+ # Only tested on Mac OS X.
+ pids = []
+ `ps -x`.each do |proc_line|
+ if proc_line =~ /^ *(\d+).*#{text}/
+ pid = $1.to_i
+ # Do not include yourself.
+ if pid != Process.pid
+ pids << $1.to_i
+ end
+ end
+ end
+ return pids
+ end
+
+ def launch_mac_browser(args, url)
+ # This is dedicated to Safari.
+ if args.length > 1
+ msg(".app type launches do not support arguments, ignoring #{args[1..99].inspect}")
+ end
+ browser = args[0]
+ pids = find_pids(browser)
+ if pids
+ kill_pids(find_pids(browser))
+ sleep(2)
+ end
+ command = "open -a \"#{browser}\" \"#{url}\""
+ msg(".app open command: #{command}")
+ system(command)
+ return find_pids(browser)
+ end
+
+ def kill_pids(pids)
+ pids.each do |pid|
+ msg("Killing #{pid}")
+ begin
+ Process.kill("INT", pid)
+ sleep(0.5)
+ Process.kill("KILL", pid)
+ rescue
+ sleep(0.1)
+ end
+ end
+ end
+
+ def encode_browser()
+ return @browser_id.gsub(' ', '_').gsub(';', '').gsub('/', '-').gsub(/[\(\):\!\@\#\$\%\^\&\*\+=\{\}\[\]\'\"\<\>\?\|\\]/, '').gsub(/_$/, '').gsub(/^_/, '')
+ end
+
+ def kill_server()
+ kill_pids([@server_pid])
+ end
+
+ def parse_test_url(value)
+ current_vars = nil
+ test_num = nil
+ subtest_data = nil
+ lookup_values = false
+ if value =~ /iexploder.cgi(.*)/
+ current_vars = $1
+ if current_vars =~ /[&\?]t=(\d+)/
+ test_num = $1
+ end
+ if current_vars =~ /[&\?]s=([\d_,]+)/
+ subtest_data = $1
+ end
+ if current_vars =~ /[&\?]l=(\w+)/
+ lookup_value = $1
+ end
+ else
+ msg("Unable to parse url in #{value}")
+ return [nil, nil, nil, nil]
+ end
+ return [current_vars, test_num, subtest_data, lookup_value]
+ end
+
+ def check_log_status()
+ timestamp, uri, user_agent = open("#{@app_base_url}last_page.cgi").read().chomp.split(' ')
+ age = (Time.now() - timestamp.to_i).to_i
+ if not @browser_id
+ @browser_id = CGI.unescape(user_agent)
+ msg("My browser is #{@browser_id}")
+ end
+
+
+ return [age, uri]
+ end
+
+ def save_testcase(url, case_type=nil)
+ msg("Saving testcase: #{url}")
+ vars, test_num, subtest_data, lookup_value = parse_test_url(url)
+ if not case_type
+ case_type = 'testcase'
+ end
+
+ testcase_name = ([case_type, encode_browser(), 'TEST', test_num, subtest_data].join('-')).gsub(/-$/, '') + ".html"
+ testcase_path = "#{@test_dir}/#{testcase_name}"
+ data = open(url).read()
+ # Slow down our redirection time, and replace our testcase urls.
+ data.gsub!(/0;URL=\/iexploder.*?\"/, "1;URL=#{testcase_name}\"")
+ data.gsub!(/window\.location=\"\/iexploder.*?\"/, "window\.location=\"#{testcase_name}\"")
+
+ # I wish I did not have to do this, but the reality is that I can't imitate header fuzzing
+ # without a webservice in the backend. Change all URL's to use a well known localhost
+ # port.
+ data.gsub!(/\/iexploder.cgi/, TESTCASE_URL)
+
+ f = File.open(testcase_path, 'w')
+ f.write(data)
+ f.close
+ msg("Wrote testcase #{testcase_path}")
+ return testcase_path
+ end
+
+ def calculate_next_url(test_num, subtest_data)
+ @ie.test_num = test_num.to_i
+ @ie.subtest_data = subtest_data
+ if subtest_data and subtest_data.length > 0
+ (width, offsets) = @ie.parseSubTestData(subtest_data)
+ # We increment within combo_creator
+ (width, offsets, lines) = combine_combo_creator(@ie.config['html_tags_per_page'], width, offsets)
+ return @ie.generateTestUrl(@ie.nextTestNum(), width, offsets)
+ else
+ return @ie.generateTestUrl(@ie.nextTestNum())
+ end
+ end
+
+ def find_crash_logs(max_age)
+ crashed_files = []
+ check_files = Dir.glob("*core*")
+ if File.exists?(MAC_CRASH_PATH)
+ check_files = check_files + Dir.glob("#{MAC_CRASH_PATH}/*.*")
+ end
+ check_files.each do |file|
+ mtime = File.stat(file).mtime
+ age = (Time.now() - mtime).to_i
+ if age < max_age
+ msg("#{file} is only #{age}s old: #{mtime}")
+ crashed_files << file
+ end
+ end
+ return crashed_files
+ end
+
+ def test_browser(args, test_num, random_mode=false)
+ # NOTE: random_mode is not yet supported.
+
+ browser_pids = []
+ subtest_data = nil
+ @ie.test_num = test_num
+ @ie.random_mode = random_mode
+ next_url = @ie.generateTestUrl(test_num)
+
+ while next_url
+ msg("Starting at: #{next_url}")
+ if browser_pids
+ kill_pids(browser_pids)
+ end
+ browser_pids = launch_browser(args, next_url)
+ test_is_running = true
+ crash_files = []
+
+ while test_is_running
+ sleep(@scan_timer)
+ begin
+ age, request_uri = check_log_status()
+ rescue
+ msg("Failed to get status. webserver likely crashed.")
+ kill_pids([@server_pid])
+ @server_pid = launch_server()
+ next_url = @ie.generateTestUrl(test_num)
+ test_is_running = false
+ next
+ end
+ vars, test_num, subtest_data, lookup_value = parse_test_url(request_uri)
+ if lookup_value == 'survived_redirect'
+ msg("We survived #{vars}. Bummer, could not repeat crash. Moving on.")
+ test_is_running = false
+ next_url = calculate_next_url(test_num, subtest_data)
+ next
+ elsif age > @watchdog_timer
+ msg("Stuck at #{vars}, waited for #{@watchdog_timer}s. Killing browser.")
+ kill_pids(browser_pids)
+ current_url = "#{@app_url}#{vars}"
+# save_testcase(current_url, 'possible')
+ crash_files = find_crash_logs(@watchdog_timer + (@scan_timer * 2))
+ if crash_files.length > 0
+ msg("Found recent crash logs: #{crash_files.inspect} - last page: #{current_url}")
+ end
+
+ if vars =~ /THE_END/
+ msg("We hung at the end. Saving a testcase just in case.")
+ save_testcase(current_url)
+ next_url = calculate_next_url(test_num, nil)
+ test_is_running = false
+ next
+ end
+
+ # This is for subtesting
+ if subtest_data
+ if lookup_value
+ msg("Confirmed crashing/hanging page at #{current_url} - saving testcase.")
+ save_testcase(current_url)
+ next_url = calculate_next_url(test_num, nil)
+ test_is_running = false
+ next
+ else
+ msg("Stopped at #{current_url}. Attempting to reproduce simplified crash/hang condition.")
+ browser_pids = launch_browser(args, "#{current_url}&l=test_redirect")
+ end
+ # Normal testing goes here
+ else
+ if lookup_value
+ msg("Reproducible crash/hang at #{current_url}, generating smaller test case.")
+ url = current_url.gsub(/&l=(\w+)/, '')
+ browser_pids = launch_browser(args, "#{url}&s=0")
+ else
+ msg("Stopped at #{current_url}. Attempting to reproduce crash/hang condition.")
+ browser_pids = launch_browser(args, "#{current_url}&l=test_redirect")
+ end
+ end
+ elsif age > @scan_timer
+ msg("Waiting for #{vars} to finish loading... (#{age}s of #{@watchdog_timer}s)")
+ end
+ end
+ end
+ end
+end
+
+if $0 == __FILE__
+ options = {
+ :port => rand(16000).to_i + 16000,
+ :test_dir => File.dirname($0) + '/../output',
+ :log_dir => File.dirname($0) + '/../output',
+ :test_num => nil,
+ :watchdog_timer => 60,
+ :scan_timer => 5,
+ :config_path => 'config.yaml',
+ :random_mode => false
+ }
+
+ optparse = OptionParser.new do |opts|
+ opts.banner = "Usage: browser_harness.rb [options] -- <browser path> <browser options>"
+ opts.on( '-t', '--test NUM', 'Test to start at' ) { |test_num| options[:test_num] = test_num.to_i }
+ opts.on( '-p', '--port NUM', 'Listen on TCP port NUM (random)' ) { |port| options[:port] = port.to_i }
+ opts.on( '-c', '--config PATH', 'Use PATH for configuration file' ) { |path| options[:config_path] = path }
+ opts.on( '-d', '--testdir PATH', 'Use PATH to save testcases (/tmp)' ) { |path| options[:test_dir] = path }
+ opts.on( '-l', '--logdir PATH', 'Use PATH to save logs (/tmp)' ) { |path| options[:log_dir] = path }
+ opts.on( '-w', '--watchdog NUM', 'How many seconds to wait for pages to load (45s)' ) { |sec| options[:watchdog_timer] = sec.to_i }
+ opts.on( '-r', '--random', 'Generate test numbers pseudo-randomly' ) { options[:random_mode] = true }
+ opts.on( '-s', '--scan NUM', 'How often to check for new log data (5s)' ) { |sec| options[:scan_timer] = sec.to_i }
+ opts.on( '-h', '--help', 'Display this screen' ) { puts opts; exit }
+ end
+ optparse.parse!
+
+ if options[:port] == 0
+ puts "Unable to parse port option. Try adding -- as an argument before you specify your browser location."
+ exit
+ end
+
+ if ARGV.length < 1
+ puts "No browser specified. Perhaps you need some --help?"
+ exit
+ end
+ puts "options: #{options.inspect}"
+ puts "browser: #{ARGV.inspect}"
+
+ harness = BrowserHarness.new(
+ options[:port],
+ options[:config_path],
+ options[:log_dir],
+ options[:test_dir],
+ options[:watchdog_timer],
+ options[:scan_timer]
+ )
+
+ harness.test_browser(ARGV, options[:test_num], options[:random_mode])
+end
diff --git a/Tools/iExploder/iexploder-1.7.2/src/config.yaml b/Tools/iExploder/iexploder-1.7.2/src/config.yaml
new file mode 100644
index 0000000..e796e8e
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/config.yaml
@@ -0,0 +1,54 @@
+# iexploder configuration file
+
+# path to the data files (css-properties, css-values, etc.)
+mangle_data_path: .
+
+# This is only used by the webserver.py, not the cgi.
+access_log_path: ../access.log
+
+# Some basic tuning for maximum crashing power.
+html_tags_per_page: 100
+attributes_per_html_tag_max: 15
+properties_per_style_max: 15
+attributes_per_style_property_max: 3
+# URL's loaded by img/src/etc. get a max of this many fuzzed headers
+headers_per_page_max: 2
+
+# How many combinations should we try when generating subtests
+subtest_combinations_max: 5
+
+# How many lines wide should we start our subtesting at? Increase for faster/looser
+# subtesting.
+initial_subtest_width: 1
+
+# How much garbage do we send the client? If you really want to explore
+# buffer overflows, consider making this a much larger size (16K+)
+buffer_overflow_length: 1025
+max_garbage_text_size: 257
+
+# These tags are X% likely to overwrite one randomly selected tag per page load
+favor_html_tags:
+ script: 65
+ style: 75
+ img: 90
+ video: 90
+ object: 90
+ embed: 90
+
+# Exclude certain tag.parameter or tag.style.attribute combinations for a given regexp.
+# An asterisk is allowed in the first field. Valid forms include:
+#
+# img.onloadbanana: "Bananarama 3000"
+# dir.style.-webkit-banana-rule: "BananaWebKit\/532\.9 |BananaTron5K"
+# *.style.-webkit-banana-rule: "BananaWebKit\/532\.9 |BananaTron5K"
+
+exclude:
+ # Hangs the test waiting for a prompt sometimes
+ iframe.src: "Firefox\/3.6"
+
+ # http://code.google.com/p/chromium/issues/detail?id=56207
+ *.style.content: "Chrome\/7\.0\.5"
+
+ # http://code.google.com/p/chromium/issues/detail?id=56208
+ progress.style.font: "Chrome\/7\.0\.5"
+
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-atrules/mozilla b/Tools/iExploder/iexploder-1.7.2/src/css-atrules/mozilla
new file mode 100644
index 0000000..c0e626b
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-atrules/mozilla
@@ -0,0 +1,6 @@
+@-moz-document
+@charset
+@font-face
+@import
+@media
+@namespace
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-atrules/webkit b/Tools/iExploder/iexploder-1.7.2/src/css-atrules/webkit
new file mode 100644
index 0000000..99ea2cc
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-atrules/webkit
@@ -0,0 +1,14 @@
+@-webkit-decls
+@-webkit-keyframe-rule
+@-webkit-keyframes
+@-webkit-mediaquery
+@-webkit-rule
+@-webkit-selector
+@-webkit-value
+@-webkit-variables-decls
+@charset
+@font-face
+@import
+@media
+@namespace
+@page
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-properties/dillo b/Tools/iExploder/iexploder-1.7.2/src/css-properties/dillo
new file mode 100644
index 0000000..72a7d45
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-properties/dillo
@@ -0,0 +1,98 @@
+background
+background-attachment
+background-color
+background-image
+background-position
+background-repeat
+border
+border-bottom
+border-bottom-color
+border-bottom-style
+border-bottom-width
+border-collapse
+border-color
+border-left
+border-left-color
+border-left-style
+border-left-width
+border-right
+border-right-color
+border-right-style
+border-rigth-width
+border-spacing
+border-style
+border-top
+border-top-color
+border-top-style
+border-top-width
+border-width
+bottom
+caption-side
+clear
+clip
+color
+content
+counter-increment
+counter-reset
+cursor
+direction
+display
+empty-cells
+float
+font
+font-family
+font-size
+font-size-adjust
+font-stretch
+font-style
+font-variant
+font-weight
+height
+last
+left
+letter-spacing
+line-height
+list-style
+list-style-image
+list-style-position
+list-style-type
+margin
+margin-bottom
+margin-left
+margin-right
+margin-top
+marker-offset
+marks
+max-height
+max-width
+min-height
+min-width
+outline
+outline-color
+outline-style
+outline-width
+overflow
+padding
+padding-bottom
+padding-left
+padding-right
+padding-top
+position
+quotes
+right
+text-align
+text-decoration
+text-indent
+text-shadow
+text-transform
+top
+unicode-bidi
+vertical-align
+visibility
+white-space
+width
+word-spacing
+x-colspan
+x-link
+x-rowspan
+z-index
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-properties/gtkhtml b/Tools/iExploder/iexploder-1.7.2/src/css-properties/gtkhtml
new file mode 100644
index 0000000..1011a4e
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-properties/gtkhtml
@@ -0,0 +1,16 @@
+background
+background-color
+background-image
+border
+border-color
+border-style
+border-width
+clear
+color
+display
+height
+padding
+text-align
+text-decoration
+white-space
+width
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-properties/internet_explorer6 b/Tools/iExploder/iexploder-1.7.2/src/css-properties/internet_explorer6
new file mode 100644
index 0000000..d23f3a1
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-properties/internet_explorer6
@@ -0,0 +1,29 @@
+filter:progid:
+filter:
+ime-mode
+layout-flow
+layout-grid
+layout-grid-char
+layout-grid-line
+layout-grid-mode
+layout-grid-type
+line-break
+overflow-x
+overflow-y
+pagebreakafter
+pagebreakbefore
+ruby-align
+ruby-overhang
+ruby-position
+text-autospace
+text-justify
+text-kashida-space
+text-underline-position
+word-break
+writing-mode
+zoom
+filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(
+filter:progid:DXImageTransform.Microsoft.Blur(
+filter:progid:DXImageTransform.Microsoft.MotionBlur(
+filter:progid:DXImageTransform.Microsoft.Gradient(
+filter:progid:DXImageTransform.Microsoft.Pixelate(
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-properties/mozilla b/Tools/iExploder/iexploder-1.7.2/src/css-properties/mozilla
new file mode 100644
index 0000000..953e606
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-properties/mozilla
@@ -0,0 +1,275 @@
+-moz-appearance
+-moz-background-inline-policy
+-moz-binding
+-moz-border-bottom-colors
+-moz-border-end
+-moz-border-end-color
+-moz-border-end-style
+-moz-border-end-width
+-moz-border-image
+-moz-border-left-colors
+-moz-border-radius
+-moz-border-radius-bottomleft
+-moz-border-radius-bottomright
+-moz-border-radius-topleft
+-moz-border-radius-topright
+-moz-border-right-colors
+-moz-border-start
+-moz-border-start-color
+-moz-border-start-style
+-moz-border-start-width
+-moz-border-top-colors
+-moz-box-align
+-moz-box-direction
+-moz-box-flex
+-moz-box-ordinal-group
+-moz-box-orient
+-moz-box-pack
+-moz-box-shadow
+-moz-box-sizing
+-moz-column-count
+-moz-column-gap
+-moz-column-rule
+-moz-column-rule-color
+-moz-column-rule-style
+-moz-column-rule-width
+-moz-column-width
+-moz-float-edge
+-moz-font-feature-settings
+-moz-font-language-override
+-moz-force-broken-image-icon
+-moz-image-region
+-moz-margin-end
+-moz-margin-start
+-moz-outline-radius
+-moz-outline-radius-bottomleft
+-moz-outline-radius-bottomright
+-moz-outline-radius-topleft
+-moz-outline-radius-topright
+-moz-padding-end
+-moz-padding-start
+-moz-script-level
+-moz-script-min-size
+-moz-script-size-multiplier
+-moz-stack-sizing
+-moz-tab-size
+-moz-transform
+-moz-transform-origin
+-moz-transition
+-moz-transition-delay
+-moz-transition-duration
+-moz-transition-property
+-moz-transition-timing-function
+-moz-user-focus
+-moz-user-input
+-moz-user-modify
+-moz-user-select
+-moz-window-shadow
+-x-system-font
+appearance
+azimuth
+background
+background-attachment
+background-clip
+background-color
+background-image
+background-origin
+background-position
+background-repeat
+background-size
+binding
+border
+border-bottom
+border-bottom-color
+border-bottom-style
+border-bottom-width
+border-collapse
+border-color
+border-end-color-value
+border-end-style-value
+border-end-width-value
+border-left
+border-left-color
+border-left-color-ltr-source
+border-left-color-rtl-source
+border-left-color-value
+border-left-style
+border-left-style-ltr-source
+border-left-style-rtl-source
+border-left-style-value
+border-left-width
+border-left-width-ltr-source
+border-left-width-rtl-source
+border-left-width-value
+border-right
+border-right-color
+border-right-color-ltr-source
+border-right-color-rtl-source
+border-right-color-value
+border-right-style
+border-right-style-ltr-source
+border-right-style-rtl-source
+border-right-style-value
+border-right-width
+border-right-width-ltr-source
+border-right-width-rtl-source
+border-right-width-value
+border-spacing
+border-start-color-value
+border-start-style-value
+border-start-width-value
+border-style
+border-top
+border-top-color
+border-top-style
+border-top-width
+border-width
+bottom
+caption-side
+clear
+clip
+clip-path
+clip-rule
+color
+color-interpolation
+color-interpolation-filters
+content
+counter-increment
+counter-reset
+cue
+cue-after
+cue-before
+cursor
+direction
+display
+dominant-baseline
+elevation
+empty-cells
+fill
+fill-opacity
+fill-rule
+filter
+float
+flood-color
+flood-opacity
+font
+font-family
+font-size
+font-size-adjust
+font-stretch
+font-style
+font-variant
+font-weight
+height
+image-rendering
+ime-mode
+left
+letter-spacing
+lighting-color
+line-height
+list-style
+list-style-image
+list-style-position
+list-style-type
+margin
+margin-bottom
+margin-end-value
+margin-left
+margin-left-ltr-source
+margin-left-rtl-source
+margin-left-value
+margin-right
+margin-right-ltr-source
+margin-right-rtl-source
+margin-right-value
+margin-start-value
+margin-top
+marker
+marker-end
+marker-mid
+marker-offset
+marker-start
+marks
+mask
+max-height
+max-width
+min-height
+min-width
+nsnull
+opacity
+orphans
+outline
+outline-color
+outline-offset
+outline-style
+outline-width
+overflow
+overflow-x
+overflow-y
+padding
+padding-bottom
+padding-end-value
+padding-left
+padding-left-ltr-source
+padding-left-rtl-source
+padding-left-value
+padding-right
+padding-right-ltr-source
+padding-right-rtl-source
+padding-right-value
+padding-start-value
+padding-top
+page
+page-break-after
+page-break-before
+page-break-inside
+pause
+pause-after
+pause-before
+pitch
+pitch-range
+pointer-events
+position
+quotes
+resize
+richness
+right
+shape-rendering
+size
+speak
+speak-header
+speak-numeral
+speak-punctuation
+speech-rate
+stop-color
+stop-opacity
+stress
+stroke
+stroke-dasharray
+stroke-dashoffset
+stroke-linecap
+stroke-linejoin
+stroke-miterlimit
+stroke-opacity
+stroke-width
+table-layout
+text-align
+text-anchor
+text-decoration
+text-indent
+text-rendering
+text-shadow
+text-transform
+top
+transition
+unicode-bidi
+vertical-align
+visibility
+voice-family
+volume
+white-space
+widows
+width
+word-spacing
+word-wrap
+z-index
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-properties/webkit b/Tools/iExploder/iexploder-1.7.2/src/css-properties/webkit
new file mode 100644
index 0000000..927e24c
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-properties/webkit
@@ -0,0 +1,256 @@
+
+-webkit-animation
+-webkit-animation-delay
+-webkit-animation-direction
+-webkit-animation-duration
+-webkit-animation-fill-mode
+-webkit-animation-iteration-count
+-webkit-animation-name
+-webkit-animation-play-state
+-webkit-animation-timing-function
+-webkit-appearance
+-webkit-backface-visibility
+-webkit-background-clip
+-webkit-background-composite
+-webkit-background-origin
+-webkit-background-size
+-webkit-border-end
+-webkit-border-end-color
+-webkit-border-end-style
+-webkit-border-end-width
+-webkit-border-fit
+-webkit-border-horizontal-spacing
+-webkit-border-image
+-webkit-border-radius
+-webkit-border-start
+-webkit-border-start-color
+-webkit-border-start-style
+-webkit-border-start-width
+-webkit-border-vertical-spacing
+-webkit-box-align
+-webkit-box-direction
+-webkit-box-flex
+-webkit-box-flex-group
+-webkit-box-lines
+-webkit-box-ordinal-group
+-webkit-box-orient
+-webkit-box-pack
+-webkit-box-reflect
+-webkit-box-shadow
+-webkit-box-sizing
+-webkit-color-correction
+-webkit-column-break-after
+-webkit-column-break-before
+-webkit-column-break-inside
+-webkit-column-count
+-webkit-column-gap
+-webkit-column-rule
+-webkit-column-rule-color
+-webkit-column-rule-style
+-webkit-column-rule-width
+-webkit-column-span
+-webkit-column-width
+-webkit-columns
+-webkit-font-size-delta
+-webkit-font-smoothing
+-webkit-highlight
+-webkit-hyphenate-character
+-webkit-hyphenate-locale
+-webkit-hyphens
+-webkit-line-break
+-webkit-line-clamp
+-webkit-margin-bottom-collapse
+-webkit-margin-collapse
+-webkit-margin-end
+-webkit-margin-start
+-webkit-margin-top-collapse
+-webkit-marquee
+-webkit-marquee-direction
+-webkit-marquee-increment
+-webkit-marquee-repetition
+-webkit-marquee-speed
+-webkit-marquee-style
+-webkit-mask
+-webkit-mask-attachment
+-webkit-mask-box-image
+-webkit-mask-clip
+-webkit-mask-composite
+-webkit-mask-image
+-webkit-mask-origin
+-webkit-mask-position
+-webkit-mask-position-x
+-webkit-mask-position-y
+-webkit-mask-repeat
+-webkit-mask-repeat-x
+-webkit-mask-repeat-y
+-webkit-mask-size
+-webkit-match-nearest-mail-blockquote-color
+-webkit-nbsp-mode
+-webkit-padding-end
+-webkit-padding-start
+-webkit-perspective
+-webkit-perspective-origin
+-webkit-perspective-origin-x
+-webkit-perspective-origin-y
+-webkit-rtl-ordering
+-webkit-text-decorations-in-effect
+-webkit-text-fill-color
+-webkit-text-security
+-webkit-text-size-adjust
+-webkit-text-stroke
+-webkit-text-stroke-color
+-webkit-text-stroke-width
+-webkit-transform
+-webkit-transform-origin
+-webkit-transform-origin-x
+-webkit-transform-origin-y
+-webkit-transform-origin-z
+-webkit-transform-style
+-webkit-transition
+-webkit-transition-delay
+-webkit-transition-duration
+-webkit-transition-property
+-webkit-transition-timing-function
+-webkit-user-drag
+-webkit-user-modify
+-webkit-user-select
+-webkit-variable-declaration-block
+background
+background-attachment
+background-clip
+background-color
+background-image
+background-origin
+background-position
+background-position-x
+background-position-y
+background-repeat
+background-repeat-x
+background-repeat-y
+background-size
+border
+border-bottom
+border-bottom-color
+border-bottom-left-radius
+border-bottom-right-radius
+border-bottom-style
+border-bottom-width
+border-collapse
+border-color
+border-left
+border-left-color
+border-left-style
+border-left-width
+border-radius
+border-right
+border-right-color
+border-right-style
+border-right-width
+border-spacing
+border-style
+border-top
+border-top-color
+border-top-left-radius
+border-top-right-radius
+border-top-style
+border-top-width
+border-width
+bottom
+caption-side
+clear
+clip
+color
+content
+counter-increment
+counter-reset
+cursor
+direction
+display
+empty-cells
+float
+font
+font-family
+font-size
+font-stretch
+font-style
+font-variant
+font-weight
+height
+left
+letter-spacing
+line-height
+list-style
+list-style-image
+list-style-position
+list-style-type
+margin
+margin-bottom
+margin-left
+margin-right
+margin-top
+max-height
+max-width
+min-height
+min-width
+opacity
+orphans
+outline
+outline-color
+outline-offset
+outline-style
+outline-width
+overflow
+overflow-x
+overflow-y
+padding
+padding-bottom
+padding-left
+padding-right
+padding-top
+page
+page-break-after
+page-break-before
+page-break-inside
+pointer-events
+position
+quotes
+resize
+right
+size
+src
+table-layout
+text-align
+text-decoration
+text-indent
+text-line-through
+text-line-through-color
+text-line-through-mode
+text-line-through-style
+text-line-through-width
+text-overflow
+text-overline
+text-overline-color
+text-overline-mode
+text-overline-style
+text-overline-width
+text-rendering
+text-shadow
+text-transform
+text-underline
+text-underline-color
+text-underline-mode
+text-underline-style
+text-underline-width
+top
+unicode-bidi
+unicode-range
+vertical-align
+visibility
+white-space
+widows
+width
+word-break
+word-spacing
+word-wrap
+z-index
+zoom
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-pseudo/mozilla b/Tools/iExploder/iexploder-1.7.2/src/css-pseudo/mozilla
new file mode 100644
index 0000000..e092ef7
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-pseudo/mozilla
@@ -0,0 +1,60 @@
+-moz-any
+-moz-any-link
+-moz-bound-element
+-moz-broken
+-moz-drag-over
+-moz-empty-except-children-with-localname
+-moz-first-node
+-moz-focusring
+-moz-handler-blocked
+-moz-handler-crashed
+-moz-handler-disabled
+-moz-has-handlerref
+-moz-is-html
+-moz-last-node
+-moz-loading
+-moz-locale-dir
+-moz-lwtheme
+-moz-lwtheme-brighttext
+-moz-lwtheme-darktext
+-moz-math-increment-script-level
+-moz-only-whitespace
+-moz-placeholder
+-moz-read-only
+-moz-read-write
+-moz-suppressed
+-moz-system-metric
+-moz-type-unsupported
+-moz-user-disabled
+-moz-window-inactive
+active
+checked
+default
+disabled
+empty
+enabled
+first-child
+first-of-type
+focus
+hover
+in-range
+indeterminate
+invalid
+lang
+last-child
+last-of-type
+link
+not
+nth-child
+nth-last-child
+nth-last-of-type
+nth-of-type
+only-child
+only-of-type
+optional
+out-of-range
+required
+root
+target
+valid
+visited
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-pseudo/webkit b/Tools/iExploder/iexploder-1.7.2/src/css-pseudo/webkit
new file mode 100644
index 0000000..07e181e
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-pseudo/webkit
@@ -0,0 +1,101 @@
+-khtml-drag
+-webkit-any-link
+-webkit-autofill
+-webkit-drag
+-webkit-file-upload-button
+-webkit-full-page-media
+-webkit-full-screen
+-webkit-full-screen-document
+-webkit-inner-spin-button
+-webkit-input-list-button
+-webkit-input-placeholder
+-webkit-input-speech-button
+-webkit-media-controls-current-time-display
+-webkit-media-controls-fullscreen-button
+-webkit-media-controls-mute-button
+-webkit-media-controls-panel
+-webkit-media-controls-play-button
+-webkit-media-controls-return-to-realtime-button
+-webkit-media-controls-rewind-button
+-webkit-media-controls-seek-back-button
+-webkit-media-controls-seek-forward-button
+-webkit-media-controls-status-display
+-webkit-media-controls-time-remaining-display
+-webkit-media-controls-timeline
+-webkit-media-controls-timeline-container
+-webkit-media-controls-toggle-closed-captions-button
+-webkit-media-controls-volume-slider
+-webkit-media-controls-volume-slider-container
+-webkit-media-controls-volume-slider-mute-button
+-webkit-meter-horizontal-bar
+-webkit-meter-horizontal-even-less-good-value
+-webkit-meter-horizontal-optimum-value
+-webkit-meter-horizontal-suboptimal-value
+-webkit-meter-vertical-bar
+-webkit-meter-vertical-even-less-good-value
+-webkit-meter-vertical-optimum-value
+-webkit-meter-vertical-suboptimal-value
+-webkit-outer-spin-button
+-webkit-progress-bar-value
+-webkit-resizer
+-webkit-scrollbar
+-webkit-scrollbar-button
+-webkit-scrollbar-corner
+-webkit-scrollbar-thumb
+-webkit-scrollbar-track
+-webkit-scrollbar-track-piece
+-webkit-search-cancel-button
+-webkit-search-decoration
+-webkit-search-results-button
+-webkit-search-results-decoration
+-webkit-slider-thumb
+active
+after
+before
+checked
+corner-present
+decrement
+default
+disabled
+double-button
+empty
+enabled
+end
+first
+first-child
+first-letter
+first-line
+first-of-type
+focus
+horizontal
+hover
+increment
+indeterminate
+invalid
+lang(
+last-child
+last-of-type
+left
+link
+no-button
+not(
+nth-child(
+nth-last-child(
+nth-last-of-type(
+nth-of-type(
+only-child
+only-of-type
+optional
+read-only
+read-write
+required
+right
+root
+selection
+single-button
+start
+target
+valid
+vertical
+visited
+window-inactive
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-values/dillo b/Tools/iExploder/iexploder-1.7.2/src/css-values/dillo
new file mode 100644
index 0000000..2d56833
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-values/dillo
@@ -0,0 +1,93 @@
+armenian
+baseline
+blink
+block
+bold
+bolder
+bottom
+center
+circle
+cjk-ideographic
+crosshair
+dashed
+decimal
+decimal-leading-zero
+default
+disc
+dotted
+double
+e-resize
+georgian
+groove
+hebrew
+help
+hidden
+hiragana
+hiragana-iroha
+inline
+inset
+inside
+italic
+justify
+katakana
+katakana-iroha
+large
+larger
+left
+light
+lighter
+line-through
+list-item
+lower-alpha
+lower-greek
+lower-latin
+lower-roman
+medium
+middle
+move
+ne-resize
+none
+normal
+nowrap
+n-resize
+nw-resize
+oblique
+outset
+outside
+overline
+pointer
+pre
+ridge
+right
+se-resize
+small
+smaller
+solid
+square
+s-resize
+string
+sub
+super
+sw-resize
+table
+table-cell
+table-footer-group
+table-header-group
+table-row
+table-row-group
+text
+text-bottom
+text-top
+thick
+thin
+top
+underline
+upper-alpha
+upper-latin
+upper-roman
+wait
+w-resize
+x-large
+x-small
+xx-large
+xx-small
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-values/gtkhtml b/Tools/iExploder/iexploder-1.7.2/src/css-values/gtkhtml
new file mode 100644
index 0000000..53a4f81
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-values/gtkhtml
@@ -0,0 +1,18 @@
+block
+both
+inherit
+inline
+inline-table
+inset
+left
+medium
+none
+normal
+nowrap
+pre
+pre-line
+pre-wrap
+right
+solid
+thick
+thin
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-values/mozilla b/Tools/iExploder/iexploder-1.7.2/src/css-values/mozilla
new file mode 100644
index 0000000..193f0c8
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-values/mozilla
@@ -0,0 +1,558 @@
+-moz-activehyperlinktext
+-moz-all
+-moz-alt-content
+-moz-anchor-decoration
+-moz-arabic-indic
+-moz-available
+-moz-bengali
+-moz-block-height
+-moz-box
+-moz-button
+-moz-buttondefault
+-moz-buttonhoverface
+-moz-buttonhovertext
+-moz-cellhighlight
+-moz-cellhighlighttext
+-moz-center
+-moz-cjk-earthly-branch
+-moz-cjk-heavenly-stem
+-moz-combobox
+-moz-comboboxtext
+-moz-compact
+-moz-crisp-edges
+-moz-deck
+-moz-desktop
+-moz-devanagari
+-moz-dialog
+-moz-dialogtext
+-moz-document
+-moz-dragtargetzone
+-moz-element
+-moz-ethiopic-halehame
+-moz-ethiopic-halehame-am
+-moz-ethiopic-halehame-ti-er
+-moz-ethiopic-halehame-ti-et
+-moz-ethiopic-numeric
+-moz-eventreerow
+-moz-field
+-moz-fieldtext
+-moz-fit-content
+-moz-grab
+-moz-grabbing
+-moz-grid
+-moz-grid-group
+-moz-grid-line
+-moz-groupbox
+-moz-gujarati
+-moz-gurmukhi
+-moz-hangul
+-moz-hangul-consonant
+-moz-hidden-unscrollable
+-moz-html-cellhighlight
+-moz-html-cellhighlighttext
+-moz-hyperlinktext
+-moz-image-rect
+-moz-info
+-moz-initial
+-moz-inline-box
+-moz-inline-grid
+-moz-inline-stack
+-moz-japanese-formal
+-moz-japanese-informal
+-moz-kannada
+-moz-khmer
+-moz-lao
+-moz-left
+-moz-list
+-moz-mac-alternateprimaryhighlight
+-moz-mac-chrome-active
+-moz-mac-chrome-inactive
+-moz-mac-disabledtoolbartext
+-moz-mac-focusring
+-moz-mac-menuselect
+-moz-mac-menushadow
+-moz-mac-menutextdisable
+-moz-mac-menutextselect
+-moz-mac-secondaryhighlight
+-moz-mac-unified-toolbar
+-moz-malayalam
+-moz-marker
+-moz-max-content
+-moz-menubarhovertext
+-moz-menubartext
+-moz-menuhover
+-moz-menuhovertext
+-moz-middle-with-baseline
+-moz-min-content
+-moz-myanmar
+-moz-nativehyperlinktext
+-moz-none
+-moz-oddtreerow
+-moz-oriya
+-moz-persian
+-moz-popup
+-moz-pull-down-menu
+-moz-right
+-moz-run-in
+-moz-scrollbars-horizontal
+-moz-scrollbars-none
+-moz-scrollbars-vertical
+-moz-show-background
+-moz-simp-chinese-formal
+-moz-simp-chinese-informal
+-moz-stack
+-moz-tamil
+-moz-telugu
+-moz-thai
+-moz-trad-chinese-formal
+-moz-trad-chinese-informal
+-moz-urdu
+-moz-use-system-font
+-moz-use-text-color
+-moz-visitedhyperlinktext
+-moz-win-borderless-glass
+-moz-win-browsertabbar-toolbox
+-moz-win-communications-toolbox
+-moz-win-communicationstext
+-moz-win-glass
+-moz-win-media-toolbox
+-moz-win-mediatext
+-moz-window
+-moz-window-button-box
+-moz-window-button-box-maximized
+-moz-window-button-close
+-moz-window-button-maximize
+-moz-window-button-minimize
+-moz-window-button-restore
+-moz-window-frame-bottom
+-moz-window-frame-left
+-moz-window-frame-right
+-moz-window-titlebar
+-moz-window-titlebar-maximized
+-moz-workspace
+-moz-zoom-in
+-moz-zoom-out
+above
+absolute
+active
+activeborder
+activecaption
+alias
+all
+all-scroll
+alphabetic
+always
+appworkspace
+armenian
+auto
+avoid
+background
+baseline
+behind
+below
+bevel
+bidi-override
+blink
+block
+block-axis
+bold
+bolder
+border-box
+both
+bottom
+bottom-outside
+bounding-box
+break-word
+butt
+button
+button-arrow-down
+button-arrow-next
+button-arrow-previous
+button-arrow-up
+button-bevel
+button-focus
+buttonface
+buttonhighlight
+buttonshadow
+buttontext
+capitalize
+caption
+captiontext
+caret
+cell
+center
+center-left
+center-right
+central
+ch
+checkbox
+checkbox-container
+checkbox-label
+checkmenuitem
+circle
+cjk-ideographic
+close-quote
+closest-corner
+closest-side
+cm
+code
+col-resize
+collapse
+condensed
+contain
+content-box
+context-menu
+continuous
+copy
+cover
+crispedges
+crop
+cross
+crosshair
+currentcolor
+dashed
+decimal
+decimal-leading-zero
+default
+deg
+dialog
+digits
+disabled
+disc
+dotted
+double
+dualbutton
+e-resize
+each-box
+ease
+ease-in
+ease-in-out
+ease-out
+element
+elements
+ellipse
+em
+embed
+enabled
+end
+evenodd
+ew-resize
+ex
+expanded
+extra-condensed
+extra-expanded
+far-left
+far-right
+farthest-corner
+farthest-side
+fast
+faster
+fill
+fixed
+geometricprecision
+georgian
+grad
+graytext
+groove
+groupbox
+hanging
+hebrew
+help
+hidden
+hide
+high
+higher
+highlight
+highlighttext
+hiragana
+hiragana-iroha
+horizontal
+hz
+icon
+ideographic
+ignore
+in
+inactive
+inactiveborder
+inactivecaption
+inactivecaptiontext
+infobackground
+infotext
+inherit
+inline
+inline-axis
+inline-block
+inline-table
+inset
+inside
+interlace
+invert
+italic
+justify
+katakana
+katakana-iroha
+khz
+landscape
+large
+larger
+left
+left-side
+leftwards
+level
+lighter
+line-through
+linear
+linearrgb
+list-item
+listbox
+listitem
+logical
+loud
+low
+lower
+lower-alpha
+lower-greek
+lower-latin
+lower-roman
+lowercase
+ltr
+margin-box
+mathematical
+matrix
+medium
+menu
+menuarrow
+menubar
+menucheckbox
+menuimage
+menuitem
+menuitemtext
+menulist
+menulist-button
+menulist-text
+menulist-textfield
+menupopup
+menuradio
+menuseparator
+menutext
+message-box
+middle
+miter
+mix
+mm
+move
+ms
+n-resize
+narrower
+ne-resize
+nesw-resize
+no-change
+no-close-quote
+no-drop
+no-open-quote
+no-repeat
+none
+nonzero
+normal
+not-allowed
+nowrap
+ns-resize
+nw-resize
+nwse-resize
+oblique
+once
+open-quote
+optimizelegibility
+optimizequality
+optimizespeed
+outset
+outside
+overline
+padding-box
+painted
+pc
+physical
+pointer
+portrait
+pre
+pre-line
+pre-wrap
+progress
+progressbar
+progressbar-vertical
+progresschunk
+progresschunk-vertical
+progressive
+pt
+px
+rad
+radio
+radio-container
+radio-label
+radiomenuitem
+read-only
+read-write
+relative
+repeat
+repeat-x
+repeat-y
+reset-size
+resizer
+resizerpanel
+reverse
+ridge
+right
+right-side
+rightwards
+rotate
+round
+row-resize
+rtl
+s
+s-resize
+scale
+scale-horizontal
+scale-vertical
+scalethumb-horizontal
+scalethumb-vertical
+scalethumbend
+scalethumbstart
+scalethumbtick
+scalex
+scaley
+scroll
+scrollbar
+scrollbar-small
+scrollbarbutton-down
+scrollbarbutton-left
+scrollbarbutton-right
+scrollbarbutton-up
+scrollbarthumb-horizontal
+scrollbarthumb-vertical
+scrollbartrack-horizontal
+scrollbartrack-vertical
+se-resize
+searchfield
+select-after
+select-all
+select-before
+select-menu
+select-same
+semi-condensed
+semi-expanded
+separate
+separator
+sheet
+show
+silent
+skew
+skewx
+skewy
+slow
+slower
+small
+small-caps
+small-caption
+smaller
+soft
+solid
+spell-out
+spinner
+spinner-downbutton
+spinner-textfield
+spinner-upbutton
+splitter
+square
+srgb
+start
+static
+status-bar
+statusbar
+statusbarpanel
+stretch
+stretch-to-fit
+stroke
+sub
+super
+sw-resize
+tab
+tab-scroll-arrow-back
+tab-scroll-arrow-forward
+table
+table-caption
+table-cell
+table-column
+table-column-group
+table-footer-group
+table-header-group
+table-row
+table-row-group
+tabpanel
+tabpanels
+text
+text-after-edge
+text-before-edge
+text-bottom
+text-top
+textfield
+textfield-multiline
+thick
+thin
+threeddarkshadow
+threedface
+threedhighlight
+threedlightshadow
+threedshadow
+toggle
+toolbar
+toolbarbutton
+toolbarbutton-dropdown
+toolbargripper
+toolbox
+tooltip
+top
+top-outside
+translate
+translatex
+translatey
+transparent
+treeheader
+treeheadercell
+treeheadersortarrow
+treeitem
+treeline
+treetwisty
+treetwistyopen
+treeview
+tri-state
+ultra-condensed
+ultra-expanded
+underline
+upper-alpha
+upper-latin
+upper-roman
+uppercase
+use-script
+vertical
+vertical-text
+visible
+visiblefill
+visiblepainted
+visiblestroke
+w-resize
+wait
+wider
+window
+windowframe
+windowtext
+write-only
+x-fast
+x-high
+x-large
+x-loud
+x-low
+x-slow
+x-small
+x-soft
+xx-large
+xx-small
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-values/other b/Tools/iExploder/iexploder-1.7.2/src/css-values/other
new file mode 100644
index 0000000..c3c1fba
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-values/other
@@ -0,0 +1,20 @@
+0
+0 auto
+0 fixed
+#339933 !important !important !important
+attr("ATTRAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA")
+block clear
+block width
+clip:rect(-0px -2000000px -200000px -0px)
+clip:rect(0px 2000000px 200000px 0px)
+no-close
+normal !important
+rgb(9999999999, 999999999, 9999999999999)
+scrollbargripper-horizontal
+scrollbargripper-vertical
+searchfield-close
+searchfield-results
+thick dashed yellow
+thick dotted blue
+unfurl
+-webkit-overlay
diff --git a/Tools/iExploder/iexploder-1.7.2/src/css-values/webkit b/Tools/iExploder/iexploder-1.7.2/src/css-values/webkit
new file mode 100644
index 0000000..bb7c7f8
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/css-values/webkit
@@ -0,0 +1,478 @@
+
+-wap-marquee
+-webkit-activelink
+-webkit-auto
+-webkit-baseline-middle
+-webkit-body
+-webkit-box
+-webkit-center
+-webkit-control
+-webkit-focus-ring-color
+-webkit-grab
+-webkit-grabbing
+-webkit-inline-box
+-webkit-left
+-webkit-link
+-webkit-marquee
+-webkit-mini-control
+-webkit-nowrap
+-webkit-right
+-webkit-small-control
+-webkit-text
+-webkit-xxx-large
+-webkit-zoom-in
+-webkit-zoom-out
+100
+200
+300
+400
+500
+600
+700
+800
+900
+a3
+a4
+a5
+above
+absolute
+activeborder
+activecaption
+afar
+after-white-space
+ahead
+alias
+all
+all-scroll
+alternate
+always
+amharic
+amharic-abegede
+antialiased
+appworkspace
+aqua
+arabic-indic
+armenian
+asterisks
+auto
+avoid
+b4
+b5
+background
+backwards
+baseline
+below
+bengali
+bidi-override
+binary
+black
+blink
+block
+block-axis
+blue
+bold
+bolder
+border
+border-box
+both
+bottom
+break-all
+break-word
+button
+button-bevel
+buttonface
+buttonhighlight
+buttonshadow
+buttontext
+cambodian
+capitalize
+caps-lock-indicator
+caption
+captiontext
+caret
+cell
+center
+checkbox
+circle
+cjk-earthly-branch
+cjk-heavenly-stem
+cjk-ideographic
+clear
+clip
+close-quote
+col-resize
+collapse
+compact
+condensed
+contain
+content
+content-box
+context-menu
+continuous
+continuous-capacity-level-indicator
+copy
+cover
+crop
+cross
+crosshair
+currentcolor
+cursive
+dashed
+decimal
+decimal-leading-zero
+default
+default-button
+destination-atop
+destination-in
+destination-out
+destination-over
+devanagari
+disc
+discard
+discrete-capacity-level-indicator
+document
+dot-dash
+dot-dot-dash
+dotted
+double
+down
+e-resize
+ease
+ease-in
+ease-in-out
+ease-out
+element
+ellipsis
+embed
+end
+ethiopic
+ethiopic-abegede
+ethiopic-abegede-am-et
+ethiopic-abegede-gez
+ethiopic-abegede-ti-er
+ethiopic-abegede-ti-et
+ethiopic-halehame-aa-er
+ethiopic-halehame-aa-et
+ethiopic-halehame-am-et
+ethiopic-halehame-gez
+ethiopic-halehame-om-et
+ethiopic-halehame-sid-et
+ethiopic-halehame-so-et
+ethiopic-halehame-ti-er
+ethiopic-halehame-ti-et
+ethiopic-halehame-tig
+ew-resize
+expanded
+extra-condensed
+extra-expanded
+fantasy
+fast
+fill
+fixed
+flat
+floating
+footnotes
+forwards
+fuchsia
+fullscreen
+geometricPrecision
+georgian
+gray
+graytext
+green
+grey
+groove
+gujarati
+gurmukhi
+hand
+hangul
+hangul-consonant
+hebrew
+help
+hidden
+hide
+higher
+highlight
+highlighttext
+hiragana
+hiragana-iroha
+horizontal
+icon
+ignore
+inactiveborder
+inactivecaption
+inactivecaptiontext
+infinite
+infobackground
+infotext
+inherit
+initial
+inline
+inline-axis
+inline-block
+inline-table
+inner-spin-button
+input-speech-button
+inset
+inside
+intrinsic
+invert
+italic
+justify
+kannada
+katakana
+katakana-iroha
+khmer
+landscape
+lao
+large
+larger
+ledger
+left
+legal
+letter
+level
+lighter
+lime
+line-through
+linear
+lines
+list-button
+list-item
+listbox
+listitem
+local
+logical
+loud
+lower
+lower-alpha
+lower-greek
+lower-hexadecimal
+lower-latin
+lower-norwegian
+lower-roman
+lowercase
+ltr
+malayalam
+manual
+maroon
+match
+maximized
+media-controls-background
+media-controls-fullscreen-background
+media-current-time-display
+media-fullscreen-button
+media-mute-button
+media-play-button
+media-return-to-realtime-button
+media-rewind-button
+media-seek-back-button
+media-seek-forward-button
+media-slider
+media-sliderthumb
+media-time-remaining-display
+media-toggle-closed-captions-button
+media-volume-slider
+media-volume-slider-container
+media-volume-slider-mute-button
+media-volume-sliderthumb
+medium
+menu
+menulist
+menulist-button
+menulist-text
+menulist-textfield
+menutext
+message-box
+meter
+middle
+min-intrinsic
+minimized
+mix
+mongolian
+monospace
+move
+multiple
+myanmar
+n-resize
+narrower
+navy
+ne-resize
+nesw-resize
+no-close-quote
+no-drop
+no-open-quote
+no-repeat
+none
+normal
+not-allowed
+nowrap
+ns-resize
+nw-resize
+nwse-resize
+oblique
+octal
+olive
+open-quote
+optimizeLegibility
+optimizeSpeed
+orange
+oriya
+oromo
+outer-spin-button
+outset
+outside
+overlay
+overline
+padding
+padding-box
+painted
+paused
+persian
+plus-darker
+plus-lighter
+pointer
+portrait
+pre
+pre-line
+pre-wrap
+preserve-3d
+progress
+progress-bar
+progress-bar-value
+purple
+push-button
+radio
+rating-level-indicator
+read-only
+read-write
+read-write-plaintext-only
+red
+relative
+relevancy-level-indicator
+repeat
+repeat-x
+repeat-y
+reset
+reverse
+ridge
+right
+round
+row-resize
+rtl
+run-in
+running
+s-resize
+sRGB
+sans-serif
+scroll
+scrollbar
+se-resize
+searchfield
+searchfield-cancel-button
+searchfield-decoration
+searchfield-results-button
+searchfield-results-decoration
+semi-condensed
+semi-expanded
+separate
+serif
+show
+sidama
+silver
+single
+skip-white-space
+slide
+slider-horizontal
+slider-vertical
+sliderthumb-horizontal
+sliderthumb-vertical
+slow
+small
+small-caps
+small-caption
+smaller
+solid
+somali
+source-atop
+source-in
+source-out
+source-over
+space
+square
+square-button
+start
+static
+status-bar
+stretch
+stroke
+sub
+subpixel-antialiased
+super
+sw-resize
+table
+table-caption
+table-cell
+table-column
+table-column-group
+table-footer-group
+table-header-group
+table-row
+table-row-group
+teal
+telugu
+text
+text-bottom
+text-top
+textarea
+textfield
+thai
+thick
+thin
+threeddarkshadow
+threedface
+threedhighlight
+threedlightshadow
+threedshadow
+tibetan
+tigre
+tigrinya-er
+tigrinya-er-abegede
+tigrinya-et
+tigrinya-et-abegede
+top
+transparent
+ultra-condensed
+ultra-expanded
+underline
+up
+upper-alpha
+upper-greek
+upper-hexadecimal
+upper-latin
+upper-norwegian
+upper-roman
+uppercase
+urdu
+vertical
+vertical-text
+visible
+visibleFill
+visiblePainted
+visibleStroke
+visual
+w-resize
+wait
+wave
+white
+wider
+window
+windowed
+windowframe
+windowtext
+x-large
+x-small
+xor
+xx-large
+xx-small
+yellow
diff --git a/Tools/iExploder/iexploder-1.7.2/src/headers/dillo b/Tools/iExploder/iexploder-1.7.2/src/headers/dillo
new file mode 100644
index 0000000..7eaee43
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/headers/dillo
@@ -0,0 +1,9 @@
+Content-Encoding
+Content-Length
+Content-Type
+Date
+Location
+Set-Cookie
+Transfer-Encoding
+Warning
+WWW-Authenticate
diff --git a/Tools/iExploder/iexploder-1.7.2/src/headers/gtkhtml b/Tools/iExploder/iexploder-1.7.2/src/headers/gtkhtml
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/headers/gtkhtml
diff --git a/Tools/iExploder/iexploder-1.7.2/src/headers/mozilla b/Tools/iExploder/iexploder-1.7.2/src/headers/mozilla
new file mode 100644
index 0000000..8eda16c
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/headers/mozilla
@@ -0,0 +1,70 @@
+Accept
+Accept-Charset
+Accept-Encoding
+Accept-Language
+Accept-Ranges
+Age
+Allow
+Authentication
+Authorization
+Cache-Control
+Connection
+Content-Base
+Content-Disposition
+Content-Encoding
+Content-Language
+Content-Length
+Content-Location
+Content-MD5
+Content-Range
+Content-Transfer-Encoding
+Content-Type
+Cookie
+Date
+Depth
+Derived-From
+Destination
+Etag
+Expect
+Expires
+Forwarded
+From
+Host
+If
+If-Match
+If-Match-Any
+If-Modified-Since
+If-None-Match
+If-None-Match-Any
+If-Range
+If-Unmodified-Since
+Keep-Alive
+Last-Modified
+Link
+Location
+Lock-Token
+Max-Forwards
+Message-Id
+Mime
+Overwrite
+Pragma
+Proxy-Authenticate
+Proxy-Authorization
+Proxy-Connection
+Range
+Referer
+Retry-After
+Server
+Set-Cookie
+Set-Cookie2
+Status-URI
+Timeout
+Title
+Trailer
+Transfer-Encoding
+Upgrade
+User-Agent
+Vary
+Version
+WWW-Authenticate
+Warning
diff --git a/Tools/iExploder/iexploder-1.7.2/src/headers/webkit b/Tools/iExploder/iexploder-1.7.2/src/headers/webkit
new file mode 100644
index 0000000..4663d64
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/headers/webkit
@@ -0,0 +1,30 @@
+Accept
+Accept-Ranges
+Access-Control-Allow-Credentials
+Access-Control-Allow-Headers
+Access-Control-Allow-Methods
+Access-Control-Allow-Origin
+Access-Control-Max-Age
+Content-Disposition
+Content-Encoding
+Content-Type
+ETag
+Last-Modified
+Origin
+Range
+Referer
+Refresh
+User-Agent
+X-DNS-Prefetch-Control
+age
+cache-control
+date
+expires
+icy-genre
+icy-metaint
+icy-name
+icy-title
+icy-url
+last-modified
+location
+pragma
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-attrs/dillo b/Tools/iExploder/iexploder-1.7.2/src/html-attrs/dillo
new file mode 100644
index 0000000..d134209
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-attrs/dillo
@@ -0,0 +1,51 @@
+accept-charset
+action
+align
+alt
+bgcolor
+border
+cellpadding
+cellspacing
+char
+checked
+codebase
+color
+cols
+colspan
+content
+coords
+data
+disabled
+enctype
+face
+href
+hspace
+http-equiv
+ismap
+link
+maxlength
+media
+method
+multiple
+name
+noshade
+nowrap
+prompt
+readonly
+rel
+rows
+rowspan
+selected
+shape
+size
+src
+start
+text
+title
+type
+usemap
+valign
+value
+vlink
+vspace
+width
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-attrs/gtkhtml b/Tools/iExploder/iexploder-1.7.2/src/html-attrs/gtkhtml
new file mode 100644
index 0000000..31f4052
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-attrs/gtkhtml
@@ -0,0 +1,64 @@
+action
+align
+alink
+all
+background
+bgcolor
+bottom
+bottommargin
+button
+checkbox
+checked
+circle
+cite
+class
+clear
+cols
+content
+content-type
+coords
+default
+dir
+hidden
+href
+hspace
+http-equiv
+image
+key
+left
+leftmargin
+link
+ltr
+marginheight
+marginwidth
+maxlength
+method
+name
+no
+onClick
+password
+poly
+post
+radio
+rect
+refresh
+reset
+right
+rightmargin
+rows
+rtl
+shape
+size
+src
+style
+submit
+target
+text
+top
+topmargin
+type
+url
+value
+vlink
+vspace
+yes
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-attrs/internet_explorer6 b/Tools/iExploder/iexploder-1.7.2/src/html-attrs/internet_explorer6
new file mode 100644
index 0000000..9e4c6ed
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-attrs/internet_explorer6
@@ -0,0 +1,18 @@
+# IE specific, from msdn.microsoft.com/workshop/author/dhtml/reference/properties
+acceptcharset
+allowtransparency
+balance
+choff
+datafld
+dataformatas
+datapagesize
+datasrc
+dynsrc
+framespacing
+galleryimg
+hidefocus
+methods
+scroll
+units
+urn
+volume
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-attrs/mozilla b/Tools/iExploder/iexploder-1.7.2/src/html-attrs/mozilla
new file mode 100644
index 0000000..5a8e6e1
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-attrs/mozilla
@@ -0,0 +1,694 @@
+SVGLinearGradientFrame
+SVGRadialGradientFrame
+_moz-type
+abbr
+acceltext
+accent
+accent-height
+accentunder
+accept
+accept-charset
+accesskey
+accumulate
+action
+actiontype
+active
+additive
+align
+alignment-baseline
+alignmentscope
+alink
+alphabetic
+alt
+alternate
+altimg
+alttext
+amplitude
+arabic-form
+archive
+aria-activedescendant
+aria-atomic
+aria-autocomplete
+aria-busy
+aria-channel
+aria-checked
+aria-controls
+aria-datatype
+aria-describedby
+aria-disabled
+aria-dropeffect
+aria-expanded
+aria-flowto
+aria-grab
+aria-haspopup
+aria-hidden
+aria-invalid
+aria-labelledby
+aria-level
+aria-live
+aria-multiline
+aria-multiselectable
+aria-owns
+aria-posinset
+aria-pressed
+aria-readonly
+aria-relevant
+aria-required
+aria-secret
+aria-selected
+aria-setsize
+aria-sort
+aria-templateid
+aria-valuemax
+aria-valuemin
+aria-valuenow
+ascent
+async
+attribute
+attributeName
+attributename
+attributetype
+autocomplete
+autofocus
+autoplay
+autosubmit
+axis
+azimuth
+background
+base
+basefrequency
+baseline
+baseline-shift
+baseprofile
+bbox
+begin
+bevelled
+bgcolor
+bias
+border
+bordercolor
+bottom
+bottommargin
+by
+calcMode
+calcmode
+cap-height
+cellpadding
+cellspacing
+char
+charcode
+charoff
+charset
+checked
+child
+cite
+class
+classid
+clear
+clip
+clip-path
+clip-rule
+clippathunits
+close
+closure
+code
+codebase
+codetype
+color
+color-interpolation
+color-interpolation-filters
+color-profile
+color-rendering
+cols
+colspan
+columnalign
+columnlines
+columnspacing
+columnspan
+columnwidth
+command
+compact
+container
+containment
+content
+contenteditable
+contentscripttype
+contentstyletype
+contextmenu
+control
+controls
+coords
+curpos
+cursor
+cx
+cy
+d
+data
+datafld
+dataformatas
+datasources
+datasrc
+datetime
+declare
+default
+defer
+definitionurl
+denomalign
+depth
+descent
+diffuseconstant
+dir
+direction
+disabled
+display
+displaystyle
+divisor
+dominant-baseline
+draggable
+dur
+dx
+dy
+edge
+edgemode
+editable
+element
+elevation
+enable-background
+encoding
+enctype
+end
+equalcolumns
+equalrows
+equalsize
+event
+events
+exponent
+expr
+extends
+externalresourcesrequired
+face
+fence
+fill
+fill-opacity
+fill-rule
+filter
+filterres
+filterunits
+flags
+flex
+flood-color
+flood-opacity
+font-family
+font-size
+font-size-adjust
+font-stretch
+font-style
+font-variant
+font-weight
+fontfamily
+fontsize
+fontstyle
+fontweight
+for
+form
+formaction
+format
+formenctype
+formmethod
+frame
+frameborder
+framespacing
+from
+fx
+fy
+g1
+g2
+glyph-name
+glyph-orientation-horizontal
+glyph-orientation-vertical
+glyphRef
+glyphref
+gradientTransform
+gradientUnits
+gradienttransform
+gradientunits
+groupalign
+handler
+hanging
+headers
+height
+hidden
+hidefocus
+high
+horiz-adv-x
+horiz-origin-x
+horiz-origin-y
+href
+hreflang
+hspace
+http-equiv
+icon
+id
+ideographic
+image-rendering
+in
+in2
+includes
+increment
+index
+infer
+inherits
+inputmode
+insertafter
+insertbefore
+intercept
+irrelevant
+ismap
+k
+k1
+k2
+k3
+k4
+kernelmatrix
+kernelunitlength
+kerning
+key
+keycode
+keypoints
+keysplines
+keytext
+keytimes
+label
+lang
+language
+largeop
+layer
+layout
+left
+leftmargin
+lengthadjust
+letter-spacing
+lighting-color
+limitingconeangle
+linebreak
+linethickness
+link
+list
+local
+longdesc
+loopend
+loopstart
+low
+lowsrc
+lquote
+lspace
+lwtheme
+lwthemetextcolor
+macros
+manifest
+marginheight
+marginwidth
+marker-end
+marker-mid
+marker-start
+markerheight
+markerunits
+markerwidth
+mask
+maskcontentunits
+maskunits
+mathbackground
+mathcolor
+mathematical
+mathsize
+mathvariant
+max
+maxheight
+maxlength
+maxpos
+maxsize
+maxwidth
+media
+mediummathspace
+member
+method
+min
+minheight
+minpos
+minsize
+minwidth
+mode
+modifiers
+movablelimits
+multiple
+name
+namespace
+nargs
+nohref
+noresize
+noshade
+notation
+nowrap
+numalign
+numoctaves
+object
+observer
+observes
+occurrence
+offset
+onabort
+onactivate
+onafterprint
+onafterupdate
+onbefordeactivate
+onbeforeactivate
+onbeforecopy
+onbeforecut
+onbeforeeditfocus
+onbeforepaste
+onbeforeprint
+onbeforeunload
+onbeforeupdate
+onbegin
+onblur
+onbounce
+oncellchange
+onchange
+onclick
+oncontextmenu
+oncontrolselect
+oncopy
+oncut
+ondataavailable
+ondatasetchanged
+ondatasetcomplete
+ondblclick
+ondeactivate
+ondrag
+ondragdrop
+ondragend
+ondragenter
+ondragleave
+ondragover
+ondragstart
+ondrop
+onend
+onerror
+onerrorupdate
+onfilterchange
+onfinish
+onfocus
+onfocusin
+onfocusout
+onformchange
+onforminput
+onhelp
+oninput
+oninvalid
+onkeydown
+onkeypress
+onkeyup
+onload
+onlosecapture
+onmessage
+onmousedown
+onmouseenter
+onmouseleave
+onmousemove
+onmouseout
+onmouseover
+onmouseup
+onmousewheel
+onmove
+onmoveend
+onmovestart
+onpaste
+onpropertychange
+onreadystatechange
+onrepeat
+onreset
+onresize
+onrowenter
+onrowexit
+onrowsdelete
+onrowsinserted
+onscroll
+onselect
+onselectstart
+onstart
+onstop
+onsubmit
+onunload
+onzoom
+opacity
+open
+operator
+optimum
+order
+ordinal
+orient
+orientation
+origin
+other
+overflow
+overline-position
+overline-thickness
+pageincrement
+panose-1
+parent
+parsetype
+path
+pathlength
+pattern
+patternContentUnits
+patternTransform
+patternUnits
+patterncontentunits
+patterntransform
+patternunits
+persist
+ping
+placeholder
+playcount
+point-size
+pointer-events
+points
+pointsatx
+pointsaty
+pointsatz
+popupalign
+popupanchor
+position
+poster
+predicate
+prefix
+preload
+preserveAspectRatio
+preservealpha
+preserveaspectratio
+primitiveunits
+profile
+prompt
+properties
+querytype
+r
+radiogroup
+radius
+readonly
+ref
+refx
+refy
+rel
+rendering-intent
+repeat
+repeat-max
+repeat-min
+repeat-start
+repeat-template
+repeatcount
+repeatdur
+replace
+required
+requiredExtensions
+requiredFeatures
+requiredextensions
+requiredfeatures
+resource
+restart
+result
+rev
+right
+rightmargin
+role
+rotate
+rowalign
+rowlines
+rows
+rowspacing
+rowspan
+rquote
+rspace
+rt
+rules
+rx
+ry
+sandbox
+scale
+scheme
+scope
+scoped
+scriptlevel
+scriptminsize
+scriptsizemultiplier
+scrolldelay
+scrolling
+seamless
+seed
+select
+selectable
+selected
+selectedIndex
+selection
+separator
+separators
+shape
+shape-rendering
+size
+sizetopopup
+slope
+sort
+sortDirection
+sortResource
+sortResource2
+sorthints
+space
+spacing
+span
+specification
+specularconstant
+specularexponent
+speed
+spreadMethod
+spreadmethod
+src
+standby
+start
+startoffset
+statedatasource
+staticHint
+stddeviation
+stemh
+stemv
+step
+stitchtiles
+stop-color
+stop-opacity
+stretchy
+strikethrough-position
+strikethrough-thickness
+string
+stroke
+stroke-dasharray
+stroke-dashoffset
+stroke-linecap
+stroke-linejoin
+stroke-miterlimit
+stroke-opacity
+stroke-width
+style
+subject
+subscriptshift
+summary
+superscriptshift
+surfacescale
+symmetric
+systemLanguage
+systemlanguage
+tabindex
+tablevalues
+tag
+target
+targets
+targetx
+targety
+template
+text
+text-anchor
+text-decoration
+text-rendering
+textlength
+thickmathspace
+thinmathspace
+title
+to
+tooltip
+tooltiptext
+top
+topmargin
+transform
+type
+u1
+u2
+underline-position
+underline-thickness
+unicode
+unicode-bidi
+unicode-range
+units-per-em
+unselectable
+uri
+usemap
+v-alphabetic
+v-hanging
+v-ideographic
+v-mathematical
+valign
+value
+values
+valuetype
+var
+variable
+version
+vert-adv-y
+vert-origin-x
+vert-origin-y
+verythickmathspace
+verythinmathspace
+veryverythickmathspace
+veryverythinmathspace
+viewBox
+viewbox
+viewtarget
+visibility
+vlink
+vspace
+when
+width
+widths
+word-spacing
+wrap
+writing-mode
+x
+x-height
+x1
+x2
+xchannelselector
+xlink:actuate
+xlink:arcrole
+xlink:href
+xlink:role
+xlink:show
+xlink:title
+xlink:type
+xml:base
+xml:lang
+xml:space
+xmlns
+xmlns:xlink
+xref
+y
+y1
+y2
+ychannelselector
+z
+zoomandpan
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-attrs/other b/Tools/iExploder/iexploder-1.7.2/src/html-attrs/other
new file mode 100644
index 0000000..8805bee
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-attrs/other
@@ -0,0 +1,36 @@
+autocheck
+bounce
+html
+nosave
+onbounce
+onclose
+oncommand
+oncommandupdate
+oncompositionend
+oncompositionstart
+ondragdrop
+ondragexit
+ondraggesture
+onfinish
+onget
+onoverflow
+onoverflowchanged
+onpaint
+onpopuphidden
+onpopuphiding
+onpopupshowing
+onpopupshown
+onset
+onstart
+ontext
+onunderflow
+onzoom
+oversrc
+pagex
+pagey
+plain
+pluginpage
+pluginspage
+unknown
+visibility
+z-index
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-attrs/webkit b/Tools/iExploder/iexploder-1.7.2/src/html-attrs/webkit
new file mode 100644
index 0000000..010f3ea
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-attrs/webkit
@@ -0,0 +1,284 @@
+
+abbr
+accept
+accept_charset
+accesskey
+action
+align
+alink
+alt
+archive
+aria-activedescendant
+aria-atomic
+aria-busy
+aria-checked
+aria-controls
+aria-describedby
+aria-disabled
+aria-dropeffect
+aria-expanded
+aria-flowto
+aria-grabbed
+aria-haspopup
+aria-help
+aria-hidden
+aria-label
+aria-labeledby
+aria-labelledby
+aria-level
+aria-live
+aria-multiselectable
+aria-orientation
+aria-owns
+aria-pressed
+aria-readonly
+aria-relevant
+aria-required
+aria-selected
+aria-valuemax
+aria-valuemin
+aria-valuenow
+aria-valuetext
+async
+attrsNullNamespace
+autocomplete
+autofocus
+autoplay
+autosave
+axis
+background
+behavior
+bgcolor
+bgproperties
+border
+bordercolor
+cellborder
+cellpadding
+cellspacing
+challenge
+char
+charoff
+charset
+checked
+cite
+class
+classid
+clear
+code
+codebase
+codetype
+color
+cols
+colspan
+compact
+composite
+content
+contenteditable
+controls
+coords
+data
+datetime
+declare
+defer
+dir
+direction
+disabled
+draggable
+enctype
+end
+event
+expanded
+face
+focused
+for
+formnovalidate
+frame
+frameborder
+headers
+height
+hidden
+high
+href
+hreflang
+hspace
+http_equiv
+id
+incremental
+indeterminate
+ismap
+keytype
+label
+lang
+language
+leftmargin
+link
+list
+longdesc
+loop
+loopend
+loopstart
+low
+lowsrc
+manifest
+marginheight
+marginwidth
+max
+maxlength
+mayscript
+media
+method
+min
+multiple
+name
+nohref
+noresize
+noshade
+novalidate
+nowrap
+object
+onabort
+onbeforecopy
+onbeforecut
+onbeforeload
+onbeforepaste
+onbeforeprocess
+onbeforeunload
+onblur
+oncanplay
+oncanplaythrough
+onchange
+onclick
+oncontextmenu
+oncopy
+oncut
+ondblclick
+ondrag
+ondragend
+ondragenter
+ondragleave
+ondragover
+ondragstart
+ondrop
+ondurationchange
+onemptied
+onended
+onerror
+onfocus
+onfocusin
+onfocusout
+onhashchange
+oninput
+oninvalid
+onkeydown
+onkeypress
+onkeyup
+onload
+onloadeddata
+onloadedmetadata
+onloadstart
+onmousedown
+onmousemove
+onmouseout
+onmouseover
+onmouseup
+onmousewheel
+onoffline
+ononline
+onorientationchange
+onpagehide
+onpageshow
+onpaste
+onpause
+onplay
+onplaying
+onpopstate
+onprogress
+onratechange
+onreset
+onresize
+onscroll
+onsearch
+onseeked
+onseeking
+onselect
+onselectstart
+onstalled
+onstorage
+onsubmit
+onsuspend
+ontimeupdate
+ontouchcancel
+ontouchend
+ontouchmove
+ontouchstart
+onunload
+onvolumechange
+onwaiting
+onwebkitanimationend
+onwebkitanimationiteration
+onwebkitanimationstart
+onwebkitbeginfullscreen
+onwebkitendfullscreen
+onwebkitfullscreenchange
+onwebkittransitionend
+optimum
+pattern
+placeholder
+playcount
+pluginurl
+poster
+precision
+preload
+primary
+profile
+progress
+prompt
+readonly
+rel
+required
+results
+rev
+role
+rows
+rowspan
+rules
+sandbox
+scheme
+scope
+scrollamount
+scrolldelay
+scrolling
+selected
+shape
+size
+sortable
+sortdirection
+span
+speech
+spellcheck
+src
+standby
+start
+step
+style
+summary
+tabindex
+tableborder
+target
+text
+title
+top
+topmargin
+truespeed
+type
+usemap
+valign
+value
+valuetype
+version
+viewsource
+vlink
+vspace
+webkitdirectory
+width
+wrap
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-tags/dillo b/Tools/iExploder/iexploder-1.7.2/src/html-tags/dillo
new file mode 100644
index 0000000..c9c0040
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-tags/dillo
@@ -0,0 +1,73 @@
+a
+abbr
+address
+area
+b
+base
+big
+blockquote
+body
+br
+button
+center
+cite
+code
+dd
+del
+dfn
+dir
+div
+dl
+dt
+em
+font
+form
+frame
+frameset
+h1
+h2
+h3
+h4
+h5
+h6
+head
+hr
+html
+i
+iframe
+img
+input
+isindex
+kbd
+li
+link
+map
+menu
+meta
+object
+ol
+option
+p
+pre
+q
+s
+samp
+script
+select
+small
+span
+strike
+strong
+style
+sub
+sup
+table
+td
+textarea
+th
+title
+tr
+tt
+u
+ul
+var
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-tags/gtkhtml b/Tools/iExploder/iexploder-1.7.2/src/html-tags/gtkhtml
new file mode 100644
index 0000000..bf51b2a
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-tags/gtkhtml
@@ -0,0 +1,46 @@
+a
+address
+b
+big
+blockquote
+body
+caption
+center
+cite
+code
+dd
+dir
+div
+dl
+dt
+em
+font
+form
+h
+html
+i
+kbd
+li
+map
+ol
+option
+p
+pre
+s
+select
+small
+span
+strike
+strong
+sub
+sup
+table
+td
+test
+textarea
+th
+tr
+tt
+u
+ul
+var
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-tags/mozilla b/Tools/iExploder/iexploder-1.7.2/src/html-tags/mozilla
new file mode 100644
index 0000000..a4a51a6
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-tags/mozilla
@@ -0,0 +1,119 @@
+a
+abbr
+acronym
+address
+applet
+area
+article
+aside
+audio
+b
+base
+basefont
+bdo
+bgsound
+big
+blink
+blockquote
+body
+br
+button
+canvas
+caption
+center
+cite
+code
+col
+colgroup
+dd
+del
+dfn
+dir
+div
+dl
+dt
+em
+embed
+fieldset
+figcaption
+figure
+font
+footer
+form
+frame
+frameset
+h1
+h2
+h3
+h4
+h5
+h6
+head
+header
+hgroup
+hr
+html
+i
+iframe
+image
+img
+input
+ins
+isindex
+kbd
+keygen
+label
+legend
+li
+link
+listing
+map
+mark
+marquee
+menu
+meta
+multicol
+nav
+nobr
+noembed
+noframes
+noscript
+object
+ol
+optgroup
+option
+output
+p
+param
+plaintext
+pre
+q
+s
+samp
+script
+section
+select
+small
+source
+span
+strike
+strong
+style
+sub
+sup
+table
+tbody
+td
+textarea
+tfoot
+th
+thead
+title
+tr
+tt
+u
+ul
+var
+video
+wbr
+xmp
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-tags/other b/Tools/iExploder/iexploder-1.7.2/src/html-tags/other
new file mode 100644
index 0000000..598f1ec
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-tags/other
@@ -0,0 +1,8 @@
+counter
+endnote
+ilayer
+parsererror
+server
+sound
+sourcetext
+xml
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-tags/webkit b/Tools/iExploder/iexploder-1.7.2/src/html-tags/webkit
new file mode 100644
index 0000000..0228666
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-tags/webkit
@@ -0,0 +1,133 @@
+
+a
+abbr
+acronym
+address
+applet
+area
+article
+aside
+audio
+b
+base
+basefont
+bdo
+bgsound
+big
+blockquote
+body
+br
+button
+canvas
+caption
+center
+cite
+code
+col
+colgroup
+command
+datagrid
+datalist
+dcell
+dcol
+dd
+del
+details
+dfn
+dir
+div
+dl
+drow
+dt
+em
+embed
+fieldset
+figcaption
+figure
+font
+footer
+form
+frame
+frameset
+h1
+h2
+h3
+h4
+h5
+h6
+head
+header
+hgroup
+hr
+html
+i
+iframe
+image
+img
+input
+ins
+isindex
+kbd
+keygen
+label
+layer
+legend
+li
+link
+listing
+map
+mark
+marquee
+menu
+meta
+meter
+nav
+nobr
+noembed
+noframes
+nolayer
+noscript
+object
+ol
+optgroup
+option
+p
+param
+plaintext
+pre
+progress
+q
+rp
+rt
+ruby
+s
+samp
+script
+section
+select
+small
+source
+span
+strike
+strong
+style
+sub
+summary
+sup
+table
+tbody
+td
+textarea
+tfoot
+th
+thead
+title
+tr
+track
+tt
+u
+ul
+var
+video
+wbr
+xmp
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-values/dillo b/Tools/iExploder/iexploder-1.7.2/src/html-values/dillo
new file mode 100644
index 0000000..ae04b00
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-values/dillo
@@ -0,0 +1,30 @@
+all
+baseline
+bottom
+button
+center
+char
+checkbox
+circle
+content-type
+default
+disc
+file
+get
+hidden
+image
+justify
+left
+password
+post
+radio
+rect
+refresh
+reset
+right
+screen
+square
+stylesheet
+submit
+text
+top
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-values/gtkhtml b/Tools/iExploder/iexploder-1.7.2/src/html-values/gtkhtml
new file mode 100644
index 0000000..055c4f0
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-values/gtkhtml
@@ -0,0 +1,9 @@
+bottom
+center
+left
+ltr
+middle
+right
+rtl
+th
+top
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-values/mozilla b/Tools/iExploder/iexploder-1.7.2/src/html-values/mozilla
new file mode 100644
index 0000000..d5e13fd
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-values/mozilla
@@ -0,0 +1,44 @@
+_blank
+_content
+_parent
+_self
+_top
+absbottom
+abscenter
+absmiddle
+auto
+baseline
+bottom
+button
+center
+char
+checkbox
+content
+content-primary
+content-targetable
+email
+file
+hidden
+image
+justify
+left
+ltr
+middle
+no
+noscroll
+off
+on
+password
+radio
+reset
+right
+rtl
+scroll
+search
+submit
+tel
+text
+texttop
+top
+url
+yes
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-values/other b/Tools/iExploder/iexploder-1.7.2/src/html-values/other
new file mode 100644
index 0000000..382e312
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-values/other
@@ -0,0 +1,16 @@
+*
+#
+?
+999999999,9999999
+999999999,9999999,9
+999999999,9999999,999999999,9999999,999999999,9999999,999999999,9999999,9
+%i %i
+%n%n%n%n%n
+_SEARCH
+vbscript
+http://127.0.0.1:2000/iexploder.cgi?test=1
+%s
+%s %s %s
+%f
+:%
+
diff --git a/Tools/iExploder/iexploder-1.7.2/src/html-values/webkit b/Tools/iExploder/iexploder-1.7.2/src/html-values/webkit
new file mode 100644
index 0000000..9d83d3a
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/html-values/webkit
@@ -0,0 +1,88 @@
+-1
+HTML
+above
+absbottom
+absmiddle
+afterBegin
+afterEnd
+all
+allow-forms
+allow-same-origin
+allow-scripts
+allow-top-navigation
+alternate
+any
+ascending
+auto
+beforeBegin
+beforeEnd
+below
+border
+bottom
+box
+button
+center
+checkbox
+circle
+color
+cols
+data
+date
+datetime
+datetime-local
+default
+descending
+dns-prefetch
+email
+false
+file
+fixed
+groups
+hard
+hidden
+hsides
+icon
+image
+infinite
+inherit
+khtml_isindex
+left
+lhs
+metadata
+middle
+month
+movie
+no
+none
+number
+off
+on
+password
+physical
+plaintext-only
+poly
+prefetch
+radio
+range
+rect
+reset
+rhs
+right
+rows
+rsa
+search
+src
+stylesheet
+submit
+tel
+texttop
+time
+top
+true
+type
+url
+viewport
+void
+vsides
+week
+yes
diff --git a/Tools/iExploder/iexploder-1.7.2/src/iexploder.cgi b/Tools/iExploder/iexploder-1.7.2/src/iexploder.cgi
new file mode 100755
index 0000000..c1a86c4
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/iexploder.cgi
@@ -0,0 +1,48 @@
+#!/usr/bin/ruby
+# iExploder - Generates bad HTML files to perform QA for web browsers.
+#
+# Copyright 2010 Thomas Stromberg - All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'cgi';
+require 'iexploder';
+
+$CONFIG_PATH = 'config.yaml'
+
+ie = IExploder.new($CONFIG_PATH)
+cgi = CGI.new("html4");
+ie.cgi_url=ENV['SCRIPT_NAME'] || '?'
+ie.browser=ENV['HTTP_USER_AGENT'] || 'unknown'
+ie.test_num = cgi.params['t'][0].to_i
+ie.subtest_data = cgi.params['s'][0] || nil
+ie.random_mode = cgi.params['r'][0]
+ie.lookup_mode = cgi.params['l'][0]
+ie.stop_num = cgi.params['x'][0] || nil
+ie.setRandomSeed()
+
+mime_type = cgi.params['m'][0] || nil
+if mime_type:
+ header_options = ie.buildHeaders(mime_type)
+ # The CGI library wants the Content-Type header to be named 'type'. It
+ # will post two Content-Type headers otherwise.
+ header_options['type'] = header_options['Content-Type'].dup
+ header_options.delete('Content-Type')
+ cgi.out(header_options) do
+ ie.buildMediaFile(mime_type)
+ end
+else
+ cgi.out('type' => 'text/html') do
+ ie.buildPage()
+ end
+end
diff --git a/Tools/iExploder/iexploder-1.7.2/src/iexploder.rb b/Tools/iExploder/iexploder-1.7.2/src/iexploder.rb
new file mode 100644
index 0000000..34e4666
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/iexploder.rb
@@ -0,0 +1,792 @@
+# encoding: ASCII-8BIT
+
+# iExploder - Generates bad HTML files to perform QA for web browsers.
+#
+# Copyright 2010 Thomas Stromberg - All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'cgi'
+require 'yaml'
+
+require './scanner.rb'
+require './version.rb'
+
+# Used to speed up subtest generation
+$TEST_CACHE = {}
+
+# Media extensions to proper mime type map (not that we always listen'
+$MIME_MAP = {
+ 'bmp' => 'image/bmp',
+ 'gif' => 'image/gif',
+ 'jpg' => 'image/jpeg',
+ 'png' => 'image/png',
+ 'svg' => 'image/svg+xml',
+ 'tiff' => 'image/tiff',
+ 'xbm' => 'image/xbm',
+ 'ico' => 'image/x-icon',
+ 'jng' => 'image/x-jng',
+ 'xpm' => 'image/x-portable-pixmap',
+ 'ogg' => 'audio/ogg',
+ 'snd' => 'audio/basic',
+ 'wav' => 'audio/wav'
+}
+
+# These tags get src properties more often than others
+$SRC_TAGS = ['img', 'audio', 'video', 'embed']
+
+class IExploder
+ attr_accessor :test_num, :subtest_data, :lookup_mode, :random_mode, :cgi_url, :browser, :claimed_browser
+ attr_accessor :offset, :lines, :stop_num, :config
+
+ def initialize(config_path)
+ @config = YAML::load(File.open(config_path))
+ @stop_num = nil
+ @subtest_data = nil
+ @test_num = 0
+ @cgi_url = '/iexploder.cgi'
+ @browser = 'UNKNOWN'
+ @claimed_browser = nil
+ readTagFiles()
+ return nil
+ end
+
+ def setRandomSeed
+ if @test_num > 0
+ srand(@test_num)
+ else
+ srand
+ end
+ end
+
+
+ def readTagFiles
+ # These if statements are so that mod_ruby doesn't have to reload the files
+ # each time
+ data_path = @config['mangle_data_path']
+ @cssTags = readTagsDir("#{data_path}/css-properties")
+ @cssPseudoTags = readTagsDir("#{data_path}/css-pseudo")
+ @cssAtRules = readTagsDir("#{data_path}/css-atrules")
+ @htmlTags = readTagsDir("#{data_path}/html-tags")
+ @htmlAttr = readTagsDir("#{data_path}/html-attrs")
+ @htmlValues = readTagsDir("#{data_path}/html-values")
+ @cssValues = readTagsDir("#{data_path}/css-values")
+ @headerValues = readTagsDir("#{data_path}/headers")
+ @protocolValues = readTagsDir("#{data_path}/protocols")
+ @mimeTypes = readTagsDir("#{data_path}/mime-types")
+ @media = readMediaDir("#{data_path}/media")
+ end
+
+ def readTagsDir(directory)
+ values = []
+ Dir.foreach(directory) { |filename|
+ if File.file?(directory + "/" + filename)
+ values = values + readTagFile(directory + "/" + filename)
+ end
+ }
+ return values.uniq
+ end
+
+ def readMediaDir(directory)
+ data = {}
+ Dir.foreach(directory) { |filename|
+ if File.file?(directory + "/" + filename)
+ (base, extension) = filename.split('.')
+ mime_type = $MIME_MAP[extension]
+ data[mime_type] = File.read(directory + "/" + filename)
+ end
+ }
+ return data
+ end
+
+ def readTagFile(filename)
+ list = Array.new
+ File.new(filename).readlines.each { |line|
+ line.chop!
+
+ # Don't include comments.
+ if (line !~ /^# /) && (line.length > 0)
+ list << line
+ end
+ }
+ return list
+ end
+
+
+ def generateHtmlValue(tag)
+ choice = rand(100)
+ tag = tag.sub('EXCLUDED_', '')
+ if tag =~ /^on/ and choice < 90
+ return generateHtmlValue('') + "()"
+ elsif tag == 'src' or tag == 'data' or tag == 'profile' and choice < 90
+ return generateGarbageUrl(tag)
+ end
+
+ case choice
+ when 0..50 then
+ return @htmlValues[rand(@htmlValues.length)]
+ when 51..75
+ return generateGarbageNumber()
+ when 76..85
+ return generateGarbageValue()
+ when 86..90
+ return generateGarbageNumber() + ',' + generateGarbageNumber()
+ when 91..98
+ return generateGarbageUrl(tag)
+ else
+ return generateOverflow()
+ end
+ end
+
+ def generateMediaUrl(tag)
+ mime_type = @media.keys[rand(@media.keys.length)]
+ return generateTestUrl(@test_num, nil, nil, mime_type)
+ end
+
+ def generateGarbageUrl(tag)
+ choice = rand(100)
+ case choice
+ when 0..30
+ return generateMediaUrl(tag)
+ when 31..50
+ return @protocolValues[rand(@protocolValues.length)] + '%' + generateGarbageValue()
+ when 51..60
+ return @protocolValues[rand(@protocolValues.length)] + '//../' + generateGarbageValue()
+ when 60..75
+ return @protocolValues[rand(@protocolValues.length)] + '//' + generateGarbageValue()
+ when 75..85
+ return generateOverflow() + ":" + generateGarbageValue()
+ when 86..97
+ return generateGarbageValue() + ":" + generateOverflow()
+ else
+ return generateOverflow()
+ end
+ end
+
+ def generateCssValue(property)
+ size_types = ['', 'em', 'px', '%', 'pt', 'pc', 'ex', 'in', 'cm', 'mm']
+
+ choice = rand(100)
+ case choice
+ when 0..50 then
+ # return the most likely scenario
+ case property.sub('EXCLUDED_', '')
+ when /-image|content/
+ return 'url(' + generateGarbageUrl(property) + ')'
+ when /-width|-radius|-spacing|margin|padding|height/
+ return generateGarbageValue() + size_types[rand(size_types.length)]
+ when /-color/
+ return generateGarbageColor()
+ when /-delay|-duration/
+ return generateGarbageValue() + 'ms'
+ else
+ return @cssValues[rand(@cssValues.length)]
+ end
+ when 51..75 then return generateGarbageNumber()
+ when 76..85 then return 'url(' + generateGarbageUrl(property) + ')'
+ when 85..98 then return generateGarbageValue()
+ else
+ return generateOverflow()
+ end
+ end
+
+ def generateGarbageColor()
+ case rand(100)
+ when 0..50 then return '#' + generateGarbageValue()
+ when 51..70 then return 'rgb(' + generateGarbageNumber() + ',' + generateGarbageNumber() + ',' + generateGarbageNumber() + ')'
+ when 71..98 then return 'rgb(' + generateGarbageNumber() + '%,' + generateGarbageNumber() + '%,' + generateGarbageNumber() + '%)'
+ else
+ return generateOverflow()
+ end
+ end
+
+ def generateGarbageNumber()
+ choice = rand(100)
+ case choice
+ when 0 then return '0'
+ when 1..40 then return '9' * rand(100)
+ when 41..60 then return '999999.' + rand(999999999999999999999).to_s
+ when 61..80 then return '-' + ('9' * rand(100))
+ when 81..90 then return '-999999.' + rand(999999999999999999999).to_s
+ when 91..98 then return generateGarbageText()
+ else
+ return generateOverflow()
+ end
+ end
+
+ def generateGarbageValue()
+ case rand(100)
+ when 0..30 then return rand(255).chr * rand(@config['buffer_overflow_length'])
+ when 31..50 then return "%n" * 50
+ when 51..65 then return ("&#" + rand(999999).to_s + ";") * rand(@config['max_garbage_text_size'])
+ when 66..70 then
+ junk = []
+ 0.upto(rand(20)+1) do
+ junk << "\\x" + rand(65535).to_s(16)
+ end
+ return junk.join('') * rand(@config['max_garbage_text_size'])
+ when 71..99 then
+ junk = []
+ chars = '%?!$#^0123456789ABCDEF%#./\&|;'
+ 0.upto(rand(20)+1) do
+ junk << chars[rand(chars.length)].chr
+ end
+ return junk.join('') * rand(@config['max_garbage_text_size'])
+ end
+ end
+
+ def generateOverflow()
+ return rand(255).chr * (@config['buffer_overflow_length'] + rand(500))
+ end
+
+ def generateGarbageText
+ case rand(100)
+ when 0..70 then return 'X' * 129
+ when 71..75 then return "%n" * 15
+ when 76..85 then return ("&#" + rand(9999999999999).to_s + ";") * rand(@config['max_garbage_text_size'])
+ when 86..90 then return generateGarbageValue()
+ when 91..98 then return rand(255).chr * rand(@config['max_garbage_text_size'])
+ else
+ return generateOverflow()
+ end
+ end
+
+ def isPropertyInBlacklist(properties)
+ # Format: [img, src] or [img, style, property]
+ blacklist_entries = []
+ if @config.has_key?('exclude') and @config['exclude']
+ blacklist_entries << properties.join('.')
+ wildcard_property = properties.dup
+ wildcard_property[0] = '*'
+ blacklist_entries << wildcard_property.join('.')
+ blacklist_entries.each do |entry|
+ if @config['exclude'].has_key?(entry) and @browser =~ /#{@config['exclude'][entry]}/
+ return true
+ end
+ end
+ end
+ return false
+ end
+
+ def generateCssStyling(tag)
+ out = ' style="'
+ 0.upto(rand(@config['properties_per_style_max'])) {
+ property = @cssTags[rand(@cssTags.length)]
+ if isPropertyInBlacklist([tag, 'style', property])
+ property = "EXCLUDED_#{property}"
+ end
+ out << property
+
+ # very small chance we let the tag run on.
+ if rand(65) > 1
+ out << ": "
+ end
+
+ values = []
+ 0.upto(rand(@config['attributes_per_style_property_max'])) {
+ values << generateCssValue(property)
+ }
+ out << values.join(' ')
+ # we almost always put the ; there.
+ if rand(65) > 1
+ out << ";\n "
+ end
+ }
+ out << "\""
+ return out
+ end
+
+ def mangleTag(tag, no_close_chance=false)
+ if not no_close_chance and rand(100) < 15
+ return "</" + tag + ">"
+ end
+ out = "<" + tag
+ if rand(100) > 1
+ out << ' '
+ else
+ out << generateOverflow()
+ end
+
+ attrNum = rand(@config['attributes_per_html_tag_max']) + 1
+ attrs = []
+ # The HTML head tag does not have many useful attributes, but is always included in tests.
+ if tag == 'head' and rand(100) < 75
+ case rand(3)
+ when 0 then attrs << 'lang'
+ when 1 then attrs << 'dir'
+ when 2 then attrs << 'profile'
+ end
+ end
+ # 75% of the time, these tags get a src attribute
+ if $SRC_TAGS.include?(tag) and rand(100) < 75
+ if @config.has_key?('exclude') and @config['exclude'] and @config['exclude'].has_key?("#{tag}.src")
+ attrs << 'EXCLUDED_src'
+ else
+ attrs << 'src'
+ end
+ end
+
+ while attrs.length < attrNum
+ attribute = @htmlAttr[rand(@htmlAttr.length)]
+ if isPropertyInBlacklist([tag, attribute])
+ attribute = "EXCLUDED_#{attribute}"
+ end
+ attrs << attribute
+ end
+
+ # Add a few HTML attributes
+ for attr in attrs
+ out << attr
+ if rand(100) > 1
+ out << '='
+ end
+ if (rand(100) >= 50)
+ quoted = 1
+ out << "\""
+ else
+ quoted = nil
+ end
+ out << generateHtmlValue(attr)
+ if quoted
+ if rand(100) >= 10
+ out << "\""
+ end
+ end
+ if rand(100) >= 1
+ out << "\n "
+ end
+ end
+
+ if rand(100) >= 25
+ out << generateCssStyling(tag)
+ end
+ out << ">\n"
+ return out
+ end
+
+ def nextTestNum()
+ if @subtest_data
+ return @test_num
+ elsif @random_mode
+ return rand(99999999999)
+ else
+ return @test_num + 1
+ end
+ end
+
+ def generateCssPattern()
+ # Generate a CSS selector pattern.
+ choice = rand(100)
+ pattern = ''
+ case choice
+ when 0..84 then pattern = @htmlTags[rand(@htmlTags.length)].dup
+ when 85..89 then pattern = "*"
+ when 90..94 then pattern = @cssAtRules[rand(@cssAtRules.length)].dup
+ when 95..100 then pattern = ''
+ end
+
+ if rand(100) < 25
+ pattern << " " + @htmlTags[rand(@htmlTags.length)]
+ end
+
+ if rand(100) < 25
+ pattern << " > " + @htmlTags[rand(@htmlTags.length)]
+ end
+
+ if rand(100) < 25
+ pattern << " + " + @htmlTags[rand(@htmlTags.length)]
+ end
+
+ if rand(100) < 10
+ pattern << "*"
+ end
+
+
+ if rand(100) < 25
+ pseudo = @cssPseudoTags[rand(@cssPseudoTags.length)].dup
+ # These tags typically have a parenthesis
+ if (pseudo =~ /^lang|^nth|^not/ and rand(100) < 75 and pseudo !~ /\(/) or rand(100) < 20
+ pseudo << '('
+ end
+
+ if pseudo =~ /\(/
+ if rand(100) < 75
+ pseudo << generateGarbageValue()
+ end
+ if rand(100) < 75
+ pseudo << ')'
+ end
+ end
+ pattern << ":" + pseudo
+ end
+
+ if rand(100) < 20
+ html_attr = @htmlAttr[rand(@htmlAttr.length)]
+ match = '[' + html_attr
+ choice = rand(100)
+ garbage = generateGarbageValue()
+ case choice
+ when 0..25 then match << ']'
+ when 26..50 then match << "=\"#{garbage}\"]"
+ when 51..75 then match << "=~\"#{garbage}\"]"
+ when 76..99 then match << "|=\"#{garbage}\"]"
+ end
+ pattern << match
+ end
+
+ if rand(100) < 20
+ if rand(100) < 50
+ pattern << '.' + generateGarbageValue()
+ else
+ pattern << '.*'
+ end
+ end
+
+ if rand(100) < 20
+ pattern << '#' + generateGarbageValue()
+ end
+
+ if rand(100) < 5
+ pattern << ' #' + generateGarbageValue()
+ end
+
+ return pattern
+ end
+
+ def buildStyleTag()
+ out = "\n"
+ 0.upto(rand(@config['properties_per_style_max'])) {
+ out << generateCssPattern()
+ if rand(100) < 90
+ out << " {\n"
+ end
+
+ 0.upto(rand(@config['properties_per_style_max'])) {
+ property = @cssTags[rand(@cssTags.length)].dup
+ if isPropertyInBlacklist(['style', 'style', property])
+ property = " EXCLUDED_#{property}"
+ end
+ out << " #{property}: "
+
+ values = []
+ 0.upto(rand(@config['attributes_per_style_property_max'])) {
+ values << generateCssValue(property)
+ }
+ out << values.join(' ')
+ if rand(100) < 95
+ out << ";\n"
+ end
+ }
+ if rand(100) < 90
+ out << "\n}\n"
+ end
+
+ }
+ return out
+ end
+
+
+ # Build any malicious javascript here. Fairly naive at the moment.
+ def buildJavaScript
+ target = @htmlTags[rand(@htmlTags.length)]
+ css_property = @cssTags[rand(@cssTags.length)]
+ css_property2 = @cssTags[rand(@cssTags.length)]
+ html_attr = @htmlAttr[rand(@htmlAttr.length)]
+ css_value = generateCssValue(css_property)
+ html_value = generateHtmlValue(html_attr)
+ html_value2 = generateGarbageNumber()
+ mangled = mangleTag(@htmlTags[rand(@htmlTags.length)]);
+ mangled2 = mangleTag(@htmlTags[rand(@htmlTags.length)]);
+
+ js = []
+ js << "window.onload=function(){"
+ js << " var ietarget = document.createElement('#{target}');"
+ js << " ietarget.style.#{css_property} = '#{css_value}';"
+ js << " ietarget.#{html_attr} = '#{html_value}';"
+ js << " document.body.appendChild(ietarget);"
+ js << " ietarget.style.#{css_property2} = #{html_value2};"
+
+ js << " document.write('#{mangled}');"
+ js << " document.write('#{mangled2}');"
+ js << "}"
+ return js.join("\n")
+ end
+
+ def buildMediaFile(mime_type)
+ if @media.has_key?(mime_type)
+ data = @media[mime_type].dup
+ else
+ puts "No media found for #{mime_type}"
+ data = generateGarbageText()
+ end
+
+ # corrupt it in a subtle way
+ choice = rand(100)
+ if choice > 50
+ garbage = generateGarbageValue()
+ else
+ garbage = rand(255).chr * rand(8)
+ end
+
+ if "1.9".respond_to?(:encoding)
+ garbage.force_encoding('ASCII-8BIT')
+ data.force_encoding('ASCII-8BIT')
+ end
+
+ garbage_start = rand(data.length)
+ garbage_end = garbage_start + garbage.length
+ data[garbage_start..garbage_end] = garbage
+ if rand(100) < 15
+ data << generateGarbageValue()
+ end
+ return data
+ end
+
+ # Parse the subtest data passed in as part of the URL
+ def parseSubTestData(subtest_data)
+ # Initialize with one line at 0
+ if not subtest_data or subtest_data.to_i == 0
+ return [@config['initial_subtest_width'], [0]]
+ end
+ (lines_at_time, offsets_string) = subtest_data.split('_')
+ offsets = offsets_string.split(',').map! {|x| x.to_i }
+ return [lines_at_time.to_i, offsets]
+ end
+
+ def generateTestUrl(test_num, subtest_width=nil, subtest_offsets=nil, mime_type=nil)
+ url = @cgi_url + '?'
+ if subtest_width
+ if subtest_offsets.length > @config['subtest_combinations_max']
+ url << "t=" << test_num.to_s << "&l=test_redirect&z=THE_END"
+ else
+ url << "t=" << test_num.to_s << "&s=" << subtest_width.to_s << "_" << subtest_offsets.join(',')
+ end
+ else
+ url << "t=" << test_num.to_s
+ end
+
+ if @random_mode
+ url << "&r=1"
+ elsif @stop_num
+ url << "&x=" << @stop_num.to_s
+ end
+
+ if mime_type
+ url << '&m=' + CGI::escape(mime_type)
+ end
+
+ url << "&b=" << CGI::escape(@browser)
+ return url
+ end
+
+ def buildBodyTags(tag_count)
+ tagList = ['body']
+ # subtract the <body> tag from tag_count.
+ 1.upto(tag_count-1) { tagList << @htmlTags[rand(@htmlTags.length)] }
+
+ # Lean ourselves toward lots of img and src tests
+ for tag, percent in @config['favor_html_tags']
+ if rand(100) < percent.to_f
+ # Don't overwrite the body tag.
+ tagList[rand(tagList.length-1)+1] = tag
+ end
+ end
+
+ # Now we have our hitlist of tags,lets mangle them.
+ mangled_tags = []
+ tagList.each do |tag|
+ tag_data = mangleTag(tag)
+ if tag == 'script'
+ if rand(100) < 40
+ tag_data = "<script>"
+ end
+ tag_data << buildJavaScript() + "\n" + "</script>\n"
+ elsif tag == 'style'
+ if rand(100) < 40
+ tag_data = "<style>"
+ end
+ tag_data << buildStyleTag() + "\n" + "</style>\n"
+ elsif rand(100) <= 90
+ tag_data << generateGarbageText() << "\n"
+ else
+ tag_data << "\n"
+ end
+
+ if rand(100) <= 33
+ tag_data << "</#{tag}>\n"
+ end
+ mangled_tags << "\n<!-- START #{tag} -->\n" + tag_data + "\n<!-- END #{tag} -->\n"
+ end
+ return mangled_tags
+ end
+
+ def buildHeaderTags(tag_count)
+ valid_head_tags = ['title', 'base', 'link', 'meta']
+ header_tags = ['html', 'head']
+ 1.upto(tag_count-1) { header_tags << valid_head_tags[rand(valid_head_tags.length)] }
+ header_tags << @htmlTags[rand(@htmlTags.length)]
+ mangled_tags = []
+ header_tags.each do |tag|
+ mangled_tags << mangleTag(tag, no_close_chance=true)
+ end
+ return mangled_tags
+ end
+
+ def buildSurvivedPage(page_type)
+ page = "<html><head>"
+ page << "<body>Bummer. You survived both redirects. Let me go sulk in the corner.</body>"
+ page << "</html>"
+ return page
+ end
+
+ def buildRedirect(test_num, subtest_data, lookup_mode, stop_num=nil)
+ # no more redirects.
+ if lookup_mode == '1' or stop_num == test_num
+ return ''
+ end
+
+ if subtest_data
+ width, offsets = parseSubTestData(@subtest_data)
+ else
+ width, offsets = nil
+ end
+
+ # We still need a redirect, but don't bother generating new data.
+ if lookup_mode
+ redirect_url = generateTestUrl(test_num, width, offsets)
+ if lookup_mode == 'test_redirect'
+ redirect_url << "&l=test_another_redirect"
+ elsif lookup_mode == 'test_another_redirect'
+ redirect_url << "&l=survived_redirect"
+ else
+ redirect_url << "&l=#{lookup_mode}"
+ end
+ else
+ # This is a normal redirect going on to the next page. If we have subtest, get the next one.
+ if subtest_data
+ width, offsets = combine_combo_creator(@config['html_tags_per_page'], width, offsets)[0..1]
+ end
+ redirect_url = generateTestUrl(nextTestNum(), width, offsets)
+ end
+
+ redirect_code = "\t<META HTTP-EQUIV=\"Refresh\" content=\"0;URL=#{redirect_url}\">\n"
+ # use both techniques, because you never know how you might be corrupting yourself.
+ redirect_code << "\t<script language=\"javascript\">setTimeout('window.location=\"#{redirect_url}\"', 1000);</script>\n"
+ return redirect_code
+ end
+
+ def buildPage()
+ if @lookup_mode == 'survived_redirect'
+ return self.buildSurvivedPage(@lookup_mode)
+ end
+ tag_count = @config['html_tags_per_page']
+
+ if $TEST_CACHE.has_key?(@test_num)
+ (header_tags, body_tags) = $TEST_CACHE[@test_num]
+ else
+ header_tags = buildHeaderTags(3)
+ body_tags = buildBodyTags(tag_count - header_tags.length)
+ end
+ required_tags = {
+ 0 => 'html',
+ 1 => 'head',
+ header_tags.length => 'body'
+ }
+
+ if @subtest_data and @subtest_data.length > 0
+ if not $TEST_CACHE.has_key?(@test_num)
+ $TEST_CACHE[@test_num] = [header_tags, body_tags]
+ end
+ (width, offsets) = parseSubTestData(@subtest_data)
+ lines = combine_combo_creator(tag_count, width, offsets)[2]
+ all_tags = header_tags + body_tags
+ body_start = header_tags.length
+ header_tags = []
+ body_tags = []
+ # <html> and <body> are required, regardless of their existence in the subtest data.
+ 0.upto(tag_count) do |line_number|
+ tag_data = nil
+ if lines.include?(line_number)
+ tag_data = all_tags[line_number]
+ elsif required_tags.key?(line_number)
+ tag_data = "<" + required_tags[line_number] + ">"
+ end
+ if tag_data
+ if line_number < body_start
+ header_tags << tag_data
+ else
+ body_tags << tag_data
+ end
+ end
+ end
+ header_tags << "<!-- subtest mode: #{offsets.length} combinations, width: #{width} -->"
+ end
+
+ htmlText = header_tags[0..1].join("\n\t")
+ htmlText << buildRedirect(@test_num, @subtest_data, @lookup_mode, @stop_num)
+ htmlText << "<title>[#{@test_num}:#{@subtest_data}] iExploder #{$VERSION} - #{generateGarbageText()}</title>\n"
+ if @claimed_browser and @claimed_browser.length > 1
+ show_browser = @claimed_browser
+ else
+ show_browser = @browser
+ end
+ htmlText << "\n<!-- iExploder #{$VERSION} | test #{@test_num}:#{@subtest_data} at #{Time.now} -->\n"
+ htmlText << "<!-- browser: #{show_browser} -->\n"
+ htmlText << header_tags[2..-1].join("\n\t")
+ htmlText << "\n</head>\n\n"
+ htmlText << body_tags.join("\n")
+ htmlText << "</body>\n</html>"
+ return htmlText
+ end
+
+ def buildHeaders(mime_type)
+ use_headers = []
+ banned_headers = []
+ response = {'Content-Type' => mime_type}
+ 0.upto(rand(@config['headers_per_page_max'])) do
+ try_header = @headerValues[rand(@headerValues.length)]
+ if ! banned_headers.include?(try_header.downcase)
+ use_headers << try_header
+ end
+ end
+ for header in use_headers.uniq
+ if rand(100) > 75
+ response[header] = generateGarbageNumber()
+ else
+ response[header] = generateGarbageUrl(header)
+ end
+ end
+ return response
+ end
+end
+
+
+# for testing
+if $0 == __FILE__
+ ie = IExploder.new('config.yaml')
+ ie.test_num = ARGV[0].to_i || 1
+ ie.subtest_data = ARGV[1] || nil
+ mime_type = ARGV[2] || nil
+ ie.setRandomSeed()
+ if not mime_type
+ html_output = ie.buildPage()
+ puts html_output
+ else
+ headers = ie.buildHeaders(mime_type)
+ for (key, value) in headers
+ puts "#{key}: #{value}"
+ end
+ puts "Mime-Type: #{mime_type}"
+ puts ie.buildMediaFile(mime_type)
+ end
+end
diff --git a/Tools/iExploder/iexploder-1.7.2/src/index.html b/Tools/iExploder/iexploder-1.7.2/src/index.html
new file mode 100644
index 0000000..8b2cef6
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/index.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+ <title>iExploder</title>
+ <style type="text/css">
+body {
+ background-color: #bbb;
+ background-image: -moz-linear-gradient(0% 100% 90deg, #e5e5e5, #666, #e5e5e5 99%);
+ background-image: -webkit-gradient(linear, 0% 0%, 0% 100%, from(#e5e5e5), to(#bbb), color-stop(.1,#666));
+}
+
+h1 {
+ margin: 0;
+ font-size: 30px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+}
+
+img {
+ width: 64px;
+ margin-right: 8px;
+ float: left;
+}
+
+form {
+ display: inline;
+}
+
+.content {
+ width: 850px;
+ margin-left: auto;
+ margin-right: auto;
+ margin-top: 2em;
+ border: 1px solid #000;
+ background-color: #f5f5f5;
+ box-shadow: 5px 5px 5px #333;
+ -moz-box-shadow: 5px 5px 5px #333;
+ -webkit-box-shadow: 5px 5px 5px #333;
+}
+
+.header {
+ background-color: #999;
+}
+
+.copyright {
+ margin-top: 4em;
+ margin-left: auto;
+ margin-right: auto;
+ font-size: 9px;
+ text-align: center;
+ color: #333;
+}
+
+ul {
+ clear: both;
+}
+
+.formtext {
+ width: 16em;
+ display: inline-block;
+}
+
+</style>
+</head>
+<body>
+
+<div class="content">
+ <div class="header"><img src="media/bug.png" alt="Bug logo"><h1>iExploder: Browser Quality Assurance Tester</h1></div>
+
+<ul class="links">
+ <li><a href="iexploder.cgi">Start from the beginning!</a></li>
+ <li><a href="iexploder.cgi?r=1">Start from a random location!</a></li>
+</ul>
+
+<ul class="formlinks">
+ <li><div class="formtext">Test from:</div>
+ <form method="get" action="iexploder.cgi" name="test">
+ <input size="12" name="t" value="0">
+ to: <input size="12" name="x" value="">
+ <input value="Go!" type="submit">
+ </form>
+ </li>
+
+
+ <li><div class="formtext">Lookup individual test:</div>
+ <form method="get" action="iexploder.cgi" name="test">
+ <input type="hidden" name="l" value="1">
+ <input size="12" name="t" value="1"> Subtest: <input size="7" name="s" value="">
+ <input value="Go!" type="submit">
+ </form>
+ </li>
+
+ <li><div class="formtext">Generate smaller testcase for:</div>
+ <form method="get" action="iexploder.cgi" name="test">
+ <input size="12" name="t" value="1">
+ <input type="hidden" name="s" value="0">
+ <input value="Go!" type="submit">
+ </form>
+ </li>
+
+</ul>
+</div>
+<div class="copyright">&copy; 2005-2010 Thomas Str&ouml;mberg &mdash; <a href="http://iexploder.googlecode.com/">iexploder.googlecode.com</a></div>
+</body>
+</html>
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/blank.ogg b/Tools/iExploder/iexploder-1.7.2/src/media/blank.ogg
new file mode 100644
index 0000000..2629f98
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/blank.ogg
Binary files differ
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/blank.snd b/Tools/iExploder/iexploder-1.7.2/src/media/blank.snd
new file mode 100644
index 0000000..32a4008
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/blank.snd
Binary files differ
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/blank.wav b/Tools/iExploder/iexploder-1.7.2/src/media/blank.wav
new file mode 100644
index 0000000..b9c31f7
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/blank.wav
Binary files differ
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/bug.bmp b/Tools/iExploder/iexploder-1.7.2/src/media/bug.bmp
new file mode 100644
index 0000000..808870a
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/bug.bmp
Binary files differ
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/bug.gif b/Tools/iExploder/iexploder-1.7.2/src/media/bug.gif
new file mode 100644
index 0000000..22e4c22
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/bug.gif
Binary files differ
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/bug.ico b/Tools/iExploder/iexploder-1.7.2/src/media/bug.ico
new file mode 100644
index 0000000..ebc5c64
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/bug.ico
Binary files differ
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/bug.jng b/Tools/iExploder/iexploder-1.7.2/src/media/bug.jng
new file mode 100644
index 0000000..39e277c
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/bug.jng
Binary files differ
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/bug.jpg b/Tools/iExploder/iexploder-1.7.2/src/media/bug.jpg
new file mode 100644
index 0000000..ca5611a
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/bug.jpg
Binary files differ
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/bug.png b/Tools/iExploder/iexploder-1.7.2/src/media/bug.png
new file mode 100755
index 0000000..4d658d7
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/bug.png
Binary files differ
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/bug.svg b/Tools/iExploder/iexploder-1.7.2/src/media/bug.svg
new file mode 100644
index 0000000..d42c0d5
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/bug.svg
@@ -0,0 +1,16389 @@
+<?xml version="1.0" standalone="no"?>
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN"
+ "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
+<svg width="128" height="128">
+ <circle cx="0" cy="0" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="19" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="20" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="21" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="22" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="23" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="24" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="25" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="26" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="27" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="28" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="29" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="30" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="31" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="32" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="33" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="34" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="35" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="36" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="37" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="38" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="39" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="40" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="41" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="42" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="43" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="44" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="45" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="46" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="47" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="48" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="49" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="50" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="51" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="52" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="53" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="54" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="55" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="56" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="57" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="58" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="59" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="60" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="61" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="62" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="63" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="64" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="65" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="66" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="67" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="68" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="69" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="70" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="71" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="72" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="73" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="74" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="75" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="76" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="77" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="78" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="79" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="80" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="81" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="82" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="83" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="84" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="85" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="86" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="87" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="88" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="89" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="90" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="91" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="92" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="93" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="94" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="95" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="96" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="97" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="98" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="99" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="100" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="101" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="102" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="103" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="104" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="105" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="106" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="107" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="108" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="109" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="110" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="111" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="112" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="113" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="114" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="0" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="1" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="19" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="20" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="21" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="22" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="23" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="24" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="25" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="26" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="27" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="28" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="29" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="30" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="31" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="32" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="33" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="34" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="35" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="36" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="37" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="38" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="39" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="40" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="41" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="42" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="43" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="44" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="45" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="46" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="47" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="48" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="49" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="50" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="51" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="52" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="53" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="54" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="55" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="56" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="57" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="58" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="59" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="60" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="61" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="62" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="63" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="64" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="65" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="66" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="67" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="68" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="69" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="70" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="71" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="72" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="73" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="74" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="75" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="76" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="77" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="78" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="79" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="80" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="81" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="82" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="83" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="84" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="85" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="86" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="87" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="88" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="89" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="90" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="91" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="92" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="93" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="94" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="95" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="96" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="97" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="98" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="99" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="100" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="101" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="102" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="103" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="104" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="105" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="106" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="107" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="108" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="109" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="110" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="111" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="112" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="113" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="114" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="1" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="2" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="19" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="20" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="21" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="22" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="23" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="24" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="25" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="26" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="27" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="28" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="29" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="30" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="31" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="32" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="33" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="34" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="35" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="36" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="37" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="38" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="39" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="40" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="41" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="42" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="43" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="44" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="45" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="46" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="47" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="48" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="49" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="50" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="51" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="52" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="53" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="54" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="55" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="56" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="57" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="58" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="59" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="60" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="61" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="62" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="63" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="64" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="65" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="66" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="67" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="68" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="69" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="70" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="71" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="72" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="73" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="74" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="75" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="76" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="77" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="78" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="79" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="80" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="81" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="82" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="83" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="84" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="85" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="86" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="87" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="88" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="89" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="90" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="91" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="92" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="93" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="94" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="95" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="96" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="97" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="98" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="99" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="100" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="101" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="102" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="103" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="104" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="105" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="106" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="107" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="108" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="109" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="110" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="111" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="112" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="113" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="114" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="2" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="3" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="19" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="20" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="21" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="22" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="23" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="24" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="25" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="26" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="27" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="28" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="29" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="30" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="31" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="32" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="33" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="34" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="35" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="36" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="37" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="38" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="39" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="40" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="41" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="42" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="43" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="44" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="45" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="46" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="47" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="48" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="49" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="50" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="51" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="52" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="53" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="54" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="55" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="56" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="57" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="58" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="59" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="60" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="61" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="62" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="63" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="64" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="65" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="66" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="67" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="68" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="69" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="70" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="71" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="72" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="73" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="74" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="75" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="76" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="77" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="78" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="79" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="80" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="81" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="82" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="83" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="84" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="85" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="86" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="87" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="88" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="89" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="90" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="91" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="92" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="93" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="94" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="95" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="96" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="97" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="98" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="99" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="100" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="101" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="102" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="103" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="104" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="105" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="106" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="107" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="108" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="109" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="110" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="111" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="112" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="113" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="114" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="3" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="4" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="19" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="20" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="21" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="22" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="23" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="24" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="25" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="26" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="27" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="28" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="29" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="30" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="31" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="32" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="33" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="34" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="35" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="36" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="37" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="38" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="39" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="40" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="41" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="42" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="43" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="44" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="45" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="46" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="47" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="48" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="49" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="50" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="51" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="52" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="53" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="54" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="55" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="56" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="57" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="58" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="59" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="60" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="61" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="62" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="63" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="64" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="65" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="66" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="67" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="68" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="69" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="70" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="71" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="72" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="73" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="74" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="75" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="76" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="77" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="78" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="79" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="80" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="81" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="82" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="83" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="84" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="85" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="86" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="87" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="88" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="89" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="90" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="91" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="92" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="93" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="94" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="95" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="96" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="97" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="98" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="99" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="100" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="101" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="102" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="103" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="104" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="105" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="106" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="107" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="108" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="109" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="110" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="111" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="112" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="113" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="114" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="4" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="5" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="19" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="20" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="21" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="22" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="23" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="24" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="25" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="26" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="27" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="28" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="29" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="30" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="31" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="32" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="33" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="34" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="35" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="36" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="37" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="38" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="39" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="40" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="41" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="42" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="43" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="44" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="45" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="46" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="47" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="48" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="49" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="50" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="51" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="52" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="53" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="54" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="55" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="56" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="57" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="58" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="59" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="60" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="61" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="62" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="63" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="64" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="65" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="66" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="67" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="68" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="69" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="70" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="71" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="72" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="73" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="74" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="75" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="76" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="77" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="78" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="79" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="80" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="81" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="82" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="83" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="84" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="85" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="86" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="87" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="88" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="89" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="90" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="91" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="92" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="93" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="94" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="95" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="96" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="97" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="98" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="99" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="100" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="101" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="102" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="103" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="104" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="105" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="106" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="107" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="108" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="109" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="110" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="111" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="112" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="113" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="114" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="5" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="6" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="19" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="20" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="21" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="22" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="23" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="24" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="25" cy="6" r="1" fill="rgba(61,30,13,0.113725)"/>
+ <circle cx="26" cy="6" r="1" fill="rgba(61,30,13,0.34902)"/>
+ <circle cx="27" cy="6" r="1" fill="rgba(61,30,13,0.00392157)"/>
+ <circle cx="28" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="29" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="30" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="31" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="32" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="33" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="34" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="35" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="36" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="37" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="38" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="39" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="40" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="41" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="42" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="43" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="44" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="53" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="54" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="55" cy="6" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="56" cy="6" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="57" cy="6" r="1" fill="rgba(74,42,21,0)"/>
+ <circle cx="58" cy="6" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="59" cy="6" r="1" fill="rgba(85,53,29,0)"/>
+ <circle cx="60" cy="6" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="61" cy="6" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="62" cy="6" r="1" fill="rgba(101,69,42,0)"/>
+ <circle cx="63" cy="6" r="1" fill="rgba(105,74,47,0)"/>
+ <circle cx="64" cy="6" r="1" fill="rgba(111,79,51,0)"/>
+ <circle cx="65" cy="6" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="66" cy="6" r="1" fill="rgba(108,76,48,0)"/>
+ <circle cx="67" cy="6" r="1" fill="rgba(102,71,44,0)"/>
+ <circle cx="68" cy="6" r="1" fill="rgba(98,65,39,0)"/>
+ <circle cx="69" cy="6" r="1" fill="rgba(93,60,35,0)"/>
+ <circle cx="70" cy="6" r="1" fill="rgba(87,55,31,0)"/>
+ <circle cx="71" cy="6" r="1" fill="rgba(82,49,27,0)"/>
+ <circle cx="72" cy="6" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="73" cy="6" r="1" fill="rgba(69,38,18,0)"/>
+ <circle cx="74" cy="6" r="1" fill="rgba(63,33,15,0)"/>
+ <circle cx="75" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="76" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="77" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="78" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="6" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="6" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="6" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="6" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="6" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="6" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="6" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="6" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="6" r="1" fill="rgba(81,49,26,0)"/>
+ <circle cx="95" cy="6" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="96" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="97" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="98" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="99" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="100" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="101" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="102" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="103" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="104" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="105" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="106" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="107" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="108" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="109" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="110" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="111" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="112" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="113" cy="6" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="114" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="6" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="7" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="19" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="20" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="21" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="22" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="23" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="24" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="25" cy="7" r="1" fill="rgba(61,30,13,0.443137)"/>
+ <circle cx="26" cy="7" r="1" fill="rgba(61,30,13,0.780392)"/>
+ <circle cx="27" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="28" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="29" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="30" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="31" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="32" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="33" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="34" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="35" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="36" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="37" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="38" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="39" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="40" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="41" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="42" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="43" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="44" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="53" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="54" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="55" cy="7" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="56" cy="7" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="57" cy="7" r="1" fill="rgba(74,42,21,0)"/>
+ <circle cx="58" cy="7" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="59" cy="7" r="1" fill="rgba(85,53,29,0)"/>
+ <circle cx="60" cy="7" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="61" cy="7" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="62" cy="7" r="1" fill="rgba(101,69,42,0)"/>
+ <circle cx="63" cy="7" r="1" fill="rgba(105,74,47,0)"/>
+ <circle cx="64" cy="7" r="1" fill="rgba(111,79,51,0)"/>
+ <circle cx="65" cy="7" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="66" cy="7" r="1" fill="rgba(108,76,48,0)"/>
+ <circle cx="67" cy="7" r="1" fill="rgba(102,71,44,0)"/>
+ <circle cx="68" cy="7" r="1" fill="rgba(98,65,39,0)"/>
+ <circle cx="69" cy="7" r="1" fill="rgba(93,60,35,0)"/>
+ <circle cx="70" cy="7" r="1" fill="rgba(87,55,31,0)"/>
+ <circle cx="71" cy="7" r="1" fill="rgba(82,49,27,0)"/>
+ <circle cx="72" cy="7" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="73" cy="7" r="1" fill="rgba(69,38,18,0)"/>
+ <circle cx="74" cy="7" r="1" fill="rgba(63,33,15,0)"/>
+ <circle cx="75" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="76" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="77" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="78" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="7" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="7" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="7" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="7" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="7" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="7" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="7" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="7" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="7" r="1" fill="rgba(81,49,26,0)"/>
+ <circle cx="95" cy="7" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="96" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="97" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="98" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="99" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="100" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="101" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="102" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="103" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="104" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="105" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="106" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="107" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="108" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="109" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="110" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="111" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="112" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="113" cy="7" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="114" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="7" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="8" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="19" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="20" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="21" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="22" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="23" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="24" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="25" cy="8" r="1" fill="rgba(61,30,13,0.184314)"/>
+ <circle cx="26" cy="8" r="1" fill="rgba(61,30,13,0.866667)"/>
+ <circle cx="27" cy="8" r="1" fill="rgba(61,30,13,0.0862745)"/>
+ <circle cx="28" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="29" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="30" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="31" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="32" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="33" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="34" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="35" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="36" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="37" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="38" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="39" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="40" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="41" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="42" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="43" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="44" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="53" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="54" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="55" cy="8" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="56" cy="8" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="57" cy="8" r="1" fill="rgba(74,42,21,0)"/>
+ <circle cx="58" cy="8" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="59" cy="8" r="1" fill="rgba(85,53,29,0)"/>
+ <circle cx="60" cy="8" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="61" cy="8" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="62" cy="8" r="1" fill="rgba(101,69,42,0)"/>
+ <circle cx="63" cy="8" r="1" fill="rgba(105,74,47,0)"/>
+ <circle cx="64" cy="8" r="1" fill="rgba(111,79,51,0)"/>
+ <circle cx="65" cy="8" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="66" cy="8" r="1" fill="rgba(108,76,48,0)"/>
+ <circle cx="67" cy="8" r="1" fill="rgba(102,71,44,0)"/>
+ <circle cx="68" cy="8" r="1" fill="rgba(98,65,39,0)"/>
+ <circle cx="69" cy="8" r="1" fill="rgba(93,60,35,0)"/>
+ <circle cx="70" cy="8" r="1" fill="rgba(87,55,31,0)"/>
+ <circle cx="71" cy="8" r="1" fill="rgba(82,49,27,0)"/>
+ <circle cx="72" cy="8" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="73" cy="8" r="1" fill="rgba(69,38,18,0)"/>
+ <circle cx="74" cy="8" r="1" fill="rgba(63,33,15,0)"/>
+ <circle cx="75" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="76" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="77" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="78" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="8" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="8" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="8" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="8" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="8" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="8" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="8" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="8" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="8" r="1" fill="rgba(81,49,26,0)"/>
+ <circle cx="95" cy="8" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="96" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="97" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="98" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="99" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="100" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="101" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="102" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="103" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="104" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="105" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="106" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="107" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="108" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="109" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="110" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="111" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="112" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="113" cy="8" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="114" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="8" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="9" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="19" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="20" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="21" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="22" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="23" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="24" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="25" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="26" cy="9" r="1" fill="rgba(61,30,13,0.74902)"/>
+ <circle cx="27" cy="9" r="1" fill="rgba(61,30,13,0.403922)"/>
+ <circle cx="28" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="29" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="30" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="31" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="32" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="33" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="34" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="35" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="36" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="37" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="38" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="39" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="40" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="41" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="42" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="43" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="44" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="45" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="53" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="54" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="55" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="56" cy="9" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="57" cy="9" r="1" fill="rgba(74,42,21,0)"/>
+ <circle cx="58" cy="9" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="59" cy="9" r="1" fill="rgba(85,53,29,0)"/>
+ <circle cx="60" cy="9" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="61" cy="9" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="62" cy="9" r="1" fill="rgba(101,69,42,0)"/>
+ <circle cx="63" cy="9" r="1" fill="rgba(105,74,47,0)"/>
+ <circle cx="64" cy="9" r="1" fill="rgba(111,79,51,0)"/>
+ <circle cx="65" cy="9" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="66" cy="9" r="1" fill="rgba(108,76,48,0)"/>
+ <circle cx="67" cy="9" r="1" fill="rgba(102,71,44,0)"/>
+ <circle cx="68" cy="9" r="1" fill="rgba(98,65,39,0)"/>
+ <circle cx="69" cy="9" r="1" fill="rgba(93,60,35,0)"/>
+ <circle cx="70" cy="9" r="1" fill="rgba(87,55,31,0)"/>
+ <circle cx="71" cy="9" r="1" fill="rgba(82,49,27,0)"/>
+ <circle cx="72" cy="9" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="73" cy="9" r="1" fill="rgba(69,38,18,0)"/>
+ <circle cx="74" cy="9" r="1" fill="rgba(63,33,15,0)"/>
+ <circle cx="75" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="76" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="77" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="78" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="9" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="9" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="9" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="9" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="9" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="9" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="9" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="9" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="9" r="1" fill="rgba(81,49,26,0)"/>
+ <circle cx="95" cy="9" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="96" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="97" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="98" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="99" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="100" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="101" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="102" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="103" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="104" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="105" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="106" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="107" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="108" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="109" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="110" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="111" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="112" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="113" cy="9" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="114" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="9" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="10" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="19" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="20" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="21" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="22" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="23" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="24" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="25" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="26" cy="10" r="1" fill="rgba(61,30,13,0.443137)"/>
+ <circle cx="27" cy="10" r="1" fill="rgba(61,30,13,0.831373)"/>
+ <circle cx="28" cy="10" r="1" fill="rgba(62,31,14,0.027451)"/>
+ <circle cx="29" cy="10" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="30" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="31" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="32" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="33" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="34" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="35" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="36" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="37" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="38" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="39" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="40" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="41" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="42" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="43" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="44" cy="10" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="45" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="53" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="54" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="55" cy="10" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="56" cy="10" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="57" cy="10" r="1" fill="rgba(74,42,21,0)"/>
+ <circle cx="58" cy="10" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="59" cy="10" r="1" fill="rgba(85,53,29,0)"/>
+ <circle cx="60" cy="10" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="61" cy="10" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="62" cy="10" r="1" fill="rgba(101,69,42,0)"/>
+ <circle cx="63" cy="10" r="1" fill="rgba(105,74,47,0)"/>
+ <circle cx="64" cy="10" r="1" fill="rgba(111,79,51,0)"/>
+ <circle cx="65" cy="10" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="66" cy="10" r="1" fill="rgba(108,76,48,0)"/>
+ <circle cx="67" cy="10" r="1" fill="rgba(102,71,44,0)"/>
+ <circle cx="68" cy="10" r="1" fill="rgba(98,65,39,0)"/>
+ <circle cx="69" cy="10" r="1" fill="rgba(93,60,35,0)"/>
+ <circle cx="70" cy="10" r="1" fill="rgba(87,55,31,0)"/>
+ <circle cx="71" cy="10" r="1" fill="rgba(82,49,27,0)"/>
+ <circle cx="72" cy="10" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="73" cy="10" r="1" fill="rgba(69,38,18,0)"/>
+ <circle cx="74" cy="10" r="1" fill="rgba(63,33,15,0)"/>
+ <circle cx="75" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="76" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="77" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="78" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="10" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="10" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="10" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="10" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="10" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="10" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="10" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="10" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="10" r="1" fill="rgba(81,49,26,0)"/>
+ <circle cx="95" cy="10" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="96" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="97" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="98" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="99" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="100" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="101" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="102" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="103" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="104" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="105" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="106" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="107" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="108" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="109" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="110" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="111" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="112" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="113" cy="10" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="114" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="10" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="11" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="19" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="20" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="21" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="22" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="23" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="24" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="25" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="26" cy="11" r="1" fill="rgba(61,30,13,0.12549)"/>
+ <circle cx="27" cy="11" r="1" fill="rgba(62,30,13,1)"/>
+ <circle cx="28" cy="11" r="1" fill="rgba(67,35,16,0.45098)"/>
+ <circle cx="29" cy="11" r="1" fill="rgba(51,24,10,0)"/>
+ <circle cx="30" cy="11" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="31" cy="11" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="32" cy="11" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="33" cy="11" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="34" cy="11" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="35" cy="11" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="36" cy="11" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="37" cy="11" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="38" cy="11" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="39" cy="11" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="40" cy="11" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="41" cy="11" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="42" cy="11" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="43" cy="11" r="1" fill="rgba(37,15,5,0)"/>
+ <circle cx="44" cy="11" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="45" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="53" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="54" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="55" cy="11" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="56" cy="11" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="57" cy="11" r="1" fill="rgba(74,42,21,0)"/>
+ <circle cx="58" cy="11" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="59" cy="11" r="1" fill="rgba(85,53,29,0)"/>
+ <circle cx="60" cy="11" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="61" cy="11" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="62" cy="11" r="1" fill="rgba(101,69,42,0)"/>
+ <circle cx="63" cy="11" r="1" fill="rgba(105,74,47,0)"/>
+ <circle cx="64" cy="11" r="1" fill="rgba(111,79,51,0)"/>
+ <circle cx="65" cy="11" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="66" cy="11" r="1" fill="rgba(108,76,48,0)"/>
+ <circle cx="67" cy="11" r="1" fill="rgba(102,71,44,0)"/>
+ <circle cx="68" cy="11" r="1" fill="rgba(98,65,39,0)"/>
+ <circle cx="69" cy="11" r="1" fill="rgba(93,60,35,0)"/>
+ <circle cx="70" cy="11" r="1" fill="rgba(87,55,31,0)"/>
+ <circle cx="71" cy="11" r="1" fill="rgba(82,49,27,0)"/>
+ <circle cx="72" cy="11" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="73" cy="11" r="1" fill="rgba(69,38,18,0)"/>
+ <circle cx="74" cy="11" r="1" fill="rgba(63,33,15,0)"/>
+ <circle cx="75" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="76" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="77" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="78" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="11" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="11" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="11" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="11" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="11" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="11" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="11" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="11" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="11" r="1" fill="rgba(81,49,26,0)"/>
+ <circle cx="95" cy="11" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="96" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="97" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="98" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="99" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="100" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="101" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="102" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="103" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="104" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="105" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="106" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="107" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="108" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="109" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="110" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="111" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="112" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="113" cy="11" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="114" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="11" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="12" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="12" r="1" fill="rgba(64,33,15,0)"/>
+ <circle cx="19" cy="12" r="1" fill="rgba(64,33,15,0)"/>
+ <circle cx="20" cy="12" r="1" fill="rgba(64,33,15,0)"/>
+ <circle cx="21" cy="12" r="1" fill="rgba(64,33,15,0)"/>
+ <circle cx="22" cy="12" r="1" fill="rgba(64,33,15,0)"/>
+ <circle cx="23" cy="12" r="1" fill="rgba(64,33,15,0)"/>
+ <circle cx="24" cy="12" r="1" fill="rgba(64,33,15,0)"/>
+ <circle cx="25" cy="12" r="1" fill="rgba(64,33,15,0)"/>
+ <circle cx="26" cy="12" r="1" fill="rgba(64,33,15,0)"/>
+ <circle cx="27" cy="12" r="1" fill="rgba(64,34,16,0.792157)"/>
+ <circle cx="28" cy="12" r="1" fill="rgba(69,38,18,0.952941)"/>
+ <circle cx="29" cy="12" r="1" fill="rgba(54,26,11,0.160784)"/>
+ <circle cx="30" cy="12" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="31" cy="12" r="1" fill="rgba(36,13,4,0)"/>
+ <circle cx="32" cy="12" r="1" fill="rgba(36,13,4,0)"/>
+ <circle cx="33" cy="12" r="1" fill="rgba(36,13,4,0)"/>
+ <circle cx="34" cy="12" r="1" fill="rgba(36,13,4,0)"/>
+ <circle cx="35" cy="12" r="1" fill="rgba(36,13,4,0)"/>
+ <circle cx="36" cy="12" r="1" fill="rgba(36,13,4,0)"/>
+ <circle cx="37" cy="12" r="1" fill="rgba(36,13,4,0)"/>
+ <circle cx="38" cy="12" r="1" fill="rgba(36,13,4,0)"/>
+ <circle cx="39" cy="12" r="1" fill="rgba(36,13,4,0)"/>
+ <circle cx="40" cy="12" r="1" fill="rgba(36,13,4,0)"/>
+ <circle cx="41" cy="12" r="1" fill="rgba(36,13,4,0)"/>
+ <circle cx="42" cy="12" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="43" cy="12" r="1" fill="rgba(37,15,5,0)"/>
+ <circle cx="44" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="45" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="53" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="54" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="55" cy="12" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="56" cy="12" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="57" cy="12" r="1" fill="rgba(74,42,21,0)"/>
+ <circle cx="58" cy="12" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="59" cy="12" r="1" fill="rgba(85,53,29,0)"/>
+ <circle cx="60" cy="12" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="61" cy="12" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="62" cy="12" r="1" fill="rgba(101,69,42,0)"/>
+ <circle cx="63" cy="12" r="1" fill="rgba(105,74,47,0)"/>
+ <circle cx="64" cy="12" r="1" fill="rgba(111,79,51,0)"/>
+ <circle cx="65" cy="12" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="66" cy="12" r="1" fill="rgba(108,76,48,0)"/>
+ <circle cx="67" cy="12" r="1" fill="rgba(102,71,44,0)"/>
+ <circle cx="68" cy="12" r="1" fill="rgba(98,65,39,0)"/>
+ <circle cx="69" cy="12" r="1" fill="rgba(93,60,35,0)"/>
+ <circle cx="70" cy="12" r="1" fill="rgba(87,55,31,0)"/>
+ <circle cx="71" cy="12" r="1" fill="rgba(82,49,27,0)"/>
+ <circle cx="72" cy="12" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="73" cy="12" r="1" fill="rgba(69,38,18,0)"/>
+ <circle cx="74" cy="12" r="1" fill="rgba(63,33,15,0)"/>
+ <circle cx="75" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="76" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="77" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="78" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="12" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="12" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="12" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="12" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="12" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="12" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="12" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="12" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="12" r="1" fill="rgba(81,49,26,0)"/>
+ <circle cx="95" cy="12" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="96" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="97" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="98" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="99" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="100" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="101" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="102" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="103" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="104" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="105" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="106" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="107" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="108" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="109" cy="12" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="110" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="111" cy="12" r="1" fill="rgba(61,30,13,0.0313725)"/>
+ <circle cx="112" cy="12" r="1" fill="rgba(61,30,13,0.0705882)"/>
+ <circle cx="113" cy="12" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="114" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="12" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="13" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="13" r="1" fill="rgba(67,36,17,0)"/>
+ <circle cx="19" cy="13" r="1" fill="rgba(67,36,17,0)"/>
+ <circle cx="20" cy="13" r="1" fill="rgba(67,36,17,0)"/>
+ <circle cx="21" cy="13" r="1" fill="rgba(67,36,17,0)"/>
+ <circle cx="22" cy="13" r="1" fill="rgba(67,36,17,0)"/>
+ <circle cx="23" cy="13" r="1" fill="rgba(67,36,17,0)"/>
+ <circle cx="24" cy="13" r="1" fill="rgba(67,36,17,0)"/>
+ <circle cx="25" cy="13" r="1" fill="rgba(67,36,17,0)"/>
+ <circle cx="26" cy="13" r="1" fill="rgba(67,36,17,0)"/>
+ <circle cx="27" cy="13" r="1" fill="rgba(68,37,18,0.556863)"/>
+ <circle cx="28" cy="13" r="1" fill="rgba(71,40,20,1)"/>
+ <circle cx="29" cy="13" r="1" fill="rgba(73,41,20,0.737255)"/>
+ <circle cx="30" cy="13" r="1" fill="rgba(74,42,21,0.00784314)"/>
+ <circle cx="31" cy="13" r="1" fill="rgba(75,43,22,0)"/>
+ <circle cx="32" cy="13" r="1" fill="rgba(75,43,22,0)"/>
+ <circle cx="33" cy="13" r="1" fill="rgba(75,43,22,0)"/>
+ <circle cx="34" cy="13" r="1" fill="rgba(75,43,22,0)"/>
+ <circle cx="35" cy="13" r="1" fill="rgba(75,43,22,0)"/>
+ <circle cx="36" cy="13" r="1" fill="rgba(75,43,22,0)"/>
+ <circle cx="37" cy="13" r="1" fill="rgba(75,43,22,0)"/>
+ <circle cx="38" cy="13" r="1" fill="rgba(75,43,22,0)"/>
+ <circle cx="39" cy="13" r="1" fill="rgba(75,43,22,0)"/>
+ <circle cx="40" cy="13" r="1" fill="rgba(75,43,22,0)"/>
+ <circle cx="41" cy="13" r="1" fill="rgba(75,43,22,0)"/>
+ <circle cx="42" cy="13" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="43" cy="13" r="1" fill="rgba(68,36,18,0)"/>
+ <circle cx="44" cy="13" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="45" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="53" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="54" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="55" cy="13" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="56" cy="13" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="57" cy="13" r="1" fill="rgba(74,42,21,0)"/>
+ <circle cx="58" cy="13" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="59" cy="13" r="1" fill="rgba(85,53,29,0)"/>
+ <circle cx="60" cy="13" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="61" cy="13" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="62" cy="13" r="1" fill="rgba(101,69,42,0)"/>
+ <circle cx="63" cy="13" r="1" fill="rgba(105,74,47,0)"/>
+ <circle cx="64" cy="13" r="1" fill="rgba(111,79,51,0)"/>
+ <circle cx="65" cy="13" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="66" cy="13" r="1" fill="rgba(108,76,48,0)"/>
+ <circle cx="67" cy="13" r="1" fill="rgba(102,71,44,0)"/>
+ <circle cx="68" cy="13" r="1" fill="rgba(98,65,39,0)"/>
+ <circle cx="69" cy="13" r="1" fill="rgba(93,60,35,0)"/>
+ <circle cx="70" cy="13" r="1" fill="rgba(87,55,31,0)"/>
+ <circle cx="71" cy="13" r="1" fill="rgba(82,49,27,0)"/>
+ <circle cx="72" cy="13" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="73" cy="13" r="1" fill="rgba(69,38,18,0)"/>
+ <circle cx="74" cy="13" r="1" fill="rgba(63,33,15,0)"/>
+ <circle cx="75" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="76" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="77" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="78" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="13" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="13" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="13" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="13" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="13" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="13" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="13" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="13" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="13" r="1" fill="rgba(83,51,27,0)"/>
+ <circle cx="95" cy="13" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="96" cy="13" r="1" fill="rgba(40,17,6,0)"/>
+ <circle cx="97" cy="13" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="98" cy="13" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="99" cy="13" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="100" cy="13" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="101" cy="13" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="102" cy="13" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="103" cy="13" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="104" cy="13" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="105" cy="13" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="106" cy="13" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="107" cy="13" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="108" cy="13" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="109" cy="13" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="110" cy="13" r="1" fill="rgba(42,18,6,0)"/>
+ <circle cx="111" cy="13" r="1" fill="rgba(61,30,13,0.321569)"/>
+ <circle cx="112" cy="13" r="1" fill="rgba(61,30,13,0.560784)"/>
+ <circle cx="113" cy="13" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="114" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="13" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="14" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="14" r="1" fill="rgba(69,39,18,0)"/>
+ <circle cx="19" cy="14" r="1" fill="rgba(69,39,18,0)"/>
+ <circle cx="20" cy="14" r="1" fill="rgba(69,39,18,0)"/>
+ <circle cx="21" cy="14" r="1" fill="rgba(69,39,18,0)"/>
+ <circle cx="22" cy="14" r="1" fill="rgba(69,39,18,0)"/>
+ <circle cx="23" cy="14" r="1" fill="rgba(69,39,18,0)"/>
+ <circle cx="24" cy="14" r="1" fill="rgba(69,39,18,0)"/>
+ <circle cx="25" cy="14" r="1" fill="rgba(69,39,18,0)"/>
+ <circle cx="26" cy="14" r="1" fill="rgba(69,39,18,0)"/>
+ <circle cx="27" cy="14" r="1" fill="rgba(70,39,19,0.427451)"/>
+ <circle cx="28" cy="14" r="1" fill="rgba(75,42,22,1)"/>
+ <circle cx="29" cy="14" r="1" fill="rgba(78,46,24,1)"/>
+ <circle cx="30" cy="14" r="1" fill="rgba(83,50,27,0.427451)"/>
+ <circle cx="31" cy="14" r="1" fill="rgba(84,51,29,0)"/>
+ <circle cx="32" cy="14" r="1" fill="rgba(84,51,29,0)"/>
+ <circle cx="33" cy="14" r="1" fill="rgba(84,51,29,0)"/>
+ <circle cx="34" cy="14" r="1" fill="rgba(84,51,29,0)"/>
+ <circle cx="35" cy="14" r="1" fill="rgba(84,51,29,0)"/>
+ <circle cx="36" cy="14" r="1" fill="rgba(84,51,29,0)"/>
+ <circle cx="37" cy="14" r="1" fill="rgba(84,51,29,0)"/>
+ <circle cx="38" cy="14" r="1" fill="rgba(84,51,29,0)"/>
+ <circle cx="39" cy="14" r="1" fill="rgba(84,51,29,0)"/>
+ <circle cx="40" cy="14" r="1" fill="rgba(84,51,29,0)"/>
+ <circle cx="41" cy="14" r="1" fill="rgba(84,51,29,0)"/>
+ <circle cx="42" cy="14" r="1" fill="rgba(85,52,29,0)"/>
+ <circle cx="43" cy="14" r="1" fill="rgba(73,40,20,0)"/>
+ <circle cx="44" cy="14" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="45" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="53" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="54" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="55" cy="14" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="56" cy="14" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="57" cy="14" r="1" fill="rgba(74,42,21,0)"/>
+ <circle cx="58" cy="14" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="59" cy="14" r="1" fill="rgba(85,53,29,0)"/>
+ <circle cx="60" cy="14" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="61" cy="14" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="62" cy="14" r="1" fill="rgba(101,69,42,0)"/>
+ <circle cx="63" cy="14" r="1" fill="rgba(105,74,47,0.0470588)"/>
+ <circle cx="64" cy="14" r="1" fill="rgba(111,79,51,0.0588235)"/>
+ <circle cx="65" cy="14" r="1" fill="rgba(112,81,53,0.0588235)"/>
+ <circle cx="66" cy="14" r="1" fill="rgba(108,76,48,0.0588235)"/>
+ <circle cx="67" cy="14" r="1" fill="rgba(102,71,44,0.0196078)"/>
+ <circle cx="68" cy="14" r="1" fill="rgba(98,65,39,0)"/>
+ <circle cx="69" cy="14" r="1" fill="rgba(93,60,35,0)"/>
+ <circle cx="70" cy="14" r="1" fill="rgba(87,55,31,0)"/>
+ <circle cx="71" cy="14" r="1" fill="rgba(82,49,27,0)"/>
+ <circle cx="72" cy="14" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="73" cy="14" r="1" fill="rgba(69,38,18,0)"/>
+ <circle cx="74" cy="14" r="1" fill="rgba(63,33,15,0)"/>
+ <circle cx="75" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="76" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="77" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="78" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="14" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="14" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="14" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="14" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="14" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="14" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="14" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="14" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="14" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="14" r="1" fill="rgba(83,51,27,0)"/>
+ <circle cx="95" cy="14" r="1" fill="rgba(83,51,27,0)"/>
+ <circle cx="96" cy="14" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="97" cy="14" r="1" fill="rgba(26,8,2,0)"/>
+ <circle cx="98" cy="14" r="1" fill="rgba(29,10,3,0)"/>
+ <circle cx="99" cy="14" r="1" fill="rgba(29,10,3,0)"/>
+ <circle cx="100" cy="14" r="1" fill="rgba(29,10,3,0)"/>
+ <circle cx="101" cy="14" r="1" fill="rgba(29,10,3,0)"/>
+ <circle cx="102" cy="14" r="1" fill="rgba(29,10,3,0)"/>
+ <circle cx="103" cy="14" r="1" fill="rgba(29,10,3,0)"/>
+ <circle cx="104" cy="14" r="1" fill="rgba(29,10,3,0)"/>
+ <circle cx="105" cy="14" r="1" fill="rgba(29,10,3,0)"/>
+ <circle cx="106" cy="14" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="107" cy="14" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="108" cy="14" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="109" cy="14" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="110" cy="14" r="1" fill="rgba(33,13,4,0.00784314)"/>
+ <circle cx="111" cy="14" r="1" fill="rgba(59,29,13,0.780392)"/>
+ <circle cx="112" cy="14" r="1" fill="rgba(62,31,14,0.611765)"/>
+ <circle cx="113" cy="14" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="114" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="14" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="15" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="15" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="19" cy="15" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="20" cy="15" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="21" cy="15" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="22" cy="15" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="23" cy="15" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="24" cy="15" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="25" cy="15" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="26" cy="15" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="27" cy="15" r="1" fill="rgba(73,41,20,0.290196)"/>
+ <circle cx="28" cy="15" r="1" fill="rgba(77,45,23,1)"/>
+ <circle cx="29" cy="15" r="1" fill="rgba(81,49,26,1)"/>
+ <circle cx="30" cy="15" r="1" fill="rgba(84,52,28,0.929412)"/>
+ <circle cx="31" cy="15" r="1" fill="rgba(86,54,30,0.113725)"/>
+ <circle cx="32" cy="15" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="33" cy="15" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="34" cy="15" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="35" cy="15" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="36" cy="15" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="37" cy="15" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="38" cy="15" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="39" cy="15" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="40" cy="15" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="41" cy="15" r="1" fill="rgba(86,53,30,0)"/>
+ <circle cx="42" cy="15" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="43" cy="15" r="1" fill="rgba(63,32,15,0)"/>
+ <circle cx="44" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="53" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="54" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="55" cy="15" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="56" cy="15" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="57" cy="15" r="1" fill="rgba(74,42,21,0)"/>
+ <circle cx="58" cy="15" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="59" cy="15" r="1" fill="rgba(85,53,29,0.0745098)"/>
+ <circle cx="60" cy="15" r="1" fill="rgba(91,58,33,0.313725)"/>
+ <circle cx="61" cy="15" r="1" fill="rgba(96,63,37,0.552941)"/>
+ <circle cx="62" cy="15" r="1" fill="rgba(101,69,42,0.733333)"/>
+ <circle cx="63" cy="15" r="1" fill="rgba(105,74,47,0.886275)"/>
+ <circle cx="64" cy="15" r="1" fill="rgba(110,79,51,0.941176)"/>
+ <circle cx="65" cy="15" r="1" fill="rgba(112,80,52,0.941176)"/>
+ <circle cx="66" cy="15" r="1" fill="rgba(107,76,48,0.92549)"/>
+ <circle cx="67" cy="15" r="1" fill="rgba(102,71,44,0.796078)"/>
+ <circle cx="68" cy="15" r="1" fill="rgba(98,65,39,0.627451)"/>
+ <circle cx="69" cy="15" r="1" fill="rgba(93,60,35,0.419608)"/>
+ <circle cx="70" cy="15" r="1" fill="rgba(87,55,31,0.168627)"/>
+ <circle cx="71" cy="15" r="1" fill="rgba(82,49,27,0.0117647)"/>
+ <circle cx="72" cy="15" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="73" cy="15" r="1" fill="rgba(69,38,18,0)"/>
+ <circle cx="74" cy="15" r="1" fill="rgba(63,33,15,0)"/>
+ <circle cx="75" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="76" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="77" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="78" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="15" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="15" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="15" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="15" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="15" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="15" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="15" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="15" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="15" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="15" r="1" fill="rgba(83,51,27,0)"/>
+ <circle cx="95" cy="15" r="1" fill="rgba(84,52,29,0)"/>
+ <circle cx="96" cy="15" r="1" fill="rgba(67,37,18,0)"/>
+ <circle cx="97" cy="15" r="1" fill="rgba(64,35,16,0)"/>
+ <circle cx="98" cy="15" r="1" fill="rgba(64,35,16,0)"/>
+ <circle cx="99" cy="15" r="1" fill="rgba(64,35,16,0)"/>
+ <circle cx="100" cy="15" r="1" fill="rgba(64,35,16,0)"/>
+ <circle cx="101" cy="15" r="1" fill="rgba(64,35,16,0)"/>
+ <circle cx="102" cy="15" r="1" fill="rgba(64,35,16,0)"/>
+ <circle cx="103" cy="15" r="1" fill="rgba(64,35,16,0)"/>
+ <circle cx="104" cy="15" r="1" fill="rgba(64,35,16,0)"/>
+ <circle cx="105" cy="15" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="106" cy="15" r="1" fill="rgba(39,16,5,0)"/>
+ <circle cx="107" cy="15" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="108" cy="15" r="1" fill="rgba(37,14,4,0)"/>
+ <circle cx="109" cy="15" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="110" cy="15" r="1" fill="rgba(51,24,9,0.513725)"/>
+ <circle cx="111" cy="15" r="1" fill="rgba(61,30,13,0.831373)"/>
+ <circle cx="112" cy="15" r="1" fill="rgba(47,21,8,0.0588235)"/>
+ <circle cx="113" cy="15" r="1" fill="rgba(47,21,8,0)"/>
+ <circle cx="114" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="15" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="16" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="16" r="1" fill="rgba(74,41,20,0)"/>
+ <circle cx="19" cy="16" r="1" fill="rgba(74,41,20,0)"/>
+ <circle cx="20" cy="16" r="1" fill="rgba(74,41,20,0)"/>
+ <circle cx="21" cy="16" r="1" fill="rgba(74,41,20,0)"/>
+ <circle cx="22" cy="16" r="1" fill="rgba(74,41,20,0)"/>
+ <circle cx="23" cy="16" r="1" fill="rgba(74,41,20,0)"/>
+ <circle cx="24" cy="16" r="1" fill="rgba(74,41,20,0)"/>
+ <circle cx="25" cy="16" r="1" fill="rgba(74,41,20,0)"/>
+ <circle cx="26" cy="16" r="1" fill="rgba(74,41,20,0)"/>
+ <circle cx="27" cy="16" r="1" fill="rgba(74,41,20,0.0509804)"/>
+ <circle cx="28" cy="16" r="1" fill="rgba(80,46,24,0.878431)"/>
+ <circle cx="29" cy="16" r="1" fill="rgba(84,51,27,1)"/>
+ <circle cx="30" cy="16" r="1" fill="rgba(87,55,30,1)"/>
+ <circle cx="31" cy="16" r="1" fill="rgba(90,57,33,0.364706)"/>
+ <circle cx="32" cy="16" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="33" cy="16" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="34" cy="16" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="35" cy="16" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="36" cy="16" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="37" cy="16" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="38" cy="16" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="39" cy="16" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="40" cy="16" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="41" cy="16" r="1" fill="rgba(92,59,34,0)"/>
+ <circle cx="42" cy="16" r="1" fill="rgba(83,50,27,0)"/>
+ <circle cx="43" cy="16" r="1" fill="rgba(59,30,13,0)"/>
+ <circle cx="44" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="53" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="54" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="55" cy="16" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="56" cy="16" r="1" fill="rgba(67,35,17,0.0196078)"/>
+ <circle cx="57" cy="16" r="1" fill="rgba(74,42,21,0.305882)"/>
+ <circle cx="58" cy="16" r="1" fill="rgba(80,47,25,0.623529)"/>
+ <circle cx="59" cy="16" r="1" fill="rgba(84,52,29,0.905882)"/>
+ <circle cx="60" cy="16" r="1" fill="rgba(91,58,33,1)"/>
+ <circle cx="61" cy="16" r="1" fill="rgba(94,62,37,1)"/>
+ <circle cx="62" cy="16" r="1" fill="rgba(99,67,40,1)"/>
+ <circle cx="63" cy="16" r="1" fill="rgba(103,71,44,1)"/>
+ <circle cx="64" cy="16" r="1" fill="rgba(106,75,48,1)"/>
+ <circle cx="65" cy="16" r="1" fill="rgba(107,75,48,1)"/>
+ <circle cx="66" cy="16" r="1" fill="rgba(105,73,46,1)"/>
+ <circle cx="67" cy="16" r="1" fill="rgba(101,69,42,1)"/>
+ <circle cx="68" cy="16" r="1" fill="rgba(97,64,38,1)"/>
+ <circle cx="69" cy="16" r="1" fill="rgba(91,59,33,1)"/>
+ <circle cx="70" cy="16" r="1" fill="rgba(87,54,30,0.972549)"/>
+ <circle cx="71" cy="16" r="1" fill="rgba(81,49,27,0.776471)"/>
+ <circle cx="72" cy="16" r="1" fill="rgba(76,44,22,0.458824)"/>
+ <circle cx="73" cy="16" r="1" fill="rgba(69,38,18,0.133333)"/>
+ <circle cx="74" cy="16" r="1" fill="rgba(63,33,15,0)"/>
+ <circle cx="75" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="76" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="77" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="78" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="16" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="16" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="16" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="16" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="16" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="16" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="16" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="16" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="16" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="16" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="16" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="16" r="1" fill="rgba(94,61,35,0)"/>
+ <circle cx="97" cy="16" r="1" fill="rgba(94,61,36,0)"/>
+ <circle cx="98" cy="16" r="1" fill="rgba(92,59,33,0)"/>
+ <circle cx="99" cy="16" r="1" fill="rgba(92,59,33,0)"/>
+ <circle cx="100" cy="16" r="1" fill="rgba(92,59,33,0)"/>
+ <circle cx="101" cy="16" r="1" fill="rgba(92,59,33,0)"/>
+ <circle cx="102" cy="16" r="1" fill="rgba(92,59,33,0)"/>
+ <circle cx="103" cy="16" r="1" fill="rgba(92,59,33,0)"/>
+ <circle cx="104" cy="16" r="1" fill="rgba(92,59,33,0)"/>
+ <circle cx="105" cy="16" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="106" cy="16" r="1" fill="rgba(77,45,23,0)"/>
+ <circle cx="107" cy="16" r="1" fill="rgba(71,40,20,0)"/>
+ <circle cx="108" cy="16" r="1" fill="rgba(64,34,16,0)"/>
+ <circle cx="109" cy="16" r="1" fill="rgba(58,28,12,0.34902)"/>
+ <circle cx="110" cy="16" r="1" fill="rgba(61,29,13,1)"/>
+ <circle cx="111" cy="16" r="1" fill="rgba(37,16,5,0.32549)"/>
+ <circle cx="112" cy="16" r="1" fill="rgba(28,9,3,0)"/>
+ <circle cx="113" cy="16" r="1" fill="rgba(28,9,3,0)"/>
+ <circle cx="114" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="16" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="17" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="17" r="1" fill="rgba(67,35,16,0)"/>
+ <circle cx="19" cy="17" r="1" fill="rgba(67,35,16,0)"/>
+ <circle cx="20" cy="17" r="1" fill="rgba(67,35,16,0)"/>
+ <circle cx="21" cy="17" r="1" fill="rgba(67,35,16,0)"/>
+ <circle cx="22" cy="17" r="1" fill="rgba(67,35,16,0)"/>
+ <circle cx="23" cy="17" r="1" fill="rgba(67,35,16,0)"/>
+ <circle cx="24" cy="17" r="1" fill="rgba(67,35,16,0)"/>
+ <circle cx="25" cy="17" r="1" fill="rgba(67,35,16,0)"/>
+ <circle cx="26" cy="17" r="1" fill="rgba(67,35,16,0)"/>
+ <circle cx="27" cy="17" r="1" fill="rgba(65,34,16,0)"/>
+ <circle cx="28" cy="17" r="1" fill="rgba(71,40,20,0.376471)"/>
+ <circle cx="29" cy="17" r="1" fill="rgba(86,54,30,1)"/>
+ <circle cx="30" cy="17" r="1" fill="rgba(90,56,32,1)"/>
+ <circle cx="31" cy="17" r="1" fill="rgba(93,61,35,0.584314)"/>
+ <circle cx="32" cy="17" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="33" cy="17" r="1" fill="rgba(97,64,38,0)"/>
+ <circle cx="34" cy="17" r="1" fill="rgba(97,64,38,0)"/>
+ <circle cx="35" cy="17" r="1" fill="rgba(97,64,38,0)"/>
+ <circle cx="36" cy="17" r="1" fill="rgba(97,64,38,0)"/>
+ <circle cx="37" cy="17" r="1" fill="rgba(97,64,38,0)"/>
+ <circle cx="38" cy="17" r="1" fill="rgba(97,64,38,0)"/>
+ <circle cx="39" cy="17" r="1" fill="rgba(97,64,38,0)"/>
+ <circle cx="40" cy="17" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="41" cy="17" r="1" fill="rgba(94,62,36,0)"/>
+ <circle cx="42" cy="17" r="1" fill="rgba(71,40,20,0)"/>
+ <circle cx="43" cy="17" r="1" fill="rgba(58,28,12,0)"/>
+ <circle cx="44" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="53" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="54" cy="17" r="1" fill="rgba(61,30,13,0.0588235)"/>
+ <circle cx="55" cy="17" r="1" fill="rgba(62,31,14,0.419608)"/>
+ <circle cx="56" cy="17" r="1" fill="rgba(65,35,17,0.807843)"/>
+ <circle cx="57" cy="17" r="1" fill="rgba(71,40,20,1)"/>
+ <circle cx="58" cy="17" r="1" fill="rgba(77,46,24,1)"/>
+ <circle cx="59" cy="17" r="1" fill="rgba(83,50,27,1)"/>
+ <circle cx="60" cy="17" r="1" fill="rgba(87,56,31,1)"/>
+ <circle cx="61" cy="17" r="1" fill="rgba(92,60,35,1)"/>
+ <circle cx="62" cy="17" r="1" fill="rgba(96,64,38,1)"/>
+ <circle cx="63" cy="17" r="1" fill="rgba(100,67,41,1)"/>
+ <circle cx="64" cy="17" r="1" fill="rgba(102,70,43,1)"/>
+ <circle cx="65" cy="17" r="1" fill="rgba(102,70,43,1)"/>
+ <circle cx="66" cy="17" r="1" fill="rgba(101,69,42,1)"/>
+ <circle cx="67" cy="17" r="1" fill="rgba(98,65,39,1)"/>
+ <circle cx="68" cy="17" r="1" fill="rgba(94,61,36,1)"/>
+ <circle cx="69" cy="17" r="1" fill="rgba(90,57,33,1)"/>
+ <circle cx="70" cy="17" r="1" fill="rgba(85,53,29,1)"/>
+ <circle cx="71" cy="17" r="1" fill="rgba(80,47,25,1)"/>
+ <circle cx="72" cy="17" r="1" fill="rgba(74,42,22,1)"/>
+ <circle cx="73" cy="17" r="1" fill="rgba(69,37,18,0.941176)"/>
+ <circle cx="74" cy="17" r="1" fill="rgba(63,32,15,0.615686)"/>
+ <circle cx="75" cy="17" r="1" fill="rgba(61,30,13,0.188235)"/>
+ <circle cx="76" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="77" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="78" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="17" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="17" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="17" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="17" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="17" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="17" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="17" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="17" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="17" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="17" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="17" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="17" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="97" cy="17" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="98" cy="17" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="99" cy="17" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="100" cy="17" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="101" cy="17" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="102" cy="17" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="103" cy="17" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="104" cy="17" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="105" cy="17" r="1" fill="rgba(84,52,29,0)"/>
+ <circle cx="106" cy="17" r="1" fill="rgba(81,48,25,0)"/>
+ <circle cx="107" cy="17" r="1" fill="rgba(74,42,21,0)"/>
+ <circle cx="108" cy="17" r="1" fill="rgba(67,36,17,0.364706)"/>
+ <circle cx="109" cy="17" r="1" fill="rgba(64,33,15,0.996078)"/>
+ <circle cx="110" cy="17" r="1" fill="rgba(43,19,7,0.686275)"/>
+ <circle cx="111" cy="17" r="1" fill="rgba(24,7,2,0.0862745)"/>
+ <circle cx="112" cy="17" r="1" fill="rgba(29,10,3,0)"/>
+ <circle cx="113" cy="17" r="1" fill="rgba(29,10,3,0)"/>
+ <circle cx="114" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="17" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="18" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="18" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="19" cy="18" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="20" cy="18" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="21" cy="18" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="22" cy="18" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="23" cy="18" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="24" cy="18" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="25" cy="18" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="26" cy="18" r="1" fill="rgba(33,12,3,0)"/>
+ <circle cx="27" cy="18" r="1" fill="rgba(31,11,3,0)"/>
+ <circle cx="28" cy="18" r="1" fill="rgba(33,12,3,0.0156863)"/>
+ <circle cx="29" cy="18" r="1" fill="rgba(76,45,23,0.733333)"/>
+ <circle cx="30" cy="18" r="1" fill="rgba(93,59,34,1)"/>
+ <circle cx="31" cy="18" r="1" fill="rgba(94,62,37,0.811765)"/>
+ <circle cx="32" cy="18" r="1" fill="rgba(78,47,25,0.0117647)"/>
+ <circle cx="33" cy="18" r="1" fill="rgba(68,39,19,0)"/>
+ <circle cx="34" cy="18" r="1" fill="rgba(69,40,20,0)"/>
+ <circle cx="35" cy="18" r="1" fill="rgba(69,40,20,0)"/>
+ <circle cx="36" cy="18" r="1" fill="rgba(69,40,20,0)"/>
+ <circle cx="37" cy="18" r="1" fill="rgba(69,40,20,0)"/>
+ <circle cx="38" cy="18" r="1" fill="rgba(69,40,20,0)"/>
+ <circle cx="39" cy="18" r="1" fill="rgba(68,39,19,0)"/>
+ <circle cx="40" cy="18" r="1" fill="rgba(77,47,24,0)"/>
+ <circle cx="41" cy="18" r="1" fill="rgba(81,48,26,0)"/>
+ <circle cx="42" cy="18" r="1" fill="rgba(64,34,16,0)"/>
+ <circle cx="43" cy="18" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="44" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="52" cy="18" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="53" cy="18" r="1" fill="rgba(59,29,13,0.356863)"/>
+ <circle cx="54" cy="18" r="1" fill="rgba(61,30,13,0.839216)"/>
+ <circle cx="55" cy="18" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="56" cy="18" r="1" fill="rgba(64,34,16,1)"/>
+ <circle cx="57" cy="18" r="1" fill="rgba(70,38,19,1)"/>
+ <circle cx="58" cy="18" r="1" fill="rgba(75,43,22,1)"/>
+ <circle cx="59" cy="18" r="1" fill="rgba(80,48,26,1)"/>
+ <circle cx="60" cy="18" r="1" fill="rgba(85,52,29,1)"/>
+ <circle cx="61" cy="18" r="1" fill="rgba(90,56,32,1)"/>
+ <circle cx="62" cy="18" r="1" fill="rgba(93,60,35,1)"/>
+ <circle cx="63" cy="18" r="1" fill="rgba(96,63,37,1)"/>
+ <circle cx="64" cy="18" r="1" fill="rgba(97,65,38,1)"/>
+ <circle cx="65" cy="18" r="1" fill="rgba(97,65,38,1)"/>
+ <circle cx="66" cy="18" r="1" fill="rgba(96,64,38,1)"/>
+ <circle cx="67" cy="18" r="1" fill="rgba(94,61,36,1)"/>
+ <circle cx="68" cy="18" r="1" fill="rgba(91,58,33,1)"/>
+ <circle cx="69" cy="18" r="1" fill="rgba(86,54,30,1)"/>
+ <circle cx="70" cy="18" r="1" fill="rgba(82,50,27,1)"/>
+ <circle cx="71" cy="18" r="1" fill="rgba(77,45,23,1)"/>
+ <circle cx="72" cy="18" r="1" fill="rgba(73,41,20,1)"/>
+ <circle cx="73" cy="18" r="1" fill="rgba(67,36,17,1)"/>
+ <circle cx="74" cy="18" r="1" fill="rgba(62,31,13,1)"/>
+ <circle cx="75" cy="18" r="1" fill="rgba(61,30,13,0.968627)"/>
+ <circle cx="76" cy="18" r="1" fill="rgba(61,30,13,0.596078)"/>
+ <circle cx="77" cy="18" r="1" fill="rgba(61,30,13,0.0941176)"/>
+ <circle cx="78" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="79" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="18" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="18" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="18" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="18" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="18" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="18" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="18" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="18" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="18" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="18" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="18" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="18" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="97" cy="18" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="98" cy="18" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="99" cy="18" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="100" cy="18" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="101" cy="18" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="102" cy="18" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="103" cy="18" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="104" cy="18" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="105" cy="18" r="1" fill="rgba(84,52,29,0)"/>
+ <circle cx="106" cy="18" r="1" fill="rgba(80,47,24,0)"/>
+ <circle cx="107" cy="18" r="1" fill="rgba(74,42,20,0.478431)"/>
+ <circle cx="108" cy="18" r="1" fill="rgba(70,38,18,1)"/>
+ <circle cx="109" cy="18" r="1" fill="rgba(59,30,13,0.909804)"/>
+ <circle cx="110" cy="18" r="1" fill="rgba(24,8,2,0.286275)"/>
+ <circle cx="111" cy="18" r="1" fill="rgba(31,11,3,0.0117647)"/>
+ <circle cx="112" cy="18" r="1" fill="rgba(31,11,4,0)"/>
+ <circle cx="113" cy="18" r="1" fill="rgba(31,11,4,0)"/>
+ <circle cx="114" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="18" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="19" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="19" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="19" cy="19" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="20" cy="19" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="21" cy="19" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="22" cy="19" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="23" cy="19" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="24" cy="19" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="25" cy="19" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="26" cy="19" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="27" cy="19" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="28" cy="19" r="1" fill="rgba(24,8,2,0)"/>
+ <circle cx="29" cy="19" r="1" fill="rgba(49,23,9,0.333333)"/>
+ <circle cx="30" cy="19" r="1" fill="rgba(92,60,34,1)"/>
+ <circle cx="31" cy="19" r="1" fill="rgba(98,65,39,0.984314)"/>
+ <circle cx="32" cy="19" r="1" fill="rgba(63,34,16,0.164706)"/>
+ <circle cx="33" cy="19" r="1" fill="rgba(34,14,4,0)"/>
+ <circle cx="34" cy="19" r="1" fill="rgba(40,16,5,0)"/>
+ <circle cx="35" cy="19" r="1" fill="rgba(40,16,5,0)"/>
+ <circle cx="36" cy="19" r="1" fill="rgba(40,16,5,0)"/>
+ <circle cx="37" cy="19" r="1" fill="rgba(40,16,5,0)"/>
+ <circle cx="38" cy="19" r="1" fill="rgba(40,16,5,0)"/>
+ <circle cx="39" cy="19" r="1" fill="rgba(37,15,5,0)"/>
+ <circle cx="40" cy="19" r="1" fill="rgba(59,31,14,0)"/>
+ <circle cx="41" cy="19" r="1" fill="rgba(76,43,22,0)"/>
+ <circle cx="42" cy="19" r="1" fill="rgba(65,35,16,0)"/>
+ <circle cx="43" cy="19" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="44" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="19" r="1" fill="rgba(61,30,13,0.0431373)"/>
+ <circle cx="52" cy="19" r="1" fill="rgba(55,26,11,0.611765)"/>
+ <circle cx="53" cy="19" r="1" fill="rgba(54,24,10,1)"/>
+ <circle cx="54" cy="19" r="1" fill="rgba(59,29,13,1)"/>
+ <circle cx="55" cy="19" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="56" cy="19" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="57" cy="19" r="1" fill="rgba(68,36,17,1)"/>
+ <circle cx="58" cy="19" r="1" fill="rgba(73,41,20,1)"/>
+ <circle cx="59" cy="19" r="1" fill="rgba(77,45,23,1)"/>
+ <circle cx="60" cy="19" r="1" fill="rgba(82,49,26,1)"/>
+ <circle cx="61" cy="19" r="1" fill="rgba(85,53,29,1)"/>
+ <circle cx="62" cy="19" r="1" fill="rgba(88,56,31,1)"/>
+ <circle cx="63" cy="19" r="1" fill="rgba(91,58,33,1)"/>
+ <circle cx="64" cy="19" r="1" fill="rgba(92,59,34,1)"/>
+ <circle cx="65" cy="19" r="1" fill="rgba(93,60,34,1)"/>
+ <circle cx="66" cy="19" r="1" fill="rgba(91,59,33,1)"/>
+ <circle cx="67" cy="19" r="1" fill="rgba(90,56,32,1)"/>
+ <circle cx="68" cy="19" r="1" fill="rgba(86,54,30,1)"/>
+ <circle cx="69" cy="19" r="1" fill="rgba(83,50,27,1)"/>
+ <circle cx="70" cy="19" r="1" fill="rgba(78,46,24,1)"/>
+ <circle cx="71" cy="19" r="1" fill="rgba(74,42,22,1)"/>
+ <circle cx="72" cy="19" r="1" fill="rgba(69,38,18,1)"/>
+ <circle cx="73" cy="19" r="1" fill="rgba(63,33,15,1)"/>
+ <circle cx="74" cy="19" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="75" cy="19" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="76" cy="19" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="77" cy="19" r="1" fill="rgba(61,30,13,0.847059)"/>
+ <circle cx="78" cy="19" r="1" fill="rgba(61,30,13,0.219608)"/>
+ <circle cx="79" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="80" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="81" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="82" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="84" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="19" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="19" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="19" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="19" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="19" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="19" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="19" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="19" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="19" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="19" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="19" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="19" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="97" cy="19" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="98" cy="19" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="99" cy="19" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="100" cy="19" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="101" cy="19" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="102" cy="19" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="103" cy="19" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="104" cy="19" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="105" cy="19" r="1" fill="rgba(84,52,29,0.027451)"/>
+ <circle cx="106" cy="19" r="1" fill="rgba(80,48,24,0.588235)"/>
+ <circle cx="107" cy="19" r="1" fill="rgba(76,43,22,1)"/>
+ <circle cx="108" cy="19" r="1" fill="rgba(73,41,20,1)"/>
+ <circle cx="109" cy="19" r="1" fill="rgba(40,17,6,0.572549)"/>
+ <circle cx="110" cy="19" r="1" fill="rgba(24,8,2,0.0980392)"/>
+ <circle cx="111" cy="19" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="112" cy="19" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="113" cy="19" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="114" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="19" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="20" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="20" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="19" cy="20" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="20" cy="20" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="21" cy="20" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="22" cy="20" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="23" cy="20" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="24" cy="20" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="25" cy="20" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="26" cy="20" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="27" cy="20" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="28" cy="20" r="1" fill="rgba(33,13,3,0)"/>
+ <circle cx="29" cy="20" r="1" fill="rgba(31,12,3,0.133333)"/>
+ <circle cx="30" cy="20" r="1" fill="rgba(85,53,30,0.901961)"/>
+ <circle cx="31" cy="20" r="1" fill="rgba(100,68,42,1)"/>
+ <circle cx="32" cy="20" r="1" fill="rgba(67,39,19,0.447059)"/>
+ <circle cx="33" cy="20" r="1" fill="rgba(45,16,6,0)"/>
+ <circle cx="34" cy="20" r="1" fill="rgba(77,17,6,0)"/>
+ <circle cx="35" cy="20" r="1" fill="rgba(78,17,6,0)"/>
+ <circle cx="36" cy="20" r="1" fill="rgba(78,17,6,0)"/>
+ <circle cx="37" cy="20" r="1" fill="rgba(78,17,6,0)"/>
+ <circle cx="38" cy="20" r="1" fill="rgba(78,15,5,0)"/>
+ <circle cx="39" cy="20" r="1" fill="rgba(78,32,14,0)"/>
+ <circle cx="40" cy="20" r="1" fill="rgba(77,47,24,0)"/>
+ <circle cx="41" cy="20" r="1" fill="rgba(75,42,22,0)"/>
+ <circle cx="42" cy="20" r="1" fill="rgba(65,35,16,0)"/>
+ <circle cx="43" cy="20" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="44" cy="20" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="20" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="20" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="20" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="20" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="20" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="50" cy="20" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="51" cy="20" r="1" fill="rgba(53,24,10,0.439216)"/>
+ <circle cx="52" cy="20" r="1" fill="rgba(150,120,89,1)"/>
+ <circle cx="53" cy="20" r="1" fill="rgba(187,163,138,1)"/>
+ <circle cx="54" cy="20" r="1" fill="rgba(55,26,11,1)"/>
+ <circle cx="55" cy="20" r="1" fill="rgba(53,24,10,1)"/>
+ <circle cx="56" cy="20" r="1" fill="rgba(61,29,13,1)"/>
+ <circle cx="57" cy="20" r="1" fill="rgba(64,33,15,1)"/>
+ <circle cx="58" cy="20" r="1" fill="rgba(69,37,18,1)"/>
+ <circle cx="59" cy="20" r="1" fill="rgba(74,41,21,1)"/>
+ <circle cx="60" cy="20" r="1" fill="rgba(77,45,23,1)"/>
+ <circle cx="61" cy="20" r="1" fill="rgba(81,48,26,1)"/>
+ <circle cx="62" cy="20" r="1" fill="rgba(84,51,27,1)"/>
+ <circle cx="63" cy="20" r="1" fill="rgba(85,53,30,1)"/>
+ <circle cx="64" cy="20" r="1" fill="rgba(87,54,30,1)"/>
+ <circle cx="65" cy="20" r="1" fill="rgba(87,54,30,1)"/>
+ <circle cx="66" cy="20" r="1" fill="rgba(86,53,30,1)"/>
+ <circle cx="67" cy="20" r="1" fill="rgba(85,52,29,1)"/>
+ <circle cx="68" cy="20" r="1" fill="rgba(82,50,27,1)"/>
+ <circle cx="69" cy="20" r="1" fill="rgba(78,46,24,1)"/>
+ <circle cx="70" cy="20" r="1" fill="rgba(75,43,22,1)"/>
+ <circle cx="71" cy="20" r="1" fill="rgba(70,39,19,1)"/>
+ <circle cx="72" cy="20" r="1" fill="rgba(65,34,16,1)"/>
+ <circle cx="73" cy="20" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="74" cy="20" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="75" cy="20" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="76" cy="20" r="1" fill="rgba(63,33,16,1)"/>
+ <circle cx="77" cy="20" r="1" fill="rgba(62,33,16,1)"/>
+ <circle cx="78" cy="20" r="1" fill="rgba(61,31,14,0.894118)"/>
+ <circle cx="79" cy="20" r="1" fill="rgba(62,31,14,0.0862745)"/>
+ <circle cx="80" cy="20" r="1" fill="rgba(58,28,12,0)"/>
+ <circle cx="81" cy="20" r="1" fill="rgba(77,47,26,0)"/>
+ <circle cx="82" cy="20" r="1" fill="rgba(65,35,16,0)"/>
+ <circle cx="83" cy="20" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="84" cy="20" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="20" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="20" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="20" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="20" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="20" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="20" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="20" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="20" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="20" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="20" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="20" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="20" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="97" cy="20" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="98" cy="20" r="1" fill="rgba(90,57,32,0)"/>
+ <circle cx="99" cy="20" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="100" cy="20" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="101" cy="20" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="102" cy="20" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="103" cy="20" r="1" fill="rgba(88,56,31,0)"/>
+ <circle cx="104" cy="20" r="1" fill="rgba(88,56,31,0.027451)"/>
+ <circle cx="105" cy="20" r="1" fill="rgba(85,53,30,0.682353)"/>
+ <circle cx="106" cy="20" r="1" fill="rgba(81,49,27,1)"/>
+ <circle cx="107" cy="20" r="1" fill="rgba(78,47,24,1)"/>
+ <circle cx="108" cy="20" r="1" fill="rgba(65,35,17,0.905882)"/>
+ <circle cx="109" cy="20" r="1" fill="rgba(21,6,1,0.305882)"/>
+ <circle cx="110" cy="20" r="1" fill="rgba(33,13,4,0.0235294)"/>
+ <circle cx="111" cy="20" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="112" cy="20" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="113" cy="20" r="1" fill="rgba(36,14,4,0)"/>
+ <circle cx="114" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="20" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="21" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="21" r="1" fill="rgba(26,9,2,0)"/>
+ <circle cx="19" cy="21" r="1" fill="rgba(26,9,2,0)"/>
+ <circle cx="20" cy="21" r="1" fill="rgba(26,9,2,0)"/>
+ <circle cx="21" cy="21" r="1" fill="rgba(26,9,2,0)"/>
+ <circle cx="22" cy="21" r="1" fill="rgba(26,9,2,0)"/>
+ <circle cx="23" cy="21" r="1" fill="rgba(26,9,2,0)"/>
+ <circle cx="24" cy="21" r="1" fill="rgba(26,9,2,0)"/>
+ <circle cx="25" cy="21" r="1" fill="rgba(26,9,2,0)"/>
+ <circle cx="26" cy="21" r="1" fill="rgba(26,9,2,0)"/>
+ <circle cx="27" cy="21" r="1" fill="rgba(26,9,2,0)"/>
+ <circle cx="28" cy="21" r="1" fill="rgba(26,9,2,0)"/>
+ <circle cx="29" cy="21" r="1" fill="rgba(24,8,2,0.0588235)"/>
+ <circle cx="30" cy="21" r="1" fill="rgba(76,46,24,0.756863)"/>
+ <circle cx="31" cy="21" r="1" fill="rgba(100,68,41,1)"/>
+ <circle cx="32" cy="21" r="1" fill="rgba(76,47,24,0.709804)"/>
+ <circle cx="33" cy="21" r="1" fill="rgba(43,17,6,0.0745098)"/>
+ <circle cx="34" cy="21" r="1" fill="rgba(77,17,6,0)"/>
+ <circle cx="35" cy="21" r="1" fill="rgba(76,14,5,0)"/>
+ <circle cx="36" cy="21" r="1" fill="rgba(76,14,5,0)"/>
+ <circle cx="37" cy="21" r="1" fill="rgba(76,14,5,0)"/>
+ <circle cx="38" cy="21" r="1" fill="rgba(77,13,4,0)"/>
+ <circle cx="39" cy="21" r="1" fill="rgba(81,34,16,0)"/>
+ <circle cx="40" cy="21" r="1" fill="rgba(78,48,25,0)"/>
+ <circle cx="41" cy="21" r="1" fill="rgba(75,42,22,0)"/>
+ <circle cx="42" cy="21" r="1" fill="rgba(65,35,16,0)"/>
+ <circle cx="43" cy="21" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="44" cy="21" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="21" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="21" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="21" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="21" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="21" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="50" cy="21" r="1" fill="rgba(55,26,11,0)"/>
+ <circle cx="51" cy="21" r="1" fill="rgba(49,21,8,0.227451)"/>
+ <circle cx="52" cy="21" r="1" fill="rgba(108,74,45,0.956863)"/>
+ <circle cx="53" cy="21" r="1" fill="rgba(213,197,178,1)"/>
+ <circle cx="54" cy="21" r="1" fill="rgba(170,143,115,1)"/>
+ <circle cx="55" cy="21" r="1" fill="rgba(83,49,26,1)"/>
+ <circle cx="56" cy="21" r="1" fill="rgba(50,22,8,1)"/>
+ <circle cx="57" cy="21" r="1" fill="rgba(50,22,9,1)"/>
+ <circle cx="58" cy="21" r="1" fill="rgba(62,32,14,1)"/>
+ <circle cx="59" cy="21" r="1" fill="rgba(69,38,18,1)"/>
+ <circle cx="60" cy="21" r="1" fill="rgba(73,41,20,1)"/>
+ <circle cx="61" cy="21" r="1" fill="rgba(76,44,22,1)"/>
+ <circle cx="62" cy="21" r="1" fill="rgba(78,47,24,1)"/>
+ <circle cx="63" cy="21" r="1" fill="rgba(81,48,25,1)"/>
+ <circle cx="64" cy="21" r="1" fill="rgba(82,49,26,1)"/>
+ <circle cx="65" cy="21" r="1" fill="rgba(82,49,26,1)"/>
+ <circle cx="66" cy="21" r="1" fill="rgba(81,48,26,1)"/>
+ <circle cx="67" cy="21" r="1" fill="rgba(78,47,24,1)"/>
+ <circle cx="68" cy="21" r="1" fill="rgba(77,45,23,1)"/>
+ <circle cx="69" cy="21" r="1" fill="rgba(74,42,21,1)"/>
+ <circle cx="70" cy="21" r="1" fill="rgba(70,39,19,1)"/>
+ <circle cx="71" cy="21" r="1" fill="rgba(67,35,16,1)"/>
+ <circle cx="72" cy="21" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="73" cy="21" r="1" fill="rgba(61,30,14,1)"/>
+ <circle cx="74" cy="21" r="1" fill="rgba(63,33,16,1)"/>
+ <circle cx="75" cy="21" r="1" fill="rgba(65,37,20,1)"/>
+ <circle cx="76" cy="21" r="1" fill="rgba(68,41,24,1)"/>
+ <circle cx="77" cy="21" r="1" fill="rgba(67,39,22,1)"/>
+ <circle cx="78" cy="21" r="1" fill="rgba(62,32,15,0.823529)"/>
+ <circle cx="79" cy="21" r="1" fill="rgba(47,21,8,0.0431373)"/>
+ <circle cx="80" cy="21" r="1" fill="rgba(71,40,20,0)"/>
+ <circle cx="81" cy="21" r="1" fill="rgba(106,78,54,0)"/>
+ <circle cx="82" cy="21" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="83" cy="21" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="84" cy="21" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="21" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="21" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="21" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="21" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="21" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="21" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="21" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="21" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="21" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="21" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="21" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="21" r="1" fill="rgba(90,57,33,0)"/>
+ <circle cx="97" cy="21" r="1" fill="rgba(95,62,37,0)"/>
+ <circle cx="98" cy="21" r="1" fill="rgba(97,65,38,0)"/>
+ <circle cx="99" cy="21" r="1" fill="rgba(93,60,35,0)"/>
+ <circle cx="100" cy="21" r="1" fill="rgba(92,59,34,0)"/>
+ <circle cx="101" cy="21" r="1" fill="rgba(92,59,34,0)"/>
+ <circle cx="102" cy="21" r="1" fill="rgba(92,59,34,0)"/>
+ <circle cx="103" cy="21" r="1" fill="rgba(92,59,34,0)"/>
+ <circle cx="104" cy="21" r="1" fill="rgba(91,58,33,0.4)"/>
+ <circle cx="105" cy="21" r="1" fill="rgba(87,55,30,1)"/>
+ <circle cx="106" cy="21" r="1" fill="rgba(83,51,27,1)"/>
+ <circle cx="107" cy="21" r="1" fill="rgba(82,49,27,1)"/>
+ <circle cx="108" cy="21" r="1" fill="rgba(45,20,7,0.635294)"/>
+ <circle cx="109" cy="21" r="1" fill="rgba(24,7,2,0.141176)"/>
+ <circle cx="110" cy="21" r="1" fill="rgba(36,13,4,0)"/>
+ <circle cx="111" cy="21" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="112" cy="21" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="113" cy="21" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="114" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="21" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="22" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="22" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="19" cy="22" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="20" cy="22" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="21" cy="22" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="22" cy="22" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="23" cy="22" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="24" cy="22" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="25" cy="22" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="26" cy="22" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="27" cy="22" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="28" cy="22" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="29" cy="22" r="1" fill="rgba(26,9,3,0.0117647)"/>
+ <circle cx="30" cy="22" r="1" fill="rgba(61,33,15,0.603922)"/>
+ <circle cx="31" cy="22" r="1" fill="rgba(98,65,39,1)"/>
+ <circle cx="32" cy="22" r="1" fill="rgba(87,56,31,0.905882)"/>
+ <circle cx="33" cy="22" r="1" fill="rgba(34,13,4,0.27451)"/>
+ <circle cx="34" cy="22" r="1" fill="rgba(55,21,8,0)"/>
+ <circle cx="35" cy="22" r="1" fill="rgba(77,42,21,0)"/>
+ <circle cx="36" cy="22" r="1" fill="rgba(76,41,21,0)"/>
+ <circle cx="37" cy="22" r="1" fill="rgba(75,39,20,0)"/>
+ <circle cx="38" cy="22" r="1" fill="rgba(71,37,18,0)"/>
+ <circle cx="39" cy="22" r="1" fill="rgba(81,48,25,0)"/>
+ <circle cx="40" cy="22" r="1" fill="rgba(78,46,24,0)"/>
+ <circle cx="41" cy="22" r="1" fill="rgba(75,42,22,0)"/>
+ <circle cx="42" cy="22" r="1" fill="rgba(65,35,16,0)"/>
+ <circle cx="43" cy="22" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="44" cy="22" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="22" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="22" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="22" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="48" cy="22" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="49" cy="22" r="1" fill="rgba(62,31,14,0.301961)"/>
+ <circle cx="50" cy="22" r="1" fill="rgba(47,22,9,0.239216)"/>
+ <circle cx="51" cy="22" r="1" fill="rgba(10,1,0,0.560784)"/>
+ <circle cx="52" cy="22" r="1" fill="rgba(4,0,0,0.984314)"/>
+ <circle cx="53" cy="22" r="1" fill="rgba(51,23,9,1)"/>
+ <circle cx="54" cy="22" r="1" fill="rgba(125,90,60,1)"/>
+ <circle cx="55" cy="22" r="1" fill="rgba(172,144,116,1)"/>
+ <circle cx="56" cy="22" r="1" fill="rgba(171,144,115,1)"/>
+ <circle cx="57" cy="22" r="1" fill="rgba(123,88,58,1)"/>
+ <circle cx="58" cy="22" r="1" fill="rgba(65,34,16,1)"/>
+ <circle cx="59" cy="22" r="1" fill="rgba(50,22,9,1)"/>
+ <circle cx="60" cy="22" r="1" fill="rgba(61,31,14,1)"/>
+ <circle cx="61" cy="22" r="1" fill="rgba(69,38,18,1)"/>
+ <circle cx="62" cy="22" r="1" fill="rgba(74,41,21,1)"/>
+ <circle cx="63" cy="22" r="1" fill="rgba(75,43,22,1)"/>
+ <circle cx="64" cy="22" r="1" fill="rgba(76,44,22,1)"/>
+ <circle cx="65" cy="22" r="1" fill="rgba(76,44,22,1)"/>
+ <circle cx="66" cy="22" r="1" fill="rgba(75,43,22,1)"/>
+ <circle cx="67" cy="22" r="1" fill="rgba(74,42,21,1)"/>
+ <circle cx="68" cy="22" r="1" fill="rgba(73,41,20,1)"/>
+ <circle cx="69" cy="22" r="1" fill="rgba(69,38,18,1)"/>
+ <circle cx="70" cy="22" r="1" fill="rgba(65,35,16,1)"/>
+ <circle cx="71" cy="22" r="1" fill="rgba(63,32,15,1)"/>
+ <circle cx="72" cy="22" r="1" fill="rgba(62,33,16,1)"/>
+ <circle cx="73" cy="22" r="1" fill="rgba(63,36,18,1)"/>
+ <circle cx="74" cy="22" r="1" fill="rgba(68,42,24,1)"/>
+ <circle cx="75" cy="22" r="1" fill="rgba(70,44,27,1)"/>
+ <circle cx="76" cy="22" r="1" fill="rgba(67,39,21,1)"/>
+ <circle cx="77" cy="22" r="1" fill="rgba(53,27,12,1)"/>
+ <circle cx="78" cy="22" r="1" fill="rgba(10,3,0,0.835294)"/>
+ <circle cx="79" cy="22" r="1" fill="rgba(0,0,0,0.219608)"/>
+ <circle cx="80" cy="22" r="1" fill="rgba(76,44,22,0.0156863)"/>
+ <circle cx="81" cy="22" r="1" fill="rgba(111,82,57,0.0117647)"/>
+ <circle cx="82" cy="22" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="83" cy="22" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="84" cy="22" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="22" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="22" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="22" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="22" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="22" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="22" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="22" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="22" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="22" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="22" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="22" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="22" r="1" fill="rgba(90,57,33,0)"/>
+ <circle cx="97" cy="22" r="1" fill="rgba(94,62,37,0)"/>
+ <circle cx="98" cy="22" r="1" fill="rgba(98,66,39,0)"/>
+ <circle cx="99" cy="22" r="1" fill="rgba(97,65,39,0)"/>
+ <circle cx="100" cy="22" r="1" fill="rgba(95,63,37,0)"/>
+ <circle cx="101" cy="22" r="1" fill="rgba(95,63,37,0)"/>
+ <circle cx="102" cy="22" r="1" fill="rgba(95,63,37,0)"/>
+ <circle cx="103" cy="22" r="1" fill="rgba(95,63,37,0.0862745)"/>
+ <circle cx="104" cy="22" r="1" fill="rgba(93,60,34,0.894118)"/>
+ <circle cx="105" cy="22" r="1" fill="rgba(88,56,31,1)"/>
+ <circle cx="106" cy="22" r="1" fill="rgba(87,54,30,1)"/>
+ <circle cx="107" cy="22" r="1" fill="rgba(55,29,13,0.764706)"/>
+ <circle cx="108" cy="22" r="1" fill="rgba(15,3,0,0.34902)"/>
+ <circle cx="109" cy="22" r="1" fill="rgba(33,12,4,0.0509804)"/>
+ <circle cx="110" cy="22" r="1" fill="rgba(36,14,5,0)"/>
+ <circle cx="111" cy="22" r="1" fill="rgba(36,14,5,0)"/>
+ <circle cx="112" cy="22" r="1" fill="rgba(36,14,5,0)"/>
+ <circle cx="113" cy="22" r="1" fill="rgba(36,14,5,0)"/>
+ <circle cx="114" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="22" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="23" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="23" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="19" cy="23" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="20" cy="23" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="21" cy="23" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="22" cy="23" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="23" cy="23" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="24" cy="23" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="25" cy="23" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="26" cy="23" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="27" cy="23" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="28" cy="23" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="29" cy="23" r="1" fill="rgba(40,17,6,0)"/>
+ <circle cx="30" cy="23" r="1" fill="rgba(59,32,14,0.419608)"/>
+ <circle cx="31" cy="23" r="1" fill="rgba(94,61,36,1)"/>
+ <circle cx="32" cy="23" r="1" fill="rgba(93,61,35,0.996078)"/>
+ <circle cx="33" cy="23" r="1" fill="rgba(43,19,7,0.47451)"/>
+ <circle cx="34" cy="23" r="1" fill="rgba(73,41,20,0.172549)"/>
+ <circle cx="35" cy="23" r="1" fill="rgba(103,72,45,0.0745098)"/>
+ <circle cx="36" cy="23" r="1" fill="rgba(96,65,39,0)"/>
+ <circle cx="37" cy="23" r="1" fill="rgba(95,63,37,0)"/>
+ <circle cx="38" cy="23" r="1" fill="rgba(85,55,30,0)"/>
+ <circle cx="39" cy="23" r="1" fill="rgba(82,49,26,0)"/>
+ <circle cx="40" cy="23" r="1" fill="rgba(78,46,24,0)"/>
+ <circle cx="41" cy="23" r="1" fill="rgba(75,42,22,0)"/>
+ <circle cx="42" cy="23" r="1" fill="rgba(65,35,16,0)"/>
+ <circle cx="43" cy="23" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="44" cy="23" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="23" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="23" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="47" cy="23" r="1" fill="rgba(61,30,13,0.027451)"/>
+ <circle cx="48" cy="23" r="1" fill="rgba(61,30,13,0.592157)"/>
+ <circle cx="49" cy="23" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="50" cy="23" r="1" fill="rgba(61,30,13,0.992157)"/>
+ <circle cx="51" cy="23" r="1" fill="rgba(50,22,9,1)"/>
+ <circle cx="52" cy="23" r="1" fill="rgba(29,11,3,1)"/>
+ <circle cx="53" cy="23" r="1" fill="rgba(19,5,1,1)"/>
+ <circle cx="54" cy="23" r="1" fill="rgba(21,5,1,1)"/>
+ <circle cx="55" cy="23" r="1" fill="rgba(47,21,8,1)"/>
+ <circle cx="56" cy="23" r="1" fill="rgba(110,76,47,1)"/>
+ <circle cx="57" cy="23" r="1" fill="rgba(178,151,123,1)"/>
+ <circle cx="58" cy="23" r="1" fill="rgba(196,174,149,1)"/>
+ <circle cx="59" cy="23" r="1" fill="rgba(161,132,101,1)"/>
+ <circle cx="60" cy="23" r="1" fill="rgba(107,73,45,1)"/>
+ <circle cx="61" cy="23" r="1" fill="rgba(68,37,18,1)"/>
+ <circle cx="62" cy="23" r="1" fill="rgba(53,25,11,1)"/>
+ <circle cx="63" cy="23" r="1" fill="rgba(61,31,14,1)"/>
+ <circle cx="64" cy="23" r="1" fill="rgba(63,33,15,1)"/>
+ <circle cx="65" cy="23" r="1" fill="rgba(63,33,15,1)"/>
+ <circle cx="66" cy="23" r="1" fill="rgba(69,38,18,1)"/>
+ <circle cx="67" cy="23" r="1" fill="rgba(68,39,20,1)"/>
+ <circle cx="68" cy="23" r="1" fill="rgba(68,37,18,1)"/>
+ <circle cx="69" cy="23" r="1" fill="rgba(65,35,18,1)"/>
+ <circle cx="70" cy="23" r="1" fill="rgba(65,37,20,1)"/>
+ <circle cx="71" cy="23" r="1" fill="rgba(67,40,22,1)"/>
+ <circle cx="72" cy="23" r="1" fill="rgba(70,44,26,1)"/>
+ <circle cx="73" cy="23" r="1" fill="rgba(70,45,27,1)"/>
+ <circle cx="74" cy="23" r="1" fill="rgba(63,37,21,1)"/>
+ <circle cx="75" cy="23" r="1" fill="rgba(46,22,9,1)"/>
+ <circle cx="76" cy="23" r="1" fill="rgba(19,6,1,1)"/>
+ <circle cx="77" cy="23" r="1" fill="black"/>
+ <circle cx="78" cy="23" r="1" fill="rgba(33,12,3,1)"/>
+ <circle cx="79" cy="23" r="1" fill="rgba(57,30,14,0.94902)"/>
+ <circle cx="80" cy="23" r="1" fill="rgba(85,63,44,0.792157)"/>
+ <circle cx="81" cy="23" r="1" fill="rgba(98,78,61,0.776471)"/>
+ <circle cx="82" cy="23" r="1" fill="rgba(61,30,13,0.211765)"/>
+ <circle cx="83" cy="23" r="1" fill="rgba(59,28,12,0)"/>
+ <circle cx="84" cy="23" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="85" cy="23" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="23" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="23" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="23" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="23" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="23" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="23" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="23" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="23" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="23" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="23" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="23" r="1" fill="rgba(90,57,33,0)"/>
+ <circle cx="97" cy="23" r="1" fill="rgba(94,62,37,0)"/>
+ <circle cx="98" cy="23" r="1" fill="rgba(98,66,39,0)"/>
+ <circle cx="99" cy="23" r="1" fill="rgba(99,67,41,0)"/>
+ <circle cx="100" cy="23" r="1" fill="rgba(99,67,40,0)"/>
+ <circle cx="101" cy="23" r="1" fill="rgba(99,67,40,0)"/>
+ <circle cx="102" cy="23" r="1" fill="rgba(99,67,40,0)"/>
+ <circle cx="103" cy="23" r="1" fill="rgba(97,65,38,0.54902)"/>
+ <circle cx="104" cy="23" r="1" fill="rgba(93,61,35,1)"/>
+ <circle cx="105" cy="23" r="1" fill="rgba(91,58,33,1)"/>
+ <circle cx="106" cy="23" r="1" fill="rgba(57,30,13,0.717647)"/>
+ <circle cx="107" cy="23" r="1" fill="rgba(0,0,0,0.45098)"/>
+ <circle cx="108" cy="23" r="1" fill="rgba(21,6,1,0.262745)"/>
+ <circle cx="109" cy="23" r="1" fill="rgba(34,13,4,0.00784314)"/>
+ <circle cx="110" cy="23" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="111" cy="23" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="112" cy="23" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="113" cy="23" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="114" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="23" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="24" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="24" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="19" cy="24" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="20" cy="24" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="21" cy="24" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="22" cy="24" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="23" cy="24" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="24" cy="24" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="25" cy="24" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="26" cy="24" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="27" cy="24" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="28" cy="24" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="29" cy="24" r="1" fill="rgba(46,21,8,0)"/>
+ <circle cx="30" cy="24" r="1" fill="rgba(53,26,11,0.160784)"/>
+ <circle cx="31" cy="24" r="1" fill="rgba(87,55,30,0.964706)"/>
+ <circle cx="32" cy="24" r="1" fill="rgba(92,60,34,1)"/>
+ <circle cx="33" cy="24" r="1" fill="rgba(91,58,33,0.945098)"/>
+ <circle cx="34" cy="24" r="1" fill="rgba(95,62,37,0.960784)"/>
+ <circle cx="35" cy="24" r="1" fill="rgba(97,65,38,0.803922)"/>
+ <circle cx="36" cy="24" r="1" fill="rgba(94,62,37,0.0666667)"/>
+ <circle cx="37" cy="24" r="1" fill="rgba(93,61,35,0)"/>
+ <circle cx="38" cy="24" r="1" fill="rgba(84,53,29,0)"/>
+ <circle cx="39" cy="24" r="1" fill="rgba(82,49,26,0)"/>
+ <circle cx="40" cy="24" r="1" fill="rgba(78,46,24,0)"/>
+ <circle cx="41" cy="24" r="1" fill="rgba(75,42,22,0)"/>
+ <circle cx="42" cy="24" r="1" fill="rgba(65,35,16,0)"/>
+ <circle cx="43" cy="24" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="44" cy="24" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="24" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="46" cy="24" r="1" fill="rgba(61,30,13,0.0745098)"/>
+ <circle cx="47" cy="24" r="1" fill="rgba(61,30,13,0.701961)"/>
+ <circle cx="48" cy="24" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="49" cy="24" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="50" cy="24" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="51" cy="24" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="52" cy="24" r="1" fill="rgba(63,32,14,1)"/>
+ <circle cx="53" cy="24" r="1" fill="rgba(55,26,11,1)"/>
+ <circle cx="54" cy="24" r="1" fill="rgba(40,16,6,1)"/>
+ <circle cx="55" cy="24" r="1" fill="rgba(24,8,2,1)"/>
+ <circle cx="56" cy="24" r="1" fill="rgba(7,0,0,1)"/>
+ <circle cx="57" cy="24" r="1" fill="rgba(21,5,1,1)"/>
+ <circle cx="58" cy="24" r="1" fill="rgba(76,44,22,1)"/>
+ <circle cx="59" cy="24" r="1" fill="rgba(137,104,74,1)"/>
+ <circle cx="60" cy="24" r="1" fill="rgba(172,145,116,1)"/>
+ <circle cx="61" cy="24" r="1" fill="rgba(172,145,117,1)"/>
+ <circle cx="62" cy="24" r="1" fill="rgba(152,122,91,1)"/>
+ <circle cx="63" cy="24" r="1" fill="rgba(120,86,56,1)"/>
+ <circle cx="64" cy="24" r="1" fill="rgba(113,79,50,1)"/>
+ <circle cx="65" cy="24" r="1" fill="rgba(109,75,46,1)"/>
+ <circle cx="66" cy="24" r="1" fill="rgba(70,42,22,1)"/>
+ <circle cx="67" cy="24" r="1" fill="rgba(70,44,27,1)"/>
+ <circle cx="68" cy="24" r="1" fill="rgba(71,44,27,1)"/>
+ <circle cx="69" cy="24" r="1" fill="rgba(69,43,26,1)"/>
+ <circle cx="70" cy="24" r="1" fill="rgba(68,42,25,1)"/>
+ <circle cx="71" cy="24" r="1" fill="rgba(61,36,20,1)"/>
+ <circle cx="72" cy="24" r="1" fill="rgba(46,23,11,1)"/>
+ <circle cx="73" cy="24" r="1" fill="rgba(24,10,3,1)"/>
+ <circle cx="74" cy="24" r="1" fill="rgba(7,2,0,1)"/>
+ <circle cx="75" cy="24" r="1" fill="rgba(36,14,4,1)"/>
+ <circle cx="76" cy="24" r="1" fill="rgba(76,45,23,1)"/>
+ <circle cx="77" cy="24" r="1" fill="rgba(99,71,47,1)"/>
+ <circle cx="78" cy="24" r="1" fill="rgba(104,82,62,1)"/>
+ <circle cx="79" cy="24" r="1" fill="rgba(95,79,68,1)"/>
+ <circle cx="80" cy="24" r="1" fill="rgba(85,76,69,1)"/>
+ <circle cx="81" cy="24" r="1" fill="rgba(86,78,72,1)"/>
+ <circle cx="82" cy="24" r="1" fill="rgba(78,59,44,0.92549)"/>
+ <circle cx="83" cy="24" r="1" fill="rgba(61,29,13,0.286275)"/>
+ <circle cx="84" cy="24" r="1" fill="rgba(59,28,12,0)"/>
+ <circle cx="85" cy="24" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="86" cy="24" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="24" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="24" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="24" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="24" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="24" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="24" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="24" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="24" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="24" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="24" r="1" fill="rgba(90,57,33,0)"/>
+ <circle cx="97" cy="24" r="1" fill="rgba(94,62,37,0)"/>
+ <circle cx="98" cy="24" r="1" fill="rgba(98,66,39,0)"/>
+ <circle cx="99" cy="24" r="1" fill="rgba(99,67,41,0)"/>
+ <circle cx="100" cy="24" r="1" fill="rgba(100,67,41,0)"/>
+ <circle cx="101" cy="24" r="1" fill="rgba(100,67,41,0)"/>
+ <circle cx="102" cy="24" r="1" fill="rgba(99,67,41,0.172549)"/>
+ <circle cx="103" cy="24" r="1" fill="rgba(97,65,38,0.968627)"/>
+ <circle cx="104" cy="24" r="1" fill="rgba(96,63,37,1)"/>
+ <circle cx="105" cy="24" r="1" fill="rgba(63,34,16,0.705882)"/>
+ <circle cx="106" cy="24" r="1" fill="rgba(0,0,0,0.431373)"/>
+ <circle cx="107" cy="24" r="1" fill="rgba(4,0,0,0.435294)"/>
+ <circle cx="108" cy="24" r="1" fill="rgba(31,12,3,0.172549)"/>
+ <circle cx="109" cy="24" r="1" fill="rgba(36,15,5,0)"/>
+ <circle cx="110" cy="24" r="1" fill="rgba(34,14,4,0)"/>
+ <circle cx="111" cy="24" r="1" fill="rgba(34,14,4,0)"/>
+ <circle cx="112" cy="24" r="1" fill="rgba(34,14,4,0)"/>
+ <circle cx="113" cy="24" r="1" fill="rgba(34,14,4,0)"/>
+ <circle cx="114" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="24" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="25" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="25" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="19" cy="25" r="1" fill="rgba(49,23,9,0)"/>
+ <circle cx="20" cy="25" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="21" cy="25" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="22" cy="25" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="23" cy="25" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="24" cy="25" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="25" cy="25" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="26" cy="25" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="27" cy="25" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="28" cy="25" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="29" cy="25" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="30" cy="25" r="1" fill="rgba(47,22,9,0.00784314)"/>
+ <circle cx="31" cy="25" r="1" fill="rgba(82,49,27,0.729412)"/>
+ <circle cx="32" cy="25" r="1" fill="rgba(90,57,33,1)"/>
+ <circle cx="33" cy="25" r="1" fill="rgba(92,59,34,1)"/>
+ <circle cx="34" cy="25" r="1" fill="rgba(92,60,34,1)"/>
+ <circle cx="35" cy="25" r="1" fill="rgba(93,61,35,1)"/>
+ <circle cx="36" cy="25" r="1" fill="rgba(93,61,35,0.67451)"/>
+ <circle cx="37" cy="25" r="1" fill="rgba(91,59,33,0)"/>
+ <circle cx="38" cy="25" r="1" fill="rgba(84,53,29,0)"/>
+ <circle cx="39" cy="25" r="1" fill="rgba(82,49,26,0)"/>
+ <circle cx="40" cy="25" r="1" fill="rgba(78,46,24,0)"/>
+ <circle cx="41" cy="25" r="1" fill="rgba(75,42,22,0)"/>
+ <circle cx="42" cy="25" r="1" fill="rgba(65,35,16,0)"/>
+ <circle cx="43" cy="25" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="44" cy="25" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="45" cy="25" r="1" fill="rgba(61,30,13,0.12549)"/>
+ <circle cx="46" cy="25" r="1" fill="rgba(61,30,13,0.792157)"/>
+ <circle cx="47" cy="25" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="48" cy="25" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="49" cy="25" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="50" cy="25" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="51" cy="25" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="52" cy="25" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="53" cy="25" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="54" cy="25" r="1" fill="rgba(63,32,14,1)"/>
+ <circle cx="55" cy="25" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="56" cy="25" r="1" fill="rgba(53,24,10,1)"/>
+ <circle cx="57" cy="25" r="1" fill="rgba(36,14,5,1)"/>
+ <circle cx="58" cy="25" r="1" fill="rgba(19,4,1,1)"/>
+ <circle cx="59" cy="25" r="1" fill="black"/>
+ <circle cx="60" cy="25" r="1" fill="rgba(10,1,0,1)"/>
+ <circle cx="61" cy="25" r="1" fill="rgba(54,28,11,1)"/>
+ <circle cx="62" cy="25" r="1" fill="rgba(91,58,33,1)"/>
+ <circle cx="63" cy="25" r="1" fill="rgba(116,83,53,1)"/>
+ <circle cx="64" cy="25" r="1" fill="rgba(142,110,79,1)"/>
+ <circle cx="65" cy="25" r="1" fill="rgba(137,104,75,1)"/>
+ <circle cx="66" cy="25" r="1" fill="rgba(70,43,25,1)"/>
+ <circle cx="67" cy="25" r="1" fill="rgba(62,40,24,1)"/>
+ <circle cx="68" cy="25" r="1" fill="rgba(53,30,16,1)"/>
+ <circle cx="69" cy="25" r="1" fill="rgba(37,18,8,1)"/>
+ <circle cx="70" cy="25" r="1" fill="rgba(21,7,2,1)"/>
+ <circle cx="71" cy="25" r="1" fill="rgba(19,6,1,1)"/>
+ <circle cx="72" cy="25" r="1" fill="rgba(39,17,6,1)"/>
+ <circle cx="73" cy="25" r="1" fill="rgba(78,49,25,1)"/>
+ <circle cx="74" cy="25" r="1" fill="rgba(121,91,64,1)"/>
+ <circle cx="75" cy="25" r="1" fill="rgba(125,99,77,1)"/>
+ <circle cx="76" cy="25" r="1" fill="rgba(110,90,73,1)"/>
+ <circle cx="77" cy="25" r="1" fill="rgba(85,71,59,1)"/>
+ <circle cx="78" cy="25" r="1" fill="rgba(76,65,55,1)"/>
+ <circle cx="79" cy="25" r="1" fill="rgba(78,68,57,1)"/>
+ <circle cx="80" cy="25" r="1" fill="rgba(83,72,63,1)"/>
+ <circle cx="81" cy="25" r="1" fill="rgba(86,76,67,1)"/>
+ <circle cx="82" cy="25" r="1" fill="rgba(91,82,76,1)"/>
+ <circle cx="83" cy="25" r="1" fill="rgba(82,65,52,0.968627)"/>
+ <circle cx="84" cy="25" r="1" fill="rgba(63,32,16,0.360784)"/>
+ <circle cx="85" cy="25" r="1" fill="rgba(59,28,11,0)"/>
+ <circle cx="86" cy="25" r="1" fill="rgba(61,31,14,0)"/>
+ <circle cx="87" cy="25" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="25" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="25" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="25" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="25" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="25" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="25" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="25" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="25" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="25" r="1" fill="rgba(90,57,33,0)"/>
+ <circle cx="97" cy="25" r="1" fill="rgba(94,62,37,0)"/>
+ <circle cx="98" cy="25" r="1" fill="rgba(98,66,39,0)"/>
+ <circle cx="99" cy="25" r="1" fill="rgba(98,66,40,0)"/>
+ <circle cx="100" cy="25" r="1" fill="rgba(99,66,40,0)"/>
+ <circle cx="101" cy="25" r="1" fill="rgba(100,67,41,0)"/>
+ <circle cx="102" cy="25" r="1" fill="rgba(99,67,41,0.686275)"/>
+ <circle cx="103" cy="25" r="1" fill="rgba(97,65,38,1)"/>
+ <circle cx="104" cy="25" r="1" fill="rgba(83,52,28,0.866667)"/>
+ <circle cx="105" cy="25" r="1" fill="rgba(12,4,0,0.447059)"/>
+ <circle cx="106" cy="25" r="1" fill="rgba(0,0,0,0.462745)"/>
+ <circle cx="107" cy="25" r="1" fill="rgba(17,5,1,0.372549)"/>
+ <circle cx="108" cy="25" r="1" fill="rgba(40,18,6,0.0705882)"/>
+ <circle cx="109" cy="25" r="1" fill="rgba(43,20,7,0)"/>
+ <circle cx="110" cy="25" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="111" cy="25" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="112" cy="25" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="113" cy="25" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="114" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="25" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="26" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="26" r="1" fill="rgba(62,34,16,0)"/>
+ <circle cx="19" cy="26" r="1" fill="rgba(43,20,8,0)"/>
+ <circle cx="20" cy="26" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="21" cy="26" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="22" cy="26" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="23" cy="26" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="24" cy="26" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="25" cy="26" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="26" cy="26" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="27" cy="26" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="28" cy="26" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="29" cy="26" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="30" cy="26" r="1" fill="rgba(47,23,9,0)"/>
+ <circle cx="31" cy="26" r="1" fill="rgba(64,35,16,0.243137)"/>
+ <circle cx="32" cy="26" r="1" fill="rgba(84,51,28,0.913725)"/>
+ <circle cx="33" cy="26" r="1" fill="rgba(88,56,32,1)"/>
+ <circle cx="34" cy="26" r="1" fill="rgba(90,58,33,1)"/>
+ <circle cx="35" cy="26" r="1" fill="rgba(88,56,32,1)"/>
+ <circle cx="36" cy="26" r="1" fill="rgba(88,57,32,1)"/>
+ <circle cx="37" cy="26" r="1" fill="rgba(87,55,30,0.552941)"/>
+ <circle cx="38" cy="26" r="1" fill="rgba(84,52,28,0.105882)"/>
+ <circle cx="39" cy="26" r="1" fill="rgba(82,49,26,0)"/>
+ <circle cx="40" cy="26" r="1" fill="rgba(78,46,24,0)"/>
+ <circle cx="41" cy="26" r="1" fill="rgba(75,42,22,0)"/>
+ <circle cx="42" cy="26" r="1" fill="rgba(65,35,16,0)"/>
+ <circle cx="43" cy="26" r="1" fill="rgba(59,29,13,0)"/>
+ <circle cx="44" cy="26" r="1" fill="rgba(61,30,13,0.192157)"/>
+ <circle cx="45" cy="26" r="1" fill="rgba(61,30,13,0.858824)"/>
+ <circle cx="46" cy="26" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="47" cy="26" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="48" cy="26" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="49" cy="26" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="50" cy="26" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="51" cy="26" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="52" cy="26" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="53" cy="26" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="54" cy="26" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="55" cy="26" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="56" cy="26" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="57" cy="26" r="1" fill="rgba(63,32,14,1)"/>
+ <circle cx="58" cy="26" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="59" cy="26" r="1" fill="rgba(54,25,10,1)"/>
+ <circle cx="60" cy="26" r="1" fill="rgba(39,16,6,1)"/>
+ <circle cx="61" cy="26" r="1" fill="rgba(24,8,2,1)"/>
+ <circle cx="62" cy="26" r="1" fill="rgba(7,0,0,1)"/>
+ <circle cx="63" cy="26" r="1" fill="black"/>
+ <circle cx="64" cy="26" r="1" fill="black"/>
+ <circle cx="65" cy="26" r="1" fill="black"/>
+ <circle cx="66" cy="26" r="1" fill="rgba(12,4,1,1)"/>
+ <circle cx="67" cy="26" r="1" fill="rgba(17,7,3,1)"/>
+ <circle cx="68" cy="26" r="1" fill="rgba(17,6,1,1)"/>
+ <circle cx="69" cy="26" r="1" fill="rgba(19,8,3,1)"/>
+ <circle cx="70" cy="26" r="1" fill="rgba(49,26,12,1)"/>
+ <circle cx="71" cy="26" r="1" fill="rgba(83,56,34,1)"/>
+ <circle cx="72" cy="26" r="1" fill="rgba(105,79,56,1)"/>
+ <circle cx="73" cy="26" r="1" fill="rgba(98,76,56,1)"/>
+ <circle cx="74" cy="26" r="1" fill="rgba(82,64,48,1)"/>
+ <circle cx="75" cy="26" r="1" fill="rgba(63,50,38,1)"/>
+ <circle cx="76" cy="26" r="1" fill="rgba(63,50,40,1)"/>
+ <circle cx="77" cy="26" r="1" fill="rgba(70,57,46,1)"/>
+ <circle cx="78" cy="26" r="1" fill="rgba(74,62,50,1)"/>
+ <circle cx="79" cy="26" r="1" fill="rgba(78,66,56,1)"/>
+ <circle cx="80" cy="26" r="1" fill="rgba(81,70,59,1)"/>
+ <circle cx="81" cy="26" r="1" fill="rgba(83,73,64,1)"/>
+ <circle cx="82" cy="26" r="1" fill="rgba(87,77,69,1)"/>
+ <circle cx="83" cy="26" r="1" fill="rgba(92,84,79,1)"/>
+ <circle cx="84" cy="26" r="1" fill="rgba(86,72,62,1)"/>
+ <circle cx="85" cy="26" r="1" fill="rgba(64,36,19,0.454902)"/>
+ <circle cx="86" cy="26" r="1" fill="rgba(59,28,11,0)"/>
+ <circle cx="87" cy="26" r="1" fill="rgba(62,33,16,0)"/>
+ <circle cx="88" cy="26" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="26" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="26" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="26" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="26" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="26" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="26" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="26" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="26" r="1" fill="rgba(90,57,33,0)"/>
+ <circle cx="97" cy="26" r="1" fill="rgba(94,62,37,0)"/>
+ <circle cx="98" cy="26" r="1" fill="rgba(98,66,39,0)"/>
+ <circle cx="99" cy="26" r="1" fill="rgba(98,66,40,0)"/>
+ <circle cx="100" cy="26" r="1" fill="rgba(97,64,38,0)"/>
+ <circle cx="101" cy="26" r="1" fill="rgba(98,66,39,0.282353)"/>
+ <circle cx="102" cy="26" r="1" fill="rgba(98,65,39,0.996078)"/>
+ <circle cx="103" cy="26" r="1" fill="rgba(97,64,38,1)"/>
+ <circle cx="104" cy="26" r="1" fill="rgba(51,26,11,0.6)"/>
+ <circle cx="105" cy="26" r="1" fill="rgba(0,0,0,0.435294)"/>
+ <circle cx="106" cy="26" r="1" fill="rgba(7,0,0,0.454902)"/>
+ <circle cx="107" cy="26" r="1" fill="rgba(28,10,3,0.223529)"/>
+ <circle cx="108" cy="26" r="1" fill="rgba(40,18,7,0.00784314)"/>
+ <circle cx="109" cy="26" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="110" cy="26" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="111" cy="26" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="112" cy="26" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="113" cy="26" r="1" fill="rgba(40,18,7,0)"/>
+ <circle cx="114" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="26" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="27" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="27" r="1" fill="rgba(100,69,42,0)"/>
+ <circle cx="19" cy="27" r="1" fill="rgba(63,36,17,0)"/>
+ <circle cx="20" cy="27" r="1" fill="rgba(40,18,7,0)"/>
+ <circle cx="21" cy="27" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="22" cy="27" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="23" cy="27" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="24" cy="27" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="25" cy="27" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="26" cy="27" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="27" cy="27" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="28" cy="27" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="29" cy="27" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="30" cy="27" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="31" cy="27" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="32" cy="27" r="1" fill="rgba(43,20,7,0.278431)"/>
+ <circle cx="33" cy="27" r="1" fill="rgba(45,21,8,0.639216)"/>
+ <circle cx="34" cy="27" r="1" fill="rgba(68,38,19,0.780392)"/>
+ <circle cx="35" cy="27" r="1" fill="rgba(85,52,29,0.941176)"/>
+ <circle cx="36" cy="27" r="1" fill="rgba(85,52,29,1)"/>
+ <circle cx="37" cy="27" r="1" fill="rgba(84,52,28,1)"/>
+ <circle cx="38" cy="27" r="1" fill="rgba(83,50,27,0.929412)"/>
+ <circle cx="39" cy="27" r="1" fill="rgba(82,49,26,0.615686)"/>
+ <circle cx="40" cy="27" r="1" fill="rgba(78,46,24,0.254902)"/>
+ <circle cx="41" cy="27" r="1" fill="rgba(75,42,22,0.0117647)"/>
+ <circle cx="42" cy="27" r="1" fill="rgba(65,35,16,0)"/>
+ <circle cx="43" cy="27" r="1" fill="rgba(51,21,7,0.286275)"/>
+ <circle cx="44" cy="27" r="1" fill="rgba(55,24,9,0.92549)"/>
+ <circle cx="45" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="46" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="47" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="48" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="49" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="50" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="51" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="52" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="53" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="54" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="55" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="56" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="57" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="58" cy="27" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="59" cy="27" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="60" cy="27" r="1" fill="rgba(63,32,14,1)"/>
+ <circle cx="61" cy="27" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="62" cy="27" r="1" fill="rgba(59,29,13,1)"/>
+ <circle cx="63" cy="27" r="1" fill="rgba(55,26,11,1)"/>
+ <circle cx="64" cy="27" r="1" fill="rgba(51,23,9,1)"/>
+ <circle cx="65" cy="27" r="1" fill="rgba(49,22,9,1)"/>
+ <circle cx="66" cy="27" r="1" fill="rgba(51,24,9,1)"/>
+ <circle cx="67" cy="27" r="1" fill="rgba(39,20,9,1)"/>
+ <circle cx="68" cy="27" r="1" fill="rgba(36,22,12,1)"/>
+ <circle cx="69" cy="27" r="1" fill="rgba(43,27,16,1)"/>
+ <circle cx="70" cy="27" r="1" fill="rgba(53,36,22,1)"/>
+ <circle cx="71" cy="27" r="1" fill="rgba(53,38,25,1)"/>
+ <circle cx="72" cy="27" r="1" fill="rgba(45,33,22,1)"/>
+ <circle cx="73" cy="27" r="1" fill="rgba(50,38,26,1)"/>
+ <circle cx="74" cy="27" r="1" fill="rgba(57,43,31,1)"/>
+ <circle cx="75" cy="27" r="1" fill="rgba(62,48,36,1)"/>
+ <circle cx="76" cy="27" r="1" fill="rgba(67,53,41,1)"/>
+ <circle cx="77" cy="27" r="1" fill="rgba(69,56,43,1)"/>
+ <circle cx="78" cy="27" r="1" fill="rgba(73,59,48,1)"/>
+ <circle cx="79" cy="27" r="1" fill="rgba(75,64,53,1)"/>
+ <circle cx="80" cy="27" r="1" fill="rgba(80,67,56,1)"/>
+ <circle cx="81" cy="27" r="1" fill="rgba(82,70,62,1)"/>
+ <circle cx="82" cy="27" r="1" fill="rgba(85,75,65,1)"/>
+ <circle cx="83" cy="27" r="1" fill="rgba(87,78,71,1)"/>
+ <circle cx="84" cy="27" r="1" fill="rgba(93,84,80,1)"/>
+ <circle cx="85" cy="27" r="1" fill="rgba(90,78,70,1)"/>
+ <circle cx="86" cy="27" r="1" fill="rgba(68,41,24,0.52549)"/>
+ <circle cx="87" cy="27" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="88" cy="27" r="1" fill="rgba(61,29,13,0)"/>
+ <circle cx="89" cy="27" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="27" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="27" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="27" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="27" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="27" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="27" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="27" r="1" fill="rgba(90,57,33,0)"/>
+ <circle cx="97" cy="27" r="1" fill="rgba(95,62,37,0)"/>
+ <circle cx="98" cy="27" r="1" fill="rgba(98,66,39,0.443137)"/>
+ <circle cx="99" cy="27" r="1" fill="rgba(98,66,40,0.415686)"/>
+ <circle cx="100" cy="27" r="1" fill="rgba(96,64,38,0.113725)"/>
+ <circle cx="101" cy="27" r="1" fill="rgba(96,63,38,0.792157)"/>
+ <circle cx="102" cy="27" r="1" fill="rgba(96,63,37,1)"/>
+ <circle cx="103" cy="27" r="1" fill="rgba(84,52,29,0.843137)"/>
+ <circle cx="104" cy="27" r="1" fill="rgba(15,4,0,0.427451)"/>
+ <circle cx="105" cy="27" r="1" fill="rgba(0,0,0,0.458824)"/>
+ <circle cx="106" cy="27" r="1" fill="rgba(22,8,2,0.301961)"/>
+ <circle cx="107" cy="27" r="1" fill="rgba(34,13,4,0.0509804)"/>
+ <circle cx="108" cy="27" r="1" fill="rgba(36,15,5,0)"/>
+ <circle cx="109" cy="27" r="1" fill="rgba(36,15,5,0)"/>
+ <circle cx="110" cy="27" r="1" fill="rgba(36,15,5,0)"/>
+ <circle cx="111" cy="27" r="1" fill="rgba(36,15,5,0)"/>
+ <circle cx="112" cy="27" r="1" fill="rgba(36,15,5,0)"/>
+ <circle cx="113" cy="27" r="1" fill="rgba(37,16,6,0)"/>
+ <circle cx="114" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="27" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="28" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="28" r="1" fill="rgba(113,82,54,0)"/>
+ <circle cx="19" cy="28" r="1" fill="rgba(112,81,54,0)"/>
+ <circle cx="20" cy="28" r="1" fill="rgba(65,38,18,0)"/>
+ <circle cx="21" cy="28" r="1" fill="rgba(37,16,5,0)"/>
+ <circle cx="22" cy="28" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="23" cy="28" r="1" fill="rgba(45,22,8,0)"/>
+ <circle cx="24" cy="28" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="25" cy="28" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="26" cy="28" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="27" cy="28" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="28" cy="28" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="29" cy="28" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="30" cy="28" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="31" cy="28" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="32" cy="28" r="1" fill="rgba(37,17,6,0.145098)"/>
+ <circle cx="33" cy="28" r="1" fill="rgba(0,0,0,0.407843)"/>
+ <circle cx="34" cy="28" r="1" fill="rgba(10,2,0,0.388235)"/>
+ <circle cx="35" cy="28" r="1" fill="rgba(55,30,13,0.247059)"/>
+ <circle cx="36" cy="28" r="1" fill="rgba(82,49,27,0.498039)"/>
+ <circle cx="37" cy="28" r="1" fill="rgba(82,50,27,0.898039)"/>
+ <circle cx="38" cy="28" r="1" fill="rgba(80,47,25,1)"/>
+ <circle cx="39" cy="28" r="1" fill="rgba(77,45,23,1)"/>
+ <circle cx="40" cy="28" r="1" fill="rgba(76,44,22,0.996078)"/>
+ <circle cx="41" cy="28" r="1" fill="rgba(73,41,20,0.772549)"/>
+ <circle cx="42" cy="28" r="1" fill="rgba(64,33,15,0.568627)"/>
+ <circle cx="43" cy="28" r="1" fill="rgba(104,85,73,0.964706)"/>
+ <circle cx="44" cy="28" r="1" fill="rgba(102,81,66,1)"/>
+ <circle cx="45" cy="28" r="1" fill="rgba(57,26,10,1)"/>
+ <circle cx="46" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="47" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="48" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="49" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="50" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="51" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="52" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="53" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="54" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="55" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="56" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="57" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="58" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="59" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="60" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="61" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="62" cy="28" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="63" cy="28" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="64" cy="28" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="65" cy="28" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="66" cy="28" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="67" cy="28" r="1" fill="rgba(46,23,11,1)"/>
+ <circle cx="68" cy="28" r="1" fill="rgba(33,20,10,1)"/>
+ <circle cx="69" cy="28" r="1" fill="rgba(39,24,13,1)"/>
+ <circle cx="70" cy="28" r="1" fill="rgba(42,27,16,1)"/>
+ <circle cx="71" cy="28" r="1" fill="rgba(45,31,19,1)"/>
+ <circle cx="72" cy="28" r="1" fill="rgba(49,35,23,1)"/>
+ <circle cx="73" cy="28" r="1" fill="rgba(54,39,27,1)"/>
+ <circle cx="74" cy="28" r="1" fill="rgba(57,43,30,1)"/>
+ <circle cx="75" cy="28" r="1" fill="rgba(61,46,33,1)"/>
+ <circle cx="76" cy="28" r="1" fill="rgba(63,50,37,1)"/>
+ <circle cx="77" cy="28" r="1" fill="rgba(68,54,42,1)"/>
+ <circle cx="78" cy="28" r="1" fill="rgba(71,57,46,1)"/>
+ <circle cx="79" cy="28" r="1" fill="rgba(74,61,49,1)"/>
+ <circle cx="80" cy="28" r="1" fill="rgba(77,64,54,1)"/>
+ <circle cx="81" cy="28" r="1" fill="rgba(81,68,58,1)"/>
+ <circle cx="82" cy="28" r="1" fill="rgba(83,72,63,1)"/>
+ <circle cx="83" cy="28" r="1" fill="rgba(86,75,68,1)"/>
+ <circle cx="84" cy="28" r="1" fill="rgba(88,79,72,1)"/>
+ <circle cx="85" cy="28" r="1" fill="rgba(94,85,81,1)"/>
+ <circle cx="86" cy="28" r="1" fill="rgba(93,83,77,1)"/>
+ <circle cx="87" cy="28" r="1" fill="rgba(70,45,29,0.6)"/>
+ <circle cx="88" cy="28" r="1" fill="rgba(58,27,10,0.0235294)"/>
+ <circle cx="89" cy="28" r="1" fill="rgba(63,32,14,0)"/>
+ <circle cx="90" cy="28" r="1" fill="rgba(68,37,18,0)"/>
+ <circle cx="91" cy="28" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="92" cy="28" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="93" cy="28" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="94" cy="28" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="95" cy="28" r="1" fill="rgba(85,53,30,0)"/>
+ <circle cx="96" cy="28" r="1" fill="rgba(90,57,33,0.117647)"/>
+ <circle cx="97" cy="28" r="1" fill="rgba(94,61,36,0.686275)"/>
+ <circle cx="98" cy="28" r="1" fill="rgba(95,62,37,1)"/>
+ <circle cx="99" cy="28" r="1" fill="rgba(95,63,37,1)"/>
+ <circle cx="100" cy="28" r="1" fill="rgba(95,61,36,0.921569)"/>
+ <circle cx="101" cy="28" r="1" fill="rgba(93,60,35,1)"/>
+ <circle cx="102" cy="28" r="1" fill="rgba(94,61,35,0.992157)"/>
+ <circle cx="103" cy="28" r="1" fill="rgba(54,28,12,0.509804)"/>
+ <circle cx="104" cy="28" r="1" fill="rgba(0,0,0,0.435294)"/>
+ <circle cx="105" cy="28" r="1" fill="rgba(19,6,1,0.360784)"/>
+ <circle cx="106" cy="28" r="1" fill="rgba(36,15,5,0.0862745)"/>
+ <circle cx="107" cy="28" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="108" cy="28" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="109" cy="28" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="110" cy="28" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="111" cy="28" r="1" fill="rgba(33,13,4,0)"/>
+ <circle cx="112" cy="28" r="1" fill="rgba(34,14,4,0)"/>
+ <circle cx="113" cy="28" r="1" fill="rgba(53,25,10,0)"/>
+ <circle cx="114" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="28" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="29" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="29" r="1" fill="rgba(110,79,51,0)"/>
+ <circle cx="19" cy="29" r="1" fill="rgba(114,83,55,0)"/>
+ <circle cx="20" cy="29" r="1" fill="rgba(107,77,48,0)"/>
+ <circle cx="21" cy="29" r="1" fill="rgba(75,45,24,0)"/>
+ <circle cx="22" cy="29" r="1" fill="rgba(42,20,7,0)"/>
+ <circle cx="23" cy="29" r="1" fill="rgba(37,17,6,0)"/>
+ <circle cx="24" cy="29" r="1" fill="rgba(40,19,7,0)"/>
+ <circle cx="25" cy="29" r="1" fill="rgba(40,19,7,0)"/>
+ <circle cx="26" cy="29" r="1" fill="rgba(40,19,7,0)"/>
+ <circle cx="27" cy="29" r="1" fill="rgba(40,19,7,0)"/>
+ <circle cx="28" cy="29" r="1" fill="rgba(40,19,7,0)"/>
+ <circle cx="29" cy="29" r="1" fill="rgba(40,19,7,0)"/>
+ <circle cx="30" cy="29" r="1" fill="rgba(40,19,7,0)"/>
+ <circle cx="31" cy="29" r="1" fill="rgba(42,20,7,0)"/>
+ <circle cx="32" cy="29" r="1" fill="rgba(36,16,5,0.0862745)"/>
+ <circle cx="33" cy="29" r="1" fill="rgba(12,3,0,0.392157)"/>
+ <circle cx="34" cy="29" r="1" fill="rgba(4,0,0,0.462745)"/>
+ <circle cx="35" cy="29" r="1" fill="rgba(36,15,5,0.176471)"/>
+ <circle cx="36" cy="29" r="1" fill="rgba(55,27,11,0)"/>
+ <circle cx="37" cy="29" r="1" fill="rgba(64,35,16,0.0901961)"/>
+ <circle cx="38" cy="29" r="1" fill="rgba(69,38,19,0.513725)"/>
+ <circle cx="39" cy="29" r="1" fill="rgba(74,42,21,0.94902)"/>
+ <circle cx="40" cy="29" r="1" fill="rgba(71,40,20,1)"/>
+ <circle cx="41" cy="29" r="1" fill="rgba(62,31,13,1)"/>
+ <circle cx="42" cy="29" r="1" fill="rgba(94,70,52,1)"/>
+ <circle cx="43" cy="29" r="1" fill="rgba(214,227,254,1)"/>
+ <circle cx="44" cy="29" r="1" fill="rgba(164,164,175,1)"/>
+ <circle cx="45" cy="29" r="1" fill="rgba(62,33,16,1)"/>
+ <circle cx="46" cy="29" r="1" fill="rgba(58,27,11,1)"/>
+ <circle cx="47" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="48" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="49" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="50" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="51" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="52" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="53" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="54" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="55" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="56" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="57" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="58" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="59" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="60" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="61" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="62" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="63" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="64" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="65" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="29" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="67" cy="29" r="1" fill="rgba(46,23,10,1)"/>
+ <circle cx="68" cy="29" r="1" fill="rgba(29,17,9,1)"/>
+ <circle cx="69" cy="29" r="1" fill="rgba(36,22,11,1)"/>
+ <circle cx="70" cy="29" r="1" fill="rgba(40,26,15,1)"/>
+ <circle cx="71" cy="29" r="1" fill="rgba(45,29,17,1)"/>
+ <circle cx="72" cy="29" r="1" fill="rgba(47,33,21,1)"/>
+ <circle cx="73" cy="29" r="1" fill="rgba(51,37,24,1)"/>
+ <circle cx="74" cy="29" r="1" fill="rgba(55,40,27,1)"/>
+ <circle cx="75" cy="29" r="1" fill="rgba(58,43,31,1)"/>
+ <circle cx="76" cy="29" r="1" fill="rgba(62,48,34,1)"/>
+ <circle cx="77" cy="29" r="1" fill="rgba(64,51,39,1)"/>
+ <circle cx="78" cy="29" r="1" fill="rgba(69,55,42,1)"/>
+ <circle cx="79" cy="29" r="1" fill="rgba(71,59,47,1)"/>
+ <circle cx="80" cy="29" r="1" fill="rgba(74,62,51,1)"/>
+ <circle cx="81" cy="29" r="1" fill="rgba(78,66,56,1)"/>
+ <circle cx="82" cy="29" r="1" fill="rgba(82,69,60,1)"/>
+ <circle cx="83" cy="29" r="1" fill="rgba(84,73,64,1)"/>
+ <circle cx="84" cy="29" r="1" fill="rgba(86,77,69,1)"/>
+ <circle cx="85" cy="29" r="1" fill="rgba(90,80,74,1)"/>
+ <circle cx="86" cy="29" r="1" fill="rgba(94,87,82,1)"/>
+ <circle cx="87" cy="29" r="1" fill="rgba(95,85,80,1)"/>
+ <circle cx="88" cy="29" r="1" fill="rgba(69,44,27,0.623529)"/>
+ <circle cx="89" cy="29" r="1" fill="rgba(62,30,13,0.0509804)"/>
+ <circle cx="90" cy="29" r="1" fill="rgba(68,37,18,0.0588235)"/>
+ <circle cx="91" cy="29" r="1" fill="rgba(73,41,20,0.168627)"/>
+ <circle cx="92" cy="29" r="1" fill="rgba(76,44,22,0.258824)"/>
+ <circle cx="93" cy="29" r="1" fill="rgba(80,47,25,0.345098)"/>
+ <circle cx="94" cy="29" r="1" fill="rgba(82,50,27,0.45098)"/>
+ <circle cx="95" cy="29" r="1" fill="rgba(85,53,30,0.529412)"/>
+ <circle cx="96" cy="29" r="1" fill="rgba(88,56,31,0.87451)"/>
+ <circle cx="97" cy="29" r="1" fill="rgba(90,57,32,1)"/>
+ <circle cx="98" cy="29" r="1" fill="rgba(91,58,33,1)"/>
+ <circle cx="99" cy="29" r="1" fill="rgba(91,58,33,1)"/>
+ <circle cx="100" cy="29" r="1" fill="rgba(91,57,33,1)"/>
+ <circle cx="101" cy="29" r="1" fill="rgba(91,58,33,1)"/>
+ <circle cx="102" cy="29" r="1" fill="rgba(81,49,26,0.72549)"/>
+ <circle cx="103" cy="29" r="1" fill="rgba(21,7,1,0.364706)"/>
+ <circle cx="104" cy="29" r="1" fill="rgba(4,1,0,0.454902)"/>
+ <circle cx="105" cy="29" r="1" fill="rgba(37,17,6,0.207843)"/>
+ <circle cx="106" cy="29" r="1" fill="rgba(43,20,7,0)"/>
+ <circle cx="107" cy="29" r="1" fill="rgba(39,17,6,0)"/>
+ <circle cx="108" cy="29" r="1" fill="rgba(39,17,6,0)"/>
+ <circle cx="109" cy="29" r="1" fill="rgba(39,17,6,0)"/>
+ <circle cx="110" cy="29" r="1" fill="rgba(39,17,6,0)"/>
+ <circle cx="111" cy="29" r="1" fill="rgba(40,18,6,0)"/>
+ <circle cx="112" cy="29" r="1" fill="rgba(54,25,10,0)"/>
+ <circle cx="113" cy="29" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="114" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="29" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="30" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="30" r="1" fill="rgba(110,79,51,0)"/>
+ <circle cx="19" cy="30" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="20" cy="30" r="1" fill="rgba(109,78,50,0)"/>
+ <circle cx="21" cy="30" r="1" fill="rgba(108,76,48,0)"/>
+ <circle cx="22" cy="30" r="1" fill="rgba(82,52,27,0)"/>
+ <circle cx="23" cy="30" r="1" fill="rgba(40,18,7,0)"/>
+ <circle cx="24" cy="30" r="1" fill="rgba(36,16,5,0)"/>
+ <circle cx="25" cy="30" r="1" fill="rgba(37,18,6,0)"/>
+ <circle cx="26" cy="30" r="1" fill="rgba(37,18,6,0)"/>
+ <circle cx="27" cy="30" r="1" fill="rgba(37,18,6,0)"/>
+ <circle cx="28" cy="30" r="1" fill="rgba(37,18,6,0)"/>
+ <circle cx="29" cy="30" r="1" fill="rgba(37,18,6,0)"/>
+ <circle cx="30" cy="30" r="1" fill="rgba(37,18,6,0)"/>
+ <circle cx="31" cy="30" r="1" fill="rgba(39,18,6,0)"/>
+ <circle cx="32" cy="30" r="1" fill="rgba(37,17,6,0.0509804)"/>
+ <circle cx="33" cy="30" r="1" fill="rgba(21,8,1,0.345098)"/>
+ <circle cx="34" cy="30" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="35" cy="30" r="1" fill="rgba(26,10,3,0.301961)"/>
+ <circle cx="36" cy="30" r="1" fill="rgba(34,12,3,0.0980392)"/>
+ <circle cx="37" cy="30" r="1" fill="rgba(39,17,6,0.0823529)"/>
+ <circle cx="38" cy="30" r="1" fill="rgba(51,27,11,0)"/>
+ <circle cx="39" cy="30" r="1" fill="rgba(65,36,17,0.192157)"/>
+ <circle cx="40" cy="30" r="1" fill="rgba(63,35,18,0.784314)"/>
+ <circle cx="41" cy="30" r="1" fill="rgba(55,26,10,1)"/>
+ <circle cx="42" cy="30" r="1" fill="rgba(90,65,48,1)"/>
+ <circle cx="43" cy="30" r="1" fill="rgba(229,235,254,1)"/>
+ <circle cx="44" cy="30" r="1" fill="rgba(204,212,236,1)"/>
+ <circle cx="45" cy="30" r="1" fill="rgba(105,87,76,1)"/>
+ <circle cx="46" cy="30" r="1" fill="rgba(57,26,11,1)"/>
+ <circle cx="47" cy="30" r="1" fill="rgba(58,26,10,1)"/>
+ <circle cx="48" cy="30" r="1" fill="rgba(59,28,12,1)"/>
+ <circle cx="49" cy="30" r="1" fill="rgba(61,29,13,1)"/>
+ <circle cx="50" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="51" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="52" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="53" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="54" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="55" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="56" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="57" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="58" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="59" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="60" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="61" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="62" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="63" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="64" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="65" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="30" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="67" cy="30" r="1" fill="rgba(46,23,10,1)"/>
+ <circle cx="68" cy="30" r="1" fill="rgba(29,15,8,1)"/>
+ <circle cx="69" cy="30" r="1" fill="rgba(31,19,10,1)"/>
+ <circle cx="70" cy="30" r="1" fill="rgba(36,23,13,1)"/>
+ <circle cx="71" cy="30" r="1" fill="rgba(42,26,16,1)"/>
+ <circle cx="72" cy="30" r="1" fill="rgba(46,30,19,1)"/>
+ <circle cx="73" cy="30" r="1" fill="rgba(49,34,22,1)"/>
+ <circle cx="74" cy="30" r="1" fill="rgba(51,38,26,1)"/>
+ <circle cx="75" cy="30" r="1" fill="rgba(57,42,29,1)"/>
+ <circle cx="76" cy="30" r="1" fill="rgba(61,45,33,1)"/>
+ <circle cx="77" cy="30" r="1" fill="rgba(63,48,37,1)"/>
+ <circle cx="78" cy="30" r="1" fill="rgba(67,53,40,1)"/>
+ <circle cx="79" cy="30" r="1" fill="rgba(70,56,45,1)"/>
+ <circle cx="80" cy="30" r="1" fill="rgba(73,60,48,1)"/>
+ <circle cx="81" cy="30" r="1" fill="rgba(75,64,53,1)"/>
+ <circle cx="82" cy="30" r="1" fill="rgba(80,67,57,1)"/>
+ <circle cx="83" cy="30" r="1" fill="rgba(82,71,61,1)"/>
+ <circle cx="84" cy="30" r="1" fill="rgba(85,74,67,1)"/>
+ <circle cx="85" cy="30" r="1" fill="rgba(87,78,70,1)"/>
+ <circle cx="86" cy="30" r="1" fill="rgba(91,81,76,1)"/>
+ <circle cx="87" cy="30" r="1" fill="rgba(96,89,86,1)"/>
+ <circle cx="88" cy="30" r="1" fill="rgba(86,72,60,1)"/>
+ <circle cx="89" cy="30" r="1" fill="rgba(63,32,14,0.870588)"/>
+ <circle cx="90" cy="30" r="1" fill="rgba(67,36,16,0.937255)"/>
+ <circle cx="91" cy="30" r="1" fill="rgba(71,40,20,0.972549)"/>
+ <circle cx="92" cy="30" r="1" fill="rgba(74,42,22,1)"/>
+ <circle cx="93" cy="30" r="1" fill="rgba(77,45,23,1)"/>
+ <circle cx="94" cy="30" r="1" fill="rgba(81,48,25,1)"/>
+ <circle cx="95" cy="30" r="1" fill="rgba(83,50,27,1)"/>
+ <circle cx="96" cy="30" r="1" fill="rgba(84,52,28,1)"/>
+ <circle cx="97" cy="30" r="1" fill="rgba(85,53,29,1)"/>
+ <circle cx="98" cy="30" r="1" fill="rgba(87,54,30,1)"/>
+ <circle cx="99" cy="30" r="1" fill="rgba(88,56,31,0.976471)"/>
+ <circle cx="100" cy="30" r="1" fill="rgba(88,55,31,0.968627)"/>
+ <circle cx="101" cy="30" r="1" fill="rgba(86,53,30,0.788235)"/>
+ <circle cx="102" cy="30" r="1" fill="rgba(50,25,10,0.305882)"/>
+ <circle cx="103" cy="30" r="1" fill="rgba(0,0,0,0.439216)"/>
+ <circle cx="104" cy="30" r="1" fill="rgba(17,5,1,0.392157)"/>
+ <circle cx="105" cy="30" r="1" fill="rgba(47,23,9,0.0862745)"/>
+ <circle cx="106" cy="30" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="107" cy="30" r="1" fill="rgba(49,24,10,0)"/>
+ <circle cx="108" cy="30" r="1" fill="rgba(49,24,10,0)"/>
+ <circle cx="109" cy="30" r="1" fill="rgba(49,24,10,0)"/>
+ <circle cx="110" cy="30" r="1" fill="rgba(47,23,10,0)"/>
+ <circle cx="111" cy="30" r="1" fill="rgba(55,27,11,0)"/>
+ <circle cx="112" cy="30" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="113" cy="30" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="114" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="30" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="31" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="31" r="1" fill="rgba(110,79,51,0)"/>
+ <circle cx="19" cy="31" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="20" cy="31" r="1" fill="rgba(108,77,49,0)"/>
+ <circle cx="21" cy="31" r="1" fill="rgba(104,72,44,0)"/>
+ <circle cx="22" cy="31" r="1" fill="rgba(101,69,42,0)"/>
+ <circle cx="23" cy="31" r="1" fill="rgba(92,59,34,0)"/>
+ <circle cx="24" cy="31" r="1" fill="rgba(59,33,14,0)"/>
+ <circle cx="25" cy="31" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="26" cy="31" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="27" cy="31" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="28" cy="31" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="29" cy="31" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="30" cy="31" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="31" cy="31" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="32" cy="31" r="1" fill="rgba(46,22,8,0.0117647)"/>
+ <circle cx="33" cy="31" r="1" fill="rgba(29,11,3,0.262745)"/>
+ <circle cx="34" cy="31" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="35" cy="31" r="1" fill="rgba(7,1,0,0.435294)"/>
+ <circle cx="36" cy="31" r="1" fill="rgba(10,2,0,0.4)"/>
+ <circle cx="37" cy="31" r="1" fill="rgba(15,4,0,0.4)"/>
+ <circle cx="38" cy="31" r="1" fill="rgba(37,17,6,0.223529)"/>
+ <circle cx="39" cy="31" r="1" fill="rgba(45,27,12,0)"/>
+ <circle cx="40" cy="31" r="1" fill="rgba(77,35,14,0.00784314)"/>
+ <circle cx="41" cy="31" r="1" fill="rgba(53,25,10,0.694118)"/>
+ <circle cx="42" cy="31" r="1" fill="rgba(31,13,5,1)"/>
+ <circle cx="43" cy="31" r="1" fill="rgba(160,150,148,1)"/>
+ <circle cx="44" cy="31" r="1" fill="rgba(243,253,254,1)"/>
+ <circle cx="45" cy="31" r="1" fill="rgba(186,189,208,1)"/>
+ <circle cx="46" cy="31" r="1" fill="rgba(114,98,88,1)"/>
+ <circle cx="47" cy="31" r="1" fill="rgba(75,48,30,1)"/>
+ <circle cx="48" cy="31" r="1" fill="rgba(61,32,15,1)"/>
+ <circle cx="49" cy="31" r="1" fill="rgba(55,26,11,1)"/>
+ <circle cx="50" cy="31" r="1" fill="rgba(57,26,11,1)"/>
+ <circle cx="51" cy="31" r="1" fill="rgba(57,26,11,1)"/>
+ <circle cx="52" cy="31" r="1" fill="rgba(58,27,11,1)"/>
+ <circle cx="53" cy="31" r="1" fill="rgba(58,27,11,1)"/>
+ <circle cx="54" cy="31" r="1" fill="rgba(58,28,11,1)"/>
+ <circle cx="55" cy="31" r="1" fill="rgba(59,28,11,1)"/>
+ <circle cx="56" cy="31" r="1" fill="rgba(59,28,12,1)"/>
+ <circle cx="57" cy="31" r="1" fill="rgba(59,29,12,1)"/>
+ <circle cx="58" cy="31" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="59" cy="31" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="60" cy="31" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="61" cy="31" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="62" cy="31" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="63" cy="31" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="64" cy="31" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="65" cy="31" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="31" r="1" fill="rgba(61,29,13,1)"/>
+ <circle cx="67" cy="31" r="1" fill="rgba(46,23,10,1)"/>
+ <circle cx="68" cy="31" r="1" fill="rgba(28,14,6,1)"/>
+ <circle cx="69" cy="31" r="1" fill="rgba(29,16,8,1)"/>
+ <circle cx="70" cy="31" r="1" fill="rgba(34,21,10,1)"/>
+ <circle cx="71" cy="31" r="1" fill="rgba(37,24,14,1)"/>
+ <circle cx="72" cy="31" r="1" fill="rgba(43,28,16,1)"/>
+ <circle cx="73" cy="31" r="1" fill="rgba(46,31,20,1)"/>
+ <circle cx="74" cy="31" r="1" fill="rgba(50,35,23,1)"/>
+ <circle cx="75" cy="31" r="1" fill="rgba(53,39,27,1)"/>
+ <circle cx="76" cy="31" r="1" fill="rgba(58,43,30,1)"/>
+ <circle cx="77" cy="31" r="1" fill="rgba(61,47,33,1)"/>
+ <circle cx="78" cy="31" r="1" fill="rgba(63,50,37,1)"/>
+ <circle cx="79" cy="31" r="1" fill="rgba(68,53,42,1)"/>
+ <circle cx="80" cy="31" r="1" fill="rgba(71,57,46,1)"/>
+ <circle cx="81" cy="31" r="1" fill="rgba(74,61,50,1)"/>
+ <circle cx="82" cy="31" r="1" fill="rgba(76,65,54,1)"/>
+ <circle cx="83" cy="31" r="1" fill="rgba(81,69,58,1)"/>
+ <circle cx="84" cy="31" r="1" fill="rgba(84,72,63,1)"/>
+ <circle cx="85" cy="31" r="1" fill="rgba(86,76,68,1)"/>
+ <circle cx="86" cy="31" r="1" fill="rgba(90,79,73,1)"/>
+ <circle cx="87" cy="31" r="1" fill="rgba(94,87,83,1)"/>
+ <circle cx="88" cy="31" r="1" fill="rgba(84,66,53,1)"/>
+ <circle cx="89" cy="31" r="1" fill="rgba(59,29,13,1)"/>
+ <circle cx="90" cy="31" r="1" fill="rgba(61,32,14,1)"/>
+ <circle cx="91" cy="31" r="1" fill="rgba(65,36,17,1)"/>
+ <circle cx="92" cy="31" r="1" fill="rgba(70,39,19,1)"/>
+ <circle cx="93" cy="31" r="1" fill="rgba(74,42,21,0.984314)"/>
+ <circle cx="94" cy="31" r="1" fill="rgba(76,44,22,0.839216)"/>
+ <circle cx="95" cy="31" r="1" fill="rgba(80,47,24,0.643137)"/>
+ <circle cx="96" cy="31" r="1" fill="rgba(83,51,27,0.486275)"/>
+ <circle cx="97" cy="31" r="1" fill="rgba(85,52,29,0.364706)"/>
+ <circle cx="98" cy="31" r="1" fill="rgba(81,48,26,0.27451)"/>
+ <circle cx="99" cy="31" r="1" fill="rgba(69,39,19,0.180392)"/>
+ <circle cx="100" cy="31" r="1" fill="rgba(70,40,20,0.152941)"/>
+ <circle cx="101" cy="31" r="1" fill="rgba(61,33,15,0.0901961)"/>
+ <circle cx="102" cy="31" r="1" fill="rgba(22,8,2,0.317647)"/>
+ <circle cx="103" cy="31" r="1" fill="rgba(0,0,0,0.482353)"/>
+ <circle cx="104" cy="31" r="1" fill="rgba(28,11,3,0.286275)"/>
+ <circle cx="105" cy="31" r="1" fill="rgba(47,24,9,0.0156863)"/>
+ <circle cx="106" cy="31" r="1" fill="rgba(49,25,10,0)"/>
+ <circle cx="107" cy="31" r="1" fill="rgba(49,25,10,0)"/>
+ <circle cx="108" cy="31" r="1" fill="rgba(49,25,10,0)"/>
+ <circle cx="109" cy="31" r="1" fill="rgba(49,25,10,0)"/>
+ <circle cx="110" cy="31" r="1" fill="rgba(53,27,11,0)"/>
+ <circle cx="111" cy="31" r="1" fill="rgba(62,30,14,0)"/>
+ <circle cx="112" cy="31" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="113" cy="31" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="114" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="31" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="32" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="32" r="1" fill="rgba(110,79,51,0)"/>
+ <circle cx="19" cy="32" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="20" cy="32" r="1" fill="rgba(108,77,49,0)"/>
+ <circle cx="21" cy="32" r="1" fill="rgba(104,72,44,0)"/>
+ <circle cx="22" cy="32" r="1" fill="rgba(99,67,40,0)"/>
+ <circle cx="23" cy="32" r="1" fill="rgba(95,62,37,0)"/>
+ <circle cx="24" cy="32" r="1" fill="rgba(90,56,32,0)"/>
+ <circle cx="25" cy="32" r="1" fill="rgba(57,30,13,0)"/>
+ <circle cx="26" cy="32" r="1" fill="rgba(40,18,6,0)"/>
+ <circle cx="27" cy="32" r="1" fill="rgba(43,20,8,0)"/>
+ <circle cx="28" cy="32" r="1" fill="rgba(43,20,8,0)"/>
+ <circle cx="29" cy="32" r="1" fill="rgba(43,20,8,0)"/>
+ <circle cx="30" cy="32" r="1" fill="rgba(43,20,8,0)"/>
+ <circle cx="31" cy="32" r="1" fill="rgba(43,20,8,0)"/>
+ <circle cx="32" cy="32" r="1" fill="rgba(45,20,8,0)"/>
+ <circle cx="33" cy="32" r="1" fill="rgba(36,16,5,0.168627)"/>
+ <circle cx="34" cy="32" r="1" fill="rgba(10,2,0,0.439216)"/>
+ <circle cx="35" cy="32" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="36" cy="32" r="1" fill="rgba(0,0,0,0.47451)"/>
+ <circle cx="37" cy="32" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="38" cy="32" r="1" fill="rgba(0,0,0,0.384314)"/>
+ <circle cx="39" cy="32" r="1" fill="rgba(106,30,4,0.298039)"/>
+ <circle cx="40" cy="32" r="1" fill="rgba(241,71,0,0.384314)"/>
+ <circle cx="41" cy="32" r="1" fill="rgba(197,60,2,0.372549)"/>
+ <circle cx="42" cy="32" r="1" fill="rgba(19,0,0,0.886275)"/>
+ <circle cx="43" cy="32" r="1" fill="rgba(34,25,16,1)"/>
+ <circle cx="44" cy="32" r="1" fill="rgba(194,190,197,1)"/>
+ <circle cx="45" cy="32" r="1" fill="rgba(254,254,254,1)"/>
+ <circle cx="46" cy="32" r="1" fill="rgba(221,223,236,1)"/>
+ <circle cx="47" cy="32" r="1" fill="rgba(179,174,181,1)"/>
+ <circle cx="48" cy="32" r="1" fill="rgba(140,126,119,1)"/>
+ <circle cx="49" cy="32" r="1" fill="rgba(112,92,79,1)"/>
+ <circle cx="50" cy="32" r="1" fill="rgba(93,69,54,1)"/>
+ <circle cx="51" cy="32" r="1" fill="rgba(83,58,40,1)"/>
+ <circle cx="52" cy="32" r="1" fill="rgba(78,52,33,1)"/>
+ <circle cx="53" cy="32" r="1" fill="rgba(73,45,27,1)"/>
+ <circle cx="54" cy="32" r="1" fill="rgba(73,46,28,1)"/>
+ <circle cx="55" cy="32" r="1" fill="rgba(73,45,26,1)"/>
+ <circle cx="56" cy="32" r="1" fill="rgba(74,46,27,1)"/>
+ <circle cx="57" cy="32" r="1" fill="rgba(70,42,24,1)"/>
+ <circle cx="58" cy="32" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="59" cy="32" r="1" fill="rgba(61,29,13,1)"/>
+ <circle cx="60" cy="32" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="61" cy="32" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="62" cy="32" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="63" cy="32" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="64" cy="32" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="65" cy="32" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="32" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="67" cy="32" r="1" fill="rgba(46,22,9,1)"/>
+ <circle cx="68" cy="32" r="1" fill="rgba(26,13,5,1)"/>
+ <circle cx="69" cy="32" r="1" fill="rgba(26,15,7,1)"/>
+ <circle cx="70" cy="32" r="1" fill="rgba(33,18,9,1)"/>
+ <circle cx="71" cy="32" r="1" fill="rgba(36,22,12,1)"/>
+ <circle cx="72" cy="32" r="1" fill="rgba(40,26,14,1)"/>
+ <circle cx="73" cy="32" r="1" fill="rgba(45,29,18,1)"/>
+ <circle cx="74" cy="32" r="1" fill="rgba(47,33,20,1)"/>
+ <circle cx="75" cy="32" r="1" fill="rgba(51,36,24,1)"/>
+ <circle cx="76" cy="32" r="1" fill="rgba(54,40,28,1)"/>
+ <circle cx="77" cy="32" r="1" fill="rgba(59,44,31,1)"/>
+ <circle cx="78" cy="32" r="1" fill="rgba(62,47,36,1)"/>
+ <circle cx="79" cy="32" r="1" fill="rgba(64,52,38,1)"/>
+ <circle cx="80" cy="32" r="1" fill="rgba(69,55,43,1)"/>
+ <circle cx="81" cy="32" r="1" fill="rgba(71,58,47,1)"/>
+ <circle cx="82" cy="32" r="1" fill="rgba(75,63,51,1)"/>
+ <circle cx="83" cy="32" r="1" fill="rgba(77,66,56,1)"/>
+ <circle cx="84" cy="32" r="1" fill="rgba(82,70,59,1)"/>
+ <circle cx="85" cy="32" r="1" fill="rgba(85,73,65,1)"/>
+ <circle cx="86" cy="32" r="1" fill="rgba(88,78,72,1)"/>
+ <circle cx="87" cy="32" r="1" fill="rgba(91,80,72,1)"/>
+ <circle cx="88" cy="32" r="1" fill="rgba(55,33,18,1)"/>
+ <circle cx="89" cy="32" r="1" fill="rgba(39,13,4,1)"/>
+ <circle cx="90" cy="32" r="1" fill="rgba(64,26,10,0.996078)"/>
+ <circle cx="91" cy="32" r="1" fill="rgba(70,34,15,0.8)"/>
+ <circle cx="92" cy="32" r="1" fill="rgba(58,36,17,0.486275)"/>
+ <circle cx="93" cy="32" r="1" fill="rgba(73,41,21,0.184314)"/>
+ <circle cx="94" cy="32" r="1" fill="rgba(78,45,23,0.0313725)"/>
+ <circle cx="95" cy="32" r="1" fill="rgba(80,47,24,0)"/>
+ <circle cx="96" cy="32" r="1" fill="rgba(68,38,18,0)"/>
+ <circle cx="97" cy="32" r="1" fill="rgba(62,33,15,0)"/>
+ <circle cx="98" cy="32" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="99" cy="32" r="1" fill="rgba(42,20,7,0.0509804)"/>
+ <circle cx="100" cy="32" r="1" fill="rgba(49,24,10,0.0235294)"/>
+ <circle cx="101" cy="32" r="1" fill="rgba(45,21,8,0.12549)"/>
+ <circle cx="102" cy="32" r="1" fill="rgba(10,2,0,0.435294)"/>
+ <circle cx="103" cy="32" r="1" fill="rgba(7,1,0,0.443137)"/>
+ <circle cx="104" cy="32" r="1" fill="rgba(37,17,6,0.164706)"/>
+ <circle cx="105" cy="32" r="1" fill="rgba(46,24,9,0)"/>
+ <circle cx="106" cy="32" r="1" fill="rgba(46,23,9,0)"/>
+ <circle cx="107" cy="32" r="1" fill="rgba(46,23,9,0)"/>
+ <circle cx="108" cy="32" r="1" fill="rgba(46,23,9,0)"/>
+ <circle cx="109" cy="32" r="1" fill="rgba(47,24,9,0)"/>
+ <circle cx="110" cy="32" r="1" fill="rgba(59,30,13,0)"/>
+ <circle cx="111" cy="32" r="1" fill="rgba(63,31,14,0)"/>
+ <circle cx="112" cy="32" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="113" cy="32" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="114" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="32" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="33" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="33" r="1" fill="rgba(110,79,51,0)"/>
+ <circle cx="19" cy="33" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="20" cy="33" r="1" fill="rgba(108,77,49,0)"/>
+ <circle cx="21" cy="33" r="1" fill="rgba(104,72,44,0)"/>
+ <circle cx="22" cy="33" r="1" fill="rgba(99,67,40,0)"/>
+ <circle cx="23" cy="33" r="1" fill="rgba(93,61,36,0)"/>
+ <circle cx="24" cy="33" r="1" fill="rgba(90,57,33,0)"/>
+ <circle cx="25" cy="33" r="1" fill="rgba(84,52,28,0)"/>
+ <circle cx="26" cy="33" r="1" fill="rgba(57,29,13,0)"/>
+ <circle cx="27" cy="33" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="28" cy="33" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="29" cy="33" r="1" fill="rgba(47,23,9,0)"/>
+ <circle cx="30" cy="33" r="1" fill="rgba(47,23,9,0)"/>
+ <circle cx="31" cy="33" r="1" fill="rgba(47,23,9,0)"/>
+ <circle cx="32" cy="33" r="1" fill="rgba(47,23,9,0)"/>
+ <circle cx="33" cy="33" r="1" fill="rgba(46,22,9,0.0470588)"/>
+ <circle cx="34" cy="33" r="1" fill="rgba(28,11,3,0.278431)"/>
+ <circle cx="35" cy="33" r="1" fill="rgba(10,2,0,0.431373)"/>
+ <circle cx="36" cy="33" r="1" fill="rgba(4,0,0,0.462745)"/>
+ <circle cx="37" cy="33" r="1" fill="rgba(0,0,0,0.439216)"/>
+ <circle cx="38" cy="33" r="1" fill="rgba(83,14,0,0.552941)"/>
+ <circle cx="39" cy="33" r="1" fill="rgba(236,69,1,0.933333)"/>
+ <circle cx="40" cy="33" r="1" fill="rgba(252,80,1,1)"/>
+ <circle cx="41" cy="33" r="1" fill="rgba(255,85,0,0.988235)"/>
+ <circle cx="42" cy="33" r="1" fill="rgba(208,65,0,0.972549)"/>
+ <circle cx="43" cy="33" r="1" fill="rgba(75,11,0,1)"/>
+ <circle cx="44" cy="33" r="1" fill="rgba(37,30,22,1)"/>
+ <circle cx="45" cy="33" r="1" fill="rgba(210,210,220,1)"/>
+ <circle cx="46" cy="33" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="47" cy="33" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="48" cy="33" r="1" fill="rgba(242,243,249,1)"/>
+ <circle cx="49" cy="33" r="1" fill="rgba(222,222,228,1)"/>
+ <circle cx="50" cy="33" r="1" fill="rgba(203,197,199,1)"/>
+ <circle cx="51" cy="33" r="1" fill="rgba(183,174,169,1)"/>
+ <circle cx="52" cy="33" r="1" fill="rgba(165,152,145,1)"/>
+ <circle cx="53" cy="33" r="1" fill="rgba(147,130,119,1)"/>
+ <circle cx="54" cy="33" r="1" fill="rgba(131,112,98,1)"/>
+ <circle cx="55" cy="33" r="1" fill="rgba(113,92,77,1)"/>
+ <circle cx="56" cy="33" r="1" fill="rgba(96,73,56,1)"/>
+ <circle cx="57" cy="33" r="1" fill="rgba(87,62,43,1)"/>
+ <circle cx="58" cy="33" r="1" fill="rgba(73,44,25,1)"/>
+ <circle cx="59" cy="33" r="1" fill="rgba(59,29,13,1)"/>
+ <circle cx="60" cy="33" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="61" cy="33" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="62" cy="33" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="63" cy="33" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="64" cy="33" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="65" cy="33" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="33" r="1" fill="rgba(59,29,13,1)"/>
+ <circle cx="67" cy="33" r="1" fill="rgba(46,22,8,1)"/>
+ <circle cx="68" cy="33" r="1" fill="rgba(26,11,4,1)"/>
+ <circle cx="69" cy="33" r="1" fill="rgba(24,12,5,1)"/>
+ <circle cx="70" cy="33" r="1" fill="rgba(29,15,8,1)"/>
+ <circle cx="71" cy="33" r="1" fill="rgba(33,20,10,1)"/>
+ <circle cx="72" cy="33" r="1" fill="rgba(36,23,13,1)"/>
+ <circle cx="73" cy="33" r="1" fill="rgba(42,27,16,1)"/>
+ <circle cx="74" cy="33" r="1" fill="rgba(46,31,19,1)"/>
+ <circle cx="75" cy="33" r="1" fill="rgba(50,34,22,1)"/>
+ <circle cx="76" cy="33" r="1" fill="rgba(53,38,25,1)"/>
+ <circle cx="77" cy="33" r="1" fill="rgba(57,42,29,1)"/>
+ <circle cx="78" cy="33" r="1" fill="rgba(61,45,33,1)"/>
+ <circle cx="79" cy="33" r="1" fill="rgba(63,49,37,1)"/>
+ <circle cx="80" cy="33" r="1" fill="rgba(65,53,41,1)"/>
+ <circle cx="81" cy="33" r="1" fill="rgba(70,57,44,1)"/>
+ <circle cx="82" cy="33" r="1" fill="rgba(73,60,49,1)"/>
+ <circle cx="83" cy="33" r="1" fill="rgba(76,63,53,1)"/>
+ <circle cx="84" cy="33" r="1" fill="rgba(78,67,57,1)"/>
+ <circle cx="85" cy="33" r="1" fill="rgba(82,72,63,1)"/>
+ <circle cx="86" cy="33" r="1" fill="rgba(88,78,71,1)"/>
+ <circle cx="87" cy="33" r="1" fill="rgba(58,41,27,1)"/>
+ <circle cx="88" cy="33" r="1" fill="rgba(7,0,0,1)"/>
+ <circle cx="89" cy="33" r="1" fill="rgba(159,95,60,1)"/>
+ <circle cx="90" cy="33" r="1" fill="rgba(205,124,85,0.988235)"/>
+ <circle cx="91" cy="33" r="1" fill="rgba(187,50,16,0.392157)"/>
+ <circle cx="92" cy="33" r="1" fill="rgba(142,45,16,0)"/>
+ <circle cx="93" cy="33" r="1" fill="rgba(59,28,11,0)"/>
+ <circle cx="94" cy="33" r="1" fill="rgba(57,30,13,0)"/>
+ <circle cx="95" cy="33" r="1" fill="rgba(40,17,6,0)"/>
+ <circle cx="96" cy="33" r="1" fill="rgba(19,6,1,0)"/>
+ <circle cx="97" cy="33" r="1" fill="rgba(40,18,7,0)"/>
+ <circle cx="98" cy="33" r="1" fill="rgba(37,17,6,0.141176)"/>
+ <circle cx="99" cy="33" r="1" fill="rgba(21,7,1,0.356863)"/>
+ <circle cx="100" cy="33" r="1" fill="rgba(28,11,3,0.329412)"/>
+ <circle cx="101" cy="33" r="1" fill="rgba(24,9,2,0.341176)"/>
+ <circle cx="102" cy="33" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="103" cy="33" r="1" fill="rgba(21,6,1,0.368627)"/>
+ <circle cx="104" cy="33" r="1" fill="rgba(45,20,8,0.0705882)"/>
+ <circle cx="105" cy="33" r="1" fill="rgba(46,23,9,0)"/>
+ <circle cx="106" cy="33" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="107" cy="33" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="108" cy="33" r="1" fill="rgba(46,23,9,0)"/>
+ <circle cx="109" cy="33" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="110" cy="33" r="1" fill="rgba(49,21,9,0)"/>
+ <circle cx="111" cy="33" r="1" fill="rgba(47,22,8,0)"/>
+ <circle cx="112" cy="33" r="1" fill="rgba(49,22,9,0)"/>
+ <circle cx="113" cy="33" r="1" fill="rgba(58,29,13,0)"/>
+ <circle cx="114" cy="33" r="1" fill="rgba(61,30,13,0.188235)"/>
+ <circle cx="115" cy="33" r="1" fill="rgba(61,30,13,0.470588)"/>
+ <circle cx="116" cy="33" r="1" fill="rgba(61,30,13,0.0431373)"/>
+ <circle cx="117" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="33" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="34" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="34" r="1" fill="rgba(110,79,51,0)"/>
+ <circle cx="19" cy="34" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="20" cy="34" r="1" fill="rgba(108,77,49,0)"/>
+ <circle cx="21" cy="34" r="1" fill="rgba(104,72,44,0)"/>
+ <circle cx="22" cy="34" r="1" fill="rgba(99,67,40,0)"/>
+ <circle cx="23" cy="34" r="1" fill="rgba(93,61,36,0)"/>
+ <circle cx="24" cy="34" r="1" fill="rgba(88,56,32,0)"/>
+ <circle cx="25" cy="34" r="1" fill="rgba(85,52,29,0)"/>
+ <circle cx="26" cy="34" r="1" fill="rgba(77,46,24,0)"/>
+ <circle cx="27" cy="34" r="1" fill="rgba(61,32,14,0)"/>
+ <circle cx="28" cy="34" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="29" cy="34" r="1" fill="rgba(47,24,10,0)"/>
+ <circle cx="30" cy="34" r="1" fill="rgba(49,24,10,0)"/>
+ <circle cx="31" cy="34" r="1" fill="rgba(49,24,10,0)"/>
+ <circle cx="32" cy="34" r="1" fill="rgba(49,24,10,0)"/>
+ <circle cx="33" cy="34" r="1" fill="rgba(49,24,10,0)"/>
+ <circle cx="34" cy="34" r="1" fill="rgba(39,18,7,0.0431373)"/>
+ <circle cx="35" cy="34" r="1" fill="rgba(26,12,4,0.14902)"/>
+ <circle cx="36" cy="34" r="1" fill="rgba(0,4,2,0.223529)"/>
+ <circle cx="37" cy="34" r="1" fill="rgba(81,18,1,0.419608)"/>
+ <circle cx="38" cy="34" r="1" fill="rgba(231,71,3,0.92549)"/>
+ <circle cx="39" cy="34" r="1" fill="rgba(254,87,4,1)"/>
+ <circle cx="40" cy="34" r="1" fill="rgba(247,89,4,1)"/>
+ <circle cx="41" cy="34" r="1" fill="rgba(248,90,3,1)"/>
+ <circle cx="42" cy="34" r="1" fill="rgba(255,94,2,1)"/>
+ <circle cx="43" cy="34" r="1" fill="rgba(240,84,1,1)"/>
+ <circle cx="44" cy="34" r="1" fill="rgba(107,20,0,1)"/>
+ <circle cx="45" cy="34" r="1" fill="rgba(55,45,33,1)"/>
+ <circle cx="46" cy="34" r="1" fill="rgba(216,214,217,1)"/>
+ <circle cx="47" cy="34" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="48" cy="34" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="49" cy="34" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="50" cy="34" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="51" cy="34" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="52" cy="34" r="1" fill="rgba(251,250,250,1)"/>
+ <circle cx="53" cy="34" r="1" fill="rgba(239,235,235,1)"/>
+ <circle cx="54" cy="34" r="1" fill="rgba(209,200,192,1)"/>
+ <circle cx="55" cy="34" r="1" fill="rgba(173,155,142,1)"/>
+ <circle cx="56" cy="34" r="1" fill="rgba(121,99,82,1)"/>
+ <circle cx="57" cy="34" r="1" fill="rgba(91,66,48,1)"/>
+ <circle cx="58" cy="34" r="1" fill="rgba(83,56,37,1)"/>
+ <circle cx="59" cy="34" r="1" fill="rgba(68,38,20,1)"/>
+ <circle cx="60" cy="34" r="1" fill="rgba(59,29,13,1)"/>
+ <circle cx="61" cy="34" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="62" cy="34" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="63" cy="34" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="64" cy="34" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="65" cy="34" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="34" r="1" fill="rgba(61,29,13,1)"/>
+ <circle cx="67" cy="34" r="1" fill="rgba(46,21,8,1)"/>
+ <circle cx="68" cy="34" r="1" fill="rgba(22,10,3,1)"/>
+ <circle cx="69" cy="34" r="1" fill="rgba(21,9,3,1)"/>
+ <circle cx="70" cy="34" r="1" fill="rgba(26,13,6,1)"/>
+ <circle cx="71" cy="34" r="1" fill="rgba(31,17,8,1)"/>
+ <circle cx="72" cy="34" r="1" fill="rgba(34,20,11,1)"/>
+ <circle cx="73" cy="34" r="1" fill="rgba(37,25,13,1)"/>
+ <circle cx="74" cy="34" r="1" fill="rgba(42,28,17,1)"/>
+ <circle cx="75" cy="34" r="1" fill="rgba(47,32,20,1)"/>
+ <circle cx="76" cy="34" r="1" fill="rgba(50,36,23,1)"/>
+ <circle cx="77" cy="34" r="1" fill="rgba(53,39,27,1)"/>
+ <circle cx="78" cy="34" r="1" fill="rgba(58,43,30,1)"/>
+ <circle cx="79" cy="34" r="1" fill="rgba(62,46,34,1)"/>
+ <circle cx="80" cy="34" r="1" fill="rgba(64,50,37,1)"/>
+ <circle cx="81" cy="34" r="1" fill="rgba(68,54,42,1)"/>
+ <circle cx="82" cy="34" r="1" fill="rgba(71,57,46,1)"/>
+ <circle cx="83" cy="34" r="1" fill="rgba(74,61,50,1)"/>
+ <circle cx="84" cy="34" r="1" fill="rgba(76,65,55,1)"/>
+ <circle cx="85" cy="34" r="1" fill="rgba(84,73,64,1)"/>
+ <circle cx="86" cy="34" r="1" fill="rgba(59,48,34,1)"/>
+ <circle cx="87" cy="34" r="1" fill="rgba(22,0,0,1)"/>
+ <circle cx="88" cy="34" r="1" fill="rgba(177,101,64,1)"/>
+ <circle cx="89" cy="34" r="1" fill="rgba(253,216,196,1)"/>
+ <circle cx="90" cy="34" r="1" fill="rgba(221,97,53,1)"/>
+ <circle cx="91" cy="34" r="1" fill="rgba(210,56,17,0.945098)"/>
+ <circle cx="92" cy="34" r="1" fill="rgba(200,53,17,0.258824)"/>
+ <circle cx="93" cy="34" r="1" fill="rgba(42,13,4,0)"/>
+ <circle cx="94" cy="34" r="1" fill="rgba(28,12,4,0)"/>
+ <circle cx="95" cy="34" r="1" fill="rgba(21,6,1,0)"/>
+ <circle cx="96" cy="34" r="1" fill="rgba(21,7,1,0.00784314)"/>
+ <circle cx="97" cy="34" r="1" fill="rgba(37,16,6,0.137255)"/>
+ <circle cx="98" cy="34" r="1" fill="rgba(21,6,1,0.376471)"/>
+ <circle cx="99" cy="34" r="1" fill="rgba(0,0,0,0.47451)"/>
+ <circle cx="100" cy="34" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="101" cy="34" r="1" fill="rgba(0,0,0,0.462745)"/>
+ <circle cx="102" cy="34" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="103" cy="34" r="1" fill="rgba(31,12,4,0.270588)"/>
+ <circle cx="104" cy="34" r="1" fill="rgba(47,24,9,0.0156863)"/>
+ <circle cx="105" cy="34" r="1" fill="rgba(47,23,9,0)"/>
+ <circle cx="106" cy="34" r="1" fill="rgba(47,23,9,0)"/>
+ <circle cx="107" cy="34" r="1" fill="rgba(47,23,9,0)"/>
+ <circle cx="108" cy="34" r="1" fill="rgba(47,22,9,0)"/>
+ <circle cx="109" cy="34" r="1" fill="rgba(34,14,5,0)"/>
+ <circle cx="110" cy="34" r="1" fill="rgba(31,12,4,0)"/>
+ <circle cx="111" cy="34" r="1" fill="rgba(33,12,4,0)"/>
+ <circle cx="112" cy="34" r="1" fill="rgba(33,12,4,0)"/>
+ <circle cx="113" cy="34" r="1" fill="rgba(36,14,5,0)"/>
+ <circle cx="114" cy="34" r="1" fill="rgba(59,29,13,0.447059)"/>
+ <circle cx="115" cy="34" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="116" cy="34" r="1" fill="rgba(62,31,14,0.0980392)"/>
+ <circle cx="117" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="34" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="35" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="35" r="1" fill="rgba(110,79,51,0)"/>
+ <circle cx="19" cy="35" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="20" cy="35" r="1" fill="rgba(108,77,49,0)"/>
+ <circle cx="21" cy="35" r="1" fill="rgba(104,72,44,0)"/>
+ <circle cx="22" cy="35" r="1" fill="rgba(99,67,40,0)"/>
+ <circle cx="23" cy="35" r="1" fill="rgba(93,61,36,0)"/>
+ <circle cx="24" cy="35" r="1" fill="rgba(88,56,32,0)"/>
+ <circle cx="25" cy="35" r="1" fill="rgba(84,51,28,0)"/>
+ <circle cx="26" cy="35" r="1" fill="rgba(78,46,24,0)"/>
+ <circle cx="27" cy="35" r="1" fill="rgba(74,42,21,0)"/>
+ <circle cx="28" cy="35" r="1" fill="rgba(67,34,16,0)"/>
+ <circle cx="29" cy="35" r="1" fill="rgba(55,28,11,0)"/>
+ <circle cx="30" cy="35" r="1" fill="rgba(50,24,10,0)"/>
+ <circle cx="31" cy="35" r="1" fill="rgba(37,21,10,0)"/>
+ <circle cx="32" cy="35" r="1" fill="rgba(24,18,10,0)"/>
+ <circle cx="33" cy="35" r="1" fill="rgba(24,18,9,0)"/>
+ <circle cx="34" cy="35" r="1" fill="rgba(17,13,6,0)"/>
+ <circle cx="35" cy="35" r="1" fill="rgba(43,18,6,0)"/>
+ <circle cx="36" cy="35" r="1" fill="rgba(113,36,6,0.0392157)"/>
+ <circle cx="37" cy="35" r="1" fill="rgba(233,80,6,0.772549)"/>
+ <circle cx="38" cy="35" r="1" fill="rgba(254,94,7,1)"/>
+ <circle cx="39" cy="35" r="1" fill="rgba(248,96,8,1)"/>
+ <circle cx="40" cy="35" r="1" fill="rgba(248,99,8,1)"/>
+ <circle cx="41" cy="35" r="1" fill="rgba(249,99,7,1)"/>
+ <circle cx="42" cy="35" r="1" fill="rgba(248,98,6,1)"/>
+ <circle cx="43" cy="35" r="1" fill="rgba(255,98,4,1)"/>
+ <circle cx="44" cy="35" r="1" fill="rgba(248,90,1,1)"/>
+ <circle cx="45" cy="35" r="1" fill="rgba(96,18,0,1)"/>
+ <circle cx="46" cy="35" r="1" fill="rgba(50,37,26,1)"/>
+ <circle cx="47" cy="35" r="1" fill="rgba(214,205,200,1)"/>
+ <circle cx="48" cy="35" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="49" cy="35" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="50" cy="35" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="51" cy="35" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="52" cy="35" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="53" cy="35" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="54" cy="35" r="1" fill="rgba(236,232,229,1)"/>
+ <circle cx="55" cy="35" r="1" fill="rgba(202,190,181,1)"/>
+ <circle cx="56" cy="35" r="1" fill="rgba(162,142,126,1)"/>
+ <circle cx="57" cy="35" r="1" fill="rgba(110,86,68,1)"/>
+ <circle cx="58" cy="35" r="1" fill="rgba(86,61,43,1)"/>
+ <circle cx="59" cy="35" r="1" fill="rgba(77,50,30,1)"/>
+ <circle cx="60" cy="35" r="1" fill="rgba(63,32,15,1)"/>
+ <circle cx="61" cy="35" r="1" fill="rgba(59,29,13,1)"/>
+ <circle cx="62" cy="35" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="63" cy="35" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="64" cy="35" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="65" cy="35" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="35" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="67" cy="35" r="1" fill="rgba(46,21,8,1)"/>
+ <circle cx="68" cy="35" r="1" fill="rgba(19,8,2,1)"/>
+ <circle cx="69" cy="35" r="1" fill="rgba(17,7,3,1)"/>
+ <circle cx="70" cy="35" r="1" fill="rgba(21,11,4,1)"/>
+ <circle cx="71" cy="35" r="1" fill="rgba(28,14,7,1)"/>
+ <circle cx="72" cy="35" r="1" fill="rgba(33,18,9,1)"/>
+ <circle cx="73" cy="35" r="1" fill="rgba(36,22,12,1)"/>
+ <circle cx="74" cy="35" r="1" fill="rgba(40,25,15,1)"/>
+ <circle cx="75" cy="35" r="1" fill="rgba(45,30,18,1)"/>
+ <circle cx="76" cy="35" r="1" fill="rgba(49,33,22,1)"/>
+ <circle cx="77" cy="35" r="1" fill="rgba(51,36,24,1)"/>
+ <circle cx="78" cy="35" r="1" fill="rgba(54,41,28,1)"/>
+ <circle cx="79" cy="35" r="1" fill="rgba(59,44,32,1)"/>
+ <circle cx="80" cy="35" r="1" fill="rgba(62,48,35,1)"/>
+ <circle cx="81" cy="35" r="1" fill="rgba(64,52,40,1)"/>
+ <circle cx="82" cy="35" r="1" fill="rgba(68,55,42,1)"/>
+ <circle cx="83" cy="35" r="1" fill="rgba(71,59,48,1)"/>
+ <circle cx="84" cy="35" r="1" fill="rgba(78,66,55,1)"/>
+ <circle cx="85" cy="35" r="1" fill="rgba(63,53,40,1)"/>
+ <circle cx="86" cy="35" r="1" fill="rgba(28,0,0,1)"/>
+ <circle cx="87" cy="35" r="1" fill="rgba(178,85,47,1)"/>
+ <circle cx="88" cy="35" r="1" fill="rgba(255,226,211,1)"/>
+ <circle cx="89" cy="35" r="1" fill="rgba(217,95,50,1)"/>
+ <circle cx="90" cy="35" r="1" fill="rgba(204,50,14,1)"/>
+ <circle cx="91" cy="35" r="1" fill="rgba(207,59,20,1)"/>
+ <circle cx="92" cy="35" r="1" fill="rgba(202,55,18,0.905882)"/>
+ <circle cx="93" cy="35" r="1" fill="rgba(90,23,7,0.219608)"/>
+ <circle cx="94" cy="35" r="1" fill="rgba(17,11,3,0.113725)"/>
+ <circle cx="95" cy="35" r="1" fill="rgba(21,6,1,0.188235)"/>
+ <circle cx="96" cy="35" r="1" fill="rgba(15,4,0,0.235294)"/>
+ <circle cx="97" cy="35" r="1" fill="rgba(17,5,1,0.376471)"/>
+ <circle cx="98" cy="35" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="99" cy="35" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="100" cy="35" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="101" cy="35" r="1" fill="rgba(0,0,0,0.47451)"/>
+ <circle cx="102" cy="35" r="1" fill="rgba(10,2,0,0.427451)"/>
+ <circle cx="103" cy="35" r="1" fill="rgba(40,19,7,0.152941)"/>
+ <circle cx="104" cy="35" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="105" cy="35" r="1" fill="rgba(49,24,9,0)"/>
+ <circle cx="106" cy="35" r="1" fill="rgba(49,24,9,0)"/>
+ <circle cx="107" cy="35" r="1" fill="rgba(49,24,9,0)"/>
+ <circle cx="108" cy="35" r="1" fill="rgba(39,17,6,0)"/>
+ <circle cx="109" cy="35" r="1" fill="rgba(33,12,4,0)"/>
+ <circle cx="110" cy="35" r="1" fill="rgba(33,12,4,0)"/>
+ <circle cx="111" cy="35" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="112" cy="35" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="113" cy="35" r="1" fill="rgba(33,12,4,0.00392157)"/>
+ <circle cx="114" cy="35" r="1" fill="rgba(59,29,13,0.705882)"/>
+ <circle cx="115" cy="35" r="1" fill="rgba(55,26,11,0.615686)"/>
+ <circle cx="116" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="35" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="36" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="36" r="1" fill="rgba(110,79,51,0)"/>
+ <circle cx="19" cy="36" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="20" cy="36" r="1" fill="rgba(108,77,49,0)"/>
+ <circle cx="21" cy="36" r="1" fill="rgba(104,72,44,0)"/>
+ <circle cx="22" cy="36" r="1" fill="rgba(99,67,40,0)"/>
+ <circle cx="23" cy="36" r="1" fill="rgba(93,61,36,0)"/>
+ <circle cx="24" cy="36" r="1" fill="rgba(88,56,32,0)"/>
+ <circle cx="25" cy="36" r="1" fill="rgba(84,51,28,0)"/>
+ <circle cx="26" cy="36" r="1" fill="rgba(78,46,24,0)"/>
+ <circle cx="27" cy="36" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="28" cy="36" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="29" cy="36" r="1" fill="rgba(63,31,14,0)"/>
+ <circle cx="30" cy="36" r="1" fill="rgba(46,26,12,0)"/>
+ <circle cx="31" cy="36" r="1" fill="rgba(116,46,12,0)"/>
+ <circle cx="32" cy="36" r="1" fill="rgba(167,66,11,0)"/>
+ <circle cx="33" cy="36" r="1" fill="rgba(162,62,11,0)"/>
+ <circle cx="34" cy="36" r="1" fill="rgba(166,62,10,0)"/>
+ <circle cx="35" cy="36" r="1" fill="rgba(234,91,11,0)"/>
+ <circle cx="36" cy="36" r="1" fill="rgba(251,94,10,0.592157)"/>
+ <circle cx="37" cy="36" r="1" fill="rgba(253,100,10,1)"/>
+ <circle cx="38" cy="36" r="1" fill="rgba(249,104,13,1)"/>
+ <circle cx="39" cy="36" r="1" fill="rgba(249,107,13,1)"/>
+ <circle cx="40" cy="36" r="1" fill="rgba(249,108,13,1)"/>
+ <circle cx="41" cy="36" r="1" fill="rgba(249,107,12,1)"/>
+ <circle cx="42" cy="36" r="1" fill="rgba(249,105,10,1)"/>
+ <circle cx="43" cy="36" r="1" fill="rgba(249,101,8,1)"/>
+ <circle cx="44" cy="36" r="1" fill="rgba(255,100,6,1)"/>
+ <circle cx="45" cy="36" r="1" fill="rgba(238,87,2,1)"/>
+ <circle cx="46" cy="36" r="1" fill="rgba(67,10,0,1)"/>
+ <circle cx="47" cy="36" r="1" fill="rgba(57,40,25,1)"/>
+ <circle cx="48" cy="36" r="1" fill="rgba(218,208,200,1)"/>
+ <circle cx="49" cy="36" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="50" cy="36" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="51" cy="36" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="52" cy="36" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="53" cy="36" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="54" cy="36" r="1" fill="rgba(250,249,249,1)"/>
+ <circle cx="55" cy="36" r="1" fill="rgba(223,215,209,1)"/>
+ <circle cx="56" cy="36" r="1" fill="rgba(187,172,159,1)"/>
+ <circle cx="57" cy="36" r="1" fill="rgba(145,123,105,1)"/>
+ <circle cx="58" cy="36" r="1" fill="rgba(98,74,56,1)"/>
+ <circle cx="59" cy="36" r="1" fill="rgba(83,57,37,1)"/>
+ <circle cx="60" cy="36" r="1" fill="rgba(71,42,23,1)"/>
+ <circle cx="61" cy="36" r="1" fill="rgba(59,29,13,1)"/>
+ <circle cx="62" cy="36" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="63" cy="36" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="64" cy="36" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="65" cy="36" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="36" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="67" cy="36" r="1" fill="rgba(47,21,8,1)"/>
+ <circle cx="68" cy="36" r="1" fill="rgba(19,6,1,1)"/>
+ <circle cx="69" cy="36" r="1" fill="rgba(10,4,1,1)"/>
+ <circle cx="70" cy="36" r="1" fill="rgba(19,8,3,1)"/>
+ <circle cx="71" cy="36" r="1" fill="rgba(22,12,5,1)"/>
+ <circle cx="72" cy="36" r="1" fill="rgba(29,16,8,1)"/>
+ <circle cx="73" cy="36" r="1" fill="rgba(34,19,10,1)"/>
+ <circle cx="74" cy="36" r="1" fill="rgba(37,23,13,1)"/>
+ <circle cx="75" cy="36" r="1" fill="rgba(40,27,16,1)"/>
+ <circle cx="76" cy="36" r="1" fill="rgba(46,30,19,1)"/>
+ <circle cx="77" cy="36" r="1" fill="rgba(50,34,22,1)"/>
+ <circle cx="78" cy="36" r="1" fill="rgba(53,38,26,1)"/>
+ <circle cx="79" cy="36" r="1" fill="rgba(55,42,29,1)"/>
+ <circle cx="80" cy="36" r="1" fill="rgba(61,46,33,1)"/>
+ <circle cx="81" cy="36" r="1" fill="rgba(63,49,37,1)"/>
+ <circle cx="82" cy="36" r="1" fill="rgba(67,52,40,1)"/>
+ <circle cx="83" cy="36" r="1" fill="rgba(71,59,48,1)"/>
+ <circle cx="84" cy="36" r="1" fill="rgba(64,54,42,1)"/>
+ <circle cx="85" cy="36" r="1" fill="rgba(19,0,0,1)"/>
+ <circle cx="86" cy="36" r="1" fill="rgba(170,67,33,1)"/>
+ <circle cx="87" cy="36" r="1" fill="rgba(255,224,209,1)"/>
+ <circle cx="88" cy="36" r="1" fill="rgba(220,103,59,1)"/>
+ <circle cx="89" cy="36" r="1" fill="rgba(207,50,14,1)"/>
+ <circle cx="90" cy="36" r="1" fill="rgba(208,61,22,1)"/>
+ <circle cx="91" cy="36" r="1" fill="rgba(206,59,20,1)"/>
+ <circle cx="92" cy="36" r="1" fill="rgba(208,57,19,1)"/>
+ <circle cx="93" cy="36" r="1" fill="rgba(184,48,14,0.862745)"/>
+ <circle cx="94" cy="36" r="1" fill="rgba(36,7,1,0.419608)"/>
+ <circle cx="95" cy="36" r="1" fill="rgba(0,0,0,0.427451)"/>
+ <circle cx="96" cy="36" r="1" fill="rgba(0,0,0,0.458824)"/>
+ <circle cx="97" cy="36" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="98" cy="36" r="1" fill="rgba(4,0,0,0.466667)"/>
+ <circle cx="99" cy="36" r="1" fill="rgba(10,2,0,0.447059)"/>
+ <circle cx="100" cy="36" r="1" fill="rgba(12,2,0,0.431373)"/>
+ <circle cx="101" cy="36" r="1" fill="rgba(12,3,0,0.419608)"/>
+ <circle cx="102" cy="36" r="1" fill="rgba(29,11,3,0.27451)"/>
+ <circle cx="103" cy="36" r="1" fill="rgba(49,24,9,0.0392157)"/>
+ <circle cx="104" cy="36" r="1" fill="rgba(51,25,10,0)"/>
+ <circle cx="105" cy="36" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="106" cy="36" r="1" fill="rgba(47,23,9,0)"/>
+ <circle cx="107" cy="36" r="1" fill="rgba(53,27,11,0)"/>
+ <circle cx="108" cy="36" r="1" fill="rgba(54,27,11,0)"/>
+ <circle cx="109" cy="36" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="110" cy="36" r="1" fill="rgba(36,14,5,0)"/>
+ <circle cx="111" cy="36" r="1" fill="rgba(34,13,4,0)"/>
+ <circle cx="112" cy="36" r="1" fill="rgba(28,9,3,0)"/>
+ <circle cx="113" cy="36" r="1" fill="rgba(31,11,3,0.239216)"/>
+ <circle cx="114" cy="36" r="1" fill="rgba(61,30,13,0.917647)"/>
+ <circle cx="115" cy="36" r="1" fill="rgba(45,19,7,0.2)"/>
+ <circle cx="116" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="36" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="37" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="37" r="1" fill="rgba(61,30,13,0.0156863)"/>
+ <circle cx="5" cy="37" r="1" fill="rgba(61,30,13,0.376471)"/>
+ <circle cx="6" cy="37" r="1" fill="rgba(61,30,13,0.435294)"/>
+ <circle cx="7" cy="37" r="1" fill="rgba(59,29,13,0.392157)"/>
+ <circle cx="8" cy="37" r="1" fill="rgba(58,28,12,0.211765)"/>
+ <circle cx="9" cy="37" r="1" fill="rgba(59,29,13,0.0235294)"/>
+ <circle cx="10" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="37" r="1" fill="rgba(110,79,51,0)"/>
+ <circle cx="19" cy="37" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="20" cy="37" r="1" fill="rgba(108,77,49,0)"/>
+ <circle cx="21" cy="37" r="1" fill="rgba(104,72,44,0)"/>
+ <circle cx="22" cy="37" r="1" fill="rgba(99,67,40,0)"/>
+ <circle cx="23" cy="37" r="1" fill="rgba(93,61,36,0)"/>
+ <circle cx="24" cy="37" r="1" fill="rgba(88,56,32,0)"/>
+ <circle cx="25" cy="37" r="1" fill="rgba(84,51,28,0)"/>
+ <circle cx="26" cy="37" r="1" fill="rgba(78,46,24,0)"/>
+ <circle cx="27" cy="37" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="28" cy="37" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="29" cy="37" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="30" cy="37" r="1" fill="rgba(40,25,13,0)"/>
+ <circle cx="31" cy="37" r="1" fill="rgba(169,66,14,0)"/>
+ <circle cx="32" cy="37" r="1" fill="rgba(255,111,14,0)"/>
+ <circle cx="33" cy="37" r="1" fill="rgba(255,109,14,0)"/>
+ <circle cx="34" cy="37" r="1" fill="rgba(255,108,14,0)"/>
+ <circle cx="35" cy="37" r="1" fill="rgba(255,103,14,0.360784)"/>
+ <circle cx="36" cy="37" r="1" fill="rgba(252,106,15,1)"/>
+ <circle cx="37" cy="37" r="1" fill="rgba(250,112,18,1)"/>
+ <circle cx="38" cy="37" r="1" fill="rgba(251,115,20,1)"/>
+ <circle cx="39" cy="37" r="1" fill="rgba(250,117,20,1)"/>
+ <circle cx="40" cy="37" r="1" fill="rgba(250,116,19,1)"/>
+ <circle cx="41" cy="37" r="1" fill="rgba(249,114,17,1)"/>
+ <circle cx="42" cy="37" r="1" fill="rgba(249,111,15,1)"/>
+ <circle cx="43" cy="37" r="1" fill="rgba(249,107,13,1)"/>
+ <circle cx="44" cy="37" r="1" fill="rgba(249,104,9,1)"/>
+ <circle cx="45" cy="37" r="1" fill="rgba(255,104,7,1)"/>
+ <circle cx="46" cy="37" r="1" fill="rgba(219,78,2,1)"/>
+ <circle cx="47" cy="37" r="1" fill="rgba(37,4,0,1)"/>
+ <circle cx="48" cy="37" r="1" fill="rgba(70,45,27,1)"/>
+ <circle cx="49" cy="37" r="1" fill="rgba(225,214,203,1)"/>
+ <circle cx="50" cy="37" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="51" cy="37" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="52" cy="37" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="53" cy="37" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="54" cy="37" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="55" cy="37" r="1" fill="rgba(242,239,236,1)"/>
+ <circle cx="56" cy="37" r="1" fill="rgba(210,199,191,1)"/>
+ <circle cx="57" cy="37" r="1" fill="rgba(173,155,139,1)"/>
+ <circle cx="58" cy="37" r="1" fill="rgba(126,102,83,1)"/>
+ <circle cx="59" cy="37" r="1" fill="rgba(88,63,45,1)"/>
+ <circle cx="60" cy="37" r="1" fill="rgba(80,52,33,1)"/>
+ <circle cx="61" cy="37" r="1" fill="rgba(64,34,16,1)"/>
+ <circle cx="62" cy="37" r="1" fill="rgba(61,29,13,1)"/>
+ <circle cx="63" cy="37" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="64" cy="37" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="65" cy="37" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="37" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="67" cy="37" r="1" fill="rgba(47,22,8,1)"/>
+ <circle cx="68" cy="37" r="1" fill="rgba(19,5,1,1)"/>
+ <circle cx="69" cy="37" r="1" fill="rgba(7,3,0,1)"/>
+ <circle cx="70" cy="37" r="1" fill="rgba(15,6,2,1)"/>
+ <circle cx="71" cy="37" r="1" fill="rgba(21,10,3,1)"/>
+ <circle cx="72" cy="37" r="1" fill="rgba(24,14,6,1)"/>
+ <circle cx="73" cy="37" r="1" fill="rgba(31,17,9,1)"/>
+ <circle cx="74" cy="37" r="1" fill="rgba(34,21,11,1)"/>
+ <circle cx="75" cy="37" r="1" fill="rgba(39,24,14,1)"/>
+ <circle cx="76" cy="37" r="1" fill="rgba(42,28,16,1)"/>
+ <circle cx="77" cy="37" r="1" fill="rgba(47,32,20,1)"/>
+ <circle cx="78" cy="37" r="1" fill="rgba(50,35,23,1)"/>
+ <circle cx="79" cy="37" r="1" fill="rgba(54,40,27,1)"/>
+ <circle cx="80" cy="37" r="1" fill="rgba(57,43,30,1)"/>
+ <circle cx="81" cy="37" r="1" fill="rgba(61,46,33,1)"/>
+ <circle cx="82" cy="37" r="1" fill="rgba(65,52,40,1)"/>
+ <circle cx="83" cy="37" r="1" fill="rgba(62,52,41,1)"/>
+ <circle cx="84" cy="37" r="1" fill="rgba(19,4,2,1)"/>
+ <circle cx="85" cy="37" r="1" fill="rgba(157,56,24,1)"/>
+ <circle cx="86" cy="37" r="1" fill="rgba(252,213,193,1)"/>
+ <circle cx="87" cy="37" r="1" fill="rgba(223,117,74,1)"/>
+ <circle cx="88" cy="37" r="1" fill="rgba(206,46,12,1)"/>
+ <circle cx="89" cy="37" r="1" fill="rgba(209,60,21,1)"/>
+ <circle cx="90" cy="37" r="1" fill="rgba(209,62,22,1)"/>
+ <circle cx="91" cy="37" r="1" fill="rgba(207,61,21,1)"/>
+ <circle cx="92" cy="37" r="1" fill="rgba(204,58,19,1)"/>
+ <circle cx="93" cy="37" r="1" fill="rgba(210,58,18,1)"/>
+ <circle cx="94" cy="37" r="1" fill="rgba(147,34,9,0.784314)"/>
+ <circle cx="95" cy="37" r="1" fill="rgba(0,0,0,0.423529)"/>
+ <circle cx="96" cy="37" r="1" fill="rgba(7,2,0,0.407843)"/>
+ <circle cx="97" cy="37" r="1" fill="rgba(10,2,0,0.329412)"/>
+ <circle cx="98" cy="37" r="1" fill="rgba(21,6,1,0.278431)"/>
+ <circle cx="99" cy="37" r="1" fill="rgba(31,12,3,0.239216)"/>
+ <circle cx="100" cy="37" r="1" fill="rgba(36,15,5,0.188235)"/>
+ <circle cx="101" cy="37" r="1" fill="rgba(39,17,6,0.156863)"/>
+ <circle cx="102" cy="37" r="1" fill="rgba(43,20,8,0.0588235)"/>
+ <circle cx="103" cy="37" r="1" fill="rgba(47,23,9,0)"/>
+ <circle cx="104" cy="37" r="1" fill="rgba(47,23,9,0)"/>
+ <circle cx="105" cy="37" r="1" fill="rgba(49,24,9,0)"/>
+ <circle cx="106" cy="37" r="1" fill="rgba(53,27,11,0)"/>
+ <circle cx="107" cy="37" r="1" fill="rgba(84,53,30,0)"/>
+ <circle cx="108" cy="37" r="1" fill="rgba(98,65,38,0)"/>
+ <circle cx="109" cy="37" r="1" fill="rgba(88,57,32,0)"/>
+ <circle cx="110" cy="37" r="1" fill="rgba(85,53,29,0)"/>
+ <circle cx="111" cy="37" r="1" fill="rgba(78,46,24,0)"/>
+ <circle cx="112" cy="37" r="1" fill="rgba(42,18,7,0.0392157)"/>
+ <circle cx="113" cy="37" r="1" fill="rgba(47,21,8,0.654902)"/>
+ <circle cx="114" cy="37" r="1" fill="rgba(57,27,11,0.807843)"/>
+ <circle cx="115" cy="37" r="1" fill="rgba(31,12,3,0.0352941)"/>
+ <circle cx="116" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="37" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="38" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="38" r="1" fill="rgba(61,30,13,0.027451)"/>
+ <circle cx="5" cy="38" r="1" fill="rgba(61,30,13,0.654902)"/>
+ <circle cx="6" cy="38" r="1" fill="rgba(61,30,13,0.921569)"/>
+ <circle cx="7" cy="38" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="8" cy="38" r="1" fill="rgba(63,31,14,1)"/>
+ <circle cx="9" cy="38" r="1" fill="rgba(63,32,14,0.843137)"/>
+ <circle cx="10" cy="38" r="1" fill="rgba(54,27,11,0.439216)"/>
+ <circle cx="11" cy="38" r="1" fill="rgba(36,14,5,0.0941176)"/>
+ <circle cx="12" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="38" r="1" fill="rgba(110,79,51,0)"/>
+ <circle cx="19" cy="38" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="20" cy="38" r="1" fill="rgba(108,77,49,0)"/>
+ <circle cx="21" cy="38" r="1" fill="rgba(104,72,44,0)"/>
+ <circle cx="22" cy="38" r="1" fill="rgba(99,67,40,0)"/>
+ <circle cx="23" cy="38" r="1" fill="rgba(93,61,36,0)"/>
+ <circle cx="24" cy="38" r="1" fill="rgba(88,56,32,0)"/>
+ <circle cx="25" cy="38" r="1" fill="rgba(84,51,28,0)"/>
+ <circle cx="26" cy="38" r="1" fill="rgba(78,46,24,0)"/>
+ <circle cx="27" cy="38" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="28" cy="38" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="29" cy="38" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="30" cy="38" r="1" fill="rgba(59,30,13,0)"/>
+ <circle cx="31" cy="38" r="1" fill="rgba(50,26,13,0)"/>
+ <circle cx="32" cy="38" r="1" fill="rgba(180,76,16,0)"/>
+ <circle cx="33" cy="38" r="1" fill="rgba(255,116,19,0)"/>
+ <circle cx="34" cy="38" r="1" fill="rgba(252,109,18,0.14902)"/>
+ <circle cx="35" cy="38" r="1" fill="rgba(252,112,18,0.921569)"/>
+ <circle cx="36" cy="38" r="1" fill="rgba(251,119,23,1)"/>
+ <circle cx="37" cy="38" r="1" fill="rgba(252,123,26,1)"/>
+ <circle cx="38" cy="38" r="1" fill="rgba(251,125,27,1)"/>
+ <circle cx="39" cy="38" r="1" fill="rgba(250,125,27,1)"/>
+ <circle cx="40" cy="38" r="1" fill="rgba(250,123,26,1)"/>
+ <circle cx="41" cy="38" r="1" fill="rgba(250,121,23,1)"/>
+ <circle cx="42" cy="38" r="1" fill="rgba(250,118,20,1)"/>
+ <circle cx="43" cy="38" r="1" fill="rgba(249,114,17,1)"/>
+ <circle cx="44" cy="38" r="1" fill="rgba(249,111,14,1)"/>
+ <circle cx="45" cy="38" r="1" fill="rgba(250,106,10,1)"/>
+ <circle cx="46" cy="38" r="1" fill="rgba(255,106,7,1)"/>
+ <circle cx="47" cy="38" r="1" fill="rgba(195,67,2,1)"/>
+ <circle cx="48" cy="38" r="1" fill="rgba(7,0,0,1)"/>
+ <circle cx="49" cy="38" r="1" fill="rgba(90,59,35,1)"/>
+ <circle cx="50" cy="38" r="1" fill="rgba(241,234,228,1)"/>
+ <circle cx="51" cy="38" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="52" cy="38" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="53" cy="38" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="54" cy="38" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="55" cy="38" r="1" fill="rgba(254,252,253,1)"/>
+ <circle cx="56" cy="38" r="1" fill="rgba(231,225,220,1)"/>
+ <circle cx="57" cy="38" r="1" fill="rgba(196,182,172,1)"/>
+ <circle cx="58" cy="38" r="1" fill="rgba(156,135,117,1)"/>
+ <circle cx="59" cy="38" r="1" fill="rgba(108,83,64,1)"/>
+ <circle cx="60" cy="38" r="1" fill="rgba(84,57,39,1)"/>
+ <circle cx="61" cy="38" r="1" fill="rgba(73,44,24,1)"/>
+ <circle cx="62" cy="38" r="1" fill="rgba(61,29,13,1)"/>
+ <circle cx="63" cy="38" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="64" cy="38" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="65" cy="38" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="38" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="67" cy="38" r="1" fill="rgba(49,23,9,1)"/>
+ <circle cx="68" cy="38" r="1" fill="rgba(17,4,0,1)"/>
+ <circle cx="69" cy="38" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="70" cy="38" r="1" fill="rgba(12,3,1,1)"/>
+ <circle cx="71" cy="38" r="1" fill="rgba(19,7,3,1)"/>
+ <circle cx="72" cy="38" r="1" fill="rgba(22,11,5,1)"/>
+ <circle cx="73" cy="38" r="1" fill="rgba(26,15,7,1)"/>
+ <circle cx="74" cy="38" r="1" fill="rgba(33,19,9,1)"/>
+ <circle cx="75" cy="38" r="1" fill="rgba(37,22,12,1)"/>
+ <circle cx="76" cy="38" r="1" fill="rgba(40,26,15,1)"/>
+ <circle cx="77" cy="38" r="1" fill="rgba(43,30,18,1)"/>
+ <circle cx="78" cy="38" r="1" fill="rgba(49,33,21,1)"/>
+ <circle cx="79" cy="38" r="1" fill="rgba(51,37,25,1)"/>
+ <circle cx="80" cy="38" r="1" fill="rgba(55,40,28,1)"/>
+ <circle cx="81" cy="38" r="1" fill="rgba(61,46,33,1)"/>
+ <circle cx="82" cy="38" r="1" fill="rgba(58,46,35,1)"/>
+ <circle cx="83" cy="38" r="1" fill="rgba(12,5,3,1)"/>
+ <circle cx="84" cy="38" r="1" fill="rgba(142,51,22,1)"/>
+ <circle cx="85" cy="38" r="1" fill="rgba(252,211,192,1)"/>
+ <circle cx="86" cy="38" r="1" fill="rgba(223,115,74,1)"/>
+ <circle cx="87" cy="38" r="1" fill="rgba(205,42,10,1)"/>
+ <circle cx="88" cy="38" r="1" fill="rgba(209,58,20,1)"/>
+ <circle cx="89" cy="38" r="1" fill="rgba(210,61,22,1)"/>
+ <circle cx="90" cy="38" r="1" fill="rgba(210,64,23,1)"/>
+ <circle cx="91" cy="38" r="1" fill="rgba(210,63,23,1)"/>
+ <circle cx="92" cy="38" r="1" fill="rgba(207,61,20,1)"/>
+ <circle cx="93" cy="38" r="1" fill="rgba(205,58,19,1)"/>
+ <circle cx="94" cy="38" r="1" fill="rgba(210,58,18,1)"/>
+ <circle cx="95" cy="38" r="1" fill="rgba(117,28,7,0.490196)"/>
+ <circle cx="96" cy="38" r="1" fill="rgba(0,8,3,0.109804)"/>
+ <circle cx="97" cy="38" r="1" fill="rgba(15,6,1,0.0588235)"/>
+ <circle cx="98" cy="38" r="1" fill="rgba(24,8,2,0.0313725)"/>
+ <circle cx="99" cy="38" r="1" fill="rgba(39,17,6,0.0196078)"/>
+ <circle cx="100" cy="38" r="1" fill="rgba(45,21,8,0.00392157)"/>
+ <circle cx="101" cy="38" r="1" fill="rgba(47,23,9,0)"/>
+ <circle cx="102" cy="38" r="1" fill="rgba(43,20,8,0)"/>
+ <circle cx="103" cy="38" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="104" cy="38" r="1" fill="rgba(63,35,16,0)"/>
+ <circle cx="105" cy="38" r="1" fill="rgba(87,56,31,0)"/>
+ <circle cx="106" cy="38" r="1" fill="rgba(97,65,39,0)"/>
+ <circle cx="107" cy="38" r="1" fill="rgba(98,66,39,0)"/>
+ <circle cx="108" cy="38" r="1" fill="rgba(97,64,38,0)"/>
+ <circle cx="109" cy="38" r="1" fill="rgba(94,62,36,0)"/>
+ <circle cx="110" cy="38" r="1" fill="rgba(88,56,32,0)"/>
+ <circle cx="111" cy="38" r="1" fill="rgba(83,51,27,0.513725)"/>
+ <circle cx="112" cy="38" r="1" fill="rgba(75,43,22,0.847059)"/>
+ <circle cx="113" cy="38" r="1" fill="rgba(69,38,18,1)"/>
+ <circle cx="114" cy="38" r="1" fill="rgba(43,19,7,0.505882)"/>
+ <circle cx="115" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="38" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="39" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="39" r="1" fill="rgba(39,15,5,0.054902)"/>
+ <circle cx="7" cy="39" r="1" fill="rgba(37,15,5,0.298039)"/>
+ <circle cx="8" cy="39" r="1" fill="rgba(40,16,6,0.619608)"/>
+ <circle cx="9" cy="39" r="1" fill="rgba(54,25,10,0.862745)"/>
+ <circle cx="10" cy="39" r="1" fill="rgba(69,38,18,1)"/>
+ <circle cx="11" cy="39" r="1" fill="rgba(75,43,22,0.929412)"/>
+ <circle cx="12" cy="39" r="1" fill="rgba(74,43,22,0.658824)"/>
+ <circle cx="13" cy="39" r="1" fill="rgba(75,44,22,0.501961)"/>
+ <circle cx="14" cy="39" r="1" fill="rgba(92,59,33,0.501961)"/>
+ <circle cx="15" cy="39" r="1" fill="rgba(95,63,37,0.486275)"/>
+ <circle cx="16" cy="39" r="1" fill="rgba(99,67,41,0.192157)"/>
+ <circle cx="17" cy="39" r="1" fill="rgba(105,73,46,0.0156863)"/>
+ <circle cx="18" cy="39" r="1" fill="rgba(110,79,51,0)"/>
+ <circle cx="19" cy="39" r="1" fill="rgba(112,81,53,0)"/>
+ <circle cx="20" cy="39" r="1" fill="rgba(108,77,49,0)"/>
+ <circle cx="21" cy="39" r="1" fill="rgba(104,72,44,0)"/>
+ <circle cx="22" cy="39" r="1" fill="rgba(99,67,40,0)"/>
+ <circle cx="23" cy="39" r="1" fill="rgba(93,61,36,0)"/>
+ <circle cx="24" cy="39" r="1" fill="rgba(88,56,32,0)"/>
+ <circle cx="25" cy="39" r="1" fill="rgba(84,51,28,0)"/>
+ <circle cx="26" cy="39" r="1" fill="rgba(78,46,24,0)"/>
+ <circle cx="27" cy="39" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="28" cy="39" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="29" cy="39" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="30" cy="39" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="31" cy="39" r="1" fill="rgba(45,25,13,0)"/>
+ <circle cx="32" cy="39" r="1" fill="rgba(124,52,15,0)"/>
+ <circle cx="33" cy="39" r="1" fill="rgba(249,114,21,0.00392157)"/>
+ <circle cx="34" cy="39" r="1" fill="rgba(254,116,20,0.701961)"/>
+ <circle cx="35" cy="39" r="1" fill="rgba(253,125,27,1)"/>
+ <circle cx="36" cy="39" r="1" fill="rgba(252,130,32,1)"/>
+ <circle cx="37" cy="39" r="1" fill="rgba(252,132,34,1)"/>
+ <circle cx="38" cy="39" r="1" fill="rgba(252,133,35,1)"/>
+ <circle cx="39" cy="39" r="1" fill="rgba(251,132,35,1)"/>
+ <circle cx="40" cy="39" r="1" fill="rgba(251,130,33,1)"/>
+ <circle cx="41" cy="39" r="1" fill="rgba(250,127,30,1)"/>
+ <circle cx="42" cy="39" r="1" fill="rgba(250,124,26,1)"/>
+ <circle cx="43" cy="39" r="1" fill="rgba(250,120,22,1)"/>
+ <circle cx="44" cy="39" r="1" fill="rgba(250,117,19,1)"/>
+ <circle cx="45" cy="39" r="1" fill="rgba(250,113,15,1)"/>
+ <circle cx="46" cy="39" r="1" fill="rgba(251,109,11,1)"/>
+ <circle cx="47" cy="39" r="1" fill="rgba(255,110,8,1)"/>
+ <circle cx="48" cy="39" r="1" fill="rgba(173,59,1,1)"/>
+ <circle cx="49" cy="39" r="1" fill="black"/>
+ <circle cx="50" cy="39" r="1" fill="rgba(104,73,46,1)"/>
+ <circle cx="51" cy="39" r="1" fill="rgba(233,222,212,1)"/>
+ <circle cx="52" cy="39" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="53" cy="39" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="54" cy="39" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="55" cy="39" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="56" cy="39" r="1" fill="rgba(248,246,245,1)"/>
+ <circle cx="57" cy="39" r="1" fill="rgba(218,209,203,1)"/>
+ <circle cx="58" cy="39" r="1" fill="rgba(182,165,151,1)"/>
+ <circle cx="59" cy="39" r="1" fill="rgba(137,114,95,1)"/>
+ <circle cx="60" cy="39" r="1" fill="rgba(94,69,50,1)"/>
+ <circle cx="61" cy="39" r="1" fill="rgba(80,52,33,1)"/>
+ <circle cx="62" cy="39" r="1" fill="rgba(65,35,18,1)"/>
+ <circle cx="63" cy="39" r="1" fill="rgba(59,29,13,1)"/>
+ <circle cx="64" cy="39" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="65" cy="39" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="39" r="1" fill="rgba(62,30,14,1)"/>
+ <circle cx="67" cy="39" r="1" fill="rgba(50,22,9,1)"/>
+ <circle cx="68" cy="39" r="1" fill="rgba(15,3,0,1)"/>
+ <circle cx="69" cy="39" r="1" fill="black"/>
+ <circle cx="70" cy="39" r="1" fill="rgba(4,1,0,1)"/>
+ <circle cx="71" cy="39" r="1" fill="rgba(15,5,1,1)"/>
+ <circle cx="72" cy="39" r="1" fill="rgba(19,8,3,1)"/>
+ <circle cx="73" cy="39" r="1" fill="rgba(24,12,5,1)"/>
+ <circle cx="74" cy="39" r="1" fill="rgba(28,16,8,1)"/>
+ <circle cx="75" cy="39" r="1" fill="rgba(34,20,10,1)"/>
+ <circle cx="76" cy="39" r="1" fill="rgba(39,24,13,1)"/>
+ <circle cx="77" cy="39" r="1" fill="rgba(42,27,16,1)"/>
+ <circle cx="78" cy="39" r="1" fill="rgba(45,31,19,1)"/>
+ <circle cx="79" cy="39" r="1" fill="rgba(50,35,22,1)"/>
+ <circle cx="80" cy="39" r="1" fill="rgba(55,40,28,1)"/>
+ <circle cx="81" cy="39" r="1" fill="rgba(49,36,25,1)"/>
+ <circle cx="82" cy="39" r="1" fill="rgba(0,1,1,1)"/>
+ <circle cx="83" cy="39" r="1" fill="rgba(142,54,25,1)"/>
+ <circle cx="84" cy="39" r="1" fill="rgba(248,199,175,1)"/>
+ <circle cx="85" cy="39" r="1" fill="rgba(222,108,68,1)"/>
+ <circle cx="86" cy="39" r="1" fill="rgba(204,38,9,1)"/>
+ <circle cx="87" cy="39" r="1" fill="rgba(208,54,19,1)"/>
+ <circle cx="88" cy="39" r="1" fill="rgba(210,59,20,1)"/>
+ <circle cx="89" cy="39" r="1" fill="rgba(210,62,22,1)"/>
+ <circle cx="90" cy="39" r="1" fill="rgba(211,65,24,1)"/>
+ <circle cx="91" cy="39" r="1" fill="rgba(211,66,24,1)"/>
+ <circle cx="92" cy="39" r="1" fill="rgba(209,64,23,1)"/>
+ <circle cx="93" cy="39" r="1" fill="rgba(207,61,21,1)"/>
+ <circle cx="94" cy="39" r="1" fill="rgba(207,59,20,1)"/>
+ <circle cx="95" cy="39" r="1" fill="rgba(206,57,18,0.862745)"/>
+ <circle cx="96" cy="39" r="1" fill="rgba(99,27,8,0.0745098)"/>
+ <circle cx="97" cy="39" r="1" fill="rgba(33,11,3,0)"/>
+ <circle cx="98" cy="39" r="1" fill="rgba(29,10,3,0)"/>
+ <circle cx="99" cy="39" r="1" fill="rgba(40,18,7,0)"/>
+ <circle cx="100" cy="39" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="101" cy="39" r="1" fill="rgba(49,24,10,0)"/>
+ <circle cx="102" cy="39" r="1" fill="rgba(46,23,9,0)"/>
+ <circle cx="103" cy="39" r="1" fill="rgba(78,47,24,0)"/>
+ <circle cx="104" cy="39" r="1" fill="rgba(98,66,39,0)"/>
+ <circle cx="105" cy="39" r="1" fill="rgba(101,69,42,0)"/>
+ <circle cx="106" cy="39" r="1" fill="rgba(99,67,41,0)"/>
+ <circle cx="107" cy="39" r="1" fill="rgba(97,65,38,0)"/>
+ <circle cx="108" cy="39" r="1" fill="rgba(97,64,38,0)"/>
+ <circle cx="109" cy="39" r="1" fill="rgba(93,61,35,0)"/>
+ <circle cx="110" cy="39" r="1" fill="rgba(88,56,31,0.380392)"/>
+ <circle cx="111" cy="39" r="1" fill="rgba(83,50,27,1)"/>
+ <circle cx="112" cy="39" r="1" fill="rgba(76,44,22,1)"/>
+ <circle cx="113" cy="39" r="1" fill="rgba(68,37,18,0.996078)"/>
+ <circle cx="114" cy="39" r="1" fill="rgba(36,15,5,0.270588)"/>
+ <circle cx="115" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="39" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="40" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="40" r="1" fill="rgba(21,7,1,0.0745098)"/>
+ <circle cx="9" cy="40" r="1" fill="rgba(15,3,0,0.203922)"/>
+ <circle cx="10" cy="40" r="1" fill="rgba(29,10,3,0.435294)"/>
+ <circle cx="11" cy="40" r="1" fill="rgba(53,26,11,0.745098)"/>
+ <circle cx="12" cy="40" r="1" fill="rgba(78,47,24,1)"/>
+ <circle cx="13" cy="40" r="1" fill="rgba(91,57,33,1)"/>
+ <circle cx="14" cy="40" r="1" fill="rgba(92,59,33,1)"/>
+ <circle cx="15" cy="40" r="1" fill="rgba(96,63,37,1)"/>
+ <circle cx="16" cy="40" r="1" fill="rgba(101,69,42,0.988235)"/>
+ <circle cx="17" cy="40" r="1" fill="rgba(107,75,48,0.8)"/>
+ <circle cx="18" cy="40" r="1" fill="rgba(111,80,52,0.568627)"/>
+ <circle cx="19" cy="40" r="1" fill="rgba(112,81,53,0.403922)"/>
+ <circle cx="20" cy="40" r="1" fill="rgba(108,77,49,0.266667)"/>
+ <circle cx="21" cy="40" r="1" fill="rgba(104,72,44,0.168627)"/>
+ <circle cx="22" cy="40" r="1" fill="rgba(99,67,40,0.294118)"/>
+ <circle cx="23" cy="40" r="1" fill="rgba(94,61,36,0.52549)"/>
+ <circle cx="24" cy="40" r="1" fill="rgba(88,56,32,0.568627)"/>
+ <circle cx="25" cy="40" r="1" fill="rgba(84,51,28,0.407843)"/>
+ <circle cx="26" cy="40" r="1" fill="rgba(78,46,24,0.129412)"/>
+ <circle cx="27" cy="40" r="1" fill="rgba(73,41,20,0.0156863)"/>
+ <circle cx="28" cy="40" r="1" fill="rgba(67,35,17,0)"/>
+ <circle cx="29" cy="40" r="1" fill="rgba(62,31,14,0)"/>
+ <circle cx="30" cy="40" r="1" fill="rgba(61,30,13,0)"/>
+ <circle cx="31" cy="40" r="1" fill="rgba(57,29,13,0)"/>
+ <circle cx="32" cy="40" r="1" fill="rgba(64,31,13,0)"/>
+ <circle cx="33" cy="40" r="1" fill="rgba(242,112,25,0.372549)"/>
+ <circle cx="34" cy="40" r="1" fill="rgba(255,127,28,1)"/>
+ <circle cx="35" cy="40" r="1" fill="rgba(254,134,35,1)"/>
+ <circle cx="36" cy="40" r="1" fill="rgba(254,139,41,1)"/>
+ <circle cx="37" cy="40" r="1" fill="rgba(252,140,43,1)"/>
+ <circle cx="38" cy="40" r="1" fill="rgba(252,140,43,1)"/>
+ <circle cx="39" cy="40" r="1" fill="rgba(252,139,43,1)"/>
+ <circle cx="40" cy="40" r="1" fill="rgba(251,136,40,1)"/>
+ <circle cx="41" cy="40" r="1" fill="rgba(251,133,37,1)"/>
+ <circle cx="42" cy="40" r="1" fill="rgba(250,130,33,1)"/>
+ <circle cx="43" cy="40" r="1" fill="rgba(250,127,30,1)"/>
+ <circle cx="44" cy="40" r="1" fill="rgba(250,123,25,1)"/>
+ <circle cx="45" cy="40" r="1" fill="rgba(250,120,21,1)"/>
+ <circle cx="46" cy="40" r="1" fill="rgba(251,116,17,1)"/>
+ <circle cx="47" cy="40" r="1" fill="rgba(252,113,13,1)"/>
+ <circle cx="48" cy="40" r="1" fill="rgba(255,111,7,1)"/>
+ <circle cx="49" cy="40" r="1" fill="rgba(169,59,0,1)"/>
+ <circle cx="50" cy="40" r="1" fill="black"/>
+ <circle cx="51" cy="40" r="1" fill="rgba(54,33,17,1)"/>
+ <circle cx="52" cy="40" r="1" fill="rgba(189,167,141,1)"/>
+ <circle cx="53" cy="40" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="54" cy="40" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="55" cy="40" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="56" cy="40" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="57" cy="40" r="1" fill="rgba(238,234,231,1)"/>
+ <circle cx="58" cy="40" r="1" fill="rgba(204,192,183,1)"/>
+ <circle cx="59" cy="40" r="1" fill="rgba(166,146,131,1)"/>
+ <circle cx="60" cy="40" r="1" fill="rgba(118,94,74,1)"/>
+ <circle cx="61" cy="40" r="1" fill="rgba(85,60,42,1)"/>
+ <circle cx="62" cy="40" r="1" fill="rgba(73,45,25,1)"/>
+ <circle cx="63" cy="40" r="1" fill="rgba(59,29,13,1)"/>
+ <circle cx="64" cy="40" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="65" cy="40" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="40" r="1" fill="rgba(62,30,14,1)"/>
+ <circle cx="67" cy="40" r="1" fill="rgba(50,23,9,1)"/>
+ <circle cx="68" cy="40" r="1" fill="rgba(15,3,0,1)"/>
+ <circle cx="69" cy="40" r="1" fill="black"/>
+ <circle cx="70" cy="40" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="71" cy="40" r="1" fill="rgba(7,2,0,1)"/>
+ <circle cx="72" cy="40" r="1" fill="rgba(17,6,2,1)"/>
+ <circle cx="73" cy="40" r="1" fill="rgba(21,10,4,1)"/>
+ <circle cx="74" cy="40" r="1" fill="rgba(26,13,6,1)"/>
+ <circle cx="75" cy="40" r="1" fill="rgba(29,17,9,1)"/>
+ <circle cx="76" cy="40" r="1" fill="rgba(36,21,11,1)"/>
+ <circle cx="77" cy="40" r="1" fill="rgba(39,24,14,1)"/>
+ <circle cx="78" cy="40" r="1" fill="rgba(43,29,18,1)"/>
+ <circle cx="79" cy="40" r="1" fill="rgba(49,34,22,1)"/>
+ <circle cx="80" cy="40" r="1" fill="rgba(33,24,13,1)"/>
+ <circle cx="81" cy="40" r="1" fill="black"/>
+ <circle cx="82" cy="40" r="1" fill="rgba(148,75,42,1)"/>
+ <circle cx="83" cy="40" r="1" fill="rgba(248,199,175,1)"/>
+ <circle cx="84" cy="40" r="1" fill="rgba(218,90,51,1)"/>
+ <circle cx="85" cy="40" r="1" fill="rgba(203,34,8,1)"/>
+ <circle cx="86" cy="40" r="1" fill="rgba(208,52,18,1)"/>
+ <circle cx="87" cy="40" r="1" fill="rgba(210,56,20,1)"/>
+ <circle cx="88" cy="40" r="1" fill="rgba(210,61,22,1)"/>
+ <circle cx="89" cy="40" r="1" fill="rgba(211,64,24,1)"/>
+ <circle cx="90" cy="40" r="1" fill="rgba(213,68,26,1)"/>
+ <circle cx="91" cy="40" r="1" fill="rgba(213,70,27,1)"/>
+ <circle cx="92" cy="40" r="1" fill="rgba(212,70,26,1)"/>
+ <circle cx="93" cy="40" r="1" fill="rgba(210,67,24,1)"/>
+ <circle cx="94" cy="40" r="1" fill="rgba(207,63,22,1)"/>
+ <circle cx="95" cy="40" r="1" fill="rgba(208,61,20,1)"/>
+ <circle cx="96" cy="40" r="1" fill="rgba(208,60,20,0.584314)"/>
+ <circle cx="97" cy="40" r="1" fill="rgba(194,56,18,0)"/>
+ <circle cx="98" cy="40" r="1" fill="rgba(69,30,12,0)"/>
+ <circle cx="99" cy="40" r="1" fill="rgba(62,33,15,0)"/>
+ <circle cx="100" cy="40" r="1" fill="rgba(71,40,20,0)"/>
+ <circle cx="101" cy="40" r="1" fill="rgba(76,44,23,0)"/>
+ <circle cx="102" cy="40" r="1" fill="rgba(82,50,27,0)"/>
+ <circle cx="103" cy="40" r="1" fill="rgba(92,59,33,0)"/>
+ <circle cx="104" cy="40" r="1" fill="rgba(96,64,37,0)"/>
+ <circle cx="105" cy="40" r="1" fill="rgba(99,67,41,0)"/>
+ <circle cx="106" cy="40" r="1" fill="rgba(98,66,40,0)"/>
+ <circle cx="107" cy="40" r="1" fill="rgba(97,65,38,0)"/>
+ <circle cx="108" cy="40" r="1" fill="rgba(97,64,38,0)"/>
+ <circle cx="109" cy="40" r="1" fill="rgba(93,61,35,0.380392)"/>
+ <circle cx="110" cy="40" r="1" fill="rgba(88,56,31,0.941176)"/>
+ <circle cx="111" cy="40" r="1" fill="rgba(83,50,27,1)"/>
+ <circle cx="112" cy="40" r="1" fill="rgba(77,45,23,1)"/>
+ <circle cx="113" cy="40" r="1" fill="rgba(67,36,17,0.956863)"/>
+ <circle cx="114" cy="40" r="1" fill="rgba(31,12,3,0.14902)"/>
+ <circle cx="115" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="40" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="41" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="41" r="1" fill="rgba(19,5,1,0.00392157)"/>
+ <circle cx="10" cy="41" r="1" fill="rgba(21,6,1,0.0627451)"/>
+ <circle cx="11" cy="41" r="1" fill="rgba(15,3,0,0.168627)"/>
+ <circle cx="12" cy="41" r="1" fill="rgba(29,11,3,0.411765)"/>
+ <circle cx="13" cy="41" r="1" fill="rgba(70,40,20,0.803922)"/>
+ <circle cx="14" cy="41" r="1" fill="rgba(91,59,33,0.992157)"/>
+ <circle cx="15" cy="41" r="1" fill="rgba(99,66,40,1)"/>
+ <circle cx="16" cy="41" r="1" fill="rgba(104,72,45,0.996078)"/>
+ <circle cx="17" cy="41" r="1" fill="rgba(103,71,44,0.968627)"/>
+ <circle cx="18" cy="41" r="1" fill="rgba(109,78,50,1)"/>
+ <circle cx="19" cy="41" r="1" fill="rgba(118,86,57,1)"/>
+ <circle cx="20" cy="41" r="1" fill="rgba(111,80,52,1)"/>
+ <circle cx="21" cy="41" r="1" fill="rgba(104,72,45,1)"/>
+ <circle cx="22" cy="41" r="1" fill="rgba(98,67,40,1)"/>
+ <circle cx="23" cy="41" r="1" fill="rgba(94,62,36,1)"/>
+ <circle cx="24" cy="41" r="1" fill="rgba(90,56,32,1)"/>
+ <circle cx="25" cy="41" r="1" fill="rgba(84,51,27,1)"/>
+ <circle cx="26" cy="41" r="1" fill="rgba(78,46,24,0.960784)"/>
+ <circle cx="27" cy="41" r="1" fill="rgba(73,41,20,0.784314)"/>
+ <circle cx="28" cy="41" r="1" fill="rgba(67,35,17,0.643137)"/>
+ <circle cx="29" cy="41" r="1" fill="rgba(62,31,14,0.564706)"/>
+ <circle cx="30" cy="41" r="1" fill="rgba(61,30,13,0.501961)"/>
+ <circle cx="31" cy="41" r="1" fill="rgba(54,28,13,0.501961)"/>
+ <circle cx="32" cy="41" r="1" fill="rgba(82,39,15,0.592157)"/>
+ <circle cx="33" cy="41" r="1" fill="rgba(244,128,43,0.913725)"/>
+ <circle cx="34" cy="41" r="1" fill="rgba(255,144,49,1)"/>
+ <circle cx="35" cy="41" r="1" fill="rgba(255,144,48,1)"/>
+ <circle cx="36" cy="41" r="1" fill="rgba(255,146,50,1)"/>
+ <circle cx="37" cy="41" r="1" fill="rgba(253,148,53,1)"/>
+ <circle cx="38" cy="41" r="1" fill="rgba(252,147,53,1)"/>
+ <circle cx="39" cy="41" r="1" fill="rgba(252,146,52,1)"/>
+ <circle cx="40" cy="41" r="1" fill="rgba(252,142,48,1)"/>
+ <circle cx="41" cy="41" r="1" fill="rgba(251,139,44,1)"/>
+ <circle cx="42" cy="41" r="1" fill="rgba(250,136,41,1)"/>
+ <circle cx="43" cy="41" r="1" fill="rgba(250,133,36,1)"/>
+ <circle cx="44" cy="41" r="1" fill="rgba(250,129,32,1)"/>
+ <circle cx="45" cy="41" r="1" fill="rgba(250,126,27,1)"/>
+ <circle cx="46" cy="41" r="1" fill="rgba(251,124,24,1)"/>
+ <circle cx="47" cy="41" r="1" fill="rgba(251,120,20,1)"/>
+ <circle cx="48" cy="41" r="1" fill="rgba(253,117,13,1)"/>
+ <circle cx="49" cy="41" r="1" fill="rgba(255,116,5,1)"/>
+ <circle cx="50" cy="41" r="1" fill="rgba(203,77,0,1)"/>
+ <circle cx="51" cy="41" r="1" fill="rgba(65,11,0,1)"/>
+ <circle cx="52" cy="41" r="1" fill="black"/>
+ <circle cx="53" cy="41" r="1" fill="rgba(114,83,55,1)"/>
+ <circle cx="54" cy="41" r="1" fill="rgba(218,204,187,1)"/>
+ <circle cx="55" cy="41" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="56" cy="41" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="57" cy="41" r="1" fill="rgba(253,252,253,1)"/>
+ <circle cx="58" cy="41" r="1" fill="rgba(226,219,215,1)"/>
+ <circle cx="59" cy="41" r="1" fill="rgba(191,176,163,1)"/>
+ <circle cx="60" cy="41" r="1" fill="rgba(149,126,108,1)"/>
+ <circle cx="61" cy="41" r="1" fill="rgba(101,76,56,1)"/>
+ <circle cx="62" cy="41" r="1" fill="rgba(80,53,34,1)"/>
+ <circle cx="63" cy="41" r="1" fill="rgba(64,35,17,1)"/>
+ <circle cx="64" cy="41" r="1" fill="rgba(59,29,13,1)"/>
+ <circle cx="65" cy="41" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="41" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="67" cy="41" r="1" fill="rgba(51,23,9,1)"/>
+ <circle cx="68" cy="41" r="1" fill="rgba(15,3,0,1)"/>
+ <circle cx="69" cy="41" r="1" fill="black"/>
+ <circle cx="70" cy="41" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="71" cy="41" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="72" cy="41" r="1" fill="rgba(10,4,1,1)"/>
+ <circle cx="73" cy="41" r="1" fill="rgba(19,8,3,1)"/>
+ <circle cx="74" cy="41" r="1" fill="rgba(22,11,5,1)"/>
+ <circle cx="75" cy="41" r="1" fill="rgba(26,14,7,1)"/>
+ <circle cx="76" cy="41" r="1" fill="rgba(31,18,9,1)"/>
+ <circle cx="77" cy="41" r="1" fill="rgba(37,24,13,1)"/>
+ <circle cx="78" cy="41" r="1" fill="rgba(36,24,14,1)"/>
+ <circle cx="79" cy="41" r="1" fill="rgba(0,7,3,1)"/>
+ <circle cx="80" cy="41" r="1" fill="rgba(39,0,0,1)"/>
+ <circle cx="81" cy="41" r="1" fill="rgba(176,108,74,1)"/>
+ <circle cx="82" cy="41" r="1" fill="rgba(247,193,169,1)"/>
+ <circle cx="83" cy="41" r="1" fill="rgba(214,70,34,1)"/>
+ <circle cx="84" cy="41" r="1" fill="rgba(203,34,8,1)"/>
+ <circle cx="85" cy="41" r="1" fill="rgba(208,50,17,1)"/>
+ <circle cx="86" cy="41" r="1" fill="rgba(209,54,20,1)"/>
+ <circle cx="87" cy="41" r="1" fill="rgba(210,59,22,1)"/>
+ <circle cx="88" cy="41" r="1" fill="rgba(213,64,24,1)"/>
+ <circle cx="89" cy="41" r="1" fill="rgba(214,68,27,1)"/>
+ <circle cx="90" cy="41" r="1" fill="rgba(215,72,29,1)"/>
+ <circle cx="91" cy="41" r="1" fill="rgba(215,75,30,1)"/>
+ <circle cx="92" cy="41" r="1" fill="rgba(214,75,30,1)"/>
+ <circle cx="93" cy="41" r="1" fill="rgba(213,74,29,1)"/>
+ <circle cx="94" cy="41" r="1" fill="rgba(210,70,26,1)"/>
+ <circle cx="95" cy="41" r="1" fill="rgba(207,65,23,1)"/>
+ <circle cx="96" cy="41" r="1" fill="rgba(214,65,22,0.976471)"/>
+ <circle cx="97" cy="41" r="1" fill="rgba(183,55,18,0.223529)"/>
+ <circle cx="98" cy="41" r="1" fill="rgba(62,30,13,0)"/>
+ <circle cx="99" cy="41" r="1" fill="rgba(64,34,16,0)"/>
+ <circle cx="100" cy="41" r="1" fill="rgba(73,41,20,0)"/>
+ <circle cx="101" cy="41" r="1" fill="rgba(80,47,25,0)"/>
+ <circle cx="102" cy="41" r="1" fill="rgba(85,52,29,0)"/>
+ <circle cx="103" cy="41" r="1" fill="rgba(91,58,33,0.0588235)"/>
+ <circle cx="104" cy="41" r="1" fill="rgba(96,64,37,0.356863)"/>
+ <circle cx="105" cy="41" r="1" fill="rgba(99,67,41,0.443137)"/>
+ <circle cx="106" cy="41" r="1" fill="rgba(98,66,40,0.0784314)"/>
+ <circle cx="107" cy="41" r="1" fill="rgba(97,65,38,0.121569)"/>
+ <circle cx="108" cy="41" r="1" fill="rgba(96,64,37,0.615686)"/>
+ <circle cx="109" cy="41" r="1" fill="rgba(92,59,34,1)"/>
+ <circle cx="110" cy="41" r="1" fill="rgba(87,55,30,1)"/>
+ <circle cx="111" cy="41" r="1" fill="rgba(81,48,26,0.988235)"/>
+ <circle cx="112" cy="41" r="1" fill="rgba(65,35,17,0.819608)"/>
+ <circle cx="113" cy="41" r="1" fill="rgba(40,17,6,0.529412)"/>
+ <circle cx="114" cy="41" r="1" fill="rgba(31,11,3,0.0588235)"/>
+ <circle cx="115" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="41" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="42" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="42" r="1" fill="rgba(17,4,0,0.0470588)"/>
+ <circle cx="13" cy="42" r="1" fill="rgba(21,7,1,0.203922)"/>
+ <circle cx="14" cy="42" r="1" fill="rgba(40,19,7,0.466667)"/>
+ <circle cx="15" cy="42" r="1" fill="rgba(53,27,11,0.596078)"/>
+ <circle cx="16" cy="42" r="1" fill="rgba(58,31,14,0.482353)"/>
+ <circle cx="17" cy="42" r="1" fill="rgba(26,10,3,0.207843)"/>
+ <circle cx="18" cy="42" r="1" fill="rgba(42,20,7,0.176471)"/>
+ <circle cx="19" cy="42" r="1" fill="rgba(71,43,22,0.266667)"/>
+ <circle cx="20" cy="42" r="1" fill="rgba(80,49,26,0.388235)"/>
+ <circle cx="21" cy="42" r="1" fill="rgba(98,66,40,0.607843)"/>
+ <circle cx="22" cy="42" r="1" fill="rgba(101,68,42,0.956863)"/>
+ <circle cx="23" cy="42" r="1" fill="rgba(94,62,36,1)"/>
+ <circle cx="24" cy="42" r="1" fill="rgba(88,56,32,1)"/>
+ <circle cx="25" cy="42" r="1" fill="rgba(83,51,27,1)"/>
+ <circle cx="26" cy="42" r="1" fill="rgba(77,46,24,1)"/>
+ <circle cx="27" cy="42" r="1" fill="rgba(73,41,20,1)"/>
+ <circle cx="28" cy="42" r="1" fill="rgba(67,35,16,1)"/>
+ <circle cx="29" cy="42" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="30" cy="42" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="31" cy="42" r="1" fill="rgba(43,23,11,1)"/>
+ <circle cx="32" cy="42" r="1" fill="rgba(164,87,37,1)"/>
+ <circle cx="33" cy="42" r="1" fill="rgba(255,159,79,1)"/>
+ <circle cx="34" cy="42" r="1" fill="rgba(255,159,79,1)"/>
+ <circle cx="35" cy="42" r="1" fill="rgba(255,157,71,1)"/>
+ <circle cx="36" cy="42" r="1" fill="rgba(255,154,61,1)"/>
+ <circle cx="37" cy="42" r="1" fill="rgba(254,154,62,1)"/>
+ <circle cx="38" cy="42" r="1" fill="rgba(253,153,63,1)"/>
+ <circle cx="39" cy="42" r="1" fill="rgba(252,151,60,1)"/>
+ <circle cx="40" cy="42" r="1" fill="rgba(252,148,56,1)"/>
+ <circle cx="41" cy="42" r="1" fill="rgba(251,144,50,1)"/>
+ <circle cx="42" cy="42" r="1" fill="rgba(250,141,46,1)"/>
+ <circle cx="43" cy="42" r="1" fill="rgba(250,137,42,1)"/>
+ <circle cx="44" cy="42" r="1" fill="rgba(250,134,37,1)"/>
+ <circle cx="45" cy="42" r="1" fill="rgba(250,133,33,1)"/>
+ <circle cx="46" cy="42" r="1" fill="rgba(251,131,30,1)"/>
+ <circle cx="47" cy="42" r="1" fill="rgba(251,128,26,1)"/>
+ <circle cx="48" cy="42" r="1" fill="rgba(252,125,20,1)"/>
+ <circle cx="49" cy="42" r="1" fill="rgba(253,120,10,1)"/>
+ <circle cx="50" cy="42" r="1" fill="rgba(255,118,1,1)"/>
+ <circle cx="51" cy="42" r="1" fill="rgba(242,101,0,1)"/>
+ <circle cx="52" cy="42" r="1" fill="rgba(147,47,0,1)"/>
+ <circle cx="53" cy="42" r="1" fill="rgba(7,0,0,1)"/>
+ <circle cx="54" cy="42" r="1" fill="rgba(21,13,7,1)"/>
+ <circle cx="55" cy="42" r="1" fill="rgba(141,110,80,1)"/>
+ <circle cx="56" cy="42" r="1" fill="rgba(225,213,200,1)"/>
+ <circle cx="57" cy="42" r="1" fill="rgba(255,254,254,1)"/>
+ <circle cx="58" cy="42" r="1" fill="rgba(250,250,252,1)"/>
+ <circle cx="59" cy="42" r="1" fill="rgba(214,204,196,1)"/>
+ <circle cx="60" cy="42" r="1" fill="rgba(175,158,142,1)"/>
+ <circle cx="61" cy="42" r="1" fill="rgba(130,105,86,1)"/>
+ <circle cx="62" cy="42" r="1" fill="rgba(90,64,45,1)"/>
+ <circle cx="63" cy="42" r="1" fill="rgba(73,43,24,1)"/>
+ <circle cx="64" cy="42" r="1" fill="rgba(59,29,13,1)"/>
+ <circle cx="65" cy="42" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="42" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="67" cy="42" r="1" fill="rgba(50,23,9,1)"/>
+ <circle cx="68" cy="42" r="1" fill="rgba(12,3,0,1)"/>
+ <circle cx="69" cy="42" r="1" fill="black"/>
+ <circle cx="70" cy="42" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="71" cy="42" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="72" cy="42" r="1" fill="rgba(4,1,0,1)"/>
+ <circle cx="73" cy="42" r="1" fill="rgba(12,5,1,1)"/>
+ <circle cx="74" cy="42" r="1" fill="rgba(17,8,3,1)"/>
+ <circle cx="75" cy="42" r="1" fill="rgba(24,13,6,1)"/>
+ <circle cx="76" cy="42" r="1" fill="rgba(31,19,9,1)"/>
+ <circle cx="77" cy="42" r="1" fill="rgba(15,13,5,1)"/>
+ <circle cx="78" cy="42" r="1" fill="black"/>
+ <circle cx="79" cy="42" r="1" fill="rgba(103,22,6,1)"/>
+ <circle cx="80" cy="42" r="1" fill="rgba(219,155,124,1)"/>
+ <circle cx="81" cy="42" r="1" fill="rgba(244,175,147,1)"/>
+ <circle cx="82" cy="42" r="1" fill="rgba(207,50,19,1)"/>
+ <circle cx="83" cy="42" r="1" fill="rgba(203,33,8,1)"/>
+ <circle cx="84" cy="42" r="1" fill="rgba(207,48,16,1)"/>
+ <circle cx="85" cy="42" r="1" fill="rgba(210,53,19,1)"/>
+ <circle cx="86" cy="42" r="1" fill="rgba(211,58,22,1)"/>
+ <circle cx="87" cy="42" r="1" fill="rgba(213,63,25,1)"/>
+ <circle cx="88" cy="42" r="1" fill="rgba(214,68,27,1)"/>
+ <circle cx="89" cy="42" r="1" fill="rgba(215,73,30,1)"/>
+ <circle cx="90" cy="42" r="1" fill="rgba(217,77,33,1)"/>
+ <circle cx="91" cy="42" r="1" fill="rgba(217,81,34,1)"/>
+ <circle cx="92" cy="42" r="1" fill="rgba(217,82,35,1)"/>
+ <circle cx="93" cy="42" r="1" fill="rgba(216,81,34,1)"/>
+ <circle cx="94" cy="42" r="1" fill="rgba(214,77,31,1)"/>
+ <circle cx="95" cy="42" r="1" fill="rgba(211,73,28,1)"/>
+ <circle cx="96" cy="42" r="1" fill="rgba(216,70,25,1)"/>
+ <circle cx="97" cy="42" r="1" fill="rgba(172,55,19,0.882353)"/>
+ <circle cx="98" cy="42" r="1" fill="rgba(53,27,11,0.709804)"/>
+ <circle cx="99" cy="42" r="1" fill="rgba(64,34,16,0.643137)"/>
+ <circle cx="100" cy="42" r="1" fill="rgba(73,41,20,0.6)"/>
+ <circle cx="101" cy="42" r="1" fill="rgba(78,46,24,0.639216)"/>
+ <circle cx="102" cy="42" r="1" fill="rgba(84,51,28,0.729412)"/>
+ <circle cx="103" cy="42" r="1" fill="rgba(88,56,31,0.886275)"/>
+ <circle cx="104" cy="42" r="1" fill="rgba(93,60,35,1)"/>
+ <circle cx="105" cy="42" r="1" fill="rgba(96,63,37,1)"/>
+ <circle cx="106" cy="42" r="1" fill="rgba(96,64,38,0.894118)"/>
+ <circle cx="107" cy="42" r="1" fill="rgba(95,63,37,0.921569)"/>
+ <circle cx="108" cy="42" r="1" fill="rgba(92,59,34,1)"/>
+ <circle cx="109" cy="42" r="1" fill="rgba(88,56,32,1)"/>
+ <circle cx="110" cy="42" r="1" fill="rgba(80,48,25,0.886275)"/>
+ <circle cx="111" cy="42" r="1" fill="rgba(42,19,7,0.517647)"/>
+ <circle cx="112" cy="42" r="1" fill="rgba(10,2,0,0.411765)"/>
+ <circle cx="113" cy="42" r="1" fill="rgba(15,2,0,0.298039)"/>
+ <circle cx="114" cy="42" r="1" fill="rgba(31,12,3,0.0431373)"/>
+ <circle cx="115" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="42" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="43" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="43" r="1" fill="rgba(29,11,3,0.00392157)"/>
+ <circle cx="14" cy="43" r="1" fill="rgba(29,10,3,0.0823529)"/>
+ <circle cx="15" cy="43" r="1" fill="rgba(12,4,0,0.266667)"/>
+ <circle cx="16" cy="43" r="1" fill="rgba(0,0,0,0.407843)"/>
+ <circle cx="17" cy="43" r="1" fill="rgba(0,0,0,0.4)"/>
+ <circle cx="18" cy="43" r="1" fill="rgba(0,0,0,0.337255)"/>
+ <circle cx="19" cy="43" r="1" fill="rgba(0,0,0,0.258824)"/>
+ <circle cx="20" cy="43" r="1" fill="rgba(31,12,4,0.0980392)"/>
+ <circle cx="21" cy="43" r="1" fill="rgba(51,26,11,0)"/>
+ <circle cx="22" cy="43" r="1" fill="rgba(70,42,21,0.176471)"/>
+ <circle cx="23" cy="43" r="1" fill="rgba(86,54,30,0.627451)"/>
+ <circle cx="24" cy="43" r="1" fill="rgba(84,52,29,0.901961)"/>
+ <circle cx="25" cy="43" r="1" fill="rgba(83,50,27,0.968627)"/>
+ <circle cx="26" cy="43" r="1" fill="rgba(78,46,24,0.917647)"/>
+ <circle cx="27" cy="43" r="1" fill="rgba(70,40,20,0.584314)"/>
+ <circle cx="28" cy="43" r="1" fill="rgba(65,34,16,0.396078)"/>
+ <circle cx="29" cy="43" r="1" fill="rgba(63,32,14,0.478431)"/>
+ <circle cx="30" cy="43" r="1" fill="rgba(42,22,10,0.737255)"/>
+ <circle cx="31" cy="43" r="1" fill="rgba(85,43,20,0.960784)"/>
+ <circle cx="32" cy="43" r="1" fill="rgba(239,153,91,1)"/>
+ <circle cx="33" cy="43" r="1" fill="rgba(255,176,111,1)"/>
+ <circle cx="34" cy="43" r="1" fill="rgba(255,173,105,1)"/>
+ <circle cx="35" cy="43" r="1" fill="rgba(255,169,92,1)"/>
+ <circle cx="36" cy="43" r="1" fill="rgba(255,162,77,1)"/>
+ <circle cx="37" cy="43" r="1" fill="rgba(254,160,72,1)"/>
+ <circle cx="38" cy="43" r="1" fill="rgba(253,159,72,1)"/>
+ <circle cx="39" cy="43" r="1" fill="rgba(252,156,68,1)"/>
+ <circle cx="40" cy="43" r="1" fill="rgba(252,152,63,1)"/>
+ <circle cx="41" cy="43" r="1" fill="rgba(251,148,56,1)"/>
+ <circle cx="42" cy="43" r="1" fill="rgba(251,145,51,1)"/>
+ <circle cx="43" cy="43" r="1" fill="rgba(250,141,47,1)"/>
+ <circle cx="44" cy="43" r="1" fill="rgba(250,138,42,1)"/>
+ <circle cx="45" cy="43" r="1" fill="rgba(250,136,38,1)"/>
+ <circle cx="46" cy="43" r="1" fill="rgba(251,136,36,1)"/>
+ <circle cx="47" cy="43" r="1" fill="rgba(251,135,32,1)"/>
+ <circle cx="48" cy="43" r="1" fill="rgba(252,132,25,1)"/>
+ <circle cx="49" cy="43" r="1" fill="rgba(252,127,15,1)"/>
+ <circle cx="50" cy="43" r="1" fill="rgba(253,120,3,1)"/>
+ <circle cx="51" cy="43" r="1" fill="rgba(255,116,0,1)"/>
+ <circle cx="52" cy="43" r="1" fill="rgba(255,112,0,1)"/>
+ <circle cx="53" cy="43" r="1" fill="rgba(217,83,0,1)"/>
+ <circle cx="54" cy="43" r="1" fill="rgba(115,32,0,1)"/>
+ <circle cx="55" cy="43" r="1" fill="black"/>
+ <circle cx="56" cy="43" r="1" fill="rgba(40,25,13,1)"/>
+ <circle cx="57" cy="43" r="1" fill="rgba(145,115,86,1)"/>
+ <circle cx="58" cy="43" r="1" fill="rgba(225,213,199,1)"/>
+ <circle cx="59" cy="43" r="1" fill="rgba(240,238,236,1)"/>
+ <circle cx="60" cy="43" r="1" fill="rgba(207,196,188,1)"/>
+ <circle cx="61" cy="43" r="1" fill="rgba(162,141,123,1)"/>
+ <circle cx="62" cy="43" r="1" fill="rgba(111,86,66,1)"/>
+ <circle cx="63" cy="43" r="1" fill="rgba(81,53,35,1)"/>
+ <circle cx="64" cy="43" r="1" fill="rgba(63,32,14,1)"/>
+ <circle cx="65" cy="43" r="1" fill="rgba(61,30,13,1)"/>
+ <circle cx="66" cy="43" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="67" cy="43" r="1" fill="rgba(47,21,8,1)"/>
+ <circle cx="68" cy="43" r="1" fill="rgba(12,2,0,1)"/>
+ <circle cx="69" cy="43" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="70" cy="43" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="71" cy="43" r="1" fill="black"/>
+ <circle cx="72" cy="43" r="1" fill="black"/>
+ <circle cx="73" cy="43" r="1" fill="rgba(12,3,0,1)"/>
+ <circle cx="74" cy="43" r="1" fill="rgba(26,13,5,1)"/>
+ <circle cx="75" cy="43" r="1" fill="rgba(21,13,5,1)"/>
+ <circle cx="76" cy="43" r="1" fill="rgba(15,0,0,1)"/>
+ <circle cx="77" cy="43" r="1" fill="rgba(83,3,0,1)"/>
+ <circle cx="78" cy="43" r="1" fill="rgba(184,91,54,1)"/>
+ <circle cx="79" cy="43" r="1" fill="rgba(247,194,171,1)"/>
+ <circle cx="80" cy="43" r="1" fill="rgba(234,140,103,1)"/>
+ <circle cx="81" cy="43" r="1" fill="rgba(205,34,8,1)"/>
+ <circle cx="82" cy="43" r="1" fill="rgba(204,35,9,1)"/>
+ <circle cx="83" cy="43" r="1" fill="rgba(207,45,16,1)"/>
+ <circle cx="84" cy="43" r="1" fill="rgba(210,51,18,1)"/>
+ <circle cx="85" cy="43" r="1" fill="rgba(210,57,21,1)"/>
+ <circle cx="86" cy="43" r="1" fill="rgba(212,62,24,1)"/>
+ <circle cx="87" cy="43" r="1" fill="rgba(214,67,27,1)"/>
+ <circle cx="88" cy="43" r="1" fill="rgba(216,71,30,1)"/>
+ <circle cx="89" cy="43" r="1" fill="rgba(217,76,33,1)"/>
+ <circle cx="90" cy="43" r="1" fill="rgba(218,81,36,1)"/>
+ <circle cx="91" cy="43" r="1" fill="rgba(219,85,38,1)"/>
+ <circle cx="92" cy="43" r="1" fill="rgba(220,87,40,1)"/>
+ <circle cx="93" cy="43" r="1" fill="rgba(219,88,39,1)"/>
+ <circle cx="94" cy="43" r="1" fill="rgba(217,85,37,1)"/>
+ <circle cx="95" cy="43" r="1" fill="rgba(214,80,33,1)"/>
+ <circle cx="96" cy="43" r="1" fill="rgba(214,76,30,1)"/>
+ <circle cx="97" cy="43" r="1" fill="rgba(213,72,27,1)"/>
+ <circle cx="98" cy="43" r="1" fill="rgba(101,37,14,1)"/>
+ <circle cx="99" cy="43" r="1" fill="rgba(50,29,13,1)"/>
+ <circle cx="100" cy="43" r="1" fill="rgba(69,37,18,1)"/>
+ <circle cx="101" cy="43" r="1" fill="rgba(74,42,21,1)"/>
+ <circle cx="102" cy="43" r="1" fill="rgba(80,47,24,1)"/>
+ <circle cx="103" cy="43" r="1" fill="rgba(84,51,27,1)"/>
+ <circle cx="104" cy="43" r="1" fill="rgba(86,54,30,1)"/>
+ <circle cx="105" cy="43" r="1" fill="rgba(90,56,32,1)"/>
+ <circle cx="106" cy="43" r="1" fill="rgba(90,57,33,1)"/>
+ <circle cx="107" cy="43" r="1" fill="rgba(88,57,31,1)"/>
+ <circle cx="108" cy="43" r="1" fill="rgba(86,54,30,1)"/>
+ <circle cx="109" cy="43" r="1" fill="rgba(83,50,27,0.886275)"/>
+ <circle cx="110" cy="43" r="1" fill="rgba(42,18,7,0.396078)"/>
+ <circle cx="111" cy="43" r="1" fill="rgba(0,0,0,0.423529)"/>
+ <circle cx="112" cy="43" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="113" cy="43" r="1" fill="rgba(21,6,1,0.294118)"/>
+ <circle cx="114" cy="43" r="1" fill="rgba(34,14,4,0.0235294)"/>
+ <circle cx="115" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="43" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="44" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="44" r="1" fill="rgba(33,12,3,0.0313725)"/>
+ <circle cx="16" cy="44" r="1" fill="rgba(28,10,3,0.207843)"/>
+ <circle cx="17" cy="44" r="1" fill="rgba(12,3,0,0.415686)"/>
+ <circle cx="18" cy="44" r="1" fill="rgba(0,0,0,0.482353)"/>
+ <circle cx="19" cy="44" r="1" fill="rgba(0,0,0,0.47451)"/>
+ <circle cx="20" cy="44" r="1" fill="rgba(10,3,0,0.423529)"/>
+ <circle cx="21" cy="44" r="1" fill="rgba(29,12,4,0.290196)"/>
+ <circle cx="22" cy="44" r="1" fill="rgba(29,12,4,0.0980392)"/>
+ <circle cx="23" cy="44" r="1" fill="rgba(33,14,5,0.00392157)"/>
+ <circle cx="24" cy="44" r="1" fill="rgba(51,27,11,0.0588235)"/>
+ <circle cx="25" cy="44" r="1" fill="rgba(69,40,19,0.152941)"/>
+ <circle cx="26" cy="44" r="1" fill="rgba(61,32,14,0.0627451)"/>
+ <circle cx="27" cy="44" r="1" fill="rgba(54,24,10,0)"/>
+ <circle cx="28" cy="44" r="1" fill="rgba(55,21,8,0)"/>
+ <circle cx="29" cy="44" r="1" fill="rgba(42,21,9,0)"/>
+ <circle cx="30" cy="44" r="1" fill="rgba(113,55,24,0)"/>
+ <circle cx="31" cy="44" r="1" fill="rgba(210,130,72,0.6)"/>
+ <circle cx="32" cy="44" r="1" fill="rgba(255,186,134,1)"/>
+ <circle cx="33" cy="44" r="1" fill="rgba(255,185,134,1)"/>
+ <circle cx="34" cy="44" r="1" fill="rgba(255,182,119,1)"/>
+ <circle cx="35" cy="44" r="1" fill="rgba(255,176,106,1)"/>
+ <circle cx="36" cy="44" r="1" fill="rgba(255,169,91,1)"/>
+ <circle cx="37" cy="44" r="1" fill="rgba(254,165,83,1)"/>
+ <circle cx="38" cy="44" r="1" fill="rgba(253,164,82,1)"/>
+ <circle cx="39" cy="44" r="1" fill="rgba(252,160,77,1)"/>
+ <circle cx="40" cy="44" r="1" fill="rgba(252,156,70,1)"/>
+ <circle cx="41" cy="44" r="1" fill="rgba(251,151,62,1)"/>
+ <circle cx="42" cy="44" r="1" fill="rgba(251,147,56,1)"/>
+ <circle cx="43" cy="44" r="1" fill="rgba(250,143,49,1)"/>
+ <circle cx="44" cy="44" r="1" fill="rgba(250,139,45,1)"/>
+ <circle cx="45" cy="44" r="1" fill="rgba(251,138,42,1)"/>
+ <circle cx="46" cy="44" r="1" fill="rgba(251,138,39,1)"/>
+ <circle cx="47" cy="44" r="1" fill="rgba(251,137,36,1)"/>
+ <circle cx="48" cy="44" r="1" fill="rgba(252,136,29,1)"/>
+ <circle cx="49" cy="44" r="1" fill="rgba(252,132,20,1)"/>
+ <circle cx="50" cy="44" r="1" fill="rgba(253,126,5,1)"/>
+ <circle cx="51" cy="44" r="1" fill="rgba(252,120,0,1)"/>
+ <circle cx="52" cy="44" r="1" fill="rgba(253,114,0,1)"/>
+ <circle cx="53" cy="44" r="1" fill="rgba(255,110,0,1)"/>
+ <circle cx="54" cy="44" r="1" fill="rgba(255,102,0,1)"/>
+ <circle cx="55" cy="44" r="1" fill="rgba(200,68,0,1)"/>
+ <circle cx="56" cy="44" r="1" fill="rgba(101,21,0,1)"/>
+ <circle cx="57" cy="44" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="58" cy="44" r="1" fill="rgba(34,22,10,1)"/>
+ <circle cx="59" cy="44" r="1" fill="rgba(129,98,69,1)"/>
+ <circle cx="60" cy="44" r="1" fill="rgba(182,161,140,1)"/>
+ <circle cx="61" cy="44" r="1" fill="rgba(186,170,156,1)"/>
+ <circle cx="62" cy="44" r="1" fill="rgba(148,127,108,1)"/>
+ <circle cx="63" cy="44" r="1" fill="rgba(98,72,53,1)"/>
+ <circle cx="64" cy="44" r="1" fill="rgba(68,38,20,1)"/>
+ <circle cx="65" cy="44" r="1" fill="rgba(59,28,12,1)"/>
+ <circle cx="66" cy="44" r="1" fill="rgba(62,31,14,1)"/>
+ <circle cx="67" cy="44" r="1" fill="rgba(45,20,7,1)"/>
+ <circle cx="68" cy="44" r="1" fill="black"/>
+ <circle cx="69" cy="44" r="1" fill="black"/>
+ <circle cx="70" cy="44" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="71" cy="44" r="1" fill="rgba(17,5,1,1)"/>
+ <circle cx="72" cy="44" r="1" fill="rgba(28,12,4,1)"/>
+ <circle cx="73" cy="44" r="1" fill="rgba(21,12,4,1)"/>
+ <circle cx="74" cy="44" r="1" fill="rgba(24,0,0,1)"/>
+ <circle cx="75" cy="44" r="1" fill="rgba(87,12,2,1)"/>
+ <circle cx="76" cy="44" r="1" fill="rgba(180,85,48,1)"/>
+ <circle cx="77" cy="44" r="1" fill="rgba(239,168,135,1)"/>
+ <circle cx="78" cy="44" r="1" fill="rgba(242,161,126,1)"/>
+ <circle cx="79" cy="44" r="1" fill="rgba(217,72,33,1)"/>
+ <circle cx="80" cy="44" r="1" fill="rgba(205,26,3,1)"/>
+ <circle cx="81" cy="44" r="1" fill="rgba(207,40,10,1)"/>
+ <circle cx="82" cy="44" r="1" fill="rgba(208,45,14,1)"/>
+ <circle cx="83" cy="44" r="1" fill="rgba(209,49,17,1)"/>
+ <circle cx="84" cy="44" r="1" fill="rgba(210,54,20,1)"/>
+ <circle cx="85" cy="44" r="1" fill="rgba(213,60,23,1)"/>
+ <circle cx="86" cy="44" r="1" fill="rgba(214,65,27,1)"/>
+ <circle cx="87" cy="44" r="1" fill="rgba(215,69,30,1)"/>
+ <circle cx="88" cy="44" r="1" fill="rgba(217,74,32,1)"/>
+ <circle cx="89" cy="44" r="1" fill="rgba(218,78,34,1)"/>
+ <circle cx="90" cy="44" r="1" fill="rgba(219,83,37,1)"/>
+ <circle cx="91" cy="44" r="1" fill="rgba(221,87,40,1)"/>
+ <circle cx="92" cy="44" r="1" fill="rgba(221,90,42,1)"/>
+ <circle cx="93" cy="44" r="1" fill="rgba(222,92,43,1)"/>
+ <circle cx="94" cy="44" r="1" fill="rgba(221,92,43,1)"/>
+ <circle cx="95" cy="44" r="1" fill="rgba(219,88,39,1)"/>
+ <circle cx="96" cy="44" r="1" fill="rgba(216,83,35,1)"/>
+ <circle cx="97" cy="44" r="1" fill="rgba(222,81,32,1)"/>
+ <circle cx="98" cy="44" r="1" fill="rgba(178,63,24,0.996078)"/>
+ <circle cx="99" cy="44" r="1" fill="rgba(51,26,11,0.890196)"/>
+ <circle cx="100" cy="44" r="1" fill="rgba(53,30,14,0.827451)"/>
+ <circle cx="101" cy="44" r="1" fill="rgba(70,39,19,0.827451)"/>
+ <circle cx="102" cy="44" r="1" fill="rgba(74,44,22,0.827451)"/>
+ <circle cx="103" cy="44" r="1" fill="rgba(80,47,24,0.909804)"/>
+ <circle cx="104" cy="44" r="1" fill="rgba(83,50,27,0.956863)"/>
+ <circle cx="105" cy="44" r="1" fill="rgba(85,53,29,0.992157)"/>
+ <circle cx="106" cy="44" r="1" fill="rgba(85,52,29,1)"/>
+ <circle cx="107" cy="44" r="1" fill="rgba(84,52,28,1)"/>
+ <circle cx="108" cy="44" r="1" fill="rgba(83,49,27,0.913725)"/>
+ <circle cx="109" cy="44" r="1" fill="rgba(55,29,13,0.368627)"/>
+ <circle cx="110" cy="44" r="1" fill="rgba(10,2,0,0.356863)"/>
+ <circle cx="111" cy="44" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="112" cy="44" r="1" fill="rgba(0,0,0,0.47451)"/>
+ <circle cx="113" cy="44" r="1" fill="rgba(17,5,1,0.286275)"/>
+ <circle cx="114" cy="44" r="1" fill="rgba(28,11,3,0.0156863)"/>
+ <circle cx="115" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="44" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="45" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="45" r="1" fill="rgba(34,14,4,0.00392157)"/>
+ <circle cx="17" cy="45" r="1" fill="rgba(36,15,5,0.137255)"/>
+ <circle cx="18" cy="45" r="1" fill="rgba(22,8,2,0.34902)"/>
+ <circle cx="19" cy="45" r="1" fill="rgba(7,1,0,0.45098)"/>
+ <circle cx="20" cy="45" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="21" cy="45" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="22" cy="45" r="1" fill="rgba(12,3,0,0.415686)"/>
+ <circle cx="23" cy="45" r="1" fill="rgba(17,5,1,0.305882)"/>
+ <circle cx="24" cy="45" r="1" fill="rgba(39,18,7,0.184314)"/>
+ <circle cx="25" cy="45" r="1" fill="rgba(51,27,11,0.0705882)"/>
+ <circle cx="26" cy="45" r="1" fill="rgba(39,18,6,0.0588235)"/>
+ <circle cx="27" cy="45" r="1" fill="rgba(37,15,5,0.0745098)"/>
+ <circle cx="28" cy="45" r="1" fill="rgba(43,16,6,0.0470588)"/>
+ <circle cx="29" cy="45" r="1" fill="rgba(0,1,1,0)"/>
+ <circle cx="30" cy="45" r="1" fill="rgba(163,77,27,0.0745098)"/>
+ <circle cx="31" cy="45" r="1" fill="rgba(255,171,94,0.886275)"/>
+ <circle cx="32" cy="45" r="1" fill="rgba(255,178,123,1)"/>
+ <circle cx="33" cy="45" r="1" fill="rgba(255,185,129,1)"/>
+ <circle cx="34" cy="45" r="1" fill="rgba(255,182,119,1)"/>
+ <circle cx="35" cy="45" r="1" fill="rgba(255,178,109,1)"/>
+ <circle cx="36" cy="45" r="1" fill="rgba(255,173,98,1)"/>
+ <circle cx="37" cy="45" r="1" fill="rgba(254,171,94,1)"/>
+ <circle cx="38" cy="45" r="1" fill="rgba(253,168,90,1)"/>
+ <circle cx="39" cy="45" r="1" fill="rgba(252,164,83,1)"/>
+ <circle cx="40" cy="45" r="1" fill="rgba(252,159,74,1)"/>
+ <circle cx="41" cy="45" r="1" fill="rgba(251,154,66,1)"/>
+ <circle cx="42" cy="45" r="1" fill="rgba(251,149,58,1)"/>
+ <circle cx="43" cy="45" r="1" fill="rgba(251,145,51,1)"/>
+ <circle cx="44" cy="45" r="1" fill="rgba(251,141,46,1)"/>
+ <circle cx="45" cy="45" r="1" fill="rgba(251,139,42,1)"/>
+ <circle cx="46" cy="45" r="1" fill="rgba(251,138,40,1)"/>
+ <circle cx="47" cy="45" r="1" fill="rgba(252,137,36,1)"/>
+ <circle cx="48" cy="45" r="1" fill="rgba(252,136,30,1)"/>
+ <circle cx="49" cy="45" r="1" fill="rgba(252,132,21,1)"/>
+ <circle cx="50" cy="45" r="1" fill="rgba(253,127,7,1)"/>
+ <circle cx="51" cy="45" r="1" fill="rgba(253,122,0,1)"/>
+ <circle cx="52" cy="45" r="1" fill="rgba(252,118,0,1)"/>
+ <circle cx="53" cy="45" r="1" fill="rgba(252,112,0,1)"/>
+ <circle cx="54" cy="45" r="1" fill="rgba(251,105,0,1)"/>
+ <circle cx="55" cy="45" r="1" fill="rgba(255,100,0,1)"/>
+ <circle cx="56" cy="45" r="1" fill="rgba(251,88,0,1)"/>
+ <circle cx="57" cy="45" r="1" fill="rgba(205,60,0,1)"/>
+ <circle cx="58" cy="45" r="1" fill="rgba(116,23,0,1)"/>
+ <circle cx="59" cy="45" r="1" fill="rgba(21,0,0,1)"/>
+ <circle cx="60" cy="45" r="1" fill="rgba(12,10,4,1)"/>
+ <circle cx="61" cy="45" r="1" fill="rgba(82,55,33,1)"/>
+ <circle cx="62" cy="45" r="1" fill="rgba(119,90,64,1)"/>
+ <circle cx="63" cy="45" r="1" fill="rgba(110,83,61,1)"/>
+ <circle cx="64" cy="45" r="1" fill="rgba(74,43,24,1)"/>
+ <circle cx="65" cy="45" r="1" fill="rgba(62,30,13,1)"/>
+ <circle cx="66" cy="45" r="1" fill="rgba(58,29,13,1)"/>
+ <circle cx="67" cy="45" r="1" fill="rgba(29,10,3,1)"/>
+ <circle cx="68" cy="45" r="1" fill="rgba(19,5,1,1)"/>
+ <circle cx="69" cy="45" r="1" fill="rgba(29,11,3,1)"/>
+ <circle cx="70" cy="45" r="1" fill="rgba(29,16,6,1)"/>
+ <circle cx="71" cy="45" r="1" fill="rgba(22,11,4,1)"/>
+ <circle cx="72" cy="45" r="1" fill="rgba(43,4,0,1)"/>
+ <circle cx="73" cy="45" r="1" fill="rgba(110,29,8,1)"/>
+ <circle cx="74" cy="45" r="1" fill="rgba(190,99,60,1)"/>
+ <circle cx="75" cy="45" r="1" fill="rgba(238,157,120,1)"/>
+ <circle cx="76" cy="45" r="1" fill="rgba(239,141,100,1)"/>
+ <circle cx="77" cy="45" r="1" fill="rgba(219,73,32,1)"/>
+ <circle cx="78" cy="45" r="1" fill="rgba(207,26,3,1)"/>
+ <circle cx="79" cy="45" r="1" fill="rgba(208,31,5,1)"/>
+ <circle cx="80" cy="45" r="1" fill="rgba(210,41,10,1)"/>
+ <circle cx="81" cy="45" r="1" fill="rgba(210,45,13,1)"/>
+ <circle cx="82" cy="45" r="1" fill="rgba(210,47,16,1)"/>
+ <circle cx="83" cy="45" r="1" fill="rgba(211,51,19,1)"/>
+ <circle cx="84" cy="45" r="1" fill="rgba(212,56,22,1)"/>
+ <circle cx="85" cy="45" r="1" fill="rgba(214,61,24,1)"/>
+ <circle cx="86" cy="45" r="1" fill="rgba(217,67,27,1)"/>
+ <circle cx="87" cy="45" r="1" fill="rgba(224,74,33,1)"/>
+ <circle cx="88" cy="45" r="1" fill="rgba(227,78,35,1)"/>
+ <circle cx="89" cy="45" r="1" fill="rgba(222,80,36,1)"/>
+ <circle cx="90" cy="45" r="1" fill="rgba(219,83,37,1)"/>
+ <circle cx="91" cy="45" r="1" fill="rgba(221,87,40,1)"/>
+ <circle cx="92" cy="45" r="1" fill="rgba(221,91,43,1)"/>
+ <circle cx="93" cy="45" r="1" fill="rgba(222,95,46,1)"/>
+ <circle cx="94" cy="45" r="1" fill="rgba(223,96,47,1)"/>
+ <circle cx="95" cy="45" r="1" fill="rgba(222,95,45,1)"/>
+ <circle cx="96" cy="45" r="1" fill="rgba(220,90,41,1)"/>
+ <circle cx="97" cy="45" r="1" fill="rgba(219,86,37,1)"/>
+ <circle cx="98" cy="45" r="1" fill="rgba(224,85,35,0.988235)"/>
+ <circle cx="99" cy="45" r="1" fill="rgba(185,70,27,0.298039)"/>
+ <circle cx="100" cy="45" r="1" fill="rgba(104,44,18,0.0235294)"/>
+ <circle cx="101" cy="45" r="1" fill="rgba(59,33,16,0.027451)"/>
+ <circle cx="102" cy="45" r="1" fill="rgba(73,28,12,0.027451)"/>
+ <circle cx="103" cy="45" r="1" fill="rgba(62,32,14,0.0509804)"/>
+ <circle cx="104" cy="45" r="1" fill="rgba(65,36,17,0.113725)"/>
+ <circle cx="105" cy="45" r="1" fill="rgba(54,27,12,0.231373)"/>
+ <circle cx="106" cy="45" r="1" fill="rgba(59,32,14,0.403922)"/>
+ <circle cx="107" cy="45" r="1" fill="rgba(62,33,15,0.486275)"/>
+ <circle cx="108" cy="45" r="1" fill="rgba(58,30,13,0.262745)"/>
+ <circle cx="109" cy="45" r="1" fill="rgba(22,9,2,0.294118)"/>
+ <circle cx="110" cy="45" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="111" cy="45" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="112" cy="45" r="1" fill="rgba(4,0,0,0.443137)"/>
+ <circle cx="113" cy="45" r="1" fill="rgba(21,6,1,0.235294)"/>
+ <circle cx="114" cy="45" r="1" fill="rgba(29,11,3,0.0156863)"/>
+ <circle cx="115" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="45" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="46" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="46" r="1" fill="rgba(43,20,8,0.0745098)"/>
+ <circle cx="19" cy="46" r="1" fill="rgba(36,16,5,0.223529)"/>
+ <circle cx="20" cy="46" r="1" fill="rgba(33,14,4,0.298039)"/>
+ <circle cx="21" cy="46" r="1" fill="rgba(26,10,3,0.294118)"/>
+ <circle cx="22" cy="46" r="1" fill="rgba(12,3,0,0.313725)"/>
+ <circle cx="23" cy="46" r="1" fill="rgba(19,6,1,0.407843)"/>
+ <circle cx="24" cy="46" r="1" fill="rgba(19,6,1,0.443137)"/>
+ <circle cx="25" cy="46" r="1" fill="rgba(22,8,2,0.388235)"/>
+ <circle cx="26" cy="46" r="1" fill="rgba(22,8,2,0.360784)"/>
+ <circle cx="27" cy="46" r="1" fill="rgba(17,5,1,0.360784)"/>
+ <circle cx="28" cy="46" r="1" fill="rgba(19,6,1,0.317647)"/>
+ <circle cx="29" cy="46" r="1" fill="rgba(12,4,1,0.12549)"/>
+ <circle cx="30" cy="46" r="1" fill="rgba(184,84,25,0.470588)"/>
+ <circle cx="31" cy="46" r="1" fill="rgba(255,155,73,1)"/>
+ <circle cx="32" cy="46" r="1" fill="rgba(255,167,97,1)"/>
+ <circle cx="33" cy="46" r="1" fill="rgba(255,176,108,1)"/>
+ <circle cx="34" cy="46" r="1" fill="rgba(255,178,108,1)"/>
+ <circle cx="35" cy="46" r="1" fill="rgba(255,175,101,1)"/>
+ <circle cx="36" cy="46" r="1" fill="rgba(255,173,96,1)"/>
+ <circle cx="37" cy="46" r="1" fill="rgba(254,173,99,1)"/>
+ <circle cx="38" cy="46" r="1" fill="rgba(253,170,93,1)"/>
+ <circle cx="39" cy="46" r="1" fill="rgba(252,165,85,1)"/>
+ <circle cx="40" cy="46" r="1" fill="rgba(252,159,76,1)"/>
+ <circle cx="41" cy="46" r="1" fill="rgba(251,154,66,1)"/>
+ <circle cx="42" cy="46" r="1" fill="rgba(251,149,59,1)"/>
+ <circle cx="43" cy="46" r="1" fill="rgba(251,145,51,1)"/>
+ <circle cx="44" cy="46" r="1" fill="rgba(251,141,45,1)"/>
+ <circle cx="45" cy="46" r="1" fill="rgba(251,138,42,1)"/>
+ <circle cx="46" cy="46" r="1" fill="rgba(251,136,37,1)"/>
+ <circle cx="47" cy="46" r="1" fill="rgba(251,135,34,1)"/>
+ <circle cx="48" cy="46" r="1" fill="rgba(252,133,28,1)"/>
+ <circle cx="49" cy="46" r="1" fill="rgba(253,131,20,1)"/>
+ <circle cx="50" cy="46" r="1" fill="rgba(253,127,7,1)"/>
+ <circle cx="51" cy="46" r="1" fill="rgba(253,122,0,1)"/>
+ <circle cx="52" cy="46" r="1" fill="rgba(252,119,0,1)"/>
+ <circle cx="53" cy="46" r="1" fill="rgba(252,115,0,1)"/>
+ <circle cx="54" cy="46" r="1" fill="rgba(250,109,0,1)"/>
+ <circle cx="55" cy="46" r="1" fill="rgba(249,101,0,1)"/>
+ <circle cx="56" cy="46" r="1" fill="rgba(248,93,0,1)"/>
+ <circle cx="57" cy="46" r="1" fill="rgba(252,87,0,1)"/>
+ <circle cx="58" cy="46" r="1" fill="rgba(250,78,0,1)"/>
+ <circle cx="59" cy="46" r="1" fill="rgba(216,57,0,1)"/>
+ <circle cx="60" cy="46" r="1" fill="rgba(140,27,0,1)"/>
+ <circle cx="61" cy="46" r="1" fill="rgba(47,2,0,1)"/>
+ <circle cx="62" cy="46" r="1" fill="black"/>
+ <circle cx="63" cy="46" r="1" fill="rgba(28,14,5,1)"/>
+ <circle cx="64" cy="46" r="1" fill="rgba(42,18,7,1)"/>
+ <circle cx="65" cy="46" r="1" fill="rgba(45,19,7,1)"/>
+ <circle cx="66" cy="46" r="1" fill="rgba(33,12,3,1)"/>
+ <circle cx="67" cy="46" r="1" fill="rgba(22,8,2,1)"/>
+ <circle cx="68" cy="46" r="1" fill="rgba(17,10,3,1)"/>
+ <circle cx="69" cy="46" r="1" fill="rgba(19,3,0,1)"/>
+ <circle cx="70" cy="46" r="1" fill="rgba(73,9,1,1)"/>
+ <circle cx="71" cy="46" r="1" fill="rgba(145,48,18,1)"/>
+ <circle cx="72" cy="46" r="1" fill="rgba(210,106,62,1)"/>
+ <circle cx="73" cy="46" r="1" fill="rgba(239,134,90,1)"/>
+ <circle cx="74" cy="46" r="1" fill="rgba(233,108,60,1)"/>
+ <circle cx="75" cy="46" r="1" fill="rgba(217,52,13,1)"/>
+ <circle cx="76" cy="46" r="1" fill="rgba(210,25,0,1)"/>
+ <circle cx="77" cy="46" r="1" fill="rgba(210,31,3,1)"/>
+ <circle cx="78" cy="46" r="1" fill="rgba(210,38,8,1)"/>
+ <circle cx="79" cy="46" r="1" fill="rgba(211,41,10,1)"/>
+ <circle cx="80" cy="46" r="1" fill="rgba(211,43,11,1)"/>
+ <circle cx="81" cy="46" r="1" fill="rgba(211,47,13,1)"/>
+ <circle cx="82" cy="46" r="1" fill="rgba(210,49,16,1)"/>
+ <circle cx="83" cy="46" r="1" fill="rgba(211,52,19,1)"/>
+ <circle cx="84" cy="46" r="1" fill="rgba(213,57,22,1)"/>
+ <circle cx="85" cy="46" r="1" fill="rgba(219,63,25,1)"/>
+ <circle cx="86" cy="46" r="1" fill="rgba(204,60,23,1)"/>
+ <circle cx="87" cy="46" r="1" fill="rgba(149,41,13,1)"/>
+ <circle cx="88" cy="46" r="1" fill="rgba(135,37,12,1)"/>
+ <circle cx="89" cy="46" r="1" fill="rgba(190,63,26,1)"/>
+ <circle cx="90" cy="46" r="1" fill="rgba(224,83,37,1)"/>
+ <circle cx="91" cy="46" r="1" fill="rgba(221,86,38,1)"/>
+ <circle cx="92" cy="46" r="1" fill="rgba(221,90,42,1)"/>
+ <circle cx="93" cy="46" r="1" fill="rgba(223,95,45,1)"/>
+ <circle cx="94" cy="46" r="1" fill="rgba(224,98,48,1)"/>
+ <circle cx="95" cy="46" r="1" fill="rgba(224,99,48,1)"/>
+ <circle cx="96" cy="46" r="1" fill="rgba(223,97,46,1)"/>
+ <circle cx="97" cy="46" r="1" fill="rgba(221,93,42,1)"/>
+ <circle cx="98" cy="46" r="1" fill="rgba(221,89,38,1)"/>
+ <circle cx="99" cy="46" r="1" fill="rgba(236,95,39,0.647059)"/>
+ <circle cx="100" cy="46" r="1" fill="rgba(142,51,18,0)"/>
+ <circle cx="101" cy="46" r="1" fill="rgba(26,12,4,0)"/>
+ <circle cx="102" cy="46" r="1" fill="rgba(71,14,4,0)"/>
+ <circle cx="103" cy="46" r="1" fill="rgba(40,16,5,0)"/>
+ <circle cx="104" cy="46" r="1" fill="rgba(37,17,6,0.0156863)"/>
+ <circle cx="105" cy="46" r="1" fill="rgba(19,6,1,0.0666667)"/>
+ <circle cx="106" cy="46" r="1" fill="rgba(33,14,4,0)"/>
+ <circle cx="107" cy="46" r="1" fill="rgba(34,15,5,0.0117647)"/>
+ <circle cx="108" cy="46" r="1" fill="rgba(29,12,3,0.266667)"/>
+ <circle cx="109" cy="46" r="1" fill="rgba(4,0,0,0.454902)"/>
+ <circle cx="110" cy="46" r="1" fill="rgba(0,0,0,0.462745)"/>
+ <circle cx="111" cy="46" r="1" fill="rgba(15,4,0,0.372549)"/>
+ <circle cx="112" cy="46" r="1" fill="rgba(22,7,1,0.223529)"/>
+ <circle cx="113" cy="46" r="1" fill="rgba(28,9,3,0.0666667)"/>
+ <circle cx="114" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="46" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="47" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="47" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="19" cy="47" r="1" fill="rgba(47,23,9,0.00784314)"/>
+ <circle cx="20" cy="47" r="1" fill="rgba(46,22,9,0.0392157)"/>
+ <circle cx="21" cy="47" r="1" fill="rgba(46,22,9,0.0352941)"/>
+ <circle cx="22" cy="47" r="1" fill="rgba(24,10,2,0.0352941)"/>
+ <circle cx="23" cy="47" r="1" fill="rgba(45,22,8,0.117647)"/>
+ <circle cx="24" cy="47" r="1" fill="rgba(37,17,6,0.25098)"/>
+ <circle cx="25" cy="47" r="1" fill="rgba(19,6,1,0.376471)"/>
+ <circle cx="26" cy="47" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="27" cy="47" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="28" cy="47" r="1" fill="rgba(0,0,0,0.462745)"/>
+ <circle cx="29" cy="47" r="1" fill="rgba(31,6,0,0.435294)"/>
+ <circle cx="30" cy="47" r="1" fill="rgba(236,106,24,0.878431)"/>
+ <circle cx="31" cy="47" r="1" fill="rgba(255,142,52,1)"/>
+ <circle cx="32" cy="47" r="1" fill="rgba(255,156,74,1)"/>
+ <circle cx="33" cy="47" r="1" fill="rgba(255,166,87,1)"/>
+ <circle cx="34" cy="47" r="1" fill="rgba(255,169,89,1)"/>
+ <circle cx="35" cy="47" r="1" fill="rgba(255,168,86,1)"/>
+ <circle cx="36" cy="47" r="1" fill="rgba(255,169,88,1)"/>
+ <circle cx="37" cy="47" r="1" fill="rgba(254,170,92,1)"/>
+ <circle cx="38" cy="47" r="1" fill="rgba(252,168,90,1)"/>
+ <circle cx="39" cy="47" r="1" fill="rgba(252,164,83,1)"/>
+ <circle cx="40" cy="47" r="1" fill="rgba(251,159,74,1)"/>
+ <circle cx="41" cy="47" r="1" fill="rgba(251,153,66,1)"/>
+ <circle cx="42" cy="47" r="1" fill="rgba(251,148,57,1)"/>
+ <circle cx="43" cy="47" r="1" fill="rgba(251,144,50,1)"/>
+ <circle cx="44" cy="47" r="1" fill="rgba(251,139,43,1)"/>
+ <circle cx="45" cy="47" r="1" fill="rgba(251,136,38,1)"/>
+ <circle cx="46" cy="47" r="1" fill="rgba(251,132,34,1)"/>
+ <circle cx="47" cy="47" r="1" fill="rgba(252,130,30,1)"/>
+ <circle cx="48" cy="47" r="1" fill="rgba(252,128,24,1)"/>
+ <circle cx="49" cy="47" r="1" fill="rgba(253,126,17,1)"/>
+ <circle cx="50" cy="47" r="1" fill="rgba(254,123,5,1)"/>
+ <circle cx="51" cy="47" r="1" fill="rgba(254,120,0,1)"/>
+ <circle cx="52" cy="47" r="1" fill="rgba(252,118,0,1)"/>
+ <circle cx="53" cy="47" r="1" fill="rgba(252,115,0,1)"/>
+ <circle cx="54" cy="47" r="1" fill="rgba(250,110,0,1)"/>
+ <circle cx="55" cy="47" r="1" fill="rgba(249,105,0,1)"/>
+ <circle cx="56" cy="47" r="1" fill="rgba(247,97,0,1)"/>
+ <circle cx="57" cy="47" r="1" fill="rgba(244,89,0,1)"/>
+ <circle cx="58" cy="47" r="1" fill="rgba(244,81,0,1)"/>
+ <circle cx="59" cy="47" r="1" fill="rgba(246,75,0,1)"/>
+ <circle cx="60" cy="47" r="1" fill="rgba(247,69,0,1)"/>
+ <circle cx="61" cy="47" r="1" fill="rgba(225,54,0,1)"/>
+ <circle cx="62" cy="47" r="1" fill="rgba(152,27,0,1)"/>
+ <circle cx="63" cy="47" r="1" fill="rgba(39,1,0,1)"/>
+ <circle cx="64" cy="47" r="1" fill="black"/>
+ <circle cx="65" cy="47" r="1" fill="black"/>
+ <circle cx="66" cy="47" r="1" fill="black"/>
+ <circle cx="67" cy="47" r="1" fill="black"/>
+ <circle cx="68" cy="47" r="1" fill="rgba(81,6,0,1)"/>
+ <circle cx="69" cy="47" r="1" fill="rgba(173,47,14,1)"/>
+ <circle cx="70" cy="47" r="1" fill="rgba(224,86,38,1)"/>
+ <circle cx="71" cy="47" r="1" fill="rgba(236,100,48,1)"/>
+ <circle cx="72" cy="47" r="1" fill="rgba(225,67,21,1)"/>
+ <circle cx="73" cy="47" r="1" fill="rgba(215,35,2,1)"/>
+ <circle cx="74" cy="47" r="1" fill="rgba(212,27,0,1)"/>
+ <circle cx="75" cy="47" r="1" fill="rgba(214,35,3,1)"/>
+ <circle cx="76" cy="47" r="1" fill="rgba(214,39,5,1)"/>
+ <circle cx="77" cy="47" r="1" fill="rgba(214,42,8,1)"/>
+ <circle cx="78" cy="47" r="1" fill="rgba(213,42,9,1)"/>
+ <circle cx="79" cy="47" r="1" fill="rgba(213,43,11,1)"/>
+ <circle cx="80" cy="47" r="1" fill="rgba(213,46,13,1)"/>
+ <circle cx="81" cy="47" r="1" fill="rgba(212,48,15,1)"/>
+ <circle cx="82" cy="47" r="1" fill="rgba(212,49,17,1)"/>
+ <circle cx="83" cy="47" r="1" fill="rgba(211,53,19,1)"/>
+ <circle cx="84" cy="47" r="1" fill="rgba(217,59,22,1)"/>
+ <circle cx="85" cy="47" r="1" fill="rgba(190,49,18,1)"/>
+ <circle cx="86" cy="47" r="1" fill="rgba(61,10,1,1)"/>
+ <circle cx="87" cy="47" r="1" fill="black"/>
+ <circle cx="88" cy="47" r="1" fill="black"/>
+ <circle cx="89" cy="47" r="1" fill="rgba(26,3,0,1)"/>
+ <circle cx="90" cy="47" r="1" fill="rgba(150,46,16,1)"/>
+ <circle cx="91" cy="47" r="1" fill="rgba(226,84,37,1)"/>
+ <circle cx="92" cy="47" r="1" fill="rgba(221,87,40,1)"/>
+ <circle cx="93" cy="47" r="1" fill="rgba(222,93,44,1)"/>
+ <circle cx="94" cy="47" r="1" fill="rgba(224,98,48,1)"/>
+ <circle cx="95" cy="47" r="1" fill="rgba(225,101,49,1)"/>
+ <circle cx="96" cy="47" r="1" fill="rgba(224,102,49,1)"/>
+ <circle cx="97" cy="47" r="1" fill="rgba(224,98,47,1)"/>
+ <circle cx="98" cy="47" r="1" fill="rgba(223,94,42,1)"/>
+ <circle cx="99" cy="47" r="1" fill="rgba(230,95,41,0.960784)"/>
+ <circle cx="100" cy="47" r="1" fill="rgba(128,46,15,0.188235)"/>
+ <circle cx="101" cy="47" r="1" fill="rgba(19,10,3,0.027451)"/>
+ <circle cx="102" cy="47" r="1" fill="rgba(45,17,6,0.0901961)"/>
+ <circle cx="103" cy="47" r="1" fill="rgba(34,14,4,0.145098)"/>
+ <circle cx="104" cy="47" r="1" fill="rgba(26,10,3,0.278431)"/>
+ <circle cx="105" cy="47" r="1" fill="rgba(15,4,0,0.384314)"/>
+ <circle cx="106" cy="47" r="1" fill="rgba(21,7,1,0.317647)"/>
+ <circle cx="107" cy="47" r="1" fill="rgba(21,7,1,0.337255)"/>
+ <circle cx="108" cy="47" r="1" fill="rgba(7,1,0,0.45098)"/>
+ <circle cx="109" cy="47" r="1" fill="rgba(0,0,0,0.47451)"/>
+ <circle cx="110" cy="47" r="1" fill="rgba(12,4,0,0.392157)"/>
+ <circle cx="111" cy="47" r="1" fill="rgba(31,12,3,0.160784)"/>
+ <circle cx="112" cy="47" r="1" fill="rgba(29,12,3,0.0196078)"/>
+ <circle cx="113" cy="47" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="114" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="47" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="48" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="48" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="19" cy="48" r="1" fill="rgba(46,23,9,0)"/>
+ <circle cx="20" cy="48" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="21" cy="48" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="22" cy="48" r="1" fill="rgba(24,10,2,0)"/>
+ <circle cx="23" cy="48" r="1" fill="rgba(50,26,10,0)"/>
+ <circle cx="24" cy="48" r="1" fill="rgba(49,25,10,0.00784314)"/>
+ <circle cx="25" cy="48" r="1" fill="rgba(43,21,8,0.0705882)"/>
+ <circle cx="26" cy="48" r="1" fill="rgba(36,16,5,0.266667)"/>
+ <circle cx="27" cy="48" r="1" fill="rgba(7,2,0,0.447059)"/>
+ <circle cx="28" cy="48" r="1" fill="rgba(0,0,0,0.45098)"/>
+ <circle cx="29" cy="48" r="1" fill="rgba(112,31,2,0.607843)"/>
+ <circle cx="30" cy="48" r="1" fill="rgba(255,112,19,1)"/>
+ <circle cx="31" cy="48" r="1" fill="rgba(255,129,33,1)"/>
+ <circle cx="32" cy="48" r="1" fill="rgba(255,145,50,1)"/>
+ <circle cx="33" cy="48" r="1" fill="rgba(255,154,62,1)"/>
+ <circle cx="34" cy="48" r="1" fill="rgba(255,159,68,1)"/>
+ <circle cx="35" cy="48" r="1" fill="rgba(255,162,74,1)"/>
+ <circle cx="36" cy="48" r="1" fill="rgba(254,165,80,1)"/>
+ <circle cx="37" cy="48" r="1" fill="rgba(253,165,84,1)"/>
+ <circle cx="38" cy="48" r="1" fill="rgba(252,164,82,1)"/>
+ <circle cx="39" cy="48" r="1" fill="rgba(252,161,77,1)"/>
+ <circle cx="40" cy="48" r="1" fill="rgba(251,157,70,1)"/>
+ <circle cx="41" cy="48" r="1" fill="rgba(251,151,62,1)"/>
+ <circle cx="42" cy="48" r="1" fill="rgba(251,146,55,1)"/>
+ <circle cx="43" cy="48" r="1" fill="rgba(251,141,47,1)"/>
+ <circle cx="44" cy="48" r="1" fill="rgba(253,138,41,1)"/>
+ <circle cx="45" cy="48" r="1" fill="rgba(255,136,35,1)"/>
+ <circle cx="46" cy="48" r="1" fill="rgba(255,134,30,1)"/>
+ <circle cx="47" cy="48" r="1" fill="rgba(255,130,24,1)"/>
+ <circle cx="48" cy="48" r="1" fill="rgba(255,124,19,1)"/>
+ <circle cx="49" cy="48" r="1" fill="rgba(253,119,13,1)"/>
+ <circle cx="50" cy="48" r="1" fill="rgba(254,116,3,1)"/>
+ <circle cx="51" cy="48" r="1" fill="rgba(254,115,0,1)"/>
+ <circle cx="52" cy="48" r="1" fill="rgba(252,114,0,1)"/>
+ <circle cx="53" cy="48" r="1" fill="rgba(252,112,0,1)"/>
+ <circle cx="54" cy="48" r="1" fill="rgba(250,110,0,1)"/>
+ <circle cx="55" cy="48" r="1" fill="rgba(249,106,0,1)"/>
+ <circle cx="56" cy="48" r="1" fill="rgba(247,100,0,1)"/>
+ <circle cx="57" cy="48" r="1" fill="rgba(245,92,0,1)"/>
+ <circle cx="58" cy="48" r="1" fill="rgba(243,85,0,1)"/>
+ <circle cx="59" cy="48" r="1" fill="rgba(241,76,0,1)"/>
+ <circle cx="60" cy="48" r="1" fill="rgba(238,69,0,1)"/>
+ <circle cx="61" cy="48" r="1" fill="rgba(239,63,0,1)"/>
+ <circle cx="62" cy="48" r="1" fill="rgba(244,58,0,1)"/>
+ <circle cx="63" cy="48" r="1" fill="rgba(211,42,0,1)"/>
+ <circle cx="64" cy="48" r="1" fill="rgba(84,11,0,1)"/>
+ <circle cx="65" cy="48" r="1" fill="black"/>
+ <circle cx="66" cy="48" r="1" fill="black"/>
+ <circle cx="67" cy="48" r="1" fill="rgba(137,16,0,1)"/>
+ <circle cx="68" cy="48" r="1" fill="rgba(221,32,0,1)"/>
+ <circle cx="69" cy="48" r="1" fill="rgba(227,43,4,1)"/>
+ <circle cx="70" cy="48" r="1" fill="rgba(220,42,4,1)"/>
+ <circle cx="71" cy="48" r="1" fill="rgba(215,28,0,1)"/>
+ <circle cx="72" cy="48" r="1" fill="rgba(216,33,0,1)"/>
+ <circle cx="73" cy="48" r="1" fill="rgba(216,37,2,1)"/>
+ <circle cx="74" cy="48" r="1" fill="rgba(216,40,4,1)"/>
+ <circle cx="75" cy="48" r="1" fill="rgba(215,42,5,1)"/>
+ <circle cx="76" cy="48" r="1" fill="rgba(214,43,6,1)"/>
+ <circle cx="77" cy="48" r="1" fill="rgba(214,44,8,1)"/>
+ <circle cx="78" cy="48" r="1" fill="rgba(214,45,10,1)"/>
+ <circle cx="79" cy="48" r="1" fill="rgba(214,44,11,1)"/>
+ <circle cx="80" cy="48" r="1" fill="rgba(213,47,13,1)"/>
+ <circle cx="81" cy="48" r="1" fill="rgba(212,47,15,1)"/>
+ <circle cx="82" cy="48" r="1" fill="rgba(212,48,16,1)"/>
+ <circle cx="83" cy="48" r="1" fill="rgba(213,51,18,1)"/>
+ <circle cx="84" cy="48" r="1" fill="rgba(212,53,19,1)"/>
+ <circle cx="85" cy="48" r="1" fill="rgba(77,13,3,1)"/>
+ <circle cx="86" cy="48" r="1" fill="black"/>
+ <circle cx="87" cy="48" r="1" fill="black"/>
+ <circle cx="88" cy="48" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="89" cy="48" r="1" fill="black"/>
+ <circle cx="90" cy="48" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="91" cy="48" r="1" fill="rgba(167,53,19,1)"/>
+ <circle cx="92" cy="48" r="1" fill="rgba(227,86,38,1)"/>
+ <circle cx="93" cy="48" r="1" fill="rgba(221,89,41,1)"/>
+ <circle cx="94" cy="48" r="1" fill="rgba(224,95,45,1)"/>
+ <circle cx="95" cy="48" r="1" fill="rgba(224,101,48,1)"/>
+ <circle cx="96" cy="48" r="1" fill="rgba(225,102,49,1)"/>
+ <circle cx="97" cy="48" r="1" fill="rgba(225,101,48,1)"/>
+ <circle cx="98" cy="48" r="1" fill="rgba(224,97,45,1)"/>
+ <circle cx="99" cy="48" r="1" fill="rgba(232,98,43,1)"/>
+ <circle cx="100" cy="48" r="1" fill="rgba(148,54,18,0.635294)"/>
+ <circle cx="101" cy="48" r="1" fill="rgba(0,3,1,0.266667)"/>
+ <circle cx="102" cy="48" r="1" fill="rgba(19,7,1,0.352941)"/>
+ <circle cx="103" cy="48" r="1" fill="rgba(15,4,0,0.411765)"/>
+ <circle cx="104" cy="48" r="1" fill="rgba(4,0,0,0.454902)"/>
+ <circle cx="105" cy="48" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="106" cy="48" r="1" fill="rgba(0,0,0,0.462745)"/>
+ <circle cx="107" cy="48" r="1" fill="rgba(4,0,0,0.466667)"/>
+ <circle cx="108" cy="48" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="109" cy="48" r="1" fill="rgba(10,1,0,0.439216)"/>
+ <circle cx="110" cy="48" r="1" fill="rgba(28,11,3,0.215686)"/>
+ <circle cx="111" cy="48" r="1" fill="rgba(34,15,5,0.0117647)"/>
+ <circle cx="112" cy="48" r="1" fill="rgba(29,12,3,0)"/>
+ <circle cx="113" cy="48" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="114" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="48" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="49" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="49" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="19" cy="49" r="1" fill="rgba(46,23,9,0)"/>
+ <circle cx="20" cy="49" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="21" cy="49" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="22" cy="49" r="1" fill="rgba(24,10,2,0)"/>
+ <circle cx="23" cy="49" r="1" fill="rgba(49,25,10,0)"/>
+ <circle cx="24" cy="49" r="1" fill="rgba(47,24,9,0)"/>
+ <circle cx="25" cy="49" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="26" cy="49" r="1" fill="rgba(54,28,11,0.0196078)"/>
+ <circle cx="27" cy="49" r="1" fill="rgba(34,16,5,0.184314)"/>
+ <circle cx="28" cy="49" r="1" fill="rgba(0,0,0,0.337255)"/>
+ <circle cx="29" cy="49" r="1" fill="rgba(188,63,6,0.768627)"/>
+ <circle cx="30" cy="49" r="1" fill="rgba(255,114,18,1)"/>
+ <circle cx="31" cy="49" r="1" fill="rgba(254,124,26,1)"/>
+ <circle cx="32" cy="49" r="1" fill="rgba(255,138,37,1)"/>
+ <circle cx="33" cy="49" r="1" fill="rgba(255,147,49,1)"/>
+ <circle cx="34" cy="49" r="1" fill="rgba(254,154,58,1)"/>
+ <circle cx="35" cy="49" r="1" fill="rgba(253,158,67,1)"/>
+ <circle cx="36" cy="49" r="1" fill="rgba(253,160,72,1)"/>
+ <circle cx="37" cy="49" r="1" fill="rgba(252,160,74,1)"/>
+ <circle cx="38" cy="49" r="1" fill="rgba(252,160,74,1)"/>
+ <circle cx="39" cy="49" r="1" fill="rgba(252,157,70,1)"/>
+ <circle cx="40" cy="49" r="1" fill="rgba(251,153,64,1)"/>
+ <circle cx="41" cy="49" r="1" fill="rgba(251,148,57,1)"/>
+ <circle cx="42" cy="49" r="1" fill="rgba(251,143,50,1)"/>
+ <circle cx="43" cy="49" r="1" fill="rgba(255,140,43,1)"/>
+ <circle cx="44" cy="49" r="1" fill="rgba(243,128,37,1)"/>
+ <circle cx="45" cy="49" r="1" fill="rgba(200,98,30,1)"/>
+ <circle cx="46" cy="49" r="1" fill="rgba(179,82,22,1)"/>
+ <circle cx="47" cy="49" r="1" fill="rgba(193,86,18,1)"/>
+ <circle cx="48" cy="49" r="1" fill="rgba(238,107,14,1)"/>
+ <circle cx="49" cy="49" r="1" fill="rgba(255,116,8,1)"/>
+ <circle cx="50" cy="49" r="1" fill="rgba(255,109,1,1)"/>
+ <circle cx="51" cy="49" r="1" fill="rgba(253,108,0,1)"/>
+ <circle cx="52" cy="49" r="1" fill="rgba(252,108,0,1)"/>
+ <circle cx="53" cy="49" r="1" fill="rgba(251,107,0,1)"/>
+ <circle cx="54" cy="49" r="1" fill="rgba(250,107,0,1)"/>
+ <circle cx="55" cy="49" r="1" fill="rgba(249,105,0,1)"/>
+ <circle cx="56" cy="49" r="1" fill="rgba(247,101,0,1)"/>
+ <circle cx="57" cy="49" r="1" fill="rgba(245,94,0,1)"/>
+ <circle cx="58" cy="49" r="1" fill="rgba(244,87,0,1)"/>
+ <circle cx="59" cy="49" r="1" fill="rgba(241,79,0,1)"/>
+ <circle cx="60" cy="49" r="1" fill="rgba(239,71,0,1)"/>
+ <circle cx="61" cy="49" r="1" fill="rgba(236,63,0,1)"/>
+ <circle cx="62" cy="49" r="1" fill="rgba(233,55,0,1)"/>
+ <circle cx="63" cy="49" r="1" fill="rgba(239,51,0,1)"/>
+ <circle cx="64" cy="49" r="1" fill="rgba(213,33,0,1)"/>
+ <circle cx="65" cy="49" r="1" fill="rgba(86,4,0,1)"/>
+ <circle cx="66" cy="49" r="1" fill="rgba(104,12,0,1)"/>
+ <circle cx="67" cy="49" r="1" fill="rgba(227,33,0,1)"/>
+ <circle cx="68" cy="49" r="1" fill="rgba(221,32,0,1)"/>
+ <circle cx="69" cy="49" r="1" fill="rgba(217,32,0,1)"/>
+ <circle cx="70" cy="49" r="1" fill="rgba(217,34,0,1)"/>
+ <circle cx="71" cy="49" r="1" fill="rgba(217,37,1,1)"/>
+ <circle cx="72" cy="49" r="1" fill="rgba(217,39,2,1)"/>
+ <circle cx="73" cy="49" r="1" fill="rgba(217,41,3,1)"/>
+ <circle cx="74" cy="49" r="1" fill="rgba(217,43,4,1)"/>
+ <circle cx="75" cy="49" r="1" fill="rgba(217,45,6,1)"/>
+ <circle cx="76" cy="49" r="1" fill="rgba(216,45,7,1)"/>
+ <circle cx="77" cy="49" r="1" fill="rgba(215,45,8,1)"/>
+ <circle cx="78" cy="49" r="1" fill="rgba(214,46,10,1)"/>
+ <circle cx="79" cy="49" r="1" fill="rgba(214,45,11,1)"/>
+ <circle cx="80" cy="49" r="1" fill="rgba(212,46,13,1)"/>
+ <circle cx="81" cy="49" r="1" fill="rgba(211,45,14,1)"/>
+ <circle cx="82" cy="49" r="1" fill="rgba(210,45,16,1)"/>
+ <circle cx="83" cy="49" r="1" fill="rgba(217,49,17,1)"/>
+ <circle cx="84" cy="49" r="1" fill="rgba(168,35,10,1)"/>
+ <circle cx="85" cy="49" r="1" fill="black"/>
+ <circle cx="86" cy="49" r="1" fill="black"/>
+ <circle cx="87" cy="49" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="88" cy="49" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="89" cy="49" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="90" cy="49" r="1" fill="black"/>
+ <circle cx="91" cy="49" r="1" fill="rgba(45,7,1,1)"/>
+ <circle cx="92" cy="49" r="1" fill="rgba(205,71,29,1)"/>
+ <circle cx="93" cy="49" r="1" fill="rgba(223,86,38,1)"/>
+ <circle cx="94" cy="49" r="1" fill="rgba(222,92,42,1)"/>
+ <circle cx="95" cy="49" r="1" fill="rgba(224,98,46,1)"/>
+ <circle cx="96" cy="49" r="1" fill="rgba(225,102,49,1)"/>
+ <circle cx="97" cy="49" r="1" fill="rgba(225,102,48,1)"/>
+ <circle cx="98" cy="49" r="1" fill="rgba(224,100,46,1)"/>
+ <circle cx="99" cy="49" r="1" fill="rgba(228,98,43,1)"/>
+ <circle cx="100" cy="49" r="1" fill="rgba(200,80,30,0.901961)"/>
+ <circle cx="101" cy="49" r="1" fill="rgba(17,2,0,0.47451)"/>
+ <circle cx="102" cy="49" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="103" cy="49" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="104" cy="49" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="105" cy="49" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="106" cy="49" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="107" cy="49" r="1" fill="rgba(0,0,0,0.462745)"/>
+ <circle cx="108" cy="49" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="109" cy="49" r="1" fill="rgba(21,7,1,0.337255)"/>
+ <circle cx="110" cy="49" r="1" fill="rgba(36,15,5,0.054902)"/>
+ <circle cx="111" cy="49" r="1" fill="rgba(34,15,5,0)"/>
+ <circle cx="112" cy="49" r="1" fill="rgba(29,12,3,0)"/>
+ <circle cx="113" cy="49" r="1" fill="rgba(28,10,3,0)"/>
+ <circle cx="114" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="49" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="50" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="50" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="19" cy="50" r="1" fill="rgba(46,23,9,0)"/>
+ <circle cx="20" cy="50" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="21" cy="50" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="22" cy="50" r="1" fill="rgba(24,10,2,0)"/>
+ <circle cx="23" cy="50" r="1" fill="rgba(49,25,10,0)"/>
+ <circle cx="24" cy="50" r="1" fill="rgba(45,23,9,0)"/>
+ <circle cx="25" cy="50" r="1" fill="rgba(40,21,9,0)"/>
+ <circle cx="26" cy="50" r="1" fill="rgba(50,27,12,0)"/>
+ <circle cx="27" cy="50" r="1" fill="rgba(21,18,9,0)"/>
+ <circle cx="28" cy="50" r="1" fill="rgba(102,29,3,0.113725)"/>
+ <circle cx="29" cy="50" r="1" fill="rgba(246,91,9,0.901961)"/>
+ <circle cx="30" cy="50" r="1" fill="rgba(254,110,16,1)"/>
+ <circle cx="31" cy="50" r="1" fill="rgba(253,124,26,1)"/>
+ <circle cx="32" cy="50" r="1" fill="rgba(254,136,36,1)"/>
+ <circle cx="33" cy="50" r="1" fill="rgba(254,145,45,1)"/>
+ <circle cx="34" cy="50" r="1" fill="rgba(253,150,53,1)"/>
+ <circle cx="35" cy="50" r="1" fill="rgba(253,153,59,1)"/>
+ <circle cx="36" cy="50" r="1" fill="rgba(252,155,63,1)"/>
+ <circle cx="37" cy="50" r="1" fill="rgba(252,155,65,1)"/>
+ <circle cx="38" cy="50" r="1" fill="rgba(252,154,65,1)"/>
+ <circle cx="39" cy="50" r="1" fill="rgba(252,151,61,1)"/>
+ <circle cx="40" cy="50" r="1" fill="rgba(251,149,56,1)"/>
+ <circle cx="41" cy="50" r="1" fill="rgba(251,145,51,1)"/>
+ <circle cx="42" cy="50" r="1" fill="rgba(253,142,45,1)"/>
+ <circle cx="43" cy="50" r="1" fill="rgba(238,127,38,1)"/>
+ <circle cx="44" cy="50" r="1" fill="rgba(147,72,32,1)"/>
+ <circle cx="45" cy="50" r="1" fill="rgba(99,46,24,1)"/>
+ <circle cx="46" cy="50" r="1" fill="rgba(77,34,17,1)"/>
+ <circle cx="47" cy="50" r="1" fill="rgba(63,25,11,1)"/>
+ <circle cx="48" cy="50" r="1" fill="rgba(77,26,6,1)"/>
+ <circle cx="49" cy="50" r="1" fill="rgba(183,68,3,1)"/>
+ <circle cx="50" cy="50" r="1" fill="rgba(255,104,0,1)"/>
+ <circle cx="51" cy="50" r="1" fill="rgba(253,102,0,1)"/>
+ <circle cx="52" cy="50" r="1" fill="rgba(252,102,0,1)"/>
+ <circle cx="53" cy="50" r="1" fill="rgba(251,102,0,1)"/>
+ <circle cx="54" cy="50" r="1" fill="rgba(249,102,0,1)"/>
+ <circle cx="55" cy="50" r="1" fill="rgba(248,102,0,1)"/>
+ <circle cx="56" cy="50" r="1" fill="rgba(247,99,0,1)"/>
+ <circle cx="57" cy="50" r="1" fill="rgba(245,95,0,1)"/>
+ <circle cx="58" cy="50" r="1" fill="rgba(244,88,0,1)"/>
+ <circle cx="59" cy="50" r="1" fill="rgba(241,81,0,1)"/>
+ <circle cx="60" cy="50" r="1" fill="rgba(239,72,0,1)"/>
+ <circle cx="61" cy="50" r="1" fill="rgba(237,63,0,1)"/>
+ <circle cx="62" cy="50" r="1" fill="rgba(234,56,0,1)"/>
+ <circle cx="63" cy="50" r="1" fill="rgba(231,49,0,1)"/>
+ <circle cx="64" cy="50" r="1" fill="rgba(230,36,0,1)"/>
+ <circle cx="65" cy="50" r="1" fill="rgba(177,14,0,1)"/>
+ <circle cx="66" cy="50" r="1" fill="rgba(160,20,0,1)"/>
+ <circle cx="67" cy="50" r="1" fill="rgba(227,33,0,1)"/>
+ <circle cx="68" cy="50" r="1" fill="rgba(217,32,0,1)"/>
+ <circle cx="69" cy="50" r="1" fill="rgba(218,34,0,1)"/>
+ <circle cx="70" cy="50" r="1" fill="rgba(218,36,1,1)"/>
+ <circle cx="71" cy="50" r="1" fill="rgba(218,39,1,1)"/>
+ <circle cx="72" cy="50" r="1" fill="rgba(218,41,3,1)"/>
+ <circle cx="73" cy="50" r="1" fill="rgba(218,44,3,1)"/>
+ <circle cx="74" cy="50" r="1" fill="rgba(218,45,5,1)"/>
+ <circle cx="75" cy="50" r="1" fill="rgba(217,46,6,1)"/>
+ <circle cx="76" cy="50" r="1" fill="rgba(216,45,7,1)"/>
+ <circle cx="77" cy="50" r="1" fill="rgba(215,45,8,1)"/>
+ <circle cx="78" cy="50" r="1" fill="rgba(214,45,9,1)"/>
+ <circle cx="79" cy="50" r="1" fill="rgba(212,44,10,1)"/>
+ <circle cx="80" cy="50" r="1" fill="rgba(211,43,11,1)"/>
+ <circle cx="81" cy="50" r="1" fill="rgba(209,42,12,1)"/>
+ <circle cx="82" cy="50" r="1" fill="rgba(209,41,13,1)"/>
+ <circle cx="83" cy="50" r="1" fill="rgba(217,45,15,1)"/>
+ <circle cx="84" cy="50" r="1" fill="rgba(126,21,5,1)"/>
+ <circle cx="85" cy="50" r="1" fill="black"/>
+ <circle cx="86" cy="50" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="87" cy="50" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="88" cy="50" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="89" cy="50" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="90" cy="50" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="91" cy="50" r="1" fill="black"/>
+ <circle cx="92" cy="50" r="1" fill="rgba(136,38,12,1)"/>
+ <circle cx="93" cy="50" r="1" fill="rgba(227,84,36,1)"/>
+ <circle cx="94" cy="50" r="1" fill="rgba(221,87,39,1)"/>
+ <circle cx="95" cy="50" r="1" fill="rgba(223,93,43,1)"/>
+ <circle cx="96" cy="50" r="1" fill="rgba(224,98,46,1)"/>
+ <circle cx="97" cy="50" r="1" fill="rgba(225,101,48,1)"/>
+ <circle cx="98" cy="50" r="1" fill="rgba(224,100,46,1)"/>
+ <circle cx="99" cy="50" r="1" fill="rgba(225,97,42,1)"/>
+ <circle cx="100" cy="50" r="1" fill="rgba(227,96,41,0.996078)"/>
+ <circle cx="101" cy="50" r="1" fill="rgba(90,26,6,0.54902)"/>
+ <circle cx="102" cy="50" r="1" fill="rgba(0,0,0,0.384314)"/>
+ <circle cx="103" cy="50" r="1" fill="rgba(12,2,0,0.4)"/>
+ <circle cx="104" cy="50" r="1" fill="rgba(7,1,0,0.396078)"/>
+ <circle cx="105" cy="50" r="1" fill="rgba(10,2,0,0.423529)"/>
+ <circle cx="106" cy="50" r="1" fill="rgba(10,1,0,0.447059)"/>
+ <circle cx="107" cy="50" r="1" fill="rgba(0,0,0,0.454902)"/>
+ <circle cx="108" cy="50" r="1" fill="rgba(12,3,0,0.415686)"/>
+ <circle cx="109" cy="50" r="1" fill="rgba(34,15,5,0.172549)"/>
+ <circle cx="110" cy="50" r="1" fill="rgba(40,20,7,0)"/>
+ <circle cx="111" cy="50" r="1" fill="rgba(40,19,7,0)"/>
+ <circle cx="112" cy="50" r="1" fill="rgba(40,19,7,0)"/>
+ <circle cx="113" cy="50" r="1" fill="rgba(39,18,6,0)"/>
+ <circle cx="114" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="50" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="51" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="51" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="19" cy="51" r="1" fill="rgba(46,23,9,0)"/>
+ <circle cx="20" cy="51" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="21" cy="51" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="22" cy="51" r="1" fill="rgba(24,10,2,0)"/>
+ <circle cx="23" cy="51" r="1" fill="rgba(33,22,10,0)"/>
+ <circle cx="24" cy="51" r="1" fill="rgba(46,24,9,0)"/>
+ <circle cx="25" cy="51" r="1" fill="rgba(65,26,8,0)"/>
+ <circle cx="26" cy="51" r="1" fill="rgba(58,29,11,0)"/>
+ <circle cx="27" cy="51" r="1" fill="rgba(122,41,8,0)"/>
+ <circle cx="28" cy="51" r="1" fill="rgba(246,83,5,0.27451)"/>
+ <circle cx="29" cy="51" r="1" fill="rgba(255,94,9,1)"/>
+ <circle cx="30" cy="51" r="1" fill="rgba(252,108,15,1)"/>
+ <circle cx="31" cy="51" r="1" fill="rgba(253,122,23,1)"/>
+ <circle cx="32" cy="51" r="1" fill="rgba(252,133,33,1)"/>
+ <circle cx="33" cy="51" r="1" fill="rgba(252,141,40,1)"/>
+ <circle cx="34" cy="51" r="1" fill="rgba(252,146,47,1)"/>
+ <circle cx="35" cy="51" r="1" fill="rgba(252,148,51,1)"/>
+ <circle cx="36" cy="51" r="1" fill="rgba(252,150,55,1)"/>
+ <circle cx="37" cy="51" r="1" fill="rgba(252,150,56,1)"/>
+ <circle cx="38" cy="51" r="1" fill="rgba(252,149,56,1)"/>
+ <circle cx="39" cy="51" r="1" fill="rgba(252,147,53,1)"/>
+ <circle cx="40" cy="51" r="1" fill="rgba(251,144,49,1)"/>
+ <circle cx="41" cy="51" r="1" fill="rgba(251,140,45,1)"/>
+ <circle cx="42" cy="51" r="1" fill="rgba(254,138,39,1)"/>
+ <circle cx="43" cy="51" r="1" fill="rgba(181,90,33,1)"/>
+ <circle cx="44" cy="51" r="1" fill="rgba(104,49,27,1)"/>
+ <circle cx="45" cy="51" r="1" fill="rgba(100,45,21,1)"/>
+ <circle cx="46" cy="51" r="1" fill="rgba(84,35,15,1)"/>
+ <circle cx="47" cy="51" r="1" fill="rgba(65,25,9,1)"/>
+ <circle cx="48" cy="51" r="1" fill="rgba(33,11,4,1)"/>
+ <circle cx="49" cy="51" r="1" fill="rgba(7,1,0,1)"/>
+ <circle cx="50" cy="51" r="1" fill="rgba(195,66,0,1)"/>
+ <circle cx="51" cy="51" r="1" fill="rgba(255,99,0,1)"/>
+ <circle cx="52" cy="51" r="1" fill="rgba(252,95,0,1)"/>
+ <circle cx="53" cy="51" r="1" fill="rgba(250,96,0,1)"/>
+ <circle cx="54" cy="51" r="1" fill="rgba(249,97,0,1)"/>
+ <circle cx="55" cy="51" r="1" fill="rgba(248,96,0,1)"/>
+ <circle cx="56" cy="51" r="1" fill="rgba(247,95,0,1)"/>
+ <circle cx="57" cy="51" r="1" fill="rgba(244,93,0,1)"/>
+ <circle cx="58" cy="51" r="1" fill="rgba(244,87,0,1)"/>
+ <circle cx="59" cy="51" r="1" fill="rgba(241,81,0,1)"/>
+ <circle cx="60" cy="51" r="1" fill="rgba(239,72,0,1)"/>
+ <circle cx="61" cy="51" r="1" fill="rgba(236,63,0,1)"/>
+ <circle cx="62" cy="51" r="1" fill="rgba(234,56,0,1)"/>
+ <circle cx="63" cy="51" r="1" fill="rgba(231,49,0,1)"/>
+ <circle cx="64" cy="51" r="1" fill="rgba(227,37,0,1)"/>
+ <circle cx="65" cy="51" r="1" fill="rgba(176,14,0,1)"/>
+ <circle cx="66" cy="51" r="1" fill="rgba(159,21,0,1)"/>
+ <circle cx="67" cy="51" r="1" fill="rgba(226,34,0,1)"/>
+ <circle cx="68" cy="51" r="1" fill="rgba(217,31,0,1)"/>
+ <circle cx="69" cy="51" r="1" fill="rgba(217,34,0,1)"/>
+ <circle cx="70" cy="51" r="1" fill="rgba(218,37,1,1)"/>
+ <circle cx="71" cy="51" r="1" fill="rgba(219,41,2,1)"/>
+ <circle cx="72" cy="51" r="1" fill="rgba(220,44,3,1)"/>
+ <circle cx="73" cy="51" r="1" fill="rgba(219,45,4,1)"/>
+ <circle cx="74" cy="51" r="1" fill="rgba(219,46,5,1)"/>
+ <circle cx="75" cy="51" r="1" fill="rgba(217,46,6,1)"/>
+ <circle cx="76" cy="51" r="1" fill="rgba(216,44,7,1)"/>
+ <circle cx="77" cy="51" r="1" fill="rgba(214,43,8,1)"/>
+ <circle cx="78" cy="51" r="1" fill="rgba(213,41,8,1)"/>
+ <circle cx="79" cy="51" r="1" fill="rgba(211,40,9,1)"/>
+ <circle cx="80" cy="51" r="1" fill="rgba(210,39,10,1)"/>
+ <circle cx="81" cy="51" r="1" fill="rgba(207,39,10,1)"/>
+ <circle cx="82" cy="51" r="1" fill="rgba(207,37,11,1)"/>
+ <circle cx="83" cy="51" r="1" fill="rgba(212,39,13,1)"/>
+ <circle cx="84" cy="51" r="1" fill="rgba(105,15,3,1)"/>
+ <circle cx="85" cy="51" r="1" fill="black"/>
+ <circle cx="86" cy="51" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="87" cy="51" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="88" cy="51" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="89" cy="51" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="90" cy="51" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="91" cy="51" r="1" fill="black"/>
+ <circle cx="92" cy="51" r="1" fill="rgba(63,12,3,1)"/>
+ <circle cx="93" cy="51" r="1" fill="rgba(215,75,30,1)"/>
+ <circle cx="94" cy="51" r="1" fill="rgba(222,84,36,1)"/>
+ <circle cx="95" cy="51" r="1" fill="rgba(222,90,40,1)"/>
+ <circle cx="96" cy="51" r="1" fill="rgba(223,95,42,1)"/>
+ <circle cx="97" cy="51" r="1" fill="rgba(224,98,44,1)"/>
+ <circle cx="98" cy="51" r="1" fill="rgba(225,99,45,1)"/>
+ <circle cx="99" cy="51" r="1" fill="rgba(224,97,42,1)"/>
+ <circle cx="100" cy="51" r="1" fill="rgba(233,100,42,1)"/>
+ <circle cx="101" cy="51" r="1" fill="rgba(168,64,22,0.576471)"/>
+ <circle cx="102" cy="51" r="1" fill="rgba(0,0,0,0.0901961)"/>
+ <circle cx="103" cy="51" r="1" fill="rgba(12,4,1,0.121569)"/>
+ <circle cx="104" cy="51" r="1" fill="rgba(19,7,1,0.12549)"/>
+ <circle cx="105" cy="51" r="1" fill="rgba(34,14,5,0.176471)"/>
+ <circle cx="106" cy="51" r="1" fill="rgba(26,10,3,0.231373)"/>
+ <circle cx="107" cy="51" r="1" fill="rgba(10,1,0,0.254902)"/>
+ <circle cx="108" cy="51" r="1" fill="rgba(24,8,2,0.192157)"/>
+ <circle cx="109" cy="51" r="1" fill="rgba(45,21,8,0.0392157)"/>
+ <circle cx="110" cy="51" r="1" fill="rgba(45,22,8,0)"/>
+ <circle cx="111" cy="51" r="1" fill="rgba(45,22,8,0)"/>
+ <circle cx="112" cy="51" r="1" fill="rgba(45,22,8,0)"/>
+ <circle cx="113" cy="51" r="1" fill="rgba(45,22,8,0)"/>
+ <circle cx="114" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="51" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="52" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="52" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="19" cy="52" r="1" fill="rgba(46,23,9,0)"/>
+ <circle cx="20" cy="52" r="1" fill="rgba(46,22,9,0)"/>
+ <circle cx="21" cy="52" r="1" fill="rgba(42,21,9,0)"/>
+ <circle cx="22" cy="52" r="1" fill="rgba(0,4,3,0)"/>
+ <circle cx="23" cy="52" r="1" fill="rgba(108,36,7,0)"/>
+ <circle cx="24" cy="52" r="1" fill="rgba(206,65,5,0)"/>
+ <circle cx="25" cy="52" r="1" fill="rgba(241,75,3,0)"/>
+ <circle cx="26" cy="52" r="1" fill="rgba(238,74,3,0)"/>
+ <circle cx="27" cy="52" r="1" fill="rgba(249,78,3,0)"/>
+ <circle cx="28" cy="52" r="1" fill="rgba(252,81,4,0.545098)"/>
+ <circle cx="29" cy="52" r="1" fill="rgba(250,91,8,1)"/>
+ <circle cx="30" cy="52" r="1" fill="rgba(251,106,13,1)"/>
+ <circle cx="31" cy="52" r="1" fill="rgba(252,120,20,1)"/>
+ <circle cx="32" cy="52" r="1" fill="rgba(252,130,28,1)"/>
+ <circle cx="33" cy="52" r="1" fill="rgba(252,136,35,1)"/>
+ <circle cx="34" cy="52" r="1" fill="rgba(252,140,40,1)"/>
+ <circle cx="35" cy="52" r="1" fill="rgba(252,142,43,1)"/>
+ <circle cx="36" cy="52" r="1" fill="rgba(252,144,46,1)"/>
+ <circle cx="37" cy="52" r="1" fill="rgba(252,144,48,1)"/>
+ <circle cx="38" cy="52" r="1" fill="rgba(252,143,48,1)"/>
+ <circle cx="39" cy="52" r="1" fill="rgba(251,142,45,1)"/>
+ <circle cx="40" cy="52" r="1" fill="rgba(251,138,42,1)"/>
+ <circle cx="41" cy="52" r="1" fill="rgba(252,136,38,1)"/>
+ <circle cx="42" cy="52" r="1" fill="rgba(247,128,33,1)"/>
+ <circle cx="43" cy="52" r="1" fill="rgba(135,64,29,1)"/>
+ <circle cx="44" cy="52" r="1" fill="rgba(101,46,23,1)"/>
+ <circle cx="45" cy="52" r="1" fill="rgba(91,39,17,1)"/>
+ <circle cx="46" cy="52" r="1" fill="rgba(74,30,11,1)"/>
+ <circle cx="47" cy="52" r="1" fill="rgba(55,19,6,1)"/>
+ <circle cx="48" cy="52" r="1" fill="rgba(34,9,2,1)"/>
+ <circle cx="49" cy="52" r="1" fill="black"/>
+ <circle cx="50" cy="52" r="1" fill="rgba(97,23,0,1)"/>
+ <circle cx="51" cy="52" r="1" fill="rgba(251,89,0,1)"/>
+ <circle cx="52" cy="52" r="1" fill="rgba(252,89,0,1)"/>
+ <circle cx="53" cy="52" r="1" fill="rgba(249,90,0,1)"/>
+ <circle cx="54" cy="52" r="1" fill="rgba(248,92,0,1)"/>
+ <circle cx="55" cy="52" r="1" fill="rgba(247,92,0,1)"/>
+ <circle cx="56" cy="52" r="1" fill="rgba(246,91,0,1)"/>
+ <circle cx="57" cy="52" r="1" fill="rgba(244,89,0,1)"/>
+ <circle cx="58" cy="52" r="1" fill="rgba(243,86,0,1)"/>
+ <circle cx="59" cy="52" r="1" fill="rgba(241,79,0,1)"/>
+ <circle cx="60" cy="52" r="1" fill="rgba(238,71,0,1)"/>
+ <circle cx="61" cy="52" r="1" fill="rgba(236,62,0,1)"/>
+ <circle cx="62" cy="52" r="1" fill="rgba(233,55,0,1)"/>
+ <circle cx="63" cy="52" r="1" fill="rgba(230,48,0,1)"/>
+ <circle cx="64" cy="52" r="1" fill="rgba(227,36,0,1)"/>
+ <circle cx="65" cy="52" r="1" fill="rgba(174,14,0,1)"/>
+ <circle cx="66" cy="52" r="1" fill="rgba(159,21,0,1)"/>
+ <circle cx="67" cy="52" r="1" fill="rgba(226,33,0,1)"/>
+ <circle cx="68" cy="52" r="1" fill="rgba(217,32,0,1)"/>
+ <circle cx="69" cy="52" r="1" fill="rgba(217,34,0,1)"/>
+ <circle cx="70" cy="52" r="1" fill="rgba(219,38,1,1)"/>
+ <circle cx="71" cy="52" r="1" fill="rgba(220,42,2,1)"/>
+ <circle cx="72" cy="52" r="1" fill="rgba(220,45,3,1)"/>
+ <circle cx="73" cy="52" r="1" fill="rgba(220,46,4,1)"/>
+ <circle cx="74" cy="52" r="1" fill="rgba(219,45,5,1)"/>
+ <circle cx="75" cy="52" r="1" fill="rgba(217,45,5,1)"/>
+ <circle cx="76" cy="52" r="1" fill="rgba(215,42,6,1)"/>
+ <circle cx="77" cy="52" r="1" fill="rgba(213,39,7,1)"/>
+ <circle cx="78" cy="52" r="1" fill="rgba(210,36,7,1)"/>
+ <circle cx="79" cy="52" r="1" fill="rgba(209,36,8,1)"/>
+ <circle cx="80" cy="52" r="1" fill="rgba(207,35,8,1)"/>
+ <circle cx="81" cy="52" r="1" fill="rgba(206,34,9,1)"/>
+ <circle cx="82" cy="52" r="1" fill="rgba(204,33,9,1)"/>
+ <circle cx="83" cy="52" r="1" fill="rgba(213,36,11,1)"/>
+ <circle cx="84" cy="52" r="1" fill="rgba(116,16,3,1)"/>
+ <circle cx="85" cy="52" r="1" fill="black"/>
+ <circle cx="86" cy="52" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="87" cy="52" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="88" cy="52" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="89" cy="52" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="90" cy="52" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="91" cy="52" r="1" fill="black"/>
+ <circle cx="92" cy="52" r="1" fill="rgba(21,2,0,1)"/>
+ <circle cx="93" cy="52" r="1" fill="rgba(196,64,24,1)"/>
+ <circle cx="94" cy="52" r="1" fill="rgba(224,82,33,1)"/>
+ <circle cx="95" cy="52" r="1" fill="rgba(221,86,37,1)"/>
+ <circle cx="96" cy="52" r="1" fill="rgba(223,92,40,1)"/>
+ <circle cx="97" cy="52" r="1" fill="rgba(224,95,42,1)"/>
+ <circle cx="98" cy="52" r="1" fill="rgba(225,97,43,1)"/>
+ <circle cx="99" cy="52" r="1" fill="rgba(226,99,43,1)"/>
+ <circle cx="100" cy="52" r="1" fill="rgba(227,98,42,1)"/>
+ <circle cx="101" cy="52" r="1" fill="rgba(227,97,40,0.74902)"/>
+ <circle cx="102" cy="52" r="1" fill="rgba(113,39,12,0)"/>
+ <circle cx="103" cy="52" r="1" fill="rgba(22,6,1,0)"/>
+ <circle cx="104" cy="52" r="1" fill="rgba(22,8,2,0)"/>
+ <circle cx="105" cy="52" r="1" fill="rgba(42,20,7,0)"/>
+ <circle cx="106" cy="52" r="1" fill="rgba(33,12,4,0.0156863)"/>
+ <circle cx="107" cy="52" r="1" fill="rgba(12,2,0,0.0235294)"/>
+ <circle cx="108" cy="52" r="1" fill="rgba(26,9,2,0.0117647)"/>
+ <circle cx="109" cy="52" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="110" cy="52" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="111" cy="52" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="112" cy="52" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="113" cy="52" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="114" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="52" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="53" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="53" r="1" fill="rgba(43,20,8,0)"/>
+ <circle cx="19" cy="53" r="1" fill="rgba(43,21,8,0)"/>
+ <circle cx="20" cy="53" r="1" fill="rgba(39,19,8,0)"/>
+ <circle cx="21" cy="53" r="1" fill="rgba(62,24,8,0)"/>
+ <circle cx="22" cy="53" r="1" fill="rgba(158,43,2,0)"/>
+ <circle cx="23" cy="53" r="1" fill="rgba(248,75,2,0)"/>
+ <circle cx="24" cy="53" r="1" fill="rgba(255,79,2,0)"/>
+ <circle cx="25" cy="53" r="1" fill="rgba(252,77,2,0)"/>
+ <circle cx="26" cy="53" r="1" fill="rgba(252,77,2,0)"/>
+ <circle cx="27" cy="53" r="1" fill="rgba(250,76,2,0.00392157)"/>
+ <circle cx="28" cy="53" r="1" fill="rgba(249,78,3,0.784314)"/>
+ <circle cx="29" cy="53" r="1" fill="rgba(250,91,6,1)"/>
+ <circle cx="30" cy="53" r="1" fill="rgba(251,105,11,1)"/>
+ <circle cx="31" cy="53" r="1" fill="rgba(252,117,18,1)"/>
+ <circle cx="32" cy="53" r="1" fill="rgba(252,125,23,1)"/>
+ <circle cx="33" cy="53" r="1" fill="rgba(252,130,29,1)"/>
+ <circle cx="34" cy="53" r="1" fill="rgba(252,134,33,1)"/>
+ <circle cx="35" cy="53" r="1" fill="rgba(252,136,36,1)"/>
+ <circle cx="36" cy="53" r="1" fill="rgba(252,137,38,1)"/>
+ <circle cx="37" cy="53" r="1" fill="rgba(252,137,39,1)"/>
+ <circle cx="38" cy="53" r="1" fill="rgba(252,136,39,1)"/>
+ <circle cx="39" cy="53" r="1" fill="rgba(251,135,37,1)"/>
+ <circle cx="40" cy="53" r="1" fill="rgba(251,133,34,1)"/>
+ <circle cx="41" cy="53" r="1" fill="rgba(253,131,31,1)"/>
+ <circle cx="42" cy="53" r="1" fill="rgba(244,121,27,1)"/>
+ <circle cx="43" cy="53" r="1" fill="rgba(114,52,23,1)"/>
+ <circle cx="44" cy="53" r="1" fill="rgba(91,39,18,1)"/>
+ <circle cx="45" cy="53" r="1" fill="rgba(78,32,13,1)"/>
+ <circle cx="46" cy="53" r="1" fill="rgba(63,23,8,1)"/>
+ <circle cx="47" cy="53" r="1" fill="rgba(43,13,4,1)"/>
+ <circle cx="48" cy="53" r="1" fill="rgba(17,3,0,1)"/>
+ <circle cx="49" cy="53" r="1" fill="black"/>
+ <circle cx="50" cy="53" r="1" fill="rgba(42,6,0,1)"/>
+ <circle cx="51" cy="53" r="1" fill="rgba(241,78,0,1)"/>
+ <circle cx="52" cy="53" r="1" fill="rgba(253,85,0,1)"/>
+ <circle cx="53" cy="53" r="1" fill="rgba(249,84,0,1)"/>
+ <circle cx="54" cy="53" r="1" fill="rgba(247,85,0,1)"/>
+ <circle cx="55" cy="53" r="1" fill="rgba(246,87,0,1)"/>
+ <circle cx="56" cy="53" r="1" fill="rgba(244,86,0,1)"/>
+ <circle cx="57" cy="53" r="1" fill="rgba(244,84,0,1)"/>
+ <circle cx="58" cy="53" r="1" fill="rgba(242,82,0,1)"/>
+ <circle cx="59" cy="53" r="1" fill="rgba(240,78,0,1)"/>
+ <circle cx="60" cy="53" r="1" fill="rgba(238,70,0,1)"/>
+ <circle cx="61" cy="53" r="1" fill="rgba(235,61,0,1)"/>
+ <circle cx="62" cy="53" r="1" fill="rgba(233,54,0,1)"/>
+ <circle cx="63" cy="53" r="1" fill="rgba(230,48,0,1)"/>
+ <circle cx="64" cy="53" r="1" fill="rgba(224,35,0,1)"/>
+ <circle cx="65" cy="53" r="1" fill="rgba(175,15,0,1)"/>
+ <circle cx="66" cy="53" r="1" fill="rgba(160,22,0,1)"/>
+ <circle cx="67" cy="53" r="1" fill="rgba(225,32,0,1)"/>
+ <circle cx="68" cy="53" r="1" fill="rgba(216,32,0,1)"/>
+ <circle cx="69" cy="53" r="1" fill="rgba(217,35,0,1)"/>
+ <circle cx="70" cy="53" r="1" fill="rgba(219,38,1,1)"/>
+ <circle cx="71" cy="53" r="1" fill="rgba(220,43,2,1)"/>
+ <circle cx="72" cy="53" r="1" fill="rgba(220,45,3,1)"/>
+ <circle cx="73" cy="53" r="1" fill="rgba(220,46,4,1)"/>
+ <circle cx="74" cy="53" r="1" fill="rgba(218,45,5,1)"/>
+ <circle cx="75" cy="53" r="1" fill="rgba(217,42,5,1)"/>
+ <circle cx="76" cy="53" r="1" fill="rgba(214,39,6,1)"/>
+ <circle cx="77" cy="53" r="1" fill="rgba(212,36,6,1)"/>
+ <circle cx="78" cy="53" r="1" fill="rgba(209,33,6,1)"/>
+ <circle cx="79" cy="53" r="1" fill="rgba(207,32,6,1)"/>
+ <circle cx="80" cy="53" r="1" fill="rgba(205,31,7,1)"/>
+ <circle cx="81" cy="53" r="1" fill="rgba(203,29,7,1)"/>
+ <circle cx="82" cy="53" r="1" fill="rgba(203,30,8,1)"/>
+ <circle cx="83" cy="53" r="1" fill="rgba(212,34,10,1)"/>
+ <circle cx="84" cy="53" r="1" fill="rgba(148,22,5,1)"/>
+ <circle cx="85" cy="53" r="1" fill="black"/>
+ <circle cx="86" cy="53" r="1" fill="black"/>
+ <circle cx="87" cy="53" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="88" cy="53" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="89" cy="53" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="90" cy="53" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="91" cy="53" r="1" fill="black"/>
+ <circle cx="92" cy="53" r="1" fill="rgba(12,1,0,1)"/>
+ <circle cx="93" cy="53" r="1" fill="rgba(189,59,21,1)"/>
+ <circle cx="94" cy="53" r="1" fill="rgba(224,79,32,1)"/>
+ <circle cx="95" cy="53" r="1" fill="rgba(220,83,34,1)"/>
+ <circle cx="96" cy="53" r="1" fill="rgba(222,89,38,1)"/>
+ <circle cx="97" cy="53" r="1" fill="rgba(224,94,41,1)"/>
+ <circle cx="98" cy="53" r="1" fill="rgba(225,97,42,1)"/>
+ <circle cx="99" cy="53" r="1" fill="rgba(227,99,43,1)"/>
+ <circle cx="100" cy="53" r="1" fill="rgba(227,99,42,1)"/>
+ <circle cx="101" cy="53" r="1" fill="rgba(231,101,42,0.964706)"/>
+ <circle cx="102" cy="53" r="1" fill="rgba(171,65,23,0.137255)"/>
+ <circle cx="103" cy="53" r="1" fill="rgba(119,42,13,0)"/>
+ <circle cx="104" cy="53" r="1" fill="rgba(103,36,11,0)"/>
+ <circle cx="105" cy="53" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="106" cy="53" r="1" fill="rgba(28,11,4,0)"/>
+ <circle cx="107" cy="53" r="1" fill="rgba(12,2,0,0)"/>
+ <circle cx="108" cy="53" r="1" fill="rgba(24,9,2,0)"/>
+ <circle cx="109" cy="53" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="110" cy="53" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="111" cy="53" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="112" cy="53" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="113" cy="53" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="114" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="53" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="54" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="54" r="1" fill="rgba(62,34,16,0)"/>
+ <circle cx="19" cy="54" r="1" fill="rgba(63,35,16,0)"/>
+ <circle cx="20" cy="54" r="1" fill="rgba(46,33,18,0)"/>
+ <circle cx="21" cy="54" r="1" fill="rgba(163,57,11,0)"/>
+ <circle cx="22" cy="54" r="1" fill="rgba(255,77,1,0)"/>
+ <circle cx="23" cy="54" r="1" fill="rgba(252,73,1,0)"/>
+ <circle cx="24" cy="54" r="1" fill="rgba(255,74,0,0)"/>
+ <circle cx="25" cy="54" r="1" fill="rgba(255,74,0,0)"/>
+ <circle cx="26" cy="54" r="1" fill="rgba(252,73,1,0)"/>
+ <circle cx="27" cy="54" r="1" fill="rgba(251,73,1,0.113725)"/>
+ <circle cx="28" cy="54" r="1" fill="rgba(249,78,2,0.960784)"/>
+ <circle cx="29" cy="54" r="1" fill="rgba(250,91,5,1)"/>
+ <circle cx="30" cy="54" r="1" fill="rgba(251,104,9,1)"/>
+ <circle cx="31" cy="54" r="1" fill="rgba(252,113,14,1)"/>
+ <circle cx="32" cy="54" r="1" fill="rgba(252,120,19,1)"/>
+ <circle cx="33" cy="54" r="1" fill="rgba(252,125,23,1)"/>
+ <circle cx="34" cy="54" r="1" fill="rgba(252,129,26,1)"/>
+ <circle cx="35" cy="54" r="1" fill="rgba(252,130,28,1)"/>
+ <circle cx="36" cy="54" r="1" fill="rgba(252,131,30,1)"/>
+ <circle cx="37" cy="54" r="1" fill="rgba(252,131,31,1)"/>
+ <circle cx="38" cy="54" r="1" fill="rgba(252,130,30,1)"/>
+ <circle cx="39" cy="54" r="1" fill="rgba(252,129,29,1)"/>
+ <circle cx="40" cy="54" r="1" fill="rgba(252,127,27,1)"/>
+ <circle cx="41" cy="54" r="1" fill="rgba(254,124,24,1)"/>
+ <circle cx="42" cy="54" r="1" fill="rgba(245,116,21,1)"/>
+ <circle cx="43" cy="54" r="1" fill="rgba(108,46,18,1)"/>
+ <circle cx="44" cy="54" r="1" fill="rgba(76,31,13,1)"/>
+ <circle cx="45" cy="54" r="1" fill="rgba(65,24,9,1)"/>
+ <circle cx="46" cy="54" r="1" fill="rgba(47,15,5,1)"/>
+ <circle cx="47" cy="54" r="1" fill="rgba(26,7,1,1)"/>
+ <circle cx="48" cy="54" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="49" cy="54" r="1" fill="black"/>
+ <circle cx="50" cy="54" r="1" fill="rgba(29,4,0,1)"/>
+ <circle cx="51" cy="54" r="1" fill="rgba(238,75,0,1)"/>
+ <circle cx="52" cy="54" r="1" fill="rgba(253,80,0,1)"/>
+ <circle cx="53" cy="54" r="1" fill="rgba(248,78,0,1)"/>
+ <circle cx="54" cy="54" r="1" fill="rgba(247,79,0,1)"/>
+ <circle cx="55" cy="54" r="1" fill="rgba(245,81,0,1)"/>
+ <circle cx="56" cy="54" r="1" fill="rgba(243,81,0,1)"/>
+ <circle cx="57" cy="54" r="1" fill="rgba(243,80,0,1)"/>
+ <circle cx="58" cy="54" r="1" fill="rgba(241,79,0,1)"/>
+ <circle cx="59" cy="54" r="1" fill="rgba(240,75,0,1)"/>
+ <circle cx="60" cy="54" r="1" fill="rgba(238,68,0,1)"/>
+ <circle cx="61" cy="54" r="1" fill="rgba(235,60,0,1)"/>
+ <circle cx="62" cy="54" r="1" fill="rgba(232,53,0,1)"/>
+ <circle cx="63" cy="54" r="1" fill="rgba(230,47,0,1)"/>
+ <circle cx="64" cy="54" r="1" fill="rgba(224,34,0,1)"/>
+ <circle cx="65" cy="54" r="1" fill="rgba(176,16,0,1)"/>
+ <circle cx="66" cy="54" r="1" fill="rgba(160,24,0,1)"/>
+ <circle cx="67" cy="54" r="1" fill="rgba(224,32,0,1)"/>
+ <circle cx="68" cy="54" r="1" fill="rgba(216,33,0,1)"/>
+ <circle cx="69" cy="54" r="1" fill="rgba(217,35,0,1)"/>
+ <circle cx="70" cy="54" r="1" fill="rgba(219,39,1,1)"/>
+ <circle cx="71" cy="54" r="1" fill="rgba(220,43,2,1)"/>
+ <circle cx="72" cy="54" r="1" fill="rgba(220,45,3,1)"/>
+ <circle cx="73" cy="54" r="1" fill="rgba(219,45,3,1)"/>
+ <circle cx="74" cy="54" r="1" fill="rgba(217,43,4,1)"/>
+ <circle cx="75" cy="54" r="1" fill="rgba(216,40,5,1)"/>
+ <circle cx="76" cy="54" r="1" fill="rgba(213,36,5,1)"/>
+ <circle cx="77" cy="54" r="1" fill="rgba(210,32,5,1)"/>
+ <circle cx="78" cy="54" r="1" fill="rgba(208,31,5,1)"/>
+ <circle cx="79" cy="54" r="1" fill="rgba(206,30,6,1)"/>
+ <circle cx="80" cy="54" r="1" fill="rgba(203,27,6,1)"/>
+ <circle cx="81" cy="54" r="1" fill="rgba(202,27,6,1)"/>
+ <circle cx="82" cy="54" r="1" fill="rgba(202,27,7,1)"/>
+ <circle cx="83" cy="54" r="1" fill="rgba(206,31,9,1)"/>
+ <circle cx="84" cy="54" r="1" fill="rgba(192,30,8,1)"/>
+ <circle cx="85" cy="54" r="1" fill="rgba(37,3,0,1)"/>
+ <circle cx="86" cy="54" r="1" fill="black"/>
+ <circle cx="87" cy="54" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="88" cy="54" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="89" cy="54" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="90" cy="54" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="91" cy="54" r="1" fill="black"/>
+ <circle cx="92" cy="54" r="1" fill="rgba(45,7,1,1)"/>
+ <circle cx="93" cy="54" r="1" fill="rgba(210,67,24,1)"/>
+ <circle cx="94" cy="54" r="1" fill="rgba(221,77,30,1)"/>
+ <circle cx="95" cy="54" r="1" fill="rgba(220,82,33,1)"/>
+ <circle cx="96" cy="54" r="1" fill="rgba(222,87,36,1)"/>
+ <circle cx="97" cy="54" r="1" fill="rgba(224,92,39,1)"/>
+ <circle cx="98" cy="54" r="1" fill="rgba(225,97,42,1)"/>
+ <circle cx="99" cy="54" r="1" fill="rgba(227,99,43,1)"/>
+ <circle cx="100" cy="54" r="1" fill="rgba(227,101,43,1)"/>
+ <circle cx="101" cy="54" r="1" fill="rgba(233,103,44,1)"/>
+ <circle cx="102" cy="54" r="1" fill="rgba(155,58,20,0.486275)"/>
+ <circle cx="103" cy="54" r="1" fill="rgba(117,41,12,0)"/>
+ <circle cx="104" cy="54" r="1" fill="rgba(133,48,15,0)"/>
+ <circle cx="105" cy="54" r="1" fill="rgba(105,38,12,0)"/>
+ <circle cx="106" cy="54" r="1" fill="rgba(37,14,4,0)"/>
+ <circle cx="107" cy="54" r="1" fill="rgba(0,1,0,0)"/>
+ <circle cx="108" cy="54" r="1" fill="rgba(24,9,2,0)"/>
+ <circle cx="109" cy="54" r="1" fill="rgba(45,21,8,0)"/>
+ <circle cx="110" cy="54" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="111" cy="54" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="112" cy="54" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="113" cy="54" r="1" fill="rgba(46,22,8,0)"/>
+ <circle cx="114" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="54" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="55" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="55" r="1" fill="rgba(103,71,44,0)"/>
+ <circle cx="19" cy="55" r="1" fill="rgba(100,68,41,0)"/>
+ <circle cx="20" cy="55" r="1" fill="rgba(96,65,38,0)"/>
+ <circle cx="21" cy="55" r="1" fill="rgba(101,61,34,0)"/>
+ <circle cx="22" cy="55" r="1" fill="rgba(94,54,28,0)"/>
+ <circle cx="23" cy="55" r="1" fill="rgba(136,56,18,0)"/>
+ <circle cx="24" cy="55" r="1" fill="rgba(169,58,9,0)"/>
+ <circle cx="25" cy="55" r="1" fill="rgba(206,62,4,0)"/>
+ <circle cx="26" cy="55" r="1" fill="rgba(242,70,0,0)"/>
+ <circle cx="27" cy="55" r="1" fill="rgba(245,71,0,0.313725)"/>
+ <circle cx="28" cy="55" r="1" fill="rgba(249,79,1,1)"/>
+ <circle cx="29" cy="55" r="1" fill="rgba(250,91,3,1)"/>
+ <circle cx="30" cy="55" r="1" fill="rgba(250,102,7,1)"/>
+ <circle cx="31" cy="55" r="1" fill="rgba(252,109,10,1)"/>
+ <circle cx="32" cy="55" r="1" fill="rgba(252,115,14,1)"/>
+ <circle cx="33" cy="55" r="1" fill="rgba(252,119,17,1)"/>
+ <circle cx="34" cy="55" r="1" fill="rgba(252,122,20,1)"/>
+ <circle cx="35" cy="55" r="1" fill="rgba(252,123,21,1)"/>
+ <circle cx="36" cy="55" r="1" fill="rgba(252,124,23,1)"/>
+ <circle cx="37" cy="55" r="1" fill="rgba(252,124,24,1)"/>
+ <circle cx="38" cy="55" r="1" fill="rgba(252,124,23,1)"/>
+ <circle cx="39" cy="55" r="1" fill="rgba(252,122,22,1)"/>
+ <circle cx="40" cy="55" r="1" fill="rgba(252,120,20,1)"/>
+ <circle cx="41" cy="55" r="1" fill="rgba(253,118,18,1)"/>
+ <circle cx="42" cy="55" r="1" fill="rgba(252,114,15,1)"/>
+ <circle cx="43" cy="55" r="1" fill="rgba(127,50,12,1)"/>
+ <circle cx="44" cy="55" r="1" fill="rgba(53,20,9,1)"/>
+ <circle cx="45" cy="55" r="1" fill="rgba(50,16,5,1)"/>
+ <circle cx="46" cy="55" r="1" fill="rgba(29,8,1,1)"/>
+ <circle cx="47" cy="55" r="1" fill="rgba(7,1,0,1)"/>
+ <circle cx="48" cy="55" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="49" cy="55" r="1" fill="black"/>
+ <circle cx="50" cy="55" r="1" fill="rgba(45,7,0,1)"/>
+ <circle cx="51" cy="55" r="1" fill="rgba(241,72,0,1)"/>
+ <circle cx="52" cy="55" r="1" fill="rgba(252,75,0,1)"/>
+ <circle cx="53" cy="55" r="1" fill="rgba(247,73,0,1)"/>
+ <circle cx="54" cy="55" r="1" fill="rgba(246,73,0,1)"/>
+ <circle cx="55" cy="55" r="1" fill="rgba(244,74,0,1)"/>
+ <circle cx="56" cy="55" r="1" fill="rgba(242,76,0,1)"/>
+ <circle cx="57" cy="55" r="1" fill="rgba(241,76,0,1)"/>
+ <circle cx="58" cy="55" r="1" fill="rgba(241,76,0,1)"/>
+ <circle cx="59" cy="55" r="1" fill="rgba(239,72,0,1)"/>
+ <circle cx="60" cy="55" r="1" fill="rgba(237,67,0,1)"/>
+ <circle cx="61" cy="55" r="1" fill="rgba(234,60,0,1)"/>
+ <circle cx="62" cy="55" r="1" fill="rgba(231,52,0,1)"/>
+ <circle cx="63" cy="55" r="1" fill="rgba(229,46,0,1)"/>
+ <circle cx="64" cy="55" r="1" fill="rgba(224,34,0,1)"/>
+ <circle cx="65" cy="55" r="1" fill="rgba(176,17,0,1)"/>
+ <circle cx="66" cy="55" r="1" fill="rgba(162,25,1,1)"/>
+ <circle cx="67" cy="55" r="1" fill="rgba(224,32,0,1)"/>
+ <circle cx="68" cy="55" r="1" fill="rgba(216,33,0,1)"/>
+ <circle cx="69" cy="55" r="1" fill="rgba(217,35,1,1)"/>
+ <circle cx="70" cy="55" r="1" fill="rgba(219,40,1,1)"/>
+ <circle cx="71" cy="55" r="1" fill="rgba(219,43,2,1)"/>
+ <circle cx="72" cy="55" r="1" fill="rgba(220,45,3,1)"/>
+ <circle cx="73" cy="55" r="1" fill="rgba(218,44,3,1)"/>
+ <circle cx="74" cy="55" r="1" fill="rgba(217,41,4,1)"/>
+ <circle cx="75" cy="55" r="1" fill="rgba(214,37,4,1)"/>
+ <circle cx="76" cy="55" r="1" fill="rgba(211,33,5,1)"/>
+ <circle cx="77" cy="55" r="1" fill="rgba(209,29,4,1)"/>
+ <circle cx="78" cy="55" r="1" fill="rgba(207,28,4,1)"/>
+ <circle cx="79" cy="55" r="1" fill="rgba(205,27,5,1)"/>
+ <circle cx="80" cy="55" r="1" fill="rgba(202,25,5,1)"/>
+ <circle cx="81" cy="55" r="1" fill="rgba(200,25,6,1)"/>
+ <circle cx="82" cy="55" r="1" fill="rgba(200,26,6,1)"/>
+ <circle cx="83" cy="55" r="1" fill="rgba(202,30,8,1)"/>
+ <circle cx="84" cy="55" r="1" fill="rgba(210,34,10,1)"/>
+ <circle cx="85" cy="55" r="1" fill="rgba(130,18,4,1)"/>
+ <circle cx="86" cy="55" r="1" fill="black"/>
+ <circle cx="87" cy="55" r="1" fill="black"/>
+ <circle cx="88" cy="55" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="89" cy="55" r="1" fill="black"/>
+ <circle cx="90" cy="55" r="1" fill="black"/>
+ <circle cx="91" cy="55" r="1" fill="black"/>
+ <circle cx="92" cy="55" r="1" fill="rgba(143,37,11,1)"/>
+ <circle cx="93" cy="55" r="1" fill="rgba(222,72,27,1)"/>
+ <circle cx="94" cy="55" r="1" fill="rgba(218,75,30,1)"/>
+ <circle cx="95" cy="55" r="1" fill="rgba(221,81,33,1)"/>
+ <circle cx="96" cy="55" r="1" fill="rgba(222,86,36,1)"/>
+ <circle cx="97" cy="55" r="1" fill="rgba(224,91,39,1)"/>
+ <circle cx="98" cy="55" r="1" fill="rgba(225,97,42,1)"/>
+ <circle cx="99" cy="55" r="1" fill="rgba(227,100,43,1)"/>
+ <circle cx="100" cy="55" r="1" fill="rgba(228,102,44,1)"/>
+ <circle cx="101" cy="55" r="1" fill="rgba(236,107,47,1)"/>
+ <circle cx="102" cy="55" r="1" fill="rgba(172,68,24,0.694118)"/>
+ <circle cx="103" cy="55" r="1" fill="rgba(104,35,10,0.0862745)"/>
+ <circle cx="104" cy="55" r="1" fill="rgba(127,46,14,0)"/>
+ <circle cx="105" cy="55" r="1" fill="rgba(126,45,14,0)"/>
+ <circle cx="106" cy="55" r="1" fill="rgba(120,43,13,0)"/>
+ <circle cx="107" cy="55" r="1" fill="rgba(54,14,3,0)"/>
+ <circle cx="108" cy="55" r="1" fill="rgba(7,5,1,0)"/>
+ <circle cx="109" cy="55" r="1" fill="rgba(42,20,8,0)"/>
+ <circle cx="110" cy="55" r="1" fill="rgba(45,22,8,0)"/>
+ <circle cx="111" cy="55" r="1" fill="rgba(45,22,8,0)"/>
+ <circle cx="112" cy="55" r="1" fill="rgba(45,22,8,0)"/>
+ <circle cx="113" cy="55" r="1" fill="rgba(45,22,8,0)"/>
+ <circle cx="114" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="55" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="56" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="56" r="1" fill="rgba(103,71,44,0)"/>
+ <circle cx="19" cy="56" r="1" fill="rgba(100,68,41,0)"/>
+ <circle cx="20" cy="56" r="1" fill="rgba(97,64,37,0)"/>
+ <circle cx="21" cy="56" r="1" fill="rgba(90,59,34,0)"/>
+ <circle cx="22" cy="56" r="1" fill="rgba(83,54,30,0)"/>
+ <circle cx="23" cy="56" r="1" fill="rgba(70,48,28,0)"/>
+ <circle cx="24" cy="56" r="1" fill="rgba(57,42,24,0)"/>
+ <circle cx="25" cy="56" r="1" fill="rgba(68,38,19,0)"/>
+ <circle cx="26" cy="56" r="1" fill="rgba(70,35,14,0)"/>
+ <circle cx="27" cy="56" r="1" fill="rgba(185,56,3,0.564706)"/>
+ <circle cx="28" cy="56" r="1" fill="rgba(255,82,0,1)"/>
+ <circle cx="29" cy="56" r="1" fill="rgba(250,91,1,1)"/>
+ <circle cx="30" cy="56" r="1" fill="rgba(251,99,3,1)"/>
+ <circle cx="31" cy="56" r="1" fill="rgba(252,105,6,1)"/>
+ <circle cx="32" cy="56" r="1" fill="rgba(252,110,9,1)"/>
+ <circle cx="33" cy="56" r="1" fill="rgba(252,113,11,1)"/>
+ <circle cx="34" cy="56" r="1" fill="rgba(252,115,13,1)"/>
+ <circle cx="35" cy="56" r="1" fill="rgba(252,117,15,1)"/>
+ <circle cx="36" cy="56" r="1" fill="rgba(252,117,16,1)"/>
+ <circle cx="37" cy="56" r="1" fill="rgba(252,118,16,1)"/>
+ <circle cx="38" cy="56" r="1" fill="rgba(252,117,16,1)"/>
+ <circle cx="39" cy="56" r="1" fill="rgba(252,115,16,1)"/>
+ <circle cx="40" cy="56" r="1" fill="rgba(252,113,14,1)"/>
+ <circle cx="41" cy="56" r="1" fill="rgba(252,110,11,1)"/>
+ <circle cx="42" cy="56" r="1" fill="rgba(255,111,9,1)"/>
+ <circle cx="43" cy="56" r="1" fill="rgba(179,67,7,1)"/>
+ <circle cx="44" cy="56" r="1" fill="rgba(22,9,4,1)"/>
+ <circle cx="45" cy="56" r="1" fill="rgba(26,7,1,1)"/>
+ <circle cx="46" cy="56" r="1" fill="rgba(10,1,0,1)"/>
+ <circle cx="47" cy="56" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="48" cy="56" r="1" fill="rgba(4,0,0,1)"/>
+ <circle cx="49" cy="56" r="1" fill="black"/>
+ <circle cx="50" cy="56" r="1" fill="rgba(108,23,0,1)"/>
+ <circle cx="51" cy="56" r="1" fill="rgba(252,74,0,1)"/>
+ <circle cx="52" cy="56" r="1" fill="rgba(249,71,0,1)"/>
+ <circle cx="53" cy="56" r="1" fill="rgba(246,69,0,1)"/>
+ <circle cx="54" cy="56" r="1" fill="rgba(244,69,0,1)"/>
+ <circle cx="55" cy="56" r="1" fill="rgba(242,69,0,1)"/>
+ <circle cx="56" cy="56" r="1" fill="rgba(242,72,0,1)"/>
+ <circle cx="57" cy="56" r="1" fill="rgba(241,73,0,1)"/>
+ <circle cx="58" cy="56" r="1" fill="rgba(239,73,0,1)"/>
+ <circle cx="59" cy="56" r="1" fill="rgba(238,71,0,1)"/>
+ <circle cx="60" cy="56" r="1" fill="rgba(236,65,0,1)"/>
+ <circle cx="61" cy="56" r="1" fill="rgba(233,59,0,1)"/>
+ <circle cx="62" cy="56" r="1" fill="rgba(231,51,0,1)"/>
+ <circle cx="63" cy="56" r="1" fill="rgba(228,46,0,1)"/>
+ <circle cx="64" cy="56" r="1" fill="rgba(223,33,0,1)"/>
+ <circle cx="65" cy="56" r="1" fill="rgba(177,18,0,1)"/>
+ <circle cx="66" cy="56" r="1" fill="rgba(163,26,1,1)"/>
+ <circle cx="67" cy="56" r="1" fill="rgba(223,31,0,1)"/>
+ <circle cx="68" cy="56" r="1" fill="rgba(215,33,0,1)"/>
+ <circle cx="69" cy="56" r="1" fill="rgba(217,36,0,1)"/>
+ <circle cx="70" cy="56" r="1" fill="rgba(219,40,1,1)"/>
+ <circle cx="71" cy="56" r="1" fill="rgba(219,42,2,1)"/>
+ <circle cx="72" cy="56" r="1" fill="rgba(220,44,3,1)"/>
+ <circle cx="73" cy="56" r="1" fill="rgba(218,42,3,1)"/>
+ <circle cx="74" cy="56" r="1" fill="rgba(216,40,4,1)"/>
+ <circle cx="75" cy="56" r="1" fill="rgba(214,36,4,1)"/>
+ <circle cx="76" cy="56" r="1" fill="rgba(210,31,4,1)"/>
+ <circle cx="77" cy="56" r="1" fill="rgba(207,27,4,1)"/>
+ <circle cx="78" cy="56" r="1" fill="rgba(205,25,4,1)"/>
+ <circle cx="79" cy="56" r="1" fill="rgba(203,24,4,1)"/>
+ <circle cx="80" cy="56" r="1" fill="rgba(202,24,5,1)"/>
+ <circle cx="81" cy="56" r="1" fill="rgba(200,24,5,1)"/>
+ <circle cx="82" cy="56" r="1" fill="rgba(201,26,6,1)"/>
+ <circle cx="83" cy="56" r="1" fill="rgba(202,29,8,1)"/>
+ <circle cx="84" cy="56" r="1" fill="rgba(205,33,9,1)"/>
+ <circle cx="85" cy="56" r="1" fill="rgba(204,35,10,1)"/>
+ <circle cx="86" cy="56" r="1" fill="rgba(102,14,3,1)"/>
+ <circle cx="87" cy="56" r="1" fill="black"/>
+ <circle cx="88" cy="56" r="1" fill="black"/>
+ <circle cx="89" cy="56" r="1" fill="black"/>
+ <circle cx="90" cy="56" r="1" fill="rgba(42,5,0,1)"/>
+ <circle cx="91" cy="56" r="1" fill="rgba(142,34,9,1)"/>
+ <circle cx="92" cy="56" r="1" fill="rgba(218,66,24,1)"/>
+ <circle cx="93" cy="56" r="1" fill="rgba(217,70,26,1)"/>
+ <circle cx="94" cy="56" r="1" fill="rgba(218,75,29,1)"/>
+ <circle cx="95" cy="56" r="1" fill="rgba(221,81,32,1)"/>
+ <circle cx="96" cy="56" r="1" fill="rgba(222,86,35,1)"/>
+ <circle cx="97" cy="56" r="1" fill="rgba(224,92,38,1)"/>
+ <circle cx="98" cy="56" r="1" fill="rgba(226,97,42,1)"/>
+ <circle cx="99" cy="56" r="1" fill="rgba(228,101,44,1)"/>
+ <circle cx="100" cy="56" r="1" fill="rgba(230,105,47,1)"/>
+ <circle cx="101" cy="56" r="1" fill="rgba(234,108,48,1)"/>
+ <circle cx="102" cy="56" r="1" fill="rgba(198,85,32,0.839216)"/>
+ <circle cx="103" cy="56" r="1" fill="rgba(95,31,8,0.192157)"/>
+ <circle cx="104" cy="56" r="1" fill="rgba(122,43,14,0.00784314)"/>
+ <circle cx="105" cy="56" r="1" fill="rgba(122,43,14,0)"/>
+ <circle cx="106" cy="56" r="1" fill="rgba(125,45,14,0)"/>
+ <circle cx="107" cy="56" r="1" fill="rgba(120,42,13,0)"/>
+ <circle cx="108" cy="56" r="1" fill="rgba(78,26,8,0)"/>
+ <circle cx="109" cy="56" r="1" fill="rgba(51,22,8,0)"/>
+ <circle cx="110" cy="56" r="1" fill="rgba(50,23,9,0)"/>
+ <circle cx="111" cy="56" r="1" fill="rgba(51,23,9,0)"/>
+ <circle cx="112" cy="56" r="1" fill="rgba(51,23,9,0)"/>
+ <circle cx="113" cy="56" r="1" fill="rgba(51,23,9,0)"/>
+ <circle cx="114" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="56" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="57" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="57" r="1" fill="rgba(103,71,44,0)"/>
+ <circle cx="19" cy="57" r="1" fill="rgba(100,68,41,0)"/>
+ <circle cx="20" cy="57" r="1" fill="rgba(96,64,37,0)"/>
+ <circle cx="21" cy="57" r="1" fill="rgba(92,59,34,0)"/>
+ <circle cx="22" cy="57" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="23" cy="57" r="1" fill="rgba(81,49,27,0)"/>
+ <circle cx="24" cy="57" r="1" fill="rgba(76,44,22,0)"/>
+ <circle cx="25" cy="57" r="1" fill="rgba(67,38,19,0)"/>
+ <circle cx="26" cy="57" r="1" fill="rgba(51,32,16,0.513725)"/>
+ <circle cx="27" cy="57" r="1" fill="rgba(190,59,3,0.988235)"/>
+ <circle cx="28" cy="57" r="1" fill="rgba(255,83,0,1)"/>
+ <circle cx="29" cy="57" r="1" fill="rgba(251,89,0,1)"/>
+ <circle cx="30" cy="57" r="1" fill="rgba(252,95,1,1)"/>
+ <circle cx="31" cy="57" r="1" fill="rgba(252,100,3,1)"/>
+ <circle cx="32" cy="57" r="1" fill="rgba(252,103,4,1)"/>
+ <circle cx="33" cy="57" r="1" fill="rgba(252,106,6,1)"/>
+ <circle cx="34" cy="57" r="1" fill="rgba(252,108,8,1)"/>
+ <circle cx="35" cy="57" r="1" fill="rgba(252,109,9,1)"/>
+ <circle cx="36" cy="57" r="1" fill="rgba(252,110,10,1)"/>
+ <circle cx="37" cy="57" r="1" fill="rgba(252,110,10,1)"/>
+ <circle cx="38" cy="57" r="1" fill="rgba(252,109,10,1)"/>
+ <circle cx="39" cy="57" r="1" fill="rgba(252,108,9,1)"/>
+ <circle cx="40" cy="57" r="1" fill="rgba(252,107,8,1)"/>
+ <circle cx="41" cy="57" r="1" fill="rgba(252,103,6,1)"/>
+ <circle cx="42" cy="57" r="1" fill="rgba(255,101,5,1)"/>
+ <circle cx="43" cy="57" r="1" fill="rgba(245,94,2,1)"/>
+ <circle cx="44" cy="57" r="1" fill="rgba(110,30,0,1)"/>
+ <circle cx="45" cy="57" r="1" fill="black"/>
+ <circle cx="46" cy="57" r="1" fill="black"/>
+ <circle cx="47" cy="57" r="1" fill="black"/>
+ <circle cx="48" cy="57" r="1" fill="black"/>
+ <circle cx="49" cy="57" r="1" fill="rgba(37,5,0,1)"/>
+ <circle cx="50" cy="57" r="1" fill="rgba(211,57,0,1)"/>
+ <circle cx="51" cy="57" r="1" fill="rgba(253,71,0,1)"/>
+ <circle cx="52" cy="57" r="1" fill="rgba(246,67,0,1)"/>
+ <circle cx="53" cy="57" r="1" fill="rgba(245,65,0,1)"/>
+ <circle cx="54" cy="57" r="1" fill="rgba(243,65,0,1)"/>
+ <circle cx="55" cy="57" r="1" fill="rgba(241,65,0,1)"/>
+ <circle cx="56" cy="57" r="1" fill="rgba(241,68,0,1)"/>
+ <circle cx="57" cy="57" r="1" fill="rgba(240,70,0,1)"/>
+ <circle cx="58" cy="57" r="1" fill="rgba(238,70,0,1)"/>
+ <circle cx="59" cy="57" r="1" fill="rgba(237,70,0,1)"/>
+ <circle cx="60" cy="57" r="1" fill="rgba(236,65,0,1)"/>
+ <circle cx="61" cy="57" r="1" fill="rgba(233,58,0,1)"/>
+ <circle cx="62" cy="57" r="1" fill="rgba(230,50,0,1)"/>
+ <circle cx="63" cy="57" r="1" fill="rgba(227,45,0,1)"/>
+ <circle cx="64" cy="57" r="1" fill="rgba(221,32,0,1)"/>
+ <circle cx="65" cy="57" r="1" fill="rgba(178,19,0,1)"/>
+ <circle cx="66" cy="57" r="1" fill="rgba(163,27,2,1)"/>
+ <circle cx="67" cy="57" r="1" fill="rgba(221,30,0,1)"/>
+ <circle cx="68" cy="57" r="1" fill="rgba(214,32,0,1)"/>
+ <circle cx="69" cy="57" r="1" fill="rgba(216,36,0,1)"/>
+ <circle cx="70" cy="57" r="1" fill="rgba(218,39,1,1)"/>
+ <circle cx="71" cy="57" r="1" fill="rgba(219,42,2,1)"/>
+ <circle cx="72" cy="57" r="1" fill="rgba(218,43,3,1)"/>
+ <circle cx="73" cy="57" r="1" fill="rgba(217,41,3,1)"/>
+ <circle cx="74" cy="57" r="1" fill="rgba(215,38,4,1)"/>
+ <circle cx="75" cy="57" r="1" fill="rgba(213,34,4,1)"/>
+ <circle cx="76" cy="57" r="1" fill="rgba(210,29,3,1)"/>
+ <circle cx="77" cy="57" r="1" fill="rgba(207,26,3,1)"/>
+ <circle cx="78" cy="57" r="1" fill="rgba(204,24,4,1)"/>
+ <circle cx="79" cy="57" r="1" fill="rgba(203,23,4,1)"/>
+ <circle cx="80" cy="57" r="1" fill="rgba(201,22,5,1)"/>
+ <circle cx="81" cy="57" r="1" fill="rgba(200,23,5,1)"/>
+ <circle cx="82" cy="57" r="1" fill="rgba(201,26,6,1)"/>
+ <circle cx="83" cy="57" r="1" fill="rgba(202,29,8,1)"/>
+ <circle cx="84" cy="57" r="1" fill="rgba(203,32,9,1)"/>
+ <circle cx="85" cy="57" r="1" fill="rgba(207,36,10,1)"/>
+ <circle cx="86" cy="57" r="1" fill="rgba(207,38,11,1)"/>
+ <circle cx="87" cy="57" r="1" fill="rgba(161,30,8,1)"/>
+ <circle cx="88" cy="57" r="1" fill="rgba(135,26,7,1)"/>
+ <circle cx="89" cy="57" r="1" fill="rgba(155,33,9,1)"/>
+ <circle cx="90" cy="57" r="1" fill="rgba(198,50,17,1)"/>
+ <circle cx="91" cy="57" r="1" fill="rgba(221,63,22,1)"/>
+ <circle cx="92" cy="57" r="1" fill="rgba(217,66,24,1)"/>
+ <circle cx="93" cy="57" r="1" fill="rgba(217,69,26,1)"/>
+ <circle cx="94" cy="57" r="1" fill="rgba(218,75,29,1)"/>
+ <circle cx="95" cy="57" r="1" fill="rgba(221,81,32,1)"/>
+ <circle cx="96" cy="57" r="1" fill="rgba(222,87,35,1)"/>
+ <circle cx="97" cy="57" r="1" fill="rgba(224,92,38,1)"/>
+ <circle cx="98" cy="57" r="1" fill="rgba(226,97,42,1)"/>
+ <circle cx="99" cy="57" r="1" fill="rgba(228,103,45,1)"/>
+ <circle cx="100" cy="57" r="1" fill="rgba(230,106,48,1)"/>
+ <circle cx="101" cy="57" r="1" fill="rgba(233,109,48,1)"/>
+ <circle cx="102" cy="57" r="1" fill="rgba(214,96,39,0.94902)"/>
+ <circle cx="103" cy="57" r="1" fill="rgba(80,23,6,0.27451)"/>
+ <circle cx="104" cy="57" r="1" fill="rgba(112,39,12,0.0470588)"/>
+ <circle cx="105" cy="57" r="1" fill="rgba(121,44,14,0)"/>
+ <circle cx="106" cy="57" r="1" fill="rgba(120,43,14,0)"/>
+ <circle cx="107" cy="57" r="1" fill="rgba(121,44,14,0)"/>
+ <circle cx="108" cy="57" r="1" fill="rgba(125,45,14,0)"/>
+ <circle cx="109" cy="57" r="1" fill="rgba(116,42,13,0)"/>
+ <circle cx="110" cy="57" r="1" fill="rgba(116,42,13,0)"/>
+ <circle cx="111" cy="57" r="1" fill="rgba(116,42,13,0)"/>
+ <circle cx="112" cy="57" r="1" fill="rgba(116,42,13,0)"/>
+ <circle cx="113" cy="57" r="1" fill="rgba(116,42,13,0)"/>
+ <circle cx="114" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="57" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="58" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="58" r="1" fill="rgba(103,71,44,0)"/>
+ <circle cx="19" cy="58" r="1" fill="rgba(100,68,41,0)"/>
+ <circle cx="20" cy="58" r="1" fill="rgba(96,64,37,0)"/>
+ <circle cx="21" cy="58" r="1" fill="rgba(92,59,34,0)"/>
+ <circle cx="22" cy="58" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="23" cy="58" r="1" fill="rgba(81,49,26,0)"/>
+ <circle cx="24" cy="58" r="1" fill="rgba(76,44,22,0.0901961)"/>
+ <circle cx="25" cy="58" r="1" fill="rgba(68,38,19,0.670588)"/>
+ <circle cx="26" cy="58" r="1" fill="rgba(68,35,16,1)"/>
+ <circle cx="27" cy="58" r="1" fill="rgba(214,65,1,1)"/>
+ <circle cx="28" cy="58" r="1" fill="rgba(254,83,0,1)"/>
+ <circle cx="29" cy="58" r="1" fill="rgba(250,87,0,1)"/>
+ <circle cx="30" cy="58" r="1" fill="rgba(252,90,0,1)"/>
+ <circle cx="31" cy="58" r="1" fill="rgba(252,93,0,1)"/>
+ <circle cx="32" cy="58" r="1" fill="rgba(252,96,1,1)"/>
+ <circle cx="33" cy="58" r="1" fill="rgba(252,99,2,1)"/>
+ <circle cx="34" cy="58" r="1" fill="rgba(252,100,3,1)"/>
+ <circle cx="35" cy="58" r="1" fill="rgba(252,102,4,1)"/>
+ <circle cx="36" cy="58" r="1" fill="rgba(252,103,5,1)"/>
+ <circle cx="37" cy="58" r="1" fill="rgba(252,102,5,1)"/>
+ <circle cx="38" cy="58" r="1" fill="rgba(252,101,4,1)"/>
+ <circle cx="39" cy="58" r="1" fill="rgba(252,100,4,1)"/>
+ <circle cx="40" cy="58" r="1" fill="rgba(253,99,3,1)"/>
+ <circle cx="41" cy="58" r="1" fill="rgba(253,96,2,1)"/>
+ <circle cx="42" cy="58" r="1" fill="rgba(254,93,0,1)"/>
+ <circle cx="43" cy="58" r="1" fill="rgba(255,91,0,1)"/>
+ <circle cx="44" cy="58" r="1" fill="rgba(249,84,0,1)"/>
+ <circle cx="45" cy="58" r="1" fill="rgba(171,48,0,1)"/>
+ <circle cx="46" cy="58" r="1" fill="rgba(103,23,0,1)"/>
+ <circle cx="47" cy="58" r="1" fill="rgba(71,13,0,1)"/>
+ <circle cx="48" cy="58" r="1" fill="rgba(120,26,0,1)"/>
+ <circle cx="49" cy="58" r="1" fill="rgba(214,58,0,1)"/>
+ <circle cx="50" cy="58" r="1" fill="rgba(255,72,0,1)"/>
+ <circle cx="51" cy="58" r="1" fill="rgba(246,66,0,1)"/>
+ <circle cx="52" cy="58" r="1" fill="rgba(244,64,0,1)"/>
+ <circle cx="53" cy="58" r="1" fill="rgba(243,61,0,1)"/>
+ <circle cx="54" cy="58" r="1" fill="rgba(241,61,0,1)"/>
+ <circle cx="55" cy="58" r="1" fill="rgba(240,63,0,1)"/>
+ <circle cx="56" cy="58" r="1" fill="rgba(240,66,0,1)"/>
+ <circle cx="57" cy="58" r="1" fill="rgba(239,68,0,1)"/>
+ <circle cx="58" cy="58" r="1" fill="rgba(238,69,0,1)"/>
+ <circle cx="59" cy="58" r="1" fill="rgba(236,67,0,1)"/>
+ <circle cx="60" cy="58" r="1" fill="rgba(234,63,0,1)"/>
+ <circle cx="61" cy="58" r="1" fill="rgba(233,57,0,1)"/>
+ <circle cx="62" cy="58" r="1" fill="rgba(230,49,0,1)"/>
+ <circle cx="63" cy="58" r="1" fill="rgba(227,44,0,1)"/>
+ <circle cx="64" cy="58" r="1" fill="rgba(221,31,0,1)"/>
+ <circle cx="65" cy="58" r="1" fill="rgba(177,19,1,1)"/>
+ <circle cx="66" cy="58" r="1" fill="rgba(163,27,3,1)"/>
+ <circle cx="67" cy="58" r="1" fill="rgba(220,30,0,1)"/>
+ <circle cx="68" cy="58" r="1" fill="rgba(214,32,0,1)"/>
+ <circle cx="69" cy="58" r="1" fill="rgba(215,35,1,1)"/>
+ <circle cx="70" cy="58" r="1" fill="rgba(217,39,1,1)"/>
+ <circle cx="71" cy="58" r="1" fill="rgba(218,42,2,1)"/>
+ <circle cx="72" cy="58" r="1" fill="rgba(218,41,3,1)"/>
+ <circle cx="73" cy="58" r="1" fill="rgba(217,40,3,1)"/>
+ <circle cx="74" cy="58" r="1" fill="rgba(214,35,3,1)"/>
+ <circle cx="75" cy="58" r="1" fill="rgba(211,32,3,1)"/>
+ <circle cx="76" cy="58" r="1" fill="rgba(208,28,3,1)"/>
+ <circle cx="77" cy="58" r="1" fill="rgba(206,26,3,1)"/>
+ <circle cx="78" cy="58" r="1" fill="rgba(203,24,4,1)"/>
+ <circle cx="79" cy="58" r="1" fill="rgba(203,22,4,1)"/>
+ <circle cx="80" cy="58" r="1" fill="rgba(200,21,4,1)"/>
+ <circle cx="81" cy="58" r="1" fill="rgba(200,23,6,1)"/>
+ <circle cx="82" cy="58" r="1" fill="rgba(201,26,6,1)"/>
+ <circle cx="83" cy="58" r="1" fill="rgba(202,29,8,1)"/>
+ <circle cx="84" cy="58" r="1" fill="rgba(203,32,9,1)"/>
+ <circle cx="85" cy="58" r="1" fill="rgba(205,36,10,1)"/>
+ <circle cx="86" cy="58" r="1" fill="rgba(207,38,11,1)"/>
+ <circle cx="87" cy="58" r="1" fill="rgba(214,44,14,1)"/>
+ <circle cx="88" cy="58" r="1" fill="rgba(217,50,16,1)"/>
+ <circle cx="89" cy="58" r="1" fill="rgba(217,54,18,1)"/>
+ <circle cx="90" cy="58" r="1" fill="rgba(215,56,20,1)"/>
+ <circle cx="91" cy="58" r="1" fill="rgba(214,60,21,1)"/>
+ <circle cx="92" cy="58" r="1" fill="rgba(215,65,24,1)"/>
+ <circle cx="93" cy="58" r="1" fill="rgba(217,70,26,1)"/>
+ <circle cx="94" cy="58" r="1" fill="rgba(219,75,29,1)"/>
+ <circle cx="95" cy="58" r="1" fill="rgba(221,81,33,1)"/>
+ <circle cx="96" cy="58" r="1" fill="rgba(223,87,36,1)"/>
+ <circle cx="97" cy="58" r="1" fill="rgba(224,92,39,1)"/>
+ <circle cx="98" cy="58" r="1" fill="rgba(226,98,42,1)"/>
+ <circle cx="99" cy="58" r="1" fill="rgba(228,103,46,1)"/>
+ <circle cx="100" cy="58" r="1" fill="rgba(230,108,48,1)"/>
+ <circle cx="101" cy="58" r="1" fill="rgba(233,111,49,1)"/>
+ <circle cx="102" cy="58" r="1" fill="rgba(224,104,44,1)"/>
+ <circle cx="103" cy="58" r="1" fill="rgba(86,33,10,0.6)"/>
+ <circle cx="104" cy="58" r="1" fill="rgba(98,33,9,0.113725)"/>
+ <circle cx="105" cy="58" r="1" fill="rgba(123,45,14,0)"/>
+ <circle cx="106" cy="58" r="1" fill="rgba(122,45,14,0)"/>
+ <circle cx="107" cy="58" r="1" fill="rgba(122,45,14,0)"/>
+ <circle cx="108" cy="58" r="1" fill="rgba(122,45,14,0)"/>
+ <circle cx="109" cy="58" r="1" fill="rgba(123,45,14,0)"/>
+ <circle cx="110" cy="58" r="1" fill="rgba(123,45,14,0)"/>
+ <circle cx="111" cy="58" r="1" fill="rgba(123,45,14,0)"/>
+ <circle cx="112" cy="58" r="1" fill="rgba(123,45,14,0)"/>
+ <circle cx="113" cy="58" r="1" fill="rgba(124,45,14,0)"/>
+ <circle cx="114" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="58" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="59" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="59" r="1" fill="rgba(103,71,44,0)"/>
+ <circle cx="19" cy="59" r="1" fill="rgba(100,68,41,0)"/>
+ <circle cx="20" cy="59" r="1" fill="rgba(96,64,37,0)"/>
+ <circle cx="21" cy="59" r="1" fill="rgba(92,59,34,0)"/>
+ <circle cx="22" cy="59" r="1" fill="rgba(86,54,30,0)"/>
+ <circle cx="23" cy="59" r="1" fill="rgba(81,49,26,0.219608)"/>
+ <circle cx="24" cy="59" r="1" fill="rgba(77,45,23,0.827451)"/>
+ <circle cx="25" cy="59" r="1" fill="rgba(67,39,21,1)"/>
+ <circle cx="26" cy="59" r="1" fill="rgba(81,37,15,0.984314)"/>
+ <circle cx="27" cy="59" r="1" fill="rgba(235,70,0,0.984314)"/>
+ <circle cx="28" cy="59" r="1" fill="rgba(251,81,0,1)"/>
+ <circle cx="29" cy="59" r="1" fill="rgba(249,84,0,1)"/>
+ <circle cx="30" cy="59" r="1" fill="rgba(249,87,0,1)"/>
+ <circle cx="31" cy="59" r="1" fill="rgba(251,89,0,1)"/>
+ <circle cx="32" cy="59" r="1" fill="rgba(252,91,0,1)"/>
+ <circle cx="33" cy="59" r="1" fill="rgba(252,93,0,1)"/>
+ <circle cx="34" cy="59" r="1" fill="rgba(252,93,0,1)"/>
+ <circle cx="35" cy="59" r="1" fill="rgba(253,94,0,1)"/>
+ <circle cx="36" cy="59" r="1" fill="rgba(253,95,0,1)"/>
+ <circle cx="37" cy="59" r="1" fill="rgba(253,95,0,1)"/>
+ <circle cx="38" cy="59" r="1" fill="rgba(253,94,0,1)"/>
+ <circle cx="39" cy="59" r="1" fill="rgba(254,93,0,1)"/>
+ <circle cx="40" cy="59" r="1" fill="rgba(254,91,0,1)"/>
+ <circle cx="41" cy="59" r="1" fill="rgba(253,90,0,1)"/>
+ <circle cx="42" cy="59" r="1" fill="rgba(253,87,0,1)"/>
+ <circle cx="43" cy="59" r="1" fill="rgba(253,85,0,1)"/>
+ <circle cx="44" cy="59" r="1" fill="rgba(255,84,0,1)"/>
+ <circle cx="45" cy="59" r="1" fill="rgba(255,85,0,1)"/>
+ <circle cx="46" cy="59" r="1" fill="rgba(252,78,0,1)"/>
+ <circle cx="47" cy="59" r="1" fill="rgba(245,74,0,1)"/>
+ <circle cx="48" cy="59" r="1" fill="rgba(255,75,0,1)"/>
+ <circle cx="49" cy="59" r="1" fill="rgba(255,72,0,1)"/>
+ <circle cx="50" cy="59" r="1" fill="rgba(246,65,0,1)"/>
+ <circle cx="51" cy="59" r="1" fill="rgba(244,62,0,1)"/>
+ <circle cx="52" cy="59" r="1" fill="rgba(242,60,0,1)"/>
+ <circle cx="53" cy="59" r="1" fill="rgba(241,58,0,1)"/>
+ <circle cx="54" cy="59" r="1" fill="rgba(241,58,0,1)"/>
+ <circle cx="55" cy="59" r="1" fill="rgba(239,61,0,1)"/>
+ <circle cx="56" cy="59" r="1" fill="rgba(239,64,0,1)"/>
+ <circle cx="57" cy="59" r="1" fill="rgba(238,66,0,1)"/>
+ <circle cx="58" cy="59" r="1" fill="rgba(236,68,0,1)"/>
+ <circle cx="59" cy="59" r="1" fill="rgba(236,65,0,1)"/>
+ <circle cx="60" cy="59" r="1" fill="rgba(233,61,0,1)"/>
+ <circle cx="61" cy="59" r="1" fill="rgba(231,56,0,1)"/>
+ <circle cx="62" cy="59" r="1" fill="rgba(229,49,0,1)"/>
+ <circle cx="63" cy="59" r="1" fill="rgba(226,42,0,1)"/>
+ <circle cx="64" cy="59" r="1" fill="rgba(220,29,0,1)"/>
+ <circle cx="65" cy="59" r="1" fill="rgba(176,19,1,1)"/>
+ <circle cx="66" cy="59" r="1" fill="rgba(163,27,3,1)"/>
+ <circle cx="67" cy="59" r="1" fill="rgba(217,28,0,1)"/>
+ <circle cx="68" cy="59" r="1" fill="rgba(212,30,0,1)"/>
+ <circle cx="69" cy="59" r="1" fill="rgba(214,35,1,1)"/>
+ <circle cx="70" cy="59" r="1" fill="rgba(217,39,1,1)"/>
+ <circle cx="71" cy="59" r="1" fill="rgba(217,41,2,1)"/>
+ <circle cx="72" cy="59" r="1" fill="rgba(217,41,3,1)"/>
+ <circle cx="73" cy="59" r="1" fill="rgba(216,38,3,1)"/>
+ <circle cx="74" cy="59" r="1" fill="rgba(214,34,3,1)"/>
+ <circle cx="75" cy="59" r="1" fill="rgba(210,30,3,1)"/>
+ <circle cx="76" cy="59" r="1" fill="rgba(207,27,3,1)"/>
+ <circle cx="77" cy="59" r="1" fill="rgba(205,24,3,1)"/>
+ <circle cx="78" cy="59" r="1" fill="rgba(203,23,3,1)"/>
+ <circle cx="79" cy="59" r="1" fill="rgba(202,21,4,1)"/>
+ <circle cx="80" cy="59" r="1" fill="rgba(200,21,4,1)"/>
+ <circle cx="81" cy="59" r="1" fill="rgba(200,23,6,1)"/>
+ <circle cx="82" cy="59" r="1" fill="rgba(202,26,6,1)"/>
+ <circle cx="83" cy="59" r="1" fill="rgba(202,29,8,1)"/>
+ <circle cx="84" cy="59" r="1" fill="rgba(203,33,9,1)"/>
+ <circle cx="85" cy="59" r="1" fill="rgba(205,36,10,1)"/>
+ <circle cx="86" cy="59" r="1" fill="rgba(206,38,11,1)"/>
+ <circle cx="87" cy="59" r="1" fill="rgba(207,43,13,1)"/>
+ <circle cx="88" cy="59" r="1" fill="rgba(207,47,14,1)"/>
+ <circle cx="89" cy="59" r="1" fill="rgba(210,51,16,1)"/>
+ <circle cx="90" cy="59" r="1" fill="rgba(212,55,19,1)"/>
+ <circle cx="91" cy="59" r="1" fill="rgba(214,60,22,1)"/>
+ <circle cx="92" cy="59" r="1" fill="rgba(216,66,24,1)"/>
+ <circle cx="93" cy="59" r="1" fill="rgba(217,70,26,1)"/>
+ <circle cx="94" cy="59" r="1" fill="rgba(219,76,29,1)"/>
+ <circle cx="95" cy="59" r="1" fill="rgba(221,82,33,1)"/>
+ <circle cx="96" cy="59" r="1" fill="rgba(223,87,36,1)"/>
+ <circle cx="97" cy="59" r="1" fill="rgba(224,93,39,1)"/>
+ <circle cx="98" cy="59" r="1" fill="rgba(227,99,43,1)"/>
+ <circle cx="99" cy="59" r="1" fill="rgba(230,105,47,1)"/>
+ <circle cx="100" cy="59" r="1" fill="rgba(231,110,48,1)"/>
+ <circle cx="101" cy="59" r="1" fill="rgba(233,111,49,1)"/>
+ <circle cx="102" cy="59" r="1" fill="rgba(230,108,47,1)"/>
+ <circle cx="103" cy="59" r="1" fill="rgba(106,48,20,0.992157)"/>
+ <circle cx="104" cy="59" r="1" fill="rgba(73,28,9,0.466667)"/>
+ <circle cx="105" cy="59" r="1" fill="rgba(126,47,14,0)"/>
+ <circle cx="106" cy="59" r="1" fill="rgba(130,51,16,0)"/>
+ <circle cx="107" cy="59" r="1" fill="rgba(130,50,16,0)"/>
+ <circle cx="108" cy="59" r="1" fill="rgba(130,50,16,0)"/>
+ <circle cx="109" cy="59" r="1" fill="rgba(130,49,16,0)"/>
+ <circle cx="110" cy="59" r="1" fill="rgba(130,49,16,0)"/>
+ <circle cx="111" cy="59" r="1" fill="rgba(130,49,16,0)"/>
+ <circle cx="112" cy="59" r="1" fill="rgba(130,49,15,0)"/>
+ <circle cx="113" cy="59" r="1" fill="rgba(130,48,14,0)"/>
+ <circle cx="114" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="59" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="60" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="60" r="1" fill="rgba(103,71,44,0)"/>
+ <circle cx="19" cy="60" r="1" fill="rgba(100,68,41,0)"/>
+ <circle cx="20" cy="60" r="1" fill="rgba(96,64,37,0)"/>
+ <circle cx="21" cy="60" r="1" fill="rgba(92,59,34,0)"/>
+ <circle cx="22" cy="60" r="1" fill="rgba(87,54,30,0.419608)"/>
+ <circle cx="23" cy="60" r="1" fill="rgba(83,50,27,0.94902)"/>
+ <circle cx="24" cy="60" r="1" fill="rgba(78,46,24,1)"/>
+ <circle cx="25" cy="60" r="1" fill="rgba(50,38,23,0.882353)"/>
+ <circle cx="26" cy="60" r="1" fill="rgba(159,51,7,0.427451)"/>
+ <circle cx="27" cy="60" r="1" fill="rgba(252,72,0,0.945098)"/>
+ <circle cx="28" cy="60" r="1" fill="rgba(247,78,0,1)"/>
+ <circle cx="29" cy="60" r="1" fill="rgba(248,83,0,1)"/>
+ <circle cx="30" cy="60" r="1" fill="rgba(249,87,0,1)"/>
+ <circle cx="31" cy="60" r="1" fill="rgba(250,89,0,1)"/>
+ <circle cx="32" cy="60" r="1" fill="rgba(251,91,0,1)"/>
+ <circle cx="33" cy="60" r="1" fill="rgba(252,90,0,1)"/>
+ <circle cx="34" cy="60" r="1" fill="rgba(252,89,0,1)"/>
+ <circle cx="35" cy="60" r="1" fill="rgba(252,89,0,1)"/>
+ <circle cx="36" cy="60" r="1" fill="rgba(253,89,0,1)"/>
+ <circle cx="37" cy="60" r="1" fill="rgba(252,89,0,1)"/>
+ <circle cx="38" cy="60" r="1" fill="rgba(252,89,0,1)"/>
+ <circle cx="39" cy="60" r="1" fill="rgba(253,87,0,1)"/>
+ <circle cx="40" cy="60" r="1" fill="rgba(253,87,0,1)"/>
+ <circle cx="41" cy="60" r="1" fill="rgba(252,85,0,1)"/>
+ <circle cx="42" cy="60" r="1" fill="rgba(252,84,0,1)"/>
+ <circle cx="43" cy="60" r="1" fill="rgba(252,82,0,1)"/>
+ <circle cx="44" cy="60" r="1" fill="rgba(252,79,0,1)"/>
+ <circle cx="45" cy="60" r="1" fill="rgba(250,76,0,1)"/>
+ <circle cx="46" cy="60" r="1" fill="rgba(251,75,0,1)"/>
+ <circle cx="47" cy="60" r="1" fill="rgba(252,73,0,1)"/>
+ <circle cx="48" cy="60" r="1" fill="rgba(249,69,0,1)"/>
+ <circle cx="49" cy="60" r="1" fill="rgba(247,66,0,1)"/>
+ <circle cx="50" cy="60" r="1" fill="rgba(244,62,0,1)"/>
+ <circle cx="51" cy="60" r="1" fill="rgba(243,60,0,1)"/>
+ <circle cx="52" cy="60" r="1" fill="rgba(241,57,0,1)"/>
+ <circle cx="53" cy="60" r="1" fill="rgba(240,55,0,1)"/>
+ <circle cx="54" cy="60" r="1" fill="rgba(239,57,0,1)"/>
+ <circle cx="55" cy="60" r="1" fill="rgba(238,59,0,1)"/>
+ <circle cx="56" cy="60" r="1" fill="rgba(238,62,0,1)"/>
+ <circle cx="57" cy="60" r="1" fill="rgba(237,64,0,1)"/>
+ <circle cx="58" cy="60" r="1" fill="rgba(236,66,0,1)"/>
+ <circle cx="59" cy="60" r="1" fill="rgba(234,64,0,1)"/>
+ <circle cx="60" cy="60" r="1" fill="rgba(233,60,0,1)"/>
+ <circle cx="61" cy="60" r="1" fill="rgba(230,54,0,1)"/>
+ <circle cx="62" cy="60" r="1" fill="rgba(228,47,0,1)"/>
+ <circle cx="63" cy="60" r="1" fill="rgba(225,41,0,1)"/>
+ <circle cx="64" cy="60" r="1" fill="rgba(219,29,0,1)"/>
+ <circle cx="65" cy="60" r="1" fill="rgba(176,20,1,1)"/>
+ <circle cx="66" cy="60" r="1" fill="rgba(163,28,3,1)"/>
+ <circle cx="67" cy="60" r="1" fill="rgba(216,27,0,1)"/>
+ <circle cx="68" cy="60" r="1" fill="rgba(210,30,0,1)"/>
+ <circle cx="69" cy="60" r="1" fill="rgba(214,34,1,1)"/>
+ <circle cx="70" cy="60" r="1" fill="rgba(216,39,1,1)"/>
+ <circle cx="71" cy="60" r="1" fill="rgba(217,41,2,1)"/>
+ <circle cx="72" cy="60" r="1" fill="rgba(217,40,3,1)"/>
+ <circle cx="73" cy="60" r="1" fill="rgba(215,36,3,1)"/>
+ <circle cx="74" cy="60" r="1" fill="rgba(213,32,3,1)"/>
+ <circle cx="75" cy="60" r="1" fill="rgba(209,29,3,1)"/>
+ <circle cx="76" cy="60" r="1" fill="rgba(206,25,3,1)"/>
+ <circle cx="77" cy="60" r="1" fill="rgba(204,23,3,1)"/>
+ <circle cx="78" cy="60" r="1" fill="rgba(203,21,3,1)"/>
+ <circle cx="79" cy="60" r="1" fill="rgba(201,21,4,1)"/>
+ <circle cx="80" cy="60" r="1" fill="rgba(200,21,4,1)"/>
+ <circle cx="81" cy="60" r="1" fill="rgba(200,23,5,1)"/>
+ <circle cx="82" cy="60" r="1" fill="rgba(202,26,6,1)"/>
+ <circle cx="83" cy="60" r="1" fill="rgba(203,30,8,1)"/>
+ <circle cx="84" cy="60" r="1" fill="rgba(203,33,9,1)"/>
+ <circle cx="85" cy="60" r="1" fill="rgba(204,35,10,1)"/>
+ <circle cx="86" cy="60" r="1" fill="rgba(207,39,11,1)"/>
+ <circle cx="87" cy="60" r="1" fill="rgba(207,43,13,1)"/>
+ <circle cx="88" cy="60" r="1" fill="rgba(208,47,14,1)"/>
+ <circle cx="89" cy="60" r="1" fill="rgba(210,51,16,1)"/>
+ <circle cx="90" cy="60" r="1" fill="rgba(212,56,20,1)"/>
+ <circle cx="91" cy="60" r="1" fill="rgba(214,61,22,1)"/>
+ <circle cx="92" cy="60" r="1" fill="rgba(216,66,24,1)"/>
+ <circle cx="93" cy="60" r="1" fill="rgba(217,71,27,1)"/>
+ <circle cx="94" cy="60" r="1" fill="rgba(219,76,30,1)"/>
+ <circle cx="95" cy="60" r="1" fill="rgba(221,82,33,1)"/>
+ <circle cx="96" cy="60" r="1" fill="rgba(224,88,36,1)"/>
+ <circle cx="97" cy="60" r="1" fill="rgba(225,94,39,1)"/>
+ <circle cx="98" cy="60" r="1" fill="rgba(227,100,43,1)"/>
+ <circle cx="99" cy="60" r="1" fill="rgba(230,106,48,1)"/>
+ <circle cx="100" cy="60" r="1" fill="rgba(231,110,50,1)"/>
+ <circle cx="101" cy="60" r="1" fill="rgba(233,112,50,1)"/>
+ <circle cx="102" cy="60" r="1" fill="rgba(236,112,48,1)"/>
+ <circle cx="103" cy="60" r="1" fill="rgba(128,55,22,1)"/>
+ <circle cx="104" cy="60" r="1" fill="rgba(46,26,12,0.952941)"/>
+ <circle cx="105" cy="60" r="1" fill="rgba(97,38,13,0.278431)"/>
+ <circle cx="106" cy="60" r="1" fill="rgba(115,43,13,0)"/>
+ <circle cx="107" cy="60" r="1" fill="rgba(113,42,14,0)"/>
+ <circle cx="108" cy="60" r="1" fill="rgba(113,43,14,0)"/>
+ <circle cx="109" cy="60" r="1" fill="rgba(114,43,14,0)"/>
+ <circle cx="110" cy="60" r="1" fill="rgba(114,43,14,0)"/>
+ <circle cx="111" cy="60" r="1" fill="rgba(114,43,14,0)"/>
+ <circle cx="112" cy="60" r="1" fill="rgba(115,44,14,0)"/>
+ <circle cx="113" cy="60" r="1" fill="rgba(111,65,35,0)"/>
+ <circle cx="114" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="60" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="61" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="61" r="1" fill="rgba(103,71,44,0)"/>
+ <circle cx="19" cy="61" r="1" fill="rgba(100,68,41,0)"/>
+ <circle cx="20" cy="61" r="1" fill="rgba(96,64,37,0.14902)"/>
+ <circle cx="21" cy="61" r="1" fill="rgba(92,59,34,0.682353)"/>
+ <circle cx="22" cy="61" r="1" fill="rgba(87,55,31,1)"/>
+ <circle cx="23" cy="61" r="1" fill="rgba(84,51,27,1)"/>
+ <circle cx="24" cy="61" r="1" fill="rgba(63,44,26,0.870588)"/>
+ <circle cx="25" cy="61" r="1" fill="rgba(135,57,13,0.160784)"/>
+ <circle cx="26" cy="61" r="1" fill="rgba(244,77,0,0.2)"/>
+ <circle cx="27" cy="61" r="1" fill="rgba(245,70,0,0.996078)"/>
+ <circle cx="28" cy="61" r="1" fill="rgba(246,78,0,1)"/>
+ <circle cx="29" cy="61" r="1" fill="rgba(248,85,1,1)"/>
+ <circle cx="30" cy="61" r="1" fill="rgba(249,90,1,1)"/>
+ <circle cx="31" cy="61" r="1" fill="rgba(250,91,1,1)"/>
+ <circle cx="32" cy="61" r="1" fill="rgba(251,92,1,1)"/>
+ <circle cx="33" cy="61" r="1" fill="rgba(251,91,0,1)"/>
+ <circle cx="34" cy="61" r="1" fill="rgba(252,88,0,1)"/>
+ <circle cx="35" cy="61" r="1" fill="rgba(252,87,0,1)"/>
+ <circle cx="36" cy="61" r="1" fill="rgba(251,85,0,1)"/>
+ <circle cx="37" cy="61" r="1" fill="rgba(252,85,0,1)"/>
+ <circle cx="38" cy="61" r="1" fill="rgba(252,84,0,1)"/>
+ <circle cx="39" cy="61" r="1" fill="rgba(252,83,0,1)"/>
+ <circle cx="40" cy="61" r="1" fill="rgba(252,83,0,1)"/>
+ <circle cx="41" cy="61" r="1" fill="rgba(252,81,0,1)"/>
+ <circle cx="42" cy="61" r="1" fill="rgba(251,80,0,1)"/>
+ <circle cx="43" cy="61" r="1" fill="rgba(250,77,0,1)"/>
+ <circle cx="44" cy="61" r="1" fill="rgba(249,76,0,1)"/>
+ <circle cx="45" cy="61" r="1" fill="rgba(248,73,0,1)"/>
+ <circle cx="46" cy="61" r="1" fill="rgba(249,71,0,1)"/>
+ <circle cx="47" cy="61" r="1" fill="rgba(248,68,0,1)"/>
+ <circle cx="48" cy="61" r="1" fill="rgba(247,65,0,1)"/>
+ <circle cx="49" cy="61" r="1" fill="rgba(244,62,0,1)"/>
+ <circle cx="50" cy="61" r="1" fill="rgba(243,59,0,1)"/>
+ <circle cx="51" cy="61" r="1" fill="rgba(242,56,0,1)"/>
+ <circle cx="52" cy="61" r="1" fill="rgba(240,54,0,1)"/>
+ <circle cx="53" cy="61" r="1" fill="rgba(239,53,0,1)"/>
+ <circle cx="54" cy="61" r="1" fill="rgba(238,55,0,1)"/>
+ <circle cx="55" cy="61" r="1" fill="rgba(236,57,0,1)"/>
+ <circle cx="56" cy="61" r="1" fill="rgba(236,61,0,1)"/>
+ <circle cx="57" cy="61" r="1" fill="rgba(236,63,0,1)"/>
+ <circle cx="58" cy="61" r="1" fill="rgba(236,65,0,1)"/>
+ <circle cx="59" cy="61" r="1" fill="rgba(234,63,0,1)"/>
+ <circle cx="60" cy="61" r="1" fill="rgba(232,58,0,1)"/>
+ <circle cx="61" cy="61" r="1" fill="rgba(230,53,0,1)"/>
+ <circle cx="62" cy="61" r="1" fill="rgba(227,46,0,1)"/>
+ <circle cx="63" cy="61" r="1" fill="rgba(224,40,0,1)"/>
+ <circle cx="64" cy="61" r="1" fill="rgba(218,28,0,1)"/>
+ <circle cx="65" cy="61" r="1" fill="rgba(175,20,1,1)"/>
+ <circle cx="66" cy="61" r="1" fill="rgba(161,28,4,1)"/>
+ <circle cx="67" cy="61" r="1" fill="rgba(214,26,0,1)"/>
+ <circle cx="68" cy="61" r="1" fill="rgba(210,30,0,1)"/>
+ <circle cx="69" cy="61" r="1" fill="rgba(214,34,1,1)"/>
+ <circle cx="70" cy="61" r="1" fill="rgba(215,37,2,1)"/>
+ <circle cx="71" cy="61" r="1" fill="rgba(217,39,2,1)"/>
+ <circle cx="72" cy="61" r="1" fill="rgba(216,38,3,1)"/>
+ <circle cx="73" cy="61" r="1" fill="rgba(214,35,3,1)"/>
+ <circle cx="74" cy="61" r="1" fill="rgba(211,31,3,1)"/>
+ <circle cx="75" cy="61" r="1" fill="rgba(208,28,3,1)"/>
+ <circle cx="76" cy="61" r="1" fill="rgba(206,24,3,1)"/>
+ <circle cx="77" cy="61" r="1" fill="rgba(203,21,3,1)"/>
+ <circle cx="78" cy="61" r="1" fill="rgba(202,21,3,1)"/>
+ <circle cx="79" cy="61" r="1" fill="rgba(200,20,4,1)"/>
+ <circle cx="80" cy="61" r="1" fill="rgba(200,20,5,1)"/>
+ <circle cx="81" cy="61" r="1" fill="rgba(201,24,5,1)"/>
+ <circle cx="82" cy="61" r="1" fill="rgba(202,27,6,1)"/>
+ <circle cx="83" cy="61" r="1" fill="rgba(203,29,8,1)"/>
+ <circle cx="84" cy="61" r="1" fill="rgba(203,33,9,1)"/>
+ <circle cx="85" cy="61" r="1" fill="rgba(204,36,10,1)"/>
+ <circle cx="86" cy="61" r="1" fill="rgba(207,40,12,1)"/>
+ <circle cx="87" cy="61" r="1" fill="rgba(207,43,13,1)"/>
+ <circle cx="88" cy="61" r="1" fill="rgba(208,47,14,1)"/>
+ <circle cx="89" cy="61" r="1" fill="rgba(210,52,17,1)"/>
+ <circle cx="90" cy="61" r="1" fill="rgba(212,57,20,1)"/>
+ <circle cx="91" cy="61" r="1" fill="rgba(214,61,22,1)"/>
+ <circle cx="92" cy="61" r="1" fill="rgba(216,66,24,1)"/>
+ <circle cx="93" cy="61" r="1" fill="rgba(217,71,27,1)"/>
+ <circle cx="94" cy="61" r="1" fill="rgba(220,77,30,1)"/>
+ <circle cx="95" cy="61" r="1" fill="rgba(221,82,33,1)"/>
+ <circle cx="96" cy="61" r="1" fill="rgba(224,89,36,1)"/>
+ <circle cx="97" cy="61" r="1" fill="rgba(226,95,40,1)"/>
+ <circle cx="98" cy="61" r="1" fill="rgba(227,101,44,1)"/>
+ <circle cx="99" cy="61" r="1" fill="rgba(230,106,48,1)"/>
+ <circle cx="100" cy="61" r="1" fill="rgba(231,112,50,1)"/>
+ <circle cx="101" cy="61" r="1" fill="rgba(233,113,51,1)"/>
+ <circle cx="102" cy="61" r="1" fill="rgba(242,116,51,1)"/>
+ <circle cx="103" cy="61" r="1" fill="rgba(147,64,24,1)"/>
+ <circle cx="104" cy="61" r="1" fill="rgba(45,26,13,1)"/>
+ <circle cx="105" cy="61" r="1" fill="rgba(67,36,17,0.894118)"/>
+ <circle cx="106" cy="61" r="1" fill="rgba(74,39,19,0.14902)"/>
+ <circle cx="107" cy="61" r="1" fill="rgba(80,46,23,0)"/>
+ <circle cx="108" cy="61" r="1" fill="rgba(84,51,27,0)"/>
+ <circle cx="109" cy="61" r="1" fill="rgba(91,56,31,0)"/>
+ <circle cx="110" cy="61" r="1" fill="rgba(96,61,35,0)"/>
+ <circle cx="111" cy="61" r="1" fill="rgba(99,66,39,0)"/>
+ <circle cx="112" cy="61" r="1" fill="rgba(103,69,42,0)"/>
+ <circle cx="113" cy="61" r="1" fill="rgba(105,75,48,0)"/>
+ <circle cx="114" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="61" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="62" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="62" r="1" fill="rgba(103,71,44,0.0666667)"/>
+ <circle cx="19" cy="62" r="1" fill="rgba(100,68,41,0.443137)"/>
+ <circle cx="20" cy="62" r="1" fill="rgba(96,64,37,0.905882)"/>
+ <circle cx="21" cy="62" r="1" fill="rgba(92,59,34,1)"/>
+ <circle cx="22" cy="62" r="1" fill="rgba(87,55,31,1)"/>
+ <circle cx="23" cy="62" r="1" fill="rgba(73,49,30,0.815686)"/>
+ <circle cx="24" cy="62" r="1" fill="rgba(140,58,15,0.129412)"/>
+ <circle cx="25" cy="62" r="1" fill="rgba(255,92,0,0)"/>
+ <circle cx="26" cy="62" r="1" fill="rgba(254,79,0,0.345098)"/>
+ <circle cx="27" cy="62" r="1" fill="rgba(241,68,0,1)"/>
+ <circle cx="28" cy="62" r="1" fill="rgba(247,81,1,1)"/>
+ <circle cx="29" cy="62" r="1" fill="rgba(249,88,1,1)"/>
+ <circle cx="30" cy="62" r="1" fill="rgba(250,92,2,1)"/>
+ <circle cx="31" cy="62" r="1" fill="rgba(251,92,1,1)"/>
+ <circle cx="32" cy="62" r="1" fill="rgba(251,91,0,1)"/>
+ <circle cx="33" cy="62" r="1" fill="rgba(251,89,0,1)"/>
+ <circle cx="34" cy="62" r="1" fill="rgba(251,87,0,1)"/>
+ <circle cx="35" cy="62" r="1" fill="rgba(251,84,0,1)"/>
+ <circle cx="36" cy="62" r="1" fill="rgba(250,81,0,1)"/>
+ <circle cx="37" cy="62" r="1" fill="rgba(250,81,0,1)"/>
+ <circle cx="38" cy="62" r="1" fill="rgba(251,80,0,1)"/>
+ <circle cx="39" cy="62" r="1" fill="rgba(250,79,0,1)"/>
+ <circle cx="40" cy="62" r="1" fill="rgba(250,78,0,1)"/>
+ <circle cx="41" cy="62" r="1" fill="rgba(250,77,0,1)"/>
+ <circle cx="42" cy="62" r="1" fill="rgba(249,76,0,1)"/>
+ <circle cx="43" cy="62" r="1" fill="rgba(249,74,0,1)"/>
+ <circle cx="44" cy="62" r="1" fill="rgba(248,72,0,1)"/>
+ <circle cx="45" cy="62" r="1" fill="rgba(247,70,0,1)"/>
+ <circle cx="46" cy="62" r="1" fill="rgba(247,67,0,1)"/>
+ <circle cx="47" cy="62" r="1" fill="rgba(246,65,0,1)"/>
+ <circle cx="48" cy="62" r="1" fill="rgba(244,62,0,1)"/>
+ <circle cx="49" cy="62" r="1" fill="rgba(243,59,0,1)"/>
+ <circle cx="50" cy="62" r="1" fill="rgba(241,55,0,1)"/>
+ <circle cx="51" cy="62" r="1" fill="rgba(240,53,0,1)"/>
+ <circle cx="52" cy="62" r="1" fill="rgba(238,51,0,1)"/>
+ <circle cx="53" cy="62" r="1" fill="rgba(238,52,0,1)"/>
+ <circle cx="54" cy="62" r="1" fill="rgba(237,53,0,1)"/>
+ <circle cx="55" cy="62" r="1" fill="rgba(235,56,0,1)"/>
+ <circle cx="56" cy="62" r="1" fill="rgba(235,59,0,1)"/>
+ <circle cx="57" cy="62" r="1" fill="rgba(234,61,0,1)"/>
+ <circle cx="58" cy="62" r="1" fill="rgba(233,63,0,1)"/>
+ <circle cx="59" cy="62" r="1" fill="rgba(233,61,0,1)"/>
+ <circle cx="60" cy="62" r="1" fill="rgba(231,56,0,1)"/>
+ <circle cx="61" cy="62" r="1" fill="rgba(229,51,0,1)"/>
+ <circle cx="62" cy="62" r="1" fill="rgba(225,45,0,1)"/>
+ <circle cx="63" cy="62" r="1" fill="rgba(223,38,0,1)"/>
+ <circle cx="64" cy="62" r="1" fill="rgba(217,27,0,1)"/>
+ <circle cx="65" cy="62" r="1" fill="rgba(174,19,1,1)"/>
+ <circle cx="66" cy="62" r="1" fill="rgba(162,29,4,1)"/>
+ <circle cx="67" cy="62" r="1" fill="rgba(214,26,0,1)"/>
+ <circle cx="68" cy="62" r="1" fill="rgba(210,29,0,1)"/>
+ <circle cx="69" cy="62" r="1" fill="rgba(213,33,1,1)"/>
+ <circle cx="70" cy="62" r="1" fill="rgba(214,37,2,1)"/>
+ <circle cx="71" cy="62" r="1" fill="rgba(215,39,2,1)"/>
+ <circle cx="72" cy="62" r="1" fill="rgba(215,38,3,1)"/>
+ <circle cx="73" cy="62" r="1" fill="rgba(213,34,3,1)"/>
+ <circle cx="74" cy="62" r="1" fill="rgba(210,30,3,1)"/>
+ <circle cx="75" cy="62" r="1" fill="rgba(207,27,3,1)"/>
+ <circle cx="76" cy="62" r="1" fill="rgba(205,23,3,1)"/>
+ <circle cx="77" cy="62" r="1" fill="rgba(202,20,3,1)"/>
+ <circle cx="78" cy="62" r="1" fill="rgba(200,20,3,1)"/>
+ <circle cx="79" cy="62" r="1" fill="rgba(200,19,4,1)"/>
+ <circle cx="80" cy="62" r="1" fill="rgba(200,21,5,1)"/>
+ <circle cx="81" cy="62" r="1" fill="rgba(201,24,6,1)"/>
+ <circle cx="82" cy="62" r="1" fill="rgba(202,27,6,1)"/>
+ <circle cx="83" cy="62" r="1" fill="rgba(203,29,8,1)"/>
+ <circle cx="84" cy="62" r="1" fill="rgba(204,33,9,1)"/>
+ <circle cx="85" cy="62" r="1" fill="rgba(205,37,10,1)"/>
+ <circle cx="86" cy="62" r="1" fill="rgba(206,40,12,1)"/>
+ <circle cx="87" cy="62" r="1" fill="rgba(208,44,13,1)"/>
+ <circle cx="88" cy="62" r="1" fill="rgba(209,48,15,1)"/>
+ <circle cx="89" cy="62" r="1" fill="rgba(210,52,18,1)"/>
+ <circle cx="90" cy="62" r="1" fill="rgba(212,57,20,1)"/>
+ <circle cx="91" cy="62" r="1" fill="rgba(214,62,22,1)"/>
+ <circle cx="92" cy="62" r="1" fill="rgba(216,67,24,1)"/>
+ <circle cx="93" cy="62" r="1" fill="rgba(217,72,27,1)"/>
+ <circle cx="94" cy="62" r="1" fill="rgba(220,78,30,1)"/>
+ <circle cx="95" cy="62" r="1" fill="rgba(222,84,33,1)"/>
+ <circle cx="96" cy="62" r="1" fill="rgba(224,89,37,1)"/>
+ <circle cx="97" cy="62" r="1" fill="rgba(226,96,41,1)"/>
+ <circle cx="98" cy="62" r="1" fill="rgba(228,102,44,1)"/>
+ <circle cx="99" cy="62" r="1" fill="rgba(230,107,48,1)"/>
+ <circle cx="100" cy="62" r="1" fill="rgba(232,112,50,1)"/>
+ <circle cx="101" cy="62" r="1" fill="rgba(233,114,52,1)"/>
+ <circle cx="102" cy="62" r="1" fill="rgba(244,117,52,1)"/>
+ <circle cx="103" cy="62" r="1" fill="rgba(162,71,28,0.988235)"/>
+ <circle cx="104" cy="62" r="1" fill="rgba(49,28,13,1)"/>
+ <circle cx="105" cy="62" r="1" fill="rgba(69,38,19,1)"/>
+ <circle cx="106" cy="62" r="1" fill="rgba(73,41,21,0.819608)"/>
+ <circle cx="107" cy="62" r="1" fill="rgba(77,46,24,0.0941176)"/>
+ <circle cx="108" cy="62" r="1" fill="rgba(84,52,29,0)"/>
+ <circle cx="109" cy="62" r="1" fill="rgba(91,58,33,0)"/>
+ <circle cx="110" cy="62" r="1" fill="rgba(96,63,38,0)"/>
+ <circle cx="111" cy="62" r="1" fill="rgba(100,69,42,0)"/>
+ <circle cx="112" cy="62" r="1" fill="rgba(104,72,46,0)"/>
+ <circle cx="113" cy="62" r="1" fill="rgba(106,74,47,0)"/>
+ <circle cx="114" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="62" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="63" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="63" r="1" fill="rgba(104,72,45,0.113725)"/>
+ <circle cx="16" cy="63" r="1" fill="rgba(106,75,47,0.592157)"/>
+ <circle cx="17" cy="63" r="1" fill="rgba(105,73,46,0.721569)"/>
+ <circle cx="18" cy="63" r="1" fill="rgba(102,70,43,0.87451)"/>
+ <circle cx="19" cy="63" r="1" fill="rgba(99,67,40,1)"/>
+ <circle cx="20" cy="63" r="1" fill="rgba(95,62,37,1)"/>
+ <circle cx="21" cy="63" r="1" fill="rgba(92,59,33,1)"/>
+ <circle cx="22" cy="63" r="1" fill="rgba(88,56,31,0.756863)"/>
+ <circle cx="23" cy="63" r="1" fill="rgba(59,38,20,0.109804)"/>
+ <circle cx="24" cy="63" r="1" fill="rgba(110,33,3,0)"/>
+ <circle cx="25" cy="63" r="1" fill="rgba(173,56,1,0)"/>
+ <circle cx="26" cy="63" r="1" fill="rgba(212,60,0,0.435294)"/>
+ <circle cx="27" cy="63" r="1" fill="rgba(246,76,3,1)"/>
+ <circle cx="28" cy="63" r="1" fill="rgba(249,122,46,1)"/>
+ <circle cx="29" cy="63" r="1" fill="rgba(249,102,13,1)"/>
+ <circle cx="30" cy="63" r="1" fill="rgba(251,93,3,1)"/>
+ <circle cx="31" cy="63" r="1" fill="rgba(251,92,3,1)"/>
+ <circle cx="32" cy="63" r="1" fill="rgba(251,87,0,1)"/>
+ <circle cx="33" cy="63" r="1" fill="rgba(251,85,0,1)"/>
+ <circle cx="34" cy="63" r="1" fill="rgba(250,84,0,1)"/>
+ <circle cx="35" cy="63" r="1" fill="rgba(250,81,0,1)"/>
+ <circle cx="36" cy="63" r="1" fill="rgba(249,78,0,1)"/>
+ <circle cx="37" cy="63" r="1" fill="rgba(249,76,0,1)"/>
+ <circle cx="38" cy="63" r="1" fill="rgba(249,76,0,1)"/>
+ <circle cx="39" cy="63" r="1" fill="rgba(249,75,0,1)"/>
+ <circle cx="40" cy="63" r="1" fill="rgba(249,74,0,1)"/>
+ <circle cx="41" cy="63" r="1" fill="rgba(249,73,0,1)"/>
+ <circle cx="42" cy="63" r="1" fill="rgba(248,70,0,1)"/>
+ <circle cx="43" cy="63" r="1" fill="rgba(247,70,0,1)"/>
+ <circle cx="44" cy="63" r="1" fill="rgba(246,68,0,1)"/>
+ <circle cx="45" cy="63" r="1" fill="rgba(246,66,0,1)"/>
+ <circle cx="46" cy="63" r="1" fill="rgba(246,63,0,1)"/>
+ <circle cx="47" cy="63" r="1" fill="rgba(244,61,0,1)"/>
+ <circle cx="48" cy="63" r="1" fill="rgba(242,58,0,1)"/>
+ <circle cx="49" cy="63" r="1" fill="rgba(241,55,0,1)"/>
+ <circle cx="50" cy="63" r="1" fill="rgba(239,52,0,1)"/>
+ <circle cx="51" cy="63" r="1" fill="rgba(238,52,0,1)"/>
+ <circle cx="52" cy="63" r="1" fill="rgba(237,50,0,1)"/>
+ <circle cx="53" cy="63" r="1" fill="rgba(236,51,0,1)"/>
+ <circle cx="54" cy="63" r="1" fill="rgba(235,52,0,1)"/>
+ <circle cx="55" cy="63" r="1" fill="rgba(234,54,0,1)"/>
+ <circle cx="56" cy="63" r="1" fill="rgba(234,57,0,1)"/>
+ <circle cx="57" cy="63" r="1" fill="rgba(233,59,0,1)"/>
+ <circle cx="58" cy="63" r="1" fill="rgba(233,61,0,1)"/>
+ <circle cx="59" cy="63" r="1" fill="rgba(232,58,0,1)"/>
+ <circle cx="60" cy="63" r="1" fill="rgba(230,54,0,1)"/>
+ <circle cx="61" cy="63" r="1" fill="rgba(227,48,0,1)"/>
+ <circle cx="62" cy="63" r="1" fill="rgba(224,43,0,1)"/>
+ <circle cx="63" cy="63" r="1" fill="rgba(222,36,0,1)"/>
+ <circle cx="64" cy="63" r="1" fill="rgba(216,26,0,1)"/>
+ <circle cx="65" cy="63" r="1" fill="rgba(174,20,2,1)"/>
+ <circle cx="66" cy="63" r="1" fill="rgba(162,29,5,1)"/>
+ <circle cx="67" cy="63" r="1" fill="rgba(212,25,0,1)"/>
+ <circle cx="68" cy="63" r="1" fill="rgba(209,29,0,1)"/>
+ <circle cx="69" cy="63" r="1" fill="rgba(212,33,1,1)"/>
+ <circle cx="70" cy="63" r="1" fill="rgba(214,37,2,1)"/>
+ <circle cx="71" cy="63" r="1" fill="rgba(215,38,3,1)"/>
+ <circle cx="72" cy="63" r="1" fill="rgba(214,37,3,1)"/>
+ <circle cx="73" cy="63" r="1" fill="rgba(212,33,3,1)"/>
+ <circle cx="74" cy="63" r="1" fill="rgba(209,29,3,1)"/>
+ <circle cx="75" cy="63" r="1" fill="rgba(206,25,3,1)"/>
+ <circle cx="76" cy="63" r="1" fill="rgba(203,22,3,1)"/>
+ <circle cx="77" cy="63" r="1" fill="rgba(201,20,3,1)"/>
+ <circle cx="78" cy="63" r="1" fill="rgba(200,19,3,1)"/>
+ <circle cx="79" cy="63" r="1" fill="rgba(200,19,4,1)"/>
+ <circle cx="80" cy="63" r="1" fill="rgba(200,22,5,1)"/>
+ <circle cx="81" cy="63" r="1" fill="rgba(201,25,6,1)"/>
+ <circle cx="82" cy="63" r="1" fill="rgba(202,27,7,1)"/>
+ <circle cx="83" cy="63" r="1" fill="rgba(203,30,8,1)"/>
+ <circle cx="84" cy="63" r="1" fill="rgba(204,33,9,1)"/>
+ <circle cx="85" cy="63" r="1" fill="rgba(205,37,11,1)"/>
+ <circle cx="86" cy="63" r="1" fill="rgba(206,40,12,1)"/>
+ <circle cx="87" cy="63" r="1" fill="rgba(208,44,14,1)"/>
+ <circle cx="88" cy="63" r="1" fill="rgba(210,48,15,1)"/>
+ <circle cx="89" cy="63" r="1" fill="rgba(211,53,18,1)"/>
+ <circle cx="90" cy="63" r="1" fill="rgba(212,58,20,1)"/>
+ <circle cx="91" cy="63" r="1" fill="rgba(214,62,22,1)"/>
+ <circle cx="92" cy="63" r="1" fill="rgba(217,67,24,1)"/>
+ <circle cx="93" cy="63" r="1" fill="rgba(218,72,27,1)"/>
+ <circle cx="94" cy="63" r="1" fill="rgba(220,79,30,1)"/>
+ <circle cx="95" cy="63" r="1" fill="rgba(222,84,33,1)"/>
+ <circle cx="96" cy="63" r="1" fill="rgba(224,90,37,1)"/>
+ <circle cx="97" cy="63" r="1" fill="rgba(227,96,41,1)"/>
+ <circle cx="98" cy="63" r="1" fill="rgba(229,103,46,1)"/>
+ <circle cx="99" cy="63" r="1" fill="rgba(231,109,49,1)"/>
+ <circle cx="100" cy="63" r="1" fill="rgba(232,113,52,1)"/>
+ <circle cx="101" cy="63" r="1" fill="rgba(233,115,52,1)"/>
+ <circle cx="102" cy="63" r="1" fill="rgba(242,118,53,1)"/>
+ <circle cx="103" cy="63" r="1" fill="rgba(176,74,27,0.807843)"/>
+ <circle cx="104" cy="63" r="1" fill="rgba(47,23,9,0.8)"/>
+ <circle cx="105" cy="63" r="1" fill="rgba(71,41,20,1)"/>
+ <circle cx="106" cy="63" r="1" fill="rgba(75,43,22,1)"/>
+ <circle cx="107" cy="63" r="1" fill="rgba(80,47,24,0.745098)"/>
+ <circle cx="108" cy="63" r="1" fill="rgba(84,52,28,0.0627451)"/>
+ <circle cx="109" cy="63" r="1" fill="rgba(90,58,33,0)"/>
+ <circle cx="110" cy="63" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="111" cy="63" r="1" fill="rgba(100,68,42,0)"/>
+ <circle cx="112" cy="63" r="1" fill="rgba(104,71,45,0)"/>
+ <circle cx="113" cy="63" r="1" fill="rgba(106,74,47,0)"/>
+ <circle cx="114" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="63" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="64" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="64" r="1" fill="rgba(85,53,29,0.027451)"/>
+ <circle cx="11" cy="64" r="1" fill="rgba(90,57,33,0.152941)"/>
+ <circle cx="12" cy="64" r="1" fill="rgba(94,61,36,0.32549)"/>
+ <circle cx="13" cy="64" r="1" fill="rgba(97,65,38,0.384314)"/>
+ <circle cx="14" cy="64" r="1" fill="rgba(99,67,41,0.34902)"/>
+ <circle cx="15" cy="64" r="1" fill="rgba(102,70,42,0.815686)"/>
+ <circle cx="16" cy="64" r="1" fill="rgba(102,71,43,1)"/>
+ <circle cx="17" cy="64" r="1" fill="rgba(101,69,42,1)"/>
+ <circle cx="18" cy="64" r="1" fill="rgba(99,67,41,1)"/>
+ <circle cx="19" cy="64" r="1" fill="rgba(97,64,38,1)"/>
+ <circle cx="20" cy="64" r="1" fill="rgba(95,63,37,1)"/>
+ <circle cx="21" cy="64" r="1" fill="rgba(90,57,32,0.662745)"/>
+ <circle cx="22" cy="64" r="1" fill="rgba(59,31,14,0.0509804)"/>
+ <circle cx="23" cy="64" r="1" fill="rgba(37,16,5,0.0117647)"/>
+ <circle cx="24" cy="64" r="1" fill="rgba(12,10,3,0.121569)"/>
+ <circle cx="25" cy="64" r="1" fill="rgba(0,5,3,0.196078)"/>
+ <circle cx="26" cy="64" r="1" fill="rgba(150,34,0,0.615686)"/>
+ <circle cx="27" cy="64" r="1" fill="rgba(251,88,13,1)"/>
+ <circle cx="28" cy="64" r="1" fill="rgba(250,145,79,1)"/>
+ <circle cx="29" cy="64" r="1" fill="rgba(250,120,34,1)"/>
+ <circle cx="30" cy="64" r="1" fill="rgba(249,96,8,1)"/>
+ <circle cx="31" cy="64" r="1" fill="rgba(250,92,5,1)"/>
+ <circle cx="32" cy="64" r="1" fill="rgba(249,85,1,1)"/>
+ <circle cx="33" cy="64" r="1" fill="rgba(249,81,0,1)"/>
+ <circle cx="34" cy="64" r="1" fill="rgba(249,79,0,1)"/>
+ <circle cx="35" cy="64" r="1" fill="rgba(249,78,0,1)"/>
+ <circle cx="36" cy="64" r="1" fill="rgba(248,75,0,1)"/>
+ <circle cx="37" cy="64" r="1" fill="rgba(247,72,0,1)"/>
+ <circle cx="38" cy="64" r="1" fill="rgba(247,71,0,1)"/>
+ <circle cx="39" cy="64" r="1" fill="rgba(247,71,0,1)"/>
+ <circle cx="40" cy="64" r="1" fill="rgba(247,70,0,1)"/>
+ <circle cx="41" cy="64" r="1" fill="rgba(247,68,0,1)"/>
+ <circle cx="42" cy="64" r="1" fill="rgba(246,67,0,1)"/>
+ <circle cx="43" cy="64" r="1" fill="rgba(245,65,0,1)"/>
+ <circle cx="44" cy="64" r="1" fill="rgba(244,64,0,1)"/>
+ <circle cx="45" cy="64" r="1" fill="rgba(244,62,0,1)"/>
+ <circle cx="46" cy="64" r="1" fill="rgba(243,59,0,1)"/>
+ <circle cx="47" cy="64" r="1" fill="rgba(242,57,0,1)"/>
+ <circle cx="48" cy="64" r="1" fill="rgba(240,54,0,1)"/>
+ <circle cx="49" cy="64" r="1" fill="rgba(239,51,0,1)"/>
+ <circle cx="50" cy="64" r="1" fill="rgba(238,50,0,1)"/>
+ <circle cx="51" cy="64" r="1" fill="rgba(237,49,0,1)"/>
+ <circle cx="52" cy="64" r="1" fill="rgba(236,48,0,1)"/>
+ <circle cx="53" cy="64" r="1" fill="rgba(235,49,0,1)"/>
+ <circle cx="54" cy="64" r="1" fill="rgba(233,50,0,1)"/>
+ <circle cx="55" cy="64" r="1" fill="rgba(233,51,0,1)"/>
+ <circle cx="56" cy="64" r="1" fill="rgba(233,55,0,1)"/>
+ <circle cx="57" cy="64" r="1" fill="rgba(233,57,0,1)"/>
+ <circle cx="58" cy="64" r="1" fill="rgba(231,57,0,1)"/>
+ <circle cx="59" cy="64" r="1" fill="rgba(230,55,0,1)"/>
+ <circle cx="60" cy="64" r="1" fill="rgba(228,51,0,1)"/>
+ <circle cx="61" cy="64" r="1" fill="rgba(226,46,0,1)"/>
+ <circle cx="62" cy="64" r="1" fill="rgba(224,41,0,1)"/>
+ <circle cx="63" cy="64" r="1" fill="rgba(221,35,0,1)"/>
+ <circle cx="64" cy="64" r="1" fill="rgba(215,25,0,1)"/>
+ <circle cx="65" cy="64" r="1" fill="rgba(174,21,2,1)"/>
+ <circle cx="66" cy="64" r="1" fill="rgba(161,29,5,1)"/>
+ <circle cx="67" cy="64" r="1" fill="rgba(210,24,0,1)"/>
+ <circle cx="68" cy="64" r="1" fill="rgba(208,29,0,1)"/>
+ <circle cx="69" cy="64" r="1" fill="rgba(211,33,1,1)"/>
+ <circle cx="70" cy="64" r="1" fill="rgba(214,36,2,1)"/>
+ <circle cx="71" cy="64" r="1" fill="rgba(214,38,2,1)"/>
+ <circle cx="72" cy="64" r="1" fill="rgba(214,36,3,1)"/>
+ <circle cx="73" cy="64" r="1" fill="rgba(210,31,3,1)"/>
+ <circle cx="74" cy="64" r="1" fill="rgba(208,27,3,1)"/>
+ <circle cx="75" cy="64" r="1" fill="rgba(205,23,3,1)"/>
+ <circle cx="76" cy="64" r="1" fill="rgba(203,20,3,1)"/>
+ <circle cx="77" cy="64" r="1" fill="rgba(201,20,3,1)"/>
+ <circle cx="78" cy="64" r="1" fill="rgba(200,18,4,1)"/>
+ <circle cx="79" cy="64" r="1" fill="rgba(200,19,4,1)"/>
+ <circle cx="80" cy="64" r="1" fill="rgba(200,22,5,1)"/>
+ <circle cx="81" cy="64" r="1" fill="rgba(201,25,6,1)"/>
+ <circle cx="82" cy="64" r="1" fill="rgba(203,27,7,1)"/>
+ <circle cx="83" cy="64" r="1" fill="rgba(203,31,8,1)"/>
+ <circle cx="84" cy="64" r="1" fill="rgba(204,34,10,1)"/>
+ <circle cx="85" cy="64" r="1" fill="rgba(205,37,11,1)"/>
+ <circle cx="86" cy="64" r="1" fill="rgba(207,41,12,1)"/>
+ <circle cx="87" cy="64" r="1" fill="rgba(207,44,14,1)"/>
+ <circle cx="88" cy="64" r="1" fill="rgba(210,49,16,1)"/>
+ <circle cx="89" cy="64" r="1" fill="rgba(211,54,18,1)"/>
+ <circle cx="90" cy="64" r="1" fill="rgba(213,58,20,1)"/>
+ <circle cx="91" cy="64" r="1" fill="rgba(214,63,22,1)"/>
+ <circle cx="92" cy="64" r="1" fill="rgba(217,68,25,1)"/>
+ <circle cx="93" cy="64" r="1" fill="rgba(219,73,28,1)"/>
+ <circle cx="94" cy="64" r="1" fill="rgba(221,80,31,1)"/>
+ <circle cx="95" cy="64" r="1" fill="rgba(222,85,34,1)"/>
+ <circle cx="96" cy="64" r="1" fill="rgba(225,91,37,1)"/>
+ <circle cx="97" cy="64" r="1" fill="rgba(227,97,42,1)"/>
+ <circle cx="98" cy="64" r="1" fill="rgba(229,104,46,1)"/>
+ <circle cx="99" cy="64" r="1" fill="rgba(231,110,49,1)"/>
+ <circle cx="100" cy="64" r="1" fill="rgba(233,114,52,1)"/>
+ <circle cx="101" cy="64" r="1" fill="rgba(234,116,53,1)"/>
+ <circle cx="102" cy="64" r="1" fill="rgba(242,120,54,1)"/>
+ <circle cx="103" cy="64" r="1" fill="rgba(178,73,26,0.803922)"/>
+ <circle cx="104" cy="64" r="1" fill="rgba(17,3,0,0.458824)"/>
+ <circle cx="105" cy="64" r="1" fill="rgba(65,35,16,0.843137)"/>
+ <circle cx="106" cy="64" r="1" fill="rgba(78,47,24,1)"/>
+ <circle cx="107" cy="64" r="1" fill="rgba(82,49,26,1)"/>
+ <circle cx="108" cy="64" r="1" fill="rgba(86,53,29,0.733333)"/>
+ <circle cx="109" cy="64" r="1" fill="rgba(90,58,33,0.054902)"/>
+ <circle cx="110" cy="64" r="1" fill="rgba(96,63,37,0)"/>
+ <circle cx="111" cy="64" r="1" fill="rgba(100,68,42,0)"/>
+ <circle cx="112" cy="64" r="1" fill="rgba(104,71,45,0)"/>
+ <circle cx="113" cy="64" r="1" fill="rgba(106,74,47,0)"/>
+ <circle cx="114" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="64" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="65" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="65" r="1" fill="rgba(71,40,20,0.0745098)"/>
+ <circle cx="8" cy="65" r="1" fill="rgba(76,45,23,0.517647)"/>
+ <circle cx="9" cy="65" r="1" fill="rgba(81,49,26,0.615686)"/>
+ <circle cx="10" cy="65" r="1" fill="rgba(85,53,29,0.835294)"/>
+ <circle cx="11" cy="65" r="1" fill="rgba(88,56,32,0.972549)"/>
+ <circle cx="12" cy="65" r="1" fill="rgba(92,59,34,1)"/>
+ <circle cx="13" cy="65" r="1" fill="rgba(95,63,37,1)"/>
+ <circle cx="14" cy="65" r="1" fill="rgba(98,66,39,1)"/>
+ <circle cx="15" cy="65" r="1" fill="rgba(98,66,39,1)"/>
+ <circle cx="16" cy="65" r="1" fill="rgba(98,66,40,1)"/>
+ <circle cx="17" cy="65" r="1" fill="rgba(99,66,39,1)"/>
+ <circle cx="18" cy="65" r="1" fill="rgba(99,66,40,1)"/>
+ <circle cx="19" cy="65" r="1" fill="rgba(96,63,37,0.976471)"/>
+ <circle cx="20" cy="65" r="1" fill="rgba(78,47,24,0.564706)"/>
+ <circle cx="21" cy="65" r="1" fill="rgba(47,24,9,0.0980392)"/>
+ <circle cx="22" cy="65" r="1" fill="rgba(29,12,3,0.184314)"/>
+ <circle cx="23" cy="65" r="1" fill="rgba(21,7,1,0.321569)"/>
+ <circle cx="24" cy="65" r="1" fill="rgba(7,1,0,0.415686)"/>
+ <circle cx="25" cy="65" r="1" fill="rgba(0,0,0,0.443137)"/>
+ <circle cx="26" cy="65" r="1" fill="rgba(153,30,0,0.752941)"/>
+ <circle cx="27" cy="65" r="1" fill="rgba(252,96,21,1)"/>
+ <circle cx="28" cy="65" r="1" fill="rgba(250,142,70,1)"/>
+ <circle cx="29" cy="65" r="1" fill="rgba(251,126,40,1)"/>
+ <circle cx="30" cy="65" r="1" fill="rgba(249,101,14,1)"/>
+ <circle cx="31" cy="65" r="1" fill="rgba(249,93,8,1)"/>
+ <circle cx="32" cy="65" r="1" fill="rgba(249,81,1,1)"/>
+ <circle cx="33" cy="65" r="1" fill="rgba(248,76,0,1)"/>
+ <circle cx="34" cy="65" r="1" fill="rgba(248,75,0,1)"/>
+ <circle cx="35" cy="65" r="1" fill="rgba(247,72,0,1)"/>
+ <circle cx="36" cy="65" r="1" fill="rgba(247,71,0,1)"/>
+ <circle cx="37" cy="65" r="1" fill="rgba(246,68,0,1)"/>
+ <circle cx="38" cy="65" r="1" fill="rgba(245,66,0,1)"/>
+ <circle cx="39" cy="65" r="1" fill="rgba(245,66,0,1)"/>
+ <circle cx="40" cy="65" r="1" fill="rgba(245,66,0,1)"/>
+ <circle cx="41" cy="65" r="1" fill="rgba(244,64,0,1)"/>
+ <circle cx="42" cy="65" r="1" fill="rgba(244,62,0,1)"/>
+ <circle cx="43" cy="65" r="1" fill="rgba(243,61,0,1)"/>
+ <circle cx="44" cy="65" r="1" fill="rgba(241,60,0,1)"/>
+ <circle cx="45" cy="65" r="1" fill="rgba(241,58,0,1)"/>
+ <circle cx="46" cy="65" r="1" fill="rgba(241,55,0,1)"/>
+ <circle cx="47" cy="65" r="1" fill="rgba(240,53,0,1)"/>
+ <circle cx="48" cy="65" r="1" fill="rgba(238,51,0,1)"/>
+ <circle cx="49" cy="65" r="1" fill="rgba(237,50,0,1)"/>
+ <circle cx="50" cy="65" r="1" fill="rgba(237,49,0,1)"/>
+ <circle cx="51" cy="65" r="1" fill="rgba(236,48,0,1)"/>
+ <circle cx="52" cy="65" r="1" fill="rgba(234,47,0,1)"/>
+ <circle cx="53" cy="65" r="1" fill="rgba(233,47,0,1)"/>
+ <circle cx="54" cy="65" r="1" fill="rgba(233,47,0,1)"/>
+ <circle cx="55" cy="65" r="1" fill="rgba(233,49,0,1)"/>
+ <circle cx="56" cy="65" r="1" fill="rgba(231,52,0,1)"/>
+ <circle cx="57" cy="65" r="1" fill="rgba(230,53,0,1)"/>
+ <circle cx="58" cy="65" r="1" fill="rgba(230,53,0,1)"/>
+ <circle cx="59" cy="65" r="1" fill="rgba(228,51,0,1)"/>
+ <circle cx="60" cy="65" r="1" fill="rgba(226,47,0,1)"/>
+ <circle cx="61" cy="65" r="1" fill="rgba(224,43,0,1)"/>
+ <circle cx="62" cy="65" r="1" fill="rgba(222,38,0,1)"/>
+ <circle cx="63" cy="65" r="1" fill="rgba(219,33,0,1)"/>
+ <circle cx="64" cy="65" r="1" fill="rgba(214,25,0,1)"/>
+ <circle cx="65" cy="65" r="1" fill="rgba(174,21,2,1)"/>
+ <circle cx="66" cy="65" r="1" fill="rgba(162,29,5,1)"/>
+ <circle cx="67" cy="65" r="1" fill="rgba(210,24,0,1)"/>
+ <circle cx="68" cy="65" r="1" fill="rgba(207,28,0,1)"/>
+ <circle cx="69" cy="65" r="1" fill="rgba(210,32,1,1)"/>
+ <circle cx="70" cy="65" r="1" fill="rgba(213,35,2,1)"/>
+ <circle cx="71" cy="65" r="1" fill="rgba(214,37,2,1)"/>
+ <circle cx="72" cy="65" r="1" fill="rgba(213,34,3,1)"/>
+ <circle cx="73" cy="65" r="1" fill="rgba(210,30,3,1)"/>
+ <circle cx="74" cy="65" r="1" fill="rgba(207,26,3,1)"/>
+ <circle cx="75" cy="65" r="1" fill="rgba(205,22,3,1)"/>
+ <circle cx="76" cy="65" r="1" fill="rgba(203,20,3,1)"/>
+ <circle cx="77" cy="65" r="1" fill="rgba(200,19,3,1)"/>
+ <circle cx="78" cy="65" r="1" fill="rgba(199,18,4,1)"/>
+ <circle cx="79" cy="65" r="1" fill="rgba(200,20,4,1)"/>
+ <circle cx="80" cy="65" r="1" fill="rgba(200,23,5,1)"/>
+ <circle cx="81" cy="65" r="1" fill="rgba(202,25,6,1)"/>
+ <circle cx="82" cy="65" r="1" fill="rgba(203,29,7,1)"/>
+ <circle cx="83" cy="65" r="1" fill="rgba(204,31,8,1)"/>
+ <circle cx="84" cy="65" r="1" fill="rgba(205,35,10,1)"/>
+ <circle cx="85" cy="65" r="1" fill="rgba(205,38,11,1)"/>
+ <circle cx="86" cy="65" r="1" fill="rgba(207,42,13,1)"/>
+ <circle cx="87" cy="65" r="1" fill="rgba(208,46,14,1)"/>
+ <circle cx="88" cy="65" r="1" fill="rgba(210,50,16,1)"/>
+ <circle cx="89" cy="65" r="1" fill="rgba(211,54,18,1)"/>
+ <circle cx="90" cy="65" r="1" fill="rgba(213,59,20,1)"/>
+ <circle cx="91" cy="65" r="1" fill="rgba(215,64,23,1)"/>
+ <circle cx="92" cy="65" r="1" fill="rgba(217,69,26,1)"/>
+ <circle cx="93" cy="65" r="1" fill="rgba(219,75,28,1)"/>
+ <circle cx="94" cy="65" r="1" fill="rgba(221,80,32,1)"/>
+ <circle cx="95" cy="65" r="1" fill="rgba(223,86,35,1)"/>
+ <circle cx="96" cy="65" r="1" fill="rgba(225,92,39,1)"/>
+ <circle cx="97" cy="65" r="1" fill="rgba(227,99,42,1)"/>
+ <circle cx="98" cy="65" r="1" fill="rgba(230,105,47,1)"/>
+ <circle cx="99" cy="65" r="1" fill="rgba(232,111,50,1)"/>
+ <circle cx="100" cy="65" r="1" fill="rgba(234,115,53,1)"/>
+ <circle cx="101" cy="65" r="1" fill="rgba(235,117,54,1)"/>
+ <circle cx="102" cy="65" r="1" fill="rgba(241,120,53,1)"/>
+ <circle cx="103" cy="65" r="1" fill="rgba(193,83,31,0.870588)"/>
+ <circle cx="104" cy="65" r="1" fill="rgba(19,0,0,0.447059)"/>
+ <circle cx="105" cy="65" r="1" fill="rgba(40,12,3,0.443137)"/>
+ <circle cx="106" cy="65" r="1" fill="rgba(78,44,22,0.878431)"/>
+ <circle cx="107" cy="65" r="1" fill="rgba(84,52,28,1)"/>
+ <circle cx="108" cy="65" r="1" fill="rgba(87,54,30,1)"/>
+ <circle cx="109" cy="65" r="1" fill="rgba(91,59,33,0.654902)"/>
+ <circle cx="110" cy="65" r="1" fill="rgba(95,63,37,0.0352941)"/>
+ <circle cx="111" cy="65" r="1" fill="rgba(100,68,42,0)"/>
+ <circle cx="112" cy="65" r="1" fill="rgba(104,71,45,0)"/>
+ <circle cx="113" cy="65" r="1" fill="rgba(106,74,47,0)"/>
+ <circle cx="114" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="65" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="66" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="66" r="1" fill="rgba(61,30,13,0.0313725)"/>
+ <circle cx="5" cy="66" r="1" fill="rgba(62,30,13,0.168627)"/>
+ <circle cx="6" cy="66" r="1" fill="rgba(65,34,16,0.384314)"/>
+ <circle cx="7" cy="66" r="1" fill="rgba(70,39,19,0.776471)"/>
+ <circle cx="8" cy="66" r="1" fill="rgba(75,43,22,1)"/>
+ <circle cx="9" cy="66" r="1" fill="rgba(80,47,25,1)"/>
+ <circle cx="10" cy="66" r="1" fill="rgba(85,52,29,1)"/>
+ <circle cx="11" cy="66" r="1" fill="rgba(88,56,31,1)"/>
+ <circle cx="12" cy="66" r="1" fill="rgba(90,57,33,0.94902)"/>
+ <circle cx="13" cy="66" r="1" fill="rgba(90,57,32,0.890196)"/>
+ <circle cx="14" cy="66" r="1" fill="rgba(93,60,35,0.960784)"/>
+ <circle cx="15" cy="66" r="1" fill="rgba(97,64,38,0.996078)"/>
+ <circle cx="16" cy="66" r="1" fill="rgba(96,63,37,0.980392)"/>
+ <circle cx="17" cy="66" r="1" fill="rgba(92,59,33,0.866667)"/>
+ <circle cx="18" cy="66" r="1" fill="rgba(75,44,22,0.643137)"/>
+ <circle cx="19" cy="66" r="1" fill="rgba(53,27,11,0.427451)"/>
+ <circle cx="20" cy="66" r="1" fill="rgba(22,8,2,0.290196)"/>
+ <circle cx="21" cy="66" r="1" fill="rgba(7,1,0,0.396078)"/>
+ <circle cx="22" cy="66" r="1" fill="rgba(4,0,0,0.462745)"/>
+ <circle cx="23" cy="66" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="24" cy="66" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="25" cy="66" r="1" fill="rgba(0,0,0,0.368627)"/>
+ <circle cx="26" cy="66" r="1" fill="rgba(163,37,0,0.690196)"/>
+ <circle cx="27" cy="66" r="1" fill="rgba(250,97,27,1)"/>
+ <circle cx="28" cy="66" r="1" fill="rgba(249,139,67,1)"/>
+ <circle cx="29" cy="66" r="1" fill="rgba(250,126,42,1)"/>
+ <circle cx="30" cy="66" r="1" fill="rgba(249,102,17,1)"/>
+ <circle cx="31" cy="66" r="1" fill="rgba(248,91,9,1)"/>
+ <circle cx="32" cy="66" r="1" fill="rgba(247,79,3,1)"/>
+ <circle cx="33" cy="66" r="1" fill="rgba(246,72,0,1)"/>
+ <circle cx="34" cy="66" r="1" fill="rgba(246,71,0,1)"/>
+ <circle cx="35" cy="66" r="1" fill="rgba(245,67,0,1)"/>
+ <circle cx="36" cy="66" r="1" fill="rgba(244,67,0,1)"/>
+ <circle cx="37" cy="66" r="1" fill="rgba(244,64,0,1)"/>
+ <circle cx="38" cy="66" r="1" fill="rgba(243,62,0,1)"/>
+ <circle cx="39" cy="66" r="1" fill="rgba(243,62,0,1)"/>
+ <circle cx="40" cy="66" r="1" fill="rgba(242,61,0,1)"/>
+ <circle cx="41" cy="66" r="1" fill="rgba(242,59,0,1)"/>
+ <circle cx="42" cy="66" r="1" fill="rgba(241,58,0,1)"/>
+ <circle cx="43" cy="66" r="1" fill="rgba(241,57,0,1)"/>
+ <circle cx="44" cy="66" r="1" fill="rgba(239,55,0,1)"/>
+ <circle cx="45" cy="66" r="1" fill="rgba(239,54,0,1)"/>
+ <circle cx="46" cy="66" r="1" fill="rgba(239,51,0,1)"/>
+ <circle cx="47" cy="66" r="1" fill="rgba(238,50,0,1)"/>
+ <circle cx="48" cy="66" r="1" fill="rgba(237,49,0,1)"/>
+ <circle cx="49" cy="66" r="1" fill="rgba(236,48,0,1)"/>
+ <circle cx="50" cy="66" r="1" fill="rgba(235,46,0,1)"/>
+ <circle cx="51" cy="66" r="1" fill="rgba(234,46,0,1)"/>
+ <circle cx="52" cy="66" r="1" fill="rgba(233,45,0,1)"/>
+ <circle cx="53" cy="66" r="1" fill="rgba(232,45,0,1)"/>
+ <circle cx="54" cy="66" r="1" fill="rgba(231,45,0,1)"/>
+ <circle cx="55" cy="66" r="1" fill="rgba(230,47,0,1)"/>
+ <circle cx="56" cy="66" r="1" fill="rgba(230,48,0,1)"/>
+ <circle cx="57" cy="66" r="1" fill="rgba(229,49,0,1)"/>
+ <circle cx="58" cy="66" r="1" fill="rgba(227,48,0,1)"/>
+ <circle cx="59" cy="66" r="1" fill="rgba(226,46,0,1)"/>
+ <circle cx="60" cy="66" r="1" fill="rgba(224,43,0,1)"/>
+ <circle cx="61" cy="66" r="1" fill="rgba(223,40,0,1)"/>
+ <circle cx="62" cy="66" r="1" fill="rgba(221,35,0,1)"/>
+ <circle cx="63" cy="66" r="1" fill="rgba(217,30,0,1)"/>
+ <circle cx="64" cy="66" r="1" fill="rgba(213,23,0,1)"/>
+ <circle cx="65" cy="66" r="1" fill="rgba(174,20,2,1)"/>
+ <circle cx="66" cy="66" r="1" fill="rgba(161,30,6,1)"/>
+ <circle cx="67" cy="66" r="1" fill="rgba(210,23,0,1)"/>
+ <circle cx="68" cy="66" r="1" fill="rgba(207,27,0,1)"/>
+ <circle cx="69" cy="66" r="1" fill="rgba(210,32,1,1)"/>
+ <circle cx="70" cy="66" r="1" fill="rgba(213,34,2,1)"/>
+ <circle cx="71" cy="66" r="1" fill="rgba(214,35,3,1)"/>
+ <circle cx="72" cy="66" r="1" fill="rgba(212,32,3,1)"/>
+ <circle cx="73" cy="66" r="1" fill="rgba(210,29,3,1)"/>
+ <circle cx="74" cy="66" r="1" fill="rgba(207,25,3,1)"/>
+ <circle cx="75" cy="66" r="1" fill="rgba(203,22,3,1)"/>
+ <circle cx="76" cy="66" r="1" fill="rgba(201,19,3,1)"/>
+ <circle cx="77" cy="66" r="1" fill="rgba(200,18,3,1)"/>
+ <circle cx="78" cy="66" r="1" fill="rgba(199,18,4,1)"/>
+ <circle cx="79" cy="66" r="1" fill="rgba(200,21,5,1)"/>
+ <circle cx="80" cy="66" r="1" fill="rgba(201,23,6,1)"/>
+ <circle cx="81" cy="66" r="1" fill="rgba(202,26,6,1)"/>
+ <circle cx="82" cy="66" r="1" fill="rgba(203,29,8,1)"/>
+ <circle cx="83" cy="66" r="1" fill="rgba(204,32,9,1)"/>
+ <circle cx="84" cy="66" r="1" fill="rgba(205,35,10,1)"/>
+ <circle cx="85" cy="66" r="1" fill="rgba(206,39,11,1)"/>
+ <circle cx="86" cy="66" r="1" fill="rgba(207,43,13,1)"/>
+ <circle cx="87" cy="66" r="1" fill="rgba(208,46,15,1)"/>
+ <circle cx="88" cy="66" r="1" fill="rgba(210,50,16,1)"/>
+ <circle cx="89" cy="66" r="1" fill="rgba(211,55,18,1)"/>
+ <circle cx="90" cy="66" r="1" fill="rgba(213,60,21,1)"/>
+ <circle cx="91" cy="66" r="1" fill="rgba(215,65,24,1)"/>
+ <circle cx="92" cy="66" r="1" fill="rgba(217,70,26,1)"/>
+ <circle cx="93" cy="66" r="1" fill="rgba(219,76,30,1)"/>
+ <circle cx="94" cy="66" r="1" fill="rgba(222,81,32,1)"/>
+ <circle cx="95" cy="66" r="1" fill="rgba(224,87,36,1)"/>
+ <circle cx="96" cy="66" r="1" fill="rgba(225,94,40,1)"/>
+ <circle cx="97" cy="66" r="1" fill="rgba(227,100,43,1)"/>
+ <circle cx="98" cy="66" r="1" fill="rgba(230,106,48,1)"/>
+ <circle cx="99" cy="66" r="1" fill="rgba(232,112,51,1)"/>
+ <circle cx="100" cy="66" r="1" fill="rgba(234,116,54,1)"/>
+ <circle cx="101" cy="66" r="1" fill="rgba(235,119,54,1)"/>
+ <circle cx="102" cy="66" r="1" fill="rgba(241,121,55,1)"/>
+ <circle cx="103" cy="66" r="1" fill="rgba(200,89,34,0.894118)"/>
+ <circle cx="104" cy="66" r="1" fill="rgba(28,3,0,0.529412)"/>
+ <circle cx="105" cy="66" r="1" fill="rgba(12,0,0,0.384314)"/>
+ <circle cx="106" cy="66" r="1" fill="rgba(42,16,5,0.435294)"/>
+ <circle cx="107" cy="66" r="1" fill="rgba(83,51,28,0.921569)"/>
+ <circle cx="108" cy="66" r="1" fill="rgba(90,56,32,1)"/>
+ <circle cx="109" cy="66" r="1" fill="rgba(93,60,35,1)"/>
+ <circle cx="110" cy="66" r="1" fill="rgba(97,64,37,0.72549)"/>
+ <circle cx="111" cy="66" r="1" fill="rgba(100,68,42,0.0666667)"/>
+ <circle cx="112" cy="66" r="1" fill="rgba(104,71,45,0)"/>
+ <circle cx="113" cy="66" r="1" fill="rgba(106,74,47,0)"/>
+ <circle cx="114" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="66" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="67" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="67" r="1" fill="rgba(57,27,11,0.192157)"/>
+ <circle cx="2" cy="67" r="1" fill="rgba(53,25,10,0.462745)"/>
+ <circle cx="3" cy="67" r="1" fill="rgba(63,31,14,0.658824)"/>
+ <circle cx="4" cy="67" r="1" fill="rgba(63,32,14,0.886275)"/>
+ <circle cx="5" cy="67" r="1" fill="rgba(63,31,14,1)"/>
+ <circle cx="6" cy="67" r="1" fill="rgba(64,34,16,1)"/>
+ <circle cx="7" cy="67" r="1" fill="rgba(69,38,18,1)"/>
+ <circle cx="8" cy="67" r="1" fill="rgba(74,41,21,1)"/>
+ <circle cx="9" cy="67" r="1" fill="rgba(67,37,17,0.870588)"/>
+ <circle cx="10" cy="67" r="1" fill="rgba(51,25,11,0.654902)"/>
+ <circle cx="11" cy="67" r="1" fill="rgba(55,29,12,0.482353)"/>
+ <circle cx="12" cy="67" r="1" fill="rgba(54,28,12,0.290196)"/>
+ <circle cx="13" cy="67" r="1" fill="rgba(34,14,5,0.305882)"/>
+ <circle cx="14" cy="67" r="1" fill="rgba(39,17,6,0.466667)"/>
+ <circle cx="15" cy="67" r="1" fill="rgba(53,28,11,0.576471)"/>
+ <circle cx="16" cy="67" r="1" fill="rgba(49,23,9,0.517647)"/>
+ <circle cx="17" cy="67" r="1" fill="rgba(22,8,2,0.407843)"/>
+ <circle cx="18" cy="67" r="1" fill="rgba(7,1,0,0.376471)"/>
+ <circle cx="19" cy="67" r="1" fill="rgba(0,0,0,0.431373)"/>
+ <circle cx="20" cy="67" r="1" fill="rgba(0,0,0,0.47451)"/>
+ <circle cx="21" cy="67" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="22" cy="67" r="1" fill="rgba(10,1,0,0.439216)"/>
+ <circle cx="23" cy="67" r="1" fill="rgba(19,6,1,0.356863)"/>
+ <circle cx="24" cy="67" r="1" fill="rgba(7,5,1,0.247059)"/>
+ <circle cx="25" cy="67" r="1" fill="rgba(87,33,8,0.0823529)"/>
+ <circle cx="26" cy="67" r="1" fill="rgba(212,64,5,0.556863)"/>
+ <circle cx="27" cy="67" r="1" fill="rgba(244,92,26,1)"/>
+ <circle cx="28" cy="67" r="1" fill="rgba(247,134,68,1)"/>
+ <circle cx="29" cy="67" r="1" fill="rgba(248,120,42,1)"/>
+ <circle cx="30" cy="67" r="1" fill="rgba(247,96,16,1)"/>
+ <circle cx="31" cy="67" r="1" fill="rgba(247,86,8,1)"/>
+ <circle cx="32" cy="67" r="1" fill="rgba(245,77,3,1)"/>
+ <circle cx="33" cy="67" r="1" fill="rgba(245,68,0,1)"/>
+ <circle cx="34" cy="67" r="1" fill="rgba(244,67,0,1)"/>
+ <circle cx="35" cy="67" r="1" fill="rgba(242,63,0,1)"/>
+ <circle cx="36" cy="67" r="1" fill="rgba(242,62,0,1)"/>
+ <circle cx="37" cy="67" r="1" fill="rgba(241,60,0,1)"/>
+ <circle cx="38" cy="67" r="1" fill="rgba(241,58,0,1)"/>
+ <circle cx="39" cy="67" r="1" fill="rgba(240,57,0,1)"/>
+ <circle cx="40" cy="67" r="1" fill="rgba(240,56,0,1)"/>
+ <circle cx="41" cy="67" r="1" fill="rgba(240,55,0,1)"/>
+ <circle cx="42" cy="67" r="1" fill="rgba(239,53,0,1)"/>
+ <circle cx="43" cy="67" r="1" fill="rgba(238,52,0,1)"/>
+ <circle cx="44" cy="67" r="1" fill="rgba(238,51,0,1)"/>
+ <circle cx="45" cy="67" r="1" fill="rgba(237,50,0,1)"/>
+ <circle cx="46" cy="67" r="1" fill="rgba(237,49,0,1)"/>
+ <circle cx="47" cy="67" r="1" fill="rgba(236,48,0,1)"/>
+ <circle cx="48" cy="67" r="1" fill="rgba(236,48,0,1)"/>
+ <circle cx="49" cy="67" r="1" fill="rgba(234,47,0,1)"/>
+ <circle cx="50" cy="67" r="1" fill="rgba(233,45,0,1)"/>
+ <circle cx="51" cy="67" r="1" fill="rgba(233,43,0,1)"/>
+ <circle cx="52" cy="67" r="1" fill="rgba(230,43,0,1)"/>
+ <circle cx="53" cy="67" r="1" fill="rgba(230,42,0,1)"/>
+ <circle cx="54" cy="67" r="1" fill="rgba(230,43,0,1)"/>
+ <circle cx="55" cy="67" r="1" fill="rgba(229,44,0,1)"/>
+ <circle cx="56" cy="67" r="1" fill="rgba(227,44,0,1)"/>
+ <circle cx="57" cy="67" r="1" fill="rgba(227,45,0,1)"/>
+ <circle cx="58" cy="67" r="1" fill="rgba(225,43,0,1)"/>
+ <circle cx="59" cy="67" r="1" fill="rgba(224,41,0,1)"/>
+ <circle cx="60" cy="67" r="1" fill="rgba(223,39,0,1)"/>
+ <circle cx="61" cy="67" r="1" fill="rgba(221,36,0,1)"/>
+ <circle cx="62" cy="67" r="1" fill="rgba(219,32,0,1)"/>
+ <circle cx="63" cy="67" r="1" fill="rgba(216,29,0,1)"/>
+ <circle cx="64" cy="67" r="1" fill="rgba(212,22,0,1)"/>
+ <circle cx="65" cy="67" r="1" fill="rgba(174,21,2,1)"/>
+ <circle cx="66" cy="67" r="1" fill="rgba(159,29,6,1)"/>
+ <circle cx="67" cy="67" r="1" fill="rgba(208,22,0,1)"/>
+ <circle cx="68" cy="67" r="1" fill="rgba(205,26,0,1)"/>
+ <circle cx="69" cy="67" r="1" fill="rgba(209,31,1,1)"/>
+ <circle cx="70" cy="67" r="1" fill="rgba(212,33,3,1)"/>
+ <circle cx="71" cy="67" r="1" fill="rgba(212,34,3,1)"/>
+ <circle cx="72" cy="67" r="1" fill="rgba(211,31,3,1)"/>
+ <circle cx="73" cy="67" r="1" fill="rgba(209,27,3,1)"/>
+ <circle cx="74" cy="67" r="1" fill="rgba(205,24,3,1)"/>
+ <circle cx="75" cy="67" r="1" fill="rgba(203,21,3,1)"/>
+ <circle cx="76" cy="67" r="1" fill="rgba(200,18,3,1)"/>
+ <circle cx="77" cy="67" r="1" fill="rgba(199,17,4,1)"/>
+ <circle cx="78" cy="67" r="1" fill="rgba(199,18,4,1)"/>
+ <circle cx="79" cy="67" r="1" fill="rgba(200,21,5,1)"/>
+ <circle cx="80" cy="67" r="1" fill="rgba(201,24,6,1)"/>
+ <circle cx="81" cy="67" r="1" fill="rgba(202,27,6,1)"/>
+ <circle cx="82" cy="67" r="1" fill="rgba(203,29,8,1)"/>
+ <circle cx="83" cy="67" r="1" fill="rgba(204,33,9,1)"/>
+ <circle cx="84" cy="67" r="1" fill="rgba(206,35,10,1)"/>
+ <circle cx="85" cy="67" r="1" fill="rgba(207,39,11,1)"/>
+ <circle cx="86" cy="67" r="1" fill="rgba(207,44,14,1)"/>
+ <circle cx="87" cy="67" r="1" fill="rgba(208,47,16,1)"/>
+ <circle cx="88" cy="67" r="1" fill="rgba(210,51,17,1)"/>
+ <circle cx="89" cy="67" r="1" fill="rgba(213,57,20,1)"/>
+ <circle cx="90" cy="67" r="1" fill="rgba(213,61,22,1)"/>
+ <circle cx="91" cy="67" r="1" fill="rgba(215,66,24,1)"/>
+ <circle cx="92" cy="67" r="1" fill="rgba(217,71,27,1)"/>
+ <circle cx="93" cy="67" r="1" fill="rgba(220,77,30,1)"/>
+ <circle cx="94" cy="67" r="1" fill="rgba(222,83,33,1)"/>
+ <circle cx="95" cy="67" r="1" fill="rgba(224,89,37,1)"/>
+ <circle cx="96" cy="67" r="1" fill="rgba(226,95,41,1)"/>
+ <circle cx="97" cy="67" r="1" fill="rgba(228,101,44,1)"/>
+ <circle cx="98" cy="67" r="1" fill="rgba(231,108,48,1)"/>
+ <circle cx="99" cy="67" r="1" fill="rgba(233,113,52,1)"/>
+ <circle cx="100" cy="67" r="1" fill="rgba(234,118,55,1)"/>
+ <circle cx="101" cy="67" r="1" fill="rgba(236,119,55,1)"/>
+ <circle cx="102" cy="67" r="1" fill="rgba(243,123,56,1)"/>
+ <circle cx="103" cy="67" r="1" fill="rgba(196,87,33,0.890196)"/>
+ <circle cx="104" cy="67" r="1" fill="rgba(31,2,0,0.552941)"/>
+ <circle cx="105" cy="67" r="1" fill="rgba(10,0,0,0.45098)"/>
+ <circle cx="106" cy="67" r="1" fill="rgba(0,0,0,0.368627)"/>
+ <circle cx="107" cy="67" r="1" fill="rgba(45,21,8,0.478431)"/>
+ <circle cx="108" cy="67" r="1" fill="rgba(90,57,33,0.960784)"/>
+ <circle cx="109" cy="67" r="1" fill="rgba(94,61,36,1)"/>
+ <circle cx="110" cy="67" r="1" fill="rgba(97,64,38,1)"/>
+ <circle cx="111" cy="67" r="1" fill="rgba(100,68,42,0.788235)"/>
+ <circle cx="112" cy="67" r="1" fill="rgba(104,71,45,0.172549)"/>
+ <circle cx="113" cy="67" r="1" fill="rgba(106,74,47,0)"/>
+ <circle cx="114" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="67" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="68" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="68" r="1" fill="rgba(61,30,13,0.552941)"/>
+ <circle cx="2" cy="68" r="1" fill="rgba(58,28,13,0.764706)"/>
+ <circle cx="3" cy="68" r="1" fill="rgba(49,22,8,0.690196)"/>
+ <circle cx="4" cy="68" r="1" fill="rgba(39,16,5,0.647059)"/>
+ <circle cx="5" cy="68" r="1" fill="rgba(36,14,4,0.647059)"/>
+ <circle cx="6" cy="68" r="1" fill="rgba(34,13,4,0.678431)"/>
+ <circle cx="7" cy="68" r="1" fill="rgba(39,16,5,0.658824)"/>
+ <circle cx="8" cy="68" r="1" fill="rgba(39,16,6,0.603922)"/>
+ <circle cx="9" cy="68" r="1" fill="rgba(17,4,0,0.454902)"/>
+ <circle cx="10" cy="68" r="1" fill="rgba(0,0,0,0.4)"/>
+ <circle cx="11" cy="68" r="1" fill="rgba(0,0,0,0.427451)"/>
+ <circle cx="12" cy="68" r="1" fill="rgba(0,0,0,0.443137)"/>
+ <circle cx="13" cy="68" r="1" fill="rgba(0,0,0,0.462745)"/>
+ <circle cx="14" cy="68" r="1" fill="rgba(0,0,0,0.458824)"/>
+ <circle cx="15" cy="68" r="1" fill="rgba(0,0,0,0.447059)"/>
+ <circle cx="16" cy="68" r="1" fill="rgba(0,0,0,0.45098)"/>
+ <circle cx="17" cy="68" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="18" cy="68" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="19" cy="68" r="1" fill="rgba(4,0,0,0.462745)"/>
+ <circle cx="20" cy="68" r="1" fill="rgba(15,4,0,0.4)"/>
+ <circle cx="21" cy="68" r="1" fill="rgba(26,9,3,0.301961)"/>
+ <circle cx="22" cy="68" r="1" fill="rgba(34,15,5,0.184314)"/>
+ <circle cx="23" cy="68" r="1" fill="rgba(28,13,4,0.0745098)"/>
+ <circle cx="24" cy="68" r="1" fill="rgba(49,22,8,0.00784314)"/>
+ <circle cx="25" cy="68" r="1" fill="rgba(224,135,76,0)"/>
+ <circle cx="26" cy="68" r="1" fill="rgba(238,86,17,0.490196)"/>
+ <circle cx="27" cy="68" r="1" fill="rgba(237,84,22,1)"/>
+ <circle cx="28" cy="68" r="1" fill="rgba(244,123,57,1)"/>
+ <circle cx="29" cy="68" r="1" fill="rgba(244,109,37,1)"/>
+ <circle cx="30" cy="68" r="1" fill="rgba(244,87,14,1)"/>
+ <circle cx="31" cy="68" r="1" fill="rgba(244,78,6,1)"/>
+ <circle cx="32" cy="68" r="1" fill="rgba(244,72,2,1)"/>
+ <circle cx="33" cy="68" r="1" fill="rgba(243,64,0,1)"/>
+ <circle cx="34" cy="68" r="1" fill="rgba(241,61,0,1)"/>
+ <circle cx="35" cy="68" r="1" fill="rgba(240,59,0,1)"/>
+ <circle cx="36" cy="68" r="1" fill="rgba(239,57,0,1)"/>
+ <circle cx="37" cy="68" r="1" fill="rgba(239,56,0,1)"/>
+ <circle cx="38" cy="68" r="1" fill="rgba(238,54,0,1)"/>
+ <circle cx="39" cy="68" r="1" fill="rgba(238,52,0,1)"/>
+ <circle cx="40" cy="68" r="1" fill="rgba(238,51,0,1)"/>
+ <circle cx="41" cy="68" r="1" fill="rgba(237,50,0,1)"/>
+ <circle cx="42" cy="68" r="1" fill="rgba(237,49,0,1)"/>
+ <circle cx="43" cy="68" r="1" fill="rgba(236,49,0,1)"/>
+ <circle cx="44" cy="68" r="1" fill="rgba(236,48,0,1)"/>
+ <circle cx="45" cy="68" r="1" fill="rgba(236,48,0,1)"/>
+ <circle cx="46" cy="68" r="1" fill="rgba(235,48,0,1)"/>
+ <circle cx="47" cy="68" r="1" fill="rgba(234,47,0,1)"/>
+ <circle cx="48" cy="68" r="1" fill="rgba(233,46,0,1)"/>
+ <circle cx="49" cy="68" r="1" fill="rgba(232,45,0,1)"/>
+ <circle cx="50" cy="68" r="1" fill="rgba(232,43,0,1)"/>
+ <circle cx="51" cy="68" r="1" fill="rgba(230,41,0,1)"/>
+ <circle cx="52" cy="68" r="1" fill="rgba(230,41,0,1)"/>
+ <circle cx="53" cy="68" r="1" fill="rgba(228,41,0,1)"/>
+ <circle cx="54" cy="68" r="1" fill="rgba(227,41,0,1)"/>
+ <circle cx="55" cy="68" r="1" fill="rgba(227,40,0,1)"/>
+ <circle cx="56" cy="68" r="1" fill="rgba(226,40,0,1)"/>
+ <circle cx="57" cy="68" r="1" fill="rgba(224,40,0,1)"/>
+ <circle cx="58" cy="68" r="1" fill="rgba(224,39,0,1)"/>
+ <circle cx="59" cy="68" r="1" fill="rgba(222,37,0,1)"/>
+ <circle cx="60" cy="68" r="1" fill="rgba(221,35,0,1)"/>
+ <circle cx="61" cy="68" r="1" fill="rgba(220,32,0,1)"/>
+ <circle cx="62" cy="68" r="1" fill="rgba(217,30,0,1)"/>
+ <circle cx="63" cy="68" r="1" fill="rgba(214,27,0,1)"/>
+ <circle cx="64" cy="68" r="1" fill="rgba(210,21,0,1)"/>
+ <circle cx="65" cy="68" r="1" fill="rgba(173,20,2,1)"/>
+ <circle cx="66" cy="68" r="1" fill="rgba(159,29,5,1)"/>
+ <circle cx="67" cy="68" r="1" fill="rgba(207,21,0,1)"/>
+ <circle cx="68" cy="68" r="1" fill="rgba(204,25,0,1)"/>
+ <circle cx="69" cy="68" r="1" fill="rgba(208,30,2,1)"/>
+ <circle cx="70" cy="68" r="1" fill="rgba(210,32,3,1)"/>
+ <circle cx="71" cy="68" r="1" fill="rgba(211,33,3,1)"/>
+ <circle cx="72" cy="68" r="1" fill="rgba(210,30,3,1)"/>
+ <circle cx="73" cy="68" r="1" fill="rgba(207,26,4,1)"/>
+ <circle cx="74" cy="68" r="1" fill="rgba(204,23,3,1)"/>
+ <circle cx="75" cy="68" r="1" fill="rgba(202,19,3,1)"/>
+ <circle cx="76" cy="68" r="1" fill="rgba(200,18,3,1)"/>
+ <circle cx="77" cy="68" r="1" fill="rgba(199,18,4,1)"/>
+ <circle cx="78" cy="68" r="1" fill="rgba(200,19,4,1)"/>
+ <circle cx="79" cy="68" r="1" fill="rgba(200,22,5,1)"/>
+ <circle cx="80" cy="68" r="1" fill="rgba(201,25,6,1)"/>
+ <circle cx="81" cy="68" r="1" fill="rgba(203,27,7,1)"/>
+ <circle cx="82" cy="68" r="1" fill="rgba(203,31,8,1)"/>
+ <circle cx="83" cy="68" r="1" fill="rgba(204,33,10,1)"/>
+ <circle cx="84" cy="68" r="1" fill="rgba(206,36,10,1)"/>
+ <circle cx="85" cy="68" r="1" fill="rgba(207,41,12,1)"/>
+ <circle cx="86" cy="68" r="1" fill="rgba(207,45,14,1)"/>
+ <circle cx="87" cy="68" r="1" fill="rgba(209,48,16,1)"/>
+ <circle cx="88" cy="68" r="1" fill="rgba(211,52,18,1)"/>
+ <circle cx="89" cy="68" r="1" fill="rgba(213,57,20,1)"/>
+ <circle cx="90" cy="68" r="1" fill="rgba(214,62,22,1)"/>
+ <circle cx="91" cy="68" r="1" fill="rgba(216,67,25,1)"/>
+ <circle cx="92" cy="68" r="1" fill="rgba(218,73,28,1)"/>
+ <circle cx="93" cy="68" r="1" fill="rgba(221,79,31,1)"/>
+ <circle cx="94" cy="68" r="1" fill="rgba(222,84,34,1)"/>
+ <circle cx="95" cy="68" r="1" fill="rgba(224,91,37,1)"/>
+ <circle cx="96" cy="68" r="1" fill="rgba(227,96,42,1)"/>
+ <circle cx="97" cy="68" r="1" fill="rgba(229,103,45,1)"/>
+ <circle cx="98" cy="68" r="1" fill="rgba(231,109,48,1)"/>
+ <circle cx="99" cy="68" r="1" fill="rgba(233,115,53,1)"/>
+ <circle cx="100" cy="68" r="1" fill="rgba(235,119,55,1)"/>
+ <circle cx="101" cy="68" r="1" fill="rgba(236,120,56,1)"/>
+ <circle cx="102" cy="68" r="1" fill="rgba(245,126,57,1)"/>
+ <circle cx="103" cy="68" r="1" fill="rgba(179,77,29,0.866667)"/>
+ <circle cx="104" cy="68" r="1" fill="rgba(24,0,0,0.564706)"/>
+ <circle cx="105" cy="68" r="1" fill="rgba(15,0,0,0.47451)"/>
+ <circle cx="106" cy="68" r="1" fill="rgba(0,0,0,0.45098)"/>
+ <circle cx="107" cy="68" r="1" fill="rgba(0,0,0,0.364706)"/>
+ <circle cx="108" cy="68" r="1" fill="rgba(54,28,12,0.54902)"/>
+ <circle cx="109" cy="68" r="1" fill="rgba(94,61,35,0.984314)"/>
+ <circle cx="110" cy="68" r="1" fill="rgba(96,64,37,1)"/>
+ <circle cx="111" cy="68" r="1" fill="rgba(100,68,41,1)"/>
+ <circle cx="112" cy="68" r="1" fill="rgba(103,71,44,0.929412)"/>
+ <circle cx="113" cy="68" r="1" fill="rgba(106,74,47,0.588235)"/>
+ <circle cx="114" cy="68" r="1" fill="rgba(107,75,48,0.317647)"/>
+ <circle cx="115" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="68" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="69" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="69" r="1" fill="rgba(61,30,13,0.0156863)"/>
+ <circle cx="2" cy="69" r="1" fill="rgba(46,20,8,0.00392157)"/>
+ <circle cx="3" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="69" r="1" fill="rgba(15,3,0,0.054902)"/>
+ <circle cx="6" cy="69" r="1" fill="rgba(19,6,1,0.12549)"/>
+ <circle cx="7" cy="69" r="1" fill="rgba(24,8,2,0.0980392)"/>
+ <circle cx="8" cy="69" r="1" fill="rgba(17,5,1,0.0666667)"/>
+ <circle cx="9" cy="69" r="1" fill="rgba(34,15,5,0.117647)"/>
+ <circle cx="10" cy="69" r="1" fill="rgba(29,12,3,0.129412)"/>
+ <circle cx="11" cy="69" r="1" fill="rgba(15,4,0,0.196078)"/>
+ <circle cx="12" cy="69" r="1" fill="rgba(17,5,1,0.345098)"/>
+ <circle cx="13" cy="69" r="1" fill="rgba(15,4,0,0.423529)"/>
+ <circle cx="14" cy="69" r="1" fill="rgba(10,1,0,0.427451)"/>
+ <circle cx="15" cy="69" r="1" fill="rgba(10,2,0,0.423529)"/>
+ <circle cx="16" cy="69" r="1" fill="rgba(10,2,0,0.419608)"/>
+ <circle cx="17" cy="69" r="1" fill="rgba(15,4,0,0.4)"/>
+ <circle cx="18" cy="69" r="1" fill="rgba(21,7,1,0.345098)"/>
+ <circle cx="19" cy="69" r="1" fill="rgba(33,14,4,0.235294)"/>
+ <circle cx="20" cy="69" r="1" fill="rgba(43,21,8,0.113725)"/>
+ <circle cx="21" cy="69" r="1" fill="rgba(46,22,9,0.0313725)"/>
+ <circle cx="22" cy="69" r="1" fill="rgba(42,20,7,0)"/>
+ <circle cx="23" cy="69" r="1" fill="rgba(28,13,4,0)"/>
+ <circle cx="24" cy="69" r="1" fill="rgba(196,131,84,0)"/>
+ <circle cx="25" cy="69" r="1" fill="rgba(255,178,118,0)"/>
+ <circle cx="26" cy="69" r="1" fill="rgba(236,88,23,0.45098)"/>
+ <circle cx="27" cy="69" r="1" fill="rgba(233,75,17,1)"/>
+ <circle cx="28" cy="69" r="1" fill="rgba(241,112,48,1)"/>
+ <circle cx="29" cy="69" r="1" fill="rgba(241,102,33,1)"/>
+ <circle cx="30" cy="69" r="1" fill="rgba(241,81,13,1)"/>
+ <circle cx="31" cy="69" r="1" fill="rgba(241,70,4,1)"/>
+ <circle cx="32" cy="69" r="1" fill="rgba(241,67,1,1)"/>
+ <circle cx="33" cy="69" r="1" fill="rgba(241,60,0,1)"/>
+ <circle cx="34" cy="69" r="1" fill="rgba(239,57,0,1)"/>
+ <circle cx="35" cy="69" r="1" fill="rgba(237,54,0,1)"/>
+ <circle cx="36" cy="69" r="1" fill="rgba(236,52,0,1)"/>
+ <circle cx="37" cy="69" r="1" fill="rgba(236,50,0,1)"/>
+ <circle cx="38" cy="69" r="1" fill="rgba(236,49,0,1)"/>
+ <circle cx="39" cy="69" r="1" fill="rgba(235,48,0,1)"/>
+ <circle cx="40" cy="69" r="1" fill="rgba(235,47,0,1)"/>
+ <circle cx="41" cy="69" r="1" fill="rgba(235,46,0,1)"/>
+ <circle cx="42" cy="69" r="1" fill="rgba(235,46,0,1)"/>
+ <circle cx="43" cy="69" r="1" fill="rgba(234,46,0,1)"/>
+ <circle cx="44" cy="69" r="1" fill="rgba(233,47,0,1)"/>
+ <circle cx="45" cy="69" r="1" fill="rgba(233,45,0,1)"/>
+ <circle cx="46" cy="69" r="1" fill="rgba(233,45,0,1)"/>
+ <circle cx="47" cy="69" r="1" fill="rgba(233,45,0,1)"/>
+ <circle cx="48" cy="69" r="1" fill="rgba(231,44,0,1)"/>
+ <circle cx="49" cy="69" r="1" fill="rgba(231,42,0,1)"/>
+ <circle cx="50" cy="69" r="1" fill="rgba(230,41,0,1)"/>
+ <circle cx="51" cy="69" r="1" fill="rgba(228,40,0,1)"/>
+ <circle cx="52" cy="69" r="1" fill="rgba(228,39,0,1)"/>
+ <circle cx="53" cy="69" r="1" fill="rgba(227,39,0,1)"/>
+ <circle cx="54" cy="69" r="1" fill="rgba(225,38,0,1)"/>
+ <circle cx="55" cy="69" r="1" fill="rgba(224,37,0,1)"/>
+ <circle cx="56" cy="69" r="1" fill="rgba(224,36,0,1)"/>
+ <circle cx="57" cy="69" r="1" fill="rgba(223,36,0,1)"/>
+ <circle cx="58" cy="69" r="1" fill="rgba(222,35,0,1)"/>
+ <circle cx="59" cy="69" r="1" fill="rgba(221,34,0,1)"/>
+ <circle cx="60" cy="69" r="1" fill="rgba(219,31,0,1)"/>
+ <circle cx="61" cy="69" r="1" fill="rgba(217,29,0,1)"/>
+ <circle cx="62" cy="69" r="1" fill="rgba(215,28,0,1)"/>
+ <circle cx="63" cy="69" r="1" fill="rgba(211,26,0,1)"/>
+ <circle cx="64" cy="69" r="1" fill="rgba(209,20,0,1)"/>
+ <circle cx="65" cy="69" r="1" fill="rgba(173,20,2,1)"/>
+ <circle cx="66" cy="69" r="1" fill="rgba(158,28,6,1)"/>
+ <circle cx="67" cy="69" r="1" fill="rgba(205,20,0,1)"/>
+ <circle cx="68" cy="69" r="1" fill="rgba(203,24,0,1)"/>
+ <circle cx="69" cy="69" r="1" fill="rgba(207,29,2,1)"/>
+ <circle cx="70" cy="69" r="1" fill="rgba(210,31,3,1)"/>
+ <circle cx="71" cy="69" r="1" fill="rgba(211,31,3,1)"/>
+ <circle cx="72" cy="69" r="1" fill="rgba(210,29,4,1)"/>
+ <circle cx="73" cy="69" r="1" fill="rgba(207,26,4,1)"/>
+ <circle cx="74" cy="69" r="1" fill="rgba(203,22,4,1)"/>
+ <circle cx="75" cy="69" r="1" fill="rgba(200,19,4,1)"/>
+ <circle cx="76" cy="69" r="1" fill="rgba(199,18,4,1)"/>
+ <circle cx="77" cy="69" r="1" fill="rgba(199,19,4,1)"/>
+ <circle cx="78" cy="69" r="1" fill="rgba(200,21,4,1)"/>
+ <circle cx="79" cy="69" r="1" fill="rgba(201,23,5,1)"/>
+ <circle cx="80" cy="69" r="1" fill="rgba(202,25,6,1)"/>
+ <circle cx="81" cy="69" r="1" fill="rgba(203,29,7,1)"/>
+ <circle cx="82" cy="69" r="1" fill="rgba(203,31,8,1)"/>
+ <circle cx="83" cy="69" r="1" fill="rgba(205,35,10,1)"/>
+ <circle cx="84" cy="69" r="1" fill="rgba(206,38,11,1)"/>
+ <circle cx="85" cy="69" r="1" fill="rgba(207,42,13,1)"/>
+ <circle cx="86" cy="69" r="1" fill="rgba(208,46,14,1)"/>
+ <circle cx="87" cy="69" r="1" fill="rgba(210,49,16,1)"/>
+ <circle cx="88" cy="69" r="1" fill="rgba(211,53,18,1)"/>
+ <circle cx="89" cy="69" r="1" fill="rgba(214,59,20,1)"/>
+ <circle cx="90" cy="69" r="1" fill="rgba(214,64,23,1)"/>
+ <circle cx="91" cy="69" r="1" fill="rgba(216,69,26,1)"/>
+ <circle cx="92" cy="69" r="1" fill="rgba(219,74,28,1)"/>
+ <circle cx="93" cy="69" r="1" fill="rgba(221,80,32,1)"/>
+ <circle cx="94" cy="69" r="1" fill="rgba(223,85,34,1)"/>
+ <circle cx="95" cy="69" r="1" fill="rgba(225,92,38,1)"/>
+ <circle cx="96" cy="69" r="1" fill="rgba(227,97,42,1)"/>
+ <circle cx="97" cy="69" r="1" fill="rgba(229,104,47,1)"/>
+ <circle cx="98" cy="69" r="1" fill="rgba(232,111,50,1)"/>
+ <circle cx="99" cy="69" r="1" fill="rgba(234,116,54,1)"/>
+ <circle cx="100" cy="69" r="1" fill="rgba(236,120,56,1)"/>
+ <circle cx="101" cy="69" r="1" fill="rgba(237,122,56,1)"/>
+ <circle cx="102" cy="69" r="1" fill="rgba(245,128,58,1)"/>
+ <circle cx="103" cy="69" r="1" fill="rgba(181,78,30,0.870588)"/>
+ <circle cx="104" cy="69" r="1" fill="rgba(28,1,0,0.584314)"/>
+ <circle cx="105" cy="69" r="1" fill="rgba(19,0,0,0.501961)"/>
+ <circle cx="106" cy="69" r="1" fill="rgba(7,0,0,0.454902)"/>
+ <circle cx="107" cy="69" r="1" fill="rgba(0,0,0,0.45098)"/>
+ <circle cx="108" cy="69" r="1" fill="rgba(4,0,0,0.368627)"/>
+ <circle cx="109" cy="69" r="1" fill="rgba(63,35,16,0.623529)"/>
+ <circle cx="110" cy="69" r="1" fill="rgba(97,64,38,1)"/>
+ <circle cx="111" cy="69" r="1" fill="rgba(98,66,39,1)"/>
+ <circle cx="112" cy="69" r="1" fill="rgba(100,68,42,1)"/>
+ <circle cx="113" cy="69" r="1" fill="rgba(103,71,44,1)"/>
+ <circle cx="114" cy="69" r="1" fill="rgba(104,72,45,1)"/>
+ <circle cx="115" cy="69" r="1" fill="rgba(103,71,44,0.380392)"/>
+ <circle cx="116" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="69" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="70" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="70" r="1" fill="rgba(39,16,6,0.0313725)"/>
+ <circle cx="13" cy="70" r="1" fill="rgba(40,19,7,0.101961)"/>
+ <circle cx="14" cy="70" r="1" fill="rgba(33,14,4,0.117647)"/>
+ <circle cx="15" cy="70" r="1" fill="rgba(31,13,4,0.113725)"/>
+ <circle cx="16" cy="70" r="1" fill="rgba(33,13,4,0.101961)"/>
+ <circle cx="17" cy="70" r="1" fill="rgba(39,17,6,0.0862745)"/>
+ <circle cx="18" cy="70" r="1" fill="rgba(40,18,7,0.0470588)"/>
+ <circle cx="19" cy="70" r="1" fill="rgba(47,22,8,0.00784314)"/>
+ <circle cx="20" cy="70" r="1" fill="rgba(50,25,10,0)"/>
+ <circle cx="21" cy="70" r="1" fill="rgba(46,23,9,0)"/>
+ <circle cx="22" cy="70" r="1" fill="rgba(24,12,4,0)"/>
+ <circle cx="23" cy="70" r="1" fill="rgba(110,61,30,0)"/>
+ <circle cx="24" cy="70" r="1" fill="rgba(255,191,141,0)"/>
+ <circle cx="25" cy="70" r="1" fill="rgba(250,170,114,0)"/>
+ <circle cx="26" cy="70" r="1" fill="rgba(233,86,24,0.396078)"/>
+ <circle cx="27" cy="70" r="1" fill="rgba(230,64,12,1)"/>
+ <circle cx="28" cy="70" r="1" fill="rgba(239,105,44,1)"/>
+ <circle cx="29" cy="70" r="1" fill="rgba(239,97,30,1)"/>
+ <circle cx="30" cy="70" r="1" fill="rgba(238,74,10,1)"/>
+ <circle cx="31" cy="70" r="1" fill="rgba(238,62,1,1)"/>
+ <circle cx="32" cy="70" r="1" fill="rgba(238,59,0,1)"/>
+ <circle cx="33" cy="70" r="1" fill="rgba(238,55,0,1)"/>
+ <circle cx="34" cy="70" r="1" fill="rgba(236,53,0,1)"/>
+ <circle cx="35" cy="70" r="1" fill="rgba(234,49,0,1)"/>
+ <circle cx="36" cy="70" r="1" fill="rgba(233,47,0,1)"/>
+ <circle cx="37" cy="70" r="1" fill="rgba(233,46,0,1)"/>
+ <circle cx="38" cy="70" r="1" fill="rgba(233,46,0,1)"/>
+ <circle cx="39" cy="70" r="1" fill="rgba(233,45,0,1)"/>
+ <circle cx="40" cy="70" r="1" fill="rgba(233,45,0,1)"/>
+ <circle cx="41" cy="70" r="1" fill="rgba(233,44,0,1)"/>
+ <circle cx="42" cy="70" r="1" fill="rgba(233,44,0,1)"/>
+ <circle cx="43" cy="70" r="1" fill="rgba(232,44,0,1)"/>
+ <circle cx="44" cy="70" r="1" fill="rgba(232,44,0,1)"/>
+ <circle cx="45" cy="70" r="1" fill="rgba(232,43,0,1)"/>
+ <circle cx="46" cy="70" r="1" fill="rgba(232,42,0,1)"/>
+ <circle cx="47" cy="70" r="1" fill="rgba(231,42,0,1)"/>
+ <circle cx="48" cy="70" r="1" fill="rgba(230,41,0,1)"/>
+ <circle cx="49" cy="70" r="1" fill="rgba(229,40,0,1)"/>
+ <circle cx="50" cy="70" r="1" fill="rgba(228,40,0,1)"/>
+ <circle cx="51" cy="70" r="1" fill="rgba(227,40,0,1)"/>
+ <circle cx="52" cy="70" r="1" fill="rgba(227,37,0,1)"/>
+ <circle cx="53" cy="70" r="1" fill="rgba(225,36,0,1)"/>
+ <circle cx="54" cy="70" r="1" fill="rgba(224,36,0,1)"/>
+ <circle cx="55" cy="70" r="1" fill="rgba(223,34,0,1)"/>
+ <circle cx="56" cy="70" r="1" fill="rgba(221,34,0,1)"/>
+ <circle cx="57" cy="70" r="1" fill="rgba(221,33,0,1)"/>
+ <circle cx="58" cy="70" r="1" fill="rgba(220,32,0,1)"/>
+ <circle cx="59" cy="70" r="1" fill="rgba(219,30,0,1)"/>
+ <circle cx="60" cy="70" r="1" fill="rgba(217,29,0,1)"/>
+ <circle cx="61" cy="70" r="1" fill="rgba(216,27,0,1)"/>
+ <circle cx="62" cy="70" r="1" fill="rgba(214,26,0,1)"/>
+ <circle cx="63" cy="70" r="1" fill="rgba(210,23,0,1)"/>
+ <circle cx="64" cy="70" r="1" fill="rgba(207,19,0,1)"/>
+ <circle cx="65" cy="70" r="1" fill="rgba(172,20,2,1)"/>
+ <circle cx="66" cy="70" r="1" fill="rgba(157,27,5,1)"/>
+ <circle cx="67" cy="70" r="1" fill="rgba(204,20,0,1)"/>
+ <circle cx="68" cy="70" r="1" fill="rgba(202,23,0,1)"/>
+ <circle cx="69" cy="70" r="1" fill="rgba(207,27,2,1)"/>
+ <circle cx="70" cy="70" r="1" fill="rgba(209,29,3,1)"/>
+ <circle cx="71" cy="70" r="1" fill="rgba(210,30,4,1)"/>
+ <circle cx="72" cy="70" r="1" fill="rgba(209,29,4,1)"/>
+ <circle cx="73" cy="70" r="1" fill="rgba(206,25,4,1)"/>
+ <circle cx="74" cy="70" r="1" fill="rgba(203,22,4,1)"/>
+ <circle cx="75" cy="70" r="1" fill="rgba(200,19,4,1)"/>
+ <circle cx="76" cy="70" r="1" fill="rgba(199,18,4,1)"/>
+ <circle cx="77" cy="70" r="1" fill="rgba(199,19,4,1)"/>
+ <circle cx="78" cy="70" r="1" fill="rgba(200,21,5,1)"/>
+ <circle cx="79" cy="70" r="1" fill="rgba(201,24,5,1)"/>
+ <circle cx="80" cy="70" r="1" fill="rgba(202,27,7,1)"/>
+ <circle cx="81" cy="70" r="1" fill="rgba(203,29,8,1)"/>
+ <circle cx="82" cy="70" r="1" fill="rgba(204,32,9,1)"/>
+ <circle cx="83" cy="70" r="1" fill="rgba(206,36,10,1)"/>
+ <circle cx="84" cy="70" r="1" fill="rgba(207,39,11,1)"/>
+ <circle cx="85" cy="70" r="1" fill="rgba(207,43,13,1)"/>
+ <circle cx="86" cy="70" r="1" fill="rgba(208,47,15,1)"/>
+ <circle cx="87" cy="70" r="1" fill="rgba(210,50,17,1)"/>
+ <circle cx="88" cy="70" r="1" fill="rgba(212,55,19,1)"/>
+ <circle cx="89" cy="70" r="1" fill="rgba(214,60,20,1)"/>
+ <circle cx="90" cy="70" r="1" fill="rgba(214,65,23,1)"/>
+ <circle cx="91" cy="70" r="1" fill="rgba(217,70,27,1)"/>
+ <circle cx="92" cy="70" r="1" fill="rgba(220,76,30,1)"/>
+ <circle cx="93" cy="70" r="1" fill="rgba(221,81,33,1)"/>
+ <circle cx="94" cy="70" r="1" fill="rgba(223,88,36,1)"/>
+ <circle cx="95" cy="70" r="1" fill="rgba(226,93,39,1)"/>
+ <circle cx="96" cy="70" r="1" fill="rgba(228,100,42,1)"/>
+ <circle cx="97" cy="70" r="1" fill="rgba(230,106,48,1)"/>
+ <circle cx="98" cy="70" r="1" fill="rgba(233,112,51,1)"/>
+ <circle cx="99" cy="70" r="1" fill="rgba(234,118,55,1)"/>
+ <circle cx="100" cy="70" r="1" fill="rgba(236,122,56,1)"/>
+ <circle cx="101" cy="70" r="1" fill="rgba(238,124,58,1)"/>
+ <circle cx="102" cy="70" r="1" fill="rgba(248,131,60,1)"/>
+ <circle cx="103" cy="70" r="1" fill="rgba(167,70,24,0.854902)"/>
+ <circle cx="104" cy="70" r="1" fill="rgba(19,0,0,0.584314)"/>
+ <circle cx="105" cy="70" r="1" fill="rgba(22,1,0,0.509804)"/>
+ <circle cx="106" cy="70" r="1" fill="rgba(10,0,0,0.462745)"/>
+ <circle cx="107" cy="70" r="1" fill="rgba(0,0,0,0.458824)"/>
+ <circle cx="108" cy="70" r="1" fill="rgba(0,0,0,0.447059)"/>
+ <circle cx="109" cy="70" r="1" fill="rgba(7,0,0,0.376471)"/>
+ <circle cx="110" cy="70" r="1" fill="rgba(63,35,16,0.635294)"/>
+ <circle cx="111" cy="70" r="1" fill="rgba(97,64,38,0.976471)"/>
+ <circle cx="112" cy="70" r="1" fill="rgba(100,67,41,1)"/>
+ <circle cx="113" cy="70" r="1" fill="rgba(99,67,41,1)"/>
+ <circle cx="114" cy="70" r="1" fill="rgba(100,68,41,1)"/>
+ <circle cx="115" cy="70" r="1" fill="rgba(100,68,41,0.952941)"/>
+ <circle cx="116" cy="70" r="1" fill="rgba(98,66,40,0.576471)"/>
+ <circle cx="117" cy="70" r="1" fill="rgba(95,63,37,0.447059)"/>
+ <circle cx="118" cy="70" r="1" fill="rgba(92,59,35,0.180392)"/>
+ <circle cx="119" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="70" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="71" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="71" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="19" cy="71" r="1" fill="rgba(46,21,8,0)"/>
+ <circle cx="20" cy="71" r="1" fill="rgba(49,24,10,0)"/>
+ <circle cx="21" cy="71" r="1" fill="rgba(45,21,9,0)"/>
+ <circle cx="22" cy="71" r="1" fill="rgba(40,18,7,0)"/>
+ <circle cx="23" cy="71" r="1" fill="rgba(203,120,74,0)"/>
+ <circle cx="24" cy="71" r="1" fill="rgba(251,167,117,0)"/>
+ <circle cx="25" cy="71" r="1" fill="rgba(244,152,99,0)"/>
+ <circle cx="26" cy="71" r="1" fill="rgba(229,77,21,0.301961)"/>
+ <circle cx="27" cy="71" r="1" fill="rgba(227,53,5,1)"/>
+ <circle cx="28" cy="71" r="1" fill="rgba(235,93,37,1)"/>
+ <circle cx="29" cy="71" r="1" fill="rgba(237,87,24,1)"/>
+ <circle cx="30" cy="71" r="1" fill="rgba(236,67,7,1)"/>
+ <circle cx="31" cy="71" r="1" fill="rgba(234,55,0,1)"/>
+ <circle cx="32" cy="71" r="1" fill="rgba(235,54,0,1)"/>
+ <circle cx="33" cy="71" r="1" fill="rgba(235,51,0,1)"/>
+ <circle cx="34" cy="71" r="1" fill="rgba(233,47,0,1)"/>
+ <circle cx="35" cy="71" r="1" fill="rgba(230,44,0,1)"/>
+ <circle cx="36" cy="71" r="1" fill="rgba(230,44,0,1)"/>
+ <circle cx="37" cy="71" r="1" fill="rgba(230,44,0,1)"/>
+ <circle cx="38" cy="71" r="1" fill="rgba(231,45,0,1)"/>
+ <circle cx="39" cy="71" r="1" fill="rgba(231,45,0,1)"/>
+ <circle cx="40" cy="71" r="1" fill="rgba(231,44,0,1)"/>
+ <circle cx="41" cy="71" r="1" fill="rgba(231,43,0,1)"/>
+ <circle cx="42" cy="71" r="1" fill="rgba(231,43,0,1)"/>
+ <circle cx="43" cy="71" r="1" fill="rgba(230,43,0,1)"/>
+ <circle cx="44" cy="71" r="1" fill="rgba(230,43,0,1)"/>
+ <circle cx="45" cy="71" r="1" fill="rgba(230,42,0,1)"/>
+ <circle cx="46" cy="71" r="1" fill="rgba(230,41,0,1)"/>
+ <circle cx="47" cy="71" r="1" fill="rgba(229,41,0,1)"/>
+ <circle cx="48" cy="71" r="1" fill="rgba(228,40,0,1)"/>
+ <circle cx="49" cy="71" r="1" fill="rgba(227,39,0,1)"/>
+ <circle cx="50" cy="71" r="1" fill="rgba(226,39,0,1)"/>
+ <circle cx="51" cy="71" r="1" fill="rgba(226,38,0,1)"/>
+ <circle cx="52" cy="71" r="1" fill="rgba(224,36,0,1)"/>
+ <circle cx="53" cy="71" r="1" fill="rgba(223,35,0,1)"/>
+ <circle cx="54" cy="71" r="1" fill="rgba(223,33,0,1)"/>
+ <circle cx="55" cy="71" r="1" fill="rgba(221,32,0,1)"/>
+ <circle cx="56" cy="71" r="1" fill="rgba(219,32,0,1)"/>
+ <circle cx="57" cy="71" r="1" fill="rgba(218,30,0,1)"/>
+ <circle cx="58" cy="71" r="1" fill="rgba(218,29,0,1)"/>
+ <circle cx="59" cy="71" r="1" fill="rgba(217,28,0,1)"/>
+ <circle cx="60" cy="71" r="1" fill="rgba(214,28,0,1)"/>
+ <circle cx="61" cy="71" r="1" fill="rgba(214,26,0,1)"/>
+ <circle cx="62" cy="71" r="1" fill="rgba(212,24,0,1)"/>
+ <circle cx="63" cy="71" r="1" fill="rgba(210,21,0,1)"/>
+ <circle cx="64" cy="71" r="1" fill="rgba(207,18,0,1)"/>
+ <circle cx="65" cy="71" r="1" fill="rgba(171,19,2,1)"/>
+ <circle cx="66" cy="71" r="1" fill="rgba(156,26,5,1)"/>
+ <circle cx="67" cy="71" r="1" fill="rgba(203,18,0,1)"/>
+ <circle cx="68" cy="71" r="1" fill="rgba(201,23,1,1)"/>
+ <circle cx="69" cy="71" r="1" fill="rgba(205,27,2,1)"/>
+ <circle cx="70" cy="71" r="1" fill="rgba(208,28,4,1)"/>
+ <circle cx="71" cy="71" r="1" fill="rgba(209,29,4,1)"/>
+ <circle cx="72" cy="71" r="1" fill="rgba(207,28,4,1)"/>
+ <circle cx="73" cy="71" r="1" fill="rgba(205,24,4,1)"/>
+ <circle cx="74" cy="71" r="1" fill="rgba(203,20,4,1)"/>
+ <circle cx="75" cy="71" r="1" fill="rgba(200,19,4,1)"/>
+ <circle cx="76" cy="71" r="1" fill="rgba(200,20,4,1)"/>
+ <circle cx="77" cy="71" r="1" fill="rgba(200,21,5,1)"/>
+ <circle cx="78" cy="71" r="1" fill="rgba(200,22,5,1)"/>
+ <circle cx="79" cy="71" r="1" fill="rgba(201,25,6,1)"/>
+ <circle cx="80" cy="71" r="1" fill="rgba(203,28,7,1)"/>
+ <circle cx="81" cy="71" r="1" fill="rgba(203,30,8,1)"/>
+ <circle cx="82" cy="71" r="1" fill="rgba(204,34,10,1)"/>
+ <circle cx="83" cy="71" r="1" fill="rgba(207,36,10,1)"/>
+ <circle cx="84" cy="71" r="1" fill="rgba(207,40,12,1)"/>
+ <circle cx="85" cy="71" r="1" fill="rgba(207,44,13,1)"/>
+ <circle cx="86" cy="71" r="1" fill="rgba(209,48,16,1)"/>
+ <circle cx="87" cy="71" r="1" fill="rgba(210,52,18,1)"/>
+ <circle cx="88" cy="71" r="1" fill="rgba(213,56,20,1)"/>
+ <circle cx="89" cy="71" r="1" fill="rgba(214,62,22,1)"/>
+ <circle cx="90" cy="71" r="1" fill="rgba(216,67,24,1)"/>
+ <circle cx="91" cy="71" r="1" fill="rgba(217,71,27,1)"/>
+ <circle cx="92" cy="71" r="1" fill="rgba(220,77,30,1)"/>
+ <circle cx="93" cy="71" r="1" fill="rgba(221,83,33,1)"/>
+ <circle cx="94" cy="71" r="1" fill="rgba(224,89,37,1)"/>
+ <circle cx="95" cy="71" r="1" fill="rgba(226,94,40,1)"/>
+ <circle cx="96" cy="71" r="1" fill="rgba(229,102,44,1)"/>
+ <circle cx="97" cy="71" r="1" fill="rgba(230,107,48,1)"/>
+ <circle cx="98" cy="71" r="1" fill="rgba(233,115,53,1)"/>
+ <circle cx="99" cy="71" r="1" fill="rgba(235,119,56,1)"/>
+ <circle cx="100" cy="71" r="1" fill="rgba(236,122,57,1)"/>
+ <circle cx="101" cy="71" r="1" fill="rgba(238,125,59,1)"/>
+ <circle cx="102" cy="71" r="1" fill="rgba(249,132,60,1)"/>
+ <circle cx="103" cy="71" r="1" fill="rgba(150,60,20,0.831373)"/>
+ <circle cx="104" cy="71" r="1" fill="rgba(7,0,0,0.580392)"/>
+ <circle cx="105" cy="71" r="1" fill="rgba(24,1,0,0.513725)"/>
+ <circle cx="106" cy="71" r="1" fill="rgba(10,0,0,0.466667)"/>
+ <circle cx="107" cy="71" r="1" fill="rgba(4,0,0,0.45098)"/>
+ <circle cx="108" cy="71" r="1" fill="rgba(4,0,0,0.447059)"/>
+ <circle cx="109" cy="71" r="1" fill="rgba(0,0,0,0.443137)"/>
+ <circle cx="110" cy="71" r="1" fill="rgba(0,0,0,0.392157)"/>
+ <circle cx="111" cy="71" r="1" fill="rgba(45,21,8,0.494118)"/>
+ <circle cx="112" cy="71" r="1" fill="rgba(83,52,28,0.780392)"/>
+ <circle cx="113" cy="71" r="1" fill="rgba(98,66,40,1)"/>
+ <circle cx="114" cy="71" r="1" fill="rgba(98,65,39,1)"/>
+ <circle cx="115" cy="71" r="1" fill="rgba(97,64,38,1)"/>
+ <circle cx="116" cy="71" r="1" fill="rgba(96,63,37,1)"/>
+ <circle cx="117" cy="71" r="1" fill="rgba(93,61,35,1)"/>
+ <circle cx="118" cy="71" r="1" fill="rgba(90,58,33,0.980392)"/>
+ <circle cx="119" cy="71" r="1" fill="rgba(87,55,31,0.705882)"/>
+ <circle cx="120" cy="71" r="1" fill="rgba(83,51,27,0.305882)"/>
+ <circle cx="121" cy="71" r="1" fill="rgba(78,46,24,0.027451)"/>
+ <circle cx="122" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="71" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="72" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="72" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="19" cy="72" r="1" fill="rgba(46,21,8,0)"/>
+ <circle cx="20" cy="72" r="1" fill="rgba(49,24,10,0)"/>
+ <circle cx="21" cy="72" r="1" fill="rgba(42,20,8,0)"/>
+ <circle cx="22" cy="72" r="1" fill="rgba(62,28,11,0)"/>
+ <circle cx="23" cy="72" r="1" fill="rgba(236,126,74,0)"/>
+ <circle cx="24" cy="72" r="1" fill="rgba(243,129,77,0)"/>
+ <circle cx="25" cy="72" r="1" fill="rgba(242,131,80,0)"/>
+ <circle cx="26" cy="72" r="1" fill="rgba(230,73,20,0.196078)"/>
+ <circle cx="27" cy="72" r="1" fill="rgba(222,42,0,0.976471)"/>
+ <circle cx="28" cy="72" r="1" fill="rgba(230,80,27,1)"/>
+ <circle cx="29" cy="72" r="1" fill="rgba(233,79,20,1)"/>
+ <circle cx="30" cy="72" r="1" fill="rgba(233,65,7,1)"/>
+ <circle cx="31" cy="72" r="1" fill="rgba(231,51,0,1)"/>
+ <circle cx="32" cy="72" r="1" fill="rgba(231,47,0,1)"/>
+ <circle cx="33" cy="72" r="1" fill="rgba(230,44,0,1)"/>
+ <circle cx="34" cy="72" r="1" fill="rgba(228,41,0,1)"/>
+ <circle cx="35" cy="72" r="1" fill="rgba(227,40,0,1)"/>
+ <circle cx="36" cy="72" r="1" fill="rgba(227,41,0,1)"/>
+ <circle cx="37" cy="72" r="1" fill="rgba(227,42,0,1)"/>
+ <circle cx="38" cy="72" r="1" fill="rgba(229,42,0,1)"/>
+ <circle cx="39" cy="72" r="1" fill="rgba(229,42,0,1)"/>
+ <circle cx="40" cy="72" r="1" fill="rgba(229,42,0,1)"/>
+ <circle cx="41" cy="72" r="1" fill="rgba(230,42,0,1)"/>
+ <circle cx="42" cy="72" r="1" fill="rgba(229,41,0,1)"/>
+ <circle cx="43" cy="72" r="1" fill="rgba(229,41,0,1)"/>
+ <circle cx="44" cy="72" r="1" fill="rgba(227,41,0,1)"/>
+ <circle cx="45" cy="72" r="1" fill="rgba(228,41,0,1)"/>
+ <circle cx="46" cy="72" r="1" fill="rgba(228,40,0,1)"/>
+ <circle cx="47" cy="72" r="1" fill="rgba(227,39,0,1)"/>
+ <circle cx="48" cy="72" r="1" fill="rgba(226,39,0,1)"/>
+ <circle cx="49" cy="72" r="1" fill="rgba(226,38,0,1)"/>
+ <circle cx="50" cy="72" r="1" fill="rgba(225,37,0,1)"/>
+ <circle cx="51" cy="72" r="1" fill="rgba(224,36,0,1)"/>
+ <circle cx="52" cy="72" r="1" fill="rgba(222,35,0,1)"/>
+ <circle cx="53" cy="72" r="1" fill="rgba(222,32,0,1)"/>
+ <circle cx="54" cy="72" r="1" fill="rgba(221,32,0,1)"/>
+ <circle cx="55" cy="72" r="1" fill="rgba(219,31,0,1)"/>
+ <circle cx="56" cy="72" r="1" fill="rgba(218,30,0,1)"/>
+ <circle cx="57" cy="72" r="1" fill="rgba(217,28,0,1)"/>
+ <circle cx="58" cy="72" r="1" fill="rgba(217,27,0,1)"/>
+ <circle cx="59" cy="72" r="1" fill="rgba(215,26,0,1)"/>
+ <circle cx="60" cy="72" r="1" fill="rgba(214,25,0,1)"/>
+ <circle cx="61" cy="72" r="1" fill="rgba(213,24,0,1)"/>
+ <circle cx="62" cy="72" r="1" fill="rgba(210,23,0,1)"/>
+ <circle cx="63" cy="72" r="1" fill="rgba(208,21,0,1)"/>
+ <circle cx="64" cy="72" r="1" fill="rgba(207,17,0,1)"/>
+ <circle cx="65" cy="72" r="1" fill="rgba(170,18,2,1)"/>
+ <circle cx="66" cy="72" r="1" fill="rgba(155,25,5,1)"/>
+ <circle cx="67" cy="72" r="1" fill="rgba(201,17,0,1)"/>
+ <circle cx="68" cy="72" r="1" fill="rgba(200,22,1,1)"/>
+ <circle cx="69" cy="72" r="1" fill="rgba(203,25,2,1)"/>
+ <circle cx="70" cy="72" r="1" fill="rgba(207,27,4,1)"/>
+ <circle cx="71" cy="72" r="1" fill="rgba(208,29,5,1)"/>
+ <circle cx="72" cy="72" r="1" fill="rgba(207,27,5,1)"/>
+ <circle cx="73" cy="72" r="1" fill="rgba(204,23,5,1)"/>
+ <circle cx="74" cy="72" r="1" fill="rgba(202,21,5,1)"/>
+ <circle cx="75" cy="72" r="1" fill="rgba(201,20,5,1)"/>
+ <circle cx="76" cy="72" r="1" fill="rgba(200,20,5,1)"/>
+ <circle cx="77" cy="72" r="1" fill="rgba(200,22,5,1)"/>
+ <circle cx="78" cy="72" r="1" fill="rgba(200,24,6,1)"/>
+ <circle cx="79" cy="72" r="1" fill="rgba(202,26,6,1)"/>
+ <circle cx="80" cy="72" r="1" fill="rgba(203,28,8,1)"/>
+ <circle cx="81" cy="72" r="1" fill="rgba(204,31,8,1)"/>
+ <circle cx="82" cy="72" r="1" fill="rgba(205,34,10,1)"/>
+ <circle cx="83" cy="72" r="1" fill="rgba(207,38,11,1)"/>
+ <circle cx="84" cy="72" r="1" fill="rgba(207,42,13,1)"/>
+ <circle cx="85" cy="72" r="1" fill="rgba(207,46,14,1)"/>
+ <circle cx="86" cy="72" r="1" fill="rgba(210,49,16,1)"/>
+ <circle cx="87" cy="72" r="1" fill="rgba(211,53,18,1)"/>
+ <circle cx="88" cy="72" r="1" fill="rgba(214,59,20,1)"/>
+ <circle cx="89" cy="72" r="1" fill="rgba(214,64,22,1)"/>
+ <circle cx="90" cy="72" r="1" fill="rgba(216,68,25,1)"/>
+ <circle cx="91" cy="72" r="1" fill="rgba(218,72,27,1)"/>
+ <circle cx="92" cy="72" r="1" fill="rgba(221,79,31,1)"/>
+ <circle cx="93" cy="72" r="1" fill="rgba(222,85,34,1)"/>
+ <circle cx="94" cy="72" r="1" fill="rgba(224,90,38,1)"/>
+ <circle cx="95" cy="72" r="1" fill="rgba(227,97,42,1)"/>
+ <circle cx="96" cy="72" r="1" fill="rgba(229,104,46,1)"/>
+ <circle cx="97" cy="72" r="1" fill="rgba(232,109,50,1)"/>
+ <circle cx="98" cy="72" r="1" fill="rgba(233,117,54,1)"/>
+ <circle cx="99" cy="72" r="1" fill="rgba(236,121,56,1)"/>
+ <circle cx="100" cy="72" r="1" fill="rgba(237,124,57,1)"/>
+ <circle cx="101" cy="72" r="1" fill="rgba(239,126,58,1)"/>
+ <circle cx="102" cy="72" r="1" fill="rgba(245,127,56,1)"/>
+ <circle cx="103" cy="72" r="1" fill="rgba(138,51,16,0.8)"/>
+ <circle cx="104" cy="72" r="1" fill="rgba(15,0,0,0.580392)"/>
+ <circle cx="105" cy="72" r="1" fill="rgba(21,1,0,0.509804)"/>
+ <circle cx="106" cy="72" r="1" fill="rgba(10,0,0,0.462745)"/>
+ <circle cx="107" cy="72" r="1" fill="rgba(4,0,0,0.435294)"/>
+ <circle cx="108" cy="72" r="1" fill="rgba(7,1,0,0.419608)"/>
+ <circle cx="109" cy="72" r="1" fill="rgba(7,2,0,0.419608)"/>
+ <circle cx="110" cy="72" r="1" fill="rgba(4,0,0,0.431373)"/>
+ <circle cx="111" cy="72" r="1" fill="rgba(0,0,0,0.407843)"/>
+ <circle cx="112" cy="72" r="1" fill="rgba(19,5,1,0.364706)"/>
+ <circle cx="113" cy="72" r="1" fill="rgba(58,31,13,0.509804)"/>
+ <circle cx="114" cy="72" r="1" fill="rgba(85,53,29,0.698039)"/>
+ <circle cx="115" cy="72" r="1" fill="rgba(91,58,33,0.721569)"/>
+ <circle cx="116" cy="72" r="1" fill="rgba(88,56,31,0.705882)"/>
+ <circle cx="117" cy="72" r="1" fill="rgba(90,57,32,0.890196)"/>
+ <circle cx="118" cy="72" r="1" fill="rgba(90,56,32,1)"/>
+ <circle cx="119" cy="72" r="1" fill="rgba(85,52,29,1)"/>
+ <circle cx="120" cy="72" r="1" fill="rgba(82,49,26,1)"/>
+ <circle cx="121" cy="72" r="1" fill="rgba(77,45,24,0.827451)"/>
+ <circle cx="122" cy="72" r="1" fill="rgba(74,42,21,0.403922)"/>
+ <circle cx="123" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="72" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="73" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="73" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="19" cy="73" r="1" fill="rgba(46,21,8,0)"/>
+ <circle cx="20" cy="73" r="1" fill="rgba(49,24,10,0)"/>
+ <circle cx="21" cy="73" r="1" fill="rgba(36,22,9,0)"/>
+ <circle cx="22" cy="73" r="1" fill="rgba(57,21,8,0)"/>
+ <circle cx="23" cy="73" r="1" fill="rgba(214,43,3,0)"/>
+ <circle cx="24" cy="73" r="1" fill="rgba(224,44,3,0)"/>
+ <circle cx="25" cy="73" r="1" fill="rgba(221,44,3,0)"/>
+ <circle cx="26" cy="73" r="1" fill="rgba(221,39,1,0.0745098)"/>
+ <circle cx="27" cy="73" r="1" fill="rgba(221,40,0,0.945098)"/>
+ <circle cx="28" cy="73" r="1" fill="rgba(226,61,9,1)"/>
+ <circle cx="29" cy="73" r="1" fill="rgba(229,67,10,1)"/>
+ <circle cx="30" cy="73" r="1" fill="rgba(229,59,4,1)"/>
+ <circle cx="31" cy="73" r="1" fill="rgba(227,46,0,1)"/>
+ <circle cx="32" cy="73" r="1" fill="rgba(225,39,0,1)"/>
+ <circle cx="33" cy="73" r="1" fill="rgba(224,38,0,1)"/>
+ <circle cx="34" cy="73" r="1" fill="rgba(224,38,0,1)"/>
+ <circle cx="35" cy="73" r="1" fill="rgba(224,37,0,1)"/>
+ <circle cx="36" cy="73" r="1" fill="rgba(225,37,0,1)"/>
+ <circle cx="37" cy="73" r="1" fill="rgba(226,39,0,1)"/>
+ <circle cx="38" cy="73" r="1" fill="rgba(227,40,0,1)"/>
+ <circle cx="39" cy="73" r="1" fill="rgba(227,39,0,1)"/>
+ <circle cx="40" cy="73" r="1" fill="rgba(227,40,0,1)"/>
+ <circle cx="41" cy="73" r="1" fill="rgba(227,40,0,1)"/>
+ <circle cx="42" cy="73" r="1" fill="rgba(227,40,0,1)"/>
+ <circle cx="43" cy="73" r="1" fill="rgba(227,40,0,1)"/>
+ <circle cx="44" cy="73" r="1" fill="rgba(227,39,0,1)"/>
+ <circle cx="45" cy="73" r="1" fill="rgba(226,39,0,1)"/>
+ <circle cx="46" cy="73" r="1" fill="rgba(226,38,0,1)"/>
+ <circle cx="47" cy="73" r="1" fill="rgba(225,36,0,1)"/>
+ <circle cx="48" cy="73" r="1" fill="rgba(224,37,0,1)"/>
+ <circle cx="49" cy="73" r="1" fill="rgba(224,36,0,1)"/>
+ <circle cx="50" cy="73" r="1" fill="rgba(223,35,0,1)"/>
+ <circle cx="51" cy="73" r="1" fill="rgba(221,33,0,1)"/>
+ <circle cx="52" cy="73" r="1" fill="rgba(221,32,0,1)"/>
+ <circle cx="53" cy="73" r="1" fill="rgba(220,31,0,1)"/>
+ <circle cx="54" cy="73" r="1" fill="rgba(218,30,0,1)"/>
+ <circle cx="55" cy="73" r="1" fill="rgba(218,30,0,1)"/>
+ <circle cx="56" cy="73" r="1" fill="rgba(217,29,0,1)"/>
+ <circle cx="57" cy="73" r="1" fill="rgba(217,26,0,1)"/>
+ <circle cx="58" cy="73" r="1" fill="rgba(215,26,0,1)"/>
+ <circle cx="59" cy="73" r="1" fill="rgba(214,25,0,1)"/>
+ <circle cx="60" cy="73" r="1" fill="rgba(213,24,0,1)"/>
+ <circle cx="61" cy="73" r="1" fill="rgba(211,23,0,1)"/>
+ <circle cx="62" cy="73" r="1" fill="rgba(210,22,0,1)"/>
+ <circle cx="63" cy="73" r="1" fill="rgba(207,20,0,1)"/>
+ <circle cx="64" cy="73" r="1" fill="rgba(205,16,0,1)"/>
+ <circle cx="65" cy="73" r="1" fill="rgba(169,18,2,1)"/>
+ <circle cx="66" cy="73" r="1" fill="rgba(154,25,5,1)"/>
+ <circle cx="67" cy="73" r="1" fill="rgba(200,17,0,1)"/>
+ <circle cx="68" cy="73" r="1" fill="rgba(199,21,1,1)"/>
+ <circle cx="69" cy="73" r="1" fill="rgba(203,24,2,1)"/>
+ <circle cx="70" cy="73" r="1" fill="rgba(207,26,4,1)"/>
+ <circle cx="71" cy="73" r="1" fill="rgba(208,28,5,1)"/>
+ <circle cx="72" cy="73" r="1" fill="rgba(207,25,6,1)"/>
+ <circle cx="73" cy="73" r="1" fill="rgba(204,22,6,1)"/>
+ <circle cx="74" cy="73" r="1" fill="rgba(202,22,5,1)"/>
+ <circle cx="75" cy="73" r="1" fill="rgba(201,22,5,1)"/>
+ <circle cx="76" cy="73" r="1" fill="rgba(200,22,5,1)"/>
+ <circle cx="77" cy="73" r="1" fill="rgba(200,23,5,1)"/>
+ <circle cx="78" cy="73" r="1" fill="rgba(201,24,6,1)"/>
+ <circle cx="79" cy="73" r="1" fill="rgba(202,27,6,1)"/>
+ <circle cx="80" cy="73" r="1" fill="rgba(203,30,8,1)"/>
+ <circle cx="81" cy="73" r="1" fill="rgba(204,33,9,1)"/>
+ <circle cx="82" cy="73" r="1" fill="rgba(206,36,10,1)"/>
+ <circle cx="83" cy="73" r="1" fill="rgba(207,40,12,1)"/>
+ <circle cx="84" cy="73" r="1" fill="rgba(207,44,13,1)"/>
+ <circle cx="85" cy="73" r="1" fill="rgba(208,48,15,1)"/>
+ <circle cx="86" cy="73" r="1" fill="rgba(210,50,17,1)"/>
+ <circle cx="87" cy="73" r="1" fill="rgba(212,54,19,1)"/>
+ <circle cx="88" cy="73" r="1" fill="rgba(214,60,21,1)"/>
+ <circle cx="89" cy="73" r="1" fill="rgba(215,65,23,1)"/>
+ <circle cx="90" cy="73" r="1" fill="rgba(217,69,26,1)"/>
+ <circle cx="91" cy="73" r="1" fill="rgba(219,74,29,1)"/>
+ <circle cx="92" cy="73" r="1" fill="rgba(221,81,32,1)"/>
+ <circle cx="93" cy="73" r="1" fill="rgba(223,86,36,1)"/>
+ <circle cx="94" cy="73" r="1" fill="rgba(226,93,39,1)"/>
+ <circle cx="95" cy="73" r="1" fill="rgba(228,99,42,1)"/>
+ <circle cx="96" cy="73" r="1" fill="rgba(230,106,47,1)"/>
+ <circle cx="97" cy="73" r="1" fill="rgba(233,112,51,1)"/>
+ <circle cx="98" cy="73" r="1" fill="rgba(234,118,55,1)"/>
+ <circle cx="99" cy="73" r="1" fill="rgba(236,123,57,1)"/>
+ <circle cx="100" cy="73" r="1" fill="rgba(238,126,59,1)"/>
+ <circle cx="101" cy="73" r="1" fill="rgba(240,128,58,1)"/>
+ <circle cx="102" cy="73" r="1" fill="rgba(241,122,53,1)"/>
+ <circle cx="103" cy="73" r="1" fill="rgba(121,42,12,0.768627)"/>
+ <circle cx="104" cy="73" r="1" fill="rgba(19,0,0,0.580392)"/>
+ <circle cx="105" cy="73" r="1" fill="rgba(21,1,0,0.505882)"/>
+ <circle cx="106" cy="73" r="1" fill="rgba(10,0,0,0.45098)"/>
+ <circle cx="107" cy="73" r="1" fill="rgba(4,0,0,0.419608)"/>
+ <circle cx="108" cy="73" r="1" fill="rgba(4,0,0,0.384314)"/>
+ <circle cx="109" cy="73" r="1" fill="rgba(10,3,0,0.352941)"/>
+ <circle cx="110" cy="73" r="1" fill="rgba(12,3,0,0.364706)"/>
+ <circle cx="111" cy="73" r="1" fill="rgba(7,1,0,0.419608)"/>
+ <circle cx="112" cy="73" r="1" fill="rgba(0,0,0,0.447059)"/>
+ <circle cx="113" cy="73" r="1" fill="rgba(0,0,0,0.392157)"/>
+ <circle cx="114" cy="73" r="1" fill="rgba(26,9,2,0.321569)"/>
+ <circle cx="115" cy="73" r="1" fill="rgba(39,18,6,0.196078)"/>
+ <circle cx="116" cy="73" r="1" fill="rgba(46,22,9,0.0823529)"/>
+ <circle cx="117" cy="73" r="1" fill="rgba(55,29,13,0.160784)"/>
+ <circle cx="118" cy="73" r="1" fill="rgba(73,42,21,0.411765)"/>
+ <circle cx="119" cy="73" r="1" fill="rgba(78,46,24,0.72549)"/>
+ <circle cx="120" cy="73" r="1" fill="rgba(80,47,24,0.996078)"/>
+ <circle cx="121" cy="73" r="1" fill="rgba(75,43,22,1)"/>
+ <circle cx="122" cy="73" r="1" fill="rgba(71,40,20,0.964706)"/>
+ <circle cx="123" cy="73" r="1" fill="rgba(67,36,17,0.4)"/>
+ <circle cx="124" cy="73" r="1" fill="rgba(62,31,14,0.0431373)"/>
+ <circle cx="125" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="73" r="1" fill="rgba(254,253,254,0)"/>
+ <circle cx="127" cy="73" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="74" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="74" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="74" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="19" cy="74" r="1" fill="rgba(46,21,8,0)"/>
+ <circle cx="20" cy="74" r="1" fill="rgba(45,24,10,0)"/>
+ <circle cx="21" cy="74" r="1" fill="rgba(50,22,9,0)"/>
+ <circle cx="22" cy="74" r="1" fill="rgba(173,29,2,0)"/>
+ <circle cx="23" cy="74" r="1" fill="rgba(221,33,0,0)"/>
+ <circle cx="24" cy="74" r="1" fill="rgba(217,33,0,0)"/>
+ <circle cx="25" cy="74" r="1" fill="rgba(217,33,0,0)"/>
+ <circle cx="26" cy="74" r="1" fill="rgba(217,34,0,0.0235294)"/>
+ <circle cx="27" cy="74" r="1" fill="rgba(217,36,0,0.835294)"/>
+ <circle cx="28" cy="74" r="1" fill="rgba(222,45,0,1)"/>
+ <circle cx="29" cy="74" r="1" fill="rgba(225,54,1,1)"/>
+ <circle cx="30" cy="74" r="1" fill="rgba(225,51,0,1)"/>
+ <circle cx="31" cy="74" r="1" fill="rgba(224,43,0,1)"/>
+ <circle cx="32" cy="74" r="1" fill="rgba(221,36,0,1)"/>
+ <circle cx="33" cy="74" r="1" fill="rgba(221,34,0,1)"/>
+ <circle cx="34" cy="74" r="1" fill="rgba(221,35,0,1)"/>
+ <circle cx="35" cy="74" r="1" fill="rgba(222,35,0,1)"/>
+ <circle cx="36" cy="74" r="1" fill="rgba(223,36,0,1)"/>
+ <circle cx="37" cy="74" r="1" fill="rgba(224,37,0,1)"/>
+ <circle cx="38" cy="74" r="1" fill="rgba(225,37,0,1)"/>
+ <circle cx="39" cy="74" r="1" fill="rgba(225,37,0,1)"/>
+ <circle cx="40" cy="74" r="1" fill="rgba(225,38,0,1)"/>
+ <circle cx="41" cy="74" r="1" fill="rgba(225,37,0,1)"/>
+ <circle cx="42" cy="74" r="1" fill="rgba(225,38,0,1)"/>
+ <circle cx="43" cy="74" r="1" fill="rgba(225,38,0,1)"/>
+ <circle cx="44" cy="74" r="1" fill="rgba(224,36,0,1)"/>
+ <circle cx="45" cy="74" r="1" fill="rgba(224,36,0,1)"/>
+ <circle cx="46" cy="74" r="1" fill="rgba(224,36,0,1)"/>
+ <circle cx="47" cy="74" r="1" fill="rgba(224,34,0,1)"/>
+ <circle cx="48" cy="74" r="1" fill="rgba(223,34,0,1)"/>
+ <circle cx="49" cy="74" r="1" fill="rgba(222,33,0,1)"/>
+ <circle cx="50" cy="74" r="1" fill="rgba(221,32,0,1)"/>
+ <circle cx="51" cy="74" r="1" fill="rgba(220,31,0,1)"/>
+ <circle cx="52" cy="74" r="1" fill="rgba(219,31,0,1)"/>
+ <circle cx="53" cy="74" r="1" fill="rgba(218,31,0,1)"/>
+ <circle cx="54" cy="74" r="1" fill="rgba(217,29,0,1)"/>
+ <circle cx="55" cy="74" r="1" fill="rgba(217,27,0,1)"/>
+ <circle cx="56" cy="74" r="1" fill="rgba(216,27,0,1)"/>
+ <circle cx="57" cy="74" r="1" fill="rgba(214,26,0,1)"/>
+ <circle cx="58" cy="74" r="1" fill="rgba(213,24,0,1)"/>
+ <circle cx="59" cy="74" r="1" fill="rgba(213,24,0,1)"/>
+ <circle cx="60" cy="74" r="1" fill="rgba(210,22,0,1)"/>
+ <circle cx="61" cy="74" r="1" fill="rgba(210,22,0,1)"/>
+ <circle cx="62" cy="74" r="1" fill="rgba(208,21,0,1)"/>
+ <circle cx="63" cy="74" r="1" fill="rgba(205,18,0,1)"/>
+ <circle cx="64" cy="74" r="1" fill="rgba(203,16,0,1)"/>
+ <circle cx="65" cy="74" r="1" fill="rgba(169,18,2,1)"/>
+ <circle cx="66" cy="74" r="1" fill="rgba(152,24,6,1)"/>
+ <circle cx="67" cy="74" r="1" fill="rgba(199,16,0,1)"/>
+ <circle cx="68" cy="74" r="1" fill="rgba(197,19,1,1)"/>
+ <circle cx="69" cy="74" r="1" fill="rgba(202,22,2,1)"/>
+ <circle cx="70" cy="74" r="1" fill="rgba(205,25,5,1)"/>
+ <circle cx="71" cy="74" r="1" fill="rgba(207,27,6,1)"/>
+ <circle cx="72" cy="74" r="1" fill="rgba(206,25,6,1)"/>
+ <circle cx="73" cy="74" r="1" fill="rgba(204,24,6,1)"/>
+ <circle cx="74" cy="74" r="1" fill="rgba(203,24,6,1)"/>
+ <circle cx="75" cy="74" r="1" fill="rgba(201,24,6,1)"/>
+ <circle cx="76" cy="74" r="1" fill="rgba(201,24,6,1)"/>
+ <circle cx="77" cy="74" r="1" fill="rgba(201,24,6,1)"/>
+ <circle cx="78" cy="74" r="1" fill="rgba(202,26,7,1)"/>
+ <circle cx="79" cy="74" r="1" fill="rgba(203,29,7,1)"/>
+ <circle cx="80" cy="74" r="1" fill="rgba(204,31,8,1)"/>
+ <circle cx="81" cy="74" r="1" fill="rgba(205,34,10,1)"/>
+ <circle cx="82" cy="74" r="1" fill="rgba(207,37,11,1)"/>
+ <circle cx="83" cy="74" r="1" fill="rgba(207,41,12,1)"/>
+ <circle cx="84" cy="74" r="1" fill="rgba(207,45,14,1)"/>
+ <circle cx="85" cy="74" r="1" fill="rgba(209,49,16,1)"/>
+ <circle cx="86" cy="74" r="1" fill="rgba(210,52,18,1)"/>
+ <circle cx="87" cy="74" r="1" fill="rgba(213,56,20,1)"/>
+ <circle cx="88" cy="74" r="1" fill="rgba(214,62,21,1)"/>
+ <circle cx="89" cy="74" r="1" fill="rgba(215,67,24,1)"/>
+ <circle cx="90" cy="74" r="1" fill="rgba(217,72,27,1)"/>
+ <circle cx="91" cy="74" r="1" fill="rgba(220,77,30,1)"/>
+ <circle cx="92" cy="74" r="1" fill="rgba(221,83,33,1)"/>
+ <circle cx="93" cy="74" r="1" fill="rgba(224,89,37,1)"/>
+ <circle cx="94" cy="74" r="1" fill="rgba(227,95,40,1)"/>
+ <circle cx="95" cy="74" r="1" fill="rgba(228,101,44,1)"/>
+ <circle cx="96" cy="74" r="1" fill="rgba(231,107,48,1)"/>
+ <circle cx="97" cy="74" r="1" fill="rgba(233,115,53,1)"/>
+ <circle cx="98" cy="74" r="1" fill="rgba(236,120,56,1)"/>
+ <circle cx="99" cy="74" r="1" fill="rgba(237,124,59,1)"/>
+ <circle cx="100" cy="74" r="1" fill="rgba(238,127,60,1)"/>
+ <circle cx="101" cy="74" r="1" fill="rgba(241,128,58,1)"/>
+ <circle cx="102" cy="74" r="1" fill="rgba(234,115,49,0.996078)"/>
+ <circle cx="103" cy="74" r="1" fill="rgba(91,24,6,0.72549)"/>
+ <circle cx="104" cy="74" r="1" fill="rgba(22,0,0,0.576471)"/>
+ <circle cx="105" cy="74" r="1" fill="rgba(19,1,0,0.498039)"/>
+ <circle cx="106" cy="74" r="1" fill="rgba(7,0,0,0.435294)"/>
+ <circle cx="107" cy="74" r="1" fill="rgba(0,0,0,0.396078)"/>
+ <circle cx="108" cy="74" r="1" fill="rgba(0,0,0,0.341176)"/>
+ <circle cx="109" cy="74" r="1" fill="rgba(7,0,0,0.27451)"/>
+ <circle cx="110" cy="74" r="1" fill="rgba(17,4,1,0.25098)"/>
+ <circle cx="111" cy="74" r="1" fill="rgba(19,5,1,0.305882)"/>
+ <circle cx="112" cy="74" r="1" fill="rgba(10,2,0,0.403922)"/>
+ <circle cx="113" cy="74" r="1" fill="rgba(0,0,0,0.458824)"/>
+ <circle cx="114" cy="74" r="1" fill="rgba(0,0,0,0.462745)"/>
+ <circle cx="115" cy="74" r="1" fill="rgba(7,1,0,0.435294)"/>
+ <circle cx="116" cy="74" r="1" fill="rgba(12,3,0,0.403922)"/>
+ <circle cx="117" cy="74" r="1" fill="rgba(17,5,1,0.368627)"/>
+ <circle cx="118" cy="74" r="1" fill="rgba(36,15,5,0.156863)"/>
+ <circle cx="119" cy="74" r="1" fill="rgba(26,10,3,0.105882)"/>
+ <circle cx="120" cy="74" r="1" fill="rgba(54,27,11,0.45098)"/>
+ <circle cx="121" cy="74" r="1" fill="rgba(70,39,19,0.933333)"/>
+ <circle cx="122" cy="74" r="1" fill="rgba(70,38,18,1)"/>
+ <circle cx="123" cy="74" r="1" fill="rgba(67,35,16,1)"/>
+ <circle cx="124" cy="74" r="1" fill="rgba(62,31,14,0.870588)"/>
+ <circle cx="125" cy="74" r="1" fill="rgba(61,30,13,0.458824)"/>
+ <circle cx="126" cy="74" r="1" fill="rgba(61,30,13,0.101961)"/>
+ <circle cx="127" cy="74" r="1" fill="rgba(253,252,252,0)"/>
+ <circle cx="0" cy="75" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="75" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="75" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="19" cy="75" r="1" fill="rgba(46,21,8,0)"/>
+ <circle cx="20" cy="75" r="1" fill="rgba(29,24,10,0)"/>
+ <circle cx="21" cy="75" r="1" fill="rgba(142,27,4,0)"/>
+ <circle cx="22" cy="75" r="1" fill="rgba(227,32,0,0)"/>
+ <circle cx="23" cy="75" r="1" fill="rgba(214,31,0,0)"/>
+ <circle cx="24" cy="75" r="1" fill="rgba(214,31,0,0)"/>
+ <circle cx="25" cy="75" r="1" fill="rgba(214,31,0,0)"/>
+ <circle cx="26" cy="75" r="1" fill="rgba(214,31,0,0)"/>
+ <circle cx="27" cy="75" r="1" fill="rgba(215,32,0,0.682353)"/>
+ <circle cx="28" cy="75" r="1" fill="rgba(220,41,0,1)"/>
+ <circle cx="29" cy="75" r="1" fill="rgba(224,51,0,1)"/>
+ <circle cx="30" cy="75" r="1" fill="rgba(224,50,0,1)"/>
+ <circle cx="31" cy="75" r="1" fill="rgba(221,42,0,1)"/>
+ <circle cx="32" cy="75" r="1" fill="rgba(220,35,0,1)"/>
+ <circle cx="33" cy="75" r="1" fill="rgba(219,32,0,1)"/>
+ <circle cx="34" cy="75" r="1" fill="rgba(220,33,0,1)"/>
+ <circle cx="35" cy="75" r="1" fill="rgba(221,33,0,1)"/>
+ <circle cx="36" cy="75" r="1" fill="rgba(221,35,0,1)"/>
+ <circle cx="37" cy="75" r="1" fill="rgba(222,36,0,1)"/>
+ <circle cx="38" cy="75" r="1" fill="rgba(223,36,0,1)"/>
+ <circle cx="39" cy="75" r="1" fill="rgba(223,36,0,1)"/>
+ <circle cx="40" cy="75" r="1" fill="rgba(223,36,0,1)"/>
+ <circle cx="41" cy="75" r="1" fill="rgba(223,34,0,1)"/>
+ <circle cx="42" cy="75" r="1" fill="rgba(223,35,0,1)"/>
+ <circle cx="43" cy="75" r="1" fill="rgba(223,35,0,1)"/>
+ <circle cx="44" cy="75" r="1" fill="rgba(222,34,0,1)"/>
+ <circle cx="45" cy="75" r="1" fill="rgba(221,34,0,1)"/>
+ <circle cx="46" cy="75" r="1" fill="rgba(221,33,0,1)"/>
+ <circle cx="47" cy="75" r="1" fill="rgba(221,33,0,1)"/>
+ <circle cx="48" cy="75" r="1" fill="rgba(221,32,0,1)"/>
+ <circle cx="49" cy="75" r="1" fill="rgba(220,31,0,1)"/>
+ <circle cx="50" cy="75" r="1" fill="rgba(219,31,0,1)"/>
+ <circle cx="51" cy="75" r="1" fill="rgba(218,31,0,1)"/>
+ <circle cx="52" cy="75" r="1" fill="rgba(217,30,0,1)"/>
+ <circle cx="53" cy="75" r="1" fill="rgba(217,28,0,1)"/>
+ <circle cx="54" cy="75" r="1" fill="rgba(217,27,0,1)"/>
+ <circle cx="55" cy="75" r="1" fill="rgba(215,26,0,1)"/>
+ <circle cx="56" cy="75" r="1" fill="rgba(214,25,0,1)"/>
+ <circle cx="57" cy="75" r="1" fill="rgba(213,25,0,1)"/>
+ <circle cx="58" cy="75" r="1" fill="rgba(212,23,0,1)"/>
+ <circle cx="59" cy="75" r="1" fill="rgba(210,22,0,1)"/>
+ <circle cx="60" cy="75" r="1" fill="rgba(210,22,0,1)"/>
+ <circle cx="61" cy="75" r="1" fill="rgba(209,20,0,1)"/>
+ <circle cx="62" cy="75" r="1" fill="rgba(207,19,0,1)"/>
+ <circle cx="63" cy="75" r="1" fill="rgba(203,18,0,1)"/>
+ <circle cx="64" cy="75" r="1" fill="rgba(202,15,0,1)"/>
+ <circle cx="65" cy="75" r="1" fill="rgba(168,17,2,1)"/>
+ <circle cx="66" cy="75" r="1" fill="rgba(150,22,5,1)"/>
+ <circle cx="67" cy="75" r="1" fill="rgba(196,14,1,1)"/>
+ <circle cx="68" cy="75" r="1" fill="rgba(196,18,2,1)"/>
+ <circle cx="69" cy="75" r="1" fill="rgba(200,21,3,1)"/>
+ <circle cx="70" cy="75" r="1" fill="rgba(204,24,5,1)"/>
+ <circle cx="71" cy="75" r="1" fill="rgba(206,26,6,1)"/>
+ <circle cx="72" cy="75" r="1" fill="rgba(206,25,7,1)"/>
+ <circle cx="73" cy="75" r="1" fill="rgba(205,26,7,1)"/>
+ <circle cx="74" cy="75" r="1" fill="rgba(203,26,6,1)"/>
+ <circle cx="75" cy="75" r="1" fill="rgba(202,25,6,1)"/>
+ <circle cx="76" cy="75" r="1" fill="rgba(202,25,6,1)"/>
+ <circle cx="77" cy="75" r="1" fill="rgba(203,26,7,1)"/>
+ <circle cx="78" cy="75" r="1" fill="rgba(207,29,7,1)"/>
+ <circle cx="79" cy="75" r="1" fill="rgba(213,32,9,1)"/>
+ <circle cx="80" cy="75" r="1" fill="rgba(214,35,10,1)"/>
+ <circle cx="81" cy="75" r="1" fill="rgba(209,36,11,1)"/>
+ <circle cx="82" cy="75" r="1" fill="rgba(207,38,11,1)"/>
+ <circle cx="83" cy="75" r="1" fill="rgba(207,42,13,1)"/>
+ <circle cx="84" cy="75" r="1" fill="rgba(207,46,14,1)"/>
+ <circle cx="85" cy="75" r="1" fill="rgba(210,50,16,1)"/>
+ <circle cx="86" cy="75" r="1" fill="rgba(211,54,19,1)"/>
+ <circle cx="87" cy="75" r="1" fill="rgba(214,59,20,1)"/>
+ <circle cx="88" cy="75" r="1" fill="rgba(215,64,23,1)"/>
+ <circle cx="89" cy="75" r="1" fill="rgba(217,69,26,1)"/>
+ <circle cx="90" cy="75" r="1" fill="rgba(218,74,28,1)"/>
+ <circle cx="91" cy="75" r="1" fill="rgba(221,80,31,1)"/>
+ <circle cx="92" cy="75" r="1" fill="rgba(222,84,34,1)"/>
+ <circle cx="93" cy="75" r="1" fill="rgba(224,92,37,1)"/>
+ <circle cx="94" cy="75" r="1" fill="rgba(227,96,42,1)"/>
+ <circle cx="95" cy="75" r="1" fill="rgba(229,104,45,1)"/>
+ <circle cx="96" cy="75" r="1" fill="rgba(232,110,49,1)"/>
+ <circle cx="97" cy="75" r="1" fill="rgba(234,117,54,1)"/>
+ <circle cx="98" cy="75" r="1" fill="rgba(236,122,57,1)"/>
+ <circle cx="99" cy="75" r="1" fill="rgba(237,125,60,1)"/>
+ <circle cx="100" cy="75" r="1" fill="rgba(239,129,60,1)"/>
+ <circle cx="101" cy="75" r="1" fill="rgba(242,127,58,1)"/>
+ <circle cx="102" cy="75" r="1" fill="rgba(223,103,42,0.972549)"/>
+ <circle cx="103" cy="75" r="1" fill="rgba(59,10,2,0.686275)"/>
+ <circle cx="104" cy="75" r="1" fill="rgba(28,1,0,0.568627)"/>
+ <circle cx="105" cy="75" r="1" fill="rgba(19,1,0,0.482353)"/>
+ <circle cx="106" cy="75" r="1" fill="rgba(4,0,0,0.423529)"/>
+ <circle cx="107" cy="75" r="1" fill="rgba(0,0,0,0.368627)"/>
+ <circle cx="108" cy="75" r="1" fill="rgba(0,0,0,0.298039)"/>
+ <circle cx="109" cy="75" r="1" fill="rgba(0,0,0,0.211765)"/>
+ <circle cx="110" cy="75" r="1" fill="rgba(10,2,0,0.14902)"/>
+ <circle cx="111" cy="75" r="1" fill="rgba(26,8,2,0.156863)"/>
+ <circle cx="112" cy="75" r="1" fill="rgba(24,8,2,0.25098)"/>
+ <circle cx="113" cy="75" r="1" fill="rgba(15,3,0,0.384314)"/>
+ <circle cx="114" cy="75" r="1" fill="rgba(4,0,0,0.458824)"/>
+ <circle cx="115" cy="75" r="1" fill="rgba(0,0,0,0.47451)"/>
+ <circle cx="116" cy="75" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="117" cy="75" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="118" cy="75" r="1" fill="rgba(4,0,0,0.462745)"/>
+ <circle cx="119" cy="75" r="1" fill="rgba(0,0,0,0.443137)"/>
+ <circle cx="120" cy="75" r="1" fill="rgba(4,0,0,0.427451)"/>
+ <circle cx="121" cy="75" r="1" fill="rgba(26,9,2,0.533333)"/>
+ <circle cx="122" cy="75" r="1" fill="rgba(36,14,4,0.627451)"/>
+ <circle cx="123" cy="75" r="1" fill="rgba(42,17,6,0.694118)"/>
+ <circle cx="124" cy="75" r="1" fill="rgba(53,25,10,0.819608)"/>
+ <circle cx="125" cy="75" r="1" fill="rgba(58,29,13,0.996078)"/>
+ <circle cx="126" cy="75" r="1" fill="rgba(62,31,14,0.913725)"/>
+ <circle cx="127" cy="75" r="1" fill="rgba(62,31,14,0.584314)"/>
+ <circle cx="0" cy="76" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="76" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="76" r="1" fill="rgba(42,19,7,0)"/>
+ <circle cx="19" cy="76" r="1" fill="rgba(39,21,8,0)"/>
+ <circle cx="20" cy="76" r="1" fill="rgba(59,24,9,0)"/>
+ <circle cx="21" cy="76" r="1" fill="rgba(203,29,0,0)"/>
+ <circle cx="22" cy="76" r="1" fill="rgba(215,29,0,0)"/>
+ <circle cx="23" cy="76" r="1" fill="rgba(212,29,0,0)"/>
+ <circle cx="24" cy="76" r="1" fill="rgba(212,29,0,0)"/>
+ <circle cx="25" cy="76" r="1" fill="rgba(212,29,0,0)"/>
+ <circle cx="26" cy="76" r="1" fill="rgba(212,29,0,0)"/>
+ <circle cx="27" cy="76" r="1" fill="rgba(213,30,0,0.541176)"/>
+ <circle cx="28" cy="76" r="1" fill="rgba(217,38,0,1)"/>
+ <circle cx="29" cy="76" r="1" fill="rgba(221,48,1,1)"/>
+ <circle cx="30" cy="76" r="1" fill="rgba(223,49,1,1)"/>
+ <circle cx="31" cy="76" r="1" fill="rgba(221,42,0,1)"/>
+ <circle cx="32" cy="76" r="1" fill="rgba(219,35,0,1)"/>
+ <circle cx="33" cy="76" r="1" fill="rgba(218,32,0,1)"/>
+ <circle cx="34" cy="76" r="1" fill="rgba(219,33,0,1)"/>
+ <circle cx="35" cy="76" r="1" fill="rgba(220,33,0,1)"/>
+ <circle cx="36" cy="76" r="1" fill="rgba(221,33,0,1)"/>
+ <circle cx="37" cy="76" r="1" fill="rgba(221,34,0,1)"/>
+ <circle cx="38" cy="76" r="1" fill="rgba(222,34,0,1)"/>
+ <circle cx="39" cy="76" r="1" fill="rgba(222,34,0,1)"/>
+ <circle cx="40" cy="76" r="1" fill="rgba(221,34,0,1)"/>
+ <circle cx="41" cy="76" r="1" fill="rgba(221,33,0,1)"/>
+ <circle cx="42" cy="76" r="1" fill="rgba(221,33,0,1)"/>
+ <circle cx="43" cy="76" r="1" fill="rgba(221,33,0,1)"/>
+ <circle cx="44" cy="76" r="1" fill="rgba(221,33,0,1)"/>
+ <circle cx="45" cy="76" r="1" fill="rgba(220,32,0,1)"/>
+ <circle cx="46" cy="76" r="1" fill="rgba(220,32,0,1)"/>
+ <circle cx="47" cy="76" r="1" fill="rgba(219,32,0,1)"/>
+ <circle cx="48" cy="76" r="1" fill="rgba(219,31,0,1)"/>
+ <circle cx="49" cy="76" r="1" fill="rgba(219,30,0,1)"/>
+ <circle cx="50" cy="76" r="1" fill="rgba(217,30,0,1)"/>
+ <circle cx="51" cy="76" r="1" fill="rgba(217,28,0,1)"/>
+ <circle cx="52" cy="76" r="1" fill="rgba(217,27,0,1)"/>
+ <circle cx="53" cy="76" r="1" fill="rgba(216,26,0,1)"/>
+ <circle cx="54" cy="76" r="1" fill="rgba(214,26,0,1)"/>
+ <circle cx="55" cy="76" r="1" fill="rgba(213,24,0,1)"/>
+ <circle cx="56" cy="76" r="1" fill="rgba(213,24,0,1)"/>
+ <circle cx="57" cy="76" r="1" fill="rgba(211,23,0,1)"/>
+ <circle cx="58" cy="76" r="1" fill="rgba(210,22,0,1)"/>
+ <circle cx="59" cy="76" r="1" fill="rgba(209,21,0,1)"/>
+ <circle cx="60" cy="76" r="1" fill="rgba(209,20,0,1)"/>
+ <circle cx="61" cy="76" r="1" fill="rgba(207,20,0,1)"/>
+ <circle cx="62" cy="76" r="1" fill="rgba(206,19,0,1)"/>
+ <circle cx="63" cy="76" r="1" fill="rgba(202,17,0,1)"/>
+ <circle cx="64" cy="76" r="1" fill="rgba(201,14,0,1)"/>
+ <circle cx="65" cy="76" r="1" fill="rgba(166,16,1,1)"/>
+ <circle cx="66" cy="76" r="1" fill="rgba(148,20,5,1)"/>
+ <circle cx="67" cy="76" r="1" fill="rgba(195,13,1,1)"/>
+ <circle cx="68" cy="76" r="1" fill="rgba(193,16,2,1)"/>
+ <circle cx="69" cy="76" r="1" fill="rgba(199,20,3,1)"/>
+ <circle cx="70" cy="76" r="1" fill="rgba(202,22,5,1)"/>
+ <circle cx="71" cy="76" r="1" fill="rgba(205,25,7,1)"/>
+ <circle cx="72" cy="76" r="1" fill="rgba(206,26,7,1)"/>
+ <circle cx="73" cy="76" r="1" fill="rgba(205,27,7,1)"/>
+ <circle cx="74" cy="76" r="1" fill="rgba(203,27,7,1)"/>
+ <circle cx="75" cy="76" r="1" fill="rgba(203,26,7,1)"/>
+ <circle cx="76" cy="76" r="1" fill="rgba(207,27,7,1)"/>
+ <circle cx="77" cy="76" r="1" fill="rgba(207,28,7,1)"/>
+ <circle cx="78" cy="76" r="1" fill="rgba(175,23,6,1)"/>
+ <circle cx="79" cy="76" r="1" fill="rgba(131,17,3,1)"/>
+ <circle cx="80" cy="76" r="1" fill="rgba(128,17,4,1)"/>
+ <circle cx="81" cy="76" r="1" fill="rgba(188,33,9,1)"/>
+ <circle cx="82" cy="76" r="1" fill="rgba(210,41,13,1)"/>
+ <circle cx="83" cy="76" r="1" fill="rgba(207,44,14,1)"/>
+ <circle cx="84" cy="76" r="1" fill="rgba(209,49,16,1)"/>
+ <circle cx="85" cy="76" r="1" fill="rgba(211,52,18,1)"/>
+ <circle cx="86" cy="76" r="1" fill="rgba(213,56,20,1)"/>
+ <circle cx="87" cy="76" r="1" fill="rgba(214,61,22,1)"/>
+ <circle cx="88" cy="76" r="1" fill="rgba(216,66,24,1)"/>
+ <circle cx="89" cy="76" r="1" fill="rgba(217,71,27,1)"/>
+ <circle cx="90" cy="76" r="1" fill="rgba(220,76,30,1)"/>
+ <circle cx="91" cy="76" r="1" fill="rgba(221,82,33,1)"/>
+ <circle cx="92" cy="76" r="1" fill="rgba(223,87,36,1)"/>
+ <circle cx="93" cy="76" r="1" fill="rgba(226,93,40,1)"/>
+ <circle cx="94" cy="76" r="1" fill="rgba(227,100,43,1)"/>
+ <circle cx="95" cy="76" r="1" fill="rgba(230,105,48,1)"/>
+ <circle cx="96" cy="76" r="1" fill="rgba(233,113,51,1)"/>
+ <circle cx="97" cy="76" r="1" fill="rgba(236,118,56,1)"/>
+ <circle cx="98" cy="76" r="1" fill="rgba(237,124,58,1)"/>
+ <circle cx="99" cy="76" r="1" fill="rgba(238,127,61,1)"/>
+ <circle cx="100" cy="76" r="1" fill="rgba(239,129,60,1)"/>
+ <circle cx="101" cy="76" r="1" fill="rgba(244,126,56,1)"/>
+ <circle cx="102" cy="76" r="1" fill="rgba(202,88,33,0.929412)"/>
+ <circle cx="103" cy="76" r="1" fill="rgba(46,6,1,0.666667)"/>
+ <circle cx="104" cy="76" r="1" fill="rgba(28,2,0,0.560784)"/>
+ <circle cx="105" cy="76" r="1" fill="rgba(17,0,0,0.466667)"/>
+ <circle cx="106" cy="76" r="1" fill="rgba(4,0,0,0.4)"/>
+ <circle cx="107" cy="76" r="1" fill="rgba(0,0,0,0.345098)"/>
+ <circle cx="108" cy="76" r="1" fill="rgba(0,0,0,0.266667)"/>
+ <circle cx="109" cy="76" r="1" fill="rgba(0,0,0,0.172549)"/>
+ <circle cx="110" cy="76" r="1" fill="rgba(0,0,0,0.0980392)"/>
+ <circle cx="111" cy="76" r="1" fill="rgba(17,6,1,0.0588235)"/>
+ <circle cx="112" cy="76" r="1" fill="rgba(31,13,6,0.0823529)"/>
+ <circle cx="113" cy="76" r="1" fill="rgba(31,12,4,0.168627)"/>
+ <circle cx="114" cy="76" r="1" fill="rgba(24,9,2,0.278431)"/>
+ <circle cx="115" cy="76" r="1" fill="rgba(19,5,1,0.356863)"/>
+ <circle cx="116" cy="76" r="1" fill="rgba(12,3,0,0.407843)"/>
+ <circle cx="117" cy="76" r="1" fill="rgba(15,4,0,0.407843)"/>
+ <circle cx="118" cy="76" r="1" fill="rgba(22,8,2,0.345098)"/>
+ <circle cx="119" cy="76" r="1" fill="rgba(24,9,2,0.286275)"/>
+ <circle cx="120" cy="76" r="1" fill="rgba(19,5,1,0.301961)"/>
+ <circle cx="121" cy="76" r="1" fill="rgba(17,3,0,0.333333)"/>
+ <circle cx="122" cy="76" r="1" fill="rgba(4,0,0,0.4)"/>
+ <circle cx="123" cy="76" r="1" fill="rgba(4,0,0,0.380392)"/>
+ <circle cx="124" cy="76" r="1" fill="rgba(15,3,0,0.352941)"/>
+ <circle cx="125" cy="76" r="1" fill="rgba(22,6,1,0.4)"/>
+ <circle cx="126" cy="76" r="1" fill="rgba(39,16,5,0.533333)"/>
+ <circle cx="127" cy="76" r="1" fill="rgba(57,27,11,0.701961)"/>
+ <circle cx="0" cy="77" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="77" r="1" fill="rgba(40,19,7,0)"/>
+ <circle cx="19" cy="77" r="1" fill="rgba(37,21,8,0)"/>
+ <circle cx="20" cy="77" r="1" fill="rgba(169,27,2,0)"/>
+ <circle cx="21" cy="77" r="1" fill="rgba(217,29,0,0)"/>
+ <circle cx="22" cy="77" r="1" fill="rgba(211,29,0,0)"/>
+ <circle cx="23" cy="77" r="1" fill="rgba(211,29,0,0)"/>
+ <circle cx="24" cy="77" r="1" fill="rgba(211,29,0,0)"/>
+ <circle cx="25" cy="77" r="1" fill="rgba(211,29,0,0)"/>
+ <circle cx="26" cy="77" r="1" fill="rgba(211,29,0,0)"/>
+ <circle cx="27" cy="77" r="1" fill="rgba(211,29,0,0.34902)"/>
+ <circle cx="28" cy="77" r="1" fill="rgba(214,33,0,1)"/>
+ <circle cx="29" cy="77" r="1" fill="rgba(219,44,1,1)"/>
+ <circle cx="30" cy="77" r="1" fill="rgba(221,48,1,1)"/>
+ <circle cx="31" cy="77" r="1" fill="rgba(220,43,0,1)"/>
+ <circle cx="32" cy="77" r="1" fill="rgba(217,34,0,1)"/>
+ <circle cx="33" cy="77" r="1" fill="rgba(217,32,0,1)"/>
+ <circle cx="34" cy="77" r="1" fill="rgba(217,31,0,1)"/>
+ <circle cx="35" cy="77" r="1" fill="rgba(219,31,0,1)"/>
+ <circle cx="36" cy="77" r="1" fill="rgba(220,32,0,1)"/>
+ <circle cx="37" cy="77" r="1" fill="rgba(221,32,0,1)"/>
+ <circle cx="38" cy="77" r="1" fill="rgba(220,32,0,1)"/>
+ <circle cx="39" cy="77" r="1" fill="rgba(220,31,0,1)"/>
+ <circle cx="40" cy="77" r="1" fill="rgba(220,31,0,1)"/>
+ <circle cx="41" cy="77" r="1" fill="rgba(220,31,0,1)"/>
+ <circle cx="42" cy="77" r="1" fill="rgba(220,31,0,1)"/>
+ <circle cx="43" cy="77" r="1" fill="rgba(220,32,0,1)"/>
+ <circle cx="44" cy="77" r="1" fill="rgba(219,32,0,1)"/>
+ <circle cx="45" cy="77" r="1" fill="rgba(218,31,0,1)"/>
+ <circle cx="46" cy="77" r="1" fill="rgba(218,30,0,1)"/>
+ <circle cx="47" cy="77" r="1" fill="rgba(217,29,0,1)"/>
+ <circle cx="48" cy="77" r="1" fill="rgba(218,28,0,1)"/>
+ <circle cx="49" cy="77" r="1" fill="rgba(217,28,0,1)"/>
+ <circle cx="50" cy="77" r="1" fill="rgba(217,28,0,1)"/>
+ <circle cx="51" cy="77" r="1" fill="rgba(216,26,0,1)"/>
+ <circle cx="52" cy="77" r="1" fill="rgba(214,26,0,1)"/>
+ <circle cx="53" cy="77" r="1" fill="rgba(214,25,0,1)"/>
+ <circle cx="54" cy="77" r="1" fill="rgba(212,24,0,1)"/>
+ <circle cx="55" cy="77" r="1" fill="rgba(212,23,0,1)"/>
+ <circle cx="56" cy="77" r="1" fill="rgba(210,22,0,1)"/>
+ <circle cx="57" cy="77" r="1" fill="rgba(209,22,0,1)"/>
+ <circle cx="58" cy="77" r="1" fill="rgba(209,21,0,1)"/>
+ <circle cx="59" cy="77" r="1" fill="rgba(208,20,0,1)"/>
+ <circle cx="60" cy="77" r="1" fill="rgba(207,19,0,1)"/>
+ <circle cx="61" cy="77" r="1" fill="rgba(206,18,0,1)"/>
+ <circle cx="62" cy="77" r="1" fill="rgba(203,18,0,1)"/>
+ <circle cx="63" cy="77" r="1" fill="rgba(201,16,0,1)"/>
+ <circle cx="64" cy="77" r="1" fill="rgba(200,13,0,1)"/>
+ <circle cx="65" cy="77" r="1" fill="rgba(165,14,1,1)"/>
+ <circle cx="66" cy="77" r="1" fill="rgba(146,18,4,1)"/>
+ <circle cx="67" cy="77" r="1" fill="rgba(192,12,1,1)"/>
+ <circle cx="68" cy="77" r="1" fill="rgba(192,15,2,1)"/>
+ <circle cx="69" cy="77" r="1" fill="rgba(197,18,3,1)"/>
+ <circle cx="70" cy="77" r="1" fill="rgba(201,21,5,1)"/>
+ <circle cx="71" cy="77" r="1" fill="rgba(204,26,7,1)"/>
+ <circle cx="72" cy="77" r="1" fill="rgba(205,28,8,1)"/>
+ <circle cx="73" cy="77" r="1" fill="rgba(205,28,8,1)"/>
+ <circle cx="74" cy="77" r="1" fill="rgba(204,28,7,1)"/>
+ <circle cx="75" cy="77" r="1" fill="rgba(210,29,8,1)"/>
+ <circle cx="76" cy="77" r="1" fill="rgba(180,23,6,1)"/>
+ <circle cx="77" cy="77" r="1" fill="rgba(92,9,1,1)"/>
+ <circle cx="78" cy="77" r="1" fill="rgba(15,1,0,1)"/>
+ <circle cx="79" cy="77" r="1" fill="black"/>
+ <circle cx="80" cy="77" r="1" fill="black"/>
+ <circle cx="81" cy="77" r="1" fill="rgba(75,11,2,1)"/>
+ <circle cx="82" cy="77" r="1" fill="rgba(204,42,13,1)"/>
+ <circle cx="83" cy="77" r="1" fill="rgba(210,47,15,1)"/>
+ <circle cx="84" cy="77" r="1" fill="rgba(210,50,17,1)"/>
+ <circle cx="85" cy="77" r="1" fill="rgba(212,54,19,1)"/>
+ <circle cx="86" cy="77" r="1" fill="rgba(214,59,20,1)"/>
+ <circle cx="87" cy="77" r="1" fill="rgba(215,63,22,1)"/>
+ <circle cx="88" cy="77" r="1" fill="rgba(216,68,24,1)"/>
+ <circle cx="89" cy="77" r="1" fill="rgba(218,73,27,1)"/>
+ <circle cx="90" cy="77" r="1" fill="rgba(220,78,30,1)"/>
+ <circle cx="91" cy="77" r="1" fill="rgba(222,84,33,1)"/>
+ <circle cx="92" cy="77" r="1" fill="rgba(224,90,37,1)"/>
+ <circle cx="93" cy="77" r="1" fill="rgba(227,96,42,1)"/>
+ <circle cx="94" cy="77" r="1" fill="rgba(229,103,45,1)"/>
+ <circle cx="95" cy="77" r="1" fill="rgba(231,108,49,1)"/>
+ <circle cx="96" cy="77" r="1" fill="rgba(233,115,54,1)"/>
+ <circle cx="97" cy="77" r="1" fill="rgba(236,121,57,1)"/>
+ <circle cx="98" cy="77" r="1" fill="rgba(237,126,60,1)"/>
+ <circle cx="99" cy="77" r="1" fill="rgba(239,128,62,1)"/>
+ <circle cx="100" cy="77" r="1" fill="rgba(239,129,59,1)"/>
+ <circle cx="101" cy="77" r="1" fill="rgba(247,124,54,1)"/>
+ <circle cx="102" cy="77" r="1" fill="rgba(166,64,21,0.87451)"/>
+ <circle cx="103" cy="77" r="1" fill="rgba(28,0,0,0.639216)"/>
+ <circle cx="104" cy="77" r="1" fill="rgba(29,2,0,0.545098)"/>
+ <circle cx="105" cy="77" r="1" fill="rgba(17,0,0,0.45098)"/>
+ <circle cx="106" cy="77" r="1" fill="rgba(4,0,0,0.380392)"/>
+ <circle cx="107" cy="77" r="1" fill="rgba(0,0,0,0.317647)"/>
+ <circle cx="108" cy="77" r="1" fill="rgba(0,0,0,0.239216)"/>
+ <circle cx="109" cy="77" r="1" fill="rgba(0,0,0,0.14902)"/>
+ <circle cx="110" cy="77" r="1" fill="rgba(0,0,0,0.0705882)"/>
+ <circle cx="111" cy="77" r="1" fill="rgba(0,0,0,0.0235294)"/>
+ <circle cx="112" cy="77" r="1" fill="rgba(19,7,3,0.00784314)"/>
+ <circle cx="113" cy="77" r="1" fill="rgba(33,16,4,0.0117647)"/>
+ <circle cx="114" cy="77" r="1" fill="rgba(43,21,7,0.027451)"/>
+ <circle cx="115" cy="77" r="1" fill="rgba(39,17,6,0.054902)"/>
+ <circle cx="116" cy="77" r="1" fill="rgba(36,15,5,0.0901961)"/>
+ <circle cx="117" cy="77" r="1" fill="rgba(42,19,7,0.0784314)"/>
+ <circle cx="118" cy="77" r="1" fill="rgba(39,18,6,0.0196078)"/>
+ <circle cx="119" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="77" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="77" r="1" fill="rgba(36,15,5,0.0313725)"/>
+ <circle cx="122" cy="77" r="1" fill="rgba(33,13,4,0.0980392)"/>
+ <circle cx="123" cy="77" r="1" fill="rgba(24,7,2,0.0784314)"/>
+ <circle cx="124" cy="77" r="1" fill="rgba(26,7,2,0.0431373)"/>
+ <circle cx="125" cy="77" r="1" fill="rgba(24,7,2,0.0313725)"/>
+ <circle cx="126" cy="77" r="1" fill="rgba(254,254,253,0)"/>
+ <circle cx="127" cy="77" r="1" fill="rgba(253,253,252,0)"/>
+ <circle cx="0" cy="78" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="78" r="1" fill="rgba(24,19,8,0)"/>
+ <circle cx="19" cy="78" r="1" fill="rgba(97,21,5,0)"/>
+ <circle cx="20" cy="78" r="1" fill="rgba(217,27,0,0)"/>
+ <circle cx="21" cy="78" r="1" fill="rgba(211,27,0,0)"/>
+ <circle cx="22" cy="78" r="1" fill="rgba(210,27,0,0)"/>
+ <circle cx="23" cy="78" r="1" fill="rgba(210,27,0,0)"/>
+ <circle cx="24" cy="78" r="1" fill="rgba(210,27,0,0)"/>
+ <circle cx="25" cy="78" r="1" fill="rgba(210,27,0,0)"/>
+ <circle cx="26" cy="78" r="1" fill="rgba(210,27,0,0)"/>
+ <circle cx="27" cy="78" r="1" fill="rgba(210,27,0,0.156863)"/>
+ <circle cx="28" cy="78" r="1" fill="rgba(212,31,0,0.976471)"/>
+ <circle cx="29" cy="78" r="1" fill="rgba(217,40,0,1)"/>
+ <circle cx="30" cy="78" r="1" fill="rgba(220,45,1,1)"/>
+ <circle cx="31" cy="78" r="1" fill="rgba(219,43,1,1)"/>
+ <circle cx="32" cy="78" r="1" fill="rgba(217,35,0,1)"/>
+ <circle cx="33" cy="78" r="1" fill="rgba(215,30,0,1)"/>
+ <circle cx="34" cy="78" r="1" fill="rgba(216,30,0,1)"/>
+ <circle cx="35" cy="78" r="1" fill="rgba(217,30,0,1)"/>
+ <circle cx="36" cy="78" r="1" fill="rgba(217,30,0,1)"/>
+ <circle cx="37" cy="78" r="1" fill="rgba(218,31,0,1)"/>
+ <circle cx="38" cy="78" r="1" fill="rgba(218,31,0,1)"/>
+ <circle cx="39" cy="78" r="1" fill="rgba(218,30,0,1)"/>
+ <circle cx="40" cy="78" r="1" fill="rgba(217,30,0,1)"/>
+ <circle cx="41" cy="78" r="1" fill="rgba(217,29,0,1)"/>
+ <circle cx="42" cy="78" r="1" fill="rgba(217,29,0,1)"/>
+ <circle cx="43" cy="78" r="1" fill="rgba(217,30,0,1)"/>
+ <circle cx="44" cy="78" r="1" fill="rgba(217,30,0,1)"/>
+ <circle cx="45" cy="78" r="1" fill="rgba(217,29,0,1)"/>
+ <circle cx="46" cy="78" r="1" fill="rgba(216,28,0,1)"/>
+ <circle cx="47" cy="78" r="1" fill="rgba(216,27,0,1)"/>
+ <circle cx="48" cy="78" r="1" fill="rgba(216,27,0,1)"/>
+ <circle cx="49" cy="78" r="1" fill="rgba(215,26,0,1)"/>
+ <circle cx="50" cy="78" r="1" fill="rgba(214,26,0,1)"/>
+ <circle cx="51" cy="78" r="1" fill="rgba(214,25,0,1)"/>
+ <circle cx="52" cy="78" r="1" fill="rgba(213,24,0,1)"/>
+ <circle cx="53" cy="78" r="1" fill="rgba(211,23,0,1)"/>
+ <circle cx="54" cy="78" r="1" fill="rgba(211,23,0,1)"/>
+ <circle cx="55" cy="78" r="1" fill="rgba(210,22,0,1)"/>
+ <circle cx="56" cy="78" r="1" fill="rgba(208,21,0,1)"/>
+ <circle cx="57" cy="78" r="1" fill="rgba(208,20,0,1)"/>
+ <circle cx="58" cy="78" r="1" fill="rgba(207,20,0,1)"/>
+ <circle cx="59" cy="78" r="1" fill="rgba(207,18,0,1)"/>
+ <circle cx="60" cy="78" r="1" fill="rgba(205,18,0,1)"/>
+ <circle cx="61" cy="78" r="1" fill="rgba(204,17,0,1)"/>
+ <circle cx="62" cy="78" r="1" fill="rgba(203,17,1,1)"/>
+ <circle cx="63" cy="78" r="1" fill="rgba(200,15,1,1)"/>
+ <circle cx="64" cy="78" r="1" fill="rgba(199,12,0,1)"/>
+ <circle cx="65" cy="78" r="1" fill="rgba(163,13,0,1)"/>
+ <circle cx="66" cy="78" r="1" fill="rgba(144,16,4,1)"/>
+ <circle cx="67" cy="78" r="1" fill="rgba(191,11,1,1)"/>
+ <circle cx="68" cy="78" r="1" fill="rgba(190,14,2,1)"/>
+ <circle cx="69" cy="78" r="1" fill="rgba(196,16,3,1)"/>
+ <circle cx="70" cy="78" r="1" fill="rgba(200,21,5,1)"/>
+ <circle cx="71" cy="78" r="1" fill="rgba(204,26,7,1)"/>
+ <circle cx="72" cy="78" r="1" fill="rgba(204,28,8,1)"/>
+ <circle cx="73" cy="78" r="1" fill="rgba(205,28,8,1)"/>
+ <circle cx="74" cy="78" r="1" fill="rgba(211,30,8,1)"/>
+ <circle cx="75" cy="78" r="1" fill="rgba(151,19,4,1)"/>
+ <circle cx="76" cy="78" r="1" fill="rgba(31,1,0,1)"/>
+ <circle cx="77" cy="78" r="1" fill="black"/>
+ <circle cx="78" cy="78" r="1" fill="black"/>
+ <circle cx="79" cy="78" r="1" fill="rgba(15,2,0,1)"/>
+ <circle cx="80" cy="78" r="1" fill="rgba(26,7,1,1)"/>
+ <circle cx="81" cy="78" r="1" fill="rgba(26,11,3,1)"/>
+ <circle cx="82" cy="78" r="1" fill="rgba(157,34,10,1)"/>
+ <circle cx="83" cy="78" r="1" fill="rgba(216,50,16,1)"/>
+ <circle cx="84" cy="78" r="1" fill="rgba(211,51,18,1)"/>
+ <circle cx="85" cy="78" r="1" fill="rgba(213,55,19,1)"/>
+ <circle cx="86" cy="78" r="1" fill="rgba(214,60,21,1)"/>
+ <circle cx="87" cy="78" r="1" fill="rgba(215,66,23,1)"/>
+ <circle cx="88" cy="78" r="1" fill="rgba(217,71,27,1)"/>
+ <circle cx="89" cy="78" r="1" fill="rgba(219,76,30,1)"/>
+ <circle cx="90" cy="78" r="1" fill="rgba(221,81,33,1)"/>
+ <circle cx="91" cy="78" r="1" fill="rgba(223,86,36,1)"/>
+ <circle cx="92" cy="78" r="1" fill="rgba(225,93,38,1)"/>
+ <circle cx="93" cy="78" r="1" fill="rgba(227,98,42,1)"/>
+ <circle cx="94" cy="78" r="1" fill="rgba(230,105,47,1)"/>
+ <circle cx="95" cy="78" r="1" fill="rgba(233,111,51,1)"/>
+ <circle cx="96" cy="78" r="1" fill="rgba(235,118,56,1)"/>
+ <circle cx="97" cy="78" r="1" fill="rgba(236,124,59,1)"/>
+ <circle cx="98" cy="78" r="1" fill="rgba(238,129,62,1)"/>
+ <circle cx="99" cy="78" r="1" fill="rgba(240,130,63,1)"/>
+ <circle cx="100" cy="78" r="1" fill="rgba(240,126,58,1)"/>
+ <circle cx="101" cy="78" r="1" fill="rgba(241,115,48,1)"/>
+ <circle cx="102" cy="78" r="1" fill="rgba(131,43,13,0.811765)"/>
+ <circle cx="103" cy="78" r="1" fill="rgba(22,0,0,0.619608)"/>
+ <circle cx="104" cy="78" r="1" fill="rgba(29,2,0,0.529412)"/>
+ <circle cx="105" cy="78" r="1" fill="rgba(15,0,0,0.431373)"/>
+ <circle cx="106" cy="78" r="1" fill="rgba(4,0,0,0.356863)"/>
+ <circle cx="107" cy="78" r="1" fill="rgba(0,0,0,0.290196)"/>
+ <circle cx="108" cy="78" r="1" fill="rgba(0,0,0,0.211765)"/>
+ <circle cx="109" cy="78" r="1" fill="rgba(0,0,0,0.12549)"/>
+ <circle cx="110" cy="78" r="1" fill="rgba(0,0,0,0.054902)"/>
+ <circle cx="111" cy="78" r="1" fill="rgba(0,0,0,0.0117647)"/>
+ <circle cx="112" cy="78" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="113" cy="78" r="1" fill="rgba(26,13,2,0)"/>
+ <circle cx="114" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="78" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="78" r="1" fill="rgba(254,253,253,0)"/>
+ <circle cx="0" cy="79" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="79" r="1" fill="rgba(46,20,7,0)"/>
+ <circle cx="19" cy="79" r="1" fill="rgba(175,24,1,0)"/>
+ <circle cx="20" cy="79" r="1" fill="rgba(216,27,0,0)"/>
+ <circle cx="21" cy="79" r="1" fill="rgba(209,26,0,0)"/>
+ <circle cx="22" cy="79" r="1" fill="rgba(210,26,0,0)"/>
+ <circle cx="23" cy="79" r="1" fill="rgba(210,26,0,0)"/>
+ <circle cx="24" cy="79" r="1" fill="rgba(210,26,0,0)"/>
+ <circle cx="25" cy="79" r="1" fill="rgba(210,26,0,0)"/>
+ <circle cx="26" cy="79" r="1" fill="rgba(210,26,0,0)"/>
+ <circle cx="27" cy="79" r="1" fill="rgba(210,26,0,0.0235294)"/>
+ <circle cx="28" cy="79" r="1" fill="rgba(210,28,0,0.835294)"/>
+ <circle cx="29" cy="79" r="1" fill="rgba(214,36,0,1)"/>
+ <circle cx="30" cy="79" r="1" fill="rgba(217,42,1,1)"/>
+ <circle cx="31" cy="79" r="1" fill="rgba(218,43,1,1)"/>
+ <circle cx="32" cy="79" r="1" fill="rgba(216,35,0,1)"/>
+ <circle cx="33" cy="79" r="1" fill="rgba(213,29,0,1)"/>
+ <circle cx="34" cy="79" r="1" fill="rgba(214,28,0,1)"/>
+ <circle cx="35" cy="79" r="1" fill="rgba(214,28,0,1)"/>
+ <circle cx="36" cy="79" r="1" fill="rgba(215,28,0,1)"/>
+ <circle cx="37" cy="79" r="1" fill="rgba(215,29,0,1)"/>
+ <circle cx="38" cy="79" r="1" fill="rgba(216,29,0,1)"/>
+ <circle cx="39" cy="79" r="1" fill="rgba(216,28,0,1)"/>
+ <circle cx="40" cy="79" r="1" fill="rgba(216,29,0,1)"/>
+ <circle cx="41" cy="79" r="1" fill="rgba(215,27,0,1)"/>
+ <circle cx="42" cy="79" r="1" fill="rgba(216,28,0,1)"/>
+ <circle cx="43" cy="79" r="1" fill="rgba(217,28,0,1)"/>
+ <circle cx="44" cy="79" r="1" fill="rgba(221,28,0,1)"/>
+ <circle cx="45" cy="79" r="1" fill="rgba(222,28,0,1)"/>
+ <circle cx="46" cy="79" r="1" fill="rgba(218,27,0,1)"/>
+ <circle cx="47" cy="79" r="1" fill="rgba(214,26,0,1)"/>
+ <circle cx="48" cy="79" r="1" fill="rgba(213,25,0,1)"/>
+ <circle cx="49" cy="79" r="1" fill="rgba(213,25,0,1)"/>
+ <circle cx="50" cy="79" r="1" fill="rgba(213,24,0,1)"/>
+ <circle cx="51" cy="79" r="1" fill="rgba(211,23,0,1)"/>
+ <circle cx="52" cy="79" r="1" fill="rgba(210,23,0,1)"/>
+ <circle cx="53" cy="79" r="1" fill="rgba(210,22,0,1)"/>
+ <circle cx="54" cy="79" r="1" fill="rgba(210,21,0,1)"/>
+ <circle cx="55" cy="79" r="1" fill="rgba(208,21,0,1)"/>
+ <circle cx="56" cy="79" r="1" fill="rgba(207,20,0,1)"/>
+ <circle cx="57" cy="79" r="1" fill="rgba(207,19,0,1)"/>
+ <circle cx="58" cy="79" r="1" fill="rgba(206,18,0,1)"/>
+ <circle cx="59" cy="79" r="1" fill="rgba(205,17,0,1)"/>
+ <circle cx="60" cy="79" r="1" fill="rgba(204,17,0,1)"/>
+ <circle cx="61" cy="79" r="1" fill="rgba(203,17,1,1)"/>
+ <circle cx="62" cy="79" r="1" fill="rgba(201,15,1,1)"/>
+ <circle cx="63" cy="79" r="1" fill="rgba(199,14,1,1)"/>
+ <circle cx="64" cy="79" r="1" fill="rgba(198,11,0,1)"/>
+ <circle cx="65" cy="79" r="1" fill="rgba(162,12,0,1)"/>
+ <circle cx="66" cy="79" r="1" fill="rgba(141,15,3,1)"/>
+ <circle cx="67" cy="79" r="1" fill="rgba(189,10,1,1)"/>
+ <circle cx="68" cy="79" r="1" fill="rgba(188,12,2,1)"/>
+ <circle cx="69" cy="79" r="1" fill="rgba(194,16,3,1)"/>
+ <circle cx="70" cy="79" r="1" fill="rgba(200,20,5,1)"/>
+ <circle cx="71" cy="79" r="1" fill="rgba(202,25,7,1)"/>
+ <circle cx="72" cy="79" r="1" fill="rgba(203,28,7,1)"/>
+ <circle cx="73" cy="79" r="1" fill="rgba(210,30,8,1)"/>
+ <circle cx="74" cy="79" r="1" fill="rgba(160,20,5,1)"/>
+ <circle cx="75" cy="79" r="1" fill="rgba(15,0,0,1)"/>
+ <circle cx="76" cy="79" r="1" fill="black"/>
+ <circle cx="77" cy="79" r="1" fill="rgba(7,0,0,1)"/>
+ <circle cx="78" cy="79" r="1" fill="rgba(22,4,0,1)"/>
+ <circle cx="79" cy="79" r="1" fill="rgba(37,11,3,1)"/>
+ <circle cx="80" cy="79" r="1" fill="rgba(50,16,5,1)"/>
+ <circle cx="81" cy="79" r="1" fill="rgba(49,20,7,1)"/>
+ <circle cx="82" cy="79" r="1" fill="rgba(119,33,11,1)"/>
+ <circle cx="83" cy="79" r="1" fill="rgba(212,51,17,1)"/>
+ <circle cx="84" cy="79" r="1" fill="rgba(213,54,18,1)"/>
+ <circle cx="85" cy="79" r="1" fill="rgba(214,58,20,1)"/>
+ <circle cx="86" cy="79" r="1" fill="rgba(215,62,22,1)"/>
+ <circle cx="87" cy="79" r="1" fill="rgba(216,68,25,1)"/>
+ <circle cx="88" cy="79" r="1" fill="rgba(218,73,28,1)"/>
+ <circle cx="89" cy="79" r="1" fill="rgba(221,78,31,1)"/>
+ <circle cx="90" cy="79" r="1" fill="rgba(222,84,34,1)"/>
+ <circle cx="91" cy="79" r="1" fill="rgba(224,89,37,1)"/>
+ <circle cx="92" cy="79" r="1" fill="rgba(227,95,41,1)"/>
+ <circle cx="93" cy="79" r="1" fill="rgba(228,101,43,1)"/>
+ <circle cx="94" cy="79" r="1" fill="rgba(230,107,48,1)"/>
+ <circle cx="95" cy="79" r="1" fill="rgba(233,114,53,1)"/>
+ <circle cx="96" cy="79" r="1" fill="rgba(236,120,56,1)"/>
+ <circle cx="97" cy="79" r="1" fill="rgba(237,126,60,1)"/>
+ <circle cx="98" cy="79" r="1" fill="rgba(239,130,63,1)"/>
+ <circle cx="99" cy="79" r="1" fill="rgba(240,132,62,1)"/>
+ <circle cx="100" cy="79" r="1" fill="rgba(241,124,56,1)"/>
+ <circle cx="101" cy="79" r="1" fill="rgba(230,104,42,0.992157)"/>
+ <circle cx="102" cy="79" r="1" fill="rgba(86,21,5,0.741176)"/>
+ <circle cx="103" cy="79" r="1" fill="rgba(31,2,0,0.611765)"/>
+ <circle cx="104" cy="79" r="1" fill="rgba(28,2,0,0.509804)"/>
+ <circle cx="105" cy="79" r="1" fill="rgba(15,0,0,0.411765)"/>
+ <circle cx="106" cy="79" r="1" fill="rgba(4,0,0,0.337255)"/>
+ <circle cx="107" cy="79" r="1" fill="rgba(0,0,0,0.270588)"/>
+ <circle cx="108" cy="79" r="1" fill="rgba(0,0,0,0.188235)"/>
+ <circle cx="109" cy="79" r="1" fill="rgba(0,0,0,0.105882)"/>
+ <circle cx="110" cy="79" r="1" fill="rgba(0,0,0,0.0431373)"/>
+ <circle cx="111" cy="79" r="1" fill="rgba(0,0,0,0.00784314)"/>
+ <circle cx="112" cy="79" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="113" cy="79" r="1" fill="rgba(22,9,1,0)"/>
+ <circle cx="114" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="79" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="80" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="80" r="1" fill="rgba(128,22,4,0)"/>
+ <circle cx="19" cy="80" r="1" fill="rgba(220,25,0,0)"/>
+ <circle cx="20" cy="80" r="1" fill="rgba(207,25,0,0)"/>
+ <circle cx="21" cy="80" r="1" fill="rgba(207,25,0,0)"/>
+ <circle cx="22" cy="80" r="1" fill="rgba(207,25,0,0)"/>
+ <circle cx="23" cy="80" r="1" fill="rgba(207,25,0,0)"/>
+ <circle cx="24" cy="80" r="1" fill="rgba(207,25,0,0)"/>
+ <circle cx="25" cy="80" r="1" fill="rgba(207,25,0,0)"/>
+ <circle cx="26" cy="80" r="1" fill="rgba(207,25,0,0)"/>
+ <circle cx="27" cy="80" r="1" fill="rgba(207,25,0,0)"/>
+ <circle cx="28" cy="80" r="1" fill="rgba(207,25,0,0.603922)"/>
+ <circle cx="29" cy="80" r="1" fill="rgba(210,32,1,1)"/>
+ <circle cx="30" cy="80" r="1" fill="rgba(215,39,1,1)"/>
+ <circle cx="31" cy="80" r="1" fill="rgba(217,42,1,1)"/>
+ <circle cx="32" cy="80" r="1" fill="rgba(215,35,1,1)"/>
+ <circle cx="33" cy="80" r="1" fill="rgba(212,28,0,1)"/>
+ <circle cx="34" cy="80" r="1" fill="rgba(211,26,0,1)"/>
+ <circle cx="35" cy="80" r="1" fill="rgba(212,27,0,1)"/>
+ <circle cx="36" cy="80" r="1" fill="rgba(214,27,0,1)"/>
+ <circle cx="37" cy="80" r="1" fill="rgba(214,27,0,1)"/>
+ <circle cx="38" cy="80" r="1" fill="rgba(214,27,0,1)"/>
+ <circle cx="39" cy="80" r="1" fill="rgba(214,27,0,1)"/>
+ <circle cx="40" cy="80" r="1" fill="rgba(214,26,0,1)"/>
+ <circle cx="41" cy="80" r="1" fill="rgba(214,26,0,1)"/>
+ <circle cx="42" cy="80" r="1" fill="rgba(218,25,0,1)"/>
+ <circle cx="43" cy="80" r="1" fill="rgba(207,25,0,1)"/>
+ <circle cx="44" cy="80" r="1" fill="rgba(173,25,2,1)"/>
+ <circle cx="45" cy="80" r="1" fill="rgba(161,24,2,1)"/>
+ <circle cx="46" cy="80" r="1" fill="rgba(187,24,0,1)"/>
+ <circle cx="47" cy="80" r="1" fill="rgba(215,24,0,1)"/>
+ <circle cx="48" cy="80" r="1" fill="rgba(214,24,0,1)"/>
+ <circle cx="49" cy="80" r="1" fill="rgba(210,23,0,1)"/>
+ <circle cx="50" cy="80" r="1" fill="rgba(210,23,0,1)"/>
+ <circle cx="51" cy="80" r="1" fill="rgba(210,22,0,1)"/>
+ <circle cx="52" cy="80" r="1" fill="rgba(209,21,0,1)"/>
+ <circle cx="53" cy="80" r="1" fill="rgba(208,21,0,1)"/>
+ <circle cx="54" cy="80" r="1" fill="rgba(208,20,0,1)"/>
+ <circle cx="55" cy="80" r="1" fill="rgba(207,20,0,1)"/>
+ <circle cx="56" cy="80" r="1" fill="rgba(207,18,0,1)"/>
+ <circle cx="57" cy="80" r="1" fill="rgba(205,18,0,1)"/>
+ <circle cx="58" cy="80" r="1" fill="rgba(204,17,0,1)"/>
+ <circle cx="59" cy="80" r="1" fill="rgba(203,17,0,1)"/>
+ <circle cx="60" cy="80" r="1" fill="rgba(202,16,0,1)"/>
+ <circle cx="61" cy="80" r="1" fill="rgba(201,15,1,1)"/>
+ <circle cx="62" cy="80" r="1" fill="rgba(200,15,1,1)"/>
+ <circle cx="63" cy="80" r="1" fill="rgba(197,13,1,1)"/>
+ <circle cx="64" cy="80" r="1" fill="rgba(197,11,0,1)"/>
+ <circle cx="65" cy="80" r="1" fill="rgba(160,11,0,1)"/>
+ <circle cx="66" cy="80" r="1" fill="rgba(139,13,3,1)"/>
+ <circle cx="67" cy="80" r="1" fill="rgba(188,10,1,1)"/>
+ <circle cx="68" cy="80" r="1" fill="rgba(188,12,2,1)"/>
+ <circle cx="69" cy="80" r="1" fill="rgba(193,17,3,1)"/>
+ <circle cx="70" cy="80" r="1" fill="rgba(198,20,5,1)"/>
+ <circle cx="71" cy="80" r="1" fill="rgba(201,24,6,1)"/>
+ <circle cx="72" cy="80" r="1" fill="rgba(205,27,7,1)"/>
+ <circle cx="73" cy="80" r="1" fill="rgba(200,27,7,1)"/>
+ <circle cx="74" cy="80" r="1" fill="rgba(58,5,0,1)"/>
+ <circle cx="75" cy="80" r="1" fill="black"/>
+ <circle cx="76" cy="80" r="1" fill="rgba(7,0,0,1)"/>
+ <circle cx="77" cy="80" r="1" fill="rgba(24,6,1,1)"/>
+ <circle cx="78" cy="80" r="1" fill="rgba(42,13,3,1)"/>
+ <circle cx="79" cy="80" r="1" fill="rgba(54,19,6,1)"/>
+ <circle cx="80" cy="80" r="1" fill="rgba(65,25,9,1)"/>
+ <circle cx="81" cy="80" r="1" fill="rgba(70,29,12,1)"/>
+ <circle cx="82" cy="80" r="1" fill="rgba(110,37,14,1)"/>
+ <circle cx="83" cy="80" r="1" fill="rgba(208,51,18,1)"/>
+ <circle cx="84" cy="80" r="1" fill="rgba(214,57,20,1)"/>
+ <circle cx="85" cy="80" r="1" fill="rgba(214,61,21,1)"/>
+ <circle cx="86" cy="80" r="1" fill="rgba(216,66,23,1)"/>
+ <circle cx="87" cy="80" r="1" fill="rgba(217,70,27,1)"/>
+ <circle cx="88" cy="80" r="1" fill="rgba(219,75,30,1)"/>
+ <circle cx="89" cy="80" r="1" fill="rgba(221,80,33,1)"/>
+ <circle cx="90" cy="80" r="1" fill="rgba(222,87,36,1)"/>
+ <circle cx="91" cy="80" r="1" fill="rgba(224,92,39,1)"/>
+ <circle cx="92" cy="80" r="1" fill="rgba(227,98,42,1)"/>
+ <circle cx="93" cy="80" r="1" fill="rgba(229,104,46,1)"/>
+ <circle cx="94" cy="80" r="1" fill="rgba(233,110,51,1)"/>
+ <circle cx="95" cy="80" r="1" fill="rgba(234,117,55,1)"/>
+ <circle cx="96" cy="80" r="1" fill="rgba(236,124,57,1)"/>
+ <circle cx="97" cy="80" r="1" fill="rgba(238,129,62,1)"/>
+ <circle cx="98" cy="80" r="1" fill="rgba(240,132,63,1)"/>
+ <circle cx="99" cy="80" r="1" fill="rgba(240,131,60,1)"/>
+ <circle cx="100" cy="80" r="1" fill="rgba(241,120,52,1)"/>
+ <circle cx="101" cy="80" r="1" fill="rgba(207,86,31,0.94902)"/>
+ <circle cx="102" cy="80" r="1" fill="rgba(51,7,1,0.694118)"/>
+ <circle cx="103" cy="80" r="1" fill="rgba(34,3,0,0.596078)"/>
+ <circle cx="104" cy="80" r="1" fill="rgba(26,2,0,0.486275)"/>
+ <circle cx="105" cy="80" r="1" fill="rgba(15,0,0,0.392157)"/>
+ <circle cx="106" cy="80" r="1" fill="rgba(7,0,0,0.317647)"/>
+ <circle cx="107" cy="80" r="1" fill="rgba(0,0,0,0.243137)"/>
+ <circle cx="108" cy="80" r="1" fill="rgba(0,0,0,0.164706)"/>
+ <circle cx="109" cy="80" r="1" fill="rgba(0,0,0,0.0901961)"/>
+ <circle cx="110" cy="80" r="1" fill="rgba(0,0,0,0.0313725)"/>
+ <circle cx="111" cy="80" r="1" fill="rgba(4,1,0,0.00392157)"/>
+ <circle cx="112" cy="80" r="1" fill="rgba(10,1,0,0)"/>
+ <circle cx="113" cy="80" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="80" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="81" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="81" r="1" fill="rgba(169,23,2,0)"/>
+ <circle cx="19" cy="81" r="1" fill="rgba(210,24,0,0)"/>
+ <circle cx="20" cy="81" r="1" fill="rgba(205,24,0,0)"/>
+ <circle cx="21" cy="81" r="1" fill="rgba(205,24,0,0)"/>
+ <circle cx="22" cy="81" r="1" fill="rgba(205,24,0,0)"/>
+ <circle cx="23" cy="81" r="1" fill="rgba(205,24,0,0)"/>
+ <circle cx="24" cy="81" r="1" fill="rgba(205,24,0,0)"/>
+ <circle cx="25" cy="81" r="1" fill="rgba(205,24,0,0)"/>
+ <circle cx="26" cy="81" r="1" fill="rgba(205,24,0,0)"/>
+ <circle cx="27" cy="81" r="1" fill="rgba(205,24,0,0)"/>
+ <circle cx="28" cy="81" r="1" fill="rgba(205,24,0,0.333333)"/>
+ <circle cx="29" cy="81" r="1" fill="rgba(209,29,1,1)"/>
+ <circle cx="30" cy="81" r="1" fill="rgba(213,37,1,1)"/>
+ <circle cx="31" cy="81" r="1" fill="rgba(215,40,1,1)"/>
+ <circle cx="32" cy="81" r="1" fill="rgba(213,34,1,1)"/>
+ <circle cx="33" cy="81" r="1" fill="rgba(210,27,0,1)"/>
+ <circle cx="34" cy="81" r="1" fill="rgba(210,25,0,1)"/>
+ <circle cx="35" cy="81" r="1" fill="rgba(210,25,0,1)"/>
+ <circle cx="36" cy="81" r="1" fill="rgba(211,25,0,1)"/>
+ <circle cx="37" cy="81" r="1" fill="rgba(212,25,0,1)"/>
+ <circle cx="38" cy="81" r="1" fill="rgba(212,25,0,1)"/>
+ <circle cx="39" cy="81" r="1" fill="rgba(212,25,0,1)"/>
+ <circle cx="40" cy="81" r="1" fill="rgba(212,25,0,1)"/>
+ <circle cx="41" cy="81" r="1" fill="rgba(216,24,0,1)"/>
+ <circle cx="42" cy="81" r="1" fill="rgba(174,26,3,1)"/>
+ <circle cx="43" cy="81" r="1" fill="rgba(93,27,9,1)"/>
+ <circle cx="44" cy="81" r="1" fill="rgba(59,24,9,1)"/>
+ <circle cx="45" cy="81" r="1" fill="rgba(50,21,8,1)"/>
+ <circle cx="46" cy="81" r="1" fill="rgba(54,18,6,1)"/>
+ <circle cx="47" cy="81" r="1" fill="rgba(116,18,3,1)"/>
+ <circle cx="48" cy="81" r="1" fill="rgba(197,21,0,1)"/>
+ <circle cx="49" cy="81" r="1" fill="rgba(214,22,0,1)"/>
+ <circle cx="50" cy="81" r="1" fill="rgba(209,21,0,1)"/>
+ <circle cx="51" cy="81" r="1" fill="rgba(208,20,0,1)"/>
+ <circle cx="52" cy="81" r="1" fill="rgba(208,20,0,1)"/>
+ <circle cx="53" cy="81" r="1" fill="rgba(207,19,0,1)"/>
+ <circle cx="54" cy="81" r="1" fill="rgba(206,19,0,1)"/>
+ <circle cx="55" cy="81" r="1" fill="rgba(206,18,0,1)"/>
+ <circle cx="56" cy="81" r="1" fill="rgba(205,17,0,1)"/>
+ <circle cx="57" cy="81" r="1" fill="rgba(203,17,0,1)"/>
+ <circle cx="58" cy="81" r="1" fill="rgba(203,17,1,1)"/>
+ <circle cx="59" cy="81" r="1" fill="rgba(202,16,1,1)"/>
+ <circle cx="60" cy="81" r="1" fill="rgba(201,15,1,1)"/>
+ <circle cx="61" cy="81" r="1" fill="rgba(200,14,1,1)"/>
+ <circle cx="62" cy="81" r="1" fill="rgba(199,14,1,1)"/>
+ <circle cx="63" cy="81" r="1" fill="rgba(196,13,1,1)"/>
+ <circle cx="64" cy="81" r="1" fill="rgba(196,10,1,1)"/>
+ <circle cx="65" cy="81" r="1" fill="rgba(159,10,0,1)"/>
+ <circle cx="66" cy="81" r="1" fill="rgba(137,11,2,1)"/>
+ <circle cx="67" cy="81" r="1" fill="rgba(188,10,1,1)"/>
+ <circle cx="68" cy="81" r="1" fill="rgba(187,13,2,1)"/>
+ <circle cx="69" cy="81" r="1" fill="rgba(192,17,3,1)"/>
+ <circle cx="70" cy="81" r="1" fill="rgba(197,20,5,1)"/>
+ <circle cx="71" cy="81" r="1" fill="rgba(200,24,6,1)"/>
+ <circle cx="72" cy="81" r="1" fill="rgba(207,27,7,1)"/>
+ <circle cx="73" cy="81" r="1" fill="rgba(178,23,5,1)"/>
+ <circle cx="74" cy="81" r="1" fill="rgba(10,1,0,1)"/>
+ <circle cx="75" cy="81" r="1" fill="black"/>
+ <circle cx="76" cy="81" r="1" fill="rgba(24,6,1,1)"/>
+ <circle cx="77" cy="81" r="1" fill="rgba(43,14,4,1)"/>
+ <circle cx="78" cy="81" r="1" fill="rgba(58,20,7,1)"/>
+ <circle cx="79" cy="81" r="1" fill="rgba(69,27,10,1)"/>
+ <circle cx="80" cy="81" r="1" fill="rgba(81,33,13,1)"/>
+ <circle cx="81" cy="81" r="1" fill="rgba(86,38,17,1)"/>
+ <circle cx="82" cy="81" r="1" fill="rgba(113,44,20,1)"/>
+ <circle cx="83" cy="81" r="1" fill="rgba(207,54,19,1)"/>
+ <circle cx="84" cy="81" r="1" fill="rgba(214,59,20,1)"/>
+ <circle cx="85" cy="81" r="1" fill="rgba(215,63,23,1)"/>
+ <circle cx="86" cy="81" r="1" fill="rgba(216,69,25,1)"/>
+ <circle cx="87" cy="81" r="1" fill="rgba(218,73,28,1)"/>
+ <circle cx="88" cy="81" r="1" fill="rgba(221,78,31,1)"/>
+ <circle cx="89" cy="81" r="1" fill="rgba(222,84,34,1)"/>
+ <circle cx="90" cy="81" r="1" fill="rgba(223,89,37,1)"/>
+ <circle cx="91" cy="81" r="1" fill="rgba(227,95,41,1)"/>
+ <circle cx="92" cy="81" r="1" fill="rgba(228,101,44,1)"/>
+ <circle cx="93" cy="81" r="1" fill="rgba(231,107,48,1)"/>
+ <circle cx="94" cy="81" r="1" fill="rgba(233,114,53,1)"/>
+ <circle cx="95" cy="81" r="1" fill="rgba(236,120,56,1)"/>
+ <circle cx="96" cy="81" r="1" fill="rgba(237,125,60,1)"/>
+ <circle cx="97" cy="81" r="1" fill="rgba(239,131,64,1)"/>
+ <circle cx="98" cy="81" r="1" fill="rgba(240,134,64,1)"/>
+ <circle cx="99" cy="81" r="1" fill="rgba(239,127,57,1)"/>
+ <circle cx="100" cy="81" r="1" fill="rgba(244,116,48,1)"/>
+ <circle cx="101" cy="81" r="1" fill="rgba(163,58,18,0.87451)"/>
+ <circle cx="102" cy="81" r="1" fill="rgba(31,1,0,0.662745)"/>
+ <circle cx="103" cy="81" r="1" fill="rgba(36,4,0,0.572549)"/>
+ <circle cx="104" cy="81" r="1" fill="rgba(24,1,0,0.462745)"/>
+ <circle cx="105" cy="81" r="1" fill="rgba(15,0,0,0.372549)"/>
+ <circle cx="106" cy="81" r="1" fill="rgba(7,0,0,0.298039)"/>
+ <circle cx="107" cy="81" r="1" fill="rgba(0,0,0,0.223529)"/>
+ <circle cx="108" cy="81" r="1" fill="rgba(0,0,0,0.141176)"/>
+ <circle cx="109" cy="81" r="1" fill="rgba(0,0,0,0.0745098)"/>
+ <circle cx="110" cy="81" r="1" fill="rgba(0,0,0,0.0235294)"/>
+ <circle cx="111" cy="81" r="1" fill="rgba(10,2,0,0.00392157)"/>
+ <circle cx="112" cy="81" r="1" fill="rgba(15,4,0,0)"/>
+ <circle cx="113" cy="81" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="114" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="81" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="82" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="82" r="1" fill="rgba(216,25,0,0)"/>
+ <circle cx="19" cy="82" r="1" fill="rgba(203,24,0,0)"/>
+ <circle cx="20" cy="82" r="1" fill="rgba(204,24,0,0)"/>
+ <circle cx="21" cy="82" r="1" fill="rgba(204,24,0,0)"/>
+ <circle cx="22" cy="82" r="1" fill="rgba(204,24,0,0)"/>
+ <circle cx="23" cy="82" r="1" fill="rgba(204,24,0,0)"/>
+ <circle cx="24" cy="82" r="1" fill="rgba(204,24,0,0)"/>
+ <circle cx="25" cy="82" r="1" fill="rgba(204,24,0,0)"/>
+ <circle cx="26" cy="82" r="1" fill="rgba(204,24,0,0)"/>
+ <circle cx="27" cy="82" r="1" fill="rgba(204,24,0,0)"/>
+ <circle cx="28" cy="82" r="1" fill="rgba(204,24,0,0.0862745)"/>
+ <circle cx="29" cy="82" r="1" fill="rgba(207,26,1,0.937255)"/>
+ <circle cx="30" cy="82" r="1" fill="rgba(211,35,2,1)"/>
+ <circle cx="31" cy="82" r="1" fill="rgba(214,38,2,1)"/>
+ <circle cx="32" cy="82" r="1" fill="rgba(212,34,1,1)"/>
+ <circle cx="33" cy="82" r="1" fill="rgba(209,27,1,1)"/>
+ <circle cx="34" cy="82" r="1" fill="rgba(208,24,0,1)"/>
+ <circle cx="35" cy="82" r="1" fill="rgba(208,23,0,1)"/>
+ <circle cx="36" cy="82" r="1" fill="rgba(209,23,0,1)"/>
+ <circle cx="37" cy="82" r="1" fill="rgba(210,24,0,1)"/>
+ <circle cx="38" cy="82" r="1" fill="rgba(210,24,0,1)"/>
+ <circle cx="39" cy="82" r="1" fill="rgba(210,24,0,1)"/>
+ <circle cx="40" cy="82" r="1" fill="rgba(215,23,0,1)"/>
+ <circle cx="41" cy="82" r="1" fill="rgba(183,26,3,1)"/>
+ <circle cx="42" cy="82" r="1" fill="rgba(78,32,13,1)"/>
+ <circle cx="43" cy="82" r="1" fill="rgba(64,29,11,1)"/>
+ <circle cx="44" cy="82" r="1" fill="rgba(67,25,9,1)"/>
+ <circle cx="45" cy="82" r="1" fill="rgba(59,22,8,1)"/>
+ <circle cx="46" cy="82" r="1" fill="rgba(51,19,6,1)"/>
+ <circle cx="47" cy="82" r="1" fill="rgba(29,15,5,1)"/>
+ <circle cx="48" cy="82" r="1" fill="rgba(74,13,3,1)"/>
+ <circle cx="49" cy="82" r="1" fill="rgba(186,19,0,1)"/>
+ <circle cx="50" cy="82" r="1" fill="rgba(212,20,0,1)"/>
+ <circle cx="51" cy="82" r="1" fill="rgba(207,19,0,1)"/>
+ <circle cx="52" cy="82" r="1" fill="rgba(207,19,0,1)"/>
+ <circle cx="53" cy="82" r="1" fill="rgba(205,19,0,1)"/>
+ <circle cx="54" cy="82" r="1" fill="rgba(204,18,0,1)"/>
+ <circle cx="55" cy="82" r="1" fill="rgba(204,16,0,1)"/>
+ <circle cx="56" cy="82" r="1" fill="rgba(203,16,1,1)"/>
+ <circle cx="57" cy="82" r="1" fill="rgba(202,16,1,1)"/>
+ <circle cx="58" cy="82" r="1" fill="rgba(202,16,1,1)"/>
+ <circle cx="59" cy="82" r="1" fill="rgba(200,14,1,1)"/>
+ <circle cx="60" cy="82" r="1" fill="rgba(200,14,1,1)"/>
+ <circle cx="61" cy="82" r="1" fill="rgba(200,13,1,1)"/>
+ <circle cx="62" cy="82" r="1" fill="rgba(198,13,2,1)"/>
+ <circle cx="63" cy="82" r="1" fill="rgba(196,12,2,1)"/>
+ <circle cx="64" cy="82" r="1" fill="rgba(195,10,1,1)"/>
+ <circle cx="65" cy="82" r="1" fill="rgba(157,9,0,1)"/>
+ <circle cx="66" cy="82" r="1" fill="rgba(136,10,2,1)"/>
+ <circle cx="67" cy="82" r="1" fill="rgba(188,11,1,1)"/>
+ <circle cx="68" cy="82" r="1" fill="rgba(187,13,3,1)"/>
+ <circle cx="69" cy="82" r="1" fill="rgba(192,17,3,1)"/>
+ <circle cx="70" cy="82" r="1" fill="rgba(197,20,5,1)"/>
+ <circle cx="71" cy="82" r="1" fill="rgba(200,24,6,1)"/>
+ <circle cx="72" cy="82" r="1" fill="rgba(207,26,7,1)"/>
+ <circle cx="73" cy="82" r="1" fill="rgba(178,23,6,1)"/>
+ <circle cx="74" cy="82" r="1" fill="rgba(15,1,0,1)"/>
+ <circle cx="75" cy="82" r="1" fill="rgba(17,4,0,1)"/>
+ <circle cx="76" cy="82" r="1" fill="rgba(42,13,4,1)"/>
+ <circle cx="77" cy="82" r="1" fill="rgba(58,20,7,1)"/>
+ <circle cx="78" cy="82" r="1" fill="rgba(70,28,10,1)"/>
+ <circle cx="79" cy="82" r="1" fill="rgba(83,34,14,1)"/>
+ <circle cx="80" cy="82" r="1" fill="rgba(94,41,18,1)"/>
+ <circle cx="81" cy="82" r="1" fill="rgba(100,47,22,1)"/>
+ <circle cx="82" cy="82" r="1" fill="rgba(128,52,24,1)"/>
+ <circle cx="83" cy="82" r="1" fill="rgba(210,57,20,1)"/>
+ <circle cx="84" cy="82" r="1" fill="rgba(216,62,21,1)"/>
+ <circle cx="85" cy="82" r="1" fill="rgba(216,67,24,1)"/>
+ <circle cx="86" cy="82" r="1" fill="rgba(217,71,27,1)"/>
+ <circle cx="87" cy="82" r="1" fill="rgba(219,76,29,1)"/>
+ <circle cx="88" cy="82" r="1" fill="rgba(221,81,33,1)"/>
+ <circle cx="89" cy="82" r="1" fill="rgba(223,87,36,1)"/>
+ <circle cx="90" cy="82" r="1" fill="rgba(225,93,38,1)"/>
+ <circle cx="91" cy="82" r="1" fill="rgba(227,98,42,1)"/>
+ <circle cx="92" cy="82" r="1" fill="rgba(229,103,46,1)"/>
+ <circle cx="93" cy="82" r="1" fill="rgba(232,110,50,1)"/>
+ <circle cx="94" cy="82" r="1" fill="rgba(234,116,54,1)"/>
+ <circle cx="95" cy="82" r="1" fill="rgba(236,122,57,1)"/>
+ <circle cx="96" cy="82" r="1" fill="rgba(238,129,63,1)"/>
+ <circle cx="97" cy="82" r="1" fill="rgba(240,133,66,1)"/>
+ <circle cx="98" cy="82" r="1" fill="rgba(241,133,63,1)"/>
+ <circle cx="99" cy="82" r="1" fill="rgba(239,122,54,1)"/>
+ <circle cx="100" cy="82" r="1" fill="rgba(236,106,42,1)"/>
+ <circle cx="101" cy="82" r="1" fill="rgba(111,31,8,0.792157)"/>
+ <circle cx="102" cy="82" r="1" fill="rgba(29,1,0,0.643137)"/>
+ <circle cx="103" cy="82" r="1" fill="rgba(34,4,0,0.54902)"/>
+ <circle cx="104" cy="82" r="1" fill="rgba(21,1,0,0.435294)"/>
+ <circle cx="105" cy="82" r="1" fill="rgba(17,0,0,0.352941)"/>
+ <circle cx="106" cy="82" r="1" fill="rgba(7,0,0,0.282353)"/>
+ <circle cx="107" cy="82" r="1" fill="rgba(0,0,0,0.203922)"/>
+ <circle cx="108" cy="82" r="1" fill="rgba(0,0,0,0.12549)"/>
+ <circle cx="109" cy="82" r="1" fill="rgba(0,0,0,0.0588235)"/>
+ <circle cx="110" cy="82" r="1" fill="rgba(0,0,0,0.0156863)"/>
+ <circle cx="111" cy="82" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="112" cy="82" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="113" cy="82" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="114" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="82" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="83" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="83" r="1" fill="rgba(191,22,1,0)"/>
+ <circle cx="19" cy="83" r="1" fill="rgba(188,22,1,0)"/>
+ <circle cx="20" cy="83" r="1" fill="rgba(188,22,1,0)"/>
+ <circle cx="21" cy="83" r="1" fill="rgba(188,22,1,0)"/>
+ <circle cx="22" cy="83" r="1" fill="rgba(188,22,1,0)"/>
+ <circle cx="23" cy="83" r="1" fill="rgba(188,22,1,0)"/>
+ <circle cx="24" cy="83" r="1" fill="rgba(188,22,1,0)"/>
+ <circle cx="25" cy="83" r="1" fill="rgba(188,22,1,0)"/>
+ <circle cx="26" cy="83" r="1" fill="rgba(188,22,1,0)"/>
+ <circle cx="27" cy="83" r="1" fill="rgba(188,22,1,0)"/>
+ <circle cx="28" cy="83" r="1" fill="rgba(188,22,1,0)"/>
+ <circle cx="29" cy="83" r="1" fill="rgba(196,23,1,0.670588)"/>
+ <circle cx="30" cy="83" r="1" fill="rgba(210,31,2,1)"/>
+ <circle cx="31" cy="83" r="1" fill="rgba(213,37,3,1)"/>
+ <circle cx="32" cy="83" r="1" fill="rgba(211,34,2,1)"/>
+ <circle cx="33" cy="83" r="1" fill="rgba(208,28,1,1)"/>
+ <circle cx="34" cy="83" r="1" fill="rgba(207,23,0,1)"/>
+ <circle cx="35" cy="83" r="1" fill="rgba(207,22,0,1)"/>
+ <circle cx="36" cy="83" r="1" fill="rgba(207,22,0,1)"/>
+ <circle cx="37" cy="83" r="1" fill="rgba(207,23,0,1)"/>
+ <circle cx="38" cy="83" r="1" fill="rgba(207,23,0,1)"/>
+ <circle cx="39" cy="83" r="1" fill="rgba(209,23,0,1)"/>
+ <circle cx="40" cy="83" r="1" fill="rgba(210,22,0,1)"/>
+ <circle cx="41" cy="83" r="1" fill="rgba(126,32,10,1)"/>
+ <circle cx="42" cy="83" r="1" fill="rgba(70,34,14,1)"/>
+ <circle cx="43" cy="83" r="1" fill="rgba(74,29,11,1)"/>
+ <circle cx="44" cy="83" r="1" fill="rgba(68,26,10,1)"/>
+ <circle cx="45" cy="83" r="1" fill="rgba(62,23,8,1)"/>
+ <circle cx="46" cy="83" r="1" fill="rgba(55,20,6,1)"/>
+ <circle cx="47" cy="83" r="1" fill="rgba(49,16,5,1)"/>
+ <circle cx="48" cy="83" r="1" fill="rgba(24,11,3,1)"/>
+ <circle cx="49" cy="83" r="1" fill="rgba(78,11,2,1)"/>
+ <circle cx="50" cy="83" r="1" fill="rgba(200,18,0,1)"/>
+ <circle cx="51" cy="83" r="1" fill="rgba(207,18,0,1)"/>
+ <circle cx="52" cy="83" r="1" fill="rgba(204,18,0,1)"/>
+ <circle cx="53" cy="83" r="1" fill="rgba(203,18,0,1)"/>
+ <circle cx="54" cy="83" r="1" fill="rgba(203,17,1,1)"/>
+ <circle cx="55" cy="83" r="1" fill="rgba(202,16,1,1)"/>
+ <circle cx="56" cy="83" r="1" fill="rgba(202,15,1,1)"/>
+ <circle cx="57" cy="83" r="1" fill="rgba(201,15,1,1)"/>
+ <circle cx="58" cy="83" r="1" fill="rgba(200,14,1,1)"/>
+ <circle cx="59" cy="83" r="1" fill="rgba(200,14,1,1)"/>
+ <circle cx="60" cy="83" r="1" fill="rgba(199,14,1,1)"/>
+ <circle cx="61" cy="83" r="1" fill="rgba(198,13,1,1)"/>
+ <circle cx="62" cy="83" r="1" fill="rgba(196,13,2,1)"/>
+ <circle cx="63" cy="83" r="1" fill="rgba(195,12,2,1)"/>
+ <circle cx="64" cy="83" r="1" fill="rgba(196,10,1,1)"/>
+ <circle cx="65" cy="83" r="1" fill="rgba(156,7,0,1)"/>
+ <circle cx="66" cy="83" r="1" fill="rgba(133,9,1,1)"/>
+ <circle cx="67" cy="83" r="1" fill="rgba(189,12,2,1)"/>
+ <circle cx="68" cy="83" r="1" fill="rgba(188,14,3,1)"/>
+ <circle cx="69" cy="83" r="1" fill="rgba(193,18,4,1)"/>
+ <circle cx="70" cy="83" r="1" fill="rgba(198,21,5,1)"/>
+ <circle cx="71" cy="83" r="1" fill="rgba(200,25,6,1)"/>
+ <circle cx="72" cy="83" r="1" fill="rgba(205,28,7,1)"/>
+ <circle cx="73" cy="83" r="1" fill="rgba(195,27,7,1)"/>
+ <circle cx="74" cy="83" r="1" fill="rgba(46,6,1,1)"/>
+ <circle cx="75" cy="83" r="1" fill="rgba(31,10,3,1)"/>
+ <circle cx="76" cy="83" r="1" fill="rgba(55,19,6,1)"/>
+ <circle cx="77" cy="83" r="1" fill="rgba(69,27,10,1)"/>
+ <circle cx="78" cy="83" r="1" fill="rgba(83,34,14,1)"/>
+ <circle cx="79" cy="83" r="1" fill="rgba(95,42,18,1)"/>
+ <circle cx="80" cy="83" r="1" fill="rgba(106,48,23,1)"/>
+ <circle cx="81" cy="83" r="1" fill="rgba(110,55,27,1)"/>
+ <circle cx="82" cy="83" r="1" fill="rgba(147,59,28,1)"/>
+ <circle cx="83" cy="83" r="1" fill="rgba(214,60,21,1)"/>
+ <circle cx="84" cy="83" r="1" fill="rgba(216,65,23,1)"/>
+ <circle cx="85" cy="83" r="1" fill="rgba(217,69,25,1)"/>
+ <circle cx="86" cy="83" r="1" fill="rgba(218,74,28,1)"/>
+ <circle cx="87" cy="83" r="1" fill="rgba(221,79,31,1)"/>
+ <circle cx="88" cy="83" r="1" fill="rgba(221,84,33,1)"/>
+ <circle cx="89" cy="83" r="1" fill="rgba(224,89,37,1)"/>
+ <circle cx="90" cy="83" r="1" fill="rgba(227,95,41,1)"/>
+ <circle cx="91" cy="83" r="1" fill="rgba(228,101,44,1)"/>
+ <circle cx="92" cy="83" r="1" fill="rgba(231,107,48,1)"/>
+ <circle cx="93" cy="83" r="1" fill="rgba(233,113,53,1)"/>
+ <circle cx="94" cy="83" r="1" fill="rgba(236,120,56,1)"/>
+ <circle cx="95" cy="83" r="1" fill="rgba(237,126,60,1)"/>
+ <circle cx="96" cy="83" r="1" fill="rgba(238,131,64,1)"/>
+ <circle cx="97" cy="83" r="1" fill="rgba(241,135,65,1)"/>
+ <circle cx="98" cy="83" r="1" fill="rgba(241,130,60,1)"/>
+ <circle cx="99" cy="83" r="1" fill="rgba(241,118,50,1)"/>
+ <circle cx="100" cy="83" r="1" fill="rgba(212,87,32,0.964706)"/>
+ <circle cx="101" cy="83" r="1" fill="rgba(57,9,2,0.717647)"/>
+ <circle cx="102" cy="83" r="1" fill="rgba(39,4,0,0.627451)"/>
+ <circle cx="103" cy="83" r="1" fill="rgba(31,2,0,0.521569)"/>
+ <circle cx="104" cy="83" r="1" fill="rgba(19,0,0,0.415686)"/>
+ <circle cx="105" cy="83" r="1" fill="rgba(12,2,0,0.333333)"/>
+ <circle cx="106" cy="83" r="1" fill="rgba(4,0,0,0.262745)"/>
+ <circle cx="107" cy="83" r="1" fill="rgba(0,0,0,0.184314)"/>
+ <circle cx="108" cy="83" r="1" fill="rgba(0,0,0,0.109804)"/>
+ <circle cx="109" cy="83" r="1" fill="rgba(0,0,0,0.0470588)"/>
+ <circle cx="110" cy="83" r="1" fill="rgba(4,0,0,0.0117647)"/>
+ <circle cx="111" cy="83" r="1" fill="rgba(22,8,1,0)"/>
+ <circle cx="112" cy="83" r="1" fill="rgba(22,8,1,0)"/>
+ <circle cx="113" cy="83" r="1" fill="rgba(22,8,1,0)"/>
+ <circle cx="114" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="83" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="84" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="84" r="1" fill="rgba(113,16,3,0)"/>
+ <circle cx="19" cy="84" r="1" fill="rgba(113,16,3,0)"/>
+ <circle cx="20" cy="84" r="1" fill="rgba(113,16,3,0)"/>
+ <circle cx="21" cy="84" r="1" fill="rgba(113,16,3,0)"/>
+ <circle cx="22" cy="84" r="1" fill="rgba(113,16,3,0)"/>
+ <circle cx="23" cy="84" r="1" fill="rgba(113,16,3,0)"/>
+ <circle cx="24" cy="84" r="1" fill="rgba(113,16,3,0)"/>
+ <circle cx="25" cy="84" r="1" fill="rgba(113,16,3,0)"/>
+ <circle cx="26" cy="84" r="1" fill="rgba(113,16,3,0)"/>
+ <circle cx="27" cy="84" r="1" fill="rgba(113,16,3,0)"/>
+ <circle cx="28" cy="84" r="1" fill="rgba(107,15,3,0)"/>
+ <circle cx="29" cy="84" r="1" fill="rgba(156,19,3,0.356863)"/>
+ <circle cx="30" cy="84" r="1" fill="rgba(210,28,2,1)"/>
+ <circle cx="31" cy="84" r="1" fill="rgba(210,34,3,1)"/>
+ <circle cx="32" cy="84" r="1" fill="rgba(210,33,2,1)"/>
+ <circle cx="33" cy="84" r="1" fill="rgba(207,27,1,1)"/>
+ <circle cx="34" cy="84" r="1" fill="rgba(205,22,0,1)"/>
+ <circle cx="35" cy="84" r="1" fill="rgba(205,21,0,1)"/>
+ <circle cx="36" cy="84" r="1" fill="rgba(205,21,1,1)"/>
+ <circle cx="37" cy="84" r="1" fill="rgba(205,21,1,1)"/>
+ <circle cx="38" cy="84" r="1" fill="rgba(206,22,0,1)"/>
+ <circle cx="39" cy="84" r="1" fill="rgba(208,21,0,1)"/>
+ <circle cx="40" cy="84" r="1" fill="rgba(201,22,1,1)"/>
+ <circle cx="41" cy="84" r="1" fill="rgba(98,36,14,1)"/>
+ <circle cx="42" cy="84" r="1" fill="rgba(77,33,14,1)"/>
+ <circle cx="43" cy="84" r="1" fill="rgba(74,29,12,1)"/>
+ <circle cx="44" cy="84" r="1" fill="rgba(69,26,10,1)"/>
+ <circle cx="45" cy="84" r="1" fill="rgba(63,23,8,1)"/>
+ <circle cx="46" cy="84" r="1" fill="rgba(55,20,6,1)"/>
+ <circle cx="47" cy="84" r="1" fill="rgba(49,16,5,1)"/>
+ <circle cx="48" cy="84" r="1" fill="rgba(42,13,3,1)"/>
+ <circle cx="49" cy="84" r="1" fill="rgba(12,9,2,1)"/>
+ <circle cx="50" cy="84" r="1" fill="rgba(130,12,1,1)"/>
+ <circle cx="51" cy="84" r="1" fill="rgba(209,18,1,1)"/>
+ <circle cx="52" cy="84" r="1" fill="rgba(203,16,0,1)"/>
+ <circle cx="53" cy="84" r="1" fill="rgba(202,16,1,1)"/>
+ <circle cx="54" cy="84" r="1" fill="rgba(202,15,1,1)"/>
+ <circle cx="55" cy="84" r="1" fill="rgba(201,14,1,1)"/>
+ <circle cx="56" cy="84" r="1" fill="rgba(200,15,1,1)"/>
+ <circle cx="57" cy="84" r="1" fill="rgba(200,14,1,1)"/>
+ <circle cx="58" cy="84" r="1" fill="rgba(199,14,1,1)"/>
+ <circle cx="59" cy="84" r="1" fill="rgba(199,13,1,1)"/>
+ <circle cx="60" cy="84" r="1" fill="rgba(197,13,2,1)"/>
+ <circle cx="61" cy="84" r="1" fill="rgba(197,13,2,1)"/>
+ <circle cx="62" cy="84" r="1" fill="rgba(196,13,3,1)"/>
+ <circle cx="63" cy="84" r="1" fill="rgba(195,13,3,1)"/>
+ <circle cx="64" cy="84" r="1" fill="rgba(195,11,1,1)"/>
+ <circle cx="65" cy="84" r="1" fill="rgba(154,6,0,1)"/>
+ <circle cx="66" cy="84" r="1" fill="rgba(131,8,1,1)"/>
+ <circle cx="67" cy="84" r="1" fill="rgba(190,14,3,1)"/>
+ <circle cx="68" cy="84" r="1" fill="rgba(188,15,3,1)"/>
+ <circle cx="69" cy="84" r="1" fill="rgba(193,19,4,1)"/>
+ <circle cx="70" cy="84" r="1" fill="rgba(198,23,5,1)"/>
+ <circle cx="71" cy="84" r="1" fill="rgba(201,26,6,1)"/>
+ <circle cx="72" cy="84" r="1" fill="rgba(203,29,8,1)"/>
+ <circle cx="73" cy="84" r="1" fill="rgba(208,31,9,1)"/>
+ <circle cx="74" cy="84" r="1" fill="rgba(109,17,4,1)"/>
+ <circle cx="75" cy="84" r="1" fill="rgba(33,15,4,1)"/>
+ <circle cx="76" cy="84" r="1" fill="rgba(67,24,9,1)"/>
+ <circle cx="77" cy="84" r="1" fill="rgba(81,33,13,1)"/>
+ <circle cx="78" cy="84" r="1" fill="rgba(94,41,18,1)"/>
+ <circle cx="79" cy="84" r="1" fill="rgba(106,48,23,1)"/>
+ <circle cx="80" cy="84" r="1" fill="rgba(116,55,28,1)"/>
+ <circle cx="81" cy="84" r="1" fill="rgba(121,63,34,1)"/>
+ <circle cx="82" cy="84" r="1" fill="rgba(176,64,28,1)"/>
+ <circle cx="83" cy="84" r="1" fill="rgba(219,62,21,1)"/>
+ <circle cx="84" cy="84" r="1" fill="rgba(216,68,25,1)"/>
+ <circle cx="85" cy="84" r="1" fill="rgba(217,72,27,1)"/>
+ <circle cx="86" cy="84" r="1" fill="rgba(220,77,30,1)"/>
+ <circle cx="87" cy="84" r="1" fill="rgba(221,83,33,1)"/>
+ <circle cx="88" cy="84" r="1" fill="rgba(223,87,36,1)"/>
+ <circle cx="89" cy="84" r="1" fill="rgba(225,93,39,1)"/>
+ <circle cx="90" cy="84" r="1" fill="rgba(228,99,42,1)"/>
+ <circle cx="91" cy="84" r="1" fill="rgba(230,104,47,1)"/>
+ <circle cx="92" cy="84" r="1" fill="rgba(233,110,51,1)"/>
+ <circle cx="93" cy="84" r="1" fill="rgba(234,117,54,1)"/>
+ <circle cx="94" cy="84" r="1" fill="rgba(236,123,58,1)"/>
+ <circle cx="95" cy="84" r="1" fill="rgba(238,129,62,1)"/>
+ <circle cx="96" cy="84" r="1" fill="rgba(240,133,66,1)"/>
+ <circle cx="97" cy="84" r="1" fill="rgba(241,134,64,1)"/>
+ <circle cx="98" cy="84" r="1" fill="rgba(238,125,56,1)"/>
+ <circle cx="99" cy="84" r="1" fill="rgba(242,114,47,1)"/>
+ <circle cx="100" cy="84" r="1" fill="rgba(163,57,18,0.878431)"/>
+ <circle cx="101" cy="84" r="1" fill="rgba(34,2,0,0.67451)"/>
+ <circle cx="102" cy="84" r="1" fill="rgba(39,4,0,0.6)"/>
+ <circle cx="103" cy="84" r="1" fill="rgba(26,2,0,0.490196)"/>
+ <circle cx="104" cy="84" r="1" fill="rgba(17,0,0,0.388235)"/>
+ <circle cx="105" cy="84" r="1" fill="rgba(12,1,0,0.309804)"/>
+ <circle cx="106" cy="84" r="1" fill="rgba(4,0,0,0.239216)"/>
+ <circle cx="107" cy="84" r="1" fill="rgba(0,0,0,0.160784)"/>
+ <circle cx="108" cy="84" r="1" fill="rgba(0,0,0,0.0901961)"/>
+ <circle cx="109" cy="84" r="1" fill="rgba(0,0,0,0.0352941)"/>
+ <circle cx="110" cy="84" r="1" fill="rgba(4,0,0,0.00392157)"/>
+ <circle cx="111" cy="84" r="1" fill="rgba(17,5,0,0)"/>
+ <circle cx="112" cy="84" r="1" fill="rgba(17,6,0,0)"/>
+ <circle cx="113" cy="84" r="1" fill="rgba(17,6,0,0)"/>
+ <circle cx="114" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="84" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="85" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="85" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="19" cy="85" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="20" cy="85" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="21" cy="85" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="22" cy="85" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="23" cy="85" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="24" cy="85" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="25" cy="85" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="26" cy="85" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="27" cy="85" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="28" cy="85" r="1" fill="rgba(109,13,1,0)"/>
+ <circle cx="29" cy="85" r="1" fill="rgba(126,14,1,0.0823529)"/>
+ <circle cx="30" cy="85" r="1" fill="rgba(198,23,2,0.901961)"/>
+ <circle cx="31" cy="85" r="1" fill="rgba(207,29,3,1)"/>
+ <circle cx="32" cy="85" r="1" fill="rgba(207,30,3,1)"/>
+ <circle cx="33" cy="85" r="1" fill="rgba(205,25,1,1)"/>
+ <circle cx="34" cy="85" r="1" fill="rgba(203,21,1,1)"/>
+ <circle cx="35" cy="85" r="1" fill="rgba(203,19,0,1)"/>
+ <circle cx="36" cy="85" r="1" fill="rgba(203,19,1,1)"/>
+ <circle cx="37" cy="85" r="1" fill="rgba(203,20,1,1)"/>
+ <circle cx="38" cy="85" r="1" fill="rgba(204,20,1,1)"/>
+ <circle cx="39" cy="85" r="1" fill="rgba(206,20,0,1)"/>
+ <circle cx="40" cy="85" r="1" fill="rgba(198,21,1,1)"/>
+ <circle cx="41" cy="85" r="1" fill="rgba(94,36,14,1)"/>
+ <circle cx="42" cy="85" r="1" fill="rgba(78,33,14,1)"/>
+ <circle cx="43" cy="85" r="1" fill="rgba(75,30,12,1)"/>
+ <circle cx="44" cy="85" r="1" fill="rgba(69,27,10,1)"/>
+ <circle cx="45" cy="85" r="1" fill="rgba(63,23,8,1)"/>
+ <circle cx="46" cy="85" r="1" fill="rgba(57,20,6,1)"/>
+ <circle cx="47" cy="85" r="1" fill="rgba(50,17,5,1)"/>
+ <circle cx="48" cy="85" r="1" fill="rgba(43,13,4,1)"/>
+ <circle cx="49" cy="85" r="1" fill="rgba(26,9,2,1)"/>
+ <circle cx="50" cy="85" r="1" fill="rgba(63,8,1,1)"/>
+ <circle cx="51" cy="85" r="1" fill="rgba(197,15,1,1)"/>
+ <circle cx="52" cy="85" r="1" fill="rgba(203,16,1,1)"/>
+ <circle cx="53" cy="85" r="1" fill="rgba(200,15,1,1)"/>
+ <circle cx="54" cy="85" r="1" fill="rgba(200,14,1,1)"/>
+ <circle cx="55" cy="85" r="1" fill="rgba(200,14,1,1)"/>
+ <circle cx="56" cy="85" r="1" fill="rgba(200,14,1,1)"/>
+ <circle cx="57" cy="85" r="1" fill="rgba(199,13,2,1)"/>
+ <circle cx="58" cy="85" r="1" fill="rgba(198,13,2,1)"/>
+ <circle cx="59" cy="85" r="1" fill="rgba(197,13,2,1)"/>
+ <circle cx="60" cy="85" r="1" fill="rgba(197,12,2,1)"/>
+ <circle cx="61" cy="85" r="1" fill="rgba(197,13,3,1)"/>
+ <circle cx="62" cy="85" r="1" fill="rgba(196,14,3,1)"/>
+ <circle cx="63" cy="85" r="1" fill="rgba(195,15,3,1)"/>
+ <circle cx="64" cy="85" r="1" fill="rgba(196,12,1,1)"/>
+ <circle cx="65" cy="85" r="1" fill="rgba(153,6,0,1)"/>
+ <circle cx="66" cy="85" r="1" fill="rgba(132,9,1,1)"/>
+ <circle cx="67" cy="85" r="1" fill="rgba(191,15,3,1)"/>
+ <circle cx="68" cy="85" r="1" fill="rgba(189,17,3,1)"/>
+ <circle cx="69" cy="85" r="1" fill="rgba(194,21,4,1)"/>
+ <circle cx="70" cy="85" r="1" fill="rgba(199,24,6,1)"/>
+ <circle cx="71" cy="85" r="1" fill="rgba(201,27,7,1)"/>
+ <circle cx="72" cy="85" r="1" fill="rgba(203,30,8,1)"/>
+ <circle cx="73" cy="85" r="1" fill="rgba(210,34,9,1)"/>
+ <circle cx="74" cy="85" r="1" fill="rgba(176,30,9,1)"/>
+ <circle cx="75" cy="85" r="1" fill="rgba(61,21,8,1)"/>
+ <circle cx="76" cy="85" r="1" fill="rgba(70,30,12,1)"/>
+ <circle cx="77" cy="85" r="1" fill="rgba(90,39,17,1)"/>
+ <circle cx="78" cy="85" r="1" fill="rgba(103,47,22,1)"/>
+ <circle cx="79" cy="85" r="1" fill="rgba(115,55,27,1)"/>
+ <circle cx="80" cy="85" r="1" fill="rgba(124,63,33,1)"/>
+ <circle cx="81" cy="85" r="1" fill="rgba(142,68,37,1)"/>
+ <circle cx="82" cy="85" r="1" fill="rgba(207,63,24,1)"/>
+ <circle cx="83" cy="85" r="1" fill="rgba(217,66,24,1)"/>
+ <circle cx="84" cy="85" r="1" fill="rgba(217,70,26,1)"/>
+ <circle cx="85" cy="85" r="1" fill="rgba(219,75,29,1)"/>
+ <circle cx="86" cy="85" r="1" fill="rgba(221,80,32,1)"/>
+ <circle cx="87" cy="85" r="1" fill="rgba(222,85,34,1)"/>
+ <circle cx="88" cy="85" r="1" fill="rgba(224,91,38,1)"/>
+ <circle cx="89" cy="85" r="1" fill="rgba(227,97,42,1)"/>
+ <circle cx="90" cy="85" r="1" fill="rgba(229,102,45,1)"/>
+ <circle cx="91" cy="85" r="1" fill="rgba(231,107,48,1)"/>
+ <circle cx="92" cy="85" r="1" fill="rgba(233,114,53,1)"/>
+ <circle cx="93" cy="85" r="1" fill="rgba(236,121,56,1)"/>
+ <circle cx="94" cy="85" r="1" fill="rgba(237,126,60,1)"/>
+ <circle cx="95" cy="85" r="1" fill="rgba(239,131,64,1)"/>
+ <circle cx="96" cy="85" r="1" fill="rgba(241,136,66,1)"/>
+ <circle cx="97" cy="85" r="1" fill="rgba(241,133,62,1)"/>
+ <circle cx="98" cy="85" r="1" fill="rgba(238,121,53,1)"/>
+ <circle cx="99" cy="85" r="1" fill="rgba(233,105,42,1)"/>
+ <circle cx="100" cy="85" r="1" fill="rgba(100,26,7,0.784314)"/>
+ <circle cx="101" cy="85" r="1" fill="rgba(33,2,0,0.65098)"/>
+ <circle cx="102" cy="85" r="1" fill="rgba(36,3,0,0.560784)"/>
+ <circle cx="103" cy="85" r="1" fill="rgba(21,0,0,0.45098)"/>
+ <circle cx="104" cy="85" r="1" fill="rgba(12,1,0,0.364706)"/>
+ <circle cx="105" cy="85" r="1" fill="rgba(7,1,0,0.290196)"/>
+ <circle cx="106" cy="85" r="1" fill="rgba(0,0,0,0.219608)"/>
+ <circle cx="107" cy="85" r="1" fill="rgba(0,0,0,0.141176)"/>
+ <circle cx="108" cy="85" r="1" fill="rgba(0,0,0,0.0705882)"/>
+ <circle cx="109" cy="85" r="1" fill="rgba(0,0,0,0.0235294)"/>
+ <circle cx="110" cy="85" r="1" fill="none"/>
+ <circle cx="111" cy="85" r="1" fill="none"/>
+ <circle cx="112" cy="85" r="1" fill="none"/>
+ <circle cx="113" cy="85" r="1" fill="none"/>
+ <circle cx="114" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="85" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="86" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="86" r="1" fill="rgba(109,14,2,0)"/>
+ <circle cx="19" cy="86" r="1" fill="rgba(109,14,2,0)"/>
+ <circle cx="20" cy="86" r="1" fill="rgba(109,14,2,0)"/>
+ <circle cx="21" cy="86" r="1" fill="rgba(109,14,2,0)"/>
+ <circle cx="22" cy="86" r="1" fill="rgba(109,14,2,0)"/>
+ <circle cx="23" cy="86" r="1" fill="rgba(109,14,2,0)"/>
+ <circle cx="24" cy="86" r="1" fill="rgba(109,14,2,0)"/>
+ <circle cx="25" cy="86" r="1" fill="rgba(109,14,2,0)"/>
+ <circle cx="26" cy="86" r="1" fill="rgba(109,14,2,0)"/>
+ <circle cx="27" cy="86" r="1" fill="rgba(109,14,2,0)"/>
+ <circle cx="28" cy="86" r="1" fill="rgba(109,14,2,0)"/>
+ <circle cx="29" cy="86" r="1" fill="rgba(103,13,1,0)"/>
+ <circle cx="30" cy="86" r="1" fill="rgba(165,17,1,0.603922)"/>
+ <circle cx="31" cy="86" r="1" fill="rgba(205,24,3,1)"/>
+ <circle cx="32" cy="86" r="1" fill="rgba(202,25,2,1)"/>
+ <circle cx="33" cy="86" r="1" fill="rgba(202,21,2,1)"/>
+ <circle cx="34" cy="86" r="1" fill="rgba(200,19,1,1)"/>
+ <circle cx="35" cy="86" r="1" fill="rgba(201,19,1,1)"/>
+ <circle cx="36" cy="86" r="1" fill="rgba(202,18,1,1)"/>
+ <circle cx="37" cy="86" r="1" fill="rgba(203,19,1,1)"/>
+ <circle cx="38" cy="86" r="1" fill="rgba(202,19,1,1)"/>
+ <circle cx="39" cy="86" r="1" fill="rgba(203,19,1,1)"/>
+ <circle cx="40" cy="86" r="1" fill="rgba(201,19,1,1)"/>
+ <circle cx="41" cy="86" r="1" fill="rgba(113,33,12,1)"/>
+ <circle cx="42" cy="86" r="1" fill="rgba(75,34,14,1)"/>
+ <circle cx="43" cy="86" r="1" fill="rgba(75,30,12,1)"/>
+ <circle cx="44" cy="86" r="1" fill="rgba(70,27,10,1)"/>
+ <circle cx="45" cy="86" r="1" fill="rgba(63,23,8,1)"/>
+ <circle cx="46" cy="86" r="1" fill="rgba(57,20,7,1)"/>
+ <circle cx="47" cy="86" r="1" fill="rgba(50,17,5,1)"/>
+ <circle cx="48" cy="86" r="1" fill="rgba(43,14,4,1)"/>
+ <circle cx="49" cy="86" r="1" fill="rgba(31,10,3,1)"/>
+ <circle cx="50" cy="86" r="1" fill="rgba(37,7,1,1)"/>
+ <circle cx="51" cy="86" r="1" fill="rgba(191,14,1,1)"/>
+ <circle cx="52" cy="86" r="1" fill="rgba(202,14,1,1)"/>
+ <circle cx="53" cy="86" r="1" fill="rgba(199,14,1,1)"/>
+ <circle cx="54" cy="86" r="1" fill="rgba(198,14,1,1)"/>
+ <circle cx="55" cy="86" r="1" fill="rgba(197,14,1,1)"/>
+ <circle cx="56" cy="86" r="1" fill="rgba(197,13,2,1)"/>
+ <circle cx="57" cy="86" r="1" fill="rgba(197,13,2,1)"/>
+ <circle cx="58" cy="86" r="1" fill="rgba(197,13,2,1)"/>
+ <circle cx="59" cy="86" r="1" fill="rgba(197,13,2,1)"/>
+ <circle cx="60" cy="86" r="1" fill="rgba(197,14,3,1)"/>
+ <circle cx="61" cy="86" r="1" fill="rgba(197,15,3,1)"/>
+ <circle cx="62" cy="86" r="1" fill="rgba(196,16,3,1)"/>
+ <circle cx="63" cy="86" r="1" fill="rgba(195,16,3,1)"/>
+ <circle cx="64" cy="86" r="1" fill="rgba(196,14,1,1)"/>
+ <circle cx="65" cy="86" r="1" fill="rgba(153,6,0,1)"/>
+ <circle cx="66" cy="86" r="1" fill="rgba(132,9,1,1)"/>
+ <circle cx="67" cy="86" r="1" fill="rgba(192,17,3,1)"/>
+ <circle cx="68" cy="86" r="1" fill="rgba(190,18,4,1)"/>
+ <circle cx="69" cy="86" r="1" fill="rgba(196,22,5,1)"/>
+ <circle cx="70" cy="86" r="1" fill="rgba(200,26,6,1)"/>
+ <circle cx="71" cy="86" r="1" fill="rgba(203,29,8,1)"/>
+ <circle cx="72" cy="86" r="1" fill="rgba(204,32,9,1)"/>
+ <circle cx="73" cy="86" r="1" fill="rgba(205,35,10,1)"/>
+ <circle cx="74" cy="86" r="1" fill="rgba(210,38,11,1)"/>
+ <circle cx="75" cy="86" r="1" fill="rgba(155,35,11,1)"/>
+ <circle cx="76" cy="86" r="1" fill="rgba(78,34,14,1)"/>
+ <circle cx="77" cy="86" r="1" fill="rgba(88,43,20,1)"/>
+ <circle cx="78" cy="86" r="1" fill="rgba(105,52,27,1)"/>
+ <circle cx="79" cy="86" r="1" fill="rgba(117,61,33,1)"/>
+ <circle cx="80" cy="86" r="1" fill="rgba(134,69,38,1)"/>
+ <circle cx="81" cy="86" r="1" fill="rgba(188,66,28,1)"/>
+ <circle cx="82" cy="86" r="1" fill="rgba(218,65,22,1)"/>
+ <circle cx="83" cy="86" r="1" fill="rgba(217,69,26,1)"/>
+ <circle cx="84" cy="86" r="1" fill="rgba(218,73,28,1)"/>
+ <circle cx="85" cy="86" r="1" fill="rgba(221,78,30,1)"/>
+ <circle cx="86" cy="86" r="1" fill="rgba(222,83,33,1)"/>
+ <circle cx="87" cy="86" r="1" fill="rgba(224,89,37,1)"/>
+ <circle cx="88" cy="86" r="1" fill="rgba(227,95,40,1)"/>
+ <circle cx="89" cy="86" r="1" fill="rgba(228,100,43,1)"/>
+ <circle cx="90" cy="86" r="1" fill="rgba(230,105,48,1)"/>
+ <circle cx="91" cy="86" r="1" fill="rgba(232,111,51,1)"/>
+ <circle cx="92" cy="86" r="1" fill="rgba(234,118,56,1)"/>
+ <circle cx="93" cy="86" r="1" fill="rgba(236,124,59,1)"/>
+ <circle cx="94" cy="86" r="1" fill="rgba(238,129,62,1)"/>
+ <circle cx="95" cy="86" r="1" fill="rgba(240,134,65,1)"/>
+ <circle cx="96" cy="86" r="1" fill="rgba(241,136,65,1)"/>
+ <circle cx="97" cy="86" r="1" fill="rgba(239,128,59,1)"/>
+ <circle cx="98" cy="86" r="1" fill="rgba(242,120,51,1)"/>
+ <circle cx="99" cy="86" r="1" fill="rgba(197,81,30,0.933333)"/>
+ <circle cx="100" cy="86" r="1" fill="rgba(46,6,1,0.705882)"/>
+ <circle cx="101" cy="86" r="1" fill="rgba(40,4,1,0.627451)"/>
+ <circle cx="102" cy="86" r="1" fill="rgba(31,2,0,0.521569)"/>
+ <circle cx="103" cy="86" r="1" fill="rgba(19,0,0,0.419608)"/>
+ <circle cx="104" cy="86" r="1" fill="rgba(15,2,0,0.337255)"/>
+ <circle cx="105" cy="86" r="1" fill="rgba(7,1,0,0.266667)"/>
+ <circle cx="106" cy="86" r="1" fill="rgba(0,0,0,0.188235)"/>
+ <circle cx="107" cy="86" r="1" fill="rgba(0,0,0,0.113725)"/>
+ <circle cx="108" cy="86" r="1" fill="rgba(0,0,0,0.0509804)"/>
+ <circle cx="109" cy="86" r="1" fill="rgba(0,0,0,0.0117647)"/>
+ <circle cx="110" cy="86" r="1" fill="none"/>
+ <circle cx="111" cy="86" r="1" fill="none"/>
+ <circle cx="112" cy="86" r="1" fill="none"/>
+ <circle cx="113" cy="86" r="1" fill="none"/>
+ <circle cx="114" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="86" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="87" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="87" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="19" cy="87" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="20" cy="87" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="21" cy="87" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="22" cy="87" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="23" cy="87" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="24" cy="87" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="25" cy="87" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="26" cy="87" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="27" cy="87" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="28" cy="87" r="1" fill="rgba(111,13,1,0)"/>
+ <circle cx="29" cy="87" r="1" fill="rgba(107,12,1,0)"/>
+ <circle cx="30" cy="87" r="1" fill="rgba(122,11,0,0.262745)"/>
+ <circle cx="31" cy="87" r="1" fill="rgba(193,18,2,0.984314)"/>
+ <circle cx="32" cy="87" r="1" fill="rgba(197,19,2,1)"/>
+ <circle cx="33" cy="87" r="1" fill="rgba(198,18,2,1)"/>
+ <circle cx="34" cy="87" r="1" fill="rgba(198,18,1,1)"/>
+ <circle cx="35" cy="87" r="1" fill="rgba(199,18,1,1)"/>
+ <circle cx="36" cy="87" r="1" fill="rgba(200,18,1,1)"/>
+ <circle cx="37" cy="87" r="1" fill="rgba(200,17,1,1)"/>
+ <circle cx="38" cy="87" r="1" fill="rgba(201,18,1,1)"/>
+ <circle cx="39" cy="87" r="1" fill="rgba(200,18,1,1)"/>
+ <circle cx="40" cy="87" r="1" fill="rgba(206,16,1,1)"/>
+ <circle cx="41" cy="87" r="1" fill="rgba(157,25,6,1)"/>
+ <circle cx="42" cy="87" r="1" fill="rgba(73,35,15,1)"/>
+ <circle cx="43" cy="87" r="1" fill="rgba(75,30,12,1)"/>
+ <circle cx="44" cy="87" r="1" fill="rgba(70,27,10,1)"/>
+ <circle cx="45" cy="87" r="1" fill="rgba(63,23,8,1)"/>
+ <circle cx="46" cy="87" r="1" fill="rgba(57,20,7,1)"/>
+ <circle cx="47" cy="87" r="1" fill="rgba(50,17,5,1)"/>
+ <circle cx="48" cy="87" r="1" fill="rgba(43,14,3,1)"/>
+ <circle cx="49" cy="87" r="1" fill="rgba(19,10,2,1)"/>
+ <circle cx="50" cy="87" r="1" fill="rgba(78,8,1,1)"/>
+ <circle cx="51" cy="87" r="1" fill="rgba(198,14,1,1)"/>
+ <circle cx="52" cy="87" r="1" fill="rgba(200,14,1,1)"/>
+ <circle cx="53" cy="87" r="1" fill="rgba(197,14,2,1)"/>
+ <circle cx="54" cy="87" r="1" fill="rgba(196,13,2,1)"/>
+ <circle cx="55" cy="87" r="1" fill="rgba(196,13,2,1)"/>
+ <circle cx="56" cy="87" r="1" fill="rgba(196,13,2,1)"/>
+ <circle cx="57" cy="87" r="1" fill="rgba(196,13,2,1)"/>
+ <circle cx="58" cy="87" r="1" fill="rgba(196,14,3,1)"/>
+ <circle cx="59" cy="87" r="1" fill="rgba(197,15,3,1)"/>
+ <circle cx="60" cy="87" r="1" fill="rgba(198,16,3,1)"/>
+ <circle cx="61" cy="87" r="1" fill="rgba(199,17,3,1)"/>
+ <circle cx="62" cy="87" r="1" fill="rgba(198,18,4,1)"/>
+ <circle cx="63" cy="87" r="1" fill="rgba(196,17,4,1)"/>
+ <circle cx="64" cy="87" r="1" fill="rgba(195,14,1,1)"/>
+ <circle cx="65" cy="87" r="1" fill="rgba(152,6,0,1)"/>
+ <circle cx="66" cy="87" r="1" fill="rgba(133,11,2,1)"/>
+ <circle cx="67" cy="87" r="1" fill="rgba(192,18,4,1)"/>
+ <circle cx="68" cy="87" r="1" fill="rgba(192,21,4,1)"/>
+ <circle cx="69" cy="87" r="1" fill="rgba(196,25,6,1)"/>
+ <circle cx="70" cy="87" r="1" fill="rgba(200,28,8,1)"/>
+ <circle cx="71" cy="87" r="1" fill="rgba(203,32,9,1)"/>
+ <circle cx="72" cy="87" r="1" fill="rgba(204,35,10,1)"/>
+ <circle cx="73" cy="87" r="1" fill="rgba(205,38,11,1)"/>
+ <circle cx="74" cy="87" r="1" fill="rgba(207,40,12,1)"/>
+ <circle cx="75" cy="87" r="1" fill="rgba(211,44,13,1)"/>
+ <circle cx="76" cy="87" r="1" fill="rgba(176,44,15,1)"/>
+ <circle cx="77" cy="87" r="1" fill="rgba(148,48,20,1)"/>
+ <circle cx="78" cy="87" r="1" fill="rgba(156,55,24,1)"/>
+ <circle cx="79" cy="87" r="1" fill="rgba(168,61,28,1)"/>
+ <circle cx="80" cy="87" r="1" fill="rgba(197,63,25,1)"/>
+ <circle cx="81" cy="87" r="1" fill="rgba(217,64,22,1)"/>
+ <circle cx="82" cy="87" r="1" fill="rgba(216,68,25,1)"/>
+ <circle cx="83" cy="87" r="1" fill="rgba(218,72,27,1)"/>
+ <circle cx="84" cy="87" r="1" fill="rgba(220,77,30,1)"/>
+ <circle cx="85" cy="87" r="1" fill="rgba(221,82,33,1)"/>
+ <circle cx="86" cy="87" r="1" fill="rgba(223,87,36,1)"/>
+ <circle cx="87" cy="87" r="1" fill="rgba(225,93,39,1)"/>
+ <circle cx="88" cy="87" r="1" fill="rgba(227,98,42,1)"/>
+ <circle cx="89" cy="87" r="1" fill="rgba(229,103,45,1)"/>
+ <circle cx="90" cy="87" r="1" fill="rgba(231,109,50,1)"/>
+ <circle cx="91" cy="87" r="1" fill="rgba(234,115,54,1)"/>
+ <circle cx="92" cy="87" r="1" fill="rgba(236,122,57,1)"/>
+ <circle cx="93" cy="87" r="1" fill="rgba(237,127,61,1)"/>
+ <circle cx="94" cy="87" r="1" fill="rgba(239,132,64,1)"/>
+ <circle cx="95" cy="87" r="1" fill="rgba(241,136,66,1)"/>
+ <circle cx="96" cy="87" r="1" fill="rgba(241,133,63,1)"/>
+ <circle cx="97" cy="87" r="1" fill="rgba(239,123,56,1)"/>
+ <circle cx="98" cy="87" r="1" fill="rgba(241,116,48,1)"/>
+ <circle cx="99" cy="87" r="1" fill="rgba(127,41,13,0.819608)"/>
+ <circle cx="100" cy="87" r="1" fill="rgba(31,1,0,0.666667)"/>
+ <circle cx="101" cy="87" r="1" fill="rgba(39,5,0,0.588235)"/>
+ <circle cx="102" cy="87" r="1" fill="rgba(26,1,0,0.482353)"/>
+ <circle cx="103" cy="87" r="1" fill="rgba(19,1,0,0.384314)"/>
+ <circle cx="104" cy="87" r="1" fill="rgba(15,2,0,0.309804)"/>
+ <circle cx="105" cy="87" r="1" fill="rgba(10,0,0,0.235294)"/>
+ <circle cx="106" cy="87" r="1" fill="rgba(0,0,0,0.156863)"/>
+ <circle cx="107" cy="87" r="1" fill="rgba(0,0,0,0.0901961)"/>
+ <circle cx="108" cy="87" r="1" fill="rgba(0,0,0,0.0352941)"/>
+ <circle cx="109" cy="87" r="1" fill="rgba(0,0,0,0.00392157)"/>
+ <circle cx="110" cy="87" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="111" cy="87" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="112" cy="87" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="113" cy="87" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="114" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="87" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="88" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="88" r="1" fill="rgba(110,11,1,0)"/>
+ <circle cx="19" cy="88" r="1" fill="rgba(110,11,1,0)"/>
+ <circle cx="20" cy="88" r="1" fill="rgba(110,11,1,0)"/>
+ <circle cx="21" cy="88" r="1" fill="rgba(110,11,1,0)"/>
+ <circle cx="22" cy="88" r="1" fill="rgba(110,11,1,0)"/>
+ <circle cx="23" cy="88" r="1" fill="rgba(110,11,1,0)"/>
+ <circle cx="24" cy="88" r="1" fill="rgba(110,11,1,0)"/>
+ <circle cx="25" cy="88" r="1" fill="rgba(110,11,1,0)"/>
+ <circle cx="26" cy="88" r="1" fill="rgba(110,11,1,0)"/>
+ <circle cx="27" cy="88" r="1" fill="rgba(110,11,1,0)"/>
+ <circle cx="28" cy="88" r="1" fill="rgba(110,11,1,0)"/>
+ <circle cx="29" cy="88" r="1" fill="rgba(110,11,1,0)"/>
+ <circle cx="30" cy="88" r="1" fill="rgba(101,10,0,0.0509804)"/>
+ <circle cx="31" cy="88" r="1" fill="rgba(162,13,1,0.74902)"/>
+ <circle cx="32" cy="88" r="1" fill="rgba(197,16,1,1)"/>
+ <circle cx="33" cy="88" r="1" fill="rgba(194,16,2,1)"/>
+ <circle cx="34" cy="88" r="1" fill="rgba(196,17,2,1)"/>
+ <circle cx="35" cy="88" r="1" fill="rgba(197,17,2,1)"/>
+ <circle cx="36" cy="88" r="1" fill="rgba(197,17,2,1)"/>
+ <circle cx="37" cy="88" r="1" fill="rgba(198,17,1,1)"/>
+ <circle cx="38" cy="88" r="1" fill="rgba(200,17,1,1)"/>
+ <circle cx="39" cy="88" r="1" fill="rgba(199,17,1,1)"/>
+ <circle cx="40" cy="88" r="1" fill="rgba(200,17,1,1)"/>
+ <circle cx="41" cy="88" r="1" fill="rgba(198,16,2,1)"/>
+ <circle cx="42" cy="88" r="1" fill="rgba(119,28,10,1)"/>
+ <circle cx="43" cy="88" r="1" fill="rgba(64,32,13,1)"/>
+ <circle cx="44" cy="88" r="1" fill="rgba(68,27,10,1)"/>
+ <circle cx="45" cy="88" r="1" fill="rgba(62,23,8,1)"/>
+ <circle cx="46" cy="88" r="1" fill="rgba(55,20,7,1)"/>
+ <circle cx="47" cy="88" r="1" fill="rgba(46,17,5,1)"/>
+ <circle cx="48" cy="88" r="1" fill="rgba(26,13,4,1)"/>
+ <circle cx="49" cy="88" r="1" fill="rgba(50,11,2,1)"/>
+ <circle cx="50" cy="88" r="1" fill="rgba(168,13,2,1)"/>
+ <circle cx="51" cy="88" r="1" fill="rgba(202,14,2,1)"/>
+ <circle cx="52" cy="88" r="1" fill="rgba(196,13,2,1)"/>
+ <circle cx="53" cy="88" r="1" fill="rgba(196,13,2,1)"/>
+ <circle cx="54" cy="88" r="1" fill="rgba(196,13,2,1)"/>
+ <circle cx="55" cy="88" r="1" fill="rgba(196,13,3,1)"/>
+ <circle cx="56" cy="88" r="1" fill="rgba(196,13,3,1)"/>
+ <circle cx="57" cy="88" r="1" fill="rgba(196,15,3,1)"/>
+ <circle cx="58" cy="88" r="1" fill="rgba(197,17,3,1)"/>
+ <circle cx="59" cy="88" r="1" fill="rgba(197,17,3,1)"/>
+ <circle cx="60" cy="88" r="1" fill="rgba(198,18,3,1)"/>
+ <circle cx="61" cy="88" r="1" fill="rgba(198,19,4,1)"/>
+ <circle cx="62" cy="88" r="1" fill="rgba(198,19,4,1)"/>
+ <circle cx="63" cy="88" r="1" fill="rgba(196,19,4,1)"/>
+ <circle cx="64" cy="88" r="1" fill="rgba(194,15,2,1)"/>
+ <circle cx="65" cy="88" r="1" fill="rgba(149,5,0,1)"/>
+ <circle cx="66" cy="88" r="1" fill="rgba(131,11,2,1)"/>
+ <circle cx="67" cy="88" r="1" fill="rgba(191,19,4,1)"/>
+ <circle cx="68" cy="88" r="1" fill="rgba(191,22,5,1)"/>
+ <circle cx="69" cy="88" r="1" fill="rgba(196,26,7,1)"/>
+ <circle cx="70" cy="88" r="1" fill="rgba(200,31,8,1)"/>
+ <circle cx="71" cy="88" r="1" fill="rgba(203,35,10,1)"/>
+ <circle cx="72" cy="88" r="1" fill="rgba(206,38,11,1)"/>
+ <circle cx="73" cy="88" r="1" fill="rgba(206,40,13,1)"/>
+ <circle cx="74" cy="88" r="1" fill="rgba(207,42,14,1)"/>
+ <circle cx="75" cy="88" r="1" fill="rgba(208,46,14,1)"/>
+ <circle cx="76" cy="88" r="1" fill="rgba(214,48,16,1)"/>
+ <circle cx="77" cy="88" r="1" fill="rgba(215,52,17,1)"/>
+ <circle cx="78" cy="88" r="1" fill="rgba(215,55,19,1)"/>
+ <circle cx="79" cy="88" r="1" fill="rgba(217,59,20,1)"/>
+ <circle cx="80" cy="88" r="1" fill="rgba(217,62,22,1)"/>
+ <circle cx="81" cy="88" r="1" fill="rgba(216,67,24,1)"/>
+ <circle cx="82" cy="88" r="1" fill="rgba(217,71,27,1)"/>
+ <circle cx="83" cy="88" r="1" fill="rgba(219,76,29,1)"/>
+ <circle cx="84" cy="88" r="1" fill="rgba(221,81,32,1)"/>
+ <circle cx="85" cy="88" r="1" fill="rgba(222,86,35,1)"/>
+ <circle cx="86" cy="88" r="1" fill="rgba(225,91,38,1)"/>
+ <circle cx="87" cy="88" r="1" fill="rgba(227,96,41,1)"/>
+ <circle cx="88" cy="88" r="1" fill="rgba(228,101,44,1)"/>
+ <circle cx="89" cy="88" r="1" fill="rgba(231,107,48,1)"/>
+ <circle cx="90" cy="88" r="1" fill="rgba(233,113,52,1)"/>
+ <circle cx="91" cy="88" r="1" fill="rgba(236,119,56,1)"/>
+ <circle cx="92" cy="88" r="1" fill="rgba(236,125,59,1)"/>
+ <circle cx="93" cy="88" r="1" fill="rgba(238,129,62,1)"/>
+ <circle cx="94" cy="88" r="1" fill="rgba(241,134,65,1)"/>
+ <circle cx="95" cy="88" r="1" fill="rgba(241,135,65,1)"/>
+ <circle cx="96" cy="88" r="1" fill="rgba(239,127,59,1)"/>
+ <circle cx="97" cy="88" r="1" fill="rgba(242,121,53,1)"/>
+ <circle cx="98" cy="88" r="1" fill="rgba(211,95,37,0.956863)"/>
+ <circle cx="99" cy="88" r="1" fill="rgba(58,10,2,0.721569)"/>
+ <circle cx="100" cy="88" r="1" fill="rgba(40,5,1,0.643137)"/>
+ <circle cx="101" cy="88" r="1" fill="rgba(34,3,0,0.545098)"/>
+ <circle cx="102" cy="88" r="1" fill="rgba(22,1,0,0.439216)"/>
+ <circle cx="103" cy="88" r="1" fill="rgba(19,2,0,0.34902)"/>
+ <circle cx="104" cy="88" r="1" fill="rgba(17,3,0,0.27451)"/>
+ <circle cx="105" cy="88" r="1" fill="rgba(7,0,0,0.203922)"/>
+ <circle cx="106" cy="88" r="1" fill="rgba(0,0,0,0.12549)"/>
+ <circle cx="107" cy="88" r="1" fill="rgba(0,0,0,0.0627451)"/>
+ <circle cx="108" cy="88" r="1" fill="rgba(0,0,0,0.0196078)"/>
+ <circle cx="109" cy="88" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="110" cy="88" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="111" cy="88" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="112" cy="88" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="113" cy="88" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="114" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="88" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="89" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="89" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="19" cy="89" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="20" cy="89" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="21" cy="89" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="22" cy="89" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="23" cy="89" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="24" cy="89" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="25" cy="89" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="26" cy="89" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="27" cy="89" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="28" cy="89" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="29" cy="89" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="30" cy="89" r="1" fill="rgba(100,9,0,0)"/>
+ <circle cx="31" cy="89" r="1" fill="rgba(110,8,0,0.407843)"/>
+ <circle cx="32" cy="89" r="1" fill="rgba(188,15,2,0.992157)"/>
+ <circle cx="33" cy="89" r="1" fill="rgba(192,16,2,1)"/>
+ <circle cx="34" cy="89" r="1" fill="rgba(192,15,2,1)"/>
+ <circle cx="35" cy="89" r="1" fill="rgba(195,16,2,1)"/>
+ <circle cx="36" cy="89" r="1" fill="rgba(196,16,2,1)"/>
+ <circle cx="37" cy="89" r="1" fill="rgba(197,16,2,1)"/>
+ <circle cx="38" cy="89" r="1" fill="rgba(197,17,2,1)"/>
+ <circle cx="39" cy="89" r="1" fill="rgba(198,17,2,1)"/>
+ <circle cx="40" cy="89" r="1" fill="rgba(197,16,2,1)"/>
+ <circle cx="41" cy="89" r="1" fill="rgba(200,16,1,1)"/>
+ <circle cx="42" cy="89" r="1" fill="rgba(193,16,2,1)"/>
+ <circle cx="43" cy="89" r="1" fill="rgba(125,24,8,1)"/>
+ <circle cx="44" cy="89" r="1" fill="rgba(71,27,10,1)"/>
+ <circle cx="45" cy="89" r="1" fill="rgba(61,23,8,1)"/>
+ <circle cx="46" cy="89" r="1" fill="rgba(55,20,6,1)"/>
+ <circle cx="47" cy="89" r="1" fill="rgba(62,16,5,1)"/>
+ <circle cx="48" cy="89" r="1" fill="rgba(106,13,3,1)"/>
+ <circle cx="49" cy="89" r="1" fill="rgba(177,13,2,1)"/>
+ <circle cx="50" cy="89" r="1" fill="rgba(202,14,2,1)"/>
+ <circle cx="51" cy="89" r="1" fill="rgba(196,14,3,1)"/>
+ <circle cx="52" cy="89" r="1" fill="rgba(196,13,3,1)"/>
+ <circle cx="53" cy="89" r="1" fill="rgba(196,14,3,1)"/>
+ <circle cx="54" cy="89" r="1" fill="rgba(196,14,3,1)"/>
+ <circle cx="55" cy="89" r="1" fill="rgba(197,15,3,1)"/>
+ <circle cx="56" cy="89" r="1" fill="rgba(197,15,3,1)"/>
+ <circle cx="57" cy="89" r="1" fill="rgba(198,18,3,1)"/>
+ <circle cx="58" cy="89" r="1" fill="rgba(198,18,4,1)"/>
+ <circle cx="59" cy="89" r="1" fill="rgba(198,18,4,1)"/>
+ <circle cx="60" cy="89" r="1" fill="rgba(198,19,4,1)"/>
+ <circle cx="61" cy="89" r="1" fill="rgba(199,21,4,1)"/>
+ <circle cx="62" cy="89" r="1" fill="rgba(197,21,5,1)"/>
+ <circle cx="63" cy="89" r="1" fill="rgba(196,21,4,1)"/>
+ <circle cx="64" cy="89" r="1" fill="rgba(193,15,2,1)"/>
+ <circle cx="65" cy="89" r="1" fill="rgba(147,4,0,1)"/>
+ <circle cx="66" cy="89" r="1" fill="rgba(130,12,2,1)"/>
+ <circle cx="67" cy="89" r="1" fill="rgba(190,20,4,1)"/>
+ <circle cx="68" cy="89" r="1" fill="rgba(190,22,5,1)"/>
+ <circle cx="69" cy="89" r="1" fill="rgba(196,28,7,1)"/>
+ <circle cx="70" cy="89" r="1" fill="rgba(201,33,9,1)"/>
+ <circle cx="71" cy="89" r="1" fill="rgba(204,37,11,1)"/>
+ <circle cx="72" cy="89" r="1" fill="rgba(206,40,12,1)"/>
+ <circle cx="73" cy="89" r="1" fill="rgba(207,42,13,1)"/>
+ <circle cx="74" cy="89" r="1" fill="rgba(208,45,14,1)"/>
+ <circle cx="75" cy="89" r="1" fill="rgba(209,48,16,1)"/>
+ <circle cx="76" cy="89" r="1" fill="rgba(210,51,17,1)"/>
+ <circle cx="77" cy="89" r="1" fill="rgba(212,55,18,1)"/>
+ <circle cx="78" cy="89" r="1" fill="rgba(213,59,20,1)"/>
+ <circle cx="79" cy="89" r="1" fill="rgba(214,62,22,1)"/>
+ <circle cx="80" cy="89" r="1" fill="rgba(215,67,24,1)"/>
+ <circle cx="81" cy="89" r="1" fill="rgba(217,70,27,1)"/>
+ <circle cx="82" cy="89" r="1" fill="rgba(219,75,28,1)"/>
+ <circle cx="83" cy="89" r="1" fill="rgba(221,79,31,1)"/>
+ <circle cx="84" cy="89" r="1" fill="rgba(222,85,34,1)"/>
+ <circle cx="85" cy="89" r="1" fill="rgba(224,89,37,1)"/>
+ <circle cx="86" cy="89" r="1" fill="rgba(226,94,40,1)"/>
+ <circle cx="87" cy="89" r="1" fill="rgba(228,100,43,1)"/>
+ <circle cx="88" cy="89" r="1" fill="rgba(230,106,47,1)"/>
+ <circle cx="89" cy="89" r="1" fill="rgba(233,111,51,1)"/>
+ <circle cx="90" cy="89" r="1" fill="rgba(235,117,55,1)"/>
+ <circle cx="91" cy="89" r="1" fill="rgba(236,122,58,1)"/>
+ <circle cx="92" cy="89" r="1" fill="rgba(238,127,61,1)"/>
+ <circle cx="93" cy="89" r="1" fill="rgba(240,132,63,1)"/>
+ <circle cx="94" cy="89" r="1" fill="rgba(241,134,64,1)"/>
+ <circle cx="95" cy="89" r="1" fill="rgba(240,130,60,1)"/>
+ <circle cx="96" cy="89" r="1" fill="rgba(238,122,55,1)"/>
+ <circle cx="97" cy="89" r="1" fill="rgba(244,119,52,1)"/>
+ <circle cx="98" cy="89" r="1" fill="rgba(138,49,16,0.835294)"/>
+ <circle cx="99" cy="89" r="1" fill="rgba(31,0,0,0.670588)"/>
+ <circle cx="100" cy="89" r="1" fill="rgba(42,5,0,0.603922)"/>
+ <circle cx="101" cy="89" r="1" fill="rgba(29,1,0,0.498039)"/>
+ <circle cx="102" cy="89" r="1" fill="rgba(21,1,0,0.4)"/>
+ <circle cx="103" cy="89" r="1" fill="rgba(21,4,0,0.317647)"/>
+ <circle cx="104" cy="89" r="1" fill="rgba(19,4,0,0.243137)"/>
+ <circle cx="105" cy="89" r="1" fill="rgba(4,0,0,0.164706)"/>
+ <circle cx="106" cy="89" r="1" fill="rgba(0,0,0,0.0941176)"/>
+ <circle cx="107" cy="89" r="1" fill="rgba(7,0,0,0.0431373)"/>
+ <circle cx="108" cy="89" r="1" fill="rgba(0,0,0,0.00784314)"/>
+ <circle cx="109" cy="89" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="110" cy="89" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="111" cy="89" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="112" cy="89" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="113" cy="89" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="114" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="89" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="90" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="90" r="1" fill="rgba(105,9,0,0)"/>
+ <circle cx="19" cy="90" r="1" fill="rgba(105,9,0,0)"/>
+ <circle cx="20" cy="90" r="1" fill="rgba(105,9,0,0)"/>
+ <circle cx="21" cy="90" r="1" fill="rgba(105,9,0,0)"/>
+ <circle cx="22" cy="90" r="1" fill="rgba(105,9,0,0)"/>
+ <circle cx="23" cy="90" r="1" fill="rgba(105,9,0,0)"/>
+ <circle cx="24" cy="90" r="1" fill="rgba(105,9,0,0)"/>
+ <circle cx="25" cy="90" r="1" fill="rgba(105,9,0,0)"/>
+ <circle cx="26" cy="90" r="1" fill="rgba(105,9,0,0)"/>
+ <circle cx="27" cy="90" r="1" fill="rgba(105,9,0,0)"/>
+ <circle cx="28" cy="90" r="1" fill="rgba(105,9,0,0)"/>
+ <circle cx="29" cy="90" r="1" fill="rgba(105,9,0,0)"/>
+ <circle cx="30" cy="90" r="1" fill="rgba(106,9,0,0)"/>
+ <circle cx="31" cy="90" r="1" fill="rgba(86,6,0,0.156863)"/>
+ <circle cx="32" cy="90" r="1" fill="rgba(149,11,1,0.792157)"/>
+ <circle cx="33" cy="90" r="1" fill="rgba(192,15,3,1)"/>
+ <circle cx="34" cy="90" r="1" fill="rgba(189,14,2,1)"/>
+ <circle cx="35" cy="90" r="1" fill="rgba(192,15,2,1)"/>
+ <circle cx="36" cy="90" r="1" fill="rgba(194,16,3,1)"/>
+ <circle cx="37" cy="90" r="1" fill="rgba(196,16,3,1)"/>
+ <circle cx="38" cy="90" r="1" fill="rgba(195,15,3,1)"/>
+ <circle cx="39" cy="90" r="1" fill="rgba(196,15,2,1)"/>
+ <circle cx="40" cy="90" r="1" fill="rgba(196,15,2,1)"/>
+ <circle cx="41" cy="90" r="1" fill="rgba(196,15,2,1)"/>
+ <circle cx="42" cy="90" r="1" fill="rgba(198,15,2,1)"/>
+ <circle cx="43" cy="90" r="1" fill="rgba(199,14,2,1)"/>
+ <circle cx="44" cy="90" r="1" fill="rgba(175,16,3,1)"/>
+ <circle cx="45" cy="90" r="1" fill="rgba(162,16,4,1)"/>
+ <circle cx="46" cy="90" r="1" fill="rgba(163,15,3,1)"/>
+ <circle cx="47" cy="90" r="1" fill="rgba(183,14,3,1)"/>
+ <circle cx="48" cy="90" r="1" fill="rgba(200,14,3,1)"/>
+ <circle cx="49" cy="90" r="1" fill="rgba(200,14,3,1)"/>
+ <circle cx="50" cy="90" r="1" fill="rgba(196,14,3,1)"/>
+ <circle cx="51" cy="90" r="1" fill="rgba(196,16,3,1)"/>
+ <circle cx="52" cy="90" r="1" fill="rgba(197,16,3,1)"/>
+ <circle cx="53" cy="90" r="1" fill="rgba(197,16,3,1)"/>
+ <circle cx="54" cy="90" r="1" fill="rgba(197,17,3,1)"/>
+ <circle cx="55" cy="90" r="1" fill="rgba(197,18,4,1)"/>
+ <circle cx="56" cy="90" r="1" fill="rgba(198,17,4,1)"/>
+ <circle cx="57" cy="90" r="1" fill="rgba(199,20,4,1)"/>
+ <circle cx="58" cy="90" r="1" fill="rgba(199,19,4,1)"/>
+ <circle cx="59" cy="90" r="1" fill="rgba(199,20,4,1)"/>
+ <circle cx="60" cy="90" r="1" fill="rgba(200,22,5,1)"/>
+ <circle cx="61" cy="90" r="1" fill="rgba(200,23,6,1)"/>
+ <circle cx="62" cy="90" r="1" fill="rgba(198,24,6,1)"/>
+ <circle cx="63" cy="90" r="1" fill="rgba(196,23,5,1)"/>
+ <circle cx="64" cy="90" r="1" fill="rgba(192,15,2,1)"/>
+ <circle cx="65" cy="90" r="1" fill="rgba(144,4,0,1)"/>
+ <circle cx="66" cy="90" r="1" fill="rgba(130,13,2,1)"/>
+ <circle cx="67" cy="90" r="1" fill="rgba(189,21,4,1)"/>
+ <circle cx="68" cy="90" r="1" fill="rgba(189,24,6,1)"/>
+ <circle cx="69" cy="90" r="1" fill="rgba(197,30,8,1)"/>
+ <circle cx="70" cy="90" r="1" fill="rgba(202,35,10,1)"/>
+ <circle cx="71" cy="90" r="1" fill="rgba(206,40,12,1)"/>
+ <circle cx="72" cy="90" r="1" fill="rgba(207,43,13,1)"/>
+ <circle cx="73" cy="90" r="1" fill="rgba(208,46,14,1)"/>
+ <circle cx="74" cy="90" r="1" fill="rgba(210,48,15,1)"/>
+ <circle cx="75" cy="90" r="1" fill="rgba(210,51,17,1)"/>
+ <circle cx="76" cy="90" r="1" fill="rgba(211,55,19,1)"/>
+ <circle cx="77" cy="90" r="1" fill="rgba(212,59,20,1)"/>
+ <circle cx="78" cy="90" r="1" fill="rgba(214,62,22,1)"/>
+ <circle cx="79" cy="90" r="1" fill="rgba(216,66,24,1)"/>
+ <circle cx="80" cy="90" r="1" fill="rgba(217,70,27,1)"/>
+ <circle cx="81" cy="90" r="1" fill="rgba(218,74,28,1)"/>
+ <circle cx="82" cy="90" r="1" fill="rgba(221,79,31,1)"/>
+ <circle cx="83" cy="90" r="1" fill="rgba(222,84,33,1)"/>
+ <circle cx="84" cy="90" r="1" fill="rgba(224,88,36,1)"/>
+ <circle cx="85" cy="90" r="1" fill="rgba(226,93,39,1)"/>
+ <circle cx="86" cy="90" r="1" fill="rgba(227,99,42,1)"/>
+ <circle cx="87" cy="90" r="1" fill="rgba(230,104,46,1)"/>
+ <circle cx="88" cy="90" r="1" fill="rgba(232,109,49,1)"/>
+ <circle cx="89" cy="90" r="1" fill="rgba(234,115,54,1)"/>
+ <circle cx="90" cy="90" r="1" fill="rgba(236,121,56,1)"/>
+ <circle cx="91" cy="90" r="1" fill="rgba(237,125,60,1)"/>
+ <circle cx="92" cy="90" r="1" fill="rgba(238,129,62,1)"/>
+ <circle cx="93" cy="90" r="1" fill="rgba(240,133,63,1)"/>
+ <circle cx="94" cy="90" r="1" fill="rgba(240,131,61,1)"/>
+ <circle cx="95" cy="90" r="1" fill="rgba(238,123,55,1)"/>
+ <circle cx="96" cy="90" r="1" fill="rgba(242,121,52,1)"/>
+ <circle cx="97" cy="90" r="1" fill="rgba(207,92,37,0.94902)"/>
+ <circle cx="98" cy="90" r="1" fill="rgba(57,10,2,0.717647)"/>
+ <circle cx="99" cy="90" r="1" fill="rgba(40,4,0,0.647059)"/>
+ <circle cx="100" cy="90" r="1" fill="rgba(36,4,0,0.552941)"/>
+ <circle cx="101" cy="90" r="1" fill="rgba(24,1,0,0.447059)"/>
+ <circle cx="102" cy="90" r="1" fill="rgba(21,2,0,0.360784)"/>
+ <circle cx="103" cy="90" r="1" fill="rgba(22,5,0,0.282353)"/>
+ <circle cx="104" cy="90" r="1" fill="rgba(21,3,0,0.207843)"/>
+ <circle cx="105" cy="90" r="1" fill="rgba(7,0,0,0.129412)"/>
+ <circle cx="106" cy="90" r="1" fill="rgba(4,0,0,0.0666667)"/>
+ <circle cx="107" cy="90" r="1" fill="rgba(7,0,0,0.0235294)"/>
+ <circle cx="108" cy="90" r="1" fill="none"/>
+ <circle cx="109" cy="90" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="110" cy="90" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="111" cy="90" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="112" cy="90" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="113" cy="90" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="114" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="90" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="91" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="91" r="1" fill="rgba(109,8,0,0)"/>
+ <circle cx="19" cy="91" r="1" fill="rgba(109,8,0,0)"/>
+ <circle cx="20" cy="91" r="1" fill="rgba(109,8,0,0)"/>
+ <circle cx="21" cy="91" r="1" fill="rgba(109,8,0,0)"/>
+ <circle cx="22" cy="91" r="1" fill="rgba(109,8,0,0)"/>
+ <circle cx="23" cy="91" r="1" fill="rgba(109,8,0,0)"/>
+ <circle cx="24" cy="91" r="1" fill="rgba(109,8,0,0)"/>
+ <circle cx="25" cy="91" r="1" fill="rgba(109,8,0,0)"/>
+ <circle cx="26" cy="91" r="1" fill="rgba(109,8,0,0)"/>
+ <circle cx="27" cy="91" r="1" fill="rgba(109,8,0,0)"/>
+ <circle cx="28" cy="91" r="1" fill="rgba(109,8,0,0)"/>
+ <circle cx="29" cy="91" r="1" fill="rgba(109,8,0,0)"/>
+ <circle cx="30" cy="91" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="31" cy="91" r="1" fill="rgba(99,7,0,0.0470588)"/>
+ <circle cx="32" cy="91" r="1" fill="rgba(87,5,0,0.462745)"/>
+ <circle cx="33" cy="91" r="1" fill="rgba(179,13,2,0.980392)"/>
+ <circle cx="34" cy="91" r="1" fill="rgba(188,14,3,1)"/>
+ <circle cx="35" cy="91" r="1" fill="rgba(188,15,3,1)"/>
+ <circle cx="36" cy="91" r="1" fill="rgba(191,15,3,1)"/>
+ <circle cx="37" cy="91" r="1" fill="rgba(192,15,3,1)"/>
+ <circle cx="38" cy="91" r="1" fill="rgba(193,15,3,1)"/>
+ <circle cx="39" cy="91" r="1" fill="rgba(194,15,3,1)"/>
+ <circle cx="40" cy="91" r="1" fill="rgba(195,15,3,1)"/>
+ <circle cx="41" cy="91" r="1" fill="rgba(195,15,3,1)"/>
+ <circle cx="42" cy="91" r="1" fill="rgba(195,15,3,1)"/>
+ <circle cx="43" cy="91" r="1" fill="rgba(196,14,3,1)"/>
+ <circle cx="44" cy="91" r="1" fill="rgba(199,14,2,1)"/>
+ <circle cx="45" cy="91" r="1" fill="rgba(200,14,2,1)"/>
+ <circle cx="46" cy="91" r="1" fill="rgba(201,14,3,1)"/>
+ <circle cx="47" cy="91" r="1" fill="rgba(199,15,3,1)"/>
+ <circle cx="48" cy="91" r="1" fill="rgba(197,15,3,1)"/>
+ <circle cx="49" cy="91" r="1" fill="rgba(196,16,3,1)"/>
+ <circle cx="50" cy="91" r="1" fill="rgba(197,17,3,1)"/>
+ <circle cx="51" cy="91" r="1" fill="rgba(197,17,3,1)"/>
+ <circle cx="52" cy="91" r="1" fill="rgba(197,17,4,1)"/>
+ <circle cx="53" cy="91" r="1" fill="rgba(198,19,4,1)"/>
+ <circle cx="54" cy="91" r="1" fill="rgba(198,19,4,1)"/>
+ <circle cx="55" cy="91" r="1" fill="rgba(199,19,4,1)"/>
+ <circle cx="56" cy="91" r="1" fill="rgba(199,20,4,1)"/>
+ <circle cx="57" cy="91" r="1" fill="rgba(199,22,5,1)"/>
+ <circle cx="58" cy="91" r="1" fill="rgba(200,22,5,1)"/>
+ <circle cx="59" cy="91" r="1" fill="rgba(200,23,5,1)"/>
+ <circle cx="60" cy="91" r="1" fill="rgba(200,24,6,1)"/>
+ <circle cx="61" cy="91" r="1" fill="rgba(200,26,7,1)"/>
+ <circle cx="62" cy="91" r="1" fill="rgba(199,25,7,1)"/>
+ <circle cx="63" cy="91" r="1" fill="rgba(196,24,6,1)"/>
+ <circle cx="64" cy="91" r="1" fill="rgba(192,16,3,1)"/>
+ <circle cx="65" cy="91" r="1" fill="rgba(143,3,0,1)"/>
+ <circle cx="66" cy="91" r="1" fill="rgba(130,13,2,1)"/>
+ <circle cx="67" cy="91" r="1" fill="rgba(189,22,5,1)"/>
+ <circle cx="68" cy="91" r="1" fill="rgba(190,25,6,1)"/>
+ <circle cx="69" cy="91" r="1" fill="rgba(197,32,9,1)"/>
+ <circle cx="70" cy="91" r="1" fill="rgba(203,37,11,1)"/>
+ <circle cx="71" cy="91" r="1" fill="rgba(207,42,13,1)"/>
+ <circle cx="72" cy="91" r="1" fill="rgba(208,46,14,1)"/>
+ <circle cx="73" cy="91" r="1" fill="rgba(209,49,16,1)"/>
+ <circle cx="74" cy="91" r="1" fill="rgba(210,52,17,1)"/>
+ <circle cx="75" cy="91" r="1" fill="rgba(211,55,18,1)"/>
+ <circle cx="76" cy="91" r="1" fill="rgba(212,59,20,1)"/>
+ <circle cx="77" cy="91" r="1" fill="rgba(214,62,22,1)"/>
+ <circle cx="78" cy="91" r="1" fill="rgba(215,65,24,1)"/>
+ <circle cx="79" cy="91" r="1" fill="rgba(217,70,26,1)"/>
+ <circle cx="80" cy="91" r="1" fill="rgba(219,74,28,1)"/>
+ <circle cx="81" cy="91" r="1" fill="rgba(221,78,31,1)"/>
+ <circle cx="82" cy="91" r="1" fill="rgba(221,83,33,1)"/>
+ <circle cx="83" cy="91" r="1" fill="rgba(223,87,36,1)"/>
+ <circle cx="84" cy="91" r="1" fill="rgba(226,92,39,1)"/>
+ <circle cx="85" cy="91" r="1" fill="rgba(227,97,42,1)"/>
+ <circle cx="86" cy="91" r="1" fill="rgba(229,103,45,1)"/>
+ <circle cx="87" cy="91" r="1" fill="rgba(231,108,48,1)"/>
+ <circle cx="88" cy="91" r="1" fill="rgba(233,113,52,1)"/>
+ <circle cx="89" cy="91" r="1" fill="rgba(235,119,56,1)"/>
+ <circle cx="90" cy="91" r="1" fill="rgba(236,124,58,1)"/>
+ <circle cx="91" cy="91" r="1" fill="rgba(237,128,61,1)"/>
+ <circle cx="92" cy="91" r="1" fill="rgba(240,131,62,1)"/>
+ <circle cx="93" cy="91" r="1" fill="rgba(240,130,60,1)"/>
+ <circle cx="94" cy="91" r="1" fill="rgba(238,124,56,1)"/>
+ <circle cx="95" cy="91" r="1" fill="rgba(237,116,49,1)"/>
+ <circle cx="96" cy="91" r="1" fill="rgba(239,114,48,1)"/>
+ <circle cx="97" cy="91" r="1" fill="rgba(121,39,11,0.811765)"/>
+ <circle cx="98" cy="91" r="1" fill="rgba(31,0,0,0.666667)"/>
+ <circle cx="99" cy="91" r="1" fill="rgba(40,5,1,0.6)"/>
+ <circle cx="100" cy="91" r="1" fill="rgba(29,2,0,0.498039)"/>
+ <circle cx="101" cy="91" r="1" fill="rgba(21,1,0,0.4)"/>
+ <circle cx="102" cy="91" r="1" fill="rgba(22,4,0,0.317647)"/>
+ <circle cx="103" cy="91" r="1" fill="rgba(24,6,0,0.243137)"/>
+ <circle cx="104" cy="91" r="1" fill="rgba(21,2,0,0.168627)"/>
+ <circle cx="105" cy="91" r="1" fill="rgba(7,0,0,0.0980392)"/>
+ <circle cx="106" cy="91" r="1" fill="rgba(4,0,0,0.0431373)"/>
+ <circle cx="107" cy="91" r="1" fill="rgba(4,0,0,0.0117647)"/>
+ <circle cx="108" cy="91" r="1" fill="none"/>
+ <circle cx="109" cy="91" r="1" fill="none"/>
+ <circle cx="110" cy="91" r="1" fill="none"/>
+ <circle cx="111" cy="91" r="1" fill="none"/>
+ <circle cx="112" cy="91" r="1" fill="none"/>
+ <circle cx="113" cy="91" r="1" fill="none"/>
+ <circle cx="114" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="91" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="92" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="19" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="20" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="21" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="22" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="23" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="24" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="25" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="26" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="27" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="28" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="29" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="30" cy="92" r="1" fill="rgba(113,8,0,0)"/>
+ <circle cx="31" cy="92" r="1" fill="rgba(114,8,0,0.00392157)"/>
+ <circle cx="32" cy="92" r="1" fill="rgba(73,4,0,0.227451)"/>
+ <circle cx="33" cy="92" r="1" fill="rgba(123,8,1,0.74902)"/>
+ <circle cx="34" cy="92" r="1" fill="rgba(192,15,3,1)"/>
+ <circle cx="35" cy="92" r="1" fill="rgba(188,15,3,1)"/>
+ <circle cx="36" cy="92" r="1" fill="rgba(189,15,3,1)"/>
+ <circle cx="37" cy="92" r="1" fill="rgba(191,16,3,1)"/>
+ <circle cx="38" cy="92" r="1" fill="rgba(192,17,3,1)"/>
+ <circle cx="39" cy="92" r="1" fill="rgba(193,16,3,1)"/>
+ <circle cx="40" cy="92" r="1" fill="rgba(194,16,3,1)"/>
+ <circle cx="41" cy="92" r="1" fill="rgba(195,17,3,1)"/>
+ <circle cx="42" cy="92" r="1" fill="rgba(195,16,3,1)"/>
+ <circle cx="43" cy="92" r="1" fill="rgba(196,16,3,1)"/>
+ <circle cx="44" cy="92" r="1" fill="rgba(196,17,3,1)"/>
+ <circle cx="45" cy="92" r="1" fill="rgba(196,17,3,1)"/>
+ <circle cx="46" cy="92" r="1" fill="rgba(196,17,3,1)"/>
+ <circle cx="47" cy="92" r="1" fill="rgba(196,18,3,1)"/>
+ <circle cx="48" cy="92" r="1" fill="rgba(197,17,3,1)"/>
+ <circle cx="49" cy="92" r="1" fill="rgba(197,17,4,1)"/>
+ <circle cx="50" cy="92" r="1" fill="rgba(197,19,4,1)"/>
+ <circle cx="51" cy="92" r="1" fill="rgba(198,18,4,1)"/>
+ <circle cx="52" cy="92" r="1" fill="rgba(199,18,4,1)"/>
+ <circle cx="53" cy="92" r="1" fill="rgba(199,20,5,1)"/>
+ <circle cx="54" cy="92" r="1" fill="rgba(199,20,5,1)"/>
+ <circle cx="55" cy="92" r="1" fill="rgba(200,20,5,1)"/>
+ <circle cx="56" cy="92" r="1" fill="rgba(200,22,5,1)"/>
+ <circle cx="57" cy="92" r="1" fill="rgba(200,24,6,1)"/>
+ <circle cx="58" cy="92" r="1" fill="rgba(200,24,6,1)"/>
+ <circle cx="59" cy="92" r="1" fill="rgba(201,25,6,1)"/>
+ <circle cx="60" cy="92" r="1" fill="rgba(201,27,7,1)"/>
+ <circle cx="61" cy="92" r="1" fill="rgba(200,27,8,1)"/>
+ <circle cx="62" cy="92" r="1" fill="rgba(200,27,7,1)"/>
+ <circle cx="63" cy="92" r="1" fill="rgba(196,26,7,1)"/>
+ <circle cx="64" cy="92" r="1" fill="rgba(190,17,3,1)"/>
+ <circle cx="65" cy="92" r="1" fill="rgba(140,4,0,1)"/>
+ <circle cx="66" cy="92" r="1" fill="rgba(130,13,3,1)"/>
+ <circle cx="67" cy="92" r="1" fill="rgba(189,22,5,1)"/>
+ <circle cx="68" cy="92" r="1" fill="rgba(191,26,6,1)"/>
+ <circle cx="69" cy="92" r="1" fill="rgba(197,33,9,1)"/>
+ <circle cx="70" cy="92" r="1" fill="rgba(203,41,12,1)"/>
+ <circle cx="71" cy="92" r="1" fill="rgba(207,45,14,1)"/>
+ <circle cx="72" cy="92" r="1" fill="rgba(209,50,16,1)"/>
+ <circle cx="73" cy="92" r="1" fill="rgba(210,52,18,1)"/>
+ <circle cx="74" cy="92" r="1" fill="rgba(211,56,19,1)"/>
+ <circle cx="75" cy="92" r="1" fill="rgba(213,59,21,1)"/>
+ <circle cx="76" cy="92" r="1" fill="rgba(214,63,22,1)"/>
+ <circle cx="77" cy="92" r="1" fill="rgba(216,66,24,1)"/>
+ <circle cx="78" cy="92" r="1" fill="rgba(217,69,26,1)"/>
+ <circle cx="79" cy="92" r="1" fill="rgba(218,73,27,1)"/>
+ <circle cx="80" cy="92" r="1" fill="rgba(221,78,30,1)"/>
+ <circle cx="81" cy="92" r="1" fill="rgba(221,82,33,1)"/>
+ <circle cx="82" cy="92" r="1" fill="rgba(223,86,35,1)"/>
+ <circle cx="83" cy="92" r="1" fill="rgba(225,91,38,1)"/>
+ <circle cx="84" cy="92" r="1" fill="rgba(227,96,42,1)"/>
+ <circle cx="85" cy="92" r="1" fill="rgba(228,101,44,1)"/>
+ <circle cx="86" cy="92" r="1" fill="rgba(230,107,48,1)"/>
+ <circle cx="87" cy="92" r="1" fill="rgba(233,112,51,1)"/>
+ <circle cx="88" cy="92" r="1" fill="rgba(235,117,55,1)"/>
+ <circle cx="89" cy="92" r="1" fill="rgba(236,123,57,1)"/>
+ <circle cx="90" cy="92" r="1" fill="rgba(237,126,60,1)"/>
+ <circle cx="91" cy="92" r="1" fill="rgba(239,130,62,1)"/>
+ <circle cx="92" cy="92" r="1" fill="rgba(240,131,62,1)"/>
+ <circle cx="93" cy="92" r="1" fill="rgba(239,125,56,1)"/>
+ <circle cx="94" cy="92" r="1" fill="rgba(236,116,49,1)"/>
+ <circle cx="95" cy="92" r="1" fill="rgba(241,115,48,1)"/>
+ <circle cx="96" cy="92" r="1" fill="rgba(188,78,29,0.917647)"/>
+ <circle cx="97" cy="92" r="1" fill="rgba(43,4,1,0.698039)"/>
+ <circle cx="98" cy="92" r="1" fill="rgba(40,5,1,0.631373)"/>
+ <circle cx="99" cy="92" r="1" fill="rgba(33,3,0,0.541176)"/>
+ <circle cx="100" cy="92" r="1" fill="rgba(24,1,0,0.439216)"/>
+ <circle cx="101" cy="92" r="1" fill="rgba(22,2,0,0.352941)"/>
+ <circle cx="102" cy="92" r="1" fill="rgba(26,7,1,0.278431)"/>
+ <circle cx="103" cy="92" r="1" fill="rgba(28,7,1,0.2)"/>
+ <circle cx="104" cy="92" r="1" fill="rgba(17,1,0,0.12549)"/>
+ <circle cx="105" cy="92" r="1" fill="rgba(4,0,0,0.0666667)"/>
+ <circle cx="106" cy="92" r="1" fill="rgba(0,0,0,0.0235294)"/>
+ <circle cx="107" cy="92" r="1" fill="rgba(4,0,0,0.00392157)"/>
+ <circle cx="108" cy="92" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="109" cy="92" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="110" cy="92" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="111" cy="92" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="112" cy="92" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="113" cy="92" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="114" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="92" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="93" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="19" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="20" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="21" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="22" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="23" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="24" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="25" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="26" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="27" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="28" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="29" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="30" cy="93" r="1" fill="rgba(110,8,0,0)"/>
+ <circle cx="31" cy="93" r="1" fill="rgba(112,8,0,0)"/>
+ <circle cx="32" cy="93" r="1" fill="rgba(94,6,0,0.105882)"/>
+ <circle cx="33" cy="93" r="1" fill="rgba(53,3,0,0.447059)"/>
+ <circle cx="34" cy="93" r="1" fill="rgba(163,13,3,0.917647)"/>
+ <circle cx="35" cy="93" r="1" fill="rgba(192,17,3,1)"/>
+ <circle cx="36" cy="93" r="1" fill="rgba(188,17,3,1)"/>
+ <circle cx="37" cy="93" r="1" fill="rgba(191,17,3,1)"/>
+ <circle cx="38" cy="93" r="1" fill="rgba(192,17,4,1)"/>
+ <circle cx="39" cy="93" r="1" fill="rgba(194,18,4,1)"/>
+ <circle cx="40" cy="93" r="1" fill="rgba(194,19,4,1)"/>
+ <circle cx="41" cy="93" r="1" fill="rgba(196,18,4,1)"/>
+ <circle cx="42" cy="93" r="1" fill="rgba(196,19,4,1)"/>
+ <circle cx="43" cy="93" r="1" fill="rgba(196,18,4,1)"/>
+ <circle cx="44" cy="93" r="1" fill="rgba(196,19,4,1)"/>
+ <circle cx="45" cy="93" r="1" fill="rgba(196,19,4,1)"/>
+ <circle cx="46" cy="93" r="1" fill="rgba(196,20,4,1)"/>
+ <circle cx="47" cy="93" r="1" fill="rgba(197,20,4,1)"/>
+ <circle cx="48" cy="93" r="1" fill="rgba(198,20,4,1)"/>
+ <circle cx="49" cy="93" r="1" fill="rgba(198,20,4,1)"/>
+ <circle cx="50" cy="93" r="1" fill="rgba(198,20,4,1)"/>
+ <circle cx="51" cy="93" r="1" fill="rgba(199,21,5,1)"/>
+ <circle cx="52" cy="93" r="1" fill="rgba(199,21,5,1)"/>
+ <circle cx="53" cy="93" r="1" fill="rgba(199,21,5,1)"/>
+ <circle cx="54" cy="93" r="1" fill="rgba(200,23,6,1)"/>
+ <circle cx="55" cy="93" r="1" fill="rgba(200,23,6,1)"/>
+ <circle cx="56" cy="93" r="1" fill="rgba(200,24,6,1)"/>
+ <circle cx="57" cy="93" r="1" fill="rgba(201,25,6,1)"/>
+ <circle cx="58" cy="93" r="1" fill="rgba(201,26,7,1)"/>
+ <circle cx="59" cy="93" r="1" fill="rgba(202,27,7,1)"/>
+ <circle cx="60" cy="93" r="1" fill="rgba(202,29,8,1)"/>
+ <circle cx="61" cy="93" r="1" fill="rgba(202,29,8,1)"/>
+ <circle cx="62" cy="93" r="1" fill="rgba(200,29,8,1)"/>
+ <circle cx="63" cy="93" r="1" fill="rgba(196,28,7,1)"/>
+ <circle cx="64" cy="93" r="1" fill="rgba(189,18,3,1)"/>
+ <circle cx="65" cy="93" r="1" fill="rgba(138,3,0,1)"/>
+ <circle cx="66" cy="93" r="1" fill="rgba(130,14,3,1)"/>
+ <circle cx="67" cy="93" r="1" fill="rgba(189,24,5,1)"/>
+ <circle cx="68" cy="93" r="1" fill="rgba(191,29,7,1)"/>
+ <circle cx="69" cy="93" r="1" fill="rgba(199,36,10,1)"/>
+ <circle cx="70" cy="93" r="1" fill="rgba(204,43,13,1)"/>
+ <circle cx="71" cy="93" r="1" fill="rgba(208,49,16,1)"/>
+ <circle cx="72" cy="93" r="1" fill="rgba(210,53,18,1)"/>
+ <circle cx="73" cy="93" r="1" fill="rgba(212,56,20,1)"/>
+ <circle cx="74" cy="93" r="1" fill="rgba(213,59,21,1)"/>
+ <circle cx="75" cy="93" r="1" fill="rgba(214,62,22,1)"/>
+ <circle cx="76" cy="93" r="1" fill="rgba(215,66,24,1)"/>
+ <circle cx="77" cy="93" r="1" fill="rgba(217,69,26,1)"/>
+ <circle cx="78" cy="93" r="1" fill="rgba(219,73,28,1)"/>
+ <circle cx="79" cy="93" r="1" fill="rgba(221,77,30,1)"/>
+ <circle cx="80" cy="93" r="1" fill="rgba(221,82,33,1)"/>
+ <circle cx="81" cy="93" r="1" fill="rgba(223,86,35,1)"/>
+ <circle cx="82" cy="93" r="1" fill="rgba(225,90,37,1)"/>
+ <circle cx="83" cy="93" r="1" fill="rgba(227,95,41,1)"/>
+ <circle cx="84" cy="93" r="1" fill="rgba(227,100,43,1)"/>
+ <circle cx="85" cy="93" r="1" fill="rgba(230,106,47,1)"/>
+ <circle cx="86" cy="93" r="1" fill="rgba(233,111,51,1)"/>
+ <circle cx="87" cy="93" r="1" fill="rgba(234,116,54,1)"/>
+ <circle cx="88" cy="93" r="1" fill="rgba(236,121,57,1)"/>
+ <circle cx="89" cy="93" r="1" fill="rgba(237,125,60,1)"/>
+ <circle cx="90" cy="93" r="1" fill="rgba(238,128,61,1)"/>
+ <circle cx="91" cy="93" r="1" fill="rgba(240,131,61,1)"/>
+ <circle cx="92" cy="93" r="1" fill="rgba(238,126,56,1)"/>
+ <circle cx="93" cy="93" r="1" fill="rgba(237,117,50,1)"/>
+ <circle cx="94" cy="93" r="1" fill="rgba(237,111,46,1)"/>
+ <circle cx="95" cy="93" r="1" fill="rgba(226,100,40,0.984314)"/>
+ <circle cx="96" cy="93" r="1" fill="rgba(88,23,6,0.764706)"/>
+ <circle cx="97" cy="93" r="1" fill="rgba(34,2,0,0.654902)"/>
+ <circle cx="98" cy="93" r="1" fill="rgba(37,4,0,0.576471)"/>
+ <circle cx="99" cy="93" r="1" fill="rgba(24,1,0,0.478431)"/>
+ <circle cx="100" cy="93" r="1" fill="rgba(21,1,0,0.384314)"/>
+ <circle cx="101" cy="93" r="1" fill="rgba(26,5,1,0.309804)"/>
+ <circle cx="102" cy="93" r="1" fill="rgba(33,9,2,0.235294)"/>
+ <circle cx="103" cy="93" r="1" fill="rgba(33,7,1,0.156863)"/>
+ <circle cx="104" cy="93" r="1" fill="rgba(19,1,0,0.0862745)"/>
+ <circle cx="105" cy="93" r="1" fill="rgba(4,0,0,0.0352941)"/>
+ <circle cx="106" cy="93" r="1" fill="rgba(0,0,0,0.00784314)"/>
+ <circle cx="107" cy="93" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="108" cy="93" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="109" cy="93" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="110" cy="93" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="111" cy="93" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="112" cy="93" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="113" cy="93" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="114" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="93" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="94" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="19" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="20" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="21" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="22" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="23" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="24" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="25" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="26" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="27" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="28" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="29" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="30" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="31" cy="94" r="1" fill="rgba(98,6,0,0)"/>
+ <circle cx="32" cy="94" r="1" fill="rgba(97,6,0,0.0196078)"/>
+ <circle cx="33" cy="94" r="1" fill="rgba(53,2,0,0.270588)"/>
+ <circle cx="34" cy="94" r="1" fill="rgba(78,6,0,0.635294)"/>
+ <circle cx="35" cy="94" r="1" fill="rgba(186,18,4,0.988235)"/>
+ <circle cx="36" cy="94" r="1" fill="rgba(189,18,4,1)"/>
+ <circle cx="37" cy="94" r="1" fill="rgba(189,18,4,1)"/>
+ <circle cx="38" cy="94" r="1" fill="rgba(192,19,4,1)"/>
+ <circle cx="39" cy="94" r="1" fill="rgba(194,20,4,1)"/>
+ <circle cx="40" cy="94" r="1" fill="rgba(195,20,4,1)"/>
+ <circle cx="41" cy="94" r="1" fill="rgba(196,21,4,1)"/>
+ <circle cx="42" cy="94" r="1" fill="rgba(196,21,4,1)"/>
+ <circle cx="43" cy="94" r="1" fill="rgba(196,21,5,1)"/>
+ <circle cx="44" cy="94" r="1" fill="rgba(197,21,5,1)"/>
+ <circle cx="45" cy="94" r="1" fill="rgba(197,21,5,1)"/>
+ <circle cx="46" cy="94" r="1" fill="rgba(197,21,5,1)"/>
+ <circle cx="47" cy="94" r="1" fill="rgba(197,21,5,1)"/>
+ <circle cx="48" cy="94" r="1" fill="rgba(198,22,5,1)"/>
+ <circle cx="49" cy="94" r="1" fill="rgba(199,22,5,1)"/>
+ <circle cx="50" cy="94" r="1" fill="rgba(199,23,5,1)"/>
+ <circle cx="51" cy="94" r="1" fill="rgba(200,23,5,1)"/>
+ <circle cx="52" cy="94" r="1" fill="rgba(200,24,6,1)"/>
+ <circle cx="53" cy="94" r="1" fill="rgba(200,25,6,1)"/>
+ <circle cx="54" cy="94" r="1" fill="rgba(200,25,6,1)"/>
+ <circle cx="55" cy="94" r="1" fill="rgba(200,26,6,1)"/>
+ <circle cx="56" cy="94" r="1" fill="rgba(201,27,7,1)"/>
+ <circle cx="57" cy="94" r="1" fill="rgba(202,28,7,1)"/>
+ <circle cx="58" cy="94" r="1" fill="rgba(202,29,8,1)"/>
+ <circle cx="59" cy="94" r="1" fill="rgba(203,30,8,1)"/>
+ <circle cx="60" cy="94" r="1" fill="rgba(203,31,8,1)"/>
+ <circle cx="61" cy="94" r="1" fill="rgba(203,32,9,1)"/>
+ <circle cx="62" cy="94" r="1" fill="rgba(202,32,8,1)"/>
+ <circle cx="63" cy="94" r="1" fill="rgba(198,30,8,1)"/>
+ <circle cx="64" cy="94" r="1" fill="rgba(189,18,3,1)"/>
+ <circle cx="65" cy="94" r="1" fill="rgba(137,3,0,1)"/>
+ <circle cx="66" cy="94" r="1" fill="rgba(131,16,3,1)"/>
+ <circle cx="67" cy="94" r="1" fill="rgba(191,26,6,1)"/>
+ <circle cx="68" cy="94" r="1" fill="rgba(192,32,8,1)"/>
+ <circle cx="69" cy="94" r="1" fill="rgba(200,39,11,1)"/>
+ <circle cx="70" cy="94" r="1" fill="rgba(206,46,15,1)"/>
+ <circle cx="71" cy="94" r="1" fill="rgba(210,52,17,1)"/>
+ <circle cx="72" cy="94" r="1" fill="rgba(211,56,20,1)"/>
+ <circle cx="73" cy="94" r="1" fill="rgba(213,60,21,1)"/>
+ <circle cx="74" cy="94" r="1" fill="rgba(214,63,22,1)"/>
+ <circle cx="75" cy="94" r="1" fill="rgba(217,66,24,1)"/>
+ <circle cx="76" cy="94" r="1" fill="rgba(217,69,26,1)"/>
+ <circle cx="77" cy="94" r="1" fill="rgba(219,73,27,1)"/>
+ <circle cx="78" cy="94" r="1" fill="rgba(220,77,30,1)"/>
+ <circle cx="79" cy="94" r="1" fill="rgba(222,82,33,1)"/>
+ <circle cx="80" cy="94" r="1" fill="rgba(223,86,35,1)"/>
+ <circle cx="81" cy="94" r="1" fill="rgba(224,90,37,1)"/>
+ <circle cx="82" cy="94" r="1" fill="rgba(226,95,41,1)"/>
+ <circle cx="83" cy="94" r="1" fill="rgba(227,100,43,1)"/>
+ <circle cx="84" cy="94" r="1" fill="rgba(230,105,47,1)"/>
+ <circle cx="85" cy="94" r="1" fill="rgba(232,110,50,1)"/>
+ <circle cx="86" cy="94" r="1" fill="rgba(233,115,53,1)"/>
+ <circle cx="87" cy="94" r="1" fill="rgba(236,120,56,1)"/>
+ <circle cx="88" cy="94" r="1" fill="rgba(237,124,59,1)"/>
+ <circle cx="89" cy="94" r="1" fill="rgba(238,127,60,1)"/>
+ <circle cx="90" cy="94" r="1" fill="rgba(239,129,61,1)"/>
+ <circle cx="91" cy="94" r="1" fill="rgba(239,126,57,1)"/>
+ <circle cx="92" cy="94" r="1" fill="rgba(236,117,49,1)"/>
+ <circle cx="93" cy="94" r="1" fill="rgba(234,109,44,1)"/>
+ <circle cx="94" cy="94" r="1" fill="rgba(239,107,43,1)"/>
+ <circle cx="95" cy="94" r="1" fill="rgba(144,49,16,0.85098)"/>
+ <circle cx="96" cy="94" r="1" fill="rgba(29,0,0,0.678431)"/>
+ <circle cx="97" cy="94" r="1" fill="rgba(42,5,1,0.615686)"/>
+ <circle cx="98" cy="94" r="1" fill="rgba(31,2,0,0.513725)"/>
+ <circle cx="99" cy="94" r="1" fill="rgba(21,0,0,0.423529)"/>
+ <circle cx="100" cy="94" r="1" fill="rgba(21,3,0,0.341176)"/>
+ <circle cx="101" cy="94" r="1" fill="rgba(29,9,2,0.270588)"/>
+ <circle cx="102" cy="94" r="1" fill="rgba(37,11,2,0.192157)"/>
+ <circle cx="103" cy="94" r="1" fill="rgba(33,6,0,0.113725)"/>
+ <circle cx="104" cy="94" r="1" fill="rgba(15,0,0,0.054902)"/>
+ <circle cx="105" cy="94" r="1" fill="rgba(4,0,0,0.0196078)"/>
+ <circle cx="106" cy="94" r="1" fill="none"/>
+ <circle cx="107" cy="94" r="1" fill="none"/>
+ <circle cx="108" cy="94" r="1" fill="none"/>
+ <circle cx="109" cy="94" r="1" fill="none"/>
+ <circle cx="110" cy="94" r="1" fill="none"/>
+ <circle cx="111" cy="94" r="1" fill="none"/>
+ <circle cx="112" cy="94" r="1" fill="none"/>
+ <circle cx="113" cy="94" r="1" fill="none"/>
+ <circle cx="114" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="94" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="95" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="19" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="20" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="21" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="22" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="23" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="24" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="25" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="26" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="27" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="28" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="29" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="30" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="31" cy="95" r="1" fill="rgba(100,6,0,0)"/>
+ <circle cx="32" cy="95" r="1" fill="rgba(103,7,0,0)"/>
+ <circle cx="33" cy="95" r="1" fill="rgba(90,5,0,0.141176)"/>
+ <circle cx="34" cy="95" r="1" fill="rgba(26,1,0,0.427451)"/>
+ <circle cx="35" cy="95" r="1" fill="rgba(123,11,2,0.780392)"/>
+ <circle cx="36" cy="95" r="1" fill="rgba(194,20,4,1)"/>
+ <circle cx="37" cy="95" r="1" fill="rgba(188,19,4,1)"/>
+ <circle cx="38" cy="95" r="1" fill="rgba(190,21,4,1)"/>
+ <circle cx="39" cy="95" r="1" fill="rgba(192,21,5,1)"/>
+ <circle cx="40" cy="95" r="1" fill="rgba(194,22,5,1)"/>
+ <circle cx="41" cy="95" r="1" fill="rgba(196,22,5,1)"/>
+ <circle cx="42" cy="95" r="1" fill="rgba(196,23,5,1)"/>
+ <circle cx="43" cy="95" r="1" fill="rgba(196,23,5,1)"/>
+ <circle cx="44" cy="95" r="1" fill="rgba(197,23,5,1)"/>
+ <circle cx="45" cy="95" r="1" fill="rgba(198,23,5,1)"/>
+ <circle cx="46" cy="95" r="1" fill="rgba(198,23,6,1)"/>
+ <circle cx="47" cy="95" r="1" fill="rgba(199,24,6,1)"/>
+ <circle cx="48" cy="95" r="1" fill="rgba(199,24,6,1)"/>
+ <circle cx="49" cy="95" r="1" fill="rgba(199,25,6,1)"/>
+ <circle cx="50" cy="95" r="1" fill="rgba(200,25,6,1)"/>
+ <circle cx="51" cy="95" r="1" fill="rgba(200,26,7,1)"/>
+ <circle cx="52" cy="95" r="1" fill="rgba(200,27,7,1)"/>
+ <circle cx="53" cy="95" r="1" fill="rgba(201,27,7,1)"/>
+ <circle cx="54" cy="95" r="1" fill="rgba(201,28,7,1)"/>
+ <circle cx="55" cy="95" r="1" fill="rgba(201,29,7,1)"/>
+ <circle cx="56" cy="95" r="1" fill="rgba(202,30,8,1)"/>
+ <circle cx="57" cy="95" r="1" fill="rgba(203,31,8,1)"/>
+ <circle cx="58" cy="95" r="1" fill="rgba(203,32,9,1)"/>
+ <circle cx="59" cy="95" r="1" fill="rgba(203,33,9,1)"/>
+ <circle cx="60" cy="95" r="1" fill="rgba(204,34,9,1)"/>
+ <circle cx="61" cy="95" r="1" fill="rgba(204,35,10,1)"/>
+ <circle cx="62" cy="95" r="1" fill="rgba(203,35,10,1)"/>
+ <circle cx="63" cy="95" r="1" fill="rgba(199,32,9,1)"/>
+ <circle cx="64" cy="95" r="1" fill="rgba(190,19,3,1)"/>
+ <circle cx="65" cy="95" r="1" fill="rgba(138,3,0,1)"/>
+ <circle cx="66" cy="95" r="1" fill="rgba(132,18,3,1)"/>
+ <circle cx="67" cy="95" r="1" fill="rgba(193,29,7,1)"/>
+ <circle cx="68" cy="95" r="1" fill="rgba(194,34,9,1)"/>
+ <circle cx="69" cy="95" r="1" fill="rgba(202,43,13,1)"/>
+ <circle cx="70" cy="95" r="1" fill="rgba(207,50,16,1)"/>
+ <circle cx="71" cy="95" r="1" fill="rgba(211,56,19,1)"/>
+ <circle cx="72" cy="95" r="1" fill="rgba(214,60,21,1)"/>
+ <circle cx="73" cy="95" r="1" fill="rgba(215,64,22,1)"/>
+ <circle cx="74" cy="95" r="1" fill="rgba(216,67,24,1)"/>
+ <circle cx="75" cy="95" r="1" fill="rgba(217,70,27,1)"/>
+ <circle cx="76" cy="95" r="1" fill="rgba(219,74,29,1)"/>
+ <circle cx="77" cy="95" r="1" fill="rgba(220,78,30,1)"/>
+ <circle cx="78" cy="95" r="1" fill="rgba(221,82,33,1)"/>
+ <circle cx="79" cy="95" r="1" fill="rgba(223,86,34,1)"/>
+ <circle cx="80" cy="95" r="1" fill="rgba(224,90,37,1)"/>
+ <circle cx="81" cy="95" r="1" fill="rgba(226,94,40,1)"/>
+ <circle cx="82" cy="95" r="1" fill="rgba(227,99,42,1)"/>
+ <circle cx="83" cy="95" r="1" fill="rgba(230,105,47,1)"/>
+ <circle cx="84" cy="95" r="1" fill="rgba(231,109,49,1)"/>
+ <circle cx="85" cy="95" r="1" fill="rgba(233,114,53,1)"/>
+ <circle cx="86" cy="95" r="1" fill="rgba(235,118,56,1)"/>
+ <circle cx="87" cy="95" r="1" fill="rgba(236,122,58,1)"/>
+ <circle cx="88" cy="95" r="1" fill="rgba(238,125,59,1)"/>
+ <circle cx="89" cy="95" r="1" fill="rgba(239,127,59,1)"/>
+ <circle cx="90" cy="95" r="1" fill="rgba(239,127,57,1)"/>
+ <circle cx="91" cy="95" r="1" fill="rgba(237,117,49,1)"/>
+ <circle cx="92" cy="95" r="1" fill="rgba(233,107,43,1)"/>
+ <circle cx="93" cy="95" r="1" fill="rgba(239,105,42,1)"/>
+ <circle cx="94" cy="95" r="1" fill="rgba(187,72,24,0.92549)"/>
+ <circle cx="95" cy="95" r="1" fill="rgba(45,5,1,0.709804)"/>
+ <circle cx="96" cy="95" r="1" fill="rgba(40,4,1,0.65098)"/>
+ <circle cx="97" cy="95" r="1" fill="rgba(36,3,0,0.556863)"/>
+ <circle cx="98" cy="95" r="1" fill="rgba(22,0,0,0.458824)"/>
+ <circle cx="99" cy="95" r="1" fill="rgba(19,1,0,0.372549)"/>
+ <circle cx="100" cy="95" r="1" fill="rgba(26,7,1,0.305882)"/>
+ <circle cx="101" cy="95" r="1" fill="rgba(34,12,3,0.227451)"/>
+ <circle cx="102" cy="95" r="1" fill="rgba(40,13,2,0.145098)"/>
+ <circle cx="103" cy="95" r="1" fill="rgba(31,5,0,0.0784314)"/>
+ <circle cx="104" cy="95" r="1" fill="rgba(12,0,0,0.0313725)"/>
+ <circle cx="105" cy="95" r="1" fill="rgba(0,0,0,0.00392157)"/>
+ <circle cx="106" cy="95" r="1" fill="none"/>
+ <circle cx="107" cy="95" r="1" fill="none"/>
+ <circle cx="108" cy="95" r="1" fill="none"/>
+ <circle cx="109" cy="95" r="1" fill="none"/>
+ <circle cx="110" cy="95" r="1" fill="none"/>
+ <circle cx="111" cy="95" r="1" fill="none"/>
+ <circle cx="112" cy="95" r="1" fill="none"/>
+ <circle cx="113" cy="95" r="1" fill="none"/>
+ <circle cx="114" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="95" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="96" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="19" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="20" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="21" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="22" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="23" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="24" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="25" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="26" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="27" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="28" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="29" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="30" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="31" cy="96" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="32" cy="96" r="1" fill="rgba(116,8,0,0)"/>
+ <circle cx="33" cy="96" r="1" fill="rgba(112,8,0,0.0313725)"/>
+ <circle cx="34" cy="96" r="1" fill="rgba(64,3,0,0.298039)"/>
+ <circle cx="35" cy="96" r="1" fill="rgba(29,2,0,0.52549)"/>
+ <circle cx="36" cy="96" r="1" fill="rgba(157,16,3,0.878431)"/>
+ <circle cx="37" cy="96" r="1" fill="rgba(194,22,5,1)"/>
+ <circle cx="38" cy="96" r="1" fill="rgba(189,21,5,1)"/>
+ <circle cx="39" cy="96" r="1" fill="rgba(191,22,5,1)"/>
+ <circle cx="40" cy="96" r="1" fill="rgba(192,23,5,1)"/>
+ <circle cx="41" cy="96" r="1" fill="rgba(195,24,6,1)"/>
+ <circle cx="42" cy="96" r="1" fill="rgba(196,24,6,1)"/>
+ <circle cx="43" cy="96" r="1" fill="rgba(196,24,6,1)"/>
+ <circle cx="44" cy="96" r="1" fill="rgba(197,25,6,1)"/>
+ <circle cx="45" cy="96" r="1" fill="rgba(198,26,6,1)"/>
+ <circle cx="46" cy="96" r="1" fill="rgba(199,26,7,1)"/>
+ <circle cx="47" cy="96" r="1" fill="rgba(200,27,7,1)"/>
+ <circle cx="48" cy="96" r="1" fill="rgba(200,27,7,1)"/>
+ <circle cx="49" cy="96" r="1" fill="rgba(200,28,7,1)"/>
+ <circle cx="50" cy="96" r="1" fill="rgba(200,28,7,1)"/>
+ <circle cx="51" cy="96" r="1" fill="rgba(200,28,7,1)"/>
+ <circle cx="52" cy="96" r="1" fill="rgba(201,29,8,1)"/>
+ <circle cx="53" cy="96" r="1" fill="rgba(201,30,8,1)"/>
+ <circle cx="54" cy="96" r="1" fill="rgba(202,30,8,1)"/>
+ <circle cx="55" cy="96" r="1" fill="rgba(203,32,9,1)"/>
+ <circle cx="56" cy="96" r="1" fill="rgba(203,32,9,1)"/>
+ <circle cx="57" cy="96" r="1" fill="rgba(203,33,9,1)"/>
+ <circle cx="58" cy="96" r="1" fill="rgba(204,35,10,1)"/>
+ <circle cx="59" cy="96" r="1" fill="rgba(204,36,10,1)"/>
+ <circle cx="60" cy="96" r="1" fill="rgba(205,38,11,1)"/>
+ <circle cx="61" cy="96" r="1" fill="rgba(205,39,11,1)"/>
+ <circle cx="62" cy="96" r="1" fill="rgba(203,39,11,1)"/>
+ <circle cx="63" cy="96" r="1" fill="rgba(200,36,10,1)"/>
+ <circle cx="64" cy="96" r="1" fill="rgba(192,21,4,1)"/>
+ <circle cx="65" cy="96" r="1" fill="rgba(140,3,0,1)"/>
+ <circle cx="66" cy="96" r="1" fill="rgba(135,19,4,1)"/>
+ <circle cx="67" cy="96" r="1" fill="rgba(196,32,8,1)"/>
+ <circle cx="68" cy="96" r="1" fill="rgba(197,37,10,1)"/>
+ <circle cx="69" cy="96" r="1" fill="rgba(203,45,14,1)"/>
+ <circle cx="70" cy="96" r="1" fill="rgba(209,53,18,1)"/>
+ <circle cx="71" cy="96" r="1" fill="rgba(213,60,20,1)"/>
+ <circle cx="72" cy="96" r="1" fill="rgba(215,64,23,1)"/>
+ <circle cx="73" cy="96" r="1" fill="rgba(217,67,25,1)"/>
+ <circle cx="74" cy="96" r="1" fill="rgba(217,71,27,1)"/>
+ <circle cx="75" cy="96" r="1" fill="rgba(218,75,29,1)"/>
+ <circle cx="76" cy="96" r="1" fill="rgba(220,78,30,1)"/>
+ <circle cx="77" cy="96" r="1" fill="rgba(221,82,33,1)"/>
+ <circle cx="78" cy="96" r="1" fill="rgba(223,86,35,1)"/>
+ <circle cx="79" cy="96" r="1" fill="rgba(224,91,37,1)"/>
+ <circle cx="80" cy="96" r="1" fill="rgba(226,95,40,1)"/>
+ <circle cx="81" cy="96" r="1" fill="rgba(227,99,42,1)"/>
+ <circle cx="82" cy="96" r="1" fill="rgba(230,104,46,1)"/>
+ <circle cx="83" cy="96" r="1" fill="rgba(231,109,48,1)"/>
+ <circle cx="84" cy="96" r="1" fill="rgba(233,114,52,1)"/>
+ <circle cx="85" cy="96" r="1" fill="rgba(235,118,55,1)"/>
+ <circle cx="86" cy="96" r="1" fill="rgba(236,121,57,1)"/>
+ <circle cx="87" cy="96" r="1" fill="rgba(237,124,58,1)"/>
+ <circle cx="88" cy="96" r="1" fill="rgba(238,125,58,1)"/>
+ <circle cx="89" cy="96" r="1" fill="rgba(238,124,56,1)"/>
+ <circle cx="90" cy="96" r="1" fill="rgba(236,117,50,1)"/>
+ <circle cx="91" cy="96" r="1" fill="rgba(233,105,42,1)"/>
+ <circle cx="92" cy="96" r="1" fill="rgba(234,100,39,1)"/>
+ <circle cx="93" cy="96" r="1" fill="rgba(214,84,30,0.972549)"/>
+ <circle cx="94" cy="96" r="1" fill="rgba(80,18,4,0.752941)"/>
+ <circle cx="95" cy="96" r="1" fill="rgba(34,3,0,0.666667)"/>
+ <circle cx="96" cy="96" r="1" fill="rgba(39,4,0,0.596078)"/>
+ <circle cx="97" cy="96" r="1" fill="rgba(26,1,0,0.498039)"/>
+ <circle cx="98" cy="96" r="1" fill="rgba(19,0,0,0.411765)"/>
+ <circle cx="99" cy="96" r="1" fill="rgba(21,4,0,0.337255)"/>
+ <circle cx="100" cy="96" r="1" fill="rgba(33,9,2,0.262745)"/>
+ <circle cx="101" cy="96" r="1" fill="rgba(43,14,3,0.180392)"/>
+ <circle cx="102" cy="96" r="1" fill="rgba(45,10,1,0.101961)"/>
+ <circle cx="103" cy="96" r="1" fill="rgba(31,1,0,0.0470588)"/>
+ <circle cx="104" cy="96" r="1" fill="rgba(4,0,0,0.0156863)"/>
+ <circle cx="105" cy="96" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="96" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="107" cy="96" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="108" cy="96" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="109" cy="96" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="110" cy="96" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="111" cy="96" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="112" cy="96" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="113" cy="96" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="114" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="96" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="97" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="19" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="20" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="21" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="22" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="23" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="24" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="25" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="26" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="27" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="28" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="29" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="30" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="31" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="32" cy="97" r="1" fill="rgba(114,8,0,0)"/>
+ <circle cx="33" cy="97" r="1" fill="rgba(115,8,0,0)"/>
+ <circle cx="34" cy="97" r="1" fill="rgba(96,6,0,0.141176)"/>
+ <circle cx="35" cy="97" r="1" fill="rgba(29,1,0,0.419608)"/>
+ <circle cx="36" cy="97" r="1" fill="rgba(57,4,0,0.6)"/>
+ <circle cx="37" cy="97" r="1" fill="rgba(176,21,5,0.945098)"/>
+ <circle cx="38" cy="97" r="1" fill="rgba(193,24,6,1)"/>
+ <circle cx="39" cy="97" r="1" fill="rgba(190,23,6,1)"/>
+ <circle cx="40" cy="97" r="1" fill="rgba(192,24,6,1)"/>
+ <circle cx="41" cy="97" r="1" fill="rgba(193,25,6,1)"/>
+ <circle cx="42" cy="97" r="1" fill="rgba(196,26,6,1)"/>
+ <circle cx="43" cy="97" r="1" fill="rgba(197,27,7,1)"/>
+ <circle cx="44" cy="97" r="1" fill="rgba(197,27,7,1)"/>
+ <circle cx="45" cy="97" r="1" fill="rgba(198,28,7,1)"/>
+ <circle cx="46" cy="97" r="1" fill="rgba(199,29,7,1)"/>
+ <circle cx="47" cy="97" r="1" fill="rgba(200,29,7,1)"/>
+ <circle cx="48" cy="97" r="1" fill="rgba(200,30,8,1)"/>
+ <circle cx="49" cy="97" r="1" fill="rgba(201,30,8,1)"/>
+ <circle cx="50" cy="97" r="1" fill="rgba(201,31,8,1)"/>
+ <circle cx="51" cy="97" r="1" fill="rgba(202,31,8,1)"/>
+ <circle cx="52" cy="97" r="1" fill="rgba(202,32,9,1)"/>
+ <circle cx="53" cy="97" r="1" fill="rgba(202,33,9,1)"/>
+ <circle cx="54" cy="97" r="1" fill="rgba(203,34,9,1)"/>
+ <circle cx="55" cy="97" r="1" fill="rgba(203,34,10,1)"/>
+ <circle cx="56" cy="97" r="1" fill="rgba(203,35,10,1)"/>
+ <circle cx="57" cy="97" r="1" fill="rgba(204,36,10,1)"/>
+ <circle cx="58" cy="97" r="1" fill="rgba(204,38,11,1)"/>
+ <circle cx="59" cy="97" r="1" fill="rgba(206,39,12,1)"/>
+ <circle cx="60" cy="97" r="1" fill="rgba(206,41,12,1)"/>
+ <circle cx="61" cy="97" r="1" fill="rgba(206,42,13,1)"/>
+ <circle cx="62" cy="97" r="1" fill="rgba(204,42,13,1)"/>
+ <circle cx="63" cy="97" r="1" fill="rgba(201,39,11,1)"/>
+ <circle cx="64" cy="97" r="1" fill="rgba(192,22,4,1)"/>
+ <circle cx="65" cy="97" r="1" fill="rgba(140,3,0,1)"/>
+ <circle cx="66" cy="97" r="1" fill="rgba(137,20,4,1)"/>
+ <circle cx="67" cy="97" r="1" fill="rgba(198,33,9,1)"/>
+ <circle cx="68" cy="97" r="1" fill="rgba(197,39,10,1)"/>
+ <circle cx="69" cy="97" r="1" fill="rgba(204,48,15,1)"/>
+ <circle cx="70" cy="97" r="1" fill="rgba(210,56,19,1)"/>
+ <circle cx="71" cy="97" r="1" fill="rgba(214,63,22,1)"/>
+ <circle cx="72" cy="97" r="1" fill="rgba(216,68,25,1)"/>
+ <circle cx="73" cy="97" r="1" fill="rgba(217,72,27,1)"/>
+ <circle cx="74" cy="97" r="1" fill="rgba(218,75,29,1)"/>
+ <circle cx="75" cy="97" r="1" fill="rgba(221,79,31,1)"/>
+ <circle cx="76" cy="97" r="1" fill="rgba(221,83,33,1)"/>
+ <circle cx="77" cy="97" r="1" fill="rgba(223,86,35,1)"/>
+ <circle cx="78" cy="97" r="1" fill="rgba(224,91,38,1)"/>
+ <circle cx="79" cy="97" r="1" fill="rgba(226,95,41,1)"/>
+ <circle cx="80" cy="97" r="1" fill="rgba(227,99,42,1)"/>
+ <circle cx="81" cy="97" r="1" fill="rgba(229,104,46,1)"/>
+ <circle cx="82" cy="97" r="1" fill="rgba(231,108,48,1)"/>
+ <circle cx="83" cy="97" r="1" fill="rgba(233,113,52,1)"/>
+ <circle cx="84" cy="97" r="1" fill="rgba(234,117,55,1)"/>
+ <circle cx="85" cy="97" r="1" fill="rgba(236,119,56,1)"/>
+ <circle cx="86" cy="97" r="1" fill="rgba(236,122,56,1)"/>
+ <circle cx="87" cy="97" r="1" fill="rgba(237,123,56,1)"/>
+ <circle cx="88" cy="97" r="1" fill="rgba(238,120,54,1)"/>
+ <circle cx="89" cy="97" r="1" fill="rgba(236,113,48,1)"/>
+ <circle cx="90" cy="97" r="1" fill="rgba(232,104,41,1)"/>
+ <circle cx="91" cy="97" r="1" fill="rgba(232,95,36,1)"/>
+ <circle cx="92" cy="97" r="1" fill="rgba(225,87,30,0.992157)"/>
+ <circle cx="93" cy="97" r="1" fill="rgba(105,28,7,0.796078)"/>
+ <circle cx="94" cy="97" r="1" fill="rgba(29,2,0,0.67451)"/>
+ <circle cx="95" cy="97" r="1" fill="rgba(40,5,1,0.619608)"/>
+ <circle cx="96" cy="97" r="1" fill="rgba(29,2,0,0.533333)"/>
+ <circle cx="97" cy="97" r="1" fill="rgba(19,0,0,0.447059)"/>
+ <circle cx="98" cy="97" r="1" fill="rgba(19,1,0,0.372549)"/>
+ <circle cx="99" cy="97" r="1" fill="rgba(28,7,1,0.298039)"/>
+ <circle cx="100" cy="97" r="1" fill="rgba(39,12,3,0.219608)"/>
+ <circle cx="101" cy="97" r="1" fill="rgba(47,14,3,0.133333)"/>
+ <circle cx="102" cy="97" r="1" fill="rgba(46,5,0,0.0666667)"/>
+ <circle cx="103" cy="97" r="1" fill="rgba(21,0,0,0.027451)"/>
+ <circle cx="104" cy="97" r="1" fill="rgba(0,0,0,0.00392157)"/>
+ <circle cx="105" cy="97" r="1" fill="rgba(17,4,0,0)"/>
+ <circle cx="106" cy="97" r="1" fill="rgba(17,4,0,0)"/>
+ <circle cx="107" cy="97" r="1" fill="rgba(17,4,0,0)"/>
+ <circle cx="108" cy="97" r="1" fill="rgba(17,4,0,0)"/>
+ <circle cx="109" cy="97" r="1" fill="rgba(17,4,0,0)"/>
+ <circle cx="110" cy="97" r="1" fill="rgba(17,4,0,0)"/>
+ <circle cx="111" cy="97" r="1" fill="rgba(17,4,0,0)"/>
+ <circle cx="112" cy="97" r="1" fill="rgba(17,4,0,0)"/>
+ <circle cx="113" cy="97" r="1" fill="rgba(17,4,0,0)"/>
+ <circle cx="114" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="97" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="98" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="19" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="20" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="21" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="22" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="23" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="24" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="25" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="26" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="27" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="28" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="29" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="30" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="31" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="32" cy="98" r="1" fill="rgba(114,7,1,0)"/>
+ <circle cx="33" cy="98" r="1" fill="rgba(115,7,1,0)"/>
+ <circle cx="34" cy="98" r="1" fill="rgba(110,7,0,0.0235294)"/>
+ <circle cx="35" cy="98" r="1" fill="rgba(68,3,0,0.278431)"/>
+ <circle cx="36" cy="98" r="1" fill="rgba(0,0,0,0.482353)"/>
+ <circle cx="37" cy="98" r="1" fill="rgba(77,8,1,0.65098)"/>
+ <circle cx="38" cy="98" r="1" fill="rgba(185,24,6,0.976471)"/>
+ <circle cx="39" cy="98" r="1" fill="rgba(193,25,6,1)"/>
+ <circle cx="40" cy="98" r="1" fill="rgba(191,25,6,1)"/>
+ <circle cx="41" cy="98" r="1" fill="rgba(192,26,6,1)"/>
+ <circle cx="42" cy="98" r="1" fill="rgba(194,27,7,1)"/>
+ <circle cx="43" cy="98" r="1" fill="rgba(196,28,7,1)"/>
+ <circle cx="44" cy="98" r="1" fill="rgba(197,29,7,1)"/>
+ <circle cx="45" cy="98" r="1" fill="rgba(199,30,8,1)"/>
+ <circle cx="46" cy="98" r="1" fill="rgba(199,31,8,1)"/>
+ <circle cx="47" cy="98" r="1" fill="rgba(200,31,8,1)"/>
+ <circle cx="48" cy="98" r="1" fill="rgba(201,32,9,1)"/>
+ <circle cx="49" cy="98" r="1" fill="rgba(202,33,9,1)"/>
+ <circle cx="50" cy="98" r="1" fill="rgba(202,34,9,1)"/>
+ <circle cx="51" cy="98" r="1" fill="rgba(203,34,9,1)"/>
+ <circle cx="52" cy="98" r="1" fill="rgba(203,35,10,1)"/>
+ <circle cx="53" cy="98" r="1" fill="rgba(203,36,10,1)"/>
+ <circle cx="54" cy="98" r="1" fill="rgba(203,36,10,1)"/>
+ <circle cx="55" cy="98" r="1" fill="rgba(204,37,11,1)"/>
+ <circle cx="56" cy="98" r="1" fill="rgba(205,39,11,1)"/>
+ <circle cx="57" cy="98" r="1" fill="rgba(205,40,11,1)"/>
+ <circle cx="58" cy="98" r="1" fill="rgba(205,42,13,1)"/>
+ <circle cx="59" cy="98" r="1" fill="rgba(206,42,13,1)"/>
+ <circle cx="60" cy="98" r="1" fill="rgba(207,45,13,1)"/>
+ <circle cx="61" cy="98" r="1" fill="rgba(207,46,14,1)"/>
+ <circle cx="62" cy="98" r="1" fill="rgba(206,45,14,1)"/>
+ <circle cx="63" cy="98" r="1" fill="rgba(202,41,12,1)"/>
+ <circle cx="64" cy="98" r="1" fill="rgba(192,23,5,1)"/>
+ <circle cx="65" cy="98" r="1" fill="rgba(139,2,0,1)"/>
+ <circle cx="66" cy="98" r="1" fill="rgba(138,21,4,1)"/>
+ <circle cx="67" cy="98" r="1" fill="rgba(199,34,9,1)"/>
+ <circle cx="68" cy="98" r="1" fill="rgba(197,40,11,1)"/>
+ <circle cx="69" cy="98" r="1" fill="rgba(204,49,15,1)"/>
+ <circle cx="70" cy="98" r="1" fill="rgba(210,58,20,1)"/>
+ <circle cx="71" cy="98" r="1" fill="rgba(214,66,24,1)"/>
+ <circle cx="72" cy="98" r="1" fill="rgba(217,72,27,1)"/>
+ <circle cx="73" cy="98" r="1" fill="rgba(219,76,30,1)"/>
+ <circle cx="74" cy="98" r="1" fill="rgba(220,80,32,1)"/>
+ <circle cx="75" cy="98" r="1" fill="rgba(221,83,33,1)"/>
+ <circle cx="76" cy="98" r="1" fill="rgba(223,87,35,1)"/>
+ <circle cx="77" cy="98" r="1" fill="rgba(224,91,37,1)"/>
+ <circle cx="78" cy="98" r="1" fill="rgba(226,95,40,1)"/>
+ <circle cx="79" cy="98" r="1" fill="rgba(227,99,43,1)"/>
+ <circle cx="80" cy="98" r="1" fill="rgba(230,104,46,1)"/>
+ <circle cx="81" cy="98" r="1" fill="rgba(230,108,49,1)"/>
+ <circle cx="82" cy="98" r="1" fill="rgba(232,112,51,1)"/>
+ <circle cx="83" cy="98" r="1" fill="rgba(233,115,53,1)"/>
+ <circle cx="84" cy="98" r="1" fill="rgba(234,117,55,1)"/>
+ <circle cx="85" cy="98" r="1" fill="rgba(235,118,54,1)"/>
+ <circle cx="86" cy="98" r="1" fill="rgba(236,118,53,1)"/>
+ <circle cx="87" cy="98" r="1" fill="rgba(236,116,49,1)"/>
+ <circle cx="88" cy="98" r="1" fill="rgba(235,109,44,1)"/>
+ <circle cx="89" cy="98" r="1" fill="rgba(231,99,37,1)"/>
+ <circle cx="90" cy="98" r="1" fill="rgba(229,90,33,1)"/>
+ <circle cx="91" cy="98" r="1" fill="rgba(229,85,29,1)"/>
+ <circle cx="92" cy="98" r="1" fill="rgba(133,38,10,0.839216)"/>
+ <circle cx="93" cy="98" r="1" fill="rgba(31,2,0,0.678431)"/>
+ <circle cx="94" cy="98" r="1" fill="rgba(40,5,1,0.635294)"/>
+ <circle cx="95" cy="98" r="1" fill="rgba(31,3,0,0.552941)"/>
+ <circle cx="96" cy="98" r="1" fill="rgba(21,0,0,0.47451)"/>
+ <circle cx="97" cy="98" r="1" fill="rgba(15,0,0,0.4)"/>
+ <circle cx="98" cy="98" r="1" fill="rgba(22,4,0,0.329412)"/>
+ <circle cx="99" cy="98" r="1" fill="rgba(34,10,2,0.254902)"/>
+ <circle cx="100" cy="98" r="1" fill="rgba(46,14,3,0.172549)"/>
+ <circle cx="101" cy="98" r="1" fill="rgba(51,12,1,0.0941176)"/>
+ <circle cx="102" cy="98" r="1" fill="rgba(42,2,0,0.0392157)"/>
+ <circle cx="103" cy="98" r="1" fill="rgba(4,0,0,0.0117647)"/>
+ <circle cx="104" cy="98" r="1" fill="rgba(0,2,0,0)"/>
+ <circle cx="105" cy="98" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="106" cy="98" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="107" cy="98" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="108" cy="98" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="109" cy="98" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="110" cy="98" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="111" cy="98" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="112" cy="98" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="113" cy="98" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="114" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="98" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="99" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="19" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="20" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="21" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="22" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="23" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="24" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="25" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="26" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="27" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="28" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="29" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="30" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="31" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="32" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="33" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="34" cy="99" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="35" cy="99" r="1" fill="rgba(95,6,0,0.101961)"/>
+ <circle cx="36" cy="99" r="1" fill="rgba(43,2,0,0.392157)"/>
+ <circle cx="37" cy="99" r="1" fill="rgba(0,0,0,0.501961)"/>
+ <circle cx="38" cy="99" r="1" fill="rgba(94,10,2,0.701961)"/>
+ <circle cx="39" cy="99" r="1" fill="rgba(191,27,7,0.992157)"/>
+ <circle cx="40" cy="99" r="1" fill="rgba(193,27,7,1)"/>
+ <circle cx="41" cy="99" r="1" fill="rgba(192,27,7,1)"/>
+ <circle cx="42" cy="99" r="1" fill="rgba(192,28,7,1)"/>
+ <circle cx="43" cy="99" r="1" fill="rgba(194,29,8,1)"/>
+ <circle cx="44" cy="99" r="1" fill="rgba(196,31,8,1)"/>
+ <circle cx="45" cy="99" r="1" fill="rgba(197,31,8,1)"/>
+ <circle cx="46" cy="99" r="1" fill="rgba(199,32,9,1)"/>
+ <circle cx="47" cy="99" r="1" fill="rgba(200,33,9,1)"/>
+ <circle cx="48" cy="99" r="1" fill="rgba(200,34,9,1)"/>
+ <circle cx="49" cy="99" r="1" fill="rgba(201,35,10,1)"/>
+ <circle cx="50" cy="99" r="1" fill="rgba(203,36,10,1)"/>
+ <circle cx="51" cy="99" r="1" fill="rgba(203,38,11,1)"/>
+ <circle cx="52" cy="99" r="1" fill="rgba(203,38,11,1)"/>
+ <circle cx="53" cy="99" r="1" fill="rgba(204,39,11,1)"/>
+ <circle cx="54" cy="99" r="1" fill="rgba(204,40,12,1)"/>
+ <circle cx="55" cy="99" r="1" fill="rgba(205,41,12,1)"/>
+ <circle cx="56" cy="99" r="1" fill="rgba(205,42,13,1)"/>
+ <circle cx="57" cy="99" r="1" fill="rgba(205,44,13,1)"/>
+ <circle cx="58" cy="99" r="1" fill="rgba(206,45,14,1)"/>
+ <circle cx="59" cy="99" r="1" fill="rgba(207,46,14,1)"/>
+ <circle cx="60" cy="99" r="1" fill="rgba(207,48,15,1)"/>
+ <circle cx="61" cy="99" r="1" fill="rgba(208,48,16,1)"/>
+ <circle cx="62" cy="99" r="1" fill="rgba(207,48,16,1)"/>
+ <circle cx="63" cy="99" r="1" fill="rgba(203,44,13,1)"/>
+ <circle cx="64" cy="99" r="1" fill="rgba(193,26,5,1)"/>
+ <circle cx="65" cy="99" r="1" fill="rgba(137,2,0,1)"/>
+ <circle cx="66" cy="99" r="1" fill="rgba(138,22,5,1)"/>
+ <circle cx="67" cy="99" r="1" fill="rgba(199,35,9,1)"/>
+ <circle cx="68" cy="99" r="1" fill="rgba(197,39,10,1)"/>
+ <circle cx="69" cy="99" r="1" fill="rgba(203,49,14,1)"/>
+ <circle cx="70" cy="99" r="1" fill="rgba(210,60,20,1)"/>
+ <circle cx="71" cy="99" r="1" fill="rgba(215,69,25,1)"/>
+ <circle cx="72" cy="99" r="1" fill="rgba(218,75,29,1)"/>
+ <circle cx="73" cy="99" r="1" fill="rgba(221,81,31,1)"/>
+ <circle cx="74" cy="99" r="1" fill="rgba(221,84,33,1)"/>
+ <circle cx="75" cy="99" r="1" fill="rgba(223,88,36,1)"/>
+ <circle cx="76" cy="99" r="1" fill="rgba(224,92,38,1)"/>
+ <circle cx="77" cy="99" r="1" fill="rgba(226,95,41,1)"/>
+ <circle cx="78" cy="99" r="1" fill="rgba(227,99,43,1)"/>
+ <circle cx="79" cy="99" r="1" fill="rgba(229,103,46,1)"/>
+ <circle cx="80" cy="99" r="1" fill="rgba(230,107,48,1)"/>
+ <circle cx="81" cy="99" r="1" fill="rgba(232,111,50,1)"/>
+ <circle cx="82" cy="99" r="1" fill="rgba(233,113,51,1)"/>
+ <circle cx="83" cy="99" r="1" fill="rgba(233,114,51,1)"/>
+ <circle cx="84" cy="99" r="1" fill="rgba(234,115,51,1)"/>
+ <circle cx="85" cy="99" r="1" fill="rgba(234,113,48,1)"/>
+ <circle cx="86" cy="99" r="1" fill="rgba(235,110,46,1)"/>
+ <circle cx="87" cy="99" r="1" fill="rgba(233,103,39,1)"/>
+ <circle cx="88" cy="99" r="1" fill="rgba(229,92,32,1)"/>
+ <circle cx="89" cy="99" r="1" fill="rgba(227,84,28,1)"/>
+ <circle cx="90" cy="99" r="1" fill="rgba(230,81,26,1)"/>
+ <circle cx="91" cy="99" r="1" fill="rgba(148,41,11,0.862745)"/>
+ <circle cx="92" cy="99" r="1" fill="rgba(37,4,1,0.690196)"/>
+ <circle cx="93" cy="99" r="1" fill="rgba(40,5,1,0.643137)"/>
+ <circle cx="94" cy="99" r="1" fill="rgba(34,4,0,0.572549)"/>
+ <circle cx="95" cy="99" r="1" fill="rgba(21,0,0,0.490196)"/>
+ <circle cx="96" cy="99" r="1" fill="rgba(15,0,0,0.419608)"/>
+ <circle cx="97" cy="99" r="1" fill="rgba(19,2,0,0.352941)"/>
+ <circle cx="98" cy="99" r="1" fill="rgba(29,9,1,0.286275)"/>
+ <circle cx="99" cy="99" r="1" fill="rgba(42,13,3,0.207843)"/>
+ <circle cx="100" cy="99" r="1" fill="rgba(50,16,3,0.121569)"/>
+ <circle cx="101" cy="99" r="1" fill="rgba(40,6,0,0.0588235)"/>
+ <circle cx="102" cy="99" r="1" fill="rgba(15,0,0,0.0196078)"/>
+ <circle cx="103" cy="99" r="1" fill="rgba(7,3,0,0)"/>
+ <circle cx="104" cy="99" r="1" fill="rgba(15,6,0,0)"/>
+ <circle cx="105" cy="99" r="1" fill="rgba(15,6,0,0)"/>
+ <circle cx="106" cy="99" r="1" fill="rgba(15,6,0,0)"/>
+ <circle cx="107" cy="99" r="1" fill="rgba(15,6,0,0)"/>
+ <circle cx="108" cy="99" r="1" fill="rgba(15,6,0,0)"/>
+ <circle cx="109" cy="99" r="1" fill="rgba(15,6,0,0)"/>
+ <circle cx="110" cy="99" r="1" fill="rgba(15,6,0,0)"/>
+ <circle cx="111" cy="99" r="1" fill="rgba(15,6,0,0)"/>
+ <circle cx="112" cy="99" r="1" fill="rgba(15,6,0,0)"/>
+ <circle cx="113" cy="99" r="1" fill="rgba(15,6,0,0)"/>
+ <circle cx="114" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="99" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="100" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="19" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="20" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="21" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="22" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="23" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="24" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="25" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="26" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="27" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="28" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="29" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="30" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="31" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="32" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="33" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="34" cy="100" r="1" fill="rgba(109,7,1,0)"/>
+ <circle cx="35" cy="100" r="1" fill="rgba(112,7,1,0.00784314)"/>
+ <circle cx="36" cy="100" r="1" fill="rgba(82,4,0,0.207843)"/>
+ <circle cx="37" cy="100" r="1" fill="rgba(24,0,0,0.458824)"/>
+ <circle cx="38" cy="100" r="1" fill="rgba(4,1,0,0.521569)"/>
+ <circle cx="39" cy="100" r="1" fill="rgba(107,14,3,0.741176)"/>
+ <circle cx="40" cy="100" r="1" fill="rgba(192,29,7,0.996078)"/>
+ <circle cx="41" cy="100" r="1" fill="rgba(194,30,8,1)"/>
+ <circle cx="42" cy="100" r="1" fill="rgba(192,30,8,1)"/>
+ <circle cx="43" cy="100" r="1" fill="rgba(192,31,8,1)"/>
+ <circle cx="44" cy="100" r="1" fill="rgba(194,32,9,1)"/>
+ <circle cx="45" cy="100" r="1" fill="rgba(196,32,9,1)"/>
+ <circle cx="46" cy="100" r="1" fill="rgba(198,34,9,1)"/>
+ <circle cx="47" cy="100" r="1" fill="rgba(199,35,10,1)"/>
+ <circle cx="48" cy="100" r="1" fill="rgba(200,37,10,1)"/>
+ <circle cx="49" cy="100" r="1" fill="rgba(201,37,11,1)"/>
+ <circle cx="50" cy="100" r="1" fill="rgba(203,39,11,1)"/>
+ <circle cx="51" cy="100" r="1" fill="rgba(203,40,11,1)"/>
+ <circle cx="52" cy="100" r="1" fill="rgba(204,41,12,1)"/>
+ <circle cx="53" cy="100" r="1" fill="rgba(205,43,13,1)"/>
+ <circle cx="54" cy="100" r="1" fill="rgba(205,44,13,1)"/>
+ <circle cx="55" cy="100" r="1" fill="rgba(206,45,14,1)"/>
+ <circle cx="56" cy="100" r="1" fill="rgba(206,45,14,1)"/>
+ <circle cx="57" cy="100" r="1" fill="rgba(207,47,15,1)"/>
+ <circle cx="58" cy="100" r="1" fill="rgba(208,48,16,1)"/>
+ <circle cx="59" cy="100" r="1" fill="rgba(209,50,16,1)"/>
+ <circle cx="60" cy="100" r="1" fill="rgba(209,51,17,1)"/>
+ <circle cx="61" cy="100" r="1" fill="rgba(209,52,18,1)"/>
+ <circle cx="62" cy="100" r="1" fill="rgba(207,51,16,1)"/>
+ <circle cx="63" cy="100" r="1" fill="rgba(203,46,14,1)"/>
+ <circle cx="64" cy="100" r="1" fill="rgba(192,25,5,1)"/>
+ <circle cx="65" cy="100" r="1" fill="rgba(135,1,0,1)"/>
+ <circle cx="66" cy="100" r="1" fill="rgba(138,23,5,1)"/>
+ <circle cx="67" cy="100" r="1" fill="rgba(199,35,8,1)"/>
+ <circle cx="68" cy="100" r="1" fill="rgba(196,38,10,1)"/>
+ <circle cx="69" cy="100" r="1" fill="rgba(203,49,14,1)"/>
+ <circle cx="70" cy="100" r="1" fill="rgba(210,61,21,1)"/>
+ <circle cx="71" cy="100" r="1" fill="rgba(216,72,27,1)"/>
+ <circle cx="72" cy="100" r="1" fill="rgba(219,79,31,1)"/>
+ <circle cx="73" cy="100" r="1" fill="rgba(221,85,34,1)"/>
+ <circle cx="74" cy="100" r="1" fill="rgba(223,88,37,1)"/>
+ <circle cx="75" cy="100" r="1" fill="rgba(224,92,38,1)"/>
+ <circle cx="76" cy="100" r="1" fill="rgba(227,96,41,1)"/>
+ <circle cx="77" cy="100" r="1" fill="rgba(227,100,43,1)"/>
+ <circle cx="78" cy="100" r="1" fill="rgba(229,103,46,1)"/>
+ <circle cx="79" cy="100" r="1" fill="rgba(230,106,48,1)"/>
+ <circle cx="80" cy="100" r="1" fill="rgba(231,109,48,1)"/>
+ <circle cx="81" cy="100" r="1" fill="rgba(232,111,49,1)"/>
+ <circle cx="82" cy="100" r="1" fill="rgba(233,111,48,1)"/>
+ <circle cx="83" cy="100" r="1" fill="rgba(233,110,48,1)"/>
+ <circle cx="84" cy="100" r="1" fill="rgba(233,107,44,1)"/>
+ <circle cx="85" cy="100" r="1" fill="rgba(233,103,40,1)"/>
+ <circle cx="86" cy="100" r="1" fill="rgba(230,95,34,1)"/>
+ <circle cx="87" cy="100" r="1" fill="rgba(227,86,28,1)"/>
+ <circle cx="88" cy="100" r="1" fill="rgba(226,78,24,1)"/>
+ <circle cx="89" cy="100" r="1" fill="rgba(228,76,23,1)"/>
+ <circle cx="90" cy="100" r="1" fill="rgba(158,44,11,0.882353)"/>
+ <circle cx="91" cy="100" r="1" fill="rgba(40,4,1,0.698039)"/>
+ <circle cx="92" cy="100" r="1" fill="rgba(39,4,1,0.65098)"/>
+ <circle cx="93" cy="100" r="1" fill="rgba(34,4,0,0.580392)"/>
+ <circle cx="94" cy="100" r="1" fill="rgba(22,0,0,0.505882)"/>
+ <circle cx="95" cy="100" r="1" fill="rgba(15,0,0,0.439216)"/>
+ <circle cx="96" cy="100" r="1" fill="rgba(15,0,0,0.376471)"/>
+ <circle cx="97" cy="100" r="1" fill="rgba(24,6,0,0.313725)"/>
+ <circle cx="98" cy="100" r="1" fill="rgba(37,11,2,0.235294)"/>
+ <circle cx="99" cy="100" r="1" fill="rgba(47,15,3,0.152941)"/>
+ <circle cx="100" cy="100" r="1" fill="rgba(51,13,1,0.0784314)"/>
+ <circle cx="101" cy="100" r="1" fill="rgba(42,3,0,0.027451)"/>
+ <circle cx="102" cy="100" r="1" fill="rgba(0,0,0,0.00784314)"/>
+ <circle cx="103" cy="100" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="104" cy="100" r="1" fill="rgba(10,3,0,0)"/>
+ <circle cx="105" cy="100" r="1" fill="rgba(10,3,0,0)"/>
+ <circle cx="106" cy="100" r="1" fill="rgba(10,3,0,0)"/>
+ <circle cx="107" cy="100" r="1" fill="rgba(10,3,0,0)"/>
+ <circle cx="108" cy="100" r="1" fill="rgba(10,3,0,0)"/>
+ <circle cx="109" cy="100" r="1" fill="rgba(10,3,0,0)"/>
+ <circle cx="110" cy="100" r="1" fill="rgba(10,3,0,0)"/>
+ <circle cx="111" cy="100" r="1" fill="rgba(10,3,0,0)"/>
+ <circle cx="112" cy="100" r="1" fill="rgba(10,3,0,0)"/>
+ <circle cx="113" cy="100" r="1" fill="rgba(10,3,0,0)"/>
+ <circle cx="114" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="100" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="101" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="19" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="20" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="21" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="22" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="23" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="24" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="25" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="26" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="27" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="28" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="29" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="30" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="31" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="32" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="33" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="34" cy="101" r="1" fill="rgba(113,8,1,0)"/>
+ <circle cx="35" cy="101" r="1" fill="rgba(114,8,1,0)"/>
+ <circle cx="36" cy="101" r="1" fill="rgba(107,8,1,0.0431373)"/>
+ <circle cx="37" cy="101" r="1" fill="rgba(61,4,0,0.309804)"/>
+ <circle cx="38" cy="101" r="1" fill="rgba(15,0,0,0.494118)"/>
+ <circle cx="39" cy="101" r="1" fill="rgba(12,1,0,0.533333)"/>
+ <circle cx="40" cy="101" r="1" fill="rgba(107,15,3,0.752941)"/>
+ <circle cx="41" cy="101" r="1" fill="rgba(192,31,8,0.992157)"/>
+ <circle cx="42" cy="101" r="1" fill="rgba(196,33,9,1)"/>
+ <circle cx="43" cy="101" r="1" fill="rgba(192,32,9,1)"/>
+ <circle cx="44" cy="101" r="1" fill="rgba(194,33,9,1)"/>
+ <circle cx="45" cy="101" r="1" fill="rgba(195,34,9,1)"/>
+ <circle cx="46" cy="101" r="1" fill="rgba(196,35,10,1)"/>
+ <circle cx="47" cy="101" r="1" fill="rgba(198,36,10,1)"/>
+ <circle cx="48" cy="101" r="1" fill="rgba(200,38,11,1)"/>
+ <circle cx="49" cy="101" r="1" fill="rgba(200,39,11,1)"/>
+ <circle cx="50" cy="101" r="1" fill="rgba(202,41,12,1)"/>
+ <circle cx="51" cy="101" r="1" fill="rgba(203,42,13,1)"/>
+ <circle cx="52" cy="101" r="1" fill="rgba(204,44,13,1)"/>
+ <circle cx="53" cy="101" r="1" fill="rgba(205,45,14,1)"/>
+ <circle cx="54" cy="101" r="1" fill="rgba(207,46,14,1)"/>
+ <circle cx="55" cy="101" r="1" fill="rgba(207,48,15,1)"/>
+ <circle cx="56" cy="101" r="1" fill="rgba(207,49,16,1)"/>
+ <circle cx="57" cy="101" r="1" fill="rgba(209,51,17,1)"/>
+ <circle cx="58" cy="101" r="1" fill="rgba(209,52,18,1)"/>
+ <circle cx="59" cy="101" r="1" fill="rgba(210,53,18,1)"/>
+ <circle cx="60" cy="101" r="1" fill="rgba(210,55,19,1)"/>
+ <circle cx="61" cy="101" r="1" fill="rgba(209,56,19,1)"/>
+ <circle cx="62" cy="101" r="1" fill="rgba(207,54,17,1)"/>
+ <circle cx="63" cy="101" r="1" fill="rgba(203,48,14,1)"/>
+ <circle cx="64" cy="101" r="1" fill="rgba(191,25,5,1)"/>
+ <circle cx="65" cy="101" r="1" fill="rgba(131,1,0,1)"/>
+ <circle cx="66" cy="101" r="1" fill="rgba(139,22,5,1)"/>
+ <circle cx="67" cy="101" r="1" fill="rgba(199,34,8,1)"/>
+ <circle cx="68" cy="101" r="1" fill="rgba(196,38,10,1)"/>
+ <circle cx="69" cy="101" r="1" fill="rgba(203,49,14,1)"/>
+ <circle cx="70" cy="101" r="1" fill="rgba(210,62,21,1)"/>
+ <circle cx="71" cy="101" r="1" fill="rgba(217,75,28,1)"/>
+ <circle cx="72" cy="101" r="1" fill="rgba(221,83,33,1)"/>
+ <circle cx="73" cy="101" r="1" fill="rgba(223,89,37,1)"/>
+ <circle cx="74" cy="101" r="1" fill="rgba(224,93,39,1)"/>
+ <circle cx="75" cy="101" r="1" fill="rgba(226,96,41,1)"/>
+ <circle cx="76" cy="101" r="1" fill="rgba(227,100,43,1)"/>
+ <circle cx="77" cy="101" r="1" fill="rgba(228,102,45,1)"/>
+ <circle cx="78" cy="101" r="1" fill="rgba(229,104,46,1)"/>
+ <circle cx="79" cy="101" r="1" fill="rgba(230,106,46,1)"/>
+ <circle cx="80" cy="101" r="1" fill="rgba(230,105,45,1)"/>
+ <circle cx="81" cy="101" r="1" fill="rgba(231,106,44,1)"/>
+ <circle cx="82" cy="101" r="1" fill="rgba(232,104,42,1)"/>
+ <circle cx="83" cy="101" r="1" fill="rgba(232,101,39,1)"/>
+ <circle cx="84" cy="101" r="1" fill="rgba(231,97,35,1)"/>
+ <circle cx="85" cy="101" r="1" fill="rgba(229,89,30,1)"/>
+ <circle cx="86" cy="101" r="1" fill="rgba(225,80,24,1)"/>
+ <circle cx="87" cy="101" r="1" fill="rgba(224,74,22,1)"/>
+ <circle cx="88" cy="101" r="1" fill="rgba(226,71,20,1)"/>
+ <circle cx="89" cy="101" r="1" fill="rgba(156,41,10,0.87451)"/>
+ <circle cx="90" cy="101" r="1" fill="rgba(42,5,1,0.701961)"/>
+ <circle cx="91" cy="101" r="1" fill="rgba(39,4,1,0.65098)"/>
+ <circle cx="92" cy="101" r="1" fill="rgba(36,4,0,0.592157)"/>
+ <circle cx="93" cy="101" r="1" fill="rgba(24,1,0,0.517647)"/>
+ <circle cx="94" cy="101" r="1" fill="rgba(15,0,0,0.454902)"/>
+ <circle cx="95" cy="101" r="1" fill="rgba(10,0,0,0.392157)"/>
+ <circle cx="96" cy="101" r="1" fill="rgba(19,4,0,0.337255)"/>
+ <circle cx="97" cy="101" r="1" fill="rgba(33,9,2,0.266667)"/>
+ <circle cx="98" cy="101" r="1" fill="rgba(45,14,3,0.184314)"/>
+ <circle cx="99" cy="101" r="1" fill="rgba(51,14,2,0.101961)"/>
+ <circle cx="100" cy="101" r="1" fill="rgba(59,3,0,0.0431373)"/>
+ <circle cx="101" cy="101" r="1" fill="rgba(34,0,0,0.0117647)"/>
+ <circle cx="102" cy="101" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="103" cy="101" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="104" cy="101" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="105" cy="101" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="106" cy="101" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="107" cy="101" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="108" cy="101" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="109" cy="101" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="110" cy="101" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="111" cy="101" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="112" cy="101" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="113" cy="101" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="114" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="101" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="102" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="19" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="20" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="21" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="22" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="23" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="24" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="25" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="26" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="27" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="28" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="29" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="30" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="31" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="32" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="33" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="34" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="35" cy="102" r="1" fill="rgba(113,10,1,0)"/>
+ <circle cx="36" cy="102" r="1" fill="rgba(114,10,1,0)"/>
+ <circle cx="37" cy="102" r="1" fill="rgba(98,8,1,0.113725)"/>
+ <circle cx="38" cy="102" r="1" fill="rgba(45,2,0,0.392157)"/>
+ <circle cx="39" cy="102" r="1" fill="rgba(12,0,0,0.505882)"/>
+ <circle cx="40" cy="102" r="1" fill="rgba(10,1,0,0.537255)"/>
+ <circle cx="41" cy="102" r="1" fill="rgba(94,13,3,0.721569)"/>
+ <circle cx="42" cy="102" r="1" fill="rgba(189,33,9,0.976471)"/>
+ <circle cx="43" cy="102" r="1" fill="rgba(199,36,10,1)"/>
+ <circle cx="44" cy="102" r="1" fill="rgba(194,34,10,1)"/>
+ <circle cx="45" cy="102" r="1" fill="rgba(194,35,10,1)"/>
+ <circle cx="46" cy="102" r="1" fill="rgba(196,36,10,1)"/>
+ <circle cx="47" cy="102" r="1" fill="rgba(197,37,11,1)"/>
+ <circle cx="48" cy="102" r="1" fill="rgba(198,39,11,1)"/>
+ <circle cx="49" cy="102" r="1" fill="rgba(200,40,11,1)"/>
+ <circle cx="50" cy="102" r="1" fill="rgba(201,42,13,1)"/>
+ <circle cx="51" cy="102" r="1" fill="rgba(202,44,14,1)"/>
+ <circle cx="52" cy="102" r="1" fill="rgba(204,46,14,1)"/>
+ <circle cx="53" cy="102" r="1" fill="rgba(204,47,15,1)"/>
+ <circle cx="54" cy="102" r="1" fill="rgba(206,49,16,1)"/>
+ <circle cx="55" cy="102" r="1" fill="rgba(207,51,16,1)"/>
+ <circle cx="56" cy="102" r="1" fill="rgba(208,52,18,1)"/>
+ <circle cx="57" cy="102" r="1" fill="rgba(209,54,18,1)"/>
+ <circle cx="58" cy="102" r="1" fill="rgba(210,55,19,1)"/>
+ <circle cx="59" cy="102" r="1" fill="rgba(210,57,20,1)"/>
+ <circle cx="60" cy="102" r="1" fill="rgba(210,58,20,1)"/>
+ <circle cx="61" cy="102" r="1" fill="rgba(210,58,20,1)"/>
+ <circle cx="62" cy="102" r="1" fill="rgba(207,55,18,1)"/>
+ <circle cx="63" cy="102" r="1" fill="rgba(203,49,14,1)"/>
+ <circle cx="64" cy="102" r="1" fill="rgba(190,25,5,1)"/>
+ <circle cx="65" cy="102" r="1" fill="rgba(130,0,0,1)"/>
+ <circle cx="66" cy="102" r="1" fill="rgba(140,24,5,1)"/>
+ <circle cx="67" cy="102" r="1" fill="rgba(200,35,8,1)"/>
+ <circle cx="68" cy="102" r="1" fill="rgba(197,40,10,1)"/>
+ <circle cx="69" cy="102" r="1" fill="rgba(203,50,14,1)"/>
+ <circle cx="70" cy="102" r="1" fill="rgba(210,64,22,1)"/>
+ <circle cx="71" cy="102" r="1" fill="rgba(217,78,30,1)"/>
+ <circle cx="72" cy="102" r="1" fill="rgba(222,87,35,1)"/>
+ <circle cx="73" cy="102" r="1" fill="rgba(224,92,39,1)"/>
+ <circle cx="74" cy="102" r="1" fill="rgba(225,95,41,1)"/>
+ <circle cx="75" cy="102" r="1" fill="rgba(227,98,42,1)"/>
+ <circle cx="76" cy="102" r="1" fill="rgba(227,100,43,1)"/>
+ <circle cx="77" cy="102" r="1" fill="rgba(227,101,43,1)"/>
+ <circle cx="78" cy="102" r="1" fill="rgba(228,101,42,1)"/>
+ <circle cx="79" cy="102" r="1" fill="rgba(229,100,41,1)"/>
+ <circle cx="80" cy="102" r="1" fill="rgba(229,99,40,1)"/>
+ <circle cx="81" cy="102" r="1" fill="rgba(230,97,37,1)"/>
+ <circle cx="82" cy="102" r="1" fill="rgba(230,94,34,1)"/>
+ <circle cx="83" cy="102" r="1" fill="rgba(230,92,32,1)"/>
+ <circle cx="84" cy="102" r="1" fill="rgba(229,85,27,1)"/>
+ <circle cx="85" cy="102" r="1" fill="rgba(224,76,22,1)"/>
+ <circle cx="86" cy="102" r="1" fill="rgba(227,73,20,1)"/>
+ <circle cx="87" cy="102" r="1" fill="rgba(223,69,19,1)"/>
+ <circle cx="88" cy="102" r="1" fill="rgba(141,35,8,0.854902)"/>
+ <circle cx="89" cy="102" r="1" fill="rgba(39,4,1,0.694118)"/>
+ <circle cx="90" cy="102" r="1" fill="rgba(39,5,1,0.654902)"/>
+ <circle cx="91" cy="102" r="1" fill="rgba(36,4,0,0.596078)"/>
+ <circle cx="92" cy="102" r="1" fill="rgba(24,0,0,0.52549)"/>
+ <circle cx="93" cy="102" r="1" fill="rgba(15,0,0,0.462745)"/>
+ <circle cx="94" cy="102" r="1" fill="rgba(10,0,0,0.411765)"/>
+ <circle cx="95" cy="102" r="1" fill="rgba(17,2,0,0.352941)"/>
+ <circle cx="96" cy="102" r="1" fill="rgba(29,8,1,0.290196)"/>
+ <circle cx="97" cy="102" r="1" fill="rgba(40,13,3,0.207843)"/>
+ <circle cx="98" cy="102" r="1" fill="rgba(49,16,3,0.12549)"/>
+ <circle cx="99" cy="102" r="1" fill="rgba(51,6,0,0.0627451)"/>
+ <circle cx="100" cy="102" r="1" fill="rgba(39,0,0,0.0196078)"/>
+ <circle cx="101" cy="102" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="102" cy="102" r="1" fill="rgba(15,7,2,0)"/>
+ <circle cx="103" cy="102" r="1" fill="rgba(15,7,1,0)"/>
+ <circle cx="104" cy="102" r="1" fill="rgba(15,7,1,0)"/>
+ <circle cx="105" cy="102" r="1" fill="rgba(15,7,1,0)"/>
+ <circle cx="106" cy="102" r="1" fill="rgba(15,7,1,0)"/>
+ <circle cx="107" cy="102" r="1" fill="rgba(15,7,1,0)"/>
+ <circle cx="108" cy="102" r="1" fill="rgba(15,7,1,0)"/>
+ <circle cx="109" cy="102" r="1" fill="rgba(15,7,1,0)"/>
+ <circle cx="110" cy="102" r="1" fill="rgba(15,7,1,0)"/>
+ <circle cx="111" cy="102" r="1" fill="rgba(15,7,1,0)"/>
+ <circle cx="112" cy="102" r="1" fill="rgba(15,7,1,0)"/>
+ <circle cx="113" cy="102" r="1" fill="rgba(15,7,1,0)"/>
+ <circle cx="114" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="102" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="103" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="19" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="20" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="21" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="22" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="23" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="24" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="25" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="26" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="27" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="28" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="29" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="30" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="31" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="32" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="33" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="34" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="35" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="36" cy="103" r="1" fill="rgba(114,11,1,0)"/>
+ <circle cx="37" cy="103" r="1" fill="rgba(114,11,2,0.00392157)"/>
+ <circle cx="38" cy="103" r="1" fill="rgba(88,7,1,0.192157)"/>
+ <circle cx="39" cy="103" r="1" fill="rgba(31,0,0,0.439216)"/>
+ <circle cx="40" cy="103" r="1" fill="rgba(12,0,0,0.509804)"/>
+ <circle cx="41" cy="103" r="1" fill="rgba(10,1,0,0.533333)"/>
+ <circle cx="42" cy="103" r="1" fill="rgba(78,10,2,0.682353)"/>
+ <circle cx="43" cy="103" r="1" fill="rgba(178,32,9,0.941176)"/>
+ <circle cx="44" cy="103" r="1" fill="rgba(202,38,11,1)"/>
+ <circle cx="45" cy="103" r="1" fill="rgba(196,37,10,1)"/>
+ <circle cx="46" cy="103" r="1" fill="rgba(195,37,11,1)"/>
+ <circle cx="47" cy="103" r="1" fill="rgba(196,38,11,1)"/>
+ <circle cx="48" cy="103" r="1" fill="rgba(197,39,11,1)"/>
+ <circle cx="49" cy="103" r="1" fill="rgba(198,40,12,1)"/>
+ <circle cx="50" cy="103" r="1" fill="rgba(200,42,13,1)"/>
+ <circle cx="51" cy="103" r="1" fill="rgba(200,44,13,1)"/>
+ <circle cx="52" cy="103" r="1" fill="rgba(203,46,14,1)"/>
+ <circle cx="53" cy="103" r="1" fill="rgba(203,48,15,1)"/>
+ <circle cx="54" cy="103" r="1" fill="rgba(205,51,17,1)"/>
+ <circle cx="55" cy="103" r="1" fill="rgba(207,53,18,1)"/>
+ <circle cx="56" cy="103" r="1" fill="rgba(208,55,18,1)"/>
+ <circle cx="57" cy="103" r="1" fill="rgba(210,57,19,1)"/>
+ <circle cx="58" cy="103" r="1" fill="rgba(210,59,20,1)"/>
+ <circle cx="59" cy="103" r="1" fill="rgba(211,60,21,1)"/>
+ <circle cx="60" cy="103" r="1" fill="rgba(211,61,22,1)"/>
+ <circle cx="61" cy="103" r="1" fill="rgba(210,60,20,1)"/>
+ <circle cx="62" cy="103" r="1" fill="rgba(207,56,19,1)"/>
+ <circle cx="63" cy="103" r="1" fill="rgba(202,49,14,1)"/>
+ <circle cx="64" cy="103" r="1" fill="rgba(189,25,6,1)"/>
+ <circle cx="65" cy="103" r="1" fill="maroon"/>
+ <circle cx="66" cy="103" r="1" fill="rgba(140,25,5,1)"/>
+ <circle cx="67" cy="103" r="1" fill="rgba(201,38,9,1)"/>
+ <circle cx="68" cy="103" r="1" fill="rgba(199,42,10,1)"/>
+ <circle cx="69" cy="103" r="1" fill="rgba(204,53,16,1)"/>
+ <circle cx="70" cy="103" r="1" fill="rgba(212,67,23,1)"/>
+ <circle cx="71" cy="103" r="1" fill="rgba(218,79,30,1)"/>
+ <circle cx="72" cy="103" r="1" fill="rgba(222,88,36,1)"/>
+ <circle cx="73" cy="103" r="1" fill="rgba(224,93,38,1)"/>
+ <circle cx="74" cy="103" r="1" fill="rgba(224,94,39,1)"/>
+ <circle cx="75" cy="103" r="1" fill="rgba(225,95,40,1)"/>
+ <circle cx="76" cy="103" r="1" fill="rgba(226,94,38,1)"/>
+ <circle cx="77" cy="103" r="1" fill="rgba(227,94,37,1)"/>
+ <circle cx="78" cy="103" r="1" fill="rgba(227,93,36,1)"/>
+ <circle cx="79" cy="103" r="1" fill="rgba(227,91,33,1)"/>
+ <circle cx="80" cy="103" r="1" fill="rgba(228,90,31,1)"/>
+ <circle cx="81" cy="103" r="1" fill="rgba(229,89,30,1)"/>
+ <circle cx="82" cy="103" r="1" fill="rgba(228,87,28,1)"/>
+ <circle cx="83" cy="103" r="1" fill="rgba(227,82,25,1)"/>
+ <circle cx="84" cy="103" r="1" fill="rgba(225,77,22,1)"/>
+ <circle cx="85" cy="103" r="1" fill="rgba(229,74,21,1)"/>
+ <circle cx="86" cy="103" r="1" fill="rgba(214,66,18,0.980392)"/>
+ <circle cx="87" cy="103" r="1" fill="rgba(119,27,6,0.819608)"/>
+ <circle cx="88" cy="103" r="1" fill="rgba(37,4,1,0.694118)"/>
+ <circle cx="89" cy="103" r="1" fill="rgba(42,5,1,0.654902)"/>
+ <circle cx="90" cy="103" r="1" fill="rgba(37,4,0,0.596078)"/>
+ <circle cx="91" cy="103" r="1" fill="rgba(26,0,0,0.529412)"/>
+ <circle cx="92" cy="103" r="1" fill="rgba(15,0,0,0.470588)"/>
+ <circle cx="93" cy="103" r="1" fill="rgba(7,0,0,0.419608)"/>
+ <circle cx="94" cy="103" r="1" fill="rgba(12,2,0,0.368627)"/>
+ <circle cx="95" cy="103" r="1" fill="rgba(28,7,0,0.305882)"/>
+ <circle cx="96" cy="103" r="1" fill="rgba(39,12,3,0.231373)"/>
+ <circle cx="97" cy="103" r="1" fill="rgba(49,15,3,0.14902)"/>
+ <circle cx="98" cy="103" r="1" fill="rgba(51,12,1,0.0784314)"/>
+ <circle cx="99" cy="103" r="1" fill="rgba(33,1,0,0.0313725)"/>
+ <circle cx="100" cy="103" r="1" fill="rgba(0,0,0,0.00392157)"/>
+ <circle cx="101" cy="103" r="1" fill="rgba(10,4,0,0)"/>
+ <circle cx="102" cy="103" r="1" fill="rgba(15,7,3,0)"/>
+ <circle cx="103" cy="103" r="1" fill="rgba(15,7,2,0)"/>
+ <circle cx="104" cy="103" r="1" fill="rgba(15,7,2,0)"/>
+ <circle cx="105" cy="103" r="1" fill="rgba(15,7,2,0)"/>
+ <circle cx="106" cy="103" r="1" fill="rgba(15,7,2,0)"/>
+ <circle cx="107" cy="103" r="1" fill="rgba(15,7,2,0)"/>
+ <circle cx="108" cy="103" r="1" fill="rgba(15,7,2,0)"/>
+ <circle cx="109" cy="103" r="1" fill="rgba(15,7,2,0)"/>
+ <circle cx="110" cy="103" r="1" fill="rgba(15,7,2,0)"/>
+ <circle cx="111" cy="103" r="1" fill="rgba(15,7,2,0)"/>
+ <circle cx="112" cy="103" r="1" fill="rgba(15,7,2,0)"/>
+ <circle cx="113" cy="103" r="1" fill="rgba(15,7,2,0)"/>
+ <circle cx="114" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="103" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="104" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="19" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="20" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="21" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="22" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="23" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="24" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="25" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="26" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="27" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="28" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="29" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="30" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="31" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="32" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="33" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="34" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="35" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="36" cy="104" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="37" cy="104" r="1" fill="rgba(115,11,2,0)"/>
+ <circle cx="38" cy="104" r="1" fill="rgba(110,11,2,0.027451)"/>
+ <circle cx="39" cy="104" r="1" fill="rgba(70,5,0,0.25098)"/>
+ <circle cx="40" cy="104" r="1" fill="rgba(19,0,0,0.462745)"/>
+ <circle cx="41" cy="104" r="1" fill="rgba(15,0,0,0.505882)"/>
+ <circle cx="42" cy="104" r="1" fill="rgba(12,0,0,0.529412)"/>
+ <circle cx="43" cy="104" r="1" fill="rgba(55,7,1,0.635294)"/>
+ <circle cx="44" cy="104" r="1" fill="rgba(155,28,8,0.882353)"/>
+ <circle cx="45" cy="104" r="1" fill="rgba(201,39,11,1)"/>
+ <circle cx="46" cy="104" r="1" fill="rgba(198,39,11,1)"/>
+ <circle cx="47" cy="104" r="1" fill="rgba(195,39,11,1)"/>
+ <circle cx="48" cy="104" r="1" fill="rgba(195,39,11,1)"/>
+ <circle cx="49" cy="104" r="1" fill="rgba(196,40,11,1)"/>
+ <circle cx="50" cy="104" r="1" fill="rgba(196,41,12,1)"/>
+ <circle cx="51" cy="104" r="1" fill="rgba(198,43,13,1)"/>
+ <circle cx="52" cy="104" r="1" fill="rgba(200,45,14,1)"/>
+ <circle cx="53" cy="104" r="1" fill="rgba(202,47,14,1)"/>
+ <circle cx="54" cy="104" r="1" fill="rgba(203,50,16,1)"/>
+ <circle cx="55" cy="104" r="1" fill="rgba(205,53,17,1)"/>
+ <circle cx="56" cy="104" r="1" fill="rgba(207,55,18,1)"/>
+ <circle cx="57" cy="104" r="1" fill="rgba(208,58,20,1)"/>
+ <circle cx="58" cy="104" r="1" fill="rgba(210,60,21,1)"/>
+ <circle cx="59" cy="104" r="1" fill="rgba(210,62,22,1)"/>
+ <circle cx="60" cy="104" r="1" fill="rgba(211,63,22,1)"/>
+ <circle cx="61" cy="104" r="1" fill="rgba(210,61,21,1)"/>
+ <circle cx="62" cy="104" r="1" fill="rgba(206,55,18,1)"/>
+ <circle cx="63" cy="104" r="1" fill="rgba(202,48,14,1)"/>
+ <circle cx="64" cy="104" r="1" fill="rgba(189,25,5,1)"/>
+ <circle cx="65" cy="104" r="1" fill="rgba(125,0,0,1)"/>
+ <circle cx="66" cy="104" r="1" fill="rgba(141,26,6,1)"/>
+ <circle cx="67" cy="104" r="1" fill="rgba(203,39,9,1)"/>
+ <circle cx="68" cy="104" r="1" fill="rgba(200,44,11,1)"/>
+ <circle cx="69" cy="104" r="1" fill="rgba(205,55,16,1)"/>
+ <circle cx="70" cy="104" r="1" fill="rgba(212,68,23,1)"/>
+ <circle cx="71" cy="104" r="1" fill="rgba(217,79,29,1)"/>
+ <circle cx="72" cy="104" r="1" fill="rgba(221,85,33,1)"/>
+ <circle cx="73" cy="104" r="1" fill="rgba(222,87,34,1)"/>
+ <circle cx="74" cy="104" r="1" fill="rgba(223,87,33,1)"/>
+ <circle cx="75" cy="104" r="1" fill="rgba(223,86,32,1)"/>
+ <circle cx="76" cy="104" r="1" fill="rgba(224,85,31,1)"/>
+ <circle cx="77" cy="104" r="1" fill="rgba(224,84,30,1)"/>
+ <circle cx="78" cy="104" r="1" fill="rgba(225,83,28,1)"/>
+ <circle cx="79" cy="104" r="1" fill="rgba(226,82,27,1)"/>
+ <circle cx="80" cy="104" r="1" fill="rgba(227,84,26,1)"/>
+ <circle cx="81" cy="104" r="1" fill="rgba(227,83,25,1)"/>
+ <circle cx="82" cy="104" r="1" fill="rgba(226,79,23,1)"/>
+ <circle cx="83" cy="104" r="1" fill="rgba(226,76,22,1)"/>
+ <circle cx="84" cy="104" r="1" fill="rgba(231,77,22,1)"/>
+ <circle cx="85" cy="104" r="1" fill="rgba(195,59,15,0.945098)"/>
+ <circle cx="86" cy="104" r="1" fill="rgba(92,19,4,0.776471)"/>
+ <circle cx="87" cy="104" r="1" fill="rgba(31,3,1,0.686275)"/>
+ <circle cx="88" cy="104" r="1" fill="rgba(42,5,1,0.65098)"/>
+ <circle cx="89" cy="104" r="1" fill="rgba(36,4,0,0.592157)"/>
+ <circle cx="90" cy="104" r="1" fill="rgba(26,1,0,0.533333)"/>
+ <circle cx="91" cy="104" r="1" fill="rgba(12,0,0,0.478431)"/>
+ <circle cx="92" cy="104" r="1" fill="rgba(7,0,0,0.431373)"/>
+ <circle cx="93" cy="104" r="1" fill="rgba(12,0,0,0.380392)"/>
+ <circle cx="94" cy="104" r="1" fill="rgba(26,5,0,0.317647)"/>
+ <circle cx="95" cy="104" r="1" fill="rgba(37,10,2,0.247059)"/>
+ <circle cx="96" cy="104" r="1" fill="rgba(46,15,3,0.164706)"/>
+ <circle cx="97" cy="104" r="1" fill="rgba(51,11,2,0.0901961)"/>
+ <circle cx="98" cy="104" r="1" fill="rgba(46,1,0,0.0392157)"/>
+ <circle cx="99" cy="104" r="1" fill="rgba(15,0,0,0.00784314)"/>
+ <circle cx="100" cy="104" r="1" fill="rgba(0,1,0,0)"/>
+ <circle cx="101" cy="104" r="1" fill="rgba(7,3,0,0)"/>
+ <circle cx="102" cy="104" r="1" fill="rgba(10,5,1,0)"/>
+ <circle cx="103" cy="104" r="1" fill="rgba(10,5,1,0)"/>
+ <circle cx="104" cy="104" r="1" fill="rgba(10,5,1,0)"/>
+ <circle cx="105" cy="104" r="1" fill="rgba(10,5,1,0)"/>
+ <circle cx="106" cy="104" r="1" fill="rgba(10,5,1,0)"/>
+ <circle cx="107" cy="104" r="1" fill="rgba(10,5,1,0)"/>
+ <circle cx="108" cy="104" r="1" fill="rgba(10,5,1,0)"/>
+ <circle cx="109" cy="104" r="1" fill="rgba(10,5,1,0)"/>
+ <circle cx="110" cy="104" r="1" fill="rgba(10,5,1,0)"/>
+ <circle cx="111" cy="104" r="1" fill="rgba(10,5,1,0)"/>
+ <circle cx="112" cy="104" r="1" fill="rgba(10,5,1,0)"/>
+ <circle cx="113" cy="104" r="1" fill="rgba(10,5,1,0)"/>
+ <circle cx="114" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="104" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="105" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="19" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="20" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="21" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="22" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="23" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="24" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="25" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="26" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="27" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="28" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="29" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="30" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="31" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="32" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="33" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="34" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="35" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="36" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="37" cy="105" r="1" fill="rgba(114,11,2,0)"/>
+ <circle cx="38" cy="105" r="1" fill="rgba(111,11,2,0)"/>
+ <circle cx="39" cy="105" r="1" fill="rgba(102,10,1,0.0509804)"/>
+ <circle cx="40" cy="105" r="1" fill="rgba(68,6,0,0.294118)"/>
+ <circle cx="41" cy="105" r="1" fill="rgba(19,0,0,0.47451)"/>
+ <circle cx="42" cy="105" r="1" fill="rgba(15,0,0,0.505882)"/>
+ <circle cx="43" cy="105" r="1" fill="rgba(15,1,0,0.52549)"/>
+ <circle cx="44" cy="105" r="1" fill="rgba(29,3,0,0.584314)"/>
+ <circle cx="45" cy="105" r="1" fill="rgba(119,20,4,0.784314)"/>
+ <circle cx="46" cy="105" r="1" fill="rgba(187,37,10,0.972549)"/>
+ <circle cx="47" cy="105" r="1" fill="rgba(200,40,11,1)"/>
+ <circle cx="48" cy="105" r="1" fill="rgba(194,38,11,1)"/>
+ <circle cx="49" cy="105" r="1" fill="rgba(192,39,11,1)"/>
+ <circle cx="50" cy="105" r="1" fill="rgba(193,39,11,1)"/>
+ <circle cx="51" cy="105" r="1" fill="rgba(195,40,11,1)"/>
+ <circle cx="52" cy="105" r="1" fill="rgba(196,42,12,1)"/>
+ <circle cx="53" cy="105" r="1" fill="rgba(198,44,13,1)"/>
+ <circle cx="54" cy="105" r="1" fill="rgba(200,47,14,1)"/>
+ <circle cx="55" cy="105" r="1" fill="rgba(202,49,16,1)"/>
+ <circle cx="56" cy="105" r="1" fill="rgba(203,52,16,1)"/>
+ <circle cx="57" cy="105" r="1" fill="rgba(205,54,18,1)"/>
+ <circle cx="58" cy="105" r="1" fill="rgba(207,57,20,1)"/>
+ <circle cx="59" cy="105" r="1" fill="rgba(208,60,21,1)"/>
+ <circle cx="60" cy="105" r="1" fill="rgba(209,61,21,1)"/>
+ <circle cx="61" cy="105" r="1" fill="rgba(207,60,20,1)"/>
+ <circle cx="62" cy="105" r="1" fill="rgba(203,55,18,1)"/>
+ <circle cx="63" cy="105" r="1" fill="rgba(200,46,13,1)"/>
+ <circle cx="64" cy="105" r="1" fill="rgba(188,25,5,1)"/>
+ <circle cx="65" cy="105" r="1" fill="rgba(122,0,0,1)"/>
+ <circle cx="66" cy="105" r="1" fill="rgba(142,28,6,1)"/>
+ <circle cx="67" cy="105" r="1" fill="rgba(205,40,9,1)"/>
+ <circle cx="68" cy="105" r="1" fill="rgba(201,45,11,1)"/>
+ <circle cx="69" cy="105" r="1" fill="rgba(207,54,16,1)"/>
+ <circle cx="70" cy="105" r="1" fill="rgba(213,65,22,1)"/>
+ <circle cx="71" cy="105" r="1" fill="rgba(216,72,25,1)"/>
+ <circle cx="72" cy="105" r="1" fill="rgba(217,76,27,1)"/>
+ <circle cx="73" cy="105" r="1" fill="rgba(218,76,27,1)"/>
+ <circle cx="74" cy="105" r="1" fill="rgba(219,75,25,1)"/>
+ <circle cx="75" cy="105" r="1" fill="rgba(220,75,24,1)"/>
+ <circle cx="76" cy="105" r="1" fill="rgba(221,75,23,1)"/>
+ <circle cx="77" cy="105" r="1" fill="rgba(222,76,23,1)"/>
+ <circle cx="78" cy="105" r="1" fill="rgba(225,77,23,1)"/>
+ <circle cx="79" cy="105" r="1" fill="rgba(226,79,23,1)"/>
+ <circle cx="80" cy="105" r="1" fill="rgba(226,78,22,1)"/>
+ <circle cx="81" cy="105" r="1" fill="rgba(225,76,22,1)"/>
+ <circle cx="82" cy="105" r="1" fill="rgba(230,77,22,1)"/>
+ <circle cx="83" cy="105" r="1" fill="rgba(224,72,20,0.996078)"/>
+ <circle cx="84" cy="105" r="1" fill="rgba(157,43,11,0.878431)"/>
+ <circle cx="85" cy="105" r="1" fill="rgba(59,10,2,0.729412)"/>
+ <circle cx="86" cy="105" r="1" fill="rgba(36,3,1,0.678431)"/>
+ <circle cx="87" cy="105" r="1" fill="rgba(43,6,1,0.643137)"/>
+ <circle cx="88" cy="105" r="1" fill="rgba(34,3,0,0.584314)"/>
+ <circle cx="89" cy="105" r="1" fill="rgba(24,0,0,0.529412)"/>
+ <circle cx="90" cy="105" r="1" fill="rgba(12,0,0,0.478431)"/>
+ <circle cx="91" cy="105" r="1" fill="rgba(4,0,0,0.431373)"/>
+ <circle cx="92" cy="105" r="1" fill="rgba(12,0,0,0.388235)"/>
+ <circle cx="93" cy="105" r="1" fill="rgba(24,4,0,0.329412)"/>
+ <circle cx="94" cy="105" r="1" fill="rgba(36,10,1,0.258824)"/>
+ <circle cx="95" cy="105" r="1" fill="rgba(45,15,2,0.176471)"/>
+ <circle cx="96" cy="105" r="1" fill="rgba(49,16,1,0.105882)"/>
+ <circle cx="97" cy="105" r="1" fill="rgba(42,6,0,0.0470588)"/>
+ <circle cx="98" cy="105" r="1" fill="rgba(17,0,0,0.0117647)"/>
+ <circle cx="99" cy="105" r="1" fill="rgba(0,1,0,0)"/>
+ <circle cx="100" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="101" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="102" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="103" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="104" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="105" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="106" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="107" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="108" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="109" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="110" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="111" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="112" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="113" cy="105" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="114" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="105" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="106" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="106" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="106" r="1" fill="rgba(114,13,2,0)"/>
+ <circle cx="39" cy="106" r="1" fill="rgba(116,13,2,0)"/>
+ <circle cx="40" cy="106" r="1" fill="rgba(108,12,2,0.0705882)"/>
+ <circle cx="41" cy="106" r="1" fill="rgba(61,5,0,0.321569)"/>
+ <circle cx="42" cy="106" r="1" fill="rgba(10,0,0,0.478431)"/>
+ <circle cx="43" cy="106" r="1" fill="rgba(12,0,0,0.498039)"/>
+ <circle cx="44" cy="106" r="1" fill="rgba(19,1,0,0.521569)"/>
+ <circle cx="45" cy="106" r="1" fill="rgba(17,1,0,0.560784)"/>
+ <circle cx="46" cy="106" r="1" fill="rgba(70,10,2,0.682353)"/>
+ <circle cx="47" cy="106" r="1" fill="rgba(153,27,7,0.886275)"/>
+ <circle cx="48" cy="106" r="1" fill="rgba(195,37,10,1)"/>
+ <circle cx="49" cy="106" r="1" fill="rgba(196,38,10,1)"/>
+ <circle cx="50" cy="106" r="1" fill="rgba(191,37,10,1)"/>
+ <circle cx="51" cy="106" r="1" fill="rgba(191,37,10,1)"/>
+ <circle cx="52" cy="106" r="1" fill="rgba(192,38,10,1)"/>
+ <circle cx="53" cy="106" r="1" fill="rgba(194,40,11,1)"/>
+ <circle cx="54" cy="106" r="1" fill="rgba(196,42,12,1)"/>
+ <circle cx="55" cy="106" r="1" fill="rgba(198,45,13,1)"/>
+ <circle cx="56" cy="106" r="1" fill="rgba(199,47,14,1)"/>
+ <circle cx="57" cy="106" r="1" fill="rgba(200,49,14,1)"/>
+ <circle cx="58" cy="106" r="1" fill="rgba(202,52,16,1)"/>
+ <circle cx="59" cy="106" r="1" fill="rgba(203,54,18,1)"/>
+ <circle cx="60" cy="106" r="1" fill="rgba(203,56,18,1)"/>
+ <circle cx="61" cy="106" r="1" fill="rgba(204,56,18,1)"/>
+ <circle cx="62" cy="106" r="1" fill="rgba(200,51,15,1)"/>
+ <circle cx="63" cy="106" r="1" fill="rgba(198,45,12,1)"/>
+ <circle cx="64" cy="106" r="1" fill="rgba(184,23,5,1)"/>
+ <circle cx="65" cy="106" r="1" fill="rgba(117,0,0,1)"/>
+ <circle cx="66" cy="106" r="1" fill="rgba(142,28,6,1)"/>
+ <circle cx="67" cy="106" r="1" fill="rgba(206,41,9,1)"/>
+ <circle cx="68" cy="106" r="1" fill="rgba(203,45,11,1)"/>
+ <circle cx="69" cy="106" r="1" fill="rgba(207,53,14,1)"/>
+ <circle cx="70" cy="106" r="1" fill="rgba(211,61,18,1)"/>
+ <circle cx="71" cy="106" r="1" fill="rgba(214,66,20,1)"/>
+ <circle cx="72" cy="106" r="1" fill="rgba(215,67,20,1)"/>
+ <circle cx="73" cy="106" r="1" fill="rgba(217,67,20,1)"/>
+ <circle cx="74" cy="106" r="1" fill="rgba(217,67,20,1)"/>
+ <circle cx="75" cy="106" r="1" fill="rgba(219,68,19,1)"/>
+ <circle cx="76" cy="106" r="1" fill="rgba(221,70,20,1)"/>
+ <circle cx="77" cy="106" r="1" fill="rgba(224,73,20,1)"/>
+ <circle cx="78" cy="106" r="1" fill="rgba(224,75,21,1)"/>
+ <circle cx="79" cy="106" r="1" fill="rgba(224,75,21,1)"/>
+ <circle cx="80" cy="106" r="1" fill="rgba(227,75,21,1)"/>
+ <circle cx="81" cy="106" r="1" fill="rgba(229,76,22,1)"/>
+ <circle cx="82" cy="106" r="1" fill="rgba(193,58,16,0.941176)"/>
+ <circle cx="83" cy="106" r="1" fill="rgba(105,24,6,0.796078)"/>
+ <circle cx="84" cy="106" r="1" fill="rgba(37,4,1,0.698039)"/>
+ <circle cx="85" cy="106" r="1" fill="rgba(39,4,1,0.666667)"/>
+ <circle cx="86" cy="106" r="1" fill="rgba(40,5,1,0.627451)"/>
+ <circle cx="87" cy="106" r="1" fill="rgba(33,3,0,0.572549)"/>
+ <circle cx="88" cy="106" r="1" fill="rgba(24,0,0,0.521569)"/>
+ <circle cx="89" cy="106" r="1" fill="rgba(12,0,0,0.47451)"/>
+ <circle cx="90" cy="106" r="1" fill="rgba(4,0,0,0.435294)"/>
+ <circle cx="91" cy="106" r="1" fill="rgba(7,0,0,0.388235)"/>
+ <circle cx="92" cy="106" r="1" fill="rgba(21,4,0,0.337255)"/>
+ <circle cx="93" cy="106" r="1" fill="rgba(33,9,1,0.266667)"/>
+ <circle cx="94" cy="106" r="1" fill="rgba(43,14,2,0.184314)"/>
+ <circle cx="95" cy="106" r="1" fill="rgba(47,14,1,0.113725)"/>
+ <circle cx="96" cy="106" r="1" fill="rgba(37,6,0,0.054902)"/>
+ <circle cx="97" cy="106" r="1" fill="rgba(10,0,0,0.0156863)"/>
+ <circle cx="98" cy="106" r="1" fill="rgba(0,1,0,0)"/>
+ <circle cx="99" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="106" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="106" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="107" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="107" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="107" r="1" fill="rgba(117,14,3,0)"/>
+ <circle cx="41" cy="107" r="1" fill="rgba(103,13,2,0.0901961)"/>
+ <circle cx="42" cy="107" r="1" fill="rgba(55,5,0,0.333333)"/>
+ <circle cx="43" cy="107" r="1" fill="rgba(10,0,0,0.47451)"/>
+ <circle cx="44" cy="107" r="1" fill="rgba(12,0,0,0.494118)"/>
+ <circle cx="45" cy="107" r="1" fill="rgba(21,1,0,0.517647)"/>
+ <circle cx="46" cy="107" r="1" fill="rgba(21,1,0,0.54902)"/>
+ <circle cx="47" cy="107" r="1" fill="rgba(33,3,0,0.603922)"/>
+ <circle cx="48" cy="107" r="1" fill="rgba(98,14,3,0.74902)"/>
+ <circle cx="49" cy="107" r="1" fill="rgba(166,29,7,0.929412)"/>
+ <circle cx="50" cy="107" r="1" fill="rgba(193,37,9,1)"/>
+ <circle cx="51" cy="107" r="1" fill="rgba(194,37,10,1)"/>
+ <circle cx="52" cy="107" r="1" fill="rgba(191,37,9,1)"/>
+ <circle cx="53" cy="107" r="1" fill="rgba(192,37,9,1)"/>
+ <circle cx="54" cy="107" r="1" fill="rgba(193,38,10,1)"/>
+ <circle cx="55" cy="107" r="1" fill="rgba(194,40,11,1)"/>
+ <circle cx="56" cy="107" r="1" fill="rgba(195,41,11,1)"/>
+ <circle cx="57" cy="107" r="1" fill="rgba(196,42,11,1)"/>
+ <circle cx="58" cy="107" r="1" fill="rgba(197,44,12,1)"/>
+ <circle cx="59" cy="107" r="1" fill="rgba(198,46,13,1)"/>
+ <circle cx="60" cy="107" r="1" fill="rgba(199,48,14,1)"/>
+ <circle cx="61" cy="107" r="1" fill="rgba(199,49,14,1)"/>
+ <circle cx="62" cy="107" r="1" fill="rgba(196,46,13,1)"/>
+ <circle cx="63" cy="107" r="1" fill="rgba(194,42,11,1)"/>
+ <circle cx="64" cy="107" r="1" fill="rgba(179,22,4,1)"/>
+ <circle cx="65" cy="107" r="1" fill="rgba(111,0,0,1)"/>
+ <circle cx="66" cy="107" r="1" fill="rgba(142,29,6,1)"/>
+ <circle cx="67" cy="107" r="1" fill="rgba(206,42,9,1)"/>
+ <circle cx="68" cy="107" r="1" fill="rgba(203,45,10,1)"/>
+ <circle cx="69" cy="107" r="1" fill="rgba(207,52,13,1)"/>
+ <circle cx="70" cy="107" r="1" fill="rgba(210,58,16,1)"/>
+ <circle cx="71" cy="107" r="1" fill="rgba(213,62,18,1)"/>
+ <circle cx="72" cy="107" r="1" fill="rgba(214,63,18,1)"/>
+ <circle cx="73" cy="107" r="1" fill="rgba(217,64,17,1)"/>
+ <circle cx="74" cy="107" r="1" fill="rgba(218,65,17,1)"/>
+ <circle cx="75" cy="107" r="1" fill="rgba(221,67,18,1)"/>
+ <circle cx="76" cy="107" r="1" fill="rgba(221,70,18,1)"/>
+ <circle cx="77" cy="107" r="1" fill="rgba(224,73,20,1)"/>
+ <circle cx="78" cy="107" r="1" fill="rgba(227,75,21,1)"/>
+ <circle cx="79" cy="107" r="1" fill="rgba(230,75,22,1)"/>
+ <circle cx="80" cy="107" r="1" fill="rgba(205,65,18,0.964706)"/>
+ <circle cx="81" cy="107" r="1" fill="rgba(131,34,8,0.843137)"/>
+ <circle cx="82" cy="107" r="1" fill="rgba(55,8,2,0.72549)"/>
+ <circle cx="83" cy="107" r="1" fill="rgba(33,3,1,0.678431)"/>
+ <circle cx="84" cy="107" r="1" fill="rgba(42,5,1,0.647059)"/>
+ <circle cx="85" cy="107" r="1" fill="rgba(37,3,0,0.603922)"/>
+ <circle cx="86" cy="107" r="1" fill="rgba(29,2,0,0.556863)"/>
+ <circle cx="87" cy="107" r="1" fill="rgba(21,0,0,0.513725)"/>
+ <circle cx="88" cy="107" r="1" fill="rgba(12,0,0,0.47451)"/>
+ <circle cx="89" cy="107" r="1" fill="rgba(4,0,0,0.431373)"/>
+ <circle cx="90" cy="107" r="1" fill="rgba(7,0,0,0.392157)"/>
+ <circle cx="91" cy="107" r="1" fill="rgba(21,4,0,0.337255)"/>
+ <circle cx="92" cy="107" r="1" fill="rgba(33,9,1,0.270588)"/>
+ <circle cx="93" cy="107" r="1" fill="rgba(43,14,2,0.192157)"/>
+ <circle cx="94" cy="107" r="1" fill="rgba(46,14,1,0.113725)"/>
+ <circle cx="95" cy="107" r="1" fill="rgba(36,5,0,0.054902)"/>
+ <circle cx="96" cy="107" r="1" fill="rgba(10,0,0,0.0196078)"/>
+ <circle cx="97" cy="107" r="1" fill="none"/>
+ <circle cx="98" cy="107" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="99" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="107" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="107" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="108" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="108" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="108" r="1" fill="rgba(115,14,3,0)"/>
+ <circle cx="41" cy="108" r="1" fill="rgba(114,14,3,0)"/>
+ <circle cx="42" cy="108" r="1" fill="rgba(101,14,2,0.0901961)"/>
+ <circle cx="43" cy="108" r="1" fill="rgba(57,6,0,0.329412)"/>
+ <circle cx="44" cy="108" r="1" fill="rgba(15,0,0,0.470588)"/>
+ <circle cx="45" cy="108" r="1" fill="rgba(7,0,0,0.490196)"/>
+ <circle cx="46" cy="108" r="1" fill="rgba(19,0,0,0.505882)"/>
+ <circle cx="47" cy="108" r="1" fill="rgba(22,1,0,0.533333)"/>
+ <circle cx="48" cy="108" r="1" fill="rgba(21,2,0,0.568627)"/>
+ <circle cx="49" cy="108" r="1" fill="rgba(43,5,1,0.639216)"/>
+ <circle cx="50" cy="108" r="1" fill="rgba(103,16,3,0.776471)"/>
+ <circle cx="51" cy="108" r="1" fill="rgba(158,29,7,0.913725)"/>
+ <circle cx="52" cy="108" r="1" fill="rgba(190,36,9,1)"/>
+ <circle cx="53" cy="108" r="1" fill="rgba(197,39,10,1)"/>
+ <circle cx="54" cy="108" r="1" fill="rgba(195,39,10,1)"/>
+ <circle cx="55" cy="108" r="1" fill="rgba(194,39,10,1)"/>
+ <circle cx="56" cy="108" r="1" fill="rgba(194,39,10,1)"/>
+ <circle cx="57" cy="108" r="1" fill="rgba(194,40,10,1)"/>
+ <circle cx="58" cy="108" r="1" fill="rgba(195,41,10,1)"/>
+ <circle cx="59" cy="108" r="1" fill="rgba(196,42,11,1)"/>
+ <circle cx="60" cy="108" r="1" fill="rgba(196,44,11,1)"/>
+ <circle cx="61" cy="108" r="1" fill="rgba(196,45,12,1)"/>
+ <circle cx="62" cy="108" r="1" fill="rgba(195,43,11,1)"/>
+ <circle cx="63" cy="108" r="1" fill="rgba(194,41,10,1)"/>
+ <circle cx="64" cy="108" r="1" fill="rgba(177,21,4,1)"/>
+ <circle cx="65" cy="108" r="1" fill="rgba(105,0,0,1)"/>
+ <circle cx="66" cy="108" r="1" fill="rgba(141,29,6,1)"/>
+ <circle cx="67" cy="108" r="1" fill="rgba(207,41,9,1)"/>
+ <circle cx="68" cy="108" r="1" fill="rgba(203,47,10,1)"/>
+ <circle cx="69" cy="108" r="1" fill="rgba(208,53,13,1)"/>
+ <circle cx="70" cy="108" r="1" fill="rgba(212,58,16,1)"/>
+ <circle cx="71" cy="108" r="1" fill="rgba(214,62,17,1)"/>
+ <circle cx="72" cy="108" r="1" fill="rgba(217,65,18,1)"/>
+ <circle cx="73" cy="108" r="1" fill="rgba(218,65,17,1)"/>
+ <circle cx="74" cy="108" r="1" fill="rgba(221,68,18,1)"/>
+ <circle cx="75" cy="108" r="1" fill="rgba(224,71,19,1)"/>
+ <circle cx="76" cy="108" r="1" fill="rgba(229,73,20,1)"/>
+ <circle cx="77" cy="108" r="1" fill="rgba(225,72,20,1)"/>
+ <circle cx="78" cy="108" r="1" fill="rgba(196,61,16,0.952941)"/>
+ <circle cx="79" cy="108" r="1" fill="rgba(137,36,9,0.85098)"/>
+ <circle cx="80" cy="108" r="1" fill="rgba(67,12,3,0.74902)"/>
+ <circle cx="81" cy="108" r="1" fill="rgba(33,2,1,0.694118)"/>
+ <circle cx="82" cy="108" r="1" fill="rgba(42,5,1,0.666667)"/>
+ <circle cx="83" cy="108" r="1" fill="rgba(39,5,1,0.623529)"/>
+ <circle cx="84" cy="108" r="1" fill="rgba(33,3,0,0.572549)"/>
+ <circle cx="85" cy="108" r="1" fill="rgba(24,0,0,0.533333)"/>
+ <circle cx="86" cy="108" r="1" fill="rgba(17,0,0,0.498039)"/>
+ <circle cx="87" cy="108" r="1" fill="rgba(10,0,0,0.466667)"/>
+ <circle cx="88" cy="108" r="1" fill="rgba(4,0,0,0.431373)"/>
+ <circle cx="89" cy="108" r="1" fill="rgba(12,1,0,0.388235)"/>
+ <circle cx="90" cy="108" r="1" fill="rgba(21,5,0,0.333333)"/>
+ <circle cx="91" cy="108" r="1" fill="rgba(34,9,1,0.266667)"/>
+ <circle cx="92" cy="108" r="1" fill="rgba(43,13,2,0.192157)"/>
+ <circle cx="93" cy="108" r="1" fill="rgba(46,13,1,0.113725)"/>
+ <circle cx="94" cy="108" r="1" fill="rgba(36,6,0,0.054902)"/>
+ <circle cx="95" cy="108" r="1" fill="rgba(10,0,0,0.0196078)"/>
+ <circle cx="96" cy="108" r="1" fill="rgba(0,0,0,0.00392157)"/>
+ <circle cx="97" cy="108" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="98" cy="108" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="108" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="108" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="109" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="109" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="109" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="109" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="109" r="1" fill="rgba(112,16,3,0)"/>
+ <circle cx="43" cy="109" r="1" fill="rgba(105,16,3,0.0745098)"/>
+ <circle cx="44" cy="109" r="1" fill="rgba(62,7,1,0.301961)"/>
+ <circle cx="45" cy="109" r="1" fill="rgba(12,0,0,0.462745)"/>
+ <circle cx="46" cy="109" r="1" fill="rgba(4,0,0,0.482353)"/>
+ <circle cx="47" cy="109" r="1" fill="rgba(15,0,0,0.490196)"/>
+ <circle cx="48" cy="109" r="1" fill="rgba(22,1,0,0.513725)"/>
+ <circle cx="49" cy="109" r="1" fill="rgba(26,2,0,0.54902)"/>
+ <circle cx="50" cy="109" r="1" fill="rgba(22,2,0,0.588235)"/>
+ <circle cx="51" cy="109" r="1" fill="rgba(39,5,1,0.647059)"/>
+ <circle cx="52" cy="109" r="1" fill="rgba(86,14,3,0.74902)"/>
+ <circle cx="53" cy="109" r="1" fill="rgba(139,25,6,0.870588)"/>
+ <circle cx="54" cy="109" r="1" fill="rgba(179,36,9,0.960784)"/>
+ <circle cx="55" cy="109" r="1" fill="rgba(196,41,11,1)"/>
+ <circle cx="56" cy="109" r="1" fill="rgba(202,42,11,1)"/>
+ <circle cx="57" cy="109" r="1" fill="rgba(200,42,10,1)"/>
+ <circle cx="58" cy="109" r="1" fill="rgba(198,41,10,1)"/>
+ <circle cx="59" cy="109" r="1" fill="rgba(198,43,10,1)"/>
+ <circle cx="60" cy="109" r="1" fill="rgba(198,45,11,1)"/>
+ <circle cx="61" cy="109" r="1" fill="rgba(198,45,12,1)"/>
+ <circle cx="62" cy="109" r="1" fill="rgba(196,44,11,1)"/>
+ <circle cx="63" cy="109" r="1" fill="rgba(196,43,11,1)"/>
+ <circle cx="64" cy="109" r="1" fill="rgba(179,23,4,1)"/>
+ <circle cx="65" cy="109" r="1" fill="rgba(102,0,0,1)"/>
+ <circle cx="66" cy="109" r="1" fill="rgba(138,29,6,1)"/>
+ <circle cx="67" cy="109" r="1" fill="rgba(207,44,10,1)"/>
+ <circle cx="68" cy="109" r="1" fill="rgba(206,50,12,1)"/>
+ <circle cx="69" cy="109" r="1" fill="rgba(210,56,14,1)"/>
+ <circle cx="70" cy="109" r="1" fill="rgba(216,63,18,1)"/>
+ <circle cx="71" cy="109" r="1" fill="rgba(221,69,20,1)"/>
+ <circle cx="72" cy="109" r="1" fill="rgba(225,73,22,1)"/>
+ <circle cx="73" cy="109" r="1" fill="rgba(230,75,22,1)"/>
+ <circle cx="74" cy="109" r="1" fill="rgba(226,73,22,1)"/>
+ <circle cx="75" cy="109" r="1" fill="rgba(210,66,19,0.976471)"/>
+ <circle cx="76" cy="109" r="1" fill="rgba(170,49,13,0.909804)"/>
+ <circle cx="77" cy="109" r="1" fill="rgba(115,27,6,0.823529)"/>
+ <circle cx="78" cy="109" r="1" fill="rgba(57,9,2,0.745098)"/>
+ <circle cx="79" cy="109" r="1" fill="rgba(34,3,1,0.701961)"/>
+ <circle cx="80" cy="109" r="1" fill="rgba(42,5,1,0.678431)"/>
+ <circle cx="81" cy="109" r="1" fill="rgba(42,5,1,0.639216)"/>
+ <circle cx="82" cy="109" r="1" fill="rgba(36,4,0,0.592157)"/>
+ <circle cx="83" cy="109" r="1" fill="rgba(28,2,0,0.54902)"/>
+ <circle cx="84" cy="109" r="1" fill="rgba(19,0,0,0.509804)"/>
+ <circle cx="85" cy="109" r="1" fill="rgba(12,0,0,0.482353)"/>
+ <circle cx="86" cy="109" r="1" fill="rgba(4,0,0,0.454902)"/>
+ <circle cx="87" cy="109" r="1" fill="rgba(4,0,0,0.423529)"/>
+ <circle cx="88" cy="109" r="1" fill="rgba(12,1,0,0.380392)"/>
+ <circle cx="89" cy="109" r="1" fill="rgba(24,5,0,0.32549)"/>
+ <circle cx="90" cy="109" r="1" fill="rgba(34,10,1,0.258824)"/>
+ <circle cx="91" cy="109" r="1" fill="rgba(45,12,2,0.180392)"/>
+ <circle cx="92" cy="109" r="1" fill="rgba(49,12,1,0.109804)"/>
+ <circle cx="93" cy="109" r="1" fill="rgba(39,6,0,0.0509804)"/>
+ <circle cx="94" cy="109" r="1" fill="rgba(12,0,0,0.0156863)"/>
+ <circle cx="95" cy="109" r="1" fill="rgba(0,0,0,0.00392157)"/>
+ <circle cx="96" cy="109" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="109" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="109" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="109" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="109" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="110" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="110" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="110" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="110" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="110" r="1" fill="rgba(110,16,3,0)"/>
+ <circle cx="43" cy="110" r="1" fill="rgba(115,17,3,0)"/>
+ <circle cx="44" cy="110" r="1" fill="rgba(92,13,2,0.054902)"/>
+ <circle cx="45" cy="110" r="1" fill="rgba(55,6,1,0.266667)"/>
+ <circle cx="46" cy="110" r="1" fill="rgba(24,1,0,0.439216)"/>
+ <circle cx="47" cy="110" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="48" cy="110" r="1" fill="rgba(7,0,0,0.478431)"/>
+ <circle cx="49" cy="110" r="1" fill="rgba(17,0,0,0.498039)"/>
+ <circle cx="50" cy="110" r="1" fill="rgba(24,2,0,0.529412)"/>
+ <circle cx="51" cy="110" r="1" fill="rgba(29,2,0,0.568627)"/>
+ <circle cx="52" cy="110" r="1" fill="rgba(28,3,0,0.603922)"/>
+ <circle cx="53" cy="110" r="1" fill="rgba(33,4,1,0.643137)"/>
+ <circle cx="54" cy="110" r="1" fill="rgba(55,8,2,0.701961)"/>
+ <circle cx="55" cy="110" r="1" fill="rgba(97,17,4,0.784314)"/>
+ <circle cx="56" cy="110" r="1" fill="rgba(134,26,6,0.862745)"/>
+ <circle cx="57" cy="110" r="1" fill="rgba(167,36,9,0.92549)"/>
+ <circle cx="58" cy="110" r="1" fill="rgba(188,42,11,0.976471)"/>
+ <circle cx="59" cy="110" r="1" fill="rgba(199,46,12,0.996078)"/>
+ <circle cx="60" cy="110" r="1" fill="rgba(204,49,13,1)"/>
+ <circle cx="61" cy="110" r="1" fill="rgba(209,52,14,1)"/>
+ <circle cx="62" cy="110" r="1" fill="rgba(210,53,14,1)"/>
+ <circle cx="63" cy="110" r="1" fill="rgba(210,53,14,1)"/>
+ <circle cx="64" cy="110" r="1" fill="rgba(190,31,7,1)"/>
+ <circle cx="65" cy="110" r="1" fill="rgba(129,3,0,1)"/>
+ <circle cx="66" cy="110" r="1" fill="rgba(170,44,12,1)"/>
+ <circle cx="67" cy="110" r="1" fill="rgba(217,53,13,1)"/>
+ <circle cx="68" cy="110" r="1" fill="rgba(218,60,17,1)"/>
+ <circle cx="69" cy="110" r="1" fill="rgba(220,68,20,1)"/>
+ <circle cx="70" cy="110" r="1" fill="rgba(220,73,23,1)"/>
+ <circle cx="71" cy="110" r="1" fill="rgba(214,74,24,0.984314)"/>
+ <circle cx="72" cy="110" r="1" fill="rgba(196,66,20,0.945098)"/>
+ <circle cx="73" cy="110" r="1" fill="rgba(158,47,13,0.886275)"/>
+ <circle cx="74" cy="110" r="1" fill="rgba(118,30,7,0.827451)"/>
+ <circle cx="75" cy="110" r="1" fill="rgba(71,13,3,0.760784)"/>
+ <circle cx="76" cy="110" r="1" fill="rgba(42,5,1,0.72549)"/>
+ <circle cx="77" cy="110" r="1" fill="rgba(36,3,1,0.701961)"/>
+ <circle cx="78" cy="110" r="1" fill="rgba(43,6,1,0.686275)"/>
+ <circle cx="79" cy="110" r="1" fill="rgba(42,6,1,0.65098)"/>
+ <circle cx="80" cy="110" r="1" fill="rgba(37,4,0,0.603922)"/>
+ <circle cx="81" cy="110" r="1" fill="rgba(29,2,0,0.560784)"/>
+ <circle cx="82" cy="110" r="1" fill="rgba(22,0,0,0.521569)"/>
+ <circle cx="83" cy="110" r="1" fill="rgba(15,0,0,0.494118)"/>
+ <circle cx="84" cy="110" r="1" fill="rgba(7,0,0,0.466667)"/>
+ <circle cx="85" cy="110" r="1" fill="rgba(4,0,0,0.443137)"/>
+ <circle cx="86" cy="110" r="1" fill="rgba(7,0,0,0.411765)"/>
+ <circle cx="87" cy="110" r="1" fill="rgba(15,2,0,0.368627)"/>
+ <circle cx="88" cy="110" r="1" fill="rgba(24,6,0,0.313725)"/>
+ <circle cx="89" cy="110" r="1" fill="rgba(34,11,1,0.243137)"/>
+ <circle cx="90" cy="110" r="1" fill="rgba(45,13,3,0.168627)"/>
+ <circle cx="91" cy="110" r="1" fill="rgba(51,14,2,0.0980392)"/>
+ <circle cx="92" cy="110" r="1" fill="rgba(42,7,0,0.0431373)"/>
+ <circle cx="93" cy="110" r="1" fill="rgba(15,0,0,0.0117647)"/>
+ <circle cx="94" cy="110" r="1" fill="rgba(7,3,0,0)"/>
+ <circle cx="95" cy="110" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="96" cy="110" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="110" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="110" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="110" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="110" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="111" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="111" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="111" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="111" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="111" r="1" fill="rgba(110,16,3,0)"/>
+ <circle cx="43" cy="111" r="1" fill="rgba(113,17,3,0)"/>
+ <circle cx="44" cy="111" r="1" fill="rgba(92,12,2,0)"/>
+ <circle cx="45" cy="111" r="1" fill="rgba(84,13,3,0.0313725)"/>
+ <circle cx="46" cy="111" r="1" fill="rgba(82,12,2,0.2)"/>
+ <circle cx="47" cy="111" r="1" fill="rgba(37,3,0,0.4)"/>
+ <circle cx="48" cy="111" r="1" fill="rgba(4,0,0,0.47451)"/>
+ <circle cx="49" cy="111" r="1" fill="rgba(4,0,0,0.478431)"/>
+ <circle cx="50" cy="111" r="1" fill="rgba(12,0,0,0.486275)"/>
+ <circle cx="51" cy="111" r="1" fill="rgba(19,1,0,0.509804)"/>
+ <circle cx="52" cy="111" r="1" fill="rgba(24,1,0,0.541176)"/>
+ <circle cx="53" cy="111" r="1" fill="rgba(31,2,0,0.576471)"/>
+ <circle cx="54" cy="111" r="1" fill="rgba(34,4,0,0.611765)"/>
+ <circle cx="55" cy="111" r="1" fill="rgba(31,4,0,0.635294)"/>
+ <circle cx="56" cy="111" r="1" fill="rgba(31,4,0,0.658824)"/>
+ <circle cx="57" cy="111" r="1" fill="rgba(47,7,1,0.690196)"/>
+ <circle cx="58" cy="111" r="1" fill="rgba(61,9,2,0.721569)"/>
+ <circle cx="59" cy="111" r="1" fill="rgba(91,16,3,0.772549)"/>
+ <circle cx="60" cy="111" r="1" fill="rgba(113,22,5,0.815686)"/>
+ <circle cx="61" cy="111" r="1" fill="rgba(130,29,7,0.847059)"/>
+ <circle cx="62" cy="111" r="1" fill="rgba(137,31,8,0.866667)"/>
+ <circle cx="63" cy="111" r="1" fill="rgba(152,37,10,0.890196)"/>
+ <circle cx="64" cy="111" r="1" fill="rgba(150,32,8,0.898039)"/>
+ <circle cx="65" cy="111" r="1" fill="rgba(140,20,5,0.898039)"/>
+ <circle cx="66" cy="111" r="1" fill="rgba(156,37,10,0.898039)"/>
+ <circle cx="67" cy="111" r="1" fill="rgba(142,33,8,0.870588)"/>
+ <circle cx="68" cy="111" r="1" fill="rgba(138,34,9,0.858824)"/>
+ <circle cx="69" cy="111" r="1" fill="rgba(125,33,9,0.827451)"/>
+ <circle cx="70" cy="111" r="1" fill="rgba(104,26,7,0.788235)"/>
+ <circle cx="71" cy="111" r="1" fill="rgba(73,15,3,0.74902)"/>
+ <circle cx="72" cy="111" r="1" fill="rgba(54,8,2,0.729412)"/>
+ <circle cx="73" cy="111" r="1" fill="rgba(36,3,1,0.705882)"/>
+ <circle cx="74" cy="111" r="1" fill="rgba(34,4,1,0.694118)"/>
+ <circle cx="75" cy="111" r="1" fill="rgba(42,5,1,0.690196)"/>
+ <circle cx="76" cy="111" r="1" fill="rgba(43,6,1,0.67451)"/>
+ <circle cx="77" cy="111" r="1" fill="rgba(42,5,1,0.643137)"/>
+ <circle cx="78" cy="111" r="1" fill="rgba(37,5,1,0.603922)"/>
+ <circle cx="79" cy="111" r="1" fill="rgba(29,2,0,0.560784)"/>
+ <circle cx="80" cy="111" r="1" fill="rgba(22,1,0,0.52549)"/>
+ <circle cx="81" cy="111" r="1" fill="rgba(17,0,0,0.498039)"/>
+ <circle cx="82" cy="111" r="1" fill="rgba(10,0,0,0.47451)"/>
+ <circle cx="83" cy="111" r="1" fill="rgba(4,0,0,0.454902)"/>
+ <circle cx="84" cy="111" r="1" fill="rgba(4,0,0,0.427451)"/>
+ <circle cx="85" cy="111" r="1" fill="rgba(10,0,0,0.396078)"/>
+ <circle cx="86" cy="111" r="1" fill="rgba(19,3,0,0.352941)"/>
+ <circle cx="87" cy="111" r="1" fill="rgba(28,8,1,0.294118)"/>
+ <circle cx="88" cy="111" r="1" fill="rgba(36,11,2,0.223529)"/>
+ <circle cx="89" cy="111" r="1" fill="rgba(43,15,2,0.14902)"/>
+ <circle cx="90" cy="111" r="1" fill="rgba(55,15,1,0.0823529)"/>
+ <circle cx="91" cy="111" r="1" fill="rgba(49,9,0,0.0392157)"/>
+ <circle cx="92" cy="111" r="1" fill="rgba(17,0,0,0.0117647)"/>
+ <circle cx="93" cy="111" r="1" fill="none"/>
+ <circle cx="94" cy="111" r="1" fill="rgba(15,4,0,0)"/>
+ <circle cx="95" cy="111" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="96" cy="111" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="111" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="111" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="111" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="111" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="112" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="112" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="112" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="112" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="112" r="1" fill="rgba(110,16,3,0)"/>
+ <circle cx="43" cy="112" r="1" fill="rgba(113,17,3,0)"/>
+ <circle cx="44" cy="112" r="1" fill="rgba(91,12,2,0)"/>
+ <circle cx="45" cy="112" r="1" fill="rgba(87,13,3,0)"/>
+ <circle cx="46" cy="112" r="1" fill="rgba(106,18,4,0.00392157)"/>
+ <circle cx="47" cy="112" r="1" fill="rgba(84,14,3,0.129412)"/>
+ <circle cx="48" cy="112" r="1" fill="rgba(55,8,1,0.32549)"/>
+ <circle cx="49" cy="112" r="1" fill="rgba(19,0,0,0.45098)"/>
+ <circle cx="50" cy="112" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="51" cy="112" r="1" fill="rgba(7,0,0,0.478431)"/>
+ <circle cx="52" cy="112" r="1" fill="rgba(15,0,0,0.490196)"/>
+ <circle cx="53" cy="112" r="1" fill="rgba(21,1,0,0.509804)"/>
+ <circle cx="54" cy="112" r="1" fill="rgba(24,2,0,0.533333)"/>
+ <circle cx="55" cy="112" r="1" fill="rgba(29,3,0,0.556863)"/>
+ <circle cx="56" cy="112" r="1" fill="rgba(31,3,0,0.580392)"/>
+ <circle cx="57" cy="112" r="1" fill="rgba(34,4,0,0.596078)"/>
+ <circle cx="58" cy="112" r="1" fill="rgba(36,4,0,0.615686)"/>
+ <circle cx="59" cy="112" r="1" fill="rgba(31,3,0,0.631373)"/>
+ <circle cx="60" cy="112" r="1" fill="rgba(31,3,0,0.643137)"/>
+ <circle cx="61" cy="112" r="1" fill="rgba(28,3,0,0.65098)"/>
+ <circle cx="62" cy="112" r="1" fill="rgba(28,2,0,0.658824)"/>
+ <circle cx="63" cy="112" r="1" fill="rgba(37,4,1,0.670588)"/>
+ <circle cx="64" cy="112" r="1" fill="rgba(42,6,1,0.678431)"/>
+ <circle cx="65" cy="112" r="1" fill="rgba(45,8,1,0.678431)"/>
+ <circle cx="66" cy="112" r="1" fill="rgba(40,5,1,0.678431)"/>
+ <circle cx="67" cy="112" r="1" fill="rgba(29,3,0,0.666667)"/>
+ <circle cx="68" cy="112" r="1" fill="rgba(28,2,0,0.662745)"/>
+ <circle cx="69" cy="112" r="1" fill="rgba(29,2,0,0.662745)"/>
+ <circle cx="70" cy="112" r="1" fill="rgba(33,3,0,0.658824)"/>
+ <circle cx="71" cy="112" r="1" fill="rgba(37,4,1,0.654902)"/>
+ <circle cx="72" cy="112" r="1" fill="rgba(40,5,1,0.65098)"/>
+ <circle cx="73" cy="112" r="1" fill="rgba(42,5,1,0.647059)"/>
+ <circle cx="74" cy="112" r="1" fill="rgba(40,6,1,0.631373)"/>
+ <circle cx="75" cy="112" r="1" fill="rgba(37,4,1,0.611765)"/>
+ <circle cx="76" cy="112" r="1" fill="rgba(34,3,0,0.584314)"/>
+ <circle cx="77" cy="112" r="1" fill="rgba(29,2,0,0.556863)"/>
+ <circle cx="78" cy="112" r="1" fill="rgba(22,1,0,0.52549)"/>
+ <circle cx="79" cy="112" r="1" fill="rgba(17,0,0,0.498039)"/>
+ <circle cx="80" cy="112" r="1" fill="rgba(10,0,0,0.478431)"/>
+ <circle cx="81" cy="112" r="1" fill="rgba(4,0,0,0.462745)"/>
+ <circle cx="82" cy="112" r="1" fill="rgba(4,0,0,0.439216)"/>
+ <circle cx="83" cy="112" r="1" fill="rgba(10,0,0,0.411765)"/>
+ <circle cx="84" cy="112" r="1" fill="rgba(19,2,0,0.376471)"/>
+ <circle cx="85" cy="112" r="1" fill="rgba(24,5,0,0.32549)"/>
+ <circle cx="86" cy="112" r="1" fill="rgba(33,10,1,0.266667)"/>
+ <circle cx="87" cy="112" r="1" fill="rgba(39,13,3,0.196078)"/>
+ <circle cx="88" cy="112" r="1" fill="rgba(49,12,3,0.129412)"/>
+ <circle cx="89" cy="112" r="1" fill="rgba(47,9,0,0.0705882)"/>
+ <circle cx="90" cy="112" r="1" fill="rgba(46,5,0,0.027451)"/>
+ <circle cx="91" cy="112" r="1" fill="rgba(26,2,0,0.00784314)"/>
+ <circle cx="92" cy="112" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="93" cy="112" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="94" cy="112" r="1" fill="rgba(15,4,0,0)"/>
+ <circle cx="95" cy="112" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="96" cy="112" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="112" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="112" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="112" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="112" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="113" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="113" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="113" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="113" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="113" r="1" fill="rgba(110,16,3,0)"/>
+ <circle cx="43" cy="113" r="1" fill="rgba(113,17,3,0)"/>
+ <circle cx="44" cy="113" r="1" fill="rgba(91,12,2,0)"/>
+ <circle cx="45" cy="113" r="1" fill="rgba(86,13,3,0)"/>
+ <circle cx="46" cy="113" r="1" fill="rgba(104,18,4,0)"/>
+ <circle cx="47" cy="113" r="1" fill="rgba(95,16,3,0)"/>
+ <circle cx="48" cy="113" r="1" fill="rgba(92,16,3,0.054902)"/>
+ <circle cx="49" cy="113" r="1" fill="rgba(74,12,2,0.223529)"/>
+ <circle cx="50" cy="113" r="1" fill="rgba(43,6,0,0.388235)"/>
+ <circle cx="51" cy="113" r="1" fill="rgba(10,0,0,0.466667)"/>
+ <circle cx="52" cy="113" r="1" fill="rgba(0,0,0,0.478431)"/>
+ <circle cx="53" cy="113" r="1" fill="rgba(4,0,0,0.478431)"/>
+ <circle cx="54" cy="113" r="1" fill="rgba(12,0,0,0.482353)"/>
+ <circle cx="55" cy="113" r="1" fill="rgba(15,0,0,0.494118)"/>
+ <circle cx="56" cy="113" r="1" fill="rgba(17,0,0,0.501961)"/>
+ <circle cx="57" cy="113" r="1" fill="rgba(21,0,0,0.509804)"/>
+ <circle cx="58" cy="113" r="1" fill="rgba(22,1,0,0.529412)"/>
+ <circle cx="59" cy="113" r="1" fill="rgba(28,2,0,0.545098)"/>
+ <circle cx="60" cy="113" r="1" fill="rgba(29,2,0,0.556863)"/>
+ <circle cx="61" cy="113" r="1" fill="rgba(31,3,0,0.564706)"/>
+ <circle cx="62" cy="113" r="1" fill="rgba(31,3,0,0.572549)"/>
+ <circle cx="63" cy="113" r="1" fill="rgba(31,3,0,0.580392)"/>
+ <circle cx="64" cy="113" r="1" fill="rgba(33,4,0,0.584314)"/>
+ <circle cx="65" cy="113" r="1" fill="rgba(34,4,0,0.588235)"/>
+ <circle cx="66" cy="113" r="1" fill="rgba(34,4,0,0.588235)"/>
+ <circle cx="67" cy="113" r="1" fill="rgba(34,3,0,0.588235)"/>
+ <circle cx="68" cy="113" r="1" fill="rgba(34,3,0,0.580392)"/>
+ <circle cx="69" cy="113" r="1" fill="rgba(33,3,0,0.580392)"/>
+ <circle cx="70" cy="113" r="1" fill="rgba(33,3,0,0.576471)"/>
+ <circle cx="71" cy="113" r="1" fill="rgba(33,3,0,0.572549)"/>
+ <circle cx="72" cy="113" r="1" fill="rgba(31,2,0,0.568627)"/>
+ <circle cx="73" cy="113" r="1" fill="rgba(29,2,0,0.556863)"/>
+ <circle cx="74" cy="113" r="1" fill="rgba(28,2,0,0.545098)"/>
+ <circle cx="75" cy="113" r="1" fill="rgba(24,2,0,0.529412)"/>
+ <circle cx="76" cy="113" r="1" fill="rgba(21,0,0,0.509804)"/>
+ <circle cx="77" cy="113" r="1" fill="rgba(15,0,0,0.494118)"/>
+ <circle cx="78" cy="113" r="1" fill="rgba(10,0,0,0.478431)"/>
+ <circle cx="79" cy="113" r="1" fill="rgba(4,0,0,0.462745)"/>
+ <circle cx="80" cy="113" r="1" fill="rgba(4,0,0,0.447059)"/>
+ <circle cx="81" cy="113" r="1" fill="rgba(7,0,0,0.423529)"/>
+ <circle cx="82" cy="113" r="1" fill="rgba(17,2,0,0.388235)"/>
+ <circle cx="83" cy="113" r="1" fill="rgba(24,5,0,0.345098)"/>
+ <circle cx="84" cy="113" r="1" fill="rgba(31,8,1,0.294118)"/>
+ <circle cx="85" cy="113" r="1" fill="rgba(37,12,3,0.231373)"/>
+ <circle cx="86" cy="113" r="1" fill="rgba(45,14,3,0.164706)"/>
+ <circle cx="87" cy="113" r="1" fill="rgba(47,14,3,0.105882)"/>
+ <circle cx="88" cy="113" r="1" fill="rgba(54,6,1,0.054902)"/>
+ <circle cx="89" cy="113" r="1" fill="rgba(36,0,0,0.0196078)"/>
+ <circle cx="90" cy="113" r="1" fill="rgba(7,0,0,0.00392157)"/>
+ <circle cx="91" cy="113" r="1" fill="rgba(24,8,2,0)"/>
+ <circle cx="92" cy="113" r="1" fill="rgba(10,0,0,0)"/>
+ <circle cx="93" cy="113" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="94" cy="113" r="1" fill="rgba(15,4,0,0)"/>
+ <circle cx="95" cy="113" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="96" cy="113" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="113" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="113" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="113" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="113" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="114" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="114" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="114" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="114" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="114" r="1" fill="rgba(110,16,3,0)"/>
+ <circle cx="43" cy="114" r="1" fill="rgba(113,17,3,0)"/>
+ <circle cx="44" cy="114" r="1" fill="rgba(91,12,2,0)"/>
+ <circle cx="45" cy="114" r="1" fill="rgba(86,13,3,0)"/>
+ <circle cx="46" cy="114" r="1" fill="rgba(104,18,4,0)"/>
+ <circle cx="47" cy="114" r="1" fill="rgba(94,16,3,0)"/>
+ <circle cx="48" cy="114" r="1" fill="rgba(93,16,3,0)"/>
+ <circle cx="49" cy="114" r="1" fill="rgba(100,18,4,0.00784314)"/>
+ <circle cx="50" cy="114" r="1" fill="rgba(92,18,4,0.105882)"/>
+ <circle cx="51" cy="114" r="1" fill="rgba(62,10,2,0.270588)"/>
+ <circle cx="52" cy="114" r="1" fill="rgba(31,3,0,0.407843)"/>
+ <circle cx="53" cy="114" r="1" fill="rgba(10,0,0,0.466667)"/>
+ <circle cx="54" cy="114" r="1" fill="rgba(0,0,0,0.47451)"/>
+ <circle cx="55" cy="114" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="56" cy="114" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="57" cy="114" r="1" fill="rgba(7,0,0,0.470588)"/>
+ <circle cx="58" cy="114" r="1" fill="rgba(7,0,0,0.478431)"/>
+ <circle cx="59" cy="114" r="1" fill="rgba(10,0,0,0.482353)"/>
+ <circle cx="60" cy="114" r="1" fill="rgba(12,0,0,0.486275)"/>
+ <circle cx="61" cy="114" r="1" fill="rgba(15,0,0,0.490196)"/>
+ <circle cx="62" cy="114" r="1" fill="rgba(15,0,0,0.494118)"/>
+ <circle cx="63" cy="114" r="1" fill="rgba(17,0,0,0.501961)"/>
+ <circle cx="64" cy="114" r="1" fill="rgba(19,0,0,0.505882)"/>
+ <circle cx="65" cy="114" r="1" fill="rgba(19,0,0,0.505882)"/>
+ <circle cx="66" cy="114" r="1" fill="rgba(19,0,0,0.505882)"/>
+ <circle cx="67" cy="114" r="1" fill="rgba(19,0,0,0.505882)"/>
+ <circle cx="68" cy="114" r="1" fill="rgba(19,0,0,0.505882)"/>
+ <circle cx="69" cy="114" r="1" fill="rgba(19,0,0,0.501961)"/>
+ <circle cx="70" cy="114" r="1" fill="rgba(19,0,0,0.501961)"/>
+ <circle cx="71" cy="114" r="1" fill="rgba(19,0,0,0.501961)"/>
+ <circle cx="72" cy="114" r="1" fill="rgba(17,0,0,0.498039)"/>
+ <circle cx="73" cy="114" r="1" fill="rgba(15,0,0,0.490196)"/>
+ <circle cx="74" cy="114" r="1" fill="rgba(12,0,0,0.486275)"/>
+ <circle cx="75" cy="114" r="1" fill="rgba(10,0,0,0.478431)"/>
+ <circle cx="76" cy="114" r="1" fill="rgba(7,0,0,0.470588)"/>
+ <circle cx="77" cy="114" r="1" fill="rgba(4,0,0,0.458824)"/>
+ <circle cx="78" cy="114" r="1" fill="rgba(4,0,0,0.443137)"/>
+ <circle cx="79" cy="114" r="1" fill="rgba(10,0,0,0.427451)"/>
+ <circle cx="80" cy="114" r="1" fill="rgba(17,1,0,0.396078)"/>
+ <circle cx="81" cy="114" r="1" fill="rgba(24,3,0,0.356863)"/>
+ <circle cx="82" cy="114" r="1" fill="rgba(29,7,0,0.305882)"/>
+ <circle cx="83" cy="114" r="1" fill="rgba(36,11,1,0.25098)"/>
+ <circle cx="84" cy="114" r="1" fill="rgba(42,13,3,0.188235)"/>
+ <circle cx="85" cy="114" r="1" fill="rgba(45,15,3,0.129412)"/>
+ <circle cx="86" cy="114" r="1" fill="rgba(49,13,1,0.0823529)"/>
+ <circle cx="87" cy="114" r="1" fill="rgba(45,7,0,0.0392157)"/>
+ <circle cx="88" cy="114" r="1" fill="rgba(26,0,0,0.0156863)"/>
+ <circle cx="89" cy="114" r="1" fill="rgba(10,0,0,0)"/>
+ <circle cx="90" cy="114" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="91" cy="114" r="1" fill="rgba(26,8,2,0)"/>
+ <circle cx="92" cy="114" r="1" fill="rgba(10,0,0,0)"/>
+ <circle cx="93" cy="114" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="94" cy="114" r="1" fill="rgba(15,4,0,0)"/>
+ <circle cx="95" cy="114" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="96" cy="114" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="114" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="114" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="114" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="114" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="115" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="115" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="115" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="115" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="115" r="1" fill="rgba(110,16,3,0)"/>
+ <circle cx="43" cy="115" r="1" fill="rgba(113,17,3,0)"/>
+ <circle cx="44" cy="115" r="1" fill="rgba(91,12,2,0)"/>
+ <circle cx="45" cy="115" r="1" fill="rgba(86,13,3,0)"/>
+ <circle cx="46" cy="115" r="1" fill="rgba(104,18,4,0)"/>
+ <circle cx="47" cy="115" r="1" fill="rgba(94,16,3,0)"/>
+ <circle cx="48" cy="115" r="1" fill="rgba(92,16,3,0)"/>
+ <circle cx="49" cy="115" r="1" fill="rgba(99,18,4,0)"/>
+ <circle cx="50" cy="115" r="1" fill="rgba(99,19,4,0)"/>
+ <circle cx="51" cy="115" r="1" fill="rgba(84,16,3,0.0235294)"/>
+ <circle cx="52" cy="115" r="1" fill="rgba(70,13,2,0.12549)"/>
+ <circle cx="53" cy="115" r="1" fill="rgba(61,11,2,0.266667)"/>
+ <circle cx="54" cy="115" r="1" fill="rgba(40,6,0,0.384314)"/>
+ <circle cx="55" cy="115" r="1" fill="rgba(19,1,0,0.45098)"/>
+ <circle cx="56" cy="115" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="57" cy="115" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="58" cy="115" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="59" cy="115" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="60" cy="115" r="1" fill="rgba(0,0,0,0.462745)"/>
+ <circle cx="61" cy="115" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="62" cy="115" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="63" cy="115" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="64" cy="115" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="65" cy="115" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="66" cy="115" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="67" cy="115" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="68" cy="115" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="69" cy="115" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="70" cy="115" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="71" cy="115" r="1" fill="rgba(4,0,0,0.470588)"/>
+ <circle cx="72" cy="115" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="73" cy="115" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="74" cy="115" r="1" fill="rgba(4,0,0,0.458824)"/>
+ <circle cx="75" cy="115" r="1" fill="rgba(4,0,0,0.45098)"/>
+ <circle cx="76" cy="115" r="1" fill="rgba(7,0,0,0.439216)"/>
+ <circle cx="77" cy="115" r="1" fill="rgba(12,1,0,0.419608)"/>
+ <circle cx="78" cy="115" r="1" fill="rgba(19,3,0,0.392157)"/>
+ <circle cx="79" cy="115" r="1" fill="rgba(24,5,0,0.34902)"/>
+ <circle cx="80" cy="115" r="1" fill="rgba(31,6,0,0.301961)"/>
+ <circle cx="81" cy="115" r="1" fill="rgba(36,8,1,0.25098)"/>
+ <circle cx="82" cy="115" r="1" fill="rgba(42,12,2,0.192157)"/>
+ <circle cx="83" cy="115" r="1" fill="rgba(47,14,2,0.141176)"/>
+ <circle cx="84" cy="115" r="1" fill="rgba(50,14,1,0.0941176)"/>
+ <circle cx="85" cy="115" r="1" fill="rgba(40,6,0,0.054902)"/>
+ <circle cx="86" cy="115" r="1" fill="rgba(31,2,0,0.027451)"/>
+ <circle cx="87" cy="115" r="1" fill="rgba(17,0,0,0.0117647)"/>
+ <circle cx="88" cy="115" r="1" fill="rgba(10,2,1,0)"/>
+ <circle cx="89" cy="115" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="90" cy="115" r="1" fill="rgba(10,1,0,0)"/>
+ <circle cx="91" cy="115" r="1" fill="rgba(26,8,2,0)"/>
+ <circle cx="92" cy="115" r="1" fill="rgba(10,0,0,0)"/>
+ <circle cx="93" cy="115" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="94" cy="115" r="1" fill="rgba(15,4,0,0)"/>
+ <circle cx="95" cy="115" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="96" cy="115" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="115" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="115" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="115" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="115" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="116" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="116" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="116" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="116" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="116" r="1" fill="rgba(110,16,3,0)"/>
+ <circle cx="43" cy="116" r="1" fill="rgba(113,17,3,0)"/>
+ <circle cx="44" cy="116" r="1" fill="rgba(91,12,2,0)"/>
+ <circle cx="45" cy="116" r="1" fill="rgba(86,13,3,0)"/>
+ <circle cx="46" cy="116" r="1" fill="rgba(104,18,4,0)"/>
+ <circle cx="47" cy="116" r="1" fill="rgba(94,16,3,0)"/>
+ <circle cx="48" cy="116" r="1" fill="rgba(92,16,3,0)"/>
+ <circle cx="49" cy="116" r="1" fill="rgba(99,18,4,0)"/>
+ <circle cx="50" cy="116" r="1" fill="rgba(98,19,4,0)"/>
+ <circle cx="51" cy="116" r="1" fill="rgba(83,16,3,0)"/>
+ <circle cx="52" cy="116" r="1" fill="rgba(77,15,3,0)"/>
+ <circle cx="53" cy="116" r="1" fill="rgba(88,18,4,0.0156863)"/>
+ <circle cx="54" cy="116" r="1" fill="rgba(91,20,5,0.101961)"/>
+ <circle cx="55" cy="116" r="1" fill="rgba(68,14,2,0.215686)"/>
+ <circle cx="56" cy="116" r="1" fill="rgba(47,8,1,0.32549)"/>
+ <circle cx="57" cy="116" r="1" fill="rgba(28,4,0,0.403922)"/>
+ <circle cx="58" cy="116" r="1" fill="rgba(17,1,0,0.447059)"/>
+ <circle cx="59" cy="116" r="1" fill="rgba(4,0,0,0.462745)"/>
+ <circle cx="60" cy="116" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="61" cy="116" r="1" fill="rgba(0,0,0,0.470588)"/>
+ <circle cx="62" cy="116" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="63" cy="116" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="64" cy="116" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="65" cy="116" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="66" cy="116" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="67" cy="116" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="68" cy="116" r="1" fill="rgba(0,0,0,0.466667)"/>
+ <circle cx="69" cy="116" r="1" fill="rgba(0,0,0,0.462745)"/>
+ <circle cx="70" cy="116" r="1" fill="rgba(0,0,0,0.458824)"/>
+ <circle cx="71" cy="116" r="1" fill="rgba(7,0,0,0.454902)"/>
+ <circle cx="72" cy="116" r="1" fill="rgba(10,0,0,0.447059)"/>
+ <circle cx="73" cy="116" r="1" fill="rgba(10,0,0,0.431373)"/>
+ <circle cx="74" cy="116" r="1" fill="rgba(15,1,0,0.415686)"/>
+ <circle cx="75" cy="116" r="1" fill="rgba(17,2,0,0.396078)"/>
+ <circle cx="76" cy="116" r="1" fill="rgba(21,4,0,0.364706)"/>
+ <circle cx="77" cy="116" r="1" fill="rgba(29,6,0,0.321569)"/>
+ <circle cx="78" cy="116" r="1" fill="rgba(36,9,1,0.278431)"/>
+ <circle cx="79" cy="116" r="1" fill="rgba(39,11,1,0.227451)"/>
+ <circle cx="80" cy="116" r="1" fill="rgba(43,11,2,0.180392)"/>
+ <circle cx="81" cy="116" r="1" fill="rgba(49,12,2,0.133333)"/>
+ <circle cx="82" cy="116" r="1" fill="rgba(53,11,1,0.0901961)"/>
+ <circle cx="83" cy="116" r="1" fill="rgba(51,9,0,0.054902)"/>
+ <circle cx="84" cy="116" r="1" fill="rgba(45,4,0,0.0313725)"/>
+ <circle cx="85" cy="116" r="1" fill="rgba(17,0,0,0.0117647)"/>
+ <circle cx="86" cy="116" r="1" fill="rgba(0,0,0,0.00392157)"/>
+ <circle cx="87" cy="116" r="1" fill="rgba(10,4,0,0)"/>
+ <circle cx="88" cy="116" r="1" fill="rgba(21,4,3,0)"/>
+ <circle cx="89" cy="116" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="90" cy="116" r="1" fill="rgba(10,1,0,0)"/>
+ <circle cx="91" cy="116" r="1" fill="rgba(26,8,2,0)"/>
+ <circle cx="92" cy="116" r="1" fill="rgba(10,0,0,0)"/>
+ <circle cx="93" cy="116" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="94" cy="116" r="1" fill="rgba(15,4,0,0)"/>
+ <circle cx="95" cy="116" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="96" cy="116" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="116" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="116" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="116" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="116" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="117" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="117" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="117" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="117" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="117" r="1" fill="rgba(110,16,3,0)"/>
+ <circle cx="43" cy="117" r="1" fill="rgba(113,17,3,0)"/>
+ <circle cx="44" cy="117" r="1" fill="rgba(91,12,2,0)"/>
+ <circle cx="45" cy="117" r="1" fill="rgba(86,13,3,0)"/>
+ <circle cx="46" cy="117" r="1" fill="rgba(104,18,4,0)"/>
+ <circle cx="47" cy="117" r="1" fill="rgba(94,16,3,0)"/>
+ <circle cx="48" cy="117" r="1" fill="rgba(92,16,3,0)"/>
+ <circle cx="49" cy="117" r="1" fill="rgba(99,18,4,0)"/>
+ <circle cx="50" cy="117" r="1" fill="rgba(98,19,4,0)"/>
+ <circle cx="51" cy="117" r="1" fill="rgba(83,16,3,0)"/>
+ <circle cx="52" cy="117" r="1" fill="rgba(76,15,3,0)"/>
+ <circle cx="53" cy="117" r="1" fill="rgba(88,18,4,0)"/>
+ <circle cx="54" cy="117" r="1" fill="rgba(97,23,7,0)"/>
+ <circle cx="55" cy="117" r="1" fill="rgba(81,16,3,0.00784314)"/>
+ <circle cx="56" cy="117" r="1" fill="rgba(75,16,3,0.054902)"/>
+ <circle cx="57" cy="117" r="1" fill="rgba(68,14,3,0.133333)"/>
+ <circle cx="58" cy="117" r="1" fill="rgba(62,13,2,0.219608)"/>
+ <circle cx="59" cy="117" r="1" fill="rgba(54,11,2,0.294118)"/>
+ <circle cx="60" cy="117" r="1" fill="rgba(37,7,1,0.34902)"/>
+ <circle cx="61" cy="117" r="1" fill="rgba(24,3,0,0.388235)"/>
+ <circle cx="62" cy="117" r="1" fill="rgba(26,3,0,0.419608)"/>
+ <circle cx="63" cy="117" r="1" fill="rgba(21,2,0,0.439216)"/>
+ <circle cx="64" cy="117" r="1" fill="rgba(10,0,0,0.443137)"/>
+ <circle cx="65" cy="117" r="1" fill="rgba(0,0,0,0.447059)"/>
+ <circle cx="66" cy="117" r="1" fill="rgba(10,0,0,0.447059)"/>
+ <circle cx="67" cy="117" r="1" fill="rgba(12,2,0,0.443137)"/>
+ <circle cx="68" cy="117" r="1" fill="rgba(12,2,0,0.431373)"/>
+ <circle cx="69" cy="117" r="1" fill="rgba(10,1,0,0.419608)"/>
+ <circle cx="70" cy="117" r="1" fill="rgba(10,0,0,0.4)"/>
+ <circle cx="71" cy="117" r="1" fill="rgba(19,3,0,0.380392)"/>
+ <circle cx="72" cy="117" r="1" fill="rgba(26,4,0,0.360784)"/>
+ <circle cx="73" cy="117" r="1" fill="rgba(28,5,0,0.337255)"/>
+ <circle cx="74" cy="117" r="1" fill="rgba(29,6,1,0.301961)"/>
+ <circle cx="75" cy="117" r="1" fill="rgba(31,8,1,0.266667)"/>
+ <circle cx="76" cy="117" r="1" fill="rgba(37,9,2,0.227451)"/>
+ <circle cx="77" cy="117" r="1" fill="rgba(42,11,2,0.184314)"/>
+ <circle cx="78" cy="117" r="1" fill="rgba(49,14,3,0.145098)"/>
+ <circle cx="79" cy="117" r="1" fill="rgba(53,14,2,0.105882)"/>
+ <circle cx="80" cy="117" r="1" fill="rgba(51,9,0,0.0705882)"/>
+ <circle cx="81" cy="117" r="1" fill="rgba(57,7,0,0.0431373)"/>
+ <circle cx="82" cy="117" r="1" fill="rgba(54,1,0,0.0235294)"/>
+ <circle cx="83" cy="117" r="1" fill="rgba(31,0,0,0.00784314)"/>
+ <circle cx="84" cy="117" r="1" fill="rgba(7,2,0,0.00392157)"/>
+ <circle cx="85" cy="117" r="1" fill="rgba(4,2,0,0)"/>
+ <circle cx="86" cy="117" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="87" cy="117" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="88" cy="117" r="1" fill="rgba(21,4,2,0)"/>
+ <circle cx="89" cy="117" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="90" cy="117" r="1" fill="rgba(10,1,0,0)"/>
+ <circle cx="91" cy="117" r="1" fill="rgba(26,8,2,0)"/>
+ <circle cx="92" cy="117" r="1" fill="rgba(10,0,0,0)"/>
+ <circle cx="93" cy="117" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="94" cy="117" r="1" fill="rgba(15,4,0,0)"/>
+ <circle cx="95" cy="117" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="96" cy="117" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="117" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="117" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="117" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="117" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="118" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="118" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="118" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="118" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="118" r="1" fill="rgba(110,16,3,0)"/>
+ <circle cx="43" cy="118" r="1" fill="rgba(113,17,3,0)"/>
+ <circle cx="44" cy="118" r="1" fill="rgba(91,12,2,0)"/>
+ <circle cx="45" cy="118" r="1" fill="rgba(86,13,3,0)"/>
+ <circle cx="46" cy="118" r="1" fill="rgba(104,18,4,0)"/>
+ <circle cx="47" cy="118" r="1" fill="rgba(94,16,3,0)"/>
+ <circle cx="48" cy="118" r="1" fill="rgba(92,16,3,0)"/>
+ <circle cx="49" cy="118" r="1" fill="rgba(99,18,4,0)"/>
+ <circle cx="50" cy="118" r="1" fill="rgba(98,19,4,0)"/>
+ <circle cx="51" cy="118" r="1" fill="rgba(83,16,3,0)"/>
+ <circle cx="52" cy="118" r="1" fill="rgba(76,15,3,0)"/>
+ <circle cx="53" cy="118" r="1" fill="rgba(88,18,4,0)"/>
+ <circle cx="54" cy="118" r="1" fill="rgba(94,23,6,0)"/>
+ <circle cx="55" cy="118" r="1" fill="rgba(74,12,2,0)"/>
+ <circle cx="56" cy="118" r="1" fill="rgba(78,11,2,0)"/>
+ <circle cx="57" cy="118" r="1" fill="rgba(76,9,2,0)"/>
+ <circle cx="58" cy="118" r="1" fill="rgba(83,17,3,0.0156863)"/>
+ <circle cx="59" cy="118" r="1" fill="rgba(87,22,5,0.054902)"/>
+ <circle cx="60" cy="118" r="1" fill="rgba(65,14,3,0.0941176)"/>
+ <circle cx="61" cy="118" r="1" fill="rgba(58,14,3,0.137255)"/>
+ <circle cx="62" cy="118" r="1" fill="rgba(69,17,3,0.188235)"/>
+ <circle cx="63" cy="118" r="1" fill="rgba(51,12,2,0.223529)"/>
+ <circle cx="64" cy="118" r="1" fill="rgba(21,2,0,0.235294)"/>
+ <circle cx="65" cy="118" r="1" fill="rgba(31,5,0,0.258824)"/>
+ <circle cx="66" cy="118" r="1" fill="rgba(51,12,2,0.278431)"/>
+ <circle cx="67" cy="118" r="1" fill="rgba(51,13,2,0.282353)"/>
+ <circle cx="68" cy="118" r="1" fill="rgba(46,12,2,0.278431)"/>
+ <circle cx="69" cy="118" r="1" fill="rgba(33,7,1,0.258824)"/>
+ <circle cx="70" cy="118" r="1" fill="rgba(22,4,0,0.239216)"/>
+ <circle cx="71" cy="118" r="1" fill="rgba(34,8,1,0.227451)"/>
+ <circle cx="72" cy="118" r="1" fill="rgba(45,11,2,0.207843)"/>
+ <circle cx="73" cy="118" r="1" fill="rgba(47,13,3,0.180392)"/>
+ <circle cx="74" cy="118" r="1" fill="rgba(45,12,2,0.152941)"/>
+ <circle cx="75" cy="118" r="1" fill="rgba(43,11,2,0.12549)"/>
+ <circle cx="76" cy="118" r="1" fill="rgba(46,12,1,0.0980392)"/>
+ <circle cx="77" cy="118" r="1" fill="rgba(54,11,2,0.0705882)"/>
+ <circle cx="78" cy="118" r="1" fill="rgba(61,12,1,0.0470588)"/>
+ <circle cx="79" cy="118" r="1" fill="rgba(62,5,0,0.027451)"/>
+ <circle cx="80" cy="118" r="1" fill="rgba(43,0,0,0.0156863)"/>
+ <circle cx="81" cy="118" r="1" fill="rgba(33,0,0,0.00784314)"/>
+ <circle cx="82" cy="118" r="1" fill="rgba(15,0,0,0)"/>
+ <circle cx="83" cy="118" r="1" fill="rgba(10,1,0,0)"/>
+ <circle cx="84" cy="118" r="1" fill="rgba(7,6,0,0)"/>
+ <circle cx="85" cy="118" r="1" fill="rgba(7,3,0,0)"/>
+ <circle cx="86" cy="118" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="87" cy="118" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="88" cy="118" r="1" fill="rgba(21,4,2,0)"/>
+ <circle cx="89" cy="118" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="90" cy="118" r="1" fill="rgba(10,1,0,0)"/>
+ <circle cx="91" cy="118" r="1" fill="rgba(26,8,2,0)"/>
+ <circle cx="92" cy="118" r="1" fill="rgba(10,0,0,0)"/>
+ <circle cx="93" cy="118" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="94" cy="118" r="1" fill="rgba(15,4,0,0)"/>
+ <circle cx="95" cy="118" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="96" cy="118" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="118" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="118" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="118" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="118" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="119" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="119" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="119" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="119" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="119" r="1" fill="rgba(110,16,3,0)"/>
+ <circle cx="43" cy="119" r="1" fill="rgba(113,17,3,0)"/>
+ <circle cx="44" cy="119" r="1" fill="rgba(91,12,2,0)"/>
+ <circle cx="45" cy="119" r="1" fill="rgba(86,13,3,0)"/>
+ <circle cx="46" cy="119" r="1" fill="rgba(104,18,4,0)"/>
+ <circle cx="47" cy="119" r="1" fill="rgba(94,16,3,0)"/>
+ <circle cx="48" cy="119" r="1" fill="rgba(92,16,3,0)"/>
+ <circle cx="49" cy="119" r="1" fill="rgba(99,18,4,0)"/>
+ <circle cx="50" cy="119" r="1" fill="rgba(98,19,4,0)"/>
+ <circle cx="51" cy="119" r="1" fill="rgba(83,16,3,0)"/>
+ <circle cx="52" cy="119" r="1" fill="rgba(76,15,3,0)"/>
+ <circle cx="53" cy="119" r="1" fill="rgba(88,18,4,0)"/>
+ <circle cx="54" cy="119" r="1" fill="rgba(94,23,6,0)"/>
+ <circle cx="55" cy="119" r="1" fill="rgba(74,12,2,0)"/>
+ <circle cx="56" cy="119" r="1" fill="rgba(78,11,2,0)"/>
+ <circle cx="57" cy="119" r="1" fill="rgba(73,4,1,0)"/>
+ <circle cx="58" cy="119" r="1" fill="rgba(85,13,3,0)"/>
+ <circle cx="59" cy="119" r="1" fill="rgba(96,8,4,0)"/>
+ <circle cx="60" cy="119" r="1" fill="rgba(69,5,0,0)"/>
+ <circle cx="61" cy="119" r="1" fill="rgba(82,21,7,0.00784314)"/>
+ <circle cx="62" cy="119" r="1" fill="rgba(103,33,15,0.0196078)"/>
+ <circle cx="63" cy="119" r="1" fill="rgba(76,23,7,0.027451)"/>
+ <circle cx="64" cy="119" r="1" fill="rgba(54,22,6,0.0313725)"/>
+ <circle cx="65" cy="119" r="1" fill="rgba(82,33,12,0.0509804)"/>
+ <circle cx="66" cy="119" r="1" fill="rgba(95,37,11,0.0745098)"/>
+ <circle cx="67" cy="119" r="1" fill="rgba(94,35,11,0.0862745)"/>
+ <circle cx="68" cy="119" r="1" fill="rgba(78,31,8,0.0941176)"/>
+ <circle cx="69" cy="119" r="1" fill="rgba(54,17,5,0.0901961)"/>
+ <circle cx="70" cy="119" r="1" fill="rgba(39,8,1,0.0823529)"/>
+ <circle cx="71" cy="119" r="1" fill="rgba(47,8,1,0.0823529)"/>
+ <circle cx="72" cy="119" r="1" fill="rgba(53,18,3,0.0745098)"/>
+ <circle cx="73" cy="119" r="1" fill="rgba(58,16,3,0.0627451)"/>
+ <circle cx="74" cy="119" r="1" fill="rgba(59,11,0,0.0509804)"/>
+ <circle cx="75" cy="119" r="1" fill="rgba(51,4,0,0.0352941)"/>
+ <circle cx="76" cy="119" r="1" fill="rgba(50,5,0,0.0235294)"/>
+ <circle cx="77" cy="119" r="1" fill="rgba(59,0,0,0.00784314)"/>
+ <circle cx="78" cy="119" r="1" fill="rgba(40,0,0,0.00392157)"/>
+ <circle cx="79" cy="119" r="1" fill="rgba(26,0,0,0.00392157)"/>
+ <circle cx="80" cy="119" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="81" cy="119" r="1" fill="none"/>
+ <circle cx="82" cy="119" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="83" cy="119" r="1" fill="rgba(15,1,0,0)"/>
+ <circle cx="84" cy="119" r="1" fill="rgba(7,6,0,0)"/>
+ <circle cx="85" cy="119" r="1" fill="rgba(7,3,0,0)"/>
+ <circle cx="86" cy="119" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="87" cy="119" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="88" cy="119" r="1" fill="rgba(21,4,2,0)"/>
+ <circle cx="89" cy="119" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="90" cy="119" r="1" fill="rgba(10,1,0,0)"/>
+ <circle cx="91" cy="119" r="1" fill="rgba(26,8,2,0)"/>
+ <circle cx="92" cy="119" r="1" fill="rgba(10,0,0,0)"/>
+ <circle cx="93" cy="119" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="94" cy="119" r="1" fill="rgba(15,4,0,0)"/>
+ <circle cx="95" cy="119" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="96" cy="119" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="119" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="119" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="119" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="119" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="120" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="120" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="120" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="120" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="120" r="1" fill="rgba(110,16,3,0)"/>
+ <circle cx="43" cy="120" r="1" fill="rgba(113,17,3,0)"/>
+ <circle cx="44" cy="120" r="1" fill="rgba(91,12,2,0)"/>
+ <circle cx="45" cy="120" r="1" fill="rgba(86,13,3,0)"/>
+ <circle cx="46" cy="120" r="1" fill="rgba(104,18,4,0)"/>
+ <circle cx="47" cy="120" r="1" fill="rgba(94,16,3,0)"/>
+ <circle cx="48" cy="120" r="1" fill="rgba(92,16,3,0)"/>
+ <circle cx="49" cy="120" r="1" fill="rgba(99,18,4,0)"/>
+ <circle cx="50" cy="120" r="1" fill="rgba(98,19,4,0)"/>
+ <circle cx="51" cy="120" r="1" fill="rgba(83,16,3,0)"/>
+ <circle cx="52" cy="120" r="1" fill="rgba(76,15,3,0)"/>
+ <circle cx="53" cy="120" r="1" fill="rgba(88,18,4,0)"/>
+ <circle cx="54" cy="120" r="1" fill="rgba(94,23,6,0)"/>
+ <circle cx="55" cy="120" r="1" fill="rgba(74,12,2,0)"/>
+ <circle cx="56" cy="120" r="1" fill="rgba(78,11,2,0)"/>
+ <circle cx="57" cy="120" r="1" fill="rgba(73,5,1,0)"/>
+ <circle cx="58" cy="120" r="1" fill="rgba(85,13,3,0)"/>
+ <circle cx="59" cy="120" r="1" fill="rgba(96,6,3,0)"/>
+ <circle cx="60" cy="120" r="1" fill="rgba(68,4,0,0)"/>
+ <circle cx="61" cy="120" r="1" fill="rgba(87,23,10,0)"/>
+ <circle cx="62" cy="120" r="1" fill="rgba(116,31,22,0)"/>
+ <circle cx="63" cy="120" r="1" fill="rgba(96,20,11,0)"/>
+ <circle cx="64" cy="120" r="1" fill="rgba(86,47,20,0)"/>
+ <circle cx="65" cy="120" r="1" fill="rgba(137,82,51,0)"/>
+ <circle cx="66" cy="120" r="1" fill="rgba(155,107,71,0.00392157)"/>
+ <circle cx="67" cy="120" r="1" fill="rgba(144,86,48,0.00784314)"/>
+ <circle cx="68" cy="120" r="1" fill="rgba(122,62,28,0.00784314)"/>
+ <circle cx="69" cy="120" r="1" fill="rgba(74,26,10,0.0156863)"/>
+ <circle cx="70" cy="120" r="1" fill="rgba(28,6,0,0.0117647)"/>
+ <circle cx="71" cy="120" r="1" fill="rgba(24,0,0,0.0117647)"/>
+ <circle cx="72" cy="120" r="1" fill="rgba(24,9,0,0.0117647)"/>
+ <circle cx="73" cy="120" r="1" fill="rgba(28,5,0,0.0117647)"/>
+ <circle cx="74" cy="120" r="1" fill="rgba(37,0,0,0.00392157)"/>
+ <circle cx="75" cy="120" r="1" fill="rgba(26,0,0,0)"/>
+ <circle cx="76" cy="120" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="77" cy="120" r="1" fill="rgba(28,0,0,0)"/>
+ <circle cx="78" cy="120" r="1" fill="none"/>
+ <circle cx="79" cy="120" r="1" fill="rgba(0,1,0,0)"/>
+ <circle cx="80" cy="120" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="81" cy="120" r="1" fill="none"/>
+ <circle cx="82" cy="120" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="83" cy="120" r="1" fill="rgba(15,1,0,0)"/>
+ <circle cx="84" cy="120" r="1" fill="rgba(7,6,0,0)"/>
+ <circle cx="85" cy="120" r="1" fill="rgba(7,3,0,0)"/>
+ <circle cx="86" cy="120" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="87" cy="120" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="88" cy="120" r="1" fill="rgba(21,4,2,0)"/>
+ <circle cx="89" cy="120" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="90" cy="120" r="1" fill="rgba(10,1,0,0)"/>
+ <circle cx="91" cy="120" r="1" fill="rgba(26,8,2,0)"/>
+ <circle cx="92" cy="120" r="1" fill="rgba(10,0,0,0)"/>
+ <circle cx="93" cy="120" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="94" cy="120" r="1" fill="rgba(15,4,0,0)"/>
+ <circle cx="95" cy="120" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="96" cy="120" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="120" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="120" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="120" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="120" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="121" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="19" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="20" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="21" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="22" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="23" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="24" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="25" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="26" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="27" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="28" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="29" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="30" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="31" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="32" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="33" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="34" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="35" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="36" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="37" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="38" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="39" cy="121" r="1" fill="rgba(115,13,2,0)"/>
+ <circle cx="40" cy="121" r="1" fill="rgba(115,13,3,0)"/>
+ <circle cx="41" cy="121" r="1" fill="rgba(112,14,3,0)"/>
+ <circle cx="42" cy="121" r="1" fill="rgba(110,16,3,0)"/>
+ <circle cx="43" cy="121" r="1" fill="rgba(113,17,3,0)"/>
+ <circle cx="44" cy="121" r="1" fill="rgba(91,12,2,0)"/>
+ <circle cx="45" cy="121" r="1" fill="rgba(86,13,3,0)"/>
+ <circle cx="46" cy="121" r="1" fill="rgba(104,18,4,0)"/>
+ <circle cx="47" cy="121" r="1" fill="rgba(94,16,3,0)"/>
+ <circle cx="48" cy="121" r="1" fill="rgba(92,16,3,0)"/>
+ <circle cx="49" cy="121" r="1" fill="rgba(99,18,4,0)"/>
+ <circle cx="50" cy="121" r="1" fill="rgba(98,19,4,0)"/>
+ <circle cx="51" cy="121" r="1" fill="rgba(83,16,3,0)"/>
+ <circle cx="52" cy="121" r="1" fill="rgba(76,15,3,0)"/>
+ <circle cx="53" cy="121" r="1" fill="rgba(88,18,4,0)"/>
+ <circle cx="54" cy="121" r="1" fill="rgba(94,23,6,0)"/>
+ <circle cx="55" cy="121" r="1" fill="rgba(74,12,2,0)"/>
+ <circle cx="56" cy="121" r="1" fill="rgba(78,11,2,0)"/>
+ <circle cx="57" cy="121" r="1" fill="rgba(73,5,1,0)"/>
+ <circle cx="58" cy="121" r="1" fill="rgba(85,13,3,0)"/>
+ <circle cx="59" cy="121" r="1" fill="rgba(96,6,3,0)"/>
+ <circle cx="60" cy="121" r="1" fill="rgba(68,4,0,0)"/>
+ <circle cx="61" cy="121" r="1" fill="rgba(86,23,9,0)"/>
+ <circle cx="62" cy="121" r="1" fill="rgba(114,28,20,0)"/>
+ <circle cx="63" cy="121" r="1" fill="rgba(95,17,11,0)"/>
+ <circle cx="64" cy="121" r="1" fill="rgba(86,47,20,0)"/>
+ <circle cx="65" cy="121" r="1" fill="rgba(141,86,55,0)"/>
+ <circle cx="66" cy="121" r="1" fill="rgba(174,134,105,0)"/>
+ <circle cx="67" cy="121" r="1" fill="rgba(158,105,68,0)"/>
+ <circle cx="68" cy="121" r="1" fill="rgba(131,62,36,0)"/>
+ <circle cx="69" cy="121" r="1" fill="rgba(59,12,4,0.00392157)"/>
+ <circle cx="70" cy="121" r="1" fill="rgba(15,0,0,0)"/>
+ <circle cx="71" cy="121" r="1" fill="none"/>
+ <circle cx="72" cy="121" r="1" fill="none"/>
+ <circle cx="73" cy="121" r="1" fill="none"/>
+ <circle cx="74" cy="121" r="1" fill="none"/>
+ <circle cx="75" cy="121" r="1" fill="none"/>
+ <circle cx="76" cy="121" r="1" fill="none"/>
+ <circle cx="77" cy="121" r="1" fill="rgba(24,0,0,0)"/>
+ <circle cx="78" cy="121" r="1" fill="rgba(10,0,0,0)"/>
+ <circle cx="79" cy="121" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="80" cy="121" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="81" cy="121" r="1" fill="none"/>
+ <circle cx="82" cy="121" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="83" cy="121" r="1" fill="rgba(15,1,0,0)"/>
+ <circle cx="84" cy="121" r="1" fill="rgba(7,6,0,0)"/>
+ <circle cx="85" cy="121" r="1" fill="rgba(7,3,0,0)"/>
+ <circle cx="86" cy="121" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="87" cy="121" r="1" fill="rgba(12,3,0,0)"/>
+ <circle cx="88" cy="121" r="1" fill="rgba(21,4,2,0)"/>
+ <circle cx="89" cy="121" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="90" cy="121" r="1" fill="rgba(10,1,0,0)"/>
+ <circle cx="91" cy="121" r="1" fill="rgba(26,8,2,0)"/>
+ <circle cx="92" cy="121" r="1" fill="rgba(10,0,0,0)"/>
+ <circle cx="93" cy="121" r="1" fill="rgba(4,0,0,0)"/>
+ <circle cx="94" cy="121" r="1" fill="rgba(15,4,0,0)"/>
+ <circle cx="95" cy="121" r="1" fill="rgba(7,2,0,0)"/>
+ <circle cx="96" cy="121" r="1" fill="rgba(7,0,0,0)"/>
+ <circle cx="97" cy="121" r="1" fill="rgba(4,1,0,0)"/>
+ <circle cx="98" cy="121" r="1" fill="rgba(7,1,0,0)"/>
+ <circle cx="99" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="100" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="101" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="102" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="103" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="104" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="105" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="106" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="107" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="108" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="109" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="110" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="111" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="112" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="113" cy="121" r="1" fill="rgba(10,2,0,0)"/>
+ <circle cx="114" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="121" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="122" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="19" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="20" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="21" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="22" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="23" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="24" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="25" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="26" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="27" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="28" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="29" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="30" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="31" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="32" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="33" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="34" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="35" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="36" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="37" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="38" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="39" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="40" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="41" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="42" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="43" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="44" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="45" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="46" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="47" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="48" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="49" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="50" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="51" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="52" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="53" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="54" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="55" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="56" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="57" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="58" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="59" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="60" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="61" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="62" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="63" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="64" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="65" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="66" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="67" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="68" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="69" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="70" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="71" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="72" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="73" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="74" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="75" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="76" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="77" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="78" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="79" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="80" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="81" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="82" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="83" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="84" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="85" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="86" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="87" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="88" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="89" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="90" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="91" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="92" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="93" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="94" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="95" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="96" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="97" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="98" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="99" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="100" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="101" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="102" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="103" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="104" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="105" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="106" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="107" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="108" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="109" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="110" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="111" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="112" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="113" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="114" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="122" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="123" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="19" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="20" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="21" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="22" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="23" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="24" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="25" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="26" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="27" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="28" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="29" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="30" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="31" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="32" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="33" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="34" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="35" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="36" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="37" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="38" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="39" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="40" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="41" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="42" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="43" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="44" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="45" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="46" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="47" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="48" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="49" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="50" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="51" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="52" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="53" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="54" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="55" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="56" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="57" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="58" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="59" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="60" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="61" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="62" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="63" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="64" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="65" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="66" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="67" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="68" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="69" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="70" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="71" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="72" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="73" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="74" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="75" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="76" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="77" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="78" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="79" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="80" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="81" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="82" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="83" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="84" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="85" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="86" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="87" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="88" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="89" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="90" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="91" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="92" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="93" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="94" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="95" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="96" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="97" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="98" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="99" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="100" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="101" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="102" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="103" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="104" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="105" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="106" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="107" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="108" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="109" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="110" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="111" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="112" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="113" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="114" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="123" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="124" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="19" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="20" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="21" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="22" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="23" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="24" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="25" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="26" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="27" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="28" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="29" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="30" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="31" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="32" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="33" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="34" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="35" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="36" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="37" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="38" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="39" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="40" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="41" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="42" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="43" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="44" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="45" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="46" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="47" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="48" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="49" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="50" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="51" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="52" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="53" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="54" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="55" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="56" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="57" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="58" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="59" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="60" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="61" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="62" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="63" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="64" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="65" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="66" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="67" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="68" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="69" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="70" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="71" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="72" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="73" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="74" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="75" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="76" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="77" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="78" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="79" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="80" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="81" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="82" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="83" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="84" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="85" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="86" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="87" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="88" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="89" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="90" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="91" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="92" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="93" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="94" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="95" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="96" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="97" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="98" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="99" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="100" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="101" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="102" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="103" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="104" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="105" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="106" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="107" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="108" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="109" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="110" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="111" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="112" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="113" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="114" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="124" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="125" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="19" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="20" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="21" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="22" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="23" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="24" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="25" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="26" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="27" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="28" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="29" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="30" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="31" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="32" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="33" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="34" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="35" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="36" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="37" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="38" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="39" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="40" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="41" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="42" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="43" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="44" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="45" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="46" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="47" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="48" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="49" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="50" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="51" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="52" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="53" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="54" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="55" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="56" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="57" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="58" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="59" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="60" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="61" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="62" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="63" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="64" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="65" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="66" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="67" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="68" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="69" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="70" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="71" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="72" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="73" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="74" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="75" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="76" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="77" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="78" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="79" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="80" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="81" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="82" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="83" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="84" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="85" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="86" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="87" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="88" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="89" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="90" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="91" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="92" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="93" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="94" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="95" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="96" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="97" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="98" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="99" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="100" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="101" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="102" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="103" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="104" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="105" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="106" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="107" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="108" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="109" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="110" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="111" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="112" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="113" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="114" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="125" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="126" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="19" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="20" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="21" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="22" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="23" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="24" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="25" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="26" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="27" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="28" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="29" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="30" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="31" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="32" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="33" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="34" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="35" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="36" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="37" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="38" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="39" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="40" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="41" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="42" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="43" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="44" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="45" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="46" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="47" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="48" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="49" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="50" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="51" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="52" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="53" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="54" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="55" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="56" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="57" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="58" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="59" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="60" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="61" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="62" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="63" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="64" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="65" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="66" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="67" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="68" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="69" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="70" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="71" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="72" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="73" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="74" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="75" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="76" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="77" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="78" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="79" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="80" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="81" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="82" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="83" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="84" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="85" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="86" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="87" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="88" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="89" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="90" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="91" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="92" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="93" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="94" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="95" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="96" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="97" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="98" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="99" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="100" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="101" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="102" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="103" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="104" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="105" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="106" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="107" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="108" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="109" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="110" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="111" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="112" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="113" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="114" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="126" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="0" cy="127" r="1" fill="rgba(255,255,255,0)"/>
+ <circle cx="1" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="2" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="3" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="4" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="5" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="6" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="7" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="8" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="9" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="10" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="11" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="12" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="13" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="14" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="15" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="16" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="17" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="18" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="19" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="20" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="21" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="22" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="23" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="24" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="25" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="26" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="27" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="28" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="29" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="30" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="31" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="32" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="33" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="34" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="35" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="36" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="37" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="38" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="39" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="40" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="41" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="42" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="43" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="44" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="45" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="46" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="47" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="48" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="49" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="50" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="51" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="52" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="53" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="54" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="55" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="56" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="57" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="58" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="59" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="60" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="61" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="62" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="63" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="64" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="65" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="66" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="67" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="68" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="69" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="70" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="71" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="72" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="73" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="74" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="75" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="76" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="77" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="78" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="79" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="80" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="81" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="82" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="83" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="84" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="85" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="86" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="87" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="88" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="89" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="90" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="91" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="92" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="93" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="94" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="95" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="96" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="97" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="98" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="99" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="100" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="101" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="102" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="103" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="104" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="105" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="106" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="107" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="108" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="109" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="110" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="111" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="112" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="113" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="114" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="115" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="116" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="117" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="118" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="119" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="120" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="121" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="122" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="123" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="124" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="125" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="126" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+ <circle cx="127" cy="127" r="1" fill="rgba(255,254,254,0)"/>
+</svg>
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/bug.tiff b/Tools/iExploder/iexploder-1.7.2/src/media/bug.tiff
new file mode 100644
index 0000000..65c6448
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/bug.tiff
Binary files differ
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/bug.xbm b/Tools/iExploder/iexploder-1.7.2/src/media/bug.xbm
new file mode 100644
index 0000000..03faaf0
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/bug.xbm
@@ -0,0 +1,174 @@
+#define bug_width 128
+#define bug_height 128
+static char bug_bits[] = {
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xEF, 0xFB, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xF7, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xF9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFB, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFE, 0xFF, 0xF7, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF,
+ 0xFF, 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFD, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFD, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xBF, 0xF9, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFB, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF,
+ 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF6,
+ 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0x7F, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF,
+ 0xEF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFD, 0xFF,
+ 0xFF, 0xFF, 0xFB, 0xFE, 0xFF, 0xFF, 0xBF, 0xFF, 0xFF, 0xDB, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xEF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x7F, 0xFF,
+ 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFE, 0xFF, 0xFF, 0xFF, 0xDF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF,
+ 0xFF, 0xE7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xCF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFB, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x77, 0xF7, 0x7D, 0xF7, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xF7, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, };
diff --git a/Tools/iExploder/iexploder-1.7.2/src/media/bug.xpm b/Tools/iExploder/iexploder-1.7.2/src/media/bug.xpm
new file mode 100644
index 0000000..2105d5c
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/media/bug.xpm
@@ -0,0 +1,390 @@
+/* XPM */
+static char *bug[] = {
+/* columns rows colors chars-per-pixel */
+"128 128 256 2",
+" c #020000",
+". c #0D0200",
+"X c #0D0B04",
+"o c #140200",
+"O c #1C0200",
+"+ c #140A04",
+"@ c #1B0C04",
+"# c #1D0F08",
+"$ c #1E1108",
+"% c #240400",
+"& c #2A0501",
+"* c #270D04",
+"= c #390902",
+"- c #2B1206",
+"; c #23150B",
+": c #2E1609",
+"> c #27160B",
+", c #341206",
+"< c #321609",
+"1 c #3E1708",
+"2 c #351A0B",
+"3 c #3D1E0D",
+"4 c #3A1307",
+"5 c #2C1D11",
+"6 c #241C13",
+"7 c #351E10",
+"8 c #3F200E",
+"9 c #332215",
+"0 c #3F2211",
+"q c #34261A",
+"w c #3A2A1D",
+"e c #37281C",
+"r c #2F2115",
+"t c #3C2E21",
+"y c #3E3125",
+"u c #490B02",
+"i c #570A01",
+"p c #441B0A",
+"a c #4B1D0B",
+"s c #591605",
+"d c #690A02",
+"f c #681704",
+"g c #761805",
+"h c #7A0401",
+"j c #48210E",
+"k c #54230E",
+"l c #432512",
+"z c #462815",
+"x c #4B2B16",
+"c c #452B1A",
+"v c #4C2E19",
+"b c #4D2211",
+"n c #502F18",
+"m c #5A2912",
+"M c #54331C",
+"N c #58381F",
+"B c #57381F",
+"V c #4C311D",
+"C c #79240A",
+"Z c #662E16",
+"A c #6D3015",
+"S c #433529",
+"D c #46382B",
+"F c #5C3B22",
+"G c #533926",
+"H c #4A3D32",
+"J c #603F25",
+"K c #793E21",
+"L c #4D4237",
+"P c #554539",
+"I c #5A402D",
+"U c #614126",
+"Y c #64442A",
+"T c #6A4A2E",
+"R c #674C35",
+"E c #765538",
+"W c #6E5137",
+"Q c #554B43",
+"! c #594E47",
+"~ c #5B524C",
+"^ c #5E5651",
+"/ c #6B5545",
+"( c #715B4A",
+") c #7A6453",
+"_ c #860701",
+"` c #980700",
+"' c #891705",
+"] c #9C1B05",
+"[ c #981404",
+"{ c #A60D01",
+"} c #BD0D02",
+"| c #B20E01",
+" . c #AD1302",
+".. c #A21B03",
+"X. c #A51503",
+"o. c #B11403",
+"O. c #BD1304",
+"+. c #BE1A06",
+"@. c #B31C06",
+"#. c #89240A",
+"$. c #992709",
+"%. c #883415",
+"&. c #953615",
+"*. c #962E10",
+"=. c #BA250A",
+"-. c #AF350D",
+";. c #C40E02",
+":. c #C90E01",
+">. c #C41304",
+",. c #CB1402",
+"<. c #C41A06",
+"1. c #CB1A05",
+"2. c #C31E08",
+"3. c #CB1E08",
+"4. c #D21600",
+"5. c #D41B01",
+"6. c #DA1D00",
+"7. c #D21E08",
+"8. c #C4240A",
+"9. c #CC240A",
+"0. c #C42B0B",
+"q. c #CD2B0D",
+"w. c #CF2006",
+"e. c #D52302",
+"r. c #DC2200",
+"t. c #DB2B03",
+"y. c #D32C0C",
+"u. c #D42608",
+"i. c #CC310E",
+"p. c #C8360B",
+"a. c #D5340A",
+"s. c #CD3411",
+"d. c #CE3B14",
+"f. c #C63B14",
+"g. c #D23412",
+"h. c #D43B15",
+"j. c #D93B14",
+"k. c #D12E10",
+"l. c #E12500",
+"z. c #E42B00",
+"x. c #E92D00",
+"c. c #E53300",
+"v. c #EC3300",
+"b. c #EB3C00",
+"n. c #E63A03",
+"m. c #F23C00",
+"M. c #F03600",
+"N. c #B6491C",
+"B. c #AC4513",
+"V. c #924C2A",
+"C. c #B0542A",
+"Z. c #9D4C26",
+"A. c #D54116",
+"S. c #DB4313",
+"D. c #D54319",
+"F. c #D9451A",
+"G. c #DB4C1D",
+"H. c #D74A1C",
+"J. c #CE4A11",
+"K. c #ED4301",
+"L. c #EC4704",
+"P. c #F54300",
+"I. c #F44C01",
+"U. c #FA4C00",
+"Y. c #F94600",
+"T. c #F45300",
+"R. c #FB5400",
+"E. c #F55C01",
+"W. c #FB5B01",
+"Q. c #F85A0A",
+"!. c #E24B16",
+"~. c #E44A14",
+"^. c #E3541B",
+"/. c #E8581B",
+"(. c #EE560B",
+"). c #FC6403",
+"_. c #FC6B02",
+"`. c #FB6C0B",
+"'. c #F86306",
+"]. c #FD7301",
+"[. c #FD7709",
+"{. c #FC7412",
+"}. c #FC7A15",
+"|. c #FC7D1A",
+" X c #F57718",
+".X c #F66515",
+"XX c #D94A21",
+"oX c #DD5422",
+"OX c #DE5C2B",
+"+X c #DC5825",
+"@X c #CD5927",
+"#X c #E15B25",
+"$X c #E25F29",
+"%X c #E45725",
+"&X c #E14D21",
+"*X c #DB6432",
+"=X c #E3632B",
+"-X c #E6692E",
+";X c #EB6B2B",
+":X c #E86428",
+">X c #E16530",
+",X c #E76C30",
+"<X c #E96E32",
+"1X c #EB6836",
+"2X c #EA7334",
+"3X c #ED7C3A",
+"4X c #EC7737",
+"5X c #F27835",
+"6X c #F67628",
+"7X c #C8621E",
+"8X c #8C6E52",
+"9X c #8F7B6C",
+"0X c #B16945",
+"qX c #DA744B",
+"wX c #FC821C",
+"eX c #FC8518",
+"rX c #FB8422",
+"tX c #FC8925",
+"yX c #FB8B2B",
+"uX c #F58026",
+"iX c #EE813D",
+"pX c #F1833D",
+"aX c #FB8B34",
+"sX c #FC9233",
+"dX c #FB953A",
+"fX c #FE9A3D",
+"gX c #FD912E",
+"hX c #A98F75",
+"jX c #988476",
+"kX c #F28742",
+"lX c #FC9C43",
+"zX c #FD9D4C",
+"xX c #EF8749",
+"cX c #FDA14B",
+"vX c #FEA757",
+"bX c #FFAC63",
+"nX c #FFB16C",
+"mX c #FCB07A",
+"MX c #E49168",
+"NX c #A9998D",
+"BX c #BAA694",
+"VX c #B3ACAC",
+"CX c #FAB488",
+"ZX c #C6B6A7",
+"AX c #D2C6B9",
+"SX c #F8C4AD",
+"DX c #D6CFCC",
+"FX c #ECD7C9",
+"GX c #F7E1D5",
+"HX c #D8DBE9",
+"JX c #FFFEFE",
+"KX c #F4F7F9",
+"LX c #EEEBEC",
+"PX c #D6E3FE",
+"IX c #BEBECB",
+"UX c None",
+/* pixels */
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX3 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX3 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX3 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX3 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX3 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXl z UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXz z z UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX3 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXx v UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX3 8 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXv M M UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXU Y T T W T T U UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX< 3 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXn M N UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXn M F F Y Y T W T Y U F M M UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX3 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXM F F UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXl z v M N F U Y T Y Y U J F M n x l 8 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXl - UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXv F F UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX8 8 8 z x n M N J J U U U F F M M v x l 8 3 3 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXz 3 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXF Y UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX2 2 8 8 3 l b v M N N N F F F N M M v x l 8 3 3 3 3 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXn x x * UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXM Y UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX8XBXj 4 3 l l z v M M M B M B M M n x b 0 8 3 3 0 0 8 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXM M n l UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXv Y v UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXT AXhXn < < 3 z b x v n M n M x v z z l 8 8 0 l z z 8 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXM M M : UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX8 U F UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX. 2 E hXhXV.l , 3 z x v x x x x z l 8 8 0 0 c c w 2 . UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXN G M 2 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXF F UXUXUXUXUXUXUXUXUXUXUXUXUXUXUX3 3 3 < @ + @ : E hXBXjXT l 2 z 8 8 z l z l 0 z c c 0 : o * 9 I R UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXU U F 8 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXF F F F U UXUXUXUXUXUXUXUXUXUXUX3 3 3 8 3 l 2 * @ o v 8XhXhX8XE W T j x c c c 0 5 + . * v Y W ~ Q Q H UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXU U 0 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXM F F F F F UXUXUXUXUXUXUXUXUX3 3 3 3 3 3 3 3 p 3 2 * o . 2 N E 8X8Xx w 2 ; + o * V E ) ( P L L Q Q ~ L UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXY U M UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXM F F F F B UXUXUXUXUXUXUX3 3 3 3 3 3 3 3 3 8 3 p 0 3 < * @ . + + o : G R R P y y D L L L Q ! ~ Q UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXU U < UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX- l M M M M M UXUXUXUX2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 l 8 8 3 2 < < < ; > 5 9 q r 9 w y S S D L L P Q ! ^ ! c UXUXUXUXUXUXUXUXUXUXUXUXUXUXF U M UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXM n v v x p / ! < 3 3 3 3 3 3 3 8 3 3 3 3 3 3 3 3 3 3 8 8 3 : $ > 5 5 q e e t y D D L L P Q Q ! ^ ^ c UXUXUXUXUXUXUXUXUXF J F J F F 3 UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXb c z 3 P PXVX0 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 8 : $ > 5 5 r q e t y y S H L L L Q Q ! ^ ^ c UXUXUXUXUXUXM N F F F F F M UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXl 2 I KXHX^ 2 2 3 3 8 3 3 3 3 3 3 3 3 3 3 3 3 3 3 8 3 : $ $ ; 5 r r q e t y S D H L L Q Q Q ~ ^ P 8 l z x x n M M M M F F M UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX5 + NXKXIX) n 8 2 1 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 : $ $ $ 6 6 r 9 e w t y S D H L L Q Q ~ ^ P 3 3 l z x v n UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXo 6 IXJXHXVX9X( P G V x c z x x 0 3 3 3 3 3 3 3 3 : @ $ ; ; > 5 r q e w t y D H H L L Q ! ~ 3 & p l UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXi L.R.R.a.u 6 DXJXJXKXHXDXVXNXjX9X( P I c 3 3 3 3 3 3 3 3 : + + $ ; > 5 5 9 q e t S y H H H H Q ! e 8XqXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXL.W.W.W.W.T.f e HXJXJXJXJXJXKXLXDXNX) I G l 3 3 3 3 3 3 3 : + + @ $ ; 6 5 r q q e y y D D H L Q c O 0XFX*Xh.UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX3 UXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX(.W.Q.'.'.'.).E.f 9 DXJXJXJXJXJXJXLXZXNX( G V 3 3 3 3 3 3 8 : o + @ @ ; ; > 5 9 q q t y y S H L S % C.GX$Xi.d.s.UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX3 3 UXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXQ.`..X`.`.`.`.'.).T.u q DXJXJXJXJXJXKXFXBX9XR G c 3 3 3 3 3 3 : o . + + # ; > 5 5 q q t y S S D y o Z.GX>Xs.h.d.d.-.UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX3 UXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX.X{.{.{. X{..X`.'.`.L.% v DXJXJXJXJXJXLXAXNX) H G l 3 3 3 3 3 : + X + @ # ; 6 5 5 q q e t S y o -.FXqXy.h.D.d.d.d.$.UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX: 2 UXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUX3 3 3 3 l UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX{.{.|.|.|. X}.{.{.`.`.`.B. U LXJXJXJXJXJXGXZXjXW G c p 3 3 3 3 < o . + + # ; ; 5 5 5 q q t t . &.FXqXq.h.d.A.d.d.d.h.UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXM x l - UXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUX- < z x x v F UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX{.|.rXrXrXrXrXwX|.}.{.{._.].-. Y GXJXJXJXJXKXDXBX9XG G l 3 3 3 3 < . . + + @ ; 6 5 5 q t t %.SXqX9.d.h.d.A.D.D.d.d.d.UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXM v z UXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUX2 v F F J Y T W UXUXUXUXF N UXUXUXUXUXUXUXUXUXwXrXyXyXyXyXtXuXrXwX X X{.[.[.-. 8 BXJXJXJXJXLXZXNX( G c 3 8 3 3 < o X + # # ; 6 5 q $ V.SXOX9.g.h.h.D.XXD.D.D.f.f.h.UXUXUXUXUXUXUXUXUXUXUXUXUXF M x z UXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXz F U Y T W E W T Y F F M n z l 8 8 2 k 6XsXsXsXsXdXdXgXyXuXtXrX|.|.}.[.].J.4 W AXJXJXJXFXZX9XR G l 3 3 8 < . . + + # $ > 6 % 0XSXXX3.k.g.h.D.h.XXD.H.H.D.D.A.UXUXUXUXUXUXUXUXUXUXUXF F M M l - UXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUX2 UXUXUXUXUXY Y J N M v z l 3 3 > C.cXcXcXdXfXdXdXdXgXaXyXtXrXwX|.}.].].'.$.X + 8XFXJXKXAXBX8XU x 3 3 3 < . . . o + $ X f BXCXk.3.k.g.h.D.XXXXXXXX@XXXXXXXF.-.2 l z n M B F J U J F F M - UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXM M M v z UXUX; z MXnXnXvXcXcXcXlXlXsXaXyXyXtXtXrXeXeX].].].J.C 6 8XDXLXDXjX/ G 8 3 3 < . . # o o i C.SXMX6.7.k.g.d.h.D.XXXXXXOX+X+X@XXXH.H.m 2 z z v M M N F N M M UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXxXCXCXnXnXvXvXcXcXlXdXdXgXyXyXuXtXeXeXeXeX]._.'.J.f > 8XBXBXjXP l 3 p - + @ + O i C.CXCX&X1.k.k.k.d.j.XXXXXXXX+XXXOXOXOXOX+XoX-.3 9 b x M M M M M M UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXbXmXCXnXnXbXbXvXvXzXlXdXsXyXyXtXtXeXeX].].].].'.).E.p.f o X B E W x 3 3 # o @ # + = C 0XmXqXF.:.7.7.k.k.g.g.D.j.XX&X&XOXOXOXOXOXOX+X+X%XUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXzXbXnXnXnXbXbXvXvXcXlXdXsXyXyXtXtXeXeXeXeX].]._._.W.R.Y.a.' & @ ; - # o . o u *.qXqX1Xj.7.7.y.y.k.k.g.g.g.D.d.*.#.N.&XOXOX*XOX>XOXOX+X$XUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX.XaXcXvXbXvXvXbXvXcXzXlXdXsXyXtXuXwX[.eX].].].]._._.'.E.T.U.P.c.] % i -.+X;XF.l.7.l.u.u.u.u.k.k.k.g.j.f.= O *.&XOXOX>X>X*X>XOX=XUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXg {.|.gXfXlXcXcXvXvXcXlXfXdXyXyXrXtXeXeX[.].].].]._._.'.E.T.L.L.L.m.t.i _ r.z.t.6.e.e.t.u.y.u.a.u.k.k.k.y.j.i -.+XOXOX>X>X>X$X=X&.UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXB.{.|.gXgXfXlXcXcXcXlXfXdXaXyXuX7XB.J.`.[._._._._._._.'.E.T.T.L.K.c.v.e.i d l.6.e.r.r.r.t.t.t.t.a.a.y.u.k.y.j.@. - XX%XOX*X>X>X>X-XJ.UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXQ.{.|.eXgXfXfXfXfXfXfXdXsXyXuXV.m b 3 a B._.).).).'._.'.E.E.T.L.b.b.c.l.| X.l.6.r.r.t.t.t.a.a.t.a.t.y.u.k.u.y.g #.%XoXOX=X>X>XOX=Xs UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXQ.`.}.eXgXgXgXfXfXfXgXgXyXtXC.Z Z k p @ J.W.).'.'.E.'.E.T.T.K.K.c.v.l.| [ l.r.e.r.t.t.t.t.t.t.u.y.u.k.k.7.k.d = XXoXOXOX=X=X=X>XB.UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXR.Q.`.}.wXtXyXyXgXgXgXgXyXtX|.V.Z m a 4 * s W.R.W.E.W.E.E.T.L.I.b.n.c.l.| X.r.6.r.r.t.t.t.t.u.t.u.u.u.7.9.9.u.g . o D.oXoXOX=XOX=X=X$XUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXU.W.`.{.}.eXrXtXeXgXyXeXrXrX XA m b 1 * . & I.R.T.T.E.T.T.T.I.K.b.c.x.l.| { l.6.r.r.t.t.t.a.t.u.u.7.7.7.3.3.7.[ . -.&XoX+X$X=X=X=X=XUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXU.Q.`.`.}.}.eXwXrXwXeXwX|.}. XA a p , O O I.R.U.U.T.T.T.T.I.K.b.c.x.l.o.X.r.e.r.r.t.c.t.t.t.u.w.3.7.3.3.3.3.+.% . * h.XXoX+X$X$X=X=X;XUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXR.Q.).`.[.}.}.}.}. XeX X}.{.[.C , , @ & I.Y.Y.I.I.I.I.L.L.K.b.n.c.r.| ] r.e.r.t.t.t.t.t.e.e.5.5.1.>.1.<.3.9.' *.XXXXoXoXOXOX=X-X<XB.UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX-.R.W.).`.`.[.[.{.{.{.{.{.`.`._.B.@ @ . f Y.Y.P.P.P.P.I.L.L.b.b.c.z.l.o.X.r.e.e.r.t.t.t.t.e.7.1.1.1.>.1.1.3.3.9.d & #.F.F.G.oX+X$X=X=X=X<X@XUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX9 p.R.W.W.).).`.`.`.`._.[.`._.`.).W.f % a.Y.P.P.P.K.K.P.L.L.K.b.c.z.6.o.X.6.6.e.t.t.t.t.e.e.6.1.1.,.1.>.1.3.3.9.9...' ] s.j.F.F.G.G.oX#X=X-X-X;X@XUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXl j J.R.R.W.W.).).).).).`.`.).).).W.W.R.-.f u g a.U.Y.P.m.m.m.P.K.K.K.b.n.x.z.r.o...6.e.e.t.t.t.t.e.7.5.1.,.1.1.1.1.3.9.9.k.k.g.j.j.h.j.F.G.oX#X+X=X-X<X<X-Xk UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXn l k K.T.R.R.R.W.W.W.W.W.).W.W.W.W.R.W.R.R.U.U.U.Y.P.P.m.m.m.m.b.K.K.K.b.n.c.z.6.o...6.6.e.e.t.t.t.e.3.3.5.,.,.>.>.1.3.3.9.9.k.y.g.h.j.F.F.G.oXoX$X=X-X<X<X;XA UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXM n 9 UXY.U.R.W.W.W.W.W.R.W.W.W.R.R.R.R.R.R.U.Y.Y.Y.Y.m.m.M.M.M.b.K.b.b.K.n.c.c.t.6.o.X.6.e.e.e.t.r.u.e.5.5.1.,.,.>.1.1.3.3.9.9.q.q.g.g.j.A.F.G.oX#X+X=X-X,X<X2XA : UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXF M M w UXUXI.T.T.W.W.W.W.W.R.R.R.R.R.R.R.U.U.U.Y.Y.Y.Y.m.m.M.M.M.b.b.b.K.K.K.b.c.z.z.6.o...5.5.e.r.t.t.e.e.5.,.,.,.1.>.1.1.3.9.9.k.y.g.g.h.j.F.F.G.oX#X=X=X,X<X2XuX&.5 l UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXU F F V UXUXUXP.T.W.W.W.W.W.R.R.R.T.U.U.U.R.U.U.I.Y.P.Y.m.m.M.M.M.M.M.v.b.b.b.b.n.c.t.t.6. ...5.5.e.e.t.e.e.5.1.,.,.>.,.>.1.1.3.9.9.9.y.g.g.h.h.F.F.G.^.#X$X=X,X<X2X5XZ.2 l x UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXT T Y Y F F N UXUXUXUXT.6X.XW.W.R.R.R.T.U.U.U.U.Y.Y.Y.Y.P.P.m.m.m.M.M.M.v.v.x.v.b.b.b.n.c.c.z.r.6.o...5.1.e.e.e.u.e.7.,.1.,.,.>.,.1.3.3.9.9.q.q.k.g.h.A.F.F.oXoX+X=X-X;X2X2X5XN.: z x n UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXY Y Y U U J F UXUXUXUX$.Q.zX|.Q.Q.R.T.U.U.U.U.P.Y.Y.Y.Y.m.m.m.M.M.M.v.M.x.x.v.c.v.v.n.n.n.c.c.z.r.4. ...4.1.e.e.t.e.5.5.1.,.1.:.,.>.1.3.3.9.9.9.k.k.g.j.A.F.G.G.oX#X=X-X,X2X2X5XN.UXl v n B UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXv M M F F U U Y U Y Y J v UXUXUXUXUX] .XxX6X.XQ.T.U.I.I.P.P.P.P.P.P.m.m.m.m.M.M.v.v.v.v.x.x.x.v.c.n.n.c.z.t.r.r.6. ...4.1.e.e.e.e.e.5.,.,.>.>.>.1.3.3.3.9.9.k.k.g.g.h.F.F.G.oX%X#X=X-X,X2X2X5XN.UXUXv M N F UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXz x n M N F N F U J F v UXUXUXUXUXUXUX...XkX6X.XQ.U.U.P.P.P.P.m.m.m.m.M.M.m.M.v.v.v.x.x.x.x.x.z.x.x.c.z.z.t.z.r.6.5. ...5.5.e.e.e.5.5.1.,.,.>.,.>.>.,.3.7.9.9.k.k.g.g.h.j.F.G.G.%X$X=X-X2X2X4XpX@XO UXUXM N F J UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUX8 8 8 0 z x l 2 UXUXUXUX2 < UXUXUXUXUXUXUXUXUXn./.zX6X.XQ.I.P.P.P.m.m.m.m.M.M.M.M.v.M.v.v.v.x.x.x.z.z.x.z.z.z.z.z.t.r.6.6.4. .] 4.1.1.e.e.e.1.1.,.,.>.;.1.1.3.3.9.9.u.k.k.g.h.j.F.G.G.oX#X$X=X-X2X2X4X5X7XO UXUXUXN J J Y UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UX3 3 < * * * * * UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX/.5X6XU.U.I.m.m.b.m.v.M.v.M.M.v.x.x.v.x.x.x.x.x.l.x.l.z.z.t.z.r.l.6.6.6.6.4.o.] 4.1.5.1.e.7.1.7.:.:.,.>.1.3.3.3.3.9.9.q.q.g.h.h.F.XXoXoX+X=X=X<X2X4X4X3XN.o UXUXUX2 F U Y T T UXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXL.5X:X(.m.P.m.m.v.v.v.v.x.x.x.x.x.x.x.x.x.x.x.x.l.l.l.l.l.l.r.r.r.6.6.6.5.4. ...,.1.1.e.e.7.1.1.:.>.>.:.1.,.3.3.9.9.q.g.g.g.h.A.F.G.G.%X#X=X>X<X4X3X4XpXN.O o UXUXUX8 U U Y T T UXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX~.;X.XL.b.b.v.v.v.x.x.x.x.x.x.x.x.x.l.x.x.x.l.l.l.l.l.l.l.l.r.r.6.6.6.6.4.4. .] 4.,.1.5.5.7.4.1.:.1.>.>.3.3.3.9.9.y.y.k.g.g.j.A.F.G.oXoX#X=X,X1X4X3X3XkXB.o O UXUXUXUXl J Y Y Y Y U UXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXv.$X/.L.n.v.v.v.z.l.x.x.x.l.x.x.x.x.x.l.x.l.l.x.l.l.r.l.6.6.6.6.6.4.6.4.4.,. .] :.1.1.5.w.7.,.1.>.:.>.:.3.3.7.9.9.9.q.k.g.h.j.F.F.G.%X#X$X-X,X2X3X3X3XaX&. O UXUXUXUXUXUXM J J J U F F M UXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXt.!.(.L.z.c.z.z.l.z.z.z.z.l.x.l.l.l.x.l.l.x.l.l.l.r.l.6.6.6.6.6.6.4.4.4.4.:. .[ ,.:.1.7.1.7.,.,.:.1.>.>.3.3.3.9.u.k.k.g.g.h.A.F.F.G.oX#X$X=X<X4X4X3X5XpX%.o o UXUXUXUXUXUXUX3 M F N F F M M v UXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXt.n.~.n.c.l.l.l.l.l.l.z.l.x.l.x.l.l.l.l.l.l.l.l.l.6.6.6.6.6.4.6.4.6.4.4.4.:.X.] ,.:.1.,.7.7.,.,.1.1.1.1.3.3.7.9.9.k.k.g.g.j.A.F.G.oX%X$X=X,X<X4X4XiX5X5XC o o UXUXUXUXUXUXUXUXUXUXUXUXUXv M x z UXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXr.t.c.t.z.t.r.r.r.r.l.l.l.l.l.l.l.l.l.l.l.r.l.6.6.6.6.6.6.6.6.4.6.4.4.4.4.:.o.[ >.>.,.7.7.,.,.1.>.3.>.>.7.7.9.9.y.k.k.g.h.j.F.G.G.oX%X$X=X,X2X4X3X3XpX2Xs o UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXz l l 3 UXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXe.r.c.n.t.r.6.r.l.r.l.r.l.r.l.r.l.l.r.6.r.6.6.6.r.6.6.6.6.4.6.4.4.4.4.:.:.:. .[ ;.;.1.>.7.7.3.1.1.1.3.7.7.u.9.9.q.k.g.g.j.A.F.G.G.%X+X$X-X2X2X3X3XpXpX=X= O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX@ * - 2 3 8 3 ",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX6.t.a.t.t.r.6.r.r.r.l.6.l.r.r.l.l.l.6.6.6.6.6.6.6.6.6.4.6.4.4.4.4.:.4.,.,.:.{ [ ;.>.>.>.3.7.1.3.3.7.7.o.' ' @.k.k.g.g.h.j.A.F.G.oX+X#X=X,X2X4X3X3XkX4X@X% O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX* 3 ",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXr.t.t.t.e.e.6.6.r.r.6.6.6.6.6.6.6.6.6.6.6.6.4.6.6.4.4.4.4.4.4.4.4.4.,.:.:.{ [ } ;.>.>.7.1.3.3.7.| i . u 9.k.g.g.j.j.F.G.G.oX#X$X-X,X2X4X3XkXiX5XB.O O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXe.t.t.t.r.6.6.6.6.r.6.6.6.6.6.6.6.6.6.6.6.6.6.6.6.4.4.4.4.4.4.:.:.:.:.:.:.{ _ ;.} ;.>.1.1.3.7.[ O . O + ..g.g.j.h.A.G.G.oX%X$X=X>X1X4X3XxX3XiX2X#.o O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX6.e.t.t.e.5.6.5.6.6.6.6.6.6.6.6.6.6.6.6.4.4.4.4.4.4.4.4.4.4.:.4.:.4.:.:.;.{ _ } ;.;.>.1.1.7.X.. . o ; , < C g.g.h.j.F.G.G.oX+X=X=X,X2X4X3X3XxX3X;Xs O O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX1.6.t.t.e.5.5.5.5.5.6.6.5.5.6.1. .] +.5.4.4.4.4.4.4.:.4.4.4.:.:.:.:.:.;.;.{ _ ;.} ;.>.1.3.>.= . + * 4 p p C s.h.j.XXD.G.oX+X#X=X-X<X4XiXiXpXpX2X@X& % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXe.e.e.e.5.5.5.4.5.5.4.4.6.@.s 1 < = g 1.,.4.4.4.,.4.4.:.:.4.:.:.:.:.;.;.` _ } } } >.<.7.@.. O * 4 p b m A s.h.j.F.XXG.oX#X$X=X-X2X3X3XpXpXiX5X-.% % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX1.e.e.e.5.,.5.4.5.4.4.4.@.b p p 1 , @ u } 4.4.,.4.4.:.,.:.:.:.:.:.;.;.;.` _ } } ;.>.1.3.o.. o * 4 j k m Z K h.j.F.F.G.G.%X$X=X-X<X2X3XiXkXpX3X;Xf O % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX>.e.e.e.1.5.,.4.,.5.4.4.' j a p 1 , , # i :.:.:.:.:.:.:.:.:.:.;.;.;.;.;.` _ ;.} >.>.<.7.<.& @ 4 p k m A A &.j.F.F.G.XXoX#X$X-X,X<X4X3XkXkXiX6X+X= & O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX7.e.e.1.,.,.,.5.,.4.,.m k a p 1 , , & . _ 4.:.:.:.:.:.:.:.:.;.;.;.;.;.` _ } } >.<.1.3.7.g # p a m A A K N.j.F.F.G.oX+X$X=X-X<X2XiXiXkXiXiX2X&.& & UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX>.1.1.,.,.,.,.,.,.,.,.k k j p 1 , , - O 4 ;.:.:.:.:.:.:.:.;.;.;.;.;.;.` _ } O.O.<.<.3.7.@.4 p m A K K V.d.j.F.G.oXoX+X=X=X;X2X4XiXiXkXiX4X:Xf % % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXX.1.1.,.,.,.,.,.,.,.,.g b a p 1 4 , - # # ;.:.:.;.;.:.;.;.;.;.;.;.;.;.` _ O.} <.1.3.3.9.7.$.b m J K V.-.F.F.G.G.oX%X=X=X*X,X4X3XiXkXpXpX5X7X& & O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX>.>.>.>.,.>.:.,.,.,.] j a p p , , * + i :.:.:.;.;.;.;.;.;.:.:.;.>.;.` _ O.>.<.3.3.9.9.k.u.-.&.&.-.D.F.F.G.G.oXoX#X=X>X<X4X4XiXkXkXpX5X2XC O & UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXX.;.>.>.;.;.:.>.>.,.:.g l p 1 , - # , { :.;.;.;.;.;.>.>.>.>.>.>.>.;.` h O.O.<.3.3.q.9.k.k.g.g.j.j.h.A.F.XXoXoX#X$X-X,X2X4XiXiXiXkXpX5X@X= & % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX} ;.} ;.;.>.>.;.;.:.>.g p 1 < u d | :.;.;.;.;.;.;.>.:.:.>.>.>.>.O.` _ O.<.<.8.q.9.k.k.k.g.g.g.j.D.XXG.oXoX+X$X=X-X<X4X4XiXpXpXiX5X5X%.% & UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX[ } } O.;.>.;.;.;.;.>.;.o.{ { | :.:.;.>.;.>.;.;.>.1.>.>.,.3.<.<.>._ _ +.+.2.3.q.q.k.k.g.h.h.j.F.F.G.XX%X%X$X=X>X<X2X4X3XiXpXiX5X5X@X= % % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX| } } O.;.>.} >.;.;.;.;.:.:.>.;.;.>.;.>.>.:.3.>.>.1.>.1.1.1.<.O.` h +.O.8.9.q.y.k.k.j.j.j.A.F.G.G.oX%X#X=X-X,X2X3X3X3XpXpX3X2X2XC % & UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXh >.} } O.;.;.;.;.>.>.>.;.>.>.>.;.>.;.>.>.>.;.1.>.>.3.1.<.3.<.} _ ' O.+.8.q.q.g.g.h.j.h.D.F.G.G.oX^.$X$X=X,X<X4X3X3XiXpX3X2X6XN.& % % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX{ O.} O.O.>.>.>.>.>.>.>.>.>.>.;.>.3.1.1.>.1.1.1.>.3.3.3.2.<.;._ _ O.+.8.q.g.g.h.j.h.F.F.F.G.oXoX#X$X=X-X2X2X3X3XpXpXpX2X;X=Xs % % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXu } O.O.O.<.>.>.>.>.<.>.<.>.>.3.>.;.3.>.3.<.3.7.3.3.3.3.3.1.O._ _ +.=.8.k.g.g.h.A.F.F.G.G.oX%X#X$X=X-X<X2X4X3X3XxX3X2X;X;X%.% & % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXh >.O.O.O.O.<.<.<.>.>.1.<.>.3.3.3.3.3.<.3.3.3.3.9.9.3.q.2.>._ ' +.8.q.s.g.h.A.F.F.XXG.oX%X+X$X=X-X,X2X4X3X3X3X4X4X;X;XJ.& & % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXO [ >.O.+.<.<.<.<.<.<.3.1.<.3.3.3.3.3.3.3.9.3.9.9.q.9.q.8.:._ ' 8.8.q.s.j.A.S.H.H.H.^.+X+X#X=X-X,X2X2X4X4XiX5X2X;X:X@Xs % % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX= @.<.O.O.<.<.<.<.2.<.3.3.3.3.3.3.8.8.9.9.9.9.9.q.k.q.8.>._ ' 2.8.i.h.A.S.H.H.H.oX+X#X=X=X-X,X2X2X2XiXiX5X2X:X#X^.f O % O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXu O.<.+.+.<.<.2.3.3.3.3.3.8.3.9.9.8.9.9.q.q.q.y.q.q.q.O._ ' 9.0.i.d.A.G.G.^.oX+X#X#X=X-X,X<X2X4X2X4X2X;X:X#X/.#.O % % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX i <.<.<.+.2.2.2.8.3.3.8.9.q.9.9.9.k.q.q.k.q.k.s.g.q.>._ ' 8.8.i.h.F.H.oXoX+X#X$X=X-X,X,X<X2X2X2X<X;X/.^.^.$.% & % UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX d +.8.=.2.2.2.8.9.8.8.9.9.k.0.q.k.q.k.k.s.g.g.s.q.<._ ' 2.0.i.h.H.oXoX+X#X:X=X-X-X,X2X;X2X;X:X:X/.!.!.-.% % % O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX. f +.2.8.2.8.8.8.9.k.0.0.k.k.k.k.s.g.g.g.g.d.s.i.<._ ' 2.8.i.d.G.oX+X+X=X=X=X-X-X-X;X-X:X:X/.!.S.S.*.& % % o UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX. . i =.8.8.8.8.8.8.q.8.k.0.k.i.s.s.g.g.d.h.d.s.i.O._ ' w.0.i.A.H.oX$X=X=X=X=X=X=X=X:X/.#X/.S.~.~.#.% % % O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX. . i @.8.8.8.0.0.0.k.0.i.i.s.s.d.h.h.h.h.h.d.i.O._ ' 9.0.p.A.^.+X+X#X$X:X#X#X#X^././.^.!.~.A.g & & % O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX. . = ] q.8.0.8.8.0.0.s.k.s.f.s.d.d.h.h.d.d.i.+.h ' y.0.d.A.oX^.+XoX/.#X^.^.^.^.^.!.!.!.J.s O & % O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX. o O g =.8.0.=.0.0.8.0.0.s.s.s.d.d.h.d.d.0.O.h ' q.0.a.A.F.H.J.H.S.!.G.!.!.(.J./.S.$.u % % % o UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXo . u ] 8.8.=.=.8.0.0.0.0.f.s.s.d.d.p.0.@.h ' y.i.s.d.S.S.S.S.S.S.!.!.!.!.~.f.f % % % % O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXo o % d ..8.8.=.=.0.0.0.0.0.0.0.p.0.0.o.d ' u.q.p.a.A.S.S.S.S.S.!.!.!.J.C = O & % O o UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXo o + & f ] 8.8.0.=.8.0.0.0.0.0.0.0.| d ' t.p.a.d.S.j.S.S.S.~.G.f.#.u % & & % O UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXo O o % s ' @.0.k.8.8.0.k.0.0.0.o.d ' 9.i.a.S.S.G.!.~.A.-.g = % % & % O o UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXO O O % = f ' $.0.q.s.s.s.s.+._ -.a.A.S.S.J.J.*.g u & % & & % O o UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXo O O O O O & = s f ' #.$.] ' $.#.#.#.f u = % % & & & % O o UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXo O O O % % O % O O % & * & O O O O % & & % % % O o UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXo O o O O O O % O % % % % % % O % O O O o UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXo o o o o o o o o UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX",
+"UXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUXUX"
+};
diff --git a/Tools/iExploder/iexploder-1.7.2/src/mime-types/dillo b/Tools/iExploder/iexploder-1.7.2/src/mime-types/dillo
new file mode 100644
index 0000000..0a789c8
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/mime-types/dillo
@@ -0,0 +1,14 @@
+application/octet-stream
+application/xhtml+xml
+application/x-www-form-urlencoded
+html/text
+image/gif
+image/jpeg
+image/jpg
+image/pjpeg
+image/png
+image/x-png
+multipart/form-data
+text/css
+text/html
+text/plain
diff --git a/Tools/iExploder/iexploder-1.7.2/src/mime-types/mozilla b/Tools/iExploder/iexploder-1.7.2/src/mime-types/mozilla
new file mode 100644
index 0000000..d3075d7
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/mime-types/mozilla
@@ -0,0 +1,122 @@
+aapplication/opensearchdescription+xml
+application/applefile
+application/atom+xml
+application/compress
+application/directory
+application/ecmascript
+application/gzip
+application/http-index-format
+application/java-archive
+application/javascript
+application/lolcat
+application/marimba
+application/mathml+xml
+application/octet-stream
+application/ogg
+application/oleobject
+application/opensearchdescription+xml
+application/pdf
+application/pgp
+application/postscript
+application/pre-encrypted
+application/rdf+xml
+application/rss+xml
+application/uue
+application/uuencode
+application/x-
+application/x-arj
+application/x-compress
+application/x-fortezza-ckl
+application/x-fortezza-krl
+application/x-gunzip
+application/x-gzip
+application/x-java-vm
+application/x-javascript
+application/x-javascript-config
+application/x-macbinary
+application/x-marimba
+application/x-moz-file
+application/x-moz-node
+application/x-moz-tabbrowser-tab
+application/x-netscape-revocation
+application/x-ns-proxy-autoconfig
+application/x-oleobject
+application/x-pgp-message
+application/x-test
+application/x-testextension
+application/x-unknown
+application/x-unknown-content-type
+application/x-uue
+application/x-uuencode
+application/x-view-source
+application/x-www-form-urlencoded
+application/x-xpinstall
+application/xhtml+xml
+application/xml
+application/zip
+audio/basic
+audio/ogg
+audio/wav
+audio/wave
+audio/webm
+audio/x-pn-wav
+audio/x-wav
+image/bmp
+image/gif
+image/jpeg
+image/pjpeg
+image/png
+image/svg+xml
+image/tiff
+image/x-icon
+image/x-jg
+image/x-jng
+image/x-portable-pixmap
+image/x-xbitmap
+image/x-xbm
+image/xbm
+message/external-body
+message/news
+more/less
+multipart/alternative
+multipart/appledouble
+multipart/byteranges
+multipart/digest
+multipart/foo
+multipart/form-data
+multipart/header-set
+multipart/mixed
+multipart/parallel
+multipart/related
+multipart/signed
+multipart/x-mixed-replace
+text/cache-manifest
+text/calendar
+text/css
+text/ecmascript
+text/enriched
+text/html
+text/javascript
+text/jsss
+text/mdl
+text/plain
+text/rdf
+text/richtext
+text/unicode
+text/uri-list
+text/url-list
+text/x-email
+text/x-moz-place
+text/x-moz-place-container
+text/x-moz-search-engine
+text/x-moz-text-internal
+text/x-moz-url
+text/x-vcard
+text/xml
+text/xsl
+video/mpeg
+video/ogg
+video/webm
+video/x-mng
+video/x-raw
+video/x-raw-yuv
diff --git a/Tools/iExploder/iexploder-1.7.2/src/mime-types/webkit b/Tools/iExploder/iexploder-1.7.2/src/mime-types/webkit
new file mode 100644
index 0000000..3dd58b2
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/mime-types/webkit
@@ -0,0 +1,157 @@
+application/andrew-inset
+application/annodex
+application/asx
+application/atom+xml
+application/ecmascript
+application/java-archive
+application/javascript
+application/json
+application/mac-compactpro
+application/mpegurl
+application/octet-stream
+application/oda
+application/ogg
+application/pdf
+application/postscript
+application/rss+xml
+application/tar
+application/x-bcpio
+application/x-bittorrent
+application/x-cdlink
+application/x-chess-pgn
+application/x-compress
+application/x-cpio
+application/x-csh
+application/x-director
+application/x-diskcopy
+application/x-dvi
+application/x-filemaker
+application/x-font-ttf
+application/x-ftp-directory
+application/x-futuresplash
+application/x-googlegears
+application/x-gzip
+application/x-hdf
+application/x-icy
+application/x-java-applet
+application/x-java-bean
+application/x-java-vm
+application/x-javascript
+application/x-koan
+application/x-latex
+application/x-media-element-proxy-plugin
+application/x-meowmeow
+application/x-moz-file
+application/x-mpeg
+application/x-mpegurl
+application/x-ms-wmd
+application/x-netcdf
+application/x-oleobject
+application/x-qt-plugin
+application/x-qt-styled-widget
+application/x-sh
+application/x-shar
+application/x-shockwave-flash
+application/x-silverlight
+application/x-tar
+application/x-tcl
+application/x-tex
+application/x-texinfo
+application/x-troff
+application/x-troff-man
+application/x-troff-me
+application/x-troff-ms
+application/x-truetype-font
+application/x-unknown-content-type
+application/x-ustar
+application/x-wais-source
+application/x-webarchive
+application/x-www-form-urlencoded
+application/xhtml+xml
+application/xml
+audio/aac
+audio/annodex
+audio/mpeg
+audio/mpegurl
+audio/ogg
+audio/scpls
+audio/speex
+audio/wav
+audio/webm
+audio/x-aac
+audio/x-caf
+audio/x-gsm
+audio/x-mpeg
+audio/x-mpegurl
+audio/x-pn-realaudio-plugin
+audio/x-vorbis
+audio/x-wav
+font/opentype
+font/otf
+font/ttf
+for/event
+image/bmp
+image/gif
+image/ico
+image/ief
+image/jpeg
+image/pjpeg
+image/png
+image/svg+xml
+image/tif
+image/tiff
+image/x-cmu-raster
+image/x-icon
+image/x-macpaint
+image/x-pcx
+image/x-portable-anymap
+image/x-portable-bitmap
+image/x-portable-graymap
+image/x-portable-pixmap
+image/x-rgb
+image/x-targa
+image/x-tiff
+image/x-xbitmap
+image/x-xpixmap
+image/x-xpm
+image/x-xwindowdump
+inline/none
+mode/options
+model/iges
+model/mesh
+model/vrml
+multipart/form-data
+multipart/x-mixed-replace
+test/npn-invoke
+text/cache-manifest
+text/calendar
+text/css
+text/ecmascript
+text/event-stream
+text/html
+text/javascript
+text/jscript
+text/livescript
+text/pdf
+text/plain
+text/ptf
+text/richtext
+text/sgml
+text/tab-separated-values
+text/uri-list
+text/url-list
+text/x-game-map
+text/x-setext
+text/xml
+text/xsl
+video/annodex
+video/divx
+video/mpeg
+video/ogg
+video/quicktime
+video/webm
+video/x-mng
+video/x-sgi-movie
+video/x-theora
+webkit/base
+x-conference/x-cooltalk
diff --git a/Tools/iExploder/iexploder-1.7.2/src/protocols/dillo b/Tools/iExploder/iexploder-1.7.2/src/protocols/dillo
new file mode 100644
index 0000000..4de61de
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/protocols/dillo
@@ -0,0 +1,4 @@
+dpi:
+ftp:
+http:
+https:
diff --git a/Tools/iExploder/iexploder-1.7.2/src/protocols/gtkhtml b/Tools/iExploder/iexploder-1.7.2/src/protocols/gtkhtml
new file mode 100644
index 0000000..61cec0b
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/protocols/gtkhtml
@@ -0,0 +1,3 @@
+ftp:
+http:
+https:
diff --git a/Tools/iExploder/iexploder-1.7.2/src/protocols/mozilla b/Tools/iExploder/iexploder-1.7.2/src/protocols/mozilla
new file mode 100644
index 0000000..cec583b
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/protocols/mozilla
@@ -0,0 +1,30 @@
+about:
+about:about
+about:addons
+about:buildconfig
+about:config
+about:crashes
+about:credits
+about:licence
+about:license
+about:logo
+about:memory
+about:mozilla
+about:neterror
+about:plugins
+about:support
+chrome:
+data:
+file:
+ftp:
+http:
+https:
+imap:
+jar:
+javascript:
+mailbox:
+mailto:
+news:
+place:
+resource:
+wyciwyg:
diff --git a/Tools/iExploder/iexploder-1.7.2/src/protocols/webkit b/Tools/iExploder/iexploder-1.7.2/src/protocols/webkit
new file mode 100644
index 0000000..b632d0c
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/protocols/webkit
@@ -0,0 +1,16 @@
+GET:
+about:
+blob:
+data:
+feed:
+feeds:
+file:
+ftp:
+http:
+https:
+javascript:
+mailto:
+rtsp:
+src:
+ws:
+wss:
diff --git a/Tools/iExploder/iexploder-1.7.2/src/scanner.rb b/Tools/iExploder/iexploder-1.7.2/src/scanner.rb
new file mode 100644
index 0000000..9a8261c
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/scanner.rb
@@ -0,0 +1,154 @@
+#
+# iExploder Combination Scanner Library (used for subtesting)
+#
+# Copyright 2010 Thomas Stromberg - All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+# This is a simple sequential combination creator with a constantly growing width
+def seq_combo_creator(total_lines, width, offset)
+ # Offsets start at 0 to total_lines-1
+ use_lines = []
+ offset.upto(offset+width-1) do |line_number|
+ use_lines << line_number
+ end
+
+ if use_lines[-1] == total_lines-1
+ width += 1
+ next_offset = 0
+ else
+ next_offset = offset + 1
+ end
+ return [width, next_offset, use_lines]
+end
+
+# This tries all combinations, giving a small test-case, but requires lots of
+# subtests.
+def combine_combo_creator(total_lines, width, offsets)
+ # puts "Asked: Total Lines: #{total_lines} Line Count: #{width} Offsets: #{offsets.join(',')}"
+ if not offsets or offsets.length == 0
+ # puts " Setting offsets to 0"
+ offsets = [0,]
+ end
+ if width < 1
+ width = 1
+ end
+
+ index = 0
+ lines = []
+ new_offsets = []
+ reset_next_offset = false
+
+ # Reverse the order from fastest to slowest
+ offsets.each_with_index do |offset, index|
+ 0.upto(width-1) do |line_offset|
+ lines << (offset + line_offset)
+ end
+ if lines[-1] >= total_lines - 1
+ # If we are the slowest, that means we are done with this iteration.
+ if index == offsets.length - 1
+ new_offset_count = offsets.length + 1
+ # Loosely follow the Fibonacci sequence when calculating width
+ width = (new_offset_count * 1.61803398).round
+ new_offsets = []
+ # 0 to offsets.length creates one additional offset
+ 0.upto(offsets.length) do |new_offset_num|
+ new_offsets << (new_offset_num * width)
+ end
+
+ # We need the lowest offset first. Oops.
+ new_offsets.reverse!
+ else
+ # Move to the next available slot.. next offset will take the one before.
+ new_offsets << offsets[index+1] + (width * 2)
+ reset_next_offset = true
+ end
+ elsif reset_next_offset
+ new_offsets << (offset + width)
+ reset_next_offset = false
+ # The first one always rotates
+ elsif index == 0
+ new_offsets << (offset + width)
+ reset_next_offset = false
+ # The others stay still normally.
+ else
+ new_offsets << offset
+ reset_next_offset = false
+ end
+ end
+
+ return [width, new_offsets, lines]
+end
+
+def avg(list)
+ sum = list.inject(0.0) { |sum, el| sum += el }
+ return sum / list.length
+end
+
+
+# for testing #################################################################
+if $0 == __FILE__
+ line_count = ARGV[0].to_i || 100
+ try_count = ARGV[1].to_i || 10
+
+ seq_iterations = []
+ combine_iterations = []
+ seq_size = []
+ combine_size = []
+
+ 1.upto(try_count) do |run|
+ puts "*" * 78
+ puts "# RUN #{run} (line-count: #{line_count})"
+ find_lines = []
+ 0.upto(rand(4)) do |count|
+ choice = rand(line_count).to_i
+ if ! find_lines.include?(choice)
+ find_lines << choice
+ end
+ end
+
+ lines = []
+ width = 1
+ offset = 0
+ attempts = 0
+ puts "Find lines: #{find_lines.join(',')}"
+ while not find_lines.all? { |x| lines.include?(x) }
+ (width, offset, lines) = seq_combo_creator(line_count, width, offset)
+ attempts += 1
+ end
+ puts "Sequential found #{find_lines.join(',')} in #{attempts} attempts with #{lines.length} total lines."
+ seq_iterations << attempts
+ seq_size << lines.length
+
+ lines = []
+ width = 1
+ offsets = []
+ attempts = 0
+ while not find_lines.all? { |x| lines.include?(x) }
+ # puts "Looking for #{find_lines.join(',')}"
+ (width, offsets, lines) = combine_combo_creator(line_count, width, offsets)
+ attempts += 1
+ end
+ puts "Combine found #{find_lines.join(',')} in #{attempts} attempts with #{lines.length} total lines."
+ combine_iterations << attempts
+ combine_size << lines.length
+ end
+ puts "-" * 78
+ puts "Seq avg iterations=#{avg(seq_iterations).to_i} length=#{avg(seq_size).to_i}"
+ puts "combine avg iterations=#{avg(combine_iterations).to_i} length=#{avg(combine_size).to_i}"
+ diff_iter = (avg(combine_iterations) / avg(seq_iterations)) * 100
+ diff_lines = (avg(combine_size) / avg(seq_size)) * 100
+ puts "Diff iterations: #{diff_iter}%"
+ puts "Diff lines: #{diff_lines}%"
+end
diff --git a/Tools/iExploder/iexploder-1.7.2/src/version.rb b/Tools/iExploder/iexploder-1.7.2/src/version.rb
new file mode 100644
index 0000000..2837237
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/version.rb
@@ -0,0 +1 @@
+$VERSION="1.7.2"
diff --git a/Tools/iExploder/iexploder-1.7.2/src/webserver.rb b/Tools/iExploder/iexploder-1.7.2/src/webserver.rb
new file mode 100755
index 0000000..7076fef
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/src/webserver.rb
@@ -0,0 +1,161 @@
+#!/usr/bin/ruby
+# iExploder Web Server (using webrick)
+#
+# Copyright 2010 Thomas Stromberg - All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+require 'cgi'
+require 'webrick'
+require 'optparse'
+require './iexploder.rb'
+
+include WEBrick
+
+$INSTANCE = nil
+$last_page_requested = [Time.now().to_i, 0]
+
+# Main CGI - Pass requests to iexploder
+class IEServlet < HTTPServlet::AbstractServlet
+ def do_GET(request, response)
+ ie = $INSTANCE.dup
+ ie.test_num = request.query['t'].to_i || 0
+ ie.subtest_data = request.query['s'] || nil
+ ie.random_mode = request.query['r']
+ ie.lookup_mode = request.query['l']
+ ie.claimed_browser = request.query['b'] || nil
+ ie.stop_num = request.query['x'] || nil
+ user_agent = request['User-agent'] || 'unknown'
+ raw_user_agent = user_agent.dup
+
+ # Shorten the user-agent displayed
+ user_agent.gsub!('Mozilla/5.0', '')
+ user_agent.gsub!('X11; ', '')
+ user_agent.gsub!('Macintosh; ', '')
+ user_agent.gsub!(' U;', '')
+ user_agent.gsub!(/^ +/, '')
+ user_agent.gsub!(' (KHTML, like Gecko)', '')
+ if user_agent =~ /Chrome/
+ user_agent.gsub!(/Safari\/[\d\.]+/, '')
+ end
+ ie.browser = user_agent
+ ie.setRandomSeed()
+ # If we are a dependency image, fiddle with the headers!
+ mime_type = request.query['m']
+ headers = []
+ if mime_type
+ for (key, value) in ie.buildHeaders(mime_type)
+ headers << "#{key}[#{value.length}]"
+ response[key] = value
+ end
+ response.body = ie.buildMediaFile(mime_type)
+ else
+ response['Content-Type'] = 'text/html'
+ response.body = ie.buildPage()
+ end
+
+ details = "?t=#{ie.test_num}"
+ if ie.subtest_data
+ details << "&s=#{ie.subtest_data}"
+ end
+ if ie.random_mode
+ details << "&r=1"
+ end
+ if ie.lookup_mode
+ details << "&l=#{ie.lookup_mode}"
+ end
+ if mime_type
+ details << "&m=#{mime_type}"
+ else
+ $last_page_requested = [Time.now().to_i, request.unparsed_uri, CGI.escape(user_agent)]
+ end
+ printf("%-45.45s %s\n", details, user_agent)
+ if headers.length > 0
+ printf("%-45.45s %s\n", "Headers for #{mime_type}:", headers.join(', '))
+ end
+ end
+end
+
+
+# Simple form
+class IEForm < HTTPServlet::AbstractServlet
+ def do_GET(request, response)
+ response['Content-Type'] = 'text/html'
+ response.body = File.read("index.html")
+ end
+end
+
+class IELogo < HTTPServlet::AbstractServlet
+ def do_GET(request, response)
+ response['Content-Type'] = 'image/png'
+ response.body = File.read("media/bug.png")
+ end
+end
+
+class NoPage < HTTPServlet::AbstractServlet
+ def do_GET(request, response)
+ response.body = 'OHAI'
+ end
+end
+
+class LastPage < HTTPServlet::AbstractServlet
+ def do_GET(request, response)
+ response.body = $last_page_requested.join(' ')
+ end
+end
+
+
+def start_server(port, config_path, log_path)
+ puts "* iExploder #{$VERSION} is loading (config=#{config_path}, port=#{port})"
+ puts "=" * 80
+ $INSTANCE = IExploder.new(config_path)
+ warn_logger = Log.new($stderr, Log::WARN)
+ config = YAML::load(File.open(config_path))
+ if not log_path
+ log_path = config['access_log_path']
+ end
+ puts "- Setting up logging to #{log_path}"
+ access_log_stream = Log.new(log_path)
+ access_log = [[ access_log_stream, AccessLog::COMMON_LOG_FORMAT ]]
+ s = WEBrick::HTTPServer.new(:Port => port, :Logger => warn_logger, :AccessLog => access_log)
+ s.mount("/", IEForm)
+ s.mount("/favicon.ico", NoPage)
+ s.mount("/media/bug.png", IELogo)
+ s.mount("/iexploder.cgi", IEServlet)
+ s.mount("/last_page.cgi", LastPage)
+ ['INT', 'TERM'].each {|signal| trap(signal) { puts "SERVER SHUTDOWN: #{signal}"; s.shutdown }}
+ puts "- iExploder is at http://127.0.0.1:#{port}"
+ s.start
+ puts ""
+ puts "Goodbye! Have a fantastic day."
+end
+
+
+
+if $0 == __FILE__
+ options = {
+ :port => 3100,
+ :config_path => 'config.yaml',
+ :log_path => nil
+ }
+
+ optparse = OptionParser.new do|opts|
+ opts.banner = "Usage: webserver.rb [options]"
+ opts.on( '-p', '--port NUM', 'Listen on TCP port NUM' ) { |port| options[:port] = port }
+ opts.on( '-c', '--config PATH', 'Use PATH for configuration file' ) { |path| options[:config_path] = path }
+ opts.on( '-l', '--log PATH', 'Use PATH for log file' ) { |path| options[:log_path] = path }
+ opts.on( '-h', '--help', 'Display this screen' ) { puts opts; exit }
+ end
+ optparse.parse!
+ start_server(options[:port], options[:config_path], options[:log_path])
+end
diff --git a/Tools/iExploder/iexploder-1.7.2/testcases/testcase-Linux_x86_64_rv2.0b6pre_Gecko-20100904_Firefox-4.0b6pre-TEST-8375-1_59.html b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-Linux_x86_64_rv2.0b6pre_Gecko-20100904_Firefox-4.0b6pre-TEST-8375-1_59.html
new file mode 100644
index 0000000..655091f
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-Linux_x86_64_rv2.0b6pre_Gecko-20100904_Firefox-4.0b6pre-TEST-8375-1_59.html
@@ -0,0 +1,47 @@
+<html>
+ <head> <META HTTP-EQUIV="Refresh" content="0;URL=testcase-Linux_x86_64_rv2.0b6pre_Gecko-20100904_Firefox-4.0b6pre-TEST-8375-1_59.html">
+ <script language="javascript">setTimeout('window.location="testcase-Linux_x86_64_rv2.0b6pre_Gecko-20100904_Firefox-4.0b6pre-TEST-8375-1_59.html"', 1000);</script>
+<title>[8375:1_59] iExploder 1.7-DEV - &#5430431573964;&#5430431573964;&#5430431573964;&#5430431573964;&#5430431573964;&#5430431573964;&#5430431573964;&#5430431573964;&#5430431573964;&#5430431573964;&#5430431573964;&#5430431573964;</title>
+
+<!-- iExploder 1.7-DEV | test 8375:1_59 at 2010-09-05 09:21:41 +0200 -->
+
+<!-- browser: (Linux x86_64; rv:2.0b6pre) Gecko/20100904 Firefox/4.0b6pre -->
+<!-- subtest mode: 1 combinations, width: 1 -->
+</head>
+
+<body>
+
+<!-- START script -->
+<script right=middle
+ onreset"http://127.0.0.1:3100/iexploder.cgi?t=8375&m=image%2Fbmp&b=%28Linux+x86_64%3B+rv%3A2.0b6pre%29+Gecko%2F20100904+Firefox%2F4.0b6pre()"
+ pluginspage="icon"
+ font-style=range
+ aria-grabbed="inherit"
+ onplaying=about:logo%&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;&#765832;()
+ submit="-9"
+ onfilterchange="http://127.0.0.1:3100/iexploder.cgi?t=8375&m=image%2Fsvg%2Bxml&b=%28Linux+x86_64%3B+rv%3A2.0b6pre%29+Gecko%2F20100904+Firefox%2F4.0b6pre"
+ ascent=baseline
+ containment=poly
+ horiz-origin-y="hidden
+ xlink:arcrole=999999999,9999999
+ style="text-overline-mode: -999999.861474621882159640833 9999999999999999999999999999999999999999999999999999999999999border-left-width-value: $44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;$44%;/0^2&A^7.FD;;
+ -moz-outline-radius: url(´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´´:942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&942;5911A%D;?#9/5&);
+ -webkit-animation: 99999999999999999999999999999999999999999999999999999999999999999999999999999999999;
+ richness: progresschunk-vertical 9999999999999999999999999999999999999999999999999999999999999999999999999999;
+ -moz-force-broken-image-icon: url(}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}:ãããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããããã) url(about:licence//aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa);
+ ">
+window.onload=function(){
+ var ietarget = document.createElement('strike');
+ ietarget.style.stress = '999999.403294590608419311316';
+ ietarget.columnlines = '/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%/3;1|3E98%:ÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚÚ';
+ document.body.appendChild(ietarget);
+ ietarget.style.speak = -9999999999999999999999999999999999;
+ document.write('</track>');
+ document.write('</a>');
+}
+</script>
+</script>
+
+<!-- END script -->
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/iExploder/iexploder-1.7.2/testcases/testcase-Opera-9.80_Linux_x86_64_en_Presto-2.6.30_Version-10.61-16704-3_108,3.html b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-Opera-9.80_Linux_x86_64_en_Presto-2.6.30_Version-10.61-16704-3_108,3.html
new file mode 100644
index 0000000..aad7ced
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-Opera-9.80_Linux_x86_64_en_Presto-2.6.30_Version-10.61-16704-3_108,3.html
@@ -0,0 +1,6 @@
+<html>
+<body style="letter-spacing: 9999999999999999;">
+<textarea>
+<applet aria-valuetext="&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;&#977637;">
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Intel_Mac_OS_X_10_6_4_en-US_AppleWebKit-534.8_Chrome-7.0.529.0-TEST-611-3_36,9.html b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Intel_Mac_OS_X_10_6_4_en-US_AppleWebKit-534.8_Chrome-7.0.529.0-TEST-611-3_36,9.html
new file mode 100644
index 0000000..0aab5ba
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Intel_Mac_OS_X_10_6_4_en-US_AppleWebKit-534.8_Chrome-7.0.529.0-TEST-611-3_36,9.html
@@ -0,0 +1,8 @@
+<html>
+<!-- iExploder 1.7 | test 611:3_36,9 at Sun Sep 19 22:00:15 +0200 2010 -->
+<!-- browser: (U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.8 Chrome/7.0.529.0 -->
+<!-- subtest mode: 2 combinations, width: 3 -->
+<body>
+<progress style="font: 9999 x; ">
+</body>
+</html>
diff --git a/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Intel_Mac_OS_X_10_6_4_en-US_AppleWebKit-534.8_hrome-7.0.529.0-TEST-55313622206-3_6,0.html b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Intel_Mac_OS_X_10_6_4_en-US_AppleWebKit-534.8_hrome-7.0.529.0-TEST-55313622206-3_6,0.html
new file mode 100644
index 0000000..5a2b9e1
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Intel_Mac_OS_X_10_6_4_en-US_AppleWebKit-534.8_hrome-7.0.529.0-TEST-55313622206-3_6,0.html
@@ -0,0 +1,11 @@
+<html style="content:
+url(//%n%n);
+">
+ <head>
+ <META HTTP-EQUIV="Refresh" content="1;testcase-U_Intel_Mac_OS_X_10_6_4_en-US_AppleWebKit-534.8_hrome-7.0.529.0-TEST-55313622206-3_6,0.html">
+<!-- iExploder 1.7 | test 55313622206:3_6,0 at Sun Sep 19 21:14:29 +0200 2010 -->
+<!-- browser: (U; Intel Mac OS X 10_6_4; en-US) AppleWebKit/534.8 Chrome/7.0.529.0 -->
+</head>
+<body>
+</body>
+</html>
diff --git a/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.6_Chrome-7.0.503.1-TEST-120813-8_72,56,24,8,0.html b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.6_Chrome-7.0.503.1-TEST-120813-8_72,56,24,8,0.html
new file mode 100644
index 0000000..43601bd
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.6_Chrome-7.0.503.1-TEST-120813-8_72,56,24,8,0.html
@@ -0,0 +1,6 @@
+<html>
+<!-- browser: (U; Linux x86_64; en-US) AppleWebKit/534.6 Chrome/7.0.503.1 -->
+<i style="font: 0 xxx;">
+<progress>
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.6_Chrome-7.0.503.1-TEST-121240-3_81,3.html b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.6_Chrome-7.0.503.1-TEST-121240-3_81,3.html
new file mode 100644
index 0000000..3f7ad07
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.6_Chrome-7.0.503.1-TEST-121240-3_81,3.html
@@ -0,0 +1,11 @@
+<html>
+<!-- browser: (U; Linux x86_64; en-US) AppleWebKit/534.6 Chrome/7.0.503.1 -->
+<textarea>
+<body>
+<style>
+dl {
+ margin: &#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;&#6076;
+}
+</style>
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-4800-5_80,65,15.html b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-4800-5_80,65,15.html
new file mode 100644
index 0000000..7a03f55
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-4800-5_80,65,15.html
@@ -0,0 +1,13 @@
+<html>
+<head>
+ <META HTTP-EQUIV="Refresh" content="1;URL=testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-4800-5_80,65,15.html">
+ <script
+ language="javascript">setTimeout('window.location="testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-4800-5_80,65,15.html"', 1000);</script>
+</head>
+
+<body>
+<textarea>
+<source>
+<option style="-webkit-hyphenate-character: &#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;&#1474;">
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-TEST-23583190347-3_15,12.html b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-TEST-23583190347-3_15,12.html
new file mode 100644
index 0000000..a6bbe3f
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/testcases/testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-TEST-23583190347-3_15,12.html
@@ -0,0 +1,14 @@
+<html>
+ <head>
+ <META HTTP-EQUIV="Refresh" content="1;URL=testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-TEST-23583190347-3_15,12.html">
+ <script language="javascript">setTimeout('window.location="testcase-U_Linux_x86_64_en-US_AppleWebKit-534.7_Chrome-7.0.513.0-TEST-23583190347-3_15,12.html"', 1000);</script>
+<!-- browser: (U; Linux x86_64; en-US) AppleWebKit/534.7 Chrome/7.0.513.0 -->
+<!-- subtest mode: 2 combinations, width: 3 -->
+</head>
+
+<body>
+
+<script style="content: url(https://);">
+</script>
+</body>
+</html> \ No newline at end of file
diff --git a/Tools/iExploder/iexploder-1.7.2/tools/lasthit.rb b/Tools/iExploder/iexploder-1.7.2/tools/lasthit.rb
new file mode 100755
index 0000000..d792d1b
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/tools/lasthit.rb
@@ -0,0 +1,74 @@
+#!/usr/bin/ruby
+# Copyright 2010 Thomas Stromberg - All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+#
+# lasthit, part of iExploder
+#
+# Shows statistics about recent agents that have tested with iExploder.
+# It takes all or part of an apache logfile via stdin, and outputs a list
+# of all the agents who tested within that section, what their last test
+# was, and how many tests they have done.
+
+# The usefulness is finding out where a browser crashed.
+
+require 'cgi'
+
+hostHash = Hash.new
+
+if (ARGV[0])
+ file = File.open(ARGV[0])
+else
+ puts "No filename specified, waiting for data via stdin..."
+ file = $stdin
+end
+
+last_index = nil
+file.readlines.each_with_index { |line, index|
+ # filter out mime hits as they produce a lot of odd user agents
+ next if line =~ /&m=/
+ if (line =~ /([\w\.]+) - - .*iexploder.cgi\?(.*?)&b=([\w\%-\.+]+)/)
+ host = $1
+ test_url = $2
+ agent = $3
+ if (! hostHash[host])
+ hostHash[host] = Hash.new
+ end
+ if (! hostHash[host][agent])
+ hostHash[host][agent] = Hash.new
+ hostHash[host][agent]['total'] = 0
+ end
+ hostHash[host][agent]['last'] = test_url
+ hostHash[host][agent]['total'] = hostHash[host][agent]['total'] + 1
+ hostHash[host][agent]['last_line'] = index
+ end
+ last_index = index
+}
+
+printf("%-14.14s | %-25.25s | %6.6s | %7.7s | %s\n",
+ "Host", "Test URL", "Total", "LineAgo", "Agent")
+puts "-" * 78
+hostHash.each_key { |host|
+ hostHash[host].each_key { |agent|
+ next if agent.length < 8
+ display_agent = CGI::unescape(agent).sub('U; ', '')
+ printf("%-14.14s | %-25.25s | %6.6s | %7.7s | %s\n",
+ host, hostHash[host][agent]['last'],
+ hostHash[host][agent]['total'],
+ hostHash[host][agent]['last_line'] - last_index,
+ display_agent);
+ }
+}
+
diff --git a/Tools/iExploder/iexploder-1.7.2/tools/osx_last_crash.rb b/Tools/iExploder/iexploder-1.7.2/tools/osx_last_crash.rb
new file mode 100755
index 0000000..d95296d
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/tools/osx_last_crash.rb
@@ -0,0 +1,63 @@
+#!/usr/bin/ruby
+# Copyright 2010 Thomas Stromberg - All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+#
+# Gives you information about the most recent crash for each application
+# that has crashed within the last 2 days
+
+$LogDir=ENV['HOME'] + '/Library/Logs/CrashReporter'
+$Days=1
+$StackCount=5
+
+files=`find #$LogDir -mtime -#$Days -type f | grep -v synergy`
+files.each { |filename|
+ filename.chop!
+ record = 0
+ date=''
+ stackTrace = []
+
+ File.open(filename).readlines.each { |line|
+ #puts line
+
+ if line =~ /^Date.*(200.*)/
+ date = $1
+ end
+
+ if line =~ /^Thread \d+ Crashed/
+ record = 1
+ # reset the stack trace
+ stackTrace = []
+ end
+
+ if record
+ stackTrace << line
+ record = record + 1
+
+ # stop recording after $StackCount lines
+ if record > ($StackCount + 2)
+ record = nil
+ end
+ end
+ }
+
+ puts File.basename(filename) + " - " + date
+ puts "==================================================="
+ stackTrace.each { |line|
+ puts line
+ }
+ puts ""
+}
+
+
diff --git a/Tools/iExploder/iexploder-1.7.2/tools/release_src.sh b/Tools/iExploder/iexploder-1.7.2/tools/release_src.sh
new file mode 100755
index 0000000..5fb625e
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/tools/release_src.sh
@@ -0,0 +1,28 @@
+#!/bin/sh
+# Create a tarball from the subversion repository.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+tmp=$$
+cd /tmp
+svn checkout http://iexploder.googlecode.com/svn/trunk/ iexploder-$$
+version=`grep '^\$VERSION' iexploder-$$/src/version.rb | cut -d\" -f2`
+echo "Version: $version"
+mv iexploder-$$ iexploder-$version
+cd iexploder-$version
+svn log > ChangeLog.txt
+find . -name "*.pyc" -delete
+find . -name ".svn" -exec rm -Rf {} \; 2>/dev/null
+cd ..
+GZIP="-9" tar -zcvf iexploder-${version}.tgz iexploder-${version}/
+rm -Rf iexploder-${version}
diff --git a/Tools/iExploder/iexploder-1.7.2/tools/update_html_tags_from_sources.sh b/Tools/iExploder/iexploder-1.7.2/tools/update_html_tags_from_sources.sh
new file mode 100755
index 0000000..f681743
--- /dev/null
+++ b/Tools/iExploder/iexploder-1.7.2/tools/update_html_tags_from_sources.sh
@@ -0,0 +1,125 @@
+#!/bin/sh
+#
+# This script imports HTML and CSS tags from source trees. Supported browsers:
+#
+# * WebKit
+# * Firefox
+# * dillo
+# * gtkhtml
+
+src_dir=$1
+tools_dir=`dirname $0`
+dest_dir="$tools_dir/../src"
+tmp_prefix="/tmp/$$"
+
+if [ -z "$src_dir" ]; then
+ echo "You must define a source directory to examine."
+fi
+
+if [ ! -d "$dest_dir" ]; then
+ echo "Unable to find htdocs directory. Tried $dest_dir"
+ exit 1
+fi
+
+
+if [ -d "$src_dir/WebKit" ]; then
+ # Tested as of WebKit-r55454
+ source_name="webkit"
+ grep -v "^#" $src_dir/WebCore/css/CSSPropertyNames.in > ${tmp_prefix}.css-properties
+ grep -v "^#" $src_dir/WebCore/css/CSSValueKeywords.in > ${tmp_prefix}.css-values
+ grep -v "^#" $src_dir/WebCore/html/HTMLAttributeNames.in | cut -d" " -f1 | \
+ egrep -v "^namespace\w*=" > ${tmp_prefix}.html-attrs
+ grep -v "^#" $src_dir/WebCore/html/HTMLTagNames.in | cut -d" " -f1 | \
+ egrep -v "^namespace\w*=" > ${tmp_prefix}.html-tags
+ egrep "equalIgnoringCase" $src_dir/WebCore/html/HTML*.cpp | \
+ ruby -e '$stdin.readlines.join("").scan(/\"([\w-]+)"/) { |tag| puts tag }' > ${tmp_prefix}.html-values
+ grep -r "protocolIs" $src_dir/WebCore/* | ruby -e '$stdin.readlines.join("").scan(/\"([\w-]+)"/) { |tag| puts "#{tag}:" }' > ${tmp_prefix}.protocols
+ grep "map->add" $src_dir/WebCore/html/HTMLInputElement.cpp | cut -d\" -f2 >> ${tmp_prefix}.html-values
+ grep "AtomicString,.*Header, (" $src_dir/WebCore/platform/network/ResourceResponseBase.cpp | cut -d\" -f2 > ${tmp_prefix}.headers
+ grep -o -r 'httpHeaderField(".*"' $src_dir | cut -d\" -f2 >> ${tmp_prefix}.headers
+ egrep -r '"[-\+a-z]+/[-\+a-z]+"' $src_dir/WebCore | ruby -e '$stdin.readlines.join("").scan(/\"([afimtvwx][\w\+-]+\/[\w\+-]+)"/) { puts $1 }' > ${tmp_prefix}.mime-types
+ grep DEFINE_STATIC $src_dir/WebCore/css/CSSSelector.cpp | cut -d\" -f2 \
+ > ${tmp_prefix}.css-pseudo
+ egrep -o '"@.*?\"' $src_dir/WebCore/css/CSSParser.cpp | cut -d\" -f2 | cut -d"{" -f1 | \
+ sed s/" "// > ${tmp_prefix}.css-atrules
+elif [ -d "$src_dir/xpcom" ]; then
+ # Tested as of Sep 1 2010
+ source_name="mozilla"
+ grep "^HTML_.*TAG" $src_dir/parser/htmlparser/public/nsHTMLTagList.h \
+ | cut -d\( -f2 | cut -d, -f1 | cut -d\) -f1 > ${tmp_prefix}.html-tags
+ grep -r "Get.*Attr.*nsGkAtoms" $src_dir | perl -ne 'if (/nsGkAtoms::(\w+)/) { print "$1\n" } '\
+ | xargs -n1 -I{} grep "({}," $src_dir/content/base/src/nsGkAtomList.h \
+ | cut -d\" -f2 > ${tmp_prefix}.html-attrs
+ grep "nsHtml5AttributeName.*nsHtml5Atoms::" $src_dir/parser/html/nsHtml5AttributeName.cpp \
+ | cut -d: -f3 | cut -d\) -f1 | cut -d, -f1 | xargs -n1 -I{} grep "({}," $src_dir/parser/html/nsHtml5AtomList.h \
+ | cut -d\" -f2 >> ${tmp_prefix}.html-attrs
+ egrep "^ [a-z-]+," $src_dir/layout/style/nsCSSPropList.h | cut -d, -f1 \
+ | awk '{ print $1 }' > ${tmp_prefix}.css-properties
+ grep 'CSS_KEY(' $src_dir/layout/style/nsCSSKeywordList.h | cut -d"(" -f2 \
+ | cut -d, -f1 > ${tmp_prefix}.css-values
+ egrep '{ "[a-z]+:' $src_dir/docshell/build/nsDocShellModule.cpp | cut -d\" -f2 \
+ > ${tmp_prefix}.protocols
+ grep -r 'aURI->SchemeIs("' $src_dir/* | cut -d\" -f2 | perl -ne 'chomp; print "$_:\n";' >> ${tmp_prefix}.protocols
+ grep -r 'uri->SchemeIs("' $src_dir/* | cut -d\" -f2 | perl -ne 'chomp; print "$_:\n";' >> ${tmp_prefix}.protocols
+ grep "{ \"" $src_dir/docshell/base/nsAboutRedirector.cpp | cut -d\" -f2 \
+ | xargs -I{} echo "about:{}" >> ${tmp_prefix}.protocols
+ grep targetScheme.EqualsLiteral $src_dir/netwerk/base/public/nsNetUtil.h \
+ | cut -d\" -f2 | sed s/$/:/g>> ${tmp_prefix}.protocols
+ grep "name.LowerCaseEqualsLiteral" $src_dir/docshell/base/nsDocShell.cpp | cut -d\" -f2 >> ${tmp_prefix}.html-values
+ egrep ' { "[a-z]+' $src_dir/content/html/content/src/nsGenericHTMLElement.cpp | cut -d\" -f2 >> ${tmp_prefix}.html-values
+ grep ' { "' $src_dir/content/html/content/src/nsHTMLInputElement.cpp | cut -d\" -f2 >> ${tmp_prefix}.html-values
+ grep -r value.LowerCaseEqualsLiteral $src_dir/content/base/src/* | cut -d\" -f2 >> ${tmp_prefix}.html-values
+ grep "^HTTP_ATOM" $src_dir/netwerk/protocol/http/nsHttpAtomList.h | cut -d\" -f2 \
+ | grep '[a-z]'>> ${tmp_prefix}.headers
+ egrep -r '"[-\+a-z]+/[-\+a-z]+"' $src_dir/browser/base $src_dir/browser/components $src_dir/uriloader $src_dir/netwerk/mime $src_dir/content/html \
+ | ruby -e '$stdin.readlines.join("").scan(/\"([afimtvwx][\w\+-]+\/[\w\+-]+)"/) { puts $1 }' > ${tmp_prefix}.mime-types
+ egrep -o '":(.*?)"' $src_dir/layout/style/nsCSSPseudoClassList.h | cut -d\" -f2 \
+ | sed s/^:// > ${tmp_prefix}.css-pseudo
+ grep AssignLiteral $src_dir/layout/style/nsCSSRules.cpp | egrep -o '"@.*?"' \
+ | cut -d\" -f2 | cut -d" " -f1 > ${tmp_prefix}.css-atrules
+elif [ -f "$src_dir/dillorc" ]; then
+ # Tested as of dillo 2.2
+ source_name="dillo"
+ grep '{"' $src_dir/src/cssparser.cc | cut -d\" -f2 > ${tmp_prefix}.css-properties
+ egrep '^ +\"[a-z-]+\", ' $src_dir/src/cssparser.cc | \
+ ruby -e '$stdin.readlines.join("").scan(/\"(.*?)\"/) { |tag| puts tag }' > ${tmp_prefix}.css-values
+ grep "_get_attr(html" $src_dir/src/html.cc | grep '"' | cut -d\" -f2 > ${tmp_prefix}.html-attrs
+ grep 'a_Html_get_attr(html.*"' $src_dir/src/*.cc | cut -d\" -f2 >> ${tmp_prefix}.html-attrs
+ grep Html_tag_open_ $src_dir/src/html.cc | grep "^ {" | cut -d\" -f2 > ${tmp_prefix}.html-tags
+ grep dStrcasecmp $src_dir/src/form.cc $src_dir/src/html.cc $src_dir/src/table.cc | \
+ ruby -e '$stdin.readlines.join("").scan(/\"([-a-z]+)\"/) { |tag| puts tag }' > ${tmp_prefix}.html-values
+ grep -r 'URL_SCHEME.*"[a-z]' $src_dir | cut -d \" -f2 | perl -ne 'chomp; print "$_:\n";' > ${tmp_prefix}.protocols
+ grep -r 'header, "' $src_dir/src/cache.c | cut -d\" -f2 > ${tmp_prefix}.headers
+ egrep -r "[-\+a-z]+/[-\+a-z]+" $src_dir/dpi $src_dir/src | \
+ ruby -e '$stdin.readlines.join("").scan(/\"([\w\+-]+\/[\w\+-]+)"/) { puts $1 }' > ${tmp_prefix}.mime-types
+elif [ -d "$src_dir/gtkhtml" ]; then
+ # tested as of gtkhtml-3.29.91
+ source_name="gtkhtml"
+ grep -r "#define ID_" $src_dir/gtkhtml/htmlengine.c | cut -d\" -f2 | egrep '^[a-z]' > ${tmp_prefix}.html-tags
+ grep "html_element_get_attr" $src_dir/gtkhtml/*.c | cut -d\" -f2 > ${tmp_prefix}.html-attrs
+ grep -r "g_ascii_strncasecmp" $src_dir/gtkhtml/*.c | cut -d\" -f2 | grep -v ":" | cut -d"=" -f1 | grep "^[a-z]" > ${tmp_prefix}.html-attrs
+ grep "g_ascii_strncasecmp" $src_dir/gtkhtml/htmlstyle.c | cut -d\" -f2 | cut -d" " -f1 | sed s/://g > ${tmp_prefix}.css-properties
+ grep "g_ascii_strcasecmp" $src_dir/gtkhtml/htmlstyle.c | cut -d\" -f2 > ${tmp_prefix}.css-values
+ grep g_ascii_strcasecmp $src_dir/gtkhtml/htmlengine.c | ruby -e '$stdin.readlines.join("").scan(/\"([\/\w-]+)"/) { |tag| puts tag }' > ${tmp_prefix}.html-values
+fi
+
+if [ "$source_name" ]; then
+ echo "Updating $source_name"
+ # We always append, never remove.
+ types="css-properties css-values html-attrs html-tags html-values protocols headers mime-types css-pseudo css-atrules"
+ for type in $types
+ do
+ if [ -f "${tmp_prefix}.${type}" ]; then
+ if [ -s "${tmp_prefix}.${type}" ]; then
+ echo "- $type"
+ cat $dest_dir/$type/$source_name ${tmp_prefix}.${type} | sort -u > $dest_dir/$type/$source_name
+ else
+ echo "- Unable to parse ${type}, source code is incompatible (skipping)"
+ fi
+ rm -f "${tmp_prefix}.${type}"
+ fi
+ done
+else
+ echo "Could not identify the correct source type for $src_dir"
+fi
+
diff --git a/Tools/iExploder/tools/lasthit.rb b/Tools/iExploder/tools/lasthit.rb
new file mode 100755
index 0000000..b569deb
--- /dev/null
+++ b/Tools/iExploder/tools/lasthit.rb
@@ -0,0 +1,53 @@
+#!/usr/bin/ruby
+# lasthit, part of iExploder
+#
+# Shows statistics about recent agents that have tested with iExploder.
+# It takes all or part of an apache logfile via stdin, and outputs a list
+# of all the agents who tested within that section, what their last test
+# was, and how many tests they have done.
+
+# The usefulness is finding out where a browser crashed.
+
+
+hostHash = Hash.new
+
+if (ARGV[0])
+ file = File.open(ARGV[0])
+else
+ file = $stdin
+end
+
+file.readlines.each { |line|
+ if (line =~ /^(.*?) .*iexploder.*?test=(\d+).* HTTP.* \"(.*?)\"$/)
+ host = $1
+ testnum = $2
+ agent = $3
+ if (! hostHash[host])
+ hostHash[host] = Hash.new
+ end
+ if (! hostHash[host][agent])
+ hostHash[host][agent] = Hash.new
+ hostHash[host][agent]['total'] = 0
+ end
+
+ hostHash[host][agent]['last'] = testnum
+ if line =~ /subtest=(\d+)/
+ hostHash[host][agent]['subtest'] = $1
+ else
+ hostHash[host][agent]['subtest'] = ''
+ end
+ hostHash[host][agent]['total'] = hostHash[host][agent]['total'] + 1
+ end
+}
+
+printf("%14.14s | %8.8s | %3.3s | %8.8s | %s\n",
+ "IP", "Test", "SubTest", "Total", "Agent")
+puts "---------------------------------------------------------------------------"
+hostHash.each_key { |host|
+
+ hostHash[host].each_key { |agent|
+ printf("%14.14s | %8.8s | %3.3s | %8.8s | %s\n",
+ host, hostHash[host][agent]['last'], hostHash[host][agent]['subtest'], hostHash[host][agent]['total'], agent);
+ }
+}
+
diff --git a/Tools/iExploder/tools/osx_last_crash.rb b/Tools/iExploder/tools/osx_last_crash.rb
new file mode 100755
index 0000000..5b62c6d
--- /dev/null
+++ b/Tools/iExploder/tools/osx_last_crash.rb
@@ -0,0 +1,48 @@
+#!/usr/bin/ruby
+# Gives you information about the most recent crash for each application
+# that has crashed within the last 2 days
+
+$LogDir=ENV['HOME'] + '/Library/Logs/CrashReporter'
+$Days=1
+$StackCount=5
+
+files=`find #$LogDir -mtime -#$Days -type f | grep -v synergy`
+files.each { |filename|
+ filename.chop!
+ record = 0
+ date=''
+ stackTrace = []
+
+ File.open(filename).readlines.each { |line|
+ #puts line
+
+ if line =~ /^Date.*(200.*)/
+ date = $1
+ end
+
+ if line =~ /^Thread \d+ Crashed/
+ record = 1
+ # reset the stack trace
+ stackTrace = []
+ end
+
+ if record
+ stackTrace << line
+ record = record + 1
+
+ # stop recording after $StackCount lines
+ if record > ($StackCount + 2)
+ record = nil
+ end
+ end
+ }
+
+ puts File.basename(filename) + " - " + date
+ puts "==================================================="
+ stackTrace.each { |line|
+ puts line
+ }
+ puts ""
+}
+
+
diff --git a/Tools/iExploder/tools/showtest.rb b/Tools/iExploder/tools/showtest.rb
new file mode 100755
index 0000000..af6b101
--- /dev/null
+++ b/Tools/iExploder/tools/showtest.rb
@@ -0,0 +1,43 @@
+#!/usr/bin/ruby
+# showtest.rb - simple CLI interface to grab a testcase
+#####################
+#
+# Copyright (c) 2006 Thomas Stromberg <thomas%stromberg.org>
+#
+# This software is provided 'as-is', without any express or implied warranty.
+# In no event will the authors be held liable for any damages arising from the
+# use of this software.
+#
+# Permission is granted to anyone to use this software for any purpose,
+# including commercial applications, and to alter it and redistribute it
+# freely, subject to the following restrictions:
+#
+# 1. The origin of this software must not be misrepresented; you must not
+# claim that you wrote the original software. If you use this software in a
+# product, an acknowledgment in the product documentation would be appreciated
+# but is not required.
+#
+# 2. Altered source versions must be plainly marked as such, and must not be
+# misrepresented as being the original software.
+#
+# 3. This notice may not be removed or altered from any source distribution.
+
+Dir.chdir('../htdocs')
+require 'iexploder';
+require 'config';
+
+### THE INTERACTION ##################################
+ie = IExploder.new($HTML_MAX_TAGS, $HTML_MAX_ATTRS, $CSS_MAX_PROPS)
+ie.readTagFiles()
+
+if ! ARGV[0]
+ puts "syntax: showtest.rb [test#] [subtest#]"
+ exit
+end
+
+ie.test_num = ARGV[0].to_i
+ie.subtest_num = ARGV[1].to_i || 0
+ie.lookup_mode = 1
+ie.setRandomSeed
+
+puts ie.buildPage()
diff --git a/Tools/mangleme/LICENSE b/Tools/mangleme/LICENSE
new file mode 100644
index 0000000..5ab7695
--- /dev/null
+++ b/Tools/mangleme/LICENSE
@@ -0,0 +1,504 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 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
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
+
+
diff --git a/Tools/mangleme/Makefile b/Tools/mangleme/Makefile
new file mode 100644
index 0000000..90d01e9
--- /dev/null
+++ b/Tools/mangleme/Makefile
@@ -0,0 +1,16 @@
+#
+# HTML manglizer
+# --------------
+# Copyright (C) 2004 by Michal Zalewski <lcamtuf@coredump.cx>
+#
+# Makefile adapted for WebKit project.
+
+CC = gcc
+CFLAGS = -Wall -O3 -fomit-frame-pointer -funroll-loops
+OUTDIR = ../../WebKitBuild/mangleme
+
+all: $(OUTDIR)/mangle.cgi $(OUTDIR)/remangle.cgi
+
+$(OUTDIR)/%.cgi: %.cgi.c
+ if [ ! -d $(OUTDIR) ]; then mkdir -p $(OUTDIR); fi
+ $(CC) $(CFLAGS) $< -o $(OUTDIR)/$*.cgi
diff --git a/Tools/mangleme/README b/Tools/mangleme/README
new file mode 100644
index 0000000..4fe2928
--- /dev/null
+++ b/Tools/mangleme/README
@@ -0,0 +1,20 @@
+
+ HTML manglizer
+ --------------
+
+ Copyright (C) 2004 by Michal Zalewski <lcamtuf@coredump.cx>
+
+ A trivial utility to automatically check for HTML parsing flaws. Generates
+ a basic set of badly mangled tags on request, with auto-refresh back to the
+ script, so that you can point a browser to it once, and let it run until
+ it crashes.
+
+ Put it in your cgi-bin directory or any other Apache folder with ExecCGI option
+ enabled, then visit the URL http://<yourserver>/<cgidir>/mangleme.cgi.
+
+ When the browser crashes, error-log should be examined for the last matching
+ entry generated by mangle.cgi; extract the hexadecimal value, then invoke
+ remangle.cgi?hex_value from the browser again. If it crashes, you've reproduced
+ the problem, and can save the remangle.cgi page using wget or such.
+
+ Check gallery/ for some samples.
diff --git a/Tools/mangleme/mangle.cgi.c b/Tools/mangleme/mangle.cgi.c
new file mode 100644
index 0000000..12ca948
--- /dev/null
+++ b/Tools/mangleme/mangle.cgi.c
@@ -0,0 +1,122 @@
+/*
+
+ HTML manglizer
+ --------------
+ Copyright (C) 2004 by Michal Zalewski <lcamtuf@coredump.cx>
+
+ HTML manglizer library. Logs random seeds to error-log; find the last entry before
+ crash, then pass it to remangle.cgi to reproduce the problem.
+
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "tags.h"
+
+#define R(x) (rand() % (x))
+
+#define MAXTCOUNT 100
+#define MAXPCOUNT 20
+#define MAXSTR2 80
+
+void make_up_value(void) {
+ char c=R(2);
+
+ if (c) putchar('"');
+
+ switch (R(31)) {
+
+ case 0: printf("javascript:"); make_up_value(); break;
+// case 1: printf("jar:"); make_up_value(); break;
+ case 2: printf("mk:"); make_up_value(); break;
+ case 3: printf("file:"); make_up_value(); break;
+ case 4: printf("http:"); make_up_value(); break;
+ case 5: printf("about:"); make_up_value(); break;
+ case 6: printf("_blank"); break;
+ case 7: printf("_self"); break;
+ case 8: printf("top"); break;
+ case 9: printf("left"); break;
+ case 10: putchar('&'); make_up_value(); putchar(';'); break;
+ case 11: make_up_value(); make_up_value(); break;
+
+ case 12 ... 20: {
+ int c = R(10) ? R(10) : (1 + R(MAXSTR2) * R(MAXSTR2));
+ char* x = malloc(c);
+ memset(x,R(256),c);
+ fwrite(x,c,1,stdout);
+ free(x);
+ break;
+ }
+
+ case 21: printf("%s","%n%n%n%n%n%n"); break;
+ case 22: putchar('#'); break;
+ case 23: putchar('*'); break;
+ default: if (R(2)) putchar('-'); printf("%d",rand()); break;
+
+ }
+
+ if (c) putchar('"');
+
+}
+
+
+void random_tag(void) {
+ int tn, tc;
+
+ do tn = R(MAXTAGS); while (!tags[tn][0]);
+ tc = R(MAXPCOUNT) + 1;
+
+ putchar('<');
+
+ switch (R(10)) {
+ case 0: putchar(R(256)); break;
+ case 1: putchar('/');
+ }
+
+ printf("%s", tags[tn][0]);
+
+ while (tc--) {
+ int pn;
+ switch (R(32)) {
+ case 0: putchar(R(256));
+ case 1: break;
+ default: putchar(' ');
+ }
+ do pn = R(MAXPARS-1) + 1; while (!tags[tn][pn]);
+ printf("%s", tags[tn][pn]);
+ switch (R(32)) {
+ case 0: putchar(R(256));
+ case 1: break;
+ default: putchar('=');
+ }
+
+ make_up_value();
+
+ }
+
+ putchar('>');
+
+}
+
+
+int main(int argc,char** argv) {
+ int tc,seed;
+
+ printf("Content-Type: text/html;charset=utf-8\nRefresh: 0;URL=mangle.cgi\n\n");
+ printf("<HTML><HEAD><META HTTP-EQUIV=\"Refresh\" content=\"0;URL=mangle.cgi\">\n");
+ printf("<script language=\"javascript\">setTimeout('window.location=\"mangle.cgi\"', 1000);</script>\n");
+
+ seed = (time(0) ^ (getpid() << 16));
+ fprintf(stderr,"[%u] Mangle attempt 0x%08x (%s) -- %s\n", (int)time(0), seed, getenv("HTTP_USER_AGENT"), getenv("REMOTE_ADDR"));
+ srand(seed);
+
+ tc = R(MAXTCOUNT) + 1;
+ while (tc--) random_tag();
+ fflush(0);
+ return 0;
+}
diff --git a/Tools/mangleme/remangle.cgi.c b/Tools/mangleme/remangle.cgi.c
new file mode 100644
index 0000000..ccc4472
--- /dev/null
+++ b/Tools/mangleme/remangle.cgi.c
@@ -0,0 +1,125 @@
+/*
+
+ HTML manglizer
+ --------------
+ Copyright (C) 2004 by Michal Zalewski <lcamtuf@coredump.cx>
+
+ Fault reproduction utility.
+
+ */
+
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "tags.h"
+
+#define R(x) (rand() % (x))
+
+#define MAXTCOUNT 100
+#define MAXPCOUNT 20
+#define MAXSTR2 80
+
+void make_up_value(void) {
+ char c=R(2);
+
+ if (c) putchar('"');
+
+ switch (R(31)) {
+
+ case 0: printf("javascript:"); make_up_value(); break;
+// case 1: printf("jar:"); make_up_value(); break;
+ case 2: printf("mk:"); make_up_value(); break;
+ case 3: printf("file:"); make_up_value(); break;
+ case 4: printf("http:"); make_up_value(); break;
+ case 5: printf("about:"); make_up_value(); break;
+ case 6: printf("_blank"); break;
+ case 7: printf("_self"); break;
+ case 8: printf("top"); break;
+ case 9: printf("left"); break;
+ case 10: putchar('&'); make_up_value(); putchar(';'); break;
+ case 11: make_up_value(); make_up_value(); break;
+
+ case 12 ... 20: {
+ int c = R(10) ? R(10) : (1 + R(MAXSTR2) * R(MAXSTR2));
+ char* x = malloc(c);
+ memset(x,R(256),c);
+ fwrite(x,c,1,stdout);
+ free(x);
+ break;
+ }
+
+ case 21: printf("%s","%n%n%n%n%n%n"); break;
+ case 22: putchar('#'); break;
+ case 23: putchar('*'); break;
+ default: if (R(2)) putchar('-'); printf("%d",rand()); break;
+
+ }
+
+ if (c) putchar('"');
+
+}
+
+
+void random_tag(void) {
+ int tn, tc;
+
+ do tn = R(MAXTAGS); while (!tags[tn][0]);
+ tc = R(MAXPCOUNT) + 1;
+
+ putchar('<');
+
+ switch (R(10)) {
+ case 0: putchar(R(256)); break;
+ case 1: putchar('/');
+ }
+
+ printf("%s", tags[tn][0]);
+
+ while (tc--) {
+ int pn;
+ switch (R(32)) {
+ case 0: putchar(R(256));
+ case 1: break;
+ default: putchar(' ');
+ }
+ do pn = R(MAXPARS-1) + 1; while (!tags[tn][pn]);
+ printf("%s", tags[tn][pn]);
+ switch (R(32)) {
+ case 0: putchar(R(256));
+ case 1: break;
+ default: putchar('=');
+ }
+
+ make_up_value();
+
+ }
+
+ putchar('>');
+
+}
+
+
+int main(int argc,char** argv) {
+ int tc,seed;
+ char* x = getenv("QUERY_STRING");
+
+ if (!x || sscanf(x,"%x",&seed) != 1) {
+ printf("Content-type: text/plain\n\nMissing or invalid parameter.\n");
+ exit(1);
+ }
+
+ printf("Content-Type: text/html;charset=utf-8\nRefresh: 0;URL=remangle.cgi?0x%08x\n\n", seed);
+ printf("<HTML><HEAD><META HTTP-EQUIV=\"Refresh\" content=\"0;URL=remangle.cgi?0x%08x\">\n", seed);
+ printf("<script language=\"javascript\">setTimeout('window.location=\"remangle.cgi?0x%08x\"', 1000);</script>\n", seed);
+
+ srand(seed);
+
+ tc = R(MAXTCOUNT) + 1;
+ while (tc--) random_tag();
+ fflush(0);
+ return 0;
+}
diff --git a/Tools/mangleme/tags.h b/Tools/mangleme/tags.h
new file mode 100644
index 0000000..5789441
--- /dev/null
+++ b/Tools/mangleme/tags.h
@@ -0,0 +1,76 @@
+/*
+
+ HTML manglizer
+ --------------
+ Copyright (C) 2004 by Michal Zalewski <lcamtuf@coredump.cx>
+
+ Tag and parameter list: guesstimating / reference compilation.
+
+ */
+
+
+#define MAXTAGS 80
+#define MAXPARS 20
+
+static char* tags[MAXTAGS][MAXPARS] = {
+ { "A", "NAME", "HREF", "REF", "REV", "TITLE", "TARGET", "SHAPE", "onLoad", "STYLE", 0 },
+ { "APPLET", "CODEBASE", "CODE", "NAME", "ALIGN", "ALT", "HEIGHT", "WIDTH", "HSPACE", "VSPACE", "DOWNLOAD", "HEIGHT", "NAME", "TITLE", "onLoad", "STYLE", 0 },
+ { "AREA", "SHAPE", "ALT", "CO-ORDS", "HREF", "onLoad", "STYLE", 0 },
+ { "B", "onLoad", "STYLE", 0 },
+ { "BANNER", "onLoad", "STYLE", 0 },
+ { "BASE", "HREF", "TARGET", "onLoad", "STYLE", 0 },
+ { "BASEFONT", "SIZE", "onLoad", "STYLE", 0 },
+ { "BGSOUND", "SRC", "LOOP", "onLoad", "STYLE", 0 },
+ { "BQ", "CLEAR", "NOWRAP", "onLoad", "STYLE", 0 },
+ { "BODY", "BACKGROUND", "BGCOLOR", "TEXT", "LINK", "ALINK", "VLINK", "LEFTMARGIN", "TOPMARGIN", "BGPROPERTIES", "onLoad", "STYLE", 0 },
+ { "CAPTION", "ALIGN", "VALIGN", "onLoad", "STYLE", 0 },
+ { "CENTER", "onLoad", "STYLE", 0 },
+ { "COL", "ALIGN", "SPAN", "onLoad", "STYLE", 0 },
+ { "COLGROUP", "ALIGN", "VALIGN", "HALIGN", "WIDTH", "SPAN", "onLoad", "STYLE", 0 },
+ { "DIV", "ALIGN", "CLASS", "LANG", "onLoad", "STYLE", 0 },
+ { "EMBED", "SRC", "HEIGHT", "WIDTH", "UNITS", "NAME", "PALETTE", "onLoad", "STYLE", 0 },
+ { "FIG", "SRC", "ALIGN", "HEIGHT", "WIDTH", "UNITS", "IMAGEMAP", "onLoad", "STYLE", 0 },
+ { "FN", "ID", "onLoad", "STYLE", 0 },
+ { "FONT", "SIZE", "COLOR", "FACE", "onLoad", "STYLE", 0 },
+ { "FORM", "ACTION", "METHOD", "ENCTYPE", "TARGET", "SCRIPT", "onLoad", "STYLE", 0 },
+ { "FRAME", "SRC", "NAME", "MARGINWIDTH", "MARGINHEIGHT", "SCROLLING", "FRAMESPACING", "onLoad", "STYLE", 0 },
+ { "FRAMESET", "ROWS", "COLS", "onLoad", "STYLE", 0 },
+ { "H1", "SRC", "DINGBAT", "onLoad", "STYLE", 0 },
+ { "HEAD", "onLoad", "STYLE", 0 },
+ { "HR", "SRC", "SIZE", "WIDTH", "ALIGN", "COLOR", "onLoad", "STYLE", 0 },
+ { "HTML", "onLoad", "STYLE", 0 },
+ { "IFRAME", "ALIGN", "FRAMEBORDER", "HEIGHT", "MARGINHEIGHT", "MARGINWIDTH", "NAME", "SCROLLING", "SRC", "ADDRESS", "WIDTH", "onLoad", "STYLE", 0 },
+ { "IMG", "ALIGN", "ALT", "SRC", "BORDER", "DYNSRC", "HEIGHT", "HSPACE", "ISMAP", "LOOP", "LOWSRC", "START", "UNITS", "USEMAP", "WIDTH", "VSPACE", "onLoad", "STYLE", 0 },
+ { "INPUT", "TYPE", "NAME", "VALUE", "onLoad", "STYLE", 0 },
+ { "ISINDEX", "HREF", "PROMPT", "onLoad", "STYLE", 0 },
+ { "LI", "SRC", "DINGBAT", "SKIP", "TYPE", "VALUE", "onLoad", "STYLE", 0 },
+ { "LINK", "REL", "REV", "HREF", "TITLE", "onLoad", "STYLE", 0 },
+ { "MAP", "NAME", "onLoad", "STYLE", 0 },
+ { "MARQUEE", "ALIGN", "BEHAVIOR", "BGCOLOR", "DIRECTION", "HEIGHT", "HSPACE", "LOOP", "SCROLLAMOUNT", "SCROLLDELAY", "WIDTH", "VSPACE", "onLoad", "STYLE", 0 },
+ { "MENU", "onLoad", "STYLE", 0 },
+ { "META", "HTTP-EQUIV", "CONTENT", "NAME", "onLoad", "STYLE", 0 },
+ { "MULTICOL", "COLS", "GUTTER", "WIDTH", "onLoad", "STYLE", 0 },
+ { "NOFRAMES", "onLoad", "STYLE", 0 },
+ { "NOTE", "CLASS", "SRC", "onLoad", "STYLE", 0 },
+ { "OVERLAY", "SRC", "X", "Y", "HEIGHT", "WIDTH", "UNITS", "IMAGEMAP", "onLoad", "STYLE", 0 },
+ { "PARAM", "NAME", "VALUE", "onLoad", "STYLE", 0 },
+ { "RANGE", "FROM", "UNTIL", "onLoad", "STYLE", 0 },
+ { "SCRIPT", "LANGUAGE", "onLoad", "STYLE", 0 },
+ { "SELECT", "NAME", "SIZE", "MULTIPLE", "WIDTH", "HEIGHT", "UNITS", "onLoad", "STYLE", 0 },
+ { "OPTION", "VALUE", "SHAPE", "onLoad", "STYLE", 0 },
+ { "SPACER", "TYPE", "SIZE", "WIDTH", "HEIGHT", "ALIGN", "onLoad", "STYLE", 0 },
+ { "SPOT", "ID", "onLoad", "STYLE", 0 },
+ { "TAB", "INDENT", "TO", "ALIGN", "DP", "onLoad", "STYLE", 0 },
+ { "TABLE", "ALIGN", "WIDTH", "BORDER", "CELLPADDING", "CELLSPACING", "BGCOLOR", "VALIGN", "COLSPEC", "UNITS", "DP", "onLoad", "STYLE", 0 },
+ { "TBODY", "CLASS", "ID", "onLoad", "STYLE", 0 },
+ { "TD", "COLSPAN", "ROWSPAN", "ALIGN", "VALIGN", "BGCOLOR", "onLoad", "STYLE", 0 },
+ { "TEXTAREA", "NAME", "COLS", "ROWS", "onLoad", "STYLE", 0 },
+ { "TEXTFLOW", "CLASS", "ID", "onLoad", "STYLE", 0 },
+ { "TFOOT", "COLSPAN", "ROWSPAN", "ALIGN", "VALIGN", "BGCOLOR", "onLoad", "STYLE", 0 },
+ { "TH", "ALIGN", "CLASS", "ID", "onLoad", "STYLE", 0 },
+ { "TITLE", "onLoad", "STYLE", 0 },
+ { "TR", "ALIGN", "VALIGN", "BGCOLOR", "CLASS", "onLoad", "STYLE", 0 },
+ { "UL", "SRC", "DINGBAT", "WRAP", "TYPE", "PLAIN", "onLoad", "STYLE", 0 },
+ { 0 }
+};
+
diff --git a/Tools/record-memory-win/main.cpp b/Tools/record-memory-win/main.cpp
new file mode 100644
index 0000000..934f101
--- /dev/null
+++ b/Tools/record-memory-win/main.cpp
@@ -0,0 +1,213 @@
+#include <windows.h>
+#include <assert.h>
+#include <psapi.h>
+#include <stdio.h>
+#include <tchar.h>
+#include <time.h>
+#include <tlhelp32.h>
+#include "Shlwapi.h"
+
+#pragma comment(lib, "psapi.lib")
+#pragma comment(lib, "shlwapi.lib")
+
+int gQueryInterval = 5; // seconds
+time_t gDuration = 0; // seconds
+LPTSTR gCommandLine;
+
+HRESULT ProcessArgs(int argc, TCHAR *argv[]);
+HRESULT PrintUsage();
+void UseImage(void (functionForQueryType(HANDLE)));
+void QueryContinuously(HANDLE hProcess);
+int EvalProcesses(HANDLE hProcess);
+time_t ElapsedTime(time_t startTime);
+
+int __cdecl _tmain (int argc, TCHAR *argv[])
+{
+ HRESULT result = ProcessArgs(argc, argv);
+ if (FAILED(result))
+ return result;
+
+ UseImage(QueryContinuously);
+ return S_OK;
+}
+
+HRESULT ProcessArgs(int argc, TCHAR *argv[])
+{
+ LPTSTR argument;
+ for( int count = 1; count < argc; count++ ) {
+ argument = argv[count] ;
+ if (wcsstr(argument, _T("-h")) || wcsstr(argument, _T("--help")))
+ return PrintUsage();
+ else if (wcsstr(argument, _T("--exe"))) {
+ gCommandLine = argv[++count];
+ } else if (wcsstr(argument, _T("-i")) ||
+ wcsstr(argument, _T("--interval"))) {
+ gQueryInterval = _wtoi(argv[++count]);
+ if (gQueryInterval < 1) {
+ printf("ERROR: invalid interval\n");
+ return E_INVALIDARG;
+ }
+ } else if (wcsstr(argument, _T("-d")) ||
+ wcsstr(argument, _T("--duration"))) {
+ gDuration = _wtoi(argv[++count]);
+ if (gDuration < 1) {
+ printf("ERROR: invalid duration\n");
+ return E_INVALIDARG;
+ }
+ } else {
+ _tprintf(_T("ERROR: unrecognized argument \"%s\"\n"), (LPCTSTR)argument);
+ return PrintUsage();
+ }
+ }
+ if (argc < 2 || !wcslen(gCommandLine) ) {
+ printf("ERROR: executable path is required\n");
+ return PrintUsage();
+ }
+ return S_OK;
+}
+
+HRESULT PrintUsage()
+{
+ printf("record-memory-win --exe EXE_PATH\n");
+ printf(" Launch an executable and print the memory usage (in Private Bytes)\n");
+ printf(" of the process.\n\n");
+ printf("Usage:\n");
+ printf("-h [--help] : Print usage\n");
+ printf("--exe arg : Launch specified image. Required\n");
+ printf("-i [--interval] arg : Print memory usage every arg seconds. Default: 5 seconds\n");
+ printf("-d [--duration] arg : Run for up to arg seconds. Default: no limit\n\n");
+ printf("Examples:\n");
+ printf(" record-memory-win --exe \"C:\\Program Files\\Safari\\Safari.exe /newprocess\"\n");
+ printf(" record-memory-win --exe \"Safari.exe /newprocess\" -i 10 -d 7200\n");
+ printf(" NOTE: Close all other browser intances to ensure launching in a new process\n");
+ printf(" Or, pass the /newprocess (or equivalent) argument to the browser\n");
+ return E_FAIL;
+}
+
+unsigned int getMemoryInfo(DWORD processID)
+{
+ unsigned int memInfo = 0;
+ HANDLE hProcess;
+ PROCESS_MEMORY_COUNTERS_EX pmc;
+
+ hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
+ PROCESS_VM_READ,
+ FALSE, processID );
+ if (NULL == hProcess)
+ return 0;
+
+ if (GetProcessMemoryInfo( hProcess, (PPROCESS_MEMORY_COUNTERS)&pmc, sizeof(pmc))) {
+ memInfo = (pmc.PrivateUsage);
+ }
+
+ CloseHandle( hProcess );
+ return memInfo;
+}
+
+void printProcessInfo(DWORD processID)
+{
+ TCHAR szProcessName[MAX_PATH] = TEXT("<unknown>");
+
+ // Get a handle to the process.
+ HANDLE hProcess = OpenProcess( PROCESS_QUERY_INFORMATION |
+ PROCESS_VM_READ,
+ FALSE, processID );
+
+ // Get the process name.
+ if (NULL != hProcess) {
+ HMODULE hMod; // An array that receives the list of module handles.
+ DWORD cbNeeded; //The number of bytes required to store all module handles in the Module array
+
+ if (EnumProcessModules(hProcess, &hMod, sizeof(hMod), &cbNeeded)) {
+ GetModuleBaseName(hProcess, hMod, szProcessName,
+ sizeof(szProcessName)/sizeof(TCHAR));
+ }
+ }
+
+ // Print the process name and identifier of matching strings, ignoring case
+ _tprintf(TEXT("%s (PID: %u)\n"), szProcessName, processID);
+
+ // Release the handle to the process.
+ CloseHandle( hProcess );
+}
+
+int evalProcesses(HANDLE hProcess)
+{
+ if (NULL == hProcess)
+ return 0;
+
+ unsigned int totalMemUsage = 0;
+ DWORD processID = GetProcessId(hProcess);
+
+ HANDLE hProcessSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+
+ PROCESSENTRY32 processEntry = { 0 };
+ processEntry.dwSize = sizeof(PROCESSENTRY32);
+
+ // Retrieves information about the first process encountered in a system snapshot
+ if(Process32First(hProcessSnapshot, &processEntry)) {
+ do {
+ // if th32processID = processID, we are the parent process!
+ // if th32ParentProcessID = processID, we are a child process!
+ if ((processEntry.th32ProcessID == processID) || (processEntry.th32ParentProcessID == processID)) {
+ unsigned int procMemUsage = 0;
+ // Record parent process memory
+ procMemUsage = getMemoryInfo(processEntry.th32ProcessID);
+ totalMemUsage += procMemUsage;
+ }
+ // Retrieves information about the next process recorded in a system snapshot.
+ } while(Process32Next(hProcessSnapshot, &processEntry));
+ }
+
+ CloseHandle(hProcessSnapshot);
+ return totalMemUsage;
+}
+
+
+void UseImage(void (functionForQueryType(HANDLE)))
+{
+ STARTUPINFO si = {0};
+ si.cb = sizeof(STARTUPINFO);
+ PROCESS_INFORMATION pi = {0};
+
+ // Start the child process.
+ if(!CreateProcess( NULL, // No module name (use command line)
+ gCommandLine, // Command line
+ NULL, // Process handle not inheritable
+ NULL, // Thread handle not inheritable
+ FALSE, // Set handle inheritance to FALSE
+ 0, // No creation flags
+ NULL, // Use parent's environment block
+ NULL, // Use parent's starting directory
+ &si, // Pointer to STARTUPINFO structure
+ &pi )) // Pointer to PROCESS_INFORMATION structure
+ printf("CreateProcess failed (%d)\n", GetLastError());
+ else {
+ printf("Created process with id: %d\n", pi.dwProcessId);
+ functionForQueryType(pi.hProcess);
+ // Close process and thread handles.
+ CloseHandle( pi.hProcess );
+ CloseHandle( pi.hThread );
+ }
+}
+
+void QueryContinuously(HANDLE hProcess)
+{
+ Sleep(2000); // give the process some time to launch
+ bool pastDuration = false;
+ time_t startTime = time(NULL);
+ unsigned int memUsage = evalProcesses(hProcess);
+ while(memUsage && !pastDuration) {
+ printf( "%u\n", memUsage );
+ Sleep(gQueryInterval*1000);
+ memUsage = evalProcesses(hProcess);
+ pastDuration = gDuration > 0 ? ElapsedTime(startTime) > gDuration : false;
+ }
+}
+
+// returns elapsed time in seconds
+time_t ElapsedTime(time_t startTime)
+{
+ time_t currentTime = time(NULL);
+ return currentTime - startTime;
+}
diff --git a/Tools/record-memory-win/record-memory-win-common.vsprops b/Tools/record-memory-win/record-memory-win-common.vsprops
new file mode 100644
index 0000000..ff23857
--- /dev/null
+++ b/Tools/record-memory-win/record-memory-win-common.vsprops
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="record-memory-win-common"
+ >
+ <Tool
+ Name="VCLinkerTool"
+ SubSystem="1"
+ />
+</VisualStudioPropertySheet>
diff --git a/Tools/record-memory-win/record-memory-win.vcproj b/Tools/record-memory-win/record-memory-win.vcproj
new file mode 100644
index 0000000..4fd6b53
--- /dev/null
+++ b/Tools/record-memory-win/record-memory-win.vcproj
@@ -0,0 +1,414 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="record-memory-win"
+ ProjectGUID="{44B9C152-1870-4035-B94D-7B3285AA0C12}"
+ RootNamespace="recordmemorywin"
+ Keyword="Win32Proj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="Release|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\record-memory-win-common.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_LTCG|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;.\record-memory-win-common.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="Debug|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;.\record-memory-win-common.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug_all.vsprops;.\record-memory-win-common.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="1"
+ InheritedPropertySheets="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\release.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\WinCairo.vsprops;.\record-memory-win-common.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="$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\common.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug.vsprops;$(WebKitVSPropsRedirectionDir)..\..\WebKitLibraries\win\tools\vsprops\debug_wincairo.vsprops;.\record-memory-win-common.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="Source Files"
+ Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}"
+ >
+ <File
+ RelativePath=".\main.cpp"
+ >
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}"
+ >
+ </Filter>
+ <Filter
+ Name="Resource Files"
+ Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav"
+ UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}"
+ >
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/Tools/vcbin/cl.exe b/Tools/vcbin/cl.exe
new file mode 100755
index 0000000..2ec78c9
--- /dev/null
+++ b/Tools/vcbin/cl.exe
Binary files differ
diff --git a/Tools/vcbin/midl.exe b/Tools/vcbin/midl.exe
new file mode 100755
index 0000000..55ecd1d
--- /dev/null
+++ b/Tools/vcbin/midl.exe
Binary files differ
diff --git a/Tools/wx/browser/browser.cpp b/Tools/wx/browser/browser.cpp
new file mode 100644
index 0000000..95c39d4
--- /dev/null
+++ b/Tools/wx/browser/browser.cpp
@@ -0,0 +1,70 @@
+/*
+ * Copyright (C) 2007 Kevin Ollivier <kevino@theolliviers.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 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.
+ */
+
+// webkit includes
+#include "WebBrowserShell.h"
+#include "WebSettings.h"
+#include "WebView.h"
+
+#include "wx/wxprec.h"
+#ifndef WX_PRECOMP
+ #include "wx/wx.h"
+#endif
+
+class MyApp : public wxApp
+{
+public:
+
+ virtual bool OnInit();
+};
+
+
+IMPLEMENT_APP(MyApp)
+
+bool MyApp::OnInit()
+{
+ wxInitAllImageHandlers();
+
+ // create the main application window
+ // see WebKit/wx/WebFrame.cpp for how to write a shell around wxWebView.
+ wxWebBrowserShell *frame = new wxWebBrowserShell(_T("wxWebKit Test App"));
+
+#ifndef NDEBUG
+ frame->ShowDebugMenu(true);
+#endif
+
+ wxWebSettings settings = frame->webview->GetWebSettings();
+#if __WXMSW__ || __WXMAC__
+ settings.SetPluginsEnabled(true);
+#endif
+ frame->webview->SetDatabasesEnabled(true);
+ settings.SetEditableLinkBehavior(wxEditableLinkOnlyLiveWithShiftKey);
+ frame->CentreOnScreen();
+ frame->Show(true);
+
+ return true;
+}
diff --git a/Tools/wx/browser/wscript b/Tools/wx/browser/wscript
new file mode 100644
index 0000000..8c22cf6
--- /dev/null
+++ b/Tools/wx/browser/wscript
@@ -0,0 +1,55 @@
+#! /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(wk_root, 'WebCore', 'bindings', 'wx'),
+ os.path.join(wk_root, 'WebKit', 'wx')]
+
+def set_options(opt):
+ common_set_options(opt)
+
+def configure(conf):
+ common_configure(conf)
+
+def build(bld):
+ import Options
+
+ obj = bld.new_task_gen(
+ features = 'cxx cprogram',
+ includes = ' '.join(include_paths),
+ source = 'browser.cpp',
+ target = 'wxBrowser',
+ uselib = 'WX CURL ICU XSLT XML ' + get_config(),
+ libpath = [output_dir],
+ uselib_local = 'wxwebkit',
+ install_path = output_dir)
+
+ if sys.platform.startswith('darwin'):
+ obj.mac_app = True
diff --git a/Tools/wx/build/build_utils.py b/Tools/wx/build/build_utils.py
new file mode 100644
index 0000000..bf440a6
--- /dev/null
+++ b/Tools/wx/build/build_utils.py
@@ -0,0 +1,188 @@
+# 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.
+#
+# Helper functions for the WebKit build.
+
+import commands
+import glob
+import os
+import platform
+import re
+import shutil
+import sys
+import urllib
+import urlparse
+
+def get_output(command):
+ """
+ Windows-compatible function for getting output from a command.
+ """
+ if sys.platform.startswith('win'):
+ f = os.popen(command)
+ return f.read().strip()
+ else:
+ return commands.getoutput(command)
+
+def get_excludes(root, patterns):
+ """
+ Get a list of exclude patterns going down several dirs.
+ TODO: Make this fully recursive.
+ """
+ excludes = []
+
+ for pattern in patterns:
+ subdir_pattern = os.sep + '*'
+ for subdir in [subdir_pattern, subdir_pattern*2, subdir_pattern*3]:
+ adir = root + subdir + os.sep + pattern
+ files = glob.glob(adir)
+ for afile in files:
+ excludes.append(os.path.basename(afile))
+
+ return excludes
+
+def get_dirs_for_features(root, features, dirs):
+ """
+ Find which directories to include in the list of build dirs based upon the
+ enabled port(s) and features.
+ """
+ outdirs = dirs
+ for adir in dirs:
+ for feature in features:
+ relpath = os.path.join(adir, feature)
+ featuredir = os.path.join(root, relpath)
+ if os.path.exists(featuredir) and not relpath in outdirs:
+ outdirs.append(relpath)
+
+ return outdirs
+
+def download_if_newer(url, destdir):
+ """
+ Checks if the file on the server is newer than the one in the user's tree,
+ and if so, downloads it.
+
+ Returns the filename of the downloaded file if downloaded, or None if
+ the existing file matches the one on the server.
+ """
+ obj = urlparse.urlparse(url)
+ filename = os.path.basename(obj.path)
+ destfile = os.path.join(destdir, filename)
+
+ urlobj = urllib.urlopen(url)
+ size = long(urlobj.info().getheader('Content-Length'))
+
+ def download_callback(downloaded, block_size, total_size):
+ downloaded = block_size * downloaded
+ if downloaded > total_size:
+ downloaded = total_size
+ sys.stdout.write('%s %d of %d bytes downloaded\r' % (filename, downloaded, total_size))
+
+ # NB: We don't check modified time as Python doesn't yet handle timezone conversion
+ # properly when converting strings to time objects.
+ if not os.path.exists(destfile) or os.path.getsize(destfile) != size:
+ urllib.urlretrieve(url, destfile, download_callback)
+ print ''
+ return destfile
+
+ return None
+
+def update_wx_deps(conf, wk_root, msvc_version='msvc2008'):
+ """
+ Download and update tools needed to build the wx port.
+ """
+ import Logs
+ Logs.info('Ensuring wxWebKit dependencies are up-to-date.')
+
+ wklibs_dir = os.path.join(wk_root, 'WebKitLibraries')
+ waf = download_if_newer('http://wxwebkit.wxcommunity.com/downloads/deps/waf', os.path.join(wk_root, 'Tools', 'wx'))
+ if waf:
+ # TODO: Make the build restart itself after an update.
+ Logs.warn('Build system updated, please restart build.')
+ sys.exit(1)
+
+ # since this module is still experimental
+ wxpy_dir = os.path.join(wk_root, 'WebKit', 'wx', 'bindings', 'python')
+ swig_module = download_if_newer('http://wxwebkit.wxcommunity.com/downloads/deps/swig.py.txt', wxpy_dir)
+ if swig_module:
+ shutil.copy(os.path.join(wxpy_dir, 'swig.py.txt'), os.path.join(wxpy_dir, 'swig.py'))
+
+ if sys.platform.startswith('win'):
+ Logs.info('downloading deps package')
+ archive = download_if_newer('http://wxwebkit.wxcommunity.com/downloads/deps/wxWebKitDeps-%s.zip' % msvc_version, wklibs_dir)
+ if archive and os.path.exists(archive):
+ os.system('unzip -o %s -d %s' % (archive, os.path.join(wklibs_dir, msvc_version)))
+
+ elif sys.platform.startswith('darwin'):
+ # export the right compiler for building the dependencies
+ if platform.release().startswith('10'): # Snow Leopard
+ os.environ['CC'] = conf.env['CC'][0]
+ os.environ['CXX'] = conf.env['CXX'][0]
+ os.system('%s/Tools/wx/install-unix-extras' % wk_root)
+
+def includeDirsForSources(sources):
+ include_dirs = []
+ for group in sources:
+ for source in group:
+ dirname = os.path.dirname(source)
+ if not dirname in include_dirs:
+ include_dirs.append(dirname)
+
+ return include_dirs
+
+def flattenSources(sources):
+ flat_sources = []
+ for group in sources:
+ flat_sources.extend(group)
+
+ return flat_sources
+
+def git_branch_name():
+ try:
+ branches = commands.getoutput("git branch --no-color")
+ match = re.search('^\* (.*)', branches, re.MULTILINE)
+ if match:
+ return ".%s" % match.group(1)
+ except:
+ pass
+
+ return ""
+
+def get_config(wk_root):
+ config_file = os.path.join(wk_root, 'WebKitBuild', 'Configuration')
+ config = 'Debug'
+
+ if os.path.exists(config_file):
+ config = open(config_file).read()
+
+ return config
+
+def svn_revision():
+ if os.system("git-svn info") == 0:
+ info = commands.getoutput("git-svn info ../..")
+ else:
+ info = commands.getoutput("svn info")
+
+ for line in info.split("\n"):
+ if line.startswith("Revision: "):
+ return line.replace("Revision: ", "").strip()
+
+ return ""
diff --git a/Tools/wx/build/settings.py b/Tools/wx/build/settings.py
new file mode 100644
index 0000000..03c0880
--- /dev/null
+++ b/Tools/wx/build/settings.py
@@ -0,0 +1,407 @@
+# 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.
+#
+# Common elements of the waf build system shared by all projects.
+
+import commands
+import os
+import platform
+import re
+import sys
+
+import Options
+
+from build_utils import *
+from waf_extensions import *
+
+# to be moved to wx when it supports more configs
+from wxpresets import *
+
+wk_root = os.path.abspath(os.path.join(os.path.dirname(__file__), '../../..'))
+
+if sys.platform.startswith('win'):
+ if not 'WXWIN' in os.environ:
+ print "Please set WXWIN to the directory containing wxWidgets."
+ sys.exit(1)
+
+ wx_root = os.environ['WXWIN']
+else:
+ wx_root = commands.getoutput('wx-config --prefix')
+
+jscore_dir = os.path.join(wk_root, 'JavaScriptCore')
+webcore_dir = os.path.join(wk_root, 'WebCore')
+wklibs_dir = os.path.join(wk_root, 'WebKitLibraries')
+
+common_defines = []
+common_cxxflags = []
+common_includes = []
+common_libs = []
+common_libpaths = []
+common_frameworks = []
+
+ports = [
+ 'Brew',
+ 'Chromium',
+ 'Gtk',
+ 'Haiku',
+ 'Mac',
+ 'None',
+ 'Qt',
+ 'Safari',
+ 'Win',
+ 'Wince',
+ 'wx',
+]
+
+port_uses = {
+ 'wx': ['CURL', 'WXGC'],
+}
+
+jscore_dirs = [
+ 'API',
+ 'bytecode',
+ 'bytecompiler',
+ 'debugger',
+ 'DerivedSources',
+ 'interpreter',
+ 'jit',
+ 'parser',
+ 'pcre',
+ 'profiler',
+ 'runtime',
+ 'wtf',
+ 'wtf/text',
+ 'wtf/unicode',
+ 'wtf/unicode/icu',
+ 'yarr',
+]
+
+webcore_dirs = [
+ 'WebCore/accessibility',
+ 'WebCore/bindings',
+ 'WebCore/bindings/cpp',
+ 'WebCore/bindings/generic',
+ 'WebCore/bindings/js',
+ 'WebCore/bindings/js/specialization',
+ 'WebCore/bridge',
+ 'WebCore/bridge/c',
+ 'WebCore/bridge/jsc',
+ 'WebCore/css',
+ 'WebCore/DerivedSources',
+ 'WebCore/dom',
+ 'WebCore/dom/default',
+ 'WebCore/editing',
+ 'WebCore/fileapi',
+ 'WebCore/history',
+ 'WebCore/html',
+ 'WebCore/html/canvas',
+ 'WebCore/html/parser',
+ 'WebCore/inspector',
+ 'WebCore/loader',
+ 'WebCore/loader/appcache',
+ 'WebCore/loader/archive',
+ 'WebCore/loader/cache',
+ 'WebCore/loader/icon',
+ 'WebCore/notifications',
+ 'WebCore/page',
+ 'WebCore/page/animation',
+ 'WebCore/platform',
+ 'WebCore/platform/animation',
+ 'WebCore/platform/graphics',
+ 'WebCore/platform/graphics/filters',
+ 'WebCore/platform/graphics/transforms',
+ 'WebCore/platform/image-decoders',
+ 'WebCore/platform/image-decoders/bmp',
+ 'WebCore/platform/image-decoders/gif',
+ 'WebCore/platform/image-decoders/ico',
+ 'WebCore/platform/image-decoders/jpeg',
+ 'WebCore/platform/image-decoders/png',
+ 'WebCore/platform/image-decoders/webp',
+ 'WebCore/platform/mock',
+ 'WebCore/platform/network',
+ 'WebCore/platform/sql',
+ 'WebCore/platform/text',
+ 'WebCore/platform/text/transcoder',
+ 'WebCore/plugins',
+ 'WebCore/rendering',
+ 'WebCore/rendering/style',
+ 'WebCore/rendering/svg',
+ 'WebCore/storage',
+ 'WebCore/svg',
+ 'WebCore/svg/animation',
+ 'WebCore/svg/graphics',
+ 'WebCore/svg/graphics/filters',
+ 'WebCore/svg/properties',
+ 'WebCore/websockets',
+ 'WebCore/xml'
+]
+
+config = get_config(wk_root)
+config_dir = config + git_branch_name()
+
+output_dir = os.path.join(wk_root, 'WebKitBuild', config_dir)
+
+build_port = "wx"
+building_on_win32 = sys.platform.startswith('win')
+
+def get_config():
+ waf_configname = config.upper().strip()
+ if building_on_win32:
+ isReleaseCRT = (config == 'Release')
+ if build_port == 'wx':
+ if Options.options.wxpython:
+ isReleaseCRT = True
+
+ if isReleaseCRT:
+ waf_configname = waf_configname + ' CRT_MULTITHREADED_DLL'
+ else:
+ waf_configname = waf_configname + ' CRT_MULTITHREADED_DLL_DBG'
+
+ return waf_configname
+
+create_hash_table = wk_root + "/JavaScriptCore/create_hash_table"
+if building_on_win32:
+ create_hash_table = get_output('cygpath --unix "%s"' % create_hash_table)
+os.environ['CREATE_HASH_TABLE'] = create_hash_table
+
+feature_defines = ['ENABLE_DATABASE', 'ENABLE_XSLT', 'ENABLE_JAVASCRIPT_DEBUGGER',
+ 'ENABLE_SVG', 'ENABLE_SVG_USE', 'ENABLE_FILTERS', 'ENABLE_SVG_FONTS',
+ 'ENABLE_SVG_ANIMATION', 'ENABLE_SVG_AS_IMAGE', 'ENABLE_SVG_FOREIGN_OBJECT',
+ 'ENABLE_JIT', 'BUILDING_%s' % build_port.upper()]
+
+msvc_version = 'msvc2008'
+
+msvclibs_dir = os.path.join(wklibs_dir, msvc_version, 'win')
+
+def get_path_to_wxconfig():
+ if 'WX_CONFIG' in os.environ:
+ return os.environ['WX_CONFIG']
+ else:
+ return 'wx-config'
+
+def common_set_options(opt):
+ """
+ Initialize common options provided to the user.
+ """
+ opt.tool_options('compiler_cxx')
+ opt.tool_options('compiler_cc')
+ opt.tool_options('python')
+
+ opt.add_option('--wxpython', action='store_true', default=False, help='Create the wxPython bindings.')
+ opt.add_option('--wx-compiler-prefix', action='store', default='vc',
+ help='Specify a different compiler prefix (do this if you used COMPILER_PREFIX when building wx itself)')
+ opt.add_option('--macosx-version', action='store', default='', help="Version of OS X to build for.")
+ opt.add_option('--msvc-version', action='store', default='', help="MSVC version to use to build. Use 8 for 2005, 9 for 2008")
+
+def common_configure(conf):
+ """
+ Configuration used by all targets, called from the target's configure() step.
+ """
+
+ conf.env['MSVC_TARGETS'] = ['x86']
+
+ if Options.options.msvc_version and Options.options.msvc_version != '':
+ print "msvc version = %s" % Options.options.msvc_version
+ conf.env['MSVC_VERSIONS'] = ['msvc %s.0' % Options.options.msvc_version]
+ else:
+ print "msvc not set!"
+ conf.env['MSVC_VERSIONS'] = ['msvc 9.0', 'msvc 8.0']
+
+ if sys.platform.startswith('cygwin'):
+ print "ERROR: You must use the Win32 Python from python.org, not Cygwin Python, when building on Windows."
+ sys.exit(1)
+
+ if sys.platform.startswith('darwin') and build_port == 'wx':
+ import platform
+ if platform.release().startswith('10'): # Snow Leopard
+ # wx currently only supports 32-bit compilation, so we want gcc-4.0 instead of 4.2 on Snow Leopard
+ # unless the user has explicitly set a different compiler.
+ if not "CC" in os.environ:
+ conf.env['CC'] = 'gcc-4.0'
+ if not "CXX" in os.environ:
+ conf.env['CXX'] = 'g++-4.0'
+ conf.check_tool('compiler_cxx')
+ conf.check_tool('compiler_cc')
+ if Options.options.wxpython:
+ conf.check_tool('python')
+ conf.check_python_headers()
+
+ if sys.platform.startswith('darwin'):
+ conf.check_tool('osx')
+
+ global msvc_version
+ global msvclibs_dir
+
+ libprefix = ''
+
+ if building_on_win32:
+ libprefix = 'lib'
+
+ found = conf.get_msvc_versions()
+ found_versions = []
+ for version in found:
+ found_versions.append(version[0])
+
+ if 'msvc 9.0' in conf.env['MSVC_VERSIONS'] and 'msvc 9.0' in found_versions:
+ msvc_version = 'msvc2008'
+ elif 'msvc 8.0' in conf.env['MSVC_VERSIONS'] and 'msvc 8.0' in found_versions:
+ msvc_version = 'msvc2005'
+
+ msvclibs_dir = os.path.join(wklibs_dir, msvc_version, 'win')
+
+ # Disable several warnings which occur many times during the build.
+ # Some of them are harmless (4099, 4344, 4396, 4800) and working around
+ # them in WebKit code is probably just not worth it. We can simply do
+ # nothing about the others (4503). A couple are possibly valid but
+ # there are just too many of them in the code so fixing them is
+ # impossible in practice and just results in tons of distracting output
+ # (4244, 4291). Finally 4996 is actively harmful as it is given for
+ # just about any use of standard C/C++ library facilities.
+ conf.env.append_value('CXXFLAGS', [
+ '/wd4099', # type name first seen using 'struct' now seen using 'class'
+ '/wd4244', # conversion from 'xxx' to 'yyy', possible loss of data:
+ '/wd4291', # no matching operator delete found (for placement new)
+ '/wd4344', # behaviour change in template deduction
+ '/wd4396', # inline can't be used in friend declaration
+ '/wd4503', # decorated name length exceeded, name was truncated
+ '/wd4800', # forcing value to bool 'true' or 'false'
+ '/wd4996', # deprecated function
+ ])
+
+ # This one also occurs in C code, so disable it there as well.
+ conf.env.append_value('CCFLAGS', ['/wd4996'])
+
+ if build_port == "wx":
+ update_wx_deps(conf, wk_root, msvc_version)
+
+ conf.env.append_value('CXXDEFINES', ['BUILDING_WX__=1', 'JS_NO_EXPORT'])
+
+ if building_on_win32:
+ conf.env.append_value('LIBPATH', os.path.join(msvclibs_dir, 'lib'))
+ # wx settings
+ global config
+ is_debug = (config == 'Debug')
+ wxdefines, wxincludes, wxlibs, wxlibpaths = get_wxmsw_settings(wx_root, shared=True, unicode=True, debug=is_debug, wxPython=Options.options.wxpython)
+ conf.env['CXXDEFINES_WX'] = wxdefines
+ conf.env['CPPPATH_WX'] = wxincludes
+ conf.env['LIB_WX'] = wxlibs
+ conf.env['LIBPATH_WX'] = wxlibpaths
+
+ if sys.platform.startswith('darwin'):
+ conf.env['LIB_ICU'] = ['icucore']
+
+ conf.env.append_value('CPPPATH', wklibs_dir)
+ conf.env.append_value('LIBPATH', wklibs_dir)
+
+ min_version = None
+
+ mac_target = 'MACOSX_DEPLOYMENT_TARGET'
+ if Options.options.macosx_version != '':
+ min_version = Options.options.macosx_version
+
+ # WebKit only supports 10.4+, but ppc systems often set this to earlier systems
+ if not min_version:
+ min_version = commands.getoutput('sw_vers -productVersion')[:4]
+ if min_version in ['10.1','10.2','10.3']:
+ min_version = '10.4'
+
+ os.environ[mac_target] = conf.env[mac_target] = min_version
+
+ sdk_version = min_version
+ if min_version == "10.4":
+ sdk_version += "u"
+ conf.env.append_value('LIB_WKINTERFACE', ['WebKitSystemInterfaceTiger'])
+ else:
+ # NOTE: There is a WebKitSystemInterfaceSnowLeopard, but when we use that
+ # on 10.6, we get a strange missing symbol error, and this library seems to
+ # work fine for wx's purposes.
+ conf.env.append_value('LIB_WKINTERFACE', ['WebKitSystemInterfaceLeopard'])
+
+ sdkroot = '/Developer/SDKs/MacOSX%s.sdk' % sdk_version
+ sdkflags = ['-arch', 'i386', '-isysroot', sdkroot]
+
+ conf.env.append_value('CPPFLAGS', sdkflags)
+ conf.env.append_value('LINKFLAGS', sdkflags)
+
+ conf.env.append_value('CPPPATH_SQLITE3', [os.path.join(wklibs_dir, 'WebCoreSQLite3')])
+ conf.env.append_value('LIB_SQLITE3', ['WebCoreSQLite3'])
+
+ conf.env.append_value('CXXDEFINES', feature_defines)
+ if config == 'Release':
+ conf.env.append_value('CPPDEFINES', 'NDEBUG')
+
+ if building_on_win32:
+ conf.env.append_value('CPPPATH', [
+ os.path.join(jscore_dir, 'os-win32'),
+ os.path.join(msvclibs_dir, 'include'),
+ os.path.join(msvclibs_dir, 'include', 'pthreads'),
+ os.path.join(msvclibs_dir, 'lib'),
+ ])
+
+ conf.env.append_value('LIB', ['libpng', 'libjpeg', 'pthreadVC2'])
+ # common win libs
+ conf.env.append_value('LIB', [
+ 'kernel32', 'user32','gdi32','comdlg32','winspool','winmm',
+ 'shell32', 'shlwapi', 'comctl32', 'ole32', 'oleaut32', 'uuid', 'advapi32',
+ 'wsock32', 'gdiplus', 'usp10','version'])
+
+ conf.env['LIB_ICU'] = ['icudt', 'icule', 'iculx', 'icuuc', 'icuin', 'icuio', 'icutu']
+
+ #curl
+ conf.env['LIB_CURL'] = ['libcurl']
+
+ #sqlite3
+ conf.env['CPPPATH_SQLITE3'] = [os.path.join(msvclibs_dir, 'include', 'SQLite')]
+ conf.env['LIB_SQLITE3'] = ['sqlite3']
+
+ #libxml2
+ conf.env['LIB_XML'] = ['libxml2']
+
+ #libxslt
+ conf.env['LIB_XSLT'] = ['libxslt']
+ else:
+ if build_port == 'wx':
+ port_uses['wx'].append('PTHREADS')
+ conf.env.append_value('LIB', ['jpeg', 'png', 'pthread'])
+ conf.env.append_value('LIBPATH', os.path.join(wklibs_dir, 'unix', 'lib'))
+ conf.env.append_value('CPPPATH', os.path.join(wklibs_dir, 'unix', 'include'))
+ conf.env.append_value('CXXFLAGS', ['-fPIC', '-DPIC'])
+
+ conf.check_cfg(path=get_path_to_wxconfig(), args='--cxxflags --libs', package='', uselib_store='WX', mandatory=True)
+
+ conf.check_cfg(msg='Checking for libxslt', path='xslt-config', args='--cflags --libs', package='', uselib_store='XSLT', mandatory=True)
+ conf.check_cfg(path='xml2-config', args='--cflags --libs', package='', uselib_store='XML', mandatory=True)
+ if sys.platform.startswith('darwin') and min_version and min_version == '10.4':
+ conf.check_cfg(path=os.path.join(wklibs_dir, 'unix', 'bin', 'curl-config'), args='--cflags --libs', package='', uselib_store='CURL', mandatory=True)
+ else:
+ conf.check_cfg(path='curl-config', args='--cflags --libs', package='', uselib_store='CURL', mandatory=True)
+
+ if not sys.platform.startswith('darwin'):
+ conf.check_cfg(package='cairo', args='--cflags --libs', uselib_store='WX', mandatory=True)
+ conf.check_cfg(package='pango', args='--cflags --libs', uselib_store='WX', mandatory=True)
+ conf.check_cfg(package='gtk+-2.0', args='--cflags --libs', uselib_store='WX', mandatory=True)
+ conf.check_cfg(package='sqlite3', args='--cflags --libs', uselib_store='SQLITE3', mandatory=True)
+ conf.check_cfg(path='icu-config', args='--cflags --ldflags', package='', uselib_store='ICU', mandatory=True)
+
+ for use in port_uses[build_port]:
+ conf.env.append_value('CXXDEFINES', ['WTF_USE_%s' % use])
diff --git a/Tools/wx/build/waf_extensions.py b/Tools/wx/build/waf_extensions.py
new file mode 100644
index 0000000..f50f264
--- /dev/null
+++ b/Tools/wx/build/waf_extensions.py
@@ -0,0 +1,83 @@
+# 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.
+#
+# This module is for code where we override waf's default behavior or extend waf
+
+import os
+import subprocess
+import sys
+
+import Utils
+
+# version of exec_command that handles Windows command lines longer than 32000 chars
+def exec_command(s, **kw):
+ filename = ''
+ if sys.platform.startswith('win') and len(' '.join(s)) > 32000:
+ import tempfile
+ (fd, filename) = tempfile.mkstemp()
+ t = []
+ for i in s:
+ if i.find(" ") != -1:
+ i = '"%s"' % i
+ t.append(i)
+ os.write(fd, ' '.join(t[1:]))
+ os.close(fd)
+
+ s = [s[0], '@' + filename]
+
+ if 'log' in kw:
+ kw['stdout'] = kw['stderr'] = kw['log']
+ del(kw['log'])
+ kw['shell'] = isinstance(s, str)
+
+ def cleanup():
+ try:
+ if os.path.exists(filename):
+ os.remove(filename)
+ except:
+ pass
+
+ try:
+ proc = subprocess.Popen(s, **kw)
+ result = proc.wait()
+ cleanup()
+ return result
+
+ except OSError:
+ cleanup()
+ raise
+
+Utils.exec_command = exec_command
+
+# Better performing h_file to keep hashing from consuming lots of time
+import stat
+def h_file(filename):
+ st = os.stat(filename)
+ if stat.S_ISDIR(st[stat.ST_MODE]): raise IOError('not a file')
+ m = Utils.md5()
+ m.update(str(st.st_mtime))
+ m.update(str(st.st_size))
+ m.update(filename)
+ return m.digest()
+
+Utils.h_file = h_file
diff --git a/Tools/wx/build/wxpresets.py b/Tools/wx/build/wxpresets.py
new file mode 100644
index 0000000..3d6b693
--- /dev/null
+++ b/Tools/wx/build/wxpresets.py
@@ -0,0 +1,120 @@
+# 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.
+#
+# Library for functions to determine wx settings based on configuration
+
+import os
+import re
+
+import Options
+
+def parse_build_cfg(filename):
+ cfg_file = open(filename, 'r')
+ cfg = {}
+ for cfg_line in cfg_file.readlines():
+ key = None
+ value = None
+ parts = cfg_line.split('=')
+ if len(parts) >= 1:
+ key = parts[0].strip()
+
+ if len(parts) >= 2:
+ value = parts[1].strip()
+ if value.isdigit():
+ value = int(value)
+
+ if key:
+ cfg[key] = value
+
+ return cfg
+
+def get_wx_version(wx_root):
+ versionText = open(os.path.join(wx_root, "include", "wx", "version.h"), "r").read()
+
+ majorVersion = re.search("#define\swxMAJOR_VERSION\s+(\d+)", versionText).group(1)
+ minorVersion = re.search("#define\swxMINOR_VERSION\s+(\d+)", versionText).group(1)
+
+ return (majorVersion, minorVersion)
+
+def get_wxmsw_settings(wx_root, shared = False, unicode = False, debug = False, wxPython=False):
+ if not os.path.exists(wx_root):
+ print "Directory %s does not exist." % wx_root
+ sys.exit(1)
+
+ defines = ['__WXMSW__']
+ includes = [os.path.join(wx_root, 'include')]
+ cxxflags = []
+ libs = []
+ libpaths = []
+
+ libdir = os.path.join(wx_root, 'lib')
+ ext = ''
+ postfix = 'vc'
+
+ version_str_nodot = ''.join(get_wx_version(wx_root))
+
+ if shared:
+ defines.append('WXUSINGDLL')
+ libdir = os.path.join(libdir, Options.options.wx_compiler_prefix + '_dll')
+ else:
+ libdir = os.path.join(libdir, Options.options.wx_compiler_prefix + '_lib')
+
+ if unicode:
+ defines.append('_UNICODE')
+ ext += 'u'
+
+ depext = ''
+ if wxPython:
+ ext += 'h'
+ depext += 'h'
+ elif debug:
+ ext += 'd'
+ depext += 'd'
+
+ configdir = os.path.join(libdir, 'msw' + ext)
+
+ monolithic = False
+ cfg_file = os.path.join(configdir, 'build.cfg')
+ if os.path.exists(cfg_file):
+ cfg = parse_build_cfg(cfg_file)
+ if "MONOLITHIC" in cfg:
+ monolithic = cfg["MONOLITHIC"]
+ libpaths.append(libdir)
+ includes.append(configdir)
+
+ def get_wxlib_name(name):
+ if name == 'base':
+ return 'wxbase%s%s' % (version_str_nodot, ext)
+
+ return "wxmsw%s%s_%s" % (version_str_nodot, ext, name)
+
+ libs.extend(['wxzlib' + depext, 'wxjpeg' + depext, 'wxpng' + depext, 'wxexpat' + depext])
+ if monolithic:
+ libs.extend(["wxmsw%s%s" % (version_str_nodot, ext)])
+ else:
+ libs.extend([get_wxlib_name('base'), get_wxlib_name('core')])
+
+ if wxPython or debug:
+ defines.append('__WXDEBUG__')
+
+ return (defines, includes, libs, libpaths)
diff --git a/Tools/wx/install-unix-extras b/Tools/wx/install-unix-extras
new file mode 100755
index 0000000..00c936c
--- /dev/null
+++ b/Tools/wx/install-unix-extras
@@ -0,0 +1,200 @@
+#!/bin/sh
+
+# 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.
+
+# A script to download the extra libraries needed to build WebKit on UNIX-based OSes.
+# libxml/libxslt need to be added, but so far I've had them on all the (UNIX) machines
+# I've tested on, so I don't have a machine to test the code on.
+
+DL_CMD="curl -L"
+
+scriptDir="$(cd $(dirname $0);pwd)"
+WK_ROOT=$scriptDir/../..
+WK_ROOTDIR=$WK_ROOT
+
+DL_DIR=/tmp/webkit-deps
+# NOTE: If you change this, make sure the dir is on the path.
+DEPS_PREFIX=$WK_ROOT/WebKitLibraries/unix
+DLLEXT=so
+
+if [ "${OSTYPE:0:6}" == "darwin" ]; then
+ DLLEXT=dylib
+fi
+
+mkdir -p $DL_DIR
+mkdir -p $DEPS_PREFIX
+
+ICU_VERSION="3.4.1"
+ICU_TARBALL="icu-$ICU_VERSION.tgz"
+ICU_URL="ftp://ftp.software.ibm.com/software/globalization/icu/$ICU_VERSION/$ICU_TARBALL"
+
+# dependent app, not lib, what should we do for these?
+
+GPERF_VERSION="3.0.1"
+GPERF_TARBALL="gperf-$GPERF_VERSION.tar.gz"
+GPERF_URL="ftp://mirrors.kernel.org/gnu/gperf/$GPERF_TARBALL"
+
+PKG_CONFIG_VERSION="0.20"
+PKG_CONFIG_TARBALL="pkg-config-$PKG_CONFIG_VERSION.tar.gz"
+PKG_CONFIG_URL="http://pkgconfig.freedesktop.org/releases/$PKG_CONFIG_TARBALL"
+
+ICONV_VERSION="1.9.2"
+ICONV_TARBALL="libiconv-$ICONV_VERSION.tar.gz"
+ICONV_URL="http://ftp.gnu.org/pub/gnu/libiconv/$ICONV_TARBALL"
+
+LIBJPEG_VERSION="6b"
+LIBJPEG_TARBALL="jpegsrc.v$LIBJPEG_VERSION.tar.gz"
+LIBJPEG_URL="http://wxwebkit.wxcommunity.com/downloads/deps/$LIBJPEG_TARBALL"
+
+LIBPNG_VERSION="1.2.33"
+LIBPNG_TARBALL="libpng-$LIBPNG_VERSION.tar.gz"
+LIBPNG_URL="http://wxwebkit.wxcommunity.com/downloads/deps/$LIBPNG_TARBALL"
+
+LIBCURL_VERSION="7.19.6"
+LIBCURL_TARBALL="curl-$LIBCURL_VERSION.tar.gz"
+LIBCURL_URL="http://curl.haxx.se/download/$LIBCURL_TARBALL"
+
+export MAC_OS_X_DEPLOYMENT_TARGET=10.4
+
+cd $DL_DIR
+# build ICU
+if [ `which icu-config >/dev/null 2>&1` ]; then
+ $DL_CMD -o $DL_DIR/$ICU_TARBALL $ICU_URL
+
+ tar xzvf $DL_DIR/$ICU_TARBALL
+ cd $DL_DIR/icu/source
+
+ chmod +x configure install-sh
+
+ if [ "${OSTYPE:0:6}" == "darwin" ]; then
+ ./configure --prefix=$DEPS_PREFIX --disable-dependency-tracking
+ make CFLAGS="-O -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc" \
+ LDFLAGS="-arch i386 -arch ppc"
+ make install
+ else
+ ./configure --prefix=$DEPS_PREFIX
+
+ make
+ #make check
+ make install
+ fi
+ cd $DL_DIR
+ rm -rf icu
+fi
+
+# TODO: What would be a good way to test for this?
+if [ ! -f $DEPS_PREFIX/lib/libiconv.$DLLEXT ]; then
+ $DL_CMD -o $DL_DIR/$ICONV_TARBALL $ICONV_URL
+
+ tar xzvf $DL_DIR/$ICONV_TARBALL
+ cd $DL_DIR/libiconv-$ICONV_VERSION
+
+ if [ "${OSTYPE:0:6}" == "darwin" ]; then
+ ./configure --prefix=$DEPS_PREFIX --disable-dependency-tracking
+ make CFLAGS="-O -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc" \
+ LDFLAGS="-arch i386 -arch ppc"
+ make install
+ else
+ ./configure --prefix=$DEPS_PREFIX
+
+ make
+ make install
+ fi
+ cd $DL_DIR
+ rm -rf $DL_DIR/libiconv-$ICONV_VERSION
+fi
+
+if [ ! -f $DEPS_PREFIX/lib/libjpeg.a ]; then
+ $DL_CMD -o $DL_DIR/$LIBJPEG_TARBALL $LIBJPEG_URL
+
+ tar xzvf $DL_DIR/$LIBJPEG_TARBALL
+ cd $DL_DIR/jpeg-$LIBJPEG_VERSION
+
+ # jpeg install command expects this to exist.
+ mkdir -p $DEPS_PREFIX/man/man1
+
+ if [ "${OSTYPE:0:6}" == "darwin" ]; then
+ ./configure --prefix=$DEPS_PREFIX --disable-dependency-tracking
+ make CFLAGS="-O -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc" \
+ LDFLAGS="-arch i386 -arch ppc"
+ make install
+ else
+ ./configure --prefix=$DEPS_PREFIX
+
+ make
+ fi
+
+ cp libjpeg.a $DEPS_PREFIX/lib
+ cp *.h $DEPS_PREFIX/include
+
+ cd $DL_DIR
+ rm -rf $DL_DIR/jpeg-$LIBJPEG_VERSION
+fi
+
+if [ ! -f $DEPS_PREFIX/lib/libpng.a ]; then
+ $DL_CMD -o $DL_DIR/$LIBPNG_TARBALL $LIBPNG_URL
+
+ tar xzvf $DL_DIR/$LIBPNG_TARBALL
+ cd $DL_DIR/libpng-$LIBPNG_VERSION
+
+ if [ "${OSTYPE:0:6}" == "darwin" ]; then
+ ./configure --prefix=$DEPS_PREFIX --disable-dependency-tracking
+ make CFLAGS="-O -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc" \
+ LDFLAGS="-arch i386 -arch ppc"
+ make install
+ else
+ ./configure --prefix=$DEPS_PREFIX
+
+ make
+ make install
+ fi
+
+ cd $DL_DIR
+ rm -rf $DL_DIR/libpng-$LIBPNG_VERSION
+fi
+
+if [ ! -f $DEPS_PREFIX/lib/libcurl.$DLLEXT ]; then
+ $DL_CMD -o $DL_DIR/$LIBCURL_TARBALL $LIBCURL_URL
+
+ tar xzvf $DL_DIR/$LIBCURL_TARBALL
+ cd $DL_DIR/curl-$LIBCURL_VERSION
+
+ if [ "${OSTYPE:0:6}" == "darwin" ]; then
+ ./configure --prefix=$DEPS_PREFIX --disable-dependency-tracking
+ make CFLAGS="-O -g -isysroot /Developer/SDKs/MacOSX10.4u.sdk -arch i386 -arch ppc" \
+ LDFLAGS="-arch i386 -arch ppc"
+ make install
+ else
+ ./configure --prefix=$DEPS_PREFIX
+
+ make
+ make install
+ fi
+
+ cd $DL_DIR
+ rm -rf $DL_DIR/curl-$LIBCURL_VERSION
+fi
diff --git a/Tools/wx/packaging/build-debian-installer.py b/Tools/wx/packaging/build-debian-installer.py
new file mode 100644
index 0000000..5c6795d
--- /dev/null
+++ b/Tools/wx/packaging/build-debian-installer.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+import os
+import shutil
+import sys
+
+sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "build")))
+
+import build_utils
+
+script_dir = os.path.abspath(os.path.dirname(__file__))
+wxwebkit_dir = os.path.abspath(os.path.join(script_dir, "..", "..", "..", "WebKitBuild", "Debug" + build_utils.git_branch_name()))
+wxwk_root = os.path.abspath(os.path.join(script_dir, "..", "..", ".."))
+
+try:
+ os.chdir(wxwk_root)
+ deb_dir = os.path.join(wxwk_root, 'wxwebkit')
+ if os.path.exists(deb_dir):
+ shutil.rmtree(deb_dir)
+ os.makedirs(deb_dir)
+ print "Archiving git tree..."
+ os.system('git archive --format=tar HEAD | gzip > %s/webkitwx_0.1.orig.tar.gz' % deb_dir)
+ src_root = os.path.join(deb_dir, 'webkitwx-0.1')
+ print "Extracting tree..."
+ os.makedirs(src_root)
+ os.chdir(src_root)
+ os.system('tar xzvf ../webkitwx_0.1.orig.tar.gz')
+
+ shutil.copytree(os.path.join(script_dir, 'debian'), os.path.join(src_root, 'debian'))
+
+ print "Building package..."
+ os.system('fakeroot debian/rules clean')
+ os.system('fakeroot debian/rules build')
+ os.system('debuild -i -rfakeroot -us -uc')
+finally:
+ shutil.rmtree(os.path.join(src_root, 'debian'))
diff --git a/Tools/wx/packaging/build-mac-installer.py b/Tools/wx/packaging/build-mac-installer.py
new file mode 100644
index 0000000..5b76b0b
--- /dev/null
+++ b/Tools/wx/packaging/build-mac-installer.py
@@ -0,0 +1,158 @@
+#!/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.
+#
+# Script for building Mac .pkg installer
+
+import commands
+import datetime
+import distutils.sysconfig
+import glob
+import optparse
+import os
+import shutil
+import string
+import sys
+import tempfile
+
+script_dir = os.path.abspath(os.path.dirname(__file__))
+sys.path.append(os.path.abspath(os.path.join(script_dir, "..", "build")))
+
+from build_utils import *
+
+import wx
+
+wxwk_root = os.path.abspath(os.path.join(script_dir, "..", "..", ".."))
+wxwebkit_dir = os.path.abspath(os.path.join(wxwk_root, "WebKitBuild", get_config(wxwk_root) + git_branch_name()))
+
+wx_version = wx.__version__[:5]
+py_version = sys.version[:3]
+
+date = str(datetime.date.today())
+
+platform = "osx"
+
+pkgname = "wxWebKit-%s-wx%s-py%s-%s" % (platform, wx_version[:3], py_version, date)
+
+tempdir = "/tmp/%s" % (pkgname)
+
+if os.path.exists(tempdir):
+ shutil.rmtree(tempdir)
+ os.makedirs(tempdir)
+
+installroot = os.path.join(tempdir, "install-root")
+installapps = os.path.join(tempdir, "install-apps")
+
+sp_root = distutils.sysconfig.get_python_lib()
+wx_root = sp_root
+if sys.platform.startswith("darwin"):
+ wx_root = "/usr/local/lib/wxPython-unicode-%s" % wx.__version__
+ sp_root = "%s/lib/python%s/site-packages" % (wx_root, py_version)
+sitepackages = "%s/wx-%s-mac-unicode/wx" % (sp_root, wx_version[:3])
+prefix = sitepackages
+
+def mac_update_dependencies(dylib, prefix):
+ """
+ Copies any non-system dependencies into the bundle, and
+ updates the install name path to the new path in the bundle.
+ """
+ global wx_root
+ system_prefixes = ["/usr/lib", "/System/Library", wx_root]
+
+ output = commands.getoutput("otool -L %s" % dylib).strip()
+ for line in output.split("\n"):
+ filename = line.split("(")[0].strip()
+ if os.path.exists(filename):
+ print "checking dll %s" % filename
+ copy = True
+ for sys_prefix in system_prefixes:
+ if filename.startswith(sys_prefix):
+ copy = False
+
+ if copy:
+ copydir = os.path.dirname(dylib)
+
+ filedir, basename = os.path.split(filename)
+ dest_filename = os.path.join(prefix, basename)
+ copyname = os.path.join(copydir, basename)
+ if not os.path.exists(copyname):
+ shutil.copy(filename, copydir)
+ os.system("install_name_tool -id %s %s" % (dest_filename, copyname))
+
+ os.system("install_name_tool -change %s %s %s" % (filename, dest_filename, dylib))
+
+def exitIfError(cmd):
+ print cmd
+ retval = os.system(cmd)
+ if retval != 0:
+ if os.path.exists(tempdir):
+ shutil.rmtree(tempdir)
+ sys.exit(1)
+
+wxroot = installroot + prefix
+wxpythonroot = installroot + sitepackages
+
+try:
+ if not os.path.exists(wxroot):
+ os.makedirs(wxroot)
+
+ if not os.path.exists(wxpythonroot):
+ os.makedirs(wxpythonroot)
+
+ for wildcard in ["*.py", "*.so", "*.dylib"]:
+ files = glob.glob(os.path.join(wxwebkit_dir, wildcard))
+ for afile in files:
+ shutil.copy(afile, wxpythonroot)
+
+ if sys.platform.startswith("darwin"):
+ dylib_path = os.path.join(wxpythonroot, "libwxwebkit.dylib")
+ os.system("install_name_tool -id %s %s" % (os.path.join(prefix, "libwxwebkit.dylib"), dylib_path))
+ mac_update_dependencies(dylib_path, prefix)
+ mac_update_dependencies(os.path.join(wxpythonroot, "_webview.so"), prefix)
+
+ demodir = installroot + "/Applications/wxWebKit/Demos"
+ if not os.path.exists(demodir):
+ os.makedirs(demodir)
+
+ shutil.copy(os.path.join(wxwk_root, "WebKit", "wx", "bindings", "python", "samples", "simple.py"), demodir)
+
+ if os.path.exists(pkgname + ".pkg"):
+ shutil.rmtree(pkgname + ".pkg")
+
+ pkg_args = ['--title ' + pkgname,
+ '--out %s.pkg' % pkgname,
+ '--version ' + date.strip(),
+ '--id org.wxwebkit.wxwebkit',
+ '--domain system',
+ '--root-volume-only',
+ '--root ' + installroot,
+ '--resources %s/mac/resources' % script_dir,
+ '--verbose'
+ ]
+
+ packagemaker = "/Developer/Applications/Utilities/PackageMaker.app/Contents/MacOS/PackageMaker"
+ exitIfError(packagemaker + " %s" % (string.join(pkg_args, " ")))
+finally:
+ if os.path.exists(tempdir):
+ shutil.rmtree(tempdir)
diff --git a/Tools/wx/packaging/build-win-installer.py b/Tools/wx/packaging/build-win-installer.py
new file mode 100644
index 0000000..ffbdd19
--- /dev/null
+++ b/Tools/wx/packaging/build-win-installer.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+
+# Copyright (C) 2008 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.
+#
+# Create a Windows installer package for wxPython wxWebKit binaries
+
+import sys, os, string
+import commands
+import datetime
+import glob
+from subprocess import *
+
+script_dir = os.path.abspath(os.path.dirname(__file__))
+sys.path.append(os.path.abspath(os.path.join(script_dir, "..", "build")))
+
+from build_utils import *
+
+wxwk_root = os.path.abspath(os.path.join(script_dir, "..", "..", ".."))
+wxwebkit_dir = os.path.abspath(os.path.join(wxwk_root, "WebKitBuild", get_config(wxwk_root) + git_branch_name()))
+
+# Find InnoSetup executable
+def getInnoSetupPath():
+ name = "ISCC.exe"
+ retval = ""
+ dirs = os.environ["PATH"].split(":")
+ # Add the default file path
+ dirs.append("C:\\Program Files\\Inno Setup 5")
+ dirs.append("C:\\Program Files (x86)\\Inno Setup 5")
+
+ if os.environ.has_key("INNO5"):
+ retval = os.environ["INNO5"]
+
+ if retval == "":
+ for dir in dirs:
+ filepath = os.path.join(dir, name)
+ if os.path.isfile(filepath):
+ retval = filepath
+
+ return retval
+
+if __name__ == "__main__":
+ innoSetup = getInnoSetupPath()
+ os.chdir(sys.path[0])
+
+ date = str(datetime.date.today())
+
+ if not os.path.exists(innoSetup):
+ print "ERROR: Cannot find InnoSetup."
+ #sys.exit(1)
+
+ if not os.path.exists(wxwebkit_dir):
+ print "ERROR: Build dir %s doesn't exist." % wxwebkit_dir
+ sys.exit(1)
+
+ fileList = """
+CopyMode: alwaysoverwrite; Source: *.pyd; DestDir: "{app}"
+CopyMode: alwaysoverwrite; Source: *.py; DestDir: "{app}"
+"""
+
+ dlls = glob.glob(os.path.join(wxwebkit_dir, "*.dll"))
+ for dll in dlls:
+ if dll.find("wxbase") == -1 and dll.find("wxmsw") == -1:
+ fileList += """CopyMode: alwaysoverwrite; Source: %s; DestDir: "{app}" \n""" % dll
+
+ installerTemplate = open("wxWebKitInstaller.iss.in", "r").read()
+
+ installerTemplate = installerTemplate.replace("<<VERSION>>", date)
+ installerTemplate = installerTemplate.replace("<<ROOTDIR>>", wxwebkit_dir )
+ installerTemplate = installerTemplate.replace("<<PYTHONVER>>", sys.version[0:3] )
+ installerTemplate = installerTemplate.replace("<<FILES>>", fileList )
+
+ outputFile = open("wxWebKitInstaller.iss", "w")
+ outputFile.write(installerTemplate)
+ outputFile.close()
+
+ success = os.system('"%s" wxWebKitInstaller.iss' % innoSetup)
+ sys.exit(success)
diff --git a/Tools/wx/packaging/debian/changelog b/Tools/wx/packaging/debian/changelog
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/Tools/wx/packaging/debian/changelog
@@ -0,0 +1 @@
+
diff --git a/Tools/wx/packaging/debian/compat b/Tools/wx/packaging/debian/compat
new file mode 100644
index 0000000..7ed6ff8
--- /dev/null
+++ b/Tools/wx/packaging/debian/compat
@@ -0,0 +1 @@
+5
diff --git a/Tools/wx/packaging/debian/control b/Tools/wx/packaging/debian/control
new file mode 100644
index 0000000..57d8407
--- /dev/null
+++ b/Tools/wx/packaging/debian/control
@@ -0,0 +1,29 @@
+Source: webkitwx
+Section: Python
+Priority: extra
+Maintainer: Kevin Ollivier <kevino@theolliviers.com>
+Build-Depends: debhelper (>= 5.0.38), python-central (>= 0.6), python-all-dev,
+ libwxgtk2.8-dev (>= 2.8.9.2-1), python-wxgtk2.8, python-wxtools (>= 2.8.9.2-1),
+ wx2.8-headers (>= 2.8.9.2-1), wx2.8-i18n (>= 2.8.9.2-1),
+ flex, bison, gperf, automake, autoconf, libtool, dpatch,
+ libxslt1-dev, libcurl4-openssl-dev,
+ libicu-dev, libjpeg62-dev, libpng12-dev, libsqlite3-dev, libgtk2.0-dev
+Build-Conflicts: python-setuptools
+XS-Python-Version: all
+Standards-Version: 3.7.3
+
+Package: python-webkitwx
+Section: python
+Architecture: any
+Depends: ${python:Depends}, ${shlibs:Depends}
+Provides: ${python:Provides}, webkitwx
+XB-Python-Version: ${python:Versions}
+Description: Python binding of wxwebkit
+ This is an experimental packaged release of webkit for wxpython
+
+Package: webkitwx-headers
+Architecture: all
+Description: Python binding of wxwebkit
+ This is an experimental packaged release of webkit for wxpython
+ These are the header files
+
diff --git a/Tools/wx/packaging/debian/copyright b/Tools/wx/packaging/debian/copyright
new file mode 100644
index 0000000..c2244ec
--- /dev/null
+++ b/Tools/wx/packaging/debian/copyright
@@ -0,0 +1,18 @@
+This package was debianized by Chris Willing c.willing@uq.edu.au on
+Thu, Sat, 11 Apr 2009 12:54:52 +1000
+
+Upstream Author: Kevin Ollivier kevino@theolliviers.com and others
+
+Copyright: 2009 Kevin Ollivier, Apple Inc., and others
+
+License:
+ LGPL
+
+
+The Debian packaging is (C) 2009, Chris Willing <c.willing@uq.edu.au> and
+is licensed under the GPL, see `/usr/share/common-licenses/GPL'.
+
+
+# Please also look if there are files or directories which have a
+# different copyright/license attached and list them here.
+
diff --git a/Tools/wx/packaging/debian/python-webkitwx.install b/Tools/wx/packaging/debian/python-webkitwx.install
new file mode 100644
index 0000000..dff51ce
--- /dev/null
+++ b/Tools/wx/packaging/debian/python-webkitwx.install
@@ -0,0 +1 @@
+WebKitBuild/Debug.master/libwxwebkit.so usr/lib/
diff --git a/Tools/wx/packaging/debian/rules b/Tools/wx/packaging/debian/rules
new file mode 100644
index 0000000..aea6def
--- /dev/null
+++ b/Tools/wx/packaging/debian/rules
@@ -0,0 +1,75 @@
+#! /usr/bin/make -f
+
+SHELL = /bin/bash
+
+PYVERS := $(shell /usr/bin/python -c 'import sys; print sys.version[:3]')
+VER := $(shell /usr/bin/python -c 'import sys; print sys.version[:3]')
+BIULD_DIR := WebKitBuild/Debug.master
+build: build-stamp
+build-stamp: $(PYVERS:%=build-python%)
+ touch $@
+build-python%:
+ touch $@
+
+clean:
+ rm -rf *-stamp build-python* build
+ rm -rf $(addprefix debian/,$(packages)) debian/files debian/substvars
+ rm -rf _trial_temp test.log
+ find . -name "*.pyc" |xargs -r rm
+ dh_clean
+
+install: build-stamp install-prereq $(PYVERS:%=install-python%) install-libs install-nover
+
+install-prereq: build-stamp
+ dh_testdir
+ dh_testroot
+ dh_clean -k
+
+install-python%: install-prereq
+ dh_install -ppython-webkitwx \
+ $(BUILD_DIR)/webview.py \
+ $(BUILD_DIR)/Debug.master/_webview.so \
+ usr/lib/python$*/site-packages/wx-2.8-gtk2-unicode/wx/
+
+install-nover: install-prereq
+ dh_install -pwebkitwx-headers \
+ $(BUILD_DIR)/JavaScriptCore \
+ usr/include/wxwebkit-1.0/
+
+install-libs: install-prereq
+ dh_install
+
+
+binary-indep:
+ (cd Tools/Scripts && ./build-webkit --wx --makeargs="--wxpython")
+ dh_testdir
+ dh_testroot
+ dh_installchangelogs -i
+ dh_installdocs -i
+ dh_strip -i
+ dh_compress -i
+ dh_fixperms -i
+ dh_installdeb -i
+ dh_gencontrol -i
+ dh_md5sums -i
+ dh_builddeb -i
+
+binary-arch:
+ dh_testdir
+ dh_testroot
+ echo $(shell pwd)
+ echo $(shell ls -l)
+ dh_installchangelogs -a
+ dh_installdocs -a WebKit/wx/bindings/python/samples/simple.py
+ dh_strip -a
+ dh_compress -a -Xsimple.py
+ dh_fixperms -a
+ dh_pycentral -a
+ dh_installdeb -a
+ dh_shlibdeps -a
+ dh_gencontrol -a
+ dh_md5sums -a
+ dh_builddeb -a
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install install-nover install-prereq install-libs
diff --git a/Tools/wx/packaging/wxWebKitInstaller.iss.in b/Tools/wx/packaging/wxWebKitInstaller.iss.in
new file mode 100644
index 0000000..ebc89d4
--- /dev/null
+++ b/Tools/wx/packaging/wxWebKitInstaller.iss.in
@@ -0,0 +1,79 @@
+; Installer script for wxWebKit for wxPython
+
+[Setup]
+AppName=wxWebKit
+AppId=wxWebKit
+AppVersion=<<VERSION>>
+AppVerName=wxWebKit <<VERSION>>
+AppCopyright=LGPL
+DefaultDirName={code:GetInstallDir|c:\DoNotInstallHere}
+AppPublisher=wxWebKit Project
+AppPublisherURL=http://wxwebkit.wxcommunity.com/pmwiki/
+AppSupportURL=http://wxwebkit.wxcommunity.com/pmwiki/
+AppUpdatesURL=http://wxwebkit.wxcommunity.com/pmwiki/
+UninstallDisplayName=wxWebKit <<VERSION>>
+UninstallFilesDir={app}\Uninstall
+
+Compression=bzip/9
+SourceDir=<<ROOTDIR>>
+OutputDir=win-installer
+OutputBaseFilename=wxWebKit-wx2.8-Py<<PYTHONVER>>-<<VERSION>>
+DisableStartupPrompt=yes
+AllowNoIcons=yes
+DisableProgramGroupPage=yes
+DisableReadyPage=yes
+
+[Files]
+<<FILES>>
+
+[Messages]
+WelcomeLabel1=Welcome to the wxWebKit for wxPython Setup Wizard
+
+[Code]
+
+program Setup;
+var
+ PythonDir : String;
+ InstallDir : String;
+
+
+function InitializeSetup(): Boolean;
+begin
+
+ (* -------------------------------------------------------------- *)
+ (* Figure out what to use as a default installation dir *)
+
+ if not RegQueryStringValue(HKEY_LOCAL_MACHINE,
+ 'Software\Python\PythonCore\<<PYTHONVER>>\InstallPath',
+ '', PythonDir) then begin
+
+ if not RegQueryStringValue(HKEY_CURRENT_USER,
+ 'Software\Python\PythonCore\<<PYTHONVER>>\InstallPath',
+ '', PythonDir) then begin
+
+ MsgBox('No installation of Python <<PYTHONVER>> found in registry.' + #13 +
+ 'Be sure to enter a pathname that places wxPython on the PYTHONPATH',
+ mbConfirmation, MB_OK);
+ PythonDir := 'C:\Put a directory on PYTHONPATH here\';
+ end;
+ end;
+ InstallDir := PythonDir + '\Lib\site-packages\wx-2.8-msw-unicode\wx\';
+ Result := True;
+end;
+
+
+
+function GetPythonDir(Default: String): String;
+begin
+ Result := PythonDir;
+end;
+
+
+
+function GetInstallDir(Default: String): String;
+begin
+ Result := InstallDir;
+end;
+
+begin
+end.